@vizamodo/aws-sts-core 0.3.1 → 0.3.2
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/sts/issue.js +20 -49
- package/package.json +7 -2
package/dist/sts/issue.js
CHANGED
|
@@ -17,6 +17,8 @@ const PROFILE_TTL = {
|
|
|
17
17
|
};
|
|
18
18
|
const DEFAULT_TTL = 2 * 60 * 60;
|
|
19
19
|
// ---- isolate-level cached signing material ----
|
|
20
|
+
// Promise-based cache to avoid cold-start race during concurrent imports
|
|
21
|
+
let signingKeyPromise = null;
|
|
20
22
|
let cachedSigningKey = null;
|
|
21
23
|
let cachedCertBase64 = null;
|
|
22
24
|
let cachedPrivateKeyBase64 = null;
|
|
@@ -34,18 +36,32 @@ async function getSigningMaterial(input) {
|
|
|
34
36
|
if (cachedSigningKey &&
|
|
35
37
|
cachedCertBase64 === input.certBase64 &&
|
|
36
38
|
cachedPrivateKeyBase64 === input.privateKeyPkcs8Base64) {
|
|
37
|
-
console.debug("[sts-cache] signingKey HIT");
|
|
38
39
|
return { signingKey: cachedSigningKey, certBase64: cachedCertBase64 };
|
|
39
40
|
}
|
|
40
|
-
|
|
41
|
+
// Reset cache only after a signing key has been resolved and material actually changed
|
|
42
|
+
if (cachedSigningKey &&
|
|
43
|
+
(cachedCertBase64 !== input.certBase64 ||
|
|
44
|
+
cachedPrivateKeyBase64 !== input.privateKeyPkcs8Base64)) {
|
|
45
|
+
signingKeyPromise = null;
|
|
46
|
+
cachedSigningKey = null;
|
|
47
|
+
}
|
|
48
|
+
if (!signingKeyPromise) {
|
|
49
|
+
try {
|
|
50
|
+
const keyBuffer = base64ToBytes(input.privateKeyPkcs8Base64);
|
|
51
|
+
signingKeyPromise = crypto.subtle.importKey("pkcs8", keyBuffer, { name: "ECDSA", namedCurve: "P-256" }, false, ["sign"]);
|
|
52
|
+
}
|
|
53
|
+
catch {
|
|
54
|
+
throw new InternalError("invalid_signing_material");
|
|
55
|
+
}
|
|
56
|
+
}
|
|
41
57
|
try {
|
|
42
|
-
|
|
43
|
-
cachedSigningKey = await crypto.subtle.importKey("pkcs8", keyBuffer, { name: "ECDSA", namedCurve: "P-256" }, false, ["sign"]);
|
|
58
|
+
cachedSigningKey = await signingKeyPromise;
|
|
44
59
|
cachedCertBase64 = input.certBase64;
|
|
45
60
|
cachedPrivateKeyBase64 = input.privateKeyPkcs8Base64;
|
|
46
61
|
return { signingKey: cachedSigningKey, certBase64: cachedCertBase64 };
|
|
47
62
|
}
|
|
48
63
|
catch {
|
|
64
|
+
signingKeyPromise = null; // allow retry after failure
|
|
49
65
|
throw new InternalError("invalid_signing_material");
|
|
50
66
|
}
|
|
51
67
|
}
|
|
@@ -82,11 +98,9 @@ export async function issueAwsCredentials(input) {
|
|
|
82
98
|
// --- MINIMAL DER WALK: extract serial number ---
|
|
83
99
|
let certSerialDec;
|
|
84
100
|
if (cachedCertSerialDec && cachedCertSerialSource === normalizedCert) {
|
|
85
|
-
console.debug("[sts-cache] certSerial HIT");
|
|
86
101
|
certSerialDec = cachedCertSerialDec;
|
|
87
102
|
}
|
|
88
103
|
else {
|
|
89
|
-
console.debug("[sts-cache] certSerial MISS → parsing DER");
|
|
90
104
|
try {
|
|
91
105
|
const der = base64ToBytes(normalizedCert);
|
|
92
106
|
let offset = 0;
|
|
@@ -149,30 +163,14 @@ export async function issueAwsCredentials(input) {
|
|
|
149
163
|
signedHeaders,
|
|
150
164
|
payloadHash,
|
|
151
165
|
});
|
|
152
|
-
console.debug("[sts-debug] canonicalRequest", {
|
|
153
|
-
amzDate,
|
|
154
|
-
signedHeaders,
|
|
155
|
-
payloadHash,
|
|
156
|
-
canonicalHeadersPreview: canonicalHeaders.slice(0, 120),
|
|
157
|
-
canonicalRequestPreview: canonicalRequest.slice(0, 200)
|
|
158
|
-
});
|
|
159
166
|
const canonicalRequestHash = await getCanonicalRequestHash(canonicalRequest);
|
|
160
|
-
console.debug("[sts-debug] canonicalRequestHash", canonicalRequestHash);
|
|
161
167
|
const stringToSign = buildStringToSign({
|
|
162
168
|
algorithm: ALGORITHM,
|
|
163
169
|
amzDate,
|
|
164
170
|
credentialScope,
|
|
165
171
|
canonicalRequestHash,
|
|
166
172
|
});
|
|
167
|
-
console.debug("[sts-debug] stringToSign", {
|
|
168
|
-
credentialScope,
|
|
169
|
-
stringPreview: stringToSign.slice(0, 200)
|
|
170
|
-
});
|
|
171
173
|
const signatureHex = await signStringToSign(stringToSign, signingKey);
|
|
172
|
-
console.debug("[sts-debug] signature", {
|
|
173
|
-
length: signatureHex.length,
|
|
174
|
-
prefix: signatureHex.slice(0, 32)
|
|
175
|
-
});
|
|
176
174
|
// 5. Build Authorization Header với số Serial (DECIMAL)
|
|
177
175
|
const finalHeaders = new Headers({
|
|
178
176
|
"Content-Type": "application/json",
|
|
@@ -180,25 +178,6 @@ export async function issueAwsCredentials(input) {
|
|
|
180
178
|
"X-Amz-X509": normalizedCert,
|
|
181
179
|
"Authorization": `AWS4-X509-ECDSA-SHA256 Credential=${certSerialDec}/${credentialScope}, SignedHeaders=${signedHeaders}, Signature=${signatureHex}`
|
|
182
180
|
});
|
|
183
|
-
console.debug("[sts-debug] requestHeaders", {
|
|
184
|
-
host,
|
|
185
|
-
amzDate,
|
|
186
|
-
signedHeaders,
|
|
187
|
-
certLen: normalizedCert.length
|
|
188
|
-
});
|
|
189
|
-
console.debug("[sts-request] issuing rolesanywhere session", {
|
|
190
|
-
region,
|
|
191
|
-
profile,
|
|
192
|
-
roleArn,
|
|
193
|
-
profileArn,
|
|
194
|
-
trustAnchorArn,
|
|
195
|
-
amzDate,
|
|
196
|
-
cacheState: {
|
|
197
|
-
hasSigningKey: !!cachedSigningKey,
|
|
198
|
-
cachedCertMatch: cachedCertBase64 === normalizedCert,
|
|
199
|
-
}
|
|
200
|
-
});
|
|
201
|
-
// 6. Execution
|
|
202
181
|
try {
|
|
203
182
|
const res = await fetch(`https://${host}${path}`, {
|
|
204
183
|
method: "POST",
|
|
@@ -231,14 +210,6 @@ export async function issueAwsCredentials(input) {
|
|
|
231
210
|
};
|
|
232
211
|
}
|
|
233
212
|
catch (e) {
|
|
234
|
-
console.error("[sts-debug] fetch failure", {
|
|
235
|
-
error: String(e),
|
|
236
|
-
region,
|
|
237
|
-
roleArn,
|
|
238
|
-
profileArn,
|
|
239
|
-
trustAnchorArn,
|
|
240
|
-
amzDate
|
|
241
|
-
});
|
|
242
213
|
if (e instanceof InternalError)
|
|
243
214
|
throw e;
|
|
244
215
|
throw new InternalError("aws_unreachable");
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@vizamodo/aws-sts-core",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.2",
|
|
4
4
|
"description": "Pure AWS STS + SigV4 (X509 Roles Anywhere) core logic",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -13,6 +13,7 @@
|
|
|
13
13
|
],
|
|
14
14
|
"scripts": {
|
|
15
15
|
"build": "tsc",
|
|
16
|
+
"test": "vitest run",
|
|
16
17
|
"clean": "rm -rf dist",
|
|
17
18
|
"prepublishOnly": "npm run build",
|
|
18
19
|
"dev": "ts-node bin/viza.ts",
|
|
@@ -20,6 +21,10 @@
|
|
|
20
21
|
"release:full": "rm -rf dist && npx npm-check-updates -u && npm install && git add package.json package-lock.json && git commit -m 'chore(deps): auto update dependencies before release' || echo 'No changes' && node versioning.js && npm login && npm publish --tag latest --access public && git push"
|
|
21
22
|
},
|
|
22
23
|
"devDependencies": {
|
|
23
|
-
"
|
|
24
|
+
"@aws-crypto/sha256-js": "^5.2.0",
|
|
25
|
+
"@aws-sdk/signature-v4": "^3.374.0",
|
|
26
|
+
"@vitest/coverage-v8": "^4.0.18",
|
|
27
|
+
"typescript": "^5.9.3",
|
|
28
|
+
"vitest": "^4.0.18"
|
|
24
29
|
}
|
|
25
30
|
}
|