split routes and model code into user-directory.js
This commit is contained in:
@@ -32,7 +32,7 @@ const apps = require('./apps.js'),
|
||||
settings = require('./settings.js'),
|
||||
system = require('./system.js'),
|
||||
tasks = require('./tasks.js'),
|
||||
users = require('./users.js');
|
||||
userDirectory = require('./user-directory.js');
|
||||
|
||||
async function getLocation() {
|
||||
const domain = await settings.get(settings.DASHBOARD_DOMAIN_KEY);
|
||||
@@ -56,7 +56,7 @@ async function clearLocation() {
|
||||
|
||||
async function getConfig() {
|
||||
const ubuntuVersion = await system.getUbuntuVersion();
|
||||
const profileConfig = await users.getProfileConfig();
|
||||
const profileConfig = await userDirectory.getProfileConfig();
|
||||
const externalLdapConfig = await externalLdap.getConfig();
|
||||
|
||||
const { fqdn:adminFqdn, domain:adminDomain } = await getLocation();
|
||||
|
||||
@@ -32,6 +32,7 @@ exports = module.exports = {
|
||||
tasks: require('./tasks.js'),
|
||||
tokens: require('./tokens.js'),
|
||||
updater: require('./updater.js'),
|
||||
userDirectory: require('./user-directory.js'),
|
||||
users: require('./users.js'),
|
||||
volumes: require('./volumes.js'),
|
||||
wellknown: require('./wellknown.js')
|
||||
|
||||
@@ -27,12 +27,13 @@ const assert = require('assert'),
|
||||
path = require('path'),
|
||||
paths = require('../paths.js'),
|
||||
safe = require('safetydance'),
|
||||
userDirectory = require('../user-directory.js'),
|
||||
users = require('../users.js');
|
||||
|
||||
async function canEditProfile(req, res, next) {
|
||||
assert.strictEqual(typeof req.user, 'object');
|
||||
|
||||
const [error, profileConfig] = await safe(users.getProfileConfig());
|
||||
const [error, profileConfig] = await safe(userDirectory.getProfileConfig());
|
||||
if (error) return next(BoxError.toHttpError(error));
|
||||
|
||||
if (profileConfig.lockUserProfiles) return next(new HttpError(403, 'admin has disallowed users from editing profiles'));
|
||||
|
||||
32
src/routes/user-directory.js
Normal file
32
src/routes/user-directory.js
Normal file
@@ -0,0 +1,32 @@
|
||||
'use strict';
|
||||
|
||||
exports = module.exports = {
|
||||
getProfileConfig,
|
||||
setProfileConfig
|
||||
};
|
||||
|
||||
const assert = require('assert'),
|
||||
BoxError = require('../boxerror.js'),
|
||||
HttpError = require('connect-lastmile').HttpError,
|
||||
HttpSuccess = require('connect-lastmile').HttpSuccess,
|
||||
safe = require('safetydance'),
|
||||
userDirectory = require('../user-directory.js');
|
||||
|
||||
async function getProfileConfig(req, res, next) {
|
||||
const [error, directoryConfig] = await safe(userDirectory.getProfileConfig());
|
||||
if (error) return next(BoxError.toHttpError(error));
|
||||
|
||||
next(new HttpSuccess(200, directoryConfig));
|
||||
}
|
||||
|
||||
async function setProfileConfig(req, res, next) {
|
||||
assert.strictEqual(typeof req.body, 'object');
|
||||
|
||||
if (typeof req.body.lockUserProfiles !== 'boolean') return next(new HttpError(400, 'lockUserProfiles is required'));
|
||||
if (typeof req.body.mandatory2FA !== 'boolean') return next(new HttpError(400, 'mandatory2FA is required'));
|
||||
|
||||
const [error] = await safe(userDirectory.setProfileConfig(req.body));
|
||||
if (error) return next(BoxError.toHttpError(error));
|
||||
|
||||
next(new HttpSuccess(200, {}));
|
||||
}
|
||||
@@ -18,9 +18,6 @@ exports = module.exports = {
|
||||
getPasswordResetLink,
|
||||
sendPasswordResetEmail,
|
||||
|
||||
setProfileConfig,
|
||||
getProfileConfig,
|
||||
|
||||
getInviteLink,
|
||||
sendInviteEmail,
|
||||
|
||||
@@ -275,22 +272,3 @@ async function sendInviteEmail(req, res, next) {
|
||||
|
||||
next(new HttpSuccess(202, {}));
|
||||
}
|
||||
|
||||
async function getProfileConfig(req, res, next) {
|
||||
const [error, directoryConfig] = await safe(users.getProfileConfig());
|
||||
if (error) return next(BoxError.toHttpError(error));
|
||||
|
||||
next(new HttpSuccess(200, directoryConfig));
|
||||
}
|
||||
|
||||
async function setProfileConfig(req, res, next) {
|
||||
assert.strictEqual(typeof req.body, 'object');
|
||||
|
||||
if (typeof req.body.lockUserProfiles !== 'boolean') return next(new HttpError(400, 'lockUserProfiles is required'));
|
||||
if (typeof req.body.mandatory2FA !== 'boolean') return next(new HttpError(400, 'mandatory2FA is required'));
|
||||
|
||||
const [error] = await safe(users.setProfileConfig(req.body));
|
||||
if (error) return next(BoxError.toHttpError(error));
|
||||
|
||||
next(new HttpSuccess(200, {}));
|
||||
}
|
||||
|
||||
@@ -215,8 +215,8 @@ async function initializeExpressSync() {
|
||||
router.del ('/api/v1/groups/:groupId', token, authorizeUserManager, routes.groups.load, routes.groups.remove);
|
||||
|
||||
// User directory
|
||||
router.get ('/api/v1/user_directory/profile_config', token, authorizeAdmin, routes.users.getProfileConfig);
|
||||
router.post('/api/v1/user_directory/profile_config', json, token, authorizeAdmin, routes.users.setProfileConfig);
|
||||
router.get ('/api/v1/user_directory/profile_config', token, authorizeAdmin, routes.userDirectory.getProfileConfig);
|
||||
router.post('/api/v1/user_directory/profile_config', json, token, authorizeAdmin, routes.userDirectory.setProfileConfig);
|
||||
|
||||
// External LDAP
|
||||
router.get ('/api/v1/external_ldap/config', token, authorizeAdmin, routes.externalLdap.getConfig);
|
||||
|
||||
36
src/test/user-directory-test.js
Normal file
36
src/test/user-directory-test.js
Normal file
@@ -0,0 +1,36 @@
|
||||
/* global it:false */
|
||||
/* global describe:false */
|
||||
/* global before:false */
|
||||
/* global after:false */
|
||||
|
||||
'use strict';
|
||||
|
||||
const common = require('./common.js'),
|
||||
expect = require('expect.js'),
|
||||
tokens = require('../tokens.js'),
|
||||
userDirectory = require('../user-directory.js');
|
||||
|
||||
describe('User Directory', function () {
|
||||
const { setup, cleanup, admin } = common;
|
||||
|
||||
before(setup);
|
||||
after(cleanup);
|
||||
|
||||
describe('profile config', function () {
|
||||
it('can get default profile config', async function () {
|
||||
const profileConfig = await userDirectory.getProfileConfig();
|
||||
expect(profileConfig.lockUserProfiles).to.be(false);
|
||||
expect(profileConfig.mandatory2FA).to.be(false);
|
||||
});
|
||||
|
||||
it('can set default profile config', async function () {
|
||||
await tokens.add({ name: 'token1', identifier: admin.id, clientId: tokens.ID_WEBADMIN, expires: Number.MAX_SAFE_INTEGER, lastUsedTime: null });
|
||||
let result = await tokens.listByUserId(admin.id);
|
||||
expect(result.length).to.be(1); // just confirm the token was really added!
|
||||
|
||||
await userDirectory.setProfileConfig({ mandatory2FA: true, lockUserProfiles: true });
|
||||
result = await tokens.listByUserId(admin.id);
|
||||
expect(result.length).to.be(0); // should have been removed by mandatory 2fa setting change
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -10,7 +10,6 @@ const BoxError = require('../boxerror.js'),
|
||||
expect = require('expect.js'),
|
||||
safe = require('safetydance'),
|
||||
speakeasy = require('speakeasy'),
|
||||
tokens = require('../tokens.js'),
|
||||
users = require('../users.js'),
|
||||
_ = require('underscore');
|
||||
|
||||
@@ -199,7 +198,7 @@ describe('User', function () {
|
||||
});
|
||||
|
||||
it('can listPaged (search)', async function () {
|
||||
let results = await users.listPaged(admin.email.slice(0, 8), null, 1, 1);
|
||||
const results = await users.listPaged(admin.email.slice(0, 8), null, 1, 1);
|
||||
expect(results.length).to.be(1);
|
||||
checkUser(results[0], admin);
|
||||
});
|
||||
@@ -632,24 +631,6 @@ describe('User', function () {
|
||||
it('can re-create user after user was removed', createOwner);
|
||||
});
|
||||
|
||||
describe('profile config', function () {
|
||||
it('can get default profile config', async function () {
|
||||
const profileConfig = await users.getProfileConfig();
|
||||
expect(profileConfig.lockUserProfiles).to.be(false);
|
||||
expect(profileConfig.mandatory2FA).to.be(false);
|
||||
});
|
||||
|
||||
it('can set default profile config', async function () {
|
||||
await tokens.add({ name: 'token1', identifier: admin.id, clientId: tokens.ID_WEBADMIN, expires: Number.MAX_SAFE_INTEGER, lastUsedTime: null });
|
||||
let result = await tokens.listByUserId(admin.id);
|
||||
expect(result.length).to.be(1); // just confirm the token was really added!
|
||||
|
||||
await users.setProfileConfig({ mandatory2FA: true, lockUserProfiles: true });
|
||||
result = await tokens.listByUserId(admin.id);
|
||||
expect(result.length).to.be(0); // should have been removed by mandatory 2fa setting change
|
||||
});
|
||||
});
|
||||
|
||||
describe('parseDisplayName', function () {
|
||||
it('parses names', function () {
|
||||
const names = [
|
||||
|
||||
41
src/user-directory.js
Normal file
41
src/user-directory.js
Normal file
@@ -0,0 +1,41 @@
|
||||
'use strict';
|
||||
|
||||
exports = module.exports = {
|
||||
getProfileConfig,
|
||||
setProfileConfig
|
||||
};
|
||||
|
||||
const assert = require('assert'),
|
||||
BoxError = require('./boxerror.js'),
|
||||
constants = require('./constants.js'),
|
||||
debug = require('debug')('box:user-directory'),
|
||||
oidc = require('./oidc.js'),
|
||||
settings = require('./settings.js'),
|
||||
tokens = require('./tokens.js'),
|
||||
users = require('./users.js');
|
||||
|
||||
async function getProfileConfig() {
|
||||
const value = await settings.getJson(settings.PROFILE_CONFIG_KEY);
|
||||
return value || { lockUserProfiles: false, mandatory2FA: false };
|
||||
}
|
||||
|
||||
async function setProfileConfig(profileConfig) {
|
||||
assert.strictEqual(typeof profileConfig, 'object');
|
||||
|
||||
if (constants.DEMO) throw new BoxError(BoxError.BAD_STATE, 'Not allowed in demo mode');
|
||||
|
||||
const oldConfig = await getProfileConfig();
|
||||
await settings.setJson(settings.PROFILE_CONFIG_KEY, profileConfig);
|
||||
|
||||
if (profileConfig.mandatory2FA && !oldConfig.mandatory2FA) {
|
||||
debug('setProfileConfig: logging out non-2FA users to enforce 2FA');
|
||||
|
||||
const allUsers = await users.list();
|
||||
for (const user of allUsers) {
|
||||
if (user.twoFactorAuthenticationEnabled) continue;
|
||||
|
||||
await tokens.delByUserIdAndType(user.id, tokens.ID_WEBADMIN);
|
||||
await oidc.revokeByUserId(user.id);
|
||||
}
|
||||
}
|
||||
}
|
||||
37
src/users.js
37
src/users.js
@@ -51,9 +51,6 @@ exports = module.exports = {
|
||||
getBackgroundImage,
|
||||
setBackgroundImage,
|
||||
|
||||
getProfileConfig,
|
||||
setProfileConfig,
|
||||
|
||||
resetSource,
|
||||
|
||||
parseDisplayName,
|
||||
@@ -91,15 +88,15 @@ const appPasswords = require('./apppasswords.js'),
|
||||
mail = require('./mail.js'),
|
||||
mailer = require('./mailer.js'),
|
||||
mysql = require('mysql'),
|
||||
oidc = require('../oidc.js'),
|
||||
qrcode = require('qrcode'),
|
||||
safe = require('safetydance'),
|
||||
settings = require('./settings.js'),
|
||||
speakeasy = require('speakeasy'),
|
||||
tokens = require('./tokens.js'),
|
||||
translation = require('./translation.js'),
|
||||
uuid = require('uuid'),
|
||||
uaParser = require('ua-parser-js'),
|
||||
userDirectory = require('./user-directory.js'),
|
||||
uuid = require('uuid'),
|
||||
superagent = require('superagent'),
|
||||
util = require('util'),
|
||||
validator = require('validator'),
|
||||
@@ -826,7 +823,7 @@ async function getInviteLink(user, auditSource) {
|
||||
if (user.source) throw new BoxError(BoxError.CONFLICT, 'User is from an external directory');
|
||||
if (!user.inviteToken) throw new BoxError(BoxError.BAD_STATE, 'User already used invite link');
|
||||
|
||||
const directoryConfig = await getProfileConfig();
|
||||
const directoryConfig = await userDirectory.getProfileConfig();
|
||||
const { fqdn:dashboardFqdn } = await dashboard.getLocation();
|
||||
let inviteLink = `https://${dashboardFqdn}/setupaccount.html?inviteToken=${user.inviteToken}&email=${encodeURIComponent(user.email)}`;
|
||||
|
||||
@@ -854,7 +851,7 @@ async function setupAccount(user, data, auditSource) {
|
||||
assert.strictEqual(typeof data, 'object');
|
||||
assert(auditSource && typeof auditSource === 'object');
|
||||
|
||||
const profileConfig = await getProfileConfig();
|
||||
const profileConfig = await userDirectory.getProfileConfig();
|
||||
|
||||
const tmp = { inviteToken: '' };
|
||||
|
||||
@@ -972,32 +969,6 @@ async function setBackgroundImage(id, backgroundImage) {
|
||||
if (result.length === 0) throw new BoxError(BoxError.NOT_FOUND, 'User not found');
|
||||
}
|
||||
|
||||
async function getProfileConfig() {
|
||||
const value = await settings.getJson(settings.PROFILE_CONFIG_KEY);
|
||||
return value || { lockUserProfiles: false, mandatory2FA: false };
|
||||
}
|
||||
|
||||
async function setProfileConfig(profileConfig) {
|
||||
assert.strictEqual(typeof profileConfig, 'object');
|
||||
|
||||
if (constants.DEMO) throw new BoxError(BoxError.BAD_STATE, 'Not allowed in demo mode');
|
||||
|
||||
const oldConfig = await getProfileConfig();
|
||||
await settings.setJson(settings.PROFILE_CONFIG_KEY, profileConfig);
|
||||
|
||||
if (profileConfig.mandatory2FA && !oldConfig.mandatory2FA) {
|
||||
debug('setProfileConfig: logging out non-2FA users to enforce 2FA');
|
||||
|
||||
const allUsers = await list();
|
||||
for (const user of allUsers) {
|
||||
if (!user.twoFactorAuthenticationEnabled) {
|
||||
await tokens.delByUserIdAndType(user.id, tokens.ID_WEBADMIN);
|
||||
await oidc.revokeByUserId(user.id);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async function resetSource() {
|
||||
await database.query('UPDATE users SET source = ?', [ '' ]);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user