diff --git a/src/routes/test/users-test.js b/src/routes/test/users-test.js index eb2d0f60c..e0c7a62a5 100644 --- a/src/routes/test/users-test.js +++ b/src/routes/test/users-test.js @@ -88,724 +88,752 @@ describe('Users API', function () { before(setup); after(cleanup); - it('device is in first time mode', function (done) { - superagent.get(SERVER_URL + '/api/v1/cloudron/status') - .end(function (err, res) { - expect(res.statusCode).to.equal(200); - expect(res.body.activated).to.not.be.ok(); - done(err); - }); + describe('owner', function () { + it('device is in first time mode', function (done) { + superagent.get(SERVER_URL + '/api/v1/cloudron/status') + .end(function (err, res) { + expect(res.statusCode).to.equal(200); + expect(res.body.activated).to.not.be.ok(); + done(err); + }); + }); + + it('create admin fails due to missing parameters', function (done) { + superagent.post(SERVER_URL + '/api/v1/cloudron/activate') + .query({ setupToken: 'somesetuptoken' }) + .send({ username: USERNAME_0 }) + .end(function (err, res) { + expect(res.statusCode).to.equal(400); + done(); + }); + }); + + it('create admin fails because only POST is allowed', function (done) { + superagent.get(SERVER_URL + '/api/v1/cloudron/activate') + .end(function (err, res) { + expect(res.statusCode).to.equal(404); + done(); + }); + }); + + it('create admin', function (done) { + superagent.post(SERVER_URL + '/api/v1/cloudron/activate') + .query({ setupToken: 'somesetuptoken' }) + .send({ username: USERNAME_0, password: PASSWORD, email: EMAIL_0 }) + .end(function (err, res) { + expect(err).to.eql(null); + expect(res.statusCode).to.equal(201); + + // stash for later use + token = res.body.token; + + superagent.get(SERVER_URL + '/api/v1/profile').query({ access_token: token }).end(function (error, result) { + expect(error).to.eql(null); + expect(result.status).to.equal(200); + + // stash for further use + user_0 = result.body; + + done(); + }); + }); + }); + + it('device left first time mode', function (done) { + superagent.get(SERVER_URL + '/api/v1/cloudron/status') + .end(function (err, res) { + expect(res.statusCode).to.equal(200); + expect(res.body.activated).to.be.ok(); + done(); + }); + }); }); - it('create admin fails due to missing parameters', function (done) { - superagent.post(SERVER_URL + '/api/v1/cloudron/activate') - .query({ setupToken: 'somesetuptoken' }) - .send({ username: USERNAME_0 }) - .end(function (err, res) { - expect(res.statusCode).to.equal(400); - done(); - }); - }); - - it('create admin fails because only POST is allowed', function (done) { - superagent.get(SERVER_URL + '/api/v1/cloudron/activate') - .end(function (err, res) { - expect(res.statusCode).to.equal(404); - done(); - }); - }); - - it('create admin', function (done) { - superagent.post(SERVER_URL + '/api/v1/cloudron/activate') - .query({ setupToken: 'somesetuptoken' }) - .send({ username: USERNAME_0, password: PASSWORD, email: EMAIL_0 }) - .end(function (err, res) { - expect(err).to.eql(null); - expect(res.statusCode).to.equal(201); - - // stash for later use - token = res.body.token; - - superagent.get(SERVER_URL + '/api/v1/profile').query({ access_token: token }).end(function (error, result) { - expect(error).to.eql(null); - expect(result.status).to.equal(200); - - // stash for further use - user_0 = result.body; + describe('user info', function () { + it('cannot get userInfo by username', function (done) { + superagent.get(SERVER_URL + '/api/v1/users/' + USERNAME_0) + .query({ access_token: token }) + .end(function (err, res) { + expect(res.statusCode).to.equal(404); done(); }); + }); + + it('can get userInfo with token', function (done) { + superagent.get(SERVER_URL + '/api/v1/users/' + user_0.id) + .query({ access_token: token }) + .end(function (err, res) { + expect(res.statusCode).to.equal(200); + expect(res.body.username).to.equal(USERNAME_0.toLowerCase()); + expect(res.body.email).to.equal(EMAIL_0.toLowerCase()); + expect(res.body.groupIds).to.eql([]); + expect(res.body.admin).to.be(true); + + done(); + }); + }); + + it('cannot get userInfo with expired token', function (done) { + var expires = Date.now() + 2000; // 1 sec + + let token = { + id: 'tid-0', + accessToken: hat(8 * 32), + identifier: user_0.id, + clientId: null, + expires: expires, + scope: 'unused', + name: 'tokenname' + }; + + tokendb.add(token, function (error) { + expect(error).to.not.be.ok(); + + setTimeout(function () { + superagent.get(SERVER_URL + '/api/v1/users/' + user_0.username) + .query({ access_token: token.accessToken }) + .end(function (error, result) { + expect(result.statusCode).to.equal(401); + done(); + }); + }, 2000); }); - }); + }); - it('device left first time mode', function (done) { - superagent.get(SERVER_URL + '/api/v1/cloudron/status') - .end(function (err, res) { - expect(res.statusCode).to.equal(200); - expect(res.body.activated).to.be.ok(); - done(); - }); - }); + it('can get userInfo with token', function (done) { + superagent.get(SERVER_URL + '/api/v1/users/' + user_0.id) + .query({ access_token: token }) + .end(function (err, res) { + expect(res.statusCode).to.equal(200); + expect(res.body.username).to.equal(USERNAME_0.toLowerCase()); + expect(res.body.email).to.equal(EMAIL_0.toLowerCase()); + expect(res.body.groupIds).to.eql([]); + expect(res.body.admin).to.be(true); - it('cannot get userInfo by username', function (done) { - superagent.get(SERVER_URL + '/api/v1/users/' + USERNAME_0) - .query({ access_token: token }) - .end(function (err, res) { - expect(res.statusCode).to.equal(404); + done(); + }); + }); - done(); - }); - }); + it('cannot get userInfo only with basic auth', function (done) { + superagent.get(SERVER_URL + '/api/v1/users/' + user_0.id) + .auth(USERNAME_0, PASSWORD) + .end(function (err, res) { + expect(res.statusCode).to.equal(401); + done(); + }); + }); - it('can get userInfo with token', function (done) { - superagent.get(SERVER_URL + '/api/v1/users/' + user_0.id) - .query({ access_token: token }) - .end(function (err, res) { - expect(res.statusCode).to.equal(200); - expect(res.body.username).to.equal(USERNAME_0.toLowerCase()); - expect(res.body.email).to.equal(EMAIL_0.toLowerCase()); - expect(res.body.groupIds).to.eql([]); - expect(res.body.admin).to.be(true); + it('cannot get userInfo with invalid token (token length)', function (done) { + superagent.get(SERVER_URL + '/api/v1/users/' + user_0.id) + .query({ access_token: 'x' + token }) + .end(function (err, res) { + expect(res.statusCode).to.equal(401); + done(); + }); + }); - done(); - }); - }); + it('cannot get userInfo with invalid token (wrong token)', function (done) { + superagent.get(SERVER_URL + '/api/v1/users/' + user_0.id) + .query({ access_token: token.toUpperCase() }) + .end(function (err, res) { + expect(res.statusCode).to.equal(401); + done(); + }); + }); - it('cannot get userInfo with expired token', function (done) { - var expires = Date.now() + 2000; // 1 sec + it('can get userInfo with token in auth header', function (done) { + superagent.get(SERVER_URL + '/api/v1/users/' + user_0.id) + .set('Authorization', 'Bearer ' + token) + .end(function (err, res) { + expect(res.statusCode).to.equal(200); + expect(res.body.username).to.equal(USERNAME_0.toLowerCase()); + expect(res.body.email).to.equal(EMAIL_0.toLowerCase()); + expect(res.body.groupIds).to.eql([]); + expect(res.body.admin).to.be(true); + expect(res.body.displayName).to.be.a('string'); + expect(res.body.password).to.not.be.ok(); + expect(res.body.salt).to.not.be.ok(); + done(); + }); + }); - let token = { - id: 'tid-0', - accessToken: hat(8 * 32), - identifier: user_0.id, - clientId: null, - expires: expires, - scope: 'unused', - name: 'tokenname' - }; + it('cannot get userInfo with invalid token in auth header', function (done) { + superagent.get(SERVER_URL + '/api/v1/users/' + user_0.id) + .set('Authorization', 'Bearer ' + 'x' + token) + .end(function (err, res) { + expect(res.statusCode).to.equal(401); + done(); + }); + }); - tokendb.add(token, function (error) { - expect(error).to.not.be.ok(); - - setTimeout(function () { - superagent.get(SERVER_URL + '/api/v1/users/' + user_0.username) - .query({ access_token: token.accessToken }) - .end(function (error, result) { - expect(result.statusCode).to.equal(401); - done(); - }); - }, 2000); + it('cannot get userInfo with invalid token (wrong token)', function (done) { + superagent.get(SERVER_URL + '/api/v1/users/' + user_0.id) + .set('Authorization', 'Bearer ' + 'x' + token.toUpperCase()) + .end(function (err, res) { + expect(res.statusCode).to.equal(401); + done(); + }); }); }); - it('can get userInfo with token', function (done) { - superagent.get(SERVER_URL + '/api/v1/users/' + user_0.id) - .query({ access_token: token }) - .end(function (err, res) { - expect(res.statusCode).to.equal(200); - expect(res.body.username).to.equal(USERNAME_0.toLowerCase()); - expect(res.body.email).to.equal(EMAIL_0.toLowerCase()); - expect(res.body.groupIds).to.eql([]); - expect(res.body.admin).to.be(true); + describe('create user', function () { - done(); - }); - }); - - it('cannot get userInfo only with basic auth', function (done) { - superagent.get(SERVER_URL + '/api/v1/users/' + user_0.id) - .auth(USERNAME_0, PASSWORD) - .end(function (err, res) { - expect(res.statusCode).to.equal(401); - done(); - }); - }); - - it('cannot get userInfo with invalid token (token length)', function (done) { - superagent.get(SERVER_URL + '/api/v1/users/' + user_0.id) - .query({ access_token: 'x' + token }) - .end(function (err, res) { - expect(res.statusCode).to.equal(401); - done(); - }); - }); - - it('cannot get userInfo with invalid token (wrong token)', function (done) { - superagent.get(SERVER_URL + '/api/v1/users/' + user_0.id) - .query({ access_token: token.toUpperCase() }) - .end(function (err, res) { - expect(res.statusCode).to.equal(401); - done(); - }); - }); - - it('can get userInfo with token in auth header', function (done) { - superagent.get(SERVER_URL + '/api/v1/users/' + user_0.id) - .set('Authorization', 'Bearer ' + token) - .end(function (err, res) { - expect(res.statusCode).to.equal(200); - expect(res.body.username).to.equal(USERNAME_0.toLowerCase()); - expect(res.body.email).to.equal(EMAIL_0.toLowerCase()); - expect(res.body.groupIds).to.eql([]); - expect(res.body.admin).to.be(true); - expect(res.body.displayName).to.be.a('string'); - expect(res.body.password).to.not.be.ok(); - expect(res.body.salt).to.not.be.ok(); - done(); - }); - }); - - it('cannot get userInfo with invalid token in auth header', function (done) { - superagent.get(SERVER_URL + '/api/v1/users/' + user_0.id) - .set('Authorization', 'Bearer ' + 'x' + token) - .end(function (err, res) { - expect(res.statusCode).to.equal(401); - done(); - }); - }); - - it('cannot get userInfo with invalid token (wrong token)', function (done) { - superagent.get(SERVER_URL + '/api/v1/users/' + user_0.id) - .set('Authorization', 'Bearer ' + 'x' + token.toUpperCase()) - .end(function (err, res) { - expect(res.statusCode).to.equal(401); - done(); - }); - }); - - it('cannot create user without email', function (done) { - superagent.post(SERVER_URL + '/api/v1/users') - .query({ access_token: token }) - .send({ username: USERNAME_1 }) - .end(function (error, result) { - expect(error).to.be.ok(); - expect(result.statusCode).to.equal(400); - done(); - }); - }); - - it('create second user succeeds', function (done) { - superagent.post(SERVER_URL + '/api/v1/users') - .query({ access_token: token }) - .send({ username: USERNAME_1, email: EMAIL_1 }) - .end(function (error, result) { - expect(error).to.not.be.ok(); - expect(result.statusCode).to.equal(201); - - user_1 = result.body; - - // HACK to get a token for second user (passwords are generated and the user should have gotten a password setup link...) - tokendb.add({ id: 'tid-3', accessToken: token_1, identifier: user_1.id, clientId: 'test-client-id', expires: Date.now() + 10000, scope: 'unused', name: 'fromtest' }, done); - }); - }); - - it('reinvite unknown user fails', function (done) { - superagent.post(SERVER_URL + '/api/v1/users/' + USERNAME_1+USERNAME_1 + '/create_invite') - .query({ access_token: token }) - .send({}) - .end(function (err, res) { - expect(err).to.be.an(Error); - expect(res.statusCode).to.equal(404); - done(); - }); - }); - - it('send invite without creating invite fails succeeds', function (done) { - superagent.post(SERVER_URL + '/api/v1/users/' + user_1.id + '/send_invite') - .query({ access_token: token }) - .send({}) - .end(function (err, res) { - expect(err).to.be.an(Error); - expect(res.statusCode).to.equal(409); - done(); - }); - }); - - it('create invite second user succeeds', function (done) { - superagent.post(SERVER_URL + '/api/v1/users/' + user_1.id + '/create_invite') - .query({ access_token: token }) - .send({}) - .end(function (err, res) { - expect(err).to.not.be.ok(); - expect(res.statusCode).to.equal(200); - expect(res.body.resetToken).to.be.ok(); - done(); - }); - }); - - it('can send invite', function (done) { - mailer._mailQueue = []; - - superagent.post(SERVER_URL + '/api/v1/users/' + user_1.id + '/send_invite') - .query({ access_token: token }) - .send({}) - .end(function (err, res) { - expect(err).to.be(null); - expect(res.statusCode).to.equal(200); - checkMails(1, done); - }); - }); - - it('set second user as admin succeeds', function (done) { - superagent.post(SERVER_URL + '/api/v1/users/' + user_1.id) - .query({ access_token: token }) - .send({ admin: true }) - .end(function (err, res) { - expect(res.statusCode).to.equal(204); - - superagent.get(SERVER_URL + '/api/v1/users/' + user_1.id) - .query({ access_token: token }) - .end(function (err, res) { - expect(res.statusCode).to.equal(200); - expect(res.body.admin).to.be(true); - - done(); - }); - }); - }); - - it('does not list groupIds when listing users', function (done) { - superagent.get(SERVER_URL + '/api/v1/users') - .query({ access_token: token }) - .end(function (error, res) { - expect(error).to.be(null); - expect(res.statusCode).to.equal(200); - expect(res.body.users).to.be.an('array'); - - res.body.users.forEach(function (user) { - expect('groupIds' in user).to.be(false); + it('cannot create user without email', function (done) { + superagent.post(SERVER_URL + '/api/v1/users') + .query({ access_token: token }) + .send({ username: USERNAME_1 }) + .end(function (error, result) { + expect(error).to.be.ok(); + expect(result.statusCode).to.equal(400); + done(); }); - done(); - }); - }); + }); - it('remove self as admin fails', function (done) { - superagent.post(SERVER_URL + '/api/v1/users/' + user_0.id) - .query({ access_token: token }) - .send({ admin: false }) - .end(function (err, res) { - expect(res.statusCode).to.equal(409); - done(); - }); - }); + it('create second user succeeds', function (done) { + superagent.post(SERVER_URL + '/api/v1/users') + .query({ access_token: token }) + .send({ username: USERNAME_1, email: EMAIL_1 }) + .end(function (error, result) { + expect(error).to.not.be.ok(); + expect(result.statusCode).to.equal(201); - it('remove second user from group succeeds', function (done) { - superagent.put(SERVER_URL + '/api/v1/users/' + user_1.id + '/groups') - .query({ access_token: token }) - .send({ groupIds: [ groupObject.id ] }) - .end(function (err, res) { - expect(res.statusCode).to.equal(204); + user_1 = result.body; - superagent.get(SERVER_URL + '/api/v1/users/' + user_1.id) - .query({ access_token: token }) - .end(function (err, res) { - expect(res.statusCode).to.equal(200); - expect(res.body.groupIds).to.eql([ groupObject.id ]); - - done(); - }); - }); - }); - - it('remove second user as admin succeeds', function (done) { - superagent.post(SERVER_URL + '/api/v1/users/' + user_1.id) - .query({ access_token: token }) - .send({ admin: false }) - .end(function (err, res) { - expect(res.statusCode).to.equal(204); - done(); - }); - }); - - it('create user missing username succeeds', function (done) { - superagent.post(SERVER_URL + '/api/v1/users') - .query({ access_token: token }) - .send({ email: `unnamed${EMAIL_2}` }) - .end(function (error, result) { - expect(result.statusCode).to.equal(201); - done(); - }); - }); - - it('create user missing email fails', function (done) { - superagent.post(SERVER_URL + '/api/v1/users') - .query({ access_token: token }) - .send({ username: USERNAME_2 }) - .end(function (error, result) { - expect(result.statusCode).to.equal(400); - done(); - }); - }); - - it('create user reserved name fails', function (done) { - superagent.post(SERVER_URL + '/api/v1/users') - .query({ access_token: token }) - .send({ username: 'no-reply' }) - .end(function (error, result) { - expect(result.statusCode).to.equal(400); - done(); - }); - }); - - it('create user with short name fails', function (done) { - superagent.post(SERVER_URL + '/api/v1/users') - .query({ access_token: token }) - .send({ username: 'n' }) - .end(function (error, result) { - expect(result.statusCode).to.equal(400); - done(); - }); - }); - - it('create second and third user', function (done) { - mailer._mailQueue = []; - superagent.post(SERVER_URL + '/api/v1/users') - .query({ access_token: token }) - .send({ username: USERNAME_2, email: EMAIL_2 }) - .end(function (error, result) { - expect(result.statusCode).to.equal(201); - - user_2 = result.body; - - superagent.post(SERVER_URL + '/api/v1/users') - .query({ access_token: token }) - .send({ username: USERNAME_3, email: EMAIL_3 }) - .end(function (error, result) { - expect(result.statusCode).to.equal(201); - - done(); - }); - }); - }); - - it('get userInfo succeeds for second user', function (done) { - superagent.get(SERVER_URL + '/api/v1/users/' + user_2.id) - .query({ access_token: token }) - .end(function (error, result) { - expect(result.statusCode).to.equal(200); - expect(result.body.username).to.equal(USERNAME_2.toLowerCase()); - expect(result.body.email).to.equal(EMAIL_2.toLowerCase()); - expect(result.body.groupIds).to.eql([]); - - done(); - }); - }); - - it('create user with same username should fail', function (done) { - superagent.post(SERVER_URL + '/api/v1/users') - .query({ access_token: token }) - .send({ username: USERNAME_2, email: EMAIL_0, invite: false }) - .end(function (err, res) { - expect(res.statusCode).to.equal(409); - done(); - }); - }); - - it('list users fails for normal user', function (done) { - superagent.get(SERVER_URL + '/api/v1/users') - .query({ access_token: token_1 }) - .end(function (error, res) { - expect(res.statusCode).to.equal(403); - done(); - }); - }); - - it('list users succeeds for admin', function (done) { - superagent.get(SERVER_URL + '/api/v1/users') - .query({ access_token: token }) - .end(function (error, res) { - expect(error).to.be(null); - expect(res.statusCode).to.equal(200); - expect(res.body.users).to.be.an('array'); - expect(res.body.users.length).to.equal(5); - - res.body.users.forEach(function (user) { - expect(user).to.be.an('object'); - expect(user.id).to.be.ok(); - expect(user.email).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(); - expect(user.groupIds).to.not.be.ok(); + // HACK to get a token for second user (passwords are generated and the user should have gotten a password setup link...) + tokendb.add({ id: 'tid-3', accessToken: token_1, identifier: user_1.id, clientId: 'test-client-id', expires: Date.now() + 10000, scope: 'unused', name: 'fromtest' }, done); }); + }); - done(); - }); - }); + it('create user missing username succeeds', function (done) { + superagent.post(SERVER_URL + '/api/v1/users') + .query({ access_token: token }) + .send({ email: `unnamed${EMAIL_2}` }) + .end(function (error, result) { + expect(result.statusCode).to.equal(201); + done(); + }); + }); - it('remove random user fails', function (done) { - superagent.del(SERVER_URL + '/api/v1/users/randomid') - .query({ access_token: token }) - .end(function (err, res) { - expect(res.statusCode).to.equal(404); - done(); - }); - }); + it('create user missing email fails', function (done) { + superagent.post(SERVER_URL + '/api/v1/users') + .query({ access_token: token }) + .send({ username: USERNAME_2 }) + .end(function (error, result) { + expect(result.statusCode).to.equal(400); + done(); + }); + }); - it('user removes himself is not allowed', function (done) { - superagent.del(SERVER_URL + '/api/v1/users/' + user_0.id) - .query({ access_token: token }) - .end(function (err, res) { - expect(res.statusCode).to.equal(409); - done(); - }); - }); + it('create user reserved name fails', function (done) { + superagent.post(SERVER_URL + '/api/v1/users') + .query({ access_token: token }) + .send({ username: 'no-reply' }) + .end(function (error, result) { + expect(result.statusCode).to.equal(400); + done(); + }); + }); - it('admin removes normal user', function (done) { - superagent.del(SERVER_URL + '/api/v1/users/' + user_1.id) - .query({ access_token: token }) - .end(function (err, res) { - expect(res.statusCode).to.equal(204); - done(); - }); - }); + it('create user with short name fails', function (done) { + superagent.post(SERVER_URL + '/api/v1/users') + .query({ access_token: token }) + .send({ username: 'n' }) + .end(function (error, result) { + expect(result.statusCode).to.equal(400); + done(); + }); + }); - it('admin removes himself should not be allowed', function (done) { - superagent.del(SERVER_URL + '/api/v1/users/' + user_0.id) - .query({ access_token: token }) - .end(function (err, res) { - expect(res.statusCode).to.equal(409); - done(); - }); - }); + it('create second and third user', function (done) { + mailer._mailQueue = []; + superagent.post(SERVER_URL + '/api/v1/users') + .query({ access_token: token }) + .send({ username: USERNAME_2, email: EMAIL_2 }) + .end(function (error, result) { + expect(result.statusCode).to.equal(201); - // Change email - it('change email fails due to missing token', function (done) { - superagent.post(SERVER_URL + '/api/v1/users/' + user_0.id) - .send({ email: EMAIL_0_NEW }) - .end(function (error, result) { - expect(result.statusCode).to.equal(401); - done(); - }); - }); + user_2 = result.body; - it('change email fails due to invalid email', function (done) { - superagent.post(SERVER_URL + '/api/v1/users/' + user_0.id) - .query({ access_token: token }) - .send({ email: 'foo@bar' }) - .end(function (error, result) { - expect(result.statusCode).to.equal(400); - done(); - }); - }); + superagent.post(SERVER_URL + '/api/v1/users') + .query({ access_token: token }) + .send({ username: USERNAME_3, email: EMAIL_3 }) + .end(function (error, result) { + expect(result.statusCode).to.equal(201); - it('change user succeeds without email nor displayName', function (done) { - superagent.post(SERVER_URL + '/api/v1/users/' + user_0.id) - .query({ access_token: token }) - .send({}) - .end(function (error, result) { - expect(result.statusCode).to.equal(204); - done(); - }); - }); + done(); + }); + }); + }); - it('change email succeeds', function (done) { - superagent.post(SERVER_URL + '/api/v1/users/' + user_2.id) - .query({ access_token: token }) - .send({ email: EMAIL_2_NEW }) - .end(function (error, result) { - expect(result.statusCode).to.equal(204); + it('get userInfo succeeds for second user', function (done) { + superagent.get(SERVER_URL + '/api/v1/users/' + user_2.id) + .query({ access_token: token }) + .end(function (error, result) { + expect(result.statusCode).to.equal(200); + expect(result.body.username).to.equal(USERNAME_2.toLowerCase()); + expect(result.body.email).to.equal(EMAIL_2.toLowerCase()); + expect(result.body.groupIds).to.eql([]); - superagent.get(SERVER_URL + '/api/v1/users/' + user_2.id) - .query({ access_token: token }) - .end(function (err, res) { - expect(res.statusCode).to.equal(200); - expect(res.body.username).to.equal(USERNAME_2.toLowerCase()); - expect(res.body.email).to.equal(EMAIL_2_NEW.toLowerCase()); - expect(res.body.displayName).to.equal(''); + done(); + }); + }); - done(); - }); - }); - }); + it('create user with same username should fail', function (done) { + superagent.post(SERVER_URL + '/api/v1/users') + .query({ access_token: token }) + .send({ username: USERNAME_2, email: EMAIL_0, invite: false }) + .end(function (err, res) { + expect(res.statusCode).to.equal(409); + done(); + }); + }); - it('change email as admin for other user succeeds', function (done) { - superagent.post(SERVER_URL + '/api/v1/users/' + user_2.id) - .query({ access_token: token }) - .send({ email: EMAIL_2 }) - .end(function (error, result) { - expect(result.statusCode).to.equal(204); + it('cannot create user with bad password', function (done) { + mailer._mailQueue = []; - superagent.get(SERVER_URL + '/api/v1/users/' + user_2.id) - .query({ access_token: token }) - .end(function (err, res) { - expect(res.statusCode).to.equal(200); - expect(res.body.username).to.equal(USERNAME_2.toLowerCase()); - expect(res.body.email).to.equal(EMAIL_2.toLowerCase()); - expect(res.body.displayName).to.equal(''); + superagent.post(SERVER_URL + '/api/v1/users') + .query({ access_token: token }) + .send({ username: USERNAME_4, email: EMAIL_4, password: 'tooweak' }) + .end(function (error, result) { + expect(error).to.be.ok(); + expect(result.statusCode).to.equal(400); + done(); + }); + }); - done(); - }); - }); - }); + it('can create user with a password', function (done) { + superagent.post(SERVER_URL + '/api/v1/users') + .query({ access_token: token }) + .send({ username: USERNAME_4, email: EMAIL_4, password: 'Secret1#' }) + .end(function (error, result) { + expect(error).to.not.be.ok(); + expect(result.statusCode).to.equal(201); - it('change displayName succeeds', function (done) { - superagent.post(SERVER_URL + '/api/v1/users/' + user_0.id) - .query({ access_token: token }) - .send({ displayName: DISPLAY_NAME_0_NEW }) - .end(function (error, result) { - expect(result.statusCode).to.equal(204); + user_4 = result.body; - superagent.get(SERVER_URL + '/api/v1/users/' + user_0.id) - .query({ access_token: token }) - .end(function (err, res) { - expect(res.statusCode).to.equal(200); - expect(res.body.username).to.equal(USERNAME_0.toLowerCase()); - expect(res.body.email).to.equal(EMAIL_0.toLowerCase()); - expect(res.body.displayName).to.equal(DISPLAY_NAME_0_NEW); + userToken = hat(8 * 32); + var expires = Date.now() + 2000; // 1 sec - done(); - }); - }); - }); + tokendb.add({ id: 'tid-2', accessToken: userToken, identifier: user_4.id, clientId: null, expires: expires, scope: 'unused', name: '' }, done); + }); + }); - it('cannot create user with bad password', function (done) { - mailer._mailQueue = []; + it('can get profile of user with pre-set password', function (done) { + superagent.get(SERVER_URL + '/api/v1/profile') + .query({ access_token: userToken }) + .end(function (err, res) { + expect(res.statusCode).to.equal(200); - superagent.post(SERVER_URL + '/api/v1/users') - .query({ access_token: token }) - .send({ username: USERNAME_4, email: EMAIL_4, password: 'tooweak' }) - .end(function (error, result) { - expect(error).to.be.ok(); - expect(result.statusCode).to.equal(400); - done(); - }); - }); + expect(res.body.email).to.be(EMAIL_4); - it('can create user with a password', function (done) { - superagent.post(SERVER_URL + '/api/v1/users') - .query({ access_token: token }) - .send({ username: USERNAME_4, email: EMAIL_4, password: 'Secret1#' }) - .end(function (error, result) { - expect(error).to.not.be.ok(); - expect(result.statusCode).to.equal(201); - - user_4 = result.body; - - userToken = hat(8 * 32); - var expires = Date.now() + 2000; // 1 sec - - tokendb.add({ id: 'tid-2', accessToken: userToken, identifier: user_4.id, clientId: null, expires: expires, scope: 'unused', name: '' }, done); - }); - }); - - it('can get profile of user with pre-set password', function (done) { - superagent.get(SERVER_URL + '/api/v1/profile') - .query({ access_token: userToken }) - .end(function (err, res) { - expect(res.statusCode).to.equal(200); - - expect(res.body.email).to.be(EMAIL_4); - - done(); - }); - }); - - // Change password - it('change password fails due to missing token', function (done) { - superagent.post(SERVER_URL + '/api/v1/users/' + user_0.id + '/password') - .send({ password: 'youdontsay' }) - .end(function (error, result) { - expect(result.statusCode).to.equal(401); - done(); - }); - }); - - it('change password fails due to small password', function (done) { - superagent.post(SERVER_URL + '/api/v1/users/' + user_0.id + '/password') - .query({ access_token: token }) - .send({ password: 'small' }) - .end(function (error, result) { - expect(result.statusCode).to.equal(400); - done(); - }); - }); - - it('change password succeeds', function (done) { - superagent.post(SERVER_URL + '/api/v1/users/' + user_0.id + '/password') - .query({ access_token: token }) - .send({ password: 'bigenough' }) - .end(function (error, result) { - expect(result.statusCode).to.equal(204); - done(); - }); - }); - - it('did change the user password', function (done) { - users.verify(user_0.id, 'bigenough', users.AP_WEBADMIN, function (error) { - expect(error).to.be(null); - done(); + done(); + }); }); }); - it('cannot add app password with invalid token', function (done) { - superagent.post(SERVER_URL + '/api/v1/app_passwords') - .query({ access_token: token + 'xx' }) - .send({ name: 'my-device', identifier: 'someapp' }) - .end(function (error, result) { - expect(result.statusCode).to.equal(401); - done(); - }); + describe('invite', function () { + + it('reinvite unknown user fails', function (done) { + superagent.post(SERVER_URL + '/api/v1/users/' + USERNAME_1+USERNAME_1 + '/create_invite') + .query({ access_token: token }) + .send({}) + .end(function (err, res) { + expect(err).to.be.an(Error); + expect(res.statusCode).to.equal(404); + done(); + }); + }); + + it('send invite without creating invite fails succeeds', function (done) { + superagent.post(SERVER_URL + '/api/v1/users/' + user_1.id + '/send_invite') + .query({ access_token: token }) + .send({}) + .end(function (err, res) { + expect(err).to.be.an(Error); + expect(res.statusCode).to.equal(409); + done(); + }); + }); + + it('create invite second user succeeds', function (done) { + superagent.post(SERVER_URL + '/api/v1/users/' + user_1.id + '/create_invite') + .query({ access_token: token }) + .send({}) + .end(function (err, res) { + expect(err).to.not.be.ok(); + expect(res.statusCode).to.equal(200); + expect(res.body.resetToken).to.be.ok(); + done(); + }); + }); + + it('can send invite', function (done) { + mailer._mailQueue = []; + + superagent.post(SERVER_URL + '/api/v1/users/' + user_1.id + '/send_invite') + .query({ access_token: token }) + .send({}) + .end(function (err, res) { + expect(err).to.be(null); + expect(res.statusCode).to.equal(200); + checkMails(1, done); + }); + }); }); - it('cannot add app password without name', function (done) { - superagent.post(SERVER_URL + '/api/v1/app_passwords') - .query({ access_token: token }) - .send({ identifier: 'someapp' }) - .end(function (error, result) { - expect(result.statusCode).to.equal(400); - done(); - }); + describe('admin status', function () { + + it('set second user as admin succeeds', function (done) { + superagent.post(SERVER_URL + '/api/v1/users/' + user_1.id) + .query({ access_token: token }) + .send({ admin: true }) + .end(function (err, res) { + expect(res.statusCode).to.equal(204); + + superagent.get(SERVER_URL + '/api/v1/users/' + user_1.id) + .query({ access_token: token }) + .end(function (err, res) { + expect(res.statusCode).to.equal(200); + expect(res.body.admin).to.be(true); + + done(); + }); + }); + }); + + it('remove self as admin fails', function (done) { + superagent.post(SERVER_URL + '/api/v1/users/' + user_0.id) + .query({ access_token: token }) + .send({ admin: false }) + .end(function (err, res) { + expect(res.statusCode).to.equal(409); + done(); + }); + }); + + it('remove second user as admin succeeds', function (done) { + superagent.post(SERVER_URL + '/api/v1/users/' + user_1.id) + .query({ access_token: token }) + .send({ admin: false }) + .end(function (err, res) { + expect(res.statusCode).to.equal(204); + done(); + }); + }); }); - let pwd; - it('can add app password', function (done) { - superagent.post(SERVER_URL + '/api/v1/app_passwords') - .query({ access_token: token }) - .send({ name: 'my-device', identifier: 'someapp' }) - .end(function (error, result) { - expect(result.statusCode).to.equal(201); - expect(result.body.password).to.be.a('string'); - pwd = result.body; - done(); - }); + describe('groups', function () { + it('does not list groupIds when listing users', function (done) { + superagent.get(SERVER_URL + '/api/v1/users') + .query({ access_token: token }) + .end(function (error, res) { + expect(error).to.be(null); + expect(res.statusCode).to.equal(200); + expect(res.body.users).to.be.an('array'); + + res.body.users.forEach(function (user) { + expect('groupIds' in user).to.be(false); + }); + done(); + }); + }); + + it('remove second user from group succeeds', function (done) { + superagent.put(SERVER_URL + '/api/v1/users/' + user_1.id + '/groups') + .query({ access_token: token }) + .send({ groupIds: [ groupObject.id ] }) + .end(function (err, res) { + expect(res.statusCode).to.equal(204); + + superagent.get(SERVER_URL + '/api/v1/users/' + user_1.id) + .query({ access_token: token }) + .end(function (err, res) { + expect(res.statusCode).to.equal(200); + expect(res.body.groupIds).to.eql([ groupObject.id ]); + + done(); + }); + }); + }); }); - it('can get app passwords', function (done) { - superagent.get(SERVER_URL + '/api/v1/app_passwords') - .query({ access_token: token }) - .end(function (error, result) { - expect(result.statusCode).to.equal(200); - expect(result.body.appPasswords).to.be.an(Array); - expect(result.body.appPasswords.length).to.be(1); - expect(result.body.appPasswords[0].name).to.be('my-device'); - expect(result.body.appPasswords[0].identifier).to.be('someapp'); - expect(result.body.appPasswords[0].hashedPassword).to.be(undefined); - expect(result.body.appPasswords[0].password).to.be(undefined); - done(); - }); + describe('list users', function () { + + it('list users fails for normal user', function (done) { + superagent.get(SERVER_URL + '/api/v1/users') + .query({ access_token: token_1 }) + .end(function (error, res) { + expect(res.statusCode).to.equal(403); + done(); + }); + }); + + it('list users succeeds for admin', function (done) { + superagent.get(SERVER_URL + '/api/v1/users') + .query({ access_token: token }) + .end(function (error, res) { + expect(error).to.be(null); + expect(res.statusCode).to.equal(200); + expect(res.body.users).to.be.an('array'); + expect(res.body.users.length).to.equal(6); + + res.body.users.forEach(function (user) { + expect(user).to.be.an('object'); + expect(user.id).to.be.ok(); + expect(user.email).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(); + expect(user.groupIds).to.not.be.ok(); + }); + + done(); + }); + }); }); - it('can get app password', function (done) { - superagent.get(SERVER_URL + '/api/v1/app_passwords/' + pwd.id) - .query({ access_token: token }) - .end(function (error, result) { - expect(result.statusCode).to.equal(200); - expect(result.body.name).to.be('my-device'); - expect(result.body.identifier).to.be('someapp'); - expect(result.body.hashedPassword).to.be(undefined); - expect(result.body.password).to.be(undefined); - done(); - }); + describe('remove', function () { + + it('remove random user fails', function (done) { + superagent.del(SERVER_URL + '/api/v1/users/randomid') + .query({ access_token: token }) + .end(function (err, res) { + expect(res.statusCode).to.equal(404); + done(); + }); + }); + + it('user removes himself is not allowed', function (done) { + superagent.del(SERVER_URL + '/api/v1/users/' + user_0.id) + .query({ access_token: token }) + .end(function (err, res) { + expect(res.statusCode).to.equal(409); + done(); + }); + }); + + it('admin removes normal user', function (done) { + superagent.del(SERVER_URL + '/api/v1/users/' + user_1.id) + .query({ access_token: token }) + .end(function (err, res) { + expect(res.statusCode).to.equal(204); + done(); + }); + }); + + it('admin removes himself should not be allowed', function (done) { + superagent.del(SERVER_URL + '/api/v1/users/' + user_0.id) + .query({ access_token: token }) + .end(function (err, res) { + expect(res.statusCode).to.equal(409); + done(); + }); + }); }); - it('can del app password', function (done) { - superagent.del(SERVER_URL + '/api/v1/app_passwords/' + pwd.id) - .query({ access_token: token }) - .end(function (error, result) { - expect(result.statusCode).to.equal(204); + describe('update', function () { + // Change email + it('change email fails due to missing token', function (done) { + superagent.post(SERVER_URL + '/api/v1/users/' + user_0.id) + .send({ email: EMAIL_0_NEW }) + .end(function (error, result) { + expect(result.statusCode).to.equal(401); + done(); + }); + }); + + it('change email fails due to invalid email', function (done) { + superagent.post(SERVER_URL + '/api/v1/users/' + user_0.id) + .query({ access_token: token }) + .send({ email: 'foo@bar' }) + .end(function (error, result) { + expect(result.statusCode).to.equal(400); + done(); + }); + }); + + it('change user succeeds without email nor displayName', function (done) { + superagent.post(SERVER_URL + '/api/v1/users/' + user_0.id) + .query({ access_token: token }) + .send({}) + .end(function (error, result) { + expect(result.statusCode).to.equal(204); + done(); + }); + }); + + it('change email succeeds', function (done) { + superagent.post(SERVER_URL + '/api/v1/users/' + user_2.id) + .query({ access_token: token }) + .send({ email: EMAIL_2_NEW }) + .end(function (error, result) { + expect(result.statusCode).to.equal(204); + + superagent.get(SERVER_URL + '/api/v1/users/' + user_2.id) + .query({ access_token: token }) + .end(function (err, res) { + expect(res.statusCode).to.equal(200); + expect(res.body.username).to.equal(USERNAME_2.toLowerCase()); + expect(res.body.email).to.equal(EMAIL_2_NEW.toLowerCase()); + expect(res.body.displayName).to.equal(''); + + done(); + }); + }); + }); + + it('change email as admin for other user succeeds', function (done) { + superagent.post(SERVER_URL + '/api/v1/users/' + user_2.id) + .query({ access_token: token }) + .send({ email: EMAIL_2 }) + .end(function (error, result) { + expect(result.statusCode).to.equal(204); + + superagent.get(SERVER_URL + '/api/v1/users/' + user_2.id) + .query({ access_token: token }) + .end(function (err, res) { + expect(res.statusCode).to.equal(200); + expect(res.body.username).to.equal(USERNAME_2.toLowerCase()); + expect(res.body.email).to.equal(EMAIL_2.toLowerCase()); + expect(res.body.displayName).to.equal(''); + + done(); + }); + }); + }); + + it('change displayName succeeds', function (done) { + superagent.post(SERVER_URL + '/api/v1/users/' + user_0.id) + .query({ access_token: token }) + .send({ displayName: DISPLAY_NAME_0_NEW }) + .end(function (error, result) { + expect(result.statusCode).to.equal(204); + + superagent.get(SERVER_URL + '/api/v1/users/' + user_0.id) + .query({ access_token: token }) + .end(function (err, res) { + expect(res.statusCode).to.equal(200); + expect(res.body.username).to.equal(USERNAME_0.toLowerCase()); + expect(res.body.email).to.equal(EMAIL_0.toLowerCase()); + expect(res.body.displayName).to.equal(DISPLAY_NAME_0_NEW); + + done(); + }); + }); + }); + }); + + describe('password', function () { + // Change password + it('change password fails due to missing token', function (done) { + superagent.post(SERVER_URL + '/api/v1/users/' + user_0.id + '/password') + .send({ password: 'youdontsay' }) + .end(function (error, result) { + expect(result.statusCode).to.equal(401); + done(); + }); + }); + + it('change password fails due to small password', function (done) { + superagent.post(SERVER_URL + '/api/v1/users/' + user_0.id + '/password') + .query({ access_token: token }) + .send({ password: 'small' }) + .end(function (error, result) { + expect(result.statusCode).to.equal(400); + done(); + }); + }); + + it('change password succeeds', function (done) { + superagent.post(SERVER_URL + '/api/v1/users/' + user_0.id + '/password') + .query({ access_token: token }) + .send({ password: 'bigenough' }) + .end(function (error, result) { + expect(result.statusCode).to.equal(204); + done(); + }); + }); + + it('did change the user password', function (done) { + users.verify(user_0.id, 'bigenough', users.AP_WEBADMIN, function (error) { + expect(error).to.be(null); done(); }); + }); + }); + + describe('app password', function () { + + it('cannot add app password with invalid token', function (done) { + superagent.post(SERVER_URL + '/api/v1/app_passwords') + .query({ access_token: token + 'xx' }) + .send({ name: 'my-device', identifier: 'someapp' }) + .end(function (error, result) { + expect(result.statusCode).to.equal(401); + done(); + }); + }); + + it('cannot add app password without name', function (done) { + superagent.post(SERVER_URL + '/api/v1/app_passwords') + .query({ access_token: token }) + .send({ identifier: 'someapp' }) + .end(function (error, result) { + expect(result.statusCode).to.equal(400); + done(); + }); + }); + + let pwd; + it('can add app password', function (done) { + superagent.post(SERVER_URL + '/api/v1/app_passwords') + .query({ access_token: token }) + .send({ name: 'my-device', identifier: 'someapp' }) + .end(function (error, result) { + expect(result.statusCode).to.equal(201); + expect(result.body.password).to.be.a('string'); + pwd = result.body; + done(); + }); + }); + + it('can get app passwords', function (done) { + superagent.get(SERVER_URL + '/api/v1/app_passwords') + .query({ access_token: token }) + .end(function (error, result) { + expect(result.statusCode).to.equal(200); + expect(result.body.appPasswords).to.be.an(Array); + expect(result.body.appPasswords.length).to.be(1); + expect(result.body.appPasswords[0].name).to.be('my-device'); + expect(result.body.appPasswords[0].identifier).to.be('someapp'); + expect(result.body.appPasswords[0].hashedPassword).to.be(undefined); + expect(result.body.appPasswords[0].password).to.be(undefined); + done(); + }); + }); + + it('can get app password', function (done) { + superagent.get(SERVER_URL + '/api/v1/app_passwords/' + pwd.id) + .query({ access_token: token }) + .end(function (error, result) { + expect(result.statusCode).to.equal(200); + expect(result.body.name).to.be('my-device'); + expect(result.body.identifier).to.be('someapp'); + expect(result.body.hashedPassword).to.be(undefined); + expect(result.body.password).to.be(undefined); + done(); + }); + }); + + it('can del app password', function (done) { + superagent.del(SERVER_URL + '/api/v1/app_passwords/' + pwd.id) + .query({ access_token: token }) + .end(function (error, result) { + expect(result.statusCode).to.equal(204); + done(); + }); + }); }); });