From 9bd215356b944c2ce0d9d16b0c65982c36f18f03 Mon Sep 17 00:00:00 2001 From: rob thijssen Date: Thu, 7 May 2026 11:50:38 +0300 Subject: [PATCH] fix: add __templates__ and image button coords to KVM form submissions The Belkin firmware requires: 1. A hidden __templates__ field in all form POSTs 2. Image button actions submitted as name.x=0&name.y=0 (not name=value) 3. ECG_kvm_powerport_cnt hidden field Without these, the device returns "Permission denied" on port config saves. Also fixed the switch endpoint with the same pattern. Co-Authored-By: Claude Opus 4.6 (1M context) --- crates/ericrfb-proxy/src/kvm.rs | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/crates/ericrfb-proxy/src/kvm.rs b/crates/ericrfb-proxy/src/kvm.rs index 643d11a..05d886a 100644 --- a/crates/ericrfb-proxy/src/kvm.rs +++ b/crates/ericrfb-proxy/src/kvm.rs @@ -93,10 +93,7 @@ fn extract_selected_option(html: &str, name: &str) -> Option { // Find "selected>" then the text until newline or '<' let sel_pos = after.find("selected>")?; let text_start = sel_pos + "selected>".len(); - let text_end = after[text_start..] - .find(['<', '\n']) - .unwrap_or(0) - + text_start; + let text_end = after[text_start..].find(['<', '\n']).unwrap_or(0) + text_start; Some(after[text_start..text_end].trim().to_string()) } @@ -175,6 +172,8 @@ pub async fn save_ports( let cookie = get_cookie(&state).await?; let mut form: Vec<(String, String)> = vec![ + // Hidden template field required by the firmware + ("__templates__".into(), " kvm_port_list kvm".into()), ("ECG_kvm_nr_ports".into(), req.port_count.to_string()), ( "ECG_key_pause_duration".into(), @@ -182,6 +181,7 @@ pub async fn save_ports( ), ("ECG_kvm_portname_cnt".into(), req.port_count.to_string()), ("ECG_kvm_hotkey_cnt".into(), req.port_count.to_string()), + ("ECG_kvm_powerport_cnt".into(), req.port_count.to_string()), ("ECG_kvm_show_in_rc_cnt".into(), req.port_count.to_string()), ]; @@ -199,7 +199,9 @@ pub async fn save_ports( } } - form.push(("action_apply".into(), "Apply".into())); + // Image button submits with .x/.y coordinates + form.push(("action_apply.x".into(), "0".into())); + form.push(("action_apply.y".into(), "0".into())); let resp = state .http_client @@ -233,8 +235,13 @@ pub async fn switch_port( let cookie = get_cookie(&state).await?; let form = [ + ( + "__templates__", + " kvm_port_list rc_preview power_control_ipmi power_control_intern power_control_direct".to_string(), + ), ("kvm_active_port_0", req.port.to_string()), - ("action_switch_0", "Switch".into()), + ("action_switch_0.x", "0".into()), + ("action_switch_0.y", "0".into()), ]; state