Source: webauthn.js

/*! meta-client/modules/webauthn */
/*jslint
    browser, long
*/
/*global
    AbortController
*/
/**
 * webauthn module.
 *
 * @module meta-client/modules/webauthn
 */
import buffers from "util-web/modules/buffers";
import Logger from "js-logger";

const LOG = Logger.get("meta-client/webauthn");

const authAbortController = new AbortController();
const authAbortSignal = authAbortController.signal;
const webauthn = {};

authAbortSignal.onabort = () => LOG.warn("onabort");

webauthn.decodePublicKeyCredentialCreationOptions = function (request) {
    const options = Object.assign(request, {
        challenge: buffers.base64UrlToBuffer(request.challenge),
        excludeCredentials: request.excludeCredentials.map(function (credential) {
            return Object.assign(credential, {id: buffers.base64UrlToBuffer(credential.id)});
        }),
        user: Object.assign(request.user, {id: buffers.base64UrlToBuffer(request.user.id)})
    });
    LOG.debug("decodePublicKeyCredentialCreationOptions", options);
    return options;
};

webauthn.encodeCreationResponse = function (response) {
    LOG.debug("encodeCreationResponse", response);
    return {
        clientExtensionResults: {},
        id: response.id,
        response: {
            attestationObject: buffers.bufferToBase64Url(response.response.attestationObject),
            clientDataJSON: buffers.bufferToBase64Url(response.response.clientDataJSON)
        },
        type: response.type
    };
};

webauthn.createCredential = function (options) {
    const publicKey = webauthn.decodePublicKeyCredentialCreationOptions(options);
    LOG.debug("createCredential", publicKey);
    return navigator.credentials.create({publicKey, signal: authAbortSignal}).then((response) => webauthn.encodeCreationResponse(response));
};

webauthn.decodePublicKeyCredentialRequestOptions = function (request) {
    const options = Object.assign(request, {
        allowCredentials: request.allowCredentials && request.allowCredentials.map(function (credential) {
            const mapped = Object.assign(credential, {id: buffers.base64UrlToBuffer(credential.id)});
            delete mapped.transports;
            return mapped;
        }),
        challenge: buffers.base64UrlToBuffer(request.challenge),
        extensions: {}
    });
    LOG.debug("decodePublicKeyCredentialRequestOptions", options);
    return options;
};

webauthn.encodeAssertionResponse = function (response) {
    LOG.debug("encodeAssertionResponse", response);
    return {
        clientExtensionResults: {},
        id: response.id,
        response: {
            authenticatorData: buffers.bufferToBase64Url(response.response.authenticatorData),
            clientDataJSON: buffers.bufferToBase64Url(response.response.clientDataJSON),
            signature: buffers.bufferToBase64Url(response.response.signature),
            userHandle: response.response.userHandle && buffers.bufferToBase64Url(response.response.userHandle)
        },
        type: response.type
    };
};

webauthn.getAssertion = function (options) {
    const publicKey = webauthn.decodePublicKeyCredentialRequestOptions(options.publicKeyCredentialRequestOptions);
    LOG.debug("getAssertion", publicKey);
    return navigator.credentials.get({publicKey, signal: authAbortSignal}).then((response) => webauthn.encodeAssertionResponse(response));
};

webauthn.abortAssertion = function () {
    LOG.debug("abortAssertion");
    authAbortController.abort();
};

export default Object.freeze(webauthn);