fix(rdp): parse guacd args response and send matching positional connect values
This commit is contained in:
parent
72526487c3
commit
9d3a93bea9
@ -54,9 +54,19 @@ export class GuacamoleService {
|
||||
// Clear the connect timeout — handshake completed
|
||||
socket.setTimeout(0);
|
||||
|
||||
// Phase 2: CONNECT with RDP parameters
|
||||
const connectInstruction = this.buildConnectInstruction(params);
|
||||
this.logger.debug(`Sending connect instruction to guacd`);
|
||||
// Parse the args instruction to get expected parameter names
|
||||
const argsInstruction = buffer.substring(0, semicolonIdx + 1);
|
||||
const argNames = this.decode(argsInstruction);
|
||||
|
||||
// First element is the opcode ("args"), rest are parameter names
|
||||
if (argNames[0] === 'args') {
|
||||
argNames.shift();
|
||||
}
|
||||
this.logger.log(`guacd expects ${argNames.length} args: ${argNames.join(', ')}`);
|
||||
|
||||
// Phase 2: CONNECT — send values in the exact order guacd expects
|
||||
const connectInstruction = this.buildConnectInstruction(params, argNames);
|
||||
this.logger.debug(`Sending connect instruction with ${argNames.length} values`);
|
||||
socket.write(connectInstruction);
|
||||
|
||||
resolve(socket);
|
||||
@ -78,7 +88,8 @@ export class GuacamoleService {
|
||||
});
|
||||
}
|
||||
|
||||
private buildConnectInstruction(params: {
|
||||
private buildConnectInstruction(
|
||||
params: {
|
||||
hostname: string;
|
||||
port: number;
|
||||
username: string;
|
||||
@ -90,19 +101,20 @@ export class GuacamoleService {
|
||||
security?: string;
|
||||
colorDepth?: number;
|
||||
ignoreCert?: boolean;
|
||||
}): string {
|
||||
// The connect instruction sends all RDP connection parameters as positional args.
|
||||
// guacd expects exactly the args it listed in the "args" response to SELECT.
|
||||
// We send the full standard RDP parameter set.
|
||||
const args: Record<string, string> = {
|
||||
hostname: params.hostname,
|
||||
port: String(params.port),
|
||||
username: params.username,
|
||||
password: params.password,
|
||||
width: String(params.width),
|
||||
height: String(params.height),
|
||||
dpi: String(params.dpi || 96),
|
||||
security: params.security || 'any',
|
||||
},
|
||||
argNames: string[],
|
||||
): string {
|
||||
// Map our params to guacd's expected arg names
|
||||
const paramMap: Record<string, string> = {
|
||||
'hostname': params.hostname,
|
||||
'port': String(params.port),
|
||||
'username': params.username,
|
||||
'password': params.password,
|
||||
'domain': params.domain || '',
|
||||
'width': String(params.width),
|
||||
'height': String(params.height),
|
||||
'dpi': String(params.dpi || 96),
|
||||
'security': params.security || 'any',
|
||||
'color-depth': String(params.colorDepth || 24),
|
||||
'ignore-cert': params.ignoreCert !== false ? 'true' : 'false',
|
||||
'disable-audio': 'false',
|
||||
@ -110,14 +122,55 @@ export class GuacamoleService {
|
||||
'enable-theming': 'true',
|
||||
'enable-font-smoothing': 'true',
|
||||
'resize-method': 'reconnect',
|
||||
'server-layout': '',
|
||||
'timezone': '',
|
||||
'console': '',
|
||||
'initial-program': '',
|
||||
'client-name': 'Wraith',
|
||||
'enable-full-window-drag': 'false',
|
||||
'enable-desktop-composition': 'false',
|
||||
'enable-menu-animations': 'false',
|
||||
'disable-bitmap-caching': 'false',
|
||||
'disable-offscreen-caching': 'false',
|
||||
'disable-glyph-caching': 'false',
|
||||
'preconnection-id': '',
|
||||
'preconnection-blob': '',
|
||||
'enable-sftp': 'false',
|
||||
'sftp-hostname': '',
|
||||
'sftp-port': '',
|
||||
'sftp-username': '',
|
||||
'sftp-password': '',
|
||||
'sftp-private-key': '',
|
||||
'sftp-passphrase': '',
|
||||
'sftp-directory': '',
|
||||
'sftp-root-directory': '',
|
||||
'sftp-server-alive-interval': '',
|
||||
'recording-path': '',
|
||||
'recording-name': '',
|
||||
'recording-exclude-output': '',
|
||||
'recording-exclude-mouse': '',
|
||||
'recording-include-keys': '',
|
||||
'create-recording-path': '',
|
||||
'remote-app': '',
|
||||
'remote-app-dir': '',
|
||||
'remote-app-args': '',
|
||||
'gateway-hostname': '',
|
||||
'gateway-port': '',
|
||||
'gateway-domain': '',
|
||||
'gateway-username': '',
|
||||
'gateway-password': '',
|
||||
'load-balance-info': '',
|
||||
'normalize-clipboard': '',
|
||||
'force-lossless': '',
|
||||
'wol-send-packet': '',
|
||||
'wol-mac-addr': '',
|
||||
'wol-broadcast-addr': '',
|
||||
'wol-udp-port': '',
|
||||
'wol-wait-time': '',
|
||||
};
|
||||
|
||||
if (params.domain) {
|
||||
args['domain'] = params.domain;
|
||||
}
|
||||
|
||||
// Build the connect instruction with opcode + all arg values
|
||||
const values = Object.values(args);
|
||||
// Build values array matching the exact order guacd expects
|
||||
const values = argNames.map((name) => paramMap[name] ?? '');
|
||||
return this.encode('connect', ...values);
|
||||
}
|
||||
|
||||
@ -133,7 +186,6 @@ export class GuacamoleService {
|
||||
|
||||
/**
|
||||
* Decode a Guacamole instruction string back to a string array.
|
||||
* Handles multiple instructions in a single buffer chunk.
|
||||
*/
|
||||
decode(instruction: string): string[] {
|
||||
const parts: string[] = [];
|
||||
|
||||
Loading…
Reference in New Issue
Block a user