-
Notifications
You must be signed in to change notification settings - Fork 751
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add SubtleCryptoProvider and update Webhooks to allow async crypto.
- Loading branch information
1 parent
3811c5d
commit 3335a69
Showing
12 changed files
with
682 additions
and
320 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,67 @@ | ||
'use strict'; | ||
|
||
const CryptoProvider = require('./CryptoProvider'); | ||
|
||
/** | ||
* `CryptoProvider which uses the SubtleCrypto interface of the Web Crypto API. | ||
*/ | ||
class SubtleCryptoProvider extends CryptoProvider { | ||
constructor(subtleCrypto) { | ||
super(); | ||
|
||
// If no subtle crypto is interface, default to the global namespace. This | ||
// is to allow custom interfaces (eg. using the Node webcrypto interface in | ||
// tests). | ||
this.subtleCrypto = subtleCrypto || crypto.subtle; | ||
} | ||
|
||
/** @override */ | ||
computeHMACSignature(payload, secret) { | ||
throw new Error( | ||
'SubtleCryptoProvider cannot be used in a synchronous context.' | ||
); | ||
} | ||
|
||
/** @override */ | ||
async computeHMACSignatureAsync(payload, secret) { | ||
const encoder = new TextEncoder('utf-8'); | ||
|
||
const key = await this.subtleCrypto.importKey( | ||
'raw', | ||
encoder.encode(secret), | ||
{ | ||
name: 'HMAC', | ||
hash: {name: 'SHA-256'}, | ||
}, | ||
false, | ||
['sign'] | ||
); | ||
|
||
const signatureBuffer = await this.subtleCrypto.sign( | ||
'hmac', | ||
key, | ||
encoder.encode(payload) | ||
); | ||
|
||
// crypto.subtle returns the signature in base64 format. This must be | ||
// encoded in hex to match the CryptoProvider contract. We map each byte in | ||
// the buffer to its corresponding hex octet and then combine into a string. | ||
const signatureBytes = new Uint8Array(signatureBuffer); | ||
const signatureHexCodes = new Array(signatureBytes.length); | ||
|
||
for (let i = 0; i < signatureBytes.length; i++) { | ||
signatureHexCodes[i] = byteHexMapping[signatureBytes[i]]; | ||
} | ||
|
||
return signatureHexCodes.join(''); | ||
} | ||
} | ||
|
||
// Cached mapping of byte to hex representation. We do this once to avoid re- | ||
// computing every time we need to convert the result of a signature to hex. | ||
const byteHexMapping = new Array(256); | ||
for (let i = 0; i < byteHexMapping.length; i++) { | ||
byteHexMapping[i] = i.toString(16).padStart(2, '0'); | ||
} | ||
|
||
module.exports = SubtleCryptoProvider; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.