Skip to content

Commit

Permalink
Remove local storage
Browse files Browse the repository at this point in the history
  • Loading branch information
benthecarman committed Oct 16, 2023
1 parent e5c2f4e commit 9cd5760
Show file tree
Hide file tree
Showing 3 changed files with 5 additions and 217 deletions.
2 changes: 1 addition & 1 deletion mutiny-core/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ js-sys = { version = "0.3.60" }
gloo-net = { version = "0.2.4" }
instant = { version = "0.1", features = ["wasm-bindgen"] }
getrandom = { version = "0.2", features = ["js"] }
windowless_sleep = { git = "https://github.com/futurepaul/windowless_sleep", commit = "e924649" }
windowless_sleep = { git = "https://github.com/futurepaul/windowless_sleep", rev = "e924649" }

[target.'cfg(target_arch = "wasm32")'.dev-dependencies]
web-sys = { version = "0.3.60", features = ["console"] }
Expand Down
5 changes: 2 additions & 3 deletions mutiny-wasm/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -34,13 +34,12 @@ wasm-logger = "0.2.0"
log = "0.4.17"
rexie = "0.4"
js-sys = "0.3.60"
gloo-storage = "0.2.2"
gloo-utils = { version = "0.1.6", features = ["serde"] }
bip39 = { version = "2.0.0" }
getrandom = { version = "0.2", features = ["js"] }
futures = "0.3.25"
urlencoding = "2.1.2"
windowless_sleep = { git = "https://github.com/futurepaul/windowless_sleep", commit = "e924649" }
windowless_sleep = { git = "https://github.com/futurepaul/windowless_sleep", rev = "e924649" }

# The `console_error_panic_hook` crate provides better debugging of panics by
# logging them with `console.error`. This is great for development, but requires
Expand All @@ -54,7 +53,7 @@ wasm-bindgen-test = "0.3.33"
web-sys = { version = "0.3.60", features = ["console"] }

[features]
default = [ ]
default = []

[package.metadata.wasm-pack.profile.release]
wasm-opt = true
215 changes: 2 additions & 213 deletions mutiny-wasm/src/indexed_db.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
use anyhow::anyhow;
use gloo_storage::{LocalStorage, Storage};
use gloo_utils::format::JsValueSerdeExt;
use lightning::util::logger::Logger;
use lightning::{log_debug, log_error};
Expand Down Expand Up @@ -204,26 +203,6 @@ impl IndexedDbStorage {
map.set(key, json)?;
}

// get the local storage data, this should take priority if it is being used
log_debug!(logger, "Reading from local storage");
let local_storage = LocalStorage::raw();
let length = LocalStorage::length();
for index in 0..length {
let key_opt: Option<String> = local_storage.key(index).unwrap();

if let Some(key) = key_opt {
// only add to the map if it is a key we expect
// this is to prevent any unexpected data from being added to the map
// from either malicious 3rd party or a previous version of the wallet
if write_to_local_storage(&key) {
// compare versions between local storage and indexed db storage
if let Some((key, value)) = Self::handle_local_storage_key(key, &map, logger)? {
map.set_data(key, value, None)?;
}
}
}
}

match vss {
None => {
let final_map = map.memory.read().unwrap();
Expand All @@ -248,76 +227,6 @@ impl IndexedDbStorage {
}
}

fn handle_local_storage_key(
key: String,
current: &MemoryStorage,
logger: &MutinyLogger,
) -> Result<Option<(String, Value)>, MutinyError> {
if key.starts_with(MONITORS_PREFIX_KEY) {
// we can get versions from monitors, so we should compare
match current.get::<Vec<u8>>(&key)? {
Some(bytes) => {
// check first byte is 1, then take u64 from next 8 bytes
let current_version = utils::get_monitor_version(bytes);

let obj: Value = LocalStorage::get(&key).unwrap();
let value = decrypt_value(&key, obj, current.password())?;
if let Ok(local_bytes) = serde_json::from_value::<Vec<u8>>(value.clone()) {
let local_version = utils::get_monitor_version(local_bytes);

// if the current version is less than the version from local storage
// then we want to use the local storage version
if current_version < local_version {
log_debug!(
logger,
"Using local storage key {key} with version {}",
local_version
);
return Ok(Some((key, value)));
}
}
}
None => {
let value: Value = LocalStorage::get(&key).unwrap();
return Ok(Some((key, value)));
}
}
} else if key.starts_with(CHANNEL_MANAGER_KEY) {
// we can get versions from channel manager, so we should compare
match current.get_data::<VersionedValue>(&key) {
Ok(Some(local)) => {
let obj: Value = LocalStorage::get(&key).unwrap();
let value = decrypt_value(&key, obj, current.password())?;

// if the current version is less than the version from local storage
// then we want to use the local storage version
if let Ok(v) = serde_json::from_value::<VersionedValue>(value.clone()) {
if v.version > local.version {
log_debug!(
logger,
"Using local storage key {key} with version {}",
v.version
);
return Ok(Some((key, value)));
}
}
}
Ok(None) => {
let obj: Value = LocalStorage::get(&key).unwrap();
let value = decrypt_value(&key, obj, current.password())?;
if serde_json::from_value::<VersionedValue>(value.clone()).is_ok() {
return Ok(Some((key, value)));
}
}
Err(_) => return Err(MutinyError::IncorrectPassword),
}
}

log_debug!(logger, "Skipping local storage key {key}");

Ok(None)
}

async fn handle_vss_key(
kv: KeyVersion,
vss: &MutinyVssClient,
Expand Down Expand Up @@ -482,18 +391,6 @@ fn used_once(key: &str) -> bool {
}
}

/// To help prevent force closes we save to local storage as well as indexed db.
/// This is because indexed db is not always reliable.
///
/// We need to do this for the channel manager and channel monitors.
fn write_to_local_storage(key: &str) -> bool {
match key {
str if str.starts_with(CHANNEL_MANAGER_KEY) => true,
str if str.starts_with(MONITORS_PREFIX_KEY) => true,
_ => false,
}
}

impl MutinyStorage for IndexedDbStorage {
fn password(&self) -> Option<&str> {
self.password.as_deref()
Expand Down Expand Up @@ -526,15 +423,6 @@ impl MutinyStorage for IndexedDbStorage {
};
});

// Some values we want to write to local storage as well as indexed db
if write_to_local_storage(&key) {
LocalStorage::set(&key, &data).map_err(|e| {
MutinyError::write_err(MutinyStorageError::Other(anyhow!(
"Failed to write to local storage: {e}"
)))
})?;
}

// some values only are read once, so we don't need to write them to memory,
// just need them in indexed db for next time
if !used_once(key.as_ref()) {
Expand All @@ -559,15 +447,6 @@ impl MutinyStorage for IndexedDbStorage {

Self::save_to_indexed_db(&self.indexed_db, &key, &data).await?;

// Some values we want to write to local storage as well as indexed db
if write_to_local_storage(&key) {
LocalStorage::set(&key, &data).map_err(|e| {
MutinyError::write_err(MutinyStorageError::Other(anyhow!(
"Failed to write to local storage: {e}"
)))
})?;
}

// some values only are read once, so we don't need to write them to memory,
// just need them in indexed db for next time
if !used_once(key.as_ref()) {
Expand Down Expand Up @@ -633,11 +512,6 @@ impl MutinyStorage for IndexedDbStorage {
.map_err(|e| MutinyError::write_err(e.into()))?;

for key in keys {
// Some values we want to write to local storage as well as indexed db
// we should delete them from local storage as well
if write_to_local_storage(&key) {
LocalStorage::delete(&key)
}
map.remove(&key);
}

Expand Down Expand Up @@ -755,30 +629,24 @@ impl MutinyStorage for IndexedDbStorage {
.await
.map_err(|e| MutinyError::write_err(anyhow!("Failed clear indexed db: {e}").into()))?;

// We use some localstorage right now for ensuring channel data
LocalStorage::clear();

Ok(())
}
}

#[cfg(test)]
mod tests {
use super::*;
use crate::indexed_db::{IndexedDbStorage, WALLET_OBJECT_STORE_NAME};
use crate::indexed_db::IndexedDbStorage;
use crate::utils::sleep;
use crate::utils::test::log;
use bip39::Mnemonic;
use bitcoin::hashes::hex::ToHex;
use gloo_storage::{LocalStorage, Storage};
use mutiny_core::storage::MutinyStorage;
use mutiny_core::test_utils::{MANAGER_BYTES, MONITOR_VERSION_HIGHER, MONITOR_VERSION_LOWER};
use mutiny_core::test_utils::MANAGER_BYTES;
use mutiny_core::{encrypt::encryption_key_from_pass, logging::MutinyLogger};
use rexie::TransactionMode;
use serde_json::json;
use std::str::FromStr;
use std::sync::Arc;
use wasm_bindgen::JsValue;
use wasm_bindgen_test::{wasm_bindgen_test as test, wasm_bindgen_test_configure};

wasm_bindgen_test_configure!(run_in_browser);
Expand Down Expand Up @@ -944,85 +812,6 @@ mod tests {
IndexedDbStorage::clear().await.unwrap();
}

async fn compare_local_storage_versions(
test_name: &str,
local_storage: Vec<u8>,
indexed_db: Vec<u8>,
) -> Vec<u8> {
let key = format!("{MONITORS_PREFIX_KEY}test_{test_name}");
// set in local storage
LocalStorage::set(&key, local_storage).unwrap();
// set in indexed db
let rexie = IndexedDbStorage::build_indexed_db_database().await.unwrap();
let tx = rexie
.transaction(&[WALLET_OBJECT_STORE_NAME], TransactionMode::ReadWrite)
.unwrap();
let store = tx.store(WALLET_OBJECT_STORE_NAME).unwrap();
store
.put(
&JsValue::from_serde(&indexed_db).unwrap(),
Some(&JsValue::from(&key)),
)
.await
.unwrap();

tx.done().await.unwrap();

let logger = Arc::new(MutinyLogger::default());
let storage = IndexedDbStorage::new(None, None, None, logger)
.await
.unwrap();

let bytes: Vec<u8> = storage.get(&key).unwrap().unwrap();

// clear the storage to clean up
IndexedDbStorage::clear().await.unwrap();

bytes
}

#[test]
async fn test_local_storage_version_0_indexed_db_version_max() {
let test_name = "test_local_storage_version_0_indexed_db_version_max";
log!("{test_name}");

let bytes = compare_local_storage_versions(
test_name,
MONITOR_VERSION_LOWER.to_vec(),
MONITOR_VERSION_HIGHER.to_vec(),
)
.await;
assert_eq!(bytes, MONITOR_VERSION_HIGHER);
}

#[test]
async fn test_local_storage_version_max_indexed_db_version_0() {
let test_name = "test_local_storage_version_max_indexed_db_version_0";
log!("{test_name}");

let bytes = compare_local_storage_versions(
test_name,
MONITOR_VERSION_HIGHER.to_vec(),
MONITOR_VERSION_LOWER.to_vec(),
)
.await;
assert_eq!(bytes, MONITOR_VERSION_HIGHER);
}

#[test]
async fn test_local_storage_version_max_indexed_db_version_max() {
let test_name = "test_local_storage_version_max_indexed_db_version_max";
log!("{test_name}");

let bytes = compare_local_storage_versions(
test_name,
MONITOR_VERSION_HIGHER.to_vec(),
MONITOR_VERSION_HIGHER.to_vec(),
)
.await;
assert_eq!(bytes, MONITOR_VERSION_HIGHER);
}

#[test]
async fn test_correct_incorrect_password_error() {
let test_name = "test_correct_incorrect_password_error";
Expand Down

0 comments on commit 9cd5760

Please sign in to comment.