/* 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); }); }); });