2026-03-04 05:23:42 +00:00
|
|
|
mod auth;
|
2026-03-05 13:56:29 +00:00
|
|
|
mod bitcoin;
|
2026-03-04 05:23:42 +00:00
|
|
|
mod container;
|
2026-03-05 13:56:29 +00:00
|
|
|
mod lnd;
|
2026-03-04 05:23:42 +00:00
|
|
|
mod node;
|
|
|
|
|
mod package;
|
|
|
|
|
mod peers;
|
feat: add TOTP 2FA, API key switcher, login progress bar, and alpha hardening plan
- TOTP 2FA: full setup/confirm/disable/login flow with Argon2id + ChaCha20-Poly1305
encrypted secret storage, QR code generation, and bcrypt-hashed backup codes
- API key switcher: OAuth vs personal API key toggle in AIUI chat settings with
status indicator, key validation, and help text
- Login progress bar: server startup detection with health check polling, form
disabled until server is ready
- AI quarantine docs: comprehensive HTML page documenting all 6 security layers
- Settings: AI Data Access permission toggles with per-category control
- Alpha hardening plan: 28-task overnight automation plan across 7 phases
(onboarding, login, app install, AIUI, UI polish, security, ISO build)
- Backlog: node discovery spatial map feature for alpha demo
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-06 12:23:57 +00:00
|
|
|
mod totp;
|
2026-03-04 05:23:42 +00:00
|
|
|
|
|
|
|
|
use crate::auth::AuthManager;
|
|
|
|
|
use crate::config::Config;
|
|
|
|
|
use crate::container::DevContainerOrchestrator;
|
|
|
|
|
use crate::port_allocator::PortAllocator;
|
2026-03-06 03:26:56 +00:00
|
|
|
use crate::session::{self, LoginRateLimiter, SessionStore};
|
2026-03-04 05:23:42 +00:00
|
|
|
use crate::state::StateManager;
|
|
|
|
|
use anyhow::{Context, Result};
|
|
|
|
|
use hyper::{Request, Response, StatusCode};
|
|
|
|
|
use serde::{Deserialize, Serialize};
|
2026-03-06 03:26:56 +00:00
|
|
|
use std::net::IpAddr;
|
2026-03-04 05:23:42 +00:00
|
|
|
use std::sync::{Arc, Mutex};
|
|
|
|
|
use tracing::{debug, error};
|
|
|
|
|
|
|
|
|
|
#[derive(Debug, Deserialize)]
|
|
|
|
|
struct RpcRequest {
|
|
|
|
|
method: String,
|
|
|
|
|
params: Option<serde_json::Value>,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[derive(Debug, Serialize)]
|
|
|
|
|
struct RpcResponse {
|
|
|
|
|
result: Option<serde_json::Value>,
|
|
|
|
|
error: Option<RpcError>,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[derive(Debug, Serialize)]
|
|
|
|
|
struct RpcError {
|
|
|
|
|
code: i32,
|
|
|
|
|
message: String,
|
|
|
|
|
data: Option<serde_json::Value>,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Default dev password when no user is set up (matches mock-backend).
|
|
|
|
|
pub(crate) const DEV_DEFAULT_PASSWORD: &str = "password123";
|
|
|
|
|
|
2026-03-06 03:26:56 +00:00
|
|
|
/// Methods that do not require a valid session cookie.
|
|
|
|
|
const UNAUTHENTICATED_METHODS: &[&str] = &[
|
|
|
|
|
"auth.login",
|
feat: add TOTP 2FA, API key switcher, login progress bar, and alpha hardening plan
- TOTP 2FA: full setup/confirm/disable/login flow with Argon2id + ChaCha20-Poly1305
encrypted secret storage, QR code generation, and bcrypt-hashed backup codes
- API key switcher: OAuth vs personal API key toggle in AIUI chat settings with
status indicator, key validation, and help text
- Login progress bar: server startup detection with health check polling, form
disabled until server is ready
- AI quarantine docs: comprehensive HTML page documenting all 6 security layers
- Settings: AI Data Access permission toggles with per-category control
- Alpha hardening plan: 28-task overnight automation plan across 7 phases
(onboarding, login, app install, AIUI, UI polish, security, ISO build)
- Backlog: node discovery spatial map feature for alpha demo
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-06 12:23:57 +00:00
|
|
|
"auth.login.totp",
|
|
|
|
|
"auth.login.backup",
|
2026-03-06 03:26:56 +00:00
|
|
|
"auth.isOnboardingComplete",
|
|
|
|
|
"health",
|
|
|
|
|
];
|
|
|
|
|
|
2026-03-04 05:23:42 +00:00
|
|
|
pub struct RpcHandler {
|
|
|
|
|
config: Config,
|
|
|
|
|
auth_manager: AuthManager,
|
|
|
|
|
orchestrator: Option<Arc<DevContainerOrchestrator>>,
|
|
|
|
|
state_manager: Arc<StateManager>,
|
|
|
|
|
port_allocator: Arc<Mutex<PortAllocator>>,
|
2026-03-06 03:26:56 +00:00
|
|
|
pub session_store: SessionStore,
|
|
|
|
|
login_rate_limiter: LoginRateLimiter,
|
2026-03-04 05:23:42 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl RpcHandler {
|
2026-03-06 03:26:56 +00:00
|
|
|
pub async fn new(
|
|
|
|
|
config: Config,
|
|
|
|
|
state_manager: Arc<StateManager>,
|
|
|
|
|
session_store: SessionStore,
|
|
|
|
|
) -> Result<Self> {
|
2026-03-04 05:23:42 +00:00
|
|
|
let auth_manager = AuthManager::new(config.data_dir.clone());
|
|
|
|
|
let orchestrator = if config.dev_mode {
|
|
|
|
|
Some(Arc::new(
|
|
|
|
|
DevContainerOrchestrator::new(config.clone()).await?,
|
|
|
|
|
))
|
|
|
|
|
} else {
|
|
|
|
|
None
|
|
|
|
|
};
|
|
|
|
|
let port_allocator = Arc::new(Mutex::new(PortAllocator::new(&config.data_dir)?));
|
|
|
|
|
|
|
|
|
|
Ok(Self {
|
|
|
|
|
config,
|
|
|
|
|
auth_manager,
|
|
|
|
|
orchestrator,
|
|
|
|
|
state_manager,
|
|
|
|
|
port_allocator,
|
2026-03-06 03:26:56 +00:00
|
|
|
session_store,
|
|
|
|
|
login_rate_limiter: LoginRateLimiter::new(),
|
2026-03-04 05:23:42 +00:00
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub async fn handle(
|
|
|
|
|
&self,
|
|
|
|
|
req: Request<hyper::Body>,
|
|
|
|
|
) -> Result<Response<hyper::Body>> {
|
2026-03-06 03:26:56 +00:00
|
|
|
// Extract session cookie before consuming the request
|
|
|
|
|
let (parts, body) = req.into_parts();
|
|
|
|
|
let session_token = session::extract_session_cookie(&parts.headers);
|
|
|
|
|
|
2026-03-04 05:23:42 +00:00
|
|
|
let body_bytes = hyper::body::to_bytes(body).await
|
|
|
|
|
.context("Failed to read body")?;
|
|
|
|
|
|
|
|
|
|
let rpc_req: RpcRequest = serde_json::from_slice(&body_bytes)
|
|
|
|
|
.context("Invalid RPC request")?;
|
|
|
|
|
|
|
|
|
|
debug!("RPC method: {}", rpc_req.method);
|
|
|
|
|
|
2026-03-06 03:26:56 +00:00
|
|
|
// Enforce authentication for non-allowlisted methods
|
|
|
|
|
let is_unauthenticated = UNAUTHENTICATED_METHODS.contains(&rpc_req.method.as_str());
|
|
|
|
|
if !is_unauthenticated {
|
|
|
|
|
let authenticated = match &session_token {
|
|
|
|
|
Some(token) => self.session_store.validate(token).await,
|
|
|
|
|
None => false,
|
|
|
|
|
};
|
|
|
|
|
if !authenticated {
|
|
|
|
|
let rpc_resp = RpcResponse {
|
|
|
|
|
result: None,
|
|
|
|
|
error: Some(RpcError {
|
|
|
|
|
code: 401,
|
|
|
|
|
message: "Unauthorized".to_string(),
|
|
|
|
|
data: None,
|
|
|
|
|
}),
|
|
|
|
|
};
|
|
|
|
|
let resp_body = serde_json::to_vec(&rpc_resp)
|
|
|
|
|
.context("Failed to serialize response")?;
|
|
|
|
|
return Ok(Response::builder()
|
|
|
|
|
.status(StatusCode::UNAUTHORIZED)
|
|
|
|
|
.header("Content-Type", "application/json")
|
|
|
|
|
.body(hyper::Body::from(resp_body))
|
|
|
|
|
.unwrap());
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Rate limit login attempts
|
|
|
|
|
if rpc_req.method == "auth.login" {
|
|
|
|
|
let client_ip = extract_client_ip(&parts.headers);
|
|
|
|
|
if !self.login_rate_limiter.check(client_ip).await {
|
|
|
|
|
let rpc_resp = RpcResponse {
|
|
|
|
|
result: None,
|
|
|
|
|
error: Some(RpcError {
|
|
|
|
|
code: 429,
|
|
|
|
|
message: "Too many login attempts. Try again later.".to_string(),
|
|
|
|
|
data: None,
|
|
|
|
|
}),
|
|
|
|
|
};
|
|
|
|
|
let resp_body = serde_json::to_vec(&rpc_resp)
|
|
|
|
|
.context("Failed to serialize response")?;
|
|
|
|
|
return Ok(Response::builder()
|
|
|
|
|
.status(StatusCode::TOO_MANY_REQUESTS)
|
|
|
|
|
.header("Content-Type", "application/json")
|
|
|
|
|
.header("Retry-After", "60")
|
|
|
|
|
.body(hyper::Body::from(resp_body))
|
|
|
|
|
.unwrap());
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
feat: add TOTP 2FA, API key switcher, login progress bar, and alpha hardening plan
- TOTP 2FA: full setup/confirm/disable/login flow with Argon2id + ChaCha20-Poly1305
encrypted secret storage, QR code generation, and bcrypt-hashed backup codes
- API key switcher: OAuth vs personal API key toggle in AIUI chat settings with
status indicator, key validation, and help text
- Login progress bar: server startup detection with health check polling, form
disabled until server is ready
- AI quarantine docs: comprehensive HTML page documenting all 6 security layers
- Settings: AI Data Access permission toggles with per-category control
- Alpha hardening plan: 28-task overnight automation plan across 7 phases
(onboarding, login, app install, AIUI, UI polish, security, ISO build)
- Backlog: node discovery spatial map feature for alpha demo
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-06 12:23:57 +00:00
|
|
|
// Extract params; clone for post-routing use (login 2FA check needs password)
|
|
|
|
|
let params = rpc_req.params;
|
|
|
|
|
let login_params: Option<serde_json::Value> = if rpc_req.method == "auth.login" {
|
|
|
|
|
params.clone()
|
|
|
|
|
} else {
|
|
|
|
|
None
|
|
|
|
|
};
|
|
|
|
|
|
2026-03-04 05:23:42 +00:00
|
|
|
// Route to handler
|
|
|
|
|
let result = match rpc_req.method.as_str() {
|
feat: add TOTP 2FA, API key switcher, login progress bar, and alpha hardening plan
- TOTP 2FA: full setup/confirm/disable/login flow with Argon2id + ChaCha20-Poly1305
encrypted secret storage, QR code generation, and bcrypt-hashed backup codes
- API key switcher: OAuth vs personal API key toggle in AIUI chat settings with
status indicator, key validation, and help text
- Login progress bar: server startup detection with health check polling, form
disabled until server is ready
- AI quarantine docs: comprehensive HTML page documenting all 6 security layers
- Settings: AI Data Access permission toggles with per-category control
- Alpha hardening plan: 28-task overnight automation plan across 7 phases
(onboarding, login, app install, AIUI, UI polish, security, ISO build)
- Backlog: node discovery spatial map feature for alpha demo
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-06 12:23:57 +00:00
|
|
|
"echo" => self.handle_echo(params).await,
|
|
|
|
|
"server.echo" => self.handle_echo(params).await,
|
|
|
|
|
"auth.login" => self.handle_auth_login(params).await,
|
2026-03-04 05:23:42 +00:00
|
|
|
"auth.logout" => self.handle_auth_logout().await,
|
feat: add TOTP 2FA, API key switcher, login progress bar, and alpha hardening plan
- TOTP 2FA: full setup/confirm/disable/login flow with Argon2id + ChaCha20-Poly1305
encrypted secret storage, QR code generation, and bcrypt-hashed backup codes
- API key switcher: OAuth vs personal API key toggle in AIUI chat settings with
status indicator, key validation, and help text
- Login progress bar: server startup detection with health check polling, form
disabled until server is ready
- AI quarantine docs: comprehensive HTML page documenting all 6 security layers
- Settings: AI Data Access permission toggles with per-category control
- Alpha hardening plan: 28-task overnight automation plan across 7 phases
(onboarding, login, app install, AIUI, UI polish, security, ISO build)
- Backlog: node discovery spatial map feature for alpha demo
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-06 12:23:57 +00:00
|
|
|
"auth.changePassword" => self.handle_auth_change_password(params).await,
|
2026-03-04 05:23:42 +00:00
|
|
|
"auth.onboardingComplete" => self.handle_auth_onboarding_complete().await,
|
|
|
|
|
"auth.isOnboardingComplete" => self.handle_auth_is_onboarding_complete().await,
|
|
|
|
|
"auth.resetOnboarding" => self.handle_auth_reset_onboarding().await,
|
|
|
|
|
|
|
|
|
|
// Container orchestration (for Archipelago-managed containers)
|
feat: add TOTP 2FA, API key switcher, login progress bar, and alpha hardening plan
- TOTP 2FA: full setup/confirm/disable/login flow with Argon2id + ChaCha20-Poly1305
encrypted secret storage, QR code generation, and bcrypt-hashed backup codes
- API key switcher: OAuth vs personal API key toggle in AIUI chat settings with
status indicator, key validation, and help text
- Login progress bar: server startup detection with health check polling, form
disabled until server is ready
- AI quarantine docs: comprehensive HTML page documenting all 6 security layers
- Settings: AI Data Access permission toggles with per-category control
- Alpha hardening plan: 28-task overnight automation plan across 7 phases
(onboarding, login, app install, AIUI, UI polish, security, ISO build)
- Backlog: node discovery spatial map feature for alpha demo
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-06 12:23:57 +00:00
|
|
|
"container-install" => self.handle_container_install(params).await,
|
|
|
|
|
"container-start" => self.handle_container_start(params).await,
|
|
|
|
|
"container-stop" => self.handle_container_stop(params).await,
|
|
|
|
|
"container-remove" => self.handle_container_remove(params).await,
|
2026-03-04 05:23:42 +00:00
|
|
|
"container-list" => self.handle_container_list().await,
|
feat: add TOTP 2FA, API key switcher, login progress bar, and alpha hardening plan
- TOTP 2FA: full setup/confirm/disable/login flow with Argon2id + ChaCha20-Poly1305
encrypted secret storage, QR code generation, and bcrypt-hashed backup codes
- API key switcher: OAuth vs personal API key toggle in AIUI chat settings with
status indicator, key validation, and help text
- Login progress bar: server startup detection with health check polling, form
disabled until server is ready
- AI quarantine docs: comprehensive HTML page documenting all 6 security layers
- Settings: AI Data Access permission toggles with per-category control
- Alpha hardening plan: 28-task overnight automation plan across 7 phases
(onboarding, login, app install, AIUI, UI polish, security, ISO build)
- Backlog: node discovery spatial map feature for alpha demo
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-06 12:23:57 +00:00
|
|
|
"container-status" => self.handle_container_status(params).await,
|
|
|
|
|
"container-logs" => self.handle_container_logs(params).await,
|
|
|
|
|
"container-health" => self.handle_container_health(params).await,
|
2026-03-04 05:23:42 +00:00
|
|
|
|
|
|
|
|
// Package management (for docker-compose apps)
|
feat: add TOTP 2FA, API key switcher, login progress bar, and alpha hardening plan
- TOTP 2FA: full setup/confirm/disable/login flow with Argon2id + ChaCha20-Poly1305
encrypted secret storage, QR code generation, and bcrypt-hashed backup codes
- API key switcher: OAuth vs personal API key toggle in AIUI chat settings with
status indicator, key validation, and help text
- Login progress bar: server startup detection with health check polling, form
disabled until server is ready
- AI quarantine docs: comprehensive HTML page documenting all 6 security layers
- Settings: AI Data Access permission toggles with per-category control
- Alpha hardening plan: 28-task overnight automation plan across 7 phases
(onboarding, login, app install, AIUI, UI polish, security, ISO build)
- Backlog: node discovery spatial map feature for alpha demo
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-06 12:23:57 +00:00
|
|
|
"package.install" => self.handle_package_install(params).await,
|
|
|
|
|
"package.start" => self.handle_package_start(params).await,
|
|
|
|
|
"package.stop" => self.handle_package_stop(params).await,
|
|
|
|
|
"package.restart" => self.handle_package_restart(params).await,
|
|
|
|
|
"package.uninstall" => self.handle_package_uninstall(params).await,
|
2026-03-04 05:23:42 +00:00
|
|
|
|
|
|
|
|
// Bundled app management (for pre-loaded container images)
|
feat: add TOTP 2FA, API key switcher, login progress bar, and alpha hardening plan
- TOTP 2FA: full setup/confirm/disable/login flow with Argon2id + ChaCha20-Poly1305
encrypted secret storage, QR code generation, and bcrypt-hashed backup codes
- API key switcher: OAuth vs personal API key toggle in AIUI chat settings with
status indicator, key validation, and help text
- Login progress bar: server startup detection with health check polling, form
disabled until server is ready
- AI quarantine docs: comprehensive HTML page documenting all 6 security layers
- Settings: AI Data Access permission toggles with per-category control
- Alpha hardening plan: 28-task overnight automation plan across 7 phases
(onboarding, login, app install, AIUI, UI polish, security, ISO build)
- Backlog: node discovery spatial map feature for alpha demo
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-06 12:23:57 +00:00
|
|
|
"bundled-app-start" => self.handle_bundled_app_start(params).await,
|
|
|
|
|
"bundled-app-stop" => self.handle_bundled_app_stop(params).await,
|
2026-03-04 05:23:42 +00:00
|
|
|
|
|
|
|
|
// Node identity and P2P peers
|
feat: add TOTP 2FA, API key switcher, login progress bar, and alpha hardening plan
- TOTP 2FA: full setup/confirm/disable/login flow with Argon2id + ChaCha20-Poly1305
encrypted secret storage, QR code generation, and bcrypt-hashed backup codes
- API key switcher: OAuth vs personal API key toggle in AIUI chat settings with
status indicator, key validation, and help text
- Login progress bar: server startup detection with health check polling, form
disabled until server is ready
- AI quarantine docs: comprehensive HTML page documenting all 6 security layers
- Settings: AI Data Access permission toggles with per-category control
- Alpha hardening plan: 28-task overnight automation plan across 7 phases
(onboarding, login, app install, AIUI, UI polish, security, ISO build)
- Backlog: node discovery spatial map feature for alpha demo
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-06 12:23:57 +00:00
|
|
|
"node-add-peer" => self.handle_node_add_peer(params).await,
|
2026-03-04 05:23:42 +00:00
|
|
|
"node-list-peers" => self.handle_node_list_peers().await,
|
feat: add TOTP 2FA, API key switcher, login progress bar, and alpha hardening plan
- TOTP 2FA: full setup/confirm/disable/login flow with Argon2id + ChaCha20-Poly1305
encrypted secret storage, QR code generation, and bcrypt-hashed backup codes
- API key switcher: OAuth vs personal API key toggle in AIUI chat settings with
status indicator, key validation, and help text
- Login progress bar: server startup detection with health check polling, form
disabled until server is ready
- AI quarantine docs: comprehensive HTML page documenting all 6 security layers
- Settings: AI Data Access permission toggles with per-category control
- Alpha hardening plan: 28-task overnight automation plan across 7 phases
(onboarding, login, app install, AIUI, UI polish, security, ISO build)
- Backlog: node discovery spatial map feature for alpha demo
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-06 12:23:57 +00:00
|
|
|
"node-remove-peer" => self.handle_node_remove_peer(params).await,
|
|
|
|
|
"node-send-message" => self.handle_node_send_message(params).await,
|
|
|
|
|
"node-check-peer" => self.handle_node_check_peer(params).await,
|
2026-03-04 05:23:42 +00:00
|
|
|
"node-messages-received" => self.handle_node_messages_received().await,
|
|
|
|
|
"node-nostr-discover" => self.handle_node_nostr_discover().await,
|
|
|
|
|
"node.did" => self.handle_node_did().await,
|
feat: add TOTP 2FA, API key switcher, login progress bar, and alpha hardening plan
- TOTP 2FA: full setup/confirm/disable/login flow with Argon2id + ChaCha20-Poly1305
encrypted secret storage, QR code generation, and bcrypt-hashed backup codes
- API key switcher: OAuth vs personal API key toggle in AIUI chat settings with
status indicator, key validation, and help text
- Login progress bar: server startup detection with health check polling, form
disabled until server is ready
- AI quarantine docs: comprehensive HTML page documenting all 6 security layers
- Settings: AI Data Access permission toggles with per-category control
- Alpha hardening plan: 28-task overnight automation plan across 7 phases
(onboarding, login, app install, AIUI, UI polish, security, ISO build)
- Backlog: node discovery spatial map feature for alpha demo
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-06 12:23:57 +00:00
|
|
|
"node.signChallenge" => self.handle_node_sign_challenge(params).await,
|
|
|
|
|
"node.createBackup" => self.handle_node_create_backup(params).await,
|
2026-03-04 05:23:42 +00:00
|
|
|
"node.tor-address" => self.handle_node_tor_address().await,
|
|
|
|
|
"node.nostr-publish" => self.handle_node_nostr_publish().await,
|
|
|
|
|
"node.nostr-pubkey" => self.handle_node_nostr_pubkey().await,
|
|
|
|
|
"node-nostr-verify-revoked" => self.handle_node_nostr_verify_revoked().await,
|
|
|
|
|
|
feat: add TOTP 2FA, API key switcher, login progress bar, and alpha hardening plan
- TOTP 2FA: full setup/confirm/disable/login flow with Argon2id + ChaCha20-Poly1305
encrypted secret storage, QR code generation, and bcrypt-hashed backup codes
- API key switcher: OAuth vs personal API key toggle in AIUI chat settings with
status indicator, key validation, and help text
- Login progress bar: server startup detection with health check polling, form
disabled until server is ready
- AI quarantine docs: comprehensive HTML page documenting all 6 security layers
- Settings: AI Data Access permission toggles with per-category control
- Alpha hardening plan: 28-task overnight automation plan across 7 phases
(onboarding, login, app install, AIUI, UI polish, security, ISO build)
- Backlog: node discovery spatial map feature for alpha demo
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-06 12:23:57 +00:00
|
|
|
// TOTP 2FA
|
|
|
|
|
"auth.totp.setup.begin" => self.handle_totp_setup_begin(params).await,
|
|
|
|
|
"auth.totp.setup.confirm" => self.handle_totp_setup_confirm(params).await,
|
|
|
|
|
"auth.totp.disable" => self.handle_totp_disable(params).await,
|
|
|
|
|
"auth.totp.status" => self.handle_totp_status().await,
|
|
|
|
|
"auth.login.totp" => self.handle_login_totp(params, &session_token).await,
|
|
|
|
|
"auth.login.backup" => self.handle_login_backup(params, &session_token).await,
|
|
|
|
|
|
2026-03-05 13:56:29 +00:00
|
|
|
// Bitcoin & Lightning deep data
|
|
|
|
|
"bitcoin.getinfo" => self.handle_bitcoin_getinfo().await,
|
|
|
|
|
"lnd.getinfo" => self.handle_lnd_getinfo().await,
|
|
|
|
|
|
2026-03-04 05:23:42 +00:00
|
|
|
_ => {
|
|
|
|
|
Err(anyhow::anyhow!("Unknown method: {}", rpc_req.method))
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// Build response
|
|
|
|
|
let rpc_resp = match result {
|
|
|
|
|
Ok(data) => RpcResponse {
|
|
|
|
|
result: Some(data),
|
|
|
|
|
error: None,
|
|
|
|
|
},
|
|
|
|
|
Err(e) => {
|
|
|
|
|
error!("RPC error: {}", e);
|
|
|
|
|
RpcResponse {
|
|
|
|
|
result: None,
|
|
|
|
|
error: Some(RpcError {
|
|
|
|
|
code: -1,
|
|
|
|
|
message: e.to_string(),
|
|
|
|
|
data: None,
|
|
|
|
|
}),
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
2026-03-06 03:26:56 +00:00
|
|
|
let resp_body = serde_json::to_vec(&rpc_resp)
|
2026-03-04 05:23:42 +00:00
|
|
|
.context("Failed to serialize response")?;
|
|
|
|
|
|
2026-03-06 03:26:56 +00:00
|
|
|
let mut response = Response::builder()
|
2026-03-04 05:23:42 +00:00
|
|
|
.status(StatusCode::OK)
|
|
|
|
|
.header("Content-Type", "application/json")
|
2026-03-06 03:26:56 +00:00
|
|
|
.body(hyper::Body::from(resp_body))
|
|
|
|
|
.unwrap();
|
|
|
|
|
|
|
|
|
|
// Track failed login attempts for rate limiting
|
|
|
|
|
if rpc_req.method == "auth.login" && rpc_resp.error.is_some() {
|
|
|
|
|
let client_ip = extract_client_ip(&parts.headers);
|
|
|
|
|
self.login_rate_limiter.record_failure(client_ip).await;
|
|
|
|
|
}
|
|
|
|
|
|
feat: add TOTP 2FA, API key switcher, login progress bar, and alpha hardening plan
- TOTP 2FA: full setup/confirm/disable/login flow with Argon2id + ChaCha20-Poly1305
encrypted secret storage, QR code generation, and bcrypt-hashed backup codes
- API key switcher: OAuth vs personal API key toggle in AIUI chat settings with
status indicator, key validation, and help text
- Login progress bar: server startup detection with health check polling, form
disabled until server is ready
- AI quarantine docs: comprehensive HTML page documenting all 6 security layers
- Settings: AI Data Access permission toggles with per-category control
- Alpha hardening plan: 28-task overnight automation plan across 7 phases
(onboarding, login, app install, AIUI, UI polish, security, ISO build)
- Backlog: node discovery spatial map feature for alpha demo
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-06 12:23:57 +00:00
|
|
|
// On successful login, check if 2FA is required
|
2026-03-06 03:26:56 +00:00
|
|
|
if rpc_req.method == "auth.login" && rpc_resp.error.is_none() {
|
feat: add TOTP 2FA, API key switcher, login progress bar, and alpha hardening plan
- TOTP 2FA: full setup/confirm/disable/login flow with Argon2id + ChaCha20-Poly1305
encrypted secret storage, QR code generation, and bcrypt-hashed backup codes
- API key switcher: OAuth vs personal API key toggle in AIUI chat settings with
status indicator, key validation, and help text
- Login progress bar: server startup detection with health check polling, form
disabled until server is ready
- AI quarantine docs: comprehensive HTML page documenting all 6 security layers
- Settings: AI Data Access permission toggles with per-category control
- Alpha hardening plan: 28-task overnight automation plan across 7 phases
(onboarding, login, app install, AIUI, UI polish, security, ISO build)
- Backlog: node discovery spatial map feature for alpha demo
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-06 12:23:57 +00:00
|
|
|
let totp_enabled = self.auth_manager.is_totp_enabled().await.unwrap_or(false);
|
|
|
|
|
if totp_enabled {
|
|
|
|
|
// 2FA enabled: create a pending session with cached TOTP secret
|
|
|
|
|
// We need the password to decrypt the TOTP secret for step 2
|
|
|
|
|
let password = login_params
|
|
|
|
|
.as_ref()
|
|
|
|
|
.and_then(|p| p.get("password"))
|
|
|
|
|
.and_then(|v| v.as_str())
|
|
|
|
|
.unwrap_or("");
|
|
|
|
|
if let Ok(Some(totp_data)) = self.auth_manager.get_totp_data().await {
|
|
|
|
|
if let Ok(secret) = crate::totp::decrypt_secret(&totp_data, password) {
|
|
|
|
|
let token = self.session_store.create_pending(secret).await;
|
|
|
|
|
response.headers_mut().insert(
|
|
|
|
|
"Set-Cookie",
|
|
|
|
|
format!("session={}; HttpOnly; SameSite=Strict; Path=/", token)
|
|
|
|
|
.parse()
|
|
|
|
|
.unwrap(),
|
|
|
|
|
);
|
|
|
|
|
// Override the response body to indicate TOTP is required
|
|
|
|
|
let totp_body = serde_json::json!({
|
|
|
|
|
"result": { "requires_totp": true },
|
|
|
|
|
"error": null
|
|
|
|
|
});
|
|
|
|
|
*response.body_mut() = hyper::Body::from(
|
|
|
|
|
serde_json::to_vec(&totp_body).unwrap_or_default(),
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
// No 2FA: create a full session immediately
|
|
|
|
|
let token = self.session_store.create().await;
|
|
|
|
|
response.headers_mut().insert(
|
|
|
|
|
"Set-Cookie",
|
|
|
|
|
format!("session={}; HttpOnly; SameSite=Strict; Path=/", token)
|
|
|
|
|
.parse()
|
|
|
|
|
.unwrap(),
|
|
|
|
|
);
|
|
|
|
|
}
|
2026-03-06 03:26:56 +00:00
|
|
|
}
|
|
|
|
|
|
feat: add TOTP 2FA, API key switcher, login progress bar, and alpha hardening plan
- TOTP 2FA: full setup/confirm/disable/login flow with Argon2id + ChaCha20-Poly1305
encrypted secret storage, QR code generation, and bcrypt-hashed backup codes
- API key switcher: OAuth vs personal API key toggle in AIUI chat settings with
status indicator, key validation, and help text
- Login progress bar: server startup detection with health check polling, form
disabled until server is ready
- AI quarantine docs: comprehensive HTML page documenting all 6 security layers
- Settings: AI Data Access permission toggles with per-category control
- Alpha hardening plan: 28-task overnight automation plan across 7 phases
(onboarding, login, app install, AIUI, UI polish, security, ISO build)
- Backlog: node discovery spatial map feature for alpha demo
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-06 12:23:57 +00:00
|
|
|
// On successful TOTP verification, the session is already upgraded to full
|
|
|
|
|
// (handled inside handle_login_totp/handle_login_backup)
|
|
|
|
|
|
2026-03-06 03:26:56 +00:00
|
|
|
// On logout, invalidate session and expire the cookie
|
|
|
|
|
if rpc_req.method == "auth.logout" {
|
|
|
|
|
if let Some(token) = &session_token {
|
|
|
|
|
self.session_store.remove(token).await;
|
|
|
|
|
}
|
|
|
|
|
response.headers_mut().insert(
|
|
|
|
|
"Set-Cookie",
|
|
|
|
|
"session=; HttpOnly; SameSite=Strict; Path=/; Max-Age=0"
|
|
|
|
|
.parse()
|
|
|
|
|
.unwrap(),
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Ok(response)
|
2026-03-04 05:23:42 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
async fn handle_echo(&self, params: Option<serde_json::Value>) -> Result<serde_json::Value> {
|
|
|
|
|
if let Some(p) = params {
|
|
|
|
|
if let Some(msg) = p.get("message").and_then(|v| v.as_str()) {
|
|
|
|
|
return Ok(serde_json::json!({ "message": msg }));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
Ok(serde_json::json!({ "message": "Hello from Archipelago!" }))
|
|
|
|
|
}
|
|
|
|
|
}
|
2026-03-06 03:26:56 +00:00
|
|
|
|
|
|
|
|
/// Extract the client IP from request headers (X-Real-IP or X-Forwarded-For).
|
|
|
|
|
fn extract_client_ip(headers: &hyper::HeaderMap) -> IpAddr {
|
|
|
|
|
headers
|
|
|
|
|
.get("x-real-ip")
|
|
|
|
|
.or_else(|| headers.get("x-forwarded-for"))
|
|
|
|
|
.and_then(|v| v.to_str().ok())
|
|
|
|
|
.and_then(|s| s.split(',').next())
|
|
|
|
|
.and_then(|s| s.trim().parse::<IpAddr>().ok())
|
|
|
|
|
.unwrap_or(IpAddr::V4(std::net::Ipv4Addr::LOCALHOST))
|
|
|
|
|
}
|