Guest User

Untitled

a guest
Mar 26th, 2018
99
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 3.30 KB | None | 0 0
  1. import { Meteor } from 'meteor/meteor';
  2. import { ValidatedMethod } from 'meteor/mdg:validated-method';
  3. import { authenticator } from 'otplib';
  4. import SimpleSchema from 'simpl-schema';
  5. import { Accounts } from 'meteor/accounts-base';
  6.  
  7. export const TwoFactorToken = {
  8. type: SimpleSchema.Integer, min: 0, max: 999999, optional: true,
  9. };
  10. export const Password = new SimpleSchema({
  11. digest: /[A-Fa-f0-9]{64}/,
  12. algorithm: { type: String, allowedValues: ['sha-256'] },
  13. });
  14.  
  15. export const userIsLoggedIn = (userId: string) => {
  16. if (!userId) {
  17. throw new Meteor.Error('users.not-authorized');
  18. }
  19. };
  20. export const tokenIsValid = (token: string, secret: string) => {
  21. if (!authenticator.check(token, secret)) {
  22. throw new Meteor.Error('twoFactor.invalid-token');
  23. }
  24. };
  25.  
  26.  
  27. export const generateSecret = new ValidatedMethod({
  28. name: 'twoFactor.generateSecret',
  29. validate: null,
  30. run() {
  31. userIsLoggedIn(this.userId);
  32. if (Meteor.user().twoFactorEnabled) {
  33. throw new Meteor.Error(
  34. 'two-factor.generateSecret.already-enabled'
  35. );
  36. }
  37. if (this.isSimulation) return null;
  38. const secret = authenticator.generateSecret();
  39. Meteor.users.update(
  40. this.userId,
  41. { $set: { 'services.twoFactorSecret': secret } }
  42. );
  43. return secret;
  44. },
  45. });
  46.  
  47. export const enableTwoFactor = new ValidatedMethod({
  48. name: 'twoFactor.enableTwoFactor',
  49. validate: new SimpleSchema({
  50. token: TwoFactorToken,
  51. }).validator(),
  52. run({ token }) {
  53. userIsLoggedIn(this.userId);
  54. if (this.isSimulation) return;
  55. tokenIsValid(token, Meteor.user().services.twoFactorSecret);
  56. Meteor.users.update(
  57. this.userId, { $set: { twoFactorEnabled: true } }
  58. );
  59. },
  60. });
  61. export const disableTwoFactor = new ValidatedMethod({
  62. name: 'twoFactor.disableTwoFactor',
  63. validate: null,
  64. run() {
  65. userIsLoggedIn(this.userId);
  66. if (this.isSimulation) return;
  67.  
  68. Meteor.users.update(
  69. this.userId,
  70. { $unset: { twoFactorEnabled: 1, 'services.twoFactorSecret': 1 } },
  71. );
  72. },
  73. });
  74.  
  75. export const login = new ValidatedMethod({
  76. name: 'twoFactor.login',
  77. validate: new SimpleSchema({
  78. email: SimpleSchema.RegEx.EmailWithTLD,
  79. password: Password,
  80. token: TwoFactorToken,
  81. }).validator(),
  82. run(options) {
  83. if (this.isSimulation) return null;
  84. const result = {
  85. type: 'twoFactor.login',
  86. userId: null,
  87. error: new Meteor.Error(
  88. 403, 'Something went wrong. Please check your credentials.'
  89. ),
  90. };
  91. const attemptLogin = () =>
  92. Accounts._attemptLogin(this, 'login', options, result);
  93. const user = Accounts.findUserByEmail(options.email);
  94. if (!user) {
  95. return attemptLogin();
  96. }
  97. result.userId = user._id;
  98. if (!user.services || !user.services.password ||
  99. !user.services.password.bcrypt) {
  100. return attemptLogin();
  101. }
  102. if (Accounts._checkPassword(user, options.password).error) {
  103. return attemptLogin();
  104. }
  105. if (user.twoFactorEnabled) {
  106. if (typeof options.token !== 'number') {
  107. throw new Meteor.Error(
  108. 401, 'Two-factor authentication required.'
  109. );
  110. }
  111. const tokenIsValid = authenticator.check(
  112. options.token, user.services.twoFactorSecret
  113. );
  114. if (!tokenIsValid) {
  115. return attemptLogin();
  116. }
  117. }
  118. result.error = null;
  119. return attemptLogin();
  120. },
  121. });
Add Comment
Please, Sign In to add comment