Files
minisrv/zefie_wtvp_minisrv/includes/classes/WTVAdmin.js

330 lines
14 KiB
JavaScript

const WTVClientSessionData = require('./WTVClientSessionData.js');
class WTVAdmin {
fs = require('fs');
path = require('path');
minisrv_config = [];
wtvr = null;
wtvshared = null;
wtvclient = null;
pcservices = false;
WTVClientSessionData = require("./WTVClientSessionData.js");
service_name = "wtv-admin";
SUCCESS = 0
FAIL = 1
INVALID_OP = 2
REASON_NOSELF = 3
REASON_EXISTS = 4
REASON_NONEXIST = 5
/**
* Creates an instance of WTVAdmin.
* @param {Object} minisrv_config
* @param {WTVClientSessionData} wtvclient
* @param {string} service_name
*/
constructor(minisrv_config, wtvclient, service_name) {
this.minisrv_config = minisrv_config;
const { WTVShared } = require("./WTVShared.js");
const WTVRegister = require("./WTVRegister.js");
this.wtvclient = wtvclient;
this.wtvshared = new WTVShared(minisrv_config);
this.wtvr = new WTVRegister(minisrv_config);
if (this.wtvclient.remoteAddress) {
// is a socket
this.clientAddress = this.wtvclient.remoteAddress;
this.pcservices = true;
} else {
// is wtvclient class
this.clientAddress = this.wtvclient.getClientAddress();
}
this.service_name = service_name;
}
/**
* Bans a specific SSID.
* @param {string} ssid The SSID to ban
* @param {string} admin_ssid The SSID of the admin requesting the ban
* @returns {number} The result of the ban operation
*/
banSSID(ssid, admin_ssid = null) {
if (ssid === admin_ssid) {
return this.REASON_NOSELF;
} else {
const fake_config = this.wtvshared.getUserConfig();
if (!fake_config.config) fake_config.config = {};
if (!fake_config.config.ssid_block_list) fake_config.config.ssid_block_list = [];
let entry_exists = false;
const self = this;
Object.keys(fake_config.config.ssid_block_list).forEach(function (k) {
if (fake_config.config.ssid_block_list[k] === ssid) {
entry_exists = true;
return self.REASON_EXISTS;
}
});
if (!entry_exists) {
fake_config.config.ssid_block_list.push(ssid);
this.wtvshared.writeToUserConfig(fake_config);
return this.SUCCESS;
}
}
}
/**
* Unbans a specific SSID.
* @param {string} ssid The SSID to unban
* @returns {number} The result of the unban operation
*/
unbanSSID(ssid) {
let config_changed = false;
const fake_config = this.wtvshared.getUserConfig();
if (!fake_config.config) fake_config.config = {};
if (!fake_config.config.ssid_block_list) fake_config.config.ssid_block_list = [];
if (typeof ssid === 'string') {
Object.keys(fake_config.config.ssid_block_list).forEach(function (k) {
if (fake_config.config.ssid_block_list[k].toLowerCase() === ssid.toLowerCase()) {
fake_config.config.ssid_block_list.splice(k, 1);
config_changed = true
}
});
} else {
Object.keys(fake_config.config.ssid_block_list).forEach(function (k) {
Object.keys(ssid).forEach(function (j) {
if (fake_config.config.ssid_block_list[k].toLowerCase() === ssid[j].toLowerCase()) {
fake_config.config.ssid_block_list.splice(k, 1);
config_changed = true
}
});
});
}
if (config_changed) {
this.wtvshared.writeToUserConfig(fake_config);
//this.minisrv_config = reloadConfig();
return this.SUCCESS
} else {
return this.REASON_NONEXIST;
}
}
/**
* Rejects a connection attempt based on the client's address or SSID.
* @param {boolean} reason_is_ssid If true, the rejection is based on SSID, otherwise on IP address
* @returns {string} The reason for rejecting the connection
*/
rejectConnection(reason_is_ssid) {
let rejectReason;
if (this.pcservices) {
rejectReason = this.clientAddress + " is not in the whitelist for PC Services Admin.";
console.log(" * Request from IP (" + this.clientAddress + ") for PC Services Admin, but that IP is not authorized.");
} else {
if (reason_is_ssid) {
rejectReason = this.wtvclient.ssid + " is not in the whitelist.";
console.log(" * Request from SSID", this.wtvshared.filterSSID(this.wtvclient.ssid), "(" + this.clientAddress + ") for wtv-admin, but that SSID is not in the admin whitelist.");
} else {
rejectReason = this.clientAddress + " is not in the whitelist for SSID " + this.wtvclient.ssid + ".";
console.log(" * Request from SSID", this.wtvshared.filterSSID(this.wtvclient.ssid), "(" + this.clientAddress + ") for wtv-admin, but that IP is not authorized for that SSID.");
}
}
return rejectReason;
}
/**
* Checks if the provided password matches the service's password.
* @param {string} password The password to check
* @returns {boolean} True if the password matches, false otherwise
*/
checkPassword(password) {
if (this.pcservices) {
if (this.minisrv_config.config.pc_admin.password) {
return (password === this.minisrv_config.config.pc_admin.password);
} else {
// no password set
return true;
}
} else {
if (this.minisrv_config.services[this.service_name].password) {
return (password === this.minisrv_config.services[this.service_name].password);
} else {
// no password set
return true;
}
}
}
/**
* Lists all registered SSIDs.
* @returns {Array} An array of arrays, each containing the SSID and its associated account information
*/
listRegisteredSSIDs() {
const search_dir = this.wtvshared.getAbsolutePath(this.minisrv_config.config.SessionStore + this.path.sep + "accounts");
const self = this;
const out = [];
this.fs.readdirSync(search_dir).forEach(file => {
if (self.fs.lstatSync(search_dir + self.path.sep + file).isDirectory()) {
const user = self.getAccountInfoBySSID(file);
out.push([file, user]);
}
});
return out;
}
/**
* Checks if the current client is authorized to access the service.
* @param {boolean} justchecking If true, only checks authorization without rejecting the connection
* @return {boolean} True if authorized, false otherwise
*/
isAuthorized(justchecking = false) {
let allowed_ssid = false;
let allowed_ip = false;
const use_ssid = (this.wtvclient.ssid && !this.pcservices) ? true : false
if (use_ssid) {
if (this.minisrv_config.services[this.service_name].authorized_ssids) {
const self = this;
Object.keys(self.minisrv_config.services[this.service_name].authorized_ssids).forEach(function (k) {
if (typeof self.minisrv_config.services[self.service_name].authorized_ssids[k] === "string") {
const ssid = self.minisrv_config.services[self.service_name].authorized_ssids[k]
if (ssid === self.wtvclient.ssid) allowed_ssid = true;
allowed_ip = true; // no ip block defined
} else {
const ssid = k;
if (ssid === self.wtvclient.ssid) {
allowed_ssid = true;
Object.keys(self.minisrv_config.services[self.service_name].authorized_ssids[k]).forEach(function (j) {
if (self.wtvshared.isInSubnet(self.clientAddress, self.minisrv_config.services[self.service_name].authorized_ssids[k][j])) {
if (allowed_ip) return;
allowed_ip = true;
}
});
}
}
});
}
} else {
if (this.pcservices) {
if (!this.minisrv_config.config.pc_admin.enabled) {
if (justchecking) return false;
else return this.rejectConnection(false);
}
if (this.minisrv_config.config.pc_admin.ip_whitelist) {
const self = this;
Object.keys(this.minisrv_config.config.pc_admin.ip_whitelist).forEach(function (k) {
if (allowed_ip) return;
allowed_ip = self.wtvshared.isInSubnet(self.clientAddress, self.minisrv_config.config.pc_admin.ip_whitelist[k]);
});
}
}
allowed_ssid = true;
}
if (justchecking) {
return (allowed_ssid && allowed_ip) ? true : false;
} else {
return (allowed_ssid && allowed_ip) ? true : this.rejectConnection(!allowed_ssid);
}
}
/**
* Gets the account information for a specific username.
* @param {string} username The username to get the account information for
* @param {string|null} directory The directory to search for user accounts, defaults to the session store directory
* @returns {Object|null} An object containing account information if the username is found, null otherwise
*/
getAccountInfo(username, directory = null) {
let search_dir = this.wtvshared.getAbsolutePath(this.minisrv_config.config.SessionStore + this.path.sep + "accounts");
let account_data = null;
const self = this;
if (directory) search_dir = directory;
this.fs.readdirSync(search_dir).forEach(file => {
if (self.fs.lstatSync(search_dir + self.path.sep + file).isDirectory() && account_data === null) {
account_data = self.getAccountInfo(username, search_dir + self.path.sep + file);
}
if (account_data !== null) return;
if (!file.match(/.*\.json/ig)) return;
try {
const temp_session_data_file = self.fs.readFileSync(search_dir + self.path.sep + file, 'Utf8');
const temp_session_data = JSON.parse(temp_session_data_file);
if (temp_session_data.subscriber_username.toLowerCase() === username.toLowerCase()) {
account_data = [temp_session_data, (search_dir + self.path.sep + file).replace(this.wtvshared.getAbsolutePath(this.minisrv_config.config.SessionStore + this.path.sep + "accounts"), "").split(this.path.sep)[1]];
}
} catch (e) {
console.error(" # Error parsing Session Data JSON", search_dir + self.path.sep + file, e);
}
});
if (account_data !== null) {
if (account_data.ssid) return account_data;
const account_info = {};
account_info.ssid = account_data[1];
account_info.username = account_data[0].subscriber_username;
account_info.user_id = account_data[0].subscriber_userid;
const userSession = new this.WTVClientSessionData(this.minisrv_config, account_info.ssid);
userSession.user_id = 0;
account_info.account_users = userSession.listPrimaryAccountUsers();
return account_info;
}
return null;
}
/**
* Gets the account information for a specific SSID.
* @param {string} ssid The SSID to get the account information for
* @returns {Object|boolean} An object containing account information if the SSID is registered, false otherwise
*/
getAccountInfoBySSID(ssid) {
const account_info = {};
const userSession = new this.WTVClientSessionData(this.minisrv_config, ssid);
userSession.user_id = 0;
if (userSession.isRegistered(false)) {
account_info.ssid = ssid;
account_info.account_users = userSession.listPrimaryAccountUsers();
if (account_info.account_users) {
if (account_info.account_users['subscriber']) {
account_info.username = account_info.account_users['subscriber'].subscriber_username;
} else {
account_info.username = account_info.account_users[0];
}
} else {
account_info.username = account_info.account_users[0];
}
account_info.user_id = 0;
return account_info;
}
else return false;
}
/**
* Gets the account session data for a specific SSID.
* @param {string} ssid The SSID to get the account data for
* @returns {WTVClientSessionData} The session data object for the account
*/
getAccountBySSID(ssid) {
const userSession = new this.WTVClientSessionData(this.minisrv_config, ssid);
userSession.user_id = 0;
return userSession;
}
/**
* Checks if a specific SSID is banned.
* @param {string} ssid The SSID to check
* @returns {boolean} True if the SSID is banned, false otherwise
*/
isBanned(ssid) {
const self = this;
let isBanned = false;
if (this.minisrv_config.config.ssid_block_list) {
Object.keys(this.minisrv_config.config.ssid_block_list).forEach(function (k) {
if (self.minisrv_config.config.ssid_block_list[k] === ssid) {
isBanned = true;
}
});
}
return isBanned;
}
}
module.exports = WTVAdmin;