119 lines
3.9 KiB
Rust
119 lines
3.9 KiB
Rust
|
|
use super::RpcHandler;
|
||
|
|
use anyhow::Result;
|
||
|
|
use archipelago_openwrt::{
|
||
|
|
detect,
|
||
|
|
router::Router,
|
||
|
|
tollgate::{self, TollGateConfig},
|
||
|
|
};
|
||
|
|
|
||
|
|
/// Default port for the local Cashu mint (nutshell / cashu-mint app).
|
||
|
|
const LOCAL_MINT_PORT: u16 = 3338;
|
||
|
|
|
||
|
|
impl RpcHandler {
|
||
|
|
/// Scan the local subnet for OpenWrt routers.
|
||
|
|
///
|
||
|
|
/// Params: `{ "subnet": "192.168.1.0", "prefix": 24,
|
||
|
|
/// "ssh_user": "root", "ssh_password": "" }`
|
||
|
|
pub(super) async fn handle_openwrt_scan(
|
||
|
|
&self,
|
||
|
|
params: Option<serde_json::Value>,
|
||
|
|
) -> Result<serde_json::Value> {
|
||
|
|
let p = params.unwrap_or_default();
|
||
|
|
let subnet: [u8; 4] = parse_ipv4(
|
||
|
|
p.get("subnet").and_then(|v| v.as_str()).unwrap_or("192.168.1.0"),
|
||
|
|
)?;
|
||
|
|
let prefix = p.get("prefix").and_then(|v| v.as_u64()).unwrap_or(24) as u8;
|
||
|
|
let ssh_user = p
|
||
|
|
.get("ssh_user")
|
||
|
|
.and_then(|v| v.as_str())
|
||
|
|
.unwrap_or("root")
|
||
|
|
.to_string();
|
||
|
|
let ssh_password = p
|
||
|
|
.get("ssh_password")
|
||
|
|
.and_then(|v| v.as_str())
|
||
|
|
.unwrap_or("")
|
||
|
|
.to_string();
|
||
|
|
|
||
|
|
let routers = detect::scan_subnet(subnet, prefix, &ssh_user, &ssh_password).await;
|
||
|
|
let ips: Vec<String> = routers.iter().map(|ip| ip.to_string()).collect();
|
||
|
|
|
||
|
|
Ok(serde_json::json!({ "routers": ips }))
|
||
|
|
}
|
||
|
|
|
||
|
|
/// Provision TollGate on an OpenWrt router and create the "archipelago" SSID.
|
||
|
|
///
|
||
|
|
/// Params: `{ "host": "192.168.1.1", "ssh_user": "root", "ssh_password": "",
|
||
|
|
/// "price_sats": 10, "step_size_ms": 60000, "min_steps": 1,
|
||
|
|
/// "mint_url": "<optional override>" }`
|
||
|
|
///
|
||
|
|
/// `mint_url` defaults to `http://<this node's IP>:3338` — the local Cashu
|
||
|
|
/// mint that must be running as an Archy app before calling this endpoint.
|
||
|
|
pub(super) async fn handle_openwrt_provision_tollgate(
|
||
|
|
&self,
|
||
|
|
params: Option<serde_json::Value>,
|
||
|
|
) -> Result<serde_json::Value> {
|
||
|
|
let p = params.ok_or_else(|| anyhow::anyhow!("Missing params"))?;
|
||
|
|
|
||
|
|
let host = p
|
||
|
|
.get("host")
|
||
|
|
.and_then(|v| v.as_str())
|
||
|
|
.ok_or_else(|| anyhow::anyhow!("Missing host"))?
|
||
|
|
.to_string();
|
||
|
|
let ssh_user = p
|
||
|
|
.get("ssh_user")
|
||
|
|
.and_then(|v| v.as_str())
|
||
|
|
.unwrap_or("root")
|
||
|
|
.to_string();
|
||
|
|
let ssh_password = p
|
||
|
|
.get("ssh_password")
|
||
|
|
.and_then(|v| v.as_str())
|
||
|
|
.unwrap_or("")
|
||
|
|
.to_string();
|
||
|
|
|
||
|
|
let default_mint_url = format!("http://{}:{}", self.config.host_ip, LOCAL_MINT_PORT);
|
||
|
|
let mint_url = p
|
||
|
|
.get("mint_url")
|
||
|
|
.and_then(|v| v.as_str())
|
||
|
|
.unwrap_or(&default_mint_url)
|
||
|
|
.to_string();
|
||
|
|
|
||
|
|
let config = TollGateConfig {
|
||
|
|
ssid: "archipelago".to_string(),
|
||
|
|
mint_url,
|
||
|
|
price_sats: p.get("price_sats").and_then(|v| v.as_u64()).unwrap_or(10),
|
||
|
|
step_size_ms: p
|
||
|
|
.get("step_size_ms")
|
||
|
|
.and_then(|v| v.as_u64())
|
||
|
|
.unwrap_or(60_000),
|
||
|
|
min_steps: p
|
||
|
|
.get("min_steps")
|
||
|
|
.and_then(|v| v.as_u64())
|
||
|
|
.unwrap_or(1) as u32,
|
||
|
|
};
|
||
|
|
|
||
|
|
let router = Router::connect_password(&host, 22, &ssh_user, &ssh_password)?;
|
||
|
|
router.verify_openwrt()?;
|
||
|
|
tollgate::provision(&router, &config).await?;
|
||
|
|
|
||
|
|
Ok(serde_json::json!({
|
||
|
|
"ok": true,
|
||
|
|
"host": host,
|
||
|
|
"ssid": config.ssid,
|
||
|
|
"mint_url": config.mint_url,
|
||
|
|
}))
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
fn parse_ipv4(s: &str) -> Result<[u8; 4]> {
|
||
|
|
let parts: Vec<&str> = s.split('.').collect();
|
||
|
|
if parts.len() != 4 {
|
||
|
|
anyhow::bail!("Invalid IPv4: {}", s);
|
||
|
|
}
|
||
|
|
Ok([
|
||
|
|
parts[0].parse()?,
|
||
|
|
parts[1].parse()?,
|
||
|
|
parts[2].parse()?,
|
||
|
|
parts[3].parse()?,
|
||
|
|
])
|
||
|
|
}
|