From 7b819e631fee56f40cc0721eb0acaa4f513dbea0 Mon Sep 17 00:00:00 2001 From: Sebastian Schmidt Date: Fri, 23 Apr 2021 09:58:17 -0600 Subject: [PATCH 01/15] Create sweet-monkeys-warn.md --- .changeset/sweet-monkeys-warn.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/sweet-monkeys-warn.md diff --git a/.changeset/sweet-monkeys-warn.md b/.changeset/sweet-monkeys-warn.md new file mode 100644 index 00000000000..6b1ac7a7f98 --- /dev/null +++ b/.changeset/sweet-monkeys-warn.md @@ -0,0 +1,5 @@ +--- +"@firebase/database": patch +--- + +Fixes a regression introduced with 8.4.1 that broke `useEmulator()`. From 71c772535b385e0211d33a5cbe3f6f2f17c8dab3 Mon Sep 17 00:00:00 2001 From: Yuchen Shi Date: Mon, 26 Apr 2021 18:47:42 -0700 Subject: [PATCH 02/15] Add mockUserToken support for Firestore. --- packages/app-types/index.d.ts | 78 +++++++++++++++++++ packages/firestore-types/index.d.ts | 10 ++- packages/firestore/src/api/credentials.ts | 32 ++++++++ packages/firestore/src/api/database.ts | 16 +++- packages/firestore/src/lite/database.ts | 26 ++++++- .../test/integration/api/validation.test.ts | 18 +++++ .../firestore/test/unit/api/database.test.ts | 17 ++++ 7 files changed, 190 insertions(+), 7 deletions(-) diff --git a/packages/app-types/index.d.ts b/packages/app-types/index.d.ts index 4aad68c7173..1234106eb17 100644 --- a/packages/app-types/index.d.ts +++ b/packages/app-types/index.d.ts @@ -121,6 +121,84 @@ export interface VersionService { version: string; } +export type FirebaseSignInProvider = + | 'custom' + | 'email' + | 'password' + | 'phone' + | 'anonymous' + | 'google.com' + | 'facebook.com' + | 'github.com' + | 'twitter.com' + | 'microsoft.com' + | 'apple.com'; + +export interface FirebaseIdToken { + // Firebase Auth tokens contain snake_case claims following the JWT standard / convention. + /* eslint-disable camelcase */ + + // Always set to https://securetoken.google.com/PROJECT_ID + iss: string; + + // Always set to PROJECT_ID + aud: string; + + // The user's unique id + sub: string; + + // The token issue time, in seconds since epoch + iat: number; + + // The token expiry time, normally 'iat' + 3600 + exp: number; + + // The user's unique id, must be equal to 'sub' + user_id: string; + + // The time the user authenticated, normally 'iat' + auth_time: number; + + // The sign in provider, only set when the provider is 'anonymous' + provider_id?: 'anonymous'; + + // The user's primary email + email?: string; + + // The user's email verification status + email_verified?: boolean; + + // The user's primary phone number + phone_number?: string; + + // The user's display name + name?: string; + + // The user's profile photo URL + picture?: string; + + // Information on all identities linked to this user + firebase: { + // The primary sign-in provider + sign_in_provider: FirebaseSignInProvider; + + // A map of providers to the user's list of unique identifiers from + // each provider + identities?: { [provider in FirebaseSignInProvider]?: string[] }; + }; + + // Custom claims set by the developer + // eslint-disable-next-line @typescript-eslint/no-explicit-any + [claim: string]: any; + + uid?: never; // Try to catch a common mistake of "uid" (should be "sub" instead). + + /* eslint-enable camelcase */ +} + +export type EmulatorMockTokenOptions = ({ user_id: string } | { sub: string }) & + Partial; + declare module '@firebase/component' { interface NameServiceMapping { 'app': FirebaseApp; diff --git a/packages/firestore-types/index.d.ts b/packages/firestore-types/index.d.ts index 13232f20a53..bed6ff3cdc0 100644 --- a/packages/firestore-types/index.d.ts +++ b/packages/firestore-types/index.d.ts @@ -15,7 +15,7 @@ * limitations under the License. */ -import { FirebaseApp, FirebaseNamespace } from '@firebase/app-types'; +import { EmulatorMockTokenOptions } from '@firebase/app-types'; export type DocumentData = { [field: string]: any }; @@ -61,7 +61,13 @@ export class FirebaseFirestore { settings(settings: Settings): void; - useEmulator(host: string, port: number): void; + useEmulator( + host: string, + port: number, + options?: { + mockUserToken?: EmulatorMockTokenOptions; + } + ): void; enablePersistence(settings?: PersistenceSettings): Promise; diff --git a/packages/firestore/src/api/credentials.ts b/packages/firestore/src/api/credentials.ts index ca1b0006ba2..6bb539e4253 100644 --- a/packages/firestore/src/api/credentials.ts +++ b/packages/firestore/src/api/credentials.ts @@ -135,6 +135,38 @@ export class EmptyCredentialsProvider implements CredentialsProvider { } } +/** A CredentialsProvider that always returns a constant token. Used for emulator token mocking. */ +export class EmulatorCredentialsProvider implements CredentialsProvider { + constructor(private token: Token) {} + + /** + * Stores the listener registered with setChangeListener() + * This isn't actually necessary since the UID never changes, but we use this + * to verify the listen contract is adhered to in tests. + */ + private changeListener: CredentialChangeListener | null = null; + + getToken(): Promise { + return Promise.resolve(this.token); + } + + invalidateToken(): void {} + + setChangeListener(changeListener: CredentialChangeListener): void { + debugAssert( + !this.changeListener, + 'Can only call setChangeListener() once.' + ); + this.changeListener = changeListener; + // Fire with initial user. + changeListener(this.token.user); + } + + removeChangeListener(): void { + this.changeListener = null; + } +} + export class FirebaseCredentialsProvider implements CredentialsProvider { /** * The auth token listener registered with FirebaseApp, retained here so we diff --git a/packages/firestore/src/api/database.ts b/packages/firestore/src/api/database.ts index e7e571ce21f..9b389d51bed 100644 --- a/packages/firestore/src/api/database.ts +++ b/packages/firestore/src/api/database.ts @@ -44,7 +44,11 @@ import { WhereFilterOp as PublicWhereFilterOp, WriteBatch as PublicWriteBatch } from '@firebase/firestore-types'; -import { Compat, getModularInstance } from '@firebase/util'; +import { + Compat, + EmulatorMockTokenOptions, + getModularInstance +} from '@firebase/util'; import { LoadBundleTask, @@ -223,8 +227,14 @@ export class Firestore this._delegate._setSettings(settingsLiteral); } - useEmulator(host: string, port: number): void { - useFirestoreEmulator(this._delegate, host, port); + useEmulator( + host: string, + port: number, + options: { + mockUserToken?: EmulatorMockTokenOptions; + } = {} + ): void { + useFirestoreEmulator(this._delegate, host, port, options); } enableNetwork(): Promise { diff --git a/packages/firestore/src/lite/database.ts b/packages/firestore/src/lite/database.ts index 6b510530d6b..fa9c2c1fb5f 100644 --- a/packages/firestore/src/lite/database.ts +++ b/packages/firestore/src/lite/database.ts @@ -24,13 +24,17 @@ import { } from '@firebase/app-exp'; import { FirebaseAuthInternalName } from '@firebase/auth-interop-types'; import { Provider } from '@firebase/component'; +import { createMockUserToken, EmulatorMockTokenOptions } from '@firebase/util'; import { CredentialsProvider, EmptyCredentialsProvider, + EmulatorCredentialsProvider, FirebaseCredentialsProvider, - makeCredentialsProvider + makeCredentialsProvider, + OAuthToken } from '../api/credentials'; +import { User } from '../auth/user'; import { DatabaseId } from '../core/database_info'; import { Code, FirestoreError } from '../util/error'; import { cast } from '../util/input_validation'; @@ -230,7 +234,10 @@ export function getFirestore(app: FirebaseApp = getApp()): FirebaseFirestore { export function useFirestoreEmulator( firestore: FirebaseFirestore, host: string, - port: number + port: number, + options: { + mockUserToken?: EmulatorMockTokenOptions; + } = {} ): void { firestore = cast(firestore, FirebaseFirestore); const settings = firestore._getSettings(); @@ -247,6 +254,21 @@ export function useFirestoreEmulator( host: `${host}:${port}`, ssl: false }); + + if (options.mockUserToken) { + const uid = options.mockUserToken.sub || options.mockUserToken.user_id; + if (!uid) { + throw new FirestoreError( + Code.INVALID_ARGUMENT, + "mockUserToken must contain 'sub' or 'user_id' field!" + ); + } + + const token = createMockUserToken(options.mockUserToken); + firestore._credentials = new EmulatorCredentialsProvider( + new OAuthToken(token, new User(uid)) + ); + } } /** diff --git a/packages/firestore/test/integration/api/validation.test.ts b/packages/firestore/test/integration/api/validation.test.ts index ec56d625bee..b69f309cf17 100644 --- a/packages/firestore/test/integration/api/validation.test.ts +++ b/packages/firestore/test/integration/api/validation.test.ts @@ -157,6 +157,24 @@ apiDescribe('Validation:', (persistence: boolean) => { expect(() => db.useEmulator('localhost', 9000)).to.throw(errorMsg); } ); + + validationIt(persistence, 'useEmulator can set mockUserToken', () => { + const db = newTestFirestore('test-project'); + // Verify that this doesn't throw. + db.useEmulator('localhost', 9000, { mockUserToken: { sub: 'foo' } }); + }); + + validationIt( + persistence, + 'throws if sub / user_id is missing in mockUserToken', + async db => { + const errorMsg = "mockUserToken must contain 'sub' or 'user_id' field!"; + + expect(() => + db.useEmulator('localhost', 9000, { mockUserToken: {} as any }) + ).to.throw(errorMsg); + } + ); }); describe('Firestore', () => { diff --git a/packages/firestore/test/unit/api/database.test.ts b/packages/firestore/test/unit/api/database.test.ts index f01c5d509eb..16786b8ac18 100644 --- a/packages/firestore/test/unit/api/database.test.ts +++ b/packages/firestore/test/unit/api/database.test.ts @@ -15,7 +15,9 @@ * limitations under the License. */ +import { createMockUserToken } from '@firebase/util'; import { expect } from 'chai'; +import { EmulatorCredentialsProvider } from '../../../src/api/credentials'; import { collectionReference, @@ -250,4 +252,19 @@ describe('Settings', () => { expect(db._delegate._getSettings().host).to.equal('localhost:9000'); expect(db._delegate._getSettings().ssl).to.be.false; }); + + it('sets credentials based on mockUserToken', async () => { + // Use a new instance of Firestore in order to configure settings. + const db = newTestFirestore(); + const mockUserToken = { sub: 'foobar' }; + db.useEmulator('localhost', 9000, { mockUserToken }); + + expect(db._delegate._getSettings().host).to.equal('localhost:9000'); + expect(db._delegate._getSettings().ssl).to.be.false; + const { credentials } = db._delegate._getSettings(); + expect(credentials).to.be.instanceOf(EmulatorCredentialsProvider); + await expect(credentials.getToken()).to.eventually.be.eql( + createMockUserToken(mockUserToken) + ); + }); }); From 5199f48d91604cf428433a60885c6e58b4a23a54 Mon Sep 17 00:00:00 2001 From: Yuchen Shi Date: Mon, 26 Apr 2021 20:12:41 -0700 Subject: [PATCH 03/15] Create lemon-ligers-protect.md --- .changeset/lemon-ligers-protect.md | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100644 .changeset/lemon-ligers-protect.md diff --git a/.changeset/lemon-ligers-protect.md b/.changeset/lemon-ligers-protect.md new file mode 100644 index 00000000000..25d541f3923 --- /dev/null +++ b/.changeset/lemon-ligers-protect.md @@ -0,0 +1,8 @@ +--- +"@firebase/app-types": minor +"@firebase/app": minor +"@firebase/firestore-types": minor +"@firebase/firestore": minor +--- + +Add mockUserToken support for Firestore. From e93fe6656db7a4e77140b0ed3d9bb3b45663bccf Mon Sep 17 00:00:00 2001 From: Yuchen Shi Date: Mon, 26 Apr 2021 20:25:58 -0700 Subject: [PATCH 04/15] Fix test for credentials. --- packages/firestore/test/unit/api/database.test.ts | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/packages/firestore/test/unit/api/database.test.ts b/packages/firestore/test/unit/api/database.test.ts index 16786b8ac18..c55e56bb6dc 100644 --- a/packages/firestore/test/unit/api/database.test.ts +++ b/packages/firestore/test/unit/api/database.test.ts @@ -259,12 +259,10 @@ describe('Settings', () => { const mockUserToken = { sub: 'foobar' }; db.useEmulator('localhost', 9000, { mockUserToken }); - expect(db._delegate._getSettings().host).to.equal('localhost:9000'); - expect(db._delegate._getSettings().ssl).to.be.false; - const { credentials } = db._delegate._getSettings(); + const credentials = db._delegate._credentials; expect(credentials).to.be.instanceOf(EmulatorCredentialsProvider); - await expect(credentials.getToken()).to.eventually.be.eql( - createMockUserToken(mockUserToken) - ); + const token = await credentials.getToken(); + expect(token!.type).to.eql('OAuth'); + expect(token!.user.uid).to.eql(mockUserToken.sub); }); }); From a099b5a869ddc34ef8347ff051c4d4b1a4b53e01 Mon Sep 17 00:00:00 2001 From: Yuchen Shi Date: Tue, 27 Apr 2021 19:52:05 -0700 Subject: [PATCH 05/15] Swap validation order. --- packages/firestore/src/lite/database.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/firestore/src/lite/database.ts b/packages/firestore/src/lite/database.ts index fa9c2c1fb5f..add1db27888 100644 --- a/packages/firestore/src/lite/database.ts +++ b/packages/firestore/src/lite/database.ts @@ -256,6 +256,8 @@ export function useFirestoreEmulator( }); if (options.mockUserToken) { + // Let createMockUserToken validate first (catches common mistakes like "uid" and missing sub.) + const token = createMockUserToken(options.mockUserToken); const uid = options.mockUserToken.sub || options.mockUserToken.user_id; if (!uid) { throw new FirestoreError( @@ -264,7 +266,6 @@ export function useFirestoreEmulator( ); } - const token = createMockUserToken(options.mockUserToken); firestore._credentials = new EmulatorCredentialsProvider( new OAuthToken(token, new User(uid)) ); From 6edfb421414d897d6dcc58d7237e398806853e41 Mon Sep 17 00:00:00 2001 From: Yuchen Shi Date: Thu, 29 Apr 2021 15:09:13 -0700 Subject: [PATCH 06/15] Bump firebase by minor. --- .changeset/lemon-ligers-protect.md | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/.changeset/lemon-ligers-protect.md b/.changeset/lemon-ligers-protect.md index 25d541f3923..d12c1a6ef1b 100644 --- a/.changeset/lemon-ligers-protect.md +++ b/.changeset/lemon-ligers-protect.md @@ -1,8 +1,9 @@ --- -"@firebase/app-types": minor -"@firebase/app": minor -"@firebase/firestore-types": minor -"@firebase/firestore": minor +'@firebase/app-types': minor +'@firebase/app': minor +'@firebase/firestore-types': minor +'@firebase/firestore': minor +'firebase': minor --- Add mockUserToken support for Firestore. From f3698ea79f270999ac8a4e69c80ce81b0af69f70 Mon Sep 17 00:00:00 2001 From: Yuchen Shi Date: Thu, 29 Apr 2021 15:20:33 -0700 Subject: [PATCH 07/15] Reuse types from @firebase/util. --- packages/app-types/index.d.ts | 78 --------------------------- packages/firestore-types/index.d.ts | 2 +- packages/firestore-types/package.json | 3 +- 3 files changed, 3 insertions(+), 80 deletions(-) diff --git a/packages/app-types/index.d.ts b/packages/app-types/index.d.ts index 1234106eb17..4aad68c7173 100644 --- a/packages/app-types/index.d.ts +++ b/packages/app-types/index.d.ts @@ -121,84 +121,6 @@ export interface VersionService { version: string; } -export type FirebaseSignInProvider = - | 'custom' - | 'email' - | 'password' - | 'phone' - | 'anonymous' - | 'google.com' - | 'facebook.com' - | 'github.com' - | 'twitter.com' - | 'microsoft.com' - | 'apple.com'; - -export interface FirebaseIdToken { - // Firebase Auth tokens contain snake_case claims following the JWT standard / convention. - /* eslint-disable camelcase */ - - // Always set to https://securetoken.google.com/PROJECT_ID - iss: string; - - // Always set to PROJECT_ID - aud: string; - - // The user's unique id - sub: string; - - // The token issue time, in seconds since epoch - iat: number; - - // The token expiry time, normally 'iat' + 3600 - exp: number; - - // The user's unique id, must be equal to 'sub' - user_id: string; - - // The time the user authenticated, normally 'iat' - auth_time: number; - - // The sign in provider, only set when the provider is 'anonymous' - provider_id?: 'anonymous'; - - // The user's primary email - email?: string; - - // The user's email verification status - email_verified?: boolean; - - // The user's primary phone number - phone_number?: string; - - // The user's display name - name?: string; - - // The user's profile photo URL - picture?: string; - - // Information on all identities linked to this user - firebase: { - // The primary sign-in provider - sign_in_provider: FirebaseSignInProvider; - - // A map of providers to the user's list of unique identifiers from - // each provider - identities?: { [provider in FirebaseSignInProvider]?: string[] }; - }; - - // Custom claims set by the developer - // eslint-disable-next-line @typescript-eslint/no-explicit-any - [claim: string]: any; - - uid?: never; // Try to catch a common mistake of "uid" (should be "sub" instead). - - /* eslint-enable camelcase */ -} - -export type EmulatorMockTokenOptions = ({ user_id: string } | { sub: string }) & - Partial; - declare module '@firebase/component' { interface NameServiceMapping { 'app': FirebaseApp; diff --git a/packages/firestore-types/index.d.ts b/packages/firestore-types/index.d.ts index bed6ff3cdc0..f7a76e32064 100644 --- a/packages/firestore-types/index.d.ts +++ b/packages/firestore-types/index.d.ts @@ -15,7 +15,7 @@ * limitations under the License. */ -import { EmulatorMockTokenOptions } from '@firebase/app-types'; +import { EmulatorMockTokenOptions } from '@firebase/util'; export type DocumentData = { [field: string]: any }; diff --git a/packages/firestore-types/package.json b/packages/firestore-types/package.json index b73bcf87f05..ba4a780ad57 100644 --- a/packages/firestore-types/package.json +++ b/packages/firestore-types/package.json @@ -12,7 +12,8 @@ "index.d.ts" ], "peerDependencies": { - "@firebase/app-types": "0.x" + "@firebase/app-types": "0.x", + "@firebase/util": "1.x" }, "repository": { "directory": "packages/firestore-types", From 2a40e0d6cd400d95bf392d57629374f67f6957a5 Mon Sep 17 00:00:00 2001 From: Yuchen Shi Date: Thu, 29 Apr 2021 15:29:44 -0700 Subject: [PATCH 08/15] Fix import lint. --- packages/firestore/test/unit/api/database.test.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/packages/firestore/test/unit/api/database.test.ts b/packages/firestore/test/unit/api/database.test.ts index c55e56bb6dc..8ba1d406a6d 100644 --- a/packages/firestore/test/unit/api/database.test.ts +++ b/packages/firestore/test/unit/api/database.test.ts @@ -15,10 +15,9 @@ * limitations under the License. */ -import { createMockUserToken } from '@firebase/util'; import { expect } from 'chai'; -import { EmulatorCredentialsProvider } from '../../../src/api/credentials'; +import { EmulatorCredentialsProvider } from '../../../src/api/credentials'; import { collectionReference, documentReference, From b2debbc73d4959a9d4e3123e3ddd7c002ad4740b Mon Sep 17 00:00:00 2001 From: Yuchen Shi Date: Thu, 29 Apr 2021 17:14:20 -0700 Subject: [PATCH 09/15] Update .changeset/lemon-ligers-protect.md Co-authored-by: Feiyang --- .changeset/lemon-ligers-protect.md | 2 -- 1 file changed, 2 deletions(-) diff --git a/.changeset/lemon-ligers-protect.md b/.changeset/lemon-ligers-protect.md index d12c1a6ef1b..3efae59f426 100644 --- a/.changeset/lemon-ligers-protect.md +++ b/.changeset/lemon-ligers-protect.md @@ -1,6 +1,4 @@ --- -'@firebase/app-types': minor -'@firebase/app': minor '@firebase/firestore-types': minor '@firebase/firestore': minor 'firebase': minor From 7bd95192ee8b540e98b4753cdc4ed4d33b002599 Mon Sep 17 00:00:00 2001 From: Yuchen Shi Date: Thu, 29 Apr 2021 17:15:26 -0700 Subject: [PATCH 10/15] Delete sweet-monkeys-warn.md --- .changeset/sweet-monkeys-warn.md | 5 ----- 1 file changed, 5 deletions(-) delete mode 100644 .changeset/sweet-monkeys-warn.md diff --git a/.changeset/sweet-monkeys-warn.md b/.changeset/sweet-monkeys-warn.md deleted file mode 100644 index 6b1ac7a7f98..00000000000 --- a/.changeset/sweet-monkeys-warn.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@firebase/database": patch ---- - -Fixes a regression introduced with 8.4.1 that broke `useEmulator()`. From 27a360d4c0b6481095dd7b3ea3d70321fb89044d Mon Sep 17 00:00:00 2001 From: Yuchen Shi Date: Fri, 30 Apr 2021 12:59:49 -0700 Subject: [PATCH 11/15] Add signature change to firebase/index.d.ts. --- packages/firebase/index.d.ts | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/packages/firebase/index.d.ts b/packages/firebase/index.d.ts index 45bf03391db..062a09f6a9b 100644 --- a/packages/firebase/index.d.ts +++ b/packages/firebase/index.d.ts @@ -15,6 +15,8 @@ * limitations under the License. */ +import { EmulatorMockTokenOptions } from '@firebase/util'; + /** * firebase is a global namespace from which all Firebase * services are accessed. @@ -8179,8 +8181,16 @@ declare namespace firebase.firestore { * * @param host the emulator host (ex: localhost). * @param port the emulator port (ex: 9000). + * @param options.mockUserToken - the mock auth token to use for unit + * testing Security Rules. */ - useEmulator(host: string, port: number): void; + useEmulator( + host: string, + port: number, + options?: { + mockUserToken?: EmulatorMockTokenOptions; + } + ): void; /** * Attempts to enable persistent storage, if possible. From 594c9bb83b52e86624fb1e8c691cba5b3356b73e Mon Sep 17 00:00:00 2001 From: Yuchen Shi Date: Fri, 30 Apr 2021 12:59:58 -0700 Subject: [PATCH 12/15] Format comments. --- packages/firestore/src/api/credentials.ts | 5 ++++- packages/firestore/src/lite/database.ts | 5 ++++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/packages/firestore/src/api/credentials.ts b/packages/firestore/src/api/credentials.ts index 6bb539e4253..69d483a8f1d 100644 --- a/packages/firestore/src/api/credentials.ts +++ b/packages/firestore/src/api/credentials.ts @@ -135,7 +135,10 @@ export class EmptyCredentialsProvider implements CredentialsProvider { } } -/** A CredentialsProvider that always returns a constant token. Used for emulator token mocking. */ +/** + * A CredentialsProvider that always returns a constant token. Used for + * emulator token mocking. + */ export class EmulatorCredentialsProvider implements CredentialsProvider { constructor(private token: Token) {} diff --git a/packages/firestore/src/lite/database.ts b/packages/firestore/src/lite/database.ts index add1db27888..43730105de5 100644 --- a/packages/firestore/src/lite/database.ts +++ b/packages/firestore/src/lite/database.ts @@ -230,6 +230,8 @@ export function getFirestore(app: FirebaseApp = getApp()): FirebaseFirestore { * emulator. * @param host - the emulator host (ex: localhost). * @param port - the emulator port (ex: 9000). + * @param options.mockUserToken - the mock auth token to use for unit testing + * Security Rules. */ export function useFirestoreEmulator( firestore: FirebaseFirestore, @@ -256,7 +258,8 @@ export function useFirestoreEmulator( }); if (options.mockUserToken) { - // Let createMockUserToken validate first (catches common mistakes like "uid" and missing sub.) + // Let createMockUserToken validate first (catches common mistakes like + // invalid field "uid" and missing field "sub" / "user_id".) const token = createMockUserToken(options.mockUserToken); const uid = options.mockUserToken.sub || options.mockUserToken.user_id; if (!uid) { From d86dbdd1f243fe34ae2a3b303ad9e171f797ee52 Mon Sep 17 00:00:00 2001 From: Yuchen Shi Date: Fri, 30 Apr 2021 14:39:19 -0700 Subject: [PATCH 13/15] Add emulator utils to Firestore externs. --- packages/firestore/externs.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/firestore/externs.json b/packages/firestore/externs.json index de3847a83f9..5b9cb8cda84 100644 --- a/packages/firestore/externs.json +++ b/packages/firestore/externs.json @@ -1,5 +1,5 @@ { - "externs" : [ + "externs": [ "node_modules/@types/node/base.d.ts", "node_modules/@types/node/globals.d.ts", "node_modules/typescript/lib/lib.es5.d.ts", @@ -26,6 +26,7 @@ "packages/logger/dist/src/logger.d.ts", "packages/webchannel-wrapper/src/index.d.ts", "packages/util/dist/src/crypt.d.ts", + "packages/util/dist/src/emulator.d.ts", "packages/util/dist/src/environment.d.ts", "packages/util/dist/src/compat.d.ts", "packages/firestore/export.ts", From dd51b9fb50454c01826e61375a6a9243ffd7a789 Mon Sep 17 00:00:00 2001 From: Yuchen Shi Date: Mon, 3 May 2021 14:10:59 -0700 Subject: [PATCH 14/15] Copy typings into firebase/index.d.ts. --- packages/firebase/index.d.ts | 77 +++++++++++++++++++++++++++++++++++- 1 file changed, 75 insertions(+), 2 deletions(-) diff --git a/packages/firebase/index.d.ts b/packages/firebase/index.d.ts index 062a09f6a9b..41bc935adcd 100644 --- a/packages/firebase/index.d.ts +++ b/packages/firebase/index.d.ts @@ -15,8 +15,6 @@ * limitations under the License. */ -import { EmulatorMockTokenOptions } from '@firebase/util'; - /** * firebase is a global namespace from which all Firebase * services are accessed. @@ -9986,6 +9984,81 @@ declare namespace firebase.firestore { name: string; stack?: string; } + + type FirebaseSignInProvider = + | 'custom' + | 'email' + | 'password' + | 'phone' + | 'anonymous' + | 'google.com' + | 'facebook.com' + | 'github.com' + | 'twitter.com' + | 'microsoft.com' + | 'apple.com'; + + interface FirebaseIdToken { + // Always set to https://securetoken.google.com/PROJECT_ID + iss: string; + + // Always set to PROJECT_ID + aud: string; + + // The user's unique id + sub: string; + + // The token issue time, in seconds since epoch + iat: number; + + // The token expiry time, normally 'iat' + 3600 + exp: number; + + // The user's unique id, must be equal to 'sub' + user_id: string; + + // The time the user authenticated, normally 'iat' + auth_time: number; + + // The sign in provider, only set when the provider is 'anonymous' + provider_id?: 'anonymous'; + + // The user's primary email + email?: string; + + // The user's email verification status + email_verified?: boolean; + + // The user's primary phone number + phone_number?: string; + + // The user's display name + name?: string; + + // The user's profile photo URL + picture?: string; + + // Information on all identities linked to this user + firebase: { + // The primary sign-in provider + sign_in_provider: FirebaseSignInProvider; + + // A map of providers to the user's list of unique identifiers from + // each provider + identities?: { [provider in FirebaseSignInProvider]?: string[] }; + }; + + // Custom claims set by the developer + [claim: string]: unknown; + + uid?: never; // Try to catch a common mistake of "uid" (should be "sub" instead). + } + + export type EmulatorMockTokenOptions = ( + | { user_id: string } + | { sub: string } + ) & + Partial; } export default firebase; From ec61867f63ee818cd2cd5af16fabf12f3692bf2a Mon Sep 17 00:00:00 2001 From: Yuchen Shi Date: Mon, 3 May 2021 14:42:00 -0700 Subject: [PATCH 15/15] Use jsdoc style comments. --- packages/firebase/index.d.ts | 38 ++++++++++++++++++------------------ 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/packages/firebase/index.d.ts b/packages/firebase/index.d.ts index 41bc935adcd..28f51f54314 100644 --- a/packages/firebase/index.d.ts +++ b/packages/firebase/index.d.ts @@ -9999,59 +9999,59 @@ declare namespace firebase.firestore { | 'apple.com'; interface FirebaseIdToken { - // Always set to https://securetoken.google.com/PROJECT_ID + /** Always set to https://securetoken.google.com/PROJECT_ID */ iss: string; - // Always set to PROJECT_ID + /** Always set to PROJECT_ID */ aud: string; - // The user's unique id + /** The user's unique id */ sub: string; - // The token issue time, in seconds since epoch + /** The token issue time, in seconds since epoch */ iat: number; - // The token expiry time, normally 'iat' + 3600 + /** The token expiry time, normally 'iat' + 3600 */ exp: number; - // The user's unique id, must be equal to 'sub' + /** The user's unique id, must be equal to 'sub' */ user_id: string; - // The time the user authenticated, normally 'iat' + /** The time the user authenticated, normally 'iat' */ auth_time: number; - // The sign in provider, only set when the provider is 'anonymous' + /** The sign in provider, only set when the provider is 'anonymous' */ provider_id?: 'anonymous'; - // The user's primary email + /** The user's primary email */ email?: string; - // The user's email verification status + /** The user's email verification status */ email_verified?: boolean; - // The user's primary phone number + /** The user's primary phone number */ phone_number?: string; - // The user's display name + /** The user's display name */ name?: string; - // The user's profile photo URL + /** The user's profile photo URL */ picture?: string; - // Information on all identities linked to this user + /** Information on all identities linked to this user */ firebase: { - // The primary sign-in provider + /** The primary sign-in provider */ sign_in_provider: FirebaseSignInProvider; - // A map of providers to the user's list of unique identifiers from - // each provider + /** A map of providers to the user's list of unique identifiers from each provider */ identities?: { [provider in FirebaseSignInProvider]?: string[] }; }; - // Custom claims set by the developer + /** Custom claims set by the developer */ [claim: string]: unknown; - uid?: never; // Try to catch a common mistake of "uid" (should be "sub" instead). + // NO LONGER SUPPORTED. Use "sub" instead. (Not a jsdoc comment to avoid generating docs.) + uid?: never; } export type EmulatorMockTokenOptions = (