diff --git a/.changeset/gentle-laws-kneel.md b/.changeset/gentle-laws-kneel.md new file mode 100644 index 00000000000..b90115f77c5 --- /dev/null +++ b/.changeset/gentle-laws-kneel.md @@ -0,0 +1,10 @@ +--- +"@firebase/database-compat": patch +"@firebase/database-types": patch +"@firebase/database": patch +"@firebase/firestore": patch +"@firebase/functions": patch +"@firebase/storage": patch +--- + +Add SSL checks to `connectDatabaseEmulator` and `connectFirestoreEmulator` diff --git a/common/api-review/database.api.md b/common/api-review/database.api.md index 0b7b36869d6..edec4d6d709 100644 --- a/common/api-review/database.api.md +++ b/common/api-review/database.api.md @@ -13,6 +13,7 @@ export function child(parent: DatabaseReference, path: string): DatabaseReferenc // @public export function connectDatabaseEmulator(db: Database, host: string, port: number, options?: { mockUserToken?: EmulatorMockTokenOptions | string; + ssl?: boolean; }): void; // @public diff --git a/common/api-review/firestore-lite.api.md b/common/api-review/firestore-lite.api.md index 4a9ef4c0171..1c05aac46b7 100644 --- a/common/api-review/firestore-lite.api.md +++ b/common/api-review/firestore-lite.api.md @@ -103,6 +103,7 @@ export class CollectionReferencefunction(app, ...) | | [getDatabase(app, url)](./database.md#getdatabase_d9cea01) | Returns the instance of the Realtime Database SDK that is associated with the provided [FirebaseApp](./app.firebaseapp.md#firebaseapp_interface). Initializes a new instance with default settings if no instance exists or if the existing instance uses a custom database URL. | | function(db, ...) | -| [connectDatabaseEmulator(db, host, port, options)](./database.md#connectdatabaseemulator_27b9e93) | Modify the provided instance to communicate with the Realtime Database emulator.

Note: This method must be called before performing any other operation. | +| [connectDatabaseEmulator(db, host, port, options)](./database.md#connectdatabaseemulator_20a9664) | Modify the provided instance to communicate with the Realtime Database emulator.

Note: This method must be called before performing any other operation. | | [goOffline(db)](./database.md#gooffline_732b338) | Disconnects from the server (all Database operations will be completed offline).The client automatically maintains a persistent connection to the Database server, which will remain active indefinitely and reconnect when disconnected. However, the goOffline() and goOnline() methods may be used to control the client connection in cases where a persistent connection is undesirable.While offline, the client will no longer receive data updates from the Database. However, all Database operations performed locally will continue to immediately fire events, allowing your application to continue behaving normally. Additionally, each operation performed locally will automatically be queued and retried upon reconnection to the Database server.To reconnect to the Database and begin receiving remote events, see goOnline(). | | [goOnline(db)](./database.md#goonline_732b338) | Reconnects to the server and synchronizes the offline Database state with the server state.This method should be used after disabling the active connection with goOffline(). Once reconnected, the client will transmit the proper data and fire the appropriate events so that your client "catches up" automatically. | | [ref(db, path)](./database.md#ref_5f88fa2) | Returns a Reference representing the location in the Database corresponding to the provided path. If no path is provided, the Reference will point to the root of the Database. | @@ -135,7 +135,7 @@ The `Database` instance of the provided app. ## function(db, ...) -### connectDatabaseEmulator(db, host, port, options) {:#connectdatabaseemulator_27b9e93} +### connectDatabaseEmulator(db, host, port, options) {:#connectdatabaseemulator_20a9664} Modify the provided instance to communicate with the Realtime Database emulator. @@ -146,6 +146,7 @@ Modify the provided instance to communicate with the Realtime Database emulator. ```typescript export declare function connectDatabaseEmulator(db: Database, host: string, port: number, options?: { mockUserToken?: EmulatorMockTokenOptions | string; + ssl?: boolean; }): void; ``` @@ -156,7 +157,7 @@ export declare function connectDatabaseEmulator(db: Database, host: string, port | db | [Database](./database.database.md#database_class) | The instance to modify. | | host | string | The emulator host (ex: localhost) | | port | number | The emulator port (ex: 8080) | -| options | { mockUserToken?: [EmulatorMockTokenOptions](./util.md#emulatormocktokenoptions) \| string; } | | +| options | { mockUserToken?: [EmulatorMockTokenOptions](./util.md#emulatormocktokenoptions) \| string; ssl?: boolean; } | | Returns: diff --git a/docs-devsite/firestore_.md b/docs-devsite/firestore_.md index 91d21e32708..70cc5221043 100644 --- a/docs-devsite/firestore_.md +++ b/docs-devsite/firestore_.md @@ -23,7 +23,7 @@ https://github.com/firebase/firebase-js-sdk | [clearIndexedDbPersistence(firestore)](./firestore_.md#clearindexeddbpersistence_231a8e0) | Clears the persistent storage. This includes pending writes and cached documents.Must be called while the [Firestore](./firestore_.firestore.md#firestore_class) instance is not started (after the app is terminated or when the app is first initialized). On startup, this function must be called before other functions (other than [initializeFirestore()](./firestore_.md#initializefirestore_fc7d200) or [getFirestore()](./firestore_.md#getfirestore))). If the [Firestore](./firestore_.firestore.md#firestore_class) instance is still running, the promise will be rejected with the error code of failed-precondition.Note: clearIndexedDbPersistence() is primarily intended to help write reliable tests that use Cloud Firestore. It uses an efficient mechanism for dropping existing data but does not attempt to securely overwrite or otherwise make cached data unrecoverable. For applications that are sensitive to the disclosure of cached data in between user sessions, we strongly recommend not enabling persistence at all. | | [collection(firestore, path, pathSegments)](./firestore_.md#collection_1eb4c23) | Gets a CollectionReference instance that refers to the collection at the specified absolute path. | | [collectionGroup(firestore, collectionId)](./firestore_.md#collectiongroup_1838fc3) | Creates and returns a new Query instance that includes all documents in the database that are contained in a collection or subcollection with the given collectionId. | -| [connectFirestoreEmulator(firestore, host, port, options)](./firestore_.md#connectfirestoreemulator_7c247cd) | Modify this instance to communicate with the Cloud Firestore emulator.Note: This must be called before this instance has been used to do any operations. | +| [connectFirestoreEmulator(firestore, host, port, options)](./firestore_.md#connectfirestoreemulator_6c8868a) | Modify this instance to communicate with the Cloud Firestore emulator.Note: This must be called before this instance has been used to do any operations. | | [disableNetwork(firestore)](./firestore_.md#disablenetwork_231a8e0) | Disables network usage for this instance. It can be re-enabled via [enableNetwork()](./firestore_.md#enablenetwork_231a8e0). While the network is disabled, any snapshot listeners, getDoc() or getDocs() calls will return results from cache, and any write operations will be queued until the network is restored. | | [doc(firestore, path, pathSegments)](./firestore_.md#doc_1eb4c23) | Gets a DocumentReference instance that refers to the document at the specified absolute path. | | [enableIndexedDbPersistence(firestore, persistenceSettings)](./firestore_.md#enableindexeddbpersistence_224174f) | Attempts to enable persistent storage, if possible.On failure, enableIndexedDbPersistence() will reject the promise or throw an exception. There are several reasons why this can fail, which can be identified by the code on the error.\* failed-precondition: The app is already open in another browser tab. \* unimplemented: The browser is incompatible with the offline persistence implementation.Note that even after a failure, the [Firestore](./firestore_.firestore.md#firestore_class) instance will remain usable, however offline persistence will be disabled.Note: enableIndexedDbPersistence() must be called before any other functions (other than [initializeFirestore()](./firestore_.md#initializefirestore_fc7d200), [getFirestore()](./firestore_.md#getfirestore) or [clearIndexedDbPersistence()](./firestore_.md#clearindexeddbpersistence_231a8e0).Persistence cannot be used in a Node.js environment. | @@ -377,7 +377,7 @@ export declare function collectionGroup(firestore: Firestore, collectionId: stri The created `Query`. -### connectFirestoreEmulator(firestore, host, port, options) {:#connectfirestoreemulator_7c247cd} +### connectFirestoreEmulator(firestore, host, port, options) {:#connectfirestoreemulator_6c8868a} Modify this instance to communicate with the Cloud Firestore emulator. @@ -388,6 +388,7 @@ Note: This must be called before this instance has been used to do any operation ```typescript export declare function connectFirestoreEmulator(firestore: Firestore, host: string, port: number, options?: { mockUserToken?: EmulatorMockTokenOptions | string; + ssl?: boolean; }): void; ``` @@ -398,7 +399,7 @@ export declare function connectFirestoreEmulator(firestore: Firestore, host: str | firestore | [Firestore](./firestore_.firestore.md#firestore_class) | The Firestore instance to configure to connect to the emulator. | | host | string | the emulator host (ex: localhost). | | port | number | the emulator port (ex: 9000). | -| options | { mockUserToken?: [EmulatorMockTokenOptions](./util.md#emulatormocktokenoptions) \| string; } | | +| options | { mockUserToken?: [EmulatorMockTokenOptions](./util.md#emulatormocktokenoptions) \| string; ssl?: boolean; } | | Returns: diff --git a/docs-devsite/firestore_lite.md b/docs-devsite/firestore_lite.md index 20fafd66c59..fe18f38bf47 100644 --- a/docs-devsite/firestore_lite.md +++ b/docs-devsite/firestore_lite.md @@ -23,7 +23,7 @@ https://github.com/firebase/firebase-js-sdk | function(firestore, ...) | | [collection(firestore, path, pathSegments)](./firestore_lite.md#collection_1eb4c23) | Gets a CollectionReference instance that refers to the collection at the specified absolute path. | | [collectionGroup(firestore, collectionId)](./firestore_lite.md#collectiongroup_1838fc3) | Creates and returns a new Query instance that includes all documents in the database that are contained in a collection or subcollection with the given collectionId. | -| [connectFirestoreEmulator(firestore, host, port, options)](./firestore_lite.md#connectfirestoreemulator_7c247cd) | Modify this instance to communicate with the Cloud Firestore emulator.Note: This must be called before this instance has been used to do any operations. | +| [connectFirestoreEmulator(firestore, host, port, options)](./firestore_lite.md#connectfirestoreemulator_6c8868a) | Modify this instance to communicate with the Cloud Firestore emulator.Note: This must be called before this instance has been used to do any operations. | | [doc(firestore, path, pathSegments)](./firestore_lite.md#doc_1eb4c23) | Gets a DocumentReference instance that refers to the document at the specified absolute path. | | [runTransaction(firestore, updateFunction, options)](./firestore_lite.md#runtransaction_6f03ec4) | Executes the given updateFunction and then attempts to commit the changes applied within the transaction. If any document read within the transaction has changed, Cloud Firestore retries the updateFunction. If it fails to commit after 5 attempts, the transaction fails.The maximum number of writes allowed in a single transaction is 500. | | [terminate(firestore)](./firestore_lite.md#terminate_231a8e0) | Terminates the provided Firestore instance.After calling terminate() only the clearIndexedDbPersistence() functions may be used. Any other function will throw a FirestoreError. Termination does not cancel any pending writes, and any promises that are awaiting a response from the server will not be resolved.To restart after termination, create a new instance of Firestore with [getFirestore()](./firestore_.md#getfirestore).Note: Under normal circumstances, calling terminate() is not required. This function is useful only when you want to force this instance to release all of its resources or in combination with [clearIndexedDbPersistence()](./firestore_.md#clearindexeddbpersistence_231a8e0) to ensure that all local state is destroyed between test runs. | @@ -308,7 +308,7 @@ export declare function collectionGroup(firestore: Firestore, collectionId: stri The created `Query`. -### connectFirestoreEmulator(firestore, host, port, options) {:#connectfirestoreemulator_7c247cd} +### connectFirestoreEmulator(firestore, host, port, options) {:#connectfirestoreemulator_6c8868a} Modify this instance to communicate with the Cloud Firestore emulator. @@ -319,6 +319,7 @@ Note: This must be called before this instance has been used to do any operation ```typescript export declare function connectFirestoreEmulator(firestore: Firestore, host: string, port: number, options?: { mockUserToken?: EmulatorMockTokenOptions | string; + ssl?: boolean; }): void; ``` @@ -329,7 +330,7 @@ export declare function connectFirestoreEmulator(firestore: Firestore, host: str | firestore | [Firestore](./firestore_lite.firestore.md#firestore_class) | The Firestore instance to configure to connect to the emulator. | | host | string | the emulator host (ex: localhost). | | port | number | the emulator port (ex: 9000). | -| options | { mockUserToken?: [EmulatorMockTokenOptions](./util.md#emulatormocktokenoptions) \| string; } | | +| options | { mockUserToken?: [EmulatorMockTokenOptions](./util.md#emulatormocktokenoptions) \| string; ssl?: boolean; } | | Returns: diff --git a/docs-devsite/functions.md b/docs-devsite/functions.md index 7e2eefa1569..b44bd5ec3cb 100644 --- a/docs-devsite/functions.md +++ b/docs-devsite/functions.md @@ -19,7 +19,7 @@ Cloud Functions for Firebase | function(app, ...) | | [getFunctions(app, regionOrCustomDomain)](./functions.md#getfunctions_60f2095) | Returns a [Functions](./functions.functions.md#functions_interface) instance for the given app. | | function(functionsInstance, ...) | -| [connectFunctionsEmulator(functionsInstance, host, port)](./functions.md#connectfunctionsemulator_505c08d) | Modify this instance to communicate with the Cloud Functions emulator.Note: this must be called before this instance has been used to do any operations. | +| [connectFunctionsEmulator(functionsInstance, host, port, ssl)](./functions.md#connectfunctionsemulator_a989598) | Modify this instance to communicate with the Cloud Functions emulator.Note: this must be called before this instance has been used to do any operations. | | [httpsCallable(functionsInstance, name, options)](./functions.md#httpscallable_1dd297c) | Returns a reference to the callable HTTPS trigger with the given name. | | [httpsCallableFromURL(functionsInstance, url, options)](./functions.md#httpscallablefromurl_7af6987) | Returns a reference to the callable HTTPS trigger with the specified url. | @@ -72,7 +72,7 @@ export declare function getFunctions(app?: FirebaseApp, regionOrCustomDomain?: s ## function(functionsInstance, ...) -### connectFunctionsEmulator(functionsInstance, host, port) {:#connectfunctionsemulator_505c08d} +### connectFunctionsEmulator(functionsInstance, host, port, ssl) {:#connectfunctionsemulator_a989598} Modify this instance to communicate with the Cloud Functions emulator. @@ -81,7 +81,7 @@ Note: this must be called before this instance has been used to do any operation Signature: ```typescript -export declare function connectFunctionsEmulator(functionsInstance: Functions, host: string, port: number): void; +export declare function connectFunctionsEmulator(functionsInstance: Functions, host: string, port: number, ssl?: boolean): void; ``` #### Parameters @@ -91,6 +91,7 @@ export declare function connectFunctionsEmulator(functionsInstance: Functions, h | functionsInstance | [Functions](./functions.functions.md#functions_interface) | | | host | string | The emulator host (ex: localhost) | | port | number | The emulator port (ex: 5001) | +| ssl | boolean | | Returns: diff --git a/docs-devsite/storage.md b/docs-devsite/storage.md index da72929ebc9..3cfaa98407e 100644 --- a/docs-devsite/storage.md +++ b/docs-devsite/storage.md @@ -19,7 +19,7 @@ Cloud Storage for Firebase | function(app, ...) | | [getStorage(app, bucketUrl)](./storage.md#getstorage_25f3a57) | Gets a [FirebaseStorage](./storage.firebasestorage.md#firebasestorage_interface) instance for the given Firebase app. | | function(storage, ...) | -| [connectStorageEmulator(storage, host, port, options)](./storage.md#connectstorageemulator_e9039de) | Modify this [FirebaseStorage](./storage.firebasestorage.md#firebasestorage_interface) instance to communicate with the Cloud Storage emulator. | +| [connectStorageEmulator(storage, host, port, options)](./storage.md#connectstorageemulator_ac343b7) | Modify this [FirebaseStorage](./storage.firebasestorage.md#firebasestorage_interface) instance to communicate with the Cloud Storage emulator. | | [ref(storage, url)](./storage.md#ref_5672fc1) | Returns a [StorageReference](./storage.storagereference.md#storagereference_interface) for the given url. | | function(ref, ...) | | [deleteObject(ref)](./storage.md#deleteobject_30df0b2) | Deletes the object at this location. | @@ -106,7 +106,7 @@ A [FirebaseStorage](./storage.firebasestorage.md#firebasestorage_interface) inst ## function(storage, ...) -### connectStorageEmulator(storage, host, port, options) {:#connectstorageemulator_e9039de} +### connectStorageEmulator(storage, host, port, options) {:#connectstorageemulator_ac343b7} Modify this [FirebaseStorage](./storage.firebasestorage.md#firebasestorage_interface) instance to communicate with the Cloud Storage emulator. @@ -115,6 +115,7 @@ Modify this [FirebaseStorage](./storage.firebasestorage.md#firebasestorage_inter ```typescript export declare function connectStorageEmulator(storage: FirebaseStorage, host: string, port: number, options?: { mockUserToken?: EmulatorMockTokenOptions | string; + ssl?: boolean; }): void; ``` @@ -125,7 +126,7 @@ export declare function connectStorageEmulator(storage: FirebaseStorage, host: s | storage | [FirebaseStorage](./storage.firebasestorage.md#firebasestorage_interface) | The [FirebaseStorage](./storage.firebasestorage.md#firebasestorage_interface) instance | | host | string | The emulator host (ex: localhost) | | port | number | The emulator port (ex: 5001) | -| options | { mockUserToken?: [EmulatorMockTokenOptions](./util.md#emulatormocktokenoptions) \| string; } | Emulator options. options.mockUserToken is the mock auth token to use for unit testing Security Rules. | +| options | { mockUserToken?: [EmulatorMockTokenOptions](./util.md#emulatormocktokenoptions) \| string; ssl?: boolean; } | Emulator options. options.mockUserToken is the mock auth token to use for unit testing Security Rules. | Returns: diff --git a/packages/database-compat/src/api/Database.ts b/packages/database-compat/src/api/Database.ts index 48682dc8b5c..2b34cfe7228 100644 --- a/packages/database-compat/src/api/Database.ts +++ b/packages/database-compat/src/api/Database.ts @@ -72,6 +72,7 @@ export class Database implements FirebaseService, Compat { port: number, options: { mockUserToken?: EmulatorMockTokenOptions; + ssl?: boolean; } = {} ): void { connectDatabaseEmulator(this._delegate, host, port, options); diff --git a/packages/database-compat/test/database.test.ts b/packages/database-compat/test/database.test.ts index fa21058591f..8d95b03efd3 100644 --- a/packages/database-compat/test/database.test.ts +++ b/packages/database-compat/test/database.test.ts @@ -292,6 +292,14 @@ describe('Database Tests', () => { expect((db as any)._delegate._repo.repoInfo_.isUsingEmulator).to.be.false; }); + it('uses ssl when useEmulator is called with ssl specified', () => { + const db = firebase.database(); + db.useEmulator('localhost', 80, { ssl: true }); + expect((db as any)._delegate._repo.repoInfo_.isUsingEmulator).to.be.true; + expect((db as any)._delegate._repo.repoInfo_.host).to.equal('localhost:80'); + expect((db as any)._delegate._repo.repoInfo_.secure).to.be.true; + }); + it('cannot call useEmulator after use', () => { const db = (firebase as any).database(); diff --git a/packages/database-types/index.d.ts b/packages/database-types/index.d.ts index 43557ebe1ac..a7a276a2abe 100644 --- a/packages/database-types/index.d.ts +++ b/packages/database-types/index.d.ts @@ -47,6 +47,7 @@ export interface Database { port: number, options?: { mockUserToken?: EmulatorMockTokenOptions | string; + ssl?: boolean; } ): void; goOffline(): void; @@ -63,6 +64,7 @@ export class FirebaseDatabase implements Database { port: number, options?: { mockUserToken?: EmulatorMockTokenOptions | string; + ssl?: boolean; } ): void; goOffline(): void; diff --git a/packages/database/src/api/Database.ts b/packages/database/src/api/Database.ts index 32fd4674a44..27d0f8180a5 100644 --- a/packages/database/src/api/Database.ts +++ b/packages/database/src/api/Database.ts @@ -91,7 +91,7 @@ function repoManagerApplyEmulatorSettings( ): void { repo.repoInfo_ = new RepoInfo( hostAndPort, - /* secure= */ false, + /* secure= */ emulatorOptions?.ssl ?? false, repo.repoInfo_.namespace, repo.repoInfo_.webSocketOnly, repo.repoInfo_.nodeAdmin, @@ -348,10 +348,12 @@ export function connectDatabaseEmulator( port: number, options: { mockUserToken?: EmulatorMockTokenOptions | string; + ssl?: boolean; } = {} ): void { db = getModularInstance(db); db._checkNotDeleted('useEmulator'); + const hostAndPort = `${host}:${port}`; const repo = db._repoInternal; if (db._instanceStarted) { diff --git a/packages/database/src/core/RepoInfo.ts b/packages/database/src/core/RepoInfo.ts index 1f8934c71d2..0eb53c3e552 100644 --- a/packages/database/src/core/RepoInfo.ts +++ b/packages/database/src/core/RepoInfo.ts @@ -24,6 +24,7 @@ import { each } from './util/util'; export interface RepoInfoEmulatorOptions { mockUserToken?: string | EmulatorMockTokenOptions; + ssl?: boolean; } /** diff --git a/packages/firestore/src/lite-api/database.ts b/packages/firestore/src/lite-api/database.ts index 9a68e2a86d6..aa9b89162a1 100644 --- a/packages/firestore/src/lite-api/database.ts +++ b/packages/firestore/src/lite-api/database.ts @@ -322,9 +322,11 @@ export function connectFirestoreEmulator( port: number, options: { mockUserToken?: EmulatorMockTokenOptions | string; + ssl?: boolean; } = {} ): void { firestore = cast(firestore, Firestore); + const ssl = options.ssl ?? false; const settings = firestore._getSettings(); const existingConfig = { ...settings, @@ -340,7 +342,7 @@ export function connectFirestoreEmulator( const newConfig = { ...settings, host: newHostSetting, - ssl: false, + ssl, emulatorOptions: options }; // No-op if the new configuration matches the current configuration. This supports SSR diff --git a/packages/firestore/test/unit/api/database.test.ts b/packages/firestore/test/unit/api/database.test.ts index 1cc1df51063..468f5922796 100644 --- a/packages/firestore/test/unit/api/database.test.ts +++ b/packages/firestore/test/unit/api/database.test.ts @@ -564,6 +564,17 @@ describe('Settings', () => { expect(db._getEmulatorOptions()).to.equal(emulatorOptions); }); + it('sets ssl to true if set in options', () => { + // Use a new instance of Firestore in order to configure settings. + const db = newTestFirestore(); + const emulatorOptions = { mockUserToken: 'test', ssl: true }; + connectFirestoreEmulator(db, '127.0.0.1', 9000, emulatorOptions); + + expect(db._getSettings().host).to.exist.and.to.equal('127.0.0.1:9000'); + expect(db._getSettings().ssl).to.exist.and.to.be.true; + expect(db._getEmulatorOptions()).to.equal(emulatorOptions); + }); + it('prefers host from useEmulator to host from settings', () => { // Use a new instance of Firestore in order to configure settings. const db = newTestFirestore(); diff --git a/packages/functions/src/api.ts b/packages/functions/src/api.ts index 7f92cba8343..e4deac11623 100644 --- a/packages/functions/src/api.ts +++ b/packages/functions/src/api.ts @@ -74,12 +74,14 @@ export function getFunctions( export function connectFunctionsEmulator( functionsInstance: Functions, host: string, - port: number + port: number, + ssl?: boolean ): void { _connectFunctionsEmulator( getModularInstance(functionsInstance as FunctionsService), host, - port + port, + ssl ); } diff --git a/packages/functions/src/service.test.ts b/packages/functions/src/service.test.ts index bb29f9025fe..d9300cc1dd3 100644 --- a/packages/functions/src/service.test.ts +++ b/packages/functions/src/service.test.ts @@ -47,6 +47,14 @@ describe('Firebase Functions > Service', () => { 'http://localhost:5005/my-project/us-central1/foo' ); }); + it('can use emulator with SSL', () => { + service = createTestService(app); + connectFunctionsEmulator(service, 'localhost', 5005, true); + assert.equal( + service._url('foo'), + 'https://localhost:5005/my-project/us-central1/foo' + ); + }); it('correctly sets region', () => { service = createTestService(app, 'my-region'); diff --git a/packages/functions/src/service.ts b/packages/functions/src/service.ts index 34cb732bf71..b782e3428f2 100644 --- a/packages/functions/src/service.ts +++ b/packages/functions/src/service.ts @@ -172,9 +172,10 @@ export class FunctionsService implements _FirebaseService { export function connectFunctionsEmulator( functionsInstance: FunctionsService, host: string, - port: number + port: number, + ssl?: boolean ): void { - functionsInstance.emulatorOrigin = `http://${host}:${port}`; + functionsInstance.emulatorOrigin = `http${ssl ? 's' : ''}://${host}:${port}`; } /** diff --git a/packages/storage-compat/src/service.ts b/packages/storage-compat/src/service.ts index b719802b74a..034ce35e823 100644 --- a/packages/storage-compat/src/service.ts +++ b/packages/storage-compat/src/service.ts @@ -92,6 +92,7 @@ export class StorageServiceCompat port: number, options: { mockUserToken?: EmulatorMockTokenOptions | string; + ssl?: boolean; } = {} ): void { connectStorageEmulator(this._delegate, host, port, options); diff --git a/packages/storage/src/api.ts b/packages/storage/src/api.ts index 84c77ea0c8c..c7393847f53 100644 --- a/packages/storage/src/api.ts +++ b/packages/storage/src/api.ts @@ -359,6 +359,7 @@ export function connectStorageEmulator( port: number, options: { mockUserToken?: EmulatorMockTokenOptions | string; + ssl?: boolean; } = {} ): void { connectEmulatorInternal(storage as FirebaseStorageImpl, host, port, options); diff --git a/packages/storage/src/service.ts b/packages/storage/src/service.ts index 422e3e1a188..ce4513bb5d9 100644 --- a/packages/storage/src/service.ts +++ b/packages/storage/src/service.ts @@ -138,10 +138,11 @@ export function connectStorageEmulator( port: number, options: { mockUserToken?: EmulatorMockTokenOptions | string; + ssl?: boolean; } = {} ): void { storage.host = `${host}:${port}`; - storage._protocol = 'http'; + storage._protocol = options.ssl ? 'https' : 'http'; const { mockUserToken } = options; if (mockUserToken) { storage._overrideAuthToken = diff --git a/packages/storage/test/unit/service.test.ts b/packages/storage/test/unit/service.test.ts index be42bb8dd6e..b4d0b0b38af 100644 --- a/packages/storage/test/unit/service.test.ts +++ b/packages/storage/test/unit/service.test.ts @@ -248,6 +248,27 @@ GOOG4-RSA-SHA256` expect(service._protocol).to.equal('http'); void getDownloadURL(ref(service, 'test.png')); }); + it('sets emulator host correctly with ssl', done => { + function newSend(connection: TestingConnection, url: string): void { + // Expect emulator host to be in url of storage operations requests, + // in this case getDownloadURL. + expect(url).to.match(/^https:\/\/test\.host\.org:1234.+/); + connection.abort(); + injectTestConnection(null); + done(); + } + + injectTestConnection(() => newTestConnection(newSend)); + const service = new FirebaseStorageImpl( + testShared.fakeApp, + testShared.fakeAuthProvider, + testShared.fakeAppCheckTokenProvider + ); + connectStorageEmulator(service, 'test.host.org', 1234, { ssl: true }); + expect(service.host).to.equal('test.host.org:1234'); + expect(service._protocol).to.equal('https'); + void getDownloadURL(ref(service, 'test.png')); + }); it('sets mock user token string if specified', done => { const mockUserToken = 'my-mock-user-token'; function newSend(