|
@@ -0,0 +1,34 @@
|
|
|
+const enc = new TextEncoder('utf-8')
|
|
|
+async function sign (secret, body) {
|
|
|
+ const algorithm = { name: 'HMAC', hash: 'SHA-384' }
|
|
|
+
|
|
|
+ const key = await crypto.subtle.importKey('raw', enc.encode(secret), algorithm, false, ['sign', 'verify'])
|
|
|
+ const signature = await crypto.subtle.sign(algorithm.name, key, enc.encode(body))
|
|
|
+ return `sha384:${Array.from(new Uint8Array(signature), x => x.toString(16).padStart(2, '0')).join('')}`
|
|
|
+}
|
|
|
+function getExpiration (future) {
|
|
|
+ return new Date(Date.now() + future)
|
|
|
+ .toISOString()
|
|
|
+ .replace('T', ' ')
|
|
|
+ .replace(/\.\d+Z$/, '+00:00')
|
|
|
+}
|
|
|
+/**
|
|
|
+ * Adds an expiration date and signs the params object if a secret is passed to
|
|
|
+ * it. If no secret is given, it returns the same object.
|
|
|
+ *
|
|
|
+ * @param {string | undefined} secret
|
|
|
+ * @param {object} params
|
|
|
+ * @returns {{ params: string, signature?: string }}
|
|
|
+ */
|
|
|
+export default async function generateSignatureIfSecret (secret, params) {
|
|
|
+ let signature
|
|
|
+ if (secret) {
|
|
|
+ // eslint-disable-next-line no-param-reassign
|
|
|
+ params.auth.expires = getExpiration(5 * 60 * 1000)
|
|
|
+ // eslint-disable-next-line no-param-reassign
|
|
|
+ params = JSON.stringify(params)
|
|
|
+ signature = await sign(secret, params)
|
|
|
+ }
|
|
|
+
|
|
|
+ return { params, signature }
|
|
|
+}
|