-
Notifications
You must be signed in to change notification settings - Fork 0
/
compileUrlTemplate.js
58 lines (56 loc) · 1.34 KB
/
compileUrlTemplate.js
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
// @ts-check
/// <reference lib="es2021" />
/**
* @param {string} str
* @param {string} key
*/
async function hmac(str, key) {
const strBytes = new TextEncoder().encode(str);
const keyBytes = new TextEncoder().encode(key);
const cryptoKey = await crypto.subtle.importKey(
"raw",
keyBytes,
{ name: "HMAC", hash: "SHA-256" },
false,
["sign"]
);
const signature = await crypto.subtle.sign("HMAC", cryptoKey, strBytes);
// Format as hex
return Array.from(new Uint8Array(signature))
.map((b) => b.toString(16).padStart(2, "0"))
.join("");
}
/**
* @param {string} urlTemplate
*/
export async function compileUrlTemplate(urlTemplate, { serialNumber }) {
const hmacRegex = /\{hmac:([^}]+)\}/g;
const hmacMap = new Map();
const promises = [];
const sn = serialNumber.replace(/:/g, "").toLowerCase();
urlTemplate.replaceAll(hmacRegex, (_, key) => {
promises.push(
hmac(sn, key).then((sig) => {
hmacMap.set(key, sig);
})
);
return "";
});
if (promises.length) {
await Promise.all(promises);
}
const expectedUrl = urlTemplate
.replaceAll("{sn}", sn)
.replaceAll(hmacRegex, (_, key) => hmacMap.get(key));
return {
generateUrl() {
return expectedUrl;
},
/**
* @param {string} url
*/
check(url) {
return url === expectedUrl;
},
};
}