@tinfoilsh/passkey-kit 0.1.0 → 0.2.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 +138 -81
- package/dist/crypto.d.ts +11 -54
- package/dist/crypto.d.ts.map +1 -1
- package/dist/crypto.js +146 -97
- package/dist/crypto.js.map +1 -1
- package/dist/errors.d.ts +11 -21
- package/dist/errors.d.ts.map +1 -1
- package/dist/errors.js +10 -27
- package/dist/errors.js.map +1 -1
- package/dist/index.d.ts +7 -10
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -7
- package/dist/index.js.map +1 -1
- package/dist/kit.d.ts +2 -62
- package/dist/kit.d.ts.map +1 -1
- package/dist/kit.js +305 -159
- package/dist/kit.js.map +1 -1
- package/dist/storage.d.ts +15 -29
- package/dist/storage.d.ts.map +1 -1
- package/dist/storage.js +113 -62
- package/dist/storage.js.map +1 -1
- package/dist/support.d.ts +2 -14
- package/dist/support.d.ts.map +1 -1
- package/dist/support.js +32 -47
- package/dist/support.js.map +1 -1
- package/dist/types.d.ts +85 -89
- package/dist/types.d.ts.map +1 -1
- package/dist/webauthn.d.ts +10 -33
- package/dist/webauthn.d.ts.map +1 -1
- package/dist/webauthn.js +89 -177
- package/dist/webauthn.js.map +1 -1
- package/dist/wrapped-key-record-codec.d.ts +4 -0
- package/dist/wrapped-key-record-codec.d.ts.map +1 -0
- package/dist/wrapped-key-record-codec.js +89 -0
- package/dist/wrapped-key-record-codec.js.map +1 -0
- package/package.json +4 -2
- package/src/crypto.ts +171 -137
- package/src/errors.ts +29 -33
- package/src/index.ts +26 -41
- package/src/kit.ts +405 -263
- package/src/storage.ts +126 -60
- package/src/support.ts +36 -50
- package/src/types.ts +99 -99
- package/src/webauthn.ts +121 -237
- package/src/wrapped-key-record-codec.ts +93 -0
- package/dist/protocol.d.ts +0 -13
- package/dist/protocol.d.ts.map +0 -1
- package/dist/protocol.js +0 -13
- package/dist/protocol.js.map +0 -1
- package/src/protocol.ts +0 -15
package/dist/storage.js
CHANGED
|
@@ -1,67 +1,118 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
},
|
|
44
|
-
removeItem(key) {
|
|
45
|
-
try {
|
|
46
|
-
if (typeof localStorage === 'undefined')
|
|
47
|
-
return;
|
|
48
|
-
localStorage.removeItem(key);
|
|
49
|
-
}
|
|
50
|
-
catch {
|
|
51
|
-
// best-effort
|
|
52
|
-
}
|
|
53
|
-
},
|
|
54
|
-
};
|
|
55
|
-
/** In-memory adapter for tests and non-browser environments. */
|
|
56
|
-
export function createMemoryStorageAdapter() {
|
|
57
|
-
const store = new Map();
|
|
1
|
+
import { base64ToBytes, bytesToBase64 } from "./codec.js";
|
|
2
|
+
function copyProfile(profile) {
|
|
3
|
+
return {
|
|
4
|
+
...profile,
|
|
5
|
+
prfSalt: profile.prfSalt.slice(),
|
|
6
|
+
hkdfInfo: profile.hkdfInfo.slice(),
|
|
7
|
+
};
|
|
8
|
+
}
|
|
9
|
+
function copyCachedResult(result) {
|
|
10
|
+
return {
|
|
11
|
+
profile: copyProfile(result.profile),
|
|
12
|
+
credentialId: result.credentialId,
|
|
13
|
+
prfOutput: result.prfOutput.slice(),
|
|
14
|
+
};
|
|
15
|
+
}
|
|
16
|
+
export function createMemoryPasskeyKeyStorage() {
|
|
17
|
+
let cached = null;
|
|
18
|
+
let localCredentialId = null;
|
|
19
|
+
return {
|
|
20
|
+
loadCachedPRFResult() {
|
|
21
|
+
return cached ? copyCachedResult(cached) : null;
|
|
22
|
+
},
|
|
23
|
+
saveCachedPRFResult(result) {
|
|
24
|
+
cached = copyCachedResult(result);
|
|
25
|
+
},
|
|
26
|
+
loadLocalCredentialId() {
|
|
27
|
+
return localCredentialId;
|
|
28
|
+
},
|
|
29
|
+
saveLocalCredentialId(credentialId) {
|
|
30
|
+
localCredentialId = credentialId;
|
|
31
|
+
},
|
|
32
|
+
clear() {
|
|
33
|
+
cached = null;
|
|
34
|
+
localCredentialId = null;
|
|
35
|
+
},
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
/** Stores raw PRF output unencrypted in localStorage under an explicit namespace. */
|
|
39
|
+
export function createInsecureBrowserLocalStoragePasskeyKeyStorage(namespace) {
|
|
40
|
+
const prefix = `passkey-key/${encodeURIComponent(namespace)}`;
|
|
41
|
+
const cachedKey = `${prefix}/cached-prf`;
|
|
42
|
+
const localCredentialKey = `${prefix}/local-credential`;
|
|
58
43
|
return {
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
44
|
+
loadCachedPRFResult() {
|
|
45
|
+
try {
|
|
46
|
+
if (typeof localStorage === "undefined")
|
|
47
|
+
return null;
|
|
48
|
+
const value = localStorage.getItem(cachedKey);
|
|
49
|
+
if (!value)
|
|
50
|
+
return null;
|
|
51
|
+
const stored = JSON.parse(value);
|
|
52
|
+
return {
|
|
53
|
+
profile: {
|
|
54
|
+
version: stored.profile.version,
|
|
55
|
+
relyingPartyId: stored.profile.relyingPartyId,
|
|
56
|
+
prfSalt: base64ToBytes(stored.profile.prfSaltBase64),
|
|
57
|
+
hkdfInfo: base64ToBytes(stored.profile.hkdfInfoBase64),
|
|
58
|
+
},
|
|
59
|
+
credentialId: stored.credentialId,
|
|
60
|
+
prfOutput: base64ToBytes(stored.prfOutputBase64),
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
catch {
|
|
64
|
+
return null;
|
|
65
|
+
}
|
|
66
|
+
},
|
|
67
|
+
saveCachedPRFResult(result) {
|
|
68
|
+
try {
|
|
69
|
+
if (typeof localStorage === "undefined")
|
|
70
|
+
return;
|
|
71
|
+
const serialized = {
|
|
72
|
+
profile: {
|
|
73
|
+
version: result.profile.version,
|
|
74
|
+
relyingPartyId: result.profile.relyingPartyId,
|
|
75
|
+
prfSaltBase64: bytesToBase64(result.profile.prfSalt),
|
|
76
|
+
hkdfInfoBase64: bytesToBase64(result.profile.hkdfInfo),
|
|
77
|
+
},
|
|
78
|
+
credentialId: result.credentialId,
|
|
79
|
+
prfOutputBase64: bytesToBase64(result.prfOutput),
|
|
80
|
+
};
|
|
81
|
+
localStorage.setItem(cachedKey, JSON.stringify(serialized));
|
|
82
|
+
}
|
|
83
|
+
catch { }
|
|
84
|
+
},
|
|
85
|
+
loadLocalCredentialId() {
|
|
86
|
+
try {
|
|
87
|
+
if (typeof localStorage === "undefined")
|
|
88
|
+
return null;
|
|
89
|
+
return localStorage.getItem(localCredentialKey);
|
|
90
|
+
}
|
|
91
|
+
catch {
|
|
92
|
+
return null;
|
|
93
|
+
}
|
|
94
|
+
},
|
|
95
|
+
saveLocalCredentialId(credentialId) {
|
|
96
|
+
try {
|
|
97
|
+
if (typeof localStorage === "undefined")
|
|
98
|
+
return;
|
|
99
|
+
localStorage.setItem(localCredentialKey, credentialId);
|
|
100
|
+
}
|
|
101
|
+
catch { }
|
|
62
102
|
},
|
|
63
|
-
|
|
64
|
-
|
|
103
|
+
clear() {
|
|
104
|
+
try {
|
|
105
|
+
if (typeof localStorage === "undefined")
|
|
106
|
+
return;
|
|
107
|
+
localStorage.removeItem(cachedKey);
|
|
108
|
+
}
|
|
109
|
+
catch { }
|
|
110
|
+
try {
|
|
111
|
+
if (typeof localStorage === "undefined")
|
|
112
|
+
return;
|
|
113
|
+
localStorage.removeItem(localCredentialKey);
|
|
114
|
+
}
|
|
115
|
+
catch { }
|
|
65
116
|
},
|
|
66
117
|
};
|
|
67
118
|
}
|
package/dist/storage.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"storage.js","sourceRoot":"","sources":["../src/storage.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"storage.js","sourceRoot":"","sources":["../src/storage.ts"],"names":[],"mappings":"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"}
|
package/dist/support.d.ts
CHANGED
|
@@ -1,15 +1,3 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
*
|
|
4
|
-
* Checks whether the current browser/platform supports the WebAuthn PRF
|
|
5
|
-
* extension. This is an optimistic check — actual PRF support is only
|
|
6
|
-
* confirmed when a credential is created with prf.enabled: true in the
|
|
7
|
-
* response. If creation fails, callers should fall back to a manual flow.
|
|
8
|
-
*
|
|
9
|
-
* Detection strategy:
|
|
10
|
-
* 1. Check window.PublicKeyCredential exists (basic WebAuthn support)
|
|
11
|
-
* 2. Check isUserVerifyingPlatformAuthenticatorAvailable() (biometric/PIN authenticator present)
|
|
12
|
-
* 3. Optionally check getClientCapabilities() for explicit PRF support signal (new API, not universal)
|
|
13
|
-
*/
|
|
14
|
-
export declare function detectPrfSupport(): Promise<boolean>;
|
|
1
|
+
import type { PasskeyCapability } from "./types.js";
|
|
2
|
+
export declare function capability(operation: "enroll" | "recover"): Promise<PasskeyCapability>;
|
|
15
3
|
//# sourceMappingURL=support.d.ts.map
|
package/dist/support.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"support.d.ts","sourceRoot":"","sources":["../src/support.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"support.d.ts","sourceRoot":"","sources":["../src/support.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;AA4BpD,wBAAsB,UAAU,CAC9B,SAAS,EAAE,QAAQ,GAAG,SAAS,GAC9B,OAAO,CAAC,iBAAiB,CAAC,CAgB5B"}
|
package/dist/support.js
CHANGED
|
@@ -1,58 +1,43 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
* 3. Optionally check getClientCapabilities() for explicit PRF support signal (new API, not universal)
|
|
13
|
-
*/
|
|
14
|
-
export async function detectPrfSupport() {
|
|
15
|
-
if (typeof window === 'undefined') {
|
|
16
|
-
return false;
|
|
17
|
-
}
|
|
18
|
-
if (!window.PublicKeyCredential) {
|
|
19
|
-
return false;
|
|
20
|
-
}
|
|
21
|
-
// Check that a platform authenticator is available (Face ID, Touch ID, Windows Hello, etc.)
|
|
1
|
+
function hasWebAuthn(operation) {
|
|
2
|
+
return (typeof navigator !== "undefined" &&
|
|
3
|
+
!!navigator.credentials &&
|
|
4
|
+
typeof navigator.credentials[operation === "enroll" ? "create" : "get"] ===
|
|
5
|
+
"function" &&
|
|
6
|
+
typeof PublicKeyCredential !== "undefined");
|
|
7
|
+
}
|
|
8
|
+
async function prfCapability() {
|
|
9
|
+
const credentialClass = PublicKeyCredential;
|
|
10
|
+
if (typeof credentialClass.getClientCapabilities !== "function")
|
|
11
|
+
return "unknown";
|
|
22
12
|
try {
|
|
23
|
-
const
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
13
|
+
const capabilities = await credentialClass.getClientCapabilities();
|
|
14
|
+
const reported = capabilities["extension:prf"];
|
|
15
|
+
if (reported === true)
|
|
16
|
+
return "supported";
|
|
17
|
+
if (reported === false)
|
|
18
|
+
return "unsupported";
|
|
27
19
|
}
|
|
28
20
|
catch {
|
|
29
|
-
return
|
|
21
|
+
return "unknown";
|
|
22
|
+
}
|
|
23
|
+
return "unknown";
|
|
24
|
+
}
|
|
25
|
+
export async function capability(operation) {
|
|
26
|
+
if (!hasWebAuthn(operation))
|
|
27
|
+
return "unsupported";
|
|
28
|
+
if (operation === "recover")
|
|
29
|
+
return prfCapability();
|
|
30
|
+
if (typeof PublicKeyCredential.isUserVerifyingPlatformAuthenticatorAvailable !== "function") {
|
|
31
|
+
return "unknown";
|
|
30
32
|
}
|
|
31
|
-
// If getClientCapabilities is available, use it for a more precise check.
|
|
32
|
-
// This API is newer and may not be present in all browsers.
|
|
33
33
|
try {
|
|
34
|
-
if (
|
|
35
|
-
|
|
36
|
-
if (caps && typeof caps === 'object') {
|
|
37
|
-
// The shape of this API varies across browser versions.
|
|
38
|
-
// Chrome returns a map-like object; check for extension-prf or prf key.
|
|
39
|
-
const hasPrf = caps['extension-prf'] === true ||
|
|
40
|
-
caps['prf'] === true;
|
|
41
|
-
if (hasPrf) {
|
|
42
|
-
return true;
|
|
43
|
-
}
|
|
44
|
-
// If getClientCapabilities is available but doesn't report PRF,
|
|
45
|
-
// that's a strong negative signal on platforms that implement it.
|
|
46
|
-
// However, since this API is still evolving, we don't treat absence
|
|
47
|
-
// as definitive — fall through to the optimistic path.
|
|
48
|
-
}
|
|
34
|
+
if (!(await PublicKeyCredential.isUserVerifyingPlatformAuthenticatorAvailable())) {
|
|
35
|
+
return "unsupported";
|
|
49
36
|
}
|
|
50
37
|
}
|
|
51
38
|
catch {
|
|
52
|
-
|
|
39
|
+
return "unknown";
|
|
53
40
|
}
|
|
54
|
-
|
|
55
|
-
// Actual PRF support will be confirmed during credential creation.
|
|
56
|
-
return true;
|
|
41
|
+
return prfCapability();
|
|
57
42
|
}
|
|
58
43
|
//# sourceMappingURL=support.js.map
|
package/dist/support.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"support.js","sourceRoot":"","sources":["../src/support.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"support.js","sourceRoot":"","sources":["../src/support.ts"],"names":[],"mappings":"AAEA,SAAS,WAAW,CAAC,SAA+B;IAClD,OAAO,CACL,OAAO,SAAS,KAAK,WAAW;QAChC,CAAC,CAAC,SAAS,CAAC,WAAW;QACvB,OAAO,SAAS,CAAC,WAAW,CAAC,SAAS,KAAK,QAAQ,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC;YACrE,UAAU;QACZ,OAAO,mBAAmB,KAAK,WAAW,CAC3C,CAAC;AACJ,CAAC;AAED,KAAK,UAAU,aAAa;IAC1B,MAAM,eAAe,GAAG,mBAEvB,CAAC;IACF,IAAI,OAAO,eAAe,CAAC,qBAAqB,KAAK,UAAU;QAAE,OAAO,SAAS,CAAC;IAClF,IAAI,CAAC;QACH,MAAM,YAAY,GAAG,MAAM,eAAe,CAAC,qBAAqB,EAAE,CAAC;QACnE,MAAM,QAAQ,GAAG,YAAY,CAAC,eAAe,CAAC,CAAC;QAC/C,IAAI,QAAQ,KAAK,IAAI;YAAE,OAAO,WAAW,CAAC;QAC1C,IAAI,QAAQ,KAAK,KAAK;YAAE,OAAO,aAAa,CAAC;IAC/C,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,SAAS,CAAC;IACnB,CAAC;IACD,OAAO,SAAS,CAAC;AACnB,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,UAAU,CAC9B,SAA+B;IAE/B,IAAI,CAAC,WAAW,CAAC,SAAS,CAAC;QAAE,OAAO,aAAa,CAAC;IAClD,IAAI,SAAS,KAAK,SAAS;QAAE,OAAO,aAAa,EAAE,CAAC;IACpD,IACE,OAAO,mBAAmB,CAAC,6CAA6C,KAAK,UAAU,EACvF,CAAC;QACD,OAAO,SAAS,CAAC;IACnB,CAAC;IACD,IAAI,CAAC;QACH,IAAI,CAAC,CAAC,MAAM,mBAAmB,CAAC,6CAA6C,EAAE,CAAC,EAAE,CAAC;YACjF,OAAO,aAAa,CAAC;QACvB,CAAC;IACH,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,SAAS,CAAC;IACnB,CAAC;IACD,OAAO,aAAa,EAAE,CAAC;AACzB,CAAC"}
|
package/dist/types.d.ts
CHANGED
|
@@ -1,101 +1,97 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
* Overrides for the messages on errors the SDK throws. Useful for branding
|
|
15
|
-
* or localization; the error classes themselves stay the same, so
|
|
16
|
-
* `instanceof` checks are unaffected.
|
|
17
|
-
*/
|
|
18
|
-
export interface PasskeyKitErrorMessages {
|
|
19
|
-
/** Message used for `PrfNotSupportedError`. */
|
|
20
|
-
prfNotSupported?: string;
|
|
21
|
-
/** Message used for `PasskeyTimeoutError`. */
|
|
22
|
-
timeout?: string;
|
|
23
|
-
}
|
|
24
|
-
export interface PasskeyKitConfig {
|
|
25
|
-
/** WebAuthn relying party id (e.g. `example.com`, or `localhost` in dev). */
|
|
26
|
-
rpId: string;
|
|
27
|
-
/** Human-readable relying party name shown in passkey prompts. */
|
|
28
|
-
rpName: string;
|
|
29
|
-
/**
|
|
30
|
-
* Input to the PRF `eval.first` salt. Must stay stable across all clients
|
|
31
|
-
* of the same protocol: changing it changes every derived KEK.
|
|
32
|
-
* Defaults to the Tinfoil v1 protocol constant.
|
|
33
|
-
*/
|
|
34
|
-
prfSaltInput?: string | Uint8Array;
|
|
35
|
-
/**
|
|
36
|
-
* HKDF info string used for domain separation when deriving the KEK from
|
|
37
|
-
* the PRF output. Defaults to the Tinfoil v1 protocol constant.
|
|
38
|
-
*/
|
|
39
|
-
hkdfInfo?: string | Uint8Array;
|
|
40
|
-
/**
|
|
41
|
-
* Local persistence for the PRF cache and this device's credential id.
|
|
42
|
-
* Defaults to a best-effort `localStorage` adapter; pass `null` to
|
|
43
|
-
* disable local persistence entirely.
|
|
44
|
-
*/
|
|
45
|
-
storage?: StorageAdapter | null;
|
|
46
|
-
storageKeys?: Partial<PasskeyKitStorageKeys>;
|
|
47
|
-
/** Timeout passed to the WebAuthn API (some browsers ignore this). */
|
|
48
|
-
webauthnTimeoutMs?: number;
|
|
49
|
-
/**
|
|
50
|
-
* Hard client-side timeout guarding against providers that never resolve
|
|
51
|
-
* the WebAuthn promise. When exceeded, `PasskeyTimeoutError` is thrown.
|
|
52
|
-
*/
|
|
53
|
-
stuckTimeoutMs?: number;
|
|
54
|
-
/** Custom messages for the errors the SDK throws. */
|
|
55
|
-
errorMessages?: PasskeyKitErrorMessages;
|
|
56
|
-
logger?: PasskeyKitLogger;
|
|
57
|
-
}
|
|
58
|
-
/** Identity attached to a newly created passkey. */
|
|
1
|
+
import type { PasskeyKeyStorage } from "./storage.js";
|
|
2
|
+
export interface PasskeyKeyProfile {
|
|
3
|
+
version: 1;
|
|
4
|
+
relyingPartyId: string;
|
|
5
|
+
prfSalt: Uint8Array;
|
|
6
|
+
hkdfInfo: Uint8Array;
|
|
7
|
+
}
|
|
8
|
+
export interface WrappedKey {
|
|
9
|
+
profile: PasskeyKeyProfile;
|
|
10
|
+
credentialId: string;
|
|
11
|
+
kekIvHex: string;
|
|
12
|
+
wrappedKeyHex: string;
|
|
13
|
+
}
|
|
59
14
|
export interface PasskeyUser {
|
|
60
|
-
|
|
61
|
-
id: string;
|
|
62
|
-
/** Account identifier shown in passkey pickers (usually an email). */
|
|
15
|
+
id: Uint8Array;
|
|
63
16
|
name: string;
|
|
64
|
-
/** Friendly display name; falls back to `name` when omitted. */
|
|
65
17
|
displayName?: string;
|
|
66
18
|
}
|
|
67
|
-
|
|
68
|
-
export
|
|
69
|
-
|
|
19
|
+
export type PasskeyCapability = "supported" | "unsupported" | "unknown";
|
|
20
|
+
export type PasskeyInteraction = "interactive" | "immediatelyAvailable";
|
|
21
|
+
export interface CreateAndWrapKeyInput {
|
|
22
|
+
user: PasskeyUser;
|
|
23
|
+
key: Uint8Array;
|
|
24
|
+
signal?: AbortSignal;
|
|
25
|
+
}
|
|
26
|
+
export interface CreatedWrappedKey {
|
|
70
27
|
credentialId: string;
|
|
71
|
-
|
|
72
|
-
|
|
28
|
+
wrappedKey: WrappedKey;
|
|
29
|
+
}
|
|
30
|
+
export interface RecoverKeyInput {
|
|
31
|
+
wrappedKeys: WrappedKey[];
|
|
32
|
+
preferredCredentialId?: string;
|
|
33
|
+
signal?: AbortSignal;
|
|
34
|
+
interaction?: PasskeyInteraction;
|
|
35
|
+
}
|
|
36
|
+
export interface EvaluateCredentialInput {
|
|
37
|
+
credentialIds: string[];
|
|
38
|
+
preferredCredentialId?: string;
|
|
39
|
+
signal?: AbortSignal;
|
|
40
|
+
interaction?: PasskeyInteraction;
|
|
73
41
|
}
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
42
|
+
export interface PRFResult {
|
|
43
|
+
output: Uint8Array;
|
|
44
|
+
}
|
|
45
|
+
export interface EvaluatedCredential {
|
|
77
46
|
credentialId: string;
|
|
78
|
-
|
|
79
|
-
kekIvHex: string;
|
|
80
|
-
/** Wrapped CEK ciphertext (including GCM tag), hex-encoded. */
|
|
81
|
-
wrappedKeyHex: string;
|
|
47
|
+
prfResult: PRFResult;
|
|
82
48
|
}
|
|
83
|
-
|
|
84
|
-
|
|
49
|
+
export interface WrapKeyWithPRFResultInput {
|
|
50
|
+
keyMaterial: Uint8Array;
|
|
85
51
|
credentialId: string;
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
export interface
|
|
52
|
+
prfResult: PRFResult;
|
|
53
|
+
}
|
|
54
|
+
export interface UnwrapKeyWithPRFResultInput {
|
|
55
|
+
wrappedKey: WrappedKey;
|
|
56
|
+
prfResult: PRFResult;
|
|
57
|
+
}
|
|
58
|
+
export interface RecoveredKey {
|
|
59
|
+
credentialId: string;
|
|
60
|
+
key: Uint8Array;
|
|
61
|
+
}
|
|
62
|
+
export interface RewrapKeyInput {
|
|
63
|
+
key: Uint8Array;
|
|
64
|
+
}
|
|
65
|
+
export interface PasskeyKeyManagerConfig {
|
|
66
|
+
profile: PasskeyKeyProfile;
|
|
67
|
+
relyingPartyName: string;
|
|
68
|
+
timeoutMs?: number;
|
|
69
|
+
storage?: PasskeyKeyStorage;
|
|
70
|
+
}
|
|
71
|
+
export interface PasskeyKeyManager {
|
|
72
|
+
capability(input: {
|
|
73
|
+
operation: "enroll" | "recover";
|
|
74
|
+
}): Promise<PasskeyCapability>;
|
|
75
|
+
createAndWrapKey(input: CreateAndWrapKeyInput): Promise<CreatedWrappedKey>;
|
|
76
|
+
recoverKey(input: RecoverKeyInput): Promise<RecoveredKey>;
|
|
77
|
+
evaluateCredential(input: EvaluateCredentialInput): Promise<EvaluatedCredential>;
|
|
78
|
+
wrapKeyWithPRFResult(input: WrapKeyWithPRFResultInput): Promise<WrappedKey>;
|
|
79
|
+
unwrapKeyWithPRFResult(input: UnwrapKeyWithPRFResultInput): Promise<Uint8Array>;
|
|
80
|
+
recoverKeyFromCache(input: RecoverKeyInput): Promise<RecoveredKey | null>;
|
|
81
|
+
rewrapKeyFromCache(input: RewrapKeyInput): Promise<WrappedKey | null>;
|
|
82
|
+
clearLocalState(): void;
|
|
83
|
+
cancelActiveCeremony(): void;
|
|
84
|
+
}
|
|
85
|
+
export interface WrappedKeyRecord {
|
|
86
|
+
version: 1;
|
|
87
|
+
profile: {
|
|
88
|
+
version: 1;
|
|
89
|
+
relyingPartyId: string;
|
|
90
|
+
prfSalt: string;
|
|
91
|
+
hkdfInfo: string;
|
|
92
|
+
};
|
|
97
93
|
credentialId: string;
|
|
98
|
-
|
|
99
|
-
|
|
94
|
+
kekIvHex: string;
|
|
95
|
+
wrappedKeyHex: string;
|
|
100
96
|
}
|
|
101
97
|
//# sourceMappingURL=types.d.ts.map
|
package/dist/types.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
|
package/dist/webauthn.d.ts
CHANGED
|
@@ -1,38 +1,15 @@
|
|
|
1
|
-
|
|
2
|
-
* WebAuthn PRF ceremonies: credential creation and assertion with the PRF
|
|
3
|
-
* extension. Pure ceremony logic — persistence of the results is handled
|
|
4
|
-
* by the kit through the hooks on {@link CeremonyContext}.
|
|
5
|
-
*/
|
|
6
|
-
import type { PasskeyKitErrorMessages, PasskeyKitLogger, PasskeyUser, PrfPasskeyResult } from "./types.js";
|
|
1
|
+
import type { PasskeyUser } from "./types.js";
|
|
7
2
|
export interface CeremonyContext {
|
|
8
3
|
rpId: string;
|
|
9
4
|
rpName: string;
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
prfSalt: Uint8Array;
|
|
13
|
-
webauthnTimeoutMs: number;
|
|
14
|
-
stuckTimeoutMs: number;
|
|
15
|
-
errorMessages?: PasskeyKitErrorMessages;
|
|
16
|
-
logger: PasskeyKitLogger;
|
|
17
|
-
/** Invoked after every successful PRF ceremony so the kit can cache state. */
|
|
18
|
-
onPrfResult(result: PrfPasskeyResult, credential: PublicKeyCredential): void;
|
|
5
|
+
prfInput: Uint8Array;
|
|
6
|
+
timeoutMs: number;
|
|
19
7
|
}
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
export declare function createPrfPasskey(ctx: CeremonyContext, user: PasskeyUser): Promise<PrfPasskeyResult | null>;
|
|
28
|
-
/**
|
|
29
|
-
* Authenticate with an existing PRF passkey to derive the PRF output.
|
|
30
|
-
*
|
|
31
|
-
* @param credentialIds - base64url-encoded credential IDs to allow. Pass all
|
|
32
|
-
* known PRF credential IDs so the browser can select the right one.
|
|
33
|
-
* @returns The matched credential ID and PRF output, or null on failure/cancel.
|
|
34
|
-
*/
|
|
35
|
-
export declare function authenticatePrfPasskey(ctx: CeremonyContext, credentialIds: string[], options?: {
|
|
36
|
-
throwOnCancel?: boolean;
|
|
37
|
-
}): Promise<PrfPasskeyResult | null>;
|
|
8
|
+
export interface InternalPrfResult {
|
|
9
|
+
credentialId: string;
|
|
10
|
+
prfOutput: Uint8Array;
|
|
11
|
+
isPlatformAuthenticator: boolean;
|
|
12
|
+
}
|
|
13
|
+
export declare function createPrfCredential(context: CeremonyContext, user: PasskeyUser, signal: AbortSignal): Promise<InternalPrfResult>;
|
|
14
|
+
export declare function evaluatePrfCredential(context: CeremonyContext, credentialIds: string[], signal: AbortSignal): Promise<InternalPrfResult>;
|
|
38
15
|
//# sourceMappingURL=webauthn.d.ts.map
|
package/dist/webauthn.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"webauthn.d.ts","sourceRoot":"","sources":["../src/webauthn.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"webauthn.d.ts","sourceRoot":"","sources":["../src/webauthn.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAM9C,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,UAAU,CAAC;IACrB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,iBAAiB;IAChC,YAAY,EAAE,MAAM,CAAC;IACrB,SAAS,EAAE,UAAU,CAAC;IACtB,uBAAuB,EAAE,OAAO,CAAC;CAClC;AAmCD,wBAAsB,mBAAmB,CACvC,OAAO,EAAE,eAAe,EACxB,IAAI,EAAE,WAAW,EACjB,MAAM,EAAE,WAAW,GAClB,OAAO,CAAC,iBAAiB,CAAC,CAqD5B;AAED,wBAAsB,qBAAqB,CACzC,OAAO,EAAE,eAAe,EACxB,aAAa,EAAE,MAAM,EAAE,EACvB,MAAM,EAAE,WAAW,GAClB,OAAO,CAAC,iBAAiB,CAAC,CAwB5B"}
|