Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
7 changes: 6 additions & 1 deletion js/.gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -29,4 +29,9 @@ yarn-error.log*
protoc-gen-grpc-web
src/android_emulation_control/*
docker/certs/jwt_secrets_pub.jwks
src/config.js

# Generated by config_gen.py — see js/README.md (Authentication section)
firebase_config.json
src/config.js
develop/envoy.yaml
docker/envoy.yaml
31 changes: 31 additions & 0 deletions js/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,37 @@ The most important thing to is to figure out if you need a [Turn Server](https:/
Most of the time there is no need for a turn server. If you do have needs for a turn server you can follow the steps in the
[README](turn/README.MD).

# Authentication

The web demo supports two authentication backends:

## Self-hosted JWT (recommended for deployments)

The `docker/` stack ships a token service (`jwt-provider/`) that mints JWTs signed by a keypair you control. This is the production path — no third-party identity provider, no shared sign-in quota, no external dependency. See `docker/` and `jwt-provider/` for the setup.

## Firebase / Google sign-in (quick-start demo only)

A lightweight on-ramp for "click sign-in, see the emulator." You bring your own Firebase project — this repo does not ship a usable one. Setup:

1. **Create a Firebase project** at https://console.firebase.google.com. Any name works (e.g. `my-aemu-demo`).
2. **Enable Google sign-in**: Authentication → Sign-in method → Google → Enable, set a project support email, Save.
3. **Add a web app**: Project settings (gear icon) → Your apps → Web → register the app, copy the `firebaseConfig` object.
4. **Save the config locally**:
```sh
cp firebase_config.example.json firebase_config.json
```
Open `firebase_config.json` and replace each placeholder value with the matching field from your project's web app config.
5. **Generate the derived files**:
```sh
python3 config_gen.py firebase_config.json
```
This writes `src/config.js` and renders `develop/envoy.yaml` + `docker/envoy.yaml` from their `.template.yaml` siblings, substituting your project ID into the envoy JWT issuer/audience.
6. **Start the dev stack** as described under *As a Developer* below.

`firebase_config.json`, `src/config.js`, and the rendered `envoy.yaml` files are gitignored — each contributor configures their own project. The `.template.yaml` files are the source of truth; rerun `config_gen.py` after changing them.

Firebase web API keys are not secrets — they're public identifiers, see [Firebase docs](https://firebase.google.com/docs/projects/api-keys). But your project *owns* every sign-in (PII, quota, abuse). Don't paste someone else's config, and don't commit yours.

# Internal Organization

This sample is based on ReactJS and uses the android-emulator-webrtc module to display the emulator.
Expand Down
75 changes: 49 additions & 26 deletions js/config_gen.py
Original file line number Diff line number Diff line change
@@ -1,41 +1,64 @@
#!/usr/bin/env python3
import sys
"""Render Firebase web SDK config and envoy proxy configs from firebase_config.json.

Run from the js/ directory:

python3 config_gen.py firebase_config.json

Generates (all gitignored — see js/.gitignore):
src/config.js Firebase web SDK config imported by login_firebase.js
develop/envoy.yaml dev envoy proxy, rendered from develop/envoy.template.yaml
docker/envoy.yaml prod envoy proxy, rendered from docker/envoy.template.yaml

See js/README.md (Authentication section) for the full BYO-Firebase setup walkthrough.
"""
import json
import sys
from pathlib import Path

SENTINEL = "__FIREBASE_PROJECT_ID__"
PLACEHOLDER_VALUES = {
"YOUR_API_KEY",
"YOUR_APP_ID",
"YOUR_PROJECT_ID",
"YOUR_SENDER_ID",
}

def replace(fname, search, replace):
if search == replace:
return

txt = ""
with open(fname, "r") as inp:
txt = inp.read()
txt.replace(search, replace)
with open(fname, "w") as out:
out.write(txt)
def render(template_path: Path, output_path: Path, project_id: str) -> None:
text = template_path.read_text()
if SENTINEL not in text:
sys.exit(f"error: sentinel {SENTINEL!r} not found in {template_path}")
output_path.write_text(text.replace(SENTINEL, project_id))


def main():
def main() -> None:
if len(sys.argv) != 2:
sys.exit(1)
sys.exit("usage: config_gen.py <firebase_config.json>")

config = {}
with open(sys.argv[1], "r") as cfg:
config = json.load(cfg)
config_path = Path(sys.argv[1])
config = json.loads(config_path.read_text())
project_id = config.get("projectId", "")

with open("src/config.js", "w") as cfg:
lines = [
"// Do not edit this file!",
"// This file was autogenerated by running:",
"// {}".format(" ".join(sys.argv)),
"export const config = {};".format(json.dumps(config, sort_keys=True, indent=4)),
]
cfg.write("\n".join(lines))
if not project_id or project_id in PLACEHOLDER_VALUES:
sys.exit(
f"error: {config_path} still has placeholder values. "
"Copy firebase_config.example.json to firebase_config.json and "
"fill in your Firebase project's web app config."
)

replace("develop/envoy.yaml", "android-emulator-webrtc-demo", config["projectId"])
replace("docker/envoy.yaml", "android-emulator-webrtc-demo", config["projectId"])
Path("src/config.js").write_text("\n".join([
"// Do not edit this file!",
"// Generated by: {} {}".format(Path(sys.argv[0]).name, config_path),
"export const config = {};".format(
json.dumps(config, sort_keys=True, indent=4)
),
"",
]))

render(Path("develop/envoy.template.yaml"), Path("develop/envoy.yaml"), project_id)
render(Path("docker/envoy.template.yaml"), Path("docker/envoy.yaml"), project_id)


if __name__ == "__main__":
main()

4 changes: 2 additions & 2 deletions js/develop/envoy.yaml → js/develop/envoy.template.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -56,9 +56,9 @@ static_resources:
"@type": type.googleapis.com/envoy.extensions.filters.http.jwt_authn.v3.JwtAuthentication
providers:
firebase_jwt:
issuer: https://securetoken.google.com/android-emulator-webrtc-demo
issuer: https://securetoken.google.com/__FIREBASE_PROJECT_ID__
audiences:
- android-emulator-webrtc-demo
- __FIREBASE_PROJECT_ID__
remote_jwks:
http_uri:
uri: https://www.googleapis.com/robot/v1/metadata/x509/securetoken@system.gserviceaccount.com
Expand Down
4 changes: 2 additions & 2 deletions js/docker/envoy.yaml → js/docker/envoy.template.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -56,9 +56,9 @@ static_resources:
"@type": type.googleapis.com/envoy.extensions.filters.http.jwt_authn.v3.JwtAuthentication
providers:
firebase_jwt:
issuer: https://securetoken.google.com/android-emulator-webrtc-demo
issuer: https://securetoken.google.com/__FIREBASE_PROJECT_ID__
audiences:
- android-emulator-webrtc-demo
- __FIREBASE_PROJECT_ID__
remote_jwks:
http_uri:
uri: https://www.googleapis.com/robot/v1/metadata/x509/securetoken@system.gserviceaccount.com
Expand Down
9 changes: 9 additions & 0 deletions js/firebase_config.example.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{
"_comment": "Copy this file to firebase_config.json and fill in the values from your own Firebase project's web app config (Project settings → Your apps → Web → SDK setup and configuration → Config). See js/README.md for the full setup walkthrough.",
"apiKey": "YOUR_API_KEY",
"authDomain": "YOUR_PROJECT_ID.firebaseapp.com",
"projectId": "YOUR_PROJECT_ID",
"storageBucket": "YOUR_PROJECT_ID.firebasestorage.app",
"messagingSenderId": "YOUR_SENDER_ID",
"appId": "YOUR_APP_ID"
}
10 changes: 0 additions & 10 deletions js/firebase_config.json

This file was deleted.

9 changes: 9 additions & 0 deletions js/src/components/login_firebase.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,15 @@ import Typography from "@mui/material/Typography";

import { config } from "../config";

if (!config.apiKey || !config.projectId || config.projectId === "YOUR_PROJECT_ID") {
throw new Error(
"Firebase config is missing or unconfigured. " +
"Copy firebase_config.example.json to firebase_config.json, " +
"fill in your Firebase project's web app config, then run: " +
"python3 config_gen.py firebase_config.json"
);
}

// Initialize the Firebase app once at module load.
const firebaseApp = initializeApp(config);
const firebaseAuth = getAuth(firebaseApp);
Expand Down
Loading