@revibase/ctap2-js 0.1.0
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 +65 -0
- package/lib/apdu.d.ts +56 -0
- package/lib/apdu.d.ts.map +1 -0
- package/lib/apdu.js +225 -0
- package/lib/buildRequests.d.ts +11 -0
- package/lib/buildRequests.d.ts.map +1 -0
- package/lib/buildRequests.js +24 -0
- package/lib/constants.d.ts +11 -0
- package/lib/constants.d.ts.map +1 -0
- package/lib/constants.js +15 -0
- package/lib/ctap2/cborUtils.d.ts +14 -0
- package/lib/ctap2/cborUtils.d.ts.map +1 -0
- package/lib/ctap2/cborUtils.js +141 -0
- package/lib/ctap2/getAssertion.d.ts +32 -0
- package/lib/ctap2/getAssertion.d.ts.map +1 -0
- package/lib/ctap2/getAssertion.js +104 -0
- package/lib/ctap2/makeCredential.d.ts +37 -0
- package/lib/ctap2/makeCredential.d.ts.map +1 -0
- package/lib/ctap2/makeCredential.js +118 -0
- package/lib/errors.d.ts +7 -0
- package/lib/errors.d.ts.map +1 -0
- package/lib/errors.js +13 -0
- package/lib/helpers/authDataExtensions.d.ts +9 -0
- package/lib/helpers/authDataExtensions.d.ts.map +1 -0
- package/lib/helpers/authDataExtensions.js +192 -0
- package/lib/helpers/base64url.d.ts +3 -0
- package/lib/helpers/base64url.d.ts.map +1 -0
- package/lib/helpers/base64url.js +29 -0
- package/lib/helpers/clientData.d.ts +9 -0
- package/lib/helpers/clientData.d.ts.map +1 -0
- package/lib/helpers/clientData.js +18 -0
- package/lib/helpers/fromWebAuthnJson.d.ts +6 -0
- package/lib/helpers/fromWebAuthnJson.d.ts.map +1 -0
- package/lib/helpers/fromWebAuthnJson.js +125 -0
- package/lib/helpers/webauthnResponses.d.ts +21 -0
- package/lib/helpers/webauthnResponses.d.ts.map +1 -0
- package/lib/helpers/webauthnResponses.js +51 -0
- package/lib/helpers/webauthnTypes.d.ts +6 -0
- package/lib/helpers/webauthnTypes.d.ts.map +1 -0
- package/lib/helpers/webauthnTypes.js +2 -0
- package/lib/index.d.ts +4 -0
- package/lib/index.d.ts.map +1 -0
- package/lib/index.js +8 -0
- package/lib/parseResponses.d.ts +19 -0
- package/lib/parseResponses.d.ts.map +1 -0
- package/lib/parseResponses.js +37 -0
- package/lib/publicApi.d.ts +15 -0
- package/lib/publicApi.d.ts.map +1 -0
- package/lib/publicApi.js +83 -0
- package/lib/types.d.ts +10 -0
- package/lib/types.d.ts.map +1 -0
- package/lib/types.js +2 -0
- package/package.json +35 -0
- package/src/apdu.ts +285 -0
- package/src/constants.ts +16 -0
- package/src/ctap2/cborUtils.ts +155 -0
- package/src/ctap2/getAssertion.ts +154 -0
- package/src/ctap2/makeCredential.ts +173 -0
- package/src/errors.ts +11 -0
- package/src/helpers/authDataExtensions.ts +214 -0
- package/src/helpers/base64url.ts +24 -0
- package/src/helpers/clientData.ts +24 -0
- package/src/helpers/fromWebAuthnJson.ts +175 -0
- package/src/helpers/webauthnResponses.ts +113 -0
- package/src/index.ts +6 -0
- package/src/parseResponses.ts +67 -0
- package/src/publicApi.ts +152 -0
- package/src/types.ts +16 -0
- package/tsconfig.json +16 -0
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.authenticatorMakeCredentialRequestFromPublicKeyCredentialCreationOptionsJSON = exports.authenticatorGetAssertionRequestFromPublicKeyCredentialRequestOptionsJSON = void 0;
|
|
4
|
+
const sha2_js_1 = require("@noble/hashes/sha2.js");
|
|
5
|
+
const utils_js_1 = require("@noble/hashes/utils.js");
|
|
6
|
+
const errors_1 = require("../errors");
|
|
7
|
+
const base64url_1 = require("./base64url");
|
|
8
|
+
const clientData_1 = require("./clientData");
|
|
9
|
+
function userVerificationToOptionalUvBool(uv) {
|
|
10
|
+
if (uv === "required") {
|
|
11
|
+
return true;
|
|
12
|
+
}
|
|
13
|
+
if (uv === "discouraged") {
|
|
14
|
+
return false;
|
|
15
|
+
}
|
|
16
|
+
return undefined;
|
|
17
|
+
}
|
|
18
|
+
function mapAuthenticatorSelection(sel) {
|
|
19
|
+
if (!sel) {
|
|
20
|
+
return undefined;
|
|
21
|
+
}
|
|
22
|
+
let rk;
|
|
23
|
+
if (sel.residentKey === "required" || sel.residentKey === "preferred") {
|
|
24
|
+
rk = true;
|
|
25
|
+
}
|
|
26
|
+
else if (sel.residentKey === "discouraged") {
|
|
27
|
+
rk = false;
|
|
28
|
+
}
|
|
29
|
+
else if (sel.requireResidentKey === true) {
|
|
30
|
+
rk = true;
|
|
31
|
+
}
|
|
32
|
+
const uv = userVerificationToOptionalUvBool(sel.userVerification);
|
|
33
|
+
if (rk === undefined && uv === undefined) {
|
|
34
|
+
return undefined;
|
|
35
|
+
}
|
|
36
|
+
const o = {};
|
|
37
|
+
if (rk !== undefined) {
|
|
38
|
+
o.rk = rk;
|
|
39
|
+
}
|
|
40
|
+
if (uv !== undefined) {
|
|
41
|
+
o.uv = uv;
|
|
42
|
+
}
|
|
43
|
+
return o;
|
|
44
|
+
}
|
|
45
|
+
function pickCtapExtensions(ext, mode) {
|
|
46
|
+
if (!ext) {
|
|
47
|
+
return undefined;
|
|
48
|
+
}
|
|
49
|
+
const out = {};
|
|
50
|
+
for (const [k, v] of Object.entries(ext)) {
|
|
51
|
+
if (v == null) {
|
|
52
|
+
continue;
|
|
53
|
+
}
|
|
54
|
+
if (mode === "assertion" && k === "credProps") {
|
|
55
|
+
continue;
|
|
56
|
+
}
|
|
57
|
+
out[k] = v;
|
|
58
|
+
}
|
|
59
|
+
return Object.keys(out).length ? out : undefined;
|
|
60
|
+
}
|
|
61
|
+
function authenticatorGetAssertionRequestFromPublicKeyCredentialRequestOptionsJSON(args) {
|
|
62
|
+
const { challenge, rpId, allowCredentials, userVerification, extensions, crossOrigin = false, topOrigin, origin, } = args;
|
|
63
|
+
if (!rpId)
|
|
64
|
+
throw new errors_1.ApduError("WebAuthn options: rpId is required");
|
|
65
|
+
const clientDataJSON = (0, clientData_1.buildCollectedClientDataJSON)("webauthn.get", {
|
|
66
|
+
challenge,
|
|
67
|
+
origin,
|
|
68
|
+
crossOrigin,
|
|
69
|
+
topOrigin,
|
|
70
|
+
});
|
|
71
|
+
const clientDataHash = (0, sha2_js_1.sha256)((0, utils_js_1.utf8ToBytes)(clientDataJSON));
|
|
72
|
+
const uv = userVerificationToOptionalUvBool(userVerification);
|
|
73
|
+
const uvOpts = uv === undefined ? undefined : { up: true, uv };
|
|
74
|
+
const parsedExtensions = extensions
|
|
75
|
+
? pickCtapExtensions(extensions, "assertion")
|
|
76
|
+
: undefined;
|
|
77
|
+
return {
|
|
78
|
+
rpId,
|
|
79
|
+
clientDataHash,
|
|
80
|
+
allowCredentials: allowCredentials?.map((d) => ({
|
|
81
|
+
id: new Uint8Array((0, base64url_1.base64URLStringToBuffer)(d.id)),
|
|
82
|
+
type: d.type ?? "public-key",
|
|
83
|
+
})),
|
|
84
|
+
extensions: parsedExtensions,
|
|
85
|
+
options: uvOpts,
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
exports.authenticatorGetAssertionRequestFromPublicKeyCredentialRequestOptionsJSON = authenticatorGetAssertionRequestFromPublicKeyCredentialRequestOptionsJSON;
|
|
89
|
+
function authenticatorMakeCredentialRequestFromPublicKeyCredentialCreationOptionsJSON(args) {
|
|
90
|
+
const { challenge, user, excludeCredentials, extensions, authenticatorSelection, crossOrigin = false, topOrigin, origin, pubKeyCredParams, rp, } = args;
|
|
91
|
+
if (!rp.id)
|
|
92
|
+
throw new errors_1.ApduError("WebAuthn options: rp.id is required");
|
|
93
|
+
const clientDataJSON = (0, clientData_1.buildCollectedClientDataJSON)("webauthn.create", {
|
|
94
|
+
challenge,
|
|
95
|
+
origin,
|
|
96
|
+
crossOrigin,
|
|
97
|
+
topOrigin,
|
|
98
|
+
});
|
|
99
|
+
const clientDataHash = (0, sha2_js_1.sha256)((0, utils_js_1.utf8ToBytes)(clientDataJSON));
|
|
100
|
+
const userId = new Uint8Array((0, base64url_1.base64URLStringToBuffer)(user.id));
|
|
101
|
+
const parsedExtensions = extensions
|
|
102
|
+
? pickCtapExtensions(extensions, "registration")
|
|
103
|
+
: undefined;
|
|
104
|
+
const opt = mapAuthenticatorSelection(authenticatorSelection);
|
|
105
|
+
return {
|
|
106
|
+
clientDataHash,
|
|
107
|
+
rp: { id: rp.id, name: rp.name },
|
|
108
|
+
user: {
|
|
109
|
+
id: userId,
|
|
110
|
+
name: user.name,
|
|
111
|
+
displayName: user.displayName,
|
|
112
|
+
},
|
|
113
|
+
pubKeyCredParams: pubKeyCredParams.map((p) => ({
|
|
114
|
+
alg: p.alg,
|
|
115
|
+
type: p.type ?? "public-key",
|
|
116
|
+
})),
|
|
117
|
+
excludeCredentials: excludeCredentials?.map((d) => ({
|
|
118
|
+
id: new Uint8Array((0, base64url_1.base64URLStringToBuffer)(d.id)),
|
|
119
|
+
type: d.type ?? "public-key",
|
|
120
|
+
})),
|
|
121
|
+
extensions: parsedExtensions,
|
|
122
|
+
options: opt,
|
|
123
|
+
};
|
|
124
|
+
}
|
|
125
|
+
exports.authenticatorMakeCredentialRequestFromPublicKeyCredentialCreationOptionsJSON = authenticatorMakeCredentialRequestFromPublicKeyCredentialCreationOptionsJSON;
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { AuthenticationResponseJSON, RegistrationResponseJSON } from "@simplewebauthn/browser";
|
|
2
|
+
import type { AuthenticatorGetAssertionResponse } from "../ctap2/getAssertion";
|
|
3
|
+
import { type AuthenticatorMakeCredentialResponse } from "../ctap2/makeCredential";
|
|
4
|
+
type ToWebAuthnResponseJSONInput = {
|
|
5
|
+
kind: "authentication";
|
|
6
|
+
assertion: AuthenticatorGetAssertionResponse;
|
|
7
|
+
credentialId?: Uint8Array;
|
|
8
|
+
clientDataJSON: string;
|
|
9
|
+
} | {
|
|
10
|
+
kind: "registration";
|
|
11
|
+
credential: AuthenticatorMakeCredentialResponse;
|
|
12
|
+
clientDataJSON: string;
|
|
13
|
+
};
|
|
14
|
+
export declare function toWebAuthnResponseJSON(input: Extract<ToWebAuthnResponseJSONInput, {
|
|
15
|
+
kind: "authentication";
|
|
16
|
+
}>): AuthenticationResponseJSON;
|
|
17
|
+
export declare function toWebAuthnResponseJSON(input: Extract<ToWebAuthnResponseJSONInput, {
|
|
18
|
+
kind: "registration";
|
|
19
|
+
}>): RegistrationResponseJSON;
|
|
20
|
+
export {};
|
|
21
|
+
//# sourceMappingURL=webauthnResponses.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"webauthnResponses.d.ts","sourceRoot":"","sources":["../../src/helpers/webauthnResponses.ts"],"names":[],"mappings":"AACA,OAAO,EACN,0BAA0B,EAC1B,wBAAwB,EACxB,MAAM,yBAAyB,CAAC;AACjC,OAAO,KAAK,EAAE,iCAAiC,EAAE,MAAM,uBAAuB,CAAC;AAE/E,OAAO,EAGN,KAAK,mCAAmC,EACxC,MAAM,yBAAyB,CAAC;AAIjC,KAAK,2BAA2B,GAC7B;IACA,IAAI,EAAE,gBAAgB,CAAC;IACvB,SAAS,EAAE,iCAAiC,CAAC;IAC7C,YAAY,CAAC,EAAE,UAAU,CAAC;IAC1B,cAAc,EAAE,MAAM,CAAC;CACtB,GACD;IACA,IAAI,EAAE,cAAc,CAAC;IACrB,UAAU,EAAE,mCAAmC,CAAC;IAChD,cAAc,EAAE,MAAM,CAAC;CACtB,CAAC;AAEL,wBAAgB,sBAAsB,CACrC,KAAK,EAAE,OAAO,CAAC,2BAA2B,EAAE;IAAE,IAAI,EAAE,gBAAgB,CAAA;CAAE,CAAC,GACrE,0BAA0B,CAAC;AAC9B,wBAAgB,sBAAsB,CACrC,KAAK,EAAE,OAAO,CAAC,2BAA2B,EAAE;IAAE,IAAI,EAAE,cAAc,CAAA;CAAE,CAAC,GACnE,wBAAwB,CAAC"}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.toWebAuthnResponseJSON = void 0;
|
|
4
|
+
const utils_js_1 = require("@noble/hashes/utils.js");
|
|
5
|
+
const errors_1 = require("../errors");
|
|
6
|
+
const makeCredential_1 = require("../ctap2/makeCredential");
|
|
7
|
+
const authDataExtensions_1 = require("./authDataExtensions");
|
|
8
|
+
const base64url_1 = require("./base64url");
|
|
9
|
+
function toWebAuthnResponseJSON(input) {
|
|
10
|
+
if (input.kind === "authentication") {
|
|
11
|
+
const { assertion, credentialId: credentialIdArg, clientDataJSON, } = input;
|
|
12
|
+
const clientExtensionResults = (0, authDataExtensions_1.parseAuthenticatorDataExtensions)(assertion.authData);
|
|
13
|
+
const credBytes = assertion.credential?.id ??
|
|
14
|
+
credentialIdArg ??
|
|
15
|
+
(() => {
|
|
16
|
+
throw new errors_1.ApduError("Assertion response missing credential id; set credentialId (base64url) on the request object or use a token that returns it in CBOR");
|
|
17
|
+
})();
|
|
18
|
+
const idStr = (0, base64url_1.bufferToBase64URLString)(credBytes);
|
|
19
|
+
return {
|
|
20
|
+
id: idStr,
|
|
21
|
+
rawId: idStr,
|
|
22
|
+
type: "public-key",
|
|
23
|
+
clientExtensionResults,
|
|
24
|
+
response: {
|
|
25
|
+
clientDataJSON: (0, base64url_1.bufferToBase64URLString)((0, utils_js_1.utf8ToBytes)(clientDataJSON)),
|
|
26
|
+
authenticatorData: (0, base64url_1.bufferToBase64URLString)(assertion.authData),
|
|
27
|
+
signature: (0, base64url_1.bufferToBase64URLString)(assertion.signature),
|
|
28
|
+
userHandle: assertion.user?.id !== undefined
|
|
29
|
+
? (0, base64url_1.bufferToBase64URLString)(assertion.user.id)
|
|
30
|
+
: undefined,
|
|
31
|
+
},
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
const { credential, clientDataJSON } = input;
|
|
35
|
+
const ao = (0, makeCredential_1.buildAttestationObjectBytes)(credential.fmt, credential.authData, credential.attStmt);
|
|
36
|
+
const credentialId = (0, makeCredential_1.extractCredentialIdFromAuthData)(credential.authData);
|
|
37
|
+
const idStr = (0, base64url_1.bufferToBase64URLString)(credentialId);
|
|
38
|
+
const clientExtensionResults = (0, authDataExtensions_1.parseAuthenticatorDataExtensions)(credential.authData);
|
|
39
|
+
return {
|
|
40
|
+
id: idStr,
|
|
41
|
+
rawId: idStr,
|
|
42
|
+
type: "public-key",
|
|
43
|
+
clientExtensionResults,
|
|
44
|
+
response: {
|
|
45
|
+
clientDataJSON: (0, base64url_1.bufferToBase64URLString)((0, utils_js_1.utf8ToBytes)(clientDataJSON)),
|
|
46
|
+
attestationObject: (0, base64url_1.bufferToBase64URLString)(ao),
|
|
47
|
+
authenticatorData: (0, base64url_1.bufferToBase64URLString)(credential.authData),
|
|
48
|
+
},
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
exports.toWebAuthnResponseJSON = toWebAuthnResponseJSON;
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Aligned with {@link https://simplewebauthn.dev/docs/packages/browser `@simplewebauthn/browser`} /
|
|
3
|
+
* `types` (same shapes as `startRegistration` / `startAuthentication` inputs and outputs).
|
|
4
|
+
*/
|
|
5
|
+
export type { AuthenticationExtensionsClientOutputs, AuthenticationResponseJSON, AuthenticatorAssertionResponseJSON, AuthenticatorAttestationResponseJSON, Base64URLString, PublicKeyCredentialCreationOptionsJSON, PublicKeyCredentialDescriptorJSON, PublicKeyCredentialRequestOptionsJSON, RegistrationResponseJSON, UserVerificationRequirement, } from "@simplewebauthn/browser";
|
|
6
|
+
//# sourceMappingURL=webauthnTypes.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"webauthnTypes.d.ts","sourceRoot":"","sources":["../../src/helpers/webauthnTypes.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,YAAY,EACX,qCAAqC,EACrC,0BAA0B,EAC1B,kCAAkC,EAClC,oCAAoC,EACpC,eAAe,EACf,sCAAsC,EACtC,iCAAiC,EACjC,qCAAqC,EACrC,wBAAwB,EACxB,2BAA2B,GAC3B,MAAM,yBAAyB,CAAC"}
|
package/lib/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,UAAU,CAAC;AACrC,OAAO,EAAE,mBAAmB,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AACnE,YAAY,EACX,6CAA6C,EAC7C,4CAA4C,GAC5C,MAAM,SAAS,CAAC"}
|
package/lib/index.js
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.registerWithNfc = exports.authenticateWithNfc = exports.ApduError = void 0;
|
|
4
|
+
var errors_1 = require("./errors");
|
|
5
|
+
Object.defineProperty(exports, "ApduError", { enumerable: true, get: function () { return errors_1.ApduError; } });
|
|
6
|
+
var publicApi_1 = require("./publicApi");
|
|
7
|
+
Object.defineProperty(exports, "authenticateWithNfc", { enumerable: true, get: function () { return publicApi_1.authenticateWithNfc; } });
|
|
8
|
+
Object.defineProperty(exports, "registerWithNfc", { enumerable: true, get: function () { return publicApi_1.registerWithNfc; } });
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { AuthenticationResponseJSON, RegistrationResponseJSON } from "@simplewebauthn/browser";
|
|
2
|
+
import { PublicKeyCredentialCreationOptionsJSONWithNfc, PublicKeyCredentialRequestOptionsJSONWithNfc } from "./types";
|
|
3
|
+
type ParseApduToWebAuthnInput = {
|
|
4
|
+
kind: "authentication";
|
|
5
|
+
apduResponse: Uint8Array;
|
|
6
|
+
request: PublicKeyCredentialRequestOptionsJSONWithNfc;
|
|
7
|
+
} | {
|
|
8
|
+
kind: "registration";
|
|
9
|
+
apduResponse: Uint8Array;
|
|
10
|
+
request: PublicKeyCredentialCreationOptionsJSONWithNfc;
|
|
11
|
+
};
|
|
12
|
+
export declare function parseApduToWebAuthnResponse(input: Extract<ParseApduToWebAuthnInput, {
|
|
13
|
+
kind: "authentication";
|
|
14
|
+
}>): AuthenticationResponseJSON;
|
|
15
|
+
export declare function parseApduToWebAuthnResponse(input: Extract<ParseApduToWebAuthnInput, {
|
|
16
|
+
kind: "registration";
|
|
17
|
+
}>): RegistrationResponseJSON;
|
|
18
|
+
export {};
|
|
19
|
+
//# sourceMappingURL=parseResponses.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"parseResponses.d.ts","sourceRoot":"","sources":["../src/parseResponses.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,0BAA0B,EAC1B,wBAAwB,EACzB,MAAM,yBAAyB,CAAC;AAKjC,OAAO,EACL,6CAA6C,EAC7C,4CAA4C,EAC7C,MAAM,SAAS,CAAC;AAEjB,KAAK,wBAAwB,GACzB;IACE,IAAI,EAAE,gBAAgB,CAAC;IACvB,YAAY,EAAE,UAAU,CAAC;IACzB,OAAO,EAAE,4CAA4C,CAAC;CACvD,GACD;IACE,IAAI,EAAE,cAAc,CAAC;IACrB,YAAY,EAAE,UAAU,CAAC;IACzB,OAAO,EAAE,6CAA6C,CAAC;CACxD,CAAC;AAEN,wBAAgB,2BAA2B,CACzC,KAAK,EAAE,OAAO,CAAC,wBAAwB,EAAE;IAAE,IAAI,EAAE,gBAAgB,CAAA;CAAE,CAAC,GACnE,0BAA0B,CAAC;AAC9B,wBAAgB,2BAA2B,CACzC,KAAK,EAAE,OAAO,CAAC,wBAAwB,EAAE;IAAE,IAAI,EAAE,cAAc,CAAA;CAAE,CAAC,GACjE,wBAAwB,CAAC"}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.parseApduToWebAuthnResponse = void 0;
|
|
4
|
+
const getAssertion_1 = require("./ctap2/getAssertion");
|
|
5
|
+
const makeCredential_1 = require("./ctap2/makeCredential");
|
|
6
|
+
const clientData_1 = require("./helpers/clientData");
|
|
7
|
+
const webauthnResponses_1 = require("./helpers/webauthnResponses");
|
|
8
|
+
function parseApduToWebAuthnResponse(input) {
|
|
9
|
+
if (input.kind === "authentication") {
|
|
10
|
+
const clientDataJSON = (0, clientData_1.buildCollectedClientDataJSON)("webauthn.get", {
|
|
11
|
+
challenge: input.request.challenge,
|
|
12
|
+
origin: input.request.origin,
|
|
13
|
+
crossOrigin: input.request.crossOrigin ?? false,
|
|
14
|
+
topOrigin: input.request.topOrigin,
|
|
15
|
+
});
|
|
16
|
+
const assertion = (0, getAssertion_1.parseAuthenticatorGetAssertionResponse)(input.apduResponse);
|
|
17
|
+
return (0, webauthnResponses_1.toWebAuthnResponseJSON)({
|
|
18
|
+
kind: "authentication",
|
|
19
|
+
assertion,
|
|
20
|
+
credentialId: assertion.credential?.id,
|
|
21
|
+
clientDataJSON,
|
|
22
|
+
});
|
|
23
|
+
}
|
|
24
|
+
const clientDataJSON = (0, clientData_1.buildCollectedClientDataJSON)("webauthn.create", {
|
|
25
|
+
challenge: input.request.challenge,
|
|
26
|
+
origin: input.request.origin,
|
|
27
|
+
crossOrigin: input.request.crossOrigin ?? false,
|
|
28
|
+
topOrigin: input.request.topOrigin,
|
|
29
|
+
});
|
|
30
|
+
const credential = (0, makeCredential_1.parseAuthenticatorMakeCredentialResponse)(input.apduResponse);
|
|
31
|
+
return (0, webauthnResponses_1.toWebAuthnResponseJSON)({
|
|
32
|
+
kind: "registration",
|
|
33
|
+
credential,
|
|
34
|
+
clientDataJSON,
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
exports.parseApduToWebAuthnResponse = parseApduToWebAuthnResponse;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { AuthenticationResponseJSON, RegistrationResponseJSON } from "@simplewebauthn/browser";
|
|
2
|
+
import { PublicKeyCredentialCreationOptionsJSONWithNfc, PublicKeyCredentialRequestOptionsJSONWithNfc } from "./types";
|
|
3
|
+
/**
|
|
4
|
+
* NFC against a Java Card FIDO2 applet: SELECT FIDO AID, then getAssertion with
|
|
5
|
+
* short APDU chaining + GET RESPONSE.
|
|
6
|
+
*
|
|
7
|
+
*/
|
|
8
|
+
export declare function authenticateWithNfc(args: PublicKeyCredentialRequestOptionsJSONWithNfc, transceive: (apdu: Uint8Array) => Promise<Uint8Array>): Promise<AuthenticationResponseJSON>;
|
|
9
|
+
/**
|
|
10
|
+
* NFC against a Java Card FIDO2 applet: SELECT FIDO AID, then makeCredential with
|
|
11
|
+
* short APDU chaining + GET RESPONSE.
|
|
12
|
+
*
|
|
13
|
+
*/
|
|
14
|
+
export declare function registerWithNfc(args: PublicKeyCredentialCreationOptionsJSONWithNfc, transceive: (apdu: Uint8Array) => Promise<Uint8Array>): Promise<RegistrationResponseJSON>;
|
|
15
|
+
//# sourceMappingURL=publicApi.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"publicApi.d.ts","sourceRoot":"","sources":["../src/publicApi.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,0BAA0B,EAC1B,wBAAwB,EACzB,MAAM,yBAAyB,CAAC;AAgBjC,OAAO,EACL,6CAA6C,EAC7C,4CAA4C,EAC7C,MAAM,SAAS,CAAC;AA4DjB;;;;GAIG;AACH,wBAAsB,mBAAmB,CACvC,IAAI,EAAE,4CAA4C,EAClD,UAAU,EAAE,CAAC,IAAI,EAAE,UAAU,KAAK,OAAO,CAAC,UAAU,CAAC,GACpD,OAAO,CAAC,0BAA0B,CAAC,CAYrC;AA6BD;;;;GAIG;AACH,wBAAsB,eAAe,CACnC,IAAI,EAAE,6CAA6C,EACnD,UAAU,EAAE,CAAC,IAAI,EAAE,UAAU,KAAK,OAAO,CAAC,UAAU,CAAC,GACpD,OAAO,CAAC,wBAAwB,CAAC,CAYnC"}
|
package/lib/publicApi.js
ADDED
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.registerWithNfc = exports.authenticateWithNfc = void 0;
|
|
4
|
+
const apdu_1 = require("./apdu");
|
|
5
|
+
const getAssertion_1 = require("./ctap2/getAssertion");
|
|
6
|
+
const makeCredential_1 = require("./ctap2/makeCredential");
|
|
7
|
+
const fromWebAuthnJson_1 = require("./helpers/fromWebAuthnJson");
|
|
8
|
+
const parseResponses_1 = require("./parseResponses");
|
|
9
|
+
const errors_1 = require("./errors");
|
|
10
|
+
/**
|
|
11
|
+
* Wraps `transceive` so failures and short reads get a stable {@link ApduError}
|
|
12
|
+
* with API/phase in the message. Re-throws {@link ApduError} from lower layers unchanged.
|
|
13
|
+
*/
|
|
14
|
+
function nfcTransceiveFor(transceive, apiLabel, phase) {
|
|
15
|
+
const label = `${apiLabel} (${phase})`;
|
|
16
|
+
return async (apdu) => {
|
|
17
|
+
try {
|
|
18
|
+
const resp = await transceive(apdu);
|
|
19
|
+
if (resp.length < 2) {
|
|
20
|
+
throw new errors_1.ApduError(`${label}: response must include SW1/SW2 (got ${resp.length} byte(s))`);
|
|
21
|
+
}
|
|
22
|
+
return resp;
|
|
23
|
+
}
|
|
24
|
+
catch (e) {
|
|
25
|
+
if (e instanceof errors_1.ApduError) {
|
|
26
|
+
throw e;
|
|
27
|
+
}
|
|
28
|
+
throw new errors_1.ApduError(`${label}: ${e instanceof Error ? e.message : String(e)}`, { cause: e });
|
|
29
|
+
}
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
async function runAuthenticateWithNfc(args, transceive) {
|
|
33
|
+
await (0, apdu_1.transceiveNfcCtap2Command)((0, apdu_1.buildSelectFidoApduSegments)(), nfcTransceiveFor(transceive, "authenticateWithNfc", "SELECT FIDO"));
|
|
34
|
+
const apduResponse = await (0, apdu_1.transceiveNfcCtap2Command)((0, apdu_1.splitExtendedApduForNfcTransmit)((0, apdu_1.buildCborCommandApdu)((0, getAssertion_1.encodeAuthenticatorGetAssertionRequest)((0, fromWebAuthnJson_1.authenticatorGetAssertionRequestFromPublicKeyCredentialRequestOptionsJSON)(args)))), nfcTransceiveFor(transceive, "authenticateWithNfc", "getAssertion"));
|
|
35
|
+
return (0, parseResponses_1.parseApduToWebAuthnResponse)({
|
|
36
|
+
kind: "authentication",
|
|
37
|
+
apduResponse,
|
|
38
|
+
request: args,
|
|
39
|
+
});
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* NFC against a Java Card FIDO2 applet: SELECT FIDO AID, then getAssertion with
|
|
43
|
+
* short APDU chaining + GET RESPONSE.
|
|
44
|
+
*
|
|
45
|
+
*/
|
|
46
|
+
async function authenticateWithNfc(args, transceive) {
|
|
47
|
+
try {
|
|
48
|
+
return await runAuthenticateWithNfc(args, transceive);
|
|
49
|
+
}
|
|
50
|
+
catch (e) {
|
|
51
|
+
if (e instanceof errors_1.ApduError) {
|
|
52
|
+
throw e;
|
|
53
|
+
}
|
|
54
|
+
throw new errors_1.ApduError(`authenticateWithNfc: ${e instanceof Error ? e.message : String(e)}`, { cause: e });
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
exports.authenticateWithNfc = authenticateWithNfc;
|
|
58
|
+
async function runRegisterWithNfc(args, transceive) {
|
|
59
|
+
await (0, apdu_1.transceiveNfcCtap2Command)((0, apdu_1.buildSelectFidoApduSegments)(), nfcTransceiveFor(transceive, "registerWithNfc", "SELECT FIDO"));
|
|
60
|
+
const apduResponse = await (0, apdu_1.transceiveNfcCtap2Command)((0, apdu_1.splitExtendedApduForNfcTransmit)((0, apdu_1.buildCborCommandApdu)((0, makeCredential_1.encodeAuthenticatorMakeCredentialRequest)((0, fromWebAuthnJson_1.authenticatorMakeCredentialRequestFromPublicKeyCredentialCreationOptionsJSON)(args)))), nfcTransceiveFor(transceive, "registerWithNfc", "makeCredential"));
|
|
61
|
+
return (0, parseResponses_1.parseApduToWebAuthnResponse)({
|
|
62
|
+
kind: "registration",
|
|
63
|
+
apduResponse,
|
|
64
|
+
request: args,
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* NFC against a Java Card FIDO2 applet: SELECT FIDO AID, then makeCredential with
|
|
69
|
+
* short APDU chaining + GET RESPONSE.
|
|
70
|
+
*
|
|
71
|
+
*/
|
|
72
|
+
async function registerWithNfc(args, transceive) {
|
|
73
|
+
try {
|
|
74
|
+
return await runRegisterWithNfc(args, transceive);
|
|
75
|
+
}
|
|
76
|
+
catch (e) {
|
|
77
|
+
if (e instanceof errors_1.ApduError) {
|
|
78
|
+
throw e;
|
|
79
|
+
}
|
|
80
|
+
throw new errors_1.ApduError(`registerWithNfc: ${e instanceof Error ? e.message : String(e)}`, { cause: e });
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
exports.registerWithNfc = registerWithNfc;
|
package/lib/types.d.ts
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { PublicKeyCredentialCreationOptionsJSON, PublicKeyCredentialRequestOptionsJSON } from "@simplewebauthn/browser";
|
|
2
|
+
type NfcWebAuthnClientFields = {
|
|
3
|
+
origin: string;
|
|
4
|
+
crossOrigin?: boolean;
|
|
5
|
+
topOrigin?: string;
|
|
6
|
+
};
|
|
7
|
+
export type PublicKeyCredentialRequestOptionsJSONWithNfc = PublicKeyCredentialRequestOptionsJSON & NfcWebAuthnClientFields;
|
|
8
|
+
export type PublicKeyCredentialCreationOptionsJSONWithNfc = PublicKeyCredentialCreationOptionsJSON & NfcWebAuthnClientFields;
|
|
9
|
+
export {};
|
|
10
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,sCAAsC,EACtC,qCAAqC,EACtC,MAAM,yBAAyB,CAAC;AAEjC,KAAK,uBAAuB,GAAG;IAC7B,MAAM,EAAE,MAAM,CAAC;IACf,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB,CAAC;AAEF,MAAM,MAAM,4CAA4C,GACtD,qCAAqC,GAAG,uBAAuB,CAAC;AAElE,MAAM,MAAM,6CAA6C,GACvD,sCAAsC,GAAG,uBAAuB,CAAC"}
|
package/lib/types.js
ADDED
package/package.json
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@revibase/ctap2-js",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Passkeys over NFC directly",
|
|
5
|
+
"main": "lib/index.js",
|
|
6
|
+
"types": "lib/index.d.ts",
|
|
7
|
+
"exports": {
|
|
8
|
+
".": {
|
|
9
|
+
"types": "./lib/index.d.ts",
|
|
10
|
+
"import": "./lib/index.js",
|
|
11
|
+
"require": "./lib/index.js",
|
|
12
|
+
"default": "./lib/index.js"
|
|
13
|
+
}
|
|
14
|
+
},
|
|
15
|
+
"license": "MIT",
|
|
16
|
+
"dependencies": {
|
|
17
|
+
"@noble/hashes": "^2.0.1",
|
|
18
|
+
"cbor-x": "^1.6.0"
|
|
19
|
+
},
|
|
20
|
+
"peerDependencies": {
|
|
21
|
+
"@simplewebauthn/browser": "^13.0.0"
|
|
22
|
+
},
|
|
23
|
+
"peerDependenciesMeta": {
|
|
24
|
+
"@simplewebauthn/browser": {
|
|
25
|
+
"optional": true
|
|
26
|
+
}
|
|
27
|
+
},
|
|
28
|
+
"devDependencies": {
|
|
29
|
+
"@simplewebauthn/browser": "^13.0.0",
|
|
30
|
+
"typescript": "~5.3.0"
|
|
31
|
+
},
|
|
32
|
+
"scripts": {
|
|
33
|
+
"build": "tsc -p tsconfig.json"
|
|
34
|
+
}
|
|
35
|
+
}
|