diff --git a/docs/modules/create-hmac.md b/docs/modules/create-hmac.md new file mode 100644 index 00000000..dd99ef00 --- /dev/null +++ b/docs/modules/create-hmac.md @@ -0,0 +1,57 @@ +--- +description: Modern alternatives to the `create-hmac` package for HMAC +--- + +# Replacements for `create-hmac` + +## `crypto.createHmac` (native, Node.js) + +```js +import { createHmac } from 'node:crypto' // [!code ++] +import createHmac from 'create-hmac' // [!code --] + +const secret = 'secret-key' +const data = 'message-to-sign' + +const hash = createHmac('sha256', secret).update(data).digest('hex') +``` + +## `crypto.subtle.sign` (native, browser) + +```js +const encoder = new TextEncoder() + +async function generateHMAC(secret, data) { + const key = await crypto.subtle.importKey( + 'raw', + encoder.encode(secret), + { name: 'HMAC', hash: 'SHA-256' }, + false, + ['sign'] + ) + + const signature = await crypto.subtle.sign('HMAC', key, encoder.encode(data)) + + return new Uint8Array(signature).toHex() +} + +const secret = 'secret-key' +const data = 'message-to-sign' + +const hash = await generateHMAC(secret, data) +``` + +## `@noble/hashes` + +```js +import { hmac } from '@noble/hashes/hmac.js' // [!code ++] +import { sha256 } from '@noble/hashes/sha256.js' // [!code ++] +import { bytesToHex } from '@noble/hashes/utils.js' // [!code ++] +import createHmac from 'create-hmac' // [!code --] + +const secret = 'secret-key' +const data = 'message-to-sign' + +const hash = createHmac('sha256', secret).update(data).digest('hex') // [!code --] +const hash = bytesToHex(hmac(sha256, secret, data)) // [!code ++] +``` diff --git a/manifests/preferred.json b/manifests/preferred.json index b0d0abfd..7897b4d3 100644 --- a/manifests/preferred.json +++ b/manifests/preferred.json @@ -174,6 +174,16 @@ "replacements": ["cpx2"], "url": {"type": "e18e", "id": "cpx"} }, + "create-hmac": { + "type": "module", + "moduleName": "create-hmac", + "replacements": [ + "crypto.createHmac", + "crypto.subtle.sign", + "@noble/hashes" + ], + "url": {"type": "e18e", "id": "create-hmac"} + }, "cross-fetch": { "type": "module", "moduleName": "cross-fetch", @@ -2774,6 +2784,11 @@ "type": "documented", "replacementModule": "@materializecss/materialize" }, + "@noble/hashes": { + "id": "@noble/hashes", + "type": "documented", + "replacementModule": "@noble/hashes" + }, "@placemarkio/tokml": { "id": "@placemarkio/tokml", "type": "documented", @@ -2989,6 +3004,15 @@ }, "url": {"type": "mdn", "id": "Web/API/Web_Crypto_API"} }, + "crypto.createHmac": { + "id": "crypto.createHmac", + "type": "native", + "url": { + "type": "node", + "id": "api/crypto.html#cryptocreatehmacalgorithm-key-options" + }, + "nodeFeatureId": {"moduleName": "crypto", "exportName": "createHmac"} + }, "crypto.randomUUID": { "id": "crypto.randomUUID", "type": "native", @@ -2998,6 +3022,15 @@ }, "url": {"type": "mdn", "id": "Web/API/Crypto/randomUUID"} }, + "crypto.subtle.sign": { + "id": "crypto.subtle.sign", + "type": "native", + "webFeatureId": { + "featureId": "web-cryptography", + "compatKey": "api.SubtleCrypto.sign" + }, + "url": {"type": "mdn", "id": "Web/API/SubtleCrypto/sign"} + }, "crypto.timingSafeEqual": { "id": "crypto.timingSafeEqual", "type": "native",