Skip to content

Fix/browser support #150

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 7 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions lib/main.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import * as utils from "./utils.js";
import { ready } from "./toolbox.js";

import { Fido2AssertionResult, Fido2AttestationResult, Fido2Result } from "./response.js";

Expand Down Expand Up @@ -166,6 +167,7 @@ class Fido2Lib {
* @see MdsCollection
*/
static async addMdsCollection(mdsCollection) {
await ready;
if (!(mdsCollection instanceof MdsCollection)) {
throw new Error(
"expected 'mdsCollection' to be instance of MdsCollection, got: " +
Expand Down Expand Up @@ -386,6 +388,7 @@ class Fido2Lib {
* @private
*/
static async validateAttestation() {
await ready;
const fmt = this.authnrData.get("fmt");

// validate input
Expand Down Expand Up @@ -542,6 +545,7 @@ class Fido2Lib {
* @throws {Error} If parsing or validation fails
*/
async attestationResult(res, expected) {
await ready;
expected.flags = factorToFlags(expected.factor, ["AT"]);
delete expected.factor;
return await Fido2AttestationResult.create(res, expected);
Expand Down Expand Up @@ -574,6 +578,7 @@ class Fido2Lib {
*/
// deno-lint-ignore require-await
async assertionResult(res, expected) {
await ready;
expected.flags = factorToFlags(expected.factor, []);
delete expected.factor;
return Fido2AssertionResult.create(res, expected);
Expand All @@ -594,6 +599,7 @@ class Fido2Lib {
* @returns {Promise<PublicKeyCredentialCreationOptions>} The options for creating calling `navigator.credentials.create()`
*/
async attestationOptions(opts) {
await ready;
opts = opts || {};

// The object being returned is described here:
Expand Down Expand Up @@ -714,6 +720,7 @@ class Fido2Lib {
* @returns {Promise<PublicKeyCredentialRequestOptions>} The options to be passed to `navigator.credentials.get()`
*/
async assertionOptions(opts) {
await ready;
opts = opts || {};

// https://w3c.github.io/webauthn/#dictdef-publickeycredentialcreationoptions
Expand Down
60 changes: 37 additions & 23 deletions lib/toolbox.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,25 +18,30 @@ import base64 from "@hexagon/base64";
import { Certificate } from "./certUtils.js";
import { PublicKey } from "./keyUtils.js";


// Import webcrypto
import * as platformCrypto from "crypto";
import * as peculiarCrypto from "@peculiar/webcrypto";
let webcrypto;
if ((typeof self !== "undefined") && "crypto" in self) {
let webcrypto = undefined;
if ((typeof self !== "undefined") && ("crypto" in self)) {
// Always use crypto if available natively (browser / Deno)
webcrypto = self.crypto;
}
const usePolyfill = async () => {
const module = await import("@peculiar/webcrypto");
webcrypto = new module.Crypto();
};
const useNative = async () => {
// Always use node webcrypto if available ( Node >= 16.0 )
// This also allows bundlers to resolve crypto with a custom polyfill
const module = await import("crypto");
webcrypto = module.webcrypto;
};

} else {
// Always use node webcrypto if available ( >= 16.0 )
if(platformCrypto && platformCrypto.webcrypto) {
webcrypto = platformCrypto.webcrypto;

} else {
// Fallback to @peculiar/webcrypto
webcrypto = new peculiarCrypto.Crypto();
}
let ready = Promise.resolve();
if (webcrypto === undefined) {
ready = ready.then(useNative).catch(usePolyfill);
}


// Set up pkijs
const pkijs = {
setEngine,
Expand All @@ -46,15 +51,23 @@ const pkijs = {
CertificateChainValidationEngine,
PublicKeyInfo,
};
pkijs.setEngine(
"newEngine",
webcrypto,
new pkijs.CryptoEngine({
name: "",
crypto: webcrypto,
subtle: webcrypto.subtle,
}),
);
const setUpPkijs = () => {
pkijs.setEngine(
"newEngine",
webcrypto,
new pkijs.CryptoEngine({
name: "",
crypto: webcrypto,
subtle: webcrypto.subtle,
}),
);
};
if (webcrypto === undefined) {
ready = ready.then(setUpPkijs);
}
else {
setUpPkijs();
}

function extractBigNum(fullArray, start, end, expectedLength) {
let num = fullArray.slice(start, end);
Expand Down Expand Up @@ -363,5 +376,6 @@ export {
pkijs,
randomValues,
verifySignature,
webcrypto
webcrypto,
ready
};
16 changes: 13 additions & 3 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 3 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -49,13 +49,15 @@
},
"dependencies": {
"@hexagon/base64": "~1.1.26",
"@peculiar/webcrypto": "~1.4.3",
"asn1js": "~3.0.2",
"cbor-x": "~1.5.3",
"jose": "^4.14.4",
"pkijs": "~3.0.15",
"tldts": "~6.0.5"
},
"optionalDependencies": {
"@peculiar/webcrypto": "~1.4.3"
},
"eslintConfig": {
"root": true,
"env": {
Expand Down
5 changes: 3 additions & 2 deletions types/main.d.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
/// <reference types="node" />

import {JWTPayload} from "jose/dist/types/types";

declare module "fido2-lib" {
// Type imports in ambient module should use import(),
// see https://stackoverflow.com/questions/39040108
type JWTPayload = import("jose/dist/types/types").JWTPayload;

class MdsEntry{
constructor(mdsEntry: Object, tocEntry: Object)
Expand Down