ox 1.2.0 → 1.3.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/CHANGELOG.md +34 -0
- package/dist/core/AbiFunction.d.ts +1 -1
- package/dist/core/AbiFunction.d.ts.map +1 -1
- package/dist/core/AbiFunction.js +6 -2
- package/dist/core/AbiFunction.js.map +1 -1
- package/dist/core/AbiParameters.d.ts +1 -1
- package/dist/core/AbiParameters.d.ts.map +1 -1
- package/dist/core/AbiParameters.js +1 -13
- package/dist/core/AbiParameters.js.map +1 -1
- package/dist/core/AesGcm.d.ts +36 -1
- package/dist/core/AesGcm.d.ts.map +1 -1
- package/dist/core/AesGcm.js +44 -0
- package/dist/core/AesGcm.js.map +1 -1
- package/dist/core/Ed25519.d.ts +46 -1
- package/dist/core/Ed25519.d.ts.map +1 -1
- package/dist/core/Ed25519.js +43 -0
- package/dist/core/Ed25519.js.map +1 -1
- package/dist/core/Engine.d.ts +1 -1
- package/dist/core/Engine.d.ts.map +1 -1
- package/dist/core/Engine.js.map +1 -1
- package/dist/core/Hash.d.ts +164 -1
- package/dist/core/Hash.d.ts.map +1 -1
- package/dist/core/Hash.js +172 -0
- package/dist/core/Hash.js.map +1 -1
- package/dist/core/Hex.d.ts.map +1 -1
- package/dist/core/Hex.js +1 -4
- package/dist/core/Hex.js.map +1 -1
- package/dist/core/Rlp.d.ts +32 -0
- package/dist/core/Rlp.d.ts.map +1 -1
- package/dist/core/Rlp.js +146 -0
- package/dist/core/Rlp.js.map +1 -1
- package/dist/core/Secp256k1.d.ts +46 -1
- package/dist/core/Secp256k1.d.ts.map +1 -1
- package/dist/core/Secp256k1.js +48 -0
- package/dist/core/Secp256k1.js.map +1 -1
- package/dist/core/WebAuthn.d.ts +224 -0
- package/dist/core/WebAuthn.d.ts.map +1 -0
- package/dist/core/WebAuthn.js +343 -0
- package/dist/core/WebAuthn.js.map +1 -0
- package/dist/core/WebAuthnP256.d.ts +46 -50
- package/dist/core/WebAuthnP256.d.ts.map +1 -1
- package/dist/core/WebAuthnP256.js +44 -50
- package/dist/core/WebAuthnP256.js.map +1 -1
- package/dist/core/internal/abiParameters.d.ts +7 -87
- package/dist/core/internal/abiParameters.d.ts.map +1 -1
- package/dist/core/internal/abiParameters.js +339 -194
- package/dist/core/internal/abiParameters.js.map +1 -1
- package/dist/core/internal/engine.d.ts +35 -2
- package/dist/core/internal/engine.d.ts.map +1 -1
- package/dist/core/internal/engine.js +12 -1
- package/dist/core/internal/engine.js.map +1 -1
- package/dist/core/internal/hash.d.ts +10 -0
- package/dist/core/internal/hash.d.ts.map +1 -1
- package/dist/core/internal/hash.js +26 -1
- package/dist/core/internal/hash.js.map +1 -1
- package/dist/index.d.ts +23 -14
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +23 -14
- package/dist/index.js.map +1 -1
- package/dist/node/Engine.d.ts +1 -1
- package/dist/node/Engine.d.ts.map +1 -1
- package/dist/node/Engine.js.map +1 -1
- package/dist/node/Hash.d.ts +6 -4
- package/dist/node/Hash.d.ts.map +1 -1
- package/dist/node/Hash.js +35 -3
- package/dist/node/Hash.js.map +1 -1
- package/dist/tempo/AuthorizationTempo.d.ts +6 -6
- package/dist/tempo/AuthorizationTempo.js +6 -6
- package/dist/tempo/KeyAuthorization.d.ts +3 -8
- package/dist/tempo/KeyAuthorization.d.ts.map +1 -1
- package/dist/tempo/KeyAuthorization.js +3 -8
- package/dist/tempo/KeyAuthorization.js.map +1 -1
- package/dist/tempo/SignatureEnvelope.d.ts +8 -8
- package/dist/tempo/SignatureEnvelope.js +8 -8
- package/dist/wasm/Engine.d.ts +1 -1
- package/dist/wasm/Engine.d.ts.map +1 -1
- package/dist/wasm/Engine.js.map +1 -1
- package/dist/wasm/Hash.d.ts +1 -1
- package/dist/wasm/Hash.d.ts.map +1 -1
- package/dist/wasm/Hash.js +5 -0
- package/dist/wasm/Hash.js.map +1 -1
- package/dist/wasm/internal/blake3.d.ts +10 -1
- package/dist/wasm/internal/blake3.d.ts.map +1 -1
- package/dist/wasm/internal/blake3.js +12 -1
- package/dist/wasm/internal/blake3.js.map +1 -1
- package/dist/wasm/internal/blake3.wasm.d.ts +3 -1
- package/dist/wasm/internal/blake3.wasm.d.ts.map +1 -1
- package/dist/wasm/internal/blake3.wasm.js +3 -1
- package/dist/wasm/internal/blake3.wasm.js.map +1 -1
- package/dist/wasm/internal/hash.d.ts +9 -0
- package/dist/wasm/internal/hash.d.ts.map +1 -1
- package/dist/wasm/internal/hash.js +13 -1
- package/dist/wasm/internal/hash.js.map +1 -1
- package/dist/wasm/internal/hashState.d.ts +25 -0
- package/dist/wasm/internal/hashState.d.ts.map +1 -0
- package/dist/wasm/internal/hashState.js +105 -0
- package/dist/wasm/internal/hashState.js.map +1 -0
- package/dist/wasm/internal/hashes.d.ts +12 -1
- package/dist/wasm/internal/hashes.d.ts.map +1 -1
- package/dist/wasm/internal/hashes.js +18 -1
- package/dist/wasm/internal/hashes.js.map +1 -1
- package/dist/wasm/internal/hashes.wasm.d.ts +11 -3
- package/dist/wasm/internal/hashes.wasm.d.ts.map +1 -1
- package/dist/wasm/internal/hashes.wasm.js +11 -3
- package/dist/wasm/internal/hashes.wasm.js.map +1 -1
- package/dist/webauthn/Authentication.d.ts +2 -0
- package/dist/webauthn/Authentication.d.ts.map +1 -1
- package/dist/webauthn/Authentication.js +2 -1
- package/dist/webauthn/Authentication.js.map +1 -1
- package/dist/webauthn/Registration.d.ts.map +1 -1
- package/dist/webauthn/Registration.js +2 -1
- package/dist/webauthn/Registration.js.map +1 -1
- package/dist/webauthn/Types.d.ts +27 -6
- package/dist/webauthn/Types.d.ts.map +1 -1
- package/dist/webauthn/internal/utils.d.ts.map +1 -1
- package/dist/webauthn/internal/utils.js +35 -9
- package/dist/webauthn/internal/utils.js.map +1 -1
- package/dist/zod/TypedData.d.ts +2 -2
- package/package.json +9 -1
- package/src/benchmarks/Ox.bench.ts +6 -0
- package/src/benchmarks/OxNode.bench.ts +8 -0
- package/src/benchmarks/OxV0.bench.ts +4 -0
- package/src/benchmarks/OxWasm.bench.ts +22 -0
- package/src/core/AbiFunction.ts +5 -5
- package/src/core/AbiParameters.ts +8 -20
- package/src/core/AesGcm.ts +86 -1
- package/src/core/Ed25519.ts +87 -1
- package/src/core/Engine.ts +1 -0
- package/src/core/Hash.ts +262 -1
- package/src/core/Hex.ts +1 -4
- package/src/core/Rlp.ts +172 -5
- package/src/core/Secp256k1.ts +92 -1
- package/src/core/WebAuthn.ts +579 -0
- package/src/core/WebAuthnP256.ts +47 -50
- package/src/core/_test/AbiFunction.test.ts +9 -0
- package/src/core/_test/AbiParameters.differential.fuzz.ts +156 -0
- package/src/core/_test/AbiParameters.encode.test.ts +22 -0
- package/src/core/_test/AbiParameters.fuzz.ts +4 -0
- package/src/core/_test/AesGcm.test.ts +76 -0
- package/src/core/_test/Ed25519.test-d.ts +13 -1
- package/src/core/_test/Ed25519.test.ts +120 -1
- package/src/core/_test/Engine.test-d.ts +9 -0
- package/src/core/_test/Engine.test.ts +1 -1
- package/src/core/_test/Hash.test-d.ts +23 -0
- package/src/core/_test/Hash.test.ts +179 -1
- package/src/core/_test/Hex.test.ts +2 -0
- package/src/core/_test/Rlp.test-d.ts +18 -0
- package/src/core/_test/Rlp.test.ts +109 -0
- package/src/core/_test/Secp256k1.test-d.ts +14 -0
- package/src/core/_test/Secp256k1.test.ts +91 -1
- package/src/core/_test/WebAuthn.test-d.ts +142 -0
- package/src/core/_test/WebAuthn.test.ts +766 -0
- package/src/core/_test/index.test.ts +1 -0
- package/src/core/internal/abiParameters.ts +466 -326
- package/src/core/internal/engine.ts +47 -2
- package/src/core/internal/hash.ts +53 -1
- package/src/index.ts +24 -14
- package/src/node/Engine.ts +1 -0
- package/src/node/Hash.ts +43 -6
- package/src/node/_test/Engine.test-d.ts +1 -0
- package/src/node/_test/Engine.test.ts +2 -0
- package/src/node/_test/Hash.test-d.ts +10 -0
- package/src/node/_test/Hash.test.ts +46 -0
- package/src/tempo/AuthorizationTempo.ts +6 -6
- package/src/tempo/KeyAuthorization.ts +3 -8
- package/src/tempo/SignatureEnvelope.ts +8 -8
- package/src/version.ts +1 -1
- package/src/wasm/Engine.ts +1 -0
- package/src/wasm/Hash.ts +10 -0
- package/src/wasm/_test/Engine.test-d.ts +1 -0
- package/src/wasm/_test/Engine.test.ts +5 -0
- package/src/wasm/_test/Hash.browser.test.ts +28 -0
- package/src/wasm/_test/Hash.test-d.ts +16 -0
- package/src/wasm/_test/Hash.test.ts +250 -1
- package/src/wasm/internal/blake3.ts +23 -2
- package/src/wasm/internal/blake3.wasm.ts +4 -1
- package/src/wasm/internal/hash.ts +27 -1
- package/src/wasm/internal/hashState.ts +154 -0
- package/src/wasm/internal/hashes.ts +56 -15
- package/src/wasm/internal/hashes.wasm.ts +15 -3
- package/src/webauthn/Authentication.ts +4 -0
- package/src/webauthn/Registration.ts +2 -0
- package/src/webauthn/Types.ts +32 -2
- package/src/webauthn/_test/Authentication.test.ts +123 -1
- package/src/webauthn/_test/Registration.test.ts +26 -6
- package/src/webauthn/_test/WebAuthn.browser.test.ts +28 -0
- package/src/webauthn/internal/utils.ts +41 -8
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
import type * as Engine from '../../core/Engine.js'
|
|
2
|
+
import type { Module } from './instantiate.js'
|
|
3
|
+
import { MemoryError } from './instantiate.js'
|
|
4
|
+
|
|
5
|
+
/** Exports required by every incremental hash state. @internal */
|
|
6
|
+
export type Exports = {
|
|
7
|
+
zero(ptr: number, length: number): void
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
/** Parameters for creating a host-owned incremental hash state. @internal */
|
|
11
|
+
export type Options<exports extends Exports> = {
|
|
12
|
+
digestSize: number
|
|
13
|
+
finalize: (exports: exports, state: number, out: number) => void
|
|
14
|
+
init: (
|
|
15
|
+
exports: exports,
|
|
16
|
+
state: number,
|
|
17
|
+
input: number,
|
|
18
|
+
inputLength: number,
|
|
19
|
+
) => void
|
|
20
|
+
input?: Uint8Array | undefined
|
|
21
|
+
stateSize: number
|
|
22
|
+
update: (
|
|
23
|
+
exports: exports,
|
|
24
|
+
state: number,
|
|
25
|
+
input: number,
|
|
26
|
+
inputLength: number,
|
|
27
|
+
) => void
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
const alignment = 8
|
|
31
|
+
const wasm32Size = 0x1_0000_0000
|
|
32
|
+
|
|
33
|
+
function align(value: number) {
|
|
34
|
+
return Math.ceil(value / alignment) * alignment
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
function reserve<exports extends Exports>(
|
|
38
|
+
module: Module<exports>,
|
|
39
|
+
end: number,
|
|
40
|
+
) {
|
|
41
|
+
if (!Number.isSafeInteger(end) || end > wasm32Size)
|
|
42
|
+
throw new MemoryError({
|
|
43
|
+
bytes: end,
|
|
44
|
+
cause: new RangeError('Hash workspace exceeds wasm32 memory.'),
|
|
45
|
+
})
|
|
46
|
+
module.reserve(end - module.heapBase)
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Creates a hash state whose authoritative bytes live in host memory.
|
|
51
|
+
*
|
|
52
|
+
* The shared WASM instance only holds a state during one synchronous call.
|
|
53
|
+
* Every workspace is cleared before control returns to the caller.
|
|
54
|
+
*
|
|
55
|
+
* @internal
|
|
56
|
+
*/
|
|
57
|
+
export function create<exports extends Exports>(
|
|
58
|
+
module: Module<exports>,
|
|
59
|
+
options: Options<exports>,
|
|
60
|
+
): Engine.HashState {
|
|
61
|
+
const { digestSize, finalize, init, stateSize, update } = options
|
|
62
|
+
const initial = options.input ?? new Uint8Array()
|
|
63
|
+
const inputPtr = module.heapBase
|
|
64
|
+
const statePtr = align(inputPtr + initial.length)
|
|
65
|
+
const end = statePtr + stateSize
|
|
66
|
+
reserve(module, end)
|
|
67
|
+
|
|
68
|
+
let state: Uint8Array
|
|
69
|
+
try {
|
|
70
|
+
module.exports.zero(module.heapBase, end - module.heapBase)
|
|
71
|
+
const view = module.view()
|
|
72
|
+
view.set(initial, inputPtr)
|
|
73
|
+
init(module.exports, statePtr, inputPtr, initial.length)
|
|
74
|
+
state = module.view().slice(statePtr, end)
|
|
75
|
+
} finally {
|
|
76
|
+
module.exports.zero(module.heapBase, end - module.heapBase)
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
return fromSnapshot(module, state, {
|
|
80
|
+
digestSize,
|
|
81
|
+
finalize,
|
|
82
|
+
stateSize,
|
|
83
|
+
update,
|
|
84
|
+
})
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
type SnapshotOptions<exports extends Exports> = Pick<
|
|
88
|
+
Options<exports>,
|
|
89
|
+
'digestSize' | 'finalize' | 'stateSize' | 'update'
|
|
90
|
+
>
|
|
91
|
+
|
|
92
|
+
function fromSnapshot<exports extends Exports>(
|
|
93
|
+
module: Module<exports>,
|
|
94
|
+
state: Uint8Array,
|
|
95
|
+
options: SnapshotOptions<exports>,
|
|
96
|
+
): Engine.HashState {
|
|
97
|
+
const { digestSize, finalize, stateSize, update } = options
|
|
98
|
+
let active = true
|
|
99
|
+
|
|
100
|
+
const assertActive = () => {
|
|
101
|
+
if (!active) throw new Error('Hash state has been destroyed.')
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
const hashState: Engine.HashState = {
|
|
105
|
+
clone() {
|
|
106
|
+
assertActive()
|
|
107
|
+
return fromSnapshot(module, state.slice(), options)
|
|
108
|
+
},
|
|
109
|
+
destroy() {
|
|
110
|
+
if (!active) return
|
|
111
|
+
active = false
|
|
112
|
+
state.fill(0)
|
|
113
|
+
},
|
|
114
|
+
digestInto(output) {
|
|
115
|
+
assertActive()
|
|
116
|
+
if (output.length < digestSize)
|
|
117
|
+
throw new RangeError(
|
|
118
|
+
`Digest output requires at least ${digestSize} bytes.`,
|
|
119
|
+
)
|
|
120
|
+
|
|
121
|
+
const statePtr = align(module.heapBase)
|
|
122
|
+
const outPtr = statePtr + stateSize
|
|
123
|
+
const end = outPtr + digestSize
|
|
124
|
+
reserve(module, end)
|
|
125
|
+
active = false
|
|
126
|
+
try {
|
|
127
|
+
module.view().set(state, statePtr)
|
|
128
|
+
finalize(module.exports, statePtr, outPtr)
|
|
129
|
+
output.set(module.view().subarray(outPtr, end))
|
|
130
|
+
} finally {
|
|
131
|
+
state.fill(0)
|
|
132
|
+
module.exports.zero(module.heapBase, end - module.heapBase)
|
|
133
|
+
}
|
|
134
|
+
},
|
|
135
|
+
update(input) {
|
|
136
|
+
assertActive()
|
|
137
|
+
const inputPtr = module.heapBase
|
|
138
|
+
const statePtr = align(inputPtr + input.length)
|
|
139
|
+
const end = statePtr + stateSize
|
|
140
|
+
reserve(module, end)
|
|
141
|
+
try {
|
|
142
|
+
const view = module.view()
|
|
143
|
+
view.set(input, inputPtr)
|
|
144
|
+
view.set(state, statePtr)
|
|
145
|
+
update(module.exports, statePtr, inputPtr, input.length)
|
|
146
|
+
state.set(module.view().subarray(statePtr, end))
|
|
147
|
+
} finally {
|
|
148
|
+
module.exports.zero(module.heapBase, end - module.heapBase)
|
|
149
|
+
}
|
|
150
|
+
},
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
return hashState
|
|
154
|
+
}
|
|
@@ -1,22 +1,51 @@
|
|
|
1
1
|
import * as hash from './hash.js'
|
|
2
|
-
import {
|
|
2
|
+
import {
|
|
3
|
+
keccak256StateSize,
|
|
4
|
+
ripemd160StateSize,
|
|
5
|
+
sha256StateSize,
|
|
6
|
+
wasmBase64,
|
|
7
|
+
} from './hashes.wasm.js'
|
|
8
|
+
import * as hashState from './hashState.js'
|
|
3
9
|
import * as internal from './instantiate.js'
|
|
4
10
|
|
|
11
|
+
type Algorithm = 'keccak256' | 'ripemd160' | 'sha256'
|
|
12
|
+
|
|
13
|
+
type StateExports = {
|
|
14
|
+
[key in `${Algorithm}_init`]: (state: number) => void
|
|
15
|
+
} & {
|
|
16
|
+
[key in `${Algorithm}_update`]: (
|
|
17
|
+
state: number,
|
|
18
|
+
input: number,
|
|
19
|
+
inputLength: number,
|
|
20
|
+
) => void
|
|
21
|
+
} & {
|
|
22
|
+
[key in `${Algorithm}_finalize`]: (state: number, out: number) => void
|
|
23
|
+
}
|
|
24
|
+
|
|
5
25
|
/** Exports shared by the Hash and Keystore providers. @internal */
|
|
6
|
-
export type Exports = hash.Exports &
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
26
|
+
export type Exports = hash.Exports &
|
|
27
|
+
hash.StateExports &
|
|
28
|
+
StateExports & {
|
|
29
|
+
keccak256(input: number, length: number, out: number): void
|
|
30
|
+
pbkdf2_sha256(
|
|
31
|
+
password: number,
|
|
32
|
+
passwordLength: number,
|
|
33
|
+
salt: number,
|
|
34
|
+
saltLength: number,
|
|
35
|
+
iterations: number,
|
|
36
|
+
out: number,
|
|
37
|
+
outLength: number,
|
|
38
|
+
scratch: number,
|
|
39
|
+
): void
|
|
40
|
+
ripemd160(input: number, length: number, out: number): void
|
|
41
|
+
sha256(input: number, length: number, out: number): void
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
const digestSize = { keccak256: 32, ripemd160: 20, sha256: 32 }
|
|
45
|
+
const stateSize = {
|
|
46
|
+
keccak256: keccak256StateSize,
|
|
47
|
+
ripemd160: ripemd160StateSize,
|
|
48
|
+
sha256: sha256StateSize,
|
|
20
49
|
}
|
|
21
50
|
|
|
22
51
|
const instantiate = /*#__PURE__*/ internal.memoize(() =>
|
|
@@ -27,3 +56,15 @@ const instantiate = /*#__PURE__*/ internal.memoize(() =>
|
|
|
27
56
|
export function load() {
|
|
28
57
|
return instantiate()
|
|
29
58
|
}
|
|
59
|
+
|
|
60
|
+
/** Creates an incremental state for one of the shared hash primitives. @internal */
|
|
61
|
+
export function create(module: internal.Module<Exports>, hash: Algorithm) {
|
|
62
|
+
return hashState.create(module, {
|
|
63
|
+
digestSize: digestSize[hash],
|
|
64
|
+
finalize: (exports, state, out) => exports[`${hash}_finalize`](state, out),
|
|
65
|
+
init: (exports, state) => exports[`${hash}_init`](state),
|
|
66
|
+
stateSize: stateSize[hash],
|
|
67
|
+
update: (exports, state, input, inputLength) =>
|
|
68
|
+
exports[`${hash}_update`](state, input, inputLength),
|
|
69
|
+
})
|
|
70
|
+
}
|
|
@@ -8,10 +8,22 @@
|
|
|
8
8
|
|
|
9
9
|
/** Base64-encoded WASM binary. */
|
|
10
10
|
export const wasmBase64 =
|
|
11
|
-
'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dnM6ACkgByAHLQAqIDBzOgAqIAcgBCAHLQArczoAKyAHIActACwgHHM6ACwgByAHLQAtIAhBEHZzOgAtIAcgBy0ALiAxczoALiAHIAggBy0AL3M6AC8gByAHLQAwIB1zOgAwIAcgBy0AMSALQRB2czoAMSAHIActADIgMnM6ADIgByALIActADNzOgAzIAcgBy0ANCAeczoANCAHIActADUgCUEQdnM6ADUgByAHLQA2IDNzOgA2IAcgCSAHLQA3czoANyAHIActADggH3M6ADggByAHLQA5IA1BEHZzOgA5IAcgBy0AOiA0czoAOiAHIA0gBy0AO3M6ADsgByAHLQA8ICBzOgA8IAcgBy0APSAKQRB2czoAPSAHIActAD4gNXM6AD4gByAKIActAD9zOgA/IABBAWsiAA0ACwtBICAGIA5rIgEgAUEgTxshAAJAIAYgDkYNAEEBIAAgAEEBTRsiA0EDcSEIQQAhBCABQQRPBEAgBSAOaiELIANBPHEhCQNAIAQgC2oiASAEIAdqIgNBIGotAAA6AAAgAUEBaiADQSFqLQAAOgAAIAFBAmogA0Eiai0AADoAACABQQNqIANBI2otAAA6AAAgCSAEQQRqIgRHDQALCyAIRQ0AQQAgCGshASAEICFqIQMgBSAEIA5qaiEEA0AgBCADLQAAOgAAIANBAWohAyAEQQFqIQQgAUEBaiIBDQALCyAMQQFqIQwgACAOaiIOIAZJDQALC0EAIQMDQCADIAdqIgBBADoAACAAQQFqQQA6AAAgAEECakEAOgAAIABBA2pBADoAACAAQQRqQQA6AAAgAEEFakEAOgAAIABBBmpBADoAACAAQQdqQQA6AAAgAEEIakEAOgAAIABBCWpBADoAACAAQQpqQQA6AAAgAEELakEAOgAAIABBDGpBADoAACAAQQ1qQQA6AAAgAEEOakEAOgAAIABBD2pBADoAACADQRBqIgNBoARHDQALC78IARJ/IAIgASgAACIDQRh0IANBgP4DcUEIdHIgA0EIdkGA/gNxIANBGHZycjYCACACIAEoAAQiA0EYdCADQYD+A3FBCHRyIANBCHZBgP4DcSADQRh2cnI2AgQgAiABKAAIIgNBGHQgA0GA/gNxQQh0ciADQQh2QYD+A3EgA0EYdnJyNgIIIAIgASgADCIDQRh0IANBgP4DcUEIdHIg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'
|
|
11
|
+
'AGFzbQEAAAABLgdgA39/fwBgAn9/AGABfwBgBn9/f39/fwBgCH9/f39/f39/AGACf38Bf2AAAX8DHRwDAAABAQEAAAIAAQICBAUAAgABAQACAAEBAgAGBQMBABAGCAF/AUHQjgQLB8wCFQZtZW1vcnkCAAxrZWNjYWtfZjE2MDAADA5rZWNjYWsyNTZfaW5pdAAIEGtlY2NhazI1Nl91cGRhdGUACRJrZWNjYWsyNTZfZmluYWxpemUACglrZWNjYWsyNTYABwtzaGEyNTZfaW5pdAAZDXNoYTI1Nl91cGRhdGUAAg9zaGEyNTZfZmluYWxpemUAGAZzaGEyNTYAFBBobWFjX3NoYTI1Nl9pbml0AAYSaG1hY19zaGEyNTZfdXBkYXRlAAIUaG1hY19zaGEyNTZfZmluYWxpemUABQtobWFjX3NoYTI1NgAADXBia2RmMl9zaGEyNTYADQ5yaXBlbWQxNjBfaW5pdAAQEHJpcGVtZDE2MF91cGRhdGUAERJyaXBlbWQxNjBfZmluYWxpemUAEglyaXBlbWQxNjAADwR6ZXJvAAQJaGVhcF9iYXNlABsKwlMcHwAgBSAAIAEQASAFIAIgAxAWIAUgBBADIAVBkAEQBAuTBAEDfyMAQbABayIDJAAgA0IANwOoASADQgA3A6ABIANCADcDmAEgA0IANwOQASADQgA3A4gBIANCADcDgAEgA0IANwN4IANCADcDcAJAIAJBwABNBEAgAkUNASACQQNxIQUgAkEETwRAIAJB/ABxIQIDQCADQfAAaiAEaiABIARqKAAANgIAIAIgBEEEaiIERw0ACwsgBUUNASABIARqIQEgA0HwAGogBGohBANAIAQgAS0AADoAACABQQFqIQEgBEEBaiEEIAVBAWsiBQ0ACwwBCyADEBUgAyABIAIQFiADIANB8ABqEBcgA0HwABAECyAAEBVBACEBA0AgA0HwAGoiBCABaiICIAItAABBNnM6AAAgAkEBaiIFIAUtAABBNnM6AAAgAkECaiIFIAUtAABBNnM6AAAgAkEDaiICIAItAABBNnM6AAAgAUEEaiIBQcAARw0ACyAAIARBwAAQFiADEBVBACEBA0AgA0HwAGoiBCABaiICIAItAABB6gBzOgAAIAJBAWoiBSAFLQAAQeoAczoAACACQQJqIgUgBS0AAEHqAHM6AAAgAkEDaiICIAItAABB6gBzOgAAIAFBBGoiAUHAAEcNAAsgAyAEQcAAEBYgACADKQMINwJwIAAgAykDEDcCeCAAIAMpAxg3AoABIAAgAykDIDcCiAEgA0HwABAEIARBwAAQBCADQbABaiQACwoAIAAgASACEBYLtgMBAn8jAEGQAWsiAiQAIAAgAkHwAGoiAxAXIAIQFSACQsAANwMAIAIgACkCcDcDCCACIAApAng3AxAgAiAAKQKAATcDGCACIAApAogBNwMgIAIgA0EgEBYgAiAAQSxqEBcgAkHwABAEIANBIBAEIAEgAC0ALDoAACABIAAtAC06AAEgASAALQAuOgACIAEgAC0ALzoAAyABIAAtADA6AAQgASAALQAxOgAFIAEgAC0AMjoABiABIAAtADM6AAcgASAALQA0OgAIIAEgAC0ANToACSABIAAtADY6AAogASAALQA3OgALIAEgAC0AODoADCABIAAtADk6AA0gASAALQA6OgAOIAEgAC0AOzoADyABIAAtADw6ABAgASAALQA9OgARIAEgAC0APjoAEiABIAAtAD86ABMgASAALQBAOgAUIAEgAC0AQToAFSABIAAtAEI6ABYgASAALQBDOgAXIAEgAC0ARDoAGCABIAAtAEU6ABkgASAALQBGOgAaIAEgAC0ARzoAGyABIAAtAEg6ABwgASAALQBJOgAdIAEgAC0ASjoAHiABIAAtAEs6AB8gAkGQAWokAAuTAQECfwJAIAFFDQACQCABQQdxIgNFBEAgASECDAELIAFBeHEhAgNAIABBADoAACAAQQFqIQAgA0EBayIDDQALCyABQQhJDQADQCAAQQA6AAAgAEEAOgABIABBADoAAiAAQQA6AAMgAEEAOgAEIABBADoABSAAQQA6AAYgAEEAOgAHIABBCGohACACQQhrIgINAAsLCwgAIAAgARADCwoAIAAgASACEAELLQECfyMAQeACayIDJAAgA0EIaiIEEAggBCAAIAEQCSAEIAIQCiADQeACaiQAC+IBAQF/IABBADYCyAEgAEIANwPAASAAQgA3A7gBIABCADcDsAEgAEIANwOoASAAQgA3A6ABIABCADcDmAEgAEIANwOQASAAQgA3A4gBIABCADcDgAEgAEIANwN4IABCADcDcCAAQgA3A2ggAEIANwNgIABCADcDWCAAQgA3A1AgAEIANwNIIABCADcDQCAAQgA3AzggAEIANwMwIABCADcDKCAAQgA3AyAgAEIANwMYIABCADcDECAAQgA3AwggAEIANwMAA0AgACABakHMAWpCADcAACABQQhqIgFBiAFHDQALC5UJAQd/AkAgACgCyAEiAwRAQYgBIANrIgcgAiACIAdLGyIEBEAgBEEDcSEFQQAhAyAEQQRPBEAgBEF8cSEIA0AgACADIAAoAsgBampBzAFqIAEgA2oiBi0AADoAACAAIAMgACgCyAFqakHNAWogBkEBai0AADoAACAAIAMgACgCyAFqakHOAWogBkECai0AADoAACAAIAMgACgCyAFqakHPAWogBkEDai0AADoAACAIIANBBGoiA0cNAAsLIAUEQCABIANqIQYgACADakHMAWohAwNAIAMgACgCyAFqIAYtAAA6AAAgBkEBaiEGIANBAWohAyAFQQFrIgUNAAsLIAAoAsgBIQMLIAAgAyAEaiIDNgLIASADQYgBRgRAIAAgACkDACAAKQDMAYU3AwAgACAAKQMIIAApANQBhTcDCCAAIAApAxAgACkA3AGFNwMQIAAgACkDGCAAKQDkAYU3AxggACAAKQMgIAApAOwBhTcDICAAIAApAyggACkA9AGFNwMoIAAgACkDMCAAKQD8AYU3AzAgACAAKQM4IAApAIQChTcDOCAAIAApA0AgACkAjAKFNwNAIAAgACkDSCAAKQCUAoU3A0ggACAAKQNQIAApAJwChTcDUCAAIAApA1ggACkApAKFNwNYIAAgACkDYCAAKQCsAoU3A2AgACAAKQNoIAApALQChTcDaCAAIAApA3AgACkAvAKFNwNwIAAgACkDeCAAKQDEAoU3A3ggACAAKQOAASAAKQDMAoU3A4ABIAAQCyAAQQA2AsgBCyACIAdNDQELIAIgBGsiBUGIAU8EQANAIAAgACkDACABIARqIgIpAACFNwMAIAAgACkDCCACKQAIhTcDCCAAIAApAxAgAkEQaikAAIU3AxAgACAAKQMYIAJBGGopAACFNwMYIAAgACkDICACQSBqKQAAhTcDICAAIAApAyggAkEoaikAAIU3AyggACAAKQMwIAJBMGopAACFNwMwIAAgACkDOCACQThqKQAAhTcDOCAAIAApA0AgAkFAaykAAIU3A0AgACAAKQNIIAJByABqKQAAhTcD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AgAiDSEJIAAoAgQiDiEBIAAoAggiDyEFIAAoAgwiECEMIAAoAhwiESEKIAAoAhgiEiEIIAAoAhQiEyEDIAAoAhAiFCEGA0AgBSEEIAEhBSACIAtqKAIAIAtBwAlqKAIAIAogBiIHQRp3IAdBFXdzIAdBB3dzaiAHQX9zIAhxIAMgB3FyampqIgYgCSIBQR53IAFBE3dzIAFBCndzIAEgBCAFc3EgBCAFcXNqaiEJIAYgDGohBiAEIQwgCCEKIAMhCCAHIQMgC0EEaiILQYACRw0ACyAAIAogEWo2AhwgACAIIBJqNgIYIAAgAyATajYCFCAAIAYgFGo2AhAgACAEIBBqNgIMIAAgBSAPajYCCCAAIAEgDmo2AgQgACAJIA1qNgIACyUBAX9BwA4tAAAiAARAQdCOBEEAIAAbDwtBwA5BAToAAEHQjgQLC7kGAwBBgAgLpAQBAAAAAAAAAIKAAAAAAAAAioAAAAAAAIAAgACAAAAAgIuAAAAAAAAAAQAAgAAAAACBgACAAAAAgAmAAAAAAACAigAAAAAAAACIAAAAAAAAAAmAAIAAAAAACgAAgAAAAACLgACAAAAAAIsAAAAAAACAiYAAAAAAAIADgAAAAAAAgAKAAAAAAACAgAAAAAAAAIAKgAAAAAAAAAoAAIAAAACAgYAAgAAAAICAgAAAAAAAgAEAAIAAAAAACIAAgAAAAICYL4pCkUQ3cc/7wLWl27XpW8JWOfER8Vmkgj+S1V4cq5iqB9gBW4MSvoUxJMN9DFV0Xb5y/rHegKcG3Jt08ZvBwWmb5IZHvu/GncEPzKEMJG8s6S2qhHRK3KmwXNqI+XZSUT6YbcYxqMgnA7DHf1m/8wvgxkeRp9VRY8oGZykpFIUKtyc4IRsu/G0sTRMNOFNUcwpluwpqdi7JwoGFLHKSoei/oktmGqhwi0vCo1FsxxnoktEkBpnWhTUO9HCgahAWwaQZCGw3Hkx3SCe1vLA0swwcOUqq2E5Pypxb828uaO6Cj3RvY6V4FHjIhAgCx4z6/76Q62xQpPej+b7yeHHGAAECAwQFBgcICQoLDA0ODwcEDQEKBg8DDAAJBQIOCwgDCg4ECQ8IAQIHAAYNCwUMAQkLCgAIDAQNAwcPDgUGAgQABQkHDAIKDgEDCAsGDw0AAAAAmXmCWqHr2W7cvBuPTv1TqQBBsAwLsAELDg8MBQgHCQsNDg8GBwkIBwYIDQsJBw8HDA8JCwcNDAsNBgcOCQ0PDggNBgUMBwULDA4PDg8JCAkOBQYIBgUMCQ8FCwYIDQwFDA0OCwgFBgUOBwAJAgsEDQYPCAEKAwwGCwMHAA0FCg4PCAwECQECDwUBAwcOBgkLCAwCCgAEDQgGBAEDCw8ABQwCDQkHCg4MDwoEAQUIBwYCDQ4AAwkL5ouiUCTRTVzzPnBt6XZtegBB8A0LUAgJCQsNDw8FBwcICw4ODAYJDQ8HDAgJCwcHDAcGDw0LCQcPCwgGBg4MDQUODQ0HBQ8FCAsODgYOBgkMCQwFDwgIBQwJDAUOBggNBgUPDQsL'
|
|
12
12
|
|
|
13
13
|
/** Constant shared with the module's C source. */
|
|
14
|
-
export const hmacSha256ScratchSize =
|
|
14
|
+
export const hmacSha256ScratchSize = 144
|
|
15
15
|
|
|
16
16
|
/** Constant shared with the module's C source. */
|
|
17
|
-
export const
|
|
17
|
+
export const hmacSha256StateSize = 144
|
|
18
|
+
|
|
19
|
+
/** Constant shared with the module's C source. */
|
|
20
|
+
export const keccak256StateSize = 344
|
|
21
|
+
|
|
22
|
+
/** Constant shared with the module's C source. */
|
|
23
|
+
export const pbkdf2Sha256ScratchSize = 352
|
|
24
|
+
|
|
25
|
+
/** Constant shared with the module's C source. */
|
|
26
|
+
export const ripemd160StateSize = 96
|
|
27
|
+
|
|
28
|
+
/** Constant shared with the module's C source. */
|
|
29
|
+
export const sha256StateSize = 112
|
|
@@ -175,6 +175,7 @@ export function getOptions(
|
|
|
175
175
|
challenge,
|
|
176
176
|
extensions,
|
|
177
177
|
rpId = window.location.hostname,
|
|
178
|
+
timeout,
|
|
178
179
|
userVerification = 'required',
|
|
179
180
|
} = options
|
|
180
181
|
return {
|
|
@@ -197,6 +198,7 @@ export function getOptions(
|
|
|
197
198
|
challenge: Bytes.fromHex(challenge),
|
|
198
199
|
...(extensions && { extensions }),
|
|
199
200
|
rpId,
|
|
201
|
+
...(timeout !== undefined && { timeout }),
|
|
200
202
|
userVerification,
|
|
201
203
|
},
|
|
202
204
|
}
|
|
@@ -214,6 +216,8 @@ export declare namespace getOptions {
|
|
|
214
216
|
| undefined
|
|
215
217
|
/** The relying party identifier to use. */
|
|
216
218
|
rpId?: Types.PublicKeyCredentialRequestOptions['rpId'] | undefined
|
|
219
|
+
/** Time, in milliseconds, that the caller is willing to wait for the operation. */
|
|
220
|
+
timeout?: Types.PublicKeyCredentialRequestOptions['timeout'] | undefined
|
|
217
221
|
/** The user verification requirement. */
|
|
218
222
|
userVerification?:
|
|
219
223
|
| Types.PublicKeyCredentialRequestOptions['userVerification']
|
|
@@ -160,6 +160,7 @@ export function getOptions(
|
|
|
160
160
|
id: window.location.hostname,
|
|
161
161
|
name: window.document.title,
|
|
162
162
|
},
|
|
163
|
+
timeout,
|
|
163
164
|
user,
|
|
164
165
|
} = options
|
|
165
166
|
const name = (user?.name ?? name_)!
|
|
@@ -184,6 +185,7 @@ export function getOptions(
|
|
|
184
185
|
},
|
|
185
186
|
],
|
|
186
187
|
rp,
|
|
188
|
+
...(timeout !== undefined && { timeout }),
|
|
187
189
|
user: {
|
|
188
190
|
id: user?.id ?? Hash.keccak256(Bytes.fromString(name), { as: 'Bytes' }),
|
|
189
191
|
name,
|
package/src/webauthn/Types.ts
CHANGED
|
@@ -38,7 +38,29 @@ export type LargeBlobSupport = {
|
|
|
38
38
|
|
|
39
39
|
export type BufferSource = ArrayBufferView | ArrayBuffer
|
|
40
40
|
|
|
41
|
-
|
|
41
|
+
/** Inputs or outputs for a WebAuthn PRF evaluation. */
|
|
42
|
+
export type PrfValues<serialized extends boolean = false> = {
|
|
43
|
+
/** First PRF input or output. */
|
|
44
|
+
first: serialized extends true ? string : BufferSource
|
|
45
|
+
/** Optional second PRF input or output. */
|
|
46
|
+
second?: (serialized extends true ? string : BufferSource) | undefined
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/** Inputs for the WebAuthn PRF extension. */
|
|
50
|
+
export type PrfExtension<serialized extends boolean = false> = {
|
|
51
|
+
/** PRF inputs for the selected credential. */
|
|
52
|
+
eval?: PrfValues<serialized> | undefined
|
|
53
|
+
/** PRF inputs keyed by base64url-encoded credential ID. */
|
|
54
|
+
evalByCredential?: Record<string, PrfValues<serialized>> | undefined
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/** Outputs from the WebAuthn PRF extension. */
|
|
58
|
+
export type PrfExtensionOutput = {
|
|
59
|
+
/** Whether the created credential supports PRF evaluation. */
|
|
60
|
+
enabled?: boolean | undefined
|
|
61
|
+
/** PRF evaluation results. */
|
|
62
|
+
results?: PrfValues | undefined
|
|
63
|
+
}
|
|
42
64
|
|
|
43
65
|
export interface AuthenticationExtensionsClientInputs<
|
|
44
66
|
serialized extends boolean = false,
|
|
@@ -47,10 +69,18 @@ export interface AuthenticationExtensionsClientInputs<
|
|
|
47
69
|
credProps?: boolean
|
|
48
70
|
hmacCreateSecret?: boolean
|
|
49
71
|
minPinLength?: boolean
|
|
50
|
-
prf?: serialized
|
|
72
|
+
prf?: PrfExtension<serialized> | undefined
|
|
51
73
|
largeBlob?: LargeBlobSupport
|
|
52
74
|
}
|
|
53
75
|
|
|
76
|
+
/** Outputs from WebAuthn client extension processing. */
|
|
77
|
+
export type AuthenticationExtensionsClientOutputs = ReturnType<
|
|
78
|
+
globalThis.PublicKeyCredential['getClientExtensionResults']
|
|
79
|
+
> & {
|
|
80
|
+
/** WebAuthn PRF extension output. */
|
|
81
|
+
prf?: PrfExtensionOutput | undefined
|
|
82
|
+
}
|
|
83
|
+
|
|
54
84
|
export interface AuthenticatorSelectionCriteria {
|
|
55
85
|
authenticatorAttachment?: AuthenticatorAttachment
|
|
56
86
|
requireResidentKey?: boolean
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { runInNewContext } from 'node:vm'
|
|
1
2
|
import { afterAll, beforeAll, describe, expect, test, vi } from 'vp/test'
|
|
2
3
|
import * as Bytes from '../../core/Bytes.js'
|
|
3
4
|
import * as Hash from '../../core/Hash.js'
|
|
@@ -5,7 +6,7 @@ import * as P256 from '../../core/P256.js'
|
|
|
5
6
|
import * as PublicKey from '../../core/PublicKey.js'
|
|
6
7
|
import * as Signature from '../../core/Signature.js'
|
|
7
8
|
import * as WebCryptoP256 from '../../core/WebCryptoP256.js'
|
|
8
|
-
import { Authentication } from '../index.js'
|
|
9
|
+
import { Authentication, type Types } from '../index.js'
|
|
9
10
|
|
|
10
11
|
beforeAll(() => {
|
|
11
12
|
vi.stubGlobal('window', {
|
|
@@ -73,6 +74,16 @@ describe('getOptions', () => {
|
|
|
73
74
|
`)
|
|
74
75
|
})
|
|
75
76
|
|
|
77
|
+
test('options: timeout', () => {
|
|
78
|
+
const options = Authentication.getOptions({
|
|
79
|
+
challenge:
|
|
80
|
+
'0xf631058a3ba1116acce12396fad0a125b5041c43f8e15723709f81aa8d5f4ccf',
|
|
81
|
+
timeout: 30_000,
|
|
82
|
+
})
|
|
83
|
+
|
|
84
|
+
expect(options.publicKey?.timeout).toMatchInlineSnapshot(`30000`)
|
|
85
|
+
})
|
|
86
|
+
|
|
76
87
|
test('options: credentialId', () => {
|
|
77
88
|
expect(
|
|
78
89
|
Authentication.getOptions({
|
|
@@ -200,6 +211,61 @@ describe('serializeOptions', () => {
|
|
|
200
211
|
expect(() => JSON.stringify(serialized)).not.toThrow()
|
|
201
212
|
})
|
|
202
213
|
|
|
214
|
+
test('with extensions (prf.evalByCredential)', () => {
|
|
215
|
+
const first = runInNewContext(
|
|
216
|
+
'Uint8Array.from([4, 5, 6]).buffer',
|
|
217
|
+
) as ArrayBuffer
|
|
218
|
+
const options: Types.CredentialRequestOptions = {
|
|
219
|
+
publicKey: {
|
|
220
|
+
challenge: new Uint8Array([1, 2, 3]),
|
|
221
|
+
extensions: {
|
|
222
|
+
prf: {
|
|
223
|
+
evalByCredential: {
|
|
224
|
+
credential: {
|
|
225
|
+
first,
|
|
226
|
+
second: new Uint8Array(),
|
|
227
|
+
},
|
|
228
|
+
},
|
|
229
|
+
},
|
|
230
|
+
},
|
|
231
|
+
},
|
|
232
|
+
}
|
|
233
|
+
const serialized = Authentication.serializeOptions(options)
|
|
234
|
+
|
|
235
|
+
expect(first).not.toBeInstanceOf(ArrayBuffer)
|
|
236
|
+
expect(serialized.publicKey!.extensions).toMatchInlineSnapshot(`
|
|
237
|
+
{
|
|
238
|
+
"prf": {
|
|
239
|
+
"evalByCredential": {
|
|
240
|
+
"credential": {
|
|
241
|
+
"first": "BAUG",
|
|
242
|
+
"second": "",
|
|
243
|
+
},
|
|
244
|
+
},
|
|
245
|
+
},
|
|
246
|
+
}
|
|
247
|
+
`)
|
|
248
|
+
expect(() => JSON.stringify(serialized)).not.toThrow()
|
|
249
|
+
})
|
|
250
|
+
|
|
251
|
+
test('with extensions (empty prf)', () => {
|
|
252
|
+
const options: Types.CredentialRequestOptions = {
|
|
253
|
+
publicKey: {
|
|
254
|
+
challenge: new Uint8Array([1, 2, 3]),
|
|
255
|
+
extensions: {
|
|
256
|
+
prf: {},
|
|
257
|
+
},
|
|
258
|
+
},
|
|
259
|
+
}
|
|
260
|
+
const serialized = Authentication.serializeOptions(options)
|
|
261
|
+
|
|
262
|
+
expect(serialized.publicKey!.extensions).toMatchInlineSnapshot(`
|
|
263
|
+
{
|
|
264
|
+
"prf": {},
|
|
265
|
+
}
|
|
266
|
+
`)
|
|
267
|
+
})
|
|
268
|
+
|
|
203
269
|
test('empty publicKey', () => {
|
|
204
270
|
const serialized = Authentication.serializeOptions({})
|
|
205
271
|
expect(serialized).toEqual({})
|
|
@@ -241,6 +307,62 @@ describe('deserializeOptions', () => {
|
|
|
241
307
|
)
|
|
242
308
|
})
|
|
243
309
|
|
|
310
|
+
test('with extensions (prf.evalByCredential)', () => {
|
|
311
|
+
const options: Types.CredentialRequestOptions = {
|
|
312
|
+
publicKey: {
|
|
313
|
+
challenge: new Uint8Array([1, 2, 3]),
|
|
314
|
+
extensions: {
|
|
315
|
+
prf: {
|
|
316
|
+
evalByCredential: {
|
|
317
|
+
credential: {
|
|
318
|
+
first: new Uint8Array([4, 5, 6]),
|
|
319
|
+
second: new Uint8Array(),
|
|
320
|
+
},
|
|
321
|
+
},
|
|
322
|
+
},
|
|
323
|
+
},
|
|
324
|
+
},
|
|
325
|
+
}
|
|
326
|
+
const serialized = Authentication.serializeOptions(options)
|
|
327
|
+
const deserialized = Authentication.deserializeOptions(serialized)
|
|
328
|
+
|
|
329
|
+
expect(deserialized.publicKey!.extensions).toMatchInlineSnapshot(`
|
|
330
|
+
{
|
|
331
|
+
"prf": {
|
|
332
|
+
"evalByCredential": {
|
|
333
|
+
"credential": {
|
|
334
|
+
"first": Uint8Array [
|
|
335
|
+
4,
|
|
336
|
+
5,
|
|
337
|
+
6,
|
|
338
|
+
],
|
|
339
|
+
"second": Uint8Array [],
|
|
340
|
+
},
|
|
341
|
+
},
|
|
342
|
+
},
|
|
343
|
+
}
|
|
344
|
+
`)
|
|
345
|
+
})
|
|
346
|
+
|
|
347
|
+
test('with extensions (empty prf)', () => {
|
|
348
|
+
const options: Types.CredentialRequestOptions = {
|
|
349
|
+
publicKey: {
|
|
350
|
+
challenge: new Uint8Array([1, 2, 3]),
|
|
351
|
+
extensions: {
|
|
352
|
+
prf: {},
|
|
353
|
+
},
|
|
354
|
+
},
|
|
355
|
+
}
|
|
356
|
+
const serialized = Authentication.serializeOptions(options)
|
|
357
|
+
const deserialized = Authentication.deserializeOptions(serialized)
|
|
358
|
+
|
|
359
|
+
expect(deserialized.publicKey!.extensions).toMatchInlineSnapshot(`
|
|
360
|
+
{
|
|
361
|
+
"prf": {},
|
|
362
|
+
}
|
|
363
|
+
`)
|
|
364
|
+
})
|
|
365
|
+
|
|
244
366
|
test('empty publicKey', () => {
|
|
245
367
|
const deserialized = Authentication.deserializeOptions({})
|
|
246
368
|
expect(deserialized).toEqual({})
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { runInNewContext } from 'node:vm'
|
|
1
2
|
import { afterAll, beforeAll, describe, expect, test, vi } from 'vp/test'
|
|
2
3
|
import * as Base64 from '../../core/Base64.js'
|
|
3
4
|
import * as Bytes from '../../core/Bytes.js'
|
|
@@ -329,6 +330,15 @@ describe('getOptions', () => {
|
|
|
329
330
|
`)
|
|
330
331
|
})
|
|
331
332
|
|
|
333
|
+
test('options: timeout', () => {
|
|
334
|
+
const options = Registration.getOptions({
|
|
335
|
+
name: 'Foo',
|
|
336
|
+
timeout: 30_000,
|
|
337
|
+
})
|
|
338
|
+
|
|
339
|
+
expect(options.publicKey?.timeout).toMatchInlineSnapshot(`30000`)
|
|
340
|
+
})
|
|
341
|
+
|
|
332
342
|
test('args: excludeCredentialIds', () => {
|
|
333
343
|
expect(
|
|
334
344
|
Registration.getOptions({
|
|
@@ -594,6 +604,9 @@ describe('serializeOptions', () => {
|
|
|
594
604
|
})
|
|
595
605
|
|
|
596
606
|
test('with extensions (prf)', () => {
|
|
607
|
+
const first = runInNewContext(
|
|
608
|
+
'Uint8Array.from([7, 8, 9]).buffer',
|
|
609
|
+
) as ArrayBuffer
|
|
597
610
|
const options: Types.CredentialCreationOptions = {
|
|
598
611
|
publicKey: {
|
|
599
612
|
challenge: new Uint8Array([1, 2, 3]),
|
|
@@ -607,7 +620,8 @@ describe('serializeOptions', () => {
|
|
|
607
620
|
extensions: {
|
|
608
621
|
prf: {
|
|
609
622
|
eval: {
|
|
610
|
-
first
|
|
623
|
+
first,
|
|
624
|
+
second: new Uint8Array(),
|
|
611
625
|
},
|
|
612
626
|
},
|
|
613
627
|
},
|
|
@@ -615,9 +629,11 @@ describe('serializeOptions', () => {
|
|
|
615
629
|
}
|
|
616
630
|
const serialized = Registration.serializeOptions(options)
|
|
617
631
|
|
|
618
|
-
expect(
|
|
619
|
-
|
|
620
|
-
|
|
632
|
+
expect(first).not.toBeInstanceOf(ArrayBuffer)
|
|
633
|
+
expect(
|
|
634
|
+
serialized.publicKey!.extensions!.prf!.eval!.first,
|
|
635
|
+
).toMatchInlineSnapshot(`"BwgJ"`)
|
|
636
|
+
expect(serialized.publicKey!.extensions!.prf!.eval!.second).toBe('')
|
|
621
637
|
expect(() => JSON.stringify(serialized)).not.toThrow()
|
|
622
638
|
})
|
|
623
639
|
|
|
@@ -674,6 +690,7 @@ describe('deserializeOptions', () => {
|
|
|
674
690
|
prf: {
|
|
675
691
|
eval: {
|
|
676
692
|
first: new Uint8Array([7, 8, 9]),
|
|
693
|
+
second: new Uint8Array(),
|
|
677
694
|
},
|
|
678
695
|
},
|
|
679
696
|
},
|
|
@@ -682,12 +699,15 @@ describe('deserializeOptions', () => {
|
|
|
682
699
|
const serialized = Registration.serializeOptions(options)
|
|
683
700
|
const deserialized = Registration.deserializeOptions(serialized)
|
|
684
701
|
|
|
685
|
-
expect(deserialized.publicKey!.extensions!.prf!.eval
|
|
702
|
+
expect(deserialized.publicKey!.extensions!.prf!.eval!.first).toBeInstanceOf(
|
|
686
703
|
Uint8Array,
|
|
687
704
|
)
|
|
688
|
-
expect(deserialized.publicKey!.extensions!.prf!.eval
|
|
705
|
+
expect(deserialized.publicKey!.extensions!.prf!.eval!.first).toEqual(
|
|
689
706
|
new Uint8Array([7, 8, 9]),
|
|
690
707
|
)
|
|
708
|
+
expect(deserialized.publicKey!.extensions!.prf!.eval!.second).toEqual(
|
|
709
|
+
new Uint8Array(),
|
|
710
|
+
)
|
|
691
711
|
})
|
|
692
712
|
|
|
693
713
|
test('empty publicKey', () => {
|