wildduck/test/api/users-test.js
2022-12-15 11:24:09 +02:00

443 lines
16 KiB
JavaScript

/*eslint no-unused-expressions: 0, prefer-arrow-callback: 0, no-console:0 */
'use strict';
const supertest = require('supertest');
const chai = require('chai');
const expect = chai.expect;
chai.config.includeStack = true;
const config = require('wild-config');
const server = supertest.agent(`http://127.0.0.1:${config.api.port}`);
describe('API Users', function () {
this.timeout(10000); // eslint-disable-line no-invalid-this
let user, user2, token;
it('should POST /users', async () => {
const response = await server
.post('/users')
.send({
username: 'myuser2',
name: 'John Smith',
address: 'john@example.com',
password: 'secretvalue',
hashedPassword: false,
emptyAddress: false,
language: 'et',
retention: 0,
targets: ['user@example.com', 'https://example.com/upload/email'],
spamLevel: 50,
quota: 1073741824,
recipients: 2000,
forwards: 2000,
requirePasswordChange: false,
imapMaxUpload: 5368709120,
imapMaxDownload: 21474836480,
pop3MaxDownload: 21474836480,
pop3MaxMessages: 300,
imapMaxConnections: 15,
receivedMax: 60,
fromWhitelist: ['user@alternative.domain', '*@example.com'],
tags: ['status:user', 'account:example.com'],
addTagsToAddress: false,
uploadSentMessages: false,
mailboxes: {
sent: 'Saadetud kirjad',
trash: 'Prügikast',
junk: 'Praht',
drafts: 'Mustandid'
},
disabledScopes: ['imap', 'pop3', 'smtp'],
metaData: {
accountIcon: 'avatar.png'
},
internalData: {
inTrial: true
},
pubKey: '-----BEGIN PGP PUBLIC KEY BLOCK-----\nVersion: Keybase OpenPGP v1.0.0\nComment: https://keybase.io/crypto\n\nxo0EYb0PqAEEANJtI/ivwudfCMmxm+a77Fll5YwSzaaI2nqhcp6pMRJ4l0aafsX3\nBcXUQpsyyELelt2xFtwTNygR4RFWVTn4OoXmO5zFtWCSegAwSyUNK7R/GXi2GTKk\nkYtxUwGcNKBkfY7yAn5KsaeuZL1feDXUGt0YHUmBds5i+6ylI+i4tNbRABEBAAHN\nH1dpbGQgRHVjayA8dGVzdEB3aWxkZHVjay5lbWFpbD7CrQQTAQoAFwUCYb0PqAIb\nLwMLCQcDFQoIAh4BAheAAAoJEJVLs8wf5gSCzBoD/3gz32OfJM1D4IrmKVwyLKxC\n1P81kL7E6ICWD2A0JF9EkojsMHl+/zagwoJejBQhmzTNkFmui5zwmdLGforKl303\ntB0l9vCTb5+eDDHOTUatJrvlw76Fz2ZjIhQTqD4xEM7MWx4xwTGY8bC5roIpdZJD\n9+vr81MXxiq9LZJDBXIyzo0EYb0PqAEEAL/uCTOrAncTRC/3cOQz+kLIzF4A9OTe\n6yxdNWWmx+uo9yJxnBv59Xz9qt8OT8Ih7SD/A4kFCuQqlyd0OFVhyd3KTAQ3CEml\nYOgL5jOE11YrEQjr36xPqO646JZuZIorKDf9PoIyipAMG89BlAoAjSXB1oeQADYn\n5fFLFVm1S7pLABEBAAHCwIMEGAEKAA8FAmG9D6gFCQ8JnAACGy4AqAkQlUuzzB/m\nBIKdIAQZAQoABgUCYb0PqAAKCRBhR/oKY9pg/YqnA/0Szmy4q4TnTBby+j57oXtn\nX/7H/xiaqlCd6bA3lbj3cPK4ybn/gnI4ECsfZfmSFG3T5C9EcZU0e9ByzimH6sxi\nOwPgKFWeJzpl5o8toR7m4wQVhv2NZRUukHe+2JH7nITS0gKeIBHMq2TbufcH6do1\n8s2G7XyLSd5Kkljxx7YmNiKoA/9CQ4l2WkARAFByyEJT9BEE4NBO0m0bI8sg0HRK\nGuP3FKcUu0Pz9R8AExEecofh8s4kaxofa2sbrTcK+L0p0hdR/39JWNuTJbxwEU3C\nA0mZKthjzL7seiRTG7Eny5gGenejRp2x0ziyMEaTgkvf44LPi06XiuE6FGnhElOc\nC7JoIc6NBGG9D6gBBADzW30GOysnqYkexL+bY9o+ai1mL+X58GPLilXJ5WXgEEdf\n8Pg/9jlEOzOnWTTgJAQDGHtwm0duKmK7EJGozLEY94QGOzRjAir6tMF2OYDQIDgj\nAoXavPAc5chFABEVUS12hUPPLoW6YgvaIb3AAZbIM8603BLXTaLGbtZ0z7eYxwAR\nAQABwsCDBBgBCgAPBQJhvQ+oBQkPCZwAAhsuAKgJEJVLs8wf5gSCnSAEGQEKAAYF\nAmG9D6gACgkQ58zrS0TNGbAiVAP/UIxYiSdoHDnBW5qB7onEiUVL5ZFk1Xk+NB0z\n7jOm1oAV0RH8I5NRQBtZ+75xar0vPTX122IdkgpaiNT0wy5Kd/2vz4LKVK9apyJI\neaZ+D7dt5Ipu1p0lWtglqL0xtjOSWuwHFwHuiRYg6eyhGN1RylFpuiKi5KykhrBS\nuBL/BHrk6AP/boRA+KIlb6s19KHNt54Kl8n8G4ZApCwZbUc2jzvbP5DZL5rcjlHd\ns4i4XE+uIJxsiX3iJZtVXzhTKuQlaoEljlhPs/TZYUmxeJ3TdV4o7emWiZ4gE8EQ\nhfxV37ew/GoYm6yME3tAZLIXbv2+bj6HZ4eE8bAMmPvpcQ+UwNJXvnk=\n=dR+x\n-----END PGP PUBLIC KEY BLOCK-----',
encryptMessages: false,
encryptForwarded: false
})
.expect(200);
expect(response.body.success).to.be.true;
expect(/^[0-9a-f]{24}$/.test(response.body.id)).to.be.true;
user = response.body.id;
});
it('should POST /authenticate', async () => {
const authResponse = await server
.post('/authenticate')
.send({
username: 'myuser2',
password: 'secretvalue'
})
.expect(200);
expect(authResponse.body.success).to.be.true;
expect(authResponse.body).to.deep.equal({
success: true,
id: user,
username: 'myuser2',
scope: 'master',
require2fa: false,
requirePasswordChange: false
});
});
it('should POST /authenticate and fail', async () => {
const authResponse = await server
.post('/authenticate')
.send({
username: 'myuser2',
password: 'invalidpass'
})
.expect(403);
expect(authResponse.body.code).to.equal('AuthFailed');
});
it('should POST /users and fail - invalid username', async () => {
const response = await server
.post('/users')
.send({
username: 'ömyuser2',
name: 'John Smith',
password: 'secretvalue'
})
.expect(400);
expect(response.body.details.username).to.exist;
});
it('should POST /authenticate and request a token', async () => {
const authResponse = await server
.post('/authenticate')
.send({
username: 'myuser2',
password: 'secretvalue',
token: true
})
.expect(200);
expect(authResponse.body.success).to.be.true;
expect(authResponse.body.token).to.exist;
token = authResponse.body.token;
});
it('should POST /users with hashed password', async () => {
const response = await server
.post('/users')
.send({
username: 'myuser2hash',
name: 'John Smith',
// password: 'test',
password: '$argon2i$v=19$m=16,t=2,p=1$SFpGczI1bWV1RVRpYjNYaw$EBE/WnOGeWint3eQ+SQ7Sg',
hashedPassword: true
})
.expect(200);
expect(response.body.success).to.be.true;
user2 = response.body.id;
const authResponse = await server
.post('/authenticate')
.send({
username: 'myuser2hash',
password: 'test'
})
.expect(200);
expect(authResponse.body.success).to.be.true;
expect(authResponse.body).to.deep.equal({
success: true,
id: user2,
username: 'myuser2hash',
scope: 'master',
require2fa: false,
requirePasswordChange: false
});
});
it('should GET /users/resolve/{username}', async () => {
const response = await server.get('/users/resolve/myuser2').expect(200);
expect(response.body).to.deep.equal({
success: true,
id: user
});
});
it('should GET /users/resolve/{username} and fail', async () => {
const response = await server.get('/users/resolve/myuser2invalid').expect(404);
expect(response.body.code).to.equal('UserNotFound');
});
it('should GET /users', async () => {
const response = await server.get('/users?query=myuser2').expect(200);
expect(response.body.success).to.be.true;
expect(response.body.results.find(entry => entry.id === user)).to.exist;
});
it('should GET /users/{user}', async () => {
let response = await server.get(`/users/${user}`).expect(200);
expect(response.body.success).to.be.true;
expect(response.body.id).to.equal(user);
});
it('should GET /users/{user} using a token', async () => {
let response = await server.get(`/users/${user}?accessToken=${token}`).expect(200);
expect(response.body.success).to.be.true;
expect(response.body.id).to.equal(user);
});
it('should GET /users/me using a token', async () => {
let response = await server.get(`/users/me?accessToken=${token}`).expect(200);
expect(response.body.success).to.be.true;
expect(response.body.id).to.equal(user);
});
it('should GET /users/{user} using a token and fail against other user', async () => {
let response = await server.get(`/users/${user2}?accessToken=${token}`);
expect(response.body.code).to.equal('MissingPrivileges');
});
it('should DELETE /authenticate', async () => {
let response = await server.delete(`/authenticate?accessToken=${token}`).expect(200);
expect(response.body.success).to.be.true;
});
it('should DELETE /authenticate with false', async () => {
// token is not valid anymore
await server.delete(`/authenticate?accessToken=${token}`).expect(403);
});
it('should PUT /users/{user}', async () => {
const name = 'John Smith 2';
// update user data
const response = await server
.put(`/users/${user}`)
.send({
name
})
.expect(200);
expect(response.body.success).to.be.true;
// request and verify
let getResponse = await server.get(`/users/${user}`);
expect(getResponse.body.success).to.be.true;
expect(getResponse.body.id).to.equal(user);
expect(getResponse.body.name).to.equal(name);
});
it('should PUT /users/{user} and renew a token', async () => {
const authResponse1 = await server
.post('/authenticate')
.send({
username: 'myuser2',
password: 'secretvalue',
token: true
})
.expect(200);
expect(authResponse1.body.success).to.be.true;
expect(authResponse1.body.token).to.exist;
let token1 = authResponse1.body.token;
const authResponse2 = await server
.post('/authenticate')
.send({
username: 'myuser2',
password: 'secretvalue',
token: true
})
.expect(200);
expect(authResponse2.body.success).to.be.true;
expect(authResponse2.body.token).to.exist;
let token2 = authResponse2.body.token;
// try out token 1
let getResponse1 = await server.get(`/users/me?accessToken=${token1}`).expect(200);
expect(getResponse1.body.success).to.be.true;
expect(getResponse1.body.id).to.equal(user);
// try out token 2
let getResponse2 = await server.get(`/users/me?accessToken=${token2}`).expect(200);
expect(getResponse2.body.success).to.be.true;
expect(getResponse2.body.id).to.equal(user);
// update password using a token
const response = await server
.put(`/users/me?accessToken=${token1}`)
.send({
password: 'secretvalue'
})
.expect(200);
expect(response.body.success).to.be.true;
// try out token 1, should have been renewed
let getResponse3 = await server.get(`/users/me?accessToken=${token1}`).expect(200);
expect(getResponse3.body.success).to.be.true;
expect(getResponse3.body.id).to.equal(user);
// try out token 2, should fail as it was not renewed
await server.get(`/users/me?accessToken=${token2}`).expect(403);
});
it('should PUT /users/{user}/logout', async () => {
// request logout
const response = await server.put(`/users/${user}/logout`).send({ reason: 'Just because' }).expect(200);
expect(response.body.success).to.be.true;
});
it('should POST /users/{user}/quota/reset', async () => {
const response = await server.post(`/users/${user}/quota/reset`).send({}).expect(200);
expect(response.body.success).to.be.true;
expect(response.body.storageUsed).to.exist;
expect(response.body.previousStorageUsed).to.exist;
});
it('should POST /quota/reset', async () => {
const response = await server.post(`/quota/reset`).send({}).expect(200);
expect(response.body.success).to.be.true;
expect(response.body.task).to.exist;
});
it('should POST /users/{user}/password/reset', async () => {
const response = await server.post(`/users/${user}/password/reset`).send({}).expect(200);
expect(response.body.success).to.be.true;
expect(response.body.password).to.exist;
const authResponse = await server
.post('/authenticate')
.send({
username: 'myuser2',
password: response.body.password
})
.expect(200);
expect(authResponse.body.success).to.be.true;
expect(authResponse.body).to.deep.equal({
success: true,
id: user,
username: 'myuser2',
scope: 'master',
require2fa: false,
// using a temporary password requires a password change
requirePasswordChange: true
});
});
it('should POST /users/{user}/password/reset using a future date', async () => {
const response = await server
.post(`/users/${user}/password/reset`)
.send({
validAfter: new Date(Date.now() + 1 * 3600 * 1000).toISOString()
})
.expect(200);
expect(response.body.success).to.be.true;
expect(response.body.password).to.exist;
// password not yet valid
await server
.post('/authenticate')
.send({
username: 'myuser2',
password: response.body.password
})
.expect(403);
});
it('should DELETE /users/{user}', async () => {
// first set the user password
const passwordUpdateResponse = await server
.put(`/users/${user}`)
.send({
password: 'secretvalue',
ip: '1.2.3.5'
})
.expect(200);
expect(passwordUpdateResponse.body.success).to.be.true;
// Delete user
const response = await server.delete(`/users/${user}?deleteAfter=${encodeURIComponent(new Date(Date.now() + 3600 * 1000).toISOString())}`).expect(200);
expect(response.body.success).to.be.true;
expect(response.body.addresses.deleted).to.gte(1);
expect(response.body.task).to.exist;
// Try to authenticate, should fail
await server
.post('/authenticate')
.send({
username: 'myuser2',
password: 'secretvalue'
})
.expect(403);
});
it('should GET /users/{user}/restore', async () => {
const response = await server.get(`/users/${user}/restore`).expect(200);
expect(response.body.success).to.be.true;
expect(response.body.username).to.equal('myuser2');
expect(response.body.recoverableAddresses).to.deep.equal(['john@example.com']);
});
it('should POST /users/{user}/restore', async () => {
const response = await server.post(`/users/${user}/restore`).send({}).expect(200);
expect(response.body.success).to.be.true;
expect(response.body.addresses.recovered).to.gte(1);
expect(response.body.addresses.main).to.equal('john@example.com');
});
it('should POST /users with DES hash', async () => {
const response = await server
.post('/users')
.send({
username: 'desuser',
name: 'Crypt Des',
address: 'des@example.com',
password: 'sBk81TlWxyZlc',
hashedPassword: true
})
.expect(200);
expect(response.body.success).to.be.true;
expect(/^[0-9a-f]{24}$/.test(response.body.id)).to.be.true;
const authResponseSuccess = await server
.post('/authenticate')
.send({
username: 'desuser',
password: '12Mina34Ise56P.'
})
.expect(200);
expect(authResponseSuccess.body.success).to.be.true;
const authResponseFail = await server
.post('/authenticate')
.send({
username: 'desuser',
password: 'wrongpass'
})
.expect(403);
expect(authResponseFail.body.error).to.exist;
});
});