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/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,20 +192,21 @@ 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
|
-
const {
|
|
208
|
+
const { url, signHeaders } = request;
|
|
209
|
+
const method = request.method.toUpperCase();
|
|
160
210
|
const region = request.region ?? "";
|
|
161
211
|
const service = request.service ?? "s3";
|
|
162
212
|
const withHash = service === "s3" || request.unsignedPayload === true;
|
|
@@ -164,7 +214,7 @@ function prepare(request, credentials, payloadHash, scheme = symmetric) {
|
|
|
164
214
|
const datetime = amzDatetime(request.now ?? Date.now());
|
|
165
215
|
const date = datetime.slice(0, 8);
|
|
166
216
|
const headers = withHash ? { "x-amz-date": datetime, "x-amz-content-sha256": payloadHash } : { "x-amz-date": datetime };
|
|
167
|
-
const extraNames = signHeaders ===
|
|
217
|
+
const extraNames = signHeaders === undefined ? [] : Object.keys(signHeaders);
|
|
168
218
|
let canonicalHeaders;
|
|
169
219
|
let signedHeaders;
|
|
170
220
|
if (extraNames.length === 0 && !sessionToken) {
|
|
@@ -183,10 +233,7 @@ x-amz-date:${datetime}
|
|
|
183
233
|
insert(names, values, "x-amz-security-token", sessionToken.trim());
|
|
184
234
|
}
|
|
185
235
|
for (const name of extraNames) {
|
|
186
|
-
const value =
|
|
187
|
-
/** @type {Record<string, string>} */
|
|
188
|
-
signHeaders[name]
|
|
189
|
-
);
|
|
236
|
+
const value = signHeaders[name];
|
|
190
237
|
const lowerName = signHeaderName(name, value);
|
|
191
238
|
headers[lowerName] = value;
|
|
192
239
|
insert(names, values, lowerName, headerValue(value));
|
|
@@ -204,12 +251,16 @@ x-amz-date:${datetime}
|
|
|
204
251
|
if (j === nBase || i < names.length && names[i] <= baseNames[j]) {
|
|
205
252
|
name = names[i];
|
|
206
253
|
value = values[i++];
|
|
207
|
-
if (j < nBase && name === baseNames[j])
|
|
254
|
+
if (j < nBase && name === baseNames[j]) {
|
|
255
|
+
j++;
|
|
256
|
+
}
|
|
208
257
|
} else {
|
|
209
258
|
name = baseNames[j];
|
|
210
259
|
value = baseValues[j++];
|
|
211
260
|
}
|
|
212
|
-
if (name === "x-amz-content-sha256")
|
|
261
|
+
if (name === "x-amz-content-sha256") {
|
|
262
|
+
payloadHash = value;
|
|
263
|
+
}
|
|
213
264
|
canonicalHeaders += `${name}:${value}
|
|
214
265
|
`;
|
|
215
266
|
signedHeaders += signedHeaders === "" ? name : ";" + name;
|
|
@@ -221,7 +272,17 @@ ${canonicalQuery(url.search)}
|
|
|
221
272
|
${canonicalHeaders}
|
|
222
273
|
${signedHeaders}
|
|
223
274
|
${payloadHash}`;
|
|
224
|
-
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
|
+
};
|
|
225
286
|
}
|
|
226
287
|
var stringToSign = (prepared, canonicalRequestHash) => `${prepared.algorithm}
|
|
227
288
|
${prepared.datetime}
|
|
@@ -231,24 +292,28 @@ function authorize(prepared, accessKeyId, signature) {
|
|
|
231
292
|
prepared.headers.authorization = `${prepared.algorithm} Credential=${accessKeyId}/${prepared.credentialScope}, SignedHeaders=${prepared.signedHeaders}, Signature=${signature}`;
|
|
232
293
|
return prepared.headers;
|
|
233
294
|
}
|
|
234
|
-
function createKeys(
|
|
235
|
-
const signingKeys =
|
|
236
|
-
const maxSigningKeys =
|
|
295
|
+
function createKeys(hmac) {
|
|
296
|
+
const signingKeys = new Map;
|
|
297
|
+
const maxSigningKeys = 1000;
|
|
237
298
|
let lastSecret;
|
|
238
299
|
let lastDate;
|
|
239
300
|
let lastRegion;
|
|
240
301
|
let lastService;
|
|
241
302
|
let lastKey;
|
|
242
|
-
return function
|
|
243
|
-
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
|
+
}
|
|
244
307
|
const cacheKey = `${date}
|
|
245
308
|
${region}
|
|
246
309
|
${service}
|
|
247
310
|
${secretAccessKey}`;
|
|
248
311
|
let signingKey = signingKeys.get(cacheKey);
|
|
249
|
-
if (signingKey ===
|
|
250
|
-
signingKey =
|
|
251
|
-
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
|
+
}
|
|
252
317
|
signingKeys.set(cacheKey, signingKey);
|
|
253
318
|
}
|
|
254
319
|
lastSecret = secretAccessKey;
|
|
@@ -259,25 +324,28 @@ ${secretAccessKey}`;
|
|
|
259
324
|
return signingKey;
|
|
260
325
|
};
|
|
261
326
|
}
|
|
262
|
-
function createSigner({ hexHash
|
|
263
|
-
return function
|
|
264
|
-
const prepared = prepare(request, credentials, payloadHashOf(request,
|
|
265
|
-
return authorize(
|
|
266
|
-
prepared,
|
|
267
|
-
credentials.accessKeyId,
|
|
268
|
-
hmacHex2(getSigningKey2(credentials.secretAccessKey, prepared.date, prepared.region, prepared.service), stringToSign(prepared, hexHash2(prepared.canonicalRequest)))
|
|
269
|
-
);
|
|
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))));
|
|
270
331
|
};
|
|
271
332
|
}
|
|
272
333
|
|
|
273
334
|
// src/presign.js
|
|
274
335
|
var encodeQueryPart = (text) => encodeURIComponent(text).replace(/[!'()*]/g, (c) => "%" + c.charCodeAt(0).toString(16).toUpperCase());
|
|
275
336
|
function preparePresign(request, credentials, payloadHash, scheme = symmetric, extra = "") {
|
|
276
|
-
const {
|
|
277
|
-
|
|
278
|
-
if (url.
|
|
337
|
+
const { url, signHeaders } = request;
|
|
338
|
+
const method = request.method.toUpperCase();
|
|
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
|
+
}
|
|
279
345
|
const expires = request.expires ?? 3600;
|
|
280
|
-
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
|
+
}
|
|
281
349
|
const region = request.region ?? "";
|
|
282
350
|
const service = request.service ?? "s3";
|
|
283
351
|
const datetime = amzDatetime(request.now ?? Date.now());
|
|
@@ -285,13 +353,21 @@ function preparePresign(request, credentials, payloadHash, scheme = symmetric, e
|
|
|
285
353
|
const credentialScope = scheme.scope(date, region, service);
|
|
286
354
|
const names = ["host"];
|
|
287
355
|
const values = [url.host];
|
|
288
|
-
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
|
+
}
|
|
289
361
|
let canonicalHeaders = "";
|
|
290
|
-
for (let i = 0;
|
|
362
|
+
for (let i = 0;i < names.length; i++) {
|
|
363
|
+
canonicalHeaders += `${names[i]}:${values[i]}
|
|
291
364
|
`;
|
|
365
|
+
}
|
|
292
366
|
const signedHeaders = names.join(";");
|
|
293
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)}`;
|
|
294
|
-
if (credentials.sessionToken)
|
|
368
|
+
if (credentials.sessionToken) {
|
|
369
|
+
auth += `&X-Amz-Security-Token=${encodeQueryPart(credentials.sessionToken)}`;
|
|
370
|
+
}
|
|
295
371
|
auth += extra;
|
|
296
372
|
const query = url.search.length > 1 ? url.search + "&" + auth : "?" + auth;
|
|
297
373
|
const hash = service === "s3" || request.unsignedPayload ? "UNSIGNED-PAYLOAD" : payloadHash;
|
|
@@ -301,77 +377,105 @@ ${canonicalQuery(query)}
|
|
|
301
377
|
${canonicalHeaders}
|
|
302
378
|
${signedHeaders}
|
|
303
379
|
${hash}`;
|
|
304
|
-
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
|
+
};
|
|
305
392
|
}
|
|
306
393
|
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
|
-
hmacHex2(getSigningKey2(credentials.secretAccessKey, prepared.date, prepared.region, prepared.service), stringToSign(prepared, hexHash2(prepared.canonicalRequest)))
|
|
313
|
-
);
|
|
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))));
|
|
314
398
|
};
|
|
315
399
|
}
|
|
316
400
|
|
|
317
401
|
// src/v4a.js
|
|
318
|
-
var asymmetric = {
|
|
402
|
+
var asymmetric = {
|
|
403
|
+
algorithm: "AWS4-ECDSA-P256-SHA256",
|
|
404
|
+
scope: (date, _region, service) => `${date}/${service}/aws4_request`
|
|
405
|
+
};
|
|
319
406
|
function regionSetOf(request) {
|
|
320
407
|
const regionSet = request.regionSet;
|
|
321
|
-
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
|
+
}
|
|
322
411
|
return regionSet;
|
|
323
412
|
}
|
|
324
|
-
var withRegionSet = (request) => ({
|
|
413
|
+
var withRegionSet = (request) => ({
|
|
414
|
+
...request,
|
|
415
|
+
signHeaders: { ...request.signHeaders, "x-amz-region-set": regionSetOf(request) }
|
|
416
|
+
});
|
|
325
417
|
var regionSetQuery = (request) => `&X-Amz-Region-Set=${encodeQueryPart(regionSetOf(request))}`;
|
|
326
|
-
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`;
|
|
327
419
|
function scalarFrom(k) {
|
|
328
420
|
const nMinusTwo = 0xffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc63254fn;
|
|
329
421
|
let c = 0n;
|
|
330
|
-
for (let i = 0;
|
|
331
|
-
|
|
422
|
+
for (let i = 0;i < 32; i++) {
|
|
423
|
+
c = c << 8n | BigInt(k[i]);
|
|
424
|
+
}
|
|
425
|
+
if (c > nMinusTwo) {
|
|
426
|
+
return;
|
|
427
|
+
}
|
|
332
428
|
c += 1n;
|
|
333
429
|
const d = new Uint8Array(32);
|
|
334
|
-
for (let i = 31;
|
|
430
|
+
for (let i = 31;i >= 0; i--, c >>= 8n) {
|
|
431
|
+
d[i] = Number(c & 0xffn);
|
|
432
|
+
}
|
|
335
433
|
return d;
|
|
336
434
|
}
|
|
337
|
-
function deriveP256(
|
|
338
|
-
for (let counter = 1;
|
|
339
|
-
const d = scalarFrom(
|
|
340
|
-
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
|
+
}
|
|
341
441
|
}
|
|
342
442
|
throw new Error("no SigV4a key for these credentials");
|
|
343
443
|
}
|
|
344
|
-
var signers = /* @__PURE__ */ new WeakMap
|
|
345
|
-
function createAsymmetric(
|
|
346
|
-
let sign = signers.get(
|
|
347
|
-
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
|
+
}
|
|
348
450
|
return sign;
|
|
349
451
|
}
|
|
350
|
-
function signerFor(
|
|
351
|
-
const keys =
|
|
452
|
+
function signerFor(hmac, ecdsa) {
|
|
453
|
+
const keys = new Map;
|
|
352
454
|
return function sign(credentials, text) {
|
|
353
455
|
const id = `${credentials.accessKeyId}/${credentials.secretAccessKey}`;
|
|
354
456
|
let key = keys.get(id);
|
|
355
|
-
if (key ===
|
|
356
|
-
key =
|
|
357
|
-
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
|
+
}
|
|
358
462
|
keys.set(id, key);
|
|
359
463
|
}
|
|
360
|
-
return
|
|
464
|
+
return ecdsa.sign(key, text);
|
|
361
465
|
};
|
|
362
466
|
}
|
|
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,
|
|
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))));
|
|
368
472
|
};
|
|
369
473
|
}
|
|
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,
|
|
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))));
|
|
375
479
|
};
|
|
376
480
|
}
|
|
377
481
|
|
|
@@ -383,17 +487,27 @@ var ecdsa = {
|
|
|
383
487
|
const ecdh = crypto.createECDH("prime256v1");
|
|
384
488
|
ecdh.setPrivateKey(d);
|
|
385
489
|
const point = ecdh.getPublicKey();
|
|
386
|
-
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
|
+
});
|
|
387
500
|
},
|
|
388
501
|
sign: (key, text) => crypto.sign("sha256", text, { key, dsaEncoding: "der" }).toString("hex")
|
|
389
502
|
};
|
|
390
503
|
|
|
391
504
|
// src/chunks.js
|
|
392
|
-
var utf8 = /* @__PURE__ */ new TextEncoder
|
|
505
|
+
var utf8 = /* @__PURE__ */ new TextEncoder;
|
|
393
506
|
function seedOf(authHeaders) {
|
|
394
507
|
const auth = authHeaders.authorization;
|
|
395
|
-
if (typeof auth !== "string" || !auth.startsWith("AWS4-HMAC-SHA256 "))
|
|
508
|
+
if (typeof auth !== "string" || !auth.startsWith("AWS4-HMAC-SHA256 ")) {
|
|
396
509
|
throw new TypeError("authHeaders must be the headers getAuthHeaders returned (a SigV4a signature cannot start a chunk or event stream)");
|
|
510
|
+
}
|
|
397
511
|
const scope = auth.slice(auth.indexOf("Credential=") + 11, auth.indexOf(",")).split("/");
|
|
398
512
|
return {
|
|
399
513
|
signature: auth.slice(auth.lastIndexOf("Signature=") + 10),
|
|
@@ -416,43 +530,49 @@ ${scope}
|
|
|
416
530
|
${previous}
|
|
417
531
|
${trailerHash}`;
|
|
418
532
|
function canonicalTrailers(trailers) {
|
|
419
|
-
return Object.keys(trailers).map((name) =>
|
|
533
|
+
return Object.keys(trailers).map((name) => {
|
|
534
|
+
const value = String(trailers[name]);
|
|
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
|
+
}
|
|
538
|
+
return [name.toLowerCase(), value.trim()];
|
|
539
|
+
}).sort((a, b) => a[0] < b[0] ? -1 : a[0] > b[0] ? 1 : 0).map(([name, value]) => `${name}:${value}
|
|
420
540
|
`).join("");
|
|
421
541
|
}
|
|
422
|
-
function frameChunk(signature,
|
|
423
|
-
const head = utf8.encode(`${
|
|
542
|
+
function frameChunk(signature, data) {
|
|
543
|
+
const head = utf8.encode(`${data.length.toString(16)};chunk-signature=${signature}\r
|
|
424
544
|
`);
|
|
425
|
-
const out = new Uint8Array(head.length +
|
|
545
|
+
const out = new Uint8Array(head.length + data.length + 2);
|
|
426
546
|
out.set(head);
|
|
427
|
-
out.set(
|
|
547
|
+
out.set(data, head.length);
|
|
428
548
|
out[out.length - 2] = 13;
|
|
429
549
|
out[out.length - 1] = 10;
|
|
430
550
|
return out;
|
|
431
551
|
}
|
|
432
552
|
function frameEnd(signature, trailers, trailerSignature) {
|
|
433
|
-
return utf8.encode(
|
|
434
|
-
trailers === void 0 ? `0;chunk-signature=${signature}\r
|
|
553
|
+
return utf8.encode(trailers === undefined ? `0;chunk-signature=${signature}\r
|
|
435
554
|
\r
|
|
436
555
|
` : `0;chunk-signature=${signature}\r
|
|
437
|
-
${trailers.replace(/\n/g,
|
|
556
|
+
${trailers.replace(/\n/g, `\r
|
|
557
|
+
`)}x-amz-trailer-signature:${trailerSignature}\r
|
|
438
558
|
\r
|
|
439
|
-
`
|
|
440
|
-
);
|
|
559
|
+
`);
|
|
441
560
|
}
|
|
442
|
-
function createChunkSigner({ hexHash
|
|
443
|
-
return function
|
|
561
|
+
function createChunkSigner({ hexHash, hmacHex, getSigningKey }) {
|
|
562
|
+
return function chunkSigner(authHeaders, credentials) {
|
|
444
563
|
const seed = seedOf(authHeaders);
|
|
445
|
-
const key =
|
|
564
|
+
const key = getSigningKey(credentials.secretAccessKey, seed.date, seed.region, seed.service);
|
|
446
565
|
let previous = seed.signature;
|
|
447
|
-
const sign = (
|
|
566
|
+
const sign = (data) => previous = hmacHex(key, chunkStringToSign(seed.datetime, seed.scope, previous, hexHash(data)));
|
|
448
567
|
return {
|
|
449
|
-
chunk: (
|
|
450
|
-
// a zero-length chunk would end the upload; it is not sent
|
|
568
|
+
chunk: (data) => data.length === 0 ? data : frameChunk(sign(data), data),
|
|
451
569
|
end(trailers) {
|
|
570
|
+
const text = trailers === undefined ? undefined : canonicalTrailers(trailers);
|
|
452
571
|
const signature = sign(new Uint8Array(0));
|
|
453
|
-
if (
|
|
454
|
-
|
|
455
|
-
|
|
572
|
+
if (text === undefined) {
|
|
573
|
+
return frameEnd(signature);
|
|
574
|
+
}
|
|
575
|
+
const trailerSignature = hmacHex(key, trailerStringToSign(seed.datetime, seed.scope, signature, hexHash(text)));
|
|
456
576
|
return frameEnd(signature, text, trailerSignature);
|
|
457
577
|
}
|
|
458
578
|
};
|
|
@@ -462,16 +582,20 @@ function createChunkSigner({ hexHash: hexHash2, hmacHex: hmacHex2, getSigningKey
|
|
|
462
582
|
// src/events.js
|
|
463
583
|
var crcTable;
|
|
464
584
|
function crc32(bytes, start, end) {
|
|
465
|
-
if (crcTable ===
|
|
585
|
+
if (crcTable === undefined) {
|
|
466
586
|
crcTable = new Int32Array(256);
|
|
467
|
-
for (let n = 0;
|
|
587
|
+
for (let n = 0;n < 256; n++) {
|
|
468
588
|
let c = n;
|
|
469
|
-
for (let k = 0;
|
|
589
|
+
for (let k = 0;k < 8; k++) {
|
|
590
|
+
c = c & 1 ? 3988292384 ^ c >>> 1 : c >>> 1;
|
|
591
|
+
}
|
|
470
592
|
crcTable[n] = c;
|
|
471
593
|
}
|
|
472
594
|
}
|
|
473
595
|
let crc = -1;
|
|
474
|
-
for (let i = start;
|
|
596
|
+
for (let i = start;i < end; i++) {
|
|
597
|
+
crc = crcTable[(crc ^ bytes[i]) & 255] ^ crc >>> 8;
|
|
598
|
+
}
|
|
475
599
|
return ~crc >>> 0;
|
|
476
600
|
}
|
|
477
601
|
function dateHeader(ms) {
|
|
@@ -482,9 +606,9 @@ function dateHeader(ms) {
|
|
|
482
606
|
new DataView(out.buffer).setBigInt64(7, BigInt(Math.floor(ms)));
|
|
483
607
|
return out;
|
|
484
608
|
}
|
|
485
|
-
function frameEvent(dateBytes, signatureHex,
|
|
609
|
+
function frameEvent(dateBytes, signatureHex, inner) {
|
|
486
610
|
const headersLength = dateBytes.length + 52;
|
|
487
|
-
const out = new Uint8Array(16 + headersLength +
|
|
611
|
+
const out = new Uint8Array(16 + headersLength + inner.length);
|
|
488
612
|
const view = new DataView(out.buffer);
|
|
489
613
|
view.setUint32(0, out.length);
|
|
490
614
|
view.setUint32(4, headersLength);
|
|
@@ -497,9 +621,11 @@ function frameEvent(dateBytes, signatureHex, inner2) {
|
|
|
497
621
|
out[at++] = 6;
|
|
498
622
|
view.setUint16(at, 32);
|
|
499
623
|
at += 2;
|
|
500
|
-
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
|
+
}
|
|
501
627
|
at += 32;
|
|
502
|
-
out.set(
|
|
628
|
+
out.set(inner, at);
|
|
503
629
|
view.setUint32(out.length - 4, crc32(out, 0, out.length - 4));
|
|
504
630
|
return out;
|
|
505
631
|
}
|
|
@@ -511,20 +637,21 @@ ${headersHash}
|
|
|
511
637
|
${payloadHash}`;
|
|
512
638
|
var eventScope = (ms, region, service) => {
|
|
513
639
|
const datetime = amzDatetime(ms);
|
|
514
|
-
return {
|
|
640
|
+
return {
|
|
641
|
+
datetime,
|
|
642
|
+
scope: `${datetime.slice(0, 8)}/${region}/${service}/aws4_request`,
|
|
643
|
+
date: datetime.slice(0, 8)
|
|
644
|
+
};
|
|
515
645
|
};
|
|
516
|
-
function createEventSigner({ hexHash
|
|
517
|
-
return function
|
|
646
|
+
function createEventSigner({ hexHash, hmacHex, getSigningKey }) {
|
|
647
|
+
return function eventSigner(authHeaders, credentials) {
|
|
518
648
|
const seed = seedOf(authHeaders);
|
|
519
649
|
let previous = seed.signature;
|
|
520
650
|
return {
|
|
521
651
|
sign(message, now = Date.now()) {
|
|
522
652
|
const { datetime, scope, date } = eventScope(now, seed.region, seed.service);
|
|
523
653
|
const header = dateHeader(now);
|
|
524
|
-
previous =
|
|
525
|
-
getSigningKey2(credentials.secretAccessKey, date, seed.region, seed.service),
|
|
526
|
-
eventStringToSign(datetime, scope, previous, hexHash2(header), hexHash2(message))
|
|
527
|
-
);
|
|
654
|
+
previous = hmacHex(getSigningKey(credentials.secretAccessKey, date, seed.region, seed.service), eventStringToSign(datetime, scope, previous, hexHash(header), hexHash(message)));
|
|
528
655
|
return frameEvent(header, previous, message);
|
|
529
656
|
}
|
|
530
657
|
};
|
|
@@ -532,7 +659,7 @@ function createEventSigner({ hexHash: hexHash2, hmacHex: hmacHex2, getSigningKey
|
|
|
532
659
|
}
|
|
533
660
|
|
|
534
661
|
// src/node.js
|
|
535
|
-
var utf82 = /* @__PURE__ */ new TextEncoder
|
|
662
|
+
var utf82 = /* @__PURE__ */ new TextEncoder;
|
|
536
663
|
var maxData = 1024;
|
|
537
664
|
var inner = /* @__PURE__ */ new Uint8Array(64 + maxData);
|
|
538
665
|
var outer = /* @__PURE__ */ new Uint8Array(64 + 32);
|
|
@@ -545,14 +672,16 @@ function hmacHexOneShot(key, text) {
|
|
|
545
672
|
blockKey = key;
|
|
546
673
|
inner.fill(54, 0, 64);
|
|
547
674
|
outer.fill(92, 0, 64);
|
|
548
|
-
for (let i = 0;
|
|
549
|
-
inner[i]
|
|
550
|
-
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];
|
|
551
678
|
}
|
|
552
679
|
}
|
|
553
680
|
const end = 64 + utf82.encodeInto(text, data).written;
|
|
554
681
|
const hex = crypto2.hash("sha256", innerViews[end] ??= inner.subarray(0, end), "hex");
|
|
555
|
-
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
|
+
}
|
|
556
685
|
return crypto2.hash("sha256", outer, "hex");
|
|
557
686
|
}
|
|
558
687
|
var hmacHexStreaming = (key, text) => crypto2.createHmac("sha256", key).update(text).digest("hex");
|
|
@@ -560,9 +689,10 @@ var hmac = (key, text) => crypto2.createHmac("sha256", key).update(text).digest(
|
|
|
560
689
|
var oneShotWorks;
|
|
561
690
|
function probe() {
|
|
562
691
|
const key = hmac("probe", "key");
|
|
563
|
-
const text =
|
|
692
|
+
const text = `AWS4-HMAC-SHA256
|
|
693
|
+
20130524T000000Z`;
|
|
564
694
|
const works = hmacHexOneShot(key, text) === hmacHexStreaming(key, text);
|
|
565
|
-
blockKey =
|
|
695
|
+
blockKey = undefined;
|
|
566
696
|
return works;
|
|
567
697
|
}
|
|
568
698
|
var hmacHex = (key, text) => (oneShotWorks ??= probe()) && text.length * 3 <= maxData && key.length <= 64 ? hmacHexOneShot(key, text) : hmacHexStreaming(key, text);
|