improve session retention

This commit is contained in:
zefie
2021-08-08 19:40:52 -04:00
parent 34d4893f30
commit 7e3d340fec
2 changed files with 61 additions and 25 deletions

View File

@@ -1,3 +1,5 @@
const { lib } = require('crypto-js');
class WTVClientSessionData { class WTVClientSessionData {
fs = require('fs'); fs = require('fs');
@@ -38,7 +40,8 @@ class WTVClientSessionData {
} }
} }
constructor(hide_ssid_in_logs, session_storage_directory) { constructor(ssid, hide_ssid_in_logs, session_storage_directory) {
this.ssid = ssid;
if (hide_ssid_in_logs) this.hide_ssid_in_logs = hide_ssid_in_logs; if (hide_ssid_in_logs) this.hide_ssid_in_logs = hide_ssid_in_logs;
if (!session_storage_directory) session_storage_directory = __dirname + "/SessionStore"; if (!session_storage_directory) session_storage_directory = __dirname + "/SessionStore";
this.session_storage = session_storage_directory; this.session_storage = session_storage_directory;
@@ -172,11 +175,13 @@ class WTVClientSessionData {
return outstring; return outstring;
} }
loadSessionData() { loadSessionData(raw_data = false) {
try { try {
if (this.fs.lstatSync(this.session_storage + this.path.sep + this.ssid + ".json")) { if (this.fs.lstatSync(this.session_storage + this.path.sep + this.ssid + ".json")) {
var session_data_file = this.fs.readFileSync(this.session_storage + this.path.sep + this.ssid + ".json", 'Utf8'); var json_data = this.fs.readFileSync(this.session_storage + this.path.sep + this.ssid + ".json", 'Utf8')
var session_data = JSON.parse(session_data_file); if (raw_data) return json_data;
var session_data = JSON.parse(json_data);
this.session_store = session_data; this.session_store = session_data;
return true; return true;
} }
@@ -188,14 +193,17 @@ class WTVClientSessionData {
} }
saveSessionData() { saveSessionData() {
if (!this.session_store.registered) { // load data from disk and merge new data
var temp_store = this.session_store; var temp_store = this.session_store;
this.loadSessionData(); if (this.loadSessionData()) this.session_store = Object.assign(this.session_store, temp_store);
this.session_store = Object.assign(this.session_store, temp_store); else this.session_store = temp_store;
} temp_store = null;
try { try {
var store_data = JSON.stringify(this.session_store); // only save if file has changed
this.fs.writeFileSync(this.session_storage + this.path.sep + this.ssid + ".json", store_data, "Utf8"); var json_save_data = JSON.stringify(this.session_store);
var json_load_data = loadSessionData(true);
if (json_save_data != json_load_data) this.fs.writeFileSync(this.session_storage + this.path.sep + this.ssid + ".json", JSON.stringify(this.session_store), "Utf8");
return true; return true;
} catch (e) { } catch (e) {
console.error(" # Error saving session data for", this.filterSSID(this.ssid), e); console.error(" # Error saving session data for", this.filterSSID(this.ssid), e);
@@ -213,16 +221,31 @@ class WTVClientSessionData {
return this.saveSessionData(); return this.saveSessionData();
} }
SaveIfRegistered() {
if (this.isRegistered()) this.saveSessionData();
}
isRegistered() {
var self = this;
var ssid_match = false;
this.fs.readdirSync(this.session_storage).forEach(file => {
if (!file.match(/.*\.json/ig)) return;
if (ssid_match) return;
if (file.split('.')[0] == self.ssid) ssid_match = true;
});
return ssid_match;
}
unregisterBox() { unregisterBox() {
try { try {
if (this.fs.lstatSync(this.session_storage + this.path.sep + this.ssid + ".json")) { if (this.fs.lstatSync(this.session_storage + this.path.sep + this.ssid + ".json")) {
return this.fs.unlinkSync(this.session_storage + this.path.sep + this.ssid + ".json"); this.fs.unlinkSync(this.session_storage + this.path.sep + this.ssid + ".json");
this.session_store = {}; this.session_store = {};
return true;
} }
} catch (e) { } catch (e) {
// Don't log error 'file not found', it just means the client isn't registered yet // Don't log error 'file not found', it just means the client isn't registered yet
if (e.code != "ENOENT") console.error(" # Error deleting session data for", this.filterSSID(this.ssid), e); console.error(" # Error deleting session data for", this.filterSSID(this.ssid), e);
return false; return false;
} }
} }

View File

@@ -279,8 +279,8 @@ function filterSSID(obj) {
return obj.substr(0, 6) + ('*').repeat(9); return obj.substr(0, 6) + ('*').repeat(9);
} }
} else { } else {
if (obj["wtv-client-serial-number"]) { if (makeSafeSSID(obj["wtv-client-serial-number"])) {
var ssid = obj["wtv-client-serial-number"]; var ssid = makeSafeSSID(obj["wtv-client-serial-number"]);
if (ssid.substr(0, 8) == "MSTVSIMU") { if (ssid.substr(0, 8) == "MSTVSIMU") {
obj["wtv-client-serial-number"] = ssid.substr(0, 10) + ('*').repeat(10) + ssid.substr(20); obj["wtv-client-serial-number"] = ssid.substr(0, 10) + ('*').repeat(10) + ssid.substr(20);
} else if (ssid.substr(0, 5) == "1SEGA") { } else if (ssid.substr(0, 5) == "1SEGA") {
@@ -296,6 +296,12 @@ function filterSSID(obj) {
} }
} }
function makeSafeSSID(ssid) {
ssid = ssid.replace(/[^a-zA-Z0-9]/g, "");
if (ssid.length == 0) ssid = null;
return ssid;
}
function makeSafePath(base, target) { function makeSafePath(base, target) {
target.replace(/[\|\&\;\$\%\@\"\<\>\+\,\\]/g, ""); target.replace(/[\|\&\;\$\%\@\"\<\>\+\,\\]/g, "");
if (path.sep != "/") target = target.replace(/\//g, path.sep); if (path.sep != "/") target = target.replace(/\//g, path.sep);
@@ -356,8 +362,11 @@ async function processURL(socket, request_headers) {
if (shortURL.indexOf(':/') >= 0 && shortURL.indexOf('://') < 0) { if (shortURL.indexOf(':/') >= 0 && shortURL.indexOf('://') < 0) {
var ssid = socket.ssid; var ssid = socket.ssid;
if (ssid == null) { if (ssid == null) {
ssid = request_headers["wtv-client-serial-number"]; // prevent possible injection attacks via SSID and filesystem SessionStore
ssid = makeSafeSSID(request_headers["wtv-client-serial-number"]);
if (ssid == "") ssid = null;
} }
var reqverb = "Request"; var reqverb = "Request";
if (request_headers.encrypted || request_headers.secure) { if (request_headers.encrypted || request_headers.secure) {
reqverb = "Encrypted " + reqverb; reqverb = "Encrypted " + reqverb;
@@ -757,7 +766,7 @@ function isUnencryptedString(string, verbose = false) {
} }
function filterSSID(ssid) { function filterSSID(ssid) {
var WTVCSD = new WTVClientSessionData(minisrv_config.config.hide_ssid_in_logs); var WTVCSD = new WTVClientSessionData(null,minisrv_config.config.hide_ssid_in_logs);
return WTVCSD.filterSSID(ssid); return WTVCSD.filterSSID(ssid);
} }
@@ -827,14 +836,17 @@ async function processRequest(socket, data_hex, skipSecure = false, encryptedReq
if (!headers) return; if (!headers) return;
if (headers["wtv-client-serial-number"] != null) { if (headers["wtv-client-serial-number"] != null && socket.ssid == null) {
socket.ssid = headers["wtv-client-serial-number"]; socket.ssid = makeSafeSSID(headers["wtv-client-serial-number"]);
if (!ssid_sessions[socket.ssid]) { if (socket.ssid != null) {
ssid_sessions[socket.ssid] = new WTVClientSessionData(minisrv_config.config.hide_ssid_in_logs); if (!ssid_sessions[socket.ssid]) {
ssid_sessions[socket.ssid] = new WTVClientSessionData(socket.ssid,minisrv_config.config.hide_ssid_in_logs);
ssid_sessions[socket.ssid].SaveIfRegistered();
}
if (!ssid_sessions[socket.ssid].data_store.sockets) ssid_sessions[socket.ssid].data_store.sockets = new Set();
ssid_sessions[socket.ssid].ssid = socket.ssid;
ssid_sessions[socket.ssid].data_store.sockets.add(socket);
} }
if (!ssid_sessions[socket.ssid].data_store.sockets) ssid_sessions[socket.ssid].data_store.sockets = new Set();
ssid_sessions[socket.ssid].ssid = socket.ssid;
ssid_sessions[socket.ssid].data_store.sockets.add(socket);
} }
var ip2long = function (ip) { var ip2long = function (ip) {
@@ -920,7 +932,8 @@ async function processRequest(socket, data_hex, skipSecure = false, encryptedReq
if (headers["wtv-capability-flags"] != null) { if (headers["wtv-capability-flags"] != null) {
if (!ssid_sessions[socket.ssid]) { if (!ssid_sessions[socket.ssid]) {
ssid_sessions[socket.ssid] = new WTVClientSessionData(minisrv_config.config.hide_ssid_in_logs); ssid_sessions[socket.ssid] = new WTVClientSessionData(socket.ssid,minisrv_config.config.hide_ssid_in_logs);
ssid_sessions[socket.ssid].SaveIfRegistered();
} }
if (!ssid_sessions[socket.ssid].capabilities) ssid_sessions[socket.ssid].capabilities = new WTVClientCapabilities(headers["wtv-capability-flags"]); if (!ssid_sessions[socket.ssid].capabilities) ssid_sessions[socket.ssid].capabilities = new WTVClientCapabilities(headers["wtv-capability-flags"]);
} }