@vizamodo/aws-sts-core 0.3.5 → 0.3.8

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.
@@ -0,0 +1,2 @@
1
+ export declare function hex(buf: ArrayBuffer | Uint8Array): string;
2
+ export declare function sha256Hex(input: string): Promise<string>;
@@ -0,0 +1,22 @@
1
+ const textEncoder = new TextEncoder();
2
+ const HEX_TABLE = new Array(256);
3
+ for (let i = 0; i < 256; i++) {
4
+ HEX_TABLE[i] = (i < 16 ? "0" : "") + i.toString(16);
5
+ }
6
+ export function hex(buf) {
7
+ const arr = buf instanceof Uint8Array ? buf : new Uint8Array(buf);
8
+ const out = new Array(arr.length);
9
+ for (let i = 0; i < arr.length; i++) {
10
+ out[i] = HEX_TABLE[arr[i]];
11
+ }
12
+ return out.join("");
13
+ }
14
+ export async function sha256Hex(input) {
15
+ const hash = await crypto.subtle.digest("SHA-256", textEncoder.encode(input));
16
+ const bytes = new Uint8Array(hash);
17
+ const hexParts = new Array(32);
18
+ for (let i = 0; i < 32; i++) {
19
+ hexParts[i] = HEX_TABLE[bytes[i]];
20
+ }
21
+ return hexParts.join("");
22
+ }
package/dist/index.d.ts CHANGED
@@ -1,3 +1,4 @@
1
1
  export * from "./types";
2
2
  export * from "./sts/issue";
3
3
  export * from "./federation/login";
4
+ export * from "./sigv4/request";
package/dist/index.js CHANGED
@@ -1,3 +1,4 @@
1
1
  export * from "./types";
2
2
  export * from "./sts/issue";
3
3
  export * from "./federation/login";
4
+ export * from "./sigv4/request";
@@ -0,0 +1,17 @@
1
+ export type AwsCredentials = {
2
+ accessKeyId: string;
3
+ secretAccessKey: string;
4
+ sessionToken?: string;
5
+ };
6
+ export type BuildSignedAwsRequestInput = {
7
+ service: string;
8
+ region: string;
9
+ target: string;
10
+ body: string;
11
+ contentType?: string;
12
+ credentials: AwsCredentials;
13
+ };
14
+ /**
15
+ * Build signed AWS JSON API request
16
+ */
17
+ export declare function buildSignedAwsRequest(input: BuildSignedAwsRequestInput): Promise<RequestInit>;
@@ -0,0 +1,124 @@
1
+ /*
2
+ SigV4 signed AWS JSON request builder.
3
+
4
+ Designed for edge runtimes (Cloudflare Workers, Deno, Bun, Node 20+).
5
+ No AWS SDK dependency.
6
+ */
7
+ import { sha256Hex, hex } from "../crypto/sha256";
8
+ const DEFAULT_CONTENT_TYPE = "application/x-amz-json-1.1";
9
+ const encoder = new TextEncoder();
10
+ const signingKeyCache = new Map();
11
+ const MAX_SIGNING_KEY_CACHE = 64;
12
+ const hmacKeyCache = new Map();
13
+ /**
14
+ * HMAC SHA256
15
+ */
16
+ async function hmac(key, data) {
17
+ const rawKey = key instanceof Uint8Array ? key : new Uint8Array(key);
18
+ const keyId = hex(rawKey);
19
+ let cryptoKey = hmacKeyCache.get(keyId);
20
+ if (!cryptoKey) {
21
+ cryptoKey = await crypto.subtle.importKey("raw", rawKey, { name: "HMAC", hash: "SHA-256" }, false, ["sign"]);
22
+ hmacKeyCache.set(keyId, cryptoKey);
23
+ }
24
+ return crypto.subtle.sign("HMAC", cryptoKey, encoder.encode(data));
25
+ }
26
+ function toUint8(buf) {
27
+ return new Uint8Array(buf);
28
+ }
29
+ /**
30
+ * Derive SigV4 signing key
31
+ */
32
+ async function getSignatureKey(secretKey, date, region, service) {
33
+ const kDate = await hmac(new TextEncoder().encode("AWS4" + secretKey), date);
34
+ const kRegion = await hmac(toUint8(kDate), region);
35
+ const kService = await hmac(toUint8(kRegion), service);
36
+ return hmac(toUint8(kService), "aws4_request");
37
+ }
38
+ /**
39
+ * Build signed AWS JSON API request
40
+ */
41
+ export async function buildSignedAwsRequest(input) {
42
+ const { service, region, target, body, credentials } = input;
43
+ const contentType = input.contentType ?? DEFAULT_CONTENT_TYPE;
44
+ const host = `${service}.${region}.amazonaws.com`;
45
+ const now = new Date();
46
+ const iso = now.toISOString();
47
+ const amzDate = iso.slice(0, 4) +
48
+ iso.slice(5, 7) +
49
+ iso.slice(8, 10) +
50
+ "T" +
51
+ iso.slice(11, 13) +
52
+ iso.slice(14, 16) +
53
+ iso.slice(17, 19) +
54
+ "Z";
55
+ const dateStamp = amzDate.slice(0, 8);
56
+ const canonicalHeaders = `content-type:${contentType}\n` +
57
+ `host:${host}\n` +
58
+ `x-amz-date:${amzDate}\n` +
59
+ `x-amz-target:${target}\n` +
60
+ (credentials.sessionToken
61
+ ? `x-amz-security-token:${credentials.sessionToken}\n`
62
+ : "");
63
+ const signedHeaders = credentials.sessionToken
64
+ ? "content-type;host;x-amz-date;x-amz-security-token;x-amz-target"
65
+ : "content-type;host;x-amz-date;x-amz-target";
66
+ const payloadHash = await sha256Hex(body);
67
+ const canonicalRequest = "POST\n" +
68
+ "/\n" +
69
+ "\n" +
70
+ canonicalHeaders +
71
+ "\n" +
72
+ signedHeaders +
73
+ "\n" +
74
+ payloadHash;
75
+ const credentialScope = dateStamp +
76
+ "/" +
77
+ region +
78
+ "/" +
79
+ service +
80
+ "/aws4_request";
81
+ const stringToSign = "AWS4-HMAC-SHA256\n" +
82
+ amzDate +
83
+ "\n" +
84
+ credentialScope +
85
+ "\n" +
86
+ await sha256Hex(canonicalRequest);
87
+ const cacheKey = await sha256Hex(credentials.secretAccessKey +
88
+ "|" +
89
+ dateStamp +
90
+ "|" +
91
+ region +
92
+ "|" +
93
+ service);
94
+ let signingKey = signingKeyCache.get(cacheKey);
95
+ if (!signingKey) {
96
+ signingKey = await getSignatureKey(credentials.secretAccessKey, dateStamp, region, service);
97
+ if (signingKeyCache.size > MAX_SIGNING_KEY_CACHE) {
98
+ const firstKey = signingKeyCache.keys().next().value;
99
+ if (firstKey)
100
+ signingKeyCache.delete(firstKey);
101
+ }
102
+ signingKeyCache.set(cacheKey, signingKey);
103
+ }
104
+ const signature = hex(await hmac(signingKey, stringToSign));
105
+ const authorization = "AWS4-HMAC-SHA256 " +
106
+ `Credential=${credentials.accessKeyId}/${credentialScope}, ` +
107
+ `SignedHeaders=${signedHeaders}, ` +
108
+ `Signature=${signature}`;
109
+ const headers = {
110
+ "Content-Type": contentType,
111
+ "X-Amz-Date": amzDate,
112
+ "X-Amz-Target": target,
113
+ Authorization: authorization,
114
+ Host: host
115
+ };
116
+ if (credentials.sessionToken) {
117
+ headers["X-Amz-Security-Token"] = credentials.sessionToken;
118
+ }
119
+ return {
120
+ method: "POST",
121
+ headers,
122
+ body
123
+ };
124
+ }
package/dist/sts/issue.js CHANGED
@@ -3,6 +3,7 @@ import { buildCanonicalRequest } from "../sigv4/canonical";
3
3
  import { buildStringToSign } from "../sigv4/string-to-sign";
4
4
  import { signStringToSign } from "./signer";
5
5
  import { InternalError } from "./errors";
6
+ import { sha256Hex } from "../crypto/sha256";
6
7
  // ---- constants (cleaner configuration, no runtime cost) ----
7
8
  const ALGORITHM = "AWS4-X509-ECDSA-SHA256";
8
9
  const SERVICE = "rolesanywhere";
@@ -26,13 +27,6 @@ let cachedPrivateKeyBase64 = null;
26
27
  let cachedCertSerialDec = null;
27
28
  let cachedCertSerialSource = null;
28
29
  const stsCredentialCache = new Map();
29
- // ---- shared encoder ----
30
- const textEncoder = new TextEncoder();
31
- // Precomputed hex table for fast byte→hex conversion (no per-byte toString alloc)
32
- const HEX_TABLE = new Array(256);
33
- for (let i = 0; i < 256; i++) {
34
- HEX_TABLE[i] = (i < 16 ? "0" : "") + i.toString(16);
35
- }
36
30
  async function getSigningMaterial(input) {
37
31
  if (cachedSigningKey &&
38
32
  cachedCertBase64 === input.certBase64 &&
@@ -261,16 +255,6 @@ function normalizeCert(raw) {
261
255
  // remove whitespace and newlines to ensure stable cache keys
262
256
  return raw.replace(/\s+/g, "");
263
257
  }
264
- async function sha256Hex(input) {
265
- // Tận dụng textEncoder có sẵn
266
- const hash = await crypto.subtle.digest("SHA-256", textEncoder.encode(input));
267
- const bytes = new Uint8Array(hash);
268
- const hexParts = new Array(32); // SHA-256 luôn là 32 bytes
269
- for (let i = 0; i < 32; i++) {
270
- hexParts[i] = HEX_TABLE[bytes[i]];
271
- }
272
- return hexParts.join("");
273
- }
274
258
  async function getCanonicalRequestHash(canonicalRequest) {
275
259
  return sha256Hex(canonicalRequest);
276
260
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vizamodo/aws-sts-core",
3
- "version": "0.3.5",
3
+ "version": "0.3.8",
4
4
  "description": "Pure AWS STS + SigV4 (X509 Roles Anywhere) core logic",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",