@simplewebauthn/server
Advanced tools
Comparing version 12.0.0 to 13.0.0-alpha1
@@ -1,13 +0,3 @@ | ||
import type { AuthenticationExtensionsClientInputs, AuthenticatorTransportFuture, Base64URLString, PublicKeyCredentialRequestOptionsJSON, UserVerificationRequirement } from '@simplewebauthn/types'; | ||
export type GenerateAuthenticationOptionsOpts = { | ||
rpID: string; | ||
allowCredentials?: { | ||
id: Base64URLString; | ||
transports?: AuthenticatorTransportFuture[]; | ||
}[]; | ||
challenge?: string | Uint8Array; | ||
timeout?: number; | ||
userVerification?: UserVerificationRequirement; | ||
extensions?: AuthenticationExtensionsClientInputs; | ||
}; | ||
import type { AuthenticationExtensionsClientInputs, AuthenticatorTransportFuture, Base64URLString, PublicKeyCredentialRequestOptionsJSON } from '../types/index.js'; | ||
export type GenerateAuthenticationOptionsOpts = Parameters<typeof generateAuthenticationOptions>[0]; | ||
/** | ||
@@ -25,3 +15,13 @@ * Prepare a value to pass into navigator.credentials.get(...) for authenticator authentication | ||
*/ | ||
export declare function generateAuthenticationOptions(options: GenerateAuthenticationOptionsOpts): Promise<PublicKeyCredentialRequestOptionsJSON>; | ||
export declare function generateAuthenticationOptions(options: { | ||
rpID: string; | ||
allowCredentials?: { | ||
id: Base64URLString; | ||
transports?: AuthenticatorTransportFuture[]; | ||
}[]; | ||
challenge?: string | Uint8Array; | ||
timeout?: number; | ||
userVerification?: 'required' | 'preferred' | 'discouraged'; | ||
extensions?: AuthenticationExtensionsClientInputs; | ||
}): Promise<PublicKeyCredentialRequestOptionsJSON>; | ||
//# sourceMappingURL=generateAuthenticationOptions.d.ts.map |
@@ -1,16 +0,8 @@ | ||
import type { AuthenticationResponseJSON, Base64URLString, CredentialDeviceType, UserVerificationRequirement, WebAuthnCredential } from '@simplewebauthn/types'; | ||
import { AuthenticationExtensionsAuthenticatorOutputs } from '../helpers/decodeAuthenticatorExtensions.js'; | ||
export type VerifyAuthenticationResponseOpts = { | ||
response: AuthenticationResponseJSON; | ||
expectedChallenge: string | ((challenge: string) => boolean | Promise<boolean>); | ||
expectedOrigin: string | string[]; | ||
expectedRPID: string | string[]; | ||
credential: WebAuthnCredential; | ||
expectedType?: string | string[]; | ||
requireUserVerification?: boolean; | ||
advancedFIDOConfig?: { | ||
userVerification?: UserVerificationRequirement; | ||
}; | ||
}; | ||
import type { AuthenticationResponseJSON, Base64URLString, CredentialDeviceType, UserVerificationRequirement, WebAuthnCredential } from '../types/index.js'; | ||
import type { AuthenticationExtensionsAuthenticatorOutputs } from '../helpers/decodeAuthenticatorExtensions.js'; | ||
/** | ||
* Configurable options when calling `verifyAuthenticationResponse()` | ||
*/ | ||
export type VerifyAuthenticationResponseOpts = Parameters<typeof verifyAuthenticationResponse>[0]; | ||
/** | ||
* Verify that the user has legitimately completed the authentication process | ||
@@ -30,3 +22,14 @@ * | ||
*/ | ||
export declare function verifyAuthenticationResponse(options: VerifyAuthenticationResponseOpts): Promise<VerifiedAuthenticationResponse>; | ||
export declare function verifyAuthenticationResponse(options: { | ||
response: AuthenticationResponseJSON; | ||
expectedChallenge: string | ((challenge: string) => boolean | Promise<boolean>); | ||
expectedOrigin: string | string[]; | ||
expectedRPID: string | string[]; | ||
credential: WebAuthnCredential; | ||
expectedType?: string | string[]; | ||
requireUserVerification?: boolean; | ||
advancedFIDOConfig?: { | ||
userVerification?: UserVerificationRequirement; | ||
}; | ||
}): Promise<VerifiedAuthenticationResponse>; | ||
/** | ||
@@ -33,0 +36,0 @@ * Result of authentication verification |
@@ -1,2 +0,2 @@ | ||
import type { Base64URLString } from '@simplewebauthn/types'; | ||
import type { Base64URLString } from '../types/index.js'; | ||
/** | ||
@@ -3,0 +3,0 @@ * Convert buffer to an OpenSSL-compatible PEM text format. |
@@ -10,3 +10,7 @@ /** | ||
* keys", but it works. | ||
* @module | ||
*/ | ||
/** | ||
* COSE public key common values | ||
*/ | ||
export type COSEPublicKey = { | ||
@@ -18,2 +22,5 @@ get(key: COSEKEYS.kty): COSEKTY | undefined; | ||
}; | ||
/** | ||
* Values specific to Octet Key Pair public keys | ||
*/ | ||
export type COSEPublicKeyOKP = COSEPublicKey & { | ||
@@ -25,2 +32,5 @@ get(key: COSEKEYS.crv): number | undefined; | ||
}; | ||
/** | ||
* Values specific to Elliptic Curve Cryptography public keys | ||
*/ | ||
export type COSEPublicKeyEC2 = COSEPublicKey & { | ||
@@ -34,2 +44,5 @@ get(key: COSEKEYS.crv): number | undefined; | ||
}; | ||
/** | ||
* Values specific to RSA public keys | ||
*/ | ||
export type COSEPublicKeyRSA = COSEPublicKey & { | ||
@@ -41,4 +54,13 @@ get(key: COSEKEYS.n): Uint8Array | undefined; | ||
}; | ||
/** | ||
* A type guard for determining if a COSE public key is an OKP key pair | ||
*/ | ||
export declare function isCOSEPublicKeyOKP(cosePublicKey: COSEPublicKey): cosePublicKey is COSEPublicKeyOKP; | ||
/** | ||
* A type guard for determining if a COSE public key is an EC2 key pair | ||
*/ | ||
export declare function isCOSEPublicKeyEC2(cosePublicKey: COSEPublicKey): cosePublicKey is COSEPublicKeyEC2; | ||
/** | ||
* A type guard for determining if a COSE public key is an RSA key pair | ||
*/ | ||
export declare function isCOSEPublicKeyRSA(cosePublicKey: COSEPublicKey): cosePublicKey is COSEPublicKeyRSA; | ||
@@ -45,0 +67,0 @@ /** |
@@ -0,1 +1,15 @@ | ||
/** | ||
* Fundamental values that are needed to discern the more specific COSE public key types below. | ||
* | ||
* The use of `Maps` here is due to CBOR encoding being used with public keys, and the CBOR "Map" | ||
* type is being decoded to JavaScript's `Map` type instead of, say, a basic Object as us JS | ||
* developers might prefer. | ||
* | ||
* These types are an unorthodox way of saying "these Maps should involve these discrete lists of | ||
* keys", but it works. | ||
* @module | ||
*/ | ||
/** | ||
* A type guard for determining if a COSE public key is an OKP key pair | ||
*/ | ||
export function isCOSEPublicKeyOKP(cosePublicKey) { | ||
@@ -5,2 +19,5 @@ const kty = cosePublicKey.get(COSEKEYS.kty); | ||
} | ||
/** | ||
* A type guard for determining if a COSE public key is an EC2 key pair | ||
*/ | ||
export function isCOSEPublicKeyEC2(cosePublicKey) { | ||
@@ -10,2 +27,5 @@ const kty = cosePublicKey.get(COSEKEYS.kty); | ||
} | ||
/** | ||
* A type guard for determining if a COSE public key is an RSA key pair | ||
*/ | ||
export function isCOSEPublicKeyRSA(cosePublicKey) { | ||
@@ -12,0 +32,0 @@ const kty = cosePublicKey.get(COSEKEYS.kty); |
@@ -27,2 +27,6 @@ /** | ||
}; | ||
/** | ||
* Make it possible to stub the return value during testing | ||
* @ignore Don't include this in docs output | ||
*/ | ||
export declare const _decodeAttestationObjectInternals: { | ||
@@ -29,0 +33,0 @@ stubThis: (value: AttestationObject) => AttestationObject; |
@@ -10,5 +10,8 @@ import { isoCBOR } from './iso/index.js'; | ||
} | ||
// Make it possible to stub the return value during testing | ||
/** | ||
* Make it possible to stub the return value during testing | ||
* @ignore Don't include this in docs output | ||
*/ | ||
export const _decodeAttestationObjectInternals = { | ||
stubThis: (value) => value, | ||
}; |
@@ -1,2 +0,2 @@ | ||
import type { Base64URLString } from '@simplewebauthn/types'; | ||
import type { Base64URLString } from '../types/index.js'; | ||
/** | ||
@@ -16,2 +16,6 @@ * Decode an authenticator's base64url-encoded clientDataJSON to JSON | ||
}; | ||
/** | ||
* Make it possible to stub the return value during testing | ||
* @ignore Don't include this in docs output | ||
*/ | ||
export declare const _decodeClientDataJSONInternals: { | ||
@@ -18,0 +22,0 @@ stubThis: (value: ClientDataJSON) => ClientDataJSON; |
@@ -10,5 +10,8 @@ import { isoBase64URL } from './iso/index.js'; | ||
} | ||
// Make it possible to stub the return value during testing | ||
/** | ||
* Make it possible to stub the return value during testing | ||
* @ignore Don't include this in docs output | ||
*/ | ||
export const _decodeClientDataJSONInternals = { | ||
stubThis: (value) => value, | ||
}; |
import { COSEPublicKey } from './cose.js'; | ||
export declare function decodeCredentialPublicKey(publicKey: Uint8Array): COSEPublicKey; | ||
/** | ||
* Make it possible to stub the return value during testing | ||
* @ignore Don't include this in docs output | ||
*/ | ||
export declare const _decodeCredentialPublicKeyInternals: { | ||
@@ -4,0 +8,0 @@ stubThis: (value: COSEPublicKey) => COSEPublicKey; |
@@ -5,5 +5,8 @@ import { isoCBOR } from './iso/index.js'; | ||
} | ||
// Make it possible to stub the return value during testing | ||
/** | ||
* Make it possible to stub the return value during testing | ||
* @ignore Don't include this in docs output | ||
*/ | ||
export const _decodeCredentialPublicKeyInternals = { | ||
stubThis: (value) => value, | ||
}; |
@@ -6,2 +6,6 @@ /** | ||
export declare function fetch(url: string): Promise<Response>; | ||
/** | ||
* Make it possible to stub the return value during testing | ||
* @ignore Don't include this in docs output | ||
*/ | ||
export declare const _fetchInternals: { | ||
@@ -8,0 +12,0 @@ stubThis: (url: string) => Promise<Response>; |
@@ -9,5 +9,8 @@ import { fetch as crossFetch } from 'cross-fetch'; | ||
} | ||
// Make it possible to stub the return value during testing | ||
/** | ||
* Make it possible to stub the return value during testing | ||
* @ignore Don't include this in docs output | ||
*/ | ||
export const _fetchInternals = { | ||
stubThis: (url) => crossFetch(url), | ||
}; |
@@ -5,2 +5,6 @@ /** | ||
export declare function generateChallenge(): Promise<Uint8Array>; | ||
/** | ||
* Make it possible to stub the return value during testing | ||
* @ignore Don't include this in docs output | ||
*/ | ||
export declare const _generateChallengeInternals: { | ||
@@ -7,0 +11,0 @@ stubThis: (value: Uint8Array) => Uint8Array; |
@@ -18,5 +18,8 @@ import { isoCrypto } from './iso/index.js'; | ||
} | ||
// Make it possible to stub the return value during testing | ||
/** | ||
* Make it possible to stub the return value during testing | ||
* @ignore Don't include this in docs output | ||
*/ | ||
export const _generateChallengeInternals = { | ||
stubThis: (value) => value, | ||
}; |
@@ -5,2 +5,6 @@ /** | ||
export declare function generateUserID(): Promise<Uint8Array>; | ||
/** | ||
* Make it possible to stub the return value during testing | ||
* @ignore Don't include this in docs output | ||
*/ | ||
export declare const _generateUserIDInternals: { | ||
@@ -7,0 +11,0 @@ stubThis: (value: Uint8Array) => Uint8Array; |
@@ -14,5 +14,8 @@ import { isoCrypto } from './iso/index.js'; | ||
} | ||
// Make it possible to stub the return value during testing | ||
/** | ||
* Make it possible to stub the return value during testing | ||
* @ignore Don't include this in docs output | ||
*/ | ||
export const _generateUserIDInternals = { | ||
stubThis: (value) => value, | ||
}; |
@@ -1,24 +0,17 @@ | ||
import { convertAAGUIDToString } from './convertAAGUIDToString.js'; | ||
import { convertCertBufferToPEM } from './convertCertBufferToPEM.js'; | ||
import { convertCOSEtoPKCS } from './convertCOSEtoPKCS.js'; | ||
import { decodeAttestationObject } from './decodeAttestationObject.js'; | ||
import { decodeClientDataJSON } from './decodeClientDataJSON.js'; | ||
import { decodeCredentialPublicKey } from './decodeCredentialPublicKey.js'; | ||
import { generateChallenge } from './generateChallenge.js'; | ||
import { generateUserID } from './generateUserID.js'; | ||
import { getCertificateInfo } from './getCertificateInfo.js'; | ||
import { isCertRevoked } from './isCertRevoked.js'; | ||
import { parseAuthenticatorData } from './parseAuthenticatorData.js'; | ||
import { toHash } from './toHash.js'; | ||
import { validateCertificatePath } from './validateCertificatePath.js'; | ||
import { verifySignature } from './verifySignature.js'; | ||
import { isoBase64URL, isoCBOR, isoCrypto, isoUint8Array } from './iso/index.js'; | ||
import * as cose from './cose.js'; | ||
export { convertAAGUIDToString, convertCertBufferToPEM, convertCOSEtoPKCS, cose, decodeAttestationObject, decodeClientDataJSON, decodeCredentialPublicKey, generateChallenge, generateUserID, getCertificateInfo, isCertRevoked, isoBase64URL, isoCBOR, isoCrypto, isoUint8Array, parseAuthenticatorData, toHash, validateCertificatePath, verifySignature, }; | ||
import type { AttestationFormat, AttestationObject, AttestationStatement } from './decodeAttestationObject.js'; | ||
import type { CertificateInfo } from './getCertificateInfo.js'; | ||
import type { ClientDataJSON } from './decodeClientDataJSON.js'; | ||
import type { COSEPublicKey, COSEPublicKeyEC2, COSEPublicKeyOKP, COSEPublicKeyRSA } from './cose.js'; | ||
import type { ParsedAuthenticatorData } from './parseAuthenticatorData.js'; | ||
export type { AttestationFormat, AttestationObject, AttestationStatement, CertificateInfo, ClientDataJSON, COSEPublicKey, COSEPublicKeyEC2, COSEPublicKeyOKP, COSEPublicKeyRSA, ParsedAuthenticatorData, }; | ||
export * from './convertAAGUIDToString.js'; | ||
export * from './convertCertBufferToPEM.js'; | ||
export * from './convertCOSEtoPKCS.js'; | ||
export * from './decodeAttestationObject.js'; | ||
export * from './decodeClientDataJSON.js'; | ||
export * from './decodeCredentialPublicKey.js'; | ||
export * from './generateChallenge.js'; | ||
export * from './generateUserID.js'; | ||
export * from './getCertificateInfo.js'; | ||
export * from './isCertRevoked.js'; | ||
export * from './parseAuthenticatorData.js'; | ||
export * from './toHash.js'; | ||
export * from './validateCertificatePath.js'; | ||
export * from './verifySignature.js'; | ||
export * from './iso/index.js'; | ||
export * as cose from './cose.js'; | ||
//# sourceMappingURL=index.d.ts.map |
@@ -1,17 +0,16 @@ | ||
import { convertAAGUIDToString } from './convertAAGUIDToString.js'; | ||
import { convertCertBufferToPEM } from './convertCertBufferToPEM.js'; | ||
import { convertCOSEtoPKCS } from './convertCOSEtoPKCS.js'; | ||
import { decodeAttestationObject } from './decodeAttestationObject.js'; | ||
import { decodeClientDataJSON } from './decodeClientDataJSON.js'; | ||
import { decodeCredentialPublicKey } from './decodeCredentialPublicKey.js'; | ||
import { generateChallenge } from './generateChallenge.js'; | ||
import { generateUserID } from './generateUserID.js'; | ||
import { getCertificateInfo } from './getCertificateInfo.js'; | ||
import { isCertRevoked } from './isCertRevoked.js'; | ||
import { parseAuthenticatorData } from './parseAuthenticatorData.js'; | ||
import { toHash } from './toHash.js'; | ||
import { validateCertificatePath } from './validateCertificatePath.js'; | ||
import { verifySignature } from './verifySignature.js'; | ||
import { isoBase64URL, isoCBOR, isoCrypto, isoUint8Array } from './iso/index.js'; | ||
import * as cose from './cose.js'; | ||
export { convertAAGUIDToString, convertCertBufferToPEM, convertCOSEtoPKCS, cose, decodeAttestationObject, decodeClientDataJSON, decodeCredentialPublicKey, generateChallenge, generateUserID, getCertificateInfo, isCertRevoked, isoBase64URL, isoCBOR, isoCrypto, isoUint8Array, parseAuthenticatorData, toHash, validateCertificatePath, verifySignature, }; | ||
export * from './convertAAGUIDToString.js'; | ||
export * from './convertCertBufferToPEM.js'; | ||
export * from './convertCOSEtoPKCS.js'; | ||
export * from './decodeAttestationObject.js'; | ||
export * from './decodeClientDataJSON.js'; | ||
export * from './decodeCredentialPublicKey.js'; | ||
export * from './generateChallenge.js'; | ||
export * from './generateUserID.js'; | ||
export * from './getCertificateInfo.js'; | ||
export * from './isCertRevoked.js'; | ||
export * from './parseAuthenticatorData.js'; | ||
export * from './toHash.js'; | ||
export * from './validateCertificatePath.js'; | ||
export * from './verifySignature.js'; | ||
export * from './iso/index.js'; | ||
export * as cose from './cose.js'; |
@@ -1,2 +0,2 @@ | ||
import type { Base64URLString } from '@simplewebauthn/types'; | ||
import type { Base64URLString } from '../../types/index.js'; | ||
/** | ||
@@ -3,0 +3,0 @@ * Decode from a Base64URL-encoded string to an ArrayBuffer. Best used when converting a |
@@ -0,1 +1,5 @@ | ||
/** | ||
* A runtime-agnostic collection of methods for working with Base64URL encoding | ||
* @module | ||
*/ | ||
import base64 from '@hexagon/base64'; | ||
@@ -2,0 +6,0 @@ /** |
@@ -0,1 +1,5 @@ | ||
/** | ||
* A runtime-agnostic collection of methods for working with CBOR encoding | ||
* @module | ||
*/ | ||
import * as tinyCbor from '@levischuck/tiny-cbor'; | ||
@@ -2,0 +6,0 @@ /** |
@@ -0,1 +1,5 @@ | ||
/** | ||
* A runtime-agnostic collection of methods for working with CBOR encoding | ||
* @module | ||
*/ | ||
import * as tinyCbor from '@levischuck/tiny-cbor'; | ||
@@ -2,0 +6,0 @@ /** |
@@ -1,2 +0,2 @@ | ||
import type { Crypto } from '@simplewebauthn/types'; | ||
import type { Crypto } from '../../../types/index.js'; | ||
/** | ||
@@ -3,0 +3,0 @@ * Try to get an instance of the Crypto API from the current runtime. Should support Node, |
@@ -0,1 +1,5 @@ | ||
/** | ||
* A runtime-agnostic collection of methods for working with the WebCrypto API | ||
* @module | ||
*/ | ||
export { digest } from './digest.js'; | ||
@@ -2,0 +6,0 @@ export { getRandomValues } from './getRandomValues.js'; |
@@ -0,3 +1,7 @@ | ||
/** | ||
* A runtime-agnostic collection of methods for working with the WebCrypto API | ||
* @module | ||
*/ | ||
export { digest } from './digest.js'; | ||
export { getRandomValues } from './getRandomValues.js'; | ||
export { verify } from './verify.js'; |
/** | ||
* A runtime-agnostic collection of methods for working with Uint8Arrays | ||
* @module | ||
*/ | ||
/** | ||
* Make sure two Uint8Arrays are deeply equivalent | ||
@@ -3,0 +7,0 @@ */ |
/** | ||
* A runtime-agnostic collection of methods for working with Uint8Arrays | ||
* @module | ||
*/ | ||
/** | ||
* Make sure two Uint8Arrays are deeply equivalent | ||
@@ -3,0 +7,0 @@ */ |
@@ -26,2 +26,6 @@ import { AuthenticationExtensionsAuthenticatorOutputs } from './decodeAuthenticatorExtensions.js'; | ||
}; | ||
/** | ||
* Make it possible to stub the return value during testing | ||
* @ignore Don't include this in docs output | ||
*/ | ||
export declare const _parseAuthenticatorDataInternals: { | ||
@@ -28,0 +32,0 @@ stubThis: (value: ParsedAuthenticatorData) => ParsedAuthenticatorData; |
@@ -100,5 +100,8 @@ import { decodeAuthenticatorExtensions, } from './decodeAuthenticatorExtensions.js'; | ||
} | ||
// Make it possible to stub the return value during testing | ||
/** | ||
* Make it possible to stub the return value during testing | ||
* @ignore Don't include this in docs output | ||
*/ | ||
export const _parseAuthenticatorDataInternals = { | ||
stubThis: (value) => value, | ||
}; |
@@ -1,2 +0,2 @@ | ||
import type { CredentialDeviceType } from '@simplewebauthn/types'; | ||
import type { CredentialDeviceType } from '../types/index.js'; | ||
/** | ||
@@ -3,0 +3,0 @@ * Make sense of Bits 3 and 4 in authenticator indicating: |
/** | ||
* Traverse an array of PEM certificates and ensure they form a proper chain | ||
* @param certificates Typically the result of `x5c.map(convertASN1toPEM)` | ||
* @param rootCertificates Possible root certificates to complete the path | ||
* @param x5cCertsPEM Typically the result of `x5c.map(convertASN1toPEM)` | ||
* @param trustAnchorsPEM PEM-formatted certs that an attestation statement x5c may chain back to | ||
*/ | ||
export declare function validateCertificatePath(certificates: string[], rootCertificates?: string[]): Promise<boolean>; | ||
export declare function validateCertificatePath(x5cCertsPEM: string[], trustAnchorsPEM?: string[]): Promise<boolean>; | ||
//# sourceMappingURL=validateCertificatePath.d.ts.map |
@@ -9,9 +9,8 @@ import { AsnSerializer } from '@peculiar/asn1-schema'; | ||
* Traverse an array of PEM certificates and ensure they form a proper chain | ||
* @param certificates Typically the result of `x5c.map(convertASN1toPEM)` | ||
* @param rootCertificates Possible root certificates to complete the path | ||
* @param x5cCertsPEM Typically the result of `x5c.map(convertASN1toPEM)` | ||
* @param trustAnchorsPEM PEM-formatted certs that an attestation statement x5c may chain back to | ||
*/ | ||
export async function validateCertificatePath(certificates, rootCertificates = []) { | ||
if (rootCertificates.length === 0) { | ||
// We have no root certs with which to create a full path, so skip path validation | ||
// TODO: Is this going to be acceptable default behavior?? | ||
export async function validateCertificatePath(x5cCertsPEM, trustAnchorsPEM = []) { | ||
if (trustAnchorsPEM.length === 0) { | ||
// We have no trust anchors to chain back to, so skip path validation | ||
return true; | ||
@@ -21,8 +20,8 @@ } | ||
let certificateNotYetValidOrExpiredErrorMessage = undefined; | ||
for (const rootCert of rootCertificates) { | ||
for (const anchorPEM of trustAnchorsPEM) { | ||
try { | ||
const certsWithRoot = certificates.concat([rootCert]); | ||
await _validatePath(certsWithRoot); | ||
const certsWithTrustAnchor = x5cCertsPEM.concat([anchorPEM]); | ||
await _validatePath(certsWithTrustAnchor); | ||
// If we successfully validated a path then there's no need to continue. Reset any existing | ||
// errors that were thrown by earlier root certificates | ||
// errors that were thrown by earlier trust anchors | ||
invalidSubjectAndIssuerError = false; | ||
@@ -44,3 +43,3 @@ certificateNotYetValidOrExpiredErrorMessage = undefined; | ||
} | ||
// We tried multiple root certs and none of them worked | ||
// We tried multiple trust anchors and none of them worked | ||
if (invalidSubjectAndIssuerError) { | ||
@@ -54,56 +53,31 @@ throw new InvalidSubjectAndIssuer(); | ||
} | ||
async function _validatePath(certificates) { | ||
if (new Set(certificates).size !== certificates.length) { | ||
/** | ||
* @param x5cCerts X.509 `x5c` certs in PEM string format | ||
* @param anchorCert X.509 trust anchor cert in PEM string format | ||
*/ | ||
async function _validatePath(x5cCertsWithTrustAnchorPEM) { | ||
if (new Set(x5cCertsWithTrustAnchorPEM).size !== x5cCertsWithTrustAnchorPEM.length) { | ||
throw new Error('Invalid certificate path: found duplicate certificates'); | ||
} | ||
// From leaf to root, make sure each cert is issued by the next certificate in the chain | ||
for (let i = 0; i < certificates.length; i += 1) { | ||
const subjectPem = certificates[i]; | ||
const isLeafCert = i === 0; | ||
const isRootCert = i + 1 >= certificates.length; | ||
let issuerPem = ''; | ||
if (isRootCert) { | ||
issuerPem = subjectPem; | ||
} | ||
else { | ||
issuerPem = certificates[i + 1]; | ||
} | ||
// Make sure no certs are revoked, and all are within their time validity window | ||
for (const certificatePEM of x5cCertsWithTrustAnchorPEM) { | ||
const certInfo = getCertificateInfo(convertPEMToBytes(certificatePEM)); | ||
await assertCertNotRevoked(certInfo.parsedCertificate); | ||
assertCertIsWithinValidTimeWindow(certInfo, certificatePEM); | ||
} | ||
// Make sure each x5c cert is issued by the next certificate in the chain | ||
for (let i = 0; i < (x5cCertsWithTrustAnchorPEM.length - 1); i += 1) { | ||
const subjectPem = x5cCertsWithTrustAnchorPEM[i]; | ||
const issuerPem = x5cCertsWithTrustAnchorPEM[i + 1]; | ||
const subjectInfo = getCertificateInfo(convertPEMToBytes(subjectPem)); | ||
const issuerInfo = getCertificateInfo(convertPEMToBytes(issuerPem)); | ||
const x509Subject = subjectInfo.parsedCertificate; | ||
// Check for certificate revocation | ||
const subjectCertRevoked = await isCertRevoked(x509Subject); | ||
if (subjectCertRevoked) { | ||
throw new Error(`Found revoked certificate in certificate path`); | ||
} | ||
// Check that intermediate certificate is within its valid time window | ||
const { notBefore, notAfter } = issuerInfo; | ||
const now = new Date(Date.now()); | ||
if (notBefore > now || notAfter < now) { | ||
if (isLeafCert) { | ||
throw new CertificateNotYetValidOrExpired(`Leaf certificate is not yet valid or expired: ${issuerPem}`); | ||
} | ||
else if (isRootCert) { | ||
throw new CertificateNotYetValidOrExpired(`Root certificate is not yet valid or expired: ${issuerPem}`); | ||
} | ||
else { | ||
throw new CertificateNotYetValidOrExpired(`Intermediate certificate is not yet valid or expired: ${issuerPem}`); | ||
} | ||
} | ||
// Make sure subject issuer is issuer subject | ||
if (subjectInfo.issuer.combined !== issuerInfo.subject.combined) { | ||
throw new InvalidSubjectAndIssuer(); | ||
} | ||
// Verify the subject certificate's signature with the issuer cert's public key | ||
const data = AsnSerializer.serialize(x509Subject.tbsCertificate); | ||
const signature = x509Subject.signatureValue; | ||
const signatureAlgorithm = mapX509SignatureAlgToCOSEAlg(x509Subject.signatureAlgorithm.algorithm); | ||
const issuerCertBytes = convertPEMToBytes(issuerPem); | ||
const verified = await verifySignature({ | ||
data: new Uint8Array(data), | ||
signature: new Uint8Array(signature), | ||
x509Certificate: issuerCertBytes, | ||
hashAlgorithm: signatureAlgorithm, | ||
}); | ||
if (!verified) { | ||
throw new Error('Invalid certificate path: invalid signature'); | ||
const issuerCertIsRootCert = issuerInfo.issuer.combined === issuerInfo.subject.combined; | ||
await assertSubjectIsSignedByIssuer(subjectInfo.parsedCertificate, issuerPem); | ||
// Perform one final check if the issuer cert is also a root certificate | ||
if (issuerCertIsRootCert) { | ||
await assertSubjectIsSignedByIssuer(issuerInfo.parsedCertificate, issuerPem); | ||
} | ||
@@ -113,2 +87,44 @@ } | ||
} | ||
/** | ||
* Check if the certificate is revoked or not. If it is, raise an error | ||
*/ | ||
async function assertCertNotRevoked(certificate) { | ||
// Check for certificate revocation | ||
const subjectCertRevoked = await isCertRevoked(certificate); | ||
if (subjectCertRevoked) { | ||
throw new Error(`Found revoked certificate in certificate path`); | ||
} | ||
} | ||
/** | ||
* Require the cert to be within its notBefore and notAfter time window | ||
* | ||
* @param certInfo Parsed cert information | ||
* @param certPEM PEM-formatted certificate, for error reporting | ||
*/ | ||
function assertCertIsWithinValidTimeWindow(certInfo, certPEM) { | ||
const { notBefore, notAfter } = certInfo; | ||
const now = new Date(Date.now()); | ||
if (notBefore > now || notAfter < now) { | ||
throw new CertificateNotYetValidOrExpired(`Certificate is not yet valid or expired: ${certPEM}`); | ||
} | ||
} | ||
/** | ||
* Ensure that the subject cert has been signed by the next cert in the chain | ||
*/ | ||
async function assertSubjectIsSignedByIssuer(subjectCert, issuerPEM) { | ||
// Verify the subject certificate's signature with the issuer cert's public key | ||
const data = AsnSerializer.serialize(subjectCert.tbsCertificate); | ||
const signature = subjectCert.signatureValue; | ||
const signatureAlgorithm = mapX509SignatureAlgToCOSEAlg(subjectCert.signatureAlgorithm.algorithm); | ||
const issuerCertBytes = convertPEMToBytes(issuerPEM); | ||
const verified = await verifySignature({ | ||
data: new Uint8Array(data), | ||
signature: new Uint8Array(signature), | ||
x509Certificate: issuerCertBytes, | ||
hashAlgorithm: signatureAlgorithm, | ||
}); | ||
if (!verified) { | ||
throw new InvalidSubjectSignatureForIssuer(); | ||
} | ||
} | ||
// Custom errors to help pass on certain errors | ||
@@ -122,2 +138,9 @@ class InvalidSubjectAndIssuer extends Error { | ||
} | ||
class InvalidSubjectSignatureForIssuer extends Error { | ||
constructor() { | ||
const message = 'Subject signature was invalid for issuer'; | ||
super(message); | ||
this.name = 'InvalidSubjectSignatureForIssuer'; | ||
} | ||
} | ||
class CertificateNotYetValidOrExpired extends Error { | ||
@@ -124,0 +147,0 @@ constructor(message) { |
@@ -12,2 +12,6 @@ import { COSEALG } from './cose.js'; | ||
}): Promise<boolean>; | ||
/** | ||
* Make it possible to stub the return value during testing | ||
* @ignore Don't include this in docs output | ||
*/ | ||
export declare const _verifySignatureInternals: { | ||
@@ -14,0 +18,0 @@ stubThis: (value: Promise<boolean>) => Promise<boolean>; |
@@ -29,5 +29,8 @@ import { isoCrypto } from './iso/index.js'; | ||
} | ||
// Make it possible to stub the return value during testing | ||
/** | ||
* Make it possible to stub the return value during testing | ||
* @ignore Don't include this in docs output | ||
*/ | ||
export const _verifySignatureInternals = { | ||
stubThis: (value) => value, | ||
}; |
@@ -1,18 +0,9 @@ | ||
/** | ||
* @packageDocumentation | ||
* @module @simplewebauthn/server | ||
*/ | ||
import { generateRegistrationOptions } from './registration/generateRegistrationOptions.js'; | ||
import { verifyRegistrationResponse } from './registration/verifyRegistrationResponse.js'; | ||
import { generateAuthenticationOptions } from './authentication/generateAuthenticationOptions.js'; | ||
import { verifyAuthenticationResponse } from './authentication/verifyAuthenticationResponse.js'; | ||
import { MetadataService } from './services/metadataService.js'; | ||
import { SettingsService } from './services/settingsService.js'; | ||
export { generateAuthenticationOptions, generateRegistrationOptions, MetadataService, SettingsService, verifyAuthenticationResponse, verifyRegistrationResponse, }; | ||
import type { GenerateRegistrationOptionsOpts } from './registration/generateRegistrationOptions.js'; | ||
import type { GenerateAuthenticationOptionsOpts } from './authentication/generateAuthenticationOptions.js'; | ||
import type { MetadataStatement } from './metadata/mdsTypes.js'; | ||
import type { VerifiedRegistrationResponse, VerifyRegistrationResponseOpts } from './registration/verifyRegistrationResponse.js'; | ||
import type { VerifiedAuthenticationResponse, VerifyAuthenticationResponseOpts } from './authentication/verifyAuthenticationResponse.js'; | ||
export type { GenerateAuthenticationOptionsOpts, GenerateRegistrationOptionsOpts, MetadataStatement, VerifiedAuthenticationResponse, VerifiedRegistrationResponse, VerifyAuthenticationResponseOpts, VerifyRegistrationResponseOpts, }; | ||
export * from './registration/generateRegistrationOptions.js'; | ||
export * from './registration/verifyRegistrationResponse.js'; | ||
export * from './authentication/generateAuthenticationOptions.js'; | ||
export * from './authentication/verifyAuthenticationResponse.js'; | ||
export * from './services/metadataService.js'; | ||
export * from './services/settingsService.js'; | ||
export * from './metadata/mdsTypes.js'; | ||
export * from './types/index.js'; | ||
//# sourceMappingURL=index.d.ts.map |
@@ -1,11 +0,8 @@ | ||
/** | ||
* @packageDocumentation | ||
* @module @simplewebauthn/server | ||
*/ | ||
import { generateRegistrationOptions } from './registration/generateRegistrationOptions.js'; | ||
import { verifyRegistrationResponse } from './registration/verifyRegistrationResponse.js'; | ||
import { generateAuthenticationOptions } from './authentication/generateAuthenticationOptions.js'; | ||
import { verifyAuthenticationResponse } from './authentication/verifyAuthenticationResponse.js'; | ||
import { MetadataService } from './services/metadataService.js'; | ||
import { SettingsService } from './services/settingsService.js'; | ||
export { generateAuthenticationOptions, generateRegistrationOptions, MetadataService, SettingsService, verifyAuthenticationResponse, verifyRegistrationResponse, }; | ||
export * from './registration/generateRegistrationOptions.js'; | ||
export * from './registration/verifyRegistrationResponse.js'; | ||
export * from './authentication/generateAuthenticationOptions.js'; | ||
export * from './authentication/verifyAuthenticationResponse.js'; | ||
export * from './services/metadataService.js'; | ||
export * from './services/settingsService.js'; | ||
export * from './metadata/mdsTypes.js'; | ||
export * from './types/index.js'; |
@@ -1,2 +0,2 @@ | ||
import type { Base64URLString } from '@simplewebauthn/types'; | ||
import type { Base64URLString } from '../types/index.js'; | ||
/** | ||
@@ -6,2 +6,3 @@ * Metadata Service structures | ||
*/ | ||
/** */ | ||
export type MDSJWTHeader = { | ||
@@ -109,2 +110,5 @@ alg: string; | ||
}; | ||
/** | ||
* langCode -> "en-US", "ja-JP", etc... | ||
*/ | ||
export type AlternativeDescriptions = { | ||
@@ -111,0 +115,0 @@ [langCode: string]: string; |
@@ -1,4 +0,4 @@ | ||
import type { Base64URLString } from '@simplewebauthn/types'; | ||
import type { Base64URLString } from '../types/index.js'; | ||
import type { AlgSign, MetadataStatement } from './mdsTypes.js'; | ||
import { COSEALG, COSECRV, COSEKTY } from '../helpers/cose.js'; | ||
import { type COSEALG, type COSECRV, COSEKTY } from '../helpers/cose.js'; | ||
/** | ||
@@ -5,0 +5,0 @@ * Match properties of the authenticator's attestation statement against expected values as |
import { convertCertBufferToPEM } from '../helpers/convertCertBufferToPEM.js'; | ||
import { validateCertificatePath } from '../helpers/validateCertificatePath.js'; | ||
import { decodeCredentialPublicKey } from '../helpers/decodeCredentialPublicKey.js'; | ||
import { COSEKEYS, COSEKTY, isCOSEPublicKeyEC2 } from '../helpers/cose.js'; | ||
import { COSEKEYS, COSEKTY, isCOSEPublicKeyEC2, } from '../helpers/cose.js'; | ||
/** | ||
@@ -6,0 +6,0 @@ * Match properties of the authenticator's attestation statement against expected values as |
@@ -1,19 +0,3 @@ | ||
import type { AttestationConveyancePreference, AuthenticationExtensionsClientInputs, AuthenticatorSelectionCriteria, AuthenticatorTransportFuture, Base64URLString, COSEAlgorithmIdentifier, PublicKeyCredentialCreationOptionsJSON } from '@simplewebauthn/types'; | ||
export type GenerateRegistrationOptionsOpts = { | ||
rpName: string; | ||
rpID: string; | ||
userName: string; | ||
userID?: Uint8Array; | ||
challenge?: string | Uint8Array; | ||
userDisplayName?: string; | ||
timeout?: number; | ||
attestationType?: AttestationConveyancePreference; | ||
excludeCredentials?: { | ||
id: Base64URLString; | ||
transports?: AuthenticatorTransportFuture[]; | ||
}[]; | ||
authenticatorSelection?: AuthenticatorSelectionCriteria; | ||
extensions?: AuthenticationExtensionsClientInputs; | ||
supportedAlgorithmIDs?: COSEAlgorithmIdentifier[]; | ||
}; | ||
import type { AuthenticationExtensionsClientInputs, AuthenticatorSelectionCriteria, AuthenticatorTransportFuture, Base64URLString, COSEAlgorithmIdentifier, PublicKeyCredentialCreationOptionsJSON } from '../types/index.js'; | ||
export type GenerateRegistrationOptionsOpts = Parameters<typeof generateRegistrationOptions>[0]; | ||
/** | ||
@@ -42,4 +26,22 @@ * Supported crypto algo identifiers | ||
* @param supportedAlgorithmIDs **(Optional)** - Array of numeric COSE algorithm identifiers supported for attestation by this RP. See https://www.iana.org/assignments/cose/cose.xhtml#algorithms. Defaults to `[-8, -7, -257]` | ||
* @param preferredAuthenticatorType **(Optional)** - Encourage the browser to prompt the user to register a specific type of authenticator | ||
*/ | ||
export declare function generateRegistrationOptions(options: GenerateRegistrationOptionsOpts): Promise<PublicKeyCredentialCreationOptionsJSON>; | ||
export declare function generateRegistrationOptions(options: { | ||
rpName: string; | ||
rpID: string; | ||
userName: string; | ||
userID?: Uint8Array; | ||
challenge?: string | Uint8Array; | ||
userDisplayName?: string; | ||
timeout?: number; | ||
attestationType?: 'direct' | 'enterprise' | 'none'; | ||
excludeCredentials?: { | ||
id: Base64URLString; | ||
transports?: AuthenticatorTransportFuture[]; | ||
}[]; | ||
authenticatorSelection?: AuthenticatorSelectionCriteria; | ||
extensions?: AuthenticationExtensionsClientInputs; | ||
supportedAlgorithmIDs?: COSEAlgorithmIdentifier[]; | ||
preferredAuthenticatorType?: 'securityKey' | 'localDevice' | 'remoteDevice'; | ||
}): Promise<PublicKeyCredentialCreationOptionsJSON>; | ||
//# sourceMappingURL=generateRegistrationOptions.d.ts.map |
@@ -66,5 +66,6 @@ import { generateChallenge } from '../helpers/generateChallenge.js'; | ||
* @param supportedAlgorithmIDs **(Optional)** - Array of numeric COSE algorithm identifiers supported for attestation by this RP. See https://www.iana.org/assignments/cose/cose.xhtml#algorithms. Defaults to `[-8, -7, -257]` | ||
* @param preferredAuthenticatorType **(Optional)** - Encourage the browser to prompt the user to register a specific type of authenticator | ||
*/ | ||
export async function generateRegistrationOptions(options) { | ||
const { rpName, rpID, userName, userID, challenge = await generateChallenge(), userDisplayName = '', timeout = 60000, attestationType = 'none', excludeCredentials = [], authenticatorSelection = defaultAuthenticatorSelection, extensions, supportedAlgorithmIDs = defaultSupportedAlgorithmIDs, } = options; | ||
const { rpName, rpID, userName, userID, challenge = await generateChallenge(), userDisplayName = '', timeout = 60000, attestationType = 'none', excludeCredentials = [], authenticatorSelection = defaultAuthenticatorSelection, extensions, supportedAlgorithmIDs = defaultSupportedAlgorithmIDs, preferredAuthenticatorType, } = options; | ||
/** | ||
@@ -131,2 +132,21 @@ * Prepare pubKeyCredParams from the array of algorithm ID's | ||
} | ||
/** | ||
* Map authenticator preference to hints. Map to authenticatorAttachment as well for | ||
* backwards-compatibility. | ||
*/ | ||
const hints = []; | ||
if (preferredAuthenticatorType) { | ||
if (preferredAuthenticatorType === 'securityKey') { | ||
hints.push('security-key'); | ||
authenticatorSelection.authenticatorAttachment = 'cross-platform'; | ||
} | ||
else if (preferredAuthenticatorType === 'localDevice') { | ||
hints.push('client-device'); | ||
authenticatorSelection.authenticatorAttachment = 'platform'; | ||
} | ||
else if (preferredAuthenticatorType === 'remoteDevice') { | ||
hints.push('hybrid'); | ||
authenticatorSelection.authenticatorAttachment = 'cross-platform'; | ||
} | ||
} | ||
return { | ||
@@ -161,3 +181,4 @@ challenge: isoBase64URL.fromBuffer(_challenge), | ||
}, | ||
hints, | ||
}; | ||
} |
@@ -1,15 +0,9 @@ | ||
import type { COSEAlgorithmIdentifier, CredentialDeviceType, RegistrationResponseJSON, WebAuthnCredential } from '@simplewebauthn/types'; | ||
import { AttestationFormat, AttestationStatement } from '../helpers/decodeAttestationObject.js'; | ||
import { AuthenticationExtensionsAuthenticatorOutputs } from '../helpers/decodeAuthenticatorExtensions.js'; | ||
export type VerifyRegistrationResponseOpts = { | ||
response: RegistrationResponseJSON; | ||
expectedChallenge: string | ((challenge: string) => boolean | Promise<boolean>); | ||
expectedOrigin: string | string[]; | ||
expectedRPID?: string | string[]; | ||
expectedType?: string | string[]; | ||
requireUserPresence?: boolean; | ||
requireUserVerification?: boolean; | ||
supportedAlgorithmIDs?: COSEAlgorithmIdentifier[]; | ||
}; | ||
import type { COSEAlgorithmIdentifier, CredentialDeviceType, RegistrationResponseJSON, WebAuthnCredential } from '../types/index.js'; | ||
import { type AttestationFormat, type AttestationStatement } from '../helpers/decodeAttestationObject.js'; | ||
import type { AuthenticationExtensionsAuthenticatorOutputs } from '../helpers/decodeAuthenticatorExtensions.js'; | ||
/** | ||
* Configurable options when calling `verifyRegistrationResponse()` | ||
*/ | ||
export type VerifyRegistrationResponseOpts = Parameters<typeof verifyRegistrationResponse>[0]; | ||
/** | ||
* Verify that the user has legitimately completed the registration process | ||
@@ -28,3 +22,12 @@ * | ||
*/ | ||
export declare function verifyRegistrationResponse(options: VerifyRegistrationResponseOpts): Promise<VerifiedRegistrationResponse>; | ||
export declare function verifyRegistrationResponse(options: { | ||
response: RegistrationResponseJSON; | ||
expectedChallenge: string | ((challenge: string) => boolean | Promise<boolean>); | ||
expectedOrigin: string | string[]; | ||
expectedRPID?: string | string[]; | ||
expectedType?: string | string[]; | ||
requireUserPresence?: boolean; | ||
requireUserVerification?: boolean; | ||
supportedAlgorithmIDs?: COSEAlgorithmIdentifier[]; | ||
}): Promise<VerifiedRegistrationResponse>; | ||
/** | ||
@@ -31,0 +34,0 @@ * Result of registration verification |
import type { MetadataStatement } from '../metadata/mdsTypes.js'; | ||
type VerificationMode = 'permissive' | 'strict'; | ||
interface MetadataService { | ||
initialize(opts?: { | ||
mdsServers?: string[]; | ||
statements?: MetadataStatement[]; | ||
verificationMode?: VerificationMode; | ||
}): Promise<void>; | ||
getStatement(aaguid: string | Uint8Array): Promise<MetadataStatement | undefined>; | ||
} | ||
/** | ||
* An implementation of `MetadataService` that can download and parse BLOBs, and support on-demand | ||
* requesting and caching of individual metadata statements. | ||
* | ||
* https://fidoalliance.org/metadata/ | ||
* Allow MetadataService to accommodate unregistered AAGUIDs (`"permissive"`), or only allow | ||
* registered AAGUIDs (`"strict"`). Currently primarily impacts how `getStatement()` operates | ||
*/ | ||
export declare class BaseMetadataService implements MetadataService { | ||
private mdsCache; | ||
private statementCache; | ||
private state; | ||
private verificationMode; | ||
export type VerificationMode = 'permissive' | 'strict'; | ||
interface MetadataService { | ||
/** | ||
@@ -47,2 +33,20 @@ * Prepare the service to handle remote MDS servers and/or cache local metadata statements. | ||
getStatement(aaguid: string | Uint8Array): Promise<MetadataStatement | undefined>; | ||
} | ||
/** | ||
* An implementation of `MetadataService` that can download and parse BLOBs, and support on-demand | ||
* requesting and caching of individual metadata statements. | ||
* | ||
* https://fidoalliance.org/metadata/ | ||
*/ | ||
export declare class BaseMetadataService implements MetadataService { | ||
private mdsCache; | ||
private statementCache; | ||
private state; | ||
private verificationMode; | ||
initialize(opts?: { | ||
mdsServers?: string[]; | ||
statements?: MetadataStatement[]; | ||
verificationMode?: VerificationMode; | ||
}): Promise<void>; | ||
getStatement(aaguid: string | Uint8Array): Promise<MetadataStatement | undefined>; | ||
/** | ||
@@ -49,0 +53,0 @@ * Download and process the latest BLOB from MDS |
@@ -51,15 +51,2 @@ import { validateCertificatePath } from '../helpers/validateCertificatePath.js'; | ||
} | ||
/** | ||
* Prepare the service to handle remote MDS servers and/or cache local metadata statements. | ||
* | ||
* **Options:** | ||
* | ||
* @param opts.mdsServers An array of URLs to FIDO Alliance Metadata Service | ||
* (version 3.0)-compatible servers. Defaults to the official FIDO MDS server | ||
* @param opts.statements An array of local metadata statements | ||
* @param opts.verificationMode How MetadataService will handle unregistered AAGUIDs. Defaults to | ||
* `"strict"` which throws errors during registration response verification when an | ||
* unregistered AAGUID is encountered. Set to `"permissive"` to allow registration by | ||
* authenticators with unregistered AAGUIDs | ||
*/ | ||
async initialize(opts = {}) { | ||
@@ -116,8 +103,2 @@ const { mdsServers = [defaultURLMDS], statements, verificationMode } = opts; | ||
} | ||
/** | ||
* Get a metadata statement for a given AAGUID. | ||
* | ||
* This method will coordinate updating the cache as per the `nextUpdate` property in the initial | ||
* BLOB download. | ||
*/ | ||
async getStatement(aaguid) { | ||
@@ -124,0 +105,0 @@ if (this.state === SERVICE_STATE.DISABLED) { |
import { AttestationFormat } from '../helpers/decodeAttestationObject.js'; | ||
type RootCertIdentifier = AttestationFormat | 'mds'; | ||
export type RootCertIdentifier = AttestationFormat | 'mds'; | ||
interface SettingsService { | ||
/** | ||
* Set potential root certificates for attestation formats that use them. Root certs will be tried | ||
* one-by-one when validating a certificate path. | ||
* | ||
* Certificates can be specified as a raw `Buffer`, or as a PEM-formatted string. If a | ||
* `Buffer` is passed in it will be converted to PEM format. | ||
*/ | ||
setRootCertificates(opts: { | ||
@@ -8,2 +15,5 @@ identifier: RootCertIdentifier; | ||
}): void; | ||
/** | ||
* Get any registered root certificates for the specified attestation format | ||
*/ | ||
getRootCertificates(opts: { | ||
@@ -10,0 +20,0 @@ identifier: RootCertIdentifier; |
@@ -17,9 +17,2 @@ import { convertCertBufferToPEM } from '../helpers/convertCertBufferToPEM.js'; | ||
} | ||
/** | ||
* Set potential root certificates for attestation formats that use them. Root certs will be tried | ||
* one-by-one when validating a certificate path. | ||
* | ||
* Certificates can be specified as a raw `Buffer`, or as a PEM-formatted string. If a | ||
* `Buffer` is passed in it will be converted to PEM format. | ||
*/ | ||
setRootCertificates(opts) { | ||
@@ -38,5 +31,2 @@ const { identifier, certificates } = opts; | ||
} | ||
/** | ||
* Get any registered root certificates for the specified attestation format | ||
*/ | ||
getRootCertificates(opts) { | ||
@@ -43,0 +33,0 @@ const { identifier } = opts; |
{ | ||
"name": "@simplewebauthn/server", | ||
"version": "12.0.0", | ||
"version": "13.0.0-alpha1", | ||
"description": "SimpleWebAuthn for Servers", | ||
@@ -59,4 +59,3 @@ "keywords": [ | ||
"@peculiar/asn1-x509": "^2.3.8", | ||
"cross-fetch": "^4.0.0", | ||
"@simplewebauthn/types": "^12.0.0" | ||
"cross-fetch": "^4.0.0" | ||
}, | ||
@@ -63,0 +62,0 @@ "devDependencies": { |
@@ -21,3 +21,3 @@ # @simplewebauthn/server <!-- omit in toc --> | ||
```sh | ||
npm install @simplewebauthn/server @simplewebauthn/types | ||
npm install @simplewebauthn/server | ||
``` | ||
@@ -28,3 +28,3 @@ | ||
```sh | ||
deno add jsr:@simplewebauthn/server jsr:@simplewebauthn/types | ||
deno add jsr:@simplewebauthn/server | ||
``` | ||
@@ -31,0 +31,0 @@ |
@@ -1,13 +0,3 @@ | ||
import type { AuthenticationExtensionsClientInputs, AuthenticatorTransportFuture, Base64URLString, PublicKeyCredentialRequestOptionsJSON, UserVerificationRequirement } from '@simplewebauthn/types'; | ||
export type GenerateAuthenticationOptionsOpts = { | ||
rpID: string; | ||
allowCredentials?: { | ||
id: Base64URLString; | ||
transports?: AuthenticatorTransportFuture[]; | ||
}[]; | ||
challenge?: string | Uint8Array; | ||
timeout?: number; | ||
userVerification?: UserVerificationRequirement; | ||
extensions?: AuthenticationExtensionsClientInputs; | ||
}; | ||
import type { AuthenticationExtensionsClientInputs, AuthenticatorTransportFuture, Base64URLString, PublicKeyCredentialRequestOptionsJSON } from '../types/index.js'; | ||
export type GenerateAuthenticationOptionsOpts = Parameters<typeof generateAuthenticationOptions>[0]; | ||
/** | ||
@@ -25,3 +15,13 @@ * Prepare a value to pass into navigator.credentials.get(...) for authenticator authentication | ||
*/ | ||
export declare function generateAuthenticationOptions(options: GenerateAuthenticationOptionsOpts): Promise<PublicKeyCredentialRequestOptionsJSON>; | ||
export declare function generateAuthenticationOptions(options: { | ||
rpID: string; | ||
allowCredentials?: { | ||
id: Base64URLString; | ||
transports?: AuthenticatorTransportFuture[]; | ||
}[]; | ||
challenge?: string | Uint8Array; | ||
timeout?: number; | ||
userVerification?: 'required' | 'preferred' | 'discouraged'; | ||
extensions?: AuthenticationExtensionsClientInputs; | ||
}): Promise<PublicKeyCredentialRequestOptionsJSON>; | ||
//# sourceMappingURL=generateAuthenticationOptions.d.ts.map |
@@ -1,16 +0,8 @@ | ||
import type { AuthenticationResponseJSON, Base64URLString, CredentialDeviceType, UserVerificationRequirement, WebAuthnCredential } from '@simplewebauthn/types'; | ||
import { AuthenticationExtensionsAuthenticatorOutputs } from '../helpers/decodeAuthenticatorExtensions.js'; | ||
export type VerifyAuthenticationResponseOpts = { | ||
response: AuthenticationResponseJSON; | ||
expectedChallenge: string | ((challenge: string) => boolean | Promise<boolean>); | ||
expectedOrigin: string | string[]; | ||
expectedRPID: string | string[]; | ||
credential: WebAuthnCredential; | ||
expectedType?: string | string[]; | ||
requireUserVerification?: boolean; | ||
advancedFIDOConfig?: { | ||
userVerification?: UserVerificationRequirement; | ||
}; | ||
}; | ||
import type { AuthenticationResponseJSON, Base64URLString, CredentialDeviceType, UserVerificationRequirement, WebAuthnCredential } from '../types/index.js'; | ||
import type { AuthenticationExtensionsAuthenticatorOutputs } from '../helpers/decodeAuthenticatorExtensions.js'; | ||
/** | ||
* Configurable options when calling `verifyAuthenticationResponse()` | ||
*/ | ||
export type VerifyAuthenticationResponseOpts = Parameters<typeof verifyAuthenticationResponse>[0]; | ||
/** | ||
* Verify that the user has legitimately completed the authentication process | ||
@@ -30,3 +22,14 @@ * | ||
*/ | ||
export declare function verifyAuthenticationResponse(options: VerifyAuthenticationResponseOpts): Promise<VerifiedAuthenticationResponse>; | ||
export declare function verifyAuthenticationResponse(options: { | ||
response: AuthenticationResponseJSON; | ||
expectedChallenge: string | ((challenge: string) => boolean | Promise<boolean>); | ||
expectedOrigin: string | string[]; | ||
expectedRPID: string | string[]; | ||
credential: WebAuthnCredential; | ||
expectedType?: string | string[]; | ||
requireUserVerification?: boolean; | ||
advancedFIDOConfig?: { | ||
userVerification?: UserVerificationRequirement; | ||
}; | ||
}): Promise<VerifiedAuthenticationResponse>; | ||
/** | ||
@@ -33,0 +36,0 @@ * Result of authentication verification |
@@ -1,2 +0,2 @@ | ||
import type { Base64URLString } from '@simplewebauthn/types'; | ||
import type { Base64URLString } from '../types/index.js'; | ||
/** | ||
@@ -3,0 +3,0 @@ * Convert buffer to an OpenSSL-compatible PEM text format. |
@@ -10,3 +10,7 @@ /** | ||
* keys", but it works. | ||
* @module | ||
*/ | ||
/** | ||
* COSE public key common values | ||
*/ | ||
export type COSEPublicKey = { | ||
@@ -18,2 +22,5 @@ get(key: COSEKEYS.kty): COSEKTY | undefined; | ||
}; | ||
/** | ||
* Values specific to Octet Key Pair public keys | ||
*/ | ||
export type COSEPublicKeyOKP = COSEPublicKey & { | ||
@@ -25,2 +32,5 @@ get(key: COSEKEYS.crv): number | undefined; | ||
}; | ||
/** | ||
* Values specific to Elliptic Curve Cryptography public keys | ||
*/ | ||
export type COSEPublicKeyEC2 = COSEPublicKey & { | ||
@@ -34,2 +44,5 @@ get(key: COSEKEYS.crv): number | undefined; | ||
}; | ||
/** | ||
* Values specific to RSA public keys | ||
*/ | ||
export type COSEPublicKeyRSA = COSEPublicKey & { | ||
@@ -41,4 +54,13 @@ get(key: COSEKEYS.n): Uint8Array | undefined; | ||
}; | ||
/** | ||
* A type guard for determining if a COSE public key is an OKP key pair | ||
*/ | ||
export declare function isCOSEPublicKeyOKP(cosePublicKey: COSEPublicKey): cosePublicKey is COSEPublicKeyOKP; | ||
/** | ||
* A type guard for determining if a COSE public key is an EC2 key pair | ||
*/ | ||
export declare function isCOSEPublicKeyEC2(cosePublicKey: COSEPublicKey): cosePublicKey is COSEPublicKeyEC2; | ||
/** | ||
* A type guard for determining if a COSE public key is an RSA key pair | ||
*/ | ||
export declare function isCOSEPublicKeyRSA(cosePublicKey: COSEPublicKey): cosePublicKey is COSEPublicKeyRSA; | ||
@@ -45,0 +67,0 @@ /** |
"use strict"; | ||
/** | ||
* Fundamental values that are needed to discern the more specific COSE public key types below. | ||
* | ||
* The use of `Maps` here is due to CBOR encoding being used with public keys, and the CBOR "Map" | ||
* type is being decoded to JavaScript's `Map` type instead of, say, a basic Object as us JS | ||
* developers might prefer. | ||
* | ||
* These types are an unorthodox way of saying "these Maps should involve these discrete lists of | ||
* keys", but it works. | ||
* @module | ||
*/ | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
@@ -10,2 +21,5 @@ exports.COSEALG = exports.COSECRV = exports.COSEKTY = exports.COSEKEYS = void 0; | ||
exports.isCOSEAlg = isCOSEAlg; | ||
/** | ||
* A type guard for determining if a COSE public key is an OKP key pair | ||
*/ | ||
function isCOSEPublicKeyOKP(cosePublicKey) { | ||
@@ -15,2 +29,5 @@ const kty = cosePublicKey.get(COSEKEYS.kty); | ||
} | ||
/** | ||
* A type guard for determining if a COSE public key is an EC2 key pair | ||
*/ | ||
function isCOSEPublicKeyEC2(cosePublicKey) { | ||
@@ -20,2 +37,5 @@ const kty = cosePublicKey.get(COSEKEYS.kty); | ||
} | ||
/** | ||
* A type guard for determining if a COSE public key is an RSA key pair | ||
*/ | ||
function isCOSEPublicKeyRSA(cosePublicKey) { | ||
@@ -22,0 +42,0 @@ const kty = cosePublicKey.get(COSEKEYS.kty); |
@@ -27,2 +27,6 @@ /** | ||
}; | ||
/** | ||
* Make it possible to stub the return value during testing | ||
* @ignore Don't include this in docs output | ||
*/ | ||
export declare const _decodeAttestationObjectInternals: { | ||
@@ -29,0 +33,0 @@ stubThis: (value: AttestationObject) => AttestationObject; |
@@ -14,5 +14,8 @@ "use strict"; | ||
} | ||
// Make it possible to stub the return value during testing | ||
/** | ||
* Make it possible to stub the return value during testing | ||
* @ignore Don't include this in docs output | ||
*/ | ||
exports._decodeAttestationObjectInternals = { | ||
stubThis: (value) => value, | ||
}; |
@@ -1,2 +0,2 @@ | ||
import type { Base64URLString } from '@simplewebauthn/types'; | ||
import type { Base64URLString } from '../types/index.js'; | ||
/** | ||
@@ -16,2 +16,6 @@ * Decode an authenticator's base64url-encoded clientDataJSON to JSON | ||
}; | ||
/** | ||
* Make it possible to stub the return value during testing | ||
* @ignore Don't include this in docs output | ||
*/ | ||
export declare const _decodeClientDataJSONInternals: { | ||
@@ -18,0 +22,0 @@ stubThis: (value: ClientDataJSON) => ClientDataJSON; |
@@ -14,5 +14,8 @@ "use strict"; | ||
} | ||
// Make it possible to stub the return value during testing | ||
/** | ||
* Make it possible to stub the return value during testing | ||
* @ignore Don't include this in docs output | ||
*/ | ||
exports._decodeClientDataJSONInternals = { | ||
stubThis: (value) => value, | ||
}; |
import { COSEPublicKey } from './cose.js'; | ||
export declare function decodeCredentialPublicKey(publicKey: Uint8Array): COSEPublicKey; | ||
/** | ||
* Make it possible to stub the return value during testing | ||
* @ignore Don't include this in docs output | ||
*/ | ||
export declare const _decodeCredentialPublicKeyInternals: { | ||
@@ -4,0 +8,0 @@ stubThis: (value: COSEPublicKey) => COSEPublicKey; |
@@ -9,5 +9,8 @@ "use strict"; | ||
} | ||
// Make it possible to stub the return value during testing | ||
/** | ||
* Make it possible to stub the return value during testing | ||
* @ignore Don't include this in docs output | ||
*/ | ||
exports._decodeCredentialPublicKeyInternals = { | ||
stubThis: (value) => value, | ||
}; |
@@ -6,2 +6,6 @@ /** | ||
export declare function fetch(url: string): Promise<Response>; | ||
/** | ||
* Make it possible to stub the return value during testing | ||
* @ignore Don't include this in docs output | ||
*/ | ||
export declare const _fetchInternals: { | ||
@@ -8,0 +12,0 @@ stubThis: (url: string) => Promise<Response>; |
@@ -13,5 +13,8 @@ "use strict"; | ||
} | ||
// Make it possible to stub the return value during testing | ||
/** | ||
* Make it possible to stub the return value during testing | ||
* @ignore Don't include this in docs output | ||
*/ | ||
exports._fetchInternals = { | ||
stubThis: (url) => (0, cross_fetch_1.fetch)(url), | ||
}; |
@@ -5,2 +5,6 @@ /** | ||
export declare function generateChallenge(): Promise<Uint8Array>; | ||
/** | ||
* Make it possible to stub the return value during testing | ||
* @ignore Don't include this in docs output | ||
*/ | ||
export declare const _generateChallengeInternals: { | ||
@@ -7,0 +11,0 @@ stubThis: (value: Uint8Array) => Uint8Array; |
@@ -22,5 +22,8 @@ "use strict"; | ||
} | ||
// Make it possible to stub the return value during testing | ||
/** | ||
* Make it possible to stub the return value during testing | ||
* @ignore Don't include this in docs output | ||
*/ | ||
exports._generateChallengeInternals = { | ||
stubThis: (value) => value, | ||
}; |
@@ -5,2 +5,6 @@ /** | ||
export declare function generateUserID(): Promise<Uint8Array>; | ||
/** | ||
* Make it possible to stub the return value during testing | ||
* @ignore Don't include this in docs output | ||
*/ | ||
export declare const _generateUserIDInternals: { | ||
@@ -7,0 +11,0 @@ stubThis: (value: Uint8Array) => Uint8Array; |
@@ -18,5 +18,8 @@ "use strict"; | ||
} | ||
// Make it possible to stub the return value during testing | ||
/** | ||
* Make it possible to stub the return value during testing | ||
* @ignore Don't include this in docs output | ||
*/ | ||
exports._generateUserIDInternals = { | ||
stubThis: (value) => value, | ||
}; |
@@ -1,24 +0,17 @@ | ||
import { convertAAGUIDToString } from './convertAAGUIDToString.js'; | ||
import { convertCertBufferToPEM } from './convertCertBufferToPEM.js'; | ||
import { convertCOSEtoPKCS } from './convertCOSEtoPKCS.js'; | ||
import { decodeAttestationObject } from './decodeAttestationObject.js'; | ||
import { decodeClientDataJSON } from './decodeClientDataJSON.js'; | ||
import { decodeCredentialPublicKey } from './decodeCredentialPublicKey.js'; | ||
import { generateChallenge } from './generateChallenge.js'; | ||
import { generateUserID } from './generateUserID.js'; | ||
import { getCertificateInfo } from './getCertificateInfo.js'; | ||
import { isCertRevoked } from './isCertRevoked.js'; | ||
import { parseAuthenticatorData } from './parseAuthenticatorData.js'; | ||
import { toHash } from './toHash.js'; | ||
import { validateCertificatePath } from './validateCertificatePath.js'; | ||
import { verifySignature } from './verifySignature.js'; | ||
import { isoBase64URL, isoCBOR, isoCrypto, isoUint8Array } from './iso/index.js'; | ||
import * as cose from './cose.js'; | ||
export { convertAAGUIDToString, convertCertBufferToPEM, convertCOSEtoPKCS, cose, decodeAttestationObject, decodeClientDataJSON, decodeCredentialPublicKey, generateChallenge, generateUserID, getCertificateInfo, isCertRevoked, isoBase64URL, isoCBOR, isoCrypto, isoUint8Array, parseAuthenticatorData, toHash, validateCertificatePath, verifySignature, }; | ||
import type { AttestationFormat, AttestationObject, AttestationStatement } from './decodeAttestationObject.js'; | ||
import type { CertificateInfo } from './getCertificateInfo.js'; | ||
import type { ClientDataJSON } from './decodeClientDataJSON.js'; | ||
import type { COSEPublicKey, COSEPublicKeyEC2, COSEPublicKeyOKP, COSEPublicKeyRSA } from './cose.js'; | ||
import type { ParsedAuthenticatorData } from './parseAuthenticatorData.js'; | ||
export type { AttestationFormat, AttestationObject, AttestationStatement, CertificateInfo, ClientDataJSON, COSEPublicKey, COSEPublicKeyEC2, COSEPublicKeyOKP, COSEPublicKeyRSA, ParsedAuthenticatorData, }; | ||
export * from './convertAAGUIDToString.js'; | ||
export * from './convertCertBufferToPEM.js'; | ||
export * from './convertCOSEtoPKCS.js'; | ||
export * from './decodeAttestationObject.js'; | ||
export * from './decodeClientDataJSON.js'; | ||
export * from './decodeCredentialPublicKey.js'; | ||
export * from './generateChallenge.js'; | ||
export * from './generateUserID.js'; | ||
export * from './getCertificateInfo.js'; | ||
export * from './isCertRevoked.js'; | ||
export * from './parseAuthenticatorData.js'; | ||
export * from './toHash.js'; | ||
export * from './validateCertificatePath.js'; | ||
export * from './verifySignature.js'; | ||
export * from './iso/index.js'; | ||
export * as cose from './cose.js'; | ||
//# sourceMappingURL=index.d.ts.map |
@@ -18,2 +18,5 @@ "use strict"; | ||
}); | ||
var __exportStar = (this && this.__exportStar) || function(m, exports) { | ||
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p); | ||
}; | ||
var __importStar = (this && this.__importStar) || function (mod) { | ||
@@ -27,37 +30,18 @@ if (mod && mod.__esModule) return mod; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.verifySignature = exports.validateCertificatePath = exports.toHash = exports.parseAuthenticatorData = exports.isoUint8Array = exports.isoCrypto = exports.isoCBOR = exports.isoBase64URL = exports.isCertRevoked = exports.getCertificateInfo = exports.generateUserID = exports.generateChallenge = exports.decodeCredentialPublicKey = exports.decodeClientDataJSON = exports.decodeAttestationObject = exports.cose = exports.convertCOSEtoPKCS = exports.convertCertBufferToPEM = exports.convertAAGUIDToString = void 0; | ||
const convertAAGUIDToString_js_1 = require("./convertAAGUIDToString.js"); | ||
Object.defineProperty(exports, "convertAAGUIDToString", { enumerable: true, get: function () { return convertAAGUIDToString_js_1.convertAAGUIDToString; } }); | ||
const convertCertBufferToPEM_js_1 = require("./convertCertBufferToPEM.js"); | ||
Object.defineProperty(exports, "convertCertBufferToPEM", { enumerable: true, get: function () { return convertCertBufferToPEM_js_1.convertCertBufferToPEM; } }); | ||
const convertCOSEtoPKCS_js_1 = require("./convertCOSEtoPKCS.js"); | ||
Object.defineProperty(exports, "convertCOSEtoPKCS", { enumerable: true, get: function () { return convertCOSEtoPKCS_js_1.convertCOSEtoPKCS; } }); | ||
const decodeAttestationObject_js_1 = require("./decodeAttestationObject.js"); | ||
Object.defineProperty(exports, "decodeAttestationObject", { enumerable: true, get: function () { return decodeAttestationObject_js_1.decodeAttestationObject; } }); | ||
const decodeClientDataJSON_js_1 = require("./decodeClientDataJSON.js"); | ||
Object.defineProperty(exports, "decodeClientDataJSON", { enumerable: true, get: function () { return decodeClientDataJSON_js_1.decodeClientDataJSON; } }); | ||
const decodeCredentialPublicKey_js_1 = require("./decodeCredentialPublicKey.js"); | ||
Object.defineProperty(exports, "decodeCredentialPublicKey", { enumerable: true, get: function () { return decodeCredentialPublicKey_js_1.decodeCredentialPublicKey; } }); | ||
const generateChallenge_js_1 = require("./generateChallenge.js"); | ||
Object.defineProperty(exports, "generateChallenge", { enumerable: true, get: function () { return generateChallenge_js_1.generateChallenge; } }); | ||
const generateUserID_js_1 = require("./generateUserID.js"); | ||
Object.defineProperty(exports, "generateUserID", { enumerable: true, get: function () { return generateUserID_js_1.generateUserID; } }); | ||
const getCertificateInfo_js_1 = require("./getCertificateInfo.js"); | ||
Object.defineProperty(exports, "getCertificateInfo", { enumerable: true, get: function () { return getCertificateInfo_js_1.getCertificateInfo; } }); | ||
const isCertRevoked_js_1 = require("./isCertRevoked.js"); | ||
Object.defineProperty(exports, "isCertRevoked", { enumerable: true, get: function () { return isCertRevoked_js_1.isCertRevoked; } }); | ||
const parseAuthenticatorData_js_1 = require("./parseAuthenticatorData.js"); | ||
Object.defineProperty(exports, "parseAuthenticatorData", { enumerable: true, get: function () { return parseAuthenticatorData_js_1.parseAuthenticatorData; } }); | ||
const toHash_js_1 = require("./toHash.js"); | ||
Object.defineProperty(exports, "toHash", { enumerable: true, get: function () { return toHash_js_1.toHash; } }); | ||
const validateCertificatePath_js_1 = require("./validateCertificatePath.js"); | ||
Object.defineProperty(exports, "validateCertificatePath", { enumerable: true, get: function () { return validateCertificatePath_js_1.validateCertificatePath; } }); | ||
const verifySignature_js_1 = require("./verifySignature.js"); | ||
Object.defineProperty(exports, "verifySignature", { enumerable: true, get: function () { return verifySignature_js_1.verifySignature; } }); | ||
const index_js_1 = require("./iso/index.js"); | ||
Object.defineProperty(exports, "isoBase64URL", { enumerable: true, get: function () { return index_js_1.isoBase64URL; } }); | ||
Object.defineProperty(exports, "isoCBOR", { enumerable: true, get: function () { return index_js_1.isoCBOR; } }); | ||
Object.defineProperty(exports, "isoCrypto", { enumerable: true, get: function () { return index_js_1.isoCrypto; } }); | ||
Object.defineProperty(exports, "isoUint8Array", { enumerable: true, get: function () { return index_js_1.isoUint8Array; } }); | ||
const cose = __importStar(require("./cose.js")); | ||
exports.cose = cose; | ||
exports.cose = void 0; | ||
__exportStar(require("./convertAAGUIDToString.js"), exports); | ||
__exportStar(require("./convertCertBufferToPEM.js"), exports); | ||
__exportStar(require("./convertCOSEtoPKCS.js"), exports); | ||
__exportStar(require("./decodeAttestationObject.js"), exports); | ||
__exportStar(require("./decodeClientDataJSON.js"), exports); | ||
__exportStar(require("./decodeCredentialPublicKey.js"), exports); | ||
__exportStar(require("./generateChallenge.js"), exports); | ||
__exportStar(require("./generateUserID.js"), exports); | ||
__exportStar(require("./getCertificateInfo.js"), exports); | ||
__exportStar(require("./isCertRevoked.js"), exports); | ||
__exportStar(require("./parseAuthenticatorData.js"), exports); | ||
__exportStar(require("./toHash.js"), exports); | ||
__exportStar(require("./validateCertificatePath.js"), exports); | ||
__exportStar(require("./verifySignature.js"), exports); | ||
__exportStar(require("./iso/index.js"), exports); | ||
exports.cose = __importStar(require("./cose.js")); |
@@ -1,2 +0,2 @@ | ||
import type { Base64URLString } from '@simplewebauthn/types'; | ||
import type { Base64URLString } from '../../types/index.js'; | ||
/** | ||
@@ -3,0 +3,0 @@ * Decode from a Base64URL-encoded string to an ArrayBuffer. Best used when converting a |
@@ -14,2 +14,6 @@ "use strict"; | ||
exports.trimPadding = trimPadding; | ||
/** | ||
* A runtime-agnostic collection of methods for working with Base64URL encoding | ||
* @module | ||
*/ | ||
const base64_1 = __importDefault(require("@hexagon/base64")); | ||
@@ -16,0 +20,0 @@ /** |
@@ -0,1 +1,5 @@ | ||
/** | ||
* A runtime-agnostic collection of methods for working with CBOR encoding | ||
* @module | ||
*/ | ||
import * as tinyCbor from '@levischuck/tiny-cbor'; | ||
@@ -2,0 +6,0 @@ /** |
@@ -28,2 +28,6 @@ "use strict"; | ||
exports.encode = encode; | ||
/** | ||
* A runtime-agnostic collection of methods for working with CBOR encoding | ||
* @module | ||
*/ | ||
const tinyCbor = __importStar(require("@levischuck/tiny-cbor")); | ||
@@ -30,0 +34,0 @@ /** |
@@ -1,2 +0,2 @@ | ||
import type { Crypto } from '@simplewebauthn/types'; | ||
import type { Crypto } from '../../../types/index.js'; | ||
/** | ||
@@ -3,0 +3,0 @@ * Try to get an instance of the Crypto API from the current runtime. Should support Node, |
@@ -0,1 +1,5 @@ | ||
/** | ||
* A runtime-agnostic collection of methods for working with the WebCrypto API | ||
* @module | ||
*/ | ||
export { digest } from './digest.js'; | ||
@@ -2,0 +6,0 @@ export { getRandomValues } from './getRandomValues.js'; |
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.verify = exports.getRandomValues = exports.digest = void 0; | ||
/** | ||
* A runtime-agnostic collection of methods for working with the WebCrypto API | ||
* @module | ||
*/ | ||
var digest_js_1 = require("./digest.js"); | ||
@@ -5,0 +9,0 @@ Object.defineProperty(exports, "digest", { enumerable: true, get: function () { return digest_js_1.digest; } }); |
/** | ||
* A runtime-agnostic collection of methods for working with Uint8Arrays | ||
* @module | ||
*/ | ||
/** | ||
* Make sure two Uint8Arrays are deeply equivalent | ||
@@ -3,0 +7,0 @@ */ |
"use strict"; | ||
/** | ||
* A runtime-agnostic collection of methods for working with Uint8Arrays | ||
* @module | ||
*/ | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
@@ -3,0 +7,0 @@ exports.areEqual = areEqual; |
@@ -26,2 +26,6 @@ import { AuthenticationExtensionsAuthenticatorOutputs } from './decodeAuthenticatorExtensions.js'; | ||
}; | ||
/** | ||
* Make it possible to stub the return value during testing | ||
* @ignore Don't include this in docs output | ||
*/ | ||
export declare const _parseAuthenticatorDataInternals: { | ||
@@ -28,0 +32,0 @@ stubThis: (value: ParsedAuthenticatorData) => ParsedAuthenticatorData; |
@@ -104,5 +104,8 @@ "use strict"; | ||
} | ||
// Make it possible to stub the return value during testing | ||
/** | ||
* Make it possible to stub the return value during testing | ||
* @ignore Don't include this in docs output | ||
*/ | ||
exports._parseAuthenticatorDataInternals = { | ||
stubThis: (value) => value, | ||
}; |
@@ -1,2 +0,2 @@ | ||
import type { CredentialDeviceType } from '@simplewebauthn/types'; | ||
import type { CredentialDeviceType } from '../types/index.js'; | ||
/** | ||
@@ -3,0 +3,0 @@ * Make sense of Bits 3 and 4 in authenticator indicating: |
/** | ||
* Traverse an array of PEM certificates and ensure they form a proper chain | ||
* @param certificates Typically the result of `x5c.map(convertASN1toPEM)` | ||
* @param rootCertificates Possible root certificates to complete the path | ||
* @param x5cCertsPEM Typically the result of `x5c.map(convertASN1toPEM)` | ||
* @param trustAnchorsPEM PEM-formatted certs that an attestation statement x5c may chain back to | ||
*/ | ||
export declare function validateCertificatePath(certificates: string[], rootCertificates?: string[]): Promise<boolean>; | ||
export declare function validateCertificatePath(x5cCertsPEM: string[], trustAnchorsPEM?: string[]): Promise<boolean>; | ||
//# sourceMappingURL=validateCertificatePath.d.ts.map |
@@ -12,9 +12,8 @@ "use strict"; | ||
* Traverse an array of PEM certificates and ensure they form a proper chain | ||
* @param certificates Typically the result of `x5c.map(convertASN1toPEM)` | ||
* @param rootCertificates Possible root certificates to complete the path | ||
* @param x5cCertsPEM Typically the result of `x5c.map(convertASN1toPEM)` | ||
* @param trustAnchorsPEM PEM-formatted certs that an attestation statement x5c may chain back to | ||
*/ | ||
async function validateCertificatePath(certificates, rootCertificates = []) { | ||
if (rootCertificates.length === 0) { | ||
// We have no root certs with which to create a full path, so skip path validation | ||
// TODO: Is this going to be acceptable default behavior?? | ||
async function validateCertificatePath(x5cCertsPEM, trustAnchorsPEM = []) { | ||
if (trustAnchorsPEM.length === 0) { | ||
// We have no trust anchors to chain back to, so skip path validation | ||
return true; | ||
@@ -24,8 +23,8 @@ } | ||
let certificateNotYetValidOrExpiredErrorMessage = undefined; | ||
for (const rootCert of rootCertificates) { | ||
for (const anchorPEM of trustAnchorsPEM) { | ||
try { | ||
const certsWithRoot = certificates.concat([rootCert]); | ||
await _validatePath(certsWithRoot); | ||
const certsWithTrustAnchor = x5cCertsPEM.concat([anchorPEM]); | ||
await _validatePath(certsWithTrustAnchor); | ||
// If we successfully validated a path then there's no need to continue. Reset any existing | ||
// errors that were thrown by earlier root certificates | ||
// errors that were thrown by earlier trust anchors | ||
invalidSubjectAndIssuerError = false; | ||
@@ -47,3 +46,3 @@ certificateNotYetValidOrExpiredErrorMessage = undefined; | ||
} | ||
// We tried multiple root certs and none of them worked | ||
// We tried multiple trust anchors and none of them worked | ||
if (invalidSubjectAndIssuerError) { | ||
@@ -57,56 +56,31 @@ throw new InvalidSubjectAndIssuer(); | ||
} | ||
async function _validatePath(certificates) { | ||
if (new Set(certificates).size !== certificates.length) { | ||
/** | ||
* @param x5cCerts X.509 `x5c` certs in PEM string format | ||
* @param anchorCert X.509 trust anchor cert in PEM string format | ||
*/ | ||
async function _validatePath(x5cCertsWithTrustAnchorPEM) { | ||
if (new Set(x5cCertsWithTrustAnchorPEM).size !== x5cCertsWithTrustAnchorPEM.length) { | ||
throw new Error('Invalid certificate path: found duplicate certificates'); | ||
} | ||
// From leaf to root, make sure each cert is issued by the next certificate in the chain | ||
for (let i = 0; i < certificates.length; i += 1) { | ||
const subjectPem = certificates[i]; | ||
const isLeafCert = i === 0; | ||
const isRootCert = i + 1 >= certificates.length; | ||
let issuerPem = ''; | ||
if (isRootCert) { | ||
issuerPem = subjectPem; | ||
} | ||
else { | ||
issuerPem = certificates[i + 1]; | ||
} | ||
// Make sure no certs are revoked, and all are within their time validity window | ||
for (const certificatePEM of x5cCertsWithTrustAnchorPEM) { | ||
const certInfo = (0, getCertificateInfo_js_1.getCertificateInfo)((0, convertPEMToBytes_js_1.convertPEMToBytes)(certificatePEM)); | ||
await assertCertNotRevoked(certInfo.parsedCertificate); | ||
assertCertIsWithinValidTimeWindow(certInfo, certificatePEM); | ||
} | ||
// Make sure each x5c cert is issued by the next certificate in the chain | ||
for (let i = 0; i < (x5cCertsWithTrustAnchorPEM.length - 1); i += 1) { | ||
const subjectPem = x5cCertsWithTrustAnchorPEM[i]; | ||
const issuerPem = x5cCertsWithTrustAnchorPEM[i + 1]; | ||
const subjectInfo = (0, getCertificateInfo_js_1.getCertificateInfo)((0, convertPEMToBytes_js_1.convertPEMToBytes)(subjectPem)); | ||
const issuerInfo = (0, getCertificateInfo_js_1.getCertificateInfo)((0, convertPEMToBytes_js_1.convertPEMToBytes)(issuerPem)); | ||
const x509Subject = subjectInfo.parsedCertificate; | ||
// Check for certificate revocation | ||
const subjectCertRevoked = await (0, isCertRevoked_js_1.isCertRevoked)(x509Subject); | ||
if (subjectCertRevoked) { | ||
throw new Error(`Found revoked certificate in certificate path`); | ||
} | ||
// Check that intermediate certificate is within its valid time window | ||
const { notBefore, notAfter } = issuerInfo; | ||
const now = new Date(Date.now()); | ||
if (notBefore > now || notAfter < now) { | ||
if (isLeafCert) { | ||
throw new CertificateNotYetValidOrExpired(`Leaf certificate is not yet valid or expired: ${issuerPem}`); | ||
} | ||
else if (isRootCert) { | ||
throw new CertificateNotYetValidOrExpired(`Root certificate is not yet valid or expired: ${issuerPem}`); | ||
} | ||
else { | ||
throw new CertificateNotYetValidOrExpired(`Intermediate certificate is not yet valid or expired: ${issuerPem}`); | ||
} | ||
} | ||
// Make sure subject issuer is issuer subject | ||
if (subjectInfo.issuer.combined !== issuerInfo.subject.combined) { | ||
throw new InvalidSubjectAndIssuer(); | ||
} | ||
// Verify the subject certificate's signature with the issuer cert's public key | ||
const data = asn1_schema_1.AsnSerializer.serialize(x509Subject.tbsCertificate); | ||
const signature = x509Subject.signatureValue; | ||
const signatureAlgorithm = (0, mapX509SignatureAlgToCOSEAlg_js_1.mapX509SignatureAlgToCOSEAlg)(x509Subject.signatureAlgorithm.algorithm); | ||
const issuerCertBytes = (0, convertPEMToBytes_js_1.convertPEMToBytes)(issuerPem); | ||
const verified = await (0, verifySignature_js_1.verifySignature)({ | ||
data: new Uint8Array(data), | ||
signature: new Uint8Array(signature), | ||
x509Certificate: issuerCertBytes, | ||
hashAlgorithm: signatureAlgorithm, | ||
}); | ||
if (!verified) { | ||
throw new Error('Invalid certificate path: invalid signature'); | ||
const issuerCertIsRootCert = issuerInfo.issuer.combined === issuerInfo.subject.combined; | ||
await assertSubjectIsSignedByIssuer(subjectInfo.parsedCertificate, issuerPem); | ||
// Perform one final check if the issuer cert is also a root certificate | ||
if (issuerCertIsRootCert) { | ||
await assertSubjectIsSignedByIssuer(issuerInfo.parsedCertificate, issuerPem); | ||
} | ||
@@ -116,2 +90,44 @@ } | ||
} | ||
/** | ||
* Check if the certificate is revoked or not. If it is, raise an error | ||
*/ | ||
async function assertCertNotRevoked(certificate) { | ||
// Check for certificate revocation | ||
const subjectCertRevoked = await (0, isCertRevoked_js_1.isCertRevoked)(certificate); | ||
if (subjectCertRevoked) { | ||
throw new Error(`Found revoked certificate in certificate path`); | ||
} | ||
} | ||
/** | ||
* Require the cert to be within its notBefore and notAfter time window | ||
* | ||
* @param certInfo Parsed cert information | ||
* @param certPEM PEM-formatted certificate, for error reporting | ||
*/ | ||
function assertCertIsWithinValidTimeWindow(certInfo, certPEM) { | ||
const { notBefore, notAfter } = certInfo; | ||
const now = new Date(Date.now()); | ||
if (notBefore > now || notAfter < now) { | ||
throw new CertificateNotYetValidOrExpired(`Certificate is not yet valid or expired: ${certPEM}`); | ||
} | ||
} | ||
/** | ||
* Ensure that the subject cert has been signed by the next cert in the chain | ||
*/ | ||
async function assertSubjectIsSignedByIssuer(subjectCert, issuerPEM) { | ||
// Verify the subject certificate's signature with the issuer cert's public key | ||
const data = asn1_schema_1.AsnSerializer.serialize(subjectCert.tbsCertificate); | ||
const signature = subjectCert.signatureValue; | ||
const signatureAlgorithm = (0, mapX509SignatureAlgToCOSEAlg_js_1.mapX509SignatureAlgToCOSEAlg)(subjectCert.signatureAlgorithm.algorithm); | ||
const issuerCertBytes = (0, convertPEMToBytes_js_1.convertPEMToBytes)(issuerPEM); | ||
const verified = await (0, verifySignature_js_1.verifySignature)({ | ||
data: new Uint8Array(data), | ||
signature: new Uint8Array(signature), | ||
x509Certificate: issuerCertBytes, | ||
hashAlgorithm: signatureAlgorithm, | ||
}); | ||
if (!verified) { | ||
throw new InvalidSubjectSignatureForIssuer(); | ||
} | ||
} | ||
// Custom errors to help pass on certain errors | ||
@@ -125,2 +141,9 @@ class InvalidSubjectAndIssuer extends Error { | ||
} | ||
class InvalidSubjectSignatureForIssuer extends Error { | ||
constructor() { | ||
const message = 'Subject signature was invalid for issuer'; | ||
super(message); | ||
this.name = 'InvalidSubjectSignatureForIssuer'; | ||
} | ||
} | ||
class CertificateNotYetValidOrExpired extends Error { | ||
@@ -127,0 +150,0 @@ constructor(message) { |
@@ -12,2 +12,6 @@ import { COSEALG } from './cose.js'; | ||
}): Promise<boolean>; | ||
/** | ||
* Make it possible to stub the return value during testing | ||
* @ignore Don't include this in docs output | ||
*/ | ||
export declare const _verifySignatureInternals: { | ||
@@ -14,0 +18,0 @@ stubThis: (value: Promise<boolean>) => Promise<boolean>; |
@@ -33,5 +33,8 @@ "use strict"; | ||
} | ||
// Make it possible to stub the return value during testing | ||
/** | ||
* Make it possible to stub the return value during testing | ||
* @ignore Don't include this in docs output | ||
*/ | ||
exports._verifySignatureInternals = { | ||
stubThis: (value) => value, | ||
}; |
@@ -1,18 +0,9 @@ | ||
/** | ||
* @packageDocumentation | ||
* @module @simplewebauthn/server | ||
*/ | ||
import { generateRegistrationOptions } from './registration/generateRegistrationOptions.js'; | ||
import { verifyRegistrationResponse } from './registration/verifyRegistrationResponse.js'; | ||
import { generateAuthenticationOptions } from './authentication/generateAuthenticationOptions.js'; | ||
import { verifyAuthenticationResponse } from './authentication/verifyAuthenticationResponse.js'; | ||
import { MetadataService } from './services/metadataService.js'; | ||
import { SettingsService } from './services/settingsService.js'; | ||
export { generateAuthenticationOptions, generateRegistrationOptions, MetadataService, SettingsService, verifyAuthenticationResponse, verifyRegistrationResponse, }; | ||
import type { GenerateRegistrationOptionsOpts } from './registration/generateRegistrationOptions.js'; | ||
import type { GenerateAuthenticationOptionsOpts } from './authentication/generateAuthenticationOptions.js'; | ||
import type { MetadataStatement } from './metadata/mdsTypes.js'; | ||
import type { VerifiedRegistrationResponse, VerifyRegistrationResponseOpts } from './registration/verifyRegistrationResponse.js'; | ||
import type { VerifiedAuthenticationResponse, VerifyAuthenticationResponseOpts } from './authentication/verifyAuthenticationResponse.js'; | ||
export type { GenerateAuthenticationOptionsOpts, GenerateRegistrationOptionsOpts, MetadataStatement, VerifiedAuthenticationResponse, VerifiedRegistrationResponse, VerifyAuthenticationResponseOpts, VerifyRegistrationResponseOpts, }; | ||
export * from './registration/generateRegistrationOptions.js'; | ||
export * from './registration/verifyRegistrationResponse.js'; | ||
export * from './authentication/generateAuthenticationOptions.js'; | ||
export * from './authentication/verifyAuthenticationResponse.js'; | ||
export * from './services/metadataService.js'; | ||
export * from './services/settingsService.js'; | ||
export * from './metadata/mdsTypes.js'; | ||
export * from './types/index.js'; | ||
//# sourceMappingURL=index.d.ts.map |
"use strict"; | ||
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { | ||
if (k2 === undefined) k2 = k; | ||
var desc = Object.getOwnPropertyDescriptor(m, k); | ||
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { | ||
desc = { enumerable: true, get: function() { return m[k]; } }; | ||
} | ||
Object.defineProperty(o, k2, desc); | ||
}) : (function(o, m, k, k2) { | ||
if (k2 === undefined) k2 = k; | ||
o[k2] = m[k]; | ||
})); | ||
var __exportStar = (this && this.__exportStar) || function(m, exports) { | ||
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p); | ||
}; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.verifyRegistrationResponse = exports.verifyAuthenticationResponse = exports.SettingsService = exports.MetadataService = exports.generateRegistrationOptions = exports.generateAuthenticationOptions = void 0; | ||
/** | ||
* @packageDocumentation | ||
* @module @simplewebauthn/server | ||
*/ | ||
const generateRegistrationOptions_js_1 = require("./registration/generateRegistrationOptions.js"); | ||
Object.defineProperty(exports, "generateRegistrationOptions", { enumerable: true, get: function () { return generateRegistrationOptions_js_1.generateRegistrationOptions; } }); | ||
const verifyRegistrationResponse_js_1 = require("./registration/verifyRegistrationResponse.js"); | ||
Object.defineProperty(exports, "verifyRegistrationResponse", { enumerable: true, get: function () { return verifyRegistrationResponse_js_1.verifyRegistrationResponse; } }); | ||
const generateAuthenticationOptions_js_1 = require("./authentication/generateAuthenticationOptions.js"); | ||
Object.defineProperty(exports, "generateAuthenticationOptions", { enumerable: true, get: function () { return generateAuthenticationOptions_js_1.generateAuthenticationOptions; } }); | ||
const verifyAuthenticationResponse_js_1 = require("./authentication/verifyAuthenticationResponse.js"); | ||
Object.defineProperty(exports, "verifyAuthenticationResponse", { enumerable: true, get: function () { return verifyAuthenticationResponse_js_1.verifyAuthenticationResponse; } }); | ||
const metadataService_js_1 = require("./services/metadataService.js"); | ||
Object.defineProperty(exports, "MetadataService", { enumerable: true, get: function () { return metadataService_js_1.MetadataService; } }); | ||
const settingsService_js_1 = require("./services/settingsService.js"); | ||
Object.defineProperty(exports, "SettingsService", { enumerable: true, get: function () { return settingsService_js_1.SettingsService; } }); | ||
__exportStar(require("./registration/generateRegistrationOptions.js"), exports); | ||
__exportStar(require("./registration/verifyRegistrationResponse.js"), exports); | ||
__exportStar(require("./authentication/generateAuthenticationOptions.js"), exports); | ||
__exportStar(require("./authentication/verifyAuthenticationResponse.js"), exports); | ||
__exportStar(require("./services/metadataService.js"), exports); | ||
__exportStar(require("./services/settingsService.js"), exports); | ||
__exportStar(require("./metadata/mdsTypes.js"), exports); | ||
__exportStar(require("./types/index.js"), exports); |
@@ -1,2 +0,2 @@ | ||
import type { Base64URLString } from '@simplewebauthn/types'; | ||
import type { Base64URLString } from '../types/index.js'; | ||
/** | ||
@@ -6,2 +6,3 @@ * Metadata Service structures | ||
*/ | ||
/** */ | ||
export type MDSJWTHeader = { | ||
@@ -109,2 +110,5 @@ alg: string; | ||
}; | ||
/** | ||
* langCode -> "en-US", "ja-JP", etc... | ||
*/ | ||
export type AlternativeDescriptions = { | ||
@@ -111,0 +115,0 @@ [langCode: string]: string; |
@@ -1,4 +0,4 @@ | ||
import type { Base64URLString } from '@simplewebauthn/types'; | ||
import type { Base64URLString } from '../types/index.js'; | ||
import type { AlgSign, MetadataStatement } from './mdsTypes.js'; | ||
import { COSEALG, COSECRV, COSEKTY } from '../helpers/cose.js'; | ||
import { type COSEALG, type COSECRV, COSEKTY } from '../helpers/cose.js'; | ||
/** | ||
@@ -5,0 +5,0 @@ * Match properties of the authenticator's attestation statement against expected values as |
@@ -1,19 +0,3 @@ | ||
import type { AttestationConveyancePreference, AuthenticationExtensionsClientInputs, AuthenticatorSelectionCriteria, AuthenticatorTransportFuture, Base64URLString, COSEAlgorithmIdentifier, PublicKeyCredentialCreationOptionsJSON } from '@simplewebauthn/types'; | ||
export type GenerateRegistrationOptionsOpts = { | ||
rpName: string; | ||
rpID: string; | ||
userName: string; | ||
userID?: Uint8Array; | ||
challenge?: string | Uint8Array; | ||
userDisplayName?: string; | ||
timeout?: number; | ||
attestationType?: AttestationConveyancePreference; | ||
excludeCredentials?: { | ||
id: Base64URLString; | ||
transports?: AuthenticatorTransportFuture[]; | ||
}[]; | ||
authenticatorSelection?: AuthenticatorSelectionCriteria; | ||
extensions?: AuthenticationExtensionsClientInputs; | ||
supportedAlgorithmIDs?: COSEAlgorithmIdentifier[]; | ||
}; | ||
import type { AuthenticationExtensionsClientInputs, AuthenticatorSelectionCriteria, AuthenticatorTransportFuture, Base64URLString, COSEAlgorithmIdentifier, PublicKeyCredentialCreationOptionsJSON } from '../types/index.js'; | ||
export type GenerateRegistrationOptionsOpts = Parameters<typeof generateRegistrationOptions>[0]; | ||
/** | ||
@@ -42,4 +26,22 @@ * Supported crypto algo identifiers | ||
* @param supportedAlgorithmIDs **(Optional)** - Array of numeric COSE algorithm identifiers supported for attestation by this RP. See https://www.iana.org/assignments/cose/cose.xhtml#algorithms. Defaults to `[-8, -7, -257]` | ||
* @param preferredAuthenticatorType **(Optional)** - Encourage the browser to prompt the user to register a specific type of authenticator | ||
*/ | ||
export declare function generateRegistrationOptions(options: GenerateRegistrationOptionsOpts): Promise<PublicKeyCredentialCreationOptionsJSON>; | ||
export declare function generateRegistrationOptions(options: { | ||
rpName: string; | ||
rpID: string; | ||
userName: string; | ||
userID?: Uint8Array; | ||
challenge?: string | Uint8Array; | ||
userDisplayName?: string; | ||
timeout?: number; | ||
attestationType?: 'direct' | 'enterprise' | 'none'; | ||
excludeCredentials?: { | ||
id: Base64URLString; | ||
transports?: AuthenticatorTransportFuture[]; | ||
}[]; | ||
authenticatorSelection?: AuthenticatorSelectionCriteria; | ||
extensions?: AuthenticationExtensionsClientInputs; | ||
supportedAlgorithmIDs?: COSEAlgorithmIdentifier[]; | ||
preferredAuthenticatorType?: 'securityKey' | 'localDevice' | 'remoteDevice'; | ||
}): Promise<PublicKeyCredentialCreationOptionsJSON>; | ||
//# sourceMappingURL=generateRegistrationOptions.d.ts.map |
@@ -70,5 +70,6 @@ "use strict"; | ||
* @param supportedAlgorithmIDs **(Optional)** - Array of numeric COSE algorithm identifiers supported for attestation by this RP. See https://www.iana.org/assignments/cose/cose.xhtml#algorithms. Defaults to `[-8, -7, -257]` | ||
* @param preferredAuthenticatorType **(Optional)** - Encourage the browser to prompt the user to register a specific type of authenticator | ||
*/ | ||
async function generateRegistrationOptions(options) { | ||
const { rpName, rpID, userName, userID, challenge = await (0, generateChallenge_js_1.generateChallenge)(), userDisplayName = '', timeout = 60000, attestationType = 'none', excludeCredentials = [], authenticatorSelection = defaultAuthenticatorSelection, extensions, supportedAlgorithmIDs = defaultSupportedAlgorithmIDs, } = options; | ||
const { rpName, rpID, userName, userID, challenge = await (0, generateChallenge_js_1.generateChallenge)(), userDisplayName = '', timeout = 60000, attestationType = 'none', excludeCredentials = [], authenticatorSelection = defaultAuthenticatorSelection, extensions, supportedAlgorithmIDs = defaultSupportedAlgorithmIDs, preferredAuthenticatorType, } = options; | ||
/** | ||
@@ -135,2 +136,21 @@ * Prepare pubKeyCredParams from the array of algorithm ID's | ||
} | ||
/** | ||
* Map authenticator preference to hints. Map to authenticatorAttachment as well for | ||
* backwards-compatibility. | ||
*/ | ||
const hints = []; | ||
if (preferredAuthenticatorType) { | ||
if (preferredAuthenticatorType === 'securityKey') { | ||
hints.push('security-key'); | ||
authenticatorSelection.authenticatorAttachment = 'cross-platform'; | ||
} | ||
else if (preferredAuthenticatorType === 'localDevice') { | ||
hints.push('client-device'); | ||
authenticatorSelection.authenticatorAttachment = 'platform'; | ||
} | ||
else if (preferredAuthenticatorType === 'remoteDevice') { | ||
hints.push('hybrid'); | ||
authenticatorSelection.authenticatorAttachment = 'cross-platform'; | ||
} | ||
} | ||
return { | ||
@@ -165,3 +185,4 @@ challenge: index_js_1.isoBase64URL.fromBuffer(_challenge), | ||
}, | ||
hints, | ||
}; | ||
} |
@@ -1,15 +0,9 @@ | ||
import type { COSEAlgorithmIdentifier, CredentialDeviceType, RegistrationResponseJSON, WebAuthnCredential } from '@simplewebauthn/types'; | ||
import { AttestationFormat, AttestationStatement } from '../helpers/decodeAttestationObject.js'; | ||
import { AuthenticationExtensionsAuthenticatorOutputs } from '../helpers/decodeAuthenticatorExtensions.js'; | ||
export type VerifyRegistrationResponseOpts = { | ||
response: RegistrationResponseJSON; | ||
expectedChallenge: string | ((challenge: string) => boolean | Promise<boolean>); | ||
expectedOrigin: string | string[]; | ||
expectedRPID?: string | string[]; | ||
expectedType?: string | string[]; | ||
requireUserPresence?: boolean; | ||
requireUserVerification?: boolean; | ||
supportedAlgorithmIDs?: COSEAlgorithmIdentifier[]; | ||
}; | ||
import type { COSEAlgorithmIdentifier, CredentialDeviceType, RegistrationResponseJSON, WebAuthnCredential } from '../types/index.js'; | ||
import { type AttestationFormat, type AttestationStatement } from '../helpers/decodeAttestationObject.js'; | ||
import type { AuthenticationExtensionsAuthenticatorOutputs } from '../helpers/decodeAuthenticatorExtensions.js'; | ||
/** | ||
* Configurable options when calling `verifyRegistrationResponse()` | ||
*/ | ||
export type VerifyRegistrationResponseOpts = Parameters<typeof verifyRegistrationResponse>[0]; | ||
/** | ||
* Verify that the user has legitimately completed the registration process | ||
@@ -28,3 +22,12 @@ * | ||
*/ | ||
export declare function verifyRegistrationResponse(options: VerifyRegistrationResponseOpts): Promise<VerifiedRegistrationResponse>; | ||
export declare function verifyRegistrationResponse(options: { | ||
response: RegistrationResponseJSON; | ||
expectedChallenge: string | ((challenge: string) => boolean | Promise<boolean>); | ||
expectedOrigin: string | string[]; | ||
expectedRPID?: string | string[]; | ||
expectedType?: string | string[]; | ||
requireUserPresence?: boolean; | ||
requireUserVerification?: boolean; | ||
supportedAlgorithmIDs?: COSEAlgorithmIdentifier[]; | ||
}): Promise<VerifiedRegistrationResponse>; | ||
/** | ||
@@ -31,0 +34,0 @@ * Result of registration verification |
import type { MetadataStatement } from '../metadata/mdsTypes.js'; | ||
type VerificationMode = 'permissive' | 'strict'; | ||
interface MetadataService { | ||
initialize(opts?: { | ||
mdsServers?: string[]; | ||
statements?: MetadataStatement[]; | ||
verificationMode?: VerificationMode; | ||
}): Promise<void>; | ||
getStatement(aaguid: string | Uint8Array): Promise<MetadataStatement | undefined>; | ||
} | ||
/** | ||
* An implementation of `MetadataService` that can download and parse BLOBs, and support on-demand | ||
* requesting and caching of individual metadata statements. | ||
* | ||
* https://fidoalliance.org/metadata/ | ||
* Allow MetadataService to accommodate unregistered AAGUIDs (`"permissive"`), or only allow | ||
* registered AAGUIDs (`"strict"`). Currently primarily impacts how `getStatement()` operates | ||
*/ | ||
export declare class BaseMetadataService implements MetadataService { | ||
private mdsCache; | ||
private statementCache; | ||
private state; | ||
private verificationMode; | ||
export type VerificationMode = 'permissive' | 'strict'; | ||
interface MetadataService { | ||
/** | ||
@@ -47,2 +33,20 @@ * Prepare the service to handle remote MDS servers and/or cache local metadata statements. | ||
getStatement(aaguid: string | Uint8Array): Promise<MetadataStatement | undefined>; | ||
} | ||
/** | ||
* An implementation of `MetadataService` that can download and parse BLOBs, and support on-demand | ||
* requesting and caching of individual metadata statements. | ||
* | ||
* https://fidoalliance.org/metadata/ | ||
*/ | ||
export declare class BaseMetadataService implements MetadataService { | ||
private mdsCache; | ||
private statementCache; | ||
private state; | ||
private verificationMode; | ||
initialize(opts?: { | ||
mdsServers?: string[]; | ||
statements?: MetadataStatement[]; | ||
verificationMode?: VerificationMode; | ||
}): Promise<void>; | ||
getStatement(aaguid: string | Uint8Array): Promise<MetadataStatement | undefined>; | ||
/** | ||
@@ -49,0 +53,0 @@ * Download and process the latest BLOB from MDS |
@@ -54,15 +54,2 @@ "use strict"; | ||
} | ||
/** | ||
* Prepare the service to handle remote MDS servers and/or cache local metadata statements. | ||
* | ||
* **Options:** | ||
* | ||
* @param opts.mdsServers An array of URLs to FIDO Alliance Metadata Service | ||
* (version 3.0)-compatible servers. Defaults to the official FIDO MDS server | ||
* @param opts.statements An array of local metadata statements | ||
* @param opts.verificationMode How MetadataService will handle unregistered AAGUIDs. Defaults to | ||
* `"strict"` which throws errors during registration response verification when an | ||
* unregistered AAGUID is encountered. Set to `"permissive"` to allow registration by | ||
* authenticators with unregistered AAGUIDs | ||
*/ | ||
async initialize(opts = {}) { | ||
@@ -119,8 +106,2 @@ const { mdsServers = [defaultURLMDS], statements, verificationMode } = opts; | ||
} | ||
/** | ||
* Get a metadata statement for a given AAGUID. | ||
* | ||
* This method will coordinate updating the cache as per the `nextUpdate` property in the initial | ||
* BLOB download. | ||
*/ | ||
async getStatement(aaguid) { | ||
@@ -127,0 +108,0 @@ if (this.state === SERVICE_STATE.DISABLED) { |
import { AttestationFormat } from '../helpers/decodeAttestationObject.js'; | ||
type RootCertIdentifier = AttestationFormat | 'mds'; | ||
export type RootCertIdentifier = AttestationFormat | 'mds'; | ||
interface SettingsService { | ||
/** | ||
* Set potential root certificates for attestation formats that use them. Root certs will be tried | ||
* one-by-one when validating a certificate path. | ||
* | ||
* Certificates can be specified as a raw `Buffer`, or as a PEM-formatted string. If a | ||
* `Buffer` is passed in it will be converted to PEM format. | ||
*/ | ||
setRootCertificates(opts: { | ||
@@ -8,2 +15,5 @@ identifier: RootCertIdentifier; | ||
}): void; | ||
/** | ||
* Get any registered root certificates for the specified attestation format | ||
*/ | ||
getRootCertificates(opts: { | ||
@@ -10,0 +20,0 @@ identifier: RootCertIdentifier; |
@@ -20,9 +20,2 @@ "use strict"; | ||
} | ||
/** | ||
* Set potential root certificates for attestation formats that use them. Root certs will be tried | ||
* one-by-one when validating a certificate path. | ||
* | ||
* Certificates can be specified as a raw `Buffer`, or as a PEM-formatted string. If a | ||
* `Buffer` is passed in it will be converted to PEM format. | ||
*/ | ||
setRootCertificates(opts) { | ||
@@ -41,5 +34,2 @@ const { identifier, certificates } = opts; | ||
} | ||
/** | ||
* Get any registered root certificates for the specified attestation format | ||
*/ | ||
getRootCertificates(opts) { | ||
@@ -46,0 +36,0 @@ const { identifier } = opts; |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
No v1
QualityPackage is not semver >=1. This means it is not stable and does not support ^ ranges.
Found 1 instance in 1 package
635000
8
413
12537
1
- Removed@simplewebauthn/types@^12.0.0
- Removed@simplewebauthn/types@12.0.0(transitive)