First pass formatting with Prettier
* Added .prettierrc.json * Added .prettierignore * Formatted
This commit is contained in:
@@ -2,107 +2,122 @@
|
||||
'use strict';
|
||||
|
||||
// ENiGMA½
|
||||
const { MenuModule } = require('./menu_module.js');
|
||||
const UserProps = require('./user_property.js');
|
||||
const { MenuModule } = require('./menu_module.js');
|
||||
const UserProps = require('./user_property.js');
|
||||
const {
|
||||
OTPTypes,
|
||||
otpFromType,
|
||||
createQRCode,
|
||||
createBackupCodes,
|
||||
} = require('./user_2fa_otp.js');
|
||||
const { Errors } = require('./enig_error.js');
|
||||
const { getServer } = require('./listening_server.js');
|
||||
const WebServerPackageName = require('./servers/content/web.js').moduleInfo.packageName;
|
||||
const WebRegister = require('./user_2fa_otp_web_register.js');
|
||||
} = require('./user_2fa_otp.js');
|
||||
const { Errors } = require('./enig_error.js');
|
||||
const { getServer } = require('./listening_server.js');
|
||||
const WebServerPackageName = require('./servers/content/web.js').moduleInfo.packageName;
|
||||
const WebRegister = require('./user_2fa_otp_web_register.js');
|
||||
|
||||
// deps
|
||||
const async = require('async');
|
||||
const _ = require('lodash');
|
||||
const iconv = require('iconv-lite');
|
||||
const async = require('async');
|
||||
const _ = require('lodash');
|
||||
const iconv = require('iconv-lite');
|
||||
|
||||
exports.moduleInfo = {
|
||||
name : 'User 2FA/OTP Configuration',
|
||||
desc : 'Module for user 2FA/OTP configuration',
|
||||
author : 'NuSkooler',
|
||||
name: 'User 2FA/OTP Configuration',
|
||||
desc: 'Module for user 2FA/OTP configuration',
|
||||
author: 'NuSkooler',
|
||||
};
|
||||
|
||||
const FormIds = {
|
||||
menu : 0,
|
||||
menu: 0,
|
||||
};
|
||||
|
||||
const MciViewIds = {
|
||||
enableToggle : 1,
|
||||
otpType : 2,
|
||||
submit : 3,
|
||||
infoText : 4,
|
||||
enableToggle: 1,
|
||||
otpType: 2,
|
||||
submit: 3,
|
||||
infoText: 4,
|
||||
|
||||
customRangeStart : 10, // 10+ = customs
|
||||
customRangeStart: 10, // 10+ = customs
|
||||
};
|
||||
|
||||
const DefaultMsg = {
|
||||
infoText: {
|
||||
disabled : 'Enabling 2-factor authentication can greatly increase account security.',
|
||||
enabled : 'A valid email address set in user config is required to enable 2-Factor Authentication.',
|
||||
rfc6238_TOTP : 'Time-Based One-Time-Password (TOTP, RFC-6238).',
|
||||
rfc4266_HOTP : 'HMAC-Based One-Time-Password (HOTP, RFC-4266).',
|
||||
googleAuth : 'Google Authenticator.',
|
||||
disabled:
|
||||
'Enabling 2-factor authentication can greatly increase account security.',
|
||||
enabled:
|
||||
'A valid email address set in user config is required to enable 2-Factor Authentication.',
|
||||
rfc6238_TOTP: 'Time-Based One-Time-Password (TOTP, RFC-6238).',
|
||||
rfc4266_HOTP: 'HMAC-Based One-Time-Password (HOTP, RFC-4266).',
|
||||
googleAuth: 'Google Authenticator.',
|
||||
},
|
||||
statusText: {
|
||||
otpNotEnabled: '2FA/OTP is not currently enabled for this account.',
|
||||
noBackupCodes: 'No backup codes remaining or set.',
|
||||
saveDisabled: '2FA/OTP is now disabled for this account.',
|
||||
saveEmailSent:
|
||||
'An 2FA/OTP registration email has been sent with further instructions.',
|
||||
saveError: 'Failed to send email. Please contact the system operator.',
|
||||
qrNotAvail: 'QR code not available for this OTP type.',
|
||||
emailRequired:
|
||||
'Your account must have a valid email address set to use this feature.',
|
||||
},
|
||||
statusText : {
|
||||
otpNotEnabled : '2FA/OTP is not currently enabled for this account.',
|
||||
noBackupCodes : 'No backup codes remaining or set.',
|
||||
saveDisabled : '2FA/OTP is now disabled for this account.',
|
||||
saveEmailSent : 'An 2FA/OTP registration email has been sent with further instructions.',
|
||||
saveError : 'Failed to send email. Please contact the system operator.',
|
||||
qrNotAvail : 'QR code not available for this OTP type.',
|
||||
emailRequired : 'Your account must have a valid email address set to use this feature.',
|
||||
}
|
||||
};
|
||||
|
||||
exports.getModule = class User2FA_OTPConfigModule extends MenuModule {
|
||||
constructor(options) {
|
||||
super(options);
|
||||
this.config = Object.assign({}, _.get(options, 'menuConfig.config'), { extraArgs : options.extraArgs });
|
||||
this.config = Object.assign({}, _.get(options, 'menuConfig.config'), {
|
||||
extraArgs: options.extraArgs,
|
||||
});
|
||||
|
||||
this.menuMethods = {
|
||||
showQRCode : (formData, extraArgs, cb) => {
|
||||
showQRCode: (formData, extraArgs, cb) => {
|
||||
return this.showQRCode(cb);
|
||||
},
|
||||
showSecret : (formData, extraArgs, cb) => {
|
||||
showSecret: (formData, extraArgs, cb) => {
|
||||
return this.showSecret(cb);
|
||||
},
|
||||
showBackupCodes : (formData, extraArgs, cb) => {
|
||||
showBackupCodes: (formData, extraArgs, cb) => {
|
||||
return this.showBackupCodes(cb);
|
||||
},
|
||||
generateNewBackupCodes : (formData, extraArgs, cb) => {
|
||||
generateNewBackupCodes: (formData, extraArgs, cb) => {
|
||||
return this.generateNewBackupCodes(cb);
|
||||
},
|
||||
saveChanges : (formData, extraArgs, cb) => {
|
||||
saveChanges: (formData, extraArgs, cb) => {
|
||||
return this.saveChanges(formData, cb);
|
||||
}
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
initSequence() {
|
||||
const webServer = getServer(WebServerPackageName);
|
||||
if(!webServer || !webServer.instance.isEnabled()) {
|
||||
this.client.log.warn('User 2FA/OTP configuration requires the web server to be enabled!');
|
||||
return this.prevMenu( () => { /* dummy */ } );
|
||||
if (!webServer || !webServer.instance.isEnabled()) {
|
||||
this.client.log.warn(
|
||||
'User 2FA/OTP configuration requires the web server to be enabled!'
|
||||
);
|
||||
return this.prevMenu(() => {
|
||||
/* dummy */
|
||||
});
|
||||
}
|
||||
return super.initSequence();
|
||||
}
|
||||
|
||||
mciReady(mciData, cb) {
|
||||
super.mciReady(mciData, err => {
|
||||
if(err) {
|
||||
if (err) {
|
||||
return cb(err);
|
||||
}
|
||||
|
||||
async.series(
|
||||
[
|
||||
(callback) => {
|
||||
return this.prepViewController('menu', FormIds.menu, mciData.menu, callback);
|
||||
callback => {
|
||||
return this.prepViewController(
|
||||
'menu',
|
||||
FormIds.menu,
|
||||
mciData.menu,
|
||||
callback
|
||||
);
|
||||
},
|
||||
(callback) => {
|
||||
callback => {
|
||||
const requiredCodes = [
|
||||
MciViewIds.enableToggle,
|
||||
MciViewIds.otpType,
|
||||
@@ -110,8 +125,11 @@ exports.getModule = class User2FA_OTPConfigModule extends MenuModule {
|
||||
];
|
||||
return this.validateMCIByViewIds('menu', requiredCodes, callback);
|
||||
},
|
||||
(callback) => {
|
||||
const enableToggleView = this.getView('menu', MciViewIds.enableToggle);
|
||||
callback => {
|
||||
const enableToggleView = this.getView(
|
||||
'menu',
|
||||
MciViewIds.enableToggle
|
||||
);
|
||||
let initialIndex = this.isOTPEnabledForUser() ? 1 : 0;
|
||||
enableToggleView.setFocusItemIndex(initialIndex);
|
||||
this.enableToggleUpdate(initialIndex);
|
||||
@@ -129,15 +147,17 @@ exports.getModule = class User2FA_OTPConfigModule extends MenuModule {
|
||||
});
|
||||
|
||||
this.viewControllers.menu.on('return', view => {
|
||||
if(view === enableToggleView) {
|
||||
return this.enableToggleUpdate(enableToggleView.focusedItemIndex);
|
||||
if (view === enableToggleView) {
|
||||
return this.enableToggleUpdate(
|
||||
enableToggleView.focusedItemIndex
|
||||
);
|
||||
} else if (view === otpTypeView) {
|
||||
return this.otpTypeUpdate(otpTypeView.focusedItemIndex);
|
||||
}
|
||||
});
|
||||
|
||||
return callback(null);
|
||||
}
|
||||
},
|
||||
],
|
||||
err => {
|
||||
return cb(err);
|
||||
@@ -148,12 +168,13 @@ exports.getModule = class User2FA_OTPConfigModule extends MenuModule {
|
||||
|
||||
displayDetails(details, cb) {
|
||||
const modOpts = {
|
||||
extraArgs : {
|
||||
artData : iconv.encode(`${details}\r\n`, 'cp437'),
|
||||
}
|
||||
extraArgs: {
|
||||
artData: iconv.encode(`${details}\r\n`, 'cp437'),
|
||||
},
|
||||
};
|
||||
this.gotoMenu(
|
||||
this.menuConfig.config.userTwoFactorAuthOTPConfigShowDetails || 'userTwoFactorAuthOTPConfigShowDetails',
|
||||
this.menuConfig.config.userTwoFactorAuthOTPConfigShowDetails ||
|
||||
'userTwoFactorAuthOTPConfigShowDetails',
|
||||
modOpts,
|
||||
cb
|
||||
);
|
||||
@@ -163,12 +184,12 @@ exports.getModule = class User2FA_OTPConfigModule extends MenuModule {
|
||||
const otp = otpFromType(this.client.user.getProperty(UserProps.AuthFactor2OTP));
|
||||
|
||||
let qrCode;
|
||||
if(!otp) {
|
||||
if (!otp) {
|
||||
qrCode = this.getStatusText('otpNotEnabled');
|
||||
} else {
|
||||
const qrOptions = {
|
||||
username : this.client.user.username,
|
||||
qrType : 'ascii',
|
||||
username: this.client.user.username,
|
||||
qrType: 'ascii',
|
||||
};
|
||||
|
||||
qrCode = createQRCode(
|
||||
@@ -177,7 +198,7 @@ exports.getModule = class User2FA_OTPConfigModule extends MenuModule {
|
||||
this.client.user.getProperty(UserProps.AuthFactor2OTPSecret)
|
||||
);
|
||||
|
||||
if(qrCode) {
|
||||
if (qrCode) {
|
||||
qrCode = qrCode.replace(/\n/g, '\r\n');
|
||||
} else {
|
||||
qrCode = this.getStatusText('qrNotAvail');
|
||||
@@ -197,13 +218,16 @@ exports.getModule = class User2FA_OTPConfigModule extends MenuModule {
|
||||
showBackupCodes(cb) {
|
||||
let info;
|
||||
const noBackupCodes = this.getStatusText('noBackupCodes');
|
||||
if(!this.isOTPEnabledForUser()) {
|
||||
if (!this.isOTPEnabledForUser()) {
|
||||
info = this.getStatusText('otpNotEnabled');
|
||||
} else {
|
||||
try {
|
||||
info = JSON.parse(this.client.user.getProperty(UserProps.AuthFactor2OTPBackupCodes) || '[]').join(', ');
|
||||
info = JSON.parse(
|
||||
this.client.user.getProperty(UserProps.AuthFactor2OTPBackupCodes) ||
|
||||
'[]'
|
||||
).join(', ');
|
||||
info = info || noBackupCodes;
|
||||
} catch(e) {
|
||||
} catch (e) {
|
||||
info = noBackupCodes;
|
||||
}
|
||||
}
|
||||
@@ -211,7 +235,7 @@ exports.getModule = class User2FA_OTPConfigModule extends MenuModule {
|
||||
}
|
||||
|
||||
generateNewBackupCodes(cb) {
|
||||
if(!this.isOTPEnabledForUser()) {
|
||||
if (!this.isOTPEnabledForUser()) {
|
||||
const info = this.getStatusText('otpNotEnabled');
|
||||
return this.displayDetails(info, cb);
|
||||
}
|
||||
@@ -221,7 +245,7 @@ exports.getModule = class User2FA_OTPConfigModule extends MenuModule {
|
||||
UserProps.AuthFactor2OTPBackupCodes,
|
||||
JSON.stringify(backupCodes),
|
||||
err => {
|
||||
if(err) {
|
||||
if (err) {
|
||||
return cb(err);
|
||||
}
|
||||
const info = backupCodes.join(', ');
|
||||
@@ -232,21 +256,25 @@ exports.getModule = class User2FA_OTPConfigModule extends MenuModule {
|
||||
|
||||
saveChanges(formData, cb) {
|
||||
const enabled = 1 === _.get(formData, 'value.enableToggle', 0);
|
||||
return enabled ? this.saveChangesEnable(formData, cb) : this.saveChangesDisable(cb);
|
||||
return enabled
|
||||
? this.saveChangesEnable(formData, cb)
|
||||
: this.saveChangesDisable(cb);
|
||||
}
|
||||
|
||||
saveChangesEnable(formData, cb) {
|
||||
// User must have an email address set to save
|
||||
const emailRegExp = /[a-z0-9!#$%&'*+/=?^_`{|}~.-]+@[a-z0-9-]+(.[a-z0-9-]+)*/;
|
||||
const emailAddr = this.client.user.getProperty(UserProps.EmailAddress);
|
||||
if(!emailAddr || !emailRegExp.test(emailAddr)) {
|
||||
if (!emailAddr || !emailRegExp.test(emailAddr)) {
|
||||
const info = this.getStatusText('emailRequired');
|
||||
return this.displayDetails(info, cb);
|
||||
}
|
||||
|
||||
const otpTypeProp = this.otpTypeFromOTPTypeIndex(_.get(formData, 'value.otpType'));
|
||||
const otpTypeProp = this.otpTypeFromOTPTypeIndex(
|
||||
_.get(formData, 'value.otpType')
|
||||
);
|
||||
|
||||
const saveFailedError = (err) => {
|
||||
const saveFailedError = err => {
|
||||
const info = this.getStatusText('saveError');
|
||||
this.displayDetails(info, () => {
|
||||
return cb(err);
|
||||
@@ -254,16 +282,18 @@ exports.getModule = class User2FA_OTPConfigModule extends MenuModule {
|
||||
};
|
||||
|
||||
// sanity check
|
||||
if(!otpFromType(otpTypeProp)) {
|
||||
return saveFailedError(Errors.Invalid('Cannot convert selected index to valid OTP type'));
|
||||
if (!otpFromType(otpTypeProp)) {
|
||||
return saveFailedError(
|
||||
Errors.Invalid('Cannot convert selected index to valid OTP type')
|
||||
);
|
||||
}
|
||||
|
||||
this.removeUserOTPProperties(err => {
|
||||
if(err) {
|
||||
if (err) {
|
||||
return saveFailedError(err);
|
||||
}
|
||||
WebRegister.sendRegisterEmail(this.client.user, otpTypeProp, err => {
|
||||
if(err) {
|
||||
if (err) {
|
||||
return saveFailedError(err);
|
||||
}
|
||||
|
||||
@@ -284,7 +314,7 @@ exports.getModule = class User2FA_OTPConfigModule extends MenuModule {
|
||||
|
||||
saveChangesDisable(cb) {
|
||||
this.removeUserOTPProperties(err => {
|
||||
if(err) {
|
||||
if (err) {
|
||||
return cb(err);
|
||||
}
|
||||
|
||||
@@ -298,41 +328,46 @@ exports.getModule = class User2FA_OTPConfigModule extends MenuModule {
|
||||
}
|
||||
|
||||
getInfoText(key) {
|
||||
return _.get(this.config, [ 'infoText', key ], DefaultMsg.infoText[key]);
|
||||
return _.get(this.config, ['infoText', key], DefaultMsg.infoText[key]);
|
||||
}
|
||||
|
||||
getStatusText(key) {
|
||||
return _.get(this.config, [ 'statusText', key ], DefaultMsg.statusText[key]);
|
||||
return _.get(this.config, ['statusText', key], DefaultMsg.statusText[key]);
|
||||
}
|
||||
|
||||
enableToggleUpdate(idx) {
|
||||
const key = {
|
||||
0 : 'disabled',
|
||||
1 : 'enabled',
|
||||
0: 'disabled',
|
||||
1: 'enabled',
|
||||
}[idx];
|
||||
this.updateCustomViewTextsWithFilter('menu', MciViewIds.customRangeStart, { infoText : this.getInfoText(key) } );
|
||||
this.updateCustomViewTextsWithFilter('menu', MciViewIds.customRangeStart, {
|
||||
infoText: this.getInfoText(key),
|
||||
});
|
||||
}
|
||||
|
||||
otpTypeIndexFromUserOTPType(defaultIndex = 0) {
|
||||
const type = this.client.user.getProperty(UserProps.AuthFactor2OTP);
|
||||
return {
|
||||
[ OTPTypes.RFC6238_TOTP ] : 0,
|
||||
[ OTPTypes.RFC4266_HOTP ] : 1,
|
||||
[ OTPTypes.GoogleAuthenticator ] : 2,
|
||||
}[type] || defaultIndex;
|
||||
return (
|
||||
{
|
||||
[OTPTypes.RFC6238_TOTP]: 0,
|
||||
[OTPTypes.RFC4266_HOTP]: 1,
|
||||
[OTPTypes.GoogleAuthenticator]: 2,
|
||||
}[type] || defaultIndex
|
||||
);
|
||||
}
|
||||
|
||||
otpTypeFromOTPTypeIndex(idx) {
|
||||
return {
|
||||
0 : OTPTypes.RFC6238_TOTP,
|
||||
1 : OTPTypes.RFC4266_HOTP,
|
||||
2 : OTPTypes.GoogleAuthenticator,
|
||||
0: OTPTypes.RFC6238_TOTP,
|
||||
1: OTPTypes.RFC4266_HOTP,
|
||||
2: OTPTypes.GoogleAuthenticator,
|
||||
}[idx];
|
||||
}
|
||||
|
||||
otpTypeUpdate(idx) {
|
||||
const key = this.otpTypeFromOTPTypeIndex(idx);
|
||||
this.updateCustomViewTextsWithFilter('menu', MciViewIds.customRangeStart, { infoText : this.getInfoText(key) } );
|
||||
this.updateCustomViewTextsWithFilter('menu', MciViewIds.customRangeStart, {
|
||||
infoText: this.getInfoText(key),
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user