@shushed/helpers 0.0.25 → 0.0.27
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.
- package/dist/index.d.ts +7 -7
- package/dist/index.js +119 -119
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { JSONSchemaType } from 'ajv';
|
|
2
2
|
import { DeepRedact } from '@hackylabs/deep-redact';
|
|
3
|
-
import {
|
|
3
|
+
import { Firestore, DocumentReference } from '@google-cloud/firestore';
|
|
4
4
|
import { PubSub, Topic, Subscription } from '@google-cloud/pubsub';
|
|
5
5
|
import * as _google_cloud_scheduler_build_protos_protos from '@google-cloud/scheduler/build/protos/protos';
|
|
6
6
|
import { CloudSchedulerClient } from '@google-cloud/scheduler';
|
|
@@ -28715,6 +28715,12 @@ declare class Runtime {
|
|
|
28715
28715
|
constructor(opts: Opts);
|
|
28716
28716
|
}
|
|
28717
28717
|
|
|
28718
|
+
declare const isPubSubRequest: (headers: Record<string, string>) => boolean;
|
|
28719
|
+
declare const isCronMessage: (headers: Record<string, string>) => boolean;
|
|
28720
|
+
declare const validateGoogleAuth: (opts: Opts & {
|
|
28721
|
+
serviceAccount?: string | null;
|
|
28722
|
+
}, headers: Record<string, string>, firestore: Firestore) => Promise<void>;
|
|
28723
|
+
|
|
28718
28724
|
type Level = 'env' | 'workflow' | 'trigger';
|
|
28719
28725
|
declare class EnvEngine extends Runtime {
|
|
28720
28726
|
docRef: Record<Level, DocumentReference>;
|
|
@@ -28827,12 +28833,6 @@ declare class JWKSHelper extends Runtime {
|
|
|
28827
28833
|
private fetchJWKS;
|
|
28828
28834
|
}
|
|
28829
28835
|
|
|
28830
|
-
declare const isPubSubRequest: (headers: Record<string, string>) => boolean;
|
|
28831
|
-
declare const isCronMessage: (headers: Record<string, string>) => boolean;
|
|
28832
|
-
declare const validateGoogleAuth: (opts: Opts & {
|
|
28833
|
-
serviceAccount?: string | null;
|
|
28834
|
-
}, headers: Record<string, string>, firestore: Firestore) => Promise<void>;
|
|
28835
|
-
|
|
28836
28836
|
type TriggerOnExecuteOptions = {
|
|
28837
28837
|
req: {
|
|
28838
28838
|
status?: number;
|
package/dist/index.js
CHANGED
|
@@ -346,8 +346,8 @@ var sanitize = new import_deep_redact.DeepRedact({
|
|
|
346
346
|
replaceStringByLength: true
|
|
347
347
|
});
|
|
348
348
|
|
|
349
|
-
// src-public/
|
|
350
|
-
var
|
|
349
|
+
// src-public/jwks.ts
|
|
350
|
+
var import_jose = require("jose");
|
|
351
351
|
|
|
352
352
|
// src-public/runtime.ts
|
|
353
353
|
var DEFAULT_BRANCH = "migratedprod";
|
|
@@ -373,16 +373,130 @@ var Runtime = class {
|
|
|
373
373
|
}
|
|
374
374
|
};
|
|
375
375
|
|
|
376
|
+
// src-public/jwks.ts
|
|
377
|
+
var CACHE_TABLE = "cache-global";
|
|
378
|
+
var JWKSHelper = class extends Runtime {
|
|
379
|
+
constructor(opts, firestore) {
|
|
380
|
+
super(opts);
|
|
381
|
+
this.firestore = firestore;
|
|
382
|
+
}
|
|
383
|
+
async validateAuthorizationHeader(authorizationHeader, expectedServiceAccount = null) {
|
|
384
|
+
const splitted = authorizationHeader.split(".");
|
|
385
|
+
const keyMeta = JSON.parse(Buffer.from(splitted[0], "base64").toString("utf-8")) || {};
|
|
386
|
+
const meta = JSON.parse(Buffer.from(splitted[1], "base64").toString("utf-8")) || {};
|
|
387
|
+
if (!meta.email_verified) {
|
|
388
|
+
throw new Error("Authorization header - Email not verified");
|
|
389
|
+
}
|
|
390
|
+
if (expectedServiceAccount === null) {
|
|
391
|
+
expectedServiceAccount = `runtime@${process.env.GCLOUD_PROJECT}.iam.gserviceaccount.com`;
|
|
392
|
+
}
|
|
393
|
+
if (meta.email !== expectedServiceAccount) {
|
|
394
|
+
throw new Error(`Authorization header - Wrong service account, got ${meta?.email}, expected ${expectedServiceAccount}`);
|
|
395
|
+
}
|
|
396
|
+
if (!keyMeta.kid || !keyMeta.alg) {
|
|
397
|
+
throw new Error("Malformed Authorization Header. KID is missing");
|
|
398
|
+
}
|
|
399
|
+
const key = await this.getKey(keyMeta.kid);
|
|
400
|
+
if (!key) {
|
|
401
|
+
throw new Error("Incorrect Authorization Header. The key has not been found in the Google JWKS set");
|
|
402
|
+
}
|
|
403
|
+
const importedKey = await (0, import_jose.importJWK)(key, keyMeta.alg);
|
|
404
|
+
let validationCorrect = true;
|
|
405
|
+
try {
|
|
406
|
+
await (0, import_jose.jwtVerify)(authorizationHeader, importedKey, {
|
|
407
|
+
issuer: ["https://accounts.google.com", "accounts.google.com"],
|
|
408
|
+
clockTolerance: 0,
|
|
409
|
+
audience: process.env.GCLOUD_PROJECT + "/" + this.triggerId
|
|
410
|
+
});
|
|
411
|
+
} catch (err) {
|
|
412
|
+
validationCorrect = false;
|
|
413
|
+
}
|
|
414
|
+
if (!validationCorrect) {
|
|
415
|
+
throw new Error("Incorrect Authorization Header. The JWT is not valid");
|
|
416
|
+
}
|
|
417
|
+
return validationCorrect;
|
|
418
|
+
}
|
|
419
|
+
async getKey(keyId) {
|
|
420
|
+
const jwks = typeof global.jwks !== "undefined" ? global.jwks : null;
|
|
421
|
+
let parsedJwks = null;
|
|
422
|
+
if (jwks) {
|
|
423
|
+
try {
|
|
424
|
+
parsedJwks = JSON.parse(jwks);
|
|
425
|
+
} catch (err) {
|
|
426
|
+
err.message.toString();
|
|
427
|
+
}
|
|
428
|
+
}
|
|
429
|
+
let keyData = parsedJwks?.keys?.find((x) => x.kid === keyId);
|
|
430
|
+
let cachedItem;
|
|
431
|
+
if (!keyData) {
|
|
432
|
+
cachedItem = await this.firestore.collection(CACHE_TABLE).doc("google-jwks").get();
|
|
433
|
+
if (cachedItem.exists && cachedItem.data()?.expires_at.toDate() > /* @__PURE__ */ new Date()) {
|
|
434
|
+
keyData = cachedItem.data()?.value;
|
|
435
|
+
}
|
|
436
|
+
}
|
|
437
|
+
keyData = parsedJwks?.keys.find((x) => x.kid === keyId);
|
|
438
|
+
if (!keyData) {
|
|
439
|
+
const result = await this.fetchJWKS();
|
|
440
|
+
parsedJwks = result.jwks;
|
|
441
|
+
if (cachedItem) {
|
|
442
|
+
cachedItem.ref.set({
|
|
443
|
+
value: parsedJwks,
|
|
444
|
+
expires_at: result.expiresAt
|
|
445
|
+
}, { merge: true });
|
|
446
|
+
}
|
|
447
|
+
keyData = parsedJwks?.keys.find((x) => x.kid === keyId);
|
|
448
|
+
}
|
|
449
|
+
if (parsedJwks && cachedItem) {
|
|
450
|
+
global.jwks = JSON.stringify(parsedJwks);
|
|
451
|
+
}
|
|
452
|
+
return keyData;
|
|
453
|
+
}
|
|
454
|
+
async fetchJWKS() {
|
|
455
|
+
const date = /* @__PURE__ */ new Date();
|
|
456
|
+
let expiresAt = new Date(Date.now() + 1e3 * 60 * 60);
|
|
457
|
+
const response = await fetch("https://www.googleapis.com/oauth2/v3/certs");
|
|
458
|
+
const maxAgePair = response.headers.get("Cache-Control")?.split(",").map((x) => x.trim().split("=")).find((x) => x[0] === "max-age");
|
|
459
|
+
if (maxAgePair && maxAgePair.length === 2) {
|
|
460
|
+
expiresAt = new Date(date.getTime() + parseInt(maxAgePair[1], 10) * 1e3);
|
|
461
|
+
}
|
|
462
|
+
const jwks = await response.json();
|
|
463
|
+
return {
|
|
464
|
+
expiresAt,
|
|
465
|
+
jwks
|
|
466
|
+
};
|
|
467
|
+
}
|
|
468
|
+
};
|
|
469
|
+
var jwks_default = JWKSHelper;
|
|
470
|
+
|
|
471
|
+
// src-public/utils.ts
|
|
472
|
+
var isPubSubRequest = (headers) => (headers["User-Agent"] || headers["user-agent"]) === "CloudPubSub-Google" || (headers["User-Agent"] || headers["user-agent"] || "").indexOf("APIs-Google") !== -1;
|
|
473
|
+
var isCronMessage = (headers) => (headers["User-Agent"] || headers["user-agent"]) === "Google-Cloud-Scheduler";
|
|
474
|
+
var validateGoogleAuth = async (opts, headers, firestore) => {
|
|
475
|
+
const token = headers.authorization?.split(" ")[1];
|
|
476
|
+
if (!token) {
|
|
477
|
+
throw new Error(
|
|
478
|
+
"Missing authorization header or invalid format, needs to be in format: Bearer <IdToken>"
|
|
479
|
+
);
|
|
480
|
+
}
|
|
481
|
+
try {
|
|
482
|
+
const jwksHelper = new jwks_default(opts, firestore);
|
|
483
|
+
await jwksHelper.validateAuthorizationHeader(token, opts.serviceAccount || null);
|
|
484
|
+
} catch (err) {
|
|
485
|
+
throw new Error("Invalid authorization header " + err.message);
|
|
486
|
+
}
|
|
487
|
+
};
|
|
488
|
+
|
|
376
489
|
// src-public/env.ts
|
|
490
|
+
var crypto = __toESM(require("crypto"));
|
|
377
491
|
var EnvEngine = class extends Runtime {
|
|
378
492
|
docRef;
|
|
379
493
|
store;
|
|
380
494
|
constructor(opts, firestore) {
|
|
381
495
|
super(opts);
|
|
382
496
|
this.docRef = {
|
|
383
|
-
env: firestore?.doc(`
|
|
384
|
-
workflow: firestore?.doc(
|
|
385
|
-
trigger: firestore?.doc(
|
|
497
|
+
env: firestore?.doc(`hush-${this.envName}/0-0`),
|
|
498
|
+
workflow: firestore?.doc(`hush-${this.envName}/${this.workflowId}-0`),
|
|
499
|
+
trigger: firestore?.doc(`hush-${this.envName}/${this.workflowId}-${this.triggerId}`)
|
|
386
500
|
};
|
|
387
501
|
this.store = {
|
|
388
502
|
env: null,
|
|
@@ -828,120 +942,6 @@ var Secrets = class extends Runtime {
|
|
|
828
942
|
}
|
|
829
943
|
};
|
|
830
944
|
var secret_default = Secrets;
|
|
831
|
-
|
|
832
|
-
// src-public/jwks.ts
|
|
833
|
-
var import_jose = require("jose");
|
|
834
|
-
var CACHE_TABLE = "cache-global";
|
|
835
|
-
var JWKSHelper = class extends Runtime {
|
|
836
|
-
constructor(opts, firestore) {
|
|
837
|
-
super(opts);
|
|
838
|
-
this.firestore = firestore;
|
|
839
|
-
}
|
|
840
|
-
async validateAuthorizationHeader(authorizationHeader, expectedServiceAccount = null) {
|
|
841
|
-
const splitted = authorizationHeader.split(".");
|
|
842
|
-
const keyMeta = JSON.parse(Buffer.from(splitted[0], "base64").toString("utf-8")) || {};
|
|
843
|
-
const meta = JSON.parse(Buffer.from(splitted[1], "base64").toString("utf-8")) || {};
|
|
844
|
-
if (!meta.email_verified) {
|
|
845
|
-
throw new Error("Authorization header - Email not verified");
|
|
846
|
-
}
|
|
847
|
-
if (expectedServiceAccount === null) {
|
|
848
|
-
expectedServiceAccount = `runtime@${process.env.GCLOUD_PROJECT}.iam.gserviceaccount.com`;
|
|
849
|
-
}
|
|
850
|
-
if (meta.email !== expectedServiceAccount) {
|
|
851
|
-
throw new Error(`Authorization header - Wrong service account, got ${meta?.email}, expected ${expectedServiceAccount}`);
|
|
852
|
-
}
|
|
853
|
-
if (!keyMeta.kid || !keyMeta.alg) {
|
|
854
|
-
throw new Error("Malformed Authorization Header. KID is missing");
|
|
855
|
-
}
|
|
856
|
-
const key = await this.getKey(keyMeta.kid);
|
|
857
|
-
if (!key) {
|
|
858
|
-
throw new Error("Incorrect Authorization Header. The key has not been found in the Google JWKS set");
|
|
859
|
-
}
|
|
860
|
-
const importedKey = await (0, import_jose.importJWK)(key, keyMeta.alg);
|
|
861
|
-
let validationCorrect = true;
|
|
862
|
-
try {
|
|
863
|
-
await (0, import_jose.jwtVerify)(authorizationHeader, importedKey, {
|
|
864
|
-
issuer: ["https://accounts.google.com", "accounts.google.com"],
|
|
865
|
-
clockTolerance: 0,
|
|
866
|
-
audience: process.env.GCLOUD_PROJECT + "/" + this.triggerId
|
|
867
|
-
});
|
|
868
|
-
} catch (err) {
|
|
869
|
-
validationCorrect = false;
|
|
870
|
-
}
|
|
871
|
-
if (!validationCorrect) {
|
|
872
|
-
throw new Error("Incorrect Authorization Header. The JWT is not valid");
|
|
873
|
-
}
|
|
874
|
-
return validationCorrect;
|
|
875
|
-
}
|
|
876
|
-
async getKey(keyId) {
|
|
877
|
-
const jwks = typeof global.jwks !== "undefined" ? global.jwks : null;
|
|
878
|
-
let parsedJwks = null;
|
|
879
|
-
if (jwks) {
|
|
880
|
-
try {
|
|
881
|
-
parsedJwks = JSON.parse(jwks);
|
|
882
|
-
} catch (err) {
|
|
883
|
-
err.message.toString();
|
|
884
|
-
}
|
|
885
|
-
}
|
|
886
|
-
let keyData = parsedJwks?.keys?.find((x) => x.kid === keyId);
|
|
887
|
-
let cachedItem;
|
|
888
|
-
if (!keyData) {
|
|
889
|
-
cachedItem = await this.firestore.collection(CACHE_TABLE).doc("google-jwks").get();
|
|
890
|
-
if (cachedItem.exists && cachedItem.data()?.expires_at.toDate() > /* @__PURE__ */ new Date()) {
|
|
891
|
-
keyData = cachedItem.data()?.value;
|
|
892
|
-
}
|
|
893
|
-
}
|
|
894
|
-
keyData = parsedJwks?.keys.find((x) => x.kid === keyId);
|
|
895
|
-
if (!keyData) {
|
|
896
|
-
const result = await this.fetchJWKS();
|
|
897
|
-
parsedJwks = result.jwks;
|
|
898
|
-
if (cachedItem) {
|
|
899
|
-
cachedItem.ref.set({
|
|
900
|
-
value: parsedJwks,
|
|
901
|
-
expires_at: result.expiresAt
|
|
902
|
-
}, { merge: true });
|
|
903
|
-
}
|
|
904
|
-
keyData = parsedJwks?.keys.find((x) => x.kid === keyId);
|
|
905
|
-
}
|
|
906
|
-
if (parsedJwks && cachedItem) {
|
|
907
|
-
global.jwks = JSON.stringify(parsedJwks);
|
|
908
|
-
}
|
|
909
|
-
return keyData;
|
|
910
|
-
}
|
|
911
|
-
async fetchJWKS() {
|
|
912
|
-
const date = /* @__PURE__ */ new Date();
|
|
913
|
-
let expiresAt = new Date(Date.now() + 1e3 * 60 * 60);
|
|
914
|
-
const response = await fetch("https://www.googleapis.com/oauth2/v3/certs");
|
|
915
|
-
const maxAgePair = response.headers.get("Cache-Control")?.split(",").map((x) => x.trim().split("=")).find((x) => x[0] === "max-age");
|
|
916
|
-
if (maxAgePair && maxAgePair.length === 2) {
|
|
917
|
-
expiresAt = new Date(date.getTime() + parseInt(maxAgePair[1], 10) * 1e3);
|
|
918
|
-
}
|
|
919
|
-
const jwks = await response.json();
|
|
920
|
-
return {
|
|
921
|
-
expiresAt,
|
|
922
|
-
jwks
|
|
923
|
-
};
|
|
924
|
-
}
|
|
925
|
-
};
|
|
926
|
-
var jwks_default = JWKSHelper;
|
|
927
|
-
|
|
928
|
-
// src-public/utils.ts
|
|
929
|
-
var isPubSubRequest = (headers) => (headers["User-Agent"] || headers["user-agent"]) === "CloudPubSub-Google" || (headers["User-Agent"] || headers["user-agent"] || "").indexOf("APIs-Google") !== -1;
|
|
930
|
-
var isCronMessage = (headers) => (headers["User-Agent"] || headers["user-agent"]) === "Google-Cloud-Scheduler";
|
|
931
|
-
var validateGoogleAuth = async (opts, headers, firestore) => {
|
|
932
|
-
const token = headers.authorization?.split(" ")[1];
|
|
933
|
-
if (!token) {
|
|
934
|
-
throw new Error(
|
|
935
|
-
"Missing authorization header or invalid format, needs to be in format: Bearer <IdToken>"
|
|
936
|
-
);
|
|
937
|
-
}
|
|
938
|
-
try {
|
|
939
|
-
const jwksHelper = new jwks_default(opts, firestore);
|
|
940
|
-
await jwksHelper.validateAuthorizationHeader(token, opts.serviceAccount || null);
|
|
941
|
-
} catch (err) {
|
|
942
|
-
throw new Error("Invalid authorization header " + err.message);
|
|
943
|
-
}
|
|
944
|
-
};
|
|
945
945
|
// Annotate the CommonJS export names for ESM import in node:
|
|
946
946
|
0 && (module.exports = {
|
|
947
947
|
lib,
|