jschan - Anonymous imageboard software. Classic look, modern features and feel. Works without JavaScript and supports Tor, I2P, Lokinet, etc.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 

222 lines
6.8 KiB

const fetch = require('node-fetch')
, OTPAuth = require('otpauth')
, redis = require(__dirname+'/../lib/redis/redis.js');
module.exports = () => describe('test two factor authentication', () => {
let sessionCookie
, csrfToken
, twofactorSecret
, twofactorToken;
test('login as admin without 2fa', async () => {
const params = new URLSearchParams();
params.append('username', 'admin');
params.append('password', process.env.TEST_ADMIN_PASSWORD);
const response = await fetch('http://localhost/forms/login', {
headers: {
'x-using-xhr': 'true',
},
method: 'POST',
body: params,
redirect: 'manual',
});
const rawHeaders = response.headers.raw();
expect(rawHeaders['set-cookie']).toBeDefined();
expect(rawHeaders['set-cookie'][0]).toMatch(/^connect\.sid/);
sessionCookie = rawHeaders['set-cookie'][0];
csrfToken = await fetch('http://localhost/csrf.json', { headers: { 'cookie': sessionCookie }})
.then(res => res.json())
.then(json => json.token);
});
test('check if twofactor setup link is on account page', async () => {
const response = await fetch('http://localhost/account.html', {
headers: {
'cookie': sessionCookie,
},
});
const text = await response.text();
expect(text).toContain('<a href="/twofactor.html"');
});
test('load twofactor page and fetch secret', async () => {
const response = await fetch('http://localhost/twofactor.html', {
headers: {
'cookie': sessionCookie,
},
});
const text = await response.text();
const indexOfSecret = text.indexOf('<span class="code">');
twofactorSecret = text.substring(indexOfSecret+19, indexOfSecret+19+32);
twofactorToken = OTPAuth.TOTP.generate({
algorithm: 'SHA256',
secret: OTPAuth.Secret.fromBase32(twofactorSecret)
});
expect(twofactorToken).toBeDefined();
});
test('submit 2fa form to enable 2fa', async () => {
const params = new URLSearchParams();
params.append('_csrf', csrfToken);
params.append('twofactor', twofactorToken);
const response = await fetch('http://localhost/forms/twofactor', {
headers: {
'x-using-xhr': 'true',
'cookie': sessionCookie,
},
method: 'POST',
body: params,
redirect: 'manual',
});
expect(response.status).toBe(200);
});
test('submit 2fa form again (should be rejected)', async () => {
const params = new URLSearchParams();
params.append('_csrf', csrfToken);
params.append('twofactor', twofactorToken);
const response = await fetch('http://localhost/forms/twofactor', {
headers: {
'x-using-xhr': 'true',
'cookie': sessionCookie,
},
method: 'POST',
body: params,
redirect: 'manual',
});
expect(response.status).toBe(403);
});
test('login as admin with missing 2fa', async () => {
const params = new URLSearchParams();
params.append('username', 'admin');
params.append('password', process.env.TEST_ADMIN_PASSWORD);
params.append('twofactor', '');
const response = await fetch('http://localhost/forms/login', {
headers: {
'x-using-xhr': 'true',
'cookie': sessionCookie,
},
method: 'POST',
body: params,
redirect: 'manual',
});
expect(response.status).toBe(403);
});
test('login as admin with incorrect 2fa', async () => {
const params = new URLSearchParams();
params.append('username', 'admin');
params.append('password', process.env.TEST_ADMIN_PASSWORD);
params.append('twofactor', '000000');
const response = await fetch('http://localhost/forms/login', {
headers: {
'x-using-xhr': 'true',
'cookie': sessionCookie,
},
method: 'POST',
body: params,
redirect: 'manual',
});
expect(response.status).toBe(403);
});
test('login as admin with correct 2fa', async () => {
await redis.deletePattern('*'); //delete used 2fa code before trying to login again (same token at this point)
const params = new URLSearchParams();
params.append('username', 'admin');
params.append('password', process.env.TEST_ADMIN_PASSWORD);
params.append('twofactor', twofactorToken);
const response = await fetch('http://localhost/forms/login', {
headers: {
'x-using-xhr': 'true',
'cookie': sessionCookie,
},
method: 'POST',
body: params,
redirect: 'manual',
});
const rawHeaders = response.headers.raw();
expect(rawHeaders['set-cookie']).toBeDefined();
expect(rawHeaders['set-cookie'][0]).toMatch(/^connect\.sid/);
});
test('login as admin again with correct 2fa (rejected for reuse)', async () => {
const params = new URLSearchParams();
params.append('username', 'admin');
params.append('password', process.env.TEST_ADMIN_PASSWORD);
params.append('twofactor', twofactorToken);
const response = await fetch('http://localhost/forms/login', {
headers: {
'x-using-xhr': 'true',
'cookie': sessionCookie,
},
method: 'POST',
body: params,
redirect: 'manual',
});
expect(response.status).toBe(403);
});
test('change admin password with missing 2fa', async () => {
const params = new URLSearchParams();
params.append('username', 'admin');
params.append('password', process.env.TEST_ADMIN_PASSWORD);
params.append('newpassword', process.env.TEST_ADMIN_PASSWORD);
params.append('newpasswordconfirm', process.env.TEST_ADMIN_PASSWORD);
params.append('twofactor', '');
const response = await fetch('http://localhost/forms/changepassword', {
headers: {
'x-using-xhr': 'true',
'cookie': sessionCookie,
},
method: 'POST',
body: params,
redirect: 'manual',
});
expect(response.status).toBe(403);
});
test('change admin password with incorrect 2fa', async () => {
const params = new URLSearchParams();
params.append('username', 'admin');
params.append('password', process.env.TEST_ADMIN_PASSWORD);
params.append('newpassword', process.env.TEST_ADMIN_PASSWORD);
params.append('newpasswordconfirm', process.env.TEST_ADMIN_PASSWORD);
params.append('twofactor', '000000');
const response = await fetch('http://localhost/forms/changepassword', {
headers: {
'x-using-xhr': 'true',
'cookie': sessionCookie,
},
method: 'POST',
body: params,
redirect: 'manual',
});
expect(response.status).toBe(403);
});
test('change admin password with correct 2fa', async () => {
await redis.deletePattern('*'); //delete used 2fa code before trying to login again (same token at this point)
const params = new URLSearchParams();
params.append('username', 'admin');
params.append('password', process.env.TEST_ADMIN_PASSWORD);
params.append('newpassword', process.env.TEST_ADMIN_PASSWORD);
params.append('newpasswordconfirm', process.env.TEST_ADMIN_PASSWORD);
params.append('twofactor', twofactorToken);
params.append('captcha', '000000');
const response = await fetch('http://localhost/forms/changepassword', {
headers: {
'x-using-xhr': 'true',
'cookie': sessionCookie,
},
method: 'POST',
body: params,
redirect: 'manual',
});
redis.close();
expect(response.status).toBe(200);
});
});