1+ import Meteor , { Accounts } from '@meteorrn/core' ;
2+
3+ import { authorizeActionChallengeHandler , authorizeActionCompletionHandler , resetPasswordCheckMFARequired , registrationChallengeHandlerTOTP , registrationCompletionHandlerTOTP , resetPasswordChallengeHandler , registrationChallengeHandlerU2F , registerCompletionHandlerU2F , loginChallengeHandler , loginCompletionHandler } from './method-names' ;
4+
5+ let useU2FAuthorizationCode = function ( code ) {
6+ if ( typeof ( code ) !== "string" || code . length !== 6 ) {
7+ throw new Error ( "Invalid Code" ) ;
8+ }
9+
10+ return { U2FAuthorizationCode :code } ;
11+ } ;
12+
13+ let assembleChallengeCompletionArguments = async function ( finishLoginParams , code ) {
14+ let { res} = finishLoginParams ;
15+ let methodArguments = [ ] ;
16+
17+ if ( res . method === "u2f" ) {
18+ let assertion ;
19+ if ( code && code . U2FAuthorizationCode ) {
20+ /*
21+ We require that the MFA.useU2FAuthorizationCode method is used
22+ even though we just pull the code out to make sure the code isn't
23+ actually an OTP due to a coding error.
24+ */
25+ let { challengeId, challengeSecret} = finishLoginParams . res ;
26+ assertion = { challengeId, challengeSecret, ...code } ;
27+ }
28+ else {
29+ assertion = await solveU2FChallenge ( res ) ;
30+ }
31+ methodArguments . push ( assertion ) ;
32+ }
33+
34+ if ( res . method === "otp" || res . method === "totp" ) {
35+ if ( ! code ) {
36+ throw new Meteor . Error ( "otp-required" , "An OTP is required" ) ;
37+ }
38+
39+ methodArguments . push ( { ...res , code} ) ;
40+ }
41+
42+ return methodArguments ;
43+ } ;
44+
45+ let finishLogin = ( finishLoginParams , code ) => new Promise ( async ( resolve , reject ) => {
46+ let methodName = loginCompletionHandler ( ) ;
47+ let methodArguments = await assembleChallengeCompletionArguments ( finishLoginParams , code ) ;
48+
49+ Meteor . _startLoggingIn ( ) ;
50+ Meteor . call (
51+ methodName ,
52+ methodArguments ,
53+ ( err , result ) => {
54+ this . _endLoggingIn ( ) ;
55+ this . _handleLoginCallback ( err , result ) ;
56+
57+ if ( err ) {
58+ reject ( err ) ;
59+ }
60+ else {
61+ resolve ( ) ;
62+ }
63+ } ,
64+ ) ;
65+ } ) ;
66+
67+ let loginWithMFA = ( username , password ) => new Promise ( ( resolve , reject ) => {
68+ Meteor . call ( loginChallengeHandler ( ) , username , Accounts . _hashPassword ( password ) , async ( err , res ) => {
69+ if ( err ) {
70+ return reject ( err ) ;
71+ }
72+
73+ let finishLoginParams = { res, _type :"login" } ;
74+ let doesSupportU2FLogin = false ;
75+
76+ resolve ( { supportsU2FLogin :doesSupportU2FLogin , method :res . method , finishLoginParams, finishParams :finishLoginParams } ) ;
77+ } ) ;
78+ } ) ;
79+
80+ let login = ( username , password ) => new Promise ( ( resolve , reject ) => {
81+ Meteor . loginWithPassword ( username , password , err => {
82+ if ( err ) {
83+ if ( err . error === "mfa-required" ) {
84+ loginWithMFA ( username , password ) . then ( resolve ) . catch ( reject ) ;
85+ }
86+ else {
87+ reject ( err ) ;
88+ }
89+ }
90+ else {
91+ resolve ( { method :null } ) ;
92+ }
93+ } ) ;
94+ } ) ;
95+
96+ export default {
97+ useU2FAuthorizationCode,
98+ finishLogin,
99+ loginWithMFA,
100+ login,
101+ } ;
0 commit comments