@bhooai/nexus-crypto 2.0.17 → 2.0.19
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/package.json +1 -1
- package/src/license.ts +46 -16
package/package.json
CHANGED
package/src/license.ts
CHANGED
|
@@ -10,23 +10,24 @@
|
|
|
10
10
|
*
|
|
11
11
|
* Flow:
|
|
12
12
|
* - `nexus license add` (browser) stores the token at
|
|
13
|
-
* `<projectRoot>/
|
|
13
|
+
* `<projectRoot>/nexus/licence/licence.jwt`.
|
|
14
14
|
* - Each run calls `ensureLicense()`, which verifies the token (signature via
|
|
15
15
|
* fetched JWKS + online status) and caches the result in memory for the run.
|
|
16
16
|
* - Gated features call `requireLicense()` (sync, reads the in-memory result).
|
|
17
17
|
*
|
|
18
18
|
* Lookup order: `NEXUS_LICENSE_KEY` env (CI/containers) →
|
|
19
|
-
* `<projectRoot>/
|
|
20
|
-
* `
|
|
19
|
+
* `<projectRoot>/nexus/licence/licence.jwt`. The token is a bearer credential, so the
|
|
20
|
+
* `nexus/licence/` folder should be gitignored.
|
|
21
21
|
*/
|
|
22
|
-
import { existsSync, mkdirSync, readFileSync, rmSync, writeFileSync } from 'node:fs';
|
|
23
|
-
import { join } from 'node:path';
|
|
22
|
+
import { existsSync, mkdirSync, readFileSync, readdirSync, rmSync, writeFileSync } from 'node:fs';
|
|
23
|
+
import { join, dirname, resolve } from 'node:path';
|
|
24
24
|
import { createLocalJWKSet, jwtVerify, type JSONWebKeySet } from 'jose';
|
|
25
25
|
|
|
26
26
|
export const LICENSE_ENV_VAR = 'NEXUS_LICENSE_KEY';
|
|
27
27
|
export const LICENSE_SERVER_ENV_VAR = 'NEXUS_LICENSE_SERVER';
|
|
28
|
-
export const LICENSE_FILE_NAME = '
|
|
29
|
-
|
|
28
|
+
export const LICENSE_FILE_NAME = 'licence.jwt';
|
|
29
|
+
/** Per-project license folder: `<projectRoot>/nexus/licence/`. */
|
|
30
|
+
export const LICENSE_DIR_NAME = 'nexus/licence';
|
|
30
31
|
export const LICENSE_ISSUER = 'nexus-bhooai-com';
|
|
31
32
|
|
|
32
33
|
/** Default authority. Override per-project/CI via `NEXUS_LICENSE_SERVER`. */
|
|
@@ -85,15 +86,30 @@ export function resolveLicenseToken(opts: ResolveOptions = {}): ResolvedLicense
|
|
|
85
86
|
const fromEnv = (env[LICENSE_ENV_VAR] ?? '').trim();
|
|
86
87
|
if (fromEnv) return { token: fromEnv, source: 'env' };
|
|
87
88
|
|
|
89
|
+
// Candidate roots: an explicit NEXUS_PROJECT_ROOT (set by `nexus dev`, so app
|
|
90
|
+
// processes whose own projectRoot is a subfolder like `apps/backend` still
|
|
91
|
+
// find the project's `license/`), then the given projectDir and its parents.
|
|
92
|
+
const roots: string[] = [];
|
|
93
|
+
const explicit = (env.NEXUS_PROJECT_ROOT ?? '').trim();
|
|
94
|
+
if (explicit) roots.push(resolve(explicit));
|
|
88
95
|
if (opts.projectDir) {
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
96
|
+
let dir = resolve(opts.projectDir);
|
|
97
|
+
for (let i = 0; i < 4; i++) {
|
|
98
|
+
if (!roots.includes(dir)) roots.push(dir);
|
|
99
|
+
const parent = dirname(dir);
|
|
100
|
+
if (parent === dir) break;
|
|
101
|
+
dir = parent;
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
for (const root of roots) {
|
|
106
|
+
const file = licenseFilePath(root);
|
|
107
|
+
if (!existsSync(file)) continue;
|
|
108
|
+
try {
|
|
109
|
+
const token = readFileSync(file, 'utf8').trim();
|
|
110
|
+
if (token) return { token, source: 'file', file };
|
|
111
|
+
} catch {
|
|
112
|
+
// unreadable → try the next root
|
|
97
113
|
}
|
|
98
114
|
}
|
|
99
115
|
return null;
|
|
@@ -112,13 +128,27 @@ export function storeLicenseToken(projectDir: string, token: string): string {
|
|
|
112
128
|
export function removeLicense(projectDir: string): boolean {
|
|
113
129
|
const dir = join(projectDir, LICENSE_DIR_NAME);
|
|
114
130
|
let removed = false;
|
|
115
|
-
for (const name of [LICENSE_FILE_NAME, '
|
|
131
|
+
for (const name of [LICENSE_FILE_NAME, 'licence.json', 'licence.lic']) {
|
|
116
132
|
const p = join(dir, name);
|
|
117
133
|
if (existsSync(p)) {
|
|
118
134
|
rmSync(p);
|
|
119
135
|
removed = true;
|
|
120
136
|
}
|
|
121
137
|
}
|
|
138
|
+
// Legacy plain-JSON license folder (pre-`nexus/licence`).
|
|
139
|
+
const legacyDir = join(projectDir, 'license');
|
|
140
|
+
for (const name of [LICENSE_FILE_NAME, 'license.jwt', 'license.json', 'license.lic']) {
|
|
141
|
+
const p = join(legacyDir, name);
|
|
142
|
+
if (existsSync(p)) {
|
|
143
|
+
rmSync(p);
|
|
144
|
+
removed = true;
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
try {
|
|
148
|
+
if (existsSync(legacyDir) && readdirSync(legacyDir).length === 0) rmSync(legacyDir);
|
|
149
|
+
} catch {
|
|
150
|
+
// ignore
|
|
151
|
+
}
|
|
122
152
|
const legacy = join(projectDir, '.nexus-license.json');
|
|
123
153
|
if (existsSync(legacy)) {
|
|
124
154
|
rmSync(legacy);
|