@intuitionrobotics/firebase 2.4.5 → 2.4.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -15,6 +15,16 @@ export type JWTInput = {
15
15
  type ConfigType = {
16
16
  [s: string]: string | JWTInput | Firebase_UserCredential;
17
17
  };
18
+ /**
19
+ * Config value meaning "no service-account key for this project — authenticate with
20
+ * Application Default Credentials instead". Set it in place of the key JSON to drop a
21
+ * long-lived secret from config; the runtime service account then needs the relevant
22
+ * roles on the target project.
23
+ *
24
+ * Deliberately opt-in: a project with NO entry at all still throws, so a typo'd project
25
+ * name fails loudly instead of silently opening a session against the wrong credentials.
26
+ */
27
+ export declare const ADC_CREDENTIALS = "adc";
18
28
  export declare class FirebaseModule_Class extends Module<ConfigType> {
19
29
  private readonly adminSessions;
20
30
  static localAdminConfigId: string;
@@ -1 +1 @@
1
- {"version":3,"file":"FirebaseModule.d.ts","sourceRoot":"","sources":["../../src/main/app-backend/FirebaseModule.ts"],"names":[],"mappings":"AAAA,OAAO,EAGH,MAAM,EAET,MAAM,8BAA8B,CAAC;AACtC,OAAO,EAAC,qBAAqB,EAAC,MAAM,iCAAiC,CAAC;AAEtE,OAAO,EAAC,KAAK,uBAAuB,EAAC,MAAM,4BAA4B,CAAC;AAExE,MAAM,MAAM,QAAQ,GAAG;IACnB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,gBAAgB,CAAC,EAAE,MAAM,CAAC;CAC7B,CAAA;AACD,KAAK,UAAU,GAAG;IACd,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,QAAQ,GAAG,uBAAuB,CAAC;CAC5D,CAAC;AAEF,qBAAa,oBACT,SAAQ,MAAM,CAAC,UAAU,CAAC;IAG1B,OAAO,CAAC,QAAQ,CAAC,aAAa,CAA+C;IAC7E,OAAc,kBAAkB,EAAE,MAAM,CAAC;IAEzC,OAAO,CAAC,eAAe,CAAC,CAAS;;IAMjC,iBAAiB,IAAI,MAAM;IAI3B,OAAO,CAAC,qBAAqB;IAQ7B,OAAO,CAAC,oBAAoB;IAoB5B,SAAS,CAAC,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;IAMlC,SAAS,CAAC,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC;IAM9B,kBAAkB,CAAC,UAAU,CAAC,EAAE,MAAM,EAAE,YAAY,CAAC,EAAE,MAAM;IA6BpE,cAAc,CAAC,SAAS,EAAE,MAAM;CAGnC;AAED,eAAO,MAAM,cAAc,sBAA6B,CAAC"}
1
+ {"version":3,"file":"FirebaseModule.d.ts","sourceRoot":"","sources":["../../src/main/app-backend/FirebaseModule.ts"],"names":[],"mappings":"AAAA,OAAO,EAGH,MAAM,EAET,MAAM,8BAA8B,CAAC;AACtC,OAAO,EAAC,qBAAqB,EAAC,MAAM,iCAAiC,CAAC;AAEtE,OAAO,EAAC,KAAK,uBAAuB,EAAC,MAAM,4BAA4B,CAAC;AAExE,MAAM,MAAM,QAAQ,GAAG;IACnB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,gBAAgB,CAAC,EAAE,MAAM,CAAC;CAC7B,CAAA;AACD,KAAK,UAAU,GAAG;IACd,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,QAAQ,GAAG,uBAAuB,CAAC;CAC5D,CAAC;AAEF;;;;;;;;GAQG;AACH,eAAO,MAAM,eAAe,QAAQ,CAAC;AAErC,qBAAa,oBACT,SAAQ,MAAM,CAAC,UAAU,CAAC;IAG1B,OAAO,CAAC,QAAQ,CAAC,aAAa,CAA+C;IAC7E,OAAc,kBAAkB,EAAE,MAAM,CAAC;IAEzC,OAAO,CAAC,eAAe,CAAC,CAAS;;IAMjC,iBAAiB,IAAI,MAAM;IAI3B,OAAO,CAAC,qBAAqB;IAQ7B,OAAO,CAAC,oBAAoB;IAoB5B,SAAS,CAAC,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;IAMlC,SAAS,CAAC,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC;IAM9B,kBAAkB,CAAC,UAAU,CAAC,EAAE,MAAM,EAAE,YAAY,CAAC,EAAE,MAAM;IAqCpE,cAAc,CAAC,SAAS,EAAE,MAAM;CAGnC;AAED,eAAO,MAAM,cAAc,sBAA6B,CAAC"}
@@ -2,6 +2,16 @@ import { BadImplementationException, ImplementationMissingException, Module, Thi
2
2
  import { FirebaseSession_Admin } from "./auth/FirebaseSession_Admin.js";
3
3
  import { readFileSync } from "fs";
4
4
  import {} from "./auth/firebase-session.js";
5
+ /**
6
+ * Config value meaning "no service-account key for this project — authenticate with
7
+ * Application Default Credentials instead". Set it in place of the key JSON to drop a
8
+ * long-lived secret from config; the runtime service account then needs the relevant
9
+ * roles on the target project.
10
+ *
11
+ * Deliberately opt-in: a project with NO entry at all still throws, so a typo'd project
12
+ * name fails loudly instead of silently opening a session against the wrong credentials.
13
+ */
14
+ export const ADC_CREDENTIALS = "adc";
5
15
  export class FirebaseModule_Class extends Module {
6
16
  // private readonly tokenSessions: { [s: string]: FirebaseSession_UserPassword; } = {};
7
17
  adminSessions = {};
@@ -58,13 +68,19 @@ export class FirebaseModule_Class extends Module {
58
68
  this.logInfo(`Creating Firebase session for project id: ${projectId}`);
59
69
  let config = this.getProjectAuth(projectId);
60
70
  const localProjectId = this.getLocalProjectIdSafe();
61
- if (!config && _projectId && localProjectId && localProjectId !== _projectId)
71
+ // Explicit opt-out of a hardcoded key: authenticate with ADC against `projectId`.
72
+ const useADC = config === ADC_CREDENTIALS;
73
+ if (useADC)
74
+ config = undefined;
75
+ if (!config && !useADC && _projectId && localProjectId && localProjectId !== _projectId)
62
76
  throw new BadImplementationException(`Config for key ${_projectId} is not defined`);
63
77
  if (typeof config === "string")
64
78
  config = JSON.parse(readFileSync(config, "utf8"));
65
79
  if (config && (!config.client_email || !config.private_key))
66
80
  throw new BadImplementationException(`Config for key ${projectId} is not an Admin credentials pattern`);
67
- session = new FirebaseSession_Admin(sessionName, config);
81
+ // Pass the resolved project id through so a keyless session can target a specific
82
+ // project rather than only the ambient one.
83
+ session = new FirebaseSession_Admin(sessionName, config, projectId);
68
84
  this.adminSessions[sessionName] = session;
69
85
  session.connect();
70
86
  return session;
@@ -1 +1 @@
1
- {"version":3,"file":"FirebaseModule.js","sourceRoot":"","sources":["../../src/main/app-backend/FirebaseModule.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"FirebaseModule.js","sourceRoot":"","sources":["../../src/main/app-backend/FirebaseModule.ts"],"names":[],"mappings":"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"}
@@ -5,10 +5,31 @@ import { type JWTInput } from "../FirebaseModule.js";
5
5
  export declare class FirebaseSession_Admin extends FirebaseSession<JWTInput & {
6
6
  databaseURL?: string;
7
7
  } | undefined, App> {
8
- constructor(sessionName: string, config?: JWTInput);
8
+ private readonly projectId?;
9
+ /**
10
+ * @param projectId target project for a keyless (ADC) session. Ignored when `config`
11
+ * carries a service-account key, since the key already names its project.
12
+ */
13
+ constructor(sessionName: string, config?: JWTInput, projectId?: string | undefined);
9
14
  connect(): void;
10
15
  getProjectId(): string;
11
16
  private createApp;
17
+ /**
18
+ * An embedded service-account key that has been retired fails at token acquisition,
19
+ * so the error surfaces from whichever SDK call happened to run first — as an opaque
20
+ * `invalid_grant` from deep inside @google-cloud/storage or firestore, naming neither
21
+ * the project nor the account. That has cost real outage time: the same retired key
22
+ * lived in several configs at once, and nothing said which.
23
+ *
24
+ * Wrapping the credential puts one greppable line at the point of failure instead:
25
+ *
26
+ * SA_KEY_UNUSABLE reason=key_revoked project=<id> sa=<email> session=<name> detail=<...>
27
+ *
28
+ * Alert on `SA_KEY_UNUSABLE` to catch a retired key the moment anything touches it,
29
+ * rather than when someone reports a 500. The original error is always rethrown, so
30
+ * behaviour is unchanged.
31
+ */
32
+ private reportUnusableKey;
12
33
  getAuth(): Auth;
13
34
  }
14
35
  //# sourceMappingURL=FirebaseSession_Admin.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"FirebaseSession_Admin.d.ts","sourceRoot":"","sources":["../../../src/main/app-backend/auth/FirebaseSession_Admin.ts"],"names":[],"mappings":"AAuBA,OAAO,EAAC,eAAe,EAAC,MAAM,uBAAuB,CAAC;AAEtD,OAAO,EACN,IAAI,EAEJ,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EACN,KAAK,GAAG,EAER,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EAAC,KAAK,QAAQ,EAAC,MAAM,sBAAsB,CAAC;AAEnD,qBAAa,qBACZ,SAAQ,eAAe,CAAC,QAAQ,GAAG;IAAE,WAAW,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG,SAAS,EAAE,GAAG,CAAC;gBAEjE,WAAW,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,QAAQ;IAI3C,OAAO,IAAI,IAAI;IAItB,YAAY,IAAI,MAAM;IActB,OAAO,CAAC,SAAS;IAWV,OAAO,IAAI,IAAI;CAGtB"}
1
+ {"version":3,"file":"FirebaseSession_Admin.d.ts","sourceRoot":"","sources":["../../../src/main/app-backend/auth/FirebaseSession_Admin.ts"],"names":[],"mappings":"AAuBA,OAAO,EAAC,eAAe,EAAC,MAAM,uBAAuB,CAAC;AAEtD,OAAO,EACN,IAAI,EAEJ,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EACN,KAAK,GAAG,EAGR,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EAAC,KAAK,QAAQ,EAAC,MAAM,sBAAsB,CAAC;AAwBnD,qBAAa,qBACZ,SAAQ,eAAe,CAAC,QAAQ,GAAG;IAAE,WAAW,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG,SAAS,EAAE,GAAG,CAAC;IAMzB,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAC;IAJ/E;;;OAGG;gBACS,WAAW,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,QAAQ,EAAmB,SAAS,CAAC,EAAE,MAAM,YAAA;IAIhF,OAAO,IAAI,IAAI;IAItB,YAAY,IAAI,MAAM;IAmBtB,OAAO,CAAC,SAAS;IAsBjB;;;;;;;;;;;;;;OAcG;IACH,OAAO,CAAC,iBAAiB;IA8BlB,OAAO,IAAI,IAAI;CAGtB"}
@@ -25,15 +25,42 @@ import { ThisShouldNotHappenException } from "@intuitionrobotics/ts-common";
25
25
  import { Auth, getAuth } from "firebase-admin/auth";
26
26
  import { initializeApp } from "firebase-admin/app";
27
27
  import {} from "../FirebaseModule.js";
28
+ /**
29
+ * Distinguish the ways an embedded service-account key stops working, so a log search
30
+ * can tell "someone deleted the key" from "someone deleted the whole account" from
31
+ * "the stored PEM is corrupt" without reading stack traces.
32
+ */
33
+ const classifyKeyFailure = (message) => {
34
+ if (/DECODER routines|unsupported|Failed to parse private key|PEM/i.test(message))
35
+ return "malformed_key";
36
+ if (/invalid_grant/i.test(message)) {
37
+ if (/Invalid JWT Signature/i.test(message))
38
+ return "key_revoked"; // key material no longer matches the account
39
+ if (/account not found|Invalid grant: account/i.test(message))
40
+ return "account_deleted"; // the service account itself is gone
41
+ return "invalid_grant";
42
+ }
43
+ return "unknown";
44
+ };
28
45
  export class FirebaseSession_Admin extends FirebaseSession {
29
- constructor(sessionName, config) {
46
+ projectId;
47
+ /**
48
+ * @param projectId target project for a keyless (ADC) session. Ignored when `config`
49
+ * carries a service-account key, since the key already names its project.
50
+ */
51
+ constructor(sessionName, config, projectId) {
30
52
  super(config, sessionName);
53
+ this.projectId = projectId;
31
54
  }
32
55
  connect() {
33
56
  this.app = this.createApp();
34
57
  }
35
58
  getProjectId() {
36
59
  if (!this.config) {
60
+ // Keyless session: prefer the project it was explicitly created for, and only
61
+ // fall back to the ambient project of the running function.
62
+ if (this.projectId)
63
+ return this.projectId;
37
64
  if (!process.env.GCLOUD_PROJECT)
38
65
  throw new ThisShouldNotHappenException("Could not deduce project id from function const!!");
39
66
  return process.env.GCLOUD_PROJECT;
@@ -43,14 +70,67 @@ export class FirebaseSession_Admin extends FirebaseSession {
43
70
  return this.config.project_id;
44
71
  }
45
72
  createApp() {
46
- if (!this.config)
47
- return initializeApp(undefined, this.sessionName);
73
+ // No key: authenticate with Application Default Credentials.
74
+ if (!this.config) {
75
+ // Passing options makes firebase-admin ignore FIREBASE_CONFIG, which is where
76
+ // Cloud Functions supplies databaseURL (and RTDB instances are not uniformly
77
+ // `<project>.firebaseio.com` — newer ones are `<project>-default-rtdb`). So for
78
+ // the ambient project keep passing undefined and let the SDK self-configure;
79
+ // name the project only when it genuinely differs.
80
+ const ambient = process.env.GCLOUD_PROJECT || process.env.GCP_PROJECT;
81
+ if (!this.projectId || this.projectId === ambient)
82
+ return initializeApp(undefined, this.sessionName);
83
+ return initializeApp({ projectId: this.projectId }, this.sessionName);
84
+ }
48
85
  const databaseURL = this.config.databaseURL || `https://${this.config.project_id}.firebaseio.com`;
49
86
  return initializeApp({
50
- credential: credential.cert(this.config),
87
+ credential: this.reportUnusableKey(credential.cert(this.config)),
51
88
  databaseURL: databaseURL
52
89
  }, this.sessionName);
53
90
  }
91
+ /**
92
+ * An embedded service-account key that has been retired fails at token acquisition,
93
+ * so the error surfaces from whichever SDK call happened to run first — as an opaque
94
+ * `invalid_grant` from deep inside @google-cloud/storage or firestore, naming neither
95
+ * the project nor the account. That has cost real outage time: the same retired key
96
+ * lived in several configs at once, and nothing said which.
97
+ *
98
+ * Wrapping the credential puts one greppable line at the point of failure instead:
99
+ *
100
+ * SA_KEY_UNUSABLE reason=key_revoked project=<id> sa=<email> session=<name> detail=<...>
101
+ *
102
+ * Alert on `SA_KEY_UNUSABLE` to catch a retired key the moment anything touches it,
103
+ * rather than when someone reports a 500. The original error is always rethrown, so
104
+ * behaviour is unchanged.
105
+ */
106
+ reportUnusableKey(cred) {
107
+ const describe = `project=${this.config?.project_id} sa=${this.config?.client_email} session=${this.sessionName}`;
108
+ const getAccessToken = cred.getAccessToken.bind(cred);
109
+ // Patch the existing credential IN PLACE rather than returning a wrapper object.
110
+ // firebase-admin picks its custom-token signer by prototype, not by shape:
111
+ //
112
+ // if (credential instanceof ServiceAccountCredential)
113
+ // return new ServiceAccountSigner(credential);
114
+ // return new IAMSigner(...); // utils/crypto-signer
115
+ //
116
+ // A plain `{getAccessToken}` satisfies the Credential *type* but fails that
117
+ // instanceof, which silently downgrades createCustomToken from signing locally
118
+ // with the embedded key to an iamcredentials signBlob call the runtime service
119
+ // account is usually not permitted to make -- breaking token minting for every
120
+ // key-backed project. Mutating the real credential keeps its prototype intact.
121
+ cred.getAccessToken = async () => {
122
+ try {
123
+ return await getAccessToken();
124
+ }
125
+ catch (e) {
126
+ const message = (e instanceof Error ? e.message : String(e)) || "";
127
+ const firstLine = message.split("\n")[0];
128
+ this.logError(`SA_KEY_UNUSABLE reason=${classifyKeyFailure(message)} ${describe} detail=${firstLine}`);
129
+ throw e;
130
+ }
131
+ };
132
+ return cred;
133
+ }
54
134
  getAuth() {
55
135
  return getAuth(this.app);
56
136
  }
@@ -1 +1 @@
1
- {"version":3,"file":"FirebaseSession_Admin.js","sourceRoot":"","sources":["../../../src/main/app-backend/auth/FirebaseSession_Admin.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAEH,oEAAoE;AACpE,mEAAmE;AACnE,OAAO,KAAK,MAAM,gBAAgB,CAAC;AACnC,OAAO,EAAqB,MAAM,gBAAgB,CAAC;AACnD,MAAM,EAAC,UAAU,EAAC,GAAG,KAAK,CAAC;AAC3B,OAAO,EAAC,eAAe,EAAC,MAAM,uBAAuB,CAAC;AACtD,OAAO,EAAC,4BAA4B,EAAC,MAAM,8BAA8B,CAAC;AAC1E,OAAO,EACN,IAAI,EACJ,OAAO,EACP,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EAEN,aAAa,EACb,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EAAe,MAAM,sBAAsB,CAAC;AAEnD,MAAM,OAAO,qBACZ,SAAQ,eAAqE;IAE7E,YAAY,WAAmB,EAAE,MAAiB;QACjD,KAAK,CAAC,MAAM,EAAE,WAAW,CAAC,CAAC;IAC5B,CAAC;IAEM,OAAO;QACb,IAAI,CAAC,GAAG,GAAG,IAAI,CAAC,SAAS,EAAE,CAAC;IAC7B,CAAC;IAED,YAAY;QACX,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,CAAC;YAClB,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,cAAc;gBAC9B,MAAM,IAAI,4BAA4B,CAAC,mDAAmD,CAAC,CAAA;YAE5F,OAAO,OAAO,CAAC,GAAG,CAAC,cAAc,CAAC;QACnC,CAAC;QAED,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,UAAU;YAC1B,MAAM,IAAI,4BAA4B,CAAC,0GAA0G,CAAC,CAAA;QAEnJ,OAAO,IAAI,CAAC,MAAM,CAAC,UAAU,CAAC;IAC/B,CAAC;IAEO,SAAS;QAChB,IAAI,CAAC,IAAI,CAAC,MAAM;YACf,OAAO,aAAa,CAAC,SAAS,EAAE,IAAI,CAAC,WAAW,CAAC,CAAC;QAEnD,MAAM,WAAW,GAAG,IAAI,CAAC,MAAM,CAAC,WAAW,IAAI,WAAW,IAAI,CAAC,MAAM,CAAC,UAAU,iBAAiB,CAAC;QAClG,OAAO,aAAa,CAAC;YACC,UAAU,EAAE,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,MAAwB,CAAC;YAC1D,WAAW,EAAE,WAAW;SACxB,EAAE,IAAI,CAAC,WAAW,CAAC,CAAC;IAC3C,CAAC;IAEM,OAAO;QACb,OAAO,OAAO,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IAC1B,CAAC;CACD"}
1
+ {"version":3,"file":"FirebaseSession_Admin.js","sourceRoot":"","sources":["../../../src/main/app-backend/auth/FirebaseSession_Admin.ts"],"names":[],"mappings":"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"}