Factorize adduser
Noah Zalev committed
Dec 7, 2021 at 19:57 UTC
184fdaf237b09f0b2c6a6318593fc5df705f445e
1 file changed
+134
-134
meshuser.js
+134
-134
@@ -1377,140 +1377,6 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
1377
if (command.responseid != null) { try { ws.send(JSON.stringify({ action: 'userbroadcast', responseid: command.responseid, result: 'ok' })); } catch (ex) { } }
1378
break;
1379
}
1380
- case 'adduser':
1381
- {
1382
- // If the email is the username, set this here.
1383
- if (domain.usernameisemail) { if (command.email) { command.username = command.email; } else { command.email = command.username; } }
1384
-
1385
- // Randomize the password if needed
1386
- if (command.randomPassword === true) { command.pass = getRandomPassword(); }
1387
-
1388
- // Add a new user account
1389
- var err = null, errid = 0, newusername, newuserid, newuserdomain;
1390
- try {
1391
- if ((user.siteadmin & 2) == 0) { err = "Permission denied"; errid = 1; }
1392
- else if (common.validateUsername(command.username, 1, 256) == false) { err = "Invalid username"; errid = 2; } // Username is between 1 and 64 characters, no spaces
1393
- else if ((command.username[0] == '~') || (command.username.indexOf('/') >= 0)) { err = "Invalid username"; errid = 2; } // Usernames cant' start with ~ and can't have '/'
1394
- else if (common.validateString(command.pass, 1, 256) == false) { err = "Invalid password"; errid = 3; } // Password is between 1 and 256 characters
1395
- else if ((command.randomPassword !== true) && (common.checkPasswordRequirements(command.pass, domain.passwordrequirements) == false)) { err = "Invalid password"; errid = 3; } // Password does not meet requirements
1396
- else if ((command.email != null) && (common.validateEmail(command.email, 1, 1024) == false)) { err = "Invalid email"; errid = 4; } // Check if this is a valid email address
1397
- else if ((obj.crossDomain === true) && (command.domain != null) && ((typeof command.domain != 'string') || (parent.parent.config.domains[command.domain] == null))) { err = "Invalid domain"; errid = 5; } // Check if this is a valid domain
1398
- else {
1399
- newuserdomain = domain;
1400
- if ((obj.crossDomain === true) && (command.domain != null)) { newuserdomain = parent.parent.config.domains[command.domain]; }
1401
- newusername = command.username;
1402
- newuserid = 'user/' + newuserdomain.id + '/' + command.username.toLowerCase();
1403
- if (command.siteadmin != null) {
1404
- if ((typeof command.siteadmin != 'number') || (Number.isInteger(command.siteadmin) == false)) { err = "Invalid site permissions"; errid = 6; } // Check permissions
1405
- else if ((user.siteadmin != SITERIGHT_ADMIN) && ((command.siteadmin & (SITERIGHT_ADMIN - 224)) != 0)) { err = "Invalid site permissions"; errid = 6; }
1406
- }
1407
- if (parent.users[newuserid]) { err = "User already exists"; errid = 7; } // Account already exists
1408
- else if ((newuserdomain.auth == 'sspi') || (newuserdomain.auth == 'ldap')) { err = "Unable to add user in this mode"; errid = 8; }
1409
- }
1410
- } catch (ex) { err = "Validation exception"; errid = 9; }
1411
-
1412
- // Handle any errors
1413
- if (err != null) {
1414
- if (command.responseid != null) {
1415
- try { ws.send(JSON.stringify({ action: 'adduser', responseid: command.responseid, result: err, msgid: errid })); } catch (ex) { }
1416
- } else {
1417
- // Send error back, user not found.
1418
- displayNotificationMessage(err, "New Account", 'ServerNotify', null, 1, errid);
1419
- }
1420
- break;
1421
- }
1422
-
1423
- // Check if we exceed the maximum number of user accounts
1424
- db.isMaxType(newuserdomain.limits.maxuseraccounts, 'user', newuserdomain.id, function (maxExceed) {
1425
- if (maxExceed) {
1426
- // Account count exceed, do notification
1427
- if (command.responseid != null) {
1428
- // Respond privately if requested
1429
- try { ws.send(JSON.stringify({ action: 'adduser', responseid: command.responseid, result: 'maxUsersExceed' })); } catch (ex) { }
1430
- } else {
1431
- // Create the notification message
1432
- var notification = { action: 'msg', type: 'notify', id: Math.random(), value: "Account limit reached.", title: "Server Limit", userid: user._id, username: user.name, domain: newuserdomain.id, titleid: 2, msgid: 10 };
1433
-
1434
- // Get the list of sessions for this user
1435
- var sessions = parent.wssessions[user._id];
1436
- if (sessions != null) { for (i in sessions) { try { if (sessions[i].domainid == newuserdomain.id) { sessions[i].send(JSON.stringify(notification)); } } catch (ex) { } } }
1437
- // TODO: Notify all sessions on other peers.
1438
- }
1439
- } else {
1440
- // Remove any events for this userid
1441
- if (command.removeEvents === true) { db.RemoveAllUserEvents(newuserdomain.id, newuserid); }
1442
-
1443
- // Create a new user
1444
- var newuser = { type: 'user', _id: newuserid, name: newusername, creation: Math.floor(Date.now() / 1000), domain: newuserdomain.id };
1445
- if (command.siteadmin != null) { newuser.siteadmin = command.siteadmin; }
1446
- else if (newuserdomain.newaccountsrights) { newuser.siteadmin = newuserdomain.newaccountsrights; }
1447
- if (command.email != null) { newuser.email = command.email.toLowerCase(); if (command.emailVerified === true) { newuser.emailVerified = true; } } // Email
1448
- if (command.resetNextLogin === true) { newuser.passchange = -1; } else { newuser.passchange = Math.floor(Date.now() / 1000); }
1449
- if (user.groups) { newuser.groups = user.groups; } // New accounts are automatically part of our groups (Realms).
1450
- if (common.validateString(command.realname, 1, 256)) { newuser.realname = command.realname; }
1451
- if ((command.consent != null) && (typeof command.consent == 'number')) { if (command.consent == 0) { delete chguser.consent; } else { newuser.consent = command.consent; } change = 1; }
1452
- if ((command.phone != null) && (typeof command.phone == 'string') && ((command.phone == '') || isPhoneNumber(command.phone))) { if (command.phone == '') { delete newuser.phone; } else { newuser.phone = command.phone; } change = 1; }
1453
-
1454
- // Auto-join any user groups
1455
- if (typeof newuserdomain.newaccountsusergroups == 'object') {
1456
- for (var i in newuserdomain.newaccountsusergroups) {
1457
- var ugrpid = newuserdomain.newaccountsusergroups[i];
1458
- if (ugrpid.indexOf('/') < 0) { ugrpid = 'ugrp/' + newuserdomain.id + '/' + ugrpid; }
1459
- var ugroup = parent.userGroups[ugrpid];
1460
- if (ugroup != null) {
1461
- // Add group to the user
1462
- if (newuser.links == null) { newuser.links = {}; }
1463
- newuser.links[ugroup._id] = { rights: 1 };
1464
-
1465
- // Add user to the group
1466
- ugroup.links[newuser._id] = { userid: newuser._id, name: newuser.name, rights: 1 };
1467
- db.Set(ugroup);
1468
-
1469
- // Notify user group change
1470
- var event = { etype: 'ugrp', userid: user._id, username: user.name, ugrpid: ugroup._id, name: ugroup.name, desc: ugroup.desc, action: 'usergroupchange', links: ugroup.links, msgid: 80, msgArgs: [newuser.name, ugroup.name], msg: 'Added user ' + newuser.name + ' to user group ' + ugroup.name, addUserDomain: newuserdomain.id };
1471
- if (db.changeStream) { event.noact = 1; } // If DB change stream is active, don't use this event to change the user group. Another event will come.
1472
- parent.parent.DispatchEvent(['*', ugroup._id, user._id, newuser._id], obj, event);
1473
- }
1474
- }
1475
- }
1476
-
1477
- parent.users[newuserid] = newuser;
1478
-
1479
- // Create a user, generate a salt and hash the password
1480
- require('./pass').hash(command.pass, function (err, salt, hash, tag) {
1481
- if (err == null) {
1482
- newuser.salt = salt;
1483
- newuser.hash = hash;
1484
- db.SetUser(newuser);
1485
-
1486
- var event, targets = ['*', 'server-users'];
1487
- if (newuser.groups) { for (var i in newuser.groups) { targets.push('server-users:' + i); } }
1488
- if (command.email == null) {
1489
- event = { etype: 'user', userid: newuser._id, username: newusername, account: parent.CloneSafeUser(newuser), action: 'accountcreate', msgid: 64, msgArgs: [command.username], msg: 'Account created, username is ' + command.username, domain: newuserdomain.id };
1490
- } else {
1491
- event = { etype: 'user', userid: newuser._id, username: newusername, account: parent.CloneSafeUser(newuser), action: 'accountcreate', msgid: 65, msgArgs: [command.email.toLowerCase()], msg: 'Account created, email is ' + command.email.toLowerCase(), domain: newuserdomain.id };
1492
- }
1493
- if (parent.db.changeStream) { event.noact = 1; } // If DB change stream is active, don't use this event to create the user. Another event will come.
1494
- parent.parent.DispatchEvent(targets, obj, event);
1495
-
1496
- // Perform email invitation
1497
- if ((command.emailInvitation == true) && (command.emailVerified == true) && command.email && domain.mailserver) {
1498
- domain.mailserver.sendAccountInviteMail(newuserdomain, (user.realname ? user.realname : user.name), newusername, command.email.toLowerCase(), command.pass, parent.getLanguageCodes(req));
1499
- }
1500
-
1501
- // Log in the auth log
1502
- if (parent.parent.authlog) { parent.parent.authLog('https', 'User ' + user.name + ' created a user account ' + newuser.name); }
1503
-
1504
- // OK Response
1505
- if (command.responseid != null) { try { ws.send(JSON.stringify({ action: 'adduser', responseid: command.responseid, result: 'ok' })); } catch (ex) { } }
1506
- } else {
1507
- if (command.responseid != null) { try { ws.send(JSON.stringify({ action: 'adduser', responseid: command.responseid, result: 'passwordHashError' })); } catch (ex) { } }
1508
- }
1509
- }, 0);
1510
- }
1511
- });
1512
- break;
1513
- }
1380
case 'edituser':
1381
{
1382
// Must be user administrator or edit self.
@@ -5764,6 +5630,7 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
5630
}
5631
5632
const serverCommands = {
5633
+ 'adduser': serverCommandAddUser,
5634
'adduserbatch': serverCommandAddUserBatch,
5635
'files': serverCommandFiles,
5636
'getnetworkinfo': serverCommandGetNetworkInfo,
@@ -5839,6 +5706,139 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
5706
'webstats': [serverUserCommandWebStats, ""]
5707
};
5708
5709
+ function serverCommandAddUser(command) {
5710
+ // If the email is the username, set this here.
5711
+ if (domain.usernameisemail) { if (command.email) { command.username = command.email; } else { command.email = command.username; } }
5712
+
5713
+ // Randomize the password if needed
5714
+ if (command.randomPassword === true) { command.pass = getRandomPassword(); }
5715
+
5716
+ // Add a new user account
5717
+ var err = null, errid = 0, newusername, newuserid, newuserdomain;
5718
+ try {
5719
+ if ((user.siteadmin & 2) == 0) { err = "Permission denied"; errid = 1; }
5720
+ else if (common.validateUsername(command.username, 1, 256) == false) { err = "Invalid username"; errid = 2; } // Username is between 1 and 64 characters, no spaces
5721
+ else if ((command.username[0] == '~') || (command.username.indexOf('/') >= 0)) { err = "Invalid username"; errid = 2; } // Usernames cant' start with ~ and can't have '/'
5722
+ else if (common.validateString(command.pass, 1, 256) == false) { err = "Invalid password"; errid = 3; } // Password is between 1 and 256 characters
5723
+ else if ((command.randomPassword !== true) && (common.checkPasswordRequirements(command.pass, domain.passwordrequirements) == false)) { err = "Invalid password"; errid = 3; } // Password does not meet requirements
5724
+ else if ((command.email != null) && (common.validateEmail(command.email, 1, 1024) == false)) { err = "Invalid email"; errid = 4; } // Check if this is a valid email address
5725
+ else if ((obj.crossDomain === true) && (command.domain != null) && ((typeof command.domain != 'string') || (parent.parent.config.domains[command.domain] == null))) { err = "Invalid domain"; errid = 5; } // Check if this is a valid domain
5726
+ else {
5727
+ newuserdomain = domain;
5728
+ if ((obj.crossDomain === true) && (command.domain != null)) { newuserdomain = parent.parent.config.domains[command.domain]; }
5729
+ newusername = command.username;
5730
+ newuserid = 'user/' + newuserdomain.id + '/' + command.username.toLowerCase();
5731
+ if (command.siteadmin != null) {
5732
+ if ((typeof command.siteadmin != 'number') || (Number.isInteger(command.siteadmin) == false)) { err = "Invalid site permissions"; errid = 6; } // Check permissions
5733
+ else if ((user.siteadmin != SITERIGHT_ADMIN) && ((command.siteadmin & (SITERIGHT_ADMIN - 224)) != 0)) { err = "Invalid site permissions"; errid = 6; }
5734
+ }
5735
+ if (parent.users[newuserid]) { err = "User already exists"; errid = 7; } // Account already exists
5736
+ else if ((newuserdomain.auth == 'sspi') || (newuserdomain.auth == 'ldap')) { err = "Unable to add user in this mode"; errid = 8; }
5737
+ }
5738
+ } catch (ex) { err = "Validation exception"; errid = 9; }
5739
+
5740
+ // Handle any errors
5741
+ if (err != null) {
5742
+ if (command.responseid != null) {
5743
+ try { ws.send(JSON.stringify({ action: 'adduser', responseid: command.responseid, result: err, msgid: errid })); } catch (ex) { }
5744
+ } else {
5745
+ // Send error back, user not found.
5746
+ displayNotificationMessage(err, "New Account", 'ServerNotify', null, 1, errid);
5747
+ }
5748
+ return;
5749
+ }
5750
+
5751
+ // Check if we exceed the maximum number of user accounts
5752
+ db.isMaxType(newuserdomain.limits.maxuseraccounts, 'user', newuserdomain.id, function (maxExceed) {
5753
+ if (maxExceed) {
5754
+ // Account count exceed, do notification
5755
+ if (command.responseid != null) {
5756
+ // Respond privately if requested
5757
+ try { ws.send(JSON.stringify({ action: 'adduser', responseid: command.responseid, result: 'maxUsersExceed' })); } catch (ex) { }
5758
+ } else {
5759
+ // Create the notification message
5760
+ var notification = { action: 'msg', type: 'notify', id: Math.random(), value: "Account limit reached.", title: "Server Limit", userid: user._id, username: user.name, domain: newuserdomain.id, titleid: 2, msgid: 10 };
5761
+
5762
+ // Get the list of sessions for this user
5763
+ var sessions = parent.wssessions[user._id];
5764
+ if (sessions != null) { for (var i in sessions) { try { if (sessions[i].domainid == newuserdomain.id) { sessions[i].send(JSON.stringify(notification)); } } catch (ex) { } } }
5765
+ // TODO: Notify all sessions on other peers.
5766
+ }
5767
+ } else {
5768
+ // Remove any events for this userid
5769
+ if (command.removeEvents === true) { db.RemoveAllUserEvents(newuserdomain.id, newuserid); }
5770
+
5771
+ // Create a new user
5772
+ var newuser = { type: 'user', _id: newuserid, name: newusername, creation: Math.floor(Date.now() / 1000), domain: newuserdomain.id };
5773
+ if (command.siteadmin != null) { newuser.siteadmin = command.siteadmin; }
5774
+ else if (newuserdomain.newaccountsrights) { newuser.siteadmin = newuserdomain.newaccountsrights; }
5775
+ if (command.email != null) { newuser.email = command.email.toLowerCase(); if (command.emailVerified === true) { newuser.emailVerified = true; } } // Email
5776
+ if (command.resetNextLogin === true) { newuser.passchange = -1; } else { newuser.passchange = Math.floor(Date.now() / 1000); }
5777
+ if (user.groups) { newuser.groups = user.groups; } // New accounts are automatically part of our groups (Realms).
5778
+ if (common.validateString(command.realname, 1, 256)) { newuser.realname = command.realname; }
5779
+ if ((command.consent != null) && (typeof command.consent == 'number')) { if (command.consent == 0) { delete chguser.consent; } else { newuser.consent = command.consent; } change = 1; }
5780
+ if ((command.phone != null) && (typeof command.phone == 'string') && ((command.phone == '') || isPhoneNumber(command.phone))) { if (command.phone == '') { delete newuser.phone; } else { newuser.phone = command.phone; } change = 1; }
5781
+
5782
+ // Auto-join any user groups
5783
+ if (typeof newuserdomain.newaccountsusergroups == 'object') {
5784
+ for (var i in newuserdomain.newaccountsusergroups) {
5785
+ var ugrpid = newuserdomain.newaccountsusergroups[i];
5786
+ if (ugrpid.indexOf('/') < 0) { ugrpid = 'ugrp/' + newuserdomain.id + '/' + ugrpid; }
5787
+ var ugroup = parent.userGroups[ugrpid];
5788
+ if (ugroup != null) {
5789
+ // Add group to the user
5790
+ if (newuser.links == null) { newuser.links = {}; }
5791
+ newuser.links[ugroup._id] = { rights: 1 };
5792
+
5793
+ // Add user to the group
5794
+ ugroup.links[newuser._id] = { userid: newuser._id, name: newuser.name, rights: 1 };
5795
+ db.Set(ugroup);
5796
+
5797
+ // Notify user group change
5798
+ var event = { etype: 'ugrp', userid: user._id, username: user.name, ugrpid: ugroup._id, name: ugroup.name, desc: ugroup.desc, action: 'usergroupchange', links: ugroup.links, msgid: 80, msgArgs: [newuser.name, ugroup.name], msg: 'Added user ' + newuser.name + ' to user group ' + ugroup.name, addUserDomain: newuserdomain.id };
5799
+ if (db.changeStream) { event.noact = 1; } // If DB change stream is active, don't use this event to change the user group. Another event will come.
5800
+ parent.parent.DispatchEvent(['*', ugroup._id, user._id, newuser._id], obj, event);
5801
+ }
5802
+ }
5803
+ }
5804
+
5805
+ parent.users[newuserid] = newuser;
5806
+
5807
+ // Create a user, generate a salt and hash the password
5808
+ require('./pass').hash(command.pass, function (err, salt, hash, tag) {
5809
+ if (err == null) {
5810
+ newuser.salt = salt;
5811
+ newuser.hash = hash;
5812
+ db.SetUser(newuser);
5813
+
5814
+ var event, targets = ['*', 'server-users'];
5815
+ if (newuser.groups) { for (var i in newuser.groups) { targets.push('server-users:' + i); } }
5816
+ if (command.email == null) {
5817
+ event = { etype: 'user', userid: newuser._id, username: newusername, account: parent.CloneSafeUser(newuser), action: 'accountcreate', msgid: 64, msgArgs: [command.username], msg: 'Account created, username is ' + command.username, domain: newuserdomain.id };
5818
+ } else {
5819
+ event = { etype: 'user', userid: newuser._id, username: newusername, account: parent.CloneSafeUser(newuser), action: 'accountcreate', msgid: 65, msgArgs: [command.email.toLowerCase()], msg: 'Account created, email is ' + command.email.toLowerCase(), domain: newuserdomain.id };
5820
+ }
5821
+ if (parent.db.changeStream) { event.noact = 1; } // If DB change stream is active, don't use this event to create the user. Another event will come.
5822
+ parent.parent.DispatchEvent(targets, obj, event);
5823
+
5824
+ // Perform email invitation
5825
+ if ((command.emailInvitation == true) && (command.emailVerified == true) && command.email && domain.mailserver) {
5826
+ domain.mailserver.sendAccountInviteMail(newuserdomain, (user.realname ? user.realname : user.name), newusername, command.email.toLowerCase(), command.pass, parent.getLanguageCodes(req));
5827
+ }
5828
+
5829
+ // Log in the auth log
5830
+ if (parent.parent.authlog) { parent.parent.authLog('https', 'User ' + user.name + ' created a user account ' + newuser.name); }
5831
+
5832
+ // OK Response
5833
+ if (command.responseid != null) { try { ws.send(JSON.stringify({ action: 'adduser', responseid: command.responseid, result: 'ok' })); } catch (ex) { } }
5834
+ } else {
5835
+ if (command.responseid != null) { try { ws.send(JSON.stringify({ action: 'adduser', responseid: command.responseid, result: 'passwordHashError' })); } catch (ex) { } }
5836
+ }
5837
+ }, 0);
5838
+ }
5839
+ });
5840
+ }
5841
+
5842
function serverCommandAddUserBatch(command) {
5843
var err = null;
5844