12e073e8cf
mostly because code is being autogenerated by all the AI stuff using this prefix. it's also used in the stack trace.
434 lines
18 KiB
JavaScript
434 lines
18 KiB
JavaScript
/* jslint node:true */
|
|
/* global it:false */
|
|
/* global describe:false */
|
|
/* global before:false */
|
|
/* global after:false */
|
|
|
|
'use strict';
|
|
|
|
const common = require('./common.js'),
|
|
expect = require('expect.js'),
|
|
speakeasy = require('speakeasy'),
|
|
superagent = require('@cloudron/superagent'),
|
|
tokens = require('../../tokens.js');
|
|
|
|
describe('Profile API', function () {
|
|
const { setup, cleanup, serverUrl, owner, user } = common;
|
|
|
|
before(setup);
|
|
after(cleanup);
|
|
|
|
describe('get profile', function () {
|
|
it('fails without token', async function () {
|
|
const response = await superagent.get(`${serverUrl}/api/v1/profile`)
|
|
.ok(() => true);
|
|
|
|
expect(response.status).to.equal(401);
|
|
});
|
|
|
|
it('fails with empty token', async function () {
|
|
const response = await superagent.get(`${serverUrl}/api/v1/profile`)
|
|
.query({ access_token: '' })
|
|
.ok(() => true);
|
|
|
|
expect(response.status).to.equal(401);
|
|
});
|
|
|
|
it('fails with invalid token', async function () {
|
|
const response = await superagent.get(`${serverUrl}/api/v1/profile`)
|
|
.query({ access_token: 'some token' })
|
|
.ok(() => true);
|
|
|
|
expect(response.status).to.equal(401);
|
|
});
|
|
|
|
it('succeeds', async function () {
|
|
const response = await superagent.get(`${serverUrl}/api/v1/profile`)
|
|
.query({ access_token: owner.token });
|
|
|
|
expect(response.status).to.equal(200);
|
|
expect(response.body.username).to.equal(owner.username.toLowerCase());
|
|
expect(response.body.email).to.equal(owner.email.toLowerCase());
|
|
expect(response.body.fallbackEmail).to.equal('');
|
|
expect(response.body.displayName).to.be.a('string');
|
|
expect(response.body.password).to.not.be.ok();
|
|
expect(response.body.salt).to.not.be.ok();
|
|
expect(response.body.language).to.be(null);
|
|
});
|
|
|
|
it('fails with expired token', async function () {
|
|
const token = await tokens.add({ identifier: '0', clientId: 'clientid-0', expires: Date.now() - 2000, allowedIpRanges: '' });
|
|
expect(token.accessToken).to.be.a('string');
|
|
|
|
const response = await superagent.get(`${serverUrl}/api/v1/profile`)
|
|
.query({ access_token: token.accessToken })
|
|
.ok(() => true);
|
|
|
|
expect(response.status).to.equal(401);
|
|
});
|
|
|
|
it('fails with invalid token in auth header', async function () {
|
|
const response = await superagent.get(`${serverUrl}/api/v1/profile`)
|
|
.set('Authorization', 'Bearer ' + 'x' + owner.token)
|
|
.ok(() => true);
|
|
|
|
expect(response.status).to.equal(401);
|
|
});
|
|
|
|
it('succeeds with token in auth header', async function () {
|
|
const response = await superagent.get(`${serverUrl}/api/v1/profile`).set('Authorization', 'Bearer ' + owner.token);
|
|
|
|
expect(response.status).to.equal(200);
|
|
expect(response.body.username).to.equal(owner.username.toLowerCase());
|
|
expect(response.body.email).to.equal(owner.email.toLowerCase());
|
|
expect(response.body.displayName).to.be.a('string');
|
|
expect(response.body.password).to.not.be.ok();
|
|
expect(response.body.salt).to.not.be.ok();
|
|
});
|
|
});
|
|
|
|
describe('email', function () {
|
|
it('change email fails due to missing token', async function () {
|
|
const response = await superagent.post(`${serverUrl}/api/v1/profile/email`)
|
|
.send({ email: 'newemail@example.com' })
|
|
.ok(() => true);
|
|
|
|
expect(response.status).to.equal(401);
|
|
});
|
|
|
|
it('change email fails due to missing password', async function () {
|
|
const response = await superagent.post(`${serverUrl}/api/v1/profile/email`)
|
|
.query({ access_token: owner.token })
|
|
.send({ email: 'newemail@example.com' })
|
|
.ok(() => true);
|
|
|
|
expect(response.status).to.equal(400);
|
|
});
|
|
|
|
it('change email fails due to invalid password', async function () {
|
|
const response = await superagent.post(`${serverUrl}/api/v1/profile/email`)
|
|
.query({ access_token: owner.token })
|
|
.send({ email: 'foo@bar.com', password: 'this is wrong' })
|
|
.ok(() => true);
|
|
|
|
expect(response.status).to.equal(412);
|
|
});
|
|
|
|
it('change email fails due to invalid email', async function () {
|
|
const response = await superagent.post(`${serverUrl}/api/v1/profile/email`)
|
|
.query({ access_token: owner.token })
|
|
.send({ email: 'foo@bar' })
|
|
.ok(() => true);
|
|
|
|
expect(response.status).to.equal(400);
|
|
});
|
|
|
|
it('change email succeeds', async function () {
|
|
const response = await superagent.post(`${serverUrl}/api/v1/profile/email`)
|
|
.query({ access_token: owner.token })
|
|
.send({ email: 'newemail@example.Com', password: owner.password });
|
|
|
|
expect(response.status).to.equal(204);
|
|
|
|
const response2 = await superagent.get(`${serverUrl}/api/v1/profile`)
|
|
.query({ access_token: owner.token });
|
|
|
|
expect(response2.status).to.equal(200);
|
|
expect(response2.body.username).to.equal(owner.username);
|
|
expect(response2.body.email).to.equal('newemail@example.com'); // lower cased
|
|
expect(response2.body.displayName).to.equal('');
|
|
});
|
|
});
|
|
|
|
describe('fallbackEmail', function () {
|
|
it('change fallback email fails due to missing password', async function () {
|
|
const response = await superagent.post(`${serverUrl}/api/v1/profile/fallback_email`)
|
|
.query({ access_token: owner.token })
|
|
.send({ fallbackEmail: 'newemail@example.com' })
|
|
.ok(() => true);
|
|
|
|
expect(response.status).to.equal(400);
|
|
});
|
|
|
|
it('change fallback email fails due to invalid password', async function () {
|
|
const response = await superagent.post(`${serverUrl}/api/v1/profile/fallback_email`)
|
|
.query({ access_token: owner.token })
|
|
.send({ fallbackEmail: 'foo@bar.com', password: 'this is wrong' })
|
|
.ok(() => true);
|
|
|
|
expect(response.status).to.equal(412);
|
|
});
|
|
|
|
it('change fallback email succeeds', async function () {
|
|
const response = await superagent.post(`${serverUrl}/api/v1/profile/fallback_email`)
|
|
.query({ access_token: owner.token })
|
|
.send({ fallbackEmail: 'NewFallbackemail@example.com', password: owner.password });
|
|
|
|
expect(response.status).to.equal(204);
|
|
|
|
const response2 = await superagent.get(`${serverUrl}/api/v1/profile`)
|
|
.query({ access_token: owner.token });
|
|
|
|
expect(response2.status).to.equal(200);
|
|
expect(response2.body.username).to.equal(owner.username);
|
|
expect(response2.body.fallbackEmail).to.equal('newfallbackemail@example.com'); // lowercase
|
|
});
|
|
});
|
|
|
|
describe('displayName', function () {
|
|
it('change displayName succeeds', async function () {
|
|
const response = await superagent.post(`${serverUrl}/api/v1/profile/display_name`)
|
|
.query({ access_token: owner.token })
|
|
.send({ displayName: 'Agent Smith' });
|
|
|
|
expect(response.status).to.equal(204);
|
|
|
|
const response2 = await superagent.get(`${serverUrl}/api/v1/profile`)
|
|
.query({ access_token: owner.token });
|
|
expect(response2.status).to.equal(200);
|
|
expect(response2.body.username).to.equal(owner.username);
|
|
expect(response2.body.email).to.equal('newemail@example.com'); // lower cased
|
|
expect(response2.body.displayName).to.equal('Agent Smith');
|
|
});
|
|
});
|
|
|
|
describe('password change', function () {
|
|
it('fails due to missing current password', async function () {
|
|
const response = await superagent.post(`${serverUrl}/api/v1/profile/password`)
|
|
.query({ access_token: owner.token })
|
|
.send({ newPassword: 'some wrong password' })
|
|
.ok(() => true);
|
|
|
|
expect(response.status).to.equal(400);
|
|
});
|
|
|
|
it('fails due to missing new password', async function () {
|
|
const response = await superagent.post(`${serverUrl}/api/v1/profile/password`)
|
|
.query({ access_token: owner.token })
|
|
.send({ password: owner.password })
|
|
.ok(() => true);
|
|
|
|
expect(response.status).to.equal(400);
|
|
});
|
|
|
|
it('fails due to wrong password', async function () {
|
|
const response = await superagent.post(`${serverUrl}/api/v1/profile/password`)
|
|
.query({ access_token: owner.token })
|
|
.send({ password: 'some wrong password', newPassword: 'MOre#$%34' })
|
|
.ok(() => true);
|
|
|
|
expect(response.status).to.equal(412);
|
|
});
|
|
|
|
it('fails due to invalid password', async function () {
|
|
const response = await superagent.post(`${serverUrl}/api/v1/profile/password`)
|
|
.query({ access_token: owner.token })
|
|
.send({ password: owner.password, newPassword: 'five' })
|
|
.ok(() => true);
|
|
|
|
expect(response.status).to.equal(400);
|
|
});
|
|
|
|
it('succeeds', async function () {
|
|
const response = await superagent.post(`${serverUrl}/api/v1/profile/password`)
|
|
.query({ access_token: owner.token })
|
|
.send({ password: owner.password, newPassword: 'MOre#$%34' });
|
|
|
|
expect(response.status).to.equal(204);
|
|
});
|
|
});
|
|
|
|
describe('2fa login', function () {
|
|
let secret;
|
|
|
|
it('can get secret', async function () {
|
|
const response = await superagent.post(`${serverUrl}/api/v1/profile/twofactorauthentication_secret`)
|
|
.query({ access_token: user.token })
|
|
.send({});
|
|
|
|
secret = response.body.secret;
|
|
});
|
|
|
|
it('can enable 2fa', async function () {
|
|
const totpToken = speakeasy.totp({ secret, encoding: 'base32' });
|
|
|
|
await superagent.post(`${serverUrl}/api/v1/profile/twofactorauthentication_enable`)
|
|
.query({ access_token: user.token })
|
|
.send({ totpToken });
|
|
});
|
|
|
|
it('fails due to missing token', async function () {
|
|
const response = await superagent.post(`${serverUrl}/api/v1/auth/login`)
|
|
.send({ username: user.username, password: user.password })
|
|
.ok(() => true);
|
|
|
|
expect(response.status).to.equal(401);
|
|
});
|
|
|
|
it('fails due to wrong token', async function () {
|
|
const response = await superagent.post(`${serverUrl}/api/v1/auth/login`)
|
|
.send({ username: user.username, password: user.password, totpToken: '12345' })
|
|
.ok(() => true);
|
|
|
|
expect(response.status).to.equal(401);
|
|
});
|
|
|
|
it('succeeds', async function () {
|
|
const totpToken = speakeasy.totp({
|
|
secret: secret,
|
|
encoding: 'base32'
|
|
});
|
|
|
|
const response = await superagent.post(`${serverUrl}/api/v1/auth/login`)
|
|
.send({ username: user.username, password: user.password, totpToken: totpToken });
|
|
|
|
expect(response.status).to.equal(200);
|
|
expect(response.body).to.be.an(Object);
|
|
expect(response.body.accessToken).to.be.a('string');
|
|
});
|
|
|
|
it('can disable 2fa', async function () {
|
|
await superagent.post(`${serverUrl}/api/v1/profile/twofactorauthentication_disable`)
|
|
.query({ access_token: user.token })
|
|
.send({ password: user.password });
|
|
});
|
|
|
|
it('did disable 2fa', async function () {
|
|
const response = await superagent.post(`${serverUrl}/api/v1/auth/login`)
|
|
.send({ username: user.username, password: user.password });
|
|
|
|
expect(response.status).to.equal(200);
|
|
expect(response.body).to.be.an(Object);
|
|
expect(response.body.accessToken).to.be.a('string');
|
|
});
|
|
});
|
|
|
|
describe('avatar', function () {
|
|
let customAvatarSize = 0;
|
|
|
|
it('empty by default', async function () {
|
|
const response = await superagent.get(`${serverUrl}/api/v1/profile/avatar/${user.id}`).ok(() => true);
|
|
expect(response.status).to.be(404);
|
|
});
|
|
|
|
it('can set custom avatar', async function () {
|
|
const response = await superagent.post(`${serverUrl}/api/v1/profile/avatar`)
|
|
.query({ access_token: user.token })
|
|
.attach('avatar', './logo.png');
|
|
|
|
customAvatarSize = require('node:fs').readFileSync('./logo.png').length;
|
|
|
|
expect(response.status).to.be(204);
|
|
});
|
|
|
|
it('did set custom avatar', async function () {
|
|
const response = await superagent.get(`${serverUrl}/api/v1/profile/avatar/${user.id}`)
|
|
.ok(() => true);
|
|
|
|
expect(parseInt(response.headers['content-length'])).to.equal(customAvatarSize);
|
|
expect(response.status).to.equal(200);
|
|
});
|
|
|
|
it('can unset custom avatar', async function () {
|
|
const response = await superagent.del(`${serverUrl}/api/v1/profile/avatar`)
|
|
.query({ access_token: user.token });
|
|
|
|
expect(response.status).to.be(204);
|
|
});
|
|
|
|
it('did unset custom avatar', async function () {
|
|
const response = await superagent.get(`${serverUrl}/api/v1/profile/avatar/${user.id}`).ok(() => true);
|
|
expect(response.status).to.be(404);
|
|
});
|
|
});
|
|
|
|
describe('background', function () {
|
|
it('no default', async function () {
|
|
const response = await superagent.get(`${serverUrl}/api/v1/profile/background_image`)
|
|
.query({ access_token: user.token })
|
|
.ok(() => true);
|
|
expect(response.status).to.be(404);
|
|
});
|
|
|
|
it('can set custom background', async function () {
|
|
const response = await superagent.post(`${serverUrl}/api/v1/profile/background_image`)
|
|
.query({ access_token: user.token })
|
|
.attach('backgroundImage', './logo.png');
|
|
|
|
expect(response.status).to.be(200);
|
|
});
|
|
|
|
it('did set custom background', async function () {
|
|
const response2 = await superagent.get(`${serverUrl}/api/v1/profile/background_image`)
|
|
.query({ access_token: user.token })
|
|
.ok(() => true);
|
|
|
|
const customAvatarSize = require('node:fs').readFileSync('./logo.png').length;
|
|
expect(parseInt(response2.headers['content-length'])).to.equal(customAvatarSize);
|
|
expect(response2.status).to.equal(200);
|
|
});
|
|
|
|
it('can unset background', async function () {
|
|
const response = await superagent.del(`${serverUrl}/api/v1/profile/background_image`)
|
|
.query({ access_token: user.token });
|
|
|
|
expect(response.status).to.be(200);
|
|
|
|
const response2 = await superagent.get(`${serverUrl}/api/v1/profile/background_image`)
|
|
.query({ access_token: user.token })
|
|
.ok(() => true);
|
|
expect(response2.status).to.be(404);
|
|
});
|
|
});
|
|
|
|
describe('language', function () {
|
|
it('fails to set unknown language', async function () {
|
|
const response = await superagent.post(`${serverUrl}/api/v1/profile/language`)
|
|
.query({ access_token: user.token })
|
|
.send({ language: 'ta' })
|
|
.ok(() => true);
|
|
expect(response.status).to.be(400);
|
|
});
|
|
|
|
it('fails to set bad language', async function () {
|
|
const response = await superagent.post(`${serverUrl}/api/v1/profile/language`)
|
|
.query({ access_token: user.token })
|
|
.send({ language: 123 })
|
|
.ok(() => true);
|
|
expect(response.status).to.be(400);
|
|
});
|
|
|
|
it('fails to set unknown language', async function () {
|
|
const response = await superagent.post(`${serverUrl}/api/v1/profile/language`)
|
|
.query({ access_token: user.token })
|
|
.send({ language: 'ta' })
|
|
.ok(() => true);
|
|
expect(response.status).to.be(400);
|
|
});
|
|
|
|
it('set valid language', async function () {
|
|
const response = await superagent.post(`${serverUrl}/api/v1/profile/language`)
|
|
.query({ access_token: user.token })
|
|
.send({ language: 'en' });
|
|
expect(response.status).to.be(204);
|
|
});
|
|
|
|
it('did set language', async function () {
|
|
const response = await superagent.get(`${serverUrl}/api/v1/profile`).query({ access_token: user.token });
|
|
expect(response.body.language).to.contain('en');
|
|
});
|
|
|
|
it('reset valid language', async function () {
|
|
const response = await superagent.post(`${serverUrl}/api/v1/profile/language`)
|
|
.query({ access_token: user.token })
|
|
.send({ language: '' });
|
|
expect(response.status).to.be(204);
|
|
});
|
|
|
|
it('did reset language', async function () {
|
|
const response = await superagent.get(`${serverUrl}/api/v1/profile`).query({ access_token: user.token });
|
|
expect(response.body.language).to.be(null);
|
|
});
|
|
});
|
|
});
|