From 839c904b35ba4e7759b3236249b7ff6cd8b84754 Mon Sep 17 00:00:00 2001 From: Sun Date: Thu, 31 Mar 2022 11:12:24 +0800 Subject: [PATCH] add pre-cloud --- Cargo.toml | 29 ++++++++------ lib/apps/service/models.dart | 2 +- src/account.rs | 71 ++++++++++++++++++++++------------ src/apps/chat/layer.rs | 17 ++++++-- src/apps/chat/models/friend.rs | 60 +++++++++++++++++++++++----- src/apps/chat/rpc.rs | 9 ++++- src/apps/cloud/layer.rs | 2 +- src/group.rs | 9 +++-- src/migrate/account.rs | 1 + src/migrate/chat.rs | 4 +- src/utils/crypto.rs | 7 ++++ types/cloud/src/lib.rs | 32 ++++++++------- 12 files changed, 171 insertions(+), 72 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 025e379..b48a0f6 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -23,6 +23,11 @@ crate-type = ["cdylib", "staticlib"] [[bin]] name = "esse" path = "src/daemon.rs" +required-features = ["daemon"] + +[features] +default = [] +daemon = ["console-subscriber"] [profile.release] opt-level = 's' @@ -31,26 +36,26 @@ codegen-units = 1 panic = 'abort' [dependencies] +aes-gcm = "0.9" anyhow = "1.0" -log = "0.4" -rand = "0.8" -once_cell = "1.9" -simplelog = "0.11" -image = "0.24" +argon2 = "0.3" base64 = "0.13" +bincode = "1.3" +blake3 = "1.3" hex = "0.4" +image = "0.24" +log = "0.4" +once_cell = "1.9" +rand = "0.8" sha2 = "0.10" -argon2 = "0.3" -blake3 = "1.3" -bincode = "1.3" -aes-gcm = "0.9" +simplelog = "0.11" sysinfo = "0.23" serde = { version = "1", features = ["derive"] } tokio = { version = "1", features = ["full"] } web3 = { version = "0.18", default-features = false, features = ["http-tls", "signing"] } tdn = { version = "0.7", default-features = false, features = ["std"] } tdn_did = { version = "0.7" } -tdn_storage = { git = "https://github.com/cympletech/tdn", branch="main" } +tdn_storage = { version = "0.7" } esse_primitives = { version = "0.1", path = "./types/primitives" } chat_types = { version = "0.1", path = "./types/chat" } group_types = { version = "0.1", path = "./types/group" } @@ -60,12 +65,11 @@ dao_types = { version = "0.1", path = "./types/dao" } data = { version = "0.1", path = "./types/data" } openssl = { version = "0.10", features = ["vendored"] } # Add for cross-compile. -console-subscriber = "0.1" # only use in bin daemon. +console-subscriber = { version = "0.1", optional = true } # only use in bin daemon. [target.'cfg(target_os="android")'.dependencies] jni = { version = "0.19", default-features = false } - # DEBUG patch. [patch.crates-io] chamomile = { git = "https://github.com/cympletech/chamomile" } @@ -73,3 +77,4 @@ chamomile_types = { git = "https://github.com/cympletech/chamomile" } tdn = { git = "https://github.com/cympletech/tdn" } tdn_types = { git = "https://github.com/cympletech/tdn" } tdn_did = { git = "https://github.com/cympletech/tdn" } +tdn_storage = { git = "https://github.com/cympletech/tdn" } diff --git a/lib/apps/service/models.dart b/lib/apps/service/models.dart index 9c319e1..d8680b9 100644 --- a/lib/apps/service/models.dart +++ b/lib/apps/service/models.dart @@ -16,7 +16,7 @@ const List INNER_SERVICES = [ InnerService.GroupChat, //InnerService.Dao, InnerService.Domain, - //InnerService.Cloud, + InnerService.Cloud, InnerService.Jarvis, ]; diff --git a/src/account.rs b/src/account.rs index 04aac7b..02a5998 100644 --- a/src/account.rs +++ b/src/account.rs @@ -56,12 +56,14 @@ pub(crate) struct Account { pub pass: String, pub name: String, pub avatar: Vec, - pub lock: String, // hashed-lock. - pub secret: Vec, // encrypted value. - pub encrypt: Vec, // encrypted encrypt key. - pub wallet: String, // main wallet info. - pub pub_height: u64, // public information height. - pub own_height: u64, // own data consensus height. + pub lock: String, // hashed-lock. + pub secret: Vec, // encrypted value. + pub encrypt: Vec, // encrypted encrypt key. + pub wallet: String, // main wallet info. + pub cloud: PeerId, // main cloud service. + pub cloud_key: [u8; 32], // main cloud session key. + pub pub_height: u64, // public information height. + pub own_height: u64, // own data consensus height. pub event: EventId, pub datetime: i64, plainkey: Vec, @@ -81,6 +83,8 @@ impl Account { encrypt: Vec, plainkey: Vec, wallet: String, + cloud: PeerId, + cloud_key: [u8; 32], ) -> Self { let start = SystemTime::now(); let datetime = start @@ -103,6 +107,8 @@ impl Account { secret, encrypt, wallet, + cloud, + cloud_key, plainkey, avatar, datetime, @@ -165,6 +171,8 @@ impl Account { ckey, key.to_vec(), wallet, + PeerId::default(), + [0u8; 32], ), sk, w, @@ -218,6 +226,14 @@ impl Account { event: EventId::from_hex(v.pop().unwrap().as_str()).unwrap_or(EventId::default()), own_height: v.pop().unwrap().as_i64() as u64, pub_height: v.pop().unwrap().as_i64() as u64, + cloud_key: hex::decode(v.pop().unwrap().as_str()) + .map(|bytes| { + let mut key = [0u8; 32]; + key.copy_from_slice(&bytes); + key + }) + .unwrap_or([0u8; 32]), + cloud: PeerId::from_hex(v.pop().unwrap().as_str()).unwrap_or(PeerId::default()), wallet: v.pop().unwrap().as_string(), avatar: base64::decode(v.pop().unwrap().as_str()).unwrap_or(vec![]), encrypt: base64::decode(v.pop().unwrap().as_str()).unwrap_or(vec![]), @@ -236,7 +252,7 @@ impl Account { pub fn get(db: &DStorage, pid: &PeerId) -> Result { let sql = format!( - "SELECT id, pid, indx, lang, pass, name, lock, mnemonic, secret, encrypt, avatar, wallet, pub_height, own_height, event, datetime FROM accounts WHERE pid = '{}'", + "SELECT id, pid, indx, lang, pass, name, lock, mnemonic, secret, encrypt, avatar, wallet, cloud, cloud_key, pub_height, own_height, event, datetime FROM accounts WHERE pid = '{}'", id_to_str(pid) ); let mut matrix = db.query(&sql)?; @@ -250,7 +266,7 @@ impl Account { pub fn all(db: &DStorage) -> Result> { let matrix = db.query( - "SELECT id, pid, indx, lang, pass, name, lock, mnemonic, secret, encrypt, avatar, wallet, pub_height, own_height, event, datetime FROM accounts ORDER BY datetime DESC", + "SELECT id, pid, indx, lang, pass, name, lock, mnemonic, secret, encrypt, avatar, wallet, cloud, cloud_key, pub_height, own_height, event, datetime FROM accounts ORDER BY datetime DESC", )?; let mut accounts = vec![]; for values in matrix { @@ -269,7 +285,7 @@ impl Account { self.id = id; self.update(db)?; } else { - let sql = format!("INSERT INTO accounts (pid, indx, lang, pass, name, lock, mnemonic, secret, encrypt, avatar, wallet, pub_height, own_height, event, datetime) VALUES ('{}', {}, {}, '{}', '{}', '{}', '{}', '{}', '{}', '{}', '{}', {}, {}, '{}', {})", + let sql = format!("INSERT INTO accounts (pid, indx, lang, pass, name, lock, mnemonic, secret, encrypt, avatar, wallet, cloud, cloud_key, pub_height, own_height, event, datetime) VALUES ('{}', {}, {}, '{}', '{}', '{}', '{}', '{}', '{}', '{}', '{}', '{}', '{}', {}, {}, '{}', {})", id_to_str(&self.pid), self.index, self.lang, @@ -281,6 +297,8 @@ impl Account { base64::encode(&self.encrypt), base64::encode(&self.avatar), self.wallet, + self.cloud.to_hex(), + hex::encode(&self.cloud_key), self.pub_height, self.own_height, self.event.to_hex(), @@ -293,12 +311,14 @@ impl Account { } pub fn update(&self, db: &DStorage) -> Result { - let sql = format!("UPDATE accounts SET name='{}', lock='{}', encrypt='{}', avatar='{}', wallet='{}', pub_height={}, own_height={}, event='{}', datetime={} WHERE id = {}", + let sql = format!("UPDATE accounts SET name='{}', lock='{}', encrypt='{}', avatar='{}', wallet='{}', cloud='{}', cloud_key='{}', pub_height={}, own_height={}, event='{}', datetime={} WHERE id = {}", self.name, self.lock, base64::encode(&self.encrypt), base64::encode(&self.avatar), self.wallet, + self.cloud.to_hex(), + hex::encode(&self.cloud_key), self.pub_height, self.own_height, self.datetime, @@ -310,10 +330,12 @@ impl Account { pub fn update_info(&self, db: &DStorage) -> Result { let sql = format!( - "UPDATE accounts SET name='{}', avatar='{}', wallet='{}', pub_height={} WHERE id = {}", + "UPDATE accounts SET name='{}', avatar='{}', wallet='{}', cloud='{}', cloud_key='{}', pub_height={} WHERE id = {}", self.name, base64::encode(&self.avatar), self.wallet, + self.cloud.to_hex(), + hex::encode(&self.cloud_key), self.pub_height, self.id, ); @@ -340,30 +362,29 @@ impl Account { #[derive(Serialize, Deserialize, Clone)] pub(crate) struct User { - pub id: PeerId, + pub height: u64, pub name: String, pub wallet: String, - pub height: u64, + pub cloud: PeerId, + pub cloud_key: [u8; 32], pub avatar: Vec, } impl User { - pub fn new(id: PeerId, name: String, avatar: Vec, wallet: String, height: u64) -> Self { + pub fn info( + height: u64, + name: String, + wallet: String, + cloud: PeerId, + cloud_key: [u8; 32], + avatar: Vec, + ) -> Self { Self { - id, - name, - avatar, - wallet, height, - } - } - - pub fn info(name: String, wallet: String, height: u64, avatar: Vec) -> Self { - Self { - id: PeerId::default(), name, wallet, - height, + cloud, + cloud_key, avatar, } } diff --git a/src/apps/chat/layer.rs b/src/apps/chat/layer.rs index 8f1f078..def0563 100644 --- a/src/apps/chat/layer.rs +++ b/src/apps/chat/layer.rs @@ -228,7 +228,14 @@ impl LayerEvent { r.is_over = true; r.is_ok = true; r.update(&db)?; - let friend = Friend::from_remote(&db, fpid, r.name, "".to_owned())?; + let friend = Friend::from_remote( + &db, + fpid, + r.name, + "".to_owned(), + PeerId::default(), + [0u8; 32], + )?; results.rpcs.push(rpc::request_agree(r.id, &friend)); // ADD NEW SESSION. @@ -282,9 +289,11 @@ impl LayerEvent { let account = Account::get(&a_db, &pid)?; if account.pub_height > height { let info = LayerEvent::InfoRes(User::info( + account.pub_height, account.name, account.wallet, - account.pub_height, + account.cloud, + account.cloud_key, account.avatar, )); let data = bincode::serialize(&info).unwrap_or(vec![]); @@ -302,9 +311,11 @@ impl LayerEvent { f.name = remote.name; f.wallet = remote.wallet; f.height = remote.height as i64; + f.cloud = remote.cloud; + f.cloud_key = remote.cloud_key; f.remote_update(&db)?; drop(db); - write_avatar_sync(&global.base, &pid, &remote.id, remote.avatar)?; + write_avatar_sync(&global.base, &pid, &f.pid, remote.avatar)?; results.rpcs.push(rpc::friend_info(&f)); let s_db = session_db(&global.base, &pid, &db_key)?; diff --git a/src/apps/chat/models/friend.rs b/src/apps/chat/models/friend.rs index 33ef7e6..135b7d4 100644 --- a/src/apps/chat/models/friend.rs +++ b/src/apps/chat/models/friend.rs @@ -15,6 +15,8 @@ pub(crate) struct Friend { pub pid: PeerId, pub name: String, pub wallet: String, + pub cloud: PeerId, + pub cloud_key: [u8; 32], pub height: i64, pub remark: String, pub is_closed: bool, @@ -22,7 +24,15 @@ pub(crate) struct Friend { } impl Friend { - pub fn new(pid: PeerId, name: String, wallet: String, remark: String, height: i64) -> Friend { + pub fn new( + pid: PeerId, + name: String, + wallet: String, + cloud: PeerId, + cloud_key: [u8; 32], + remark: String, + height: i64, + ) -> Friend { let start = SystemTime::now(); let datetime = start .duration_since(UNIX_EPOCH) @@ -34,6 +44,8 @@ impl Friend { pid, name, wallet, + cloud, + cloud_key, height, remark, datetime, @@ -48,6 +60,14 @@ impl Friend { is_closed: v.pop().unwrap().as_bool(), remark: v.pop().unwrap().as_string(), height: v.pop().unwrap().as_i64(), + cloud_key: hex::decode(v.pop().unwrap().as_str()) + .map(|bytes| { + let mut key = [0u8; 32]; + key.copy_from_slice(&bytes); + key + }) + .unwrap_or([0u8; 32]), + cloud: PeerId::from_hex(v.pop().unwrap().as_str()).unwrap_or(PeerId::default()), wallet: v.pop().unwrap().as_string(), name: v.pop().unwrap().as_string(), pid: id_from_str(v.pop().unwrap().as_str()).unwrap_or(PeerId::default()), @@ -55,15 +75,24 @@ impl Friend { } } - pub fn from_remote(db: &DStorage, pid: PeerId, name: String, wallet: String) -> Result { + pub fn from_remote( + db: &DStorage, + pid: PeerId, + name: String, + wallet: String, + cloud: PeerId, + cloud_key: [u8; 32], + ) -> Result { if let Ok(mut friend) = Friend::get_id(&db, &pid) { friend.name = name; friend.wallet = wallet; + friend.cloud = cloud; + friend.cloud_key = cloud_key; friend.is_closed = false; friend.remote_update(&db)?; Ok(friend) } else { - let mut friend = Friend::new(pid, name, wallet, "".to_owned(), 0); + let mut friend = Friend::new(pid, name, wallet, cloud, cloud_key, "".to_owned(), 0); friend.insert(&db)?; Ok(friend) } @@ -86,6 +115,7 @@ impl Friend { id_to_str(&self.pid), self.name, self.wallet, + self.cloud.to_hex(), self.remark, self.is_closed, self.datetime @@ -98,6 +128,7 @@ impl Friend { id_to_str(&self.pid), self.name, self.wallet, + self.cloud.to_hex(), self.remark, self.is_closed, self.datetime, @@ -106,7 +137,7 @@ impl Friend { } pub fn get_id(db: &DStorage, pid: &PeerId) -> Result { - let sql = format!("SELECT id, pid, name, wallet, height, remark, is_closed, datetime FROM friends WHERE pid = '{}'", id_to_str(pid)); + let sql = format!("SELECT id, pid, name, wallet, cloud, cloud_key, height, remark, is_closed, datetime FROM friends WHERE pid = '{}'", id_to_str(pid)); let mut matrix = db.query(&sql)?; if matrix.len() > 0 { Ok(Friend::from_values(matrix.pop().unwrap())) // safe unwrap() @@ -116,7 +147,7 @@ impl Friend { } pub fn get(db: &DStorage, id: &i64) -> Result { - let sql = format!("SELECT id, pid, name, wallet, height, remark, is_closed, datetime FROM friends WHERE id = {}", id); + let sql = format!("SELECT id, pid, name, wallet, cloud, cloud_key, height, remark, is_closed, datetime FROM friends WHERE id = {}", id); let mut matrix = db.query(&sql)?; if matrix.len() > 0 { Ok(Friend::from_values(matrix.pop().unwrap())) // safe unwrap() @@ -128,7 +159,7 @@ impl Friend { /// use in rpc when load account friends. pub fn list(db: &DStorage) -> Result> { let matrix = db.query( - "SELECT id, pid, name, wallet, height, remark, is_closed, datetime FROM friends", + "SELECT id, pid, name, wallet, cloud, cloud_key, height, remark, is_closed, datetime FROM friends", )?; let mut friends = vec![]; for values in matrix { @@ -138,10 +169,12 @@ impl Friend { } pub fn insert(&mut self, db: &DStorage) -> Result<()> { - let sql = format!("INSERT INTO friends (pid, name, wallet, height, remark, is_closed, datetime) VALUES ('{}', '{}', '{}', {}, '{}', {}, {})", + let sql = format!("INSERT INTO friends (pid, name, wallet, cloud, cloud_key, height, remark, is_closed, datetime) VALUES ('{}', '{}', '{}', '{}', '{}', {}, '{}', {}, {})", id_to_str(&self.pid), self.name, self.wallet, + self.cloud.to_hex(), + hex::encode(&self.cloud_key), self.height, self.remark, self.is_closed, @@ -153,9 +186,11 @@ impl Friend { } pub fn update(&self, db: &DStorage) -> Result { - let sql = format!("UPDATE friends SET name = '{}', wallet = '{}', height={}, remark = '{}', is_closed = {} WHERE id = {}", + let sql = format!("UPDATE friends SET name='{}', wallet='{}', cloud='{}', cloud_key='{}', height={}, remark='{}', is_closed={} WHERE id={}", self.name, self.wallet, + self.cloud.to_hex(), + hex::encode(&self.cloud_key), self.height, self.remark, self.is_closed, @@ -174,8 +209,13 @@ impl Friend { pub fn remote_update(&self, db: &DStorage) -> Result { let sql = format!( - "UPDATE friends SET name='{}', wallet='{}', height={}, is_closed = false WHERE id = {}", - self.name, self.wallet, self.height, self.id, + "UPDATE friends SET name='{}', wallet='{}', cloud='{}', cloud_key='{}', height={}, is_closed = false WHERE id = {}", + self.name, + self.wallet, + self.cloud.to_hex(), + hex::encode(&self.cloud_key), + self.height, + self.id, ); db.update(&sql) } diff --git a/src/apps/chat/rpc.rs b/src/apps/chat/rpc.rs index 48d545b..04de7da 100644 --- a/src/apps/chat/rpc.rs +++ b/src/apps/chat/rpc.rs @@ -315,7 +315,14 @@ pub(crate) fn new_rpc_handler(handler: &mut RpcHandler) { request.is_over = true; request.update(&db)?; - let friend = Friend::from_remote(&db, request.pid, request.name, "".to_owned())?; + let friend = Friend::from_remote( + &db, + request.pid, + request.name, + "".to_owned(), + PeerId::default(), + [0u8; 32], + )?; results.rpcs.push(json!([id, friend.to_rpc()])); // ADD NEW SESSION. diff --git a/src/apps/cloud/layer.rs b/src/apps/cloud/layer.rs index 771ff8c..c53b886 100644 --- a/src/apps/cloud/layer.rs +++ b/src/apps/cloud/layer.rs @@ -19,7 +19,7 @@ pub(crate) async fn handle(msg: RecvType, global: &Arc) -> Result { - let LayerServerEvent(_event) = bincode::deserialize(&bytes)?; + let _event: LayerServerEvent = bincode::deserialize(&bytes)?; } RecvType::Delivery(_t, _tid, _is_ok) => { // MAYBE diff --git a/src/group.rs b/src/group.rs index 389cf78..8cb53d6 100644 --- a/src/group.rs +++ b/src/group.rs @@ -435,12 +435,13 @@ impl Group { pub fn clone_user(&self, pid: &PeerId) -> Result { if let Some(u) = self.accounts.get(pid) { - Ok(User::new( - u.pid, + Ok(User::info( + u.pub_height, u.name.clone(), - u.avatar.clone(), u.wallet.clone(), - u.pub_height, + u.cloud.clone(), + u.cloud_key.clone(), + u.avatar.clone(), )) } else { Err(anyhow!("user missing.")) diff --git a/src/migrate/account.rs b/src/migrate/account.rs index dbae9f9..b263d5c 100644 --- a/src/migrate/account.rs +++ b/src/migrate/account.rs @@ -13,6 +13,7 @@ pub(super) const ACCOUNT_VERSIONS: [&str; 13] = [ mnemonic TEXT NOT NULL, avatar TEXT NOT NULL, wallet TEXT NOT NULL, + cloud TEXT NOT NULL, pub_height INTEGER NOT NULL, own_height INTEGER NOT NULL, event TEXT NOT NULL, diff --git a/src/migrate/chat.rs b/src/migrate/chat.rs index 16fb747..369e0d1 100644 --- a/src/migrate/chat.rs +++ b/src/migrate/chat.rs @@ -4,7 +4,9 @@ pub(super) const CHAT_VERSIONS: [&str; 3] = [ id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, pid TEXT NOT NULL, name TEXT NOT NULL, - wallet TEXT, + wallet TEXT NOT NULL, + cloud TEXT NOT NULL, + cloud_key TEXT NOT NULL, height INTEGER NOT NULL, remark TEXT, is_closed INTEGER NOT NULL, diff --git a/src/utils/crypto.rs b/src/utils/crypto.rs index 7111649..da5b0f4 100644 --- a/src/utils/crypto.rs +++ b/src/utils/crypto.rs @@ -7,6 +7,7 @@ use argon2::{ Argon2, }; use sha2::{Digest, Sha256}; +use tdn::types::primitives::{PeerId, PeerKey}; const FIX_PADDING: [u8; 19] = [ 69, 83, 83, 69, 70, 111, 114, 68, 97, 116, 97, 83, 101, 99, 117, 114, 105, 116, 121, @@ -194,3 +195,9 @@ pub fn _decrypt_multiple( } Ok(pbytes) } + +/// Compute the session key in the cloud. +#[inline] +pub fn cloud_key(key: &[u8; 32]) -> Aes256Gcm { + Aes256Gcm::new(GenericArray::from_slice(key)) +} diff --git a/types/cloud/src/lib.rs b/types/cloud/src/lib.rs index 703b364..c82d92b 100644 --- a/types/cloud/src/lib.rs +++ b/types/cloud/src/lib.rs @@ -1,28 +1,32 @@ use serde::{Deserialize, Serialize}; -use tdn_types::group::GroupId; +use tdn_types::{group::GroupId, primitives::PeerId}; /// Personal data cloud service default TDN GROUP ID. pub const CLOUD_ID: GroupId = 5; -/// ESSE service to peer layer Event. -#[derive(Serialize, Deserialize)] -pub struct LayerServerEvent(pub ServerEvent); - -/// ESSE peer to layer Event. -#[derive(Serialize, Deserialize)] -pub struct LayerPeerEvent(pub PeerEvent); - /// ESSE service to peer Event. #[derive(Serialize, Deserialize)] -pub enum ServerEvent { +pub enum LayerServerEvent { /// check result status. - /// params: provider name, is support request proxy. - Status(String, bool), + /// params: provider name, free space, VIP space & price. + Status(String, u64, Vec<(u64, u64)>), + /// Peer check result: PeerId, is running. + PeerStatus(PeerId, bool), + /// Sync event. + SyncEvent, + /// Sync file. + SyncFile, } /// ESSE peer to service Event. #[derive(Serialize, Deserialize)] -pub enum PeerEvent { - /// check service status is ok. +pub enum LayerPeerEvent { + /// check service info. Check, + /// check PeerId is running at this service. + PeerCheck(PeerId), + /// Send sync event. + Event, + /// Send sync file. + File, }