-
Notifications
You must be signed in to change notification settings - Fork 573
/
credentialDerivation.ts
70 lines (62 loc) · 2.5 KB
/
credentialDerivation.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
import { Credentials, HashConstructor, SourceData } from "@aws-sdk/types";
import { toHex } from "@aws-sdk/util-hex-encoding";
import { KEY_TYPE_IDENTIFIER, MAX_CACHE_SIZE } from "./constants";
const signingKeyCache: Record<string, Uint8Array> = {};
const cacheQueue: Array<string> = [];
/**
* Create a string describing the scope of credentials used to sign a request.
*
* @param shortDate The current calendar date in the form YYYYMMDD.
* @param region The AWS region in which the service resides.
* @param service The service to which the signed request is being sent.
*/
export const createScope = (shortDate: string, region: string, service: string): string =>
`${shortDate}/${region}/${service}/${KEY_TYPE_IDENTIFIER}`;
/**
* Derive a signing key from its composite parts
*
* @param sha256Constructor A constructor function that can instantiate SHA-256
* hash objects.
* @param credentials The credentials with which the request will be
* signed.
* @param shortDate The current calendar date in the form YYYYMMDD.
* @param region The AWS region in which the service resides.
* @param service The service to which the signed request is being
* sent.
*/
export const getSigningKey = async (
sha256Constructor: HashConstructor,
credentials: Credentials,
shortDate: string,
region: string,
service: string
): Promise<Uint8Array> => {
const credsHash = await hmac(sha256Constructor, credentials.secretAccessKey, credentials.accessKeyId);
const cacheKey = `${shortDate}:${region}:${service}:${toHex(credsHash)}:${credentials.sessionToken}`;
if (cacheKey in signingKeyCache) {
return signingKeyCache[cacheKey];
}
cacheQueue.push(cacheKey);
while (cacheQueue.length > MAX_CACHE_SIZE) {
delete signingKeyCache[cacheQueue.shift() as string];
}
let key: SourceData = `AWS4${credentials.secretAccessKey}`;
for (const signable of [shortDate, region, service, KEY_TYPE_IDENTIFIER]) {
key = await hmac(sha256Constructor, key, signable);
}
return (signingKeyCache[cacheKey] = key as Uint8Array);
};
/**
* @internal
*/
export const clearCredentialCache = (): void => {
cacheQueue.length = 0;
Object.keys(signingKeyCache).forEach((cacheKey) => {
delete signingKeyCache[cacheKey];
});
};
const hmac = (ctor: HashConstructor, secret: SourceData, data: SourceData): Promise<Uint8Array> => {
const hash = new ctor(secret);
hash.update(data);
return hash.digest();
};