sigflint 1.0.0 → 1.0.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/CHANGELOG.md +15 -0
- package/README.md +26 -8
- package/dist/bun.js +267 -142
- package/dist/node.js +281 -151
- package/index.d.ts +8 -2
- package/package.json +47 -38
- package/src/base.js +264 -60
- package/src/bun.js +11 -0
- package/src/chunks.js +66 -17
- package/src/ecdsa-node.js +16 -1
- package/src/events.js +44 -6
- package/src/node.js +30 -4
- package/src/presign.js +80 -13
- package/src/v4a.js +89 -19
- package/src/web.js +195 -30
- package/types/base.d.ts +82 -35
- package/types/chunks.d.ts +37 -11
- package/types/ecdsa-node.d.ts +7 -2
- package/types/events.d.ts +26 -6
- package/types/presign.d.ts +20 -10
- package/types/v4a.d.ts +42 -13
package/dist/bun.js
CHANGED
|
@@ -1,20 +1,26 @@
|
|
|
1
|
+
// @bun
|
|
1
2
|
// src/bun.js
|
|
2
|
-
import crypto2 from "
|
|
3
|
+
import crypto2 from "crypto";
|
|
3
4
|
|
|
4
5
|
// src/base.js
|
|
5
6
|
var emptyBodyHash = "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855";
|
|
6
|
-
var symmetric = {
|
|
7
|
+
var symmetric = {
|
|
8
|
+
algorithm: "AWS4-HMAC-SHA256",
|
|
9
|
+
scope: (date, region, service) => `${date}/${region}/${service}/aws4_request`
|
|
10
|
+
};
|
|
7
11
|
var reSafePath = /^[A-Za-z0-9\-._~/]*$/;
|
|
8
12
|
var reSafeQuery = /^[A-Za-z0-9\-._~=&]*$/;
|
|
9
13
|
var reSpaces = /[ \t]+/g;
|
|
10
|
-
var reDirty = /\t|
|
|
14
|
+
var reDirty = /\t| {2}/;
|
|
11
15
|
var pathTable;
|
|
12
16
|
var queryTable;
|
|
13
17
|
function tables() {
|
|
14
|
-
if (pathTable !==
|
|
18
|
+
if (pathTable !== undefined) {
|
|
19
|
+
return;
|
|
20
|
+
}
|
|
15
21
|
pathTable = new Array(256);
|
|
16
22
|
queryTable = new Array(256);
|
|
17
|
-
for (let b = 0;
|
|
23
|
+
for (let b = 0;b < 256; b++) {
|
|
18
24
|
const c = String.fromCharCode(b);
|
|
19
25
|
const unreserved = /[A-Za-z0-9\-._~]/.test(c);
|
|
20
26
|
const escaped = (b < 16 ? "%0" : "%") + b.toString(16).toUpperCase();
|
|
@@ -23,18 +29,26 @@ function tables() {
|
|
|
23
29
|
}
|
|
24
30
|
}
|
|
25
31
|
function hexValue(code) {
|
|
26
|
-
if (code >= 48 && code <= 57)
|
|
27
|
-
|
|
28
|
-
|
|
32
|
+
if (code >= 48 && code <= 57) {
|
|
33
|
+
return code - 48;
|
|
34
|
+
}
|
|
35
|
+
if (code >= 65 && code <= 70) {
|
|
36
|
+
return code - 55;
|
|
37
|
+
}
|
|
38
|
+
if (code >= 97 && code <= 102) {
|
|
39
|
+
return code - 87;
|
|
40
|
+
}
|
|
29
41
|
return -1;
|
|
30
42
|
}
|
|
31
43
|
function canonicalEncode(string, table) {
|
|
32
44
|
let out = "";
|
|
33
45
|
let start = 0;
|
|
34
|
-
for (let i = 0;
|
|
46
|
+
for (let i = 0;i < string.length; i++) {
|
|
35
47
|
const code = string.charCodeAt(i);
|
|
36
48
|
const same = table[code];
|
|
37
|
-
if (same.length === 1 && code !== 43)
|
|
49
|
+
if (same.length === 1 && code !== 43) {
|
|
50
|
+
continue;
|
|
51
|
+
}
|
|
38
52
|
out += string.slice(start, i);
|
|
39
53
|
start = i + 1;
|
|
40
54
|
if (code === 37) {
|
|
@@ -56,21 +70,32 @@ function canonicalEncode(string, table) {
|
|
|
56
70
|
function canonicalPathGeneral(pathname) {
|
|
57
71
|
const parts = pathname.split("/");
|
|
58
72
|
const kept = [];
|
|
59
|
-
for (let i = 0;
|
|
73
|
+
for (let i = 0;i < parts.length; i++) {
|
|
60
74
|
const part = parts[i];
|
|
61
|
-
if (part === "" || part === ".")
|
|
62
|
-
|
|
63
|
-
|
|
75
|
+
if (part === "" || part === ".") {
|
|
76
|
+
continue;
|
|
77
|
+
}
|
|
78
|
+
if (part === "..") {
|
|
79
|
+
kept.pop();
|
|
80
|
+
} else {
|
|
81
|
+
kept.push(part);
|
|
82
|
+
}
|
|
64
83
|
}
|
|
65
84
|
const path = (pathname.startsWith("/") ? "/" : "") + kept.join("/") + (pathname.endsWith("/") && kept.length > 0 ? "/" : "");
|
|
66
|
-
if (reSafePath.test(path))
|
|
85
|
+
if (reSafePath.test(path)) {
|
|
86
|
+
return path === "" ? "/" : path;
|
|
87
|
+
}
|
|
67
88
|
tables();
|
|
68
89
|
let out = "";
|
|
69
|
-
for (let i = 0;
|
|
90
|
+
for (let i = 0;i < path.length; i++) {
|
|
91
|
+
out += queryTable[path.charCodeAt(i)] === path[i] || path[i] === "/" ? path[i] : queryTable[path.charCodeAt(i)];
|
|
92
|
+
}
|
|
70
93
|
return out;
|
|
71
94
|
}
|
|
72
95
|
function canonicalPathS3(pathname) {
|
|
73
|
-
if (reSafePath.test(pathname))
|
|
96
|
+
if (reSafePath.test(pathname)) {
|
|
97
|
+
return pathname === "" ? "/" : pathname;
|
|
98
|
+
}
|
|
74
99
|
tables();
|
|
75
100
|
return canonicalEncode(pathname, pathTable);
|
|
76
101
|
}
|
|
@@ -79,24 +104,34 @@ function comparePairs(a, b) {
|
|
|
79
104
|
return a[0] < b[0] ? -1 : a[0] > b[0] ? 1 : a[1] < b[1] ? -1 : a[1] > b[1] ? 1 : 0;
|
|
80
105
|
}
|
|
81
106
|
function canonicalQuery(search) {
|
|
82
|
-
if (search.length < 2)
|
|
107
|
+
if (search.length < 2) {
|
|
108
|
+
return "";
|
|
109
|
+
}
|
|
83
110
|
const query = search.slice(1);
|
|
84
111
|
const simple = reSafeQuery.test(query);
|
|
85
112
|
if (simple) {
|
|
86
|
-
let
|
|
113
|
+
let out = "";
|
|
87
114
|
let previousName = "";
|
|
88
115
|
let previousValue = "";
|
|
89
116
|
let start = 0;
|
|
90
|
-
for (
|
|
117
|
+
for (;; ) {
|
|
91
118
|
let end = query.indexOf("&", start);
|
|
92
|
-
if (end === -1)
|
|
119
|
+
if (end === -1) {
|
|
120
|
+
end = query.length;
|
|
121
|
+
}
|
|
93
122
|
let eq = query.indexOf("=", start);
|
|
94
|
-
if (eq === -1 || eq > end)
|
|
123
|
+
if (eq === -1 || eq > end) {
|
|
124
|
+
eq = end;
|
|
125
|
+
}
|
|
95
126
|
const name = query.slice(start, eq);
|
|
96
127
|
const value = query.slice(eq + 1, end);
|
|
97
|
-
if (end === start || eq === start || value.includes("=") || start > 0 && (name < previousName || name === previousName && value <= previousValue))
|
|
98
|
-
|
|
99
|
-
|
|
128
|
+
if (end === start || eq === start || value.includes("=") || start > 0 && (name < previousName || name === previousName && value <= previousValue)) {
|
|
129
|
+
break;
|
|
130
|
+
}
|
|
131
|
+
out += (start === 0 ? "" : "&") + name + "=" + value;
|
|
132
|
+
if (end === query.length) {
|
|
133
|
+
return out;
|
|
134
|
+
}
|
|
100
135
|
previousName = name;
|
|
101
136
|
previousValue = value;
|
|
102
137
|
start = end + 1;
|
|
@@ -105,25 +140,36 @@ function canonicalQuery(search) {
|
|
|
105
140
|
tables();
|
|
106
141
|
const pairs = [];
|
|
107
142
|
for (const part of query.split("&")) {
|
|
108
|
-
if (part === "")
|
|
143
|
+
if (part === "") {
|
|
144
|
+
continue;
|
|
145
|
+
}
|
|
109
146
|
const eq = part.indexOf("=");
|
|
110
147
|
const rawName = eq === -1 ? part : part.slice(0, eq);
|
|
111
148
|
const rawValue = eq === -1 ? "" : part.slice(eq + 1);
|
|
112
|
-
pairs.push(simple && !rawValue.includes("=") ? [rawName, rawValue] : [
|
|
149
|
+
pairs.push(simple && !rawValue.includes("=") ? [rawName, rawValue] : [
|
|
150
|
+
canonicalEncode(rawName, queryTable),
|
|
151
|
+
canonicalEncode(rawValue, queryTable)
|
|
152
|
+
]);
|
|
153
|
+
}
|
|
154
|
+
if (pairs.length > 1) {
|
|
155
|
+
pairs.sort(comparePairs);
|
|
113
156
|
}
|
|
114
|
-
if (pairs.length > 1) pairs.sort(comparePairs);
|
|
115
157
|
let out = "";
|
|
116
|
-
for (let i = 0;
|
|
158
|
+
for (let i = 0;i < pairs.length; i++) {
|
|
159
|
+
out += (i === 0 ? "" : "&") + pairs[i][0] + "=" + pairs[i][1];
|
|
160
|
+
}
|
|
117
161
|
return out;
|
|
118
162
|
}
|
|
119
163
|
function insert(names, values, name, value) {
|
|
120
164
|
let i = names.length;
|
|
121
|
-
while (i > 0 && names[i - 1] > name)
|
|
165
|
+
while (i > 0 && names[i - 1] > name) {
|
|
166
|
+
i--;
|
|
167
|
+
}
|
|
122
168
|
if (i > 0 && names[i - 1] === name) {
|
|
123
169
|
values[i - 1] = value;
|
|
124
170
|
return;
|
|
125
171
|
}
|
|
126
|
-
for (let j = names.length;
|
|
172
|
+
for (let j = names.length;j > i; j--) {
|
|
127
173
|
names[j] = names[j - 1];
|
|
128
174
|
values[j] = values[j - 1];
|
|
129
175
|
}
|
|
@@ -132,8 +178,12 @@ function insert(names, values, name, value) {
|
|
|
132
178
|
}
|
|
133
179
|
function signHeaderName(name, value) {
|
|
134
180
|
const lowerName = name.toLowerCase();
|
|
135
|
-
if (lowerName === "x-amz-date" || lowerName === "authorization" || lowerName === "__proto__")
|
|
136
|
-
|
|
181
|
+
if (lowerName === "x-amz-date" || lowerName === "authorization" || lowerName === "__proto__") {
|
|
182
|
+
throw new TypeError(`signHeaders cannot contain ${lowerName}`);
|
|
183
|
+
}
|
|
184
|
+
if (/[\r\n]/.test(value)) {
|
|
185
|
+
throw new TypeError(`signHeaders ${lowerName} has a line break in its value`);
|
|
186
|
+
}
|
|
137
187
|
return lowerName;
|
|
138
188
|
}
|
|
139
189
|
var headerValue = (value) => {
|
|
@@ -143,20 +193,21 @@ var headerValue = (value) => {
|
|
|
143
193
|
var lastSecond = NaN;
|
|
144
194
|
var lastDatetime = "";
|
|
145
195
|
function amzDatetime(now) {
|
|
146
|
-
const second = Math.floor(now /
|
|
196
|
+
const second = Math.floor(now / 1000);
|
|
147
197
|
if (second !== lastSecond) {
|
|
148
|
-
const iso = new Date(second *
|
|
198
|
+
const iso = new Date(second * 1000).toISOString();
|
|
149
199
|
lastDatetime = iso.slice(0, 4) + iso.slice(5, 7) + iso.slice(8, 10) + "T" + iso.slice(11, 13) + iso.slice(14, 16) + iso.slice(17, 19) + "Z";
|
|
150
200
|
lastSecond = second;
|
|
151
201
|
}
|
|
152
202
|
return lastDatetime;
|
|
153
203
|
}
|
|
154
|
-
function payloadHashOf(request,
|
|
204
|
+
function payloadHashOf(request, hexHash) {
|
|
155
205
|
const body = request.body ?? "";
|
|
156
|
-
return request.unsignedPayload ? "UNSIGNED-PAYLOAD" : body.length === 0 ? emptyBodyHash :
|
|
206
|
+
return request.unsignedPayload ? "UNSIGNED-PAYLOAD" : body.length === 0 ? emptyBodyHash : hexHash(body);
|
|
157
207
|
}
|
|
158
208
|
function prepare(request, credentials, payloadHash, scheme = symmetric) {
|
|
159
|
-
const {
|
|
209
|
+
const { url, signHeaders } = request;
|
|
210
|
+
const method = request.method.toUpperCase();
|
|
160
211
|
const region = request.region ?? "";
|
|
161
212
|
const service = request.service ?? "s3";
|
|
162
213
|
const withHash = service === "s3" || request.unsignedPayload === true;
|
|
@@ -164,7 +215,7 @@ function prepare(request, credentials, payloadHash, scheme = symmetric) {
|
|
|
164
215
|
const datetime = amzDatetime(request.now ?? Date.now());
|
|
165
216
|
const date = datetime.slice(0, 8);
|
|
166
217
|
const headers = withHash ? { "x-amz-date": datetime, "x-amz-content-sha256": payloadHash } : { "x-amz-date": datetime };
|
|
167
|
-
const extraNames = signHeaders ===
|
|
218
|
+
const extraNames = signHeaders === undefined ? [] : Object.keys(signHeaders);
|
|
168
219
|
let canonicalHeaders;
|
|
169
220
|
let signedHeaders;
|
|
170
221
|
if (extraNames.length === 0 && !sessionToken) {
|
|
@@ -183,10 +234,7 @@ x-amz-date:${datetime}
|
|
|
183
234
|
insert(names, values, "x-amz-security-token", sessionToken.trim());
|
|
184
235
|
}
|
|
185
236
|
for (const name of extraNames) {
|
|
186
|
-
const value =
|
|
187
|
-
/** @type {Record<string, string>} */
|
|
188
|
-
signHeaders[name]
|
|
189
|
-
);
|
|
237
|
+
const value = signHeaders[name];
|
|
190
238
|
const lowerName = signHeaderName(name, value);
|
|
191
239
|
headers[lowerName] = value;
|
|
192
240
|
insert(names, values, lowerName, headerValue(value));
|
|
@@ -204,12 +252,16 @@ x-amz-date:${datetime}
|
|
|
204
252
|
if (j === nBase || i < names.length && names[i] <= baseNames[j]) {
|
|
205
253
|
name = names[i];
|
|
206
254
|
value = values[i++];
|
|
207
|
-
if (j < nBase && name === baseNames[j])
|
|
255
|
+
if (j < nBase && name === baseNames[j]) {
|
|
256
|
+
j++;
|
|
257
|
+
}
|
|
208
258
|
} else {
|
|
209
259
|
name = baseNames[j];
|
|
210
260
|
value = baseValues[j++];
|
|
211
261
|
}
|
|
212
|
-
if (name === "x-amz-content-sha256")
|
|
262
|
+
if (name === "x-amz-content-sha256") {
|
|
263
|
+
payloadHash = value;
|
|
264
|
+
}
|
|
213
265
|
canonicalHeaders += `${name}:${value}
|
|
214
266
|
`;
|
|
215
267
|
signedHeaders += signedHeaders === "" ? name : ";" + name;
|
|
@@ -221,7 +273,17 @@ ${canonicalQuery(url.search)}
|
|
|
221
273
|
${canonicalHeaders}
|
|
222
274
|
${signedHeaders}
|
|
223
275
|
${payloadHash}`;
|
|
224
|
-
return {
|
|
276
|
+
return {
|
|
277
|
+
headers,
|
|
278
|
+
canonicalRequest,
|
|
279
|
+
datetime,
|
|
280
|
+
date,
|
|
281
|
+
region,
|
|
282
|
+
service,
|
|
283
|
+
credentialScope: scheme.scope(date, region, service),
|
|
284
|
+
signedHeaders,
|
|
285
|
+
algorithm: scheme.algorithm
|
|
286
|
+
};
|
|
225
287
|
}
|
|
226
288
|
var stringToSign = (prepared, canonicalRequestHash) => `${prepared.algorithm}
|
|
227
289
|
${prepared.datetime}
|
|
@@ -231,24 +293,28 @@ function authorize(prepared, accessKeyId, signature) {
|
|
|
231
293
|
prepared.headers.authorization = `${prepared.algorithm} Credential=${accessKeyId}/${prepared.credentialScope}, SignedHeaders=${prepared.signedHeaders}, Signature=${signature}`;
|
|
232
294
|
return prepared.headers;
|
|
233
295
|
}
|
|
234
|
-
function createKeys(
|
|
235
|
-
const signingKeys =
|
|
236
|
-
const maxSigningKeys =
|
|
296
|
+
function createKeys(hmac) {
|
|
297
|
+
const signingKeys = new Map;
|
|
298
|
+
const maxSigningKeys = 1000;
|
|
237
299
|
let lastSecret;
|
|
238
300
|
let lastDate;
|
|
239
301
|
let lastRegion;
|
|
240
302
|
let lastService;
|
|
241
303
|
let lastKey;
|
|
242
|
-
return function
|
|
243
|
-
if (secretAccessKey === lastSecret && date === lastDate && region === lastRegion && service === lastService)
|
|
304
|
+
return function getSigningKey(secretAccessKey, date, region, service) {
|
|
305
|
+
if (secretAccessKey === lastSecret && date === lastDate && region === lastRegion && service === lastService) {
|
|
306
|
+
return lastKey;
|
|
307
|
+
}
|
|
244
308
|
const cacheKey = `${date}
|
|
245
309
|
${region}
|
|
246
310
|
${service}
|
|
247
311
|
${secretAccessKey}`;
|
|
248
312
|
let signingKey = signingKeys.get(cacheKey);
|
|
249
|
-
if (signingKey ===
|
|
250
|
-
signingKey =
|
|
251
|
-
if (signingKeys.size >= maxSigningKeys)
|
|
313
|
+
if (signingKey === undefined) {
|
|
314
|
+
signingKey = hmac(hmac(hmac(hmac("AWS4" + secretAccessKey, date), region), service), "aws4_request");
|
|
315
|
+
if (signingKeys.size >= maxSigningKeys) {
|
|
316
|
+
signingKeys.delete(signingKeys.keys().next().value);
|
|
317
|
+
}
|
|
252
318
|
signingKeys.set(cacheKey, signingKey);
|
|
253
319
|
}
|
|
254
320
|
lastSecret = secretAccessKey;
|
|
@@ -259,25 +325,28 @@ ${secretAccessKey}`;
|
|
|
259
325
|
return signingKey;
|
|
260
326
|
};
|
|
261
327
|
}
|
|
262
|
-
function createSigner({ hexHash
|
|
263
|
-
return function
|
|
264
|
-
const prepared = prepare(request, credentials, payloadHashOf(request,
|
|
265
|
-
return authorize(
|
|
266
|
-
prepared,
|
|
267
|
-
credentials.accessKeyId,
|
|
268
|
-
hmacHex(getSigningKey2(credentials.secretAccessKey, prepared.date, prepared.region, prepared.service), stringToSign(prepared, hexHash2(prepared.canonicalRequest)))
|
|
269
|
-
);
|
|
328
|
+
function createSigner({ hexHash, hmacHex, getSigningKey }) {
|
|
329
|
+
return function getAuthHeaders(request, credentials) {
|
|
330
|
+
const prepared = prepare(request, credentials, payloadHashOf(request, hexHash));
|
|
331
|
+
return authorize(prepared, credentials.accessKeyId, hmacHex(getSigningKey(credentials.secretAccessKey, prepared.date, prepared.region, prepared.service), stringToSign(prepared, hexHash(prepared.canonicalRequest))));
|
|
270
332
|
};
|
|
271
333
|
}
|
|
272
334
|
|
|
273
335
|
// src/presign.js
|
|
274
336
|
var encodeQueryPart = (text) => encodeURIComponent(text).replace(/[!'()*]/g, (c) => "%" + c.charCodeAt(0).toString(16).toUpperCase());
|
|
275
337
|
function preparePresign(request, credentials, payloadHash, scheme = symmetric, extra = "") {
|
|
276
|
-
const {
|
|
277
|
-
|
|
278
|
-
if (url.
|
|
338
|
+
const { url, signHeaders } = request;
|
|
339
|
+
const method = request.method.toUpperCase();
|
|
340
|
+
if (url.protocol !== "https:" && url.protocol !== "http:") {
|
|
341
|
+
throw new TypeError("presign needs an http or https URL");
|
|
342
|
+
}
|
|
343
|
+
if (url.search.length > 1 && (url.search.includes("X-Amz-Signature=") || url.search.includes("X-Amz-Algorithm="))) {
|
|
344
|
+
throw new TypeError("the URL is already presigned");
|
|
345
|
+
}
|
|
279
346
|
const expires = request.expires ?? 3600;
|
|
280
|
-
if (!Number.isInteger(expires) || expires < 1 || expires > 604800)
|
|
347
|
+
if (!Number.isInteger(expires) || expires < 1 || expires > 604800) {
|
|
348
|
+
throw new RangeError("expires must be a whole number of seconds from 1 to 604800 (7 days)");
|
|
349
|
+
}
|
|
281
350
|
const region = request.region ?? "";
|
|
282
351
|
const service = request.service ?? "s3";
|
|
283
352
|
const datetime = amzDatetime(request.now ?? Date.now());
|
|
@@ -285,13 +354,21 @@ function preparePresign(request, credentials, payloadHash, scheme = symmetric, e
|
|
|
285
354
|
const credentialScope = scheme.scope(date, region, service);
|
|
286
355
|
const names = ["host"];
|
|
287
356
|
const values = [url.host];
|
|
288
|
-
if (signHeaders !==
|
|
357
|
+
if (signHeaders !== undefined) {
|
|
358
|
+
for (const name of Object.keys(signHeaders)) {
|
|
359
|
+
insert(names, values, signHeaderName(name, signHeaders[name]), headerValue(signHeaders[name]));
|
|
360
|
+
}
|
|
361
|
+
}
|
|
289
362
|
let canonicalHeaders = "";
|
|
290
|
-
for (let i = 0;
|
|
363
|
+
for (let i = 0;i < names.length; i++) {
|
|
364
|
+
canonicalHeaders += `${names[i]}:${values[i]}
|
|
291
365
|
`;
|
|
366
|
+
}
|
|
292
367
|
const signedHeaders = names.join(";");
|
|
293
368
|
let auth = `X-Amz-Algorithm=${scheme.algorithm}&X-Amz-Credential=${encodeQueryPart(`${credentials.accessKeyId}/${credentialScope}`)}&X-Amz-Date=${datetime}&X-Amz-Expires=${expires}&X-Amz-SignedHeaders=${encodeQueryPart(signedHeaders)}`;
|
|
294
|
-
if (credentials.sessionToken)
|
|
369
|
+
if (credentials.sessionToken) {
|
|
370
|
+
auth += `&X-Amz-Security-Token=${encodeQueryPart(credentials.sessionToken)}`;
|
|
371
|
+
}
|
|
295
372
|
auth += extra;
|
|
296
373
|
const query = url.search.length > 1 ? url.search + "&" + auth : "?" + auth;
|
|
297
374
|
const hash = service === "s3" || request.unsignedPayload ? "UNSIGNED-PAYLOAD" : payloadHash;
|
|
@@ -301,99 +378,137 @@ ${canonicalQuery(query)}
|
|
|
301
378
|
${canonicalHeaders}
|
|
302
379
|
${signedHeaders}
|
|
303
380
|
${hash}`;
|
|
304
|
-
return {
|
|
381
|
+
return {
|
|
382
|
+
canonicalRequest,
|
|
383
|
+
datetime,
|
|
384
|
+
date,
|
|
385
|
+
region,
|
|
386
|
+
service,
|
|
387
|
+
credentialScope,
|
|
388
|
+
signedHeaders,
|
|
389
|
+
algorithm: scheme.algorithm,
|
|
390
|
+
base: url.origin + url.pathname,
|
|
391
|
+
query
|
|
392
|
+
};
|
|
305
393
|
}
|
|
306
394
|
var presignedUrl = (prepared, signature) => `${prepared.base}${prepared.query}&X-Amz-Signature=${signature}`;
|
|
307
|
-
function createPresigner({ hexHash
|
|
308
|
-
return function
|
|
309
|
-
const prepared = preparePresign(request, credentials, payloadHashOf(request,
|
|
310
|
-
return presignedUrl(
|
|
311
|
-
prepared,
|
|
312
|
-
hmacHex(getSigningKey2(credentials.secretAccessKey, prepared.date, prepared.region, prepared.service), stringToSign(prepared, hexHash2(prepared.canonicalRequest)))
|
|
313
|
-
);
|
|
395
|
+
function createPresigner({ hexHash, hmacHex, getSigningKey }) {
|
|
396
|
+
return function presign(request, credentials) {
|
|
397
|
+
const prepared = preparePresign(request, credentials, payloadHashOf(request, hexHash));
|
|
398
|
+
return presignedUrl(prepared, hmacHex(getSigningKey(credentials.secretAccessKey, prepared.date, prepared.region, prepared.service), stringToSign(prepared, hexHash(prepared.canonicalRequest))));
|
|
314
399
|
};
|
|
315
400
|
}
|
|
316
401
|
|
|
317
402
|
// src/v4a.js
|
|
318
|
-
var asymmetric = {
|
|
403
|
+
var asymmetric = {
|
|
404
|
+
algorithm: "AWS4-ECDSA-P256-SHA256",
|
|
405
|
+
scope: (date, _region, service) => `${date}/${service}/aws4_request`
|
|
406
|
+
};
|
|
319
407
|
function regionSetOf(request) {
|
|
320
408
|
const regionSet = request.regionSet;
|
|
321
|
-
if (typeof regionSet !== "string" || regionSet === "")
|
|
409
|
+
if (typeof regionSet !== "string" || regionSet === "") {
|
|
410
|
+
throw new TypeError("SigV4a needs request.regionSet, for example 'us-east-1,us-west-2' or '*'");
|
|
411
|
+
}
|
|
322
412
|
return regionSet;
|
|
323
413
|
}
|
|
324
|
-
var withRegionSet = (request) => ({
|
|
414
|
+
var withRegionSet = (request) => ({
|
|
415
|
+
...request,
|
|
416
|
+
signHeaders: { ...request.signHeaders, "x-amz-region-set": regionSetOf(request) }
|
|
417
|
+
});
|
|
325
418
|
var regionSetQuery = (request) => `&X-Amz-Region-Set=${encodeQueryPart(regionSetOf(request))}`;
|
|
326
|
-
var kdfInput = (accessKeyId, counter) => `\
|
|
419
|
+
var kdfInput = (accessKeyId, counter) => `\x00\x00\x00\x01AWS4-ECDSA-P256-SHA256\x00${accessKeyId}${String.fromCharCode(counter)}\x00\x00\x01\x00`;
|
|
327
420
|
function scalarFrom(k) {
|
|
328
421
|
const nMinusTwo = 0xffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc63254fn;
|
|
329
422
|
let c = 0n;
|
|
330
|
-
for (let i = 0;
|
|
331
|
-
|
|
423
|
+
for (let i = 0;i < 32; i++) {
|
|
424
|
+
c = c << 8n | BigInt(k[i]);
|
|
425
|
+
}
|
|
426
|
+
if (c > nMinusTwo) {
|
|
427
|
+
return;
|
|
428
|
+
}
|
|
332
429
|
c += 1n;
|
|
333
430
|
const d = new Uint8Array(32);
|
|
334
|
-
for (let i = 31;
|
|
431
|
+
for (let i = 31;i >= 0; i--, c >>= 8n) {
|
|
432
|
+
d[i] = Number(c & 0xffn);
|
|
433
|
+
}
|
|
335
434
|
return d;
|
|
336
435
|
}
|
|
337
|
-
function deriveP256(
|
|
338
|
-
for (let counter = 1;
|
|
339
|
-
const d = scalarFrom(
|
|
340
|
-
if (d !==
|
|
436
|
+
function deriveP256(hmac, accessKeyId, secretAccessKey) {
|
|
437
|
+
for (let counter = 1;counter < 128; counter++) {
|
|
438
|
+
const d = scalarFrom(hmac("AWS4A" + secretAccessKey, kdfInput(accessKeyId, counter)));
|
|
439
|
+
if (d !== undefined) {
|
|
440
|
+
return d;
|
|
441
|
+
}
|
|
341
442
|
}
|
|
342
443
|
throw new Error("no SigV4a key for these credentials");
|
|
343
444
|
}
|
|
344
|
-
var signers = /* @__PURE__ */ new WeakMap
|
|
345
|
-
function createAsymmetric(
|
|
346
|
-
let sign = signers.get(
|
|
347
|
-
if (sign ===
|
|
445
|
+
var signers = /* @__PURE__ */ new WeakMap;
|
|
446
|
+
function createAsymmetric(hmac, ecdsa) {
|
|
447
|
+
let sign = signers.get(ecdsa);
|
|
448
|
+
if (sign === undefined) {
|
|
449
|
+
signers.set(ecdsa, sign = signerFor(hmac, ecdsa));
|
|
450
|
+
}
|
|
348
451
|
return sign;
|
|
349
452
|
}
|
|
350
|
-
function signerFor(
|
|
351
|
-
const keys =
|
|
453
|
+
function signerFor(hmac, ecdsa) {
|
|
454
|
+
const keys = new Map;
|
|
352
455
|
return function sign(credentials, text) {
|
|
353
456
|
const id = `${credentials.accessKeyId}/${credentials.secretAccessKey}`;
|
|
354
457
|
let key = keys.get(id);
|
|
355
|
-
if (key ===
|
|
356
|
-
key =
|
|
357
|
-
if (keys.size >=
|
|
458
|
+
if (key === undefined) {
|
|
459
|
+
key = ecdsa.key(deriveP256(hmac, credentials.accessKeyId, credentials.secretAccessKey));
|
|
460
|
+
if (keys.size >= 1000) {
|
|
461
|
+
keys.delete(keys.keys().next().value);
|
|
462
|
+
}
|
|
358
463
|
keys.set(id, key);
|
|
359
464
|
}
|
|
360
|
-
return
|
|
465
|
+
return ecdsa.sign(key, text);
|
|
361
466
|
};
|
|
362
467
|
}
|
|
363
|
-
function createSignerV4a({ hexHash
|
|
364
|
-
const sign = createAsymmetric(
|
|
365
|
-
return function
|
|
366
|
-
const prepared = prepare(withRegionSet(request), credentials, payloadHashOf(request,
|
|
367
|
-
return authorize(prepared, credentials.accessKeyId, sign(credentials, stringToSign(prepared,
|
|
468
|
+
function createSignerV4a({ hexHash, hmac, ecdsa }) {
|
|
469
|
+
const sign = createAsymmetric(hmac, ecdsa);
|
|
470
|
+
return function getAuthHeadersV4a(request, credentials) {
|
|
471
|
+
const prepared = prepare(withRegionSet(request), credentials, payloadHashOf(request, hexHash), asymmetric);
|
|
472
|
+
return authorize(prepared, credentials.accessKeyId, sign(credentials, stringToSign(prepared, hexHash(prepared.canonicalRequest))));
|
|
368
473
|
};
|
|
369
474
|
}
|
|
370
|
-
function createPresignerV4a({ hexHash
|
|
371
|
-
const sign = createAsymmetric(
|
|
372
|
-
return function
|
|
373
|
-
const prepared = preparePresign(request, credentials, payloadHashOf(request,
|
|
374
|
-
return presignedUrl(prepared, sign(credentials, stringToSign(prepared,
|
|
475
|
+
function createPresignerV4a({ hexHash, hmac, ecdsa }) {
|
|
476
|
+
const sign = createAsymmetric(hmac, ecdsa);
|
|
477
|
+
return function presignV4a(request, credentials) {
|
|
478
|
+
const prepared = preparePresign(request, credentials, payloadHashOf(request, hexHash), asymmetric, regionSetQuery(request));
|
|
479
|
+
return presignedUrl(prepared, sign(credentials, stringToSign(prepared, hexHash(prepared.canonicalRequest))));
|
|
375
480
|
};
|
|
376
481
|
}
|
|
377
482
|
|
|
378
483
|
// src/ecdsa-node.js
|
|
379
|
-
import crypto from "
|
|
484
|
+
import crypto from "crypto";
|
|
380
485
|
var b64url = (bytes) => Buffer.from(bytes).toString("base64url");
|
|
381
486
|
var ecdsa = {
|
|
382
487
|
key(d) {
|
|
383
488
|
const ecdh = crypto.createECDH("prime256v1");
|
|
384
489
|
ecdh.setPrivateKey(d);
|
|
385
490
|
const point = ecdh.getPublicKey();
|
|
386
|
-
return crypto.createPrivateKey({
|
|
491
|
+
return crypto.createPrivateKey({
|
|
492
|
+
key: {
|
|
493
|
+
kty: "EC",
|
|
494
|
+
crv: "P-256",
|
|
495
|
+
d: b64url(d),
|
|
496
|
+
x: b64url(point.subarray(1, 33)),
|
|
497
|
+
y: b64url(point.subarray(33))
|
|
498
|
+
},
|
|
499
|
+
format: "jwk"
|
|
500
|
+
});
|
|
387
501
|
},
|
|
388
502
|
sign: (key, text) => crypto.sign("sha256", text, { key, dsaEncoding: "der" }).toString("hex")
|
|
389
503
|
};
|
|
390
504
|
|
|
391
505
|
// src/chunks.js
|
|
392
|
-
var utf8 = /* @__PURE__ */ new TextEncoder
|
|
506
|
+
var utf8 = /* @__PURE__ */ new TextEncoder;
|
|
393
507
|
function seedOf(authHeaders) {
|
|
394
508
|
const auth = authHeaders.authorization;
|
|
395
|
-
if (typeof auth !== "string" || !auth.startsWith("AWS4-HMAC-SHA256 "))
|
|
509
|
+
if (typeof auth !== "string" || !auth.startsWith("AWS4-HMAC-SHA256 ")) {
|
|
396
510
|
throw new TypeError("authHeaders must be the headers getAuthHeaders returned (a SigV4a signature cannot start a chunk or event stream)");
|
|
511
|
+
}
|
|
397
512
|
const scope = auth.slice(auth.indexOf("Credential=") + 11, auth.indexOf(",")).split("/");
|
|
398
513
|
return {
|
|
399
514
|
signature: auth.slice(auth.lastIndexOf("Signature=") + 10),
|
|
@@ -416,7 +531,13 @@ ${scope}
|
|
|
416
531
|
${previous}
|
|
417
532
|
${trailerHash}`;
|
|
418
533
|
function canonicalTrailers(trailers) {
|
|
419
|
-
return Object.keys(trailers).map((name) =>
|
|
534
|
+
return Object.keys(trailers).map((name) => {
|
|
535
|
+
const value = String(trailers[name]);
|
|
536
|
+
if (/[\r\n]/.test(name) || /[\r\n]/.test(value)) {
|
|
537
|
+
throw new TypeError("a trailer name or value cannot hold a line break");
|
|
538
|
+
}
|
|
539
|
+
return [name.toLowerCase(), value.trim()];
|
|
540
|
+
}).sort((a, b) => a[0] < b[0] ? -1 : a[0] > b[0] ? 1 : 0).map(([name, value]) => `${name}:${value}
|
|
420
541
|
`).join("");
|
|
421
542
|
}
|
|
422
543
|
function frameChunk(signature, data) {
|
|
@@ -430,29 +551,29 @@ function frameChunk(signature, data) {
|
|
|
430
551
|
return out;
|
|
431
552
|
}
|
|
432
553
|
function frameEnd(signature, trailers, trailerSignature) {
|
|
433
|
-
return utf8.encode(
|
|
434
|
-
trailers === void 0 ? `0;chunk-signature=${signature}\r
|
|
554
|
+
return utf8.encode(trailers === undefined ? `0;chunk-signature=${signature}\r
|
|
435
555
|
\r
|
|
436
556
|
` : `0;chunk-signature=${signature}\r
|
|
437
|
-
${trailers.replace(/\n/g,
|
|
557
|
+
${trailers.replace(/\n/g, `\r
|
|
558
|
+
`)}x-amz-trailer-signature:${trailerSignature}\r
|
|
438
559
|
\r
|
|
439
|
-
`
|
|
440
|
-
);
|
|
560
|
+
`);
|
|
441
561
|
}
|
|
442
|
-
function createChunkSigner({ hexHash
|
|
443
|
-
return function
|
|
562
|
+
function createChunkSigner({ hexHash, hmacHex, getSigningKey }) {
|
|
563
|
+
return function chunkSigner(authHeaders, credentials) {
|
|
444
564
|
const seed = seedOf(authHeaders);
|
|
445
|
-
const key =
|
|
565
|
+
const key = getSigningKey(credentials.secretAccessKey, seed.date, seed.region, seed.service);
|
|
446
566
|
let previous = seed.signature;
|
|
447
|
-
const sign = (data) => previous = hmacHex(key, chunkStringToSign(seed.datetime, seed.scope, previous,
|
|
567
|
+
const sign = (data) => previous = hmacHex(key, chunkStringToSign(seed.datetime, seed.scope, previous, hexHash(data)));
|
|
448
568
|
return {
|
|
449
569
|
chunk: (data) => data.length === 0 ? data : frameChunk(sign(data), data),
|
|
450
|
-
// a zero-length chunk would end the upload; it is not sent
|
|
451
570
|
end(trailers) {
|
|
571
|
+
const text = trailers === undefined ? undefined : canonicalTrailers(trailers);
|
|
452
572
|
const signature = sign(new Uint8Array(0));
|
|
453
|
-
if (
|
|
454
|
-
|
|
455
|
-
|
|
573
|
+
if (text === undefined) {
|
|
574
|
+
return frameEnd(signature);
|
|
575
|
+
}
|
|
576
|
+
const trailerSignature = hmacHex(key, trailerStringToSign(seed.datetime, seed.scope, signature, hexHash(text)));
|
|
456
577
|
return frameEnd(signature, text, trailerSignature);
|
|
457
578
|
}
|
|
458
579
|
};
|
|
@@ -462,16 +583,20 @@ function createChunkSigner({ hexHash: hexHash2, hmacHex, getSigningKey: getSigni
|
|
|
462
583
|
// src/events.js
|
|
463
584
|
var crcTable;
|
|
464
585
|
function crc32(bytes, start, end) {
|
|
465
|
-
if (crcTable ===
|
|
586
|
+
if (crcTable === undefined) {
|
|
466
587
|
crcTable = new Int32Array(256);
|
|
467
|
-
for (let n = 0;
|
|
588
|
+
for (let n = 0;n < 256; n++) {
|
|
468
589
|
let c = n;
|
|
469
|
-
for (let k = 0;
|
|
590
|
+
for (let k = 0;k < 8; k++) {
|
|
591
|
+
c = c & 1 ? 3988292384 ^ c >>> 1 : c >>> 1;
|
|
592
|
+
}
|
|
470
593
|
crcTable[n] = c;
|
|
471
594
|
}
|
|
472
595
|
}
|
|
473
596
|
let crc = -1;
|
|
474
|
-
for (let i = start;
|
|
597
|
+
for (let i = start;i < end; i++) {
|
|
598
|
+
crc = crcTable[(crc ^ bytes[i]) & 255] ^ crc >>> 8;
|
|
599
|
+
}
|
|
475
600
|
return ~crc >>> 0;
|
|
476
601
|
}
|
|
477
602
|
function dateHeader(ms) {
|
|
@@ -497,7 +622,9 @@ function frameEvent(dateBytes, signatureHex, inner) {
|
|
|
497
622
|
out[at++] = 6;
|
|
498
623
|
view.setUint16(at, 32);
|
|
499
624
|
at += 2;
|
|
500
|
-
for (let i = 0;
|
|
625
|
+
for (let i = 0;i < 32; i++) {
|
|
626
|
+
out[at + i] = parseInt(signatureHex.slice(2 * i, 2 * i + 2), 16);
|
|
627
|
+
}
|
|
501
628
|
at += 32;
|
|
502
629
|
out.set(inner, at);
|
|
503
630
|
view.setUint32(out.length - 4, crc32(out, 0, out.length - 4));
|
|
@@ -511,20 +638,21 @@ ${headersHash}
|
|
|
511
638
|
${payloadHash}`;
|
|
512
639
|
var eventScope = (ms, region, service) => {
|
|
513
640
|
const datetime = amzDatetime(ms);
|
|
514
|
-
return {
|
|
641
|
+
return {
|
|
642
|
+
datetime,
|
|
643
|
+
scope: `${datetime.slice(0, 8)}/${region}/${service}/aws4_request`,
|
|
644
|
+
date: datetime.slice(0, 8)
|
|
645
|
+
};
|
|
515
646
|
};
|
|
516
|
-
function createEventSigner({ hexHash
|
|
517
|
-
return function
|
|
647
|
+
function createEventSigner({ hexHash, hmacHex, getSigningKey }) {
|
|
648
|
+
return function eventSigner(authHeaders, credentials) {
|
|
518
649
|
const seed = seedOf(authHeaders);
|
|
519
650
|
let previous = seed.signature;
|
|
520
651
|
return {
|
|
521
652
|
sign(message, now = Date.now()) {
|
|
522
653
|
const { datetime, scope, date } = eventScope(now, seed.region, seed.service);
|
|
523
654
|
const header = dateHeader(now);
|
|
524
|
-
previous = hmacHex(
|
|
525
|
-
getSigningKey2(credentials.secretAccessKey, date, seed.region, seed.service),
|
|
526
|
-
eventStringToSign(datetime, scope, previous, hexHash2(header), hexHash2(message))
|
|
527
|
-
);
|
|
655
|
+
previous = hmacHex(getSigningKey(credentials.secretAccessKey, date, seed.region, seed.service), eventStringToSign(datetime, scope, previous, hexHash(header), hexHash(message)));
|
|
528
656
|
return frameEvent(header, previous, message);
|
|
529
657
|
}
|
|
530
658
|
};
|
|
@@ -532,10 +660,7 @@ function createEventSigner({ hexHash: hexHash2, hmacHex, getSigningKey: getSigni
|
|
|
532
660
|
}
|
|
533
661
|
|
|
534
662
|
// src/bun.js
|
|
535
|
-
var bun =
|
|
536
|
-
/** @type {any} */
|
|
537
|
-
globalThis.Bun
|
|
538
|
-
);
|
|
663
|
+
var bun = globalThis.Bun;
|
|
539
664
|
var baseKey;
|
|
540
665
|
var base;
|
|
541
666
|
var hmac = (key, data) => crypto2.createHmac("sha256", key).update(data).digest();
|