@qntx/wallet-native 0.5.2 → 0.7.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/WalletNative.podspec +1 -1
- package/android/build.gradle +3 -24
- package/cpp/host/Passkey.hpp +5 -4
- package/cpp/platform/PasskeyIos.mm +477 -10
- package/dist/index.d.mts +0 -6
- package/dist/index.mjs +3 -6
- package/dist/index.mjs.map +1 -1
- package/kernel/generated/kernel-entry.js +1862 -2351
- package/kernel/generated/kernel.manifest.json +3 -3
- package/package.json +3 -3
package/dist/index.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.mjs","names":[],"sources":["../src/cbor.ts","../src/host.ts","../src/index.ts"],"sourcesContent":["/**\n * CBOR framing for the kernel channel. `ProtocolValue` travels main-side ↔ kernel-side as CBOR; the\n * C++ layer moves bytes only. Decode is deliberately strict: floats, unsafe integers, undefined,\n * tags, non-string map keys, duplicate keys and indefinite-length items are all rejected — the wire\n * format carries exactly one value domain.\n */\nimport { decode, encode } from \"cborg\";\nimport type { DecodeOptions } from \"cborg\";\n\nimport type { ProtocolValue } from \"@qntx/wallet/protocol\";\n\nexport const FRAME_MAX_BYTES: number = 1024 * 1024;\n\nexport type CborErrorCode =\n | \"oversize\"\n | \"truncated\"\n | \"malformed\"\n | \"float\"\n | \"unsafe-int\"\n | \"bigint\"\n | \"undefined\"\n | \"tag\"\n | \"non-string-key\"\n | \"duplicate-key\"\n | \"indefinite\"\n | \"bad-type\";\n\nexport class CborError extends Error {\n readonly code: CborErrorCode;\n constructor(code: CborErrorCode, message: string) {\n super(message);\n this.name = \"CborError\";\n this.code = code;\n }\n}\n\nconst DECODE_OPTIONS: DecodeOptions = {\n strict: true,\n useMaps: false,\n rejectDuplicateMapKeys: true,\n allowUndefined: false,\n allowIndefinite: false,\n allowNaN: false,\n allowInfinity: false,\n allowBigInt: false,\n};\n\n/** Reject non-safe-integer numbers and non-string map keys; cborg flags cover the rest. */\nfunction validate(value: unknown): asserts value is ProtocolValue {\n if (value === null || typeof value === \"boolean\" || typeof value === \"string\") {\n return;\n }\n if (typeof value === \"number\") {\n if (!Number.isInteger(value)) {\n throw new CborError(\"float\", \"cbor frame: non-integer number\");\n }\n if (!Number.isSafeInteger(value)) {\n throw new CborError(\"unsafe-int\", \"cbor frame: integer outside the safe range\");\n }\n return;\n }\n if (value instanceof Uint8Array) {\n return;\n }\n if (Array.isArray(value)) {\n for (const item of value) {\n validate(item);\n }\n return;\n }\n if (typeof value === \"object\") {\n // oxlint-disable-next-line typescript/no-unsafe-type-assertion -- the object came from a CBOR map\n for (const [key, item] of Object.entries(value as Record<string, unknown>)) {\n if (typeof key !== \"string\") {\n throw new CborError(\"non-string-key\", \"cbor frame: non-string map key\");\n }\n validate(item);\n }\n return;\n }\n throw new CborError(\"bad-type\", `cbor frame: unsupported value type ${typeof value}`);\n}\n\n/** Classify a cborg rejection into the frame error taxonomy. */\nfunction classify(error: unknown): CborError {\n if (error instanceof CborError) {\n return error;\n }\n const text = error instanceof Error ? error.message : String(error);\n const table: ReadonlyArray<[RegExp, CborErrorCode]> = [\n [/duplicate key|repeat map key/i, \"duplicate-key\"],\n [/indefinite/i, \"indefinite\"],\n [/undefined/i, \"undefined\"],\n [/bigint|safe integer range/i, \"unsafe-int\"],\n [/tag/i, \"tag\"],\n [/string/i, \"non-string-key\"],\n ];\n for (const [pattern, code] of table) {\n if (pattern.test(text)) {\n return new CborError(code, `cbor frame: ${text}`);\n }\n }\n return new CborError(\"malformed\", `cbor frame: ${text}`);\n}\n\n/** Encode a `ProtocolValue` to a CBOR frame, enforcing the 1 MiB cap. */\nexport function encodeFrame(value: ProtocolValue): ArrayBuffer {\n validate(value);\n const bytes = encode(value);\n if (bytes.byteLength > FRAME_MAX_BYTES) {\n throw new CborError(\"oversize\", `cbor frame: ${bytes.byteLength} bytes exceeds the 1 MiB cap`);\n }\n return bytes.buffer.slice(bytes.byteOffset, bytes.byteOffset + bytes.byteLength);\n}\n\n/** Decode a CBOR frame back to a `ProtocolValue`, enforcing the 1 MiB cap and strictness. */\nexport function decodeFrame(frame: ArrayBuffer | Uint8Array): ProtocolValue {\n const bytes = frame instanceof Uint8Array ? frame : new Uint8Array(frame);\n if (bytes.byteLength > FRAME_MAX_BYTES) {\n throw new CborError(\"oversize\", `cbor frame: ${bytes.byteLength} bytes exceeds the 1 MiB cap`);\n }\n if (bytes.byteLength === 0) {\n throw new CborError(\"truncated\", \"cbor frame: empty frame\");\n }\n try {\n const value: unknown = decode(bytes, DECODE_OPTIONS);\n validate(value);\n return value;\n } catch (error) {\n throw classify(error);\n }\n}\n","/**\n * `KernelHost` JS wrapper: CBOR frames over a Nitro-host-shaped channel. The host moves bytes only\n * — encode/decode happens here and in the kernel entry — so a malformed inbound frame can never\n * reach the message domain: the port exits `integrity` and the host runtime is destroyed.\n */\nimport type { MainPort, PortExit } from \"@qntx/wallet/host\";\nimport type { ProtocolValue } from \"@qntx/wallet/protocol\";\n\nimport { decodeFrame, encodeFrame } from \"./cbor.ts\";\n\nexport type KernelExitReason = \"locked\" | \"crashed\" | \"integrity\" | \"background\";\n\n/**\n * Structural mirror of the Nitro `KernelHost` spec (W2b registers the real hybrid object; tests\n * drive the same shape over an in-memory frame pipe).\n */\nexport type KernelHostLike = {\n readonly start: (backgroundLockSeconds: number) => void;\n readonly post: (frame: ArrayBuffer) => void;\n readonly onMessage: (cb: (frame: ArrayBuffer) => void) => void;\n readonly onExit: (cb: (reason: KernelExitReason) => void) => void;\n readonly lock: () => void;\n};\n\nexport function spawnFromHost(host: KernelHostLike, backgroundLockSeconds: number): MainPort {\n const exitHandlers = new Set<(reason: PortExit) => void>();\n let exited = false;\n\n const exit = (reason: PortExit): void => {\n if (exited) {\n return;\n }\n exited = true;\n for (const handler of exitHandlers) {\n handler(reason);\n }\n host.lock();\n };\n\n host.onMessage((frame) => {\n let message: ProtocolValue;\n try {\n message = decodeFrame(frame);\n } catch {\n exit(\"crashed\");\n return;\n }\n dispatch(message);\n });\n\n // The platform locked the enclave in the background — report it honestly so\n // the channel takes the lock path, not the crash path.\n host.onExit((reason) => {\n exit(reason === \"background\" ? \"background\" : \"crashed\");\n });\n\n const messageHandlers = new Set<(message: unknown) => void>();\n const dispatch = (message: unknown): void => {\n for (const handler of messageHandlers) {\n handler(message);\n }\n };\n\n host.start(backgroundLockSeconds);\n\n return {\n post: (message, transfer) => {\n const frame = encodeFrame(message);\n host.post(frame);\n // Structured clone would neuter transferred buffers on the web; the main↔kernel\n // contract is the same here — the caller's buffers hold secrets (passwords, PRF\n // output) and are zeroed once their bytes are inside the frame.\n for (const buffer of transfer) {\n new Uint8Array(buffer).fill(0);\n }\n },\n listen: (handler) => {\n messageHandlers.add(handler);\n return () => {\n messageHandlers.delete(handler);\n };\n },\n onExit: (handler) => {\n exitHandlers.add(handler);\n return () => {\n exitHandlers.delete(handler);\n };\n },\n terminate: () => {\n exit(\"crashed\");\n },\n };\n}\n","import { WalletError } from \"@qntx/wallet\";\nimport type { AutoLockPolicy, PasskeyConfig, Wallet } from \"@qntx/wallet\";\nimport type { SetTimer } from \"@qntx/wallet/host\";\n/**\n * `@qntx/wallet-native`: the RN host entry. `createNativeWallet` adapts a `KernelHost` (Nitro\n * hybrid from W2b, or any object with the same shape) to the wallet `connectKernel` entry — the\n * returned `Wallet` is the same type as the web/node host.\n */\nimport { connectKernel } from \"@qntx/wallet/host\";\n\nimport { spawnFromHost } from \"./host.ts\";\nimport type { KernelHostLike } from \"./host.ts\";\nimport type { KernelHost } from \"./specs/kernel-host.nitro.ts\";\n\nexport type NativeWalletOptions = {\n readonly passkey: PasskeyConfig;\n readonly autoLock: AutoLockPolicy;\n /**\n * The Nitro `KernelHost` hybrid object (or a like-shaped fake for tests). Defaults to\n * `NitroModules.createHybridObject(\"KernelHost\")` — the only Nitro-registered object.\n */\n readonly host?: KernelHostLike;\n};\n\nconst setTimer: SetTimer = (delayMs, fn) => {\n const id = setTimeout(fn, delayMs);\n return () => {\n clearTimeout(id);\n };\n};\n\nasync function defaultHost(): Promise<KernelHostLike> {\n const { NitroModules } = await import(\"react-native-nitro-modules\");\n return NitroModules.createHybridObject<KernelHost>(\"KernelHost\");\n}\n\nexport async function createNativeWallet(options: NativeWalletOptions): Promise<Wallet> {\n const { autoLock } = options;\n const host = options.host ?? (await defaultHost());\n if (autoLock.platform !== \"native\") {\n throw new WalletError(\n \"invalid-input\",\n \"createNativeWallet accepts only the native autoLock policy\",\n );\n }\n // The native host owns the auto-lock signal: the platform layer calls host.lock() on\n // background expiry — the kernel never sees a presence source here.\n return connectKernel({\n spawn: () => spawnFromHost(host, autoLock.backgroundSeconds),\n factors: \"hardware\",\n passkey: options.passkey,\n ceremony: undefined,\n setTimer,\n });\n}\n\nexport { spawnFromHost, type KernelHostLike, type KernelExitReason } from \"./host.ts\";\nexport {\n encodeFrame,\n decodeFrame,\n CborError,\n FRAME_MAX_BYTES,\n type CborErrorCode,\n} from \"./cbor.ts\";\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.mjs","names":[],"sources":["../src/cbor.ts","../src/host.ts","../src/index.ts"],"sourcesContent":["/**\n * CBOR framing for the kernel channel. `ProtocolValue` travels main-side ↔ kernel-side as CBOR; the\n * C++ layer moves bytes only. Decode is deliberately strict: floats, unsafe integers, undefined,\n * tags, non-string map keys, duplicate keys and indefinite-length items are all rejected — the wire\n * format carries exactly one value domain.\n */\nimport { decode, encode } from \"cborg\";\nimport type { DecodeOptions } from \"cborg\";\n\nimport type { ProtocolValue } from \"@qntx/wallet/protocol\";\n\nexport const FRAME_MAX_BYTES: number = 1024 * 1024;\n\nexport type CborErrorCode =\n | \"oversize\"\n | \"truncated\"\n | \"malformed\"\n | \"float\"\n | \"unsafe-int\"\n | \"bigint\"\n | \"undefined\"\n | \"tag\"\n | \"non-string-key\"\n | \"duplicate-key\"\n | \"indefinite\"\n | \"bad-type\";\n\nexport class CborError extends Error {\n readonly code: CborErrorCode;\n constructor(code: CborErrorCode, message: string) {\n super(message);\n this.name = \"CborError\";\n this.code = code;\n }\n}\n\nconst DECODE_OPTIONS: DecodeOptions = {\n strict: true,\n useMaps: false,\n rejectDuplicateMapKeys: true,\n allowUndefined: false,\n allowIndefinite: false,\n allowNaN: false,\n allowInfinity: false,\n allowBigInt: false,\n};\n\n/** Reject non-safe-integer numbers and non-string map keys; cborg flags cover the rest. */\nfunction validate(value: unknown): asserts value is ProtocolValue {\n if (value === null || typeof value === \"boolean\" || typeof value === \"string\") {\n return;\n }\n if (typeof value === \"number\") {\n if (!Number.isInteger(value)) {\n throw new CborError(\"float\", \"cbor frame: non-integer number\");\n }\n if (!Number.isSafeInteger(value)) {\n throw new CborError(\"unsafe-int\", \"cbor frame: integer outside the safe range\");\n }\n return;\n }\n if (value instanceof Uint8Array) {\n return;\n }\n if (Array.isArray(value)) {\n for (const item of value) {\n validate(item);\n }\n return;\n }\n if (typeof value === \"object\") {\n // oxlint-disable-next-line typescript/no-unsafe-type-assertion -- the object came from a CBOR map\n for (const [key, item] of Object.entries(value as Record<string, unknown>)) {\n if (typeof key !== \"string\") {\n throw new CborError(\"non-string-key\", \"cbor frame: non-string map key\");\n }\n validate(item);\n }\n return;\n }\n throw new CborError(\"bad-type\", `cbor frame: unsupported value type ${typeof value}`);\n}\n\n/** Classify a cborg rejection into the frame error taxonomy. */\nfunction classify(error: unknown): CborError {\n if (error instanceof CborError) {\n return error;\n }\n const text = error instanceof Error ? error.message : String(error);\n const table: ReadonlyArray<[RegExp, CborErrorCode]> = [\n [/duplicate key|repeat map key/i, \"duplicate-key\"],\n [/indefinite/i, \"indefinite\"],\n [/undefined/i, \"undefined\"],\n [/bigint|safe integer range/i, \"unsafe-int\"],\n [/tag/i, \"tag\"],\n [/string/i, \"non-string-key\"],\n ];\n for (const [pattern, code] of table) {\n if (pattern.test(text)) {\n return new CborError(code, `cbor frame: ${text}`);\n }\n }\n return new CborError(\"malformed\", `cbor frame: ${text}`);\n}\n\n/** Encode a `ProtocolValue` to a CBOR frame, enforcing the 1 MiB cap. */\nexport function encodeFrame(value: ProtocolValue): ArrayBuffer {\n validate(value);\n const bytes = encode(value);\n if (bytes.byteLength > FRAME_MAX_BYTES) {\n throw new CborError(\"oversize\", `cbor frame: ${bytes.byteLength} bytes exceeds the 1 MiB cap`);\n }\n return bytes.buffer.slice(bytes.byteOffset, bytes.byteOffset + bytes.byteLength);\n}\n\n/** Decode a CBOR frame back to a `ProtocolValue`, enforcing the 1 MiB cap and strictness. */\nexport function decodeFrame(frame: ArrayBuffer | Uint8Array): ProtocolValue {\n const bytes = frame instanceof Uint8Array ? frame : new Uint8Array(frame);\n if (bytes.byteLength > FRAME_MAX_BYTES) {\n throw new CborError(\"oversize\", `cbor frame: ${bytes.byteLength} bytes exceeds the 1 MiB cap`);\n }\n if (bytes.byteLength === 0) {\n throw new CborError(\"truncated\", \"cbor frame: empty frame\");\n }\n try {\n const value: unknown = decode(bytes, DECODE_OPTIONS);\n validate(value);\n return value;\n } catch (error) {\n throw classify(error);\n }\n}\n","/**\n * `KernelHost` JS wrapper: CBOR frames over a Nitro-host-shaped channel. The host moves bytes only\n * — encode/decode happens here and in the kernel entry — so a malformed inbound frame can never\n * reach the message domain: the port exits `integrity` and the host runtime is destroyed.\n */\nimport type { MainPort, PortExit } from \"@qntx/wallet/host\";\nimport type { ProtocolValue } from \"@qntx/wallet/protocol\";\n\nimport { decodeFrame, encodeFrame } from \"./cbor.ts\";\n\nexport type KernelExitReason = \"locked\" | \"crashed\" | \"integrity\" | \"background\";\n\n/**\n * Structural mirror of the Nitro `KernelHost` spec (W2b registers the real hybrid object; tests\n * drive the same shape over an in-memory frame pipe).\n */\nexport type KernelHostLike = {\n readonly start: (backgroundLockSeconds: number) => void;\n readonly post: (frame: ArrayBuffer) => void;\n readonly onMessage: (cb: (frame: ArrayBuffer) => void) => void;\n readonly onExit: (cb: (reason: KernelExitReason) => void) => void;\n readonly lock: () => void;\n};\n\nexport function spawnFromHost(host: KernelHostLike, backgroundLockSeconds: number): MainPort {\n const exitHandlers = new Set<(reason: PortExit) => void>();\n let exited = false;\n\n const exit = (reason: PortExit): void => {\n if (exited) {\n return;\n }\n exited = true;\n for (const handler of exitHandlers) {\n handler(reason);\n }\n host.lock();\n };\n\n host.onMessage((frame) => {\n let message: ProtocolValue;\n try {\n message = decodeFrame(frame);\n } catch {\n exit(\"crashed\");\n return;\n }\n dispatch(message);\n });\n\n // The platform locked the enclave in the background — report it honestly so\n // the channel takes the lock path, not the crash path.\n host.onExit((reason) => {\n exit(reason === \"background\" ? \"background\" : \"crashed\");\n });\n\n const messageHandlers = new Set<(message: unknown) => void>();\n const dispatch = (message: unknown): void => {\n for (const handler of messageHandlers) {\n handler(message);\n }\n };\n\n host.start(backgroundLockSeconds);\n\n return {\n post: (message, transfer) => {\n const frame = encodeFrame(message);\n host.post(frame);\n // Structured clone would neuter transferred buffers on the web; the main↔kernel\n // contract is the same here — the caller's buffers hold secrets (passwords, PRF\n // output) and are zeroed once their bytes are inside the frame.\n for (const buffer of transfer) {\n new Uint8Array(buffer).fill(0);\n }\n },\n listen: (handler) => {\n messageHandlers.add(handler);\n return () => {\n messageHandlers.delete(handler);\n };\n },\n onExit: (handler) => {\n exitHandlers.add(handler);\n return () => {\n exitHandlers.delete(handler);\n };\n },\n terminate: () => {\n exit(\"crashed\");\n },\n };\n}\n","import { WalletError } from \"@qntx/wallet\";\nimport type { AutoLockPolicy, PasskeyConfig, Wallet } from \"@qntx/wallet\";\nimport type { SetTimer } from \"@qntx/wallet/host\";\n/**\n * `@qntx/wallet-native`: the RN host entry. `createNativeWallet` adapts a `KernelHost` (Nitro\n * hybrid from W2b, or any object with the same shape) to the wallet `connectKernel` entry — the\n * returned `Wallet` is the same type as the web/node host.\n */\nimport { connectKernel } from \"@qntx/wallet/host\";\n\nimport { spawnFromHost } from \"./host.ts\";\nimport type { KernelHostLike } from \"./host.ts\";\nimport type { KernelHost } from \"./specs/kernel-host.nitro.ts\";\n\nexport type NativeWalletOptions = {\n readonly passkey: PasskeyConfig;\n readonly autoLock: AutoLockPolicy;\n /**\n * The Nitro `KernelHost` hybrid object (or a like-shaped fake for tests). Defaults to\n * `NitroModules.createHybridObject(\"KernelHost\")` — the only Nitro-registered object.\n */\n readonly host?: KernelHostLike;\n};\n\nconst setTimer: SetTimer = (delayMs, fn) => {\n const id = setTimeout(fn, delayMs);\n return () => {\n clearTimeout(id);\n };\n};\n\nasync function defaultHost(): Promise<KernelHostLike> {\n const { NitroModules } = await import(\"react-native-nitro-modules\");\n return NitroModules.createHybridObject<KernelHost>(\"KernelHost\");\n}\n\nexport async function createNativeWallet(options: NativeWalletOptions): Promise<Wallet> {\n const { autoLock } = options;\n const host = options.host ?? (await defaultHost());\n if (autoLock.platform !== \"native\") {\n throw new WalletError(\n \"invalid-input\",\n \"createNativeWallet accepts only the native autoLock policy\",\n );\n }\n // The native host owns the auto-lock signal: the platform layer calls host.lock() on\n // background expiry — the kernel never sees a presence source here.\n return connectKernel({\n spawn: () => spawnFromHost(host, autoLock.backgroundSeconds),\n factors: \"hardware\",\n passkey: options.passkey,\n ceremony: undefined,\n setTimer,\n });\n}\n\nexport { spawnFromHost, type KernelHostLike, type KernelExitReason } from \"./host.ts\";\nexport {\n encodeFrame,\n decodeFrame,\n CborError,\n FRAME_MAX_BYTES,\n type CborErrorCode,\n} from \"./cbor.ts\";\n"],"mappings":"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"}
|