@oxyhq/core 12.5.0 → 12.5.1
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/dist/cjs/.tsbuildinfo +1 -1
- package/dist/cjs/crypto/polyfill.js +85 -17
- package/dist/esm/.tsbuildinfo +1 -1
- package/dist/esm/crypto/polyfill.js +86 -18
- package/dist/types/.tsbuildinfo +1 -1
- package/dist/types/crypto/polyfill.d.ts +16 -4
- package/package.json +1 -1
- package/src/crypto/__tests__/polyfill.test.ts +109 -0
- package/src/crypto/polyfill.ts +94 -18
|
@@ -5,10 +5,22 @@
|
|
|
5
5
|
* Ensures Buffer and crypto.getRandomValues are available
|
|
6
6
|
* across all platforms (Node.js, Browser, React Native).
|
|
7
7
|
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
8
|
+
* Guard order when installing a `getRandomValues` shim (see bottom of file and
|
|
9
|
+
* {@link cryptoPolyfill}):
|
|
10
|
+
*
|
|
11
|
+
* 1. A REAL `globalThis.crypto.getRandomValues` — used as-is (browser, Node
|
|
12
|
+
* >= 20, modern Hermes). The shim below is only installed when the host is
|
|
13
|
+
* missing it, so this branch is the install-time gate.
|
|
14
|
+
* 2. Node — backed by the built-in `node:crypto` module (`webcrypto`, else
|
|
15
|
+
* `randomFillSync`). This is what a Node runtime WITHOUT a global WebCrypto
|
|
16
|
+
* (Node 18 script entrypoints, some embedded hosts) falls back to.
|
|
17
|
+
* 3. React Native — `expo-crypto.getRandomBytes` (statically imported via the
|
|
18
|
+
* per-platform `platform/crypto` module in `@oxyhq/protocol`).
|
|
19
|
+
*
|
|
20
|
+
* Historically step (2) delegated to `@oxyhq/protocol`'s RN-only
|
|
21
|
+
* `getRandomBytesRN`, which THROWS on Node — so any Node host lacking a global
|
|
22
|
+
* WebCrypto crashed here instead of getting randomness. It is now a proper
|
|
23
|
+
* Node-backed implementation.
|
|
12
24
|
*/
|
|
13
25
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
14
26
|
exports.Buffer = void 0;
|
|
@@ -32,23 +44,79 @@ if (!globalObject.Buffer) {
|
|
|
32
44
|
globalObject.Buffer = buffer_1.Buffer;
|
|
33
45
|
}
|
|
34
46
|
/**
|
|
35
|
-
*
|
|
36
|
-
* `
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
*
|
|
47
|
+
* Lazily-resolved `node:crypto` module, cached after the first attempt.
|
|
48
|
+
* `undefined` = not tried yet; `null` = tried and unavailable (non-Node host).
|
|
49
|
+
*/
|
|
50
|
+
let cachedNodeCrypto;
|
|
51
|
+
/**
|
|
52
|
+
* Synchronously load `node:crypto` on a Node runtime, or `null` elsewhere.
|
|
53
|
+
*
|
|
54
|
+
* Uses a guarded, Node-only `require`. Every runtime that actually reaches this
|
|
55
|
+
* branch has a working CommonJS `require`: `@oxyhq/core` publishes no
|
|
56
|
+
* `"type": "module"`, so Node loads it as CommonJS and the `require` free
|
|
57
|
+
* variable is present. Browsers never reach here (they own `globalThis.crypto`,
|
|
58
|
+
* so this polyfill is never installed) and React Native takes the
|
|
59
|
+
* `getRandomBytesRN` branch — so the `node:crypto` reference is dead code in
|
|
60
|
+
* those bundles, and Expo's Metro resolver shims `node:*` builtins, keeping
|
|
61
|
+
* web/native bundles green.
|
|
62
|
+
*/
|
|
63
|
+
function loadNodeCryptoSync() {
|
|
64
|
+
if (cachedNodeCrypto !== undefined) {
|
|
65
|
+
return cachedNodeCrypto;
|
|
66
|
+
}
|
|
67
|
+
if (typeof require !== 'function') {
|
|
68
|
+
cachedNodeCrypto = null;
|
|
69
|
+
return cachedNodeCrypto;
|
|
70
|
+
}
|
|
71
|
+
try {
|
|
72
|
+
cachedNodeCrypto = require('node:crypto');
|
|
73
|
+
}
|
|
74
|
+
catch {
|
|
75
|
+
// No Node crypto (unexpected on a real Node host) — degrade to the next
|
|
76
|
+
// mechanism rather than crash.
|
|
77
|
+
cachedNodeCrypto = null;
|
|
78
|
+
}
|
|
79
|
+
return cachedNodeCrypto;
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* Fill `array` with cryptographically-secure random bytes from `node:crypto`.
|
|
83
|
+
* Prefers `webcrypto.getRandomValues`; falls back to `randomFillSync`. Returns
|
|
84
|
+
* `false` when Node crypto is unavailable so the caller can try the next
|
|
85
|
+
* mechanism.
|
|
41
86
|
*/
|
|
42
|
-
function
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
87
|
+
function fillFromNodeCrypto(array) {
|
|
88
|
+
const nodeCrypto = loadNodeCryptoSync();
|
|
89
|
+
if (!nodeCrypto) {
|
|
90
|
+
return false;
|
|
91
|
+
}
|
|
92
|
+
const webcrypto = nodeCrypto.webcrypto;
|
|
93
|
+
if (webcrypto && typeof webcrypto.getRandomValues === 'function') {
|
|
94
|
+
try {
|
|
95
|
+
webcrypto.getRandomValues(array);
|
|
96
|
+
return true;
|
|
97
|
+
}
|
|
98
|
+
catch {
|
|
99
|
+
// `webcrypto.getRandomValues` rejects non-integer views (Float*Array,
|
|
100
|
+
// DataView); fall through to `randomFillSync`, which accepts any view.
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
if (typeof nodeCrypto.randomFillSync === 'function') {
|
|
104
|
+
nodeCrypto.randomFillSync(array);
|
|
105
|
+
return true;
|
|
106
|
+
}
|
|
107
|
+
return false;
|
|
48
108
|
}
|
|
49
109
|
const cryptoPolyfill = {
|
|
50
110
|
getRandomValues(array) {
|
|
51
|
-
|
|
111
|
+
// Node: back the CSPRNG with `node:crypto`. This is the path that matters on
|
|
112
|
+
// Node runtimes shipping WITHOUT a global WebCrypto — where delegating to
|
|
113
|
+
// the RN-only expo-crypto stub would throw.
|
|
114
|
+
if ((0, protocol_1.isNodeJS)() && fillFromNodeCrypto(array)) {
|
|
115
|
+
return array;
|
|
116
|
+
}
|
|
117
|
+
// React Native (and any non-Node host without WebCrypto): synchronous
|
|
118
|
+
// expo-crypto via @oxyhq/protocol's RN `platform/crypto` variant.
|
|
119
|
+
const bytes = (0, protocol_1.getRandomBytesRN)(array.byteLength);
|
|
52
120
|
const uint8View = new Uint8Array(array.buffer, array.byteOffset, array.byteLength);
|
|
53
121
|
uint8View.set(bytes);
|
|
54
122
|
return array;
|