openvibers/openvibe.connect Commits
OpenVibe Link: the new name in pages, docs and messages (#69)
Changes
@@@ -23,14 +23,14 @@ Live at **[connect.openvibe.website](https://connect.openvibe.website)**. Part oThe client opens one outgoing connection, so it works behind any router or hotspot, and it reconnects by itself. Itonly ever connects to `localhost` on the port you gave it.--### From a computer with OpenVibe Node (no key)++### From a computer with OpenVibe Link (no key)--A computer you added on [openvibe.bot/machines](https://openvibe.bot/machines) runs OpenVibe Node and has its own++A computer you added on [openvibe.bot/machines](https://openvibe.bot/machines) runs OpenVibe Link and has its ownOpenVibe sign-in. On the share's page, pick it under "Or serve it from one of your computers", then on that computer:```bashopenvibe-node share --share shr_… # serve it now--sudo openvibe-node share add --share shr_… # or keep it up with the Node service++sudo openvibe-node share add --share shr_… # or keep it up with the Link service```There is no key to copy. The computer proves itself twice at every connection: with its Network node token (subject@@@ -164,7 +164,7 @@ With a person's OpenVibe token as a Bearer (or the session on connect.openvibe.w| `POST /api/v1/shares/:id/key` | a new key → `{ share, key }`; the connected computer is disconnected || `GET /api/v1/shares/:id/visits` | who opened it in the last 7 days || `GET /api/v1/shares/:id/requests` `?after=<seq>` | the last 100 requests through it, newest first (the inspector, below) |--| `GET /api/v1/machines` | your computers that can serve a share (OpenVibe Node, from Network) |++| `GET /api/v1/machines` | your computers that can serve a share (OpenVibe Link, from Network) || `PUT /api/v1/shares/:id/node` `{ node: 'nod_…' \| null }` | one of your computers serves it (the key stops working) → `{ share }`; `null` lets it go → `{ share, key }` |A computer, with its Network node token (audience `openvibe.website`) as a Bearer:@@@ -189,7 +189,7 @@ browser ──https──▶ Cloudflare ──▶ nginx ──▶ Connect (5240)- `server/edge/inspector.js` — the share page's Requests list (CON-8 v0): the last 100 requests per share, in memoryonly, with the method, the path (query values shown as "…"), status, time, bytes and the visitor's name. No headers,no bodies; a restart forgets them.--- `server/auth/node-auth.js` — a computer as OpenVibe Node: its node token, and the single-use tunnel tokens (CON-4).++- `server/auth/node-auth.js` — a computer as OpenVibe Link: its node token, and the single-use tunnel tokens (CON-4).- `server/machines.js` — the owner's computers, read from Network with the owner's own token.- `server/hooks.js`, `server/http/hooks.js` — webhook addresses, the sealed kept webhooks, the 1,000-deep queue, thedelivery log and Events' deliveries (CON-15).@@@ -21,7 +21,7 @@"The client: hello with a hashed-at-rest key, streams both ways with backpressure, SSE, WebSocket upgrades as a byte pipe, reconnect, takeover, stop on a bad key","The gate: /grant with OpenVibe sign-in, one-time codes, __Host-ovc bound to the share and its policy version","Durable webhooks (CON-15): an address on each share keeps up to 1,000 webhooks for 72 hours, sealed at rest, replays them in order with x-openvibe-received-at and a delivery log the owner can read",-- "The OpenVibe Node plugin (CON-4): a share served by the owner's paired computer, no key, with `openvibe-node share <port>` and the share in `openvibe-node status`",++ "The OpenVibe Link plugin (CON-4): a share served by the owner's paired computer, no key, with `openvibe-node share <port>` and the share in `openvibe-node status`","What the app gets: localhost Host, X-Forwarded-Host, X-OpenVibe-User/Subject; Set-Cookie Domain removed; no CDN caching","Pages (front door, your shares, a share's page), the API for a person's token, account export/deletion","Checks on PGlite and PostgreSQL, including a share end to end through the real client"@@@ -9,7 +9,7 @@* tunnel.open({ onRes, onData, onEnd, onAbort, onPause, onResume }) → stream id* tunnel.send(obj), tunnel.data(id, buf), tunnel.end(id), tunnel.abort(id, code, message), tunnel.release(id)*-- * A computer bound to a share as OpenVibe Node (CON-4) says hello with two credentials instead of a key:++ * A computer bound to a share as OpenVibe Link (CON-4) says hello with two credentials instead of a key:* { t: 'hello', share: 'shr_…', node_token: <its Network node token>, tunnel: 'ovt_…' } (server/auth/node-auth.js). Its* node token lasts 300 s, so it sends { t: 'reauth', node_token } with a fresh one before then (answered* { t: 'reauthed', until }); a tunnel whose token ran out is closed (4000, the computer reconnects), so a computer@@@ -164,7 +164,7 @@ function createTunnels({ shares, config, log = console, onConnect = null, nodeAulet share;let node = null;if (m.key === undefined && (m.node_token !== undefined || m.tunnel !== undefined)) {-- // A computer as OpenVibe Node (CON-4): its node token and a tunnel token, both checked.++ // A computer as OpenVibe Link (CON-4): its node token and a tunnel token, both checked.if (!nodeAuth) return refuse(ws, 'unavailable', 'Try again in a moment.');const v = await nodeAuth.verify(m.node_token);if (!v.ok) return v.status === 503 ? refuse(ws, 'unavailable', 'Try again in a moment.') : refuse(ws, 'node_invalid', 'OpenVibe did not take this computer\'s node token. Pair it with OpenVibe again.');@@@ -12,7 +12,7 @@* goes while the computer is off, one of the sites on the domain (CON-17), '' or null to clear* DELETE /shares/:id close it (the host answers 410 from then on)* POST /shares/:id/key a new key → { share, key }; the connected computer is disconnected-- * PUT /shares/:id/node { node: 'nod_…' } one of your computers serves it, as OpenVibe Node (CON-4): the key++ * PUT /shares/:id/node { node: 'nod_…' } one of your computers serves it, as OpenVibe Link (CON-4): the key* stops working → { share }; { node: null } lets the computer go → { share, key } (a new key)* GET /machines your computers that can serve a share (Network's list of your machines)* GET /shares/:id/hooks its webhook addresses (CON-15): each kept webhook waits up to 72 hours for the computer@@@ -115,7 +115,7 @@ function createApi(ctx) {if (typeof want !== 'string') return fail(res, req, 422, 'share.invalid_node', 'Name one of your computers by its id (nod_…), or null.');const found = await machines.find(req.principal.token, want);if (!found.ok) return fail(res, req, 503, 'machines.unavailable', 'Your computers could not be read from OpenVibe just now. Try again in a moment.');-- if (!found.machine) return fail(res, req, 404, 'share.unknown_node', 'That is not one of your computers. Pair it with OpenVibe Node first.');++ if (!found.machine) return fail(res, req, 404, 'share.unknown_node', 'That is not one of your computers. Pair it with OpenVibe Link first.');const { share: updated } = await shares.bindNode(owner(req), share.id, found.machine);tunnels.close(share.id, 4003, 'now served by one of your computers');return res.json({ share: shape(updated) });@@@ -1,7 +1,7 @@'use strict';/**-- * /api/v1/node: a person's computer, as OpenVibe Node (CON-4, ADR-057 decision 4). Every call carries the computer's++ * /api/v1/node: a person's computer, as OpenVibe Link (CON-4, ADR-057 decision 4). Every call carries the computer's* Network node token (Authorization: Bearer, subject node:nod_…, audience openvibe.website); nothing here answers to a* person's token or the session.*@@@ -148,7 +148,7 @@ function createPageRoutes(ctx) {}const found = await machines.find(req.viewer.token, want);if (!found.ok) return showShare(req, res, share, { error: 'Your computers could not be read from OpenVibe just now. Try again in a moment.' }, 503);-- if (!found.machine) return showShare(req, res, share, { error: 'That is not one of your computers. Pair it with OpenVibe Node first.' }, 404);++ if (!found.machine) return showShare(req, res, share, { error: 'That is not one of your computers. Pair it with OpenVibe Link first.' }, 404);const { share: updated } = await shares.bindNode(owner(req), share.id, found.machine);tunnels.close(share.id, 4003, 'now served by one of your computers');return res.redirect(303, `/shares/${encodeURIComponent(share.id)}?served=1`);@@@ -149,7 +149,7 @@ function createShares(s, { config }) {status: row.status,policy_version: Number(row.policy_version),key_prefix: row.node_id ? null : row.key_prefix,-- // Served by one of the owner's computers, as OpenVibe Node (CON-4): its Network node principal and name.++ // Served by one of the owner's computers, as OpenVibe Link (CON-4): its Network node principal and name.node: row.node_id ? { id: row.node_id, name: row.node_name || 'A computer' } : null,note: row.note || null,created_at: iso(row.created_at),@@@ -262,7 +262,7 @@ function createShares(s, { config }) {const share = await owned(owner, id);if (share.status !== 'active') throw new ShareError(410, 'share.revoked', 'That share is closed.');const key = newKey();-- // A new key means the key serves it: a computer bound as OpenVibe Node is let go (CON-4).++ // A new key means the key serves it: a computer bound as OpenVibe Link is let go (CON-4).await db.exec('UPDATE shares SET key_prefix = $2, key_hash = $3, node_id = NULL, node_name = NULL, updated_at = now() WHERE id = $1', [share.id, key.slice(0, 10), sha256(key)]);return { share: await get(share.id), key };}@@@ -232,7 +232,7 @@ function requestRow(q) {const MACHINES_URL = 'https://openvibe.bot/machines';/**-- * Which computer serves it (CON-4): one of the owner's computers as OpenVibe Node (no key to copy; removing the computer++ * Which computer serves it (CON-4): one of the owner's computers as OpenVibe Link (no key to copy; removing the computer* on OpenVibe stops it), or the one-file client with the connect key. `machines` is null when Network could not be read.*/function nodeBlock(share, machines, now) {@@@ -240,15 +240,15 @@ function nodeBlock(share, machines, now) {const run = `openvibe-node share --share ${share.id}`;const keep = `sudo openvibe-node share add --share ${share.id}`;return `<section class="cn-node" aria-labelledby="cn-node-h"><h2 id="cn-node-h">Your computer serves it</h2>--<p><b>${esc(share.node.name)}</b> serves this share as OpenVibe Node: no key to copy, and removing the computer on OpenVibe stops it within five minutes.</p>++<p><b>${esc(share.node.name)}</b> serves this share as OpenVibe Link: no key to copy, and removing the computer on OpenVibe stops it within five minutes.</p><ol class="cn-steps"><li><span>On that computer, serve it now:</span><div class="cn-copy"><code id="cn-node-run">${esc(run)}</code><button type="button" class="cn-btn cn-btn-quiet" data-ovk-copy="#cn-node-run" hidden>${kit.icon('copy')} Copy</button></div></li>--<li><span>Or keep it up with the Node service, across restarts:</span><div class="cn-copy"><code id="cn-node-keep">${esc(keep)}</code><button type="button" class="cn-btn cn-btn-quiet" data-ovk-copy="#cn-node-keep" hidden>${kit.icon('copy')} Copy</button></div></li>++<li><span>Or keep it up with the Link service, across restarts:</span><div class="cn-copy"><code id="cn-node-keep">${esc(keep)}</code><button type="button" class="cn-btn cn-btn-quiet" data-ovk-copy="#cn-node-keep" hidden>${kit.icon('copy')} Copy</button></div></li></ol><form method="post" action="/shares/${esc(share.id)}/node"><input type="hidden" name="node" value=""><button class="cn-btn cn-btn-quiet" type="submit">${kit.icon('key')} Use a connect key instead</button><span>The computer stops serving it and a new key is shown once.</span></form></section>`;}-- const intro = '<p>Pick one of your computers that runs OpenVibe Node and it serves this share with its own sign-in: no key to copy, and removing the computer on OpenVibe stops it. The connect key stops working while a computer serves it.</p>';++ const intro = '<p>Pick one of your computers that runs OpenVibe Link and it serves this share with its own sign-in: no key to copy, and removing the computer on OpenVibe stops it. The connect key stops working while a computer serves it.</p>';let list;if (machines === null) list = '<p class="cn-empty">Your computers could not be read from OpenVibe just now. Reload the page in a moment.</p>';else if (!machines.length) list = `<p class="cn-empty">No computers yet. <a href="${esc(MACHINES_URL)}">Add one on openvibe.bot/machines</a>, then come back here.</p>`;@@@ -358,7 +358,7 @@ function sharePage({ share, connected, tunnel = null, visits = [], requests = []const state = closed ? 'Closed' : connected ? 'Connected' : 'Not connected';const stateText = closed ? `Closed ${ago(share.revoked_at, now)}. The address answers "closed" and stays yours.`: connected ? `Connected ${ago(tunnel && tunnel.connectedAt ? new Date(tunnel.connectedAt).toISOString() : share.last_connected_at, now)}${tunnel && tunnel.clientInfo && tunnel.clientInfo.port ? `, serving localhost:${tunnel.clientInfo.port}` : ''}.`-- : share.last_connected_at ? `Last connected ${ago(share.last_connected_at, now)}. ${share.node ? `Start OpenVibe Node on ${share.node.name}` : 'Run ov-connect on your computer'} to bring it back.` : 'Never connected yet. Run the command below on your computer.';++ : share.last_connected_at ? `Last connected ${ago(share.last_connected_at, now)}. ${share.node ? `Start OpenVibe Link on ${share.node.name}` : 'Run ov-connect on your computer'} to bring it back.` : 'Never connected yet. Run the command below on your computer.';const visitRows = visits.length? `<ul class="cn-visits">${visits.map((v) => `<li><b>${v.username ? `@${esc(v.username)}` : 'someone'}</b><span>${esc(v.requests)} ${v.requests === 1 ? 'request' : 'requests'}${v.denied ? `, ${esc(v.denied)} turned away` : ''} · ${esc(ago(v.last_at, now))}</span></li>`).join('')}</ul>`: '<p class="cn-empty">Nobody has opened it in the last 7 days.</p>';@@@ -391,7 +391,7 @@ ${key ? keyBlock(share, key, baseUrl) : ''}<div><dt>Port</dt><dd>localhost:${esc(share.local_port)}</dd></div><div><dt>Requests</dt><dd>${esc(Number(share.requests).toLocaleString('en-US'))}</dd></div><div><dt>Data</dt><dd>${esc(fmtBytes(share.bytes_in))} in · ${esc(fmtBytes(share.bytes_out))} out</dd></div>--${share.node ? `<div><dt>Served by</dt><dd>${esc(share.node.name)} (OpenVibe Node)</dd></div>` : `<div><dt>Key</dt><dd><code>${esc(share.key_prefix)}…</code></dd></div>`}++${share.node ? `<div><dt>Served by</dt><dd>${esc(share.node.name)} (OpenVibe Link)</dd></div>` : `<div><dt>Key</dt><dd><code>${esc(share.key_prefix)}…</code></dd></div>`}<div><dt>Made</dt><dd>${esc(ago(share.created_at, now))}</dd></div>${share.expires_at ? `<div><dt>${closed ? 'Ended' : 'Closes'}</dt><dd><time datetime="${esc(share.expires_at)}">${esc(closed ? ago(share.expires_at, now) : until(share.expires_at, now))}</time></dd></div>` : ''}</dl>@@@ -1,6 +1,6 @@'use strict';/**-- * A share served by one of its owner's computers, as OpenVibe Node (CON-4, ADR-057 decision 4): the owner picks the++ * A share served by one of its owner's computers, as OpenVibe Link (CON-4, ADR-057 decision 4): the owner picks the* computer from their machines on Network; the computer asks for a tunnel token with its node token and says hello with* both; a visitor's request reaches it; it sends a fresh node token before the old one runs out, and a tunnel whose token* ran out is closed. Every refusal: another person's computer, a token for another audience, a spent or late tunnel
@@ -23,14 +23,14 @@ Live at **[connect.openvibe.website](https://connect.openvibe.website)**. Part o
@@ -23,14 +23,14 @@ Live at **[connect.openvibe.website](https://connect.openvibe.website)**. Part o
The client opens one outgoing connection, so it works behind any router or hotspot, and it reconnects by itself. It
The client opens one outgoing connection, so it works behind any router or hotspot, and it reconnects by itself. It
only ever connects to `localhost` on the port you gave it.
only ever connects to `localhost` on the port you gave it.
-### From a computer with OpenVibe Node (no key)
+### From a computer with OpenVibe Link (no key)
-A computer you added on [openvibe.bot/machines](https://openvibe.bot/machines) runs OpenVibe Node and has its own
+A computer you added on [openvibe.bot/machines](https://openvibe.bot/machines) runs OpenVibe Link and has its own
OpenVibe sign-in. On the share's page, pick it under "Or serve it from one of your computers", then on that computer:
OpenVibe sign-in. On the share's page, pick it under "Or serve it from one of your computers", then on that computer:
```bash
```bash
openvibe-node share --share shr_… # serve it now
openvibe-node share --share shr_… # serve it now
-sudo openvibe-node share add --share shr_… # or keep it up with the Node service
+sudo openvibe-node share add --share shr_… # or keep it up with the Link service
```
```
There is no key to copy. The computer proves itself twice at every connection: with its Network node token (subject
There is no key to copy. The computer proves itself twice at every connection: with its Network node token (subject
@@ -164,7 +164,7 @@ With a person's OpenVibe token as a Bearer (or the session on connect.openvibe.w
@@ -164,7 +164,7 @@ With a person's OpenVibe token as a Bearer (or the session on connect.openvibe.w
| `POST /api/v1/shares/:id/key` | a new key → `{ share, key }`; the connected computer is disconnected |
| `POST /api/v1/shares/:id/key` | a new key → `{ share, key }`; the connected computer is disconnected |
| `GET /api/v1/shares/:id/visits` | who opened it in the last 7 days |
| `GET /api/v1/shares/:id/visits` | who opened it in the last 7 days |
| `GET /api/v1/shares/:id/requests` `?after=<seq>` | the last 100 requests through it, newest first (the inspector, below) |
| `GET /api/v1/shares/:id/requests` `?after=<seq>` | the last 100 requests through it, newest first (the inspector, below) |
-| `GET /api/v1/machines` | your computers that can serve a share (OpenVibe Node, from Network) |
+| `GET /api/v1/machines` | your computers that can serve a share (OpenVibe Link, from Network) |
| `PUT /api/v1/shares/:id/node` `{ node: 'nod_…' \| null }` | one of your computers serves it (the key stops working) → `{ share }`; `null` lets it go → `{ share, key }` |
| `PUT /api/v1/shares/:id/node` `{ node: 'nod_…' \| null }` | one of your computers serves it (the key stops working) → `{ share }`; `null` lets it go → `{ share, key }` |
A computer, with its Network node token (audience `openvibe.website`) as a Bearer:
A computer, with its Network node token (audience `openvibe.website`) as a Bearer:
@@ -189,7 +189,7 @@ browser ──https──▶ Cloudflare ──▶ nginx ──▶ Connect (5240)
@@ -189,7 +189,7 @@ browser ──https──▶ Cloudflare ──▶ nginx ──▶ Connect (5240)
- `server/edge/inspector.js` — the share page's Requests list (CON-8 v0): the last 100 requests per share, in memory
- `server/edge/inspector.js` — the share page's Requests list (CON-8 v0): the last 100 requests per share, in memory
only, with the method, the path (query values shown as "…"), status, time, bytes and the visitor's name. No headers,
only, with the method, the path (query values shown as "…"), status, time, bytes and the visitor's name. No headers,
no bodies; a restart forgets them.
no bodies; a restart forgets them.
-- `server/auth/node-auth.js` — a computer as OpenVibe Node: its node token, and the single-use tunnel tokens (CON-4).
+- `server/auth/node-auth.js` — a computer as OpenVibe Link: its node token, and the single-use tunnel tokens (CON-4).
- `server/machines.js` — the owner's computers, read from Network with the owner's own token.
- `server/machines.js` — the owner's computers, read from Network with the owner's own token.
- `server/hooks.js`, `server/http/hooks.js` — webhook addresses, the sealed kept webhooks, the 1,000-deep queue, the
- `server/hooks.js`, `server/http/hooks.js` — webhook addresses, the sealed kept webhooks, the 1,000-deep queue, the
delivery log and Events' deliveries (CON-15).
delivery log and Events' deliveries (CON-15).
@@ -21,7 +21,7 @@
@@ -21,7 +21,7 @@
"The client: hello with a hashed-at-rest key, streams both ways with backpressure, SSE, WebSocket upgrades as a byte pipe, reconnect, takeover, stop on a bad key",
"The client: hello with a hashed-at-rest key, streams both ways with backpressure, SSE, WebSocket upgrades as a byte pipe, reconnect, takeover, stop on a bad key",
"The gate: /grant with OpenVibe sign-in, one-time codes, __Host-ovc bound to the share and its policy version",
"The gate: /grant with OpenVibe sign-in, one-time codes, __Host-ovc bound to the share and its policy version",
"Durable webhooks (CON-15): an address on each share keeps up to 1,000 webhooks for 72 hours, sealed at rest, replays them in order with x-openvibe-received-at and a delivery log the owner can read",
"Durable webhooks (CON-15): an address on each share keeps up to 1,000 webhooks for 72 hours, sealed at rest, replays them in order with x-openvibe-received-at and a delivery log the owner can read",
- "The OpenVibe Node plugin (CON-4): a share served by the owner's paired computer, no key, with `openvibe-node share <port>` and the share in `openvibe-node status`",
+ "The OpenVibe Link plugin (CON-4): a share served by the owner's paired computer, no key, with `openvibe-node share <port>` and the share in `openvibe-node status`",
"What the app gets: localhost Host, X-Forwarded-Host, X-OpenVibe-User/Subject; Set-Cookie Domain removed; no CDN caching",
"What the app gets: localhost Host, X-Forwarded-Host, X-OpenVibe-User/Subject; Set-Cookie Domain removed; no CDN caching",
"Pages (front door, your shares, a share's page), the API for a person's token, account export/deletion",
"Pages (front door, your shares, a share's page), the API for a person's token, account export/deletion",
"Checks on PGlite and PostgreSQL, including a share end to end through the real client"
"Checks on PGlite and PostgreSQL, including a share end to end through the real client"
@@ -9,7 +9,7 @@
@@ -9,7 +9,7 @@
* tunnel.open({ onRes, onData, onEnd, onAbort, onPause, onResume }) → stream id
* tunnel.open({ onRes, onData, onEnd, onAbort, onPause, onResume }) → stream id
* tunnel.send(obj), tunnel.data(id, buf), tunnel.end(id), tunnel.abort(id, code, message), tunnel.release(id)
* tunnel.send(obj), tunnel.data(id, buf), tunnel.end(id), tunnel.abort(id, code, message), tunnel.release(id)
*
*
- * A computer bound to a share as OpenVibe Node (CON-4) says hello with two credentials instead of a key:
+ * A computer bound to a share as OpenVibe Link (CON-4) says hello with two credentials instead of a key:
* { t: 'hello', share: 'shr_…', node_token: <its Network node token>, tunnel: 'ovt_…' } (server/auth/node-auth.js). Its
* { t: 'hello', share: 'shr_…', node_token: <its Network node token>, tunnel: 'ovt_…' } (server/auth/node-auth.js). Its
* node token lasts 300 s, so it sends { t: 'reauth', node_token } with a fresh one before then (answered
* node token lasts 300 s, so it sends { t: 'reauth', node_token } with a fresh one before then (answered
* { t: 'reauthed', until }); a tunnel whose token ran out is closed (4000, the computer reconnects), so a computer
* { t: 'reauthed', until }); a tunnel whose token ran out is closed (4000, the computer reconnects), so a computer
@@ -164,7 +164,7 @@ function createTunnels({ shares, config, log = console, onConnect = null, nodeAu
@@ -164,7 +164,7 @@ function createTunnels({ shares, config, log = console, onConnect = null, nodeAu
let share;
let share;
let node = null;
let node = null;
if (m.key === undefined && (m.node_token !== undefined || m.tunnel !== undefined)) {
if (m.key === undefined && (m.node_token !== undefined || m.tunnel !== undefined)) {
- // A computer as OpenVibe Node (CON-4): its node token and a tunnel token, both checked.
+ // A computer as OpenVibe Link (CON-4): its node token and a tunnel token, both checked.
if (!nodeAuth) return refuse(ws, 'unavailable', 'Try again in a moment.');
if (!nodeAuth) return refuse(ws, 'unavailable', 'Try again in a moment.');
const v = await nodeAuth.verify(m.node_token);
const v = await nodeAuth.verify(m.node_token);
if (!v.ok) return v.status === 503 ? refuse(ws, 'unavailable', 'Try again in a moment.') : refuse(ws, 'node_invalid', 'OpenVibe did not take this computer\'s node token. Pair it with OpenVibe again.');
if (!v.ok) return v.status === 503 ? refuse(ws, 'unavailable', 'Try again in a moment.') : refuse(ws, 'node_invalid', 'OpenVibe did not take this computer\'s node token. Pair it with OpenVibe again.');
@@ -12,7 +12,7 @@
@@ -12,7 +12,7 @@
* goes while the computer is off, one of the sites on the domain (CON-17), '' or null to clear
* goes while the computer is off, one of the sites on the domain (CON-17), '' or null to clear
* DELETE /shares/:id close it (the host answers 410 from then on)
* DELETE /shares/:id close it (the host answers 410 from then on)
* POST /shares/:id/key a new key → { share, key }; the connected computer is disconnected
* POST /shares/:id/key a new key → { share, key }; the connected computer is disconnected
- * PUT /shares/:id/node { node: 'nod_…' } one of your computers serves it, as OpenVibe Node (CON-4): the key
+ * PUT /shares/:id/node { node: 'nod_…' } one of your computers serves it, as OpenVibe Link (CON-4): the key
* stops working → { share }; { node: null } lets the computer go → { share, key } (a new key)
* stops working → { share }; { node: null } lets the computer go → { share, key } (a new key)
* GET /machines your computers that can serve a share (Network's list of your machines)
* GET /machines your computers that can serve a share (Network's list of your machines)
* GET /shares/:id/hooks its webhook addresses (CON-15): each kept webhook waits up to 72 hours for the computer
* GET /shares/:id/hooks its webhook addresses (CON-15): each kept webhook waits up to 72 hours for the computer
@@ -115,7 +115,7 @@ function createApi(ctx) {
@@ -115,7 +115,7 @@ function createApi(ctx) {
if (typeof want !== 'string') return fail(res, req, 422, 'share.invalid_node', 'Name one of your computers by its id (nod_…), or null.');
if (typeof want !== 'string') return fail(res, req, 422, 'share.invalid_node', 'Name one of your computers by its id (nod_…), or null.');
const found = await machines.find(req.principal.token, want);
const found = await machines.find(req.principal.token, want);
if (!found.ok) return fail(res, req, 503, 'machines.unavailable', 'Your computers could not be read from OpenVibe just now. Try again in a moment.');
if (!found.ok) return fail(res, req, 503, 'machines.unavailable', 'Your computers could not be read from OpenVibe just now. Try again in a moment.');
- if (!found.machine) return fail(res, req, 404, 'share.unknown_node', 'That is not one of your computers. Pair it with OpenVibe Node first.');
+ if (!found.machine) return fail(res, req, 404, 'share.unknown_node', 'That is not one of your computers. Pair it with OpenVibe Link first.');
const { share: updated } = await shares.bindNode(owner(req), share.id, found.machine);
const { share: updated } = await shares.bindNode(owner(req), share.id, found.machine);
tunnels.close(share.id, 4003, 'now served by one of your computers');
tunnels.close(share.id, 4003, 'now served by one of your computers');
return res.json({ share: shape(updated) });
return res.json({ share: shape(updated) });
@@ -1,7 +1,7 @@
@@ -1,7 +1,7 @@
'use strict';
'use strict';
/**
/**
- * /api/v1/node: a person's computer, as OpenVibe Node (CON-4, ADR-057 decision 4). Every call carries the computer's
+ * /api/v1/node: a person's computer, as OpenVibe Link (CON-4, ADR-057 decision 4). Every call carries the computer's
* Network node token (Authorization: Bearer, subject node:nod_…, audience openvibe.website); nothing here answers to a
* Network node token (Authorization: Bearer, subject node:nod_…, audience openvibe.website); nothing here answers to a
* person's token or the session.
* person's token or the session.
*
*
@@ -148,7 +148,7 @@ function createPageRoutes(ctx) {
@@ -148,7 +148,7 @@ function createPageRoutes(ctx) {
}
}
const found = await machines.find(req.viewer.token, want);
const found = await machines.find(req.viewer.token, want);
if (!found.ok) return showShare(req, res, share, { error: 'Your computers could not be read from OpenVibe just now. Try again in a moment.' }, 503);
if (!found.ok) return showShare(req, res, share, { error: 'Your computers could not be read from OpenVibe just now. Try again in a moment.' }, 503);
- if (!found.machine) return showShare(req, res, share, { error: 'That is not one of your computers. Pair it with OpenVibe Node first.' }, 404);
+ if (!found.machine) return showShare(req, res, share, { error: 'That is not one of your computers. Pair it with OpenVibe Link first.' }, 404);
const { share: updated } = await shares.bindNode(owner(req), share.id, found.machine);
const { share: updated } = await shares.bindNode(owner(req), share.id, found.machine);
tunnels.close(share.id, 4003, 'now served by one of your computers');
tunnels.close(share.id, 4003, 'now served by one of your computers');
return res.redirect(303, `/shares/${encodeURIComponent(share.id)}?served=1`);
return res.redirect(303, `/shares/${encodeURIComponent(share.id)}?served=1`);
@@ -149,7 +149,7 @@ function createShares(s, { config }) {
@@ -149,7 +149,7 @@ function createShares(s, { config }) {
status: row.status,
status: row.status,
policy_version: Number(row.policy_version),
policy_version: Number(row.policy_version),
key_prefix: row.node_id ? null : row.key_prefix,
key_prefix: row.node_id ? null : row.key_prefix,
- // Served by one of the owner's computers, as OpenVibe Node (CON-4): its Network node principal and name.
+ // Served by one of the owner's computers, as OpenVibe Link (CON-4): its Network node principal and name.
node: row.node_id ? { id: row.node_id, name: row.node_name || 'A computer' } : null,
node: row.node_id ? { id: row.node_id, name: row.node_name || 'A computer' } : null,
note: row.note || null,
note: row.note || null,
created_at: iso(row.created_at),
created_at: iso(row.created_at),
@@ -262,7 +262,7 @@ function createShares(s, { config }) {
@@ -262,7 +262,7 @@ function createShares(s, { config }) {
const share = await owned(owner, id);
const share = await owned(owner, id);
if (share.status !== 'active') throw new ShareError(410, 'share.revoked', 'That share is closed.');
if (share.status !== 'active') throw new ShareError(410, 'share.revoked', 'That share is closed.');
const key = newKey();
const key = newKey();
- // A new key means the key serves it: a computer bound as OpenVibe Node is let go (CON-4).
+ // A new key means the key serves it: a computer bound as OpenVibe Link is let go (CON-4).
await db.exec('UPDATE shares SET key_prefix = $2, key_hash = $3, node_id = NULL, node_name = NULL, updated_at = now() WHERE id = $1', [share.id, key.slice(0, 10), sha256(key)]);
await db.exec('UPDATE shares SET key_prefix = $2, key_hash = $3, node_id = NULL, node_name = NULL, updated_at = now() WHERE id = $1', [share.id, key.slice(0, 10), sha256(key)]);
return { share: await get(share.id), key };
return { share: await get(share.id), key };
}
}
@@ -232,7 +232,7 @@ function requestRow(q) {
@@ -232,7 +232,7 @@ function requestRow(q) {
const MACHINES_URL = 'https://openvibe.bot/machines';
const MACHINES_URL = 'https://openvibe.bot/machines';
/**
/**
- * Which computer serves it (CON-4): one of the owner's computers as OpenVibe Node (no key to copy; removing the computer
+ * Which computer serves it (CON-4): one of the owner's computers as OpenVibe Link (no key to copy; removing the computer
* on OpenVibe stops it), or the one-file client with the connect key. `machines` is null when Network could not be read.
* on OpenVibe stops it), or the one-file client with the connect key. `machines` is null when Network could not be read.
*/
*/
function nodeBlock(share, machines, now) {
function nodeBlock(share, machines, now) {
@@ -240,15 +240,15 @@ function nodeBlock(share, machines, now) {
@@ -240,15 +240,15 @@ function nodeBlock(share, machines, now) {
const run = `openvibe-node share --share ${share.id}`;
const run = `openvibe-node share --share ${share.id}`;
const keep = `sudo openvibe-node share add --share ${share.id}`;
const keep = `sudo openvibe-node share add --share ${share.id}`;
return `<section class="cn-node" aria-labelledby="cn-node-h"><h2 id="cn-node-h">Your computer serves it</h2>
return `<section class="cn-node" aria-labelledby="cn-node-h"><h2 id="cn-node-h">Your computer serves it</h2>
-<p><b>${esc(share.node.name)}</b> serves this share as OpenVibe Node: no key to copy, and removing the computer on OpenVibe stops it within five minutes.</p>
+<p><b>${esc(share.node.name)}</b> serves this share as OpenVibe Link: no key to copy, and removing the computer on OpenVibe stops it within five minutes.</p>
<ol class="cn-steps">
<ol class="cn-steps">
<li><span>On that computer, serve it now:</span><div class="cn-copy"><code id="cn-node-run">${esc(run)}</code><button type="button" class="cn-btn cn-btn-quiet" data-ovk-copy="#cn-node-run" hidden>${kit.icon('copy')} Copy</button></div></li>
<li><span>On that computer, serve it now:</span><div class="cn-copy"><code id="cn-node-run">${esc(run)}</code><button type="button" class="cn-btn cn-btn-quiet" data-ovk-copy="#cn-node-run" hidden>${kit.icon('copy')} Copy</button></div></li>
-<li><span>Or keep it up with the Node service, across restarts:</span><div class="cn-copy"><code id="cn-node-keep">${esc(keep)}</code><button type="button" class="cn-btn cn-btn-quiet" data-ovk-copy="#cn-node-keep" hidden>${kit.icon('copy')} Copy</button></div></li>
+<li><span>Or keep it up with the Link service, across restarts:</span><div class="cn-copy"><code id="cn-node-keep">${esc(keep)}</code><button type="button" class="cn-btn cn-btn-quiet" data-ovk-copy="#cn-node-keep" hidden>${kit.icon('copy')} Copy</button></div></li>
</ol>
</ol>
<form method="post" action="/shares/${esc(share.id)}/node"><input type="hidden" name="node" value=""><button class="cn-btn cn-btn-quiet" type="submit">${kit.icon('key')} Use a connect key instead</button><span>The computer stops serving it and a new key is shown once.</span></form>
<form method="post" action="/shares/${esc(share.id)}/node"><input type="hidden" name="node" value=""><button class="cn-btn cn-btn-quiet" type="submit">${kit.icon('key')} Use a connect key instead</button><span>The computer stops serving it and a new key is shown once.</span></form>
</section>`;
</section>`;
}
}
- const intro = '<p>Pick one of your computers that runs OpenVibe Node and it serves this share with its own sign-in: no key to copy, and removing the computer on OpenVibe stops it. The connect key stops working while a computer serves it.</p>';
+ const intro = '<p>Pick one of your computers that runs OpenVibe Link and it serves this share with its own sign-in: no key to copy, and removing the computer on OpenVibe stops it. The connect key stops working while a computer serves it.</p>';
let list;
let list;
if (machines === null) list = '<p class="cn-empty">Your computers could not be read from OpenVibe just now. Reload the page in a moment.</p>';
if (machines === null) list = '<p class="cn-empty">Your computers could not be read from OpenVibe just now. Reload the page in a moment.</p>';
else if (!machines.length) list = `<p class="cn-empty">No computers yet. <a href="${esc(MACHINES_URL)}">Add one on openvibe.bot/machines</a>, then come back here.</p>`;
else if (!machines.length) list = `<p class="cn-empty">No computers yet. <a href="${esc(MACHINES_URL)}">Add one on openvibe.bot/machines</a>, then come back here.</p>`;
@@ -358,7 +358,7 @@ function sharePage({ share, connected, tunnel = null, visits = [], requests = []
@@ -358,7 +358,7 @@ function sharePage({ share, connected, tunnel = null, visits = [], requests = []
const state = closed ? 'Closed' : connected ? 'Connected' : 'Not connected';
const state = closed ? 'Closed' : connected ? 'Connected' : 'Not connected';
const stateText = closed ? `Closed ${ago(share.revoked_at, now)}. The address answers "closed" and stays yours.`
const stateText = closed ? `Closed ${ago(share.revoked_at, now)}. The address answers "closed" and stays yours.`
: connected ? `Connected ${ago(tunnel && tunnel.connectedAt ? new Date(tunnel.connectedAt).toISOString() : share.last_connected_at, now)}${tunnel && tunnel.clientInfo && tunnel.clientInfo.port ? `, serving localhost:${tunnel.clientInfo.port}` : ''}.`
: connected ? `Connected ${ago(tunnel && tunnel.connectedAt ? new Date(tunnel.connectedAt).toISOString() : share.last_connected_at, now)}${tunnel && tunnel.clientInfo && tunnel.clientInfo.port ? `, serving localhost:${tunnel.clientInfo.port}` : ''}.`
- : share.last_connected_at ? `Last connected ${ago(share.last_connected_at, now)}. ${share.node ? `Start OpenVibe Node on ${share.node.name}` : 'Run ov-connect on your computer'} to bring it back.` : 'Never connected yet. Run the command below on your computer.';
+ : share.last_connected_at ? `Last connected ${ago(share.last_connected_at, now)}. ${share.node ? `Start OpenVibe Link on ${share.node.name}` : 'Run ov-connect on your computer'} to bring it back.` : 'Never connected yet. Run the command below on your computer.';
const visitRows = visits.length
const visitRows = visits.length
? `<ul class="cn-visits">${visits.map((v) => `<li><b>${v.username ? `@${esc(v.username)}` : 'someone'}</b><span>${esc(v.requests)} ${v.requests === 1 ? 'request' : 'requests'}${v.denied ? `, ${esc(v.denied)} turned away` : ''} · ${esc(ago(v.last_at, now))}</span></li>`).join('')}</ul>`
? `<ul class="cn-visits">${visits.map((v) => `<li><b>${v.username ? `@${esc(v.username)}` : 'someone'}</b><span>${esc(v.requests)} ${v.requests === 1 ? 'request' : 'requests'}${v.denied ? `, ${esc(v.denied)} turned away` : ''} · ${esc(ago(v.last_at, now))}</span></li>`).join('')}</ul>`
: '<p class="cn-empty">Nobody has opened it in the last 7 days.</p>';
: '<p class="cn-empty">Nobody has opened it in the last 7 days.</p>';
@@ -391,7 +391,7 @@ ${key ? keyBlock(share, key, baseUrl) : ''}
@@ -391,7 +391,7 @@ ${key ? keyBlock(share, key, baseUrl) : ''}
<div><dt>Port</dt><dd>localhost:${esc(share.local_port)}</dd></div>
<div><dt>Port</dt><dd>localhost:${esc(share.local_port)}</dd></div>
<div><dt>Requests</dt><dd>${esc(Number(share.requests).toLocaleString('en-US'))}</dd></div>
<div><dt>Requests</dt><dd>${esc(Number(share.requests).toLocaleString('en-US'))}</dd></div>
<div><dt>Data</dt><dd>${esc(fmtBytes(share.bytes_in))} in · ${esc(fmtBytes(share.bytes_out))} out</dd></div>
<div><dt>Data</dt><dd>${esc(fmtBytes(share.bytes_in))} in · ${esc(fmtBytes(share.bytes_out))} out</dd></div>
-${share.node ? `<div><dt>Served by</dt><dd>${esc(share.node.name)} (OpenVibe Node)</dd></div>` : `<div><dt>Key</dt><dd><code>${esc(share.key_prefix)}…</code></dd></div>`}
+${share.node ? `<div><dt>Served by</dt><dd>${esc(share.node.name)} (OpenVibe Link)</dd></div>` : `<div><dt>Key</dt><dd><code>${esc(share.key_prefix)}…</code></dd></div>`}
<div><dt>Made</dt><dd>${esc(ago(share.created_at, now))}</dd></div>
<div><dt>Made</dt><dd>${esc(ago(share.created_at, now))}</dd></div>
${share.expires_at ? `<div><dt>${closed ? 'Ended' : 'Closes'}</dt><dd><time datetime="${esc(share.expires_at)}">${esc(closed ? ago(share.expires_at, now) : until(share.expires_at, now))}</time></dd></div>` : ''}
${share.expires_at ? `<div><dt>${closed ? 'Ended' : 'Closes'}</dt><dd><time datetime="${esc(share.expires_at)}">${esc(closed ? ago(share.expires_at, now) : until(share.expires_at, now))}</time></dd></div>` : ''}
</dl>
</dl>
@@ -1,6 +1,6 @@
@@ -1,6 +1,6 @@
'use strict';
'use strict';
/**
/**
- * A share served by one of its owner's computers, as OpenVibe Node (CON-4, ADR-057 decision 4): the owner picks the
+ * A share served by one of its owner's computers, as OpenVibe Link (CON-4, ADR-057 decision 4): the owner picks the
* computer from their machines on Network; the computer asks for a tunnel token with its node token and says hello with
* computer from their machines on Network; the computer asks for a tunnel token with its node token and says hello with
* both; a visitor's request reaches it; it sends a fresh node token before the old one runs out, and a tunnel whose token
* both; a visitor's request reaches it; it sends a fresh node token before the old one runs out, and a tunnel whose token
* ran out is closed. Every refusal: another person's computer, a token for another audience, a spent or late tunnel
* ran out is closed. Every refusal: another person's computer, a token for another audience, a spent or late tunnel