we discussed a bit on what this does and it's confusing as it stands: * Use case of this is lost in the realms of time * Possible guess by is that it was to move users of different Cloudron to a central cloudron * Currently, the design is a bit flawed because the make user local button doesn’t pin the user. The state is lost in next synchronization. * Maybe, one should use export/import user for this use case * Let’s disable this button for now, feature is not complete.
612 lines
24 KiB
JavaScript
612 lines
24 KiB
JavaScript
/* global it:false */
|
|
/* global describe:false */
|
|
/* global before:false */
|
|
/* global after:false */
|
|
|
|
'use strict';
|
|
|
|
const common = require('./common.js'),
|
|
expect = require('expect.js'),
|
|
superagent = require('superagent'),
|
|
users = require('../../users.js');
|
|
|
|
describe('Users API', function () {
|
|
const { setup, cleanup, serverUrl, owner, user, dashboardDomain } = common;
|
|
|
|
const user2 = {
|
|
id: null,
|
|
username: 'User2',
|
|
password: 'Foobar?1339',
|
|
email: 'uSer2@cloudron.LoCal',
|
|
token: null
|
|
};
|
|
|
|
const user3 = {
|
|
id: null,
|
|
username: 'transientuser',
|
|
password: 'Foobar?1334',
|
|
email: 'transient@cloudron.LoCal',
|
|
};
|
|
|
|
const unnamedUser = {
|
|
id: null,
|
|
email: 'unnameduser@cloudron.local',
|
|
};
|
|
|
|
const userWithPassword = {
|
|
id: null,
|
|
username: 'userwithpassword',
|
|
password: 'Secret123#',
|
|
email: 'userwithpassword@cloudron.local',
|
|
token: null
|
|
};
|
|
|
|
before(setup);
|
|
after(cleanup);
|
|
|
|
describe('user info', async function () {
|
|
it('cannot get userInfo of random user', async function () {
|
|
const response = await superagent.get(`${serverUrl}/api/v1/users/baduserid`)
|
|
.query({ access_token: owner.token })
|
|
.ok(() => true);
|
|
|
|
expect(response.statusCode).to.equal(404);
|
|
});
|
|
|
|
it('can get userInfo with token', async function () {
|
|
const response = await superagent.get(`${serverUrl}/api/v1/users/${user.id}`)
|
|
.query({ access_token: owner.token });
|
|
|
|
expect(response.statusCode).to.equal(200);
|
|
expect(response.body.username).to.equal(user.username.toLowerCase());
|
|
expect(response.body.email).to.equal(user.email.toLowerCase());
|
|
expect(response.body.groupIds).to.eql([]);
|
|
expect(response.body.role).to.be(users.ROLE_USER);
|
|
});
|
|
|
|
it('cannot get userInfo with normal user token', async function () {
|
|
const reponse = await superagent.get(`${serverUrl}/api/v1/users/${user.id}`)
|
|
.query({ access_token: user.token })
|
|
.ok(() => true);
|
|
|
|
expect(reponse.statusCode).to.equal(403);
|
|
});
|
|
});
|
|
|
|
describe('create user', function () {
|
|
it('cannot create user without email', async function () {
|
|
const response = await superagent.post(`${serverUrl}/api/v1/users`)
|
|
.query({ access_token: owner.token })
|
|
.send({ username: user2.username })
|
|
.ok(() => true);
|
|
|
|
expect(response.statusCode).to.equal(400);
|
|
});
|
|
|
|
it('cannot create user with non email fallbackEmail', async function () {
|
|
const response = await superagent.post(`${serverUrl}/api/v1/users`)
|
|
.query({ access_token: owner.token })
|
|
.send({ username: user2.username, email: user2.email, fallbackEmail: 'notanemail' })
|
|
.ok(() => true);
|
|
|
|
expect(response.statusCode).to.equal(400);
|
|
});
|
|
|
|
it('create second user succeeds', async function () {
|
|
const response = await superagent.post(`${serverUrl}/api/v1/users`)
|
|
.query({ access_token: owner.token })
|
|
.send({ username: user2.username, email: user2.email });
|
|
|
|
expect(response.statusCode).to.equal(201);
|
|
|
|
user2.id = response.body.id;
|
|
});
|
|
|
|
it('get userInfo succeeds for second user', async function () {
|
|
const response = await superagent.get(`${serverUrl}/api/v1/users/${user2.id}`)
|
|
.query({ access_token: owner.token });
|
|
|
|
expect(response.statusCode).to.equal(200);
|
|
expect(response.body.username).to.equal(user2.username.toLowerCase());
|
|
expect(response.body.email).to.equal(user2.email.toLowerCase());
|
|
expect(response.body.groupIds).to.eql([]);
|
|
});
|
|
|
|
it('create user missing username succeeds', async function () {
|
|
const response = await superagent.post(`${serverUrl}/api/v1/users`)
|
|
.query({ access_token: owner.token })
|
|
.send({ email: unnamedUser.email });
|
|
|
|
expect(response.statusCode).to.equal(201);
|
|
unnamedUser.id = response.body.id;
|
|
});
|
|
|
|
it('create user missing email fails', async function () {
|
|
const response = await superagent.post(`${serverUrl}/api/v1/users`)
|
|
.query({ access_token: owner.token })
|
|
.send({ username: 'someusername' })
|
|
.ok(() => true);
|
|
|
|
expect(response.statusCode).to.equal(400);
|
|
});
|
|
|
|
it('create user reserved name fails', async function () {
|
|
const response = await superagent.post(`${serverUrl}/api/v1/users`)
|
|
.query({ access_token: owner.token })
|
|
.send({ username: 'no-reply', email: 'reserved@cloudron.local' })
|
|
.ok(() => true);
|
|
|
|
expect(response.statusCode).to.equal(400);
|
|
});
|
|
|
|
it('create user with short name succeeds', async function () {
|
|
const response = await superagent.post(`${serverUrl}/api/v1/users`)
|
|
.query({ access_token: owner.token })
|
|
.send({ username: 'n', email: 'singleletter@cloudron.local' });
|
|
|
|
expect(response.statusCode).to.equal(201);
|
|
});
|
|
|
|
it('create user with same username should fail', async function () {
|
|
const response = await superagent.post(`${serverUrl}/api/v1/users`)
|
|
.query({ access_token: owner.token })
|
|
.send({ username: user2.username, email: user2.email })
|
|
.ok(() => true);
|
|
|
|
expect(response.statusCode).to.equal(409);
|
|
});
|
|
|
|
it('cannot create user with bad password', async function () {
|
|
const response = await superagent.post(`${serverUrl}/api/v1/users`)
|
|
.query({ access_token: owner.token })
|
|
.send({ username: 'badpassworduser', email: 'badpass@cloudron.local', password:'tooweak' })
|
|
.ok(() => true);
|
|
|
|
expect(response.statusCode).to.equal(400);
|
|
});
|
|
|
|
it('can create user with a password', async function () {
|
|
const response = await superagent.post(`${serverUrl}/api/v1/users`)
|
|
.query({ access_token: owner.token })
|
|
.send({ username: userWithPassword.username, email: userWithPassword.email, password: userWithPassword.password });
|
|
|
|
expect(response.statusCode).to.equal(201);
|
|
userWithPassword.id = response.body.id;
|
|
});
|
|
|
|
it('did set password of created user', async function () {
|
|
await users.verify(userWithPassword.id, userWithPassword.password, users.AP_WEBADMIN, {});
|
|
});
|
|
});
|
|
|
|
describe('invite', function () {
|
|
it('creationg fails for unknown user', async function () {
|
|
const response = await superagent.get(`${serverUrl}/api/v1/users/randomuserid/invite_link`)
|
|
.query({ access_token: owner.token })
|
|
.send({})
|
|
.ok(() => true);
|
|
|
|
expect(response.statusCode).to.equal(404);
|
|
});
|
|
|
|
it('creation succeeds', async function () {
|
|
const response = await superagent.get(`${serverUrl}/api/v1/users/${user.id}/invite_link`)
|
|
.query({ access_token: owner.token })
|
|
.send({})
|
|
.ok(() => true);
|
|
|
|
expect(response.statusCode).to.equal(200);
|
|
expect(response.body.inviteLink).to.be.a('string');
|
|
});
|
|
|
|
it('sending succeeds', async function () {
|
|
common.clearMailQueue();
|
|
|
|
const response = await superagent.post(`${serverUrl}/api/v1/users/${user.id}/send_invite_email`)
|
|
.query({ access_token: owner.token })
|
|
.send({ email: user.email });
|
|
|
|
expect(response.statusCode).to.equal(202);
|
|
await common.checkMails(1);
|
|
});
|
|
});
|
|
|
|
describe('admin status', function () {
|
|
it('set second user as admin succeeds', async function () {
|
|
const response = await superagent.post(`${serverUrl}/api/v1/users/${user.id}`)
|
|
.query({ access_token: owner.token })
|
|
.send({ role: users.ROLE_ADMIN });
|
|
|
|
expect(response.statusCode).to.equal(204);
|
|
});
|
|
|
|
it('did set second user as admin', async function () {
|
|
const response = await superagent.get(`${serverUrl}/api/v1/users/${user.id}`)
|
|
.query({ access_token: owner.token });
|
|
|
|
expect(response.statusCode).to.equal(200);
|
|
expect(response.body.role).to.be(users.ROLE_ADMIN);
|
|
});
|
|
|
|
it('make self as admin fails', async function () {
|
|
const response = await superagent.post(`${serverUrl}/api/v1/users/${owner.id}`)
|
|
.query({ access_token: owner.token })
|
|
.send({ role: users.ROLE_ADMIN })
|
|
.ok(() => true);
|
|
|
|
expect(response.statusCode).to.equal(409);
|
|
});
|
|
|
|
it('make self as normal user fails', async function () {
|
|
const response = await superagent.post(`${serverUrl}/api/v1/users/${owner.id}`)
|
|
.query({ access_token: owner.token })
|
|
.send({ role: users.ROLE_USER })
|
|
.ok(() => true);
|
|
|
|
expect(response.statusCode).to.equal(409);
|
|
});
|
|
|
|
it('remove second user as admin succeeds', async function () {
|
|
const response = await superagent.post(`${serverUrl}/api/v1/users/${user.id}`)
|
|
.query({ access_token: owner.token })
|
|
.send({ role: users.ROLE_USER });
|
|
|
|
expect(response.statusCode).to.equal(204);
|
|
});
|
|
|
|
it('normal user cannot change role of admin', async function () {
|
|
const response = await superagent.post(`${serverUrl}/api/v1/users/${owner.id}`)
|
|
.query({ access_token: user.token })
|
|
.send({ role: users.ROLE_USER })
|
|
.ok(() => true);
|
|
|
|
expect(response.statusCode).to.equal(403);
|
|
});
|
|
});
|
|
|
|
describe('groups', function () {
|
|
it('lists groupIds when listing users', async function () {
|
|
const response = await superagent.get(`${serverUrl}/api/v1/users`)
|
|
.query({ access_token: owner.token });
|
|
|
|
expect(response.statusCode).to.equal(200);
|
|
expect(response.body.users).to.be.an('array');
|
|
|
|
response.body.users.forEach(function (user) {
|
|
expect('groupIds' in user).to.be(true);
|
|
});
|
|
});
|
|
});
|
|
|
|
describe('list users', function () {
|
|
it('list users fails for normal user', async function () {
|
|
const response = await superagent.get(`${serverUrl}/api/v1/users`)
|
|
.query({ access_token: user.token })
|
|
.ok(() => true);
|
|
|
|
expect(response.statusCode).to.equal(403);
|
|
});
|
|
|
|
it('list users succeeds for admin', async function () {
|
|
const response = await superagent.get(`${serverUrl}/api/v1/users`)
|
|
.query({ access_token: owner.token });
|
|
|
|
expect(response.statusCode).to.equal(200);
|
|
expect(response.body.users).to.be.an('array');
|
|
expect(response.body.users.length).to.be.greaterThan(3);
|
|
|
|
response.body.users.forEach(function (user) {
|
|
expect(user).to.be.an('object');
|
|
expect(user.id).to.be.ok();
|
|
expect(user.email).to.be.ok();
|
|
expect(user.role).to.be.ok();
|
|
if (!user.email.startsWith('unnamed')) expect(user.username).to.be.ok();
|
|
expect(user.password).to.not.be.ok();
|
|
expect(user.salt).to.not.be.ok();
|
|
});
|
|
});
|
|
});
|
|
|
|
describe('update', function () {
|
|
it('change email fails due to missing token', async function () {
|
|
const response = await superagent.post(`${serverUrl}/api/v1/users/${user2.id}`)
|
|
.send({ email: 'newemail@cloudron.local' })
|
|
.ok(() => true);
|
|
|
|
expect(response.statusCode).to.equal(401);
|
|
});
|
|
|
|
it('change email fails due to invalid email', async function () {
|
|
const response = await superagent.post(`${serverUrl}/api/v1/users/${user2.id}`)
|
|
.query({ access_token: owner.token })
|
|
.send({ email: 'newemail@cloudron' })
|
|
.ok(() => true);
|
|
|
|
expect(response.statusCode).to.equal(400);
|
|
});
|
|
|
|
it('change fallbackEmail fails due to invalid email', async function () {
|
|
const response = await superagent.post(`${serverUrl}/api/v1/users/${user2.id}`)
|
|
.query({ access_token: owner.token })
|
|
.send({ fallbackEmail: 'newemail@cloudron' })
|
|
.ok(() => true);
|
|
|
|
expect(response.statusCode).to.equal(400);
|
|
});
|
|
|
|
it('change user succeeds without email nor displayName', async function () {
|
|
const response = await superagent.post(`${serverUrl}/api/v1/users/${user2.id}`)
|
|
.query({ access_token: owner.token })
|
|
.send({});
|
|
|
|
expect(response.statusCode).to.equal(204);
|
|
});
|
|
|
|
it('change email succeeds', async function () {
|
|
user2.email = 'NewEmail@cloudron.local';
|
|
const response = await superagent.post(`${serverUrl}/api/v1/users/${user2.id}`)
|
|
.query({ access_token: owner.token })
|
|
.send({ email: user2.email });
|
|
|
|
expect(response.statusCode).to.equal(204);
|
|
|
|
const response2 = await superagent.get(`${serverUrl}/api/v1/users/${user2.id}`)
|
|
.query({ access_token: owner.token });
|
|
|
|
expect(response2.statusCode).to.equal(200);
|
|
expect(response2.body.username).to.equal(user2.username.toLowerCase());
|
|
expect(response2.body.email).to.equal(user2.email.toLowerCase());
|
|
expect(response2.body.displayName).to.equal('');
|
|
});
|
|
|
|
it('cannot change email to existing one', async function () {
|
|
const response = await superagent.post(`${serverUrl}/api/v1/users/${user2.id}`)
|
|
.query({ access_token: owner.token })
|
|
.send({ email: owner.email })
|
|
.ok(() => true);
|
|
|
|
expect(response.statusCode).to.equal(409);
|
|
});
|
|
|
|
it('can change display name', async function () {
|
|
const displayName = 'New name';
|
|
|
|
const response = await superagent.post(`${serverUrl}/api/v1/users/${user2.id}`)
|
|
.query({ access_token: owner.token })
|
|
.send({ displayName: displayName });
|
|
|
|
expect(response.statusCode).to.equal(204);
|
|
|
|
const response2 = await superagent.get(`${serverUrl}/api/v1/users/${user2.id}`)
|
|
.query({ access_token: owner.token });
|
|
|
|
expect(response2.statusCode).to.equal(200);
|
|
expect(response2.body.displayName).to.equal(displayName);
|
|
});
|
|
});
|
|
|
|
describe('password', function () {
|
|
it('change password fails due to missing token', async function () {
|
|
const response = await superagent.post(`${serverUrl}/api/v1/users/${user.id}/password`)
|
|
.send({ password: 'youdontsay' })
|
|
.ok(() => true);
|
|
|
|
expect(response.statusCode).to.equal(401);
|
|
});
|
|
|
|
it('change password fails due to small password', async function () {
|
|
const response = await superagent.post(`${serverUrl}/api/v1/users/${user.id}/password`)
|
|
.query({ access_token: owner.token })
|
|
.send({ password: 'small' })
|
|
.ok(() => true);
|
|
|
|
expect(response.statusCode).to.equal(400);
|
|
});
|
|
|
|
it('change password succeeds', async function () {
|
|
const response = await superagent.post(`${serverUrl}/api/v1/users/${user.id}/password`)
|
|
.query({ access_token: owner.token })
|
|
.send({ password: 'bigenough' });
|
|
|
|
expect(response.statusCode).to.equal(204);
|
|
});
|
|
|
|
it('did change the user password', async function () {
|
|
await users.verify(user.id, 'bigenough', users.AP_WEBADMIN, {});
|
|
});
|
|
});
|
|
|
|
describe('role - user manager', function () {
|
|
it('can make normal user a usermanager', async function () {
|
|
const response = await superagent.post(`${serverUrl}/api/v1/users/${user.id}`)
|
|
.query({ access_token: owner.token })
|
|
.send({ role: users.ROLE_USER_MANAGER });
|
|
|
|
expect(response.statusCode).to.equal(204);
|
|
});
|
|
|
|
it('can list users as usermanager', async function () {
|
|
const response = await superagent.get(`${serverUrl}/api/v1/users`)
|
|
.query({ access_token: user.token });
|
|
|
|
expect(response.statusCode).to.equal(200);
|
|
expect(response.body.users).to.be.an(Array);
|
|
expect(response.body.users.length).to.be.greaterThan(3);
|
|
});
|
|
|
|
it('cannot set password of admin', async function () {
|
|
const response = await superagent.post(`${serverUrl}/api/v1/users/${owner.id}/password`)
|
|
.query({ access_token: user.token })
|
|
.send({ password: 'bigenough' })
|
|
.ok(() => true);
|
|
|
|
expect(response.statusCode).to.equal(403);
|
|
});
|
|
|
|
it('can set password of another', async function () {
|
|
const response = await superagent.post(`${serverUrl}/api/v1/users/${user2.id}/password`)
|
|
.query({ access_token: user.token })
|
|
.send({ password: 'bigenough' });
|
|
|
|
expect(response.statusCode).to.equal(204);
|
|
});
|
|
|
|
it('cannot change admin bit of another', async function () {
|
|
const response = await superagent.post(`${serverUrl}/api/v1/users/${owner.id}`)
|
|
.query({ access_token: user.token })
|
|
.send({ role: users.ROLE_ADMIN })
|
|
.ok(() => true);
|
|
|
|
expect(response.statusCode).to.equal(403);
|
|
});
|
|
|
|
it('cannot change admin bit of self', async function () {
|
|
const response = await superagent.post(`${serverUrl}/api/v1/users/${user.id}`)
|
|
.query({ access_token: user.token })
|
|
.send({ role: users.ROLE_ADMIN })
|
|
.ok(() => true);
|
|
|
|
expect(response.statusCode).to.equal(409);
|
|
});
|
|
|
|
it('cannot remove admin', async function () {
|
|
const response = await superagent.del(`${serverUrl}/api/v1/users/${owner.id}`)
|
|
.query({ access_token: user.token })
|
|
.ok(() => true);
|
|
|
|
expect(response.statusCode).to.equal(403);
|
|
});
|
|
|
|
it('can create user as user manager', async function () {
|
|
const response = await superagent.post(`${serverUrl}/api/v1/users`)
|
|
.query({ access_token: user.token })
|
|
.send({ username: user3.username, email: user3.email });
|
|
|
|
expect(response.statusCode).to.equal(201);
|
|
|
|
user3.id = response.body.id;
|
|
});
|
|
|
|
it('can remove normal user as user manager', async function () {
|
|
const response = await superagent.del(`${serverUrl}/api/v1/users/${user3.id}`)
|
|
.query({ access_token: user.token });
|
|
|
|
expect(response.statusCode).to.equal(204);
|
|
});
|
|
|
|
it('add mailbox fails', async function () {
|
|
const response = await superagent.post(`${serverUrl}/api/v1/mail/${dashboardDomain}/mailboxes`)
|
|
.send({ name: 'support', ownerId: owner.id, ownerType: 'user', active: true })
|
|
.query({ access_token: user.token })
|
|
.ok(() => true);
|
|
|
|
expect(response.statusCode).to.equal(403);
|
|
});
|
|
});
|
|
|
|
describe('role - mail manager', function () {
|
|
it('can make normal user a usermanager', async function () {
|
|
const response = await superagent.post(`${serverUrl}/api/v1/users/${user.id}`)
|
|
.query({ access_token: owner.token })
|
|
.send({ role: users.ROLE_MAIL_MANAGER });
|
|
|
|
expect(response.statusCode).to.equal(204);
|
|
});
|
|
|
|
it('can list users as mail manager', async function () {
|
|
const response = await superagent.get(`${serverUrl}/api/v1/users`)
|
|
.query({ access_token: user.token });
|
|
|
|
expect(response.statusCode).to.equal(200);
|
|
expect(response.body.users).to.be.an(Array);
|
|
expect(response.body.users.length).to.be.greaterThan(3);
|
|
});
|
|
|
|
it('cannot change admin bit of self', async function () {
|
|
const response = await superagent.post(`${serverUrl}/api/v1/users/${user.id}`)
|
|
.query({ access_token: user.token })
|
|
.send({ role: users.ROLE_ADMIN })
|
|
.ok(() => true);
|
|
|
|
expect(response.statusCode).to.equal(409);
|
|
});
|
|
|
|
it('cannot remove admin', async function () {
|
|
const response = await superagent.del(`${serverUrl}/api/v1/users/${owner.id}`)
|
|
.query({ access_token: user.token })
|
|
.ok(() => true);
|
|
|
|
expect(response.statusCode).to.equal(403);
|
|
});
|
|
|
|
it('can create user as mail manager', async function () {
|
|
const response = await superagent.post(`${serverUrl}/api/v1/users`)
|
|
.query({ access_token: user.token })
|
|
.send({ username: user3.username, email: user3.email });
|
|
|
|
expect(response.statusCode).to.equal(201);
|
|
|
|
user3.id = response.body.id;
|
|
});
|
|
|
|
it('can remove normal user as mail manager', async function () {
|
|
const response = await superagent.del(`${serverUrl}/api/v1/users/${user3.id}`)
|
|
.query({ access_token: user.token });
|
|
|
|
expect(response.statusCode).to.equal(204);
|
|
});
|
|
|
|
it('add mailbox succeeds as mail manager', async function () {
|
|
const response = await superagent.post(`${serverUrl}/api/v1/mail/${dashboardDomain}/mailboxes`)
|
|
.send({ name: 'support', ownerId: owner.id, ownerType: 'user', active: true, storageQuota: 0, messagesQuota: 0 })
|
|
.query({ access_token: user.token });
|
|
|
|
expect(response.statusCode).to.equal(201);
|
|
});
|
|
|
|
it('list mailbox succeeds as mail manager', async function () {
|
|
const response = await superagent.get(`${serverUrl}/api/v1/mail/${dashboardDomain}/mailboxes`)
|
|
.query({ access_token: user.token });
|
|
|
|
expect(response.statusCode).to.equal(200);
|
|
expect(response.body.mailboxes.length).to.be(1);
|
|
expect(response.body.mailboxes[0].name).to.be('support');
|
|
});
|
|
});
|
|
|
|
describe('remove', function () {
|
|
it('remove random user fails', async function () {
|
|
const response = await superagent.del(`${serverUrl}/api/v1/users/randomid`)
|
|
.query({ access_token: owner.token })
|
|
.ok(() => true);
|
|
|
|
expect(response.statusCode).to.equal(404);
|
|
});
|
|
|
|
it('user cannot removes himself', async function () {
|
|
const response = await superagent.del(`${serverUrl}/api/v1/users/${owner.id}`)
|
|
.query({ access_token: owner.token })
|
|
.ok(() => true);
|
|
|
|
expect(response.statusCode).to.equal(409);
|
|
});
|
|
|
|
it('admin removes normal user', async function () {
|
|
const response = await superagent.del(`${serverUrl}/api/v1/users/${user2.id}`)
|
|
.query({ access_token: owner.token })
|
|
.ok(() => true);
|
|
|
|
expect(response.statusCode).to.equal(204);
|
|
});
|
|
|
|
it('admin removes himself should not be allowed', async function () {
|
|
const response = await superagent.del(`${serverUrl}/api/v1/users/${owner.id}`)
|
|
.query({ access_token: owner.token })
|
|
.ok(() => true);
|
|
|
|
expect(response.statusCode).to.equal(409);
|
|
});
|
|
});
|
|
});
|
|
|