mirror of
https://github.com/Ylianst/MeshCentral.git
synced 2025-01-23 04:33:14 -05:00
Added server password timeout and reset on next login.
This commit is contained in:
parent
5a4f0e6450
commit
8709d56bd0
@ -316,6 +316,7 @@ function run(argv) {
|
|||||||
// Display Intel AMT versions
|
// Display Intel AMT versions
|
||||||
var amtMeiModule = require('amt-mei');
|
var amtMeiModule = require('amt-mei');
|
||||||
var amtMei = new amtMeiModule();
|
var amtMei = new amtMeiModule();
|
||||||
|
if (amtMei == null) { console.log("Intel(R) AMT not supported or insufficient access rights."); exit(1); return; }
|
||||||
amtMei.on('error', function (e) { console.log('ERROR: ' + e); exit(1); return; });
|
amtMei.on('error', function (e) { console.log('ERROR: ' + e); exit(1); return; });
|
||||||
amtMei.getVersion(function (val) {
|
amtMei.getVersion(function (val) {
|
||||||
console.log("MEI Version = " + val.BiosVersion.toString());
|
console.log("MEI Version = " + val.BiosVersion.toString());
|
||||||
@ -326,6 +327,7 @@ function run(argv) {
|
|||||||
// Display Intel AMT list of trusted hashes
|
// Display Intel AMT list of trusted hashes
|
||||||
var amtMeiModule = require('amt-mei');
|
var amtMeiModule = require('amt-mei');
|
||||||
var amtMei = new amtMeiModule();
|
var amtMei = new amtMeiModule();
|
||||||
|
if (amtMei == null) { console.log("Intel(R) AMT not supported or insufficient access rights."); exit(1); return; }
|
||||||
amtMei.on('error', function (e) { console.log('ERROR: ' + e); exit(1); return; });
|
amtMei.on('error', function (e) { console.log('ERROR: ' + e); exit(1); return; });
|
||||||
amtMei.getHashHandles(function (handles) {
|
amtMei.getHashHandles(function (handles) {
|
||||||
exitOnCount = handles.length;
|
exitOnCount = handles.length;
|
||||||
@ -341,6 +343,7 @@ function run(argv) {
|
|||||||
mestate = {};
|
mestate = {};
|
||||||
var amtMeiModule = require('amt-mei');
|
var amtMeiModule = require('amt-mei');
|
||||||
var amtMei = new amtMeiModule();
|
var amtMei = new amtMeiModule();
|
||||||
|
if (amtMei == null) { console.log("Intel(R) AMT not supported or insufficient access rights."); exit(1); return; }
|
||||||
amtMei.on('error', function (e) { console.log('ERROR: ' + e); exit(1); return; });
|
amtMei.on('error', function (e) { console.log('ERROR: ' + e); exit(1); return; });
|
||||||
amtMei.getVersion(function (result) { if (result) { for (var version in result.Versions) { if (result.Versions[version].Description == 'AMT') { mestate.ver = result.Versions[version].Version; } } } });
|
amtMei.getVersion(function (result) { if (result) { for (var version in result.Versions) { if (result.Versions[version].Description == 'AMT') { mestate.ver = result.Versions[version].Version; } } } });
|
||||||
amtMei.getProvisioningState(function (result) { if (result) { mestate.ProvisioningState = result; } });
|
amtMei.getProvisioningState(function (result) { if (result) { mestate.ProvisioningState = result; } });
|
||||||
@ -381,6 +384,7 @@ function run(argv) {
|
|||||||
mestate = {};
|
mestate = {};
|
||||||
var amtMeiModule = require('amt-mei');
|
var amtMeiModule = require('amt-mei');
|
||||||
var amtMei = new amtMeiModule();
|
var amtMei = new amtMeiModule();
|
||||||
|
if (amtMei == null) { console.log("Intel(R) AMT not supported or insufficient access rights."); exit(1); return; }
|
||||||
amtMei.on('error', function (e) { console.log('ERROR: ' + e); exit(1); return; });
|
amtMei.on('error', function (e) { console.log('ERROR: ' + e); exit(1); return; });
|
||||||
amtMei.getVersion(function (result) { console.log('getVersion: ' + JSON.stringify(result)); });
|
amtMei.getVersion(function (result) { console.log('getVersion: ' + JSON.stringify(result)); });
|
||||||
amtMei.getProvisioningState(function (result) { console.log('getProvisioningState: ' + JSON.stringify(result)); });
|
amtMei.getProvisioningState(function (result) { console.log('getProvisioningState: ' + JSON.stringify(result)); });
|
||||||
@ -666,6 +670,7 @@ function startMeshCommander() {
|
|||||||
function deactivateCCM() {
|
function deactivateCCM() {
|
||||||
var amtMeiModule = require('amt-mei');
|
var amtMeiModule = require('amt-mei');
|
||||||
var amtMei = new amtMeiModule();
|
var amtMei = new amtMeiModule();
|
||||||
|
if (amtMei == null) { console.log("Intel(R) AMT not supported or insufficient access rights."); exit(1); return; }
|
||||||
amtMei.on('error', function (e) { console.log('ERROR: ' + e); exit(1); return; });
|
amtMei.on('error', function (e) { console.log('ERROR: ' + e); exit(1); return; });
|
||||||
amtMei.unprovision(1, function (status) { if (status == 0) { console.log('Success'); } else { console.log('Error ' + status); } exit(1); });
|
amtMei.unprovision(1, function (status) { if (status == 0) { console.log('Success'); } else { console.log('Error ' + status); } exit(1); });
|
||||||
}
|
}
|
||||||
@ -708,6 +713,7 @@ function getAmtUuid() {
|
|||||||
if (settings.hostname == null) {
|
if (settings.hostname == null) {
|
||||||
var amtMeiModule = require('amt-mei');
|
var amtMeiModule = require('amt-mei');
|
||||||
var amtMei = new amtMeiModule();
|
var amtMei = new amtMeiModule();
|
||||||
|
if (amtMei == null) { console.log("Intel(R) AMT not supported or insufficient access rights."); exit(1); return; }
|
||||||
amtMei.on('error', function (e) { console.log('ERROR: ' + e); exit(1); return; });
|
amtMei.on('error', function (e) { console.log('ERROR: ' + e); exit(1); return; });
|
||||||
amtMei.getUuid(function (result) { if ((result == null) || (result.uuid == null)) { console.log('Failed.'); } else { console.log(result.uuid); } exit(1); });
|
amtMei.getUuid(function (result) { if ((result == null) || (result.uuid == null)) { console.log('Failed.'); } else { console.log(result.uuid); } exit(1); });
|
||||||
} else {
|
} else {
|
||||||
@ -829,6 +835,7 @@ function getAmtInfo(func, tag) {
|
|||||||
getAmtInfoFetchingTimer = null;
|
getAmtInfoFetchingTimer = null;
|
||||||
var amtMeiModule = require('amt-mei');
|
var amtMeiModule = require('amt-mei');
|
||||||
amtMei = new amtMeiModule();
|
amtMei = new amtMeiModule();
|
||||||
|
if (amtMei == null) { console.log("Intel(R) AMT not supported or insufficient access rights."); exit(1); return; }
|
||||||
amtMei.on('error', function (e) { console.log('ERROR: ' + e); exit(1); return; });
|
amtMei.on('error', function (e) { console.log('ERROR: ' + e); exit(1); return; });
|
||||||
}, 3000);
|
}, 3000);
|
||||||
amtMei.getProtocolVersion(function (result) { if (result != null) { amtMeiTmpState.MeiVersion = result; } });
|
amtMei.getProtocolVersion(function (result) { if (result != null) { amtMeiTmpState.MeiVersion = result; } });
|
||||||
@ -890,6 +897,7 @@ function startLms(func) {
|
|||||||
|
|
||||||
var amtMeiModule = require('amt-mei');
|
var amtMeiModule = require('amt-mei');
|
||||||
amtMei = new amtMeiModule();
|
amtMei = new amtMeiModule();
|
||||||
|
if (amtMei == null) { console.log("Intel(R) AMT not supported or insufficient access rights."); exit(1); return; }
|
||||||
amtMei.on('error', function (e) { console.log('ERROR: ' + e); exit(1); return; });
|
amtMei.on('error', function (e) { console.log('ERROR: ' + e); exit(1); return; });
|
||||||
//console.log("PTHI Connected.");
|
//console.log("PTHI Connected.");
|
||||||
|
|
||||||
|
@ -58,7 +58,7 @@ CheckInstallAgent() {
|
|||||||
# Linux x86, 64 bit
|
# Linux x86, 64 bit
|
||||||
machineid=6
|
machineid=6
|
||||||
fi
|
fi
|
||||||
if [ $machinetype == 'x86' ] || [ $machinetype == 'i686' ]
|
if [ $machinetype == 'x86' ] || [ $machinetype == 'i686' ] || [ $machinetype == 'i586' ]
|
||||||
then
|
then
|
||||||
# Linux x86, 32 bit
|
# Linux x86, 32 bit
|
||||||
machineid=5
|
machineid=5
|
||||||
|
42
meshuser.js
42
meshuser.js
@ -470,7 +470,7 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
|
|||||||
|
|
||||||
switch (cmd) {
|
switch (cmd) {
|
||||||
case 'help': {
|
case 'help': {
|
||||||
r = 'Available commands: help, args, resetserver, showconfig, usersessions, tasklimiter, setmaxtasks, cores.';
|
r = 'Available commands: help, args, resetserver, showconfig, usersessions, tasklimiter, setmaxtasks, cores, migrationagents, swarmstats.';
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 'args': {
|
case 'args': {
|
||||||
@ -536,6 +536,31 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
|
|||||||
r = JSON.stringify(removeAllUnderScore(config), null, 4);
|
r = JSON.stringify(removeAllUnderScore(config), null, 4);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case 'migrationagents': {
|
||||||
|
if (obj.parent.parent.swarmserver == null) {
|
||||||
|
r = 'Swarm server not running.';
|
||||||
|
} else {
|
||||||
|
for (var i in obj.parent.parent.swarmserver.migrationAgents) {
|
||||||
|
var arch = obj.parent.parent.swarmserver.migrationAgents[i];
|
||||||
|
for (var j in arch) { var agent = arch[j]; r += 'Arch ' + agent.arch + ', Ver ' + agent.ver + ', Size ' + agent.binary.length + '<br />'; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 'swarmstats': {
|
||||||
|
if (obj.parent.parent.swarmserver == null) {
|
||||||
|
r = 'Swarm server not running.';
|
||||||
|
} else {
|
||||||
|
for (var i in obj.parent.parent.swarmserver.stats) {
|
||||||
|
if (typeof obj.parent.parent.swarmserver.stats[i] == 'object') {
|
||||||
|
r += i + ' ' + JSON.stringify(obj.parent.parent.swarmserver.stats[i]) + '<br />';
|
||||||
|
} else {
|
||||||
|
r += i + ' ' + obj.parent.parent.swarmserver.stats[i] + '<br />';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
default: { // This is an unknown command, return an error message
|
default: { // This is an unknown command, return an error message
|
||||||
r = 'Unknown command \"' + cmd + '\", type \"help\" for list of avaialble commands.';
|
r = 'Unknown command \"' + cmd + '\", type \"help\" for list of avaialble commands.';
|
||||||
break;
|
break;
|
||||||
@ -822,11 +847,11 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
|
|||||||
if (hint.length > 250) hint = hint.substring(0, 250);
|
if (hint.length > 250) hint = hint.substring(0, 250);
|
||||||
user.salt = salt;
|
user.salt = salt;
|
||||||
user.hash = hash;
|
user.hash = hash;
|
||||||
user.passhint = req.body.apasswordhint;
|
user.passhint = hint;
|
||||||
user.passchange = Math.floor(Date.now() / 1000);
|
user.passchange = Math.floor(Date.now() / 1000);
|
||||||
delete user.passtype;
|
delete user.passtype;
|
||||||
obj.db.SetUser(user);
|
obj.db.SetUser(user);
|
||||||
obj.parent.parent.DispatchEvent(['*', 'server-users'], obj, { etype: 'user', username: user.name, action: 'passchange', msg: 'Account password changed: ' + user.name, domain: domain.id });
|
obj.parent.parent.DispatchEvent(['*', 'server-users'], obj, { etype: 'user', username: user.name, account: obj.parent.CloneSafeUser(user), action: 'accountchange', msg: 'Account password changed: ' + user.name, domain: domain.id });
|
||||||
|
|
||||||
// Send user notification of password change
|
// Send user notification of password change
|
||||||
displayNotificationMessage('Password changed.');
|
displayNotificationMessage('Password changed.');
|
||||||
@ -854,19 +879,18 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
|
|||||||
// Compute the password hash & save it
|
// Compute the password hash & save it
|
||||||
require('./pass').hash(command.pass, function (err, salt, hash) {
|
require('./pass').hash(command.pass, function (err, salt, hash) {
|
||||||
if (!err) {
|
if (!err) {
|
||||||
var annonceChange = false;
|
|
||||||
chguser.salt = salt;
|
chguser.salt = salt;
|
||||||
chguser.hash = hash;
|
chguser.hash = hash;
|
||||||
chguser.passhint = command.hint;
|
chguser.passhint = command.hint;
|
||||||
chguser.passchange = Math.floor(Date.now() / 1000);
|
if (command.resetNextLogin == true) { chguser.passchange = -1; } else { chguser.passchange = Math.floor(Date.now() / 1000); }
|
||||||
delete chguser.passtype; // Remove the password type if one was present.
|
delete chguser.passtype; // Remove the password type if one was present.
|
||||||
if (command.removeMultiFactor == true) {
|
if (command.removeMultiFactor == true) {
|
||||||
if (chguser.otpsecret) { delete chguser.otpsecret; annonceChange = true; }
|
if (chguser.otpsecret) { delete chguser.otpsecret; }
|
||||||
if (chguser.otphkeys) { delete chguser.otphkeys; annonceChange = true; }
|
if (chguser.otphkeys) { delete chguser.otphkeys; }
|
||||||
if (chguser.otpkeys) { delete chguser.otpkeys; annonceChange = true; }
|
if (chguser.otpkeys) { delete chguser.otpkeys; }
|
||||||
}
|
}
|
||||||
obj.db.SetUser(chguser);
|
obj.db.SetUser(chguser);
|
||||||
if (annonceChange == true) { obj.parent.parent.DispatchEvent(['*', 'server-users', user._id, chguser._id], obj, { etype: 'user', username: user.name, account: obj.parent.CloneSafeUser(chguser), action: 'accountchange', msg: 'Removed 2nd factor auth.', domain: domain.id }); }
|
obj.parent.parent.DispatchEvent(['*', 'server-users', user._id, chguser._id], obj, { etype: 'user', username: user.name, account: obj.parent.CloneSafeUser(chguser), action: 'accountchange', msg: 'Changed account credentials.', domain: domain.id });
|
||||||
} else {
|
} else {
|
||||||
// Report that the password change failed
|
// Report that the password change failed
|
||||||
// TODO
|
// TODO
|
||||||
|
@ -48,7 +48,7 @@
|
|||||||
"_NewAccountEmailDomains": [ "sample.com" ],
|
"_NewAccountEmailDomains": [ "sample.com" ],
|
||||||
"Footer": "<a href='https://twitter.com/mytwitter'>Twitter</a>",
|
"Footer": "<a href='https://twitter.com/mytwitter'>Twitter</a>",
|
||||||
"_CertUrl": "https://192.168.2.106:443/",
|
"_CertUrl": "https://192.168.2.106:443/",
|
||||||
"_PasswordRequirements": { "min": 8, "max": 128, "upper": 1, "lower": 1, "numeric": 1, "nonalpha": 1 },
|
"_PasswordRequirements": { "min": 8, "max": 128, "upper": 1, "lower": 1, "numeric": 1, "nonalpha": 1, "reset": 90 },
|
||||||
"_AgentNoProxy": true,
|
"_AgentNoProxy": true,
|
||||||
"_GeoLocation": true,
|
"_GeoLocation": true,
|
||||||
"_UserAllowedIP": "127.0.0.1,192.168.1.0/24",
|
"_UserAllowedIP": "127.0.0.1,192.168.1.0/24",
|
||||||
|
@ -23,10 +23,10 @@ module.exports.CreateSwarmServer = function (parent, db, args, certificates) {
|
|||||||
obj.legacyAgentConnections = {};
|
obj.legacyAgentConnections = {};
|
||||||
obj.migrationAgents = {};
|
obj.migrationAgents = {};
|
||||||
obj.agentActionCount = {};
|
obj.agentActionCount = {};
|
||||||
const common = require('./common.js');
|
obj.stats = { blockedConnect: 0, connectCount: 0, clientCertConnectCount: 0, noCertConnectCount: 0, bytesIn: 0, bytesOut: 0, httpGetRequest: 0, pushedAgents: {}, close: 0, onclose: 0 }
|
||||||
//const net = require('net');
|
|
||||||
const tls = require('tls');
|
const tls = require('tls');
|
||||||
const forge = require('node-forge');
|
const forge = require('node-forge');
|
||||||
|
const common = require('./common.js');
|
||||||
|
|
||||||
const LegacyMeshProtocol = {
|
const LegacyMeshProtocol = {
|
||||||
NODEPUSH: 1, // Used to send a node block to another peer.
|
NODEPUSH: 1, // Used to send a node block to another peer.
|
||||||
@ -149,26 +149,41 @@ module.exports.CreateSwarmServer = function (parent, db, args, certificates) {
|
|||||||
// Called when a legacy agent connects to this server
|
// Called when a legacy agent connects to this server
|
||||||
function onConnection(socket) {
|
function onConnection(socket) {
|
||||||
// Check for blocked IP address
|
// Check for blocked IP address
|
||||||
if (checkSwarmIpAddress(socket, obj.args.swarmallowedip) == false) { Debug(1, "SWARM:New blocked agent connection"); return; }
|
if (checkSwarmIpAddress(socket, obj.args.swarmallowedip) == false) { obj.stats.blockedConnect++; Debug(1, "SWARM:New blocked agent connection"); return; }
|
||||||
|
obj.stats.connectCount++;
|
||||||
|
|
||||||
socket.tag = { first: true, clientCert: socket.getPeerCertificate(true), accumulator: "", socket: socket };
|
socket.tag = { first: true, clientCert: socket.getPeerCertificate(true), accumulator: "", socket: socket };
|
||||||
socket.setEncoding('binary');
|
socket.setEncoding('binary');
|
||||||
socket.pingTimer = setInterval(function () { obj.SendCommand(socket, LegacyMeshProtocol.PING); }, 20000);
|
socket.pingTimer = setInterval(function () { obj.SendCommand(socket, LegacyMeshProtocol.PING); }, 20000);
|
||||||
Debug(1, 'SWARM:New legacy agent connection');
|
Debug(1, 'SWARM:New legacy agent connection');
|
||||||
|
|
||||||
|
if ((socket.tag.clientCert == null) || (socket.tag.clientCert.subject == null)) { obj.stats.noCertConnectCount++; } else { obj.stats.clientCertConnectCount++; }
|
||||||
|
|
||||||
socket.addListener("data", function (data) {
|
socket.addListener("data", function (data) {
|
||||||
if (args.swarmdebug) { var buf = Buffer.from(data, "binary"); console.log('SWARM <-- (' + buf.length + '):' + buf.toString('hex')); } // Print out received bytes
|
if (args.swarmdebug) { var buf = Buffer.from(data, "binary"); console.log('SWARM <-- (' + buf.length + '):' + buf.toString('hex')); } // Print out received bytes
|
||||||
|
obj.stats.bytesIn += data.length;
|
||||||
socket.tag.accumulator += data;
|
socket.tag.accumulator += data;
|
||||||
|
|
||||||
// Detect if this is an HTTPS request, if it is, return a simple answer and disconnect. This is useful for debugging access to the MPS port.
|
// Detect if this is an HTTPS request, if it is, return a simple answer and disconnect. This is useful for debugging access to the MPS port.
|
||||||
if (socket.tag.first == true) {
|
if (socket.tag.first == true) {
|
||||||
if (socket.tag.accumulator.length < 3) return;
|
if (socket.tag.accumulator.length < 3) return;
|
||||||
if (socket.tag.accumulator.substring(0, 3) == 'GET') { /*console.log("Swarm Connection, HTTP GET detected: " + socket.remoteAddress);*/ socket.write('HTTP/1.1 200 OK\r\nContent-Type: text/html\r\nConnection: close\r\n\r\n<!DOCTYPE html><html><head><meta charset="UTF-8"></head><body>MeshCentral2 legacy swarm server.<br />MeshCentral1 mesh agents should connect here for updates.</body></html>'); socket.end(); return; }
|
if (socket.tag.accumulator.substring(0, 3) == 'GET') {
|
||||||
|
obj.stats.httpGetRequest++;
|
||||||
|
/*console.log("Swarm Connection, HTTP GET detected: " + socket.remoteAddress);*/
|
||||||
|
socket.write('HTTP/1.1 200 OK\r\nContent-Type: text/html\r\nConnection: close\r\n\r\n<!DOCTYPE html><html><head><meta charset="UTF-8"></head><body>MeshCentral2 legacy swarm server.<br />MeshCentral1 mesh agents should connect here for updates.</body></html>');
|
||||||
|
socket.end();
|
||||||
|
return;
|
||||||
|
}
|
||||||
socket.tag.first = false;
|
socket.tag.first = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// A client certificate is required
|
// A client certificate is required
|
||||||
if (!socket.tag.clientCert.subject) { /*console.log("Swarm Connection, no client cert: " + socket.remoteAddress);*/ socket.write('HTTP/1.1 200 OK\r\nContent-Type: text/plain\r\nConnection: close\r\n\r\nMeshCentral2 legacy swarm server.\r\nNo client certificate given.'); socket.end(); return; }
|
if ((socket.tag.clientCert == null) || (socket.tag.clientCert.subject == null)) {
|
||||||
|
/*console.log("Swarm Connection, no client cert: " + socket.remoteAddress);*/
|
||||||
|
socket.write('HTTP/1.1 200 OK\r\nContent-Type: text/plain\r\nConnection: close\r\n\r\nMeshCentral2 legacy swarm server.\r\nNo client certificate given.');
|
||||||
|
socket.end();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// Parse all of the agent binary command data we can
|
// Parse all of the agent binary command data we can
|
||||||
@ -215,6 +230,10 @@ module.exports.CreateSwarmServer = function (parent, db, args, certificates) {
|
|||||||
socket.tag.updatePtr = 0;
|
socket.tag.updatePtr = 0;
|
||||||
//console.log('Performing legacy agent update from ' + nodeblock.agentversion + '.' + nodeblock.agenttype + ' to ' + socket.tag.update.ver + '.' + socket.tag.update.arch + ' on ' + nodeblock.agentname + '.');
|
//console.log('Performing legacy agent update from ' + nodeblock.agentversion + '.' + nodeblock.agenttype + ' to ' + socket.tag.update.ver + '.' + socket.tag.update.arch + ' on ' + nodeblock.agentname + '.');
|
||||||
|
|
||||||
|
// Update stats
|
||||||
|
if (obj.stats.pushedAgents[nodeblock.agenttype] == null) { obj.stats.pushedAgents[nodeblock.agenttype] = {}; }
|
||||||
|
if (obj.stats.pushedAgents[nodeblock.agenttype][nextAgentVersion] == null) { obj.stats.pushedAgents[nodeblock.agenttype][nextAgentVersion] = 0; } else { obj.stats.pushedAgents[nodeblock.agenttype][nextAgentVersion]++; }
|
||||||
|
|
||||||
// Start the agent download using the task limiter so not to flood the server. Low priority task
|
// Start the agent download using the task limiter so not to flood the server. Low priority task
|
||||||
obj.parent.taskLimiter.launch(function (socket, taskid, taskLimiterQueue) {
|
obj.parent.taskLimiter.launch(function (socket, taskid, taskLimiterQueue) {
|
||||||
if (socket.xclosed == 1) {
|
if (socket.xclosed == 1) {
|
||||||
@ -286,6 +305,7 @@ module.exports.CreateSwarmServer = function (parent, db, args, certificates) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
socket.addListener("close", function () {
|
socket.addListener("close", function () {
|
||||||
|
obj.stats.onclose++;
|
||||||
Debug(1, 'Swarm:Connection closed');
|
Debug(1, 'Swarm:Connection closed');
|
||||||
if (socket.pingTimer != null) { clearInterval(socket.pingTimer); delete socket.pingTimer; }
|
if (socket.pingTimer != null) { clearInterval(socket.pingTimer); delete socket.pingTimer; }
|
||||||
if (socket.tag && (typeof socket.tag.taskid == 'number')) {
|
if (socket.tag && (typeof socket.tag.taskid == 'number')) {
|
||||||
@ -358,6 +378,7 @@ module.exports.CreateSwarmServer = function (parent, db, args, certificates) {
|
|||||||
|
|
||||||
// Disconnect legacy agent connection
|
// Disconnect legacy agent connection
|
||||||
obj.close = function (socket) {
|
obj.close = function (socket) {
|
||||||
|
obj.stats.close++;
|
||||||
try { socket.close(); } catch (e) { }
|
try { socket.close(); } catch (e) { }
|
||||||
socket.xclosed = 1;
|
socket.xclosed = 1;
|
||||||
};
|
};
|
||||||
@ -368,6 +389,7 @@ module.exports.CreateSwarmServer = function (parent, db, args, certificates) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
function Write(socket, data) {
|
function Write(socket, data) {
|
||||||
|
obj.stats.bytesOut += data.length;
|
||||||
if (args.swarmdebug) {
|
if (args.swarmdebug) {
|
||||||
// Print out sent bytes
|
// Print out sent bytes
|
||||||
var buf = Buffer.from(data, "binary");
|
var buf = Buffer.from(data, "binary");
|
||||||
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@ -243,7 +243,7 @@
|
|||||||
<div style="margin-left:9px;margin-bottom:8px">
|
<div style="margin-left:9px;margin-bottom:8px">
|
||||||
<div style="margin-top:5px"><span id="verifyEmailId" style="display:none"><a onclick="account_showVerifyEmail()" style="cursor:pointer">Verify email</a></span></div>
|
<div style="margin-top:5px"><span id="verifyEmailId" style="display:none"><a onclick="account_showVerifyEmail()" style="cursor:pointer">Verify email</a></span></div>
|
||||||
<div style="margin-top:5px"><a onclick="account_showChangeEmail()" style="cursor:pointer">Change email address</a></div>
|
<div style="margin-top:5px"><a onclick="account_showChangeEmail()" style="cursor:pointer">Change email address</a></div>
|
||||||
<div style="margin-top:5px"><a onclick="account_showChangePassword()" style="cursor:pointer">Change password</a></div>
|
<div style="margin-top:5px"><a onclick="account_showChangePassword()" style="cursor:pointer">Change password</a><span id="p2nextPasswordUpdateTime"></span></div>
|
||||||
<div style="margin-top:5px"><a onclick="account_showDeleteAccount()" style="cursor:pointer">Delete account</a></div>
|
<div style="margin-top:5px"><a onclick="account_showDeleteAccount()" style="cursor:pointer">Delete account</a></div>
|
||||||
</div>
|
</div>
|
||||||
<br style=clear:both />
|
<br style=clear:both />
|
||||||
@ -654,8 +654,21 @@
|
|||||||
QV('verifyEmailId', (userinfo.emailVerified !== true) && (userinfo.email != null) && (serverinfo.emailcheck == true));
|
QV('verifyEmailId', (userinfo.emailVerified !== true) && (userinfo.email != null) && (serverinfo.emailcheck == true));
|
||||||
QV('manageAuthApp', features & 4096);
|
QV('manageAuthApp', features & 4096);
|
||||||
QV('manageOtp', ((features & 4096) != 0) && ((userinfo.otpsecret == 1) || (userinfo.otphkeys > 0)));
|
QV('manageOtp', ((features & 4096) != 0) && ((userinfo.otpsecret == 1) || (userinfo.otphkeys > 0)));
|
||||||
|
|
||||||
|
if (typeof userinfo.passchange == 'number') {
|
||||||
|
if (userinfo.passchange == -1) { QH('p2nextPasswordUpdateTime', ' - Reset on next login.'); }
|
||||||
|
else if ((passRequirements != null) && (typeof passRequirements.reset == 'number')) {
|
||||||
|
var seconds = (userinfo.passchange) + (passRequirements.reset * 86400) - Math.floor(Date.now() / 1000);
|
||||||
|
if (seconds < 0) { QH('p2nextPasswordUpdateTime', ' - Reset on next login.'); }
|
||||||
|
else if (seconds < 3600) { QH('p2nextPasswordUpdateTime', ' - Reset in ' + Math.floor(seconds / 60) + ' minute' + addLetterS(Math.floor(seconds / 60)) + '.'); }
|
||||||
|
else if (seconds < 86400) { QH('p2nextPasswordUpdateTime', ' - Reset in ' + Math.floor(seconds / 3600) + ' hour' + addLetterS(Math.floor(seconds / 3600)) + '.'); }
|
||||||
|
else { QH('p2nextPasswordUpdateTime', ' - Reset in ' + Math.floor(seconds / 86400) + ' day' + addLetterS(Math.floor(seconds / 86400)) + '.'); }
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function addLetterS(x) { return (x > 1) ? 's' : ''; }
|
||||||
|
|
||||||
function onMessage(server, message) {
|
function onMessage(server, message) {
|
||||||
switch (message.action) {
|
switch (message.action) {
|
||||||
case 'serverinfo': {
|
case 'serverinfo': {
|
||||||
|
@ -260,7 +260,7 @@
|
|||||||
<p style="margin-left:40px">
|
<p style="margin-left:40px">
|
||||||
<span id="verifyEmailId" style="display:none"><a onclick="account_showVerifyEmail()" style="cursor:pointer">Verify email</a><br /></span>
|
<span id="verifyEmailId" style="display:none"><a onclick="account_showVerifyEmail()" style="cursor:pointer">Verify email</a><br /></span>
|
||||||
<a onclick="account_showChangeEmail()" style="cursor:pointer">Change email address</a><br />
|
<a onclick="account_showChangeEmail()" style="cursor:pointer">Change email address</a><br />
|
||||||
<a onclick="account_showChangePassword()" style="cursor:pointer">Change password</a><br />
|
<a onclick="account_showChangePassword()" style="cursor:pointer">Change password</a><span id="p2nextPasswordUpdateTime"></span><br />
|
||||||
<a onclick="account_showDeleteAccount()" style="cursor:pointer">Delete account</a><br />
|
<a onclick="account_showDeleteAccount()" style="cursor:pointer">Delete account</a><br />
|
||||||
</p>
|
</p>
|
||||||
<br style=clear:both />
|
<br style=clear:both />
|
||||||
@ -1190,8 +1190,21 @@
|
|||||||
QV('authAppSetupCheck', userinfo.otpsecret == 1);
|
QV('authAppSetupCheck', userinfo.otpsecret == 1);
|
||||||
QV('authKeySetupCheck', userinfo.otphkeys > 0);
|
QV('authKeySetupCheck', userinfo.otphkeys > 0);
|
||||||
QV('authCodesSetupCheck', userinfo.otpkeys > 0);
|
QV('authCodesSetupCheck', userinfo.otpkeys > 0);
|
||||||
|
|
||||||
|
if (typeof userinfo.passchange == 'number') {
|
||||||
|
if (userinfo.passchange == -1) { QH('p2nextPasswordUpdateTime', ' - Reset on next login.'); }
|
||||||
|
else if ((passRequirements != null) && (typeof passRequirements.reset == 'number')) {
|
||||||
|
var seconds = (userinfo.passchange) + (passRequirements.reset * 86400) - Math.floor(Date.now() / 1000);
|
||||||
|
if (seconds < 0) { QH('p2nextPasswordUpdateTime', ' - Reset on next login.'); }
|
||||||
|
else if (seconds < 3600) { QH('p2nextPasswordUpdateTime', ' - Reset in ' + Math.floor(seconds / 60) + ' minute' + addLetterS(Math.floor(seconds / 60)) + '.'); }
|
||||||
|
else if (seconds < 86400) { QH('p2nextPasswordUpdateTime', ' - Reset in ' + Math.floor(seconds / 3600) + ' hour' + addLetterS(Math.floor(seconds / 3600)) + '.'); }
|
||||||
|
else { QH('p2nextPasswordUpdateTime', ' - Reset in ' + Math.floor(seconds / 86400) + ' day' + addLetterS(Math.floor(seconds / 86400)) + '.'); }
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function addLetterS(x) { return (x > 1) ? 's' : ''; }
|
||||||
|
|
||||||
function onMessage(server, message) {
|
function onMessage(server, message) {
|
||||||
switch (message.action) {
|
switch (message.action) {
|
||||||
case 'serverstats': {
|
case 'serverstats': {
|
||||||
@ -1767,7 +1780,9 @@
|
|||||||
}
|
}
|
||||||
case 'login': {
|
case 'login': {
|
||||||
// Update the last login time
|
// Update the last login time
|
||||||
if (users != null && users['user/' + domain + '/' + message.event.username.toLowerCase()]) { users['user/' + domain + '/' + message.event.username.toLowerCase()].login = Math.floor(message.event.time / 1000); }
|
if (users != null && users['user/' + domain + '/' + message.event.username.toLowerCase()]) {
|
||||||
|
users['user/' + domain + '/' + message.event.username.toLowerCase()].login = Math.floor(new Date(message.event.time).getTime() / 1000);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 'scanamtdevice': {
|
case 'scanamtdevice': {
|
||||||
@ -6584,6 +6599,8 @@
|
|||||||
if (user.quota) x += addDeviceAttribute('Server Quota', EscapeHtml(parseInt(user.quota) / 1024) + ' k');
|
if (user.quota) x += addDeviceAttribute('Server Quota', EscapeHtml(parseInt(user.quota) / 1024) + ' k');
|
||||||
x += addDeviceAttribute('Creation', new Date(user.creation * 1000).toLocaleString());
|
x += addDeviceAttribute('Creation', new Date(user.creation * 1000).toLocaleString());
|
||||||
if (user.login) x += addDeviceAttribute('Last Login', new Date(user.login * 1000).toLocaleString());
|
if (user.login) x += addDeviceAttribute('Last Login', new Date(user.login * 1000).toLocaleString());
|
||||||
|
if (user.passchange == -1) { x += addDeviceAttribute('Password', 'Will be changed on next login.'); }
|
||||||
|
else if (user.passchange) { x += addDeviceAttribute('Password', 'Last changed: ' + new Date(user.passchange * 1000).toLocaleString()); }
|
||||||
|
|
||||||
var linkCount = 0, linkCountStr = '<i>None<i>';
|
var linkCount = 0, linkCountStr = '<i>None<i>';
|
||||||
if (user.links) {
|
if (user.links) {
|
||||||
@ -6674,6 +6691,7 @@
|
|||||||
x += addHtmlValue('Password', '<input id=p4pass2 type=password style=width:230px maxlength=256 onchange=showCreateNewAccountDialogValidate(1) onkeyup=showCreateNewAccountDialogValidate(1)></input>');
|
x += addHtmlValue('Password', '<input id=p4pass2 type=password style=width:230px maxlength=256 onchange=showCreateNewAccountDialogValidate(1) onkeyup=showCreateNewAccountDialogValidate(1)></input>');
|
||||||
x += addHtmlValue('Password hint', '<input id=p4hint type=text style=width:230px maxlength=256></input>');
|
x += addHtmlValue('Password hint', '<input id=p4hint type=text style=width:230px maxlength=256></input>');
|
||||||
if (passRequirements) { var r = []; for (var i in passRequirements) { r.push(i + ':' + passRequirements[i]); } x += '<div style=font-size:x-small;padding:6px>Requirements: ' + r.join(', ') + '.</div>'; }
|
if (passRequirements) { var r = []; for (var i in passRequirements) { r.push(i + ':' + passRequirements[i]); } x += '<div style=font-size:x-small;padding:6px>Requirements: ' + r.join(', ') + '.</div>'; }
|
||||||
|
x += '<div><input id=p4resetNextLogin type=checkbox />Force password reset on next login.</div>';
|
||||||
if (multiFactor == 1) { x += '<div><input id=p4twoFactorRemove type=checkbox />Remove all 2nd factor authentication.</div>'; }
|
if (multiFactor == 1) { x += '<div><input id=p4twoFactorRemove type=checkbox />Remove all 2nd factor authentication.</div>'; }
|
||||||
setDialogMode(2, "Change Password for " + EscapeHtml(currentUser.name), 3, p30showUserChangePassDialogEx, x, multiFactor);
|
setDialogMode(2, "Change Password for " + EscapeHtml(currentUser.name), 3, p30showUserChangePassDialogEx, x, multiFactor);
|
||||||
showCreateNewAccountDialogValidate(1);
|
showCreateNewAccountDialogValidate(1);
|
||||||
@ -6683,7 +6701,7 @@
|
|||||||
function p30showUserChangePassDialogEx(b, tag) {
|
function p30showUserChangePassDialogEx(b, tag) {
|
||||||
var removeMultiFactor = false;
|
var removeMultiFactor = false;
|
||||||
if ((tag == 1) && (Q('p4twoFactorRemove').checked == true)) { removeMultiFactor = true; }
|
if ((tag == 1) && (Q('p4twoFactorRemove').checked == true)) { removeMultiFactor = true; }
|
||||||
if (Q('p4pass1').value == Q('p4pass2').value) { meshserver.send({ action: 'changeuserpass', user: currentUser.name, pass: Q('p4pass1').value, hint: Q('p4hint').value, removeMultiFactor: removeMultiFactor }); }
|
if (Q('p4pass1').value == Q('p4pass2').value) { meshserver.send({ action: 'changeuserpass', user: currentUser.name, pass: Q('p4pass1').value, hint: Q('p4hint').value, removeMultiFactor: removeMultiFactor, resetNextLogin: Q('p4resetNextLogin').checked }); }
|
||||||
}
|
}
|
||||||
|
|
||||||
function p30showDeleteUserDialog() {
|
function p30showDeleteUserDialog() {
|
||||||
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@ -188,6 +188,35 @@
|
|||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div id=resetpasswordpanel style="position:relative;background-color: #979797;border-radius:16px;width:300px;padding:16px;text-align:center;display:none">
|
||||||
|
<form action=resetpassword method=post>
|
||||||
|
<div id=message6>
|
||||||
|
{{{message}}}
|
||||||
|
</div>
|
||||||
|
<div id="rpasswordPolicyCallout" style="left:-10px;width:100px;display:none;position:absolute;background-color:#FFC;border-radius:5px;padding:5px;box-shadow:0px 0px 15px #666;font-size:10px"></div>
|
||||||
|
<table>
|
||||||
|
<tr>
|
||||||
|
<td id="rnuPass1" width=100 align=right>Password:</td>
|
||||||
|
<td><input id=rapassword1 type=password name=rpassword1 autocomplete=off maxlength=256 onkeydown=haltReturn(event) onchange=validatePassReset(3,event) onkeyup=validatePassReset(3,event) /></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td id="rnuPass2" align=right>Password:</td>
|
||||||
|
<td><input id=rapassword2 type=password name=rpassword2 autocomplete=off maxlength=256 onkeydown=haltReturn(event) onchange=validatePassReset(4,event) onkeyup=validatePassReset(4,event) /></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td id="rnuHint" align=right>Password Hint:</td>
|
||||||
|
<td><input id=rapasswordhint type=text name=rpasswordhint autocomplete=off maxlength=256 onkeydown=haltReturn(event) onchange=validatePassReset(5,event) onkeyup=validatePassReset(5,event) /></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td colspan=2>
|
||||||
|
<div style=float:right><input id=resetPassButton type=submit value="Reset Password" disabled="disabled" /></div>
|
||||||
|
<div id=rpassWarning style="padding-top:6px"></div>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
<hr /><a onclick=xgo(1) style=cursor:pointer>Back to login</a>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
@ -288,6 +317,7 @@
|
|||||||
QV('message3', false);
|
QV('message3', false);
|
||||||
QV('message4', false);
|
QV('message4', false);
|
||||||
QV('message5', false);
|
QV('message5', false);
|
||||||
|
QV('message6', false);
|
||||||
go(x);
|
go(x);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -299,10 +329,13 @@
|
|||||||
QV('resetpanel', x == 3);
|
QV('resetpanel', x == 3);
|
||||||
QV('tokenpanel', x == 4);
|
QV('tokenpanel', x == 4);
|
||||||
QV('resettokenpanel', x == 5);
|
QV('resettokenpanel', x == 5);
|
||||||
|
QV('resetpasswordpanel', x == 6);
|
||||||
if (x == 1) { Q('username').focus(); }
|
if (x == 1) { Q('username').focus(); }
|
||||||
if (x == 2) { Q('ausername').focus(); }
|
if (x == 2) { Q('ausername').focus(); }
|
||||||
if (x == 3) { Q('remail').focus(); }
|
if (x == 3) { Q('remail').focus(); }
|
||||||
if (x == 4) { Q('tokenInput').focus(); }
|
if (x == 4) { Q('tokenInput').focus(); }
|
||||||
|
if (x == 5) { Q('resetTokenInput').focus(); }
|
||||||
|
if (x == 6) { Q('rapassword1').focus(); }
|
||||||
}
|
}
|
||||||
|
|
||||||
function validateLogin(box, e) {
|
function validateLogin(box, e) {
|
||||||
@ -355,6 +388,52 @@
|
|||||||
if (e != null) { haltEvent(e); }
|
if (e != null) { haltEvent(e); }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function validatePassReset(box, e) {
|
||||||
|
setDialogMode(0);
|
||||||
|
var pass1ok = (Q('rapassword1').value.length > 0);
|
||||||
|
var pass2ok = (Q('rapassword2').value.length > 0) && (Q('rapassword2').value == Q('rapassword1').value);
|
||||||
|
var ok = (pass1ok && pass2ok);
|
||||||
|
|
||||||
|
// Color the fields
|
||||||
|
QS('rnuPass1').color = pass1ok ? 'black' : '#7b241c';
|
||||||
|
QS('rnuPass2').color = pass2ok ? 'black' : '#7b241c';
|
||||||
|
|
||||||
|
if (Q('rapassword1').value == '') {
|
||||||
|
QH('rpassWarning', '');
|
||||||
|
QV('rpasswordPolicyCallout', false);
|
||||||
|
} else {
|
||||||
|
if (passRequirements == null || passRequirements == '') {
|
||||||
|
// No password requirements, display password strength
|
||||||
|
var passStrength = checkPasswordStrength(Q('rapassword1').value);
|
||||||
|
if (passStrength >= 80) { QH('rpassWarning', '<span style=color:green><b>Strong Password</b><span>'); }
|
||||||
|
else if (passStrength >= 60) { QH('rpassWarning', '<span style=color:blue><b>Good Password</b><span>'); }
|
||||||
|
else { QH('rpassWarning', '<span style=color:red><b>Weak Password</b><span>'); }
|
||||||
|
} else {
|
||||||
|
// Password requirements provided, use that
|
||||||
|
var passReq = checkPasswordRequirements(Q('rapassword1').value, passRequirements);
|
||||||
|
if (passReq == false) {
|
||||||
|
ok = false;
|
||||||
|
QS('rnuPass1').color = '#7b241c';
|
||||||
|
QS('rnuPass2').color = '#7b241c';
|
||||||
|
QH('rpassWarning', '<div style=color:red;cursor:pointer onclick=showPasswordPolicy()><b>Password Policy</b><div>'); // This is also a link to the password policy
|
||||||
|
QV('rpasswordPolicyCallout', true);
|
||||||
|
QH('rpasswordPolicyCallout', passwordPolicyText(Q('rapassword1').value));
|
||||||
|
} else {
|
||||||
|
QH('rpassWarning', '');
|
||||||
|
QV('rpasswordPolicyCallout', false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ((e != null) && (e.keyCode == 13)) {
|
||||||
|
if (box == 2) { Q('rapassword1').focus(); }
|
||||||
|
if (box == 3) { Q('rapassword2').focus(); }
|
||||||
|
if (box == 4) { Q('rapasswordhint').focus(); }
|
||||||
|
if (box == 6) { Q('resetPassButton').click(); }
|
||||||
|
}
|
||||||
|
if (e != null) { haltEvent(e); }
|
||||||
|
QE('resetPassButton', ok);
|
||||||
|
}
|
||||||
|
|
||||||
function validateReset(e) {
|
function validateReset(e) {
|
||||||
setDialogMode(0);
|
setDialogMode(0);
|
||||||
var x = validateEmail(Q('remail').value);
|
var x = validateEmail(Q('remail').value);
|
||||||
|
@ -167,19 +167,19 @@
|
|||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td id="nuPass1" align=right>Password:</td>
|
<td id="nuPass1" align=right>Password:</td>
|
||||||
<td><input id=apassword1 type=password name=password1 autocomplete=off maxlength=256 onkeydown=haltReturn(event) onchange=validateCreate(3) onkeyup=validateCreate(3,event) /></td>
|
<td><input id=apassword1 type=password name=password1 autocomplete=off maxlength=256 onkeydown=haltReturn(event) onchange=validateCreate(3,event) onkeyup=validateCreate(3,event) /></td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td id="nuPass2" align=right>Password:</td>
|
<td id="nuPass2" align=right>Password:</td>
|
||||||
<td><input id=apassword2 type=password name=password2 autocomplete=off maxlength=256 onkeydown=haltReturn(event) onchange=validateCreate(4) onkeyup=validateCreate(4,event) /></td>
|
<td><input id=apassword2 type=password name=password2 autocomplete=off maxlength=256 onkeydown=haltReturn(event) onchange=validateCreate(4,event) onkeyup=validateCreate(4,event) /></td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td id="nuHint" align=right>Password Hint:</td>
|
<td id="nuHint" align=right>Password Hint:</td>
|
||||||
<td><input id=apasswordhint type=text name=apasswordhint autocomplete=off maxlength=256 onkeydown=haltReturn(event) onchange=validateCreate(5) onkeyup=validateCreate(5,event) /></td>
|
<td><input id=apasswordhint type=text name=apasswordhint autocomplete=off maxlength=256 onkeydown=haltReturn(event) onchange=validateCreate(5,event) onkeyup=validateCreate(5,event) /></td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr id=newAccountPass title="Enter the account creation token">
|
<tr id=newAccountPass title="Enter the account creation token">
|
||||||
<td id="nuToken" align=right>Creation Token:</td>
|
<td id="nuToken" align=right>Creation Token:</td>
|
||||||
<td><input id=anewaccountpass type=password name=anewaccountpass autocomplete=off maxlength=256 onkeydown=haltReturn(event) onchange=validateCreate(6) onkeyup=validateCreate(6,event) /></td>
|
<td><input id=anewaccountpass type=password name=anewaccountpass autocomplete=off maxlength=256 onkeydown=haltReturn(event) onchange=validateCreate(6,event) onkeyup=validateCreate(6,event) /></td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td colspan=2>
|
<td colspan=2>
|
||||||
@ -258,6 +258,35 @@
|
|||||||
<hr /><a onclick=xgo(1) style=cursor:pointer>Back to login</a>
|
<hr /><a onclick=xgo(1) style=cursor:pointer>Back to login</a>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
|
<div id=resetpasswordpanel style="position:relative;background-color: #979797;border-radius:16px;width:300px;padding:16px;text-align:center;display:none">
|
||||||
|
<form action=resetpassword method=post>
|
||||||
|
<div id=message6>
|
||||||
|
{{{message}}}
|
||||||
|
</div>
|
||||||
|
<div id="rpasswordPolicyCallout" style="left:-10px;width:100px;display:none;position:absolute;background-color:#FFC;border-radius:5px;padding:5px;box-shadow:0px 0px 15px #666;font-size:10px"></div>
|
||||||
|
<table>
|
||||||
|
<tr>
|
||||||
|
<td id="rnuPass1" width=100 align=right>Password:</td>
|
||||||
|
<td><input id=rapassword1 type=password name=rpassword1 autocomplete=off maxlength=256 onkeydown=haltReturn(event) onchange=validatePassReset(3,event) onkeyup=validatePassReset(3,event) /></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td id="rnuPass2" align=right>Password:</td>
|
||||||
|
<td><input id=rapassword2 type=password name=rpassword2 autocomplete=off maxlength=256 onkeydown=haltReturn(event) onchange=validatePassReset(4,event) onkeyup=validatePassReset(4,event) /></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td id="rnuHint" align=right>Password Hint:</td>
|
||||||
|
<td><input id=rapasswordhint type=text name=rpasswordhint autocomplete=off maxlength=256 onkeydown=haltReturn(event) onchange=validatePassReset(5,event) onkeyup=validatePassReset(5,event) /></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td colspan=2>
|
||||||
|
<div style=float:right><input id=resetPassButton type=submit value="Reset Password" disabled="disabled" /></div>
|
||||||
|
<div id=rpassWarning style="padding-top:6px"></div>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
<hr /><a onclick=xgo(1) style=cursor:pointer>Back to login</a>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
</table>
|
</table>
|
||||||
@ -373,6 +402,7 @@
|
|||||||
QV('message3', false);
|
QV('message3', false);
|
||||||
QV('message4', false);
|
QV('message4', false);
|
||||||
QV('message5', false);
|
QV('message5', false);
|
||||||
|
QV('message6', false);
|
||||||
go(x);
|
go(x);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -384,10 +414,13 @@
|
|||||||
QV('resetpanel', x == 3);
|
QV('resetpanel', x == 3);
|
||||||
QV('tokenpanel', x == 4);
|
QV('tokenpanel', x == 4);
|
||||||
QV('resettokenpanel', x == 5);
|
QV('resettokenpanel', x == 5);
|
||||||
|
QV('resetpasswordpanel', x == 6);
|
||||||
if (x == 1) { Q('username').focus(); }
|
if (x == 1) { Q('username').focus(); }
|
||||||
if (x == 2) { Q('ausername').focus(); }
|
if (x == 2) { Q('ausername').focus(); }
|
||||||
if (x == 3) { Q('remail').focus(); }
|
if (x == 3) { Q('remail').focus(); }
|
||||||
if (x == 4) { Q('tokenInput').focus(); }
|
if (x == 4) { Q('tokenInput').focus(); }
|
||||||
|
if (x == 5) { Q('resetTokenInput').focus(); }
|
||||||
|
if (x == 6) { Q('rapassword1').focus(); }
|
||||||
}
|
}
|
||||||
|
|
||||||
function validateLogin(box, e) {
|
function validateLogin(box, e) {
|
||||||
@ -452,6 +485,52 @@
|
|||||||
QE('createButton', ok);
|
QE('createButton', ok);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function validatePassReset(box, e) {
|
||||||
|
setDialogMode(0);
|
||||||
|
var pass1ok = (Q('rapassword1').value.length > 0);
|
||||||
|
var pass2ok = (Q('rapassword2').value.length > 0) && (Q('rapassword2').value == Q('rapassword1').value);
|
||||||
|
var ok = (pass1ok && pass2ok);
|
||||||
|
|
||||||
|
// Color the fields
|
||||||
|
QS('rnuPass1').color = pass1ok ? 'black' : '#7b241c';
|
||||||
|
QS('rnuPass2').color = pass2ok ? 'black' : '#7b241c';
|
||||||
|
|
||||||
|
if (Q('rapassword1').value == '') {
|
||||||
|
QH('rpassWarning', '');
|
||||||
|
QV('rpasswordPolicyCallout', false);
|
||||||
|
} else {
|
||||||
|
if (passRequirements == null || passRequirements == '') {
|
||||||
|
// No password requirements, display password strength
|
||||||
|
var passStrength = checkPasswordStrength(Q('rapassword1').value);
|
||||||
|
if (passStrength >= 80) { QH('rpassWarning', '<span style=color:green><b>Strong Password</b><span>'); }
|
||||||
|
else if (passStrength >= 60) { QH('rpassWarning', '<span style=color:blue><b>Good Password</b><span>'); }
|
||||||
|
else { QH('rpassWarning', '<span style=color:red><b>Weak Password</b><span>'); }
|
||||||
|
} else {
|
||||||
|
// Password requirements provided, use that
|
||||||
|
var passReq = checkPasswordRequirements(Q('rapassword1').value, passRequirements);
|
||||||
|
if (passReq == false) {
|
||||||
|
ok = false;
|
||||||
|
QS('rnuPass1').color = '#7b241c';
|
||||||
|
QS('rnuPass2').color = '#7b241c';
|
||||||
|
QH('rpassWarning', '<div style=color:red;cursor:pointer onclick=showPasswordPolicy()><b>Password Policy</b><div>'); // This is also a link to the password policy
|
||||||
|
QV('rpasswordPolicyCallout', true);
|
||||||
|
QH('rpasswordPolicyCallout', passwordPolicyText(Q('rapassword1').value));
|
||||||
|
} else {
|
||||||
|
QH('rpassWarning', '');
|
||||||
|
QV('rpasswordPolicyCallout', false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ((e != null) && (e.keyCode == 13)) {
|
||||||
|
if (box == 2) { Q('rapassword1').focus(); }
|
||||||
|
if (box == 3) { Q('rapassword2').focus(); }
|
||||||
|
if (box == 4) { Q('rapasswordhint').focus(); }
|
||||||
|
if (box == 6) { Q('resetPassButton').click(); }
|
||||||
|
}
|
||||||
|
if (e != null) { haltEvent(e); }
|
||||||
|
QE('resetPassButton', ok);
|
||||||
|
}
|
||||||
|
|
||||||
function passwordPolicyText(pass) {
|
function passwordPolicyText(pass) {
|
||||||
var policy = '<div style=text-align:left>';
|
var policy = '<div style=text-align:left>';
|
||||||
var counts = strCount(pass);
|
var counts = strCount(pass);
|
||||||
|
126
webserver.js
126
webserver.js
@ -419,7 +419,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
|
|||||||
var user = obj.users[userid];
|
var user = obj.users[userid];
|
||||||
|
|
||||||
// Check if this user has 2-step login active
|
// Check if this user has 2-step login active
|
||||||
if (checkUserOneTimePasswordRequired(domain, user)) {
|
if ((req.session.loginmode != '6') && checkUserOneTimePasswordRequired(domain, user)) {
|
||||||
checkUserOneTimePassword(req, domain, user, req.body.token, req.body.hwtoken, function (result) {
|
checkUserOneTimePassword(req, domain, user, req.body.token, req.body.hwtoken, function (result) {
|
||||||
if (result == false) {
|
if (result == false) {
|
||||||
var randomWaitTime = 0;
|
var randomWaitTime = 0;
|
||||||
@ -439,14 +439,14 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
|
|||||||
}, randomWaitTime);
|
}, randomWaitTime);
|
||||||
} else {
|
} else {
|
||||||
// Login succesful
|
// Login succesful
|
||||||
completeLoginRequest(req, res, domain, user, userid);
|
completeLoginRequest(req, res, domain, user, userid, xusername, xpassword);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Login succesful
|
// Login succesful
|
||||||
completeLoginRequest(req, res, domain, user, userid);
|
completeLoginRequest(req, res, domain, user, userid, xusername, xpassword);
|
||||||
} else {
|
} else {
|
||||||
// Login failed, wait a random delay
|
// Login failed, wait a random delay
|
||||||
setTimeout(function () {
|
setTimeout(function () {
|
||||||
@ -466,10 +466,22 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function completeLoginRequest(req, res, domain, user, userid) {
|
function completeLoginRequest(req, res, domain, user, userid, xusername, xpassword) {
|
||||||
|
// Check if we need to change the password
|
||||||
|
if ((typeof user.passchange == 'number') && ((user.passchange == -1) || ((typeof domain.passwordrequirements == 'object') && (typeof domain.passwordrequirements.reset == 'number') && (user.passchange + (domain.passwordrequirements.reset * 86400) < Math.floor(Date.now() / 1000))))) {
|
||||||
|
// Request a password change
|
||||||
|
req.session.loginmode = '6';
|
||||||
|
req.session.error = '<b style=color:#8C001A>Password change requested.</b>';
|
||||||
|
req.session.resettokenusername = xusername;
|
||||||
|
req.session.resettokenpassword = xpassword;
|
||||||
|
res.redirect(domain.url);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// Save login time
|
// Save login time
|
||||||
user.login = Math.floor(Date.now() / 1000);
|
user.login = Math.floor(Date.now() / 1000);
|
||||||
obj.db.SetUser(user);
|
obj.db.SetUser(user);
|
||||||
|
obj.parent.DispatchEvent(['*'], obj, { etype: 'user', username: user.name, account: obj.CloneSafeUser(user), action: 'login', msg: 'Account login', domain: domain.id });
|
||||||
|
|
||||||
// Regenerate session when signing in to prevent fixation
|
// Regenerate session when signing in to prevent fixation
|
||||||
//req.session.regenerate(function () {
|
//req.session.regenerate(function () {
|
||||||
@ -506,8 +518,6 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
|
|||||||
res.redirect(domain.url);
|
res.redirect(domain.url);
|
||||||
}
|
}
|
||||||
//});
|
//});
|
||||||
|
|
||||||
obj.parent.DispatchEvent(['*'], obj, { etype: 'user', username: user.name, action: 'login', msg: 'Account login', domain: domain.id });
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleCreateAccountRequest(req, res) {
|
function handleCreateAccountRequest(req, res) {
|
||||||
@ -521,7 +531,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
|
|||||||
var i = -1;
|
var i = -1;
|
||||||
if (typeof req.body.email == 'string') { i = req.body.email.indexOf('@'); }
|
if (typeof req.body.email == 'string') { i = req.body.email.indexOf('@'); }
|
||||||
if (i == -1) {
|
if (i == -1) {
|
||||||
req.session.loginmode = 2;
|
req.session.loginmode = '2';
|
||||||
req.session.error = '<b style=color:#8C001A>Unable to create account.</b>';
|
req.session.error = '<b style=color:#8C001A>Unable to create account.</b>';
|
||||||
res.redirect(domain.url);
|
res.redirect(domain.url);
|
||||||
return;
|
return;
|
||||||
@ -529,7 +539,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
|
|||||||
var emailok = false, emaildomain = req.body.email.substring(i + 1).toLowerCase();
|
var emailok = false, emaildomain = req.body.email.substring(i + 1).toLowerCase();
|
||||||
for (var i in domain.newaccountemaildomains) { if (emaildomain == domain.newaccountemaildomains[i].toLowerCase()) { emailok = true; } }
|
for (var i in domain.newaccountemaildomains) { if (emaildomain == domain.newaccountemaildomains[i].toLowerCase()) { emailok = true; } }
|
||||||
if (emailok == false) {
|
if (emailok == false) {
|
||||||
req.session.loginmode = 2;
|
req.session.loginmode = '2';
|
||||||
req.session.error = '<b style=color:#8C001A>Unable to create account.</b>';
|
req.session.error = '<b style=color:#8C001A>Unable to create account.</b>';
|
||||||
res.redirect(domain.url);
|
res.redirect(domain.url);
|
||||||
return;
|
return;
|
||||||
@ -539,33 +549,33 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
|
|||||||
// Check if we exceed the maximum number of user accounts
|
// Check if we exceed the maximum number of user accounts
|
||||||
obj.db.isMaxType(domain.limits.maxuseraccounts, 'user', domain.id, function (maxExceed) {
|
obj.db.isMaxType(domain.limits.maxuseraccounts, 'user', domain.id, function (maxExceed) {
|
||||||
if (maxExceed) {
|
if (maxExceed) {
|
||||||
req.session.loginmode = 2;
|
req.session.loginmode = '2';
|
||||||
req.session.error = '<b style=color:#8C001A>Account limit reached.</b>';
|
req.session.error = '<b style=color:#8C001A>Account limit reached.</b>';
|
||||||
console.log('max', req.session);
|
console.log('max', req.session);
|
||||||
res.redirect(domain.url);
|
res.redirect(domain.url);
|
||||||
} else {
|
} else {
|
||||||
if (!obj.common.validateUsername(req.body.username, 1, 64) || !obj.common.validateEmail(req.body.email, 1, 256) || !obj.common.validateString(req.body.password1, 1, 256) || !obj.common.validateString(req.body.password2, 1, 256) || (req.body.password1 != req.body.password2) || req.body.username == '~' || !obj.common.checkPasswordRequirements(req.body.password1, domain.passwordrequirements)) {
|
if (!obj.common.validateUsername(req.body.username, 1, 64) || !obj.common.validateEmail(req.body.email, 1, 256) || !obj.common.validateString(req.body.password1, 1, 256) || !obj.common.validateString(req.body.password2, 1, 256) || (req.body.password1 != req.body.password2) || req.body.username == '~' || !obj.common.checkPasswordRequirements(req.body.password1, domain.passwordrequirements)) {
|
||||||
req.session.loginmode = 2;
|
req.session.loginmode = '2';
|
||||||
req.session.error = '<b style=color:#8C001A>Unable to create account.</b>';
|
req.session.error = '<b style=color:#8C001A>Unable to create account.</b>';
|
||||||
res.redirect(domain.url);
|
res.redirect(domain.url);
|
||||||
} else {
|
} else {
|
||||||
// Check if this email was already verified
|
// Check if this email was already verified
|
||||||
obj.db.GetUserWithVerifiedEmail(domain.id, req.body.email, function (err, docs) {
|
obj.db.GetUserWithVerifiedEmail(domain.id, req.body.email, function (err, docs) {
|
||||||
if (docs.length > 0) {
|
if (docs.length > 0) {
|
||||||
req.session.loginmode = 2;
|
req.session.loginmode = '2';
|
||||||
req.session.error = '<b style=color:#8C001A>Existing account with this email address.</b>';
|
req.session.error = '<b style=color:#8C001A>Existing account with this email address.</b>';
|
||||||
res.redirect(domain.url);
|
res.redirect(domain.url);
|
||||||
} else {
|
} else {
|
||||||
// Check if there is domain.newAccountToken, check if supplied token is valid
|
// Check if there is domain.newAccountToken, check if supplied token is valid
|
||||||
if ((domain.newaccountspass != null) && (domain.newaccountspass != '') && (req.body.anewaccountpass != domain.newaccountspass)) {
|
if ((domain.newaccountspass != null) && (domain.newaccountspass != '') && (req.body.anewaccountpass != domain.newaccountspass)) {
|
||||||
req.session.loginmode = 2;
|
req.session.loginmode = '2';
|
||||||
req.session.error = '<b style=color:#8C001A>Invalid account creation token.</b>';
|
req.session.error = '<b style=color:#8C001A>Invalid account creation token.</b>';
|
||||||
res.redirect(domain.url);
|
res.redirect(domain.url);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// Check if user exists
|
// Check if user exists
|
||||||
if (obj.users['user/' + domain.id + '/' + req.body.username.toLowerCase()]) {
|
if (obj.users['user/' + domain.id + '/' + req.body.username.toLowerCase()]) {
|
||||||
req.session.loginmode = 2;
|
req.session.loginmode = '2';
|
||||||
req.session.error = '<b style=color:#8C001A>Username already exists.</b>';
|
req.session.error = '<b style=color:#8C001A>Username already exists.</b>';
|
||||||
} else {
|
} else {
|
||||||
var hint = req.body.apasswordhint;
|
var hint = req.body.apasswordhint;
|
||||||
@ -599,6 +609,82 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Called to process an account password reset
|
||||||
|
function handleResetPasswordRequest(req, res) {
|
||||||
|
const domain = checkUserIpAddress(req, res);
|
||||||
|
|
||||||
|
// Check everything is ok
|
||||||
|
if ((domain == null) || (domain.auth == 'sspi') || (typeof req.body.rpassword1 != 'string') || (typeof req.body.rpassword2 != 'string') || (req.body.rpassword1 != req.body.rpassword2) || (typeof req.body.rpasswordhint != 'string') || (req.session == null) || (typeof req.session.resettokenusername != 'string') || (typeof req.session.resettokenpassword != 'string')) {
|
||||||
|
delete req.session.loginmode;
|
||||||
|
delete req.session.tokenusername;
|
||||||
|
delete req.session.tokenpassword;
|
||||||
|
delete req.session.resettokenusername;
|
||||||
|
delete req.session.resettokenpassword;
|
||||||
|
delete req.session.tokenemail;
|
||||||
|
delete req.session.success;
|
||||||
|
delete req.session.error;
|
||||||
|
delete req.session.passhint;
|
||||||
|
res.redirect(domain.url);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Authenticate the user
|
||||||
|
obj.authenticate(req.session.resettokenusername, req.session.resettokenpassword, domain, function (err, userid, passhint) {
|
||||||
|
if (userid) {
|
||||||
|
// Login
|
||||||
|
var user = obj.users[userid];
|
||||||
|
|
||||||
|
// If we have password requirements, check this here.
|
||||||
|
if (!obj.common.checkPasswordRequirements(req.body.rpassword1, domain.passwordrequirements)) {
|
||||||
|
req.session.loginmode = '6';
|
||||||
|
req.session.error = '<b style=color:#8C001A>Password rejected, use a different one.</b>';
|
||||||
|
res.redirect(domain.url);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if the password is the same as the previous one
|
||||||
|
require('./pass').hash(req.body.rpassword1, user.salt, function (err, hash) {
|
||||||
|
if (user.hash == hash) {
|
||||||
|
// This is the same password, request a password change again
|
||||||
|
req.session.loginmode = '6';
|
||||||
|
req.session.error = '<b style=color:#8C001A>Password rejected, use a different one.</b>';
|
||||||
|
res.redirect(domain.url);
|
||||||
|
} else {
|
||||||
|
// Update the password, use a different salt.
|
||||||
|
require('./pass').hash(req.body.rpassword1, function (err, salt, hash) {
|
||||||
|
if (err) throw err;
|
||||||
|
user.salt = salt;
|
||||||
|
user.hash = hash;
|
||||||
|
user.passhint = req.body.rpasswordhint;
|
||||||
|
user.passchange = Math.floor(Date.now() / 1000);
|
||||||
|
delete user.passtype;
|
||||||
|
obj.db.SetUser(user);
|
||||||
|
obj.parent.DispatchEvent(['*', 'server-users', user._id], obj, { etype: 'user', username: user.name, account: obj.CloneSafeUser(user), action: 'accountchange', msg: 'User password reset', domain: domain.id });
|
||||||
|
|
||||||
|
// Login succesful
|
||||||
|
req.session.userid = userid;
|
||||||
|
req.session.domainid = domain.id;
|
||||||
|
completeLoginRequest(req, res, domain, obj.users[userid], userid, req.session.tokenusername, req.session.tokenpassword);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
// Failed, error out.
|
||||||
|
delete req.session.loginmode;
|
||||||
|
delete req.session.tokenusername;
|
||||||
|
delete req.session.tokenpassword;
|
||||||
|
delete req.session.resettokenusername;
|
||||||
|
delete req.session.resettokenpassword;
|
||||||
|
delete req.session.tokenemail;
|
||||||
|
delete req.session.success;
|
||||||
|
delete req.session.error;
|
||||||
|
delete req.session.passhint;
|
||||||
|
res.redirect(domain.url);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
// Called to process an account reset request
|
// Called to process an account reset request
|
||||||
function handleResetAccountRequest(req, res) {
|
function handleResetAccountRequest(req, res) {
|
||||||
const domain = checkUserIpAddress(req, res);
|
const domain = checkUserIpAddress(req, res);
|
||||||
@ -610,13 +696,13 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
|
|||||||
|
|
||||||
// Check the email stirng format
|
// Check the email stirng format
|
||||||
if (!email || checkEmail(email) == false) {
|
if (!email || checkEmail(email) == false) {
|
||||||
req.session.loginmode = 3;
|
req.session.loginmode = '3';
|
||||||
req.session.error = '<b style=color:#8C001A>Invalid email.</b>';
|
req.session.error = '<b style=color:#8C001A>Invalid email.</b>';
|
||||||
res.redirect(domain.url);
|
res.redirect(domain.url);
|
||||||
} else {
|
} else {
|
||||||
obj.db.GetUserWithVerifiedEmail(domain.id, email, function (err, docs) {
|
obj.db.GetUserWithVerifiedEmail(domain.id, email, function (err, docs) {
|
||||||
if ((err != null) || (docs.length == 0)) {
|
if ((err != null) || (docs.length == 0)) {
|
||||||
req.session.loginmode = 3;
|
req.session.loginmode = '3';
|
||||||
req.session.error = '<b style=color:#8C001A>Account not found.</b>';
|
req.session.error = '<b style=color:#8C001A>Account not found.</b>';
|
||||||
res.redirect(domain.url);
|
res.redirect(domain.url);
|
||||||
} else {
|
} else {
|
||||||
@ -635,11 +721,11 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
|
|||||||
delete req.session.tokenemail;
|
delete req.session.tokenemail;
|
||||||
if (obj.parent.mailserver != null) {
|
if (obj.parent.mailserver != null) {
|
||||||
obj.parent.mailserver.sendAccountResetMail(domain, user.name, user.email);
|
obj.parent.mailserver.sendAccountResetMail(domain, user.name, user.email);
|
||||||
req.session.loginmode = 1;
|
req.session.loginmode = '1';
|
||||||
req.session.error = '<b style=color:darkgreen>Hold on, reset mail sent.</b>';
|
req.session.error = '<b style=color:darkgreen>Hold on, reset mail sent.</b>';
|
||||||
res.redirect(domain.url);
|
res.redirect(domain.url);
|
||||||
} else {
|
} else {
|
||||||
req.session.loginmode = 3;
|
req.session.loginmode = '3';
|
||||||
req.session.error = '<b style=color:#8C001A>Unable to sent email.</b>';
|
req.session.error = '<b style=color:#8C001A>Unable to sent email.</b>';
|
||||||
res.redirect(domain.url);
|
res.redirect(domain.url);
|
||||||
}
|
}
|
||||||
@ -649,11 +735,11 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
|
|||||||
// No second factor, send email to perform recovery.
|
// No second factor, send email to perform recovery.
|
||||||
if (obj.parent.mailserver != null) {
|
if (obj.parent.mailserver != null) {
|
||||||
obj.parent.mailserver.sendAccountResetMail(domain, user.name, user.email);
|
obj.parent.mailserver.sendAccountResetMail(domain, user.name, user.email);
|
||||||
req.session.loginmode = 1;
|
req.session.loginmode = '1';
|
||||||
req.session.error = '<b style=color:darkgreen>Hold on, reset mail sent.</b>';
|
req.session.error = '<b style=color:darkgreen>Hold on, reset mail sent.</b>';
|
||||||
res.redirect(domain.url);
|
res.redirect(domain.url);
|
||||||
} else {
|
} else {
|
||||||
req.session.loginmode = 3;
|
req.session.loginmode = '3';
|
||||||
req.session.error = '<b style=color:#8C001A>Unable to sent email.</b>';
|
req.session.error = '<b style=color:#8C001A>Unable to sent email.</b>';
|
||||||
res.redirect(domain.url);
|
res.redirect(domain.url);
|
||||||
}
|
}
|
||||||
@ -1074,7 +1160,6 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
|
|||||||
if (err != null) message = '<p class="msg error">' + err + '</p>';
|
if (err != null) message = '<p class="msg error">' + err + '</p>';
|
||||||
if (msg != null) message = '<p class="msg success">' + msg + '</p>';
|
if (msg != null) message = '<p class="msg success">' + msg + '</p>';
|
||||||
if (passhint != null) passhint = EscapeHtml(passhint);
|
if (passhint != null) passhint = EscapeHtml(passhint);
|
||||||
|
|
||||||
var emailcheck = ((obj.parent.mailserver != null) && (domain.auth != 'sspi'));
|
var emailcheck = ((obj.parent.mailserver != null) && (domain.auth != 'sspi'));
|
||||||
|
|
||||||
if (obj.args.minify && !req.query.nominify) {
|
if (obj.args.minify && !req.query.nominify) {
|
||||||
@ -2271,6 +2356,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
|
|||||||
obj.app.post(url + 'changepassword', handlePasswordChangeRequest);
|
obj.app.post(url + 'changepassword', handlePasswordChangeRequest);
|
||||||
obj.app.post(url + 'deleteaccount', handleDeleteAccountRequest);
|
obj.app.post(url + 'deleteaccount', handleDeleteAccountRequest);
|
||||||
obj.app.post(url + 'createaccount', handleCreateAccountRequest);
|
obj.app.post(url + 'createaccount', handleCreateAccountRequest);
|
||||||
|
obj.app.post(url + 'resetpassword', handleResetPasswordRequest);
|
||||||
obj.app.post(url + 'resetaccount', handleResetAccountRequest);
|
obj.app.post(url + 'resetaccount', handleResetAccountRequest);
|
||||||
obj.app.get(url + 'checkmail', handleCheckMailRequest);
|
obj.app.get(url + 'checkmail', handleCheckMailRequest);
|
||||||
obj.app.post(url + 'amtevents.ashx', obj.handleAmtEventRequest);
|
obj.app.post(url + 'amtevents.ashx', obj.handleAmtEventRequest);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user