diff --git a/meshuser.js b/meshuser.js
index 367a6b40..d55a9412 100644
--- a/meshuser.js
+++ b/meshuser.js
@@ -4961,7 +4961,7 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
const doc = docs[i];
if (doc.expireTime < now) {
// This share is expired.
- parent.db.Remove(doc._id, function () { }); delete docs[i]; removed = true;
+ parent.db.Remove(doc._id, function () { }); removed = true;
} else {
// This share is ok, remove extra data we don't need to send.
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
break;
}
case 'loginTokens': { // Respond with the list of currently valid login tokens
+ if ((typeof domain.passwordrequirements != 'object') && (domain.passwordrequirements.logintokens == false)) break; // Login tokens are not supported on this server
+
+ // If remove is an array or strings, we are going to be removing these and returning the results.
+ if (common.validateStrArray(command.remove, 1) == false) { delete command.remove; }
+
parent.db.GetAllTypeNodeFiltered(['logintoken-' + user._id], domain.id, 'logintoken', null, function (err, docs) {
if (err != null) return;
var now = Date.now(), removed = 0, okDocs = [];
for (var i = 0; i < docs.length; i++) {
const doc = docs[i];
- if (doc.expireTime < now) {
+ if (((doc.expire != 0) && (doc.expire < now)) || (doc.tokenUser == null) || ((command.remove != null) && (command.remove.indexOf(doc.tokenUser) >= 0))) {
// This share is expired.
- parent.db.Remove(doc._id, function () { }); delete docs[i]; removed++;
+ parent.db.Remove(doc._id, function () { }); removed++;
} else {
// This share is ok, remove extra data we don't need to send.
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
// Dispatch the new event
var targets = ['*', 'server-users', user._id];
if (user.groups) { for (var i in user.groups) { targets.push('server-users:' + i); } }
- var event = { etype: 'user', userid: user._id, username: user.name, action: 'loginTokenAdded', msgid: 115, msg: "Added login token", domain: domain.id };
+ 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 } };
parent.parent.DispatchEvent(targets, obj, event);
});
-
break;
}
case 'getDeviceDetails': {
diff --git a/views/default.handlebars b/views/default.handlebars
index 282bcfcf..2c5c5fb7 100644
--- a/views/default.handlebars
+++ b/views/default.handlebars
@@ -385,8 +385,9 @@
+
Device Groups
- ( New )
+ - New
@@ -2004,6 +2005,7 @@
if (updateNaggleFlags & 8192) { updateUserGroups(); }
if (updateNaggleFlags & 16384) { updateUsers(); }
if (updateNaggleFlags & 32768) { updateRecordings(); }
+ if (updateNaggleFlags & 65536) { updateLoginTokens(); }
updateNaggleTimer = null;
updateNaggleFlags = 0;
gotoStartViewPage();
@@ -3169,11 +3171,17 @@
if ((Q('DevFilterSelect').value == 2) || (Q('DevFilterSelect').value == 6)) { mainUpdate(1); }
break;
}
- case 'loginTokenChanged': {
+ case 'loginTokenChanged': { // Login tokens have changed
if (message.event.userid != userinfo._id) return;
loginTokens = message.event.loginTokens;
- // TODO: Update
- console.log('t1', loginTokens);
+ mainUpdate(65536);
+ break;
+ }
+ case 'loginTokenAdded': { // A login token was added
+ if (message.event.userid != userinfo._id) return;
+ if (loginTokens == null) { loginTokens = []; }
+ loginTokens.push(message.event.newToken);
+ mainUpdate(65536);
break;
}
case 'stopped': { // Server is stopping.
@@ -3342,7 +3350,7 @@
saveAs(new Blob([message.data], { type: 'application/octet-stream' }), "devicelist" + '.' + message.type);
break;
}
- case 'createLoginToken': {
+ case 'createLoginToken': { // A new login token was created
if (xxdialogMode) return;
var x = "Take note of this username and password, the password cannot be shown again." + '
';
x += addHtmlValue("Name", EscapeHtml(message.name))
@@ -3352,10 +3360,9 @@
setDialogMode(2, "Create Login Token", 1, null, x);
break;
}
- case 'loginTokens': {
+ case 'loginTokens': { // Reveiced the list of login tokens
loginTokens = message.loginTokens;
- // TODO: Update
- console.log('t2', loginTokens);
+ mainUpdate(65536);
break;
}
default:
@@ -10437,6 +10444,38 @@
QV('p2noMeshFound', count == 0);
}
+
+ function updateLoginTokens() {
+ var x = '', count = 1;
+ if ((loginTokens != null) && (loginTokens.length > 0)) {
+ x += '' + "Active Login Tokens" + ' - ' + "New" + '
' + "Name" + ' | ' + "Username" + ' |
';
+ for (var i = 0; i < loginTokens.length; i++) {
+ var ltoken = loginTokens[i];
+ var trash = '';
+ var details = '';
+ if (ltoken.expire != 0) { details = EscapeHtml(format("Expires {0}", printDateTime(new Date(ltoken.expire)))) + ' '; }
+ x += ' ' + EscapeHtml(ltoken.name) + ' | ' + details + trash + ' ' + EscapeHtml(ltoken.tokenUser) + ' |
';
+ }
+ x += '
';
+ QV('accountCreateLoginTokenSpan', false);
+ } else {
+ QV('accountCreateLoginTokenSpan', features2 & 0x00000080);
+ }
+ QH('p2logintokens', x);
+ }
+
+ function p2removeLoginToken(e, tokenUser) {
+ tokenUser = decodeURIComponent(tokenUser);
+ if (loginTokens == null) return;
+ var token = null;
+ for (var i = 0; i < loginTokens.length; i++) { if (loginTokens[i].tokenUser == tokenUser) { token = loginTokens[i]; } }
+ if (token == null) return;
+ var x = "Confirm removal of this login token?" + '
';
+ x += addHtmlValue("Name", EscapeHtml(token.name));
+ x += addHtmlValue("Username", EscapeHtml(token.tokenUser));
+ setDialogMode(2, "Remove Login Token", 3, function(b, tokenUser) { meshserver.send({ action: 'loginTokens', remove: [ tokenUser ] }); }, x, tokenUser);
+ }
+
function gotoMesh(meshid) {
currentMesh = meshes[meshid];
p20updateMesh();