mirror of https://github.com/ospab/ostp.git
fix(migrate): backfill outbound SOCKS5 credential fields
migrate_server_json backfilled the `api` section but not the newer
outbound.username / outbound.password (added with SOCKS5 upstream auth), so a
server config predating them reported "nothing to migrate" while the fields were
absent. Now backfilled to their "" (no-auth) default.
Deliberately does NOT inject the optional bind_ip (top level) or per-rule
send_from: absent means "use the default source", which is correct and concise,
and a placeholder would be either stripped (null) or, worse, parse as an invalid
source IP (""). Those stay hand-added when the operator wants multi-address
egress. Test covers both the backfill and the no-inject.
This commit is contained in:
parent
c1b7172fc0
commit
d170b6de73
|
|
@ -353,6 +353,22 @@ pub fn migrate_server_json(json: Value) -> (Value, MigrationReport) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Backfill the SOCKS5 credential fields on `outbound`, added after some
|
||||||
|
// server configs already existed. These are plain strings that default to
|
||||||
|
// "" (no-auth), so making them explicit is safe and concise. The optional
|
||||||
|
// `bind_ip` (top level) and per-rule `send_from` are deliberately NOT
|
||||||
|
// backfilled: absent means "use the default source", which is correct — and
|
||||||
|
// a placeholder would either be stripped (null) or, worse, parse as an
|
||||||
|
// invalid source IP ("").
|
||||||
|
if let Some(outbound) = obj.get_mut("outbound").and_then(|o| o.as_object_mut()) {
|
||||||
|
for key in ["username", "password"] {
|
||||||
|
if !outbound.contains_key(key) {
|
||||||
|
report.note(format!("Added outbound.{key} = \"\" (missing default)"));
|
||||||
|
outbound.insert(key.to_string(), json!(""));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
(out, report)
|
(out, report)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -584,6 +600,31 @@ mod tests {
|
||||||
assert!(report.notes.iter().any(|n| n.contains("api.token")));
|
assert!(report.notes.iter().any(|n| n.contains("api.token")));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// A server config whose `outbound` predates the SOCKS5 credential fields
|
||||||
|
/// must get them backfilled — this is exactly the "migrate said nothing to
|
||||||
|
/// migrate but the new fields were missing" gap. The optional bind_ip /
|
||||||
|
/// send_from must NOT be injected (absent = correct).
|
||||||
|
#[test]
|
||||||
|
fn server_migrate_backfills_outbound_credentials() {
|
||||||
|
let old = json!({
|
||||||
|
"listen": "0.0.0.0:50000",
|
||||||
|
"access_keys": ["k1"],
|
||||||
|
"api": { "enabled": true, "bind": "0.0.0.0:9090", "webpath": "", "username": "", "password_hash": "" },
|
||||||
|
"outbound": {
|
||||||
|
"enabled": false, "protocol": "socks5", "address": "127.0.0.1", "port": 40000,
|
||||||
|
"default_action": "proxy",
|
||||||
|
"rules": [{ "action": "proxy", "domain_suffix": [".onion"] }]
|
||||||
|
}
|
||||||
|
});
|
||||||
|
let (new, report) = migrate_server_json(old);
|
||||||
|
assert!(report.changed, "adding the missing credential fields is a change");
|
||||||
|
assert_eq!(new["outbound"]["username"], "");
|
||||||
|
assert_eq!(new["outbound"]["password"], "");
|
||||||
|
// Optional fields are left absent, not injected.
|
||||||
|
assert!(new.get("bind_ip").is_none());
|
||||||
|
assert!(new["outbound"]["rules"][0].get("send_from").is_none());
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn detect_kind_falls_back_to_structural_sniffing_without_mode_tag() {
|
fn detect_kind_falls_back_to_structural_sniffing_without_mode_tag() {
|
||||||
assert_eq!(detect_kind(&json!({"access_key": "x", "server": "y"})), Some(ConfigKind::Client));
|
assert_eq!(detect_kind(&json!({"access_key": "x", "server": "y"})), Some(ConfigKind::Client));
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue