Skip to content

Auto Enable SSL for Firebase Studio #8980

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 32 commits into from
Apr 29, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
02c52c6
Added test project to fdc
maneesht Apr 11, 2025
37d0f18
Fixed formatting
maneesht Apr 11, 2025
a4d7813
Fix linting
maneesht Apr 11, 2025
170b15a
Excluded example integration from tsconfig
maneesht Apr 11, 2025
ec405ae
Fixed example-integration package.json
maneesht Apr 11, 2025
248f654
Added ssl check for firestore
maneesht Apr 23, 2025
14ef1bc
Added ssl checks for RTDB
maneesht Apr 23, 2025
a8fe7de
Merge remote-tracking branch 'origin/main' into mtewani/add-ssl-check…
maneesht Apr 23, 2025
df4a115
Removed unnecessary files
maneesht Apr 23, 2025
f867d3b
Removed unnecessary data connect changes
maneesht Apr 23, 2025
4f23f33
Create gentle-laws-kneel.md
maneesht Apr 23, 2025
e755d8c
Addressed feedback
maneesht Apr 28, 2025
ceed5ab
Addressed linting issue
maneesht Apr 28, 2025
44e2d8b
Added functions change
maneesht Apr 28, 2025
a1b85e2
Removed linting rules
maneesht Apr 28, 2025
d67b284
Updated useEmulator
maneesht Apr 28, 2025
a8b208b
Updated functions signatures
maneesht Apr 28, 2025
205f9ca
Updated docsite changes
maneesht Apr 28, 2025
4bc9433
Added tests
maneesht Apr 28, 2025
a32ea8b
Updated docsite
maneesht Apr 28, 2025
07f44b6
Fixed formatting
maneesht Apr 28, 2025
d305dec
Only checked if user is on cloudworkstation for ssl
maneesht Apr 29, 2025
fc6469a
Removed ssl from storage compat
maneesht Apr 29, 2025
0a0cb7a
Revert devsite changes
maneesht Apr 29, 2025
25f8be9
Added return type
maneesht Apr 29, 2025
59ab583
Fixed tests
maneesht Apr 29, 2025
d473c45
Removed changeset
maneesht Apr 29, 2025
43b4d6d
Create nice-plants-thank.md
maneesht Apr 29, 2025
5538911
Fixed test
maneesht Apr 29, 2025
54f2d7a
Merge branch 'mtewani/auto-ssl-cloudworkstations' of https://github.c…
maneesht Apr 29, 2025
0b807f9
Fixed firestore test
maneesht Apr 29, 2025
e6f8263
Added public tag to
maneesht Apr 29, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions .changeset/nice-plants-thank.md
Original file line number Diff line number Diff line change
@@ -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 changes: 3 additions & 0 deletions common/api-review/util.api.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
11 changes: 11 additions & 0 deletions packages/database-compat/test/database.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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();

Expand Down
9 changes: 7 additions & 2 deletions packages/database/src/api/Database.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,8 @@ import {
createMockUserToken,
deepEqual,
EmulatorMockTokenOptions,
getDefaultEmulatorHostnameAndPort
getDefaultEmulatorHostnameAndPort,
isCloudWorkstation
} from '@firebase/util';

import { AppCheckTokenProvider } from '../core/AppCheckTokenProvider';
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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) {
Expand Down
1 change: 1 addition & 0 deletions packages/firestore/externs.json
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down
6 changes: 4 additions & 2 deletions packages/firestore/src/lite-api/database.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,8 @@ import {
createMockUserToken,
deepEqual,
EmulatorMockTokenOptions,
getDefaultEmulatorHostnameAndPort
getDefaultEmulatorHostnameAndPort,
isCloudWorkstation
} from '@firebase/util';

import {
Expand Down Expand Up @@ -325,6 +326,7 @@ export function connectFirestoreEmulator(
} = {}
): void {
firestore = cast(firestore, Firestore);
const useSsl = isCloudWorkstation(host);
const settings = firestore._getSettings();
const existingConfig = {
...settings,
Expand All @@ -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
Expand Down
14 changes: 14 additions & 0 deletions packages/firestore/test/unit/api/database.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand Down
9 changes: 9 additions & 0 deletions packages/functions/src/service.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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');
Expand Down
6 changes: 5 additions & 1 deletion packages/functions/src/service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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';

Expand Down Expand Up @@ -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}`;
}

/**
Expand Down
9 changes: 7 additions & 2 deletions packages/storage/src/service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down Expand Up @@ -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 =
Expand Down
22 changes: 22 additions & 0 deletions packages/storage/test/unit/service.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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(
Expand Down
1 change: 1 addition & 0 deletions packages/util/index.node.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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 change: 1 addition & 0 deletions packages/util/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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 changes: 24 additions & 0 deletions packages/util/src/url.ts
Original file line number Diff line number Diff line change
@@ -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');
}
Loading