mirror of
https://github.com/hanzoai/firebase-js-sdk.git
synced 2026-09-24 16:59:10 +00:00
* exports for analytics * support exports for app * support exports for app-check * add exports to auth * support exports for auth-compat * add exports to component * add exports to database packages * exports for firestore * add exports to functions * add exports to installations * add exports to logger * add exports to messaging * add exports to perf * add exports to rc * add exports to storage * update template * add exports to util * add exports to webchannel * use default import to import cjs libs * make node code esm compatible * remove esm entrypoint for app in nodejs to mininize dual package hazard * reorganize builds by env * fix typo * format * remove esm entrypoint for nodejs for fcm * expose package.json to nodejs * fix * fix path in build * simplify exports * formatting * enable esModuleInterop * use default import * use default import * remove esm support for Nodejs in messaging
330 lines
11 KiB
TypeScript
330 lines
11 KiB
TypeScript
/**
|
|
* @license
|
|
* Copyright 2020 Google LLC
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
|
|
import { FirebaseError } from '@firebase/util';
|
|
import { expect, use } from 'chai';
|
|
import chaiAsPromised from 'chai-as-promised';
|
|
import firebase from '@firebase/app-compat';
|
|
import {
|
|
getOobCodes,
|
|
OobCodeSession
|
|
} from '../../../../auth/test/helpers/integration/emulator_rest_helpers';
|
|
import {
|
|
cleanUpTestInstance,
|
|
initializeTestInstance,
|
|
randomEmail
|
|
} from '../../helpers/helpers';
|
|
import { ActionCodeSettings } from '@firebase/auth-types';
|
|
|
|
use(chaiAsPromised);
|
|
|
|
declare const xit: typeof it;
|
|
|
|
const BASE_SETTINGS: ActionCodeSettings = {
|
|
url: 'http://localhost/action_code_return',
|
|
handleCodeInApp: true
|
|
};
|
|
|
|
describe('Integration test: oob codes', () => {
|
|
let email: string;
|
|
|
|
beforeEach(() => {
|
|
initializeTestInstance();
|
|
email = randomEmail();
|
|
});
|
|
|
|
afterEach(async () => {
|
|
await cleanUpTestInstance();
|
|
});
|
|
|
|
async function code(toEmail: string): Promise<OobCodeSession> {
|
|
const codes = await getOobCodes();
|
|
return codes.reverse().find(({ email }) => email === toEmail)!;
|
|
}
|
|
|
|
context('flows beginning with sendSignInLinkToEmail', () => {
|
|
let oobSession: OobCodeSession;
|
|
|
|
beforeEach(async () => {
|
|
oobSession = await sendEmailLink();
|
|
});
|
|
|
|
async function sendEmailLink(toEmail = email): Promise<OobCodeSession> {
|
|
await firebase.auth().sendSignInLinkToEmail(toEmail, BASE_SETTINGS);
|
|
|
|
// An email has been sent to the user. Normally you'd detect this state
|
|
// when the app redirects back. We will ask the emulator for the results
|
|
// and force the state instead.
|
|
return code(toEmail);
|
|
}
|
|
|
|
it('allows user to sign in', async () => {
|
|
const { user, operationType } = await firebase
|
|
.auth()
|
|
.signInWithEmailLink(email, oobSession.oobLink);
|
|
|
|
expect(operationType).to.eq('signIn');
|
|
expect(user).to.eq(firebase.auth().currentUser);
|
|
expect(user!.uid).to.be.a('string');
|
|
expect(user!.email).to.eq(email);
|
|
expect(user!.emailVerified).to.be.true;
|
|
expect(user!.isAnonymous).to.be.false;
|
|
});
|
|
|
|
it('sign in works with an email credential', async () => {
|
|
const cred = firebase.auth.EmailAuthProvider.credentialWithLink(
|
|
email,
|
|
oobSession.oobLink
|
|
);
|
|
const { user, operationType } = await firebase
|
|
.auth()
|
|
.signInWithCredential(cred);
|
|
|
|
expect(operationType).to.eq('signIn');
|
|
expect(user).to.eq(firebase.auth().currentUser);
|
|
expect(user!.uid).to.be.a('string');
|
|
expect(user!.email).to.eq(email);
|
|
expect(user!.emailVerified).to.be.true;
|
|
expect(user!.isAnonymous).to.be.false;
|
|
});
|
|
|
|
it('reauthenticate works with email credential', async () => {
|
|
let cred = firebase.auth.EmailAuthProvider.credentialWithLink(
|
|
email,
|
|
oobSession.oobLink
|
|
);
|
|
const { user: oldUser } = await firebase
|
|
.auth()
|
|
.signInWithCredential(cred);
|
|
|
|
const reauthSession = await sendEmailLink();
|
|
cred = firebase.auth.EmailAuthProvider.credentialWithLink(
|
|
email,
|
|
reauthSession.oobLink
|
|
);
|
|
const { user: newUser, operationType } =
|
|
await oldUser!.reauthenticateWithCredential(cred);
|
|
|
|
expect(newUser!.uid).to.eq(oldUser!.uid);
|
|
expect(operationType).to.eq('reauthenticate');
|
|
expect(firebase.auth().currentUser).to.eq(newUser);
|
|
});
|
|
|
|
it('reauthenticate throws with different email', async () => {
|
|
let cred = firebase.auth.EmailAuthProvider.credentialWithLink(
|
|
email,
|
|
oobSession.oobLink
|
|
);
|
|
const { user: oldUser } = await firebase
|
|
.auth()
|
|
.signInWithCredential(cred);
|
|
|
|
const newEmail = randomEmail();
|
|
const reauthSession = await sendEmailLink(newEmail);
|
|
cred = firebase.auth.EmailAuthProvider.credentialWithLink(
|
|
newEmail,
|
|
reauthSession.oobLink
|
|
);
|
|
await expect(
|
|
oldUser!.reauthenticateWithCredential(cred)
|
|
).to.be.rejectedWith(FirebaseError, 'auth/user-mismatch');
|
|
expect(firebase.auth().currentUser).to.eq(oldUser);
|
|
});
|
|
|
|
it('reauthenticate throws if user is deleted', async () => {
|
|
let cred = firebase.auth.EmailAuthProvider.credentialWithLink(
|
|
email,
|
|
oobSession.oobLink
|
|
);
|
|
const { user: oldUser } = await firebase
|
|
.auth()
|
|
.signInWithCredential(cred);
|
|
|
|
await oldUser!.delete();
|
|
const reauthSession = await sendEmailLink(email);
|
|
cred = firebase.auth.EmailAuthProvider.credentialWithLink(
|
|
email,
|
|
reauthSession.oobLink
|
|
);
|
|
await expect(
|
|
oldUser!.reauthenticateWithCredential(cred)
|
|
).to.be.rejectedWith(FirebaseError, 'auth/user-mismatch');
|
|
expect(firebase.auth().currentUser).to.be.null;
|
|
});
|
|
|
|
it('other accounts can be linked', async () => {
|
|
const cred = firebase.auth.EmailAuthProvider.credentialWithLink(
|
|
email,
|
|
oobSession.oobLink
|
|
);
|
|
const { user: original } = await firebase.auth().signInAnonymously();
|
|
|
|
expect(original!.isAnonymous).to.be.true;
|
|
const { user: linked, operationType } =
|
|
await original!.linkWithCredential(cred);
|
|
|
|
expect(operationType).to.eq('link');
|
|
expect(linked!.uid).to.eq(original!.uid);
|
|
expect(linked!.isAnonymous).to.be.false;
|
|
expect(firebase.auth().currentUser).to.eq(linked);
|
|
expect(linked!.email).to.eq(email);
|
|
expect(linked!.emailVerified).to.be.true;
|
|
});
|
|
|
|
it('can be linked to a custom token', async () => {
|
|
const { user: original } = await firebase.auth().signInWithCustomToken(
|
|
JSON.stringify({
|
|
uid: 'custom-uid'
|
|
})
|
|
);
|
|
|
|
const cred = firebase.auth.EmailAuthProvider.credentialWithLink(
|
|
email,
|
|
oobSession.oobLink
|
|
);
|
|
const { user: linked } = await original!.linkWithCredential(cred);
|
|
|
|
expect(linked!.uid).to.eq(original!.uid);
|
|
expect(firebase.auth().currentUser).to.eq(linked);
|
|
expect(linked!.email).to.eq(email);
|
|
expect(linked!.emailVerified).to.be.true;
|
|
});
|
|
|
|
it('cannot link if original account is deleted', async () => {
|
|
const cred = firebase.auth.EmailAuthProvider.credentialWithLink(
|
|
email,
|
|
oobSession.oobLink
|
|
);
|
|
const { user } = await firebase.auth().signInAnonymously();
|
|
|
|
expect(user!.isAnonymous).to.be.true;
|
|
await user!.delete();
|
|
await expect(user!.linkWithCredential(cred)).to.be.rejectedWith(
|
|
FirebaseError,
|
|
'auth/user-token-expired'
|
|
);
|
|
});
|
|
|
|
it('code can only be used once', async () => {
|
|
const link = oobSession.oobLink;
|
|
await firebase.auth().signInWithEmailLink(email, link);
|
|
await expect(
|
|
firebase.auth().signInWithEmailLink(email, link)
|
|
).to.be.rejectedWith(FirebaseError, 'auth/invalid-action-code');
|
|
});
|
|
|
|
it('fetchSignInMethodsForEmail returns the correct values', async () => {
|
|
const { user } = await firebase
|
|
.auth()
|
|
.signInWithEmailLink(email, oobSession.oobLink);
|
|
expect(await firebase.auth().fetchSignInMethodsForEmail(email)).to.eql([
|
|
'emailLink'
|
|
]);
|
|
|
|
await user!.updatePassword('password');
|
|
const updatedMethods = await firebase
|
|
.auth()
|
|
.fetchSignInMethodsForEmail(email);
|
|
expect(updatedMethods).to.have.length(2);
|
|
expect(updatedMethods).to.include('emailLink');
|
|
expect(updatedMethods).to.include('password');
|
|
});
|
|
|
|
it('throws an error if the wrong code is provided', async () => {
|
|
const otherSession = await sendEmailLink(randomEmail());
|
|
await expect(
|
|
firebase.auth().signInWithEmailLink(email, otherSession.oobLink)
|
|
).to.be.rejectedWith(FirebaseError, 'auth/invalid-email');
|
|
});
|
|
});
|
|
|
|
it('can be used to verify email', async () => {
|
|
// Create an unverified user
|
|
const { user } = await firebase
|
|
.auth()
|
|
.createUserWithEmailAndPassword(email, 'password');
|
|
expect(user!.emailVerified).to.be.false;
|
|
expect(await firebase.auth().fetchSignInMethodsForEmail(email)).to.eql([
|
|
'password'
|
|
]);
|
|
await user!.sendEmailVerification();
|
|
|
|
// Apply the email verification code
|
|
await firebase.auth().applyActionCode((await code(email)).oobCode);
|
|
await user!.reload();
|
|
expect(user!.emailVerified).to.be.true;
|
|
});
|
|
|
|
it('can be used to initiate password reset', async () => {
|
|
const { user: original } = await firebase
|
|
.auth()
|
|
.createUserWithEmailAndPassword(email, 'password');
|
|
await original!.sendEmailVerification(); // Can only reset verified user emails
|
|
await firebase.auth().applyActionCode((await code(email)).oobCode);
|
|
|
|
// Send and confirm the password reset
|
|
await firebase.auth().sendPasswordResetEmail(email);
|
|
const oobCode = (await code(email)).oobCode;
|
|
expect(await firebase.auth().verifyPasswordResetCode(oobCode)).to.eq(email);
|
|
await firebase.auth().confirmPasswordReset(oobCode, 'new-password');
|
|
|
|
// Make sure the new password works and the old one doesn't
|
|
const { user } = await firebase
|
|
.auth()
|
|
.signInWithEmailAndPassword(email, 'new-password');
|
|
expect(user!.uid).to.eq(original!.uid);
|
|
expect(user!.emailVerified).to.be.true;
|
|
expect(await firebase.auth().fetchSignInMethodsForEmail(email)).to.eql([
|
|
'password'
|
|
]);
|
|
|
|
await expect(
|
|
firebase.auth().signInWithEmailAndPassword(email, 'password')
|
|
).to.be.rejectedWith(FirebaseError, 'auth/wrong-password');
|
|
});
|
|
|
|
// Test is ignored for now as the emulator does not currently support the
|
|
// verify-and-change-email operation.
|
|
xit('verifyBeforeUpdateEmail waits until flow completes', async () => {
|
|
const updatedEmail = randomEmail();
|
|
|
|
// Create an initial user with the basic email
|
|
await firebase.auth().sendSignInLinkToEmail(email, BASE_SETTINGS);
|
|
const { user } = await firebase
|
|
.auth()
|
|
.signInWithEmailLink(email, (await code(email)).oobLink);
|
|
await user!.verifyBeforeUpdateEmail(updatedEmail, BASE_SETTINGS);
|
|
expect(user!.email).to.eq(email);
|
|
|
|
// Finish the update email flow
|
|
await firebase.auth().applyActionCode((await code(updatedEmail)).oobCode);
|
|
await user!.reload();
|
|
expect(user!.emailVerified).to.be.true;
|
|
expect(user!.email).to.eq(updatedEmail);
|
|
expect(firebase.auth().currentUser).to.eq(user);
|
|
|
|
// Old email doesn't work but new one does
|
|
await expect(
|
|
firebase.auth().signInWithEmailAndPassword(email, 'password')
|
|
).to.be.rejectedWith(FirebaseError, 'auth/alskdjf');
|
|
const { user: newSignIn } = await firebase
|
|
.auth()
|
|
.signInWithEmailAndPassword(updatedEmail, 'password');
|
|
expect(newSignIn!.uid).to.eq(user!.uid);
|
|
});
|
|
});
|