feat: Add two-factor authentication via TOTP
Adds TOTP setup with QR code, login challenge, recovery codes and trusted devices that let a browser skip the second factor for 30 days. Admins can reset another user's second factor by confirming with their own password.
This commit is contained in:
@@ -0,0 +1,56 @@
|
||||
/*!
|
||||
* Copyright (c) 2024 PLANKA Software GmbH
|
||||
* Licensed under the Fair Use License: https://github.com/plankanban/planka/blob/master/LICENSE.md
|
||||
*/
|
||||
|
||||
const bcrypt = require('bcrypt');
|
||||
const crypto = require('crypto');
|
||||
|
||||
const CHARS = 'abcdefghijklmnopqrstuvwxyz0123456789';
|
||||
const CODE_COUNT = 10;
|
||||
const GROUP_LENGTH = 5;
|
||||
const BCRYPT_ROUNDS = 10;
|
||||
|
||||
// Largest multiple of CHARS.length that fits in one byte — anything above it
|
||||
// would skew the character distribution via the modulo, so we rejection-sample.
|
||||
const MAX_UNBIASED_BYTE = Math.floor(256 / CHARS.length) * CHARS.length;
|
||||
|
||||
const pickUnbiasedByte = () => {
|
||||
// Loop bounded statistically: ~11% of bytes get rejected, so the expected
|
||||
// number of draws per character is ~1.125.
|
||||
// eslint-disable-next-line no-constant-condition
|
||||
while (true) {
|
||||
const [byte] = crypto.randomBytes(1);
|
||||
if (byte < MAX_UNBIASED_BYTE) {
|
||||
return byte;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const generateCode = () => {
|
||||
let left = '';
|
||||
let right = '';
|
||||
for (let i = 0; i < GROUP_LENGTH; i += 1) {
|
||||
left += CHARS[pickUnbiasedByte() % CHARS.length];
|
||||
right += CHARS[pickUnbiasedByte() % CHARS.length];
|
||||
}
|
||||
return `${left}-${right}`;
|
||||
};
|
||||
|
||||
module.exports = {
|
||||
inputs: {},
|
||||
|
||||
async fn() {
|
||||
const plain = [];
|
||||
const hashed = [];
|
||||
|
||||
for (let i = 0; i < CODE_COUNT; i += 1) {
|
||||
const code = generateCode();
|
||||
plain.push(code);
|
||||
// eslint-disable-next-line no-await-in-loop
|
||||
hashed.push(await bcrypt.hash(code, BCRYPT_ROUNDS));
|
||||
}
|
||||
|
||||
return { plain, hashed };
|
||||
},
|
||||
};
|
||||
Reference in New Issue
Block a user