@polyjose/node 0.0.0-stage → 0.1.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/LICENSE +21 -0
- package/README.md +155 -2
- package/THIRD-PARTY-NOTICES.txt +80 -0
- package/addon-sha256.json +10 -0
- package/backend.d.ts +90 -0
- package/backend.js +378 -0
- package/binding.cjs +869 -0
- package/binding.d.ts +469 -0
- package/facade/api.d.ts +123 -0
- package/facade/api.js +567 -0
- package/facade/backend.d.ts +159 -0
- package/facade/backend.js +19 -0
- package/facade/error-codes.d.ts +4 -0
- package/facade/error-codes.js +22 -0
- package/facade/normalize.d.ts +134 -0
- package/facade/normalize.js +380 -0
- package/facade/types.d.ts +206 -0
- package/facade/types.js +14 -0
- package/index.d.ts +11 -0
- package/index.js +12 -0
- package/package.json +64 -4
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 The polyjose contributors
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -1,3 +1,156 @@
|
|
|
1
|
-
#
|
|
1
|
+
# @polyjose/node
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
polyjose for Node.js: JOSE (JWS, JWE, JWK and JWT; RFC 7515 to 7519) implemented in pure Rust and
|
|
4
|
+
loaded as a Node-API addon. All cryptography comes from the RustCrypto and dalek crates, with no
|
|
5
|
+
OpenSSL. Verify and decrypt always take an explicit algorithm allow-list, and `none` is never
|
|
6
|
+
accepted (RFC 8725).
|
|
7
|
+
|
|
8
|
+
## Install
|
|
9
|
+
|
|
10
|
+
```sh
|
|
11
|
+
npm install @polyjose/node
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
npm also installs the matching prebuilt addon, `@polyjose/node-<platform>`, for macOS (x64,
|
|
15
|
+
arm64), Linux glibc and musl (x64, arm64) and Windows (x64, arm64). Each is an optional
|
|
16
|
+
dependency at exactly this package's version, and npm installs only the one for your platform.
|
|
17
|
+
If you install with `--omit=optional`, no addon is installed and the import throws.
|
|
18
|
+
|
|
19
|
+
### Linux glibc floor
|
|
20
|
+
|
|
21
|
+
The Linux glibc addons (`linux-x64-gnu`, `linux-arm64-gnu`) need **glibc 2.28 or later**. That is
|
|
22
|
+
also the floor of the official Node.js 22 and later Linux builds, so any glibc system that runs
|
|
23
|
+
official Node 22 can load the addon. They are built in the `manylinux_2_28` images (glibc 2.28),
|
|
24
|
+
and the build fails if an addon needs a newer glibc symbol version.
|
|
25
|
+
|
|
26
|
+
| Distribution | glibc |
|
|
27
|
+
|---|---|
|
|
28
|
+
| RHEL, AlmaLinux, Rocky Linux 8 | 2.28 |
|
|
29
|
+
| Debian 11 | 2.31 |
|
|
30
|
+
| Ubuntu 20.04 | 2.31 |
|
|
31
|
+
| RHEL, AlmaLinux, Rocky Linux 9 | 2.34 |
|
|
32
|
+
| Amazon Linux 2023, AWS Lambda `nodejs22.x` and `nodejs24.x` | 2.34 |
|
|
33
|
+
| Ubuntu 22.04 | 2.35 |
|
|
34
|
+
| Debian 12 | 2.36 |
|
|
35
|
+
| Ubuntu 24.04 | 2.39 |
|
|
36
|
+
|
|
37
|
+
Any later release of these works too. Amazon Linux 2 (glibc 2.26) is not supported: it reached its
|
|
38
|
+
end of life on 2026-06-30, and official Node 22 doesn't run on it either. Alpine and other musl
|
|
39
|
+
systems use the `linux-x64-musl` and `linux-arm64-musl` addons instead.
|
|
40
|
+
|
|
41
|
+
## Module format
|
|
42
|
+
|
|
43
|
+
- The package is **ESM only** and needs **Node.js 22.12 or later**.
|
|
44
|
+
- CommonJS code can still load it with `require("@polyjose/node")`, through Node's `require(esm)`
|
|
45
|
+
(unflagged since 22.12).
|
|
46
|
+
- Every operation returns a Promise. The work runs on the libuv thread pool, so it doesn't block
|
|
47
|
+
the event loop.
|
|
48
|
+
- The API and its TypeScript types are the same as `@polyjose/wasm`, so you can switch between
|
|
49
|
+
the two packages by changing the import.
|
|
50
|
+
|
|
51
|
+
## Documentation
|
|
52
|
+
|
|
53
|
+
Guides and the API reference are at <https://polyjose.dev>. The Node.js guide is at
|
|
54
|
+
<https://polyjose.dev/start/node/>.
|
|
55
|
+
|
|
56
|
+
## Loading the addon
|
|
57
|
+
|
|
58
|
+
The package loads **only the polyjose addon whose SHA-256 it was built with**. Otherwise the
|
|
59
|
+
import throws an `Error` with `code` `ERR_POLYJOSE_ADDON_REFUSED`, and nothing it refused has run.
|
|
60
|
+
|
|
61
|
+
- **The hash pin.** The package ships `addon-sha256.json`: the SHA-256 of each platform's addon,
|
|
62
|
+
generated when the package is built. Before anything loads, the package picks the one addon file
|
|
63
|
+
for your platform, the same one the generated napi-rs loader (`binding.cjs`) would pick:
|
|
64
|
+
1. the file named by `NAPI_RS_NATIVE_LIBRARY_PATH`, if set (see below);
|
|
65
|
+
2. else a local `polyjose.<platform>.node` next to the loader;
|
|
66
|
+
3. else the platform package `@polyjose/node-<platform>`, found through Node's normal module
|
|
67
|
+
resolution: this package's `node_modules`, then every ancestor `node_modules`, then
|
|
68
|
+
`NODE_PATH`.
|
|
69
|
+
|
|
70
|
+
It hashes that file and refuses it unless the hash is the pinned one. The refusal names the
|
|
71
|
+
platform, both hashes and where the file came from. There is no fallback to another file. So a
|
|
72
|
+
substitute is refused wherever it was planted, a native addon as much as a JavaScript file,
|
|
73
|
+
including when the genuine platform package is missing: after `npm install --omit=optional`, or
|
|
74
|
+
on a platform polyjose doesn't publish. A package without the map, or without an entry for your
|
|
75
|
+
platform, loads nothing.
|
|
76
|
+
- **No swap after the check.** The package writes the bytes it checked to a new private directory
|
|
77
|
+
in `os.tmpdir()` (mode `0700`; on Windows, your own `%TEMP%`), checks the copy again, and has
|
|
78
|
+
the loader load exactly that copy. Then it deletes the copy; the loaded addon stays in memory.
|
|
79
|
+
Windows can't delete a loaded DLL, so there each copy (the size of the addon) stays in the
|
|
80
|
+
temporary directory. The temporary directory must allow loading native code: if yours is
|
|
81
|
+
mounted `noexec`, point `TMPDIR` (`TEMP` on Windows) at one that does.
|
|
82
|
+
- **Every candidate is native.** Before that, everything the loader could pick must be a native
|
|
83
|
+
`.node` file. If any candidate resolves to something else, such as a JavaScript
|
|
84
|
+
`@polyjose/node-<platform>` in a parent folder or on `NODE_PATH`, the import throws before that
|
|
85
|
+
file runs.
|
|
86
|
+
- **After loading,** the result must be exactly the checked copy, not wrapped by any JavaScript,
|
|
87
|
+
and its own `version()` must be this package's version. An addon from another polyjose release
|
|
88
|
+
is refused, whatever `NAPI_RS_ENFORCE_VERSION_CHECK` says.
|
|
89
|
+
- polyjose **never publishes a `wasm32-wasi` package**. The napi-rs loader still has a WASI
|
|
90
|
+
fallback, tried when the native load fails: `./polyjose.wasi.cjs`, then
|
|
91
|
+
`@polyjose/node-wasm32-wasi`. The package never reaches it. If either WASI file or package can be
|
|
92
|
+
found from the loader's directory, the import throws before anything is loaded. If loading the
|
|
93
|
+
checked copy fails, the import throws "Cannot find native binding". For WebAssembly, use
|
|
94
|
+
`@polyjose/wasm`.
|
|
95
|
+
|
|
96
|
+
These checks keep the package from *choosing* a substitute. They can't protect against code that
|
|
97
|
+
already runs in your process, which can change anything.
|
|
98
|
+
|
|
99
|
+
### Environment variables
|
|
100
|
+
|
|
101
|
+
| Variable | Effect |
|
|
102
|
+
|---|---|
|
|
103
|
+
| `NAPI_RS_NATIVE_LIBRARY_PATH` | Loads the addon from this path instead of the installed one, **only if its SHA-256 is the pinned one** for your platform (see below). |
|
|
104
|
+
| `NAPI_RS_FORCE_WASI` | **Refused.** If it is set, whatever the value (even `false` or empty), the import throws. |
|
|
105
|
+
| `NAPI_RS_WASI_FLAVOR` | **Refused**, like `NAPI_RS_FORCE_WASI`. |
|
|
106
|
+
| `NAPI_RS_ENFORCE_VERSION_CHECK` | Read by the generated loader only. The package checks the hash and the version anyway (see above). |
|
|
107
|
+
|
|
108
|
+
**`NAPI_RS_NATIVE_LIBRARY_PATH` is held to the same pin.** It names the file the package checks, so
|
|
109
|
+
it can only relocate polyjose's own addon, for example out of an archive or a bundle. A JavaScript
|
|
110
|
+
file there is refused before it runs; any other native library is refused by its hash. The package
|
|
111
|
+
sets the variable to its private copy while the loader runs and restores your value right after.
|
|
112
|
+
|
|
113
|
+
### A panic in the addon aborts the process
|
|
114
|
+
|
|
115
|
+
If the Rust code ever panics, Node.js **aborts the whole process** (SIGABRT). The Promise isn't
|
|
116
|
+
rejected, and no `catch` or `process.on("uncaughtException")` handler runs. This fails closed:
|
|
117
|
+
no partial result is returned, and no memory is corrupted. Today we know of no input that causes a
|
|
118
|
+
panic; the core forbids `panic!`, `unwrap` and `expect`. A server that must survive a panic should
|
|
119
|
+
run polyjose in a worker process it can restart. Turning panics into rejected Promises is planned.
|
|
120
|
+
|
|
121
|
+
### Side effects of loading
|
|
122
|
+
|
|
123
|
+
- **Linux:** to tell musl from glibc, the package reads `/usr/bin/ldd`, as the generated loader
|
|
124
|
+
would. If that fails, it calls `process.report.getReport()`, and before that it sets
|
|
125
|
+
`process.report.excludeNetwork = true` for the whole process. If there is no report either, the
|
|
126
|
+
import throws. (The loader's last resort, `ldd --version` in a child process, is never run.)
|
|
127
|
+
- **Windows x64:** an embedder that runs Node as a shared library (`node_target_type` is
|
|
128
|
+
`shared_library`), or a Node whose `shlib_suffix` is `dll.a`, maps to the `win32-x64-gnu`
|
|
129
|
+
platform, as in the loader. polyjose doesn't publish that addon, so those hosts can't load the
|
|
130
|
+
package.
|
|
131
|
+
- **Temporary directory:** each import that loads the addon creates one directory in
|
|
132
|
+
`os.tmpdir()` (see "No swap after the check").
|
|
133
|
+
- **`__napiBindingTarget`:** the loaded addon has an extra property, `__napiBindingTarget`
|
|
134
|
+
(`"native"`), set by the loader. The package's own API doesn't export it.
|
|
135
|
+
|
|
136
|
+
## Secrets in results
|
|
137
|
+
|
|
138
|
+
Results are plain objects, and their byte fields are plain `Uint8Array`s. So **printing a result
|
|
139
|
+
prints its secret bytes**: `console.log`, `util.inspect`, `JSON.stringify` and error reporters
|
|
140
|
+
show every byte. (The Kotlin and Swift bindings redact these fields when printed; JavaScript keeps
|
|
141
|
+
plain data instead, ADR 0065.)
|
|
142
|
+
|
|
143
|
+
- Never log a `JwsVerified` or `JweDecrypted` result.
|
|
144
|
+
- Never log the options and records that carry a secret: `JwsVerifyOptions` (`detachedPayload`),
|
|
145
|
+
`JweEncryptOptions` (`aad`), `JwsSigner` and `JweRecipient` (`key`). Never log a private JWK.
|
|
146
|
+
- The seven secret fields are `JwsSigner.key`, `JweRecipient.key`, `JwsVerified.payload`,
|
|
147
|
+
`JweDecrypted.plaintext`, `JweDecrypted.aad`, `JweEncryptOptions.aad` and
|
|
148
|
+
`JwsVerifyOptions.detachedPayload`.
|
|
149
|
+
- When you are done with a returned `Uint8Array`, wipe it with `fill(0)`. JavaScript strings, such
|
|
150
|
+
as a JWK's text, can't be wiped.
|
|
151
|
+
|
|
152
|
+
## License
|
|
153
|
+
|
|
154
|
+
MIT; see `LICENSE`. `THIRD-PARTY-NOTICES.txt` lists the third-party code this package contains.
|
|
155
|
+
Each platform package carries its own `THIRD-PARTY-NOTICES.txt` for the Rust crates compiled into
|
|
156
|
+
its addon.
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
THIRD-PARTY NOTICES
|
|
2
|
+
|
|
3
|
+
Artifact: @polyjose/node 0.1.1
|
|
4
|
+
|
|
5
|
+
This package is polyjose's JavaScript layer for Node.js: the shared facade (facade/), the
|
|
6
|
+
package entry (index.js, backend.js), their TypeScript declarations, and the Node-API loader
|
|
7
|
+
(binding.cjs, binding.d.ts). It contains no native code. The facade and the entry are
|
|
8
|
+
polyjose's own code. binding.cjs and binding.d.ts are generated by @napi-rs/cli 3.10.12
|
|
9
|
+
from its loader template; its license is reproduced below.
|
|
10
|
+
|
|
11
|
+
The native addon, and the Rust crates compiled into it, ship in one platform package per
|
|
12
|
+
target, each with its own THIRD-PARTY-NOTICES.txt:
|
|
13
|
+
@polyjose/node-darwin-arm64
|
|
14
|
+
@polyjose/node-darwin-x64
|
|
15
|
+
@polyjose/node-linux-arm64-gnu
|
|
16
|
+
@polyjose/node-linux-arm64-musl
|
|
17
|
+
@polyjose/node-linux-x64-gnu
|
|
18
|
+
@polyjose/node-linux-x64-musl
|
|
19
|
+
@polyjose/node-win32-arm64-msvc
|
|
20
|
+
@polyjose/node-win32-x64-msvc
|
|
21
|
+
|
|
22
|
+
Generated by bindings/node/scripts/pack-main.sh; do not edit.
|
|
23
|
+
|
|
24
|
+
================================================================================
|
|
25
|
+
polyjose
|
|
26
|
+
================================================================================
|
|
27
|
+
License: MIT
|
|
28
|
+
Repository: https://github.com/bharathkontham/polyjose
|
|
29
|
+
|
|
30
|
+
--- License text: LICENSE ---
|
|
31
|
+
MIT License
|
|
32
|
+
|
|
33
|
+
Copyright (c) 2026 The polyjose contributors
|
|
34
|
+
|
|
35
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
36
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
37
|
+
in the Software without restriction, including without limitation the rights
|
|
38
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
39
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
40
|
+
furnished to do so, subject to the following conditions:
|
|
41
|
+
|
|
42
|
+
The above copyright notice and this permission notice shall be included in all
|
|
43
|
+
copies or substantial portions of the Software.
|
|
44
|
+
|
|
45
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
46
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
47
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
48
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
49
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
50
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
51
|
+
SOFTWARE.
|
|
52
|
+
|
|
53
|
+
================================================================================
|
|
54
|
+
@napi-rs/cli 3.10.12 (generated binding.cjs and binding.d.ts)
|
|
55
|
+
================================================================================
|
|
56
|
+
License: MIT
|
|
57
|
+
Repository: https://github.com/napi-rs/napi-rs
|
|
58
|
+
|
|
59
|
+
--- License text: LICENSE ---
|
|
60
|
+
MIT License
|
|
61
|
+
|
|
62
|
+
Copyright (c) 2020 LongYinan
|
|
63
|
+
|
|
64
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
65
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
66
|
+
in the Software without restriction, including without limitation the rights
|
|
67
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
68
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
69
|
+
furnished to do so, subject to the following conditions:
|
|
70
|
+
|
|
71
|
+
The above copyright notice and this permission notice shall be included in all
|
|
72
|
+
copies or substantial portions of the Software.
|
|
73
|
+
|
|
74
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
75
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
76
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
77
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
78
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
79
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
80
|
+
SOFTWARE.
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
{
|
|
2
|
+
"darwin-arm64": "eb38505b0e82c9c6b0000422bc4818e82dc71aa3deaf9eb86e28b1ccfecc72b6",
|
|
3
|
+
"darwin-x64": "237d8fe44770833f96a8d2ae5b2c41122d939d6ce4f1dfe8e8801ba3f7d064d1",
|
|
4
|
+
"linux-arm64-gnu": "115fd95fce72f00ec5e0029abf44205068f9c4097ed52fd9d6a1618eaaa61ef5",
|
|
5
|
+
"linux-arm64-musl": "de73ab1a2f5f61d9917e043aac756a2ca54021a788a994145d6e5e0f0211ac86",
|
|
6
|
+
"linux-x64-gnu": "a13b6b39e8661230844fa43d2b8baa9396e55c2a7ccfb6917cb56bc033083aef",
|
|
7
|
+
"linux-x64-musl": "1a114b20c79f6e5b974c42f01a2bc1f1cd2a9542fa98b05af5720c22f9544732",
|
|
8
|
+
"win32-arm64-msvc": "2d1fa65e5b8b45cf2f9bc04e0a33063af9d6eb374fdea0cca5bd74bb072bd2aa",
|
|
9
|
+
"win32-x64-msvc": "f69ec67864cbb3e898c36d8f0aae2643cf2c37f533320fb9d095cc7db6c5a3f2"
|
|
10
|
+
}
|
package/backend.d.ts
ADDED
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The napi-rs backend of `@polyjose/node` (ADR 0031 §1-§2, `bindings/js/BACKEND.md`).
|
|
3
|
+
*
|
|
4
|
+
* The generated loader `binding.cjs` (`napi build --platform --js binding.cjs`) already is the
|
|
5
|
+
* backend contract: one function per ADR 0030 §4 operation, camelCase, in the ADR's argument
|
|
6
|
+
* order, rejecting with an `Error` whose `code` is one of `errorCodes()` (ADR 0030 §5). So this
|
|
7
|
+
* module only loads it, checks what it loaded and gives it the facade's `Backend` type; it adds no
|
|
8
|
+
* JOSE logic and renames nothing (ADR 0030 §1: loading and integrity checks are entry idiom).
|
|
9
|
+
*
|
|
10
|
+
* The loader is CommonJS (it picks the platform's `.node` file at run time), loaded here through
|
|
11
|
+
* `createRequire`, so the package stays ESM-only (ADR 0031 §3). Its types come from the generated
|
|
12
|
+
* `binding.d.ts`.
|
|
13
|
+
*
|
|
14
|
+
* **Fail closed (feature 0007 F02; review-code.md SF-4, review-security.md M1).** The generated
|
|
15
|
+
* loader returns the first module that loads, of any kind:
|
|
16
|
+
* - `NAPI_RS_NATIVE_LIBRARY_PATH`, if set;
|
|
17
|
+
* - then `./polyjose.<platform>.node` next to it;
|
|
18
|
+
* - then `require('@polyjose/node-<platform>')`, which walks every ancestor `node_modules` and
|
|
19
|
+
* `NODE_PATH`;
|
|
20
|
+
* - then a WASI chain: `./polyjose.wasi.cjs`, then `@polyjose/node-wasm32-wasi`. The napi-rs CLI
|
|
21
|
+
* 3.10.12 template always emits it; no `napi build` option omits it, and
|
|
22
|
+
* `NAPI_RS_FORCE_WASI` / `NAPI_RS_WASI_FLAVOR` can select it.
|
|
23
|
+
* It stamps a JavaScript module found that way `"native"` too. So a JS file planted in an
|
|
24
|
+
* ancestor directory or on `NODE_PATH` would become the crypto backend and could "verify" any
|
|
25
|
+
* token. polyjose publishes only native addons (ADR 0031 §2: eight targets, no WASI build;
|
|
26
|
+
* `@polyjose/wasm` is a separate package). The generated file is never edited; this module wraps
|
|
27
|
+
* it and accepts nothing else.
|
|
28
|
+
*
|
|
29
|
+
* **Before loading,** nothing runs unless every module the loader could pick is a native addon:
|
|
30
|
+
* 1. Neither WASI variable is set, whatever its value.
|
|
31
|
+
* 2. No WASI candidate resolves.
|
|
32
|
+
* 3. Every native candidate that resolves is a `.node` file: the override path, and for every
|
|
33
|
+
* platform the loader probes, `./polyjose.<platform>.node` and `@polyjose/node-<platform>`.
|
|
34
|
+
* `@polyjose/node-<platform>/package.json`, which the loader also reads, must be a
|
|
35
|
+
* `package.json`.
|
|
36
|
+
* Resolution is the loader's own: `backend.js` sits next to `binding.cjs`, and `require.resolve`
|
|
37
|
+
* uses the same directory, `node_modules` walk, `NODE_PATH` and symlink handling as the loader's
|
|
38
|
+
* `require`, and runs no code. Node loads a `.node` file only as a native addon, never as
|
|
39
|
+
* JavaScript.
|
|
40
|
+
*
|
|
41
|
+
* **The hash pin (feature 0007 F07; bindings security audit N-M1, the JVM's 0008 F05 bar).** Steps
|
|
42
|
+
* 1-6 make sure the package loads a native addon at this version, but `version()` is what the
|
|
43
|
+
* addon itself says, and a native addon is as easy to plant as a JavaScript file. So before the
|
|
44
|
+
* loader runs, this module also *authenticates* the addon:
|
|
45
|
+
* a. `addon-sha256.json`, next to this file, maps each platform polyjose built this package for
|
|
46
|
+
* to its addon's SHA-256 (FIPS 180-4). It is generated, never hand-edited:
|
|
47
|
+
* `scripts/addon-hashes.sh`, run by `scripts/build.sh` for a local build and by the release
|
|
48
|
+
* assembly of the main package for every published platform. No map, a malformed one, or no
|
|
49
|
+
* entry for this host refuses the load: nothing is trusted by default.
|
|
50
|
+
* b. It picks the one file the loader would load on this host (the platform name of
|
|
51
|
+
* `hostPlatform`, the loader's own): `NAPI_RS_NATIVE_LIBRARY_PATH` when set, else
|
|
52
|
+
* `./polyjose.<platform>.node`, else `@polyjose/node-<platform>`, resolved as above. A
|
|
53
|
+
* caller's override is not refused; it is held to the same pin.
|
|
54
|
+
* c. It reads that file once, hashes those bytes with `node:crypto` and refuses on a mismatch,
|
|
55
|
+
* naming the platform, the source and both hashes. There is no fallback to another candidate.
|
|
56
|
+
* d. It writes the same bytes, with `O_EXCL`, into a new directory from `fs.mkdtempSync` under
|
|
57
|
+
* `os.tmpdir()` (mode 0700 on POSIX; on Windows the per-user `%TEMP%` ACL), under a random
|
|
58
|
+
* leaf name (macOS looks a leaf name up in `DYLD_LIBRARY_PATH` before the path), checks the
|
|
59
|
+
* copy's SHA-256 again, and points `NAPI_RS_NATIVE_LIBRARY_PATH` at it for the one
|
|
60
|
+
* synchronous `require("./binding.cjs")`. The loader's override branch loads exactly that
|
|
61
|
+
* path and probes nothing else, so between the check and `dlopen` only this user (who can
|
|
62
|
+
* already change anything they run) could swap the file; whoever can write the installed
|
|
63
|
+
* file or an ancestor `node_modules` can't. The caller's environment is restored right
|
|
64
|
+
* after, and the copy is deleted (a loaded library stays mapped; Windows can't delete a
|
|
65
|
+
* loaded DLL, so there the copy stays in the temporary directory).
|
|
66
|
+
*
|
|
67
|
+
* **After loading,** what the loader returned must be:
|
|
68
|
+
* 4. the exports of exactly one `.node` module in the CommonJS cache, the private copy of step
|
|
69
|
+
* d, shared only with a loader (`binding.cjs`), so no JavaScript module wraps or re-exports
|
|
70
|
+
* it, and a `binding.cjs` that other code required first (with its own addon) is refused;
|
|
71
|
+
* 5. stamped `__napiBindingTarget === "native"`;
|
|
72
|
+
* 6. at this package's version: `version()` must equal `package.json`'s version. That is the
|
|
73
|
+
* workspace version, which every release keeps in step (feature 0007 T04). So an addon from
|
|
74
|
+
* another release is refused, whatever `NAPI_RS_ENFORCE_VERSION_CHECK` says (SF-4 item 3).
|
|
75
|
+
* Every refusal is an `Error` with `code` `ERR_POLYJOSE_ADDON_REFUSED`. This doesn't defend against
|
|
76
|
+
* code already running in the process, which can patch anything. It makes sure the package never
|
|
77
|
+
* selects a substitute.
|
|
78
|
+
*
|
|
79
|
+
* `test/loader.test.ts` pins the loader's load targets and checks `LOADER_PLATFORMS` against them.
|
|
80
|
+
* So a CLI bump that adds a candidate fails there before this module can miss it.
|
|
81
|
+
*/
|
|
82
|
+
import type { Backend } from "./facade/backend.js";
|
|
83
|
+
/**
|
|
84
|
+
* Every platform name the generated loader probes: the eight polyjose publishes (ADR 0031 §2) and
|
|
85
|
+
* the napi-rs template's others, which are never published. `test/loader.test.ts` checks that this
|
|
86
|
+
* is exactly the loader's set.
|
|
87
|
+
*/
|
|
88
|
+
export declare const LOADER_PLATFORMS: readonly ["darwin-x64", "darwin-arm64", "linux-x64-gnu", "linux-arm64-gnu", "linux-x64-musl", "linux-arm64-musl", "win32-x64-msvc", "win32-arm64-msvc", "android-arm64", "android-arm-eabi", "win32-x64-gnu", "win32-ia32-msvc", "darwin-universal", "freebsd-x64", "freebsd-arm64", "freebsd-ppc64", "linux-arm-musleabihf", "linux-arm-gnueabihf", "linux-loong64-musl", "linux-loong64-gnu", "linux-riscv64-musl", "linux-riscv64-gnu", "linux-ppc64-gnu", "linux-s390x-gnu", "openharmony-arm64", "openharmony-x64", "openharmony-arm"];
|
|
89
|
+
/** The napi loader, typed as the facade's backend. */
|
|
90
|
+
export declare const backend: Backend;
|