fix: better error for missing web crypto

This PR simply detects missing web crypto and throws an error with an appropriate message.

This is a stepping stone that will help users understand the problem until we have time to do a refactor of this module and of all the modules that use it to enable optionally passing your own crypto implementation.

refs https://github.com/libp2p/js-libp2p-crypto/pull/149
refs https://github.com/libp2p/js-libp2p-crypto/pull/150
refs https://github.com/libp2p/js-libp2p-crypto/issues/105
refs https://github.com/ipfs/js-ipfs/issues/2153
refs https://github.com/ipfs/js-ipfs/issues/2017

License: MIT
Signed-off-by: Alan Shaw <alan@tableflip.io>
This commit is contained in:
Alan Shaw
2019-07-17 11:17:18 +01:00
committed by Jacob Heun
parent 0b686d363c
commit a5e05603ef
6 changed files with 123 additions and 23 deletions

View File

@ -1,6 +1,6 @@
'use strict'
const webcrypto = require('../webcrypto.js')
const webcrypto = require('../webcrypto')
const lengths = require('./lengths')
const hashTypes = {
@ -10,13 +10,13 @@ const hashTypes = {
}
const sign = async (key, data) => {
return Buffer.from(await webcrypto.subtle.sign({ name: 'HMAC' }, key, data))
return Buffer.from(await webcrypto.get().subtle.sign({ name: 'HMAC' }, key, data))
}
exports.create = async function (hashType, secret) {
const hash = hashTypes[hashType]
const key = await webcrypto.subtle.importKey(
const key = await webcrypto.get().subtle.importKey(
'raw',
secret,
{

View File

@ -1,7 +1,7 @@
'use strict'
const errcode = require('err-code')
const webcrypto = require('../webcrypto.js')
const webcrypto = require('../webcrypto')
const BN = require('asn1.js').bignum
const { toBase64, toBn } = require('../util')
const validateCurveType = require('./validate-curve-type')
@ -14,8 +14,7 @@ const bits = {
exports.generateEphmeralKeyPair = async function (curve) {
validateCurveType(Object.keys(bits), curve)
const pair = await webcrypto.subtle.generateKey(
const pair = await webcrypto.get().subtle.generateKey(
{
name: 'ECDH',
namedCurve: curve
@ -29,7 +28,7 @@ exports.generateEphmeralKeyPair = async function (curve) {
let privateKey
if (forcePrivate) {
privateKey = await webcrypto.subtle.importKey(
privateKey = await webcrypto.get().subtle.importKey(
'jwk',
unmarshalPrivateKey(curve, forcePrivate),
{
@ -44,7 +43,7 @@ exports.generateEphmeralKeyPair = async function (curve) {
}
const keys = [
await webcrypto.subtle.importKey(
await webcrypto.get().subtle.importKey(
'jwk',
unmarshalPublicKey(curve, theirPub),
{
@ -57,7 +56,7 @@ exports.generateEphmeralKeyPair = async function (curve) {
privateKey
]
return Buffer.from(await webcrypto.subtle.deriveBits(
return Buffer.from(await webcrypto.get().subtle.deriveBits(
{
name: 'ECDH',
namedCurve: curve,
@ -68,7 +67,7 @@ exports.generateEphmeralKeyPair = async function (curve) {
))
}
const publicKey = await webcrypto.subtle.exportKey('jwk', pair.publicKey)
const publicKey = await webcrypto.get().subtle.exportKey('jwk', pair.publicKey)
return {
key: marshalPublicKey(publicKey),

View File

@ -1,12 +1,12 @@
'use strict'
const webcrypto = require('../webcrypto.js')
const webcrypto = require('../webcrypto')
const randomBytes = require('../random-bytes')
exports.utils = require('./rsa-utils')
exports.generateKey = async function (bits) {
const pair = await webcrypto.subtle.generateKey(
const pair = await webcrypto.get().subtle.generateKey(
{
name: 'RSASSA-PKCS1-v1_5',
modulusLength: bits,
@ -27,7 +27,7 @@ exports.generateKey = async function (bits) {
// Takes a jwk key
exports.unmarshalPrivateKey = async function (key) {
const privateKey = await webcrypto.subtle.importKey(
const privateKey = await webcrypto.get().subtle.importKey(
'jwk',
key,
{
@ -57,7 +57,7 @@ exports.unmarshalPrivateKey = async function (key) {
exports.getRandomValues = randomBytes
exports.hashAndSign = async function (key, msg) {
const privateKey = await webcrypto.subtle.importKey(
const privateKey = await webcrypto.get().subtle.importKey(
'jwk',
key,
{
@ -68,7 +68,7 @@ exports.hashAndSign = async function (key, msg) {
['sign']
)
const sig = await webcrypto.subtle.sign(
const sig = await webcrypto.get().subtle.sign(
{ name: 'RSASSA-PKCS1-v1_5' },
privateKey,
Uint8Array.from(msg)
@ -78,7 +78,7 @@ exports.hashAndSign = async function (key, msg) {
}
exports.hashAndVerify = async function (key, sig, msg) {
const publicKey = await webcrypto.subtle.importKey(
const publicKey = await webcrypto.get().subtle.importKey(
'jwk',
key,
{
@ -89,7 +89,7 @@ exports.hashAndVerify = async function (key, sig, msg) {
['verify']
)
return webcrypto.subtle.verify(
return webcrypto.get().subtle.verify(
{ name: 'RSASSA-PKCS1-v1_5' },
publicKey,
sig,
@ -99,13 +99,13 @@ exports.hashAndVerify = async function (key, sig, msg) {
function exportKey (pair) {
return Promise.all([
webcrypto.subtle.exportKey('jwk', pair.privateKey),
webcrypto.subtle.exportKey('jwk', pair.publicKey)
webcrypto.get().subtle.exportKey('jwk', pair.privateKey),
webcrypto.get().subtle.exportKey('jwk', pair.publicKey)
])
}
function derivePublicFromPrivate (jwKey) {
return webcrypto.subtle.importKey(
return webcrypto.get().subtle.importKey(
'jwk',
{
kty: jwKey.kty,

View File

@ -1,5 +1,24 @@
/* global self */
/* eslint-env browser */
'use strict'
module.exports = self.crypto || self.msCrypto
// Check native crypto exists and is enabled (In insecure context `self.crypto`
// exists but `self.crypto.subtle` does not).
exports.get = (win = self) => {
const nativeCrypto = win.crypto || win.msCrypto
if (!nativeCrypto || !nativeCrypto.subtle) {
throw Object.assign(
new Error(
'Missing Web Crypto API. ' +
'The most likely cause of this error is that this page is being accessed ' +
'from an insecure context (i.e. not HTTPS). For more information and ' +
'possible resolutions see ' +
'https://github.com/libp2p/js-libp2p-crypto/blob/master/README.md#web-crypto-api'
),
{ code: 'ERR_MISSING_WEB_CRYPTO' }
)
}
return nativeCrypto
}