More work on login tokens.

Ylian Saint-Hilaire committed Apr 15, 2021 at 20:51 UTC 0f99e9bf380b801f064be35ca61dde3edef13595
2 files changed +56 -13
meshuser.js
+9 -5
@@ -4961,7 +4961,7 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
4961 const doc = docs[i];
4962 if (doc.expireTime < now) {
4963 // This share is expired.
4964 - parent.db.Remove(doc._id, function () { }); delete docs[i]; removed = true;
4964 + parent.db.Remove(doc._id, function () { }); removed = true;
4965 } else {
4966 // This share is ok, remove extra data we don't need to send.
4967 delete doc._id; delete doc.domain; delete doc.nodeid; delete doc.type;
@@ -5611,14 +5611,19 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
5611 break;
5612 }
5613 case 'loginTokens': { // Respond with the list of currently valid login tokens
5614 + if ((typeof domain.passwordrequirements != 'object') && (domain.passwordrequirements.logintokens == false)) break; // Login tokens are not supported on this server
5615 +
5616 + // If remove is an array or strings, we are going to be removing these and returning the results.
5617 + if (common.validateStrArray(command.remove, 1) == false) { delete command.remove; }
5618 +
5619 parent.db.GetAllTypeNodeFiltered(['logintoken-' + user._id], domain.id, 'logintoken', null, function (err, docs) {
5620 if (err != null) return;
5621 var now = Date.now(), removed = 0, okDocs = [];
5622 for (var i = 0; i < docs.length; i++) {
5623 const doc = docs[i];
5619 - if (doc.expireTime < now) {
5624 + if (((doc.expire != 0) && (doc.expire < now)) || (doc.tokenUser == null) || ((command.remove != null) && (command.remove.indexOf(doc.tokenUser) >= 0))) {
5625 // This share is expired.
5621 - parent.db.Remove(doc._id, function () { }); delete docs[i]; removed++;
5626 + parent.db.Remove(doc._id, function () { }); removed++;
5627 } else {
5628 // This share is ok, remove extra data we don't need to send.
5629 delete doc._id; delete doc.domain; delete doc.nodeid; delete doc.type; delete doc.userid; delete doc.salt; delete doc.hash;
@@ -5668,10 +5673,9 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
5673 // Dispatch the new event
5674 var targets = ['*', 'server-users', user._id];
5675 if (user.groups) { for (var i in user.groups) { targets.push('server-users:' + i); } }
5671 - var event = { etype: 'user', userid: user._id, username: user.name, action: 'loginTokenAdded', msgid: 115, msg: "Added login token", domain: domain.id };
5676 + var event = { etype: 'user', userid: user._id, username: user.name, action: 'loginTokenAdded', msgid: 115, msg: "Added login token", domain: domain.id, newToken: { name: command.name, tokenUser: tokenUser, created: created, expire: expire } };
5677 parent.parent.DispatchEvent(targets, obj, event);
5678 });
5674 -
5679 break;
5680 }
5681 case 'getDeviceDetails': {
views/default.handlebars
+47 -8
@@ -385,8 +385,9 @@
385 </p>
386 <br style=clear:both />
387 </div>
388 + <div id=p2logintokens></div>
389 <strong>Device Groups</strong>
389 - <span id="p2createMeshLink1">( <a href=# onclick="return account_createMesh()" class="newMeshBtn"> New</a> )</span>
390 + <span id="p2createMeshLink1"> - <a href=# onclick="return account_createMesh()" class="newMeshBtn"> New</a></span>
391 <br /><br />
392 <div id=p2meshes></div>
393 <div id=p2noMeshFound style="display:none">No device groups.<span id="p2createMeshLink2"> <a href=# onclick="return account_createMesh()"><strong>Get started here!</strong></a></span></div>
@@ -2004,6 +2005,7 @@
2005 if (updateNaggleFlags & 8192) { updateUserGroups(); }
2006 if (updateNaggleFlags & 16384) { updateUsers(); }
2007 if (updateNaggleFlags & 32768) { updateRecordings(); }
2008 + if (updateNaggleFlags & 65536) { updateLoginTokens(); }
2009 updateNaggleTimer = null;
2010 updateNaggleFlags = 0;
2011 gotoStartViewPage();
@@ -3169,11 +3171,17 @@
3171 if ((Q('DevFilterSelect').value == 2) || (Q('DevFilterSelect').value == 6)) { mainUpdate(1); }
3172 break;
3173 }
3172 - case 'loginTokenChanged': {
3174 + case 'loginTokenChanged': { // Login tokens have changed
3175 if (message.event.userid != userinfo._id) return;
3176 loginTokens = message.event.loginTokens;
3175 - // TODO: Update
3176 - console.log('t1', loginTokens);
3177 + mainUpdate(65536);
3178 + break;
3179 + }
3180 + case 'loginTokenAdded': { // A login token was added
3181 + if (message.event.userid != userinfo._id) return;
3182 + if (loginTokens == null) { loginTokens = []; }
3183 + loginTokens.push(message.event.newToken);
3184 + mainUpdate(65536);
3185 break;
3186 }
3187 case 'stopped': { // Server is stopping.
@@ -3342,7 +3350,7 @@
3350 saveAs(new Blob([message.data], { type: 'application/octet-stream' }), "devicelist" + '.' + message.type);
3351 break;
3352 }
3345 - case 'createLoginToken': {
3353 + case 'createLoginToken': { // A new login token was created
3354 if (xxdialogMode) return;
3355 var x = "Take note of this username and password, the password cannot be shown again." + '<br /><br />';
3356 x += addHtmlValue("Name", EscapeHtml(message.name))
@@ -3352,10 +3360,9 @@
3360 setDialogMode(2, "Create Login Token", 1, null, x);
3361 break;
3362 }
3355 - case 'loginTokens': {
3363 + case 'loginTokens': { // Reveiced the list of login tokens
3364 loginTokens = message.loginTokens;
3357 - // TODO: Update
3358 - console.log('t2', loginTokens);
3365 + mainUpdate(65536);
3366 break;
3367 }
3368 default:
@@ -10437,6 +10444,38 @@
10444 QV('p2noMeshFound', count == 0);
10445 }
10446
10447 +
10448 + function updateLoginTokens() {
10449 + var x = '', count = 1;
10450 + if ((loginTokens != null) && (loginTokens.length > 0)) {
10451 + x += '<p><strong>' + "Active Login Tokens" + '</strong> - <span id="p2createMeshLink1"> <a href=# onclick="return account_createLoginToken()" class="newMeshBtn"> ' + "New" + '</a></span></p><div style=margin-left:40px><table style="color:black;background-color:#EEE;border-color:#AAA;border-width:1px;border-style:solid;border-collapse:collapse" border=0 cellpadding=2 cellspacing=0 width=100%><tbody><tr style=background-color:#AAAAAA;font-weight:bold><th scope=col style=text-align:left;width:430px>' + "Name" + '</th><th scope=col style=text-align:left>' + "Username" + '</th></tr>';
10452 + for (var i = 0; i < loginTokens.length; i++) {
10453 + var ltoken = loginTokens[i];
10454 + var trash = '<a href=# onclick=\'return p2removeLoginToken(event,"' + encodeURIComponentEx(ltoken.tokenUser) + '")\' title="' + "Remove login token" + '" style=cursor:pointer><img src=images/trash.png border=0 height=10 width=10></a>';
10455 + var details = '';
10456 + if (ltoken.expire != 0) { details = EscapeHtml(format("Expires {0}", printDateTime(new Date(ltoken.expire)))) + ' '; }
10457 + x += '<tr ' + (((++count % 2) == 0) ? 'style=background-color:#DDD' : '') + '><td style=width:30%><div class=m' + 2 + '></div><div>&nbsp;' + EscapeHtml(ltoken.name) + '<div></div></div></td><td style=width:70%><div style=float:right>' + details + trash + '</div><div>' + EscapeHtml(ltoken.tokenUser) + '</div></td></tr>';
10458 + }
10459 + x += '</tbody></table></div><br />';
10460 + QV('accountCreateLoginTokenSpan', false);
10461 + } else {
10462 + QV('accountCreateLoginTokenSpan', features2 & 0x00000080);
10463 + }
10464 + QH('p2logintokens', x);
10465 + }
10466 +
10467 + function p2removeLoginToken(e, tokenUser) {
10468 + tokenUser = decodeURIComponent(tokenUser);
10469 + if (loginTokens == null) return;
10470 + var token = null;
10471 + for (var i = 0; i < loginTokens.length; i++) { if (loginTokens[i].tokenUser == tokenUser) { token = loginTokens[i]; } }
10472 + if (token == null) return;
10473 + var x = "Confirm removal of this login token?" + '<br /><br />';
10474 + x += addHtmlValue("Name", EscapeHtml(token.name));
10475 + x += addHtmlValue("Username", EscapeHtml(token.tokenUser));
10476 + setDialogMode(2, "Remove Login Token", 3, function(b, tokenUser) { meshserver.send({ action: 'loginTokens', remove: [ tokenUser ] }); }, x, tokenUser);
10477 + }
10478 +
10479 function gotoMesh(meshid) {
10480 currentMesh = meshes[meshid];
10481 p20updateMesh();