@nevermined-io/cli 1.4.0 → 1.4.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.
Files changed (43) hide show
  1. package/dist/base-command.d.ts +11 -1
  2. package/dist/base-command.d.ts.map +1 -1
  3. package/dist/base-command.js +14 -0
  4. package/dist/base-command.js.map +1 -1
  5. package/dist/commands/cards/delegate.d.ts +26 -0
  6. package/dist/commands/cards/delegate.d.ts.map +1 -0
  7. package/dist/commands/cards/delegate.js +87 -0
  8. package/dist/commands/cards/delegate.js.map +1 -0
  9. package/dist/commands/cards/enroll.d.ts +25 -0
  10. package/dist/commands/cards/enroll.d.ts.map +1 -0
  11. package/dist/commands/cards/enroll.js +88 -0
  12. package/dist/commands/cards/enroll.js.map +1 -0
  13. package/dist/commands/cards/setup.d.ts +28 -0
  14. package/dist/commands/cards/setup.d.ts.map +1 -0
  15. package/dist/commands/cards/setup.js +113 -0
  16. package/dist/commands/cards/setup.js.map +1 -0
  17. package/dist/commands/login.js +1 -26
  18. package/dist/commands/login.js.map +1 -1
  19. package/dist/commands/organizations/get-my-memberships.d.ts +15 -0
  20. package/dist/commands/organizations/get-my-memberships.d.ts.map +1 -0
  21. package/dist/commands/organizations/get-my-memberships.js +25 -0
  22. package/dist/commands/organizations/get-my-memberships.js.map +1 -0
  23. package/dist/commands/organizations/get-organization-activity.d.ts +18 -0
  24. package/dist/commands/organizations/get-organization-activity.d.ts.map +1 -0
  25. package/dist/commands/organizations/get-organization-activity.js +32 -0
  26. package/dist/commands/organizations/get-organization-activity.js.map +1 -0
  27. package/dist/generator/command-generator.d.ts.map +1 -1
  28. package/dist/generator/command-generator.js +3 -1
  29. package/dist/generator/command-generator.js.map +1 -1
  30. package/dist/utils/browser.d.ts +14 -0
  31. package/dist/utils/browser.d.ts.map +1 -0
  32. package/dist/utils/browser.js +41 -0
  33. package/dist/utils/browser.js.map +1 -0
  34. package/dist/utils/orgs.d.ts +36 -0
  35. package/dist/utils/orgs.d.ts.map +1 -0
  36. package/dist/utils/orgs.js +65 -0
  37. package/dist/utils/orgs.js.map +1 -0
  38. package/dist/utils/widget-redirect-flow.d.ts +83 -0
  39. package/dist/utils/widget-redirect-flow.d.ts.map +1 -0
  40. package/dist/utils/widget-redirect-flow.js +259 -0
  41. package/dist/utils/widget-redirect-flow.js.map +1 -0
  42. package/oclif.manifest.json +421 -57
  43. package/package.json +1 -1
@@ -0,0 +1,259 @@
1
+ import { createServer } from 'http';
2
+ import { randomBytes, timingSafeEqual } from 'crypto';
3
+ import { openBrowser } from './browser.js';
4
+ const SELF_MINT_FETCH_TIMEOUT_MS = 15_000;
5
+ /**
6
+ * Default timeout for a redirect-mode CLI flow. Mirrors the existing
7
+ * `nvm login` callback timeout — 5 minutes is enough for the user to
8
+ * tab into the browser, complete a card enrolment + delegation, and
9
+ * land back at the CLI.
10
+ */
11
+ const REDIRECT_TIMEOUT_MS = 5 * 60 * 1000;
12
+ /**
13
+ * Constant-time string equality for the CSRF `state` nonce. The state we
14
+ * issue is a 32-char hex string (`randomBytes(16).toString('hex')`), so
15
+ * we ALWAYS allocate fixed 16-byte buffers from `hex` regardless of the
16
+ * caller-supplied value's encoding. Computing buffer length from string
17
+ * length would diverge on non-ASCII input (`a.length` is UTF-16 code
18
+ * units; `Buffer.from(a, 'utf8').length` is byte count), and a crafted
19
+ * non-hex `received` could otherwise throw inside `timingSafeEqual`.
20
+ *
21
+ * Inputs must already have been verified to be 32 hex chars by the
22
+ * caller (or we reject up front).
23
+ */
24
+ function safeEqualHexState(received, expected) {
25
+ if (!/^[0-9a-f]{32}$/i.test(received) || !/^[0-9a-f]{32}$/i.test(expected))
26
+ return false;
27
+ return timingSafeEqual(Buffer.from(received, 'hex'), Buffer.from(expected, 'hex'));
28
+ }
29
+ /**
30
+ * Shared redirect-mode handshake for any CLI command that hands the user
31
+ * off to an `/embed/*` page and waits for a localhost callback.
32
+ *
33
+ * Flow:
34
+ * 1. Bind a one-shot HTTP server on `127.0.0.1:0` (the OS picks a free port).
35
+ * 2. Compute `returnUrl = http://127.0.0.1:<port>/callback` and hand it
36
+ * to `opts.mintSession`. The caller mints a widget session bound to
37
+ * that exact returnUrl (which the backend can validate against the
38
+ * session-specific allow-list at creation time). We use the literal
39
+ * `127.0.0.1` rather than `localhost` because the server binds to
40
+ * `127.0.0.1` and Node 17+ resolves `localhost` to `::1` first on
41
+ * modern hosts — the browser would stall on the IPv6 attempt before
42
+ * falling back to IPv4.
43
+ * 3. Open the browser at `{frontend}/embed/<path>?sessionToken=…&returnUrl=…&state=<rand>`.
44
+ * 4. Resolve when the embed page redirects to `/callback?…&state=<echo>`.
45
+ * `state` is compared in constant time.
46
+ *
47
+ * Rejects on bind failure, mint failure, 5-minute timeout, or
48
+ * state-mismatched callback (the bad request gets a styled error page
49
+ * and the server stays alive — the legitimate callback can still land).
50
+ */
51
+ export async function runWidgetRedirectFlow(opts) {
52
+ const state = randomBytes(16).toString('hex');
53
+ return new Promise((resolve, reject) => {
54
+ let resolved = false;
55
+ let timeout;
56
+ const finalize = (err, value) => {
57
+ if (resolved)
58
+ return;
59
+ resolved = true;
60
+ if (timeout)
61
+ clearTimeout(timeout);
62
+ server.close();
63
+ if (err)
64
+ reject(err);
65
+ else if (value)
66
+ resolve(value);
67
+ };
68
+ const server = createServer((req, res) => {
69
+ const url = new URL(req.url || '/', 'http://localhost');
70
+ if (url.pathname !== '/callback') {
71
+ res.writeHead(404).end('Not found');
72
+ return;
73
+ }
74
+ const receivedState = url.searchParams.get('state');
75
+ if (!receivedState || !safeEqualHexState(receivedState, state)) {
76
+ // INTENTIONALLY do NOT close the server here. The state nonce
77
+ // is 128 bits of randomness, so brute-forcing one bad callback
78
+ // per request is infeasible. Closing on first 400 would let an
79
+ // attacker (or a misconfigured redirect) DoS the legitimate
80
+ // browser callback that's about to arrive. The 5-minute timer
81
+ // is the upper bound on how long we'll wait either way.
82
+ res.writeHead(400, { 'Content-Type': 'text/html' }).end(errorHtml('Callback rejected', 'State mismatch. This callback did not match the request that started the flow — close this tab and re-run the command.'));
83
+ return;
84
+ }
85
+ // Convert URLSearchParams → plain object, dropping the bookkeeping
86
+ // `state` field (the caller doesn't need to re-validate it).
87
+ const query = {};
88
+ for (const [key, value] of url.searchParams.entries()) {
89
+ if (key === 'state')
90
+ continue;
91
+ query[key] = value;
92
+ }
93
+ res.writeHead(200, { 'Content-Type': 'text/html' }).end(successHtml(opts.successPageTitle ?? 'All done', 'You can close this tab and return to your terminal.'));
94
+ finalize(undefined, { state, query });
95
+ });
96
+ timeout = setTimeout(() => {
97
+ finalize(new Error(opts.timeoutMessage ?? 'Browser flow timed out after 5 minutes. Please try again.'));
98
+ }, REDIRECT_TIMEOUT_MS);
99
+ server.on('error', (err) => {
100
+ finalize(new Error(`Failed to start local callback server: ${err.message}`));
101
+ });
102
+ server.listen(0, '127.0.0.1', () => {
103
+ const addr = server.address();
104
+ if (!addr || typeof addr === 'string') {
105
+ finalize(new Error('Failed to obtain local callback port'));
106
+ return;
107
+ }
108
+ // Symmetric with the server bind above (`127.0.0.1` only). Using
109
+ // the `localhost` alias here would cause an IPv6 stall on modern
110
+ // Linux/macOS where Node's `dns.lookup` prefers `::1`. The backend
111
+ // returnUrl allow-list accepts both forms.
112
+ const returnUrl = `http://127.0.0.1:${addr.port}/callback`;
113
+ // Mint the session now that returnUrl is known. The backend's
114
+ // allow-list check at session creation can validate the URL the
115
+ // browser will actually be redirected to.
116
+ void (async () => {
117
+ let sessionToken;
118
+ try {
119
+ const minted = await opts.mintSession({ returnUrl });
120
+ sessionToken = minted.sessionToken;
121
+ }
122
+ catch (mintErr) {
123
+ finalize(mintErr instanceof Error ? mintErr : new Error(String(mintErr)));
124
+ return;
125
+ }
126
+ const browserUrl = buildEmbedUrl({
127
+ frontendUrl: opts.frontendUrl,
128
+ embedPath: opts.embedPath,
129
+ sessionToken,
130
+ returnUrl,
131
+ state,
132
+ extra: opts.extraSearchParams,
133
+ });
134
+ if (opts.noBrowser) {
135
+ opts.log('Open this URL in your browser to continue:');
136
+ opts.log('');
137
+ opts.log(browserUrl);
138
+ opts.log('');
139
+ opts.log('Waiting for completion...');
140
+ }
141
+ else {
142
+ opts.log('Opening browser...');
143
+ openBrowser(browserUrl).catch(() => {
144
+ opts.log('Could not open the browser automatically. Open this URL manually:');
145
+ opts.log('');
146
+ opts.log(browserUrl);
147
+ });
148
+ opts.log('Waiting for completion...');
149
+ }
150
+ })();
151
+ });
152
+ });
153
+ }
154
+ function buildEmbedUrl(opts) {
155
+ const url = new URL(opts.embedPath, opts.frontendUrl);
156
+ url.searchParams.set('sessionToken', opts.sessionToken);
157
+ url.searchParams.set('returnUrl', opts.returnUrl);
158
+ url.searchParams.set('state', opts.state);
159
+ if (opts.extra) {
160
+ for (const [k, v] of Object.entries(opts.extra)) {
161
+ url.searchParams.set(k, v);
162
+ }
163
+ }
164
+ return url.toString();
165
+ }
166
+ function successHtml(title, message) {
167
+ // Plain HTML, no third-party assets, no scripts. The page is shown
168
+ // once and the user closes the tab; keep it self-contained so a
169
+ // captive-portal-style network doesn't break the success state.
170
+ return buildHtmlPage(title, message, '#f8f9fa', '#0f5132', '#d1e7dd');
171
+ }
172
+ function errorHtml(title, message) {
173
+ // Same shell as the success page (so the layout looks consistent if
174
+ // the user sees both back-to-back), but tinted red so a state mismatch
175
+ // or other 4xx response is visually distinct from "we're done".
176
+ return buildHtmlPage(title, message, '#f8f9fa', '#842029', '#f8d7da');
177
+ }
178
+ function buildHtmlPage(title, message, pageBg, fgColor, panelBg) {
179
+ return `<!doctype html>
180
+ <html><head><meta charset="utf-8"><title>${escapeHtml(title)}</title></head>
181
+ <body style="font-family: system-ui, sans-serif; display:flex; align-items:center; justify-content:center; min-height:100vh; margin:0; background:${pageBg};">
182
+ <div style="text-align:center; max-width: 480px; padding: 24px; background:${panelBg}; color:${fgColor}; border-radius:8px;">
183
+ <h2 style="margin: 0 0 12px;">${escapeHtml(title)}</h2>
184
+ <p style="margin: 0;">${escapeHtml(message)}</p>
185
+ </div>
186
+ </body></html>`;
187
+ }
188
+ function escapeHtml(value) {
189
+ return value
190
+ .replace(/&/g, '&amp;')
191
+ .replace(/</g, '&lt;')
192
+ .replace(/>/g, '&gt;')
193
+ .replace(/"/g, '&quot;')
194
+ .replace(/'/g, '&#39;');
195
+ }
196
+ /**
197
+ * Hosts a request to `mintSelfWidgetSession` may be sent over plaintext
198
+ * without warning. Loopback addresses are always safe; every other host
199
+ * must use `https:` because we're about to send the user's NVM API key
200
+ * in the `Authorization` header. The `custom` environment variable
201
+ * (`NVM_BACKEND_URL`) is the only realistic way a user could accidentally
202
+ * point this at a plaintext non-localhost URL.
203
+ */
204
+ const LOOPBACK_HOSTNAMES = new Set([
205
+ 'localhost',
206
+ '127.0.0.1',
207
+ '::1',
208
+ '[::1]',
209
+ ]);
210
+ export async function mintSelfWidgetSession(args) {
211
+ const url = new URL('/api/v1/widgets/session/self', args.backendUrl);
212
+ // Refuse to send the API key over plaintext to a non-loopback host.
213
+ // All four built-in environments are `https://`, so this only bites
214
+ // when a user has set `NVM_BACKEND_URL` to a custom plaintext
215
+ // endpoint — exactly the case where they'd otherwise leak the key
216
+ // without realising.
217
+ if (url.protocol === 'http:' &&
218
+ !LOOPBACK_HOSTNAMES.has(url.hostname.toLowerCase())) {
219
+ throw new Error(`Refusing to send the NVM API key over plaintext to ${url.host}. Set NVM_BACKEND_URL to an https:// endpoint, or use a loopback host (localhost / 127.0.0.1 / [::1]).`);
220
+ }
221
+ // 15s ceiling for the request — without it, an unreachable backend
222
+ // (DNS failure, TLS handshake hang, network partition) leaves the CLI
223
+ // frozen with no output. `AbortSignal.timeout` (Node 17.3+) is the
224
+ // idiomatic replacement for a hand-rolled `AbortController` + setTimeout.
225
+ let response;
226
+ try {
227
+ response = await fetch(url, {
228
+ method: 'POST',
229
+ headers: {
230
+ 'Content-Type': 'application/json',
231
+ Authorization: `Bearer ${args.nvmApiKey}`,
232
+ },
233
+ body: JSON.stringify({
234
+ orgId: args.orgId,
235
+ ...(args.returnUrl ? { returnUrl: args.returnUrl } : {}),
236
+ }),
237
+ signal: AbortSignal.timeout(SELF_MINT_FETCH_TIMEOUT_MS),
238
+ });
239
+ }
240
+ catch (cause) {
241
+ if (cause instanceof Error && (cause.name === 'TimeoutError' || cause.name === 'AbortError')) {
242
+ throw new Error(`Self-mint widget session request timed out after ${SELF_MINT_FETCH_TIMEOUT_MS / 1000}s — check that ${args.backendUrl} is reachable.`);
243
+ }
244
+ throw cause;
245
+ }
246
+ if (!response.ok) {
247
+ const detail = await response
248
+ .json()
249
+ .catch(() => ({ message: response.statusText }));
250
+ const message = detail.message ??
251
+ `Self-mint widget session failed (HTTP ${response.status})`;
252
+ const err = new Error(message);
253
+ err.status = response.status;
254
+ err.apiCode = detail.code;
255
+ throw err;
256
+ }
257
+ return (await response.json());
258
+ }
259
+ //# sourceMappingURL=widget-redirect-flow.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"widget-redirect-flow.js","sourceRoot":"","sources":["../../src/utils/widget-redirect-flow.ts"],"names":[],"mappings":"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"}