Skip to content

Instantly share code, notes, and snippets.

@morloy
Last active August 9, 2018 09:09
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save morloy/dc4d3e5c2ba53134440811da2598c5b8 to your computer and use it in GitHub Desktop.
Save morloy/dc4d3e5c2ba53134440811da2598c5b8 to your computer and use it in GitHub Desktop.
// /imports/startup/server/twoFactorAuthServer.js
import { Meteor } from 'meteor/meteor';
import { Accounts } from 'meteor/accounts-base';
import SimpleSchema from 'simpl-schema';
import otplib from 'otplib';
import { TwoFactorToken } from '/imports/api/methods/twoFactorAuth';
// Invalidate password login attempt, if 2FA is enabled
Accounts.validateLoginAttempt(info =>
info.allowed && !(info.type === 'password' && info.user.twoFactorEnabled));
const handleError = () => {
throw new Meteor.Error(403, 'Something went wrong. Please check your credentials.');
};
Accounts.registerLoginHandler('two-factor', (options) => {
if (!options.twoFactorPassword) { return undefined; }
new SimpleSchema({
user: new SimpleSchema({
email: SimpleSchema.RegEx.EmailWithTLD,
}),
twoFactorPassword: new SimpleSchema({
digest: /[A-Fa-f0-9]{64}/,
algorithm: { type: String, allowedValues: ['sha-256'] },
}),
twoFactorToken: TwoFactorToken,
}).validate(options);
const user = Accounts.findUserByEmail(options.user.email);
if (!user) handleError();
if (!user.services || !user.services.password || !user.services.password.bcrypt) {
return handleError();
}
if (Accounts._checkPassword(user, options.twoFactorPassword).error) {
return handleError();
}
if (user.twoFactorEnabled) {
if (typeof options.twoFactorToken !== 'number') {
throw new Meteor.Error('two-factor-required');
}
if (!otplib.authenticator.check(options.twoFactorToken, user.services.twoFactorSecret)) {
return handleError();
}
}
return { userId: user._id };
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment