mirror of
https://github.com/NuSkooler/enigma-bbs.git
synced 2025-07-24 03:30:40 +02:00
Good progress on 2FA/OTP config
This commit is contained in:
parent
b62f55961f
commit
8802ae24ba
7 changed files with 230 additions and 10 deletions
171
core/user_2fa_otp_config.js
Normal file
171
core/user_2fa_otp_config.js
Normal file
|
@ -0,0 +1,171 @@
|
|||
/* jslint node: true */
|
||||
'use strict';
|
||||
|
||||
// ENiGMA½
|
||||
const { MenuModule } = require('./menu_module.js');
|
||||
const UserProps = require('./user_property.js');
|
||||
const {
|
||||
OTPTypes,
|
||||
otpFromType,
|
||||
createQRCode,
|
||||
} = require('./user_2fa_otp.js');
|
||||
|
||||
// deps
|
||||
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',
|
||||
};
|
||||
|
||||
const FormIds = {
|
||||
menu : 0,
|
||||
};
|
||||
|
||||
const MciViewIds = {
|
||||
enableToggle : 1,
|
||||
typeSelection : 2,
|
||||
submission : 3,
|
||||
infoText : 4,
|
||||
|
||||
customRangeStart : 10, // 10+ = customs
|
||||
};
|
||||
|
||||
exports.getModule = class User2FA_OTPConfigModule extends MenuModule {
|
||||
constructor(options) {
|
||||
super(options);
|
||||
this.config = Object.assign({}, _.get(options, 'menuConfig.config'), { extraArgs : options.extraArgs });
|
||||
|
||||
this.menuMethods = {
|
||||
showQRCode : (formData, extraArgs, cb) => {
|
||||
return this.showQRCode(cb);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
mciReady(mciData, cb) {
|
||||
super.mciReady(mciData, err => {
|
||||
if(err) {
|
||||
return cb(err);
|
||||
}
|
||||
|
||||
async.series(
|
||||
[
|
||||
(callback) => {
|
||||
return this.prepViewController('menu', FormIds.menu, mciData.menu, callback);
|
||||
},
|
||||
(callback) => {
|
||||
const requiredCodes = [
|
||||
MciViewIds.enableToggle,
|
||||
MciViewIds.typeSelection,
|
||||
MciViewIds.submission,
|
||||
];
|
||||
return this.validateMCIByViewIds('menu', requiredCodes, callback);
|
||||
},
|
||||
(callback) => {
|
||||
const enableToggleView = this.getView('menu', MciViewIds.enableToggle);
|
||||
let initialIndex = this.isOTPEnabledForUser() ? 1 : 0;
|
||||
enableToggleView.setFocusItemIndex(initialIndex);
|
||||
this.enableToggleUpdate(initialIndex);
|
||||
|
||||
enableToggleView.on('index update', idx => {
|
||||
return this.enableToggleUpdate(idx);
|
||||
});
|
||||
|
||||
const typeSelectionView = this.getView('menu', MciViewIds.typeSelection);
|
||||
initialIndex = this.typeSelectionIndexFromUserOTPType();
|
||||
typeSelectionView.setFocusItemIndex(initialIndex);
|
||||
|
||||
typeSelectionView.on('index update', idx => {
|
||||
return this.typeSelectionUpdate(idx);
|
||||
});
|
||||
|
||||
this.viewControllers.menu.on('return', view => {
|
||||
if(view === enableToggleView) {
|
||||
return this.enableToggleUpdate(enableToggleView.focusedItemIndex);
|
||||
} else if (view === typeSelectionView) {
|
||||
return this.typeSelectionUpdate(typeSelectionView.focusedItemIndex);
|
||||
}
|
||||
});
|
||||
|
||||
return callback(null);
|
||||
}
|
||||
],
|
||||
err => {
|
||||
return cb(err);
|
||||
}
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
showQRCode(cb) {
|
||||
const otp = otpFromType(this.client.user.getProperty(UserProps.AuthFactor2OTP));
|
||||
let qrCodeAscii = '';
|
||||
if(!otp) {
|
||||
qrCodeAscii = '2FA/OTP is not currently enabled for this account';
|
||||
}
|
||||
|
||||
const qrOptions = {
|
||||
username : this.client.user.username,
|
||||
qrType : 'ascii',
|
||||
};
|
||||
qrCodeAscii = createQRCode(
|
||||
otp,
|
||||
qrOptions,
|
||||
this.client.user.getProperty(UserProps.AuthFactor2OTPSecret)
|
||||
).replace(/\n/g, '\r\n');
|
||||
|
||||
const modOpts = {
|
||||
extraArgs : {
|
||||
artData : iconv.encode(`${qrCodeAscii}\r\n`, 'cp437'),
|
||||
}
|
||||
};
|
||||
this.gotoMenu(
|
||||
this.menuConfig.config.mainMenuUser2FAOTP_ShowQR || 'mainMenuUser2FAOTP_ShowQR',
|
||||
modOpts,
|
||||
cb
|
||||
);
|
||||
}
|
||||
|
||||
isOTPEnabledForUser() {
|
||||
return this.typeSelectionIndexFromUserOTPType(-1) != -1;
|
||||
}
|
||||
|
||||
getInfoText(key) {
|
||||
return _.get(this.config, [ 'infoText', key ], '');
|
||||
}
|
||||
|
||||
enableToggleUpdate(idx) {
|
||||
const key = {
|
||||
0 : '2faDisabled',
|
||||
1 : '2faEnabled',
|
||||
}[idx];
|
||||
this.updateCustomViewTextsWithFilter('menu', MciViewIds.customRangeStart, { infoText : this.getInfoText(key) } );
|
||||
}
|
||||
|
||||
typeSelectionIndexFromUserOTPType(defaultIndex = 0) {
|
||||
const type = this.client.user.getProperty(UserProps.AuthFactor2OTP);
|
||||
return {
|
||||
[ OTPTypes.RFC6238_TOTP ] : 0,
|
||||
[ OTPTypes.RFC4266_HOTP ] : 1,
|
||||
[ OTPTypes.GoogleAuthenticator ] : 2,
|
||||
}[type] || defaultIndex;
|
||||
}
|
||||
|
||||
otpTypeFromTypeSelectionIndex(idx) {
|
||||
return {
|
||||
0 : OTPTypes.RFC6238_TOTP,
|
||||
1 : OTPTypes.RFC4266_HOTP,
|
||||
2 : OTPTypes.GoogleAuthenticator,
|
||||
}[idx];
|
||||
}
|
||||
|
||||
typeSelectionUpdate(idx) {
|
||||
const key = '2faType_' + this.otpTypeFromTypeSelectionIndex(idx);
|
||||
this.updateCustomViewTextsWithFilter('menu', MciViewIds.customRangeStart, { infoText : this.getInfoText(key) } );
|
||||
}
|
||||
};
|
||||
|
Loading…
Add table
Add a link
Reference in a new issue