mirror of
https://github.com/The-Low-Code-Foundation/OpenNoodl.git
synced 2026-01-11 14:52:55 +01:00
Co-Authored-By: Eric Tuvesson <eric.tuvesson@gmail.com> Co-Authored-By: mikaeltellhed <2311083+mikaeltellhed@users.noreply.github.com> Co-Authored-By: kotte <14197736+mrtamagotchi@users.noreply.github.com> Co-Authored-By: Anders Larsson <64838990+anders-topp@users.noreply.github.com> Co-Authored-By: Johan <4934465+joolsus@users.noreply.github.com> Co-Authored-By: Tore Knudsen <18231882+torekndsn@users.noreply.github.com> Co-Authored-By: victoratndl <99176179+victoratndl@users.noreply.github.com>
232 lines
6.3 KiB
JavaScript
232 lines
6.3 KiB
JavaScript
const crypto = require('crypto');
|
|
const inquirer = require('inquirer');
|
|
const OTPAuth = require('otpauth');
|
|
const { copy } = require('./utils.js');
|
|
const phrases = {
|
|
enterPassword: 'Enter a password:',
|
|
enterUsername: 'Enter a username:',
|
|
enterAppName: 'Enter the app name:',
|
|
}
|
|
const getAlgorithm = async () => {
|
|
let { algorithm } = await inquirer.prompt([
|
|
{
|
|
type: 'list',
|
|
name: 'algorithm',
|
|
message: 'Which hashing algorithm do you want to use?',
|
|
default: 'SHA1',
|
|
choices: [
|
|
'SHA1',
|
|
'SHA224',
|
|
'SHA256',
|
|
'SHA384',
|
|
'SHA512',
|
|
'SHA3-224',
|
|
'SHA3-256',
|
|
'SHA3-384',
|
|
'SHA3-512',
|
|
'Other'
|
|
]
|
|
}
|
|
]);
|
|
if (algorithm === 'Other') {
|
|
const result = await inquirer.prompt([
|
|
{
|
|
type: 'input',
|
|
name: 'algorithm',
|
|
message: 'Enter the hashing algorithm you want to use:'
|
|
}
|
|
]);
|
|
algorithm = result.algorithm;
|
|
}
|
|
const { digits, period } = await inquirer.prompt([
|
|
{
|
|
type: 'number',
|
|
name: 'digits',
|
|
default: 6,
|
|
message: 'Enter the number of digits the one-time password should have:'
|
|
},
|
|
{
|
|
type: 'number',
|
|
name: 'period',
|
|
default: 30,
|
|
message: 'Enter how long the one-time password should be valid (in seconds):'
|
|
}
|
|
])
|
|
return { algorithm, digits, period};
|
|
};
|
|
const generateSecret = ({ app, username, algorithm, digits, period }) => {
|
|
const secret = new OTPAuth.Secret();
|
|
const totp = new OTPAuth.TOTP({
|
|
issuer: app,
|
|
label: username,
|
|
algorithm,
|
|
digits,
|
|
period,
|
|
secret
|
|
});
|
|
const url = totp.toString();
|
|
const config = { mfa: secret.base32 };
|
|
config.app = app;
|
|
config.url = url;
|
|
if (algorithm !== 'SHA1') {
|
|
config.mfaAlgorithm = algorithm;
|
|
}
|
|
if (digits != 6) {
|
|
config.mfaDigits = digits;
|
|
}
|
|
if (period != 30) {
|
|
config.mfaPeriod = period;
|
|
}
|
|
return { config };
|
|
};
|
|
const showQR = text => {
|
|
const QRCode = require('qrcode');
|
|
QRCode.toString(text, { type: 'terminal' }, (err, url) => {
|
|
console.log(
|
|
'\n------------------------------------------------------------------------------' +
|
|
`\n\n${url}`
|
|
);
|
|
});
|
|
};
|
|
|
|
const showInstructions = ({ app, username, passwordCopied, encrypt, config }) => {
|
|
const {secret, url} = config;
|
|
const mfaJSON = {...config};
|
|
delete mfaJSON.url;
|
|
let orderCounter = 0;
|
|
const getOrder = () => {
|
|
orderCounter++;
|
|
return orderCounter;
|
|
}
|
|
console.log(
|
|
'------------------------------------------------------------------------------' +
|
|
'\n\nFollow these steps to complete the set-up:'
|
|
);
|
|
|
|
console.log(
|
|
`\n${getOrder()}. Add the following settings for user "${username}" ${app ? `in app "${app}" ` : '' }to the Parse Dashboard configuration.` +
|
|
`\n\n ${JSON.stringify(mfaJSON)}`
|
|
);
|
|
|
|
if (passwordCopied) {
|
|
console.log(
|
|
`\n${getOrder()}. Securely store the generated login password that has been copied to your clipboard.`
|
|
);
|
|
}
|
|
|
|
if (secret) {
|
|
console.log(
|
|
`\n${getOrder()}. Open the authenticator app to scan the QR code above or enter this secret code:` +
|
|
`\n\n ${secret}` +
|
|
'\n\n If the secret code generates incorrect one-time passwords, try this alternative:' +
|
|
`\n\n ${url}` +
|
|
`\n\n${getOrder()}. Destroy any records of the QR code and the secret code to secure the account.`
|
|
);
|
|
}
|
|
|
|
if (encrypt) {
|
|
console.log(
|
|
`\n${getOrder()}. Make sure that "useEncryptedPasswords" is set to "true" in your dashboard configuration.` +
|
|
'\n You chose to generate an encrypted password for this user.' +
|
|
'\n Any existing users with non-encrypted passwords will require newly created, encrypted passwords.'
|
|
);
|
|
}
|
|
console.log(
|
|
'\n------------------------------------------------------------------------------\n'
|
|
);
|
|
}
|
|
|
|
module.exports = {
|
|
async createUser() {
|
|
const data = {};
|
|
|
|
console.log('');
|
|
const { username, password } = await inquirer.prompt([
|
|
{
|
|
type: 'input',
|
|
name: 'username',
|
|
message: phrases.enterUsername
|
|
},
|
|
{
|
|
type: 'confirm',
|
|
name: 'password',
|
|
message: 'Do you want to auto-generate a password?'
|
|
}
|
|
]);
|
|
data.user = username;
|
|
if (!password) {
|
|
const { password } = await inquirer.prompt([
|
|
{
|
|
type: 'password',
|
|
name: 'password',
|
|
message: phrases.enterPassword
|
|
}
|
|
]);
|
|
data.pass = password;
|
|
} else {
|
|
const password = crypto.randomBytes(20).toString('base64');
|
|
data.pass = password;
|
|
}
|
|
const { mfa, encrypt } = await inquirer.prompt([
|
|
{
|
|
type: 'confirm',
|
|
name: 'encrypt',
|
|
message: 'Should the password be encrypted? (strongly recommended, otherwise it is stored in clear-text)'
|
|
},
|
|
{
|
|
type: 'confirm',
|
|
name: 'mfa',
|
|
message: 'Do you want to enable multi-factor authentication?'
|
|
}
|
|
]);
|
|
if (encrypt) {
|
|
// Copy the raw password to clipboard
|
|
copy(data.pass);
|
|
|
|
// Encrypt password
|
|
const bcrypt = require('bcryptjs');
|
|
const salt = bcrypt.genSaltSync(10);
|
|
data.pass = bcrypt.hashSync(data.pass, salt);
|
|
}
|
|
const config = {};
|
|
if (mfa) {
|
|
const { app } = await inquirer.prompt([
|
|
{
|
|
type: 'input',
|
|
name: 'app',
|
|
message: phrases.enterAppName
|
|
}
|
|
]);
|
|
const { algorithm, digits, period } = await getAlgorithm();
|
|
const secret =generateSecret({ app, username, algorithm, digits, period });
|
|
Object.assign(config, secret.config);
|
|
showQR(secret.config.url);
|
|
}
|
|
config.user = data.user;
|
|
config.pass = data.pass ;
|
|
showInstructions({ app: data.app, username, passwordCopied: true, encrypt, config });
|
|
},
|
|
async createMFA() {
|
|
console.log('');
|
|
const { username, app } = await inquirer.prompt([
|
|
{
|
|
type: 'input',
|
|
name: 'username',
|
|
message:
|
|
'Enter the username for which you want to enable multi-factor authentication:'
|
|
},
|
|
{
|
|
type: 'input',
|
|
name: 'app',
|
|
message: phrases.enterAppName
|
|
}
|
|
]);
|
|
const { algorithm, digits, period } = await getAlgorithm();
|
|
|
|
const { config } = generateSecret({ app, username, algorithm, digits, period });
|
|
showQR(config.url);
|
|
// Compose config
|
|
showInstructions({ app, username, config });
|
|
}
|
|
};
|