@sebspark/gcp-iam 3.0.1 → 3.0.3
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.js +10 -38
- package/dist/index.js.map +1 -0
- package/package.json +4 -4
- package/dist/index.d.mts +0 -25
- package/dist/index.mjs +0 -155
package/dist/index.js
CHANGED
|
@@ -1,35 +1,7 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
var __defProp = Object.defineProperty;
|
|
3
|
-
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
-
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
-
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
-
var __export = (target, all) => {
|
|
7
|
-
for (var name in all)
|
|
8
|
-
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
-
};
|
|
10
|
-
var __copyProps = (to, from, except, desc) => {
|
|
11
|
-
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
-
for (let key of __getOwnPropNames(from))
|
|
13
|
-
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
-
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
-
}
|
|
16
|
-
return to;
|
|
17
|
-
};
|
|
18
|
-
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
-
|
|
20
|
-
// src/index.ts
|
|
21
|
-
var index_exports = {};
|
|
22
|
-
__export(index_exports, {
|
|
23
|
-
clearCache: () => clearCache,
|
|
24
|
-
getApiGatewayTokenByClientId: () => getApiGatewayTokenByClientId,
|
|
25
|
-
getApiGatewayTokenByUrl: () => getApiGatewayTokenByUrl
|
|
26
|
-
});
|
|
27
|
-
module.exports = __toCommonJS(index_exports);
|
|
28
|
-
|
|
29
1
|
// src/apiGatewayToken.ts
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
2
|
+
import { IAMCredentialsClient } from "@google-cloud/iam-credentials";
|
|
3
|
+
import { getLogger } from "@sebspark/otel";
|
|
4
|
+
import { GoogleAuth } from "google-auth-library";
|
|
33
5
|
|
|
34
6
|
// src/lruCache.ts
|
|
35
7
|
var LruCache = class {
|
|
@@ -73,14 +45,14 @@ var LruCache = class {
|
|
|
73
45
|
// src/apiGatewayToken.ts
|
|
74
46
|
var expInSeconds = 60 * 60;
|
|
75
47
|
var apiGatewayJwtCache = new LruCache();
|
|
76
|
-
var logger =
|
|
48
|
+
var logger = getLogger("gcp-iam");
|
|
77
49
|
var generateTokenByUrl = async ({
|
|
78
50
|
apiURL,
|
|
79
51
|
key
|
|
80
52
|
}) => {
|
|
81
53
|
try {
|
|
82
|
-
const iamClient = new
|
|
83
|
-
const auth = new
|
|
54
|
+
const iamClient = new IAMCredentialsClient();
|
|
55
|
+
const auth = new GoogleAuth();
|
|
84
56
|
const cred = await auth.getCredentials();
|
|
85
57
|
const serviceAccountEmail = cred.client_email;
|
|
86
58
|
if (!serviceAccountEmail) {
|
|
@@ -156,7 +128,7 @@ var checkCache = ({
|
|
|
156
128
|
};
|
|
157
129
|
var generateTokenByClientId = async (clientId) => {
|
|
158
130
|
try {
|
|
159
|
-
const auth = new
|
|
131
|
+
const auth = new GoogleAuth({
|
|
160
132
|
scopes: "https://www.googleapis.com/auth/cloud-platform"
|
|
161
133
|
});
|
|
162
134
|
const client = await auth.getIdTokenClient(clientId);
|
|
@@ -176,9 +148,9 @@ var getApiGatewayTokenByClientId = async (clientId) => {
|
|
|
176
148
|
generate: () => generateTokenByClientId(clientId)
|
|
177
149
|
});
|
|
178
150
|
};
|
|
179
|
-
|
|
180
|
-
0 && (module.exports = {
|
|
151
|
+
export {
|
|
181
152
|
clearCache,
|
|
182
153
|
getApiGatewayTokenByClientId,
|
|
183
154
|
getApiGatewayTokenByUrl
|
|
184
|
-
}
|
|
155
|
+
};
|
|
156
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/apiGatewayToken.ts","../src/lruCache.ts"],"sourcesContent":["import { IAMCredentialsClient } from '@google-cloud/iam-credentials'\nimport { getLogger } from '@sebspark/otel'\nimport { GoogleAuth } from 'google-auth-library'\nimport { LruCache } from './lruCache'\n\nconst expInSeconds = 60 * 60\n// TODO: Make ttl changeable from getApiGatewayToken function\nconst apiGatewayJwtCache = new LruCache<Promise<string>>()\n\nconst logger = getLogger('gcp-iam')\n\nconst generateTokenByUrl = async ({\n apiURL,\n key,\n}: {\n apiURL: string\n key?: string\n}) => {\n try {\n const iamClient = new IAMCredentialsClient()\n const auth = new GoogleAuth()\n const cred = await auth.getCredentials()\n const serviceAccountEmail = cred.client_email\n\n if (!serviceAccountEmail) {\n throw new Error('No service account e-mail could be found.')\n }\n\n // Remove when verified\n logger.info(`Service account e-mail being used: ${serviceAccountEmail}`)\n\n /**\n * JWT Header.\n */\n\n const header = {\n alg: 'RS256',\n typ: 'JWT',\n }\n const headerBase64 = Buffer.from(JSON.stringify(header)).toString('base64')\n\n /**\n * JWT Payload.\n */\n\n const now = Math.floor(Date.now() / 1000)\n const payload = {\n iss: serviceAccountEmail,\n sub: serviceAccountEmail,\n aud: apiURL,\n iat: now,\n exp: now + expInSeconds,\n }\n\n const payloadBase64 = Buffer.from(JSON.stringify(payload)).toString(\n 'base64'\n )\n\n /**\n * JWT Signature.\n */\n\n const unsignedJWT = `${headerBase64}.${payloadBase64}`\n const [response] = await iamClient.signBlob({\n delegates: [serviceAccountEmail],\n name: `projects/-/serviceAccounts/${serviceAccountEmail}`,\n payload: new Uint8Array(Buffer.from(unsignedJWT)),\n })\n\n if (!response.signedBlob) {\n throw new Error(\n 'signBlob(...) returned an empty response. Cannot sign JWT.'\n )\n }\n\n // Debug.\n logger.debug(\n `New JWT for ${key || apiURL} created. Signed with ${response.keyId}.`\n )\n\n // Encode the binary signature to Base64.\n const signature = Buffer.from(response.signedBlob).toString('base64')\n\n // Combine into the final JWT.\n const signedJWT = `${unsignedJWT}.${signature}`\n\n return signedJWT\n } catch (error) {\n if (process.env.GCP_IAM_SOFT_FAIL === 'true') {\n logger.info('Soft fail enabled, returning empty JWT')\n return ''\n }\n\n logger.error('Error generating system JWT', error as Error)\n\n throw new Error(`Error generating system JWT: ${JSON.stringify(error)}`)\n }\n}\n\n/**\n * Generate a system token for the API Gateway.\n * This is intended to be run under the context of the service account signing the JWT.\n * @param apiUrl The URL of the API Gateway including the path of the specific API to be accessed using the token.\n * @param serviceAccountEmail The email of the service account to be used.\n * @param logger An optional logger to use for logging.\n * @returns A JWT.\n */\nexport const getApiGatewayTokenByUrl = async ({\n apiURL,\n key,\n}: {\n apiURL: string\n key?: string\n}): Promise<string> => {\n return checkCache({\n cacheKey: key || apiURL,\n generate: () => generateTokenByUrl({ apiURL, key }),\n })\n}\n\n/**\n *\n * @param key Clears a cached JWT by key.\n */\nexport const clearCache = async (key: string) => {\n apiGatewayJwtCache.clear(key)\n}\n\nconst checkCache = ({\n cacheKey,\n generate,\n}: {\n cacheKey: string\n generate: () => Promise<string>\n}) => {\n /**\n * Check if there is a cached JWT\n */\n\n const cachedJwt = apiGatewayJwtCache.get(cacheKey)\n if (cachedJwt) {\n logger.debug(`JWT for ${cacheKey} found in cache.`)\n return cachedJwt\n }\n\n const jwtPromise = generate()\n\n // cache generated jwt\n apiGatewayJwtCache.put(cacheKey, jwtPromise, (expInSeconds / 2) * 1000)\n\n return jwtPromise\n}\n\nconst generateTokenByClientId = async (clientId: string) => {\n try {\n const auth = new GoogleAuth({\n scopes: 'https://www.googleapis.com/auth/cloud-platform',\n })\n const client = await auth.getIdTokenClient(clientId)\n\n return await client.idTokenProvider.fetchIdToken(clientId)\n } catch (error) {\n if (process.env.GCP_IAM_SOFT_FAIL === 'true') {\n logger.info('Soft fail enabled, returning empty JWT.')\n return ''\n }\n\n logger.error('Error generating system JWT', error as Error)\n\n throw new Error(`Error generating system JWT: ${JSON.stringify(error)}`)\n }\n}\n\n/**\n * Generates a JWT for the API Gateway, using Client ID as audience.\n * @param clientId OAUTH Client ID.\n * @returns ID Token.\n */\nexport const getApiGatewayTokenByClientId = async (\n clientId: string\n): Promise<string> => {\n return checkCache({\n cacheKey: clientId,\n generate: () => generateTokenByClientId(clientId),\n })\n}\n","export class LruCache<T> {\n private values: Map<string, { timestamp: number; data: T; ttl: number }> =\n new Map<string, { timestamp: number; data: T; ttl: number }>()\n private readonly maxEntries: number = 10000\n private readonly defaultTTL: number = 1000 * 10 // 10 seconds\n\n constructor(props?: { ttl?: number; maxEntries?: number }) {\n this.defaultTTL = props?.ttl ?? this.defaultTTL\n this.maxEntries = props?.maxEntries ?? this.maxEntries\n }\n\n public get(key: string): T | undefined {\n const hasKey = this.values.has(key)\n\n if (hasKey) {\n // peek the entry, re-insert for LRU strategy\n const entry = this.values.get(key) as {\n timestamp: number\n data: T\n ttl: number\n }\n if (Date.now() - entry.timestamp > entry.ttl) {\n this.values.delete(key)\n return undefined\n }\n this.values.delete(key)\n this.values.set(key, entry)\n return entry.data\n }\n }\n\n public put(key: string, value: T, ttl?: number) {\n if (this.values.size >= this.maxEntries) {\n // least-recently used cache eviction strategy\n const keyToDelete = this.values.keys().next().value as string\n this.values.delete(keyToDelete)\n }\n\n this.values.set(key, {\n data: value,\n timestamp: Date.now(),\n ttl: ttl || this.defaultTTL,\n })\n }\n\n public clear(key: string) {\n this.values.delete(key)\n }\n}\n"],"mappings":"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","names":[]}
|
package/package.json
CHANGED
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sebspark/gcp-iam",
|
|
3
|
-
"version": "3.0.
|
|
3
|
+
"version": "3.0.3",
|
|
4
4
|
"license": "Apache-2.0",
|
|
5
|
+
"type": "module",
|
|
5
6
|
"main": "dist/index.js",
|
|
6
|
-
"module": "dist/index.mjs",
|
|
7
7
|
"types": "dist/index.d.ts",
|
|
8
8
|
"files": [
|
|
9
9
|
"dist"
|
|
10
10
|
],
|
|
11
11
|
"scripts": {
|
|
12
|
-
"build": "tsup
|
|
12
|
+
"build": "tsup src/index.ts --config ./tsup.config.ts",
|
|
13
13
|
"dev": "tsc --watch --noEmit",
|
|
14
14
|
"lint": "biome check .",
|
|
15
15
|
"test": "vitest run --passWithNoTests --coverage",
|
|
@@ -24,6 +24,6 @@
|
|
|
24
24
|
"google-auth-library": "10.5.0"
|
|
25
25
|
},
|
|
26
26
|
"peerDependencies": {
|
|
27
|
-
"@sebspark/otel": ">=2.0.
|
|
27
|
+
"@sebspark/otel": ">=2.0.5"
|
|
28
28
|
}
|
|
29
29
|
}
|
package/dist/index.d.mts
DELETED
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Generate a system token for the API Gateway.
|
|
3
|
-
* This is intended to be run under the context of the service account signing the JWT.
|
|
4
|
-
* @param apiUrl The URL of the API Gateway including the path of the specific API to be accessed using the token.
|
|
5
|
-
* @param serviceAccountEmail The email of the service account to be used.
|
|
6
|
-
* @param logger An optional logger to use for logging.
|
|
7
|
-
* @returns A JWT.
|
|
8
|
-
*/
|
|
9
|
-
declare const getApiGatewayTokenByUrl: ({ apiURL, key, }: {
|
|
10
|
-
apiURL: string;
|
|
11
|
-
key?: string;
|
|
12
|
-
}) => Promise<string>;
|
|
13
|
-
/**
|
|
14
|
-
*
|
|
15
|
-
* @param key Clears a cached JWT by key.
|
|
16
|
-
*/
|
|
17
|
-
declare const clearCache: (key: string) => Promise<void>;
|
|
18
|
-
/**
|
|
19
|
-
* Generates a JWT for the API Gateway, using Client ID as audience.
|
|
20
|
-
* @param clientId OAUTH Client ID.
|
|
21
|
-
* @returns ID Token.
|
|
22
|
-
*/
|
|
23
|
-
declare const getApiGatewayTokenByClientId: (clientId: string) => Promise<string>;
|
|
24
|
-
|
|
25
|
-
export { clearCache, getApiGatewayTokenByClientId, getApiGatewayTokenByUrl };
|
package/dist/index.mjs
DELETED
|
@@ -1,155 +0,0 @@
|
|
|
1
|
-
// src/apiGatewayToken.ts
|
|
2
|
-
import { IAMCredentialsClient } from "@google-cloud/iam-credentials";
|
|
3
|
-
import { getLogger } from "@sebspark/otel";
|
|
4
|
-
import { GoogleAuth } from "google-auth-library";
|
|
5
|
-
|
|
6
|
-
// src/lruCache.ts
|
|
7
|
-
var LruCache = class {
|
|
8
|
-
values = /* @__PURE__ */ new Map();
|
|
9
|
-
maxEntries = 1e4;
|
|
10
|
-
defaultTTL = 1e3 * 10;
|
|
11
|
-
// 10 seconds
|
|
12
|
-
constructor(props) {
|
|
13
|
-
this.defaultTTL = props?.ttl ?? this.defaultTTL;
|
|
14
|
-
this.maxEntries = props?.maxEntries ?? this.maxEntries;
|
|
15
|
-
}
|
|
16
|
-
get(key) {
|
|
17
|
-
const hasKey = this.values.has(key);
|
|
18
|
-
if (hasKey) {
|
|
19
|
-
const entry = this.values.get(key);
|
|
20
|
-
if (Date.now() - entry.timestamp > entry.ttl) {
|
|
21
|
-
this.values.delete(key);
|
|
22
|
-
return void 0;
|
|
23
|
-
}
|
|
24
|
-
this.values.delete(key);
|
|
25
|
-
this.values.set(key, entry);
|
|
26
|
-
return entry.data;
|
|
27
|
-
}
|
|
28
|
-
}
|
|
29
|
-
put(key, value, ttl) {
|
|
30
|
-
if (this.values.size >= this.maxEntries) {
|
|
31
|
-
const keyToDelete = this.values.keys().next().value;
|
|
32
|
-
this.values.delete(keyToDelete);
|
|
33
|
-
}
|
|
34
|
-
this.values.set(key, {
|
|
35
|
-
data: value,
|
|
36
|
-
timestamp: Date.now(),
|
|
37
|
-
ttl: ttl || this.defaultTTL
|
|
38
|
-
});
|
|
39
|
-
}
|
|
40
|
-
clear(key) {
|
|
41
|
-
this.values.delete(key);
|
|
42
|
-
}
|
|
43
|
-
};
|
|
44
|
-
|
|
45
|
-
// src/apiGatewayToken.ts
|
|
46
|
-
var expInSeconds = 60 * 60;
|
|
47
|
-
var apiGatewayJwtCache = new LruCache();
|
|
48
|
-
var logger = getLogger("gcp-iam");
|
|
49
|
-
var generateTokenByUrl = async ({
|
|
50
|
-
apiURL,
|
|
51
|
-
key
|
|
52
|
-
}) => {
|
|
53
|
-
try {
|
|
54
|
-
const iamClient = new IAMCredentialsClient();
|
|
55
|
-
const auth = new GoogleAuth();
|
|
56
|
-
const cred = await auth.getCredentials();
|
|
57
|
-
const serviceAccountEmail = cred.client_email;
|
|
58
|
-
if (!serviceAccountEmail) {
|
|
59
|
-
throw new Error("No service account e-mail could be found.");
|
|
60
|
-
}
|
|
61
|
-
logger.info(`Service account e-mail being used: ${serviceAccountEmail}`);
|
|
62
|
-
const header = {
|
|
63
|
-
alg: "RS256",
|
|
64
|
-
typ: "JWT"
|
|
65
|
-
};
|
|
66
|
-
const headerBase64 = Buffer.from(JSON.stringify(header)).toString("base64");
|
|
67
|
-
const now = Math.floor(Date.now() / 1e3);
|
|
68
|
-
const payload = {
|
|
69
|
-
iss: serviceAccountEmail,
|
|
70
|
-
sub: serviceAccountEmail,
|
|
71
|
-
aud: apiURL,
|
|
72
|
-
iat: now,
|
|
73
|
-
exp: now + expInSeconds
|
|
74
|
-
};
|
|
75
|
-
const payloadBase64 = Buffer.from(JSON.stringify(payload)).toString(
|
|
76
|
-
"base64"
|
|
77
|
-
);
|
|
78
|
-
const unsignedJWT = `${headerBase64}.${payloadBase64}`;
|
|
79
|
-
const [response] = await iamClient.signBlob({
|
|
80
|
-
delegates: [serviceAccountEmail],
|
|
81
|
-
name: `projects/-/serviceAccounts/${serviceAccountEmail}`,
|
|
82
|
-
payload: new Uint8Array(Buffer.from(unsignedJWT))
|
|
83
|
-
});
|
|
84
|
-
if (!response.signedBlob) {
|
|
85
|
-
throw new Error(
|
|
86
|
-
"signBlob(...) returned an empty response. Cannot sign JWT."
|
|
87
|
-
);
|
|
88
|
-
}
|
|
89
|
-
logger.debug(
|
|
90
|
-
`New JWT for ${key || apiURL} created. Signed with ${response.keyId}.`
|
|
91
|
-
);
|
|
92
|
-
const signature = Buffer.from(response.signedBlob).toString("base64");
|
|
93
|
-
const signedJWT = `${unsignedJWT}.${signature}`;
|
|
94
|
-
return signedJWT;
|
|
95
|
-
} catch (error) {
|
|
96
|
-
if (process.env.GCP_IAM_SOFT_FAIL === "true") {
|
|
97
|
-
logger.info("Soft fail enabled, returning empty JWT");
|
|
98
|
-
return "";
|
|
99
|
-
}
|
|
100
|
-
logger.error("Error generating system JWT", error);
|
|
101
|
-
throw new Error(`Error generating system JWT: ${JSON.stringify(error)}`);
|
|
102
|
-
}
|
|
103
|
-
};
|
|
104
|
-
var getApiGatewayTokenByUrl = async ({
|
|
105
|
-
apiURL,
|
|
106
|
-
key
|
|
107
|
-
}) => {
|
|
108
|
-
return checkCache({
|
|
109
|
-
cacheKey: key || apiURL,
|
|
110
|
-
generate: () => generateTokenByUrl({ apiURL, key })
|
|
111
|
-
});
|
|
112
|
-
};
|
|
113
|
-
var clearCache = async (key) => {
|
|
114
|
-
apiGatewayJwtCache.clear(key);
|
|
115
|
-
};
|
|
116
|
-
var checkCache = ({
|
|
117
|
-
cacheKey,
|
|
118
|
-
generate
|
|
119
|
-
}) => {
|
|
120
|
-
const cachedJwt = apiGatewayJwtCache.get(cacheKey);
|
|
121
|
-
if (cachedJwt) {
|
|
122
|
-
logger.debug(`JWT for ${cacheKey} found in cache.`);
|
|
123
|
-
return cachedJwt;
|
|
124
|
-
}
|
|
125
|
-
const jwtPromise = generate();
|
|
126
|
-
apiGatewayJwtCache.put(cacheKey, jwtPromise, expInSeconds / 2 * 1e3);
|
|
127
|
-
return jwtPromise;
|
|
128
|
-
};
|
|
129
|
-
var generateTokenByClientId = async (clientId) => {
|
|
130
|
-
try {
|
|
131
|
-
const auth = new GoogleAuth({
|
|
132
|
-
scopes: "https://www.googleapis.com/auth/cloud-platform"
|
|
133
|
-
});
|
|
134
|
-
const client = await auth.getIdTokenClient(clientId);
|
|
135
|
-
return await client.idTokenProvider.fetchIdToken(clientId);
|
|
136
|
-
} catch (error) {
|
|
137
|
-
if (process.env.GCP_IAM_SOFT_FAIL === "true") {
|
|
138
|
-
logger.info("Soft fail enabled, returning empty JWT.");
|
|
139
|
-
return "";
|
|
140
|
-
}
|
|
141
|
-
logger.error("Error generating system JWT", error);
|
|
142
|
-
throw new Error(`Error generating system JWT: ${JSON.stringify(error)}`);
|
|
143
|
-
}
|
|
144
|
-
};
|
|
145
|
-
var getApiGatewayTokenByClientId = async (clientId) => {
|
|
146
|
-
return checkCache({
|
|
147
|
-
cacheKey: clientId,
|
|
148
|
-
generate: () => generateTokenByClientId(clientId)
|
|
149
|
-
});
|
|
150
|
-
};
|
|
151
|
-
export {
|
|
152
|
-
clearCache,
|
|
153
|
-
getApiGatewayTokenByClientId,
|
|
154
|
-
getApiGatewayTokenByUrl
|
|
155
|
-
};
|