Skip to content

Commit

Permalink
Merge pull request #58 from MutinyWallet/welcome-route
Browse files Browse the repository at this point in the history
Welcome route
  • Loading branch information
TonyGiorgio authored Jun 11, 2024
2 parents cfb6384 + 6f17790 commit 14099c5
Show file tree
Hide file tree
Showing 6 changed files with 264 additions and 40 deletions.
20 changes: 20 additions & 0 deletions src/bridge.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,10 @@ pub enum UICoreMsg {
GetFederationInfo(InviteCode),
AddFederation(InviteCode),
Unlock(String),
Init {
password: String,
seed: Option<String>,
},
GetSeedWords,
}

Expand Down Expand Up @@ -63,6 +67,11 @@ pub enum CoreUIMsg {
FederationInfo(ClientConfig),
AddFederationSuccess,
FederationListUpdated(Vec<FederationItem>),
NeedsInit,
Initing,
InitSuccess,
InitFailed(String),
Locked,
Unlocking,
UnlockSuccess,
UnlockFailed(String),
Expand Down Expand Up @@ -128,6 +137,17 @@ impl UIHandle {
.await;
}

pub async fn init(&self, id: Uuid, password: String) {
self.msg_send(UICoreMsgPacket {
msg: UICoreMsg::Init {
password,
seed: None, // FIXME: Use this
},
id,
})
.await;
}

pub async fn add_federation(&self, id: Uuid, invite: InviteCode) {
self.msg_send(UICoreMsgPacket {
msg: UICoreMsg::AddFederation(invite),
Expand Down
34 changes: 22 additions & 12 deletions src/conf.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use anyhow::anyhow;
use bip39::{Language, Mnemonic};
use bitcoin::Network;
use log::info;
use log::{error, info};
use std::path::PathBuf;
use std::str::FromStr;
use std::sync::Arc;
Expand All @@ -21,23 +22,32 @@ pub fn data_dir(network: Network) -> PathBuf {
}
}

// todo store in encrypted database
pub fn get_mnemonic(db: Arc<dyn DBConnection + Send + Sync>) -> anyhow::Result<Mnemonic> {
pub fn retrieve_mnemonic(db: Arc<dyn DBConnection + Send + Sync>) -> anyhow::Result<Mnemonic> {
match db.get_seed()? {
Some(m) => {
info!("retrieved existing seed");
Ok(Mnemonic::from_str(&m)?)
}
None => {
let new_profile = NewProfile {
id: uuid::Uuid::new_v4().to_string(),
seed_words: Mnemonic::generate_in(Language::English, 12)?.to_string(),
};

let p = db.insert_new_profile(new_profile)?;

info!("creating new seed");
Ok(Mnemonic::from_str(&p.seed_words)?)
error!("Tried to retrieve seed but none was stored");
Err(anyhow!("No seed stored"))
}
}
}

pub fn generate_mnemonic(
db: Arc<dyn DBConnection + Send + Sync>,
words: Option<String>,
) -> anyhow::Result<Mnemonic> {
let mnemonic_words = words.unwrap_or(Mnemonic::generate_in(Language::English, 12)?.to_string());

let new_profile = NewProfile {
id: uuid::Uuid::new_v4().to_string(),
seed_words: mnemonic_words,
};

let p = db.insert_new_profile(new_profile)?;

info!("creating new seed");
Ok(Mnemonic::from_str(&p.seed_words)?)
}
115 changes: 93 additions & 22 deletions src/core.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,22 +19,22 @@ use iced::{
futures::{channel::mpsc::Sender, SinkExt},
subscription::{self, Subscription},
};
use log::{error, info, trace, warn};
use log::{error, trace, warn};
use tokio::sync::RwLock;
use tokio::task::spawn_blocking;
use uuid::Uuid;

use crate::components::FederationItem;
use crate::db::check_password;
use crate::fedimint_client::{
spawn_onchain_payment_subscription, spawn_onchain_receive_subscription, FederationInviteOrId,
};
use crate::{
bridge::{self, CoreUIMsg, UICoreMsg},
conf::{self, get_mnemonic},
conf::{self, retrieve_mnemonic},
db::DBConnection,
Message,
};
use crate::{components::FederationItem, conf::generate_mnemonic};
use crate::{
db::setup_db,
fedimint_client::{
Expand All @@ -44,6 +44,7 @@ use crate::{
};

const PEG_IN_TIMEOUT_YEAR: Duration = Duration::from_secs(86400 * 365);
const HARBOR_FILE_NAME: &str = "harbor.sqlite";

#[derive(Clone)]
struct HarborCore {
Expand Down Expand Up @@ -381,11 +382,26 @@ pub fn run_core() -> Subscription<Message> {
std::fs::create_dir_all(path.clone()).expect("Could not create datadir");
log::info!("Using datadir: {path:?}");

// FIXME: Artificial sleep because it loads too fast
tokio::time::sleep(Duration::from_secs(1)).await;

// Check if the database file exists already, if so tell UI to unlock
if std::fs::metadata(path.join(HARBOR_FILE_NAME)).is_ok() {
tx.send(Message::core_msg(None, CoreUIMsg::Locked))
.await
.expect("should send");
} else {
tx.send(Message::core_msg(None, CoreUIMsg::NeedsInit))
.await
.expect("should send");
}

loop {
let msg = core_handle.recv().await;

let id = msg.as_ref().map(|m| m.id);

// Watch for either Unlock or Init, ignore everything else until started
match msg.map(|m| m.msg) {
Some(UICoreMsg::Unlock(password)) => {
log::info!("Sending unlock message");
Expand All @@ -394,30 +410,41 @@ pub fn run_core() -> Subscription<Message> {
.expect("should send");

// attempting to unlock
let db_path = path.join("harbor.sqlite");

let db_path = path.join(HARBOR_FILE_NAME);
let db_path = db_path.to_str().unwrap().to_string();

// if the db file doesn't exist, dont call check_password
// if the db file doesn't exist, error out to go through init flow
if !std::path::Path::new(&db_path).exists() {
info!("Database does not exist, it will be created");
} else {
if let Err(e) = check_password(&db_path, &password) {
// probably invalid password
error!("error using password: {e}");

tx.send(Message::core_msg(
id,
CoreUIMsg::UnlockFailed(e.to_string()),
))
.await
.expect("should send");
continue;
}
error!("Database does not exist, new wallet is required");

tx.send(Message::core_msg(
id,
CoreUIMsg::UnlockFailed(
"Database does not exist, new wallet is required".to_string(),
),
))
.await
.expect("should send");

log::info!("Correct password");
continue;
}

if let Err(e) = check_password(&db_path, &password) {
// probably invalid password
error!("error using password: {e}");

tx.send(Message::core_msg(
id,
CoreUIMsg::UnlockFailed(e.to_string()),
))
.await
.expect("should send");

continue;
}

log::info!("Correct password");

let db = spawn_blocking(move || setup_db(&db_path, password))
.await
.expect("Could not create join handle");
Expand All @@ -435,7 +462,7 @@ pub fn run_core() -> Subscription<Message> {
}
let db = db.expect("no error");

let mnemonic = get_mnemonic(db.clone()).expect("should get seed");
let mnemonic = retrieve_mnemonic(db.clone()).expect("should get seed");

let stop = Arc::new(AtomicBool::new(false));

Expand Down Expand Up @@ -475,6 +502,47 @@ pub fn run_core() -> Subscription<Message> {

process_core(&mut core_handle, &core).await;
}
Some(UICoreMsg::Init { password, seed }) => {
log::info!("Sending init message");
tx.send(Message::core_msg(id, CoreUIMsg::Initing))
.await
.expect("should send");

// set up the DB with the provided password
let db_path = path.join(HARBOR_FILE_NAME);
let db =
spawn_blocking(move || setup_db(db_path.to_str().unwrap(), password))
.await
.expect("Could not create join handle");

if let Err(e) = db {
error!("error creating DB: {e}");

tx.send(Message::core_msg(id, CoreUIMsg::InitFailed(e.to_string())))
.await
.expect("should send");

continue;
}
let db = db.expect("no error");

let core = HarborCore {
storage: db.clone(),
tx: tx.clone(),
mnemonic: generate_mnemonic(db.clone(), seed)
.expect("should generate words"),
network,
clients: Arc::new(RwLock::new(HashMap::new())),
stop: Arc::new(AtomicBool::new(false)),
};

tx.send(Message::core_msg(id, CoreUIMsg::InitSuccess))
.await
.expect("should send");

process_core(&mut core_handle, &core).await;
}

_ => {
warn!("Ignoring unrelated message to locked core")
}
Expand Down Expand Up @@ -577,6 +645,9 @@ async fn process_core(core_handle: &mut bridge::CoreHandle, core: &HarborCore) {
UICoreMsg::Unlock(_password) => {
unreachable!("should already be unlocked")
}
UICoreMsg::Init { .. } => {
unreachable!("should already be inited")
}
UICoreMsg::GetSeedWords => {
let seed_words = core.get_seed_words().await;
core.msg(Some(msg.id), CoreUIMsg::SeedWords(seed_words))
Expand Down
Loading

0 comments on commit 14099c5

Please sign in to comment.