diff --git a/zefie_wtvp_minisrv/ServiceVault/wtv-head-waiter/ValidateLogin.js b/zefie_wtvp_minisrv/ServiceVault/wtv-head-waiter/ValidateLogin.js index 13d750dd..2a59e1c4 100644 --- a/zefie_wtvp_minisrv/ServiceVault/wtv-head-waiter/ValidateLogin.js +++ b/zefie_wtvp_minisrv/ServiceVault/wtv-head-waiter/ValidateLogin.js @@ -71,9 +71,8 @@ minisrv-no-mail-count: true Content-Type: text/html`; if (client_challenge_response) { headers += ` -wtv-encrypted: true -wtv-ticket: ${wtvsec_login.ticket_b64} -`; +wtv-encrypted: true`; + if (wtvsec_login) ssid_sessions[socket.ssid].data_store.wtvsec_login.update_ticket = true; } if (limitedLoginRegistered) gourl = "wtv-head-waiter:/password?"; headers += ` diff --git a/zefie_wtvp_minisrv/ServiceVault/wtv-head-waiter/login-stage-two.js b/zefie_wtvp_minisrv/ServiceVault/wtv-head-waiter/login-stage-two.js index 3f7bf2b6..047cdef7 100644 --- a/zefie_wtvp_minisrv/ServiceVault/wtv-head-waiter/login-stage-two.js +++ b/zefie_wtvp_minisrv/ServiceVault/wtv-head-waiter/login-stage-two.js @@ -39,14 +39,28 @@ else { } else { var userid = ssid_sessions[socket.ssid].getSessionData("subscriber_userid") var nickname = ssid_sessions[socket.ssid].getSessionData("subscriber_username"); - var human_name = ssid_sessions[socket.ssid].getSessionData("subscriber_name"); + var human_name = ssid_sessions[socket.ssid].getSessionData("subscriber_name") || nickname; var messenger_enabled = ssid_sessions[socket.ssid].getSessionData("messenger_enabled") || 0; var messenger_authorized = ssid_sessions[socket.ssid].getSessionData("messenger_authorized") || 0; var home_url = "wtv-home:/splash?"; } var limitedLogin = ssid_sessions[socket.ssid].lockdown; var limitedLoginRegistered = (limitedLogin || (ssid_sessions[socket.ssid].isRegistered() && ssid_sessions[socket.ssid].getSessionData('password_valid'))); - var offline_user_list = CryptoJS.enc.Latin1.parse("\n\t\n").toString(CryptoJS.enc.Base64); + var offline_user_list = null; + if (ssid_sessions[socket.ssid].isRegistered() && ssid_sessions[socket.ssid].user_id == 0) { + var accounts = ssid_sessions[socket.ssid].listPrimaryAccountUsers(); + console.log(accounts); + var num_accounts = ssid_sessions[socket.ssid].getNumberOfUserAccounts(); + var offline_user_list_str = "\n"; + var i = 0; + Object.keys(accounts).forEach((k) => { + var account_display_name = (accounts[k].subscriber_name) ? accounts[k].subscriber_name : accounts[k].subscriber_username + offline_user_list_str += "\t" + '' + "\n"; + i++; + }); + offline_user_list_str += "\n"; + offline_user_list = CryptoJS.enc.Latin1.parse(offline_user_list_str).toString(CryptoJS.enc.Base64); + } if (limitedLoginRegistered) var home_url = "wtv-head-waiter:/password?"; @@ -74,8 +88,8 @@ wtv-login-timeout: 7200 if (!limitedLogin) { headers += getServiceString('all', { "exceptions": ["wtv-register"] }); - headers += `wtv-offline-user-list: ${offline_user_list} -wtv-messenger-authorized: ${messenger_authorized} + if (offline_user_list) headers += "wtv-offline-user-list: " + offline_user_list + "\n"; + headers += `wtv-messenger-authorized: ${messenger_authorized} wtv-messenger-enable: ${messenger_enabled} wtv-messagewatch-checktimeoffset: off `; diff --git a/zefie_wtvp_minisrv/ServiceVault/wtv-register/ValidateReviewAccountInfo.js b/zefie_wtvp_minisrv/ServiceVault/wtv-register/ValidateReviewAccountInfo.js index 4e3f904b..c8b10619 100644 --- a/zefie_wtvp_minisrv/ServiceVault/wtv-register/ValidateReviewAccountInfo.js +++ b/zefie_wtvp_minisrv/ServiceVault/wtv-register/ValidateReviewAccountInfo.js @@ -17,7 +17,7 @@ if (!request_headers.query.registering || ssid_sessions[socket.ssid].setSessionData("subscriber_username", request_headers.query.subscriber_username); ssid_sessions[socket.ssid].setSessionData("subscriber_contact", request_headers.query.subscriber_contact); ssid_sessions[socket.ssid].setSessionData("subscriber_contact_method", request_headers.query.subscriber_contact_method); - ssid_sessions[socket.ssid].setSessionData("subscriber_userid", '1' + Math.floor(Math.random() * 1000000000000000000)); + ssid_sessions[socket.ssid].setSessionData("subscriber_userid", 0); ssid_sessions[socket.ssid].setSessionData("registered", true); if (!ssid_sessions[socket.ssid].storeSessionData(true)) { var errpage = wtvshared.doErrorPage(400); diff --git a/zefie_wtvp_minisrv/ServiceVault/wtv-setup/validate-add-user-done.js b/zefie_wtvp_minisrv/ServiceVault/wtv-setup/validate-add-user-done.js index 042a34e7..b1787f2f 100644 --- a/zefie_wtvp_minisrv/ServiceVault/wtv-setup/validate-add-user-done.js +++ b/zefie_wtvp_minisrv/ServiceVault/wtv-setup/validate-add-user-done.js @@ -30,6 +30,7 @@ if (errpage) { var freeUserId = ssid_sessions[socket.ssid].findFreeUserSlot(ssid_sessions[socket.ssid]); if (freeUserId) { userSession.user_id = freeUserId; + userSession.setSessionData("subscriber_userid", freeUserId); userSession.setSessionData("subscriber_name", request_headers.query.display_name); userSession.setSessionData("subscriber_username", request_headers.query.user_name); userSession.setSessionData("registered", true); diff --git a/zefie_wtvp_minisrv/WTVClientSessionData.js b/zefie_wtvp_minisrv/WTVClientSessionData.js index 44c6b619..662f6292 100644 --- a/zefie_wtvp_minisrv/WTVClientSessionData.js +++ b/zefie_wtvp_minisrv/WTVClientSessionData.js @@ -1,6 +1,7 @@ const { lib } = require('crypto-js'); const CryptoJS = require('crypto-js'); const WTVMail = require('./WTVMail.js') +const WTVSec = require('./WTVSec.js'); class WTVClientSessionData { fs = require('fs'); @@ -54,10 +55,31 @@ class WTVClientSessionData { } - switchUserID(user_id, update_mail = true) { + switchUserID(user_id, update_mail = true, update_ticket = true) { this.user_id = user_id; this.loadSessionData(); this.mailstore = new WTVMail(this.minisrv_config, this.ssid, this) + if (this.data_store.wtvsec_login && update_ticket) this.setTicketData('user_id', user_id); + } + + setTicketData(key, value) { + if (this.data_store.wtvsec_login) this.data_store.wtvsec_login.setTicketData(key, value); + else return false; + + return true; + } + + getTicketData(key) { + if (this.data_store.wtvsec_login) return this.data_store.wtvsec_login.getTicketData(key); + + return false; + } + + deleteTicketData(key) { + if (this.data_store.wtvsec_login) this.data_store.wtvsec_login.deleteTicketData(key); + else return false; + + return true; } findFreeUserSlot() { diff --git a/zefie_wtvp_minisrv/WTVSec.js b/zefie_wtvp_minisrv/WTVSec.js index a73a5c31..935cc034 100644 --- a/zefie_wtvp_minisrv/WTVSec.js +++ b/zefie_wtvp_minisrv/WTVSec.js @@ -32,6 +32,8 @@ class WTVSec { hRC4_Key2 = null; RC4Session = new Array(); minisrv_config = []; + update_ticket = false; + ticket_store = {}; /** * @@ -41,7 +43,7 @@ class WTVSec { * @param {Boolean} minisrv_config.config.debug_flags.debug Enable debugging * */ - constructor(minisrv_config, wtv_incarnation = 1) { + constructor(minisrv_config, wtv_incarnation = 1) { this.minisrv_config = minisrv_config; this.initial_shared_key = CryptoJS.enc.Base64.parse(this.initial_shared_key_b64); @@ -87,11 +89,15 @@ class WTVSec { */ PrepareTicket() { // store last challenge response in ticket - var ticket_data = this.challenge_raw; + if (this.minisrv_config.config.debug_flags.debug) console.log(" * Preparing a new ticket with ticket_store:", this.ticket_store) + var ticket_data_raw = this.challenge_raw; try { - var ticket_data_enc = CryptoJS.DES.encrypt(ticket_data, this.initial_shared_key, { + var ticket_data = ticket_data_raw.toString(CryptoJS.enc.Hex) + CryptoJS.enc.Utf8.parse(JSON.stringify(this.ticket_store)).toString(CryptoJS.enc.Hex); + + ticket_data_raw = CryptoJS.enc.Hex.parse(ticket_data); + var ticket_data_enc = CryptoJS.DES.encrypt(ticket_data_raw, this.initial_shared_key, { mode: CryptoJS.mode.ECB, - padding: CryptoJS.pad.NoPadding + padding: CryptoJS.pad.Pkcs7 }); // create a copy of WordArray since concat modifies the original var challenge_signed_key = this.DuplicateWordArray(this.challenge_signed_key); @@ -103,6 +109,17 @@ class WTVSec { return this.ticket_b64; } + tryDecodeJSON(json_string) { + var out; + try { + out = JSON.parse(json_string); + } catch (e) { + console.log(e); + out = {}; + } + return out; + } + /** * Decodes a wtv-ticket to set up this instance * @@ -112,6 +129,7 @@ class WTVSec { var ticket_hex = CryptoJS.enc.Base64.parse(ticket_b64).toString(CryptoJS.enc.Hex); var challenge_key = CryptoJS.enc.Hex.parse(ticket_hex.substring(0, 16)); var challenge_enc = CryptoJS.enc.Hex.parse(ticket_hex.substring(16)); + var ticket_dec = CryptoJS.DES.decrypt( { ciphertext: challenge_enc @@ -119,11 +137,46 @@ class WTVSec { this.initial_shared_key, { mode: CryptoJS.mode.ECB, - padding: CryptoJS.pad.NoPadding + padding: CryptoJS.pad.Pkcs7 } ); - this.ProcessChallenge(ticket_dec.toString(CryptoJS.enc.Base64), challenge_key); - console.log(" * Decoded session from wtv-ticket"); + var data_offset = 216; // (108 * 2); + var challenge_code = ticket_dec.toString().substring(0, data_offset); + var challenge_code_b64 = CryptoJS.enc.Hex.parse(challenge_code).toString(CryptoJS.enc.Base64); + if ((ticket_dec.sigBytes * 2) >= challenge_code.length) { + var ticket_data_dec = CryptoJS.enc.Hex.parse(ticket_dec.toString().substring(data_offset)).toString(CryptoJS.enc.Utf8); + this.ticket_store = this.tryDecodeJSON(ticket_data_dec); + } else { + this.ticket_store = {}; + } + + this.ProcessChallenge(challenge_code_b64, challenge_key); + if (this.minisrv_config.config.debug_flags.debug) console.log(" * Decoded session from wtv-ticket with ticket_store:", this.ticket_store); + } + + getTicketData(key = null) { + if (typeof (this.ticket_store) === 'session_store') return null; + else if (key === null) return this.ticket_store; + else return null; + } + + setTicketData(key, value) { + if (key === null) throw ("WTVSec.ssetTicketDataet(): invalid key provided"); + if (typeof (this.ticket_store) === 'undefined') this.ticket_store = {}; + this.ticket_store[key] = value; + if (this.ticket_b64) this.PrepareTicket(); + this.update_ticket = true; + } + + deleteTicketData(key) { + if (key === null) throw ("WTVSec.deleteTicketData(): invalid key provided"); + if (typeof (this.ticket_store) === 'undefined') { + this.ticket_store = {}; + return; + } + delete this.ticket_store[key]; + if (this.ticket_b64) this.PrepareTicket(); + this.update_ticket = true; } /** diff --git a/zefie_wtvp_minisrv/app.js b/zefie_wtvp_minisrv/app.js index 7f1bfd55..cdfb2636 100644 --- a/zefie_wtvp_minisrv/app.js +++ b/zefie_wtvp_minisrv/app.js @@ -405,19 +405,6 @@ Location: " + minisrv_config.config.unauthorized_url`; return; } - /* - if (ssid_sessions[socket.ssid].isRegistered(false) && !ssid_sessions[socket.ssid].isAuthorized(shortURL, 'login', true)) { - if (!ssid_sessions[socket.ssid].getSessionData("subscriber_username")) { - headers = `300 Session Error -Location: client:relogin`; - data = ""; - sendToClient(socket, headers, data); - console.log(" * Session error: Asking client to relogin via socket ID", socket.id); - return; - } - } - */ - // Check URL for :/, but not :// (to differentiate wtv urls) if (shortURL.indexOf(':/') >= 0 && shortURL.indexOf('://') == -1) { var ssid = socket.ssid; @@ -802,6 +789,7 @@ async function sendToClient(socket, headers_obj, data) { if (headers_obj["secure"]) delete headers_obj["secure"]; } + // calculate content length // make sure we are using our Content-length and not one set in a script. if (headers_obj["Content-Length"]) delete headers_obj["Content-Length"]; @@ -809,13 +797,14 @@ async function sendToClient(socket, headers_obj, data) { headers_obj["Content-length"] = content_length; + // Send wtv-ticket if it has been flagged as updated if (ssid_sessions[socket.ssid]) { if (ssid_sessions[socket.ssid].data_store.wtvsec_login) { if (ssid_sessions[socket.ssid].data_store.wtvsec_login.ticket_b64) { - if (ssid_sessions[socket.ssid].data_store.update_ticket) { + if (ssid_sessions[socket.ssid].data_store.wtvsec_login.update_ticket) { headers_obj["wtv-ticket"] = ssid_sessions[socket.ssid].data_store.wtvsec_login.ticket_b64; headers_obj = moveObjectElement("wtv-ticket", "Connection", headers_obj); - ssid_sessions[socket.ssid].data_store.update_ticket = false; + ssid_sessions[socket.ssid].data_store.wtvsec_login.update_ticket = false; } } } @@ -1077,13 +1066,22 @@ async function processRequest(socket, data_hex, skipSecure = false, encryptedReq if (headers["wtv-incarnation"]) ssid_sessions[socket.ssid].data_store.wtvsec_login.set_incarnation(headers["wtv-incarnation"]); ssid_sessions[socket.ssid].data_store.wtvsec_login.ticket_b64 = headers["wtv-ticket"]; ssid_sessions[socket.ssid].data_store.wtvsec_login.DecodeTicket(ssid_sessions[socket.ssid].data_store.wtvsec_login.ticket_b64); - } else { - if (ssid_sessions[socket.ssid].data_store.wtvsec_login.ticket_b64 != headers["wtv-ticket"]) { - if (minisrv_config.config.debug_flags.debug) console.log(" # New ticket from client"); - ssid_sessions[socket.ssid].data_store.wtvsec_login.ticket_b64 = headers["wtv-ticket"]; - ssid_sessions[socket.ssid].data_store.wtvsec_login.DecodeTicket(ssid_sessions[socket.ssid].data_store.wtvsec_login.ticket_b64); - if (headers["wtv-incarnation"]) ssid_sessions[socket.ssid].data_store.wtvsec_login.set_incarnation(headers["wtv-incarnation"]); + if (ssid_sessions[socket.ssid].data_store.wtvsec_login.ticket_store.user_id) { + if (ssid_sessions[socket.ssid].data_store.wtvsec_login.ticket_store.user_id > 0) + ssid_sessions[socket.ssid].switchUserID(ssid_sessions[socket.ssid].data_store.wtvsec_login.ticket_store.user_id, true, false); } + } else { + if (ssid_sessions[socket.ssid].data_store.wtvsec_login.ticket_b64 != headers["wtv-ticket"]) + if (!ssid_sessions[socket.ssid].data_store.wtvsec_login.update_ticket) { + if (minisrv_config.config.debug_flags.debug) console.log(" # New ticket from client"); + ssid_sessions[socket.ssid].data_store.wtvsec_login.ticket_b64 = headers["wtv-ticket"]; + ssid_sessions[socket.ssid].data_store.wtvsec_login.DecodeTicket(ssid_sessions[socket.ssid].data_store.wtvsec_login.ticket_b64); + if (headers["wtv-incarnation"]) ssid_sessions[socket.ssid].data_store.wtvsec_login.set_incarnation(headers["wtv-incarnation"]); + if (ssid_sessions[socket.ssid].data_store.wtvsec_login.ticket_store.user_id > 0) { + if (ssid_sessions[socket.ssid].user_id != ssid_sessions[socket.ssid].data_store.wtvsec_login.ticket_store.user_id) + switchUserID(ssid_sessions[socket.ssid].data_store.wtvsec_login.ticket_store.user_id, true, false); + } + } } } }