v0.9.55 (#32)
* v0.9.55 - CGI Support (eg PHP, Perl, etc) - Slight PC Admin updates - Numerous bug fixes - Security updates --------- Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
This commit is contained in:
32
zefie_wtvp_minisrv/includes/classes/Prototypes.js
Normal file
32
zefie_wtvp_minisrv/includes/classes/Prototypes.js
Normal file
@@ -0,0 +1,32 @@
|
||||
const prototypes = {
|
||||
String: {
|
||||
reverse: function () {
|
||||
return this.split("").reverse().join("");
|
||||
},
|
||||
toHexString: function () {
|
||||
var result = '';
|
||||
for (var i = 0; i < this.length; i++) {
|
||||
result += this.charCodeAt(i).toString(16);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
},
|
||||
Array: {
|
||||
replace: function(sub, newSub) {
|
||||
splits = this.split(sub, 2);
|
||||
return Array.concat(splits[0], newSub, splits[1])
|
||||
},
|
||||
moveKey: function (from, to) {
|
||||
this.splice(to, 0, this.splice(from, 1)[0]);
|
||||
return this;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
for (const [type, methods] of Object.entries(prototypes)) {
|
||||
for (const [name, method] of Object.entries(methods)) {
|
||||
if (!global[type].prototype[name]) {
|
||||
global[type].prototype[name] = method;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -6,9 +6,18 @@ class WTVAdmin {
|
||||
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
|
||||
|
||||
constructor(minisrv_config, wtvclient, service_name) {
|
||||
this.minisrv_config = minisrv_config;
|
||||
var { WTVShared } = require("./WTVShared.js");
|
||||
@@ -16,10 +25,69 @@ class WTVAdmin {
|
||||
this.wtvclient = wtvclient;
|
||||
this.wtvshared = new WTVShared(minisrv_config);
|
||||
this.wtvr = new WTVRegister(minisrv_config);
|
||||
this.clientAddress = wtvclient.getClientAddress();
|
||||
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;
|
||||
}
|
||||
|
||||
banSSID(ssid, admin_ssid = null) {
|
||||
if (ssid == admin_ssid) {
|
||||
return this.REASON_NOSELF;
|
||||
} else {
|
||||
var 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 = [];
|
||||
var entry_exists = false;
|
||||
var self = this;
|
||||
Object.keys(fake_config.config.ssid_block_list).forEach(function (k) {
|
||||
if (fake_config.config.ssid_block_list[k] == ssid) {
|
||||
return self.REASON_EXISTS;
|
||||
}
|
||||
});
|
||||
if (!entry_exists) {
|
||||
fake_config.config.ssid_block_list.push(ssid);
|
||||
this.wtvshared.writeToUserConfig(fake_config);
|
||||
return this.SUCCESS;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
unbanSSID(ssid) {
|
||||
var config_changed = false;
|
||||
var fake_config = wtvshared.getUserConfig();
|
||||
if (!fake_config.config) fake_config.config = {};
|
||||
if (!fake_config.config.ssid_block_list) fake_config.config.ssid_block_list = [];
|
||||
if (typeof request_headers.query.ssid === 'string') {
|
||||
Object.keys(fake_config.config.ssid_block_list).forEach(function (k) {
|
||||
if (fake_config.config.ssid_block_list[k].toLowerCase() == request_headers.query.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(request_headers.query.ssid).forEach(function (j) {
|
||||
if (fake_config.config.ssid_block_list[k].toLowerCase() == request_headers.query.ssid[j].toLowerCase()) {
|
||||
fake_config.config.ssid_block_list.splice(k, 1);
|
||||
config_changed = true
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
if (config_changed) {
|
||||
wtvshared.writeToUserConfig(fake_config);
|
||||
minisrv_config = reloadConfig();
|
||||
return this.SUCCESS
|
||||
} else {
|
||||
return this.REASON_NONEXIST;
|
||||
}
|
||||
}
|
||||
|
||||
ip2long(ip) {
|
||||
var components;
|
||||
@@ -53,47 +121,87 @@ class WTVAdmin {
|
||||
|
||||
rejectConnection(reason_is_ssid) {
|
||||
var rejectReason;
|
||||
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.");
|
||||
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 {
|
||||
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.");
|
||||
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;
|
||||
}
|
||||
|
||||
checkPassword(password) {
|
||||
if (this.minisrv_config.services[this.service_name].password) {
|
||||
return (password == this.minisrv_config.services[this.service_name].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 {
|
||||
// no password set
|
||||
return true;
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
listRegisteredSSIDs() {
|
||||
var search_dir = this.wtvshared.getAbsolutePath(this.minisrv_config.config.SessionStore + this.path.sep + "accounts");
|
||||
var self = this;
|
||||
var out = [];
|
||||
this.fs.readdirSync(search_dir).forEach(file => {
|
||||
if (self.fs.lstatSync(search_dir + self.path.sep + file).isDirectory()) {
|
||||
var user = self.getAccountInfoBySSID(file);
|
||||
out.push([file, user]);
|
||||
}
|
||||
});
|
||||
return out;
|
||||
}
|
||||
|
||||
isAuthorized(justchecking = false) {
|
||||
var allowed_ssid = false;
|
||||
var allowed_ip = false;
|
||||
if (this.minisrv_config.services[this.service_name].authorized_ssids) {
|
||||
var 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") {
|
||||
var 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 {
|
||||
var 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.isInSubnet(self.clientAddress, self.minisrv_config.services[self.service_name].authorized_ssids[k][j])) {
|
||||
allowed_ip = true;
|
||||
}
|
||||
});
|
||||
var use_ssid = (this.wtvclient.ssid && !this.pcservices) ? true : false
|
||||
if (use_ssid) {
|
||||
if (this.minisrv_config.services[this.service_name].authorized_ssids) {
|
||||
var 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") {
|
||||
var 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 {
|
||||
var 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.isInSubnet(self.clientAddress, self.minisrv_config.services[self.service_name].authorized_ssids[k][j])) {
|
||||
allowed_ip = true;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
} else {
|
||||
if (this.pcservices) {
|
||||
if (this.minisrv_config.config.pc_admin.ip_whitelist) {
|
||||
var self = this;
|
||||
Object.keys(this.minisrv_config.config.pc_admin.ip_whitelist).forEach(function (k) {
|
||||
allowed_ip = self.isInSubnet(self.clientAddress, self.minisrv_config.config.pc_admin.ip_whitelist[k]);
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
allowed_ssid = true;
|
||||
}
|
||||
if (justchecking) {
|
||||
return (allowed_ssid && allowed_ip) ? true : false;
|
||||
@@ -103,7 +211,7 @@ class WTVAdmin {
|
||||
}
|
||||
|
||||
getAccountInfo(username, directory = null) {
|
||||
var search_dir = this.minisrv_config.config.SessionStore + this.path.sep + "accounts";
|
||||
var search_dir = this.wtvshared.getAbsolutePath(this.minisrv_config.config.SessionStore + this.path.sep + "accounts");
|
||||
var account_data = null;
|
||||
var self = this;
|
||||
if (directory) search_dir = directory;
|
||||
@@ -118,7 +226,7 @@ class WTVAdmin {
|
||||
var 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.minisrv_config.config.SessionStore + this.path.sep + "accounts", "").split(this.path.sep)[1]];
|
||||
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);
|
||||
@@ -145,7 +253,16 @@ class WTVAdmin {
|
||||
if (userSession.isRegistered(false)) {
|
||||
account_info.ssid = ssid;
|
||||
account_info.account_users = userSession.listPrimaryAccountUsers();
|
||||
account_info.username = account_info.account_users['subscriber'].subscriber_username;
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -127,6 +127,19 @@ class WTVClientSessionData {
|
||||
return true;
|
||||
}
|
||||
|
||||
isAddressInAddressBook(addr) {
|
||||
const addresses = this.getSessionData("address_book");
|
||||
if (addresses) {
|
||||
for (let i = 0; i < addresses.length; i++) {
|
||||
console.log(addr.toLowerCase(), addresses[i].address.toLowerCase())
|
||||
if (addr.toLowerCase() == addresses[i].address.toLowerCase()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
findFreeUserSlot() {
|
||||
if (this.user_id != 0) return false; // subscriber only command
|
||||
var master_directory = this.getUserStoreDirectory(true);
|
||||
@@ -158,10 +171,11 @@ class WTVClientSessionData {
|
||||
var master_directory = this.getUserStoreDirectory(true);
|
||||
var account_data = [];
|
||||
var self = this;
|
||||
this.debug(this.ssid)
|
||||
this.fs.readdirSync(master_directory).forEach(f => {
|
||||
if (self.fs.lstatSync(master_directory + self.path.sep + f).isDirectory()) {
|
||||
if (f.substr(0, 4) == "user") {
|
||||
var user_file = master_directory + self.path.sep + f + self.path.sep + f + ".json";
|
||||
var user_file = this.path.resolve(master_directory + self.path.sep + f + self.path.sep + f + ".json");
|
||||
if (self.fs.existsSync(user_file)) {
|
||||
if (f == "user0") {
|
||||
account_data['subscriber'] = JSON.parse(this.fs.readFileSync(user_file));
|
||||
@@ -193,7 +207,7 @@ class WTVClientSessionData {
|
||||
}
|
||||
|
||||
getAccountStoreDirectory() {
|
||||
return this.path.resolve(this.wtvshared.getAbsolutePath() + this.path.sep + this.minisrv_config.config.SessionStore + this.path.sep + "accounts");
|
||||
return this.wtvshared.getAbsolutePath(this.minisrv_config.config.SessionStore + this.path.sep + "accounts");
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -205,7 +219,7 @@ class WTVClientSessionData {
|
||||
if (user_id == null) user_id = this.user_id;
|
||||
var userstore = this.getAccountStoreDirectory() + this.path.sep + this.ssid + this.path.sep;
|
||||
if (!subscriber) userstore += "user" + user_id + this.path.sep;
|
||||
return userstore;
|
||||
return this.wtvshared.getAbsolutePath(userstore);
|
||||
}
|
||||
|
||||
removeUser(user_id) {
|
||||
@@ -264,7 +278,7 @@ class WTVClientSessionData {
|
||||
if (!store_dir) return false; // unregistered
|
||||
// FileStore
|
||||
store_dir += "FileStore" + this.path.sep;
|
||||
var store_dir_path = this.wtvshared.makeSafePath(store_dir, path.replace('/', this.path.sep));
|
||||
var store_dir_path = this.wtvshared.getAbsolutePath(this.wtvshared.makeSafePath(store_dir, path.replace('/', this.path.sep)));
|
||||
if (this.fs.existsSync(store_dir_path)) return this.fs.readFileSync(store_dir_path);
|
||||
else return false;
|
||||
}
|
||||
@@ -611,8 +625,8 @@ class WTVClientSessionData {
|
||||
}
|
||||
|
||||
getSessionData(key = null) {
|
||||
if (typeof (this.data_store) === 'session_store') return null;
|
||||
else if (key === null) return this.data_store;
|
||||
if (typeof (this.session_store) === 'session_store') return null;
|
||||
else if (key === null) return this.session_store;
|
||||
else if (this.session_store[key]) return this.session_store[key];
|
||||
else return null;
|
||||
}
|
||||
|
||||
@@ -376,7 +376,7 @@ class WTVMail {
|
||||
|
||||
checkUserExists(username, directory = null) {
|
||||
// returns the user's ssid, and user_id and userid in an array if true, false if not
|
||||
var search_dir = this.minisrv_config.config.SessionStore;
|
||||
var search_dir = this.path.resolve(this.wtvshared.getAbsolutePath() + this.path.sep + this.minisrv_config.config.SessionStore);
|
||||
var return_val = false;
|
||||
var self = this;
|
||||
if (directory) search_dir = directory;
|
||||
@@ -388,9 +388,11 @@ class WTVMail {
|
||||
try {
|
||||
var temp_session_data_file = self.fs.readFileSync(search_dir + self.path.sep + file, 'Utf8');
|
||||
var temp_session_data = JSON.parse(temp_session_data_file);
|
||||
if (temp_session_data.subscriber_username.toLowerCase() == username.toLowerCase()) {
|
||||
return_val = search_dir.replace(this.minisrv_config.config.SessionStore + self.path.sep + "accounts" + self.path.sep, '').replace("user", '').split(self.path.sep);
|
||||
return_val.push(temp_session_data.subscriber_name);
|
||||
if (temp_session_data.subscriber_username) {
|
||||
if (temp_session_data.subscriber_username.toLowerCase() == username.toLowerCase()) {
|
||||
return_val = search_dir.replace(this.minisrv_config.config.SessionStore + self.path.sep + "accounts" + self.path.sep, '').replace("user", '').split(self.path.sep);
|
||||
return_val.push(temp_session_data.subscriber_name);
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
console.error(" # Error parsing Session Data JSON", file, e);
|
||||
|
||||
@@ -228,13 +228,13 @@ class WTVNewsServer {
|
||||
post_data.headers['Injection-Date'] = this.strftime("%a, %-d %b %Y %H:%M:%S %z", Date.parse(Date.now()))
|
||||
|
||||
// Reorder headers per examples in RFC3977 sect 6.2.1.3, not sure if needed
|
||||
post_data.headers = this.wtvshared.moveObjectElement('Path', null, post_data.headers, true);
|
||||
post_data.headers = this.wtvshared.moveObjectElement('From', 'Path', post_data.headers, true);
|
||||
post_data.headers = this.wtvshared.moveObjectElement('Newsgroups', 'From', post_data.headers, true);
|
||||
post_data.headers = this.wtvshared.moveObjectElement('Subject', 'Newsgroups', post_data.headers, true);
|
||||
post_data.headers = this.wtvshared.moveObjectElement('Date', 'Subject', post_data.headers, true);
|
||||
post_data.headers = this.wtvshared.moveObjectElement('Organization', 'Date', post_data.headers, true);
|
||||
post_data.headers = this.wtvshared.moveObjectElement('Message-ID', 'Organization', post_data.headers, true);
|
||||
post_data.headers = this.wtvshared.moveObjectKey('Path', null, post_data.headers, true);
|
||||
post_data.headers = this.wtvshared.moveObjectKey('From', 'Path', post_data.headers, true);
|
||||
post_data.headers = this.wtvshared.moveObjectKey('Newsgroups', 'From', post_data.headers, true);
|
||||
post_data.headers = this.wtvshared.moveObjectKey('Subject', 'Newsgroups', post_data.headers, true);
|
||||
post_data.headers = this.wtvshared.moveObjectKey('Date', 'Subject', post_data.headers, true);
|
||||
post_data.headers = this.wtvshared.moveObjectKey('Organization', 'Date', post_data.headers, true);
|
||||
post_data.headers = this.wtvshared.moveObjectKey('Message-ID', 'Organization', post_data.headers, true);
|
||||
// end reordering of headers
|
||||
|
||||
if (this.articleExists(group, post_data.articleNumber)) return false // should not occur, but just in case
|
||||
|
||||
@@ -95,9 +95,9 @@ class WTVRegister {
|
||||
}
|
||||
data += `<display nooptions>
|
||||
|
||||
<table width=520 align=center cellspacing=0 cellpadding=0>
|
||||
<table width=480 align=center cellspacing=0 cellpadding=0>
|
||||
<tr>
|
||||
<td height=272>
|
||||
<td height=242>
|
||||
<font size=+1>
|
||||
${main_content}
|
||||
<p>
|
||||
|
||||
@@ -349,7 +349,7 @@ class WTVShared {
|
||||
|
||||
utf8Decode(utf8String) {
|
||||
if (typeof utf8String !== 'string') {
|
||||
throw new TypeError('parameter <20>utf8String<6E> is not a string');
|
||||
throw new TypeError('parameter <20>utf8String<6E> is not a string');
|
||||
}
|
||||
const textDecoder = new TextDecoder('utf-8');
|
||||
const bytes = new Uint8Array(utf8String.split('').map(c => c.charCodeAt(0)));
|
||||
@@ -480,57 +480,6 @@ class WTVShared {
|
||||
else return this.parseSSID(ssid).manufacturer || null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Moves an object to the desired location in the object (reorder)
|
||||
* @param {string} currentKey Name of the object Key to move
|
||||
* @param {string} afterKey Name of the object key to place currentKey after
|
||||
* @param {object} obj The object to work on
|
||||
* @param {boolean} caseInsensitive
|
||||
* @returns {object} The modified object
|
||||
*/
|
||||
moveObjectElement(currentKey, afterKey, obj, caseInsensitive = false) {
|
||||
let keys = Object.keys(obj);
|
||||
let values = Object.values(obj);
|
||||
|
||||
if (caseInsensitive) {
|
||||
const lowerCurrentKey = currentKey.toLowerCase();
|
||||
const foundKey = keys.find(k => k.toLowerCase() === lowerCurrentKey);
|
||||
currentKey = foundKey || currentKey;
|
||||
}
|
||||
|
||||
const afterKeyIndex = typeof afterKey === 'string' ?
|
||||
keys.findIndex(k => caseInsensitive ? k.toLowerCase() === afterKey.toLowerCase() : k === afterKey)
|
||||
: -1;
|
||||
|
||||
if (afterKeyIndex === -1) {
|
||||
// If afterKey is not found or not defined, don't move the element
|
||||
return obj;
|
||||
}
|
||||
|
||||
const currentIndex = keys.indexOf(currentKey);
|
||||
if (currentIndex === -1) {
|
||||
// If currentKey is not found, don't move the element
|
||||
return obj;
|
||||
}
|
||||
|
||||
// Remove the current element from keys and values
|
||||
const [currentKeyValue] = values.splice(currentIndex, 1);
|
||||
keys.splice(currentIndex, 1);
|
||||
|
||||
// Insert the current element after the afterKey position
|
||||
keys.splice(afterKeyIndex + 1, 0, currentKey);
|
||||
values.splice(afterKeyIndex + 1, 0, currentKeyValue);
|
||||
|
||||
// Reconstruct the object with the new order
|
||||
const result = {};
|
||||
keys.forEach((key, index) => {
|
||||
result[key] = values[index];
|
||||
});
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
readMiniSrvConfig(user_config = true, notices = true, reload_notice = false) {
|
||||
const log = (msg) => {
|
||||
if (notices || reload_notice) console.log(msg);
|
||||
@@ -608,7 +557,7 @@ class WTVShared {
|
||||
var new_user_config = {};
|
||||
Object.assign(new_user_config, minisrv_user_config, config);
|
||||
if (this.minisrv_config.config.debug_flags.debug) console.log(" * Writing new user configuration...");
|
||||
this.fs.writeFileSync(this.getAbsolutePath("user_config.json", this.parentDirectory), JSON.stringify(new_user_config, null, "\t"));
|
||||
this.fs.writeFileSync(this.getAbsolutePath("user_config.json", this.appdir), JSON.stringify(new_user_config, null, "\t"));
|
||||
return true;
|
||||
}
|
||||
catch (e) {
|
||||
@@ -827,6 +776,7 @@ class WTVShared {
|
||||
}
|
||||
});
|
||||
}
|
||||
delete newobj.raw_headers;
|
||||
|
||||
return newobj;
|
||||
}
|
||||
@@ -1160,6 +1110,67 @@ class WTVShared {
|
||||
getTemplate(service_name, path, path_only = false) {
|
||||
return this.getServiceDep(service_name + this.path.sep + path, path_only, true);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Finds a key in an object
|
||||
* @param {string} key The key to find
|
||||
* @param {object} obj The object to search
|
||||
* @param {boolean} case_insensitive Search case insensitive
|
||||
* @returns
|
||||
*/
|
||||
findObjectKeyIndex(key, obj, case_insensitive = false) {
|
||||
const keys = Object.keys(obj);
|
||||
if (case_insensitive) {
|
||||
key = key.toLowerCase();
|
||||
return keys.findIndex(k => k.toLowerCase() === key);
|
||||
}
|
||||
return keys.indexOf(key);
|
||||
}
|
||||
/**
|
||||
* Moves an object to the desired location in the object (reorder)
|
||||
* @param {string|int} currentKey Name of the object Key to move or the index to move
|
||||
* @param {string|int} destKey Name of the object key to place currentKey after or the index to place it at
|
||||
* @param {object} obj The object to work on
|
||||
* @param {boolean} case_insensitive Search case insensitive
|
||||
* @returns {object} The modified object
|
||||
*/
|
||||
moveObjectKey(currentKey, destKey, obj, case_insensitive = false) {
|
||||
let keys = Object.keys(obj);
|
||||
let values = Object.values(obj);
|
||||
|
||||
const currentIndex = typeof currentKey === 'string' ? this.findObjectKeyIndex(currentKey, obj, case_insensitive) : parseInt(currentKey);
|
||||
if (currentIndex === -1) return obj;
|
||||
|
||||
var destIndex = typeof destKey === 'string' ? this.findObjectKeyIndex(destKey, obj, case_insensitive) : parseInt(destKey);
|
||||
|
||||
// Bump by one if the destKey is a string (put after the key)
|
||||
if (typeof destKey === 'string' && destIndex !== -1) destIndex++;
|
||||
|
||||
// If destKey is not found or not defined, don't move the element
|
||||
if (isNaN(destIndex)) return obj;
|
||||
|
||||
// Remove the current element from keys and values
|
||||
const [currentKeyValue] = values.splice(currentIndex, 1);
|
||||
const [currentKeyName] = keys.splice(currentIndex, 1);
|
||||
|
||||
// Insert the current element after the destKey position
|
||||
keys.splice(destIndex, 0, currentKeyName);
|
||||
values.splice(destIndex, 0, currentKeyValue);
|
||||
|
||||
// Reconstruct the object with the new order
|
||||
const result = {};
|
||||
keys.forEach((key, index) => {
|
||||
result[key] = values[index];
|
||||
});
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
getCaseInsensitiveKey(key, obj) {
|
||||
const foundKey = Object.keys(obj).find(k => k.toLowerCase() === key.toLowerCase());
|
||||
return foundKey || null;
|
||||
}
|
||||
}
|
||||
|
||||
class clientShowAlert {
|
||||
|
||||
Reference in New Issue
Block a user