Auto Enable SSL for Firebase Studio (#8980)

This commit is contained in:
Maneesh Tewani
2025-04-29 11:24:16 -07:00
committed by GitHub
parent d2cbf1a03d
commit 87f0f13fa4
14 changed files with 119 additions and 7 deletions
+10
View File
@@ -0,0 +1,10 @@
---
"@firebase/database-compat": patch
"@firebase/database": patch
"@firebase/firestore": patch
"@firebase/functions": patch
"@firebase/storage": patch
"@firebase/util": patch
---
Auto Enable SSL for Firebase Studio
+3
View File
@@ -269,6 +269,9 @@ export function isBrowserExtension(): boolean;
// @public
export function isCloudflareWorker(): boolean;
// @public
export function isCloudWorkstation(host: string): boolean;
// Warning: (ae-missing-release-tag) "isElectron" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
//
// @public
@@ -292,6 +292,17 @@ 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();
const cloudWorkstation = 'abc.cloudworkstations.dev';
db.useEmulator(cloudWorkstation, 80);
expect((db as any)._delegate._repo.repoInfo_.isUsingEmulator).to.be.true;
expect((db as any)._delegate._repo.repoInfo_.host).to.equal(
`${cloudWorkstation}:80`
);
expect((db as any)._delegate._repo.repoInfo_.secure).to.be.true;
});
it('cannot call useEmulator after use', () => {
const db = (firebase as any).database();
+7 -2
View File
@@ -29,7 +29,8 @@ import {
createMockUserToken,
deepEqual,
EmulatorMockTokenOptions,
getDefaultEmulatorHostnameAndPort
getDefaultEmulatorHostnameAndPort,
isCloudWorkstation
} from '@firebase/util';
import { AppCheckTokenProvider } from '../core/AppCheckTokenProvider';
@@ -89,9 +90,12 @@ function repoManagerApplyEmulatorSettings(
emulatorOptions: RepoInfoEmulatorOptions,
tokenProvider?: AuthTokenProvider
): void {
const portIndex = hostAndPort.lastIndexOf(':');
const host = hostAndPort.substring(0, portIndex);
const useSsl = isCloudWorkstation(host);
repo.repoInfo_ = new RepoInfo(
hostAndPort,
/* secure= */ false,
/* secure= */ useSsl,
repo.repoInfo_.namespace,
repo.repoInfo_.webSocketOnly,
repo.repoInfo_.nodeAdmin,
@@ -352,6 +356,7 @@ export function connectDatabaseEmulator(
): void {
db = getModularInstance(db);
db._checkNotDeleted('useEmulator');
const hostAndPort = `${host}:${port}`;
const repo = db._repoInternal;
if (db._instanceStarted) {
+1
View File
@@ -33,6 +33,7 @@
"packages/util/dist/src/compat.d.ts",
"packages/util/dist/src/global.d.ts",
"packages/util/dist/src/obj.d.ts",
"packages/util/dist/src/url.d.ts",
"packages/firestore/src/protos/firestore_bundle_proto.ts",
"packages/firestore/src/protos/firestore_proto_api.ts",
"packages/firestore/src/util/error.ts",
+4 -2
View File
@@ -26,7 +26,8 @@ import {
createMockUserToken,
deepEqual,
EmulatorMockTokenOptions,
getDefaultEmulatorHostnameAndPort
getDefaultEmulatorHostnameAndPort,
isCloudWorkstation
} from '@firebase/util';
import {
@@ -325,6 +326,7 @@ export function connectFirestoreEmulator(
} = {}
): void {
firestore = cast(firestore, Firestore);
const useSsl = isCloudWorkstation(host);
const settings = firestore._getSettings();
const existingConfig = {
...settings,
@@ -340,7 +342,7 @@ export function connectFirestoreEmulator(
const newConfig = {
...settings,
host: newHostSetting,
ssl: false,
ssl: useSsl,
emulatorOptions: options
};
// No-op if the new configuration matches the current configuration. This supports SSR
@@ -564,6 +564,20 @@ describe('Settings', () => {
expect(db._getEmulatorOptions()).to.equal(emulatorOptions);
});
it('sets ssl to true if cloud workstation host', () => {
// Use a new instance of Firestore in order to configure settings.
const db = newTestFirestore();
const emulatorOptions = { mockUserToken: 'test' };
const workstationHost = 'abc.cloudworkstations.dev';
connectFirestoreEmulator(db, workstationHost, 9000, emulatorOptions);
expect(db._getSettings().host).to.exist.and.to.equal(
`${workstationHost}: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();
+9
View File
@@ -47,6 +47,15 @@ describe('Firebase Functions > Service', () => {
'http://localhost:5005/my-project/us-central1/foo'
);
});
it('can use emulator with SSL', () => {
service = createTestService(app);
const workstationHost = 'abc.cloudworkstations.dev';
connectFunctionsEmulator(service, workstationHost, 5005);
assert.equal(
service._url('foo'),
`https://${workstationHost}:5005/my-project/us-central1/foo`
);
});
it('correctly sets region', () => {
service = createTestService(app, 'my-region');
+5 -1
View File
@@ -30,6 +30,7 @@ import { Provider } from '@firebase/component';
import { FirebaseAuthInternalName } from '@firebase/auth-interop-types';
import { MessagingInternalComponentName } from '@firebase/messaging-interop-types';
import { AppCheckInternalComponentName } from '@firebase/app-check-interop-types';
import { isCloudWorkstation } from '@firebase/util';
export const DEFAULT_REGION = 'us-central1';
@@ -174,7 +175,10 @@ export function connectFunctionsEmulator(
host: string,
port: number
): void {
functionsInstance.emulatorOrigin = `http://${host}:${port}`;
const useSsl = isCloudWorkstation(host);
functionsInstance.emulatorOrigin = `http${
useSsl ? 's' : ''
}://${host}:${port}`;
}
/**
+7 -2
View File
@@ -42,7 +42,11 @@ import {
} from './implementation/error';
import { validateNumber } from './implementation/type';
import { FirebaseStorage } from './public-types';
import { createMockUserToken, EmulatorMockTokenOptions } from '@firebase/util';
import {
createMockUserToken,
EmulatorMockTokenOptions,
isCloudWorkstation
} from '@firebase/util';
import { Connection, ConnectionType } from './implementation/connection';
export function isUrl(path?: string): boolean {
@@ -141,7 +145,8 @@ export function connectStorageEmulator(
} = {}
): void {
storage.host = `${host}:${port}`;
storage._protocol = 'http';
const useSsl = isCloudWorkstation(host);
storage._protocol = useSsl ? 'https' : 'http';
const { mockUserToken } = options;
if (mockUserToken) {
storage._overrideAuthToken =
@@ -248,6 +248,28 @@ 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\.cloudworkstations\.dev:1234.+/);
connection.abort();
injectTestConnection(null);
done();
}
injectTestConnection(() => newTestConnection(newSend));
const service = new FirebaseStorageImpl(
testShared.fakeApp,
testShared.fakeAuthProvider,
testShared.fakeAppCheckTokenProvider
);
const workstationHost = 'test.cloudworkstations.dev';
connectStorageEmulator(service, workstationHost, 1234);
expect(service.host).to.equal(`${workstationHost}: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(
+1
View File
@@ -42,3 +42,4 @@ export * from './src/exponential_backoff';
export * from './src/formatters';
export * from './src/compat';
export * from './src/global';
export * from './src/url';
+1
View File
@@ -37,3 +37,4 @@ export * from './src/exponential_backoff';
export * from './src/formatters';
export * from './src/compat';
export * from './src/global';
export * from './src/url';
+24
View File
@@ -0,0 +1,24 @@
/**
* @license
* Copyright 2025 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.
*/
/**
* Checks whether host is a cloud workstation or not.
* @public
*/
export function isCloudWorkstation(host: string): boolean {
return host.endsWith('.cloudworkstations.dev');
}