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