Skip to content

Commit 23efb8f

Browse files
committed
totp integration test
1 parent d8c26f6 commit 23efb8f

File tree

2 files changed

+167
-0
lines changed

2 files changed

+167
-0
lines changed

packages/auth/test/helpers/integration/helpers.ts

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,12 @@ import { getAuth, connectAuthEmulator } from '../../../'; // Use browser OR node
2323
import { _generateEventId } from '../../../src/core/util/event_id';
2424
import { getAppConfig, getEmulatorUrl } from './settings';
2525
import { resetEmulator } from './emulator_rest_helpers';
26+
import { StartTotpMfaEnrollmentResponse } from '../../../src/api/account_management/mfa';
2627

28+
//import * as otpauth from "https://deno.land/x/[email protected]/dist/otpauth.esm.js";
29+
//// <reference path="helpers.d.ts"/>
30+
const totp = require('totp-generator');
31+
//import * as totp from 'otpauth';
2732
interface IntegrationTestAuth extends Auth {
2833
cleanUp(): Promise<void>;
2934
}
@@ -93,3 +98,18 @@ function stubConsoleToSilenceEmulatorWarnings(): sinon.SinonStub {
9398
}
9499
});
95100
}
101+
102+
export async function mockTotp(sharedSecretKey: string, periodSec: number, verificationCodeLength: number){
103+
console.log("**** starting to mock totp");
104+
105+
let digits = 9;
106+
let period = 30;
107+
let secret = "private";
108+
const headers = new Headers();
109+
110+
let token = totp(sharedSecretKey, { period: periodSec, digits: verificationCodeLength });
111+
console.log("***"+token);
112+
113+
return token
114+
115+
}
Lines changed: 147 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,147 @@
1+
/**
2+
* @license
3+
* Copyright 2020 Google LLC
4+
*
5+
* Licensed under the Apache License, Version 2.0 (the "License");
6+
* you may not use this file except in compliance with the License.
7+
* You may obtain a copy of the License at
8+
*
9+
* http://www.apache.org/licenses/LICENSE-2.0
10+
*
11+
* Unless required by applicable law or agreed to in writing, software
12+
* distributed under the License is distributed on an "AS IS" BASIS,
13+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
* See the License for the specific language governing permissions and
15+
* limitations under the License.
16+
*/
17+
18+
import { expect, use } from 'chai';
19+
import chaiAsPromised from 'chai-as-promised';
20+
import * as sinon from 'sinon';
21+
import sinonChai from 'sinon-chai';
22+
23+
//import { mockTotp } from '../../helpers/integration/helpers';
24+
import {Auth, createUserWithEmailAndPassword, multiFactor, signInAnonymously, signInWithEmailAndPassword, UserCredential} from '@firebase/auth';
25+
26+
import {
27+
cleanUpTestInstance,
28+
getTestInstance,
29+
mockTotp,
30+
randomEmail
31+
} from '../../helpers/integration/helpers';
32+
import { MultiFactorAssertionImpl } from '../../../src/mfa/mfa_assertion';
33+
34+
import { MultiFactorSessionImpl } from '../../../src/mfa/mfa_session';
35+
import { TotpMultiFactorAssertionImpl, TotpMultiFactorGenerator, TotpSecret } from '../../../src/mfa/assertions/totp';
36+
import * as MFA from '../../../src/api/account_management/mfa';
37+
import { FirebaseError } from '@firebase/util';
38+
39+
40+
41+
use(chaiAsPromised);
42+
use(sinonChai);
43+
44+
const TOTP_COMB_A = {
45+
46+
response: { sharedSecretKey: 'secretKey3',
47+
verificationCodeLength: 30,
48+
hashingAlgorithm: 'sha1',
49+
periodSec:30,
50+
sessionInfo: 'testsSessionInfo',
51+
finalizeEnrollmentTime: Date.now()
52+
},
53+
code: '...'
54+
};
55+
56+
const TOTP_COMB_B = {
57+
58+
response: { sharedSecretKey: 'secretKey2',
59+
verificationCodeLength: 30,
60+
hashingAlgorithm: 'sha1',
61+
periodSec: 30,
62+
sessionInfo: 'testsSessionInfo',
63+
finalizeEnrollmentTime: Date.now()
64+
},
65+
code: '...'
66+
};
67+
68+
describe(' Integration tests: Mfa TOTP', () => {
69+
let auth: Auth;
70+
let idToken: string;
71+
let signUpCred: UserCredential;
72+
let email: string;
73+
let assertion: MultiFactorAssertionImpl;
74+
let _request: MFA.StartTotpMfaEnrollmentRequest;
75+
let startMfaResponse: MFA.StartTotpMfaEnrollmentResponse;
76+
let displayName: string;
77+
beforeEach(async () => {
78+
auth = getTestInstance();
79+
email =randomEmail();
80+
idToken = 'testIdToken';
81+
signUpCred = await createUserWithEmailAndPassword(
82+
auth,
83+
email,
84+
'password'
85+
);
86+
await auth.signOut();
87+
});
88+
89+
afterEach(async () => {
90+
await cleanUpTestInstance(auth);
91+
92+
});
93+
it('should verify using otp', async () => {
94+
95+
console.log(email);
96+
const cr = await signInWithEmailAndPassword(auth, email, 'password');
97+
98+
startMfaResponse = { totpSessionInfo: TOTP_COMB_A.response}
99+
100+
101+
102+
const mfaUser = multiFactor(cr.user);
103+
sinon.spy(MultiFactorSessionImpl, '_fromIdtoken');
104+
105+
sinon.stub(mfaUser, 'getSession').returns(
106+
Promise.resolve(MultiFactorSessionImpl._fromIdtoken(idToken, auth as any)));
107+
108+
sinon.stub(MFA, 'startEnrollTotpMfa').callsFake((_auth,_request)=>{
109+
110+
return Promise.resolve(startMfaResponse)
111+
})
112+
113+
114+
115+
const session = await mfaUser.getSession();
116+
117+
console.log(session);
118+
119+
const totpSecret = await TotpMultiFactorGenerator.generateSecret(
120+
session
121+
);
122+
123+
console.log("**** totpSecret"+ totpSecret);
124+
// https://stackoverflow.com/questions/48931815/sinon-stub-not-replacing-function
125+
// https://stackoverflow.com/questions/61051247/chai-spies-expect-to-have-been-called-is-failing-on-local-methods
126+
expect(MultiFactorSessionImpl._fromIdtoken).to.have.been.calledOnce;
127+
//expect(TotpSecret._fromStartTotpMfaEnrollmentResponse).to.have.been.calledOnce;
128+
expect(MFA.startEnrollTotpMfa).to.have.been.calledOnce;
129+
130+
expect(await MFA.startEnrollTotpMfa(auth as any, _request)).to.eql(startMfaResponse)
131+
132+
expect(totpSecret.secretKey).to.eql(startMfaResponse.totpSessionInfo.sharedSecretKey)
133+
expect(totpSecret.codeLength).to.eql(startMfaResponse.totpSessionInfo.verificationCodeLength)
134+
135+
const totpVerificationCode = await mockTotp(totpSecret.secretKey, totpSecret.codeLength, totpSecret.codeIntervalSeconds);
136+
137+
const multiFactorAssertion = TotpMultiFactorGenerator.assertionForEnrollment(
138+
totpSecret,
139+
totpVerificationCode
140+
);
141+
console.log(totpVerificationCode);
142+
// auth/invalid-idToken
143+
await expect(mfaUser.enroll(multiFactorAssertion, displayName)).to.be.rejectedWith(FirebaseError, 'auth/invalid-id-token')
144+
145+
146+
})
147+
})

0 commit comments

Comments
 (0)