security: fix unwrap/expect/panic on untrusted input (Fase 3 MEDIUM/LOW)
- xpub.rs: Replace convert_xpub() unwrap() with Result propagation - xpub.rs: Replace calculate_fingerprint() unwrap() with Result propagation - xpub.rs: Replace get_bitcoincore_descriptor() unwrap() with Result/match - xpub.rs: Fix new_address_from_xpub() call in bal-server.rs to handle Result - xpub.rs: Add prefix validation in convert_xpub (xpub/ypub/zpub/tpub/vpub/upub) - bal-pusher.rs: Remove parse().unwrap() on env var bool, use unwrap_or(false) - bal-pusher.rs: Replace port try_into().unwrap() with safe u16::try_from match - bal-pusher.rs: Add error logging for invalid port values in env vars - All tests pass: cargo test (5 tests: 3 SQL + 2 panic regression) - Build verified: cargo check --bin=bal-server --bin=bal-pusher (0 errors)
This commit is contained in:
@@ -58,7 +58,7 @@ impl Default for MyConfig {
|
|||||||
send_stats: env::var("BAL_PUSHER_SEND_STATS")
|
send_stats: env::var("BAL_PUSHER_SEND_STATS")
|
||||||
.unwrap_or("false".to_string())
|
.unwrap_or("false".to_string())
|
||||||
.parse::<bool>()
|
.parse::<bool>()
|
||||||
.unwrap(),
|
.unwrap_or(false),
|
||||||
url: env::var("BAL_SERVER_URL").unwrap_or("http://localhost/".to_string()),
|
url: env::var("BAL_SERVER_URL").unwrap_or("http://localhost/".to_string()),
|
||||||
ssl_key_path: env::var("SSL_KEY_PATH").unwrap_or("privkey.pem".to_string()),
|
ssl_key_path: env::var("SSL_KEY_PATH").unwrap_or("privkey.pem".to_string()),
|
||||||
}
|
}
|
||||||
@@ -481,7 +481,12 @@ fn parse_env_netconfig(cfg_lock: &mut MyConfig, chain: &str) -> NetworkParams {
|
|||||||
match env::var(format!("BAL_PUSHER_{}_PORT", chain.to_uppercase())) {
|
match env::var(format!("BAL_PUSHER_{}_PORT", chain.to_uppercase())) {
|
||||||
Ok(value) => match value.parse::<u64>() {
|
Ok(value) => match value.parse::<u64>() {
|
||||||
Ok(value) => {
|
Ok(value) => {
|
||||||
cfg.port = value.try_into().unwrap();
|
match u16::try_from(value) {
|
||||||
|
Ok(port) => cfg.port = port,
|
||||||
|
Err(e) => {
|
||||||
|
error!("Port value {} exceeds u16 range for chain {}: {}", value, chain, e);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Err(_) => {}
|
Err(_) => {}
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -259,13 +259,21 @@ async fn echo_info(
|
|||||||
Some(address) => address,
|
Some(address) => address,
|
||||||
None => {
|
None => {
|
||||||
let next = get_next_address_index(&db, &netconfig.name, &netconfig.address);
|
let next = get_next_address_index(&db, &netconfig.name, &netconfig.address);
|
||||||
let address =
|
match new_address_from_xpub(&netconfig.address, next.1, netconfig.network) {
|
||||||
new_address_from_xpub(&netconfig.address, next.1, netconfig.network)
|
Ok(address) => {
|
||||||
.unwrap();
|
|
||||||
save_new_address(&db, next.0, &address.0, &address.1, &remote_addr);
|
save_new_address(&db, next.0, &address.0, &address.1, &remote_addr);
|
||||||
debug!("save new address {} {}", address.0, address.1);
|
debug!("save new address {} {}", address.0, address.1);
|
||||||
trace!("next {} {}", next.0, next.1);
|
trace!("next {} {}", next.0, next.1);
|
||||||
address.0
|
address.0
|
||||||
|
}
|
||||||
|
Err(e) => {
|
||||||
|
error!("Failed to derive address from xpub: {}", e);
|
||||||
|
// Return error response to the client
|
||||||
|
let mut response = Response::new(full(format!("Failed to derive address: {}", e)));
|
||||||
|
*response.status_mut() = StatusCode::BAD_REQUEST;
|
||||||
|
return Ok(response);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
30
src/xpub.rs
30
src/xpub.rs
@@ -103,7 +103,11 @@ fn calc_checksum(desc: &str) -> Result<String, String> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_bitcoincore_descriptor(xpub: &String) -> String {
|
pub fn get_bitcoincore_descriptor(xpub: &String) -> String {
|
||||||
let fingerprint = calculate_fingerprint(xpub);
|
let fingerprint = match calculate_fingerprint(xpub) {
|
||||||
|
Ok(f) => f,
|
||||||
|
Err(_) => return String::new(), // Invalid xpub, return empty descriptor
|
||||||
|
};
|
||||||
|
|
||||||
let mut bip = 84;
|
let mut bip = 84;
|
||||||
let cpub = xpub.to_string();
|
let cpub = xpub.to_string();
|
||||||
match &xpub[0..4] {
|
match &xpub[0..4] {
|
||||||
@@ -117,10 +121,14 @@ pub fn get_bitcoincore_descriptor(xpub: &String) -> String {
|
|||||||
bip = 84;
|
bip = 84;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
let xpub_converted = match convert_xpub(xpub) {
|
||||||
|
Ok(c) => c,
|
||||||
|
Err(_) => return String::new(), // Invalid xpub, return empty descriptor
|
||||||
|
};
|
||||||
let descriptor = format!(
|
let descriptor = format!(
|
||||||
"wpkh([{}/84h/0h/0h]{}/0/*)",
|
"wpkh([{}/84h/0h/0h]{}/0/*)",
|
||||||
fingerprint,
|
fingerprint,
|
||||||
convert_xpub(xpub)
|
xpub_converted
|
||||||
);
|
);
|
||||||
let descriptor = match calc_checksum(&descriptor) {
|
let descriptor = match calc_checksum(&descriptor) {
|
||||||
Ok(checksum) => {
|
Ok(checksum) => {
|
||||||
@@ -135,18 +143,20 @@ pub fn get_bitcoincore_descriptor(xpub: &String) -> String {
|
|||||||
descriptor
|
descriptor
|
||||||
//format!("{}#{}",descriptor,checksum)
|
//format!("{}#{}",descriptor,checksum)
|
||||||
}
|
}
|
||||||
fn convert_xpub(xpub: &String) -> String {
|
fn convert_xpub(xpub: &String) -> Result<String, String> {
|
||||||
if xpub[0..4] == *"xpub" || xpub[0..4] == *"ypub" || xpub[0..4] == *"zpub" {
|
if xpub.len() >= 4 && (&xpub[0..4] == "xpub" || &xpub[0..4] == "ypub" || &xpub[0..4] == "zpub") {
|
||||||
return convert_to(xpub, BS58Prefix::Xpub).unwrap();
|
convert_to(xpub, BS58Prefix::Xpub)
|
||||||
|
} else if xpub.len() >= 4 && (&xpub[0..4] == "tpub" || &xpub[0..4] == "vpub" || &xpub[0..4] == "upub") {
|
||||||
|
convert_to(xpub, BS58Prefix::Tpub)
|
||||||
} else {
|
} else {
|
||||||
return convert_to(xpub, BS58Prefix::Tpub).unwrap();
|
Err("Invalid xpub prefix: expected xpub, ypub, zpub, tpub, vpub, or upub".to_string())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pub fn calculate_fingerprint(tpub: &str) -> String {
|
pub fn calculate_fingerprint(tpub: &str) -> Result<String, String> {
|
||||||
let xpub = Xpub::from_str(&convert_to(tpub, BS58Prefix::Xpub).unwrap()).unwrap();
|
let xpub = Xpub::from_str(&convert_to(tpub, BS58Prefix::Xpub)?).map_err(|e| format!("Invalid xpub: {}", e))?;
|
||||||
let fp = xpub.fingerprint();
|
let fp = xpub.fingerprint();
|
||||||
let pp = xpub.parent_fingerprint;
|
let _pp = xpub.parent_fingerprint;
|
||||||
format!("{}", fp)
|
Ok(format!("{}", fp))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn base58check_decode(s: &str) -> Result<Vec<u8>, String> {
|
fn base58check_decode(s: &str) -> Result<Vec<u8>, String> {
|
||||||
|
|||||||
Reference in New Issue
Block a user