ai-remote 0.4.2 → 0.4.3
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/index.js +1 -6
- package/dist/protocols/index.js +3 -34
- package/dist/protocols/ssh/session.js +17 -608
- package/dist/protocols/ssh/terminal.js +6 -190
- package/dist/shared/connection.js +1 -113
- package/dist/shared/hosts.js +1 -132
- package/dist/shared/icons.js +1 -41
- package/dist/shared/protocol.js +1 -39
- package/dist/shared/signals.js +1 -41
- package/package.json +1 -1
- package/dist/protocols/rdp/buffer.d.ts +0 -38
- package/dist/protocols/rdp/buffer.js +0 -169
- package/dist/protocols/rdp/caps.d.ts +0 -49
- package/dist/protocols/rdp/caps.js +0 -259
- package/dist/protocols/rdp/cert.d.ts +0 -18
- package/dist/protocols/rdp/cert.js +0 -134
- package/dist/protocols/rdp/client.d.ts +0 -56
- package/dist/protocols/rdp/client.js +0 -1069
- package/dist/protocols/rdp/cliprdr.d.ts +0 -27
- package/dist/protocols/rdp/cliprdr.js +0 -239
- package/dist/protocols/rdp/credssp.d.ts +0 -34
- package/dist/protocols/rdp/credssp.js +0 -253
- package/dist/protocols/rdp/crypto.d.ts +0 -63
- package/dist/protocols/rdp/crypto.js +0 -368
- package/dist/protocols/rdp/display.d.ts +0 -38
- package/dist/protocols/rdp/display.js +0 -588
- package/dist/protocols/rdp/gcc.d.ts +0 -23
- package/dist/protocols/rdp/gcc.js +0 -131
- package/dist/protocols/rdp/keymap.d.ts +0 -9
- package/dist/protocols/rdp/keymap.js +0 -131
- package/dist/protocols/rdp/mcs.d.ts +0 -40
- package/dist/protocols/rdp/mcs.js +0 -222
- package/dist/protocols/rdp/ntlm.d.ts +0 -61
- package/dist/protocols/rdp/ntlm.js +0 -304
- package/dist/protocols/rdp/pdu.d.ts +0 -155
- package/dist/protocols/rdp/pdu.js +0 -443
- package/dist/protocols/rdp/rail.d.ts +0 -119
- package/dist/protocols/rdp/rail.js +0 -382
- package/dist/protocols/rdp/rle.d.ts +0 -13
- package/dist/protocols/rdp/rle.js +0 -275
- package/dist/protocols/rdp/sec.d.ts +0 -59
- package/dist/protocols/rdp/sec.js +0 -155
- package/dist/protocols/rdp/session.d.ts +0 -62
- package/dist/protocols/rdp/session.js +0 -306
- package/dist/protocols/rdp/tls.d.ts +0 -18
- package/dist/protocols/rdp/tls.js +0 -353
- package/dist/protocols/rdp/vchannel.d.ts +0 -28
- package/dist/protocols/rdp/vchannel.js +0 -58
- package/dist/protocols/rdp/x224.d.ts +0 -40
- package/dist/protocols/rdp/x224.js +0 -109
- package/dist/protocols/ssh/kex.d.ts +0 -97
- package/dist/protocols/ssh/kex.js +0 -176
- package/dist/protocols/ssh/messages.d.ts +0 -50
- package/dist/protocols/ssh/messages.js +0 -54
- package/dist/protocols/ssh/transport.d.ts +0 -62
- package/dist/protocols/ssh/transport.js +0 -612
- package/dist/protocols/ssh/wire.d.ts +0 -52
- package/dist/protocols/ssh/wire.js +0 -188
- package/dist/protocols/vnc/input.d.ts +0 -5
- package/dist/protocols/vnc/input.js +0 -15
- package/dist/protocols/vnc/session.d.ts +0 -12
- package/dist/protocols/vnc/session.js +0 -258
|
@@ -1,59 +0,0 @@
|
|
|
1
|
-
import { concatBytes } from './buffer';
|
|
2
|
-
export declare const SEC_FLAG: {
|
|
3
|
-
EXCHANGE_PKT: number;
|
|
4
|
-
TRANSPORT_REQ: number;
|
|
5
|
-
ENCRYPT: number;
|
|
6
|
-
RESET_SEQNO: number;
|
|
7
|
-
IGNORE_SEQNO: number;
|
|
8
|
-
INFO_PKT: number;
|
|
9
|
-
LICENSE_PKT: number;
|
|
10
|
-
LICENSE_ENCRYPT_CS: number;
|
|
11
|
-
REDIRECTION_PKT: number;
|
|
12
|
-
SECURE_CHECKSUM: number;
|
|
13
|
-
AUTODETECT_REQ: number;
|
|
14
|
-
AUTODETECT_RSP: number;
|
|
15
|
-
HEARTBEAT: number;
|
|
16
|
-
};
|
|
17
|
-
export declare class SecurityLayer {
|
|
18
|
-
#private;
|
|
19
|
-
private encryptionMethod;
|
|
20
|
-
private encryptionLevel;
|
|
21
|
-
private keys;
|
|
22
|
-
private encryptState;
|
|
23
|
-
private decryptState;
|
|
24
|
-
private encryptedPdus;
|
|
25
|
-
private decryptedPdus;
|
|
26
|
-
constructor();
|
|
27
|
-
/** True when data PDUs carry a basic security header at all. */
|
|
28
|
-
get headerPresent(): boolean;
|
|
29
|
-
get encryptionEnabled(): boolean;
|
|
30
|
-
configure(encryptionMethod: number, encryptionLevel: number, clientRandom: Uint8Array, serverRandom: Uint8Array): void;
|
|
31
|
-
/**
|
|
32
|
-
* Prefix a payload with the basic security header, signing and encrypting it
|
|
33
|
-
* when the negotiated level asks for that.
|
|
34
|
-
*
|
|
35
|
-
* `flags` carries the PDU-kind bits (SEC_INFO_PKT and friends). A payload with
|
|
36
|
-
* no flags and no encryption needs no header at all.
|
|
37
|
-
*/
|
|
38
|
-
wrap(payload: Uint8Array, flags?: number): Uint8Array<ArrayBufferLike>;
|
|
39
|
-
/**
|
|
40
|
-
* Strip (and if needed decrypt) the basic security header from a host PDU.
|
|
41
|
-
* `headerMandatory` forces the header to be read even when the host reported
|
|
42
|
-
* no encryption, which licensing PDUs require.
|
|
43
|
-
*/
|
|
44
|
-
unwrap(bytes: Uint8Array, headerMandatory?: boolean): {
|
|
45
|
-
flags: number;
|
|
46
|
-
payload: Uint8Array<ArrayBufferLike>;
|
|
47
|
-
};
|
|
48
|
-
/**
|
|
49
|
-
* Fast-path output carries the same signature and RC4 stream as a slow-path
|
|
50
|
-
* PDU, but without the basic security header in front of it.
|
|
51
|
-
*/
|
|
52
|
-
decryptFastPath(payload: Uint8Array): Uint8Array<ArrayBufferLike>;
|
|
53
|
-
/**
|
|
54
|
-
* Security Exchange PDU (MS-RDPBCGR 2.2.1.10): the client random encrypted
|
|
55
|
-
* with the host public key, followed by eight bytes of padding.
|
|
56
|
-
*/
|
|
57
|
-
static securityExchange(encryptedClientRandom: any): Uint8Array<ArrayBufferLike>;
|
|
58
|
-
}
|
|
59
|
-
export { concatBytes };
|
|
@@ -1,155 +0,0 @@
|
|
|
1
|
-
import { Reader, Writer, concatBytes } from "./buffer.js";
|
|
2
|
-
import {
|
|
3
|
-
ENCRYPTION_METHOD,
|
|
4
|
-
deriveSessionKeys,
|
|
5
|
-
macSignature,
|
|
6
|
-
rc4Crypt,
|
|
7
|
-
rc4Init,
|
|
8
|
-
updateSessionKey
|
|
9
|
-
} from "./crypto.js";
|
|
10
|
-
import { ENCRYPTION_LEVEL } from "./gcc.js";
|
|
11
|
-
const SEC_FLAG = {
|
|
12
|
-
EXCHANGE_PKT: 1,
|
|
13
|
-
TRANSPORT_REQ: 2,
|
|
14
|
-
ENCRYPT: 8,
|
|
15
|
-
RESET_SEQNO: 16,
|
|
16
|
-
IGNORE_SEQNO: 32,
|
|
17
|
-
INFO_PKT: 64,
|
|
18
|
-
LICENSE_PKT: 128,
|
|
19
|
-
LICENSE_ENCRYPT_CS: 512,
|
|
20
|
-
REDIRECTION_PKT: 1024,
|
|
21
|
-
SECURE_CHECKSUM: 2048,
|
|
22
|
-
AUTODETECT_REQ: 4096,
|
|
23
|
-
AUTODETECT_RSP: 8192,
|
|
24
|
-
HEARTBEAT: 16384
|
|
25
|
-
};
|
|
26
|
-
const KEY_ROTATION_INTERVAL = 4096;
|
|
27
|
-
class SecurityLayer {
|
|
28
|
-
encryptionMethod;
|
|
29
|
-
encryptionLevel;
|
|
30
|
-
keys;
|
|
31
|
-
encryptState;
|
|
32
|
-
decryptState;
|
|
33
|
-
encryptedPdus;
|
|
34
|
-
decryptedPdus;
|
|
35
|
-
constructor() {
|
|
36
|
-
this.encryptionMethod = ENCRYPTION_METHOD.NONE;
|
|
37
|
-
this.encryptionLevel = ENCRYPTION_LEVEL.NONE;
|
|
38
|
-
this.keys = null;
|
|
39
|
-
this.encryptState = null;
|
|
40
|
-
this.decryptState = null;
|
|
41
|
-
this.encryptedPdus = 0;
|
|
42
|
-
this.decryptedPdus = 0;
|
|
43
|
-
}
|
|
44
|
-
/** True when data PDUs carry a basic security header at all. */
|
|
45
|
-
get headerPresent() {
|
|
46
|
-
return this.encryptionLevel !== ENCRYPTION_LEVEL.NONE || this.encryptionMethod !== ENCRYPTION_METHOD.NONE;
|
|
47
|
-
}
|
|
48
|
-
get encryptionEnabled() {
|
|
49
|
-
return this.encryptionMethod !== ENCRYPTION_METHOD.NONE && this.keys !== null;
|
|
50
|
-
}
|
|
51
|
-
configure(encryptionMethod, encryptionLevel, clientRandom, serverRandom) {
|
|
52
|
-
this.encryptionMethod = encryptionMethod;
|
|
53
|
-
this.encryptionLevel = encryptionLevel;
|
|
54
|
-
if (encryptionMethod === ENCRYPTION_METHOD.NONE) return;
|
|
55
|
-
if (encryptionMethod & ENCRYPTION_METHOD.FIPS) {
|
|
56
|
-
throw new Error("RDP: this host requires FIPS encryption, which this client does not implement");
|
|
57
|
-
}
|
|
58
|
-
this.keys = deriveSessionKeys(clientRandom, serverRandom, encryptionMethod);
|
|
59
|
-
this.encryptState = rc4Init(this.keys.encryptKey);
|
|
60
|
-
this.decryptState = rc4Init(this.keys.decryptKey);
|
|
61
|
-
}
|
|
62
|
-
#rotateEncryptKey() {
|
|
63
|
-
this.keys.encryptKey = updateSessionKey(
|
|
64
|
-
this.keys.initialEncryptKey,
|
|
65
|
-
this.keys.encryptKey,
|
|
66
|
-
this.keys.keyLength,
|
|
67
|
-
this.keys.is40Bit
|
|
68
|
-
);
|
|
69
|
-
this.encryptState = rc4Init(this.keys.encryptKey);
|
|
70
|
-
this.encryptedPdus = 0;
|
|
71
|
-
}
|
|
72
|
-
#rotateDecryptKey() {
|
|
73
|
-
this.keys.decryptKey = updateSessionKey(
|
|
74
|
-
this.keys.initialDecryptKey,
|
|
75
|
-
this.keys.decryptKey,
|
|
76
|
-
this.keys.keyLength,
|
|
77
|
-
this.keys.is40Bit
|
|
78
|
-
);
|
|
79
|
-
this.decryptState = rc4Init(this.keys.decryptKey);
|
|
80
|
-
this.decryptedPdus = 0;
|
|
81
|
-
}
|
|
82
|
-
/**
|
|
83
|
-
* Prefix a payload with the basic security header, signing and encrypting it
|
|
84
|
-
* when the negotiated level asks for that.
|
|
85
|
-
*
|
|
86
|
-
* `flags` carries the PDU-kind bits (SEC_INFO_PKT and friends). A payload with
|
|
87
|
-
* no flags and no encryption needs no header at all.
|
|
88
|
-
*/
|
|
89
|
-
wrap(payload, flags = 0) {
|
|
90
|
-
const encrypt = this.encryptionEnabled;
|
|
91
|
-
if (!encrypt && flags === 0 && !this.headerPresent) return payload;
|
|
92
|
-
const writer = new Writer(payload.length + 16);
|
|
93
|
-
writer.u16le(flags | (encrypt ? SEC_FLAG.ENCRYPT : 0));
|
|
94
|
-
writer.u16le(0);
|
|
95
|
-
if (!encrypt) {
|
|
96
|
-
writer.raw(payload);
|
|
97
|
-
return writer.take();
|
|
98
|
-
}
|
|
99
|
-
writer.raw(macSignature(this.keys.macKey, payload));
|
|
100
|
-
writer.raw(rc4Crypt(this.encryptState, payload));
|
|
101
|
-
if (++this.encryptedPdus === KEY_ROTATION_INTERVAL) this.#rotateEncryptKey();
|
|
102
|
-
return writer.take();
|
|
103
|
-
}
|
|
104
|
-
/**
|
|
105
|
-
* Strip (and if needed decrypt) the basic security header from a host PDU.
|
|
106
|
-
* `headerMandatory` forces the header to be read even when the host reported
|
|
107
|
-
* no encryption, which licensing PDUs require.
|
|
108
|
-
*/
|
|
109
|
-
unwrap(bytes, headerMandatory = false) {
|
|
110
|
-
if (!this.headerPresent && !headerMandatory) return { flags: 0, payload: bytes };
|
|
111
|
-
if (bytes.length < 4) return { flags: 0, payload: bytes };
|
|
112
|
-
const reader = new Reader(bytes);
|
|
113
|
-
const flags = reader.u16le();
|
|
114
|
-
reader.u16le();
|
|
115
|
-
if (!(flags & SEC_FLAG.ENCRYPT)) {
|
|
116
|
-
return { flags, payload: reader.rest() };
|
|
117
|
-
}
|
|
118
|
-
if (!this.encryptionEnabled) {
|
|
119
|
-
throw new Error("RDP: the host encrypted a PDU before the session keys existed");
|
|
120
|
-
}
|
|
121
|
-
reader.skip(8);
|
|
122
|
-
const payload = rc4Crypt(this.decryptState, reader.rest());
|
|
123
|
-
if (++this.decryptedPdus === KEY_ROTATION_INTERVAL) this.#rotateDecryptKey();
|
|
124
|
-
return { flags, payload };
|
|
125
|
-
}
|
|
126
|
-
/**
|
|
127
|
-
* Fast-path output carries the same signature and RC4 stream as a slow-path
|
|
128
|
-
* PDU, but without the basic security header in front of it.
|
|
129
|
-
*/
|
|
130
|
-
decryptFastPath(payload) {
|
|
131
|
-
if (!this.encryptionEnabled) return payload;
|
|
132
|
-
if (payload.length <= 8) return payload;
|
|
133
|
-
const decrypted = rc4Crypt(this.decryptState, payload.subarray(8));
|
|
134
|
-
if (++this.decryptedPdus === KEY_ROTATION_INTERVAL) this.#rotateDecryptKey();
|
|
135
|
-
return decrypted;
|
|
136
|
-
}
|
|
137
|
-
/**
|
|
138
|
-
* Security Exchange PDU (MS-RDPBCGR 2.2.1.10): the client random encrypted
|
|
139
|
-
* with the host public key, followed by eight bytes of padding.
|
|
140
|
-
*/
|
|
141
|
-
static securityExchange(encryptedClientRandom) {
|
|
142
|
-
const writer = new Writer(encryptedClientRandom.length + 16);
|
|
143
|
-
writer.u16le(SEC_FLAG.EXCHANGE_PKT);
|
|
144
|
-
writer.u16le(0);
|
|
145
|
-
writer.u32le(encryptedClientRandom.length + 8);
|
|
146
|
-
writer.raw(encryptedClientRandom);
|
|
147
|
-
writer.zeros(8);
|
|
148
|
-
return writer.take();
|
|
149
|
-
}
|
|
150
|
-
}
|
|
151
|
-
export {
|
|
152
|
-
SEC_FLAG,
|
|
153
|
-
SecurityLayer,
|
|
154
|
-
concatBytes
|
|
155
|
-
};
|
|
@@ -1,62 +0,0 @@
|
|
|
1
|
-
import type { ProtocolDriver } from '../types';
|
|
2
|
-
export declare class RdpSession extends EventTarget {
|
|
3
|
-
#private;
|
|
4
|
-
readonly protocol: 'rdp';
|
|
5
|
-
constructor(container: any, url: string, options?: {});
|
|
6
|
-
/**
|
|
7
|
-
* Ask the host to size the remote application's window to the room this
|
|
8
|
-
* session has on the page. Full-desktop sessions have nothing to do here:
|
|
9
|
-
* their size is fixed when the connection is negotiated.
|
|
10
|
-
*/
|
|
11
|
-
fitToViewport(): any;
|
|
12
|
-
get connected(): boolean;
|
|
13
|
-
get canvas(): HTMLCanvasElement | null;
|
|
14
|
-
/** The workspace instruments this socket for byte counters and keepalives. */
|
|
15
|
-
get socket(): WebSocket | null;
|
|
16
|
-
get _sock(): {
|
|
17
|
-
_websocket: any;
|
|
18
|
-
};
|
|
19
|
-
get scaleViewport(): any;
|
|
20
|
-
set scaleViewport(enabled: any);
|
|
21
|
-
get viewOnly(): any;
|
|
22
|
-
set viewOnly(enabled: any);
|
|
23
|
-
/**
|
|
24
|
-
* The on-screen keyboard and the special-keys dialog call this with an X11
|
|
25
|
-
* keysym and a DOM code. RDP wants a scancode, so the code decides; the
|
|
26
|
-
* keysym is only a fallback for characters with no key of their own.
|
|
27
|
-
*/
|
|
28
|
-
sendKey(keysym: any, code: number, pressed: boolean): void;
|
|
29
|
-
sendCtrlAltDel(): void;
|
|
30
|
-
/** Desktop pixels. Returns false when the session cannot accept input. */
|
|
31
|
-
movePointer(x: number, y: number): boolean;
|
|
32
|
-
clickPointer(x: number, y: number, button?: number): boolean;
|
|
33
|
-
pointerButton(x: number, y: number, button?: number, pressed?: boolean): boolean;
|
|
34
|
-
scrollPointer(x: number, y: number, delta: {
|
|
35
|
-
x: number;
|
|
36
|
-
y: number;
|
|
37
|
-
}): boolean;
|
|
38
|
-
/** Type a run of characters, which RDP carries as Unicode rather than keys. */
|
|
39
|
-
typeText(text: string): boolean;
|
|
40
|
-
/** What the canvas is showing, for a screen capture or a coordinate check. */
|
|
41
|
-
get screenGeometry(): {
|
|
42
|
-
width: any;
|
|
43
|
-
height: any;
|
|
44
|
-
viewport: any;
|
|
45
|
-
};
|
|
46
|
-
/**
|
|
47
|
-
* Hand text to the host's clipboard, falling back to typing it when the host
|
|
48
|
-
* declined the clipboard channel -- xrdp builds often do.
|
|
49
|
-
*/
|
|
50
|
-
clipboardPasteFrom(text: string): void;
|
|
51
|
-
/**
|
|
52
|
-
* Deliver text into the session, which is what the clipboard drawer's button
|
|
53
|
-
* has always visibly done. `clipboardPasteFrom` only loads the clipboard, the
|
|
54
|
-
* way noVNC's method of that name does.
|
|
55
|
-
*/
|
|
56
|
-
pasteText(text: string): any;
|
|
57
|
-
releaseKeyboard(): void;
|
|
58
|
-
/** True once the host has agreed to share its clipboard. */
|
|
59
|
-
get clipboardShared(): any;
|
|
60
|
-
disconnect(): void;
|
|
61
|
-
}
|
|
62
|
-
export declare const rdpDriver: ProtocolDriver;
|
|
@@ -1,306 +0,0 @@
|
|
|
1
|
-
import { RdpClient } from "./client.js";
|
|
2
|
-
import { RdpDisplay } from "./display.js";
|
|
3
|
-
import { DEFAULT_PORTS } from "../../shared/protocol.js";
|
|
4
|
-
const DIALOG = {
|
|
5
|
-
usernameLabel: "Username",
|
|
6
|
-
usernamePlaceholder: "Windows username",
|
|
7
|
-
usernameHelp: "Use the Windows account name for this computer.",
|
|
8
|
-
passwordLabel: "Password",
|
|
9
|
-
passwordPlaceholder: "Windows password",
|
|
10
|
-
passwordHelp: "Use the Windows account password. It may be left empty when the host presents its own sign-in screen.",
|
|
11
|
-
// Credentials may be left empty and typed on the remote sign-in screen.
|
|
12
|
-
requiresPassword: false
|
|
13
|
-
};
|
|
14
|
-
function buildUrl(origin, settings) {
|
|
15
|
-
const query = new URLSearchParams({
|
|
16
|
-
host: settings.host,
|
|
17
|
-
port: String(settings.port),
|
|
18
|
-
security: settings.security
|
|
19
|
-
});
|
|
20
|
-
return `${origin}/rdp-ws?${query}`;
|
|
21
|
-
}
|
|
22
|
-
function describeDisconnect({ code, reason, suffix }) {
|
|
23
|
-
if (/hybrid_required|requires network level|authenticates before/i.test(reason)) {
|
|
24
|
-
return `The RDP host signs in before showing a desktop${suffix}. Enter the Windows username and password and connect again.`;
|
|
25
|
-
}
|
|
26
|
-
if (code === 1011 || /cannot connect|unreachable|tcp error|tcp write/i.test(reason)) {
|
|
27
|
-
return `The Worker could not keep a TCP connection to the RDP host${suffix}. Check that Remote Desktop is enabled and listening on this address and port.`;
|
|
28
|
-
}
|
|
29
|
-
return null;
|
|
30
|
-
}
|
|
31
|
-
class RdpSession extends EventTarget {
|
|
32
|
-
protocol = "rdp";
|
|
33
|
-
constructor(container, url, options = {}) {
|
|
34
|
-
super();
|
|
35
|
-
this.url = url;
|
|
36
|
-
this.options = options;
|
|
37
|
-
this.display = new RdpDisplay(container);
|
|
38
|
-
this.display.viewOnly = Boolean(options.viewOnly);
|
|
39
|
-
this._rfbConnectionState = "connecting";
|
|
40
|
-
this._scaleViewport = options.scaleViewport !== false;
|
|
41
|
-
this.display.scaleViewport = this._scaleViewport;
|
|
42
|
-
this.lastErrorMessage = "";
|
|
43
|
-
this.hostLabel = options.hostLabel || "Remote Desktop";
|
|
44
|
-
this.#createClient(options.security || "auto");
|
|
45
|
-
this.remoteAppLayoutObserver = options.remoteApp?.program && typeof ResizeObserver === "function" ? new ResizeObserver(() => this.fitToViewport()) : null;
|
|
46
|
-
this.remoteAppLayoutObserver?.observe(this.display.scrollHost);
|
|
47
|
-
}
|
|
48
|
-
#createClient(security) {
|
|
49
|
-
this.security = security;
|
|
50
|
-
this.client = new RdpClient(this.url, {
|
|
51
|
-
width: this.options.width,
|
|
52
|
-
height: this.options.height,
|
|
53
|
-
username: this.options.credentials?.username || "",
|
|
54
|
-
password: this.options.credentials?.password || "",
|
|
55
|
-
domain: this.options.domain || "",
|
|
56
|
-
security,
|
|
57
|
-
keyboardLayout: this.options.keyboardLayout || 1033,
|
|
58
|
-
clientName: this.options.clientName || "cf-gateway",
|
|
59
|
-
remoteApp: this.options.remoteApp || null
|
|
60
|
-
});
|
|
61
|
-
this.client.addEventListener("ready", (event) => {
|
|
62
|
-
const { width, height } = event.detail;
|
|
63
|
-
this.display.resize(width, height);
|
|
64
|
-
this.display.attachInput(this.client);
|
|
65
|
-
this.display.focus();
|
|
66
|
-
this.fitToViewport();
|
|
67
|
-
this._rfbConnectionState = "connected";
|
|
68
|
-
this.dispatchEvent(new CustomEvent("connect"));
|
|
69
|
-
this.dispatchEvent(new CustomEvent("desktopname", {
|
|
70
|
-
detail: { name: `${this.hostLabel} (${width}x${height})` }
|
|
71
|
-
}));
|
|
72
|
-
});
|
|
73
|
-
this.client.addEventListener("resize", (event) => {
|
|
74
|
-
const { width, height } = event.detail;
|
|
75
|
-
this.display.resize(width, height);
|
|
76
|
-
this.dispatchEvent(new CustomEvent("desktopname", {
|
|
77
|
-
detail: { name: `${this.hostLabel} (${width}x${height})` }
|
|
78
|
-
}));
|
|
79
|
-
this.fitToViewport();
|
|
80
|
-
});
|
|
81
|
-
this.client.addEventListener("remoteappviewport", (event) => {
|
|
82
|
-
this.display.setViewport(event.detail);
|
|
83
|
-
});
|
|
84
|
-
this.client.addEventListener("bitmap", (event) => {
|
|
85
|
-
this.display.drawRects(event.detail.rects, event.detail.palette);
|
|
86
|
-
this.dispatchEvent(new CustomEvent("frame", {
|
|
87
|
-
detail: { rects: event.detail.rects }
|
|
88
|
-
}));
|
|
89
|
-
});
|
|
90
|
-
this.client.addEventListener("palette", (event) => {
|
|
91
|
-
this.display.palette = event.detail;
|
|
92
|
-
});
|
|
93
|
-
this.client.addEventListener("pointer", (event) => {
|
|
94
|
-
this.display.applyPointer(event.detail);
|
|
95
|
-
});
|
|
96
|
-
this.client.addEventListener("clipboard", (event) => {
|
|
97
|
-
this.dispatchEvent(new CustomEvent("clipboard", { detail: { text: event.detail.text } }));
|
|
98
|
-
});
|
|
99
|
-
this.client.addEventListener("remoteappresult", (event) => {
|
|
100
|
-
this.dispatchEvent(new CustomEvent("remoteappresult", { detail: event.detail }));
|
|
101
|
-
});
|
|
102
|
-
this.client.addEventListener("remoteappwindow", (event) => {
|
|
103
|
-
this.dispatchEvent(new CustomEvent("remoteappwindow", { detail: event.detail }));
|
|
104
|
-
});
|
|
105
|
-
this.client.addEventListener("remoteappclosed", (event) => {
|
|
106
|
-
this.dispatchEvent(new CustomEvent("remoteappclosed", { detail: event.detail }));
|
|
107
|
-
});
|
|
108
|
-
this.client.addEventListener("error", (event) => {
|
|
109
|
-
this.lastErrorMessage = event.detail.message;
|
|
110
|
-
});
|
|
111
|
-
this.client.addEventListener("close", (event) => {
|
|
112
|
-
this._rfbConnectionState = "disconnected";
|
|
113
|
-
this.remoteAppLayoutObserver?.disconnect();
|
|
114
|
-
this.display.destroy();
|
|
115
|
-
this.dispatchEvent(new CustomEvent("disconnect", {
|
|
116
|
-
detail: {
|
|
117
|
-
clean: Boolean(event.detail.clean),
|
|
118
|
-
message: this.lastErrorMessage || event.detail.message || "",
|
|
119
|
-
code: event.detail.code,
|
|
120
|
-
phase: event.detail.phase
|
|
121
|
-
}
|
|
122
|
-
}));
|
|
123
|
-
});
|
|
124
|
-
}
|
|
125
|
-
/**
|
|
126
|
-
* Ask the host to size the remote application's window to the room this
|
|
127
|
-
* session has on the page. Full-desktop sessions have nothing to do here:
|
|
128
|
-
* their size is fixed when the connection is negotiated.
|
|
129
|
-
*/
|
|
130
|
-
fitToViewport() {
|
|
131
|
-
if (!this.options.remoteApp?.program) return false;
|
|
132
|
-
const bounds = this.display.container.getBoundingClientRect();
|
|
133
|
-
const width = Math.floor(bounds.width || this.options.width || 0);
|
|
134
|
-
const height = Math.floor(bounds.height || this.options.height || 0);
|
|
135
|
-
if (width <= 0 || height <= 0) return false;
|
|
136
|
-
return this.client.fitRemoteApp(width, height);
|
|
137
|
-
}
|
|
138
|
-
get connected() {
|
|
139
|
-
return this._rfbConnectionState === "connected";
|
|
140
|
-
}
|
|
141
|
-
get canvas() {
|
|
142
|
-
return this.display?.canvas ?? null;
|
|
143
|
-
}
|
|
144
|
-
/** The workspace instruments this socket for byte counters and keepalives. */
|
|
145
|
-
get socket() {
|
|
146
|
-
return this.client.socket ?? null;
|
|
147
|
-
}
|
|
148
|
-
get _sock() {
|
|
149
|
-
return { _websocket: this.client.socket };
|
|
150
|
-
}
|
|
151
|
-
get scaleViewport() {
|
|
152
|
-
return this._scaleViewport;
|
|
153
|
-
}
|
|
154
|
-
set scaleViewport(enabled) {
|
|
155
|
-
this._scaleViewport = Boolean(enabled);
|
|
156
|
-
this.display.setScaleViewport(this._scaleViewport);
|
|
157
|
-
}
|
|
158
|
-
get viewOnly() {
|
|
159
|
-
return this.display.viewOnly;
|
|
160
|
-
}
|
|
161
|
-
set viewOnly(enabled) {
|
|
162
|
-
this.display.viewOnly = Boolean(enabled);
|
|
163
|
-
if (enabled) this.display.releaseAllKeys();
|
|
164
|
-
}
|
|
165
|
-
/**
|
|
166
|
-
* The on-screen keyboard and the special-keys dialog call this with an X11
|
|
167
|
-
* keysym and a DOM code. RDP wants a scancode, so the code decides; the
|
|
168
|
-
* keysym is only a fallback for characters with no key of their own.
|
|
169
|
-
*/
|
|
170
|
-
sendKey(keysym, code, pressed) {
|
|
171
|
-
if (code && this.client.sendKeyByCode(code, pressed)) return;
|
|
172
|
-
if (!pressed || !keysym) return;
|
|
173
|
-
if (keysym >= 32 && keysym <= 1114111) {
|
|
174
|
-
this.client.sendUnicode(String.fromCodePoint(keysym));
|
|
175
|
-
}
|
|
176
|
-
}
|
|
177
|
-
sendCtrlAltDel() {
|
|
178
|
-
this.client.sendCtrlAltDel();
|
|
179
|
-
}
|
|
180
|
-
// --- pointer, for the AI pane's screen-control tool ----------------------
|
|
181
|
-
//
|
|
182
|
-
// The display already turns browser events into these calls; exposing them
|
|
183
|
-
// lets something other than a mouse drive the same path.
|
|
184
|
-
/** Desktop pixels. Returns false when the session cannot accept input. */
|
|
185
|
-
movePointer(x, y) {
|
|
186
|
-
if (!this.client?.connected || this.display.viewOnly) return false;
|
|
187
|
-
this.client.sendMouseMove(...this.#clampToDesktop(x, y));
|
|
188
|
-
return true;
|
|
189
|
-
}
|
|
190
|
-
clickPointer(x, y, button = 0) {
|
|
191
|
-
if (!this.client?.connected || this.display.viewOnly) return false;
|
|
192
|
-
const [px, py] = this.#clampToDesktop(x, y);
|
|
193
|
-
this.client.sendMouseMove(px, py);
|
|
194
|
-
this.pointerButton(px, py, button, true);
|
|
195
|
-
this.pointerButton(px, py, button, false);
|
|
196
|
-
return true;
|
|
197
|
-
}
|
|
198
|
-
pointerButton(x, y, button = 0, pressed = true) {
|
|
199
|
-
if (!this.client?.connected || this.display.viewOnly) return false;
|
|
200
|
-
const [px, py] = this.#clampToDesktop(x, y);
|
|
201
|
-
this.client.sendMouseButton(button, pressed, px, py);
|
|
202
|
-
return true;
|
|
203
|
-
}
|
|
204
|
-
scrollPointer(x, y, delta) {
|
|
205
|
-
if (!this.client?.connected || this.display.viewOnly) return false;
|
|
206
|
-
const [px, py] = this.#clampToDesktop(x, y);
|
|
207
|
-
for (let i = 0; i < Math.min(20, Math.abs(delta.y)); i++) {
|
|
208
|
-
this.client.sendWheel(Math.sign(delta.y), px, py, false);
|
|
209
|
-
}
|
|
210
|
-
for (let i = 0; i < Math.min(20, Math.abs(delta.x)); i++) {
|
|
211
|
-
this.client.sendWheel(Math.sign(delta.x), px, py, true);
|
|
212
|
-
}
|
|
213
|
-
return true;
|
|
214
|
-
}
|
|
215
|
-
/** Type a run of characters, which RDP carries as Unicode rather than keys. */
|
|
216
|
-
typeText(text) {
|
|
217
|
-
if (!this.client?.connected || this.display.viewOnly || !text) return false;
|
|
218
|
-
let printable = "";
|
|
219
|
-
const flushPrintable = () => {
|
|
220
|
-
if (!printable) return;
|
|
221
|
-
this.client.sendUnicode(printable);
|
|
222
|
-
printable = "";
|
|
223
|
-
};
|
|
224
|
-
for (const character of text) {
|
|
225
|
-
if (character === "\n" || character === "\r") {
|
|
226
|
-
flushPrintable();
|
|
227
|
-
this.client.sendKeyByCode("Enter", true);
|
|
228
|
-
this.client.sendKeyByCode("Enter", false);
|
|
229
|
-
} else if (character === " ") {
|
|
230
|
-
flushPrintable();
|
|
231
|
-
this.client.sendKeyByCode("Tab", true);
|
|
232
|
-
this.client.sendKeyByCode("Tab", false);
|
|
233
|
-
} else {
|
|
234
|
-
printable += character;
|
|
235
|
-
}
|
|
236
|
-
}
|
|
237
|
-
flushPrintable();
|
|
238
|
-
return true;
|
|
239
|
-
}
|
|
240
|
-
#clampToDesktop(x, y) {
|
|
241
|
-
return [
|
|
242
|
-
Math.max(0, Math.min((this.display.width || 1) - 1, Math.round(x))),
|
|
243
|
-
Math.max(0, Math.min((this.display.height || 1) - 1, Math.round(y)))
|
|
244
|
-
];
|
|
245
|
-
}
|
|
246
|
-
/** What the canvas is showing, for a screen capture or a coordinate check. */
|
|
247
|
-
get screenGeometry() {
|
|
248
|
-
return {
|
|
249
|
-
width: this.display.width,
|
|
250
|
-
height: this.display.height,
|
|
251
|
-
viewport: { ...this.display.viewport }
|
|
252
|
-
};
|
|
253
|
-
}
|
|
254
|
-
/**
|
|
255
|
-
* Hand text to the host's clipboard, falling back to typing it when the host
|
|
256
|
-
* declined the clipboard channel -- xrdp builds often do.
|
|
257
|
-
*/
|
|
258
|
-
clipboardPasteFrom(text) {
|
|
259
|
-
if (!text) return;
|
|
260
|
-
const shared = this.client.setClipboardText(text);
|
|
261
|
-
if (!shared || typeof shared.then !== "function") {
|
|
262
|
-
this.client.sendUnicode(text);
|
|
263
|
-
return;
|
|
264
|
-
}
|
|
265
|
-
shared.then((acknowledged) => {
|
|
266
|
-
if (!acknowledged) this.client.sendUnicode(text);
|
|
267
|
-
});
|
|
268
|
-
}
|
|
269
|
-
/**
|
|
270
|
-
* Deliver text into the session, which is what the clipboard drawer's button
|
|
271
|
-
* has always visibly done. `clipboardPasteFrom` only loads the clipboard, the
|
|
272
|
-
* way noVNC's method of that name does.
|
|
273
|
-
*/
|
|
274
|
-
pasteText(text) {
|
|
275
|
-
return text ? this.client.pasteToHost(text) : false;
|
|
276
|
-
}
|
|
277
|
-
releaseKeyboard() {
|
|
278
|
-
this.display.releaseAllKeys();
|
|
279
|
-
this.display.blur();
|
|
280
|
-
}
|
|
281
|
-
/** True once the host has agreed to share its clipboard. */
|
|
282
|
-
get clipboardShared() {
|
|
283
|
-
return this.client.clipboardShared;
|
|
284
|
-
}
|
|
285
|
-
disconnect() {
|
|
286
|
-
this.remoteAppLayoutObserver?.disconnect();
|
|
287
|
-
this.client.disconnect();
|
|
288
|
-
this.display.destroy();
|
|
289
|
-
this._rfbConnectionState = "disconnected";
|
|
290
|
-
}
|
|
291
|
-
}
|
|
292
|
-
const rdpDriver = {
|
|
293
|
-
protocol: "rdp",
|
|
294
|
-
label: "RDP Client",
|
|
295
|
-
defaultPort: DEFAULT_PORTS.rdp,
|
|
296
|
-
dialog: DIALOG,
|
|
297
|
-
buildUrl,
|
|
298
|
-
createSession: (container, url, options) => new RdpSession(container, url, options),
|
|
299
|
-
// The RDP client logs its own progress, so there is nothing to add here.
|
|
300
|
-
describeState: () => ({}),
|
|
301
|
-
describeDisconnect
|
|
302
|
-
};
|
|
303
|
-
export {
|
|
304
|
-
RdpSession,
|
|
305
|
-
rdpDriver
|
|
306
|
-
};
|
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
export declare class Tls12Client {
|
|
2
|
-
#private;
|
|
3
|
-
/**
|
|
4
|
-
* @param {(bytes: Uint8Array) => void} send write raw bytes to the transport
|
|
5
|
-
* @param {(bytes: Uint8Array) => void} onData decrypted application data
|
|
6
|
-
* @param {(error: Error) => void} onError fatal protocol failure
|
|
7
|
-
*/
|
|
8
|
-
constructor({ send, onData, onError }: {
|
|
9
|
-
onData: any;
|
|
10
|
-
onError: any;
|
|
11
|
-
send: any;
|
|
12
|
-
});
|
|
13
|
-
start(): Promise<any>;
|
|
14
|
-
/** Feed transport bytes. Calls are serialized, so order is preserved. */
|
|
15
|
-
receive(bytes: Uint8Array): any;
|
|
16
|
-
/** Send application data once the handshake has completed. */
|
|
17
|
-
write(plaintext: Uint8Array): any;
|
|
18
|
-
}
|