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/src/web.js
CHANGED
|
@@ -3,41 +3,91 @@
|
|
|
3
3
|
import { payloadHashOf, prepare, stringToSign, authorize } from './base.js';
|
|
4
4
|
import { preparePresign, presignedUrl } from './presign.js';
|
|
5
5
|
import { asymmetric, withRegionSet, regionSetQuery, kdfInput, scalarFrom } from './v4a.js';
|
|
6
|
-
import {
|
|
6
|
+
import {
|
|
7
|
+
seedOf,
|
|
8
|
+
chunkStringToSign,
|
|
9
|
+
trailerStringToSign,
|
|
10
|
+
canonicalTrailers,
|
|
11
|
+
frameChunk,
|
|
12
|
+
frameEnd,
|
|
13
|
+
} from './chunks.js';
|
|
7
14
|
import { dateHeader, frameEvent, eventStringToSign, eventScope } from './events.js';
|
|
8
15
|
|
|
9
16
|
const subtle = /* @__PURE__ */ (() => globalThis.crypto.subtle)();
|
|
10
17
|
const utf8 = /* @__PURE__ */ new TextEncoder();
|
|
11
18
|
|
|
12
|
-
const hexOfByte = /* @__PURE__ */ Array.from({ length: 256 }, (_, i) =>
|
|
19
|
+
const hexOfByte = /* @__PURE__ */ Array.from({ length: 256 }, (_, i) =>
|
|
20
|
+
i.toString(16).padStart(2, '0'),
|
|
21
|
+
);
|
|
22
|
+
/** @param {ArrayBuffer | Uint8Array} buffer */
|
|
13
23
|
function toHex(buffer) {
|
|
14
24
|
const bytes = new Uint8Array(buffer);
|
|
15
25
|
let out = '';
|
|
16
|
-
for (let i = 0; i < bytes.length; i++)
|
|
26
|
+
for (let i = 0; i < bytes.length; i++) {
|
|
27
|
+
out += hexOfByte[/** @type {number} */ (bytes[i])];
|
|
28
|
+
}
|
|
17
29
|
return out;
|
|
18
30
|
}
|
|
19
31
|
|
|
20
|
-
|
|
21
|
-
const
|
|
32
|
+
/** @param {string | Uint8Array} data */
|
|
33
|
+
const hexHash = async (data) =>
|
|
34
|
+
toHex(
|
|
35
|
+
await subtle.digest(
|
|
36
|
+
'SHA-256',
|
|
37
|
+
typeof data === 'string' ? utf8.encode(data) : /** @type {Uint8Array<ArrayBuffer>} */ (data),
|
|
38
|
+
),
|
|
39
|
+
);
|
|
40
|
+
/** @param {Uint8Array<ArrayBuffer> | ArrayBuffer} raw */
|
|
41
|
+
const importKey = (raw) =>
|
|
42
|
+
subtle.importKey('raw', raw, { name: 'HMAC', hash: 'SHA-256' }, false, ['sign']);
|
|
22
43
|
// the next key in the derivation chain: the HMAC of data, as a key
|
|
44
|
+
/**
|
|
45
|
+
* @param {CryptoKey} key
|
|
46
|
+
* @param {string} data
|
|
47
|
+
*/
|
|
23
48
|
const deriveKey = async (key, data) => importKey(await subtle.sign('HMAC', key, utf8.encode(data)));
|
|
24
49
|
|
|
50
|
+
/** @type {Map<string, CryptoKey>} */
|
|
25
51
|
const signingKeys = new Map();
|
|
26
52
|
const maxSigningKeys = 1000;
|
|
53
|
+
/** @type {string | undefined} */
|
|
27
54
|
let lastSecret;
|
|
55
|
+
/** @type {string | undefined} */
|
|
28
56
|
let lastDate;
|
|
57
|
+
/** @type {string | undefined} */
|
|
29
58
|
let lastRegion;
|
|
59
|
+
/** @type {string | undefined} */
|
|
30
60
|
let lastService;
|
|
61
|
+
/** @type {CryptoKey | undefined} */
|
|
31
62
|
let lastKey;
|
|
32
63
|
|
|
64
|
+
/**
|
|
65
|
+
* @param {string} secretAccessKey
|
|
66
|
+
* @param {string} date
|
|
67
|
+
* @param {string} region
|
|
68
|
+
* @param {string} service
|
|
69
|
+
* @returns {Promise<CryptoKey>}
|
|
70
|
+
*/
|
|
33
71
|
async function getSigningKey(secretAccessKey, date, region, service) {
|
|
34
|
-
if (
|
|
72
|
+
if (
|
|
73
|
+
secretAccessKey === lastSecret &&
|
|
74
|
+
date === lastDate &&
|
|
75
|
+
region === lastRegion &&
|
|
76
|
+
service === lastService
|
|
77
|
+
) {
|
|
78
|
+
return /** @type {CryptoKey} */ (lastKey);
|
|
79
|
+
}
|
|
35
80
|
const cacheKey = `${date}\n${region}\n${service}\n${secretAccessKey}`;
|
|
36
81
|
let signingKey = signingKeys.get(cacheKey);
|
|
37
82
|
if (signingKey === undefined) {
|
|
38
83
|
const dateKey = await deriveKey(await importKey(utf8.encode('AWS4' + secretAccessKey)), date);
|
|
39
|
-
signingKey = await deriveKey(
|
|
40
|
-
|
|
84
|
+
signingKey = await deriveKey(
|
|
85
|
+
await deriveKey(await deriveKey(dateKey, region), service),
|
|
86
|
+
'aws4_request',
|
|
87
|
+
);
|
|
88
|
+
if (signingKeys.size >= maxSigningKeys) {
|
|
89
|
+
signingKeys.delete(/** @type {string} */ (signingKeys.keys().next().value));
|
|
90
|
+
}
|
|
41
91
|
signingKeys.set(cacheKey, signingKey);
|
|
42
92
|
}
|
|
43
93
|
lastSecret = secretAccessKey;
|
|
@@ -48,44 +98,88 @@ async function getSigningKey(secretAccessKey, date, region, service) {
|
|
|
48
98
|
return signingKey;
|
|
49
99
|
}
|
|
50
100
|
|
|
101
|
+
/**
|
|
102
|
+
* @param {import('./base.js').Credentials} credentials
|
|
103
|
+
* @param {{ date: string, region: string, service: string }} prepared
|
|
104
|
+
* @param {string} text
|
|
105
|
+
*/
|
|
51
106
|
const signSymmetric = async (credentials, prepared, text) =>
|
|
52
|
-
toHex(
|
|
107
|
+
toHex(
|
|
108
|
+
await subtle.sign(
|
|
109
|
+
'HMAC',
|
|
110
|
+
await getSigningKey(
|
|
111
|
+
credentials.secretAccessKey,
|
|
112
|
+
prepared.date,
|
|
113
|
+
prepared.region,
|
|
114
|
+
prepared.service,
|
|
115
|
+
),
|
|
116
|
+
utf8.encode(text),
|
|
117
|
+
),
|
|
118
|
+
);
|
|
53
119
|
|
|
54
120
|
// SigV4a: the derived scalar goes in as a PKCS#8 private key without the public point, which WebCrypto computes itself
|
|
55
121
|
const pkcs8 = /* @__PURE__ */ Uint8Array.from([
|
|
56
|
-
0x30, 0x41, 0x02, 0x01, 0x00, 0x30, 0x13, 0x06, 0x07, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x02, 0x01,
|
|
57
|
-
|
|
122
|
+
0x30, 0x41, 0x02, 0x01, 0x00, 0x30, 0x13, 0x06, 0x07, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x02, 0x01,
|
|
123
|
+
0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x03, 0x01, 0x07, 0x04, 0x27, 0x30, 0x25, 0x02, 0x01,
|
|
124
|
+
0x01, 0x04, 0x20,
|
|
58
125
|
]);
|
|
126
|
+
/** @type {Map<string, CryptoKey>} */
|
|
59
127
|
const asymmetricKeys = new Map();
|
|
128
|
+
/** @param {import('./base.js').Credentials} credentials */
|
|
60
129
|
async function getAsymmetricKey({ accessKeyId, secretAccessKey }) {
|
|
61
130
|
const id = `${accessKeyId}/${secretAccessKey}`;
|
|
62
131
|
let key = asymmetricKeys.get(id);
|
|
63
132
|
if (key === undefined) {
|
|
64
133
|
const root = await importKey(utf8.encode('AWS4A' + secretAccessKey));
|
|
65
134
|
for (let counter = 1; key === undefined; counter++) {
|
|
66
|
-
if (counter > 127)
|
|
67
|
-
|
|
135
|
+
if (counter > 127) {
|
|
136
|
+
throw new Error('no SigV4a key for these credentials');
|
|
137
|
+
}
|
|
138
|
+
const d = scalarFrom(
|
|
139
|
+
new Uint8Array(
|
|
140
|
+
await subtle.sign('HMAC', root, utf8.encode(kdfInput(accessKeyId, counter))),
|
|
141
|
+
),
|
|
142
|
+
);
|
|
68
143
|
if (d !== undefined) {
|
|
69
144
|
const der = new Uint8Array(pkcs8.length + 32);
|
|
70
145
|
der.set(pkcs8);
|
|
71
146
|
der.set(d, pkcs8.length);
|
|
72
|
-
key = await subtle.importKey('pkcs8', der, { name: 'ECDSA', namedCurve: 'P-256' }, false, [
|
|
147
|
+
key = await subtle.importKey('pkcs8', der, { name: 'ECDSA', namedCurve: 'P-256' }, false, [
|
|
148
|
+
'sign',
|
|
149
|
+
]);
|
|
73
150
|
}
|
|
74
151
|
}
|
|
75
|
-
if (asymmetricKeys.size >= 1000)
|
|
152
|
+
if (asymmetricKeys.size >= 1000) {
|
|
153
|
+
asymmetricKeys.delete(/** @type {string} */ (asymmetricKeys.keys().next().value));
|
|
154
|
+
}
|
|
76
155
|
asymmetricKeys.set(id, key);
|
|
77
156
|
}
|
|
78
157
|
return key;
|
|
79
158
|
}
|
|
80
159
|
// r and s as DER integers: leading zeros dropped, a zero byte in front when the top bit is set
|
|
160
|
+
/** @param {Uint8Array} bytes */
|
|
81
161
|
function derInteger(bytes) {
|
|
82
162
|
let start = 0;
|
|
83
|
-
while (start < bytes.length - 1 && bytes[start] === 0)
|
|
163
|
+
while (start < bytes.length - 1 && bytes[start] === 0) {
|
|
164
|
+
start++;
|
|
165
|
+
}
|
|
84
166
|
const body = bytes.subarray(start);
|
|
85
|
-
return
|
|
167
|
+
return /** @type {number} */ (body[0]) & 0x80
|
|
168
|
+
? [0x02, body.length + 1, 0, ...body]
|
|
169
|
+
: [0x02, body.length, ...body];
|
|
86
170
|
}
|
|
171
|
+
/**
|
|
172
|
+
* @param {import('./base.js').Credentials} credentials
|
|
173
|
+
* @param {string} text
|
|
174
|
+
*/
|
|
87
175
|
async function signAsymmetric(credentials, text) {
|
|
88
|
-
const raw = new Uint8Array(
|
|
176
|
+
const raw = new Uint8Array(
|
|
177
|
+
await subtle.sign(
|
|
178
|
+
{ name: 'ECDSA', hash: 'SHA-256' },
|
|
179
|
+
await getAsymmetricKey(credentials),
|
|
180
|
+
utf8.encode(text),
|
|
181
|
+
),
|
|
182
|
+
);
|
|
89
183
|
const body = [...derInteger(raw.subarray(0, 32)), ...derInteger(raw.subarray(32))];
|
|
90
184
|
return toHex(Uint8Array.from([0x30, body.length, ...body]));
|
|
91
185
|
}
|
|
@@ -98,7 +192,15 @@ async function signAsymmetric(credentials, text) {
|
|
|
98
192
|
*/
|
|
99
193
|
export async function getAuthHeaders(request, credentials) {
|
|
100
194
|
const prepared = prepare(request, credentials, await payloadHashOf(request, hexHash));
|
|
101
|
-
return authorize(
|
|
195
|
+
return authorize(
|
|
196
|
+
prepared,
|
|
197
|
+
credentials.accessKeyId,
|
|
198
|
+
await signSymmetric(
|
|
199
|
+
credentials,
|
|
200
|
+
prepared,
|
|
201
|
+
stringToSign(prepared, await hexHash(prepared.canonicalRequest)),
|
|
202
|
+
),
|
|
203
|
+
);
|
|
102
204
|
}
|
|
103
205
|
|
|
104
206
|
/**
|
|
@@ -108,8 +210,20 @@ export async function getAuthHeaders(request, credentials) {
|
|
|
108
210
|
* @returns {Promise<import('./base.js').AuthHeaders>}
|
|
109
211
|
*/
|
|
110
212
|
export async function getAuthHeadersV4a(request, credentials) {
|
|
111
|
-
const prepared = prepare(
|
|
112
|
-
|
|
213
|
+
const prepared = prepare(
|
|
214
|
+
withRegionSet(request),
|
|
215
|
+
credentials,
|
|
216
|
+
await payloadHashOf(request, hexHash),
|
|
217
|
+
asymmetric,
|
|
218
|
+
);
|
|
219
|
+
return authorize(
|
|
220
|
+
prepared,
|
|
221
|
+
credentials.accessKeyId,
|
|
222
|
+
await signAsymmetric(
|
|
223
|
+
credentials,
|
|
224
|
+
stringToSign(prepared, await hexHash(prepared.canonicalRequest)),
|
|
225
|
+
),
|
|
226
|
+
);
|
|
113
227
|
}
|
|
114
228
|
|
|
115
229
|
/**
|
|
@@ -120,7 +234,14 @@ export async function getAuthHeadersV4a(request, credentials) {
|
|
|
120
234
|
*/
|
|
121
235
|
export async function presign(request, credentials) {
|
|
122
236
|
const prepared = preparePresign(request, credentials, await payloadHashOf(request, hexHash));
|
|
123
|
-
return presignedUrl(
|
|
237
|
+
return presignedUrl(
|
|
238
|
+
prepared,
|
|
239
|
+
await signSymmetric(
|
|
240
|
+
credentials,
|
|
241
|
+
prepared,
|
|
242
|
+
stringToSign(prepared, await hexHash(prepared.canonicalRequest)),
|
|
243
|
+
),
|
|
244
|
+
);
|
|
124
245
|
}
|
|
125
246
|
|
|
126
247
|
/**
|
|
@@ -130,10 +251,26 @@ export async function presign(request, credentials) {
|
|
|
130
251
|
* @returns {Promise<string>}
|
|
131
252
|
*/
|
|
132
253
|
export async function presignV4a(request, credentials) {
|
|
133
|
-
const prepared = preparePresign(
|
|
134
|
-
|
|
254
|
+
const prepared = preparePresign(
|
|
255
|
+
request,
|
|
256
|
+
credentials,
|
|
257
|
+
await payloadHashOf(request, hexHash),
|
|
258
|
+
asymmetric,
|
|
259
|
+
regionSetQuery(request),
|
|
260
|
+
);
|
|
261
|
+
return presignedUrl(
|
|
262
|
+
prepared,
|
|
263
|
+
await signAsymmetric(
|
|
264
|
+
credentials,
|
|
265
|
+
stringToSign(prepared, await hexHash(prepared.canonicalRequest)),
|
|
266
|
+
),
|
|
267
|
+
);
|
|
135
268
|
}
|
|
136
269
|
|
|
270
|
+
/**
|
|
271
|
+
* @param {CryptoKey} key
|
|
272
|
+
* @param {string} text
|
|
273
|
+
*/
|
|
137
274
|
const signWith = async (key, text) => toHex(await subtle.sign('HMAC', key, utf8.encode(text)));
|
|
138
275
|
|
|
139
276
|
/**
|
|
@@ -145,18 +282,40 @@ const signWith = async (key, text) => toHex(await subtle.sign('HMAC', key, utf8.
|
|
|
145
282
|
export function chunkSigner(authHeaders, credentials) {
|
|
146
283
|
const seed = seedOf(authHeaders);
|
|
147
284
|
let previous = seed.signature;
|
|
148
|
-
const keyPromise = getSigningKey(
|
|
285
|
+
const keyPromise = getSigningKey(
|
|
286
|
+
credentials.secretAccessKey,
|
|
287
|
+
seed.date,
|
|
288
|
+
seed.region,
|
|
289
|
+
seed.service,
|
|
290
|
+
);
|
|
149
291
|
// chunks are signed one after the other: a call waits for the one before it
|
|
150
292
|
/** @type {Promise<any>} */
|
|
151
293
|
let turn = Promise.resolve();
|
|
152
|
-
|
|
294
|
+
/** @param {Uint8Array} data */
|
|
295
|
+
const sign = (data) =>
|
|
296
|
+
(turn = turn.then(
|
|
297
|
+
async () =>
|
|
298
|
+
(previous = await signWith(
|
|
299
|
+
await keyPromise,
|
|
300
|
+
chunkStringToSign(seed.datetime, seed.scope, previous, await hexHash(data)),
|
|
301
|
+
)),
|
|
302
|
+
));
|
|
153
303
|
return {
|
|
154
304
|
chunk: async (data) => (data.length === 0 ? data : frameChunk(await sign(data), data)),
|
|
155
305
|
async end(trailers) {
|
|
156
306
|
const text = trailers === undefined ? undefined : canonicalTrailers(trailers); // before sign(), so a refused trailer leaves the chain where it was
|
|
157
307
|
const signature = await sign(new Uint8Array(0));
|
|
158
|
-
if (text === undefined)
|
|
159
|
-
|
|
308
|
+
if (text === undefined) {
|
|
309
|
+
return frameEnd(signature);
|
|
310
|
+
}
|
|
311
|
+
return frameEnd(
|
|
312
|
+
signature,
|
|
313
|
+
text,
|
|
314
|
+
await signWith(
|
|
315
|
+
await keyPromise,
|
|
316
|
+
trailerStringToSign(seed.datetime, seed.scope, signature, await hexHash(text)),
|
|
317
|
+
),
|
|
318
|
+
);
|
|
160
319
|
},
|
|
161
320
|
};
|
|
162
321
|
}
|
|
@@ -179,7 +338,13 @@ export function eventSigner(authHeaders, credentials) {
|
|
|
179
338
|
const header = dateHeader(now);
|
|
180
339
|
previous = await signWith(
|
|
181
340
|
await getSigningKey(credentials.secretAccessKey, date, seed.region, seed.service),
|
|
182
|
-
eventStringToSign(
|
|
341
|
+
eventStringToSign(
|
|
342
|
+
datetime,
|
|
343
|
+
scope,
|
|
344
|
+
previous,
|
|
345
|
+
await hexHash(header),
|
|
346
|
+
await hexHash(message),
|
|
347
|
+
),
|
|
183
348
|
);
|
|
184
349
|
return frameEvent(header, previous, message);
|
|
185
350
|
})),
|
package/types/base.d.ts
CHANGED
|
@@ -1,23 +1,48 @@
|
|
|
1
1
|
export declare const emptyBodyHash = "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855";
|
|
2
|
-
|
|
3
|
-
export declare const symmetric: {
|
|
2
|
+
export type Scheme = {
|
|
4
3
|
algorithm: string;
|
|
5
|
-
scope: (date:
|
|
4
|
+
scope: (date: string, region: string, service: string) => string;
|
|
6
5
|
};
|
|
7
|
-
/**
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
6
|
+
/**
|
|
7
|
+
* @typedef {Object} Scheme
|
|
8
|
+
* @property {string} algorithm
|
|
9
|
+
* @property {(date: string, region: string, service: string) => string} scope
|
|
10
|
+
*/
|
|
11
|
+
/**
|
|
12
|
+
* The scheme of a signature: its algorithm name and how the credential scope is written. SigV4a (v4a.js) has its own.
|
|
13
|
+
* @type {Scheme}
|
|
14
|
+
*/
|
|
15
|
+
export declare const symmetric: Scheme;
|
|
16
|
+
/**
|
|
17
|
+
* The canonical path for a service.
|
|
18
|
+
* @param {string} service
|
|
19
|
+
* @param {string} pathname
|
|
20
|
+
*/
|
|
21
|
+
export declare const canonicalPath: (service: string, pathname: string) => string;
|
|
22
|
+
/** @param {string} search - url.search, which is '' or starts with '?' */
|
|
23
|
+
export declare function canonicalQuery(search: string): string;
|
|
24
|
+
/**
|
|
25
|
+
* Inserts into the name-ordered lists, replacing an entry with the same name.
|
|
26
|
+
* @param {string[]} names
|
|
27
|
+
* @param {string[]} values
|
|
28
|
+
* @param {string} name
|
|
29
|
+
* @param {string} value
|
|
30
|
+
*/
|
|
31
|
+
export declare function insert(names: string[], values: string[], name: string, value: string): void;
|
|
13
32
|
/**
|
|
14
33
|
* Refuses a signHeaders entry that cannot be signed as given: x-amz-date and authorization are set by the signer, `__proto__` cannot be a property of the
|
|
15
34
|
* returned headers, and a line break in a value would start another canonical header line. Returns the lowercase name.
|
|
35
|
+
* @param {string} name
|
|
36
|
+
* @param {string} value
|
|
37
|
+
*/
|
|
38
|
+
export declare function signHeaderName(name: string, value: string): string;
|
|
39
|
+
/**
|
|
40
|
+
* A header value as it is signed: trimmed, runs of spaces and tabs collapsed.
|
|
41
|
+
* @param {unknown} value
|
|
16
42
|
*/
|
|
17
|
-
export declare
|
|
18
|
-
/**
|
|
19
|
-
export declare
|
|
20
|
-
export declare function amzDatetime(now: any): string;
|
|
43
|
+
export declare const headerValue: (value: unknown) => string;
|
|
44
|
+
/** @param {number} now - milliseconds since the epoch */
|
|
45
|
+
export declare function amzDatetime(now: number): string;
|
|
21
46
|
export type SignRequest = {
|
|
22
47
|
/**
|
|
23
48
|
* - GET, HEAD, PUT, POST, DELETE; any case, signed in upper case (as botocore does)
|
|
@@ -111,33 +136,55 @@ export type Primitives = {
|
|
|
111
136
|
* @property {(key: Uint8Array, data: string) => string} hmacHex - HMAC-SHA-256 as lowercase hex
|
|
112
137
|
* @property {ReturnType<typeof createKeys>} getSigningKey - the entry's one signing-key cache, shared by every symmetric signer
|
|
113
138
|
*/
|
|
114
|
-
/**
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
139
|
+
/**
|
|
140
|
+
* The payload hash for x-amz-content-sha256. The hash function may return a promise, which is then the result.
|
|
141
|
+
* @template {string | Promise<string>} H
|
|
142
|
+
* @param {SignRequest} request
|
|
143
|
+
* @param {(data: string) => H} hexHash
|
|
144
|
+
* @returns {string | H}
|
|
145
|
+
*/
|
|
146
|
+
export declare function payloadHashOf<H extends string | Promise<string>>(request: SignRequest, hexHash: (data: string) => H): string | H;
|
|
147
|
+
/**
|
|
148
|
+
* Everything up to the hashing: the headers to return, the canonical request and the credential scope.
|
|
149
|
+
* @param {SignRequest} request
|
|
150
|
+
* @param {Credentials} credentials
|
|
151
|
+
* @param {string} payloadHash
|
|
152
|
+
* @param {Scheme} [scheme]
|
|
153
|
+
*/
|
|
154
|
+
export declare function prepare(request: SignRequest, credentials: Credentials, payloadHash: string, scheme?: Scheme): {
|
|
155
|
+
headers: AuthHeaders;
|
|
128
156
|
canonicalRequest: string;
|
|
129
157
|
datetime: string;
|
|
130
158
|
date: string;
|
|
131
|
-
region:
|
|
132
|
-
service:
|
|
159
|
+
region: string;
|
|
160
|
+
service: string;
|
|
133
161
|
credentialScope: string;
|
|
134
162
|
signedHeaders: any;
|
|
135
163
|
algorithm: string;
|
|
136
164
|
};
|
|
137
|
-
export
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
165
|
+
export type StringToSignParts = {
|
|
166
|
+
algorithm: string;
|
|
167
|
+
datetime: string;
|
|
168
|
+
credentialScope: string;
|
|
169
|
+
};
|
|
170
|
+
/** @typedef {{ algorithm: string, datetime: string, credentialScope: string }} StringToSignParts */
|
|
171
|
+
/**
|
|
172
|
+
* @param {StringToSignParts} prepared
|
|
173
|
+
* @param {string} canonicalRequestHash
|
|
174
|
+
*/
|
|
175
|
+
export declare const stringToSign: (prepared: StringToSignParts, canonicalRequestHash: string) => string;
|
|
176
|
+
/**
|
|
177
|
+
* Adds the authorization header to the headers to return.
|
|
178
|
+
* @param {ReturnType<typeof prepare>} prepared
|
|
179
|
+
* @param {string} accessKeyId
|
|
180
|
+
* @param {string} signature
|
|
181
|
+
*/
|
|
182
|
+
export declare function authorize(prepared: ReturnType<typeof prepare>, accessKeyId: string, signature: string): AuthHeaders;
|
|
183
|
+
/**
|
|
184
|
+
* @param {(key: string | Uint8Array, data: string) => Uint8Array} hmac
|
|
185
|
+
* @returns {(secretAccessKey: string, date: string, region: string, service: string) => Uint8Array}
|
|
186
|
+
*/
|
|
187
|
+
export declare function createKeys(hmac: (key: string | Uint8Array, data: string) => Uint8Array): (secretAccessKey: string, date: string, region: string, service: string) => Uint8Array;
|
|
141
188
|
/**
|
|
142
189
|
* @param {Primitives} primitives
|
|
143
190
|
* @returns {(request: SignRequest, credentials: Credentials) => AuthHeaders}
|
package/types/chunks.d.ts
CHANGED
|
@@ -1,21 +1,47 @@
|
|
|
1
1
|
export declare const utf8: TextEncoder;
|
|
2
|
-
/**
|
|
3
|
-
|
|
2
|
+
/**
|
|
3
|
+
* The seed signature, timestamp and scope of a signed request, from the headers getAuthHeaders returned.
|
|
4
|
+
* @param {import('./base.js').AuthHeaders} authHeaders
|
|
5
|
+
*/
|
|
6
|
+
export declare function seedOf(authHeaders: import('./base.js').AuthHeaders): {
|
|
4
7
|
signature: string;
|
|
5
|
-
datetime:
|
|
8
|
+
datetime: string;
|
|
6
9
|
date: string;
|
|
7
10
|
region: string;
|
|
8
11
|
service: string;
|
|
9
12
|
scope: string;
|
|
10
13
|
};
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
14
|
+
/**
|
|
15
|
+
* @param {string} datetime
|
|
16
|
+
* @param {string} scope
|
|
17
|
+
* @param {string} previous
|
|
18
|
+
* @param {string} payloadHash
|
|
19
|
+
*/
|
|
20
|
+
export declare const chunkStringToSign: (datetime: string, scope: string, previous: string, payloadHash: string) => string;
|
|
21
|
+
/**
|
|
22
|
+
* @param {string} datetime
|
|
23
|
+
* @param {string} scope
|
|
24
|
+
* @param {string} previous
|
|
25
|
+
* @param {string} trailerHash
|
|
26
|
+
*/
|
|
27
|
+
export declare const trailerStringToSign: (datetime: string, scope: string, previous: string, trailerHash: string) => string;
|
|
28
|
+
/** Trailing headers in canonical form: lowercase names in name order, each line ending in a newline. A line break in a name or value would start another trailer line, so it throws.
|
|
29
|
+
* @param {Record<string, string>} trailers
|
|
30
|
+
*/
|
|
31
|
+
export declare function canonicalTrailers(trailers: Record<string, string>): string;
|
|
32
|
+
/**
|
|
33
|
+
* The bytes of one chunk on the wire: size in hex, signature, the data.
|
|
34
|
+
* @param {string} signature
|
|
35
|
+
* @param {Uint8Array} data
|
|
36
|
+
*/
|
|
37
|
+
export declare function frameChunk(signature: string, data: Uint8Array): Uint8Array<ArrayBuffer>;
|
|
38
|
+
/**
|
|
39
|
+
* The last chunk (no data), with the signed trailing headers when there are any.
|
|
40
|
+
* @param {string} signature
|
|
41
|
+
* @param {string} [trailers] - canonical trailing headers
|
|
42
|
+
* @param {string} [trailerSignature]
|
|
43
|
+
*/
|
|
44
|
+
export declare function frameEnd(signature: string, trailers?: string, trailerSignature?: string): Uint8Array<ArrayBuffer>;
|
|
19
45
|
export type ChunkSigner = {
|
|
20
46
|
/**
|
|
21
47
|
* - the bytes to send for one chunk of the body
|
package/types/ecdsa-node.d.ts
CHANGED
|
@@ -1,5 +1,10 @@
|
|
|
1
1
|
import crypto from 'node:crypto';
|
|
2
2
|
export declare const ecdsa: {
|
|
3
|
-
|
|
4
|
-
|
|
3
|
+
/** @param {Uint8Array} d */
|
|
4
|
+
key(d: Uint8Array): crypto.KeyObject;
|
|
5
|
+
/**
|
|
6
|
+
* @param {crypto.KeyObject} key
|
|
7
|
+
* @param {string} text
|
|
8
|
+
*/
|
|
9
|
+
sign: (key: crypto.KeyObject, text: string) => string;
|
|
5
10
|
};
|
package/types/events.d.ts
CHANGED
|
@@ -1,9 +1,29 @@
|
|
|
1
|
-
/**
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
export declare
|
|
6
|
-
|
|
1
|
+
/**
|
|
2
|
+
* The :date header of an event: name, type 8 (timestamp), milliseconds since the epoch as 8 bytes.
|
|
3
|
+
* @param {number} ms
|
|
4
|
+
*/
|
|
5
|
+
export declare function dateHeader(ms: number): Uint8Array<ArrayBuffer>;
|
|
6
|
+
/**
|
|
7
|
+
* The signed event: prelude, the :date and :chunk-signature headers, the inner message as payload, checksums.
|
|
8
|
+
* @param {Uint8Array} dateBytes
|
|
9
|
+
* @param {string} signatureHex
|
|
10
|
+
* @param {Uint8Array} inner
|
|
11
|
+
*/
|
|
12
|
+
export declare function frameEvent(dateBytes: Uint8Array, signatureHex: string, inner: Uint8Array): Uint8Array<ArrayBuffer>;
|
|
13
|
+
/**
|
|
14
|
+
* @param {string} datetime
|
|
15
|
+
* @param {string} scope
|
|
16
|
+
* @param {string} previous
|
|
17
|
+
* @param {string} headersHash
|
|
18
|
+
* @param {string} payloadHash
|
|
19
|
+
*/
|
|
20
|
+
export declare const eventStringToSign: (datetime: string, scope: string, previous: string, headersHash: string, payloadHash: string) => string;
|
|
21
|
+
/**
|
|
22
|
+
* @param {number} ms
|
|
23
|
+
* @param {string} region
|
|
24
|
+
* @param {string} service
|
|
25
|
+
*/
|
|
26
|
+
export declare const eventScope: (ms: number, region: string, service: string) => {
|
|
7
27
|
datetime: string;
|
|
8
28
|
scope: string;
|
|
9
29
|
date: string;
|
package/types/presign.d.ts
CHANGED
|
@@ -1,25 +1,35 @@
|
|
|
1
|
-
|
|
1
|
+
/** @param {string} text */
|
|
2
|
+
export declare const encodeQueryPart: (text: string) => string;
|
|
2
3
|
/**
|
|
3
4
|
* Everything up to the hashing for a presigned URL. `request.expires` is the lifetime in seconds (default 3600). Only the host and request.signHeaders are
|
|
4
5
|
* signed; S3 URLs are always UNSIGNED-PAYLOAD, other services sign the body hash. `extra` is appended to the authentication parameters.
|
|
6
|
+
* @param {import('./base.js').SignRequest} request
|
|
7
|
+
* @param {import('./base.js').Credentials} credentials
|
|
8
|
+
* @param {string} payloadHash
|
|
9
|
+
* @param {import('./base.js').Scheme} [scheme]
|
|
10
|
+
* @param {string} [extra]
|
|
5
11
|
*/
|
|
6
|
-
export declare function preparePresign(request:
|
|
7
|
-
algorithm: string;
|
|
8
|
-
scope: (date: any, region: any, service: any) => string;
|
|
9
|
-
}, extra?: string): {
|
|
12
|
+
export declare function preparePresign(request: import('./base.js').SignRequest, credentials: import('./base.js').Credentials, payloadHash: string, scheme?: import('./base.js').Scheme, extra?: string): {
|
|
10
13
|
canonicalRequest: string;
|
|
11
14
|
datetime: string;
|
|
12
15
|
date: string;
|
|
13
|
-
region:
|
|
14
|
-
service:
|
|
16
|
+
region: string;
|
|
17
|
+
service: string;
|
|
15
18
|
credentialScope: string;
|
|
16
19
|
signedHeaders: string;
|
|
17
20
|
algorithm: string;
|
|
18
|
-
base:
|
|
21
|
+
base: string;
|
|
19
22
|
query: string;
|
|
20
23
|
};
|
|
21
|
-
/**
|
|
22
|
-
|
|
24
|
+
/**
|
|
25
|
+
* The URL to hand out: the original URL with the authentication query parameters and the signature appended.
|
|
26
|
+
* @param {{ base: string, query: string }} prepared
|
|
27
|
+
* @param {string} signature
|
|
28
|
+
*/
|
|
29
|
+
export declare const presignedUrl: (prepared: {
|
|
30
|
+
base: string;
|
|
31
|
+
query: string;
|
|
32
|
+
}, signature: string) => string;
|
|
23
33
|
/**
|
|
24
34
|
* @param {import('./base.js').Primitives} primitives
|
|
25
35
|
* @returns {(request: import('./base.js').SignRequest, credentials: import('./base.js').Credentials) => string}
|