@gjsify/webcrypto 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/src/index.ts ADDED
@@ -0,0 +1,78 @@
1
+ // W3C WebCrypto API for GJS
2
+ // Reference: refs/deno/ext/crypto/00_crypto.js
3
+ // Copyright (c) 2018-2026 the Deno authors. MIT license.
4
+ // Reimplemented for GJS using @gjsify/crypto primitives.
5
+ //
6
+ // On Node.js (and any environment with native WebCrypto), this module
7
+ // re-exports the native globals for zero overhead.
8
+ // On GJS, it provides a polyfill and registers globals.
9
+
10
+ import { SubtleCrypto } from './subtle.js';
11
+ import { CryptoKey } from './crypto-key.js';
12
+ export type { CryptoKeyPair, KeyUsage, KeyAlgorithm, KeyType } from './crypto-key.js';
13
+
14
+ // Save reference to native crypto BEFORE any overwriting to avoid recursion
15
+ const _nativeCrypto = typeof globalThis.crypto !== 'undefined' ? globalThis.crypto : null;
16
+
17
+ /**
18
+ * Crypto object per the W3C WebCrypto API.
19
+ * Provides getRandomValues(), randomUUID(), and subtle (SubtleCrypto).
20
+ */
21
+ class CryptoPolyfill {
22
+ readonly subtle = new SubtleCrypto();
23
+
24
+ getRandomValues<T extends ArrayBufferView>(array: T): T {
25
+ if (!(array instanceof Int8Array || array instanceof Uint8Array ||
26
+ array instanceof Int16Array || array instanceof Uint16Array ||
27
+ array instanceof Int32Array || array instanceof Uint32Array ||
28
+ array instanceof Uint8ClampedArray || array instanceof BigInt64Array ||
29
+ array instanceof BigUint64Array)) {
30
+ throw new DOMException('The provided value is not of type \'(Int8Array or Int16Array or Int32Array or Uint8Array or Uint8ClampedArray or Uint16Array or Uint32Array or BigInt64Array or BigUint64Array)\'', 'TypeMismatchError');
31
+ }
32
+ if (array.byteLength > 65536) {
33
+ throw new DOMException('The ArrayBufferView\'s byte length exceeds the number of bytes of entropy available via this API (65536)', 'QuotaExceededError');
34
+ }
35
+ const bytes = new Uint8Array(array.buffer as ArrayBuffer, array.byteOffset, array.byteLength);
36
+ // Use saved reference to native crypto (NOT globalThis.crypto which may be this polyfill)
37
+ if (_nativeCrypto && typeof _nativeCrypto.getRandomValues === 'function') {
38
+ _nativeCrypto.getRandomValues(bytes as Uint8Array<ArrayBuffer>);
39
+ } else {
40
+ // Fallback: use GLib or Math.random
41
+ for (let i = 0; i < bytes.length; i++) {
42
+ bytes[i] = Math.floor(Math.random() * 256);
43
+ }
44
+ }
45
+ return array;
46
+ }
47
+
48
+ randomUUID(): `${string}-${string}-${string}-${string}-${string}` {
49
+ if (_nativeCrypto && typeof _nativeCrypto.randomUUID === 'function') {
50
+ return _nativeCrypto.randomUUID();
51
+ }
52
+ // Manual UUID v4 generation
53
+ const bytes = new Uint8Array(16);
54
+ this.getRandomValues(bytes);
55
+ bytes[6] = (bytes[6] & 0x0f) | 0x40; // version 4
56
+ bytes[8] = (bytes[8] & 0x3f) | 0x80; // variant 1
57
+ const hex = Array.from(bytes, b => b.toString(16).padStart(2, '0')).join('');
58
+ return `${hex.slice(0, 8)}-${hex.slice(8, 12)}-${hex.slice(12, 16)}-${hex.slice(16, 20)}-${hex.slice(20)}` as `${string}-${string}-${string}-${string}-${string}`;
59
+ }
60
+ }
61
+
62
+ // Use native if available (Node.js, browser), polyfill otherwise
63
+ const hasNativeSubtle = _nativeCrypto !== null
64
+ && typeof _nativeCrypto.subtle !== 'undefined'
65
+ && typeof _nativeCrypto.subtle.digest === 'function';
66
+
67
+ const cryptoInstance = hasNativeSubtle ? _nativeCrypto! : new CryptoPolyfill();
68
+ const subtleInstance = hasNativeSubtle ? _nativeCrypto!.subtle : new SubtleCrypto();
69
+
70
+ // Register globals on GJS if needed
71
+ if (typeof globalThis.crypto === 'undefined' || typeof globalThis.crypto.subtle === 'undefined') {
72
+ (globalThis as unknown as Record<string, unknown>).crypto = cryptoInstance;
73
+ }
74
+
75
+ export { CryptoKey, SubtleCrypto, CryptoPolyfill as Crypto };
76
+ export { subtleInstance as subtle, cryptoInstance as crypto };
77
+
78
+ export default cryptoInstance;