@simplewebauthn/server 9.0.3 → 10.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -2
- package/esm/authentication/generateAuthenticationOptions.d.ts +16 -14
- package/esm/authentication/generateAuthenticationOptions.js +21 -16
- package/esm/authentication/verifyAuthenticationResponse.d.ts +13 -18
- package/esm/authentication/verifyAuthenticationResponse.js +12 -17
- package/esm/deps.d.ts +1 -1
- package/esm/helpers/convertCertBufferToPEM.js +1 -1
- package/esm/helpers/decodeClientDataJSON.d.ts +2 -1
- package/esm/helpers/decodeClientDataJSON.js +1 -1
- package/esm/helpers/generateUserID.d.ts +7 -0
- package/esm/helpers/generateUserID.js +17 -0
- package/esm/helpers/index.d.ts +2 -1
- package/esm/helpers/index.js +2 -1
- package/esm/helpers/iso/isoBase64URL.d.ts +10 -5
- package/esm/helpers/iso/isoBase64URL.js +13 -7
- package/esm/helpers/iso/isoCrypto/getWebCrypto.d.ts +0 -289
- package/esm/helpers/iso/isoCrypto/getWebCrypto.js +26 -41
- package/esm/helpers/iso/isoCrypto/unwrapEC2Signature.d.ts +2 -1
- package/esm/helpers/iso/isoCrypto/unwrapEC2Signature.js +58 -16
- package/esm/helpers/iso/isoCrypto/verify.js +6 -2
- package/esm/metadata/parseJWT.js +2 -2
- package/esm/registration/generateRegistrationOptions.d.ts +19 -19
- package/esm/registration/generateRegistrationOptions.js +40 -22
- package/esm/registration/verifications/verifyAttestationAndroidSafetyNet.js +2 -2
- package/esm/registration/verifyRegistrationResponse.d.ts +9 -12
- package/esm/registration/verifyRegistrationResponse.js +8 -11
- package/package.json +3 -3
- package/script/authentication/generateAuthenticationOptions.d.ts +16 -14
- package/script/authentication/generateAuthenticationOptions.js +21 -16
- package/script/authentication/verifyAuthenticationResponse.d.ts +13 -18
- package/script/authentication/verifyAuthenticationResponse.js +12 -17
- package/script/deps.d.ts +1 -1
- package/script/helpers/convertCertBufferToPEM.js +1 -1
- package/script/helpers/decodeClientDataJSON.d.ts +2 -1
- package/script/helpers/decodeClientDataJSON.js +1 -1
- package/script/helpers/generateUserID.d.ts +7 -0
- package/script/helpers/generateUserID.js +21 -0
- package/script/helpers/index.d.ts +2 -1
- package/script/helpers/index.js +3 -1
- package/script/helpers/iso/isoBase64URL.d.ts +10 -5
- package/script/helpers/iso/isoBase64URL.js +18 -11
- package/script/helpers/iso/isoCrypto/getWebCrypto.d.ts +0 -288
- package/script/helpers/iso/isoCrypto/getWebCrypto.js +26 -64
- package/script/helpers/iso/isoCrypto/unwrapEC2Signature.d.ts +2 -1
- package/script/helpers/iso/isoCrypto/unwrapEC2Signature.js +58 -16
- package/script/helpers/iso/isoCrypto/verify.js +5 -1
- package/script/metadata/parseJWT.js +2 -2
- package/script/registration/generateRegistrationOptions.d.ts +19 -19
- package/script/registration/generateRegistrationOptions.js +40 -22
- package/script/registration/verifications/verifyAttestationAndroidSafetyNet.js +2 -2
- package/script/registration/verifyRegistrationResponse.d.ts +9 -12
- package/script/registration/verifyRegistrationResponse.js +8 -11
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { generateChallenge } from '../helpers/generateChallenge.js';
|
|
2
|
+
import { generateUserID } from '../helpers/generateUserID.js';
|
|
2
3
|
import { isoBase64URL, isoUint8Array } from '../helpers/iso/index.js';
|
|
3
4
|
/**
|
|
4
5
|
* Supported crypto algo identifiers
|
|
@@ -46,28 +47,25 @@ const defaultAuthenticatorSelection = {
|
|
|
46
47
|
*/
|
|
47
48
|
const defaultSupportedAlgorithmIDs = [-8, -7, -257];
|
|
48
49
|
/**
|
|
49
|
-
* Prepare a value to pass into navigator.credentials.create(...) for authenticator
|
|
50
|
+
* Prepare a value to pass into navigator.credentials.create(...) for authenticator registration
|
|
50
51
|
*
|
|
51
52
|
* **Options:**
|
|
52
53
|
*
|
|
53
|
-
* @param rpName User-visible, "friendly" website/service name
|
|
54
|
-
* @param rpID Valid domain name (after `https://`)
|
|
55
|
-
* @param
|
|
56
|
-
* @param
|
|
57
|
-
* @param challenge Random value the authenticator needs to sign and pass back
|
|
58
|
-
* @param userDisplayName User's actual name
|
|
59
|
-
* @param timeout How long (in ms) the user can take to complete attestation
|
|
60
|
-
* @param attestationType Specific attestation statement
|
|
61
|
-
* @param excludeCredentials Authenticators registered by the user so the user can't register the
|
|
62
|
-
*
|
|
63
|
-
* @param
|
|
64
|
-
*
|
|
65
|
-
* @param extensions Additional plugins the authenticator or browser should use during attestation
|
|
66
|
-
* @param supportedAlgorithmIDs Array of numeric COSE algorithm identifiers supported for
|
|
67
|
-
* attestation by this RP. See https://www.iana.org/assignments/cose/cose.xhtml#algorithms
|
|
54
|
+
* @param rpName - User-visible, "friendly" website/service name
|
|
55
|
+
* @param rpID - Valid domain name (after `https://`)
|
|
56
|
+
* @param userName - User's website-specific username (email, etc...)
|
|
57
|
+
* @param userID **(Optional)** - User's website-specific unique ID. Defaults to generating a random identifier
|
|
58
|
+
* @param challenge **(Optional)** - Random value the authenticator needs to sign and pass back. Defaults to generating a random value
|
|
59
|
+
* @param userDisplayName **(Optional)** - User's actual name. Defaults to `""`
|
|
60
|
+
* @param timeout **(Optional)** - How long (in ms) the user can take to complete attestation. Defaults to `60000`
|
|
61
|
+
* @param attestationType **(Optional)** - Specific attestation statement. Defaults to `"none"`
|
|
62
|
+
* @param excludeCredentials **(Optional)** - Authenticators registered by the user so the user can't register the same credential multiple times. Defaults to `[]`
|
|
63
|
+
* @param authenticatorSelection **(Optional)** - Advanced criteria for restricting the types of authenticators that may be used. Defaults to `{ residentKey: 'preferred', userVerification: 'preferred' }`
|
|
64
|
+
* @param extensions **(Optional)** - Additional plugins the authenticator or browser should use during attestation
|
|
65
|
+
* @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]`
|
|
68
66
|
*/
|
|
69
67
|
export async function generateRegistrationOptions(options) {
|
|
70
|
-
const { rpName, rpID,
|
|
68
|
+
const { rpName, rpID, userName, userID, challenge = await generateChallenge(), userDisplayName = '', timeout = 60000, attestationType = 'none', excludeCredentials = [], authenticatorSelection = defaultAuthenticatorSelection, extensions, supportedAlgorithmIDs = defaultSupportedAlgorithmIDs, } = options;
|
|
71
69
|
/**
|
|
72
70
|
* Prepare pubKeyCredParams from the array of algorithm ID's
|
|
73
71
|
*/
|
|
@@ -115,6 +113,20 @@ export async function generateRegistrationOptions(options) {
|
|
|
115
113
|
if (typeof _challenge === 'string') {
|
|
116
114
|
_challenge = isoUint8Array.fromUTF8String(_challenge);
|
|
117
115
|
}
|
|
116
|
+
/**
|
|
117
|
+
* Explicitly disallow use of strings for userID anymore because `isoBase64URL.fromBuffer()` below
|
|
118
|
+
* will return an empty string if one gets through!
|
|
119
|
+
*/
|
|
120
|
+
if (typeof userID === 'string') {
|
|
121
|
+
throw new Error(`String values for \`userID\` are no longer supported. See https://simplewebauthn.dev/docs/advanced/server/custom-user-ids`);
|
|
122
|
+
}
|
|
123
|
+
/**
|
|
124
|
+
* Generate a user ID if one is not provided
|
|
125
|
+
*/
|
|
126
|
+
let _userID = userID;
|
|
127
|
+
if (!_userID) {
|
|
128
|
+
_userID = await generateUserID();
|
|
129
|
+
}
|
|
118
130
|
return {
|
|
119
131
|
challenge: isoBase64URL.fromBuffer(_challenge),
|
|
120
132
|
rp: {
|
|
@@ -122,17 +134,23 @@ export async function generateRegistrationOptions(options) {
|
|
|
122
134
|
id: rpID,
|
|
123
135
|
},
|
|
124
136
|
user: {
|
|
125
|
-
id:
|
|
137
|
+
id: isoBase64URL.fromBuffer(_userID),
|
|
126
138
|
name: userName,
|
|
127
139
|
displayName: userDisplayName,
|
|
128
140
|
},
|
|
129
141
|
pubKeyCredParams,
|
|
130
142
|
timeout,
|
|
131
143
|
attestation: attestationType,
|
|
132
|
-
excludeCredentials: excludeCredentials.map((cred) =>
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
144
|
+
excludeCredentials: excludeCredentials.map((cred) => {
|
|
145
|
+
if (!isoBase64URL.isBase64URL(cred.id)) {
|
|
146
|
+
throw new Error(`excludeCredential id "${cred.id}" is not a valid base64url string`);
|
|
147
|
+
}
|
|
148
|
+
return {
|
|
149
|
+
...cred,
|
|
150
|
+
id: isoBase64URL.trimPadding(cred.id),
|
|
151
|
+
type: 'public-key',
|
|
152
|
+
};
|
|
153
|
+
}),
|
|
136
154
|
authenticatorSelection,
|
|
137
155
|
extensions: {
|
|
138
156
|
...extensions,
|
|
@@ -23,8 +23,8 @@ export async function verifyAttestationAndroidSafetyNet(options) {
|
|
|
23
23
|
// Prepare to verify a JWT
|
|
24
24
|
const jwt = isoUint8Array.toUTF8String(response);
|
|
25
25
|
const jwtParts = jwt.split('.');
|
|
26
|
-
const HEADER = JSON.parse(isoBase64URL.
|
|
27
|
-
const PAYLOAD = JSON.parse(isoBase64URL.
|
|
26
|
+
const HEADER = JSON.parse(isoBase64URL.toUTF8String(jwtParts[0]));
|
|
27
|
+
const PAYLOAD = JSON.parse(isoBase64URL.toUTF8String(jwtParts[1]));
|
|
28
28
|
const SIGNATURE = jwtParts[2];
|
|
29
29
|
/**
|
|
30
30
|
* START Verify PAYLOAD
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { COSEAlgorithmIdentifier, CredentialDeviceType, RegistrationResponseJSON } from '../deps.js';
|
|
1
|
+
import type { Base64URLString, COSEAlgorithmIdentifier, CredentialDeviceType, RegistrationResponseJSON } from '../deps.js';
|
|
2
2
|
import { AttestationFormat, AttestationStatement } from '../helpers/decodeAttestationObject.js';
|
|
3
3
|
import { AuthenticationExtensionsAuthenticatorOutputs } from '../helpers/decodeAuthenticatorExtensions.js';
|
|
4
4
|
export type VerifyRegistrationResponseOpts = {
|
|
@@ -15,16 +15,13 @@ export type VerifyRegistrationResponseOpts = {
|
|
|
15
15
|
*
|
|
16
16
|
* **Options:**
|
|
17
17
|
*
|
|
18
|
-
* @param response Response returned by **@simplewebauthn/browser**'s `startAuthentication()`
|
|
19
|
-
* @param expectedChallenge The base64url-encoded `options.challenge` returned by
|
|
20
|
-
*
|
|
21
|
-
* @param
|
|
22
|
-
* @param
|
|
23
|
-
* @param
|
|
24
|
-
* @param
|
|
25
|
-
* (via PIN, fingerprint, etc...)
|
|
26
|
-
* @param supportedAlgorithmIDs Array of numeric COSE algorithm identifiers supported for
|
|
27
|
-
* attestation by this RP. See https://www.iana.org/assignments/cose/cose.xhtml#algorithms
|
|
18
|
+
* @param response - Response returned by **@simplewebauthn/browser**'s `startAuthentication()`
|
|
19
|
+
* @param expectedChallenge - The base64url-encoded `options.challenge` returned by `generateRegistrationOptions()`
|
|
20
|
+
* @param expectedOrigin - Website URL (or array of URLs) that the registration should have occurred on
|
|
21
|
+
* @param expectedRPID - RP ID (or array of IDs) that was specified in the registration options
|
|
22
|
+
* @param expectedType **(Optional)** - The response type expected ('webauthn.create')
|
|
23
|
+
* @param requireUserVerification **(Optional)** - Enforce user verification by the authenticator (via PIN, fingerprint, etc...) Defaults to `true`
|
|
24
|
+
* @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 all supported algorithm IDs
|
|
28
25
|
*/
|
|
29
26
|
export declare function verifyRegistrationResponse(options: VerifyRegistrationResponseOpts): Promise<VerifiedRegistrationResponse>;
|
|
30
27
|
/**
|
|
@@ -59,7 +56,7 @@ export type VerifiedRegistrationResponse = {
|
|
|
59
56
|
fmt: AttestationFormat;
|
|
60
57
|
counter: number;
|
|
61
58
|
aaguid: string;
|
|
62
|
-
credentialID:
|
|
59
|
+
credentialID: Base64URLString;
|
|
63
60
|
credentialPublicKey: Uint8Array;
|
|
64
61
|
credentialType: 'public-key';
|
|
65
62
|
attestationObject: Uint8Array;
|
|
@@ -21,16 +21,13 @@ import { verifyAttestationApple } from './verifications/verifyAttestationApple.j
|
|
|
21
21
|
*
|
|
22
22
|
* **Options:**
|
|
23
23
|
*
|
|
24
|
-
* @param response Response returned by **@simplewebauthn/browser**'s `startAuthentication()`
|
|
25
|
-
* @param expectedChallenge The base64url-encoded `options.challenge` returned by
|
|
26
|
-
*
|
|
27
|
-
* @param
|
|
28
|
-
* @param
|
|
29
|
-
* @param
|
|
30
|
-
* @param
|
|
31
|
-
* (via PIN, fingerprint, etc...)
|
|
32
|
-
* @param supportedAlgorithmIDs Array of numeric COSE algorithm identifiers supported for
|
|
33
|
-
* attestation by this RP. See https://www.iana.org/assignments/cose/cose.xhtml#algorithms
|
|
24
|
+
* @param response - Response returned by **@simplewebauthn/browser**'s `startAuthentication()`
|
|
25
|
+
* @param expectedChallenge - The base64url-encoded `options.challenge` returned by `generateRegistrationOptions()`
|
|
26
|
+
* @param expectedOrigin - Website URL (or array of URLs) that the registration should have occurred on
|
|
27
|
+
* @param expectedRPID - RP ID (or array of IDs) that was specified in the registration options
|
|
28
|
+
* @param expectedType **(Optional)** - The response type expected ('webauthn.create')
|
|
29
|
+
* @param requireUserVerification **(Optional)** - Enforce user verification by the authenticator (via PIN, fingerprint, etc...) Defaults to `true`
|
|
30
|
+
* @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 all supported algorithm IDs
|
|
34
31
|
*/
|
|
35
32
|
export async function verifyRegistrationResponse(options) {
|
|
36
33
|
const { response, expectedChallenge, expectedOrigin, expectedRPID, expectedType, requireUserVerification = true, supportedAlgorithmIDs = supportedCOSEAlgorithmIdentifiers, } = options;
|
|
@@ -194,7 +191,7 @@ export async function verifyRegistrationResponse(options) {
|
|
|
194
191
|
fmt,
|
|
195
192
|
counter,
|
|
196
193
|
aaguid: convertAAGUIDToString(aaguid),
|
|
197
|
-
credentialID,
|
|
194
|
+
credentialID: isoBase64URL.fromBuffer(credentialID),
|
|
198
195
|
credentialPublicKey,
|
|
199
196
|
credentialType,
|
|
200
197
|
attestationObject,
|
package/package.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"module": "./esm/index.js",
|
|
3
3
|
"main": "./script/index.js",
|
|
4
4
|
"name": "@simplewebauthn/server",
|
|
5
|
-
"version": "
|
|
5
|
+
"version": "10.0.1",
|
|
6
6
|
"description": "SimpleWebAuthn for Servers",
|
|
7
7
|
"license": "MIT",
|
|
8
8
|
"author": "Matthew Miller <matthew@millerti.me>",
|
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
"access": "public"
|
|
17
17
|
},
|
|
18
18
|
"engines": {
|
|
19
|
-
"node": ">=
|
|
19
|
+
"node": ">=20.0.0"
|
|
20
20
|
},
|
|
21
21
|
"bugs": {
|
|
22
22
|
"url": "https://github.com/MasterKale/SimpleWebAuthn/issues"
|
|
@@ -56,7 +56,7 @@
|
|
|
56
56
|
"@peculiar/asn1-rsa": "^2.3.8",
|
|
57
57
|
"@peculiar/asn1-schema": "^2.3.8",
|
|
58
58
|
"@peculiar/asn1-x509": "^2.3.8",
|
|
59
|
-
"@simplewebauthn/types": "^
|
|
59
|
+
"@simplewebauthn/types": "^10.0.0",
|
|
60
60
|
"cross-fetch": "^4.0.0"
|
|
61
61
|
},
|
|
62
62
|
"devDependencies": {
|
|
@@ -1,23 +1,25 @@
|
|
|
1
|
-
import type { AuthenticationExtensionsClientInputs,
|
|
1
|
+
import type { AuthenticationExtensionsClientInputs, AuthenticatorTransportFuture, Base64URLString, PublicKeyCredentialRequestOptionsJSON, UserVerificationRequirement } from '../deps.js';
|
|
2
2
|
export type GenerateAuthenticationOptionsOpts = {
|
|
3
|
-
|
|
3
|
+
rpID: string;
|
|
4
|
+
allowCredentials?: {
|
|
5
|
+
id: Base64URLString;
|
|
6
|
+
transports?: AuthenticatorTransportFuture[];
|
|
7
|
+
}[];
|
|
4
8
|
challenge?: string | Uint8Array;
|
|
5
9
|
timeout?: number;
|
|
6
10
|
userVerification?: UserVerificationRequirement;
|
|
7
11
|
extensions?: AuthenticationExtensionsClientInputs;
|
|
8
|
-
rpID?: string;
|
|
9
12
|
};
|
|
10
13
|
/**
|
|
11
|
-
* Prepare a value to pass into navigator.credentials.get(...) for authenticator
|
|
14
|
+
* Prepare a value to pass into navigator.credentials.get(...) for authenticator authentication
|
|
12
15
|
*
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
* @param
|
|
16
|
-
* user
|
|
17
|
-
* @param
|
|
18
|
-
* @param
|
|
19
|
-
* set to `'preferred'` or `'required'` as desired.
|
|
20
|
-
* @param extensions Additional plugins the authenticator or browser should use during authentication
|
|
21
|
-
* @param rpID Valid domain name (after `https://`)
|
|
16
|
+
* **Options:**
|
|
17
|
+
*
|
|
18
|
+
* @param rpID - Valid domain name (after `https://`)
|
|
19
|
+
* @param allowCredentials **(Optional)** - Authenticators previously registered by the user, if any. If undefined the client will ask the user which credential they want to use
|
|
20
|
+
* @param challenge **(Optional)** - Random value the authenticator needs to sign and pass back user for authentication. Defaults to generating a random value
|
|
21
|
+
* @param timeout **(Optional)** - How long (in ms) the user can take to complete authentication. Defaults to `60000`
|
|
22
|
+
* @param userVerification **(Optional)** - Set to `'discouraged'` when asserting as part of a 2FA flow, otherwise set to `'preferred'` or `'required'` as desired. Defaults to `"preferred"`
|
|
23
|
+
* @param extensions **(Optional)** - Additional plugins the authenticator or browser should use during authentication
|
|
22
24
|
*/
|
|
23
|
-
export declare function generateAuthenticationOptions(options
|
|
25
|
+
export declare function generateAuthenticationOptions(options: GenerateAuthenticationOptionsOpts): Promise<PublicKeyCredentialRequestOptionsJSON>;
|
|
@@ -4,19 +4,18 @@ exports.generateAuthenticationOptions = void 0;
|
|
|
4
4
|
const index_js_1 = require("../helpers/iso/index.js");
|
|
5
5
|
const generateChallenge_js_1 = require("../helpers/generateChallenge.js");
|
|
6
6
|
/**
|
|
7
|
-
* Prepare a value to pass into navigator.credentials.get(...) for authenticator
|
|
7
|
+
* Prepare a value to pass into navigator.credentials.get(...) for authenticator authentication
|
|
8
8
|
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
* @param
|
|
12
|
-
* user
|
|
13
|
-
* @param
|
|
14
|
-
* @param
|
|
15
|
-
* set to `'preferred'` or `'required'` as desired.
|
|
16
|
-
* @param extensions Additional plugins the authenticator or browser should use during authentication
|
|
17
|
-
* @param rpID Valid domain name (after `https://`)
|
|
9
|
+
* **Options:**
|
|
10
|
+
*
|
|
11
|
+
* @param rpID - Valid domain name (after `https://`)
|
|
12
|
+
* @param allowCredentials **(Optional)** - Authenticators previously registered by the user, if any. If undefined the client will ask the user which credential they want to use
|
|
13
|
+
* @param challenge **(Optional)** - Random value the authenticator needs to sign and pass back user for authentication. Defaults to generating a random value
|
|
14
|
+
* @param timeout **(Optional)** - How long (in ms) the user can take to complete authentication. Defaults to `60000`
|
|
15
|
+
* @param userVerification **(Optional)** - Set to `'discouraged'` when asserting as part of a 2FA flow, otherwise set to `'preferred'` or `'required'` as desired. Defaults to `"preferred"`
|
|
16
|
+
* @param extensions **(Optional)** - Additional plugins the authenticator or browser should use during authentication
|
|
18
17
|
*/
|
|
19
|
-
async function generateAuthenticationOptions(options
|
|
18
|
+
async function generateAuthenticationOptions(options) {
|
|
20
19
|
const { allowCredentials, challenge = await (0, generateChallenge_js_1.generateChallenge)(), timeout = 60000, userVerification = 'preferred', extensions, rpID, } = options;
|
|
21
20
|
/**
|
|
22
21
|
* Preserve ability to specify `string` values for challenges
|
|
@@ -26,15 +25,21 @@ async function generateAuthenticationOptions(options = {}) {
|
|
|
26
25
|
_challenge = index_js_1.isoUint8Array.fromUTF8String(_challenge);
|
|
27
26
|
}
|
|
28
27
|
return {
|
|
28
|
+
rpId: rpID,
|
|
29
29
|
challenge: index_js_1.isoBase64URL.fromBuffer(_challenge),
|
|
30
|
-
allowCredentials: allowCredentials?.map((cred) =>
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
30
|
+
allowCredentials: allowCredentials?.map((cred) => {
|
|
31
|
+
if (!index_js_1.isoBase64URL.isBase64URL(cred.id)) {
|
|
32
|
+
throw new Error(`excludeCredential id "${cred.id}" is not a valid base64url string`);
|
|
33
|
+
}
|
|
34
|
+
return {
|
|
35
|
+
...cred,
|
|
36
|
+
id: index_js_1.isoBase64URL.trimPadding(cred.id),
|
|
37
|
+
type: 'public-key',
|
|
38
|
+
};
|
|
39
|
+
}),
|
|
34
40
|
timeout,
|
|
35
41
|
userVerification,
|
|
36
42
|
extensions,
|
|
37
|
-
rpId: rpID,
|
|
38
43
|
};
|
|
39
44
|
}
|
|
40
45
|
exports.generateAuthenticationOptions = generateAuthenticationOptions;
|
|
@@ -1,36 +1,31 @@
|
|
|
1
|
-
import type { AuthenticationResponseJSON, AuthenticatorDevice, CredentialDeviceType, UserVerificationRequirement } from '../deps.js';
|
|
1
|
+
import type { AuthenticationResponseJSON, AuthenticatorDevice, Base64URLString, CredentialDeviceType, UserVerificationRequirement } from '../deps.js';
|
|
2
2
|
import { AuthenticationExtensionsAuthenticatorOutputs } from '../helpers/decodeAuthenticatorExtensions.js';
|
|
3
3
|
export type VerifyAuthenticationResponseOpts = {
|
|
4
4
|
response: AuthenticationResponseJSON;
|
|
5
5
|
expectedChallenge: string | ((challenge: string) => boolean | Promise<boolean>);
|
|
6
6
|
expectedOrigin: string | string[];
|
|
7
7
|
expectedRPID: string | string[];
|
|
8
|
-
expectedType?: string | string[];
|
|
9
8
|
authenticator: AuthenticatorDevice;
|
|
9
|
+
expectedType?: string | string[];
|
|
10
10
|
requireUserVerification?: boolean;
|
|
11
11
|
advancedFIDOConfig?: {
|
|
12
12
|
userVerification?: UserVerificationRequirement;
|
|
13
13
|
};
|
|
14
14
|
};
|
|
15
15
|
/**
|
|
16
|
-
* Verify that the user has legitimately completed the
|
|
16
|
+
* Verify that the user has legitimately completed the authentication process
|
|
17
17
|
*
|
|
18
18
|
* **Options:**
|
|
19
19
|
*
|
|
20
|
-
* @param response Response returned by **@simplewebauthn/browser**'s `startAssertion()`
|
|
21
|
-
* @param expectedChallenge The base64url-encoded `options.challenge` returned by
|
|
22
|
-
*
|
|
23
|
-
* @param
|
|
24
|
-
* @param
|
|
25
|
-
* @param expectedType (Optional) The response type expected ('webauthn.get')
|
|
26
|
-
* @param
|
|
27
|
-
* @param
|
|
28
|
-
* (
|
|
29
|
-
* @param advancedFIDOConfig (Optional) Options for satisfying more stringent FIDO RP feature
|
|
30
|
-
* requirements
|
|
31
|
-
* @param advancedFIDOConfig.userVerification (Optional) Enable alternative rules for evaluating the
|
|
32
|
-
* User Presence and User Verified flags in authenticator data: UV (and UP) flags are optional
|
|
33
|
-
* unless this value is `"required"`
|
|
20
|
+
* @param response - Response returned by **@simplewebauthn/browser**'s `startAssertion()`
|
|
21
|
+
* @param expectedChallenge - The base64url-encoded `options.challenge` returned by `generateAuthenticationOptions()`
|
|
22
|
+
* @param expectedOrigin - Website URL (or array of URLs) that the registration should have occurred on
|
|
23
|
+
* @param expectedRPID - RP ID (or array of IDs) that was specified in the registration options
|
|
24
|
+
* @param authenticator - An internal {@link AuthenticatorDevice} matching the credential's ID
|
|
25
|
+
* @param expectedType **(Optional)** - The response type expected ('webauthn.get')
|
|
26
|
+
* @param requireUserVerification **(Optional)** - Enforce user verification by the authenticator (via PIN, fingerprint, etc...) Defaults to `true`
|
|
27
|
+
* @param advancedFIDOConfig **(Optional)** - Options for satisfying more stringent FIDO RP feature requirements
|
|
28
|
+
* @param advancedFIDOConfig.userVerification **(Optional)** - Enable alternative rules for evaluating the User Presence and User Verified flags in authenticator data: UV (and UP) flags are optional unless this value is `"required"`
|
|
34
29
|
*/
|
|
35
30
|
export declare function verifyAuthenticationResponse(options: VerifyAuthenticationResponseOpts): Promise<VerifiedAuthenticationResponse>;
|
|
36
31
|
/**
|
|
@@ -56,7 +51,7 @@ export declare function verifyAuthenticationResponse(options: VerifyAuthenticati
|
|
|
56
51
|
export type VerifiedAuthenticationResponse = {
|
|
57
52
|
verified: boolean;
|
|
58
53
|
authenticationInfo: {
|
|
59
|
-
credentialID:
|
|
54
|
+
credentialID: Base64URLString;
|
|
60
55
|
newCounter: number;
|
|
61
56
|
userVerified: boolean;
|
|
62
57
|
credentialDeviceType: CredentialDeviceType;
|
|
@@ -9,24 +9,19 @@ const parseBackupFlags_js_1 = require("../helpers/parseBackupFlags.js");
|
|
|
9
9
|
const matchExpectedRPID_js_1 = require("../helpers/matchExpectedRPID.js");
|
|
10
10
|
const index_js_1 = require("../helpers/iso/index.js");
|
|
11
11
|
/**
|
|
12
|
-
* Verify that the user has legitimately completed the
|
|
12
|
+
* Verify that the user has legitimately completed the authentication process
|
|
13
13
|
*
|
|
14
14
|
* **Options:**
|
|
15
15
|
*
|
|
16
|
-
* @param response Response returned by **@simplewebauthn/browser**'s `startAssertion()`
|
|
17
|
-
* @param expectedChallenge The base64url-encoded `options.challenge` returned by
|
|
18
|
-
*
|
|
19
|
-
* @param
|
|
20
|
-
* @param
|
|
21
|
-
* @param expectedType (Optional) The response type expected ('webauthn.get')
|
|
22
|
-
* @param
|
|
23
|
-
* @param
|
|
24
|
-
* (
|
|
25
|
-
* @param advancedFIDOConfig (Optional) Options for satisfying more stringent FIDO RP feature
|
|
26
|
-
* requirements
|
|
27
|
-
* @param advancedFIDOConfig.userVerification (Optional) Enable alternative rules for evaluating the
|
|
28
|
-
* User Presence and User Verified flags in authenticator data: UV (and UP) flags are optional
|
|
29
|
-
* unless this value is `"required"`
|
|
16
|
+
* @param response - Response returned by **@simplewebauthn/browser**'s `startAssertion()`
|
|
17
|
+
* @param expectedChallenge - The base64url-encoded `options.challenge` returned by `generateAuthenticationOptions()`
|
|
18
|
+
* @param expectedOrigin - Website URL (or array of URLs) that the registration should have occurred on
|
|
19
|
+
* @param expectedRPID - RP ID (or array of IDs) that was specified in the registration options
|
|
20
|
+
* @param authenticator - An internal {@link AuthenticatorDevice} matching the credential's ID
|
|
21
|
+
* @param expectedType **(Optional)** - The response type expected ('webauthn.get')
|
|
22
|
+
* @param requireUserVerification **(Optional)** - Enforce user verification by the authenticator (via PIN, fingerprint, etc...) Defaults to `true`
|
|
23
|
+
* @param advancedFIDOConfig **(Optional)** - Options for satisfying more stringent FIDO RP feature requirements
|
|
24
|
+
* @param advancedFIDOConfig.userVerification **(Optional)** - Enable alternative rules for evaluating the User Presence and User Verified flags in authenticator data: UV (and UP) flags are optional unless this value is `"required"`
|
|
30
25
|
*/
|
|
31
26
|
async function verifyAuthenticationResponse(options) {
|
|
32
27
|
const { response, expectedChallenge, expectedOrigin, expectedRPID, expectedType, authenticator, requireUserVerification = true, advancedFIDOConfig, } = options;
|
|
@@ -87,10 +82,10 @@ async function verifyAuthenticationResponse(options) {
|
|
|
87
82
|
throw new Error(`Unexpected authentication response origin "${origin}", expected "${expectedOrigin}"`);
|
|
88
83
|
}
|
|
89
84
|
}
|
|
90
|
-
if (!index_js_1.isoBase64URL.
|
|
85
|
+
if (!index_js_1.isoBase64URL.isBase64URL(assertionResponse.authenticatorData)) {
|
|
91
86
|
throw new Error('Credential response authenticatorData was not a base64url string');
|
|
92
87
|
}
|
|
93
|
-
if (!index_js_1.isoBase64URL.
|
|
88
|
+
if (!index_js_1.isoBase64URL.isBase64URL(assertionResponse.signature)) {
|
|
94
89
|
throw new Error('Credential response signature was not a base64url string');
|
|
95
90
|
}
|
|
96
91
|
if (assertionResponse.userHandle &&
|
package/script/deps.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export type { AttestationConveyancePreference, AuthenticationExtensionsClientInputs, AuthenticationResponseJSON, AuthenticatorDevice, AuthenticatorSelectionCriteria, Base64URLString, COSEAlgorithmIdentifier, CredentialDeviceType, Crypto, PublicKeyCredentialCreationOptionsJSON,
|
|
1
|
+
export type { AttestationConveyancePreference, AuthenticationExtensionsClientInputs, AuthenticationResponseJSON, AuthenticatorDevice, AuthenticatorSelectionCriteria, AuthenticatorTransportFuture, Base64URLString, COSEAlgorithmIdentifier, CredentialDeviceType, Crypto, PublicKeyCredentialCreationOptionsJSON, PublicKeyCredentialParameters, PublicKeyCredentialRequestOptionsJSON, RegistrationResponseJSON, UserVerificationRequirement, } from '@simplewebauthn/types';
|
|
2
2
|
export * as tinyCbor from '@levischuck/tiny-cbor';
|
|
3
3
|
export { default as base64 } from '@hexagon/base64';
|
|
4
4
|
export { fetch as crossFetch } from 'cross-fetch';
|
|
@@ -11,7 +11,7 @@ function convertCertBufferToPEM(certBuffer) {
|
|
|
11
11
|
* Get certBuffer to a base64 representation
|
|
12
12
|
*/
|
|
13
13
|
if (typeof certBuffer === 'string') {
|
|
14
|
-
if (index_js_1.isoBase64URL.
|
|
14
|
+
if (index_js_1.isoBase64URL.isBase64URL(certBuffer)) {
|
|
15
15
|
b64cert = index_js_1.isoBase64URL.toBase64(certBuffer);
|
|
16
16
|
}
|
|
17
17
|
else if (index_js_1.isoBase64URL.isBase64(certBuffer)) {
|
|
@@ -1,7 +1,8 @@
|
|
|
1
|
+
import type { Base64URLString } from '../deps.js';
|
|
1
2
|
/**
|
|
2
3
|
* Decode an authenticator's base64url-encoded clientDataJSON to JSON
|
|
3
4
|
*/
|
|
4
|
-
export declare function decodeClientDataJSON(data:
|
|
5
|
+
export declare function decodeClientDataJSON(data: Base64URLString): ClientDataJSON;
|
|
5
6
|
export type ClientDataJSON = {
|
|
6
7
|
type: string;
|
|
7
8
|
challenge: string;
|
|
@@ -6,7 +6,7 @@ const index_js_1 = require("./iso/index.js");
|
|
|
6
6
|
* Decode an authenticator's base64url-encoded clientDataJSON to JSON
|
|
7
7
|
*/
|
|
8
8
|
function decodeClientDataJSON(data) {
|
|
9
|
-
const toString = index_js_1.isoBase64URL.
|
|
9
|
+
const toString = index_js_1.isoBase64URL.toUTF8String(data);
|
|
10
10
|
const clientData = JSON.parse(toString);
|
|
11
11
|
return exports._decodeClientDataJSONInternals.stubThis(clientData);
|
|
12
12
|
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports._generateUserIDInternals = exports.generateUserID = void 0;
|
|
4
|
+
const index_js_1 = require("./iso/index.js");
|
|
5
|
+
/**
|
|
6
|
+
* Generate a suitably random value to be used as user ID
|
|
7
|
+
*/
|
|
8
|
+
async function generateUserID() {
|
|
9
|
+
/**
|
|
10
|
+
* WebAuthn spec says user.id has a max length of 64 bytes. I prefer how 32 random bytes look
|
|
11
|
+
* after they're base64url-encoded so I'm choosing to go with that here.
|
|
12
|
+
*/
|
|
13
|
+
const newUserID = new Uint8Array(32);
|
|
14
|
+
await index_js_1.isoCrypto.getRandomValues(newUserID);
|
|
15
|
+
return exports._generateUserIDInternals.stubThis(newUserID);
|
|
16
|
+
}
|
|
17
|
+
exports.generateUserID = generateUserID;
|
|
18
|
+
// Make it possible to stub the return value during testing
|
|
19
|
+
exports._generateUserIDInternals = {
|
|
20
|
+
stubThis: (value) => value,
|
|
21
|
+
};
|
|
@@ -5,6 +5,7 @@ import { decodeAttestationObject } from './decodeAttestationObject.js';
|
|
|
5
5
|
import { decodeClientDataJSON } from './decodeClientDataJSON.js';
|
|
6
6
|
import { decodeCredentialPublicKey } from './decodeCredentialPublicKey.js';
|
|
7
7
|
import { generateChallenge } from './generateChallenge.js';
|
|
8
|
+
import { generateUserID } from './generateUserID.js';
|
|
8
9
|
import { getCertificateInfo } from './getCertificateInfo.js';
|
|
9
10
|
import { isCertRevoked } from './isCertRevoked.js';
|
|
10
11
|
import { parseAuthenticatorData } from './parseAuthenticatorData.js';
|
|
@@ -13,7 +14,7 @@ import { validateCertificatePath } from './validateCertificatePath.js';
|
|
|
13
14
|
import { verifySignature } from './verifySignature.js';
|
|
14
15
|
import { isoBase64URL, isoCBOR, isoCrypto, isoUint8Array } from './iso/index.js';
|
|
15
16
|
import * as cose from './cose.js';
|
|
16
|
-
export { convertAAGUIDToString, convertCertBufferToPEM, convertCOSEtoPKCS, cose, decodeAttestationObject, decodeClientDataJSON, decodeCredentialPublicKey, generateChallenge, getCertificateInfo, isCertRevoked, isoBase64URL, isoCBOR, isoCrypto, isoUint8Array, parseAuthenticatorData, toHash, validateCertificatePath, verifySignature, };
|
|
17
|
+
export { convertAAGUIDToString, convertCertBufferToPEM, convertCOSEtoPKCS, cose, decodeAttestationObject, decodeClientDataJSON, decodeCredentialPublicKey, generateChallenge, generateUserID, getCertificateInfo, isCertRevoked, isoBase64URL, isoCBOR, isoCrypto, isoUint8Array, parseAuthenticatorData, toHash, validateCertificatePath, verifySignature, };
|
|
17
18
|
import type { AttestationFormat, AttestationObject, AttestationStatement } from './decodeAttestationObject.js';
|
|
18
19
|
import type { CertificateInfo } from './getCertificateInfo.js';
|
|
19
20
|
import type { ClientDataJSON } from './decodeClientDataJSON.js';
|
package/script/helpers/index.js
CHANGED
|
@@ -23,7 +23,7 @@ var __importStar = (this && this.__importStar) || function (mod) {
|
|
|
23
23
|
return result;
|
|
24
24
|
};
|
|
25
25
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
26
|
-
exports.verifySignature = exports.validateCertificatePath = exports.toHash = exports.parseAuthenticatorData = exports.isoUint8Array = exports.isoCrypto = exports.isoCBOR = exports.isoBase64URL = exports.isCertRevoked = exports.getCertificateInfo = exports.generateChallenge = exports.decodeCredentialPublicKey = exports.decodeClientDataJSON = exports.decodeAttestationObject = exports.cose = exports.convertCOSEtoPKCS = exports.convertCertBufferToPEM = exports.convertAAGUIDToString = void 0;
|
|
26
|
+
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;
|
|
27
27
|
const convertAAGUIDToString_js_1 = require("./convertAAGUIDToString.js");
|
|
28
28
|
Object.defineProperty(exports, "convertAAGUIDToString", { enumerable: true, get: function () { return convertAAGUIDToString_js_1.convertAAGUIDToString; } });
|
|
29
29
|
const convertCertBufferToPEM_js_1 = require("./convertCertBufferToPEM.js");
|
|
@@ -38,6 +38,8 @@ const decodeCredentialPublicKey_js_1 = require("./decodeCredentialPublicKey.js")
|
|
|
38
38
|
Object.defineProperty(exports, "decodeCredentialPublicKey", { enumerable: true, get: function () { return decodeCredentialPublicKey_js_1.decodeCredentialPublicKey; } });
|
|
39
39
|
const generateChallenge_js_1 = require("./generateChallenge.js");
|
|
40
40
|
Object.defineProperty(exports, "generateChallenge", { enumerable: true, get: function () { return generateChallenge_js_1.generateChallenge; } });
|
|
41
|
+
const generateUserID_js_1 = require("./generateUserID.js");
|
|
42
|
+
Object.defineProperty(exports, "generateUserID", { enumerable: true, get: function () { return generateUserID_js_1.generateUserID; } });
|
|
41
43
|
const getCertificateInfo_js_1 = require("./getCertificateInfo.js");
|
|
42
44
|
Object.defineProperty(exports, "getCertificateInfo", { enumerable: true, get: function () { return getCertificateInfo_js_1.getCertificateInfo; } });
|
|
43
45
|
const isCertRevoked_js_1 = require("./isCertRevoked.js");
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { Base64URLString } from '../../deps.js';
|
|
1
2
|
/**
|
|
2
3
|
* Decode from a Base64URL-encoded string to an ArrayBuffer. Best used when converting a
|
|
3
4
|
* credential ID from a JSON string to an ArrayBuffer, like in allowCredentials or
|
|
@@ -20,13 +21,13 @@ export declare function fromBuffer(buffer: Uint8Array, to?: 'base64' | 'base64ur
|
|
|
20
21
|
*/
|
|
21
22
|
export declare function toBase64(base64urlString: string): string;
|
|
22
23
|
/**
|
|
23
|
-
* Encode a string to base64url
|
|
24
|
+
* Encode a UTF-8 string to base64url
|
|
24
25
|
*/
|
|
25
|
-
export declare function
|
|
26
|
+
export declare function fromUTF8String(utf8String: string): string;
|
|
26
27
|
/**
|
|
27
|
-
* Decode a base64url string into its original string
|
|
28
|
+
* Decode a base64url string into its original UTF-8 string
|
|
28
29
|
*/
|
|
29
|
-
export declare function
|
|
30
|
+
export declare function toUTF8String(base64urlString: string): string;
|
|
30
31
|
/**
|
|
31
32
|
* Confirm that the string is encoded into base64
|
|
32
33
|
*/
|
|
@@ -34,4 +35,8 @@ export declare function isBase64(input: string): boolean;
|
|
|
34
35
|
/**
|
|
35
36
|
* Confirm that the string is encoded into base64url, with support for optional padding
|
|
36
37
|
*/
|
|
37
|
-
export declare function
|
|
38
|
+
export declare function isBase64URL(input: string): boolean;
|
|
39
|
+
/**
|
|
40
|
+
* Remove optional padding from a base64url-encoded string
|
|
41
|
+
*/
|
|
42
|
+
export declare function trimPadding(input: Base64URLString): Base64URLString;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.
|
|
3
|
+
exports.trimPadding = exports.isBase64URL = exports.isBase64 = exports.toUTF8String = exports.fromUTF8String = exports.toBase64 = exports.fromBuffer = exports.toBuffer = void 0;
|
|
4
4
|
const deps_js_1 = require("../../deps.js");
|
|
5
5
|
/**
|
|
6
6
|
* Decode from a Base64URL-encoded string to an ArrayBuffer. Best used when converting a
|
|
@@ -36,19 +36,19 @@ function toBase64(base64urlString) {
|
|
|
36
36
|
}
|
|
37
37
|
exports.toBase64 = toBase64;
|
|
38
38
|
/**
|
|
39
|
-
* Encode a string to base64url
|
|
39
|
+
* Encode a UTF-8 string to base64url
|
|
40
40
|
*/
|
|
41
|
-
function
|
|
42
|
-
return deps_js_1.base64.fromString(
|
|
41
|
+
function fromUTF8String(utf8String) {
|
|
42
|
+
return deps_js_1.base64.fromString(utf8String, true);
|
|
43
43
|
}
|
|
44
|
-
exports.
|
|
44
|
+
exports.fromUTF8String = fromUTF8String;
|
|
45
45
|
/**
|
|
46
|
-
* Decode a base64url string into its original string
|
|
46
|
+
* Decode a base64url string into its original UTF-8 string
|
|
47
47
|
*/
|
|
48
|
-
function
|
|
48
|
+
function toUTF8String(base64urlString) {
|
|
49
49
|
return deps_js_1.base64.toString(base64urlString, true);
|
|
50
50
|
}
|
|
51
|
-
exports.
|
|
51
|
+
exports.toUTF8String = toUTF8String;
|
|
52
52
|
/**
|
|
53
53
|
* Confirm that the string is encoded into base64
|
|
54
54
|
*/
|
|
@@ -59,9 +59,16 @@ exports.isBase64 = isBase64;
|
|
|
59
59
|
/**
|
|
60
60
|
* Confirm that the string is encoded into base64url, with support for optional padding
|
|
61
61
|
*/
|
|
62
|
-
function
|
|
62
|
+
function isBase64URL(input) {
|
|
63
63
|
// Trim padding characters from the string if present
|
|
64
|
-
input = input
|
|
64
|
+
input = trimPadding(input);
|
|
65
65
|
return deps_js_1.base64.validate(input, true);
|
|
66
66
|
}
|
|
67
|
-
exports.
|
|
67
|
+
exports.isBase64URL = isBase64URL;
|
|
68
|
+
/**
|
|
69
|
+
* Remove optional padding from a base64url-encoded string
|
|
70
|
+
*/
|
|
71
|
+
function trimPadding(input) {
|
|
72
|
+
return input.replace(/=/g, '');
|
|
73
|
+
}
|
|
74
|
+
exports.trimPadding = trimPadding;
|