Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- import { Meteor } from 'meteor/meteor';
- import { ValidatedMethod } from 'meteor/mdg:validated-method';
- import { authenticator } from 'otplib';
- import SimpleSchema from 'simpl-schema';
- import { Accounts } from 'meteor/accounts-base';
- export const TwoFactorToken = {
- type: SimpleSchema.Integer, min: 0, max: 999999, optional: true,
- };
- export const Password = new SimpleSchema({
- digest: /[A-Fa-f0-9]{64}/,
- algorithm: { type: String, allowedValues: ['sha-256'] },
- });
- export const userIsLoggedIn = (userId: string) => {
- if (!userId) {
- throw new Meteor.Error('users.not-authorized');
- }
- };
- export const tokenIsValid = (token: string, secret: string) => {
- if (!authenticator.check(token, secret)) {
- throw new Meteor.Error('twoFactor.invalid-token');
- }
- };
- export const generateSecret = new ValidatedMethod({
- name: 'twoFactor.generateSecret',
- validate: null,
- run() {
- userIsLoggedIn(this.userId);
- if (Meteor.user().twoFactorEnabled) {
- throw new Meteor.Error(
- 'two-factor.generateSecret.already-enabled'
- );
- }
- if (this.isSimulation) return null;
- const secret = authenticator.generateSecret();
- Meteor.users.update(
- this.userId,
- { $set: { 'services.twoFactorSecret': secret } }
- );
- return secret;
- },
- });
- export const enableTwoFactor = new ValidatedMethod({
- name: 'twoFactor.enableTwoFactor',
- validate: new SimpleSchema({
- token: TwoFactorToken,
- }).validator(),
- run({ token }) {
- userIsLoggedIn(this.userId);
- if (this.isSimulation) return;
- tokenIsValid(token, Meteor.user().services.twoFactorSecret);
- Meteor.users.update(
- this.userId, { $set: { twoFactorEnabled: true } }
- );
- },
- });
- export const disableTwoFactor = new ValidatedMethod({
- name: 'twoFactor.disableTwoFactor',
- validate: null,
- run() {
- userIsLoggedIn(this.userId);
- if (this.isSimulation) return;
- Meteor.users.update(
- this.userId,
- { $unset: { twoFactorEnabled: 1, 'services.twoFactorSecret': 1 } },
- );
- },
- });
- export const login = new ValidatedMethod({
- name: 'twoFactor.login',
- validate: new SimpleSchema({
- email: SimpleSchema.RegEx.EmailWithTLD,
- password: Password,
- token: TwoFactorToken,
- }).validator(),
- run(options) {
- if (this.isSimulation) return null;
- const result = {
- type: 'twoFactor.login',
- userId: null,
- error: new Meteor.Error(
- 403, 'Something went wrong. Please check your credentials.'
- ),
- };
- const attemptLogin = () =>
- Accounts._attemptLogin(this, 'login', options, result);
- const user = Accounts.findUserByEmail(options.email);
- if (!user) {
- return attemptLogin();
- }
- result.userId = user._id;
- if (!user.services || !user.services.password ||
- !user.services.password.bcrypt) {
- return attemptLogin();
- }
- if (Accounts._checkPassword(user, options.password).error) {
- return attemptLogin();
- }
- if (user.twoFactorEnabled) {
- if (typeof options.token !== 'number') {
- throw new Meteor.Error(
- 401, 'Two-factor authentication required.'
- );
- }
- const tokenIsValid = authenticator.check(
- options.token, user.services.twoFactorSecret
- );
- if (!tokenIsValid) {
- return attemptLogin();
- }
- }
- result.error = null;
- return attemptLogin();
- },
- });
Add Comment
Please, Sign In to add comment