Added browser notification support in the main web app.
2
agents/meshcmd.min.js
vendored
@ -72,7 +72,7 @@ function CreateWsmanComm(/*host, port, user, pass, tls, extra*/)
|
||||
obj.PerformAjaxEx = function (postdata, callback, tag, url, action) {
|
||||
if (obj.FailAllError != 0) { if (obj.FailAllError != 999) { obj.gotNextMessagesError({ status: obj.FailAllError }, 'error', null, [postdata, callback, tag]); } return; }
|
||||
if (!postdata) postdata = "";
|
||||
//console.log("SEND: " + postdata); // DEBUG
|
||||
if (globalDebugFlags & 1) { console.log("SEND: " + postdata + "\r\n\r\n"); } // DEBUG
|
||||
|
||||
// We are in a DukTape environement
|
||||
if (obj.digest == null)
|
||||
@ -92,9 +92,9 @@ function CreateWsmanComm(/*host, port, user, pass, tls, extra*/)
|
||||
//console.log('Request ' + (obj.RequestCount++));
|
||||
req.on('error', function (e) { obj.gotNextMessagesError({ status: 600 }, 'error', null, [postdata, callback, tag]); });
|
||||
req.on('response', function (response) {
|
||||
//console.log('Response: ' + response.statusCode);
|
||||
if (globalDebugFlags & 1) { console.log('Response: ' + response.statusCode); }
|
||||
if (response.statusCode != 200) {
|
||||
//console.log('ERR:' + JSON.stringify(response));
|
||||
if (globalDebugFlags & 1) { console.log('ERR:' + JSON.stringify(response)); }
|
||||
obj.gotNextMessagesError({ status: response.statusCode }, 'error', null, [postdata, callback, tag]);
|
||||
} else {
|
||||
response.acc = '';
|
||||
@ -116,7 +116,7 @@ function CreateWsmanComm(/*host, port, user, pass, tls, extra*/)
|
||||
obj.gotNextMessages = function (data, status, request, callArgs) {
|
||||
obj.ActiveAjaxCount--;
|
||||
if (obj.FailAllError == 999) return;
|
||||
//console.log("RECV: " + data); // DEBUG
|
||||
if (globalDebugFlags & 1) { console.log("RECV: " + data + "\r\n\r\n"); } // DEBUG
|
||||
if (obj.FailAllError != 0) { callArgs[1](null, obj.FailAllError, callArgs[2]); return; }
|
||||
if (request.status != 200) { callArgs[1](null, request.status, callArgs[2]); return; }
|
||||
callArgs[1](data, 200, callArgs[2]);
|
||||
|
@ -1 +1 @@
|
||||
function CreateWsmanComm(){var a={};a.PendingAjax=[];a.ActiveAjaxCount=0;a.MaxActiveAjaxCount=1;a.FailAllError=0;a.digest=null;a.RequestCount=0;if(arguments.length==1&&typeof(arguments[0]=="object")){a.host=arguments[0].host;a.port=arguments[0].port;a.authToken=arguments[0].authToken;a.tls=arguments[0].tls}else{a.host=arguments[0];a.port=arguments[1];a.user=arguments[2];a.pass=arguments[3];a.tls=arguments[4]}a.PerformAjax=function(d,c,f,e,g,b){if((a.ActiveAjaxCount==0||((a.ActiveAjaxCount<a.MaxActiveAjaxCount)&&(a.challengeParams!=null)))&&a.PendingAjax.length==0){a.PerformAjaxEx(d,c,f,g,b)}else{if(e==1){a.PendingAjax.unshift([d,c,f,g,b])}else{a.PendingAjax.push([d,c,f,g,b])}}};a.PerformNextAjax=function(){if(a.ActiveAjaxCount>=a.MaxActiveAjaxCount||a.PendingAjax.length==0){return}var b=a.PendingAjax.shift();a.PerformAjaxEx(b[0],b[1],b[2],b[3],b[4]);a.PerformNextAjax()};a.PerformAjaxEx=function(d,c,g,h,b){if(a.FailAllError!=0){if(a.FailAllError!=999){a.gotNextMessagesError({status:a.FailAllError},"error",null,[d,c,g])}return}if(!d){d=""}if(a.digest==null){if(a.authToken){a.digest=require("http-digest").create({authToken:a.authToken})}else{a.digest=require("http-digest").create(a.user,a.pass)}a.digest.http=require("http")}var f={protocol:(a.tls==1?"https:":"http:"),method:"POST",host:a.host,path:"/wsman",port:a.port,rejectUnauthorized:false,checkServerIdentity:function(i){console.log("checkServerIdentity",JSON.stringify(i))}};var e=a.digest.request(f);e.on("error",function(i){a.gotNextMessagesError({status:600},"error",null,[d,c,g])});e.on("response",function(i){if(i.statusCode!=200){a.gotNextMessagesError({status:i.statusCode},"error",null,[d,c,g])}else{i.acc="";i.on("data",function(j){this.acc+=j});i.on("end",function(){a.gotNextMessages(i.acc,"success",{status:i.statusCode},[d,c,g])})}});e.end(d);a.ActiveAjaxCount++;return e};a.pendingAjaxCall=[];a.gotNextMessages=function(c,e,d,b){a.ActiveAjaxCount--;if(a.FailAllError==999){return}if(a.FailAllError!=0){b[1](null,a.FailAllError,b[2]);return}if(d.status!=200){b[1](null,d.status,b[2]);return}b[1](c,200,b[2]);a.PerformNextAjax()};a.gotNextMessagesError=function(d,e,c,b){a.ActiveAjaxCount--;if(a.FailAllError==999){return}if(a.FailAllError!=0){b[1](null,a.FailAllError,b[2]);return}if(a.FailAllError!=999){b[1]({Header:{HttpError:d.status}},d.status,b[2])}a.PerformNextAjax()};a.CancelAllQueries=function(b){while(a.PendingAjax.length>0){var c=a.PendingAjax.shift();c[1](null,b,c[2])}};return a}module.exports=CreateWsmanComm;
|
||||
function CreateWsmanComm(){var a={};a.PendingAjax=[];a.ActiveAjaxCount=0;a.MaxActiveAjaxCount=1;a.FailAllError=0;a.digest=null;a.RequestCount=0;if(arguments.length==1&&typeof(arguments[0]=="object")){a.host=arguments[0].host;a.port=arguments[0].port;a.authToken=arguments[0].authToken;a.tls=arguments[0].tls}else{a.host=arguments[0];a.port=arguments[1];a.user=arguments[2];a.pass=arguments[3];a.tls=arguments[4]}a.PerformAjax=function(d,c,f,e,g,b){if((a.ActiveAjaxCount==0||((a.ActiveAjaxCount<a.MaxActiveAjaxCount)&&(a.challengeParams!=null)))&&a.PendingAjax.length==0){a.PerformAjaxEx(d,c,f,g,b)}else{if(e==1){a.PendingAjax.unshift([d,c,f,g,b])}else{a.PendingAjax.push([d,c,f,g,b])}}};a.PerformNextAjax=function(){if(a.ActiveAjaxCount>=a.MaxActiveAjaxCount||a.PendingAjax.length==0){return}var b=a.PendingAjax.shift();a.PerformAjaxEx(b[0],b[1],b[2],b[3],b[4]);a.PerformNextAjax()};a.PerformAjaxEx=function(d,c,g,h,b){if(a.FailAllError!=0){if(a.FailAllError!=999){a.gotNextMessagesError({status:a.FailAllError},"error",null,[d,c,g])}return}if(!d){d=""}if(globalDebugFlags&1){console.log("SEND: "+d+"\r\n\r\n")}if(a.digest==null){if(a.authToken){a.digest=require("http-digest").create({authToken:a.authToken})}else{a.digest=require("http-digest").create(a.user,a.pass)}a.digest.http=require("http")}var f={protocol:(a.tls==1?"https:":"http:"),method:"POST",host:a.host,path:"/wsman",port:a.port,rejectUnauthorized:false,checkServerIdentity:function(i){console.log("checkServerIdentity",JSON.stringify(i))}};var e=a.digest.request(f);e.on("error",function(i){a.gotNextMessagesError({status:600},"error",null,[d,c,g])});e.on("response",function(i){if(globalDebugFlags&1){console.log("Response: "+i.statusCode)}if(i.statusCode!=200){if(globalDebugFlags&1){console.log("ERR:"+JSON.stringify(i))}a.gotNextMessagesError({status:i.statusCode},"error",null,[d,c,g])}else{i.acc="";i.on("data",function(j){this.acc+=j});i.on("end",function(){a.gotNextMessages(i.acc,"success",{status:i.statusCode},[d,c,g])})}});e.end(d);a.ActiveAjaxCount++;return e};a.pendingAjaxCall=[];a.gotNextMessages=function(c,e,d,b){a.ActiveAjaxCount--;if(a.FailAllError==999){return}if(globalDebugFlags&1){console.log("RECV: "+c+"\r\n\r\n")}if(a.FailAllError!=0){b[1](null,a.FailAllError,b[2]);return}if(d.status!=200){b[1](null,d.status,b[2]);return}b[1](c,200,b[2]);a.PerformNextAjax()};a.gotNextMessagesError=function(d,e,c,b){a.ActiveAjaxCount--;if(a.FailAllError==999){return}if(a.FailAllError!=0){b[1](null,a.FailAllError,b[2]);return}if(a.FailAllError!=999){b[1]({Header:{HttpError:d.status}},d.status,b[2])}a.PerformNextAjax()};a.CancelAllQueries=function(b){while(a.PendingAjax.length>0){var c=a.PendingAjax.shift();c[1](null,b,c[2])}};return a}module.exports=CreateWsmanComm;
|
28
meshuser.js
@ -753,7 +753,7 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
|
||||
db.GetUserWithVerifiedEmail(domain.id, command.email, function (err, docs) {
|
||||
if (docs.length > 0) {
|
||||
// Notify the duplicate email error
|
||||
try { ws.send(JSON.stringify({ action: 'msg', type: 'notify', value: 'Failed to change email address, another account already using: <b>' + EscapeHtml(command.email) + '</b>.' })); } catch (ex) { }
|
||||
try { ws.send(JSON.stringify({ action: 'msg', type: 'notify', title: 'Account Settings', tag: 'ServerNotify', value: 'Failed to change email address, another account already using: <b>' + EscapeHtml(command.email) + '</b>.' })); } catch (ex) { }
|
||||
} else {
|
||||
// Update the user's email
|
||||
var oldemail = user.email;
|
||||
@ -857,8 +857,8 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
|
||||
}
|
||||
}
|
||||
|
||||
// Remove notes for this user
|
||||
db.Remove('nt' + deluser._id);
|
||||
db.Remove('ws' + deluser._id); // Remove user web state
|
||||
db.Remove('nt' + deluser._id); // Remove notes for this user
|
||||
|
||||
// Delete all files on the server for this account
|
||||
try {
|
||||
@ -883,7 +883,7 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
|
||||
if (common.validateString(command.msg, 1, 256) == false) break; // Notification message is between 1 and 256 characters
|
||||
|
||||
// Create the notification message
|
||||
var notification = { action: "msg", type: "notify", domain: domain.id, "value": command.msg };
|
||||
var notification = { action: "msg", type: "notify", domain: domain.id, "value": command.msg, "title": user.name, icon: 0, tag: "broadcast" };
|
||||
|
||||
// Send the notification on all user sessions for this server
|
||||
for (var i in parent.wssessions2) {
|
||||
@ -925,7 +925,7 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
|
||||
// Account count exceed, do notification
|
||||
|
||||
// Create the notification message
|
||||
var notification = { action: "msg", type: "notify", value: "Account limit reached.", userid: user._id, username: user.name, domain: domain.id };
|
||||
var notification = { action: "msg", type: "notify", value: "Account limit reached.", title: "Server Limit", userid: user._id, username: user.name, domain: domain.id };
|
||||
|
||||
// Get the list of sessions for this user
|
||||
var sessions = parent.wssessions[user._id];
|
||||
@ -1025,7 +1025,7 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
|
||||
require('./pass').hash(command.newpass, function (err, salt, hash) {
|
||||
if (err) {
|
||||
// Send user notification of error
|
||||
displayNotificationMessage('Error, password not changed.');
|
||||
displayNotificationMessage('Error, password not changed.', 'Account Settings', 'ServerNotify');
|
||||
} else {
|
||||
// Change the password
|
||||
if ((domain.passwordrequirements != null) && (domain.passwordrequirements.hint === true) && (command.hint != null)) {
|
||||
@ -1044,12 +1044,12 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
|
||||
parent.parent.DispatchEvent(targets, obj, { etype: 'user', username: user.name, account: parent.CloneSafeUser(user), action: 'accountchange', msg: 'Account password changed: ' + user.name, domain: domain.id });
|
||||
|
||||
// Send user notification of password change
|
||||
displayNotificationMessage('Password changed.');
|
||||
displayNotificationMessage('Password changed.', 'Account Settings', 'ServerNotify');
|
||||
}
|
||||
});
|
||||
} else {
|
||||
// Send user notification of error
|
||||
displayNotificationMessage('Current password not correct.');
|
||||
displayNotificationMessage('Current password not correct.', 'Account Settings', 'ServerNotify');
|
||||
}
|
||||
});
|
||||
break;
|
||||
@ -1112,7 +1112,7 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
|
||||
if ((user.groups != null) && (user.groups.length > 0) && ((chguser.groups == null) || (findOne(chguser.groups, user.groups) == false))) break;
|
||||
|
||||
// Create the notification message
|
||||
var notification = { "action": "msg", "type": "notify", "value": "<b>" + user.name + "</b>: " + EscapeHtml(command.msg), "userid": user._id, "username": user.name };
|
||||
var notification = { "action": "msg", "type": "notify", "value": command.msg, "title": user.name, "icon": 9, "userid": user._id, "username": user.name };
|
||||
|
||||
// Get the list of sessions for this user
|
||||
var sessions = parent.wssessions[command.userid];
|
||||
@ -1138,7 +1138,7 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
|
||||
|
||||
// Create the notification message
|
||||
var notification = {
|
||||
"action": "msg", "type": "notify", "value": "<b>" + user.name + "</b>: Chat Request, Click here to accept.", "userid": user._id, "username": user.name, "tag": 'meshmessenger/' + encodeURIComponent(command.userid) + '/' + encodeURIComponent(user._id)
|
||||
"action": "msg", "type": "notify", "value": "Chat Request, Click here to accept.", "title": user.name, "userid": user._id, "username": user.name, "tag": 'meshmessenger/' + encodeURIComponent(command.userid) + '/' + encodeURIComponent(user._id)
|
||||
};
|
||||
|
||||
// Get the list of sessions for this user
|
||||
@ -2297,6 +2297,12 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
|
||||
});
|
||||
break;
|
||||
}
|
||||
case 'userWebState': {
|
||||
if (common.validateString(command.state, 1, 10000) == false) break; // Check state size, no more than 10k
|
||||
db.Set({ _id: 'ws' + user._id, state: command.state });
|
||||
parent.parent.DispatchEvent([user._id], obj, { action: 'userWebState', nolog: 1, domain: domain.id, state: command.state });
|
||||
break;
|
||||
}
|
||||
case 'getNotes':
|
||||
{
|
||||
// Argument validation
|
||||
@ -2363,7 +2369,7 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
|
||||
}
|
||||
|
||||
// Display a notification message for this session only.
|
||||
function displayNotificationMessage(msg, tag) { ws.send(JSON.stringify({ "action": "msg", "type": "notify", "value": msg, "userid": user._id, "username": user.name, "tag": tag })); }
|
||||
function displayNotificationMessage(msg, title, tag) { ws.send(JSON.stringify({ "action": "msg", "type": "notify", "value": msg, "title": title, "userid": user._id, "username": user.name, "tag": tag })); }
|
||||
|
||||
// Read the folder and all sub-folders and serialize that into json.
|
||||
function readFilesRec(path) {
|
||||
|
BIN
public/images/notify/icons128-0.png
Normal file
After Width: | Height: | Size: 5.7 KiB |
BIN
public/images/notify/icons128-1.png
Normal file
After Width: | Height: | Size: 5.8 KiB |
BIN
public/images/notify/icons128-2.png
Normal file
After Width: | Height: | Size: 6.4 KiB |
BIN
public/images/notify/icons128-3.png
Normal file
After Width: | Height: | Size: 6.5 KiB |
BIN
public/images/notify/icons128-4.png
Normal file
After Width: | Height: | Size: 4.6 KiB |
BIN
public/images/notify/icons128-5.png
Normal file
After Width: | Height: | Size: 4.7 KiB |
BIN
public/images/notify/icons128-6.png
Normal file
After Width: | Height: | Size: 8.1 KiB |
BIN
public/images/notify/icons128-7.png
Normal file
After Width: | Height: | Size: 6.9 KiB |
BIN
public/images/notify/icons128-8.png
Normal file
After Width: | Height: | Size: 4.5 KiB |
BIN
public/images/servericon120.png
Normal file
After Width: | Height: | Size: 16 KiB |
BIN
public/images/servericon64.png
Normal file
After Width: | Height: | Size: 5.4 KiB |
@ -1008,7 +1008,7 @@ NoMeshesPanel img {
|
||||
width: 250px;
|
||||
}
|
||||
|
||||
#p12warning, #p12warning2, #p14warning, #p14warning2 {
|
||||
#p12warning, #p12warning2, #p11warning, #p11warning2 {
|
||||
max-width: 100%;
|
||||
display: none;
|
||||
cursor: pointer;
|
||||
|
@ -257,6 +257,7 @@
|
||||
<p><strong>Account actions</strong></p>
|
||||
<p class="mL">
|
||||
<span id="verifyEmailId" style="display:none"><a onclick="account_showVerifyEmail()">Verify email</a><br /></span>
|
||||
<span id="accountEnableNotificationsSpan" style="display:none"><a onclick="account_enableNotifications()">Enable web notifications</a><br /></span>
|
||||
<a onclick="account_showChangeEmail()">Change email address</a><br />
|
||||
<a onclick="account_showChangePassword()">Change password</a><span id="p2nextPasswordUpdateTime"></span><br />
|
||||
<a onclick="account_showDeleteAccount()">Delete account</a><br />
|
||||
@ -415,19 +416,18 @@
|
||||
<h1>Desktop - <span id=p11deviceName></span></h1>
|
||||
</div>
|
||||
</div>
|
||||
<div id="p14warning" onclick="showFeaturesDlg()">
|
||||
<div id="p11warning" onclick="showFeaturesDlg()">
|
||||
<div class="icon2"></div>
|
||||
<div class="warningbox">Intel® AMT Redirection port or KVM feature is disabled<span id="p14warninga">, click here to enable it.</span></div>
|
||||
<div class="warningbox">Intel® AMT Redirection port or KVM feature is disabled<span id="p11warninga">, click here to enable it.</span></div>
|
||||
</div>
|
||||
<div id="p14warning2" onclick="showPowerActionDlg()">
|
||||
<div id="p11warning2" onclick="showPowerActionDlg()">
|
||||
<div class="icon2"></div>
|
||||
<div class="warningbox">Remote computer is not powered on, click here to issue a power command.</div>
|
||||
</div>
|
||||
|
||||
<div id=deskarea0 cellpadding=0 cellspacing=0>
|
||||
<div id=deskarea1 class="areaHead">
|
||||
<div class="toright2">
|
||||
<span id="p14power"></span>
|
||||
<span id="p11power"></span>
|
||||
<div class='deskareaicon' title="Toggle View Mode" onclick="toggleAspectRatio(1)">⇲</div>
|
||||
<div class='deskareaicon' title="Rotate Left" onclick="drotate(-1)">↺</div>
|
||||
<div class='deskareaicon' title="Rotate Right" onclick="drotate(1)">↻</div>
|
||||
@ -498,7 +498,7 @@
|
||||
</div>
|
||||
<div id="p12warning" onclick=showFeaturesDlg()>
|
||||
<div class="icon2"></div>
|
||||
<div class="warningbox">Intel® AMT Redirection port or KVM feature is disabled<span id="p14warninga">, click here to enable it.</span></div>
|
||||
<div class="warningbox">Intel® AMT Redirection port or KVM feature is disabled<span id="p12warninga">, click here to enable it.</span></div>
|
||||
</div>
|
||||
<div id="p12warning2" onclick=showPowerActionDlg()>
|
||||
<div class="icon2"></div>
|
||||
@ -871,6 +871,13 @@
|
||||
</div>
|
||||
<script type="text/javascript">
|
||||
'use strict';
|
||||
|
||||
// Process server-side web state
|
||||
var webState = "{{{webstate}}}";
|
||||
if (webState != "") { webState = JSON.parse(decodeURIComponent(webState)); }
|
||||
for (var i in webState) { localStorage.setItem(i, webState[i]); }
|
||||
//localStorage.clear();
|
||||
|
||||
var args;
|
||||
var autoReconnect = true;
|
||||
var powerStatetable = ['', 'Powered', 'Sleep', 'Sleep', 'Sleep', 'Hibernating', 'Power off', 'Present'];
|
||||
@ -985,11 +992,11 @@
|
||||
|
||||
// Setup page controls
|
||||
Q('sortselect').selectedIndex = sort = getstore("sort", 0);
|
||||
Q('sizeselect').selectedIndex = getstore("viewsize", 1);
|
||||
Q('SearchInput').value = getstore("search", "");
|
||||
Q('sizeselect').selectedIndex = getstore("_viewsize", 1);
|
||||
Q('SearchInput').value = getstore("_search", "");
|
||||
showRealNames = (getstore("showRealNames", 0) == 1);
|
||||
Q('RealNameCheckBox').checked = showRealNames;
|
||||
Q('viewselect').value = getstore("deviceView", 1);
|
||||
Q('viewselect').value = getstore("_deviceView", 1);
|
||||
Q('DeskControl').checked = (getstore('DeskControl', 1) == 1);
|
||||
|
||||
// Display the page devices
|
||||
@ -1198,7 +1205,7 @@
|
||||
updateNaggleTimer = setTimeout(function () {
|
||||
if (updateNaggleFlags & 512) { center(); }
|
||||
if (updateNaggleFlags & 1) { onSearchInputChanged(); }
|
||||
if (updateNaggleFlags & 2) { onSortSelectChange(true); }
|
||||
if (updateNaggleFlags & 2) { onSortSelectChange(false); }
|
||||
if (updateNaggleFlags & 128) { updateMeshes(); }
|
||||
if (updateNaggleFlags & 4) { updateDevices(); }
|
||||
if (updateNaggleFlags & 8) { drawNotifications(); }
|
||||
@ -1345,7 +1352,7 @@
|
||||
// Node was found, dispatch the message
|
||||
if (message.type == 'console') { p15consoleReceive(nodes[index], message.value); } // This is a console message.
|
||||
else if (message.type == 'notify') { // This is a notification message.
|
||||
var n = { text:message.value };
|
||||
var n = { text: message.value, title: message.title, icon: message.icon };
|
||||
if (message.nodeid != null) { n.nodeid = message.nodeid; }
|
||||
if (message.tag != null) { n.tag = message.tag; }
|
||||
if (message.username != null) { n.username = message.username; }
|
||||
@ -1362,7 +1369,7 @@
|
||||
}
|
||||
} else {
|
||||
if (message.type == 'notify') { // This is a notification message.
|
||||
var n = { text:message.value };
|
||||
var n = { text: message.value, title: message.title, icon: message.icon };
|
||||
if (message.tag != null) { n.tag = message.tag; }
|
||||
if (message.username != null) { n.username = message.username; }
|
||||
addNotification(n);
|
||||
@ -1606,6 +1613,24 @@
|
||||
masterUpdate(32);
|
||||
}
|
||||
switch (message.event.action) {
|
||||
case 'userWebState': {
|
||||
// New user web state, update the web page as needed
|
||||
if (localStorage != null) {
|
||||
var oldShowRealNames = localStorage.getItem('showRealNames');
|
||||
var oldUiMode = localStorage.getItem('uiMode');
|
||||
var oldSort = localStorage.getItem('sort');
|
||||
|
||||
var webstate = JSON.parse(message.event.state);
|
||||
for (var i in webstate) { localStorage.setItem(i, webstate[i]); }
|
||||
|
||||
// Update the web page
|
||||
if ((webstate.deskAspectRatio != null) && (webstate.deskAspectRatio != deskAspectRatio)) { deskAspectRatio = webstate.deskAspectRatio; deskAdjust(); }
|
||||
if ((webstate.showRealNames != null) && (webstate.showRealNames != oldShowRealNames)) { showRealNames = Q('RealNameCheckBox').checked = (webstate.showRealNames == "1"); masterUpdate(6); }
|
||||
if ((webstate.uiMode != null) && (webstate.uiMode != oldUiMode)) { userInterfaceSelectMenu(parseInt(webstate.uiMode)); }
|
||||
if ((webstate.sort != null) && (webstate.sort != oldSort)) { document.getElementById("sortselect").selectedIndex = sort = parseInt(webstate.sort); masterUpdate(6); }
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 'servertimelinestats': { addServerTimelineStats(message.event.data); break; }
|
||||
case 'accountcreate':
|
||||
case 'accountchange': {
|
||||
@ -1904,7 +1929,7 @@
|
||||
break;
|
||||
}
|
||||
case 'notify': {
|
||||
var n = { text: message.event.value };
|
||||
var n = { text: message.event.value, title: message.event.title, icon: message.event.icon };
|
||||
if (message.event.tag != null) { n.tag = message.event.tag; }
|
||||
addNotification(n);
|
||||
break;
|
||||
@ -1939,7 +1964,7 @@
|
||||
function onRealNameCheckBox() {
|
||||
showRealNames = Q('RealNameCheckBox').checked;
|
||||
putstore("showRealNames", showRealNames ? 1 : 0);
|
||||
masterUpdate(6)
|
||||
masterUpdate(6);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -1947,8 +1972,8 @@
|
||||
if (i != null) { Q('viewselect').value = i; }
|
||||
for (var j = 1; j < 5; j++) { Q('devViewButton' + j).classList.remove('viewSelectorSel'); }
|
||||
Q('devViewButton' + Q('viewselect').value).classList.add('viewSelectorSel');
|
||||
putstore("deviceView", Q('viewselect').value);
|
||||
putstore("viewsize", Q('sizeselect').value);
|
||||
putstore("_deviceView", Q('viewselect').value);
|
||||
putstore("_viewsize", Q('sizeselect').value);
|
||||
masterUpdate(4);
|
||||
setTimeout("masterUpdate(512)", 200);
|
||||
}
|
||||
@ -2873,7 +2898,7 @@
|
||||
function onConsoleFocus(x) { consoleFocus = x; }
|
||||
|
||||
function onSearchInputChanged() {
|
||||
var x = Q('SearchInput').value.toLowerCase().trim(); putstore("search", x);
|
||||
var x = Q('SearchInput').value.toLowerCase().trim(); putstore("_search", x);
|
||||
var userSearch = null, ipSearch = null, groupSearch = null;
|
||||
if (x.startsWith('user:')) { userSearch = x.substring(5); }
|
||||
else if (x.startsWith('u:')) { userSearch = x.substring(2); }
|
||||
@ -3617,7 +3642,6 @@
|
||||
var powerTimeline = null;
|
||||
function getCurrentNode() { return currentNode; };
|
||||
function gotoDevice(nodeid, panel, refresh, event) {
|
||||
|
||||
// Remind the user to verify the email address
|
||||
if ((userinfo.emailVerified !== true) && (serverinfo.emailcheck == true) && (userinfo.siteadmin != 0xFFFFFFFF)) { setDialogMode(2, "Account Security", 1, null, "Unable to access a device until a email address is verified. This is required for password recovery. Go to the \"My Account\" tab to change and verify an email address."); return; }
|
||||
|
||||
@ -5760,6 +5784,10 @@
|
||||
meshserver.send({ action: 'otp-hkey-get' });
|
||||
}
|
||||
|
||||
function account_enableNotifications() {
|
||||
if (Notification) { Notification.requestPermission().then(function (permission) { QV('accountEnableNotificationsSpan', permission != "granted"); }); }
|
||||
}
|
||||
|
||||
function account_showVerifyEmail() {
|
||||
if (xxdialogMode || (userinfo.emailVerified == true) || (serverinfo.emailcheck != true)) return;
|
||||
var x = "Click ok to send a verification mail to:<br /><div style=padding:8px><b>" + EscapeHtml(userinfo.email) + "</b></div>Please wait a few minute to receive the verification.";
|
||||
@ -7328,20 +7356,21 @@
|
||||
function notificationSelected(id) {
|
||||
var j = -1;
|
||||
for (var i in notifications) { if (notifications[i].id == id) { j = i; } }
|
||||
if (j != -1) {
|
||||
var n = notifications[j];
|
||||
if (n.nodeid != null) {
|
||||
if (n.tag == 'desktop') gotoDevice(n.nodeid, 12); // Desktop
|
||||
else if (n.tag == 'terminal') gotoDevice(n.nodeid, 11); // Terminal
|
||||
else if (n.tag == 'files') gotoDevice(n.nodeid, 13); // Files
|
||||
else if (n.tag == 'intelamt') gotoDevice(n.nodeid, 14); // Intel AMT
|
||||
else if (n.tag == 'console') gotoDevice(n.nodeid, 15); // Files
|
||||
else gotoDevice(n.nodeid, 10); // General
|
||||
} else {
|
||||
if (n.tag.startsWith('meshmessenger/')) {
|
||||
window.open('/messenger?id=' + n.tag + '&title=' + encodeURIComponent(n.username), n.tag.split('/')[2]);
|
||||
notificationDelete(id);
|
||||
}
|
||||
if (j != -1) { notificationSelectedEx(notifications[j], id); }
|
||||
}
|
||||
|
||||
function notificationSelectedEx(n, id) {
|
||||
if (n.nodeid != null) {
|
||||
if (n.tag == 'desktop') gotoDevice(n.nodeid, 12); // Desktop
|
||||
else if (n.tag == 'terminal') gotoDevice(n.nodeid, 11); // Terminal
|
||||
else if (n.tag == 'files') gotoDevice(n.nodeid, 13); // Files
|
||||
else if (n.tag == 'intelamt') gotoDevice(n.nodeid, 14); // Intel AMT
|
||||
else if (n.tag == 'console') gotoDevice(n.nodeid, 15); // Files
|
||||
else gotoDevice(n.nodeid, 10); // General
|
||||
} else {
|
||||
if (n.tag.startsWith('meshmessenger/')) {
|
||||
window.open('/messenger?id=' + n.tag + '&title=' + encodeURIComponent(n.username), n.tag.split('/')[2]);
|
||||
notificationDelete(id);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -7367,12 +7396,29 @@
|
||||
|
||||
// Add a new notification and play the notification sound
|
||||
function addNotification(n) {
|
||||
if (n.time == null) { n.time = Date.now(); }
|
||||
if (n.id == null) { n.id = Math.random(); }
|
||||
notifications.unshift(n);
|
||||
setNotificationCount(notifications.length);
|
||||
Q('chimes').play();
|
||||
clickNotificationIcon(true);
|
||||
// If web notifications are granted, use it.
|
||||
if (Notification && (Notification.permission == "granted")) {
|
||||
var notification;
|
||||
if (n.nodeid) {
|
||||
var node = getNodeFromId(n.nodeid);
|
||||
if (node) { notification = new Notification("{{{title}}} - " + node.name, { tag: n.tag, body: n.text, icon: '/images/notify/icons128-' + node.icon + '.png' }); }
|
||||
} else {
|
||||
if (n.icon == null) { n.icon = 0; }
|
||||
notification = new Notification("{{{title}}} - " + n.title, { tag: n.tag, body: n.text, icon: '/images/notify/icons128-' + n.icon + '.png' });
|
||||
}
|
||||
notification.xtag = n.tag;
|
||||
notification.nodeid = n.nodeid;
|
||||
notification.username = n.username;
|
||||
notification.onclick = function (e) { notificationSelectedEx(e.target); }
|
||||
Q('chimes').play();
|
||||
} else {
|
||||
if (n.time == null) { n.time = Date.now(); }
|
||||
if (n.id == null) { n.id = Math.random(); }
|
||||
notifications.unshift(n);
|
||||
setNotificationCount(notifications.length);
|
||||
Q('chimes').play();
|
||||
clickNotificationIcon(true);
|
||||
}
|
||||
}
|
||||
|
||||
// Remove all notifications
|
||||
@ -7688,6 +7734,9 @@
|
||||
QC(panels[i]).add((x == i) ? 'style3sel' : 'style3x');
|
||||
}
|
||||
|
||||
// If going to the remote desktop tab, adjust the tab.
|
||||
if (x == 11) { deskAdjust(); }
|
||||
|
||||
// Panel 115 is weird, it's panel 15 for device console but used as a server console.
|
||||
if (x == 115) { QV('p15', true); }
|
||||
QV('p15uploadCore', x != 115);
|
||||
@ -7696,6 +7745,9 @@
|
||||
|
||||
if (x == 1) masterUpdate(4);
|
||||
|
||||
// Setup web notifications
|
||||
if ((x == 2) && Notification) { QV('accountEnableNotificationsSpan', Notification.permission != 'granted'); }
|
||||
|
||||
// Fetch the server timeline stats if needed
|
||||
if ((x == 40) && (serverTimelineStats == null)) { refreshServerTimelineStats(); }
|
||||
|
||||
@ -7705,7 +7757,7 @@
|
||||
|
||||
// Generic methods
|
||||
function joinPaths() { var x = []; for (var i in arguments) { var w = arguments[i]; if ((w != null) && (w != '')) { while (w.endsWith('/') || w.endsWith('\\')) { w = w.substring(0, w.length - 1); } while (w.startsWith('/') || w.startsWith('\\')) { w = w.substring(1); } x.push(w); } } return x.join('/'); }
|
||||
function putstore(name, val) { try { if (typeof (localStorage) === 'undefined') return; localStorage.setItem(name, val); } catch (e) { } }
|
||||
function putstore(name, val) { try { if ((typeof (localStorage) === 'undefined') || (localStorage.getItem(name) == val)) return; localStorage.setItem(name, val); } catch (e) { } if (name[0] != '_') { var s = {}; for (var i = 0, len = localStorage.length; i < len; ++i) { var k = localStorage.key(i); if (k[0] != '_') { s[k] = localStorage.getItem(k); } } meshserver.send({ action: 'userWebState', state: JSON.stringify(s) }); } }
|
||||
function getstore(name, val) { try { if (typeof (localStorage) === 'undefined') return val; var v = localStorage.getItem(name); if ((v == null) || (v == null)) return val; return v; } catch (e) { return val; } }
|
||||
//function addLink(x, f) { return "<a style=cursor:pointer;color:darkblue;text-decoration:none onclick='" + f + "'>♦ " + x + "</a>"; }
|
||||
function addLink(x, f) { return "<span style=cursor:pointer;text-decoration:none onclick='" + f + "'>" + x + " <img class=hoverButton src=images/link5.png></span>"; }
|
||||
|
26
webserver.js
@ -1292,18 +1292,22 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
|
||||
if ((!obj.args.user) && (obj.args.nousers != true) && (nologout == false)) { logoutcontrol += ' <a href=' + domain.url + 'logout?' + Math.random() + ' style=color:white>Logout</a>'; } // If a default user is in use or no user mode, don't display the logout button
|
||||
var httpsPort = ((obj.args.aliasport == null) ? obj.args.port : obj.args.aliasport); // Use HTTPS alias port is specified
|
||||
|
||||
if (obj.args.minify && !req.query.nominify) {
|
||||
// Try to server the minified version if we can.
|
||||
try {
|
||||
res.render(obj.path.join(obj.parent.webViewsPath, isMobileBrowser(req) ? 'default-mobile-min' : 'default-min'), { authCookie: authCookie, viewmode: viewmode, currentNode: currentNode, logoutControl: logoutcontrol, title: domain.title, title2: domain.title2, extitle: encodeURIComponent(domain.title), extitle2: encodeURIComponent(domain.title2), domainurl: domain.url, domain: domain.id, debuglevel: parent.debugLevel, serverDnsName: obj.getWebServerName(domain), serverRedirPort: args.redirport, serverPublicPort: httpsPort, noServerBackup: (args.noserverbackup == 1 ? 1 : 0), features: features, sessiontime: args.sessiontime, mpspass: args.mpspass, passRequirements: passRequirements, webcerthash: Buffer.from(obj.webCertificateFullHashs[domain.id], 'binary').toString('base64').replace(/\+/g, '@').replace(/\//g, '$'), footer: (domain.footer == null) ? '' : domain.footer });
|
||||
} catch (ex) {
|
||||
// In case of an exception, serve the non-minified version.
|
||||
res.render(obj.path.join(obj.parent.webViewsPath, isMobileBrowser(req) ? 'default-mobile' : 'default'), { authCookie: authCookie, viewmode: viewmode, currentNode: currentNode, logoutControl: logoutcontrol, title: domain.title, title2: domain.title2, extitle: encodeURIComponent(domain.title), extitle2: encodeURIComponent(domain.title2), domainurl: domain.url, domain: domain.id, debuglevel: parent.debugLevel, serverDnsName: obj.getWebServerName(domain), serverRedirPort: args.redirport, serverPublicPort: httpsPort, noServerBackup: (args.noserverbackup == 1 ? 1 : 0), features: features, sessiontime: args.sessiontime, mpspass: args.mpspass, passRequirements: passRequirements, webcerthash: Buffer.from(obj.webCertificateFullHashs[domain.id], 'binary').toString('base64').replace(/\+/g, '@').replace(/\//g, '$'), footer: (domain.footer == null) ? '' : domain.footer });
|
||||
// Fetch the web state
|
||||
obj.db.Get('ws' + user._id, function (err, states) {
|
||||
var webstate = (states.length == 1) ? states[0].state : '';
|
||||
if (obj.args.minify && !req.query.nominify) {
|
||||
// Try to server the minified version if we can.
|
||||
try {
|
||||
res.render(obj.path.join(obj.parent.webViewsPath, isMobileBrowser(req) ? 'default-mobile-min' : 'default-min'), { authCookie: authCookie, viewmode: viewmode, currentNode: currentNode, logoutControl: logoutcontrol, title: domain.title, title2: domain.title2, extitle: encodeURIComponent(domain.title), extitle2: encodeURIComponent(domain.title2), domainurl: domain.url, domain: domain.id, debuglevel: parent.debugLevel, serverDnsName: obj.getWebServerName(domain), serverRedirPort: args.redirport, serverPublicPort: httpsPort, noServerBackup: (args.noserverbackup == 1 ? 1 : 0), features: features, sessiontime: args.sessiontime, mpspass: args.mpspass, passRequirements: passRequirements, webcerthash: Buffer.from(obj.webCertificateFullHashs[domain.id], 'binary').toString('base64').replace(/\+/g, '@').replace(/\//g, '$'), footer: (domain.footer == null) ? '' : domain.footer, webstate: encodeURIComponent(webstate) });
|
||||
} catch (ex) {
|
||||
// In case of an exception, serve the non-minified version.
|
||||
res.render(obj.path.join(obj.parent.webViewsPath, isMobileBrowser(req) ? 'default-mobile' : 'default'), { authCookie: authCookie, viewmode: viewmode, currentNode: currentNode, logoutControl: logoutcontrol, title: domain.title, title2: domain.title2, extitle: encodeURIComponent(domain.title), extitle2: encodeURIComponent(domain.title2), domainurl: domain.url, domain: domain.id, debuglevel: parent.debugLevel, serverDnsName: obj.getWebServerName(domain), serverRedirPort: args.redirport, serverPublicPort: httpsPort, noServerBackup: (args.noserverbackup == 1 ? 1 : 0), features: features, sessiontime: args.sessiontime, mpspass: args.mpspass, passRequirements: passRequirements, webcerthash: Buffer.from(obj.webCertificateFullHashs[domain.id], 'binary').toString('base64').replace(/\+/g, '@').replace(/\//g, '$'), footer: (domain.footer == null) ? '' : domain.footer, webstate: encodeURIComponent(webstate) });
|
||||
}
|
||||
} else {
|
||||
// Serve non-minified version of web pages.
|
||||
res.render(obj.path.join(obj.parent.webViewsPath, isMobileBrowser(req) ? 'default-mobile' : 'default'), { authCookie: authCookie, viewmode: viewmode, currentNode: currentNode, logoutControl: logoutcontrol, title: domain.title, title2: domain.title2, extitle: encodeURIComponent(domain.title), extitle2: encodeURIComponent(domain.title2), domainurl: domain.url, domain: domain.id, debuglevel: parent.debugLevel, serverDnsName: obj.getWebServerName(domain), serverRedirPort: args.redirport, serverPublicPort: httpsPort, noServerBackup: (args.noserverbackup == 1 ? 1 : 0), features: features, sessiontime: args.sessiontime, mpspass: args.mpspass, passRequirements: passRequirements, webcerthash: Buffer.from(obj.webCertificateFullHashs[domain.id], 'binary').toString('base64').replace(/\+/g, '@').replace(/\//g, '$'), footer: (domain.footer == null) ? '' : domain.footer, webstate: encodeURIComponent(webstate) });
|
||||
}
|
||||
} else {
|
||||
// Serve non-minified version of web pages.
|
||||
res.render(obj.path.join(obj.parent.webViewsPath, isMobileBrowser(req) ? 'default-mobile' : 'default'), { authCookie: authCookie, viewmode: viewmode, currentNode: currentNode, logoutControl: logoutcontrol, title: domain.title, title2: domain.title2, extitle: encodeURIComponent(domain.title), extitle2: encodeURIComponent(domain.title2), domainurl: domain.url, domain: domain.id, debuglevel: parent.debugLevel, serverDnsName: obj.getWebServerName(domain), serverRedirPort: args.redirport, serverPublicPort: httpsPort, noServerBackup: (args.noserverbackup == 1 ? 1 : 0), features: features, sessiontime: args.sessiontime, mpspass: args.mpspass, passRequirements: passRequirements, webcerthash: Buffer.from(obj.webCertificateFullHashs[domain.id], 'binary').toString('base64').replace(/\+/g, '@').replace(/\//g, '$'), footer: (domain.footer == null) ? '' : domain.footer });
|
||||
}
|
||||
});
|
||||
} else {
|
||||
// Send back the login application
|
||||
// If this is a 2 factor auth request, look for a hardware key challenge.
|
||||
|