herdr-remote-relay 0.3.23 → 0.3.25
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/auth-store.js +14 -1
- package/dist/protocol/herdr-keys.d.ts +8 -0
- package/dist/protocol/herdr-keys.js +34 -0
- package/dist/protocol/index.d.ts +1 -0
- package/dist/protocol/index.js +1 -0
- package/dist/protocol/messages.d.ts +12 -0
- package/dist/server/client-channel.js +1 -0
- package/dist/server/host-channel.js +3 -1
- package/dist/server/sessions.js +1 -0
- package/dist/server/types.d.ts +2 -0
- package/package.json +1 -1
- package/web/dist/assets/index-k4NH1O2l.js +61 -0
- package/web/dist/index.html +1 -1
- package/web/dist/assets/index-Ctj0LjgS.js +0 -61
package/dist/auth-store.js
CHANGED
|
@@ -17,6 +17,19 @@ function nowIso(now = Date.now()) {
|
|
|
17
17
|
function validHostId(value) {
|
|
18
18
|
return typeof value === 'string' && /^[A-Za-z0-9][A-Za-z0-9._:-]{0,127}$/.test(value);
|
|
19
19
|
}
|
|
20
|
+
/**
|
|
21
|
+
* What a person reads off one screen and types on another: six characters,
|
|
22
|
+
* without 0/O or 1/I/L to confuse. Cutting base64 and dropping its `-` and `_`
|
|
23
|
+
* made one code in seven shorter than six, and some too short to pair at all.
|
|
24
|
+
*/
|
|
25
|
+
const PAIR_CODE_ALPHABET = 'ABCDEFGHJKMNPQRSTUVWXYZ23456789';
|
|
26
|
+
const PAIR_CODE_LENGTH = 6;
|
|
27
|
+
function newPairCode() {
|
|
28
|
+
let code = '';
|
|
29
|
+
for (let i = 0; i < PAIR_CODE_LENGTH; i += 1)
|
|
30
|
+
code += PAIR_CODE_ALPHABET[crypto.randomInt(PAIR_CODE_ALPHABET.length)];
|
|
31
|
+
return code;
|
|
32
|
+
}
|
|
20
33
|
class AuthStore {
|
|
21
34
|
stateFile;
|
|
22
35
|
pairingTtlMs;
|
|
@@ -119,7 +132,7 @@ class AuthStore {
|
|
|
119
132
|
this.cleanup(now);
|
|
120
133
|
let code;
|
|
121
134
|
do {
|
|
122
|
-
code =
|
|
135
|
+
code = newPairCode();
|
|
123
136
|
} while ([...this.pairings.values()].some((pairing) => equalHash(pairing.codeHash, hash(code))));
|
|
124
137
|
const expiresAt = now + this.pairingTtlMs;
|
|
125
138
|
this.pairings.set(code, {
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Validates the Herdr prefix keys crossing the wire, or read from a config
|
|
3
|
+
* file, into one canonical list: lowercase, no whitespace, no duplicates, at
|
|
4
|
+
* most `MAX_HERDR_PREFIX_KEYS` short entries. Herdr ignores entries it cannot
|
|
5
|
+
* read and so does this. `undefined` when nothing usable is left, so a host
|
|
6
|
+
* that says nothing and one that says garbage look the same.
|
|
7
|
+
*/
|
|
8
|
+
export declare function sanitizeHerdrPrefixKeys(value: unknown): string[] | undefined;
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
// The keys that put the workstation's Herdr into prefix mode, as a host reads
|
|
2
|
+
// them from Herdr's config and a browser receives them. Browser-safe: no Node
|
|
3
|
+
// APIs, so the web app imports it.
|
|
4
|
+
/** Herdr accepts any number of prefix keys; a window has no use for more than this. */
|
|
5
|
+
const MAX_HERDR_PREFIX_KEYS = 8;
|
|
6
|
+
/** Longest real combo is `ctrl+shift+double_quote`; this leaves room for spelling variants. */
|
|
7
|
+
const MAX_HERDR_PREFIX_KEY_LENGTH = 32;
|
|
8
|
+
/**
|
|
9
|
+
* What the browser can act on: a key combo is printable ASCII (modifiers and
|
|
10
|
+
* key names joined by `+`). Whitespace is removed before this is tested.
|
|
11
|
+
*/
|
|
12
|
+
const PREFIX_KEY = /^[\x21-\x7e]+$/;
|
|
13
|
+
/**
|
|
14
|
+
* Validates the Herdr prefix keys crossing the wire, or read from a config
|
|
15
|
+
* file, into one canonical list: lowercase, no whitespace, no duplicates, at
|
|
16
|
+
* most `MAX_HERDR_PREFIX_KEYS` short entries. Herdr ignores entries it cannot
|
|
17
|
+
* read and so does this. `undefined` when nothing usable is left, so a host
|
|
18
|
+
* that says nothing and one that says garbage look the same.
|
|
19
|
+
*/
|
|
20
|
+
export function sanitizeHerdrPrefixKeys(value) {
|
|
21
|
+
if (!Array.isArray(value))
|
|
22
|
+
return undefined;
|
|
23
|
+
const keys = new Set();
|
|
24
|
+
for (const entry of value) {
|
|
25
|
+
if (keys.size >= MAX_HERDR_PREFIX_KEYS)
|
|
26
|
+
break;
|
|
27
|
+
if (typeof entry !== 'string')
|
|
28
|
+
continue;
|
|
29
|
+
const key = entry.replace(/\s+/g, '').toLowerCase();
|
|
30
|
+
if (key.length <= MAX_HERDR_PREFIX_KEY_LENGTH && PREFIX_KEY.test(key))
|
|
31
|
+
keys.add(key);
|
|
32
|
+
}
|
|
33
|
+
return keys.size > 0 ? [...keys] : undefined;
|
|
34
|
+
}
|
package/dist/protocol/index.d.ts
CHANGED
package/dist/protocol/index.js
CHANGED
|
@@ -94,6 +94,11 @@ export interface ServerReadyMessage {
|
|
|
94
94
|
clientCount?: number;
|
|
95
95
|
/** The workstation's herdr-remote release; null when it is too old to say. */
|
|
96
96
|
hostVersion?: string | null;
|
|
97
|
+
/**
|
|
98
|
+
* The keys that put the workstation's Herdr into prefix mode, lowercase,
|
|
99
|
+
* like `ctrl+b`. Left out when the host is too old to say.
|
|
100
|
+
*/
|
|
101
|
+
herdrPrefixKeys?: string[];
|
|
97
102
|
}
|
|
98
103
|
export interface ServerPairedMessage {
|
|
99
104
|
type: 'paired';
|
|
@@ -133,6 +138,8 @@ export interface ServerSessionRestartedMessage {
|
|
|
133
138
|
terminalFont?: HostTerminalFont | null;
|
|
134
139
|
/** As in `ready`: the host may have come back on another release. */
|
|
135
140
|
hostVersion?: string | null;
|
|
141
|
+
/** As in `ready`: the host may have come back with another Herdr config. */
|
|
142
|
+
herdrPrefixKeys?: string[];
|
|
136
143
|
}
|
|
137
144
|
export interface ServerExitMessage {
|
|
138
145
|
type: 'exit';
|
|
@@ -239,6 +246,11 @@ export interface HostHelloMessage {
|
|
|
239
246
|
version?: string;
|
|
240
247
|
terminalPalette?: HostTerminalPalette | null;
|
|
241
248
|
terminalFont?: HostTerminalFont | null;
|
|
249
|
+
/**
|
|
250
|
+
* The keys `keys.prefix` in the workstation's Herdr config names, as the
|
|
251
|
+
* host read them. The relay sanitizes them; older connectors leave them out.
|
|
252
|
+
*/
|
|
253
|
+
herdrPrefixKeys?: string[];
|
|
242
254
|
capabilities?: string[];
|
|
243
255
|
}
|
|
244
256
|
/** One PTY the host is running, as the relay's status page lists it. */
|
|
@@ -148,6 +148,7 @@ export function handleClientConnection(relay, ws, req) {
|
|
|
148
148
|
terminalFont: host.terminalFont || null,
|
|
149
149
|
clientCount: host.clients.size,
|
|
150
150
|
hostVersion: host.version,
|
|
151
|
+
...(host.herdrPrefixKeys ? { herdrPrefixKeys: host.herdrPrefixKeys } : {}),
|
|
151
152
|
});
|
|
152
153
|
if (host.agentStatus)
|
|
153
154
|
jsonSend(ws, host.agentStatus);
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
// The host side of the relay: a workstation's WebSocket, from its hello and
|
|
2
2
|
// the hand-off from an older connection to every message it sends after.
|
|
3
3
|
import os from 'node:os';
|
|
4
|
-
import { CAPABILITY, PROTOCOL_VERSION, sanitizeTerminalFont, sanitizeTerminalPalette, unpackStreamFrame, } from '../protocol/index.js';
|
|
4
|
+
import { CAPABILITY, PROTOCOL_VERSION, sanitizeHerdrPrefixKeys, sanitizeTerminalFont, sanitizeTerminalPalette, unpackStreamFrame, } from '../protocol/index.js';
|
|
5
5
|
import { forwardFontChunk, forwardFontSubset, settleFontChunk, settleFontSubset, } from './font-proxy.js';
|
|
6
6
|
import { broadcastAgentStatus, broadcastTerminalFont, broadcastUpdateStatus, releaseVersion, } from './host-broadcasts.js';
|
|
7
7
|
import { allowHostHandshake } from './requests.js';
|
|
@@ -10,6 +10,7 @@ import { closeSocket, isOpen, jsonSend, parseJson, randomId, rejectHandshake } f
|
|
|
10
10
|
import { broadcastToClients, notifyHostClientCount, sendClientBinary } from './transport.js';
|
|
11
11
|
function createHostRecord(message, ws, pending, clients = new Set()) {
|
|
12
12
|
const capabilities = Array.isArray(message.capabilities) ? message.capabilities : [];
|
|
13
|
+
const herdrPrefixKeys = sanitizeHerdrPrefixKeys(message.herdrPrefixKeys);
|
|
13
14
|
return {
|
|
14
15
|
id: message.hostId,
|
|
15
16
|
ws,
|
|
@@ -23,6 +24,7 @@ function createHostRecord(message, ws, pending, clients = new Set()) {
|
|
|
23
24
|
terminalPalette: sanitizeTerminalPalette(message.terminalPalette),
|
|
24
25
|
/** Family, size and fetchable files of the workstation's terminal font. */
|
|
25
26
|
terminalFont: sanitizeTerminalFont(message.terminalFont),
|
|
27
|
+
...(herdrPrefixKeys ? { herdrPrefixKeys } : {}),
|
|
26
28
|
/** The latest workstation snapshot is replayed when a browser joins late. */
|
|
27
29
|
agentStatus: null,
|
|
28
30
|
/** Whether the workstation's herdr-remote is behind; replayed the same way. */
|
package/dist/server/sessions.js
CHANGED
|
@@ -72,6 +72,7 @@ export function startSession(relay, host, client, { restarted = false } = {}) {
|
|
|
72
72
|
terminalPalette: host.terminalPalette || null,
|
|
73
73
|
terminalFont: host.terminalFont || null,
|
|
74
74
|
hostVersion: host.version,
|
|
75
|
+
...(host.herdrPrefixKeys ? { herdrPrefixKeys: host.herdrPrefixKeys } : {}),
|
|
75
76
|
});
|
|
76
77
|
}
|
|
77
78
|
}
|
package/dist/server/types.d.ts
CHANGED
|
@@ -31,6 +31,8 @@ export interface RelayHost {
|
|
|
31
31
|
connectedAtMs: number;
|
|
32
32
|
terminalPalette: HostTerminalPalette | null;
|
|
33
33
|
terminalFont: HostTerminalFont | null;
|
|
34
|
+
/** Sanitized `keys.prefix` of the host's Herdr; absent when the host did not say. */
|
|
35
|
+
herdrPrefixKeys?: string[];
|
|
34
36
|
/** The latest agent summary, replayed to a window that joins late. */
|
|
35
37
|
agentStatus: ServerAgentStatusMessage | null;
|
|
36
38
|
/** Whether the workstation's herdr-remote is behind; replayed the same way. */
|