From 6b3570e15002660ee124a3c841bb36827204f71a Mon Sep 17 00:00:00 2001 From: Aiden McClelland Date: Tue, 14 Sep 2021 12:19:20 -0600 Subject: [PATCH] recovery mode in embassyd --- appmgr/src/bin/embassy-init.rs | 8 ++++++- appmgr/src/bin/embassyd.rs | 36 +++++++++++++++++++++++++++++-- appmgr/src/error.rs | 6 ++++-- appmgr/src/middleware/mod.rs | 1 + appmgr/src/middleware/recovery.rs | 36 +++++++++++++++++++++++++++++++ 5 files changed, 82 insertions(+), 5 deletions(-) create mode 100644 appmgr/src/middleware/recovery.rs diff --git a/appmgr/src/bin/embassy-init.rs b/appmgr/src/bin/embassy-init.rs index eb2140ecb..e5befe5d9 100644 --- a/appmgr/src/bin/embassy-init.rs +++ b/appmgr/src/bin/embassy-init.rs @@ -5,7 +5,9 @@ use embassy::context::rpc::RpcContextConfig; use embassy::context::{RecoveryContext, SetupContext}; use embassy::disk::main::DEFAULT_PASSWORD; use embassy::hostname::get_product_key; +use embassy::middleware::cors::cors; use embassy::middleware::encrypt::encrypt; +use embassy::middleware::recovery::recovery; use embassy::util::Invoke; use embassy::{Error, ResultExt}; use http::StatusCode; @@ -38,6 +40,7 @@ async fn init(cfg_path: Option<&str>) -> Result<(), Error> { context: ctx.clone(), status: status_fn, middleware: [ + cors, encrypt, ] }) @@ -144,7 +147,10 @@ async fn inner_main(cfg_path: Option<&str>) -> Result<(), Error> { command: embassy::recovery_api, context: ctx.clone(), status: status_fn, - middleware: [ ] + middleware: [ + cors, + recovery, + ] }) .with_graceful_shutdown({ let mut shutdown = ctx.shutdown.subscribe(); diff --git a/appmgr/src/bin/embassyd.rs b/appmgr/src/bin/embassyd.rs index b18609dd4..91f41c918 100644 --- a/appmgr/src/bin/embassyd.rs +++ b/appmgr/src/bin/embassyd.rs @@ -1,12 +1,13 @@ use std::time::Duration; use anyhow::anyhow; -use embassy::context::RpcContext; +use embassy::context::{RecoveryContext, RpcContext}; use embassy::db::model::Database; use embassy::db::subscribe; use embassy::hostname::{get_hostname, get_id}; use embassy::middleware::auth::auth; use embassy::middleware::cors::cors; +use embassy::middleware::recovery::recovery; use embassy::net::tor::{os_key, tor_health_check}; use embassy::shutdown::Shutdown; use embassy::status::{check_all, synchronize_all}; @@ -250,7 +251,38 @@ fn main() { .enable_all() .build() .expect("failed to initialize runtime"); - rt.block_on(inner_main(cfg_path, filter)) + rt.block_on(async { + match inner_main(cfg_path, filter).await { + Ok(a) => Ok(a), + Err(e) => { + (|| async { + log::error!("{}", e.source); + log::debug!("{}", e.source); + embassy::sound::BEETHOVEN.play().await?; + let ctx = RecoveryContext::init(cfg_path, e).await?; + rpc_server!({ + command: embassy::recovery_api, + context: ctx.clone(), + status: status_fn, + middleware: [ + cors, + recovery, + ] + }) + .with_graceful_shutdown({ + let mut shutdown = ctx.shutdown.subscribe(); + async move { + shutdown.recv().await.expect("context dropped"); + } + }) + .await + .with_kind(embassy::ErrorKind::Network)?; + Ok::<_, Error>(None) + })() + .await + } + } + }) }; match res { diff --git a/appmgr/src/error.rs b/appmgr/src/error.rs index a7d768849..93b410147 100644 --- a/appmgr/src/error.rs +++ b/appmgr/src/error.rs @@ -30,7 +30,7 @@ pub enum ErrorKind { InvalidOnionAddress = 22, Pack = 23, ValidateS9pk = 24, - OpenSSL = 25, + OpenSSL = 25, // REMOVE Tor = 26, ConfigGen = 27, ParseNumber = 28, @@ -56,6 +56,7 @@ pub enum ErrorKind { Zfs = 48, OpenSsl = 49, PasswordHashGeneration = 50, + RecoveryMode = 51, } impl ErrorKind { pub fn as_str(&self) -> &'static str { @@ -85,7 +86,7 @@ impl ErrorKind { InvalidOnionAddress => "Invalid Onion Address", Pack => "Pack Error", ValidateS9pk => "S9PK Validation Error", - OpenSSL => "OpenSSL Error", + OpenSSL => "OpenSSL Error", // Remove Tor => "Tor Daemon Error", ConfigGen => "Config Generation Error", ParseNumber => "Number Parsing Error", @@ -111,6 +112,7 @@ impl ErrorKind { Zfs => "ZFS Error", OpenSsl => "OpenSSL Internal Error", PasswordHashGeneration => "Password Hash Generation Error", + RecoveryMode => "Embassy is in Recovery Mode", } } } diff --git a/appmgr/src/middleware/mod.rs b/appmgr/src/middleware/mod.rs index 3a21fd142..f349363b8 100644 --- a/appmgr/src/middleware/mod.rs +++ b/appmgr/src/middleware/mod.rs @@ -1,3 +1,4 @@ pub mod auth; pub mod cors; pub mod encrypt; +pub mod recovery; diff --git a/appmgr/src/middleware/recovery.rs b/appmgr/src/middleware/recovery.rs new file mode 100644 index 000000000..8dd5c33d9 --- /dev/null +++ b/appmgr/src/middleware/recovery.rs @@ -0,0 +1,36 @@ +use futures::FutureExt; +use rpc_toolkit::hyper::http::Error as HttpError; +use rpc_toolkit::hyper::{Body, Request, Response}; +use rpc_toolkit::rpc_server_helpers::{noop4, DynMiddlewareStage2, DynMiddlewareStage3}; +use rpc_toolkit::yajrc::RpcMethod; +use rpc_toolkit::Metadata; + +use crate::Error; + +pub async fn recovery( + _req: &mut Request, + _metadata: M, +) -> Result>, HttpError> { + Ok(Ok(Box::new(|_, rpc_req| { + let method = rpc_req.method.as_str().to_owned(); + async move { + let res: DynMiddlewareStage3 = Box::new(|_, rpc_res| { + async move { + if let Err(e) = rpc_res { + if e.code == -32601 { + *e = Error::new( + anyhow::anyhow!("{} is not available on the Recovery API", method), + crate::ErrorKind::RecoveryMode, + ) + .into(); + } + } + Ok(Ok(noop4())) + } + .boxed() + }); + Ok::<_, HttpError>(Ok(res)) + } + .boxed() + }))) +}