import TestApp from "../src/TestApp"; import useApp from "./_app"; import Controller from "../src/Controller"; import supertest from "supertest"; import CsrfProtectionComponent from "../src/components/CsrfProtectionComponent"; import MysqlConnectionManager from "../src/db/MysqlConnectionManager"; import config from "config"; import User from "../src/auth/models/User"; import UserNameComponent from "../src/auth/models/UserNameComponent"; import UserPasswordComponent from "../src/auth/password/UserPasswordComponent"; import {popEmail} from "./_mail_server"; let app: TestApp; useApp(async (addr, port) => { await MysqlConnectionManager.prepare(); await MysqlConnectionManager.query('DROP DATABASE IF EXISTS ' + config.get('mysql.database')); await MysqlConnectionManager.endPool(); return app = new class extends TestApp { protected async init(): Promise { this.use(new class extends Controller { public routes(): void { this.get('/', (req, res) => { res.render('home'); }, 'home'); this.get('/csrf', (req, res) => { res.send(CsrfProtectionComponent.getCsrfToken(req.getSession())); }, 'csrf'); } }()); await super.init(); } }(addr, port); }); let agent: supertest.SuperTest; beforeAll(() => { agent = supertest(app.getExpressApp()); }); describe('Register with username', () => { let cookies: string[]; let csrf: string; test('General case', async () => { const res = await agent.get('/csrf').expect(200); cookies = res.get('Set-Cookie'); csrf = res.text; // Register user await agent.post('/auth/register') .set('Cookie', cookies) .send({ csrf: csrf, auth_method: 'password', identifier: 'entrapta', password: 'darla_is_cute', password_confirmation: 'darla_is_cute', terms: 'on', }) .expect(302) .expect('Location', '/'); // Verify saved user const user = await User.select() .where('name', 'entrapta') .first(); expect(user).toBeDefined(); expect(user?.as(UserNameComponent).name).toStrictEqual('entrapta'); await expect(user?.as(UserPasswordComponent).verifyPassword('darla_is_cute')).resolves.toStrictEqual(true); }); test('Can\'t register when logged in', async () => { await agent.post('/auth/register') .set('Cookie', cookies) .send({ csrf: csrf, auth_method: 'password', identifier: 'entrapta2', password: 'darla_is_cute', password_confirmation: 'darla_is_cute', terms: 'on', }) .expect(302) .expect('Location', '/csrf'); const user2 = await User.select() .where('name', 'entrapta2') .first(); expect(user2).toBeNull(); }); test('Cannot register taken username', async () => { // Check that there is no hordak in DB expect(await User.select() .where('name', 'hordak') .count()).toStrictEqual(0); const res1 = await agent.get('/csrf').expect(200); // Register user await agent.post('/auth/register') .set('Cookie', res1.get('Set-Cookie')) .send({ csrf: res1.text, auth_method: 'password', identifier: 'hordak', password: 'horde_prime_will_rise', password_confirmation: 'horde_prime_will_rise', terms: 'on', }) .expect(302) .expect('Location', '/'); // Verify saved user expect(await User.select() .where('name', 'hordak') .count()).toStrictEqual(1); const res2 = await agent.get('/csrf').expect(200); // Attempt register same user const res = await agent.post('/auth/register') .set('Cookie', res2.get('Set-Cookie')) .send({ csrf: res2.text, auth_method: 'password', identifier: 'hordak', password: 'horde_prime_will_rise_unless', password_confirmation: 'horde_prime_will_rise_unless', terms: 'on', }) .expect(400); // username field should be translated from identifier expect(res.body.messages?.username?.name).toStrictEqual('AlreadyExistsValidationError'); // Verify nothing changed expect(await User.select() .where('name', 'hordak') .count()).toStrictEqual(1); }); }); describe('Register with email (magic_link)', () => { test('General case', async () => { const res = await agent.get('/csrf').expect(200); const cookies = res.get('Set-Cookie'); const csrf = res.text; await agent.post('/auth/register') .set('Cookie', cookies) .send({ csrf: csrf, auth_method: 'magic_link', identifier: 'glimmer@example.org', name: 'glimmer', }) .expect(302) .expect('Location', '/magic/lobby?redirect_uri=%2Fcsrf'); const mail: Record | null = await popEmail(); expect(mail).not.toBeNull(); const query = (mail?.text as string).split('/magic/link?')[1].split('\n')[0]; expect(query).toBeDefined(); await agent.get('/magic/link?' + query) .expect(200); await agent.get('/magic/lobby') .set('Cookie', cookies) .expect(302) .expect('Location', '/'); // Verify saved user const user = await User.select() .with('mainEmail') .where('name', 'glimmer') .first(); expect(user).toBeDefined(); const email = user?.mainEmail.getOrFail(); expect(email).toBeDefined(); expect(email?.email).toStrictEqual('glimmer@example.org'); expect(user?.as(UserNameComponent).name).toStrictEqual('glimmer'); await expect(user?.as(UserPasswordComponent).verifyPassword('')).resolves.toStrictEqual(false); }); test('Cannot register without specifying username', async () => { const res = await agent.get('/csrf').expect(200); const cookies = res.get('Set-Cookie'); const csrf = res.text; await agent.post('/auth/register') .set('Cookie', cookies) .send({ csrf: csrf, auth_method: 'magic_link', identifier: 'glimmer@example.org', }) .expect(400); expect(await popEmail()).toBeNull(); }); test('Cannot register taken username', async () => { const res = await agent.get('/csrf').expect(200); const cookies = res.get('Set-Cookie'); const csrf = res.text; await agent.post('/auth/register') .set('Cookie', cookies) .send({ csrf: csrf, auth_method: 'magic_link', identifier: 'angella@example.org', name: 'angella', }) .expect(302) .expect('Location', '/magic/lobby?redirect_uri=%2Fcsrf'); const mail: Record | null = await popEmail(); expect(mail).not.toBeNull(); const query = (mail?.text as string).split('/magic/link?')[1].split('\n')[0]; expect(query).toBeDefined(); await agent.get('/magic/link?' + query) .expect(200); await agent.get('/magic/lobby') .set('Cookie', cookies) .expect(302) .expect('Location', '/'); // Verify saved user const user = await User.select() .with('mainEmail') .where('name', 'glimmer') .first(); expect(user).toBeDefined(); // Attempt register with another mail but same username const res2 = await agent.get('/csrf').expect(200); await agent.post('/auth/register') .set('Cookie', res2.get('Set-Cookie')) .send({ csrf: res2.text, auth_method: 'magic_link', identifier: 'angella_something_else@example.org', name: 'angella', }) .expect(400); expect(await popEmail()).toBeNull(); }); test('Cannot register taken email', async () => { const res = await agent.get('/csrf').expect(200); const cookies = res.get('Set-Cookie'); const csrf = res.text; await agent.post('/auth/register') .set('Cookie', cookies) .send({ csrf: csrf, auth_method: 'magic_link', identifier: 'bow@example.org', name: 'bow', }) .expect(302) .expect('Location', '/magic/lobby?redirect_uri=%2Fcsrf'); const mail: Record | null = await popEmail(); expect(mail).not.toBeNull(); const query = (mail?.text as string).split('/magic/link?')[1].split('\n')[0]; expect(query).toBeDefined(); await agent.get('/magic/link?' + query) .expect(200); await agent.get('/magic/lobby') .set('Cookie', cookies) .expect(302) .expect('Location', '/'); // Verify saved user const user = await User.select() .with('mainEmail') .where('name', 'glimmer') .first(); expect(user).toBeDefined(); // Attempt register with another mail but same username const res2 = await agent.get('/csrf').expect(200); await agent.post('/auth/register') .set('Cookie', res2.get('Set-Cookie')) .send({ csrf: res2.text, auth_method: 'magic_link', identifier: 'bow@example.org', name: 'bow2', }) .expect(400); expect(await popEmail()).toBeNull(); }); });