PHP WebShell

Текущая директория: /usr/lib/node_modules/bitgo/node_modules/ox/_esm/core

Просмотр файла: WebAuthnP256.js

import * as Base64 from './Base64.js';
import * as Bytes from './Bytes.js';
import * as Errors from './Errors.js';
import * as Hash from './Hash.js';
import * as Hex from './Hex.js';
import * as internal from './internal/webauthn.js';
import * as P256 from './P256.js';
export const createChallenge = Uint8Array.from([
    105, 171, 180, 181, 160, 222, 75, 198, 42, 42, 32, 31, 141, 37, 186, 233,
]);
/**
 * Creates a new WebAuthn P256 Credential, which can be stored and later used for signing.
 *
 * @example
 * ```ts twoslash
 * import { WebAuthnP256 } from 'ox'
 *
 * const credential = await WebAuthnP256.createCredential({ name: 'Example' }) // [!code focus]
 * // @log: {
 * // @log:   id: 'oZ48...',
 * // @log:   publicKey: { x: 51421...5123n, y: 12345...6789n },
 * // @log:   raw: PublicKeyCredential {},
 * // @log: }
 *
 * const { metadata, signature } = await WebAuthnP256.sign({
 *   credentialId: credential.id,
 *   challenge: '0xdeadbeef',
 * })
 * ```
 *
 * @param options - Credential creation options.
 * @returns A WebAuthn P256 credential.
 */
export async function createCredential(options) {
    const { createFn = window.navigator.credentials.create.bind(window.navigator.credentials), ...rest } = options;
    const creationOptions = getCredentialCreationOptions(rest);
    try {
        const credential = (await createFn(creationOptions));
        if (!credential)
            throw new CredentialCreationFailedError();
        const response = credential.response;
        const publicKey = await internal.parseCredentialPublicKey(response);
        return {
            id: credential.id,
            publicKey,
            raw: credential,
        };
    }
    catch (error) {
        throw new CredentialCreationFailedError({
            cause: error,
        });
    }
}
/**
 * Gets the authenticator data which contains information about the
 * processing of an authenticator request (ie. from `WebAuthnP256.sign`).
 *
 * :::warning
 *
 * This function is mainly for testing purposes or for manually constructing
 * autenticator data. In most cases you will not need this function.
 * `authenticatorData` is typically returned as part of the
 * {@link ox#WebAuthnP256.(sign:function)} response (ie. an authenticator response).
 *
 * :::
 *
 * @example
 * ```ts twoslash
 * import { WebAuthnP256 } from 'ox'
 *
 * const authenticatorData = WebAuthnP256.getAuthenticatorData({
 *   rpId: 'example.com',
 *   signCount: 420,
 * })
 * // @log: "0xa379a6f6eeafb9a55e378c118034e2751e682fab9f2d30ab13d2125586ce194705000001a4"
 * ```
 *
 * @param options - Options to construct the authenticator data.
 * @returns The authenticator data.
 */
export function getAuthenticatorData(options = {}) {
    const { flag = 5, rpId = window.location.hostname, signCount = 0 } = options;
    const rpIdHash = Hash.sha256(Hex.fromString(rpId));
    const flag_bytes = Hex.fromNumber(flag, { size: 1 });
    const signCount_bytes = Hex.fromNumber(signCount, { size: 4 });
    return Hex.concat(rpIdHash, flag_bytes, signCount_bytes);
}
/**
 * Constructs the Client Data in stringified JSON format which represents client data that
 * was passed to `credentials.get()` in {@link ox#WebAuthnP256.(sign:function)}.
 *
 * :::warning
 *
 * This function is mainly for testing purposes or for manually constructing
 * client data. In most cases you will not need this function.
 * `clientDataJSON` is typically returned as part of the
 * {@link ox#WebAuthnP256.(sign:function)} response (ie. an authenticator response).
 *
 * :::
 *
 * @example
 * ```ts twoslash
 * import { WebAuthnP256 } from 'ox'
 *
 * const clientDataJSON = WebAuthnP256.getClientDataJSON({
 *   challenge: '0xdeadbeef',
 *   origin: 'https://example.com',
 * })
 * // @log: "{"type":"webauthn.get","challenge":"3q2-7w","origin":"https://example.com","crossOrigin":false}"
 * ```
 *
 * @param options - Options to construct the client data.
 * @returns The client data.
 */
export function getClientDataJSON(options) {
    const { challenge, crossOrigin = false, extraClientData, origin = window.location.origin, } = options;
    return JSON.stringify({
        type: 'webauthn.get',
        challenge: Base64.fromHex(challenge, { url: true, pad: false }),
        origin,
        crossOrigin,
        ...extraClientData,
    });
}
/**
 * Returns the creation options for a P256 WebAuthn Credential to be used with
 * the Web Authentication API.
 *
 * @example
 * ```ts twoslash
 * import { WebAuthnP256 } from 'ox'
 *
 * const options = WebAuthnP256.getCredentialCreationOptions({ name: 'Example' })
 *
 * const credential = await window.navigator.credentials.create(options)
 * ```
 *
 * @param options - Options.
 * @returns The credential creation options.
 */
export function getCredentialCreationOptions(options) {
    const { attestation = 'none', authenticatorSelection = {
        residentKey: 'preferred',
        requireResidentKey: false,
        userVerification: 'required',
    }, challenge = createChallenge, excludeCredentialIds, extensions, name: name_, rp = {
        id: window.location.hostname,
        name: window.document.title,
    }, user, } = options;
    const name = (user?.name ?? name_);
    return {
        publicKey: {
            attestation,
            authenticatorSelection,
            challenge,
            ...(excludeCredentialIds
                ? {
                    excludeCredentials: excludeCredentialIds?.map((id) => ({
                        id: Base64.toBytes(id),
                        type: 'public-key',
                    })),
                }
                : {}),
            pubKeyCredParams: [
                {
                    type: 'public-key',
                    alg: -7, // p256
                },
            ],
            ...(extensions && { extensions }),
            rp,
            user: {
                id: user?.id ?? Hash.keccak256(Bytes.fromString(name), { as: 'Bytes' }),
                name,
                displayName: user?.displayName ?? name,
            },
        },
    };
}
/**
 * Returns the request options to sign a challenge with the Web Authentication API.
 *
 * @example
 * ```ts twoslash
 * import { WebAuthnP256 } from 'ox'
 *
 * const options = WebAuthnP256.getCredentialRequestOptions({
 *   challenge: '0xdeadbeef',
 * })
 *
 * const credential = await window.navigator.credentials.get(options)
 * ```
 *
 * @param options - Options.
 * @returns The credential request options.
 */
export function getCredentialRequestOptions(options) {
    const { credentialId, challenge, extensions, rpId = window.location.hostname, userVerification = 'required', } = options;
    return {
        publicKey: {
            ...(credentialId
                ? {
                    allowCredentials: Array.isArray(credentialId)
                        ? credentialId.map((id) => ({
                            id: Base64.toBytes(id),
                            type: 'public-key',
                        }))
                        : [
                            {
                                id: Base64.toBytes(credentialId),
                                type: 'public-key',
                            },
                        ],
                }
                : {}),
            challenge: Bytes.fromHex(challenge),
            ...(extensions && { extensions }),
            rpId,
            userVerification,
        },
    };
}
/**
 * Constructs the final digest that was signed and computed by the authenticator. This payload includes
 * the cryptographic `challenge`, as well as authenticator metadata (`authenticatorData` + `clientDataJSON`).
 * This value can be also used with raw P256 verification (such as {@link ox#P256.(verify:function)} or
 * {@link ox#WebCryptoP256.(verify:function)}).
 *
 * :::warning
 *
 * This function is mainly for testing purposes or for manually constructing
 * signing payloads. In most cases you will not need this function and
 * instead use {@link ox#WebAuthnP256.(sign:function)}.
 *
 * :::
 *
 * @example
 * ```ts twoslash
 * import { WebAuthnP256, WebCryptoP256 } from 'ox'
 *
 * const { metadata, payload } = WebAuthnP256.getSignPayload({ // [!code focus]
 *   challenge: '0xdeadbeef', // [!code focus]
 * }) // [!code focus]
 * // @log: {
 * // @log:   metadata: {
 * // @log:     authenticatorData: "0x49960de5880e8c687434170f6476605b8fe4aeb9a28632c7995cf3ba831d97630500000000",
 * // @log:     challengeIndex: 23,
 * // @log:     clientDataJSON: "{"type":"webauthn.get","challenge":"9jEFijuhEWrM4SOW-tChJbUEHEP44VcjcJ-Bqo1fTM8","origin":"http://localhost:5173","crossOrigin":false}",
 * // @log:     typeIndex: 1,
 * // @log:     userVerificationRequired: true,
 * // @log:   },
 * // @log:   payload: "0x49960de5880e8c687434170f6476605b8fe4aeb9a28632c7995cf3ba831d9763050000000045086dcb06a5f234db625bcdc94e657f86b76b6fd3eb9c30543eabc1e577a4b0",
 * // @log: }
 *
 * const { publicKey, privateKey } = await WebCryptoP256.createKeyPair()
 *
 * const signature = await WebCryptoP256.sign({
 *   payload,
 *   privateKey,
 * })
 * ```
 *
 * @param options - Options to construct the signing payload.
 * @returns The signing payload.
 */
export function getSignPayload(options) {
    const { challenge, crossOrigin, extraClientData, flag, origin, rpId, signCount, userVerification = 'required', } = options;
    const authenticatorData = getAuthenticatorData({
        flag,
        rpId,
        signCount,
    });
    const clientDataJSON = getClientDataJSON({
        challenge,
        crossOrigin,
        extraClientData,
        origin,
    });
    const clientDataJSONHash = Hash.sha256(Hex.fromString(clientDataJSON));
    const challengeIndex = clientDataJSON.indexOf('"challenge"');
    const typeIndex = clientDataJSON.indexOf('"type"');
    const metadata = {
        authenticatorData,
        clientDataJSON,
        challengeIndex,
        typeIndex,
        userVerificationRequired: userVerification === 'required',
    };
    const payload = Hex.concat(authenticatorData, clientDataJSONHash);
    return { metadata, payload };
}
/**
 * Signs a challenge using a stored WebAuthn P256 Credential. If no Credential is provided,
 * a prompt will be displayed for the user to select an existing Credential
 * that was previously registered.
 *
 * @example
 * ```ts twoslash
 * import { WebAuthnP256 } from 'ox'
 *
 * const credential = await WebAuthnP256.createCredential({
 *   name: 'Example',
 * })
 *
 * const { metadata, signature } = await WebAuthnP256.sign({ // [!code focus]
 *   credentialId: credential.id, // [!code focus]
 *   challenge: '0xdeadbeef', // [!code focus]
 * }) // [!code focus]
 * // @log: {
 * // @log:   metadata: {
 * // @log:     authenticatorData: '0x49960de5880e8c687434170f6476605b8fe4aeb9a28632c7995cf3ba831d97630500000000',
 * // @log:     clientDataJSON: '{"type":"webauthn.get","challenge":"9jEFijuhEWrM4SOW-tChJbUEHEP44VcjcJ-Bqo1fTM8","origin":"http://localhost:5173","crossOrigin":false}',
 * // @log:     challengeIndex: 23,
 * // @log:     typeIndex: 1,
 * // @log:     userVerificationRequired: true,
 * // @log:   },
 * // @log:   signature: { r: 51231...4215n, s: 12345...6789n },
 * // @log: }
 * ```
 *
 * @param options - Options.
 * @returns The signature.
 */
export async function sign(options) {
    const { getFn = window.navigator.credentials.get.bind(window.navigator.credentials), ...rest } = options;
    const requestOptions = getCredentialRequestOptions(rest);
    try {
        const credential = (await getFn(requestOptions));
        if (!credential)
            throw new CredentialRequestFailedError();
        const response = credential.response;
        const clientDataJSON = String.fromCharCode(...new Uint8Array(response.clientDataJSON));
        const challengeIndex = clientDataJSON.indexOf('"challenge"');
        const typeIndex = clientDataJSON.indexOf('"type"');
        const signature = internal.parseAsn1Signature(new Uint8Array(response.signature));
        return {
            metadata: {
                authenticatorData: Hex.fromBytes(new Uint8Array(response.authenticatorData)),
                clientDataJSON,
                challengeIndex,
                typeIndex,
                userVerificationRequired: requestOptions.publicKey.userVerification === 'required',
            },
            signature,
            raw: credential,
        };
    }
    catch (error) {
        throw new CredentialRequestFailedError({
            cause: error,
        });
    }
}
/**
 * Verifies a signature using the Credential's public key and the challenge which was signed.
 *
 * @example
 * ```ts twoslash
 * import { WebAuthnP256 } from 'ox'
 *
 * const credential = await WebAuthnP256.createCredential({
 *   name: 'Example',
 * })
 *
 * const { metadata, signature } = await WebAuthnP256.sign({
 *   credentialId: credential.id,
 *   challenge: '0xdeadbeef',
 * })
 *
 * const result = await WebAuthnP256.verify({ // [!code focus]
 *   metadata, // [!code focus]
 *   challenge: '0xdeadbeef', // [!code focus]
 *   publicKey: credential.publicKey, // [!code focus]
 *   signature, // [!code focus]
 * }) // [!code focus]
 * // @log: true
 * ```
 *
 * @param options - Options.
 * @returns Whether the signature is valid.
 */
export function verify(options) {
    const { challenge, hash = true, metadata, publicKey, signature } = options;
    const { authenticatorData, challengeIndex, clientDataJSON, typeIndex, userVerificationRequired, } = metadata;
    const authenticatorDataBytes = Bytes.fromHex(authenticatorData);
    // Check length of `authenticatorData`.
    if (authenticatorDataBytes.length < 37)
        return false;
    const flag = authenticatorDataBytes[32];
    // Verify that the UP bit of the flags in authData is set.
    if ((flag & 0x01) !== 0x01)
        return false;
    // If user verification was determined to be required, verify that
    // the UV bit of the flags in authData is set. Otherwise, ignore the
    // value of the UV flag.
    if (userVerificationRequired && (flag & 0x04) !== 0x04)
        return false;
    // If the BE bit of the flags in authData is not set, verify that
    // the BS bit is not set.
    if ((flag & 0x08) !== 0x08 && (flag & 0x10) === 0x10)
        return false;
    // Check that response is for an authentication assertion
    const type = '"type":"webauthn.get"';
    if (type !== clientDataJSON.slice(Number(typeIndex), type.length + 1))
        return false;
    // Check that hash is in the clientDataJSON.
    const match = clientDataJSON
        .slice(Number(challengeIndex))
        .match(/^"challenge":"(.*?)"/);
    if (!match)
        return false;
    // Validate the challenge in the clientDataJSON.
    const [_, challenge_extracted] = match;
    if (Hex.fromBytes(Base64.toBytes(challenge_extracted)) !== challenge)
        return false;
    const clientDataJSONHash = Hash.sha256(Bytes.fromString(clientDataJSON), {
        as: 'Bytes',
    });
    const payload = Bytes.concat(authenticatorDataBytes, clientDataJSONHash);
    return P256.verify({
        hash,
        payload,
        publicKey,
        signature,
    });
}
/** Thrown when a WebAuthn P256 credential creation fails. */
export class CredentialCreationFailedError extends Errors.BaseError {
    constructor({ cause } = {}) {
        super('Failed to create credential.', {
            cause,
        });
        Object.defineProperty(this, "name", {
            enumerable: true,
            configurable: true,
            writable: true,
            value: 'WebAuthnP256.CredentialCreationFailedError'
        });
    }
}
/** Thrown when a WebAuthn P256 credential request fails. */
export class CredentialRequestFailedError extends Errors.BaseError {
    constructor({ cause } = {}) {
        super('Failed to request credential.', {
            cause,
        });
        Object.defineProperty(this, "name", {
            enumerable: true,
            configurable: true,
            writable: true,
            value: 'WebAuthnP256.CredentialRequestFailedError'
        });
    }
}
//# sourceMappingURL=WebAuthnP256.js.map

Выполнить команду


Для локальной разработки. Не используйте в интернете!