@@ -2445,9 +2445,9 @@ describe('OTP TOTP auth adatper', () => {
24452445 const response = user . get ( 'authDataResponse' ) ;
24462446 expect ( response . mfa ) . toBeDefined ( ) ;
24472447 expect ( response . mfa . recovery ) . toBeDefined ( ) ;
2448- expect ( response . mfa . recovery . length ) . toEqual ( 2 ) ;
2448+ expect ( response . mfa . recovery . split ( ',' ) . length ) . toEqual ( 2 ) ;
24492449 await user . fetch ( ) ;
2450- expect ( user . get ( 'authData' ) . mfa ) . toEqual ( { enabled : true } ) ;
2450+ expect ( user . get ( 'authData' ) . mfa ) . toEqual ( { status : 'enabled' } ) ;
24512451 } ) ;
24522452
24532453 it ( 'can login with valid token' , async ( ) => {
@@ -2473,13 +2473,15 @@ describe('OTP TOTP auth adatper', () => {
24732473 username : 'username' ,
24742474 password : 'password' ,
24752475 authData : {
2476- mfa : totp . generate ( ) ,
2476+ mfa : {
2477+ token : totp . generate ( ) ,
2478+ } ,
24772479 } ,
24782480 } ) ,
24792481 } ) . then ( res => res . data ) ;
24802482 expect ( response . objectId ) . toEqual ( user . id ) ;
24812483 expect ( response . sessionToken ) . toBeDefined ( ) ;
2482- expect ( response . authData ) . toEqual ( { mfa : { enabled : true } } ) ;
2484+ expect ( response . authData ) . toEqual ( { mfa : { status : 'enabled' } } ) ;
24832485 expect ( Object . keys ( response ) . sort ( ) ) . toEqual (
24842486 [
24852487 'objectId' ,
@@ -2528,6 +2530,42 @@ describe('OTP TOTP auth adatper', () => {
25282530 expect ( user . get ( 'authData' ) . mfa . secret ) . toEqual ( new_secret . base32 ) ;
25292531 } ) ;
25302532
2533+ it ( 'cannot change OTP with invalid token' , async ( ) => {
2534+ const user = await Parse . User . signUp ( 'username' , 'password' ) ;
2535+ const OTPAuth = require ( 'otpauth' ) ;
2536+ const secret = new OTPAuth . Secret ( ) ;
2537+ const totp = new OTPAuth . TOTP ( {
2538+ algorithm : 'SHA1' ,
2539+ digits : 6 ,
2540+ period : 30 ,
2541+ secret,
2542+ } ) ;
2543+ const token = totp . generate ( ) ;
2544+ await user . save (
2545+ { authData : { mfa : { secret : secret . base32 , token } } } ,
2546+ { sessionToken : user . getSessionToken ( ) }
2547+ ) ;
2548+
2549+ const new_secret = new OTPAuth . Secret ( ) ;
2550+ const new_totp = new OTPAuth . TOTP ( {
2551+ algorithm : 'SHA1' ,
2552+ digits : 6 ,
2553+ period : 30 ,
2554+ secret : new_secret ,
2555+ } ) ;
2556+ const new_token = new_totp . generate ( ) ;
2557+ await expectAsync (
2558+ user . save (
2559+ {
2560+ authData : { mfa : { secret : new_secret . base32 , token : new_token , old : '123' } } ,
2561+ } ,
2562+ { sessionToken : user . getSessionToken ( ) }
2563+ )
2564+ ) . toBeRejectedWith ( new Parse . Error ( Parse . Error . OTHER_CAUSE , 'Invalid MFA token' ) ) ;
2565+ await user . fetch ( { useMasterKey : true } ) ;
2566+ expect ( user . get ( 'authData' ) . mfa . secret ) . toEqual ( secret . base32 ) ;
2567+ } ) ;
2568+
25312569 it ( 'future logins require TOTP token' , async ( ) => {
25322570 const user = await Parse . User . signUp ( 'username' , 'password' ) ;
25332571 const OTPAuth = require ( 'otpauth' ) ;
@@ -2572,7 +2610,9 @@ describe('OTP TOTP auth adatper', () => {
25722610 username : 'username' ,
25732611 password : 'password' ,
25742612 authData : {
2575- mfa : 'abcd' ,
2613+ mfa : {
2614+ token : 'abcd' ,
2615+ } ,
25762616 } ,
25772617 } ) ,
25782618 } ) . catch ( e => {
@@ -2619,7 +2659,7 @@ describe('OTP SMS auth adatper', () => {
26192659 const spy = spyOn ( mfa , 'sendSMS' ) . and . callThrough ( ) ;
26202660 await user . save ( { authData : { mfa : { mobile : '+11111111111' } } } , { sessionToken } ) ;
26212661 await user . fetch ( { sessionToken } ) ;
2622- expect ( user . get ( 'authData' ) ) . toEqual ( { mfa : { enabled : false } } ) ;
2662+ expect ( user . get ( 'authData' ) ) . toEqual ( { mfa : { status : 'disabled' } } ) ;
26232663 expect ( spy ) . toHaveBeenCalledWith ( code , '+11111111111' ) ;
26242664 await user . fetch ( { useMasterKey : true } ) ;
26252665 const authData = user . get ( 'authData' ) . mfa ?. pending ;
@@ -2629,7 +2669,7 @@ describe('OTP SMS auth adatper', () => {
26292669
26302670 await user . save ( { authData : { mfa : { mobile, token : code } } } , { sessionToken } ) ;
26312671 await user . fetch ( { sessionToken } ) ;
2632- expect ( user . get ( 'authData' ) ) . toEqual ( { mfa : { enabled : true } } ) ;
2672+ expect ( user . get ( 'authData' ) ) . toEqual ( { mfa : { status : 'enabled' } } ) ;
26332673 } ) ;
26342674
26352675 it ( 'future logins require SMS code' , async ( ) => {
@@ -2658,7 +2698,9 @@ describe('OTP SMS auth adatper', () => {
26582698 username : 'username' ,
26592699 password : 'password' ,
26602700 authData : {
2661- mfa : true ,
2701+ mfa : {
2702+ token : 'request' ,
2703+ } ,
26622704 } ,
26632705 } ) ,
26642706 } ) . catch ( e => e . data ) ;
@@ -2672,13 +2714,15 @@ describe('OTP SMS auth adatper', () => {
26722714 username : 'username' ,
26732715 password : 'password' ,
26742716 authData : {
2675- mfa : code ,
2717+ mfa : {
2718+ token : code ,
2719+ } ,
26762720 } ,
26772721 } ) ,
26782722 } ) . then ( res => res . data ) ;
26792723 expect ( response . objectId ) . toEqual ( user . id ) ;
26802724 expect ( response . sessionToken ) . toBeDefined ( ) ;
2681- expect ( response . authData ) . toEqual ( { mfa : { enabled : true } } ) ;
2725+ expect ( response . authData ) . toEqual ( { mfa : { status : 'enabled' } } ) ;
26822726 expect ( Object . keys ( response ) . sort ( ) ) . toEqual (
26832727 [
26842728 'objectId' ,
0 commit comments