herdr-remote-relay 0.3.18 → 0.3.20
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/protocol/messages.d.ts +23 -2
- package/dist/protocol/messages.js +2 -0
- package/dist/server/client-channel.js +29 -0
- package/dist/server/host-channel.js +2 -0
- package/dist/server/sessions.js +3 -0
- package/dist/server/types.d.ts +5 -1
- package/package.json +1 -1
- package/web/dist/assets/index-C4TsMsWu.js +61 -0
- package/web/dist/assets/index-DOSL54ax.css +32 -0
- package/web/dist/index.html +2 -2
- package/web/dist/assets/index-AFVlGWXS.css +0 -32
- package/web/dist/assets/index-BNlCImyk.js +0 -61
|
@@ -9,8 +9,11 @@ export declare const CAPABILITY: {
|
|
|
9
9
|
readonly idleHeartbeat: "idle_heartbeat";
|
|
10
10
|
/** The host routes output by 16-bit stream index (v2 frames). */
|
|
11
11
|
readonly binaryFrameV2: "binary_frame_v2";
|
|
12
|
+
/** The host can open an elevated PowerShell as a tab of its Windows Herdr. */
|
|
13
|
+
readonly adminTabs: "admin_tabs";
|
|
12
14
|
};
|
|
13
15
|
export type ClientRole = 'controller' | 'viewer';
|
|
16
|
+
export type HostShellProfile = 'posix' | 'cmd' | 'powershell' | 'git-bash';
|
|
14
17
|
export interface ClientHelloMessage {
|
|
15
18
|
type: 'hello';
|
|
16
19
|
protocol: 1;
|
|
@@ -49,6 +52,13 @@ export interface ClientPasteFileMessage {
|
|
|
49
52
|
export interface ClientHerdrStartMessage {
|
|
50
53
|
type: 'herdr_start';
|
|
51
54
|
}
|
|
55
|
+
/**
|
|
56
|
+
* Open an elevated PowerShell as a new tab of the workstation's Herdr. Carries
|
|
57
|
+
* nothing: the host decides what runs, through its own pre-authorized broker.
|
|
58
|
+
*/
|
|
59
|
+
export interface ClientAdminTabOpenMessage {
|
|
60
|
+
type: 'admin_tab_open';
|
|
61
|
+
}
|
|
52
62
|
/** One slice of an announced font file, by the file's hash. */
|
|
53
63
|
export interface ClientHostFontChunkRequestMessage {
|
|
54
64
|
type: 'host_font_chunk_request';
|
|
@@ -66,13 +76,17 @@ export interface ClientHostFontSubsetRequestMessage {
|
|
|
66
76
|
export interface ClientHostFontRefreshMessage {
|
|
67
77
|
type: 'host_font_refresh';
|
|
68
78
|
}
|
|
69
|
-
export type ClientJsonMessage = ClientHelloMessage | ClientHostFontChunkRequestMessage | ClientHostFontSubsetRequestMessage | ClientHostFontRefreshMessage | ClientClaimControlMessage | ClientReleaseControlMessage | ClientResizeMessage | ClientPingMessage | ClientPasteFileMessage | ClientHerdrStartMessage;
|
|
79
|
+
export type ClientJsonMessage = ClientHelloMessage | ClientHostFontChunkRequestMessage | ClientHostFontSubsetRequestMessage | ClientHostFontRefreshMessage | ClientClaimControlMessage | ClientReleaseControlMessage | ClientResizeMessage | ClientPingMessage | ClientPasteFileMessage | ClientHerdrStartMessage | ClientAdminTabOpenMessage;
|
|
70
80
|
export interface ServerReadyMessage {
|
|
71
81
|
type: 'ready';
|
|
72
82
|
role: ClientRole;
|
|
73
83
|
controllerId?: string | null;
|
|
74
84
|
hostId?: string;
|
|
75
85
|
hostname?: string;
|
|
86
|
+
platform?: string;
|
|
87
|
+
shellProfile?: HostShellProfile;
|
|
88
|
+
/** The relay and Windows host can both open an administrator terminal tab. */
|
|
89
|
+
adminTerminalSupported?: boolean;
|
|
76
90
|
clientId?: string;
|
|
77
91
|
terminalPalette?: HostTerminalPalette | null;
|
|
78
92
|
terminalFont?: HostTerminalFont | null;
|
|
@@ -110,6 +124,9 @@ export interface ServerSessionRestartedMessage {
|
|
|
110
124
|
cols?: number;
|
|
111
125
|
rows?: number;
|
|
112
126
|
hostname?: string;
|
|
127
|
+
platform?: string;
|
|
128
|
+
shellProfile?: HostShellProfile;
|
|
129
|
+
adminTerminalSupported?: boolean;
|
|
113
130
|
terminalPalette?: HostTerminalPalette | null;
|
|
114
131
|
terminalFont?: HostTerminalFont | null;
|
|
115
132
|
}
|
|
@@ -210,6 +227,7 @@ export interface HostHelloMessage {
|
|
|
210
227
|
password?: string | null;
|
|
211
228
|
hostname?: string;
|
|
212
229
|
platform?: string;
|
|
230
|
+
shellProfile?: HostShellProfile;
|
|
213
231
|
arch?: string;
|
|
214
232
|
terminalPalette?: HostTerminalPalette | null;
|
|
215
233
|
terminalFont?: HostTerminalFont | null;
|
|
@@ -292,6 +310,9 @@ export interface RelayResizeMessage extends StreamAddressed {
|
|
|
292
310
|
export interface RelayHerdrStartMessage extends StreamAddressed {
|
|
293
311
|
type: 'herdr_start';
|
|
294
312
|
}
|
|
313
|
+
export interface RelayAdminTabOpenMessage extends StreamAddressed {
|
|
314
|
+
type: 'admin_tab_open';
|
|
315
|
+
}
|
|
295
316
|
export interface RelayHostFontRefreshMessage extends StreamAddressed {
|
|
296
317
|
type: 'host_font_refresh';
|
|
297
318
|
}
|
|
@@ -317,5 +338,5 @@ export interface RelayErrorMessage {
|
|
|
317
338
|
code: string;
|
|
318
339
|
message: string;
|
|
319
340
|
}
|
|
320
|
-
export type RelayToHostMessage = RelayHostReadyMessage | RelayClientCountMessage | RelaySessionStartMessage | RelaySessionStopMessage | RelayResizeMessage | RelayHerdrStartMessage | RelayHostFontRefreshMessage | RelayHostFontChunkRequestMessage | RelayHostFontSubsetRequestMessage | RelayPasteFileMessage | RelayErrorMessage;
|
|
341
|
+
export type RelayToHostMessage = RelayHostReadyMessage | RelayClientCountMessage | RelaySessionStartMessage | RelaySessionStopMessage | RelayResizeMessage | RelayHerdrStartMessage | RelayAdminTabOpenMessage | RelayHostFontRefreshMessage | RelayHostFontChunkRequestMessage | RelayHostFontSubsetRequestMessage | RelayPasteFileMessage | RelayErrorMessage;
|
|
321
342
|
export {};
|
|
@@ -15,4 +15,6 @@ export const CAPABILITY = {
|
|
|
15
15
|
idleHeartbeat: 'idle_heartbeat',
|
|
16
16
|
/** The host routes output by 16-bit stream index (v2 frames). */
|
|
17
17
|
binaryFrameV2: 'binary_frame_v2',
|
|
18
|
+
/** The host can open an elevated PowerShell as a tab of its Windows Herdr. */
|
|
19
|
+
adminTabs: 'admin_tabs',
|
|
18
20
|
};
|
|
@@ -10,6 +10,8 @@ import { enqueueDelayedSend, notifyHostClientCount } from './transport.js';
|
|
|
10
10
|
const HERDR_START_REPEAT_MS = 3_000;
|
|
11
11
|
/** A window asks its workstation to re-read the terminal font at most this often. */
|
|
12
12
|
const FONT_REFRESH_REPEAT_MS = 2_000;
|
|
13
|
+
/** A window opens an administrator tab at most this often. */
|
|
14
|
+
const ADMIN_TAB_REPEAT_MS = 1_000;
|
|
13
15
|
function verifyImageMagicBytes(mime, dataBase64) {
|
|
14
16
|
if (typeof dataBase64 !== 'string' || dataBase64.length === 0)
|
|
15
17
|
return false;
|
|
@@ -136,6 +138,9 @@ export function handleClientConnection(relay, ws, req) {
|
|
|
136
138
|
controllerId: null,
|
|
137
139
|
hostId: host.id,
|
|
138
140
|
hostname: host.hostname,
|
|
141
|
+
platform: host.platform,
|
|
142
|
+
...(host.shellProfile ? { shellProfile: host.shellProfile } : {}),
|
|
143
|
+
adminTerminalSupported: host.adminTabsAvailable,
|
|
139
144
|
clientId: client.id,
|
|
140
145
|
// Delivered with `ready`, before the first PTY byte, so the terminal
|
|
141
146
|
// is painted in the host's colors from its very first frame.
|
|
@@ -255,6 +260,30 @@ function handleClientMessage(relay, client, raw, isBinary) {
|
|
|
255
260
|
});
|
|
256
261
|
}
|
|
257
262
|
}
|
|
263
|
+
else if (message.type === 'admin_tab_open') {
|
|
264
|
+
// Routed like herdr_start. The host runs the fixed elevated PowerShell of
|
|
265
|
+
// its own broker; nothing in this message chooses what starts.
|
|
266
|
+
if (!client.session || !isOpen(host.ws))
|
|
267
|
+
return;
|
|
268
|
+
if (!host.adminTabsAvailable) {
|
|
269
|
+
jsonSend(client.ws, {
|
|
270
|
+
type: 'error',
|
|
271
|
+
code: 'admin_terminal_unsupported',
|
|
272
|
+
message: 'Update the host connector to open administrator terminals.',
|
|
273
|
+
});
|
|
274
|
+
return;
|
|
275
|
+
}
|
|
276
|
+
// A double tap is one request; a second tab needs a second, later tap.
|
|
277
|
+
const now = Date.now();
|
|
278
|
+
if (client.adminTabAt && now - client.adminTabAt < ADMIN_TAB_REPEAT_MS)
|
|
279
|
+
return;
|
|
280
|
+
client.adminTabAt = now;
|
|
281
|
+
jsonSend(host.ws, {
|
|
282
|
+
type: 'admin_tab_open',
|
|
283
|
+
clientId: client.session.streamId,
|
|
284
|
+
streamId: client.session.streamId,
|
|
285
|
+
});
|
|
286
|
+
}
|
|
258
287
|
else if (message.type === 'host_font_chunk_request') {
|
|
259
288
|
requestFontChunk(host, client, message);
|
|
260
289
|
}
|
|
@@ -15,6 +15,8 @@ function createHostRecord(message, ws, pending, clients = new Set()) {
|
|
|
15
15
|
ws,
|
|
16
16
|
hostname: typeof message.hostname === 'string' ? message.hostname.slice(0, 128) : os.hostname(),
|
|
17
17
|
platform: typeof message.platform === 'string' ? message.platform.slice(0, 32) : process.platform,
|
|
18
|
+
...(message.shellProfile === 'git-bash' ? { shellProfile: message.shellProfile } : {}),
|
|
19
|
+
adminTabsAvailable: capabilities.includes(CAPABILITY.adminTabs),
|
|
18
20
|
arch: typeof message.arch === 'string' ? message.arch.slice(0, 32) : process.arch,
|
|
19
21
|
connectedAt: new Date(pending.connectedAt).toISOString(),
|
|
20
22
|
connectedAtMs: pending.connectedAt,
|
package/dist/server/sessions.js
CHANGED
|
@@ -66,6 +66,9 @@ export function startSession(relay, host, client, { restarted = false } = {}) {
|
|
|
66
66
|
cols: client.cols,
|
|
67
67
|
rows: client.rows,
|
|
68
68
|
hostname: host.hostname,
|
|
69
|
+
platform: host.platform,
|
|
70
|
+
...(host.shellProfile ? { shellProfile: host.shellProfile } : {}),
|
|
71
|
+
adminTerminalSupported: host.adminTabsAvailable,
|
|
69
72
|
terminalPalette: host.terminalPalette || null,
|
|
70
73
|
terminalFont: host.terminalFont || null,
|
|
71
74
|
});
|
package/dist/server/types.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { WebSocket } from 'ws';
|
|
2
2
|
import type { AuthStore } from '../auth-store.js';
|
|
3
3
|
import type { RelayMetrics } from '../metrics.js';
|
|
4
|
-
import type { ClientRole, HostPtySummary, ServerAgentStatusMessage, ServerUpdateStatusMessage } from '../protocol/messages.js';
|
|
4
|
+
import type { ClientRole, HostPtySummary, ServerAgentStatusMessage, ServerUpdateStatusMessage, HostShellProfile } from '../protocol/messages.js';
|
|
5
5
|
import type { HostTerminalFont, HostTerminalPalette } from '../protocol/terminal.js';
|
|
6
6
|
import type { RelayConfig } from '../relay-config.js';
|
|
7
7
|
/** A WebSocket plus the liveness flag the heartbeat keeps on it. */
|
|
@@ -23,6 +23,9 @@ export interface RelayHost {
|
|
|
23
23
|
ws: RelaySocket | null;
|
|
24
24
|
hostname: string;
|
|
25
25
|
platform: string;
|
|
26
|
+
shellProfile?: HostShellProfile;
|
|
27
|
+
/** The host can open an administrator terminal as a Herdr tab. */
|
|
28
|
+
adminTabsAvailable: boolean;
|
|
26
29
|
arch: string;
|
|
27
30
|
connectedAt: string;
|
|
28
31
|
connectedAtMs: number;
|
|
@@ -72,6 +75,7 @@ export interface RelayClient {
|
|
|
72
75
|
cols: number;
|
|
73
76
|
rows: number;
|
|
74
77
|
herdrStartAt?: number;
|
|
78
|
+
adminTabAt?: number;
|
|
75
79
|
fontRefreshAt?: number;
|
|
76
80
|
/** When each outstanding font chunk request was sent. */
|
|
77
81
|
fontChunkRequests?: number[];
|