diff --git a/src/routes/test/cloudron-test.js b/src/routes/test/cloudron-test.js index eed1e5e3d..48f274240 100644 --- a/src/routes/test/cloudron-test.js +++ b/src/routes/test/cloudron-test.js @@ -8,7 +8,8 @@ const constants = require('../../constants.js'), common = require('./common.js'), expect = require('expect.js'), - superagent = require('@cloudron/superagent'); + superagent = require('@cloudron/superagent'), + url = require('node:url'); describe('Cloudron', function () { const { setup, cleanup, serverUrl, owner, user, dashboardFqdn } = common; @@ -50,108 +51,100 @@ describe('Cloudron', function () { }); describe('account setup', function () { - it('succeeds without pre-set username and display name', async function () { - const USER = { - email: 'setup1@account.com', - password: 'test?!3434543534', - username: 'setupuser1', - displayName: 'setup user1', - }; + it('user can set username and display name', async function () { + const email = 'setup1@account.com'; + const password = 'test?!3434543534'; + const username = 'setupuser1'; + const displayName = 'setup user1'; const response = await superagent.post(`${serverUrl}/api/v1/users`) .query({ access_token: owner.token }) - .send({ email: USER.email }); + .send({ email }); expect(response.status).to.equal(201); - USER.id = response.body.id; + const userId = response.body.id; - const response2 = await superagent.get(`${serverUrl}/api/v1/users/${USER.id}/invite_link`) + const response2 = await superagent.get(`${serverUrl}/api/v1/users/${userId}/invite_link`) .query({ access_token: owner.token }) .ok(() => true); expect(response2.status).to.equal(200); const response3 = await superagent.post(`${serverUrl}/api/v1/auth/setup_account`) .send({ - inviteToken: require('node:url').parse(response2.body.inviteLink, true).query.inviteToken, - password: USER.password, - username: USER.username, - displayName: USER.displayName + inviteToken: url.parse(response2.body.inviteLink, true).query.inviteToken, + password, username, displayName }) .ok(() => true); expect(response3.status).to.equal(201); expect(response3.body.accessToken).to.be.a('string'); - const response4 = await superagent.get(`${serverUrl}/api/v1/users/${USER.id}`) + const response4 = await superagent.get(`${serverUrl}/api/v1/users/${userId}`) .query({ access_token: owner.token }) .ok(() => true); expect(response4.status).to.equal(200); - expect(response4.body.username).to.equal(USER.username); - expect(response4.body.displayName).to.equal(USER.displayName); + expect(response4.body.username).to.equal(username); + expect(response4.body.displayName).to.equal(displayName); const response5 = await superagent.post(`${serverUrl}/api/v1/auth/login`) - .send({ username: USER.username, password: USER.password }); + .send({ username, password }); expect(response5.status).to.equal(200); }); - it('succeeds and overwrites with pre-set username and display name', async function () { - const USER = { - email: 'setup2@account.com', - password: 'test?!3434543534', - username: 'presetup2', - displayName: 'setup user2', - }; + it('user can overwrite display name (username and email preset)', async function () { + const email = 'setup2@account.com'; + const password = 'test?!3434543534'; + const username = 'presetup2'; + const displayName = 'setup user2'; const response = await superagent.post(`${serverUrl}/api/v1/users`) .query({ access_token: owner.token }) - .send({ email: USER.email, username: 'presetup2', displayName: 'pre setup' }); + .send({ email, username: 'presetup2', displayName: 'pre setup' }); expect(response.status).to.equal(201); - USER.id = response.body.id; + const userId = response.body.id; - const response2 = await superagent.get(`${serverUrl}/api/v1/users/${USER.id}/invite_link`) + const response2 = await superagent.get(`${serverUrl}/api/v1/users/${userId}/invite_link`) .query({ access_token: owner.token }) .ok(() => true); expect(response2.status).to.equal(200); const response3 = await superagent.post(`${serverUrl}/api/v1/auth/setup_account`) .send({ - inviteToken: require('node:url').parse(response2.body.inviteLink, true).query.inviteToken, - password: USER.password, + inviteToken: url.parse(response2.body.inviteLink, true).query.inviteToken, + password, username: 'setupuser2', // this will cause a conflict. cannot change username - displayName: USER.displayName + displayName }) .ok(() => true); expect(response3.status).to.equal(409); const response4 = await superagent.post(`${serverUrl}/api/v1/auth/setup_account`) .send({ - inviteToken: require('node:url').parse(response2.body.inviteLink, true).query.inviteToken, - password: USER.password, - displayName: USER.displayName + inviteToken: url.parse(response2.body.inviteLink, true).query.inviteToken, + password, + displayName }) .ok(() => true); expect(response4.status).to.equal(201); expect(response4.body.accessToken).to.be.a('string'); - const response5 = await superagent.get(`${serverUrl}/api/v1/users/${USER.id}`) + const response5 = await superagent.get(`${serverUrl}/api/v1/users/${userId}`) .query({ access_token: owner.token }) .ok(() => true); expect(response5.status).to.equal(200); - expect(response5.body.username).to.equal(USER.username); - expect(response5.body.displayName).to.equal(USER.displayName); + expect(response5.body.username).to.equal(username); + expect(response5.body.displayName).to.equal(displayName); const response6 = await superagent.post(`${serverUrl}/api/v1/auth/login`) - .send({ username: USER.username, password: USER.password }); + .send({ username, password }); expect(response6.status).to.equal(200); }); - it('succeeds and does not overwrite pre-set username and display name if profiles are locked', async function () { - const USER = { - email: 'setup3@account.com', - password: 'test?!3434543534', - username: 'setupuser3', - displayName: 'setup user3', - }; + it('cannot set username and display name when profiles are locked', async function () { + const email = 'setup3@account.com'; + const password = 'test?!3434543534'; + const username = 'setupuser3'; + const displayName = 'setup user3'; const response0 = await superagent.post(`${serverUrl}/api/v1/user_directory/profile_config`) .query({ access_token: owner.token }) @@ -160,27 +153,33 @@ describe('Cloudron', function () { const response = await superagent.post(`${serverUrl}/api/v1/users`) .query({ access_token: owner.token }) - .send({ email: USER.email, username: 'presetup3', displayName: 'pre setup3' }); + .send({ email, username: 'presetup3', displayName: 'pre setup3' }); expect(response.status).to.equal(201); - USER.id = response.body.id; + const userId = response.body.id; - const response2 = await superagent.get(`${serverUrl}/api/v1/users/${USER.id}/invite_link`) + const response2 = await superagent.get(`${serverUrl}/api/v1/users/${userId}/invite_link`) .query({ access_token: owner.token }) .ok(() => true); expect(response2.status).to.equal(200); - const response3 = await superagent.post(`${serverUrl}/api/v1/auth/setup_account`) + let response3 = await superagent.post(`${serverUrl}/api/v1/auth/setup_account`) .send({ - inviteToken: require('node:url').parse(response2.body.inviteLink, true).query.inviteToken, - password: USER.password, - username: USER.username, // ignored - displayName: USER.displayName // ignored + inviteToken: url.parse(response2.body.inviteLink, true).query.inviteToken, + password, + username, // cannot set username when profile is locked + }) + .ok(() => true); + expect(response3.status).to.equal(409); + + response3 = await superagent.post(`${serverUrl}/api/v1/auth/setup_account`) + .send({ + inviteToken: url.parse(response2.body.inviteLink, true).query.inviteToken, + password, }) .ok(() => true); expect(response3.status).to.equal(201); - expect(response3.body.accessToken).to.be.a('string'); - const response4 = await superagent.get(`${serverUrl}/api/v1/users/${USER.id}`) + const response4 = await superagent.get(`${serverUrl}/api/v1/users/${userId}`) .query({ access_token: owner.token }) .ok(() => true); @@ -189,7 +188,7 @@ describe('Cloudron', function () { expect(response4.body.displayName).to.equal('pre setup3'); // what the admin provided const response5 = await superagent.post(`${serverUrl}/api/v1/auth/login`) - .send({ username: 'presetup3', password: USER.password }); + .send({ username: 'presetup3', password }); expect(response5.status).to.equal(200); }); }); diff --git a/src/users.js b/src/users.js index e8fea57ef..7c3a4e8fd 100644 --- a/src/users.js +++ b/src/users.js @@ -887,6 +887,14 @@ async function setupAccount(user, data, auditSource) { assert.strictEqual(typeof data, 'object'); assert(auditSource && typeof auditSource === 'object'); + const profileConfig = await userDirectory.getProfileConfig(); + + // error out if admin has not provided a username + if (profileConfig.lockUserProfiles) { + if (!user.username) throw new BoxError(BoxError.CONFLICT, 'Account cannot be setup without a username'); + if (data.username) throw new BoxError(BoxError.CONFLICT, 'Username cannot be changed because profiles are locked'); + } + const tmp = { inviteToken: '' }; if (data.username) { @@ -906,13 +914,6 @@ async function setupAccount(user, data, auditSource) { const error = validatePassword(data.password); if (error) throw error; - const profileConfig = await userDirectory.getProfileConfig(); - - // error out if admin has not provided a username - if (profileConfig.lockUserProfiles && !user.username) { - throw new BoxError(BoxError.CONFLICT, 'Account cannot be setup without a username'); - } - await update(user, tmp, auditSource); await setPassword(user, data.password, auditSource);