more clippy
This commit is contained in:
parent
c7d4462e0e
commit
f596b3ce05
@ -103,11 +103,11 @@ impl<S: Subscriber + for<'a> registry::LookupSpan<'a>> Layer<S> for ApiTracingLa
|
|||||||
None
|
None
|
||||||
};
|
};
|
||||||
|
|
||||||
(inner.update_callback)(VeilidUpdate::Log(VeilidLog {
|
(inner.update_callback)(VeilidUpdate::Log(Box::new(VeilidLog {
|
||||||
log_level,
|
log_level,
|
||||||
message,
|
message,
|
||||||
backtrace,
|
backtrace,
|
||||||
}))
|
})))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -168,7 +168,7 @@ impl AttachmentManager {
|
|||||||
})
|
})
|
||||||
.unwrap_or(true);
|
.unwrap_or(true);
|
||||||
if send_update {
|
if send_update {
|
||||||
Some((update_callback, Self::get_veilid_state_inner(&*inner)))
|
Some((update_callback, Self::get_veilid_state_inner(&inner)))
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
@ -197,11 +197,11 @@ impl AttachmentManager {
|
|||||||
};
|
};
|
||||||
|
|
||||||
if let Some(update_callback) = update_callback {
|
if let Some(update_callback) = update_callback {
|
||||||
update_callback(VeilidUpdate::Attachment(VeilidStateAttachment {
|
update_callback(VeilidUpdate::Attachment(Box::new(VeilidStateAttachment {
|
||||||
state,
|
state,
|
||||||
public_internet_ready: false,
|
public_internet_ready: false,
|
||||||
local_network_ready: false,
|
local_network_ready: false,
|
||||||
}))
|
})))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -325,8 +325,8 @@ impl AttachmentManager {
|
|||||||
// self.inner.lock().last_attachment_state
|
// self.inner.lock().last_attachment_state
|
||||||
// }
|
// }
|
||||||
|
|
||||||
fn get_veilid_state_inner(inner: &AttachmentManagerInner) -> VeilidStateAttachment {
|
fn get_veilid_state_inner(inner: &AttachmentManagerInner) -> Box<VeilidStateAttachment> {
|
||||||
VeilidStateAttachment {
|
Box::new(VeilidStateAttachment {
|
||||||
state: inner.last_attachment_state,
|
state: inner.last_attachment_state,
|
||||||
public_internet_ready: inner
|
public_internet_ready: inner
|
||||||
.last_routing_table_health
|
.last_routing_table_health
|
||||||
@ -338,11 +338,11 @@ impl AttachmentManager {
|
|||||||
.as_ref()
|
.as_ref()
|
||||||
.map(|x| x.local_network_ready)
|
.map(|x| x.local_network_ready)
|
||||||
.unwrap_or(false),
|
.unwrap_or(false),
|
||||||
}
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_veilid_state(&self) -> VeilidStateAttachment {
|
pub fn get_veilid_state(&self) -> Box<VeilidStateAttachment> {
|
||||||
let inner = self.inner.lock();
|
let inner = self.inner.lock();
|
||||||
Self::get_veilid_state_inner(&*inner)
|
Self::get_veilid_state_inner(&inner)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,3 @@
|
|||||||
#![allow(clippy::bool_assert_comparison)]
|
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
use core::convert::TryFrom;
|
use core::convert::TryFrom;
|
||||||
|
|
||||||
@ -338,14 +336,14 @@ async fn test_operations(vcrypto: CryptoSystemVersion) {
|
|||||||
assert_eq!(d4.first_nonzero_nibble(), Some((0, 0x9u8)));
|
assert_eq!(d4.first_nonzero_nibble(), Some((0, 0x9u8)));
|
||||||
|
|
||||||
// Verify bits
|
// Verify bits
|
||||||
assert_eq!(d1.bit(0), true);
|
assert!(d1.bit(0));
|
||||||
assert_eq!(d1.bit(1), false);
|
assert!(!d1.bit(1));
|
||||||
assert_eq!(d1.bit(7), false);
|
assert!(!d1.bit(7));
|
||||||
assert_eq!(d1.bit(8), false);
|
assert!(!d1.bit(8));
|
||||||
assert_eq!(d1.bit(14), true);
|
assert!(d1.bit(14));
|
||||||
assert_eq!(d1.bit(15), false);
|
assert!(!d1.bit(15));
|
||||||
assert_eq!(d1.bit(254), true);
|
assert!(d1.bit(254));
|
||||||
assert_eq!(d1.bit(255), false);
|
assert!(!d1.bit(255));
|
||||||
|
|
||||||
assert_eq!(d1.first_nonzero_bit(), Some(0));
|
assert_eq!(d1.first_nonzero_bit(), Some(0));
|
||||||
assert_eq!(d2.first_nonzero_bit(), Some(0));
|
assert_eq!(d2.first_nonzero_bit(), Some(0));
|
||||||
|
@ -73,7 +73,7 @@ impl NetworkManager {
|
|||||||
inner.stats.clone()
|
inner.stats.clone()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_veilid_state(&self) -> VeilidStateNetwork {
|
pub fn get_veilid_state(&self) -> Box<VeilidStateNetwork> {
|
||||||
let has_state = self
|
let has_state = self
|
||||||
.unlocked_inner
|
.unlocked_inner
|
||||||
.components
|
.components
|
||||||
@ -83,12 +83,12 @@ impl NetworkManager {
|
|||||||
.unwrap_or(false);
|
.unwrap_or(false);
|
||||||
|
|
||||||
if !has_state {
|
if !has_state {
|
||||||
return VeilidStateNetwork {
|
return Box::new(VeilidStateNetwork {
|
||||||
started: false,
|
started: false,
|
||||||
bps_down: 0.into(),
|
bps_down: 0.into(),
|
||||||
bps_up: 0.into(),
|
bps_up: 0.into(),
|
||||||
peers: Vec::new(),
|
peers: Vec::new(),
|
||||||
};
|
});
|
||||||
}
|
}
|
||||||
let routing_table = self.routing_table();
|
let routing_table = self.routing_table();
|
||||||
|
|
||||||
@ -100,7 +100,7 @@ impl NetworkManager {
|
|||||||
)
|
)
|
||||||
};
|
};
|
||||||
|
|
||||||
VeilidStateNetwork {
|
Box::new(VeilidStateNetwork {
|
||||||
started: true,
|
started: true,
|
||||||
bps_down,
|
bps_down,
|
||||||
bps_up,
|
bps_up,
|
||||||
@ -119,7 +119,7 @@ impl NetworkManager {
|
|||||||
}
|
}
|
||||||
out
|
out
|
||||||
},
|
},
|
||||||
}
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(super) fn send_network_update(&self) {
|
pub(super) fn send_network_update(&self) {
|
||||||
|
@ -261,9 +261,8 @@ impl ReceiptManager {
|
|||||||
|
|
||||||
// Wait on all the multi-call callbacks
|
// Wait on all the multi-call callbacks
|
||||||
loop {
|
loop {
|
||||||
match callbacks.next().timeout_at(stop_token.clone()).await {
|
if let Ok(None) | Err(_) = callbacks.next().timeout_at(stop_token.clone()).await {
|
||||||
Ok(Some(_)) => {}
|
break;
|
||||||
Ok(None) | Err(_) => break,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -307,7 +306,7 @@ impl ReceiptManager {
|
|||||||
|
|
||||||
// Wait for everything to stop
|
// Wait for everything to stop
|
||||||
debug!("waiting for timeout task to stop");
|
debug!("waiting for timeout task to stop");
|
||||||
if !timeout_task.join().await.is_ok() {
|
if timeout_task.join().await.is_err() {
|
||||||
panic!("joining timeout task failed");
|
panic!("joining timeout task failed");
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -333,7 +332,7 @@ impl ReceiptManager {
|
|||||||
let mut inner = self.inner.lock();
|
let mut inner = self.inner.lock();
|
||||||
inner.records_by_nonce.insert(receipt_nonce, record);
|
inner.records_by_nonce.insert(receipt_nonce, record);
|
||||||
|
|
||||||
Self::update_next_oldest_timestamp(&mut *inner);
|
Self::update_next_oldest_timestamp(&mut inner);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn record_single_shot_receipt(
|
pub fn record_single_shot_receipt(
|
||||||
@ -351,7 +350,7 @@ impl ReceiptManager {
|
|||||||
let mut inner = self.inner.lock();
|
let mut inner = self.inner.lock();
|
||||||
inner.records_by_nonce.insert(receipt_nonce, record);
|
inner.records_by_nonce.insert(receipt_nonce, record);
|
||||||
|
|
||||||
Self::update_next_oldest_timestamp(&mut *inner);
|
Self::update_next_oldest_timestamp(&mut inner);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn update_next_oldest_timestamp(inner: &mut ReceiptManagerInner) {
|
fn update_next_oldest_timestamp(inner: &mut ReceiptManagerInner) {
|
||||||
@ -382,7 +381,7 @@ impl ReceiptManager {
|
|||||||
bail!("receipt not recorded");
|
bail!("receipt not recorded");
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
Self::update_next_oldest_timestamp(&mut *inner);
|
Self::update_next_oldest_timestamp(&mut inner);
|
||||||
record
|
record
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -448,14 +447,12 @@ impl ReceiptManager {
|
|||||||
let receipt_event = match receipt_returned {
|
let receipt_event = match receipt_returned {
|
||||||
ReceiptReturned::OutOfBand => ReceiptEvent::ReturnedOutOfBand,
|
ReceiptReturned::OutOfBand => ReceiptEvent::ReturnedOutOfBand,
|
||||||
ReceiptReturned::Safety => ReceiptEvent::ReturnedSafety,
|
ReceiptReturned::Safety => ReceiptEvent::ReturnedSafety,
|
||||||
ReceiptReturned::InBand {
|
ReceiptReturned::InBand { inbound_noderef } => {
|
||||||
ref inbound_noderef,
|
ReceiptEvent::ReturnedInBand { inbound_noderef }
|
||||||
} => ReceiptEvent::ReturnedInBand {
|
}
|
||||||
inbound_noderef: inbound_noderef.clone(),
|
ReceiptReturned::Private { private_route } => {
|
||||||
},
|
ReceiptEvent::ReturnedPrivate { private_route }
|
||||||
ReceiptReturned::Private { ref private_route } => ReceiptEvent::ReturnedPrivate {
|
}
|
||||||
private_route: private_route.clone(),
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
|
|
||||||
let callback_future = Self::perform_callback(receipt_event, &mut record_mut);
|
let callback_future = Self::perform_callback(receipt_event, &mut record_mut);
|
||||||
@ -464,7 +461,7 @@ impl ReceiptManager {
|
|||||||
if record_mut.returns_so_far == record_mut.expected_returns {
|
if record_mut.returns_so_far == record_mut.expected_returns {
|
||||||
inner.records_by_nonce.remove(&receipt_nonce);
|
inner.records_by_nonce.remove(&receipt_nonce);
|
||||||
|
|
||||||
Self::update_next_oldest_timestamp(&mut *inner);
|
Self::update_next_oldest_timestamp(&mut inner);
|
||||||
}
|
}
|
||||||
(callback_future, stop_token)
|
(callback_future, stop_token)
|
||||||
};
|
};
|
||||||
|
@ -141,10 +141,10 @@ impl RouteSpecStore {
|
|||||||
dr
|
dr
|
||||||
};
|
};
|
||||||
|
|
||||||
let update = VeilidUpdate::RouteChange(VeilidRouteChange {
|
let update = VeilidUpdate::RouteChange(Box::new(VeilidRouteChange {
|
||||||
dead_routes,
|
dead_routes,
|
||||||
dead_remote_routes,
|
dead_remote_routes,
|
||||||
});
|
}));
|
||||||
|
|
||||||
let update_callback = self.unlocked_inner.routing_table.update_callback();
|
let update_callback = self.unlocked_inner.routing_table.update_callback();
|
||||||
update_callback(update);
|
update_callback(update);
|
||||||
|
@ -94,9 +94,9 @@ impl RPCProcessor {
|
|||||||
|
|
||||||
// Pass the call up through the update callback
|
// Pass the call up through the update callback
|
||||||
let message_q = app_call_q.destructure();
|
let message_q = app_call_q.destructure();
|
||||||
(self.unlocked_inner.update_callback)(VeilidUpdate::AppCall(VeilidAppCall::new(
|
(self.unlocked_inner.update_callback)(VeilidUpdate::AppCall(Box::new(VeilidAppCall::new(
|
||||||
sender, message_q, op_id,
|
sender, message_q, op_id,
|
||||||
)));
|
))));
|
||||||
|
|
||||||
// Wait for an app call answer to come back from the app
|
// Wait for an app call answer to come back from the app
|
||||||
let res = self
|
let res = self
|
||||||
|
@ -58,8 +58,8 @@ impl RPCProcessor {
|
|||||||
|
|
||||||
// Pass the message up through the update callback
|
// Pass the message up through the update callback
|
||||||
let message = app_message.destructure();
|
let message = app_message.destructure();
|
||||||
(self.unlocked_inner.update_callback)(VeilidUpdate::AppMessage(VeilidAppMessage::new(
|
(self.unlocked_inner.update_callback)(VeilidUpdate::AppMessage(Box::new(
|
||||||
sender, message,
|
VeilidAppMessage::new(sender, message),
|
||||||
)));
|
)));
|
||||||
|
|
||||||
Ok(NetworkResult::value(()))
|
Ok(NetworkResult::value(()))
|
||||||
|
@ -1,9 +1,7 @@
|
|||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
mod table_db;
|
mod table_db;
|
||||||
mod table_store;
|
|
||||||
pub use table_db::*;
|
pub use table_db::*;
|
||||||
pub use table_store::*;
|
|
||||||
|
|
||||||
pub mod tests;
|
pub mod tests;
|
||||||
|
|
||||||
@ -15,3 +13,582 @@ use wasm::*;
|
|||||||
mod native;
|
mod native;
|
||||||
#[cfg(not(target_arch = "wasm32"))]
|
#[cfg(not(target_arch = "wasm32"))]
|
||||||
use native::*;
|
use native::*;
|
||||||
|
|
||||||
|
use keyvaluedb::*;
|
||||||
|
|
||||||
|
const ALL_TABLE_NAMES: &[u8] = b"all_table_names";
|
||||||
|
|
||||||
|
struct TableStoreInner {
|
||||||
|
opened: BTreeMap<String, Weak<TableDBUnlockedInner>>,
|
||||||
|
encryption_key: Option<TypedSharedSecret>,
|
||||||
|
all_table_names: HashMap<String, String>,
|
||||||
|
all_tables_db: Option<Database>,
|
||||||
|
crypto: Option<Crypto>,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Veilid Table Storage
|
||||||
|
/// Database for storing key value pairs persistently and securely across runs
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub struct TableStore {
|
||||||
|
config: VeilidConfig,
|
||||||
|
protected_store: ProtectedStore,
|
||||||
|
table_store_driver: TableStoreDriver,
|
||||||
|
inner: Arc<Mutex<TableStoreInner>>, // Sync mutex here because TableDB drops can happen at any time
|
||||||
|
async_lock: Arc<AsyncMutex<()>>, // Async mutex for operations
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TableStore {
|
||||||
|
fn new_inner() -> TableStoreInner {
|
||||||
|
TableStoreInner {
|
||||||
|
opened: BTreeMap::new(),
|
||||||
|
encryption_key: None,
|
||||||
|
all_table_names: HashMap::new(),
|
||||||
|
all_tables_db: None,
|
||||||
|
crypto: None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub(crate) fn new(config: VeilidConfig, protected_store: ProtectedStore) -> Self {
|
||||||
|
let inner = Self::new_inner();
|
||||||
|
let table_store_driver = TableStoreDriver::new(config.clone());
|
||||||
|
|
||||||
|
Self {
|
||||||
|
config,
|
||||||
|
protected_store,
|
||||||
|
inner: Arc::new(Mutex::new(inner)),
|
||||||
|
table_store_driver,
|
||||||
|
async_lock: Arc::new(AsyncMutex::new(())),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn set_crypto(&self, crypto: Crypto) {
|
||||||
|
let mut inner = self.inner.lock();
|
||||||
|
inner.crypto = Some(crypto);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Flush internal control state (must not use crypto)
|
||||||
|
async fn flush(&self) {
|
||||||
|
let (all_table_names_value, all_tables_db) = {
|
||||||
|
let inner = self.inner.lock();
|
||||||
|
let all_table_names_value = serialize_json_bytes(&inner.all_table_names);
|
||||||
|
(all_table_names_value, inner.all_tables_db.clone().unwrap())
|
||||||
|
};
|
||||||
|
let mut dbt = DBTransaction::new();
|
||||||
|
dbt.put(0, ALL_TABLE_NAMES, &all_table_names_value);
|
||||||
|
if let Err(e) = all_tables_db.write(dbt).await {
|
||||||
|
error!("failed to write all tables db: {}", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Internal naming support
|
||||||
|
// Adds rename capability and ensures names of tables are totally unique and valid
|
||||||
|
|
||||||
|
fn namespaced_name(&self, table: &str) -> VeilidAPIResult<String> {
|
||||||
|
if !table
|
||||||
|
.chars()
|
||||||
|
.all(|c| char::is_alphanumeric(c) || c == '_' || c == '-')
|
||||||
|
{
|
||||||
|
apibail_invalid_argument!("table name is invalid", "table", table);
|
||||||
|
}
|
||||||
|
let c = self.config.get();
|
||||||
|
let namespace = c.namespace.clone();
|
||||||
|
Ok(if namespace.is_empty() {
|
||||||
|
table.to_string()
|
||||||
|
} else {
|
||||||
|
format!("_ns_{}_{}", namespace, table)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn name_get_or_create(&self, table: &str) -> VeilidAPIResult<String> {
|
||||||
|
let name = self.namespaced_name(table)?;
|
||||||
|
|
||||||
|
let mut inner = self.inner.lock();
|
||||||
|
// Do we have this name yet?
|
||||||
|
if let Some(real_name) = inner.all_table_names.get(&name) {
|
||||||
|
return Ok(real_name.clone());
|
||||||
|
}
|
||||||
|
|
||||||
|
// If not, make a new low level name mapping
|
||||||
|
let mut real_name_bytes = [0u8; 32];
|
||||||
|
random_bytes(&mut real_name_bytes);
|
||||||
|
let real_name = data_encoding::BASE64URL_NOPAD.encode(&real_name_bytes);
|
||||||
|
|
||||||
|
if inner
|
||||||
|
.all_table_names
|
||||||
|
.insert(name.to_owned(), real_name.clone())
|
||||||
|
.is_some()
|
||||||
|
{
|
||||||
|
panic!("should not have had some value");
|
||||||
|
};
|
||||||
|
|
||||||
|
Ok(real_name)
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn name_delete(&self, table: &str) -> VeilidAPIResult<Option<String>> {
|
||||||
|
let name = self.namespaced_name(table)?;
|
||||||
|
let mut inner = self.inner.lock();
|
||||||
|
let real_name = inner.all_table_names.remove(&name);
|
||||||
|
Ok(real_name)
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn name_get(&self, table: &str) -> VeilidAPIResult<Option<String>> {
|
||||||
|
let name = self.namespaced_name(table)?;
|
||||||
|
let inner = self.inner.lock();
|
||||||
|
let real_name = inner.all_table_names.get(&name).cloned();
|
||||||
|
Ok(real_name)
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn name_rename(&self, old_table: &str, new_table: &str) -> VeilidAPIResult<()> {
|
||||||
|
let old_name = self.namespaced_name(old_table)?;
|
||||||
|
let new_name = self.namespaced_name(new_table)?;
|
||||||
|
|
||||||
|
let mut inner = self.inner.lock();
|
||||||
|
// Ensure new name doesn't exist
|
||||||
|
if inner.all_table_names.contains_key(&new_name) {
|
||||||
|
return Err(VeilidAPIError::generic("new table already exists"));
|
||||||
|
}
|
||||||
|
// Do we have this name yet?
|
||||||
|
let Some(real_name) = inner.all_table_names.remove(&old_name) else {
|
||||||
|
return Err(VeilidAPIError::generic("table does not exist"));
|
||||||
|
};
|
||||||
|
// Insert with new name
|
||||||
|
inner.all_table_names.insert(new_name.to_owned(), real_name);
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Delete all known tables
|
||||||
|
async fn delete_all(&self) {
|
||||||
|
// Get all tables
|
||||||
|
let real_names = {
|
||||||
|
let mut inner = self.inner.lock();
|
||||||
|
let real_names = inner
|
||||||
|
.all_table_names
|
||||||
|
.values()
|
||||||
|
.cloned()
|
||||||
|
.collect::<Vec<String>>();
|
||||||
|
inner.all_table_names.clear();
|
||||||
|
real_names
|
||||||
|
};
|
||||||
|
|
||||||
|
// Delete all tables
|
||||||
|
for table_name in real_names {
|
||||||
|
if let Err(e) = self.table_store_driver.delete(&table_name).await {
|
||||||
|
error!("error deleting table: {}", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
self.flush().await;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn maybe_unprotect_device_encryption_key(
|
||||||
|
&self,
|
||||||
|
dek_bytes: &[u8],
|
||||||
|
device_encryption_key_password: &str,
|
||||||
|
) -> EyreResult<TypedSharedSecret> {
|
||||||
|
// Ensure the key is at least as long as necessary if unencrypted
|
||||||
|
if dek_bytes.len() < (4 + SHARED_SECRET_LENGTH) {
|
||||||
|
bail!("device encryption key is not valid");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get cryptosystem
|
||||||
|
let kind = FourCC::try_from(&dek_bytes[0..4]).unwrap();
|
||||||
|
let crypto = self.inner.lock().crypto.as_ref().unwrap().clone();
|
||||||
|
let Some(vcrypto) = crypto.get(kind) else {
|
||||||
|
bail!("unsupported cryptosystem");
|
||||||
|
};
|
||||||
|
|
||||||
|
if !device_encryption_key_password.is_empty() {
|
||||||
|
if dek_bytes.len()
|
||||||
|
!= (4 + SHARED_SECRET_LENGTH + vcrypto.aead_overhead() + NONCE_LENGTH)
|
||||||
|
{
|
||||||
|
bail!("password protected device encryption key is not valid");
|
||||||
|
}
|
||||||
|
let protected_key = &dek_bytes[4..(4 + SHARED_SECRET_LENGTH + vcrypto.aead_overhead())];
|
||||||
|
let nonce =
|
||||||
|
Nonce::try_from(&dek_bytes[(4 + SHARED_SECRET_LENGTH + vcrypto.aead_overhead())..])
|
||||||
|
.wrap_err("invalid nonce")?;
|
||||||
|
|
||||||
|
let shared_secret = vcrypto
|
||||||
|
.derive_shared_secret(device_encryption_key_password.as_bytes(), &nonce.bytes)
|
||||||
|
.wrap_err("failed to derive shared secret")?;
|
||||||
|
let unprotected_key = vcrypto
|
||||||
|
.decrypt_aead(protected_key, &nonce, &shared_secret, None)
|
||||||
|
.wrap_err("failed to decrypt device encryption key")?;
|
||||||
|
return Ok(TypedSharedSecret::new(
|
||||||
|
kind,
|
||||||
|
SharedSecret::try_from(unprotected_key.as_slice())
|
||||||
|
.wrap_err("invalid shared secret")?,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
if dek_bytes.len() != (4 + SHARED_SECRET_LENGTH) {
|
||||||
|
bail!("password protected device encryption key is not valid");
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(TypedSharedSecret::new(
|
||||||
|
kind,
|
||||||
|
SharedSecret::try_from(&dek_bytes[4..])?,
|
||||||
|
))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn maybe_protect_device_encryption_key(
|
||||||
|
&self,
|
||||||
|
dek: TypedSharedSecret,
|
||||||
|
device_encryption_key_password: &str,
|
||||||
|
) -> EyreResult<Vec<u8>> {
|
||||||
|
// Check if we are to protect the key
|
||||||
|
if device_encryption_key_password.is_empty() {
|
||||||
|
debug!("no dek password");
|
||||||
|
// Return the unprotected key bytes
|
||||||
|
let mut out = Vec::with_capacity(4 + SHARED_SECRET_LENGTH);
|
||||||
|
out.extend_from_slice(&dek.kind.0);
|
||||||
|
out.extend_from_slice(&dek.value.bytes);
|
||||||
|
return Ok(out);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get cryptosystem
|
||||||
|
let crypto = self.inner.lock().crypto.as_ref().unwrap().clone();
|
||||||
|
let Some(vcrypto) = crypto.get(dek.kind) else {
|
||||||
|
bail!("unsupported cryptosystem");
|
||||||
|
};
|
||||||
|
|
||||||
|
let nonce = vcrypto.random_nonce();
|
||||||
|
let shared_secret = vcrypto
|
||||||
|
.derive_shared_secret(device_encryption_key_password.as_bytes(), &nonce.bytes)
|
||||||
|
.wrap_err("failed to derive shared secret")?;
|
||||||
|
let mut protected_key = vcrypto
|
||||||
|
.encrypt_aead(&dek.value.bytes, &nonce, &shared_secret, None)
|
||||||
|
.wrap_err("failed to decrypt device encryption key")?;
|
||||||
|
let mut out =
|
||||||
|
Vec::with_capacity(4 + SHARED_SECRET_LENGTH + vcrypto.aead_overhead() + NONCE_LENGTH);
|
||||||
|
out.extend_from_slice(&dek.kind.0);
|
||||||
|
out.append(&mut protected_key);
|
||||||
|
out.extend_from_slice(&nonce.bytes);
|
||||||
|
assert!(out.len() == 4 + SHARED_SECRET_LENGTH + vcrypto.aead_overhead() + NONCE_LENGTH);
|
||||||
|
Ok(out)
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn load_device_encryption_key(&self) -> EyreResult<Option<TypedSharedSecret>> {
|
||||||
|
let dek_bytes: Option<Vec<u8>> = self
|
||||||
|
.protected_store
|
||||||
|
.load_user_secret("device_encryption_key")
|
||||||
|
.await?;
|
||||||
|
let Some(dek_bytes) = dek_bytes else {
|
||||||
|
debug!("no device encryption key");
|
||||||
|
return Ok(None);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Get device encryption key protection password if we have it
|
||||||
|
let device_encryption_key_password = {
|
||||||
|
let c = self.config.get();
|
||||||
|
c.protected_store.device_encryption_key_password.clone()
|
||||||
|
};
|
||||||
|
|
||||||
|
Ok(Some(self.maybe_unprotect_device_encryption_key(
|
||||||
|
&dek_bytes,
|
||||||
|
&device_encryption_key_password,
|
||||||
|
)?))
|
||||||
|
}
|
||||||
|
async fn save_device_encryption_key(
|
||||||
|
&self,
|
||||||
|
device_encryption_key: Option<TypedSharedSecret>,
|
||||||
|
) -> EyreResult<()> {
|
||||||
|
let Some(device_encryption_key) = device_encryption_key else {
|
||||||
|
// Remove the device encryption key
|
||||||
|
let existed = self
|
||||||
|
.protected_store
|
||||||
|
.remove_user_secret("device_encryption_key")
|
||||||
|
.await?;
|
||||||
|
debug!("removed device encryption key. existed: {}", existed);
|
||||||
|
return Ok(());
|
||||||
|
};
|
||||||
|
|
||||||
|
// Get new device encryption key protection password if we are changing it
|
||||||
|
let new_device_encryption_key_password = {
|
||||||
|
let c = self.config.get();
|
||||||
|
c.protected_store.new_device_encryption_key_password.clone()
|
||||||
|
};
|
||||||
|
let device_encryption_key_password =
|
||||||
|
if let Some(new_device_encryption_key_password) = new_device_encryption_key_password {
|
||||||
|
// Change password
|
||||||
|
debug!("changing dek password");
|
||||||
|
self.config
|
||||||
|
.with_mut(|c| {
|
||||||
|
c.protected_store.device_encryption_key_password =
|
||||||
|
new_device_encryption_key_password.clone();
|
||||||
|
Ok(new_device_encryption_key_password)
|
||||||
|
})
|
||||||
|
.unwrap()
|
||||||
|
} else {
|
||||||
|
// Get device encryption key protection password if we have it
|
||||||
|
debug!("saving with existing dek password");
|
||||||
|
let c = self.config.get();
|
||||||
|
c.protected_store.device_encryption_key_password.clone()
|
||||||
|
};
|
||||||
|
|
||||||
|
let dek_bytes = self.maybe_protect_device_encryption_key(
|
||||||
|
device_encryption_key,
|
||||||
|
&device_encryption_key_password,
|
||||||
|
)?;
|
||||||
|
|
||||||
|
// Save the new device encryption key
|
||||||
|
let existed = self
|
||||||
|
.protected_store
|
||||||
|
.save_user_secret("device_encryption_key", &dek_bytes)
|
||||||
|
.await?;
|
||||||
|
debug!("saving device encryption key. existed: {}", existed);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) async fn init(&self) -> EyreResult<()> {
|
||||||
|
let _async_guard = self.async_lock.lock().await;
|
||||||
|
|
||||||
|
// Get device encryption key from protected store
|
||||||
|
let mut device_encryption_key = self.load_device_encryption_key().await?;
|
||||||
|
let mut device_encryption_key_changed = false;
|
||||||
|
if let Some(device_encryption_key) = device_encryption_key {
|
||||||
|
// If encryption in current use is not the best encryption, then run table migration
|
||||||
|
let best_kind = best_crypto_kind();
|
||||||
|
if device_encryption_key.kind != best_kind {
|
||||||
|
// XXX: Run migration. See issue #209
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// If we don't have an encryption key yet, then make one with the best cryptography and save it
|
||||||
|
let best_kind = best_crypto_kind();
|
||||||
|
let mut shared_secret = SharedSecret::default();
|
||||||
|
random_bytes(&mut shared_secret.bytes);
|
||||||
|
|
||||||
|
device_encryption_key = Some(TypedSharedSecret::new(best_kind, shared_secret));
|
||||||
|
device_encryption_key_changed = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check for password change
|
||||||
|
let changing_password = self
|
||||||
|
.config
|
||||||
|
.get()
|
||||||
|
.protected_store
|
||||||
|
.new_device_encryption_key_password
|
||||||
|
.is_some();
|
||||||
|
|
||||||
|
// Save encryption key if it has changed or if the protecting password wants to change
|
||||||
|
if device_encryption_key_changed || changing_password {
|
||||||
|
self.save_device_encryption_key(device_encryption_key)
|
||||||
|
.await?;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Deserialize all table names
|
||||||
|
let all_tables_db = self
|
||||||
|
.table_store_driver
|
||||||
|
.open("__veilid_all_tables", 1)
|
||||||
|
.await
|
||||||
|
.wrap_err("failed to create all tables table")?;
|
||||||
|
match all_tables_db.get(0, ALL_TABLE_NAMES).await {
|
||||||
|
Ok(Some(v)) => match deserialize_json_bytes::<HashMap<String, String>>(&v) {
|
||||||
|
Ok(all_table_names) => {
|
||||||
|
let mut inner = self.inner.lock();
|
||||||
|
inner.all_table_names = all_table_names;
|
||||||
|
}
|
||||||
|
Err(e) => {
|
||||||
|
error!("could not deserialize __veilid_all_tables: {}", e);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
Ok(None) => {
|
||||||
|
// No table names yet, that's okay
|
||||||
|
trace!("__veilid_all_tables is empty");
|
||||||
|
}
|
||||||
|
Err(e) => {
|
||||||
|
error!("could not get __veilid_all_tables: {}", e);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
{
|
||||||
|
let mut inner = self.inner.lock();
|
||||||
|
inner.encryption_key = device_encryption_key;
|
||||||
|
inner.all_tables_db = Some(all_tables_db);
|
||||||
|
}
|
||||||
|
|
||||||
|
let do_delete = {
|
||||||
|
let c = self.config.get();
|
||||||
|
c.table_store.delete
|
||||||
|
};
|
||||||
|
|
||||||
|
if do_delete {
|
||||||
|
self.delete_all().await;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) async fn terminate(&self) {
|
||||||
|
let _async_guard = self.async_lock.lock().await;
|
||||||
|
|
||||||
|
self.flush().await;
|
||||||
|
|
||||||
|
let mut inner = self.inner.lock();
|
||||||
|
if !inner.opened.is_empty() {
|
||||||
|
panic!(
|
||||||
|
"all open databases should have been closed: {:?}",
|
||||||
|
inner.opened
|
||||||
|
);
|
||||||
|
}
|
||||||
|
inner.all_tables_db = None;
|
||||||
|
inner.all_table_names.clear();
|
||||||
|
inner.encryption_key = None;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn on_table_db_drop(&self, table: String) {
|
||||||
|
log_rtab!("dropping table db: {}", table);
|
||||||
|
let mut inner = self.inner.lock();
|
||||||
|
if inner.opened.remove(&table).is_none() {
|
||||||
|
unreachable!("should have removed an item");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get or create a TableDB database table. If the column count is greater than an
|
||||||
|
/// existing TableDB's column count, the database will be upgraded to add the missing columns
|
||||||
|
pub async fn open(&self, name: &str, column_count: u32) -> VeilidAPIResult<TableDB> {
|
||||||
|
let _async_guard = self.async_lock.lock().await;
|
||||||
|
|
||||||
|
// If we aren't initialized yet, bail
|
||||||
|
{
|
||||||
|
let inner = self.inner.lock();
|
||||||
|
if inner.all_tables_db.is_none() {
|
||||||
|
apibail_not_initialized!();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let table_name = self.name_get_or_create(name).await?;
|
||||||
|
|
||||||
|
// See if this table is already opened, if so the column count must be the same
|
||||||
|
{
|
||||||
|
let mut inner = self.inner.lock();
|
||||||
|
if let Some(table_db_weak_inner) = inner.opened.get(&table_name) {
|
||||||
|
match TableDB::try_new_from_weak_inner(table_db_weak_inner.clone(), column_count) {
|
||||||
|
Some(tdb) => {
|
||||||
|
// Ensure column count isnt bigger
|
||||||
|
let existing_col_count = tdb.get_column_count()?;
|
||||||
|
if column_count > existing_col_count {
|
||||||
|
return Err(VeilidAPIError::generic(format!(
|
||||||
|
"database must be closed before increasing column count {} -> {}",
|
||||||
|
existing_col_count, column_count,
|
||||||
|
)));
|
||||||
|
}
|
||||||
|
|
||||||
|
return Ok(tdb);
|
||||||
|
}
|
||||||
|
None => {
|
||||||
|
inner.opened.remove(&table_name);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Open table db using platform-specific driver
|
||||||
|
let mut db = match self
|
||||||
|
.table_store_driver
|
||||||
|
.open(&table_name, column_count)
|
||||||
|
.await
|
||||||
|
{
|
||||||
|
Ok(db) => db,
|
||||||
|
Err(e) => {
|
||||||
|
self.name_delete(name).await.expect("cleanup failed");
|
||||||
|
self.flush().await;
|
||||||
|
return Err(e);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Flush table names to disk
|
||||||
|
self.flush().await;
|
||||||
|
|
||||||
|
// If more columns are available, open the low level db with the max column count but restrict the tabledb object to the number requested
|
||||||
|
let existing_col_count = db.num_columns().map_err(VeilidAPIError::from)?;
|
||||||
|
if existing_col_count > column_count {
|
||||||
|
drop(db);
|
||||||
|
db = match self
|
||||||
|
.table_store_driver
|
||||||
|
.open(&table_name, existing_col_count)
|
||||||
|
.await
|
||||||
|
{
|
||||||
|
Ok(db) => db,
|
||||||
|
Err(e) => {
|
||||||
|
self.name_delete(name).await.expect("cleanup failed");
|
||||||
|
self.flush().await;
|
||||||
|
return Err(e);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// Wrap low-level Database in TableDB object
|
||||||
|
let mut inner = self.inner.lock();
|
||||||
|
let table_db = TableDB::new(
|
||||||
|
table_name.clone(),
|
||||||
|
self.clone(),
|
||||||
|
inner.crypto.as_ref().unwrap().clone(),
|
||||||
|
db,
|
||||||
|
inner.encryption_key,
|
||||||
|
inner.encryption_key,
|
||||||
|
column_count,
|
||||||
|
);
|
||||||
|
|
||||||
|
// Keep track of opened DBs
|
||||||
|
inner
|
||||||
|
.opened
|
||||||
|
.insert(table_name.clone(), table_db.weak_inner());
|
||||||
|
|
||||||
|
Ok(table_db)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Delete a TableDB table by name
|
||||||
|
pub async fn delete(&self, name: &str) -> VeilidAPIResult<bool> {
|
||||||
|
let _async_guard = self.async_lock.lock().await;
|
||||||
|
// If we aren't initialized yet, bail
|
||||||
|
{
|
||||||
|
let inner = self.inner.lock();
|
||||||
|
if inner.all_tables_db.is_none() {
|
||||||
|
apibail_not_initialized!();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let Some(table_name) = self.name_get(name).await? else {
|
||||||
|
// Did not exist in name table
|
||||||
|
return Ok(false);
|
||||||
|
};
|
||||||
|
|
||||||
|
// See if this table is opened
|
||||||
|
{
|
||||||
|
let inner = self.inner.lock();
|
||||||
|
if inner.opened.contains_key(&table_name) {
|
||||||
|
apibail_generic!("Not deleting table that is still opened");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Delete table db using platform-specific driver
|
||||||
|
let deleted = self.table_store_driver.delete(&table_name).await?;
|
||||||
|
if !deleted {
|
||||||
|
// Table missing? Just remove name
|
||||||
|
warn!(
|
||||||
|
"table existed in name table but not in storage: {} : {}",
|
||||||
|
name, table_name
|
||||||
|
);
|
||||||
|
}
|
||||||
|
self.name_delete(name).await.expect("failed to delete name");
|
||||||
|
self.flush().await;
|
||||||
|
|
||||||
|
Ok(true)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Rename a TableDB table
|
||||||
|
pub async fn rename(&self, old_name: &str, new_name: &str) -> VeilidAPIResult<()> {
|
||||||
|
let _async_guard = self.async_lock.lock().await;
|
||||||
|
// If we aren't initialized yet, bail
|
||||||
|
{
|
||||||
|
let inner = self.inner.lock();
|
||||||
|
if inner.all_tables_db.is_none() {
|
||||||
|
apibail_not_initialized!();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
trace!("TableStore::rename {} -> {}", old_name, new_name);
|
||||||
|
self.name_rename(old_name, new_name).await?;
|
||||||
|
self.flush().await;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -22,7 +22,7 @@ impl TableStoreDriver {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub async fn open(&self, table_name: &str, column_count: u32) -> VeilidAPIResult<Database> {
|
pub async fn open(&self, table_name: &str, column_count: u32) -> VeilidAPIResult<Database> {
|
||||||
let dbpath = self.get_dbpath(&table_name)?;
|
let dbpath = self.get_dbpath(table_name)?;
|
||||||
|
|
||||||
// Ensure permissions are correct
|
// Ensure permissions are correct
|
||||||
ensure_file_private_owner(&dbpath).map_err(VeilidAPIError::internal)?;
|
ensure_file_private_owner(&dbpath).map_err(VeilidAPIError::internal)?;
|
||||||
@ -43,7 +43,7 @@ impl TableStoreDriver {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub async fn delete(&self, table_name: &str) -> VeilidAPIResult<bool> {
|
pub async fn delete(&self, table_name: &str) -> VeilidAPIResult<bool> {
|
||||||
let dbpath = self.get_dbpath(&table_name)?;
|
let dbpath = self.get_dbpath(table_name)?;
|
||||||
if !dbpath.exists() {
|
if !dbpath.exists() {
|
||||||
return Ok(false);
|
return Ok(false);
|
||||||
}
|
}
|
||||||
|
@ -1,589 +0,0 @@
|
|||||||
use super::*;
|
|
||||||
use keyvaluedb::*;
|
|
||||||
|
|
||||||
const ALL_TABLE_NAMES: &[u8] = b"all_table_names";
|
|
||||||
|
|
||||||
struct TableStoreInner {
|
|
||||||
opened: BTreeMap<String, Weak<TableDBUnlockedInner>>,
|
|
||||||
encryption_key: Option<TypedSharedSecret>,
|
|
||||||
all_table_names: HashMap<String, String>,
|
|
||||||
all_tables_db: Option<Database>,
|
|
||||||
crypto: Option<Crypto>,
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Veilid Table Storage
|
|
||||||
/// Database for storing key value pairs persistently and securely across runs
|
|
||||||
#[derive(Clone)]
|
|
||||||
pub struct TableStore {
|
|
||||||
config: VeilidConfig,
|
|
||||||
protected_store: ProtectedStore,
|
|
||||||
table_store_driver: TableStoreDriver,
|
|
||||||
inner: Arc<Mutex<TableStoreInner>>, // Sync mutex here because TableDB drops can happen at any time
|
|
||||||
async_lock: Arc<AsyncMutex<()>>, // Async mutex for operations
|
|
||||||
}
|
|
||||||
|
|
||||||
impl TableStore {
|
|
||||||
fn new_inner() -> TableStoreInner {
|
|
||||||
TableStoreInner {
|
|
||||||
opened: BTreeMap::new(),
|
|
||||||
encryption_key: None,
|
|
||||||
all_table_names: HashMap::new(),
|
|
||||||
all_tables_db: None,
|
|
||||||
crypto: None,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
pub(crate) fn new(config: VeilidConfig, protected_store: ProtectedStore) -> Self {
|
|
||||||
let inner = Self::new_inner();
|
|
||||||
let table_store_driver = TableStoreDriver::new(config.clone());
|
|
||||||
|
|
||||||
Self {
|
|
||||||
config,
|
|
||||||
protected_store,
|
|
||||||
inner: Arc::new(Mutex::new(inner)),
|
|
||||||
table_store_driver,
|
|
||||||
async_lock: Arc::new(AsyncMutex::new(())),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) fn set_crypto(&self, crypto: Crypto) {
|
|
||||||
let mut inner = self.inner.lock();
|
|
||||||
inner.crypto = Some(crypto);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Flush internal control state (must not use crypto)
|
|
||||||
async fn flush(&self) {
|
|
||||||
let (all_table_names_value, all_tables_db) = {
|
|
||||||
let inner = self.inner.lock();
|
|
||||||
let all_table_names_value = serialize_json_bytes(&inner.all_table_names);
|
|
||||||
(all_table_names_value, inner.all_tables_db.clone().unwrap())
|
|
||||||
};
|
|
||||||
let mut dbt = DBTransaction::new();
|
|
||||||
dbt.put(0, ALL_TABLE_NAMES, &all_table_names_value);
|
|
||||||
if let Err(e) = all_tables_db.write(dbt).await {
|
|
||||||
error!("failed to write all tables db: {}", e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Internal naming support
|
|
||||||
// Adds rename capability and ensures names of tables are totally unique and valid
|
|
||||||
|
|
||||||
fn namespaced_name(&self, table: &str) -> VeilidAPIResult<String> {
|
|
||||||
if !table
|
|
||||||
.chars()
|
|
||||||
.all(|c| char::is_alphanumeric(c) || c == '_' || c == '-')
|
|
||||||
{
|
|
||||||
apibail_invalid_argument!("table name is invalid", "table", table);
|
|
||||||
}
|
|
||||||
let c = self.config.get();
|
|
||||||
let namespace = c.namespace.clone();
|
|
||||||
Ok(if namespace.is_empty() {
|
|
||||||
table.to_string()
|
|
||||||
} else {
|
|
||||||
format!("_ns_{}_{}", namespace, table)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn name_get_or_create(&self, table: &str) -> VeilidAPIResult<String> {
|
|
||||||
let name = self.namespaced_name(table)?;
|
|
||||||
|
|
||||||
let mut inner = self.inner.lock();
|
|
||||||
// Do we have this name yet?
|
|
||||||
if let Some(real_name) = inner.all_table_names.get(&name) {
|
|
||||||
return Ok(real_name.clone());
|
|
||||||
}
|
|
||||||
|
|
||||||
// If not, make a new low level name mapping
|
|
||||||
let mut real_name_bytes = [0u8; 32];
|
|
||||||
random_bytes(&mut real_name_bytes);
|
|
||||||
let real_name = data_encoding::BASE64URL_NOPAD.encode(&real_name_bytes);
|
|
||||||
|
|
||||||
if inner
|
|
||||||
.all_table_names
|
|
||||||
.insert(name.to_owned(), real_name.clone())
|
|
||||||
.is_some()
|
|
||||||
{
|
|
||||||
panic!("should not have had some value");
|
|
||||||
};
|
|
||||||
|
|
||||||
Ok(real_name)
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn name_delete(&self, table: &str) -> VeilidAPIResult<Option<String>> {
|
|
||||||
let name = self.namespaced_name(table)?;
|
|
||||||
let mut inner = self.inner.lock();
|
|
||||||
let real_name = inner.all_table_names.remove(&name);
|
|
||||||
Ok(real_name)
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn name_get(&self, table: &str) -> VeilidAPIResult<Option<String>> {
|
|
||||||
let name = self.namespaced_name(table)?;
|
|
||||||
let inner = self.inner.lock();
|
|
||||||
let real_name = inner.all_table_names.get(&name).cloned();
|
|
||||||
Ok(real_name)
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn name_rename(&self, old_table: &str, new_table: &str) -> VeilidAPIResult<()> {
|
|
||||||
let old_name = self.namespaced_name(old_table)?;
|
|
||||||
let new_name = self.namespaced_name(new_table)?;
|
|
||||||
|
|
||||||
let mut inner = self.inner.lock();
|
|
||||||
// Ensure new name doesn't exist
|
|
||||||
if inner.all_table_names.contains_key(&new_name) {
|
|
||||||
return Err(VeilidAPIError::generic("new table already exists"));
|
|
||||||
}
|
|
||||||
// Do we have this name yet?
|
|
||||||
let Some(real_name) = inner.all_table_names.remove(&old_name) else {
|
|
||||||
return Err(VeilidAPIError::generic("table does not exist"));
|
|
||||||
};
|
|
||||||
// Insert with new name
|
|
||||||
inner.all_table_names.insert(new_name.to_owned(), real_name);
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Delete all known tables
|
|
||||||
async fn delete_all(&self) {
|
|
||||||
// Get all tables
|
|
||||||
let real_names = {
|
|
||||||
let mut inner = self.inner.lock();
|
|
||||||
let real_names = inner
|
|
||||||
.all_table_names
|
|
||||||
.values()
|
|
||||||
.cloned()
|
|
||||||
.collect::<Vec<String>>();
|
|
||||||
inner.all_table_names.clear();
|
|
||||||
real_names
|
|
||||||
};
|
|
||||||
|
|
||||||
// Delete all tables
|
|
||||||
for table_name in real_names {
|
|
||||||
if let Err(e) = self.table_store_driver.delete(&table_name).await {
|
|
||||||
error!("error deleting table: {}", e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
self.flush().await;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) fn maybe_unprotect_device_encryption_key(
|
|
||||||
&self,
|
|
||||||
dek_bytes: &[u8],
|
|
||||||
device_encryption_key_password: &str,
|
|
||||||
) -> EyreResult<TypedSharedSecret> {
|
|
||||||
// Ensure the key is at least as long as necessary if unencrypted
|
|
||||||
if dek_bytes.len() < (4 + SHARED_SECRET_LENGTH) {
|
|
||||||
bail!("device encryption key is not valid");
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get cryptosystem
|
|
||||||
let kind = FourCC::try_from(&dek_bytes[0..4]).unwrap();
|
|
||||||
let crypto = self.inner.lock().crypto.as_ref().unwrap().clone();
|
|
||||||
let Some(vcrypto) = crypto.get(kind) else {
|
|
||||||
bail!("unsupported cryptosystem");
|
|
||||||
};
|
|
||||||
|
|
||||||
if !device_encryption_key_password.is_empty() {
|
|
||||||
if dek_bytes.len()
|
|
||||||
!= (4 + SHARED_SECRET_LENGTH + vcrypto.aead_overhead() + NONCE_LENGTH)
|
|
||||||
{
|
|
||||||
bail!("password protected device encryption key is not valid");
|
|
||||||
}
|
|
||||||
let protected_key = &dek_bytes[4..(4 + SHARED_SECRET_LENGTH + vcrypto.aead_overhead())];
|
|
||||||
let nonce = &dek_bytes[(4 + SHARED_SECRET_LENGTH + vcrypto.aead_overhead())..];
|
|
||||||
|
|
||||||
let shared_secret = vcrypto
|
|
||||||
.derive_shared_secret(device_encryption_key_password.as_bytes(), &nonce)
|
|
||||||
.wrap_err("failed to derive shared secret")?;
|
|
||||||
let unprotected_key = vcrypto
|
|
||||||
.decrypt_aead(
|
|
||||||
&protected_key,
|
|
||||||
&Nonce::try_from(nonce).wrap_err("invalid nonce")?,
|
|
||||||
&shared_secret,
|
|
||||||
None,
|
|
||||||
)
|
|
||||||
.wrap_err("failed to decrypt device encryption key")?;
|
|
||||||
return Ok(TypedSharedSecret::new(
|
|
||||||
kind,
|
|
||||||
SharedSecret::try_from(unprotected_key.as_slice())
|
|
||||||
.wrap_err("invalid shared secret")?,
|
|
||||||
));
|
|
||||||
}
|
|
||||||
|
|
||||||
if dek_bytes.len() != (4 + SHARED_SECRET_LENGTH) {
|
|
||||||
bail!("password protected device encryption key is not valid");
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(TypedSharedSecret::new(
|
|
||||||
kind,
|
|
||||||
SharedSecret::try_from(&dek_bytes[4..])?,
|
|
||||||
))
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) fn maybe_protect_device_encryption_key(
|
|
||||||
&self,
|
|
||||||
dek: TypedSharedSecret,
|
|
||||||
device_encryption_key_password: &str,
|
|
||||||
) -> EyreResult<Vec<u8>> {
|
|
||||||
// Check if we are to protect the key
|
|
||||||
if device_encryption_key_password.is_empty() {
|
|
||||||
debug!("no dek password");
|
|
||||||
// Return the unprotected key bytes
|
|
||||||
let mut out = Vec::with_capacity(4 + SHARED_SECRET_LENGTH);
|
|
||||||
out.extend_from_slice(&dek.kind.0);
|
|
||||||
out.extend_from_slice(&dek.value.bytes);
|
|
||||||
return Ok(out);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get cryptosystem
|
|
||||||
let crypto = self.inner.lock().crypto.as_ref().unwrap().clone();
|
|
||||||
let Some(vcrypto) = crypto.get(dek.kind) else {
|
|
||||||
bail!("unsupported cryptosystem");
|
|
||||||
};
|
|
||||||
|
|
||||||
let nonce = vcrypto.random_nonce();
|
|
||||||
let shared_secret = vcrypto
|
|
||||||
.derive_shared_secret(device_encryption_key_password.as_bytes(), &nonce.bytes)
|
|
||||||
.wrap_err("failed to derive shared secret")?;
|
|
||||||
let mut protected_key = vcrypto
|
|
||||||
.encrypt_aead(
|
|
||||||
&dek.value.bytes,
|
|
||||||
&Nonce::try_from(nonce).wrap_err("invalid nonce")?,
|
|
||||||
&shared_secret,
|
|
||||||
None,
|
|
||||||
)
|
|
||||||
.wrap_err("failed to decrypt device encryption key")?;
|
|
||||||
let mut out =
|
|
||||||
Vec::with_capacity(4 + SHARED_SECRET_LENGTH + vcrypto.aead_overhead() + NONCE_LENGTH);
|
|
||||||
out.extend_from_slice(&dek.kind.0);
|
|
||||||
out.append(&mut protected_key);
|
|
||||||
out.extend_from_slice(&nonce.bytes);
|
|
||||||
assert!(out.len() == 4 + SHARED_SECRET_LENGTH + vcrypto.aead_overhead() + NONCE_LENGTH);
|
|
||||||
Ok(out)
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn load_device_encryption_key(&self) -> EyreResult<Option<TypedSharedSecret>> {
|
|
||||||
let dek_bytes: Option<Vec<u8>> = self
|
|
||||||
.protected_store
|
|
||||||
.load_user_secret("device_encryption_key")
|
|
||||||
.await?;
|
|
||||||
let Some(dek_bytes) = dek_bytes else {
|
|
||||||
debug!("no device encryption key");
|
|
||||||
return Ok(None);
|
|
||||||
};
|
|
||||||
|
|
||||||
// Get device encryption key protection password if we have it
|
|
||||||
let device_encryption_key_password = {
|
|
||||||
let c = self.config.get();
|
|
||||||
c.protected_store.device_encryption_key_password.clone()
|
|
||||||
};
|
|
||||||
|
|
||||||
Ok(Some(self.maybe_unprotect_device_encryption_key(
|
|
||||||
&dek_bytes,
|
|
||||||
&device_encryption_key_password,
|
|
||||||
)?))
|
|
||||||
}
|
|
||||||
async fn save_device_encryption_key(
|
|
||||||
&self,
|
|
||||||
device_encryption_key: Option<TypedSharedSecret>,
|
|
||||||
) -> EyreResult<()> {
|
|
||||||
let Some(device_encryption_key) = device_encryption_key else {
|
|
||||||
// Remove the device encryption key
|
|
||||||
let existed = self
|
|
||||||
.protected_store
|
|
||||||
.remove_user_secret("device_encryption_key")
|
|
||||||
.await?;
|
|
||||||
debug!("removed device encryption key. existed: {}", existed);
|
|
||||||
return Ok(());
|
|
||||||
};
|
|
||||||
|
|
||||||
// Get new device encryption key protection password if we are changing it
|
|
||||||
let new_device_encryption_key_password = {
|
|
||||||
let c = self.config.get();
|
|
||||||
c.protected_store.new_device_encryption_key_password.clone()
|
|
||||||
};
|
|
||||||
let device_encryption_key_password =
|
|
||||||
if let Some(new_device_encryption_key_password) = new_device_encryption_key_password {
|
|
||||||
// Change password
|
|
||||||
debug!("changing dek password");
|
|
||||||
self.config
|
|
||||||
.with_mut(|c| {
|
|
||||||
c.protected_store.device_encryption_key_password =
|
|
||||||
new_device_encryption_key_password.clone();
|
|
||||||
Ok(new_device_encryption_key_password)
|
|
||||||
})
|
|
||||||
.unwrap()
|
|
||||||
} else {
|
|
||||||
// Get device encryption key protection password if we have it
|
|
||||||
debug!("saving with existing dek password");
|
|
||||||
let c = self.config.get();
|
|
||||||
c.protected_store.device_encryption_key_password.clone()
|
|
||||||
};
|
|
||||||
|
|
||||||
let dek_bytes = self.maybe_protect_device_encryption_key(
|
|
||||||
device_encryption_key,
|
|
||||||
&device_encryption_key_password,
|
|
||||||
)?;
|
|
||||||
|
|
||||||
// Save the new device encryption key
|
|
||||||
let existed = self
|
|
||||||
.protected_store
|
|
||||||
.save_user_secret("device_encryption_key", &dek_bytes)
|
|
||||||
.await?;
|
|
||||||
debug!("saving device encryption key. existed: {}", existed);
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) async fn init(&self) -> EyreResult<()> {
|
|
||||||
let _async_guard = self.async_lock.lock().await;
|
|
||||||
|
|
||||||
// Get device encryption key from protected store
|
|
||||||
let mut device_encryption_key = self.load_device_encryption_key().await?;
|
|
||||||
let mut device_encryption_key_changed = false;
|
|
||||||
if let Some(device_encryption_key) = device_encryption_key {
|
|
||||||
// If encryption in current use is not the best encryption, then run table migration
|
|
||||||
let best_kind = best_crypto_kind();
|
|
||||||
if device_encryption_key.kind != best_kind {
|
|
||||||
// XXX: Run migration. See issue #209
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// If we don't have an encryption key yet, then make one with the best cryptography and save it
|
|
||||||
let best_kind = best_crypto_kind();
|
|
||||||
let mut shared_secret = SharedSecret::default();
|
|
||||||
random_bytes(&mut shared_secret.bytes);
|
|
||||||
|
|
||||||
device_encryption_key = Some(TypedSharedSecret::new(best_kind, shared_secret));
|
|
||||||
device_encryption_key_changed = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check for password change
|
|
||||||
let changing_password = self
|
|
||||||
.config
|
|
||||||
.get()
|
|
||||||
.protected_store
|
|
||||||
.new_device_encryption_key_password
|
|
||||||
.is_some();
|
|
||||||
|
|
||||||
// Save encryption key if it has changed or if the protecting password wants to change
|
|
||||||
if device_encryption_key_changed || changing_password {
|
|
||||||
self.save_device_encryption_key(device_encryption_key)
|
|
||||||
.await?;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Deserialize all table names
|
|
||||||
let all_tables_db = self
|
|
||||||
.table_store_driver
|
|
||||||
.open("__veilid_all_tables", 1)
|
|
||||||
.await
|
|
||||||
.wrap_err("failed to create all tables table")?;
|
|
||||||
match all_tables_db.get(0, ALL_TABLE_NAMES).await {
|
|
||||||
Ok(Some(v)) => match deserialize_json_bytes::<HashMap<String, String>>(&v) {
|
|
||||||
Ok(all_table_names) => {
|
|
||||||
let mut inner = self.inner.lock();
|
|
||||||
inner.all_table_names = all_table_names;
|
|
||||||
}
|
|
||||||
Err(e) => {
|
|
||||||
error!("could not deserialize __veilid_all_tables: {}", e);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
Ok(None) => {
|
|
||||||
// No table names yet, that's okay
|
|
||||||
trace!("__veilid_all_tables is empty");
|
|
||||||
}
|
|
||||||
Err(e) => {
|
|
||||||
error!("could not get __veilid_all_tables: {}", e);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
{
|
|
||||||
let mut inner = self.inner.lock();
|
|
||||||
inner.encryption_key = device_encryption_key;
|
|
||||||
inner.all_tables_db = Some(all_tables_db);
|
|
||||||
}
|
|
||||||
|
|
||||||
let do_delete = {
|
|
||||||
let c = self.config.get();
|
|
||||||
c.table_store.delete
|
|
||||||
};
|
|
||||||
|
|
||||||
if do_delete {
|
|
||||||
self.delete_all().await;
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) async fn terminate(&self) {
|
|
||||||
let _async_guard = self.async_lock.lock().await;
|
|
||||||
|
|
||||||
self.flush().await;
|
|
||||||
|
|
||||||
let mut inner = self.inner.lock();
|
|
||||||
if !inner.opened.is_empty() {
|
|
||||||
panic!(
|
|
||||||
"all open databases should have been closed: {:?}",
|
|
||||||
inner.opened
|
|
||||||
);
|
|
||||||
}
|
|
||||||
inner.all_tables_db = None;
|
|
||||||
inner.all_table_names.clear();
|
|
||||||
inner.encryption_key = None;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) fn on_table_db_drop(&self, table: String) {
|
|
||||||
log_rtab!("dropping table db: {}", table);
|
|
||||||
let mut inner = self.inner.lock();
|
|
||||||
if inner.opened.remove(&table).is_none() {
|
|
||||||
unreachable!("should have removed an item");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Get or create a TableDB database table. If the column count is greater than an
|
|
||||||
/// existing TableDB's column count, the database will be upgraded to add the missing columns
|
|
||||||
pub async fn open(&self, name: &str, column_count: u32) -> VeilidAPIResult<TableDB> {
|
|
||||||
let _async_guard = self.async_lock.lock().await;
|
|
||||||
|
|
||||||
// If we aren't initialized yet, bail
|
|
||||||
{
|
|
||||||
let inner = self.inner.lock();
|
|
||||||
if inner.all_tables_db.is_none() {
|
|
||||||
apibail_not_initialized!();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let table_name = self.name_get_or_create(name).await?;
|
|
||||||
|
|
||||||
// See if this table is already opened, if so the column count must be the same
|
|
||||||
{
|
|
||||||
let mut inner = self.inner.lock();
|
|
||||||
if let Some(table_db_weak_inner) = inner.opened.get(&table_name) {
|
|
||||||
match TableDB::try_new_from_weak_inner(table_db_weak_inner.clone(), column_count) {
|
|
||||||
Some(tdb) => {
|
|
||||||
// Ensure column count isnt bigger
|
|
||||||
let existing_col_count = tdb.get_column_count()?;
|
|
||||||
if column_count > existing_col_count {
|
|
||||||
return Err(VeilidAPIError::generic(format!(
|
|
||||||
"database must be closed before increasing column count {} -> {}",
|
|
||||||
existing_col_count, column_count,
|
|
||||||
)));
|
|
||||||
}
|
|
||||||
|
|
||||||
return Ok(tdb);
|
|
||||||
}
|
|
||||||
None => {
|
|
||||||
inner.opened.remove(&table_name);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Open table db using platform-specific driver
|
|
||||||
let mut db = match self
|
|
||||||
.table_store_driver
|
|
||||||
.open(&table_name, column_count)
|
|
||||||
.await
|
|
||||||
{
|
|
||||||
Ok(db) => db,
|
|
||||||
Err(e) => {
|
|
||||||
self.name_delete(name).await.expect("cleanup failed");
|
|
||||||
self.flush().await;
|
|
||||||
return Err(e);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// Flush table names to disk
|
|
||||||
self.flush().await;
|
|
||||||
|
|
||||||
// If more columns are available, open the low level db with the max column count but restrict the tabledb object to the number requested
|
|
||||||
let existing_col_count = db.num_columns().map_err(VeilidAPIError::from)?;
|
|
||||||
if existing_col_count > column_count {
|
|
||||||
drop(db);
|
|
||||||
db = match self
|
|
||||||
.table_store_driver
|
|
||||||
.open(&table_name, existing_col_count)
|
|
||||||
.await
|
|
||||||
{
|
|
||||||
Ok(db) => db,
|
|
||||||
Err(e) => {
|
|
||||||
self.name_delete(name).await.expect("cleanup failed");
|
|
||||||
self.flush().await;
|
|
||||||
return Err(e);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
// Wrap low-level Database in TableDB object
|
|
||||||
let mut inner = self.inner.lock();
|
|
||||||
let table_db = TableDB::new(
|
|
||||||
table_name.clone(),
|
|
||||||
self.clone(),
|
|
||||||
inner.crypto.as_ref().unwrap().clone(),
|
|
||||||
db,
|
|
||||||
inner.encryption_key.clone(),
|
|
||||||
inner.encryption_key.clone(),
|
|
||||||
column_count,
|
|
||||||
);
|
|
||||||
|
|
||||||
// Keep track of opened DBs
|
|
||||||
inner
|
|
||||||
.opened
|
|
||||||
.insert(table_name.clone(), table_db.weak_inner());
|
|
||||||
|
|
||||||
Ok(table_db)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Delete a TableDB table by name
|
|
||||||
pub async fn delete(&self, name: &str) -> VeilidAPIResult<bool> {
|
|
||||||
let _async_guard = self.async_lock.lock().await;
|
|
||||||
// If we aren't initialized yet, bail
|
|
||||||
{
|
|
||||||
let inner = self.inner.lock();
|
|
||||||
if inner.all_tables_db.is_none() {
|
|
||||||
apibail_not_initialized!();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let Some(table_name) = self.name_get(name).await? else {
|
|
||||||
// Did not exist in name table
|
|
||||||
return Ok(false);
|
|
||||||
};
|
|
||||||
|
|
||||||
// See if this table is opened
|
|
||||||
{
|
|
||||||
let inner = self.inner.lock();
|
|
||||||
if inner.opened.contains_key(&table_name) {
|
|
||||||
apibail_generic!("Not deleting table that is still opened");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Delete table db using platform-specific driver
|
|
||||||
let deleted = self.table_store_driver.delete(&table_name).await?;
|
|
||||||
if !deleted {
|
|
||||||
// Table missing? Just remove name
|
|
||||||
warn!(
|
|
||||||
"table existed in name table but not in storage: {} : {}",
|
|
||||||
name, table_name
|
|
||||||
);
|
|
||||||
}
|
|
||||||
self.name_delete(&name)
|
|
||||||
.await
|
|
||||||
.expect("failed to delete name");
|
|
||||||
self.flush().await;
|
|
||||||
|
|
||||||
Ok(true)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Rename a TableDB table
|
|
||||||
pub async fn rename(&self, old_name: &str, new_name: &str) -> VeilidAPIResult<()> {
|
|
||||||
let _async_guard = self.async_lock.lock().await;
|
|
||||||
// If we aren't initialized yet, bail
|
|
||||||
{
|
|
||||||
let inner = self.inner.lock();
|
|
||||||
if inner.all_tables_db.is_none() {
|
|
||||||
apibail_not_initialized!();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
trace!("TableStore::rename {} -> {}", old_name, new_name);
|
|
||||||
self.name_rename(old_name, new_name).await?;
|
|
||||||
self.flush().await;
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
@ -50,7 +50,7 @@ pub async fn test_delete_open_delete(ts: TableStore) {
|
|||||||
pub async fn test_store_delete_load(ts: TableStore) {
|
pub async fn test_store_delete_load(ts: TableStore) {
|
||||||
trace!("test_store_delete_load");
|
trace!("test_store_delete_load");
|
||||||
|
|
||||||
ts.delete("test").await;
|
let _ = ts.delete("test").await;
|
||||||
let db = ts.open("test", 3).await.expect("should have opened");
|
let db = ts.open("test", 3).await.expect("should have opened");
|
||||||
assert!(
|
assert!(
|
||||||
ts.delete("test").await.is_err(),
|
ts.delete("test").await.is_err(),
|
||||||
|
@ -23,14 +23,12 @@ pub async fn test_protected_store(ps: ProtectedStore) {
|
|||||||
|
|
||||||
let d1: [u8; 0] = [];
|
let d1: [u8; 0] = [];
|
||||||
|
|
||||||
assert_eq!(
|
assert!(!ps
|
||||||
ps.save_user_secret("_test_key", &[2u8, 3u8, 4u8])
|
.save_user_secret("_test_key", &[2u8, 3u8, 4u8])
|
||||||
.await
|
.await
|
||||||
.unwrap(),
|
.unwrap());
|
||||||
false
|
|
||||||
);
|
|
||||||
info!("testing saving user secret");
|
info!("testing saving user secret");
|
||||||
assert_eq!(ps.save_user_secret("_test_key", &d1).await.unwrap(), true);
|
assert!(ps.save_user_secret("_test_key", &d1).await.unwrap());
|
||||||
info!("testing loading user secret");
|
info!("testing loading user secret");
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
ps.load_user_secret("_test_key").await.unwrap(),
|
ps.load_user_secret("_test_key").await.unwrap(),
|
||||||
@ -46,23 +44,21 @@ pub async fn test_protected_store(ps: ProtectedStore) {
|
|||||||
info!("testing loading broken user secret again");
|
info!("testing loading broken user secret again");
|
||||||
assert_eq!(ps.load_user_secret("_test_broken").await.unwrap(), None);
|
assert_eq!(ps.load_user_secret("_test_broken").await.unwrap(), None);
|
||||||
info!("testing remove user secret");
|
info!("testing remove user secret");
|
||||||
assert_eq!(ps.remove_user_secret("_test_key").await.unwrap(), true);
|
assert!(ps.remove_user_secret("_test_key").await.unwrap());
|
||||||
info!("testing remove user secret again");
|
info!("testing remove user secret again");
|
||||||
assert_eq!(ps.remove_user_secret("_test_key").await.unwrap(), false);
|
assert!(!ps.remove_user_secret("_test_key").await.unwrap());
|
||||||
info!("testing remove broken user secret");
|
info!("testing remove broken user secret");
|
||||||
assert_eq!(ps.remove_user_secret("_test_broken").await.unwrap(), false);
|
assert!(!ps.remove_user_secret("_test_broken").await.unwrap());
|
||||||
info!("testing remove broken user secret again");
|
info!("testing remove broken user secret again");
|
||||||
assert_eq!(ps.remove_user_secret("_test_broken").await.unwrap(), false);
|
assert!(!ps.remove_user_secret("_test_broken").await.unwrap());
|
||||||
|
|
||||||
let d2: [u8; 10] = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
|
let d2: [u8; 10] = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
|
||||||
|
|
||||||
assert_eq!(
|
assert!(!ps
|
||||||
ps.save_user_secret("_test_key", &[2u8, 3u8, 4u8])
|
.save_user_secret("_test_key", &[2u8, 3u8, 4u8])
|
||||||
.await
|
.await
|
||||||
.unwrap(),
|
.unwrap());
|
||||||
false
|
assert!(ps.save_user_secret("_test_key", &d2).await.unwrap());
|
||||||
);
|
|
||||||
assert_eq!(ps.save_user_secret("_test_key", &d2).await.unwrap(), true);
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
ps.load_user_secret("_test_key").await.unwrap(),
|
ps.load_user_secret("_test_key").await.unwrap(),
|
||||||
Some(d2.to_vec())
|
Some(d2.to_vec())
|
||||||
@ -73,10 +69,10 @@ pub async fn test_protected_store(ps: ProtectedStore) {
|
|||||||
);
|
);
|
||||||
assert_eq!(ps.load_user_secret("_test_broken").await.unwrap(), None);
|
assert_eq!(ps.load_user_secret("_test_broken").await.unwrap(), None);
|
||||||
assert_eq!(ps.load_user_secret("_test_broken").await.unwrap(), None);
|
assert_eq!(ps.load_user_secret("_test_broken").await.unwrap(), None);
|
||||||
assert_eq!(ps.remove_user_secret("_test_key").await.unwrap(), true);
|
assert!(ps.remove_user_secret("_test_key").await.unwrap());
|
||||||
assert_eq!(ps.remove_user_secret("_test_key").await.unwrap(), false);
|
assert!(ps.remove_user_secret("_test_key").await.unwrap());
|
||||||
assert_eq!(ps.remove_user_secret("_test_broken").await.unwrap(), false);
|
assert!(!ps.remove_user_secret("_test_key").await.unwrap());
|
||||||
assert_eq!(ps.remove_user_secret("_test_broken").await.unwrap(), false);
|
assert!(!ps.remove_user_secret("_test_broken").await.unwrap());
|
||||||
|
|
||||||
let _ = ps.remove_user_secret("_test_key").await;
|
let _ = ps.remove_user_secret("_test_key").await;
|
||||||
let _ = ps.remove_user_secret("_test_broken").await;
|
let _ = ps.remove_user_secret("_test_broken").await;
|
||||||
|
@ -1,5 +1,3 @@
|
|||||||
#![allow(clippy::bool_assert_comparison)]
|
|
||||||
|
|
||||||
use crate::*;
|
use crate::*;
|
||||||
|
|
||||||
cfg_if! {
|
cfg_if! {
|
||||||
@ -168,7 +166,7 @@ fn config_callback(key: String) -> ConfigCallbackReturn {
|
|||||||
match key.as_str() {
|
match key.as_str() {
|
||||||
"program_name" => Ok(Box::new(String::from("VeilidCoreTests"))),
|
"program_name" => Ok(Box::new(String::from("VeilidCoreTests"))),
|
||||||
"namespace" => Ok(Box::<String>::default()),
|
"namespace" => Ok(Box::<String>::default()),
|
||||||
"capabilities.disable" => Ok(Box::<Vec::<FourCC>>::default()),
|
"capabilities.disable" => Ok(Box::<Vec<FourCC>>::default()),
|
||||||
"table_store.directory" => Ok(Box::new(get_table_store_path())),
|
"table_store.directory" => Ok(Box::new(get_table_store_path())),
|
||||||
"table_store.delete" => Ok(Box::new(true)),
|
"table_store.delete" => Ok(Box::new(true)),
|
||||||
"block_store.directory" => Ok(Box::new(get_block_store_path())),
|
"block_store.directory" => Ok(Box::new(get_block_store_path())),
|
||||||
@ -193,7 +191,7 @@ fn config_callback(key: String) -> ConfigCallbackReturn {
|
|||||||
"network.network_key_password" => Ok(Box::new(Option::<String>::None)),
|
"network.network_key_password" => Ok(Box::new(Option::<String>::None)),
|
||||||
"network.routing_table.node_id" => Ok(Box::new(TypedKeyGroup::new())),
|
"network.routing_table.node_id" => Ok(Box::new(TypedKeyGroup::new())),
|
||||||
"network.routing_table.node_id_secret" => Ok(Box::new(TypedSecretGroup::new())),
|
"network.routing_table.node_id_secret" => Ok(Box::new(TypedSecretGroup::new())),
|
||||||
"network.routing_table.bootstrap" => Ok(Box::<Vec::<String>>::default()),
|
"network.routing_table.bootstrap" => Ok(Box::<Vec<String>>::default()),
|
||||||
"network.routing_table.limit_over_attached" => Ok(Box::new(64u32)),
|
"network.routing_table.limit_over_attached" => Ok(Box::new(64u32)),
|
||||||
"network.routing_table.limit_fully_attached" => Ok(Box::new(32u32)),
|
"network.routing_table.limit_fully_attached" => Ok(Box::new(32u32)),
|
||||||
"network.routing_table.limit_attached_strong" => Ok(Box::new(16u32)),
|
"network.routing_table.limit_attached_strong" => Ok(Box::new(16u32)),
|
||||||
@ -295,13 +293,13 @@ pub async fn test_config() {
|
|||||||
assert_eq!(inner.namespace, String::from(""));
|
assert_eq!(inner.namespace, String::from(""));
|
||||||
assert_eq!(inner.capabilities.disable, Vec::<FourCC>::new());
|
assert_eq!(inner.capabilities.disable, Vec::<FourCC>::new());
|
||||||
assert_eq!(inner.table_store.directory, get_table_store_path());
|
assert_eq!(inner.table_store.directory, get_table_store_path());
|
||||||
assert_eq!(inner.table_store.delete, true);
|
assert!(inner.table_store.delete);
|
||||||
assert_eq!(inner.block_store.directory, get_block_store_path());
|
assert_eq!(inner.block_store.directory, get_block_store_path());
|
||||||
assert_eq!(inner.block_store.delete, true);
|
assert!(inner.block_store.delete);
|
||||||
assert_eq!(inner.protected_store.allow_insecure_fallback, true);
|
assert!(inner.protected_store.allow_insecure_fallback);
|
||||||
assert_eq!(inner.protected_store.always_use_insecure_storage, false);
|
assert!(!inner.protected_store.always_use_insecure_storage);
|
||||||
assert_eq!(inner.protected_store.directory, get_protected_store_path());
|
assert_eq!(inner.protected_store.directory, get_protected_store_path());
|
||||||
assert_eq!(inner.protected_store.delete, true);
|
assert!(inner.protected_store.delete);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
inner.protected_store.device_encryption_key_password,
|
inner.protected_store.device_encryption_key_password,
|
||||||
"".to_owned()
|
"".to_owned()
|
||||||
@ -351,38 +349,38 @@ pub async fn test_config() {
|
|||||||
5_000u32
|
5_000u32
|
||||||
);
|
);
|
||||||
|
|
||||||
assert_eq!(inner.network.upnp, false);
|
assert!(!inner.network.upnp);
|
||||||
assert_eq!(inner.network.detect_address_changes, true);
|
assert!(inner.network.detect_address_changes);
|
||||||
assert_eq!(inner.network.restricted_nat_retries, 3u32);
|
assert_eq!(inner.network.restricted_nat_retries, 3u32);
|
||||||
assert_eq!(inner.network.tls.certificate_path, get_certfile_path());
|
assert_eq!(inner.network.tls.certificate_path, get_certfile_path());
|
||||||
assert_eq!(inner.network.tls.private_key_path, get_keyfile_path());
|
assert_eq!(inner.network.tls.private_key_path, get_keyfile_path());
|
||||||
assert_eq!(inner.network.tls.connection_initial_timeout_ms, 2_000u32);
|
assert_eq!(inner.network.tls.connection_initial_timeout_ms, 2_000u32);
|
||||||
|
|
||||||
assert_eq!(inner.network.application.https.enabled, false);
|
assert!(!inner.network.application.https.enabled);
|
||||||
assert_eq!(inner.network.application.https.listen_address, "");
|
assert_eq!(inner.network.application.https.listen_address, "");
|
||||||
assert_eq!(inner.network.application.https.path, "app");
|
assert_eq!(inner.network.application.https.path, "app");
|
||||||
assert_eq!(inner.network.application.https.url, None);
|
assert_eq!(inner.network.application.https.url, None);
|
||||||
assert_eq!(inner.network.application.http.enabled, false);
|
assert!(!inner.network.application.http.enabled);
|
||||||
assert_eq!(inner.network.application.http.listen_address, "");
|
assert_eq!(inner.network.application.http.listen_address, "");
|
||||||
assert_eq!(inner.network.application.http.path, "app");
|
assert_eq!(inner.network.application.http.path, "app");
|
||||||
assert_eq!(inner.network.application.http.url, None);
|
assert_eq!(inner.network.application.http.url, None);
|
||||||
assert_eq!(inner.network.protocol.udp.enabled, true);
|
assert!(inner.network.protocol.udp.enabled);
|
||||||
assert_eq!(inner.network.protocol.udp.socket_pool_size, 16u32);
|
assert_eq!(inner.network.protocol.udp.socket_pool_size, 16u32);
|
||||||
assert_eq!(inner.network.protocol.udp.listen_address, "");
|
assert_eq!(inner.network.protocol.udp.listen_address, "");
|
||||||
assert_eq!(inner.network.protocol.udp.public_address, None);
|
assert_eq!(inner.network.protocol.udp.public_address, None);
|
||||||
assert_eq!(inner.network.protocol.tcp.connect, true);
|
assert!(inner.network.protocol.tcp.connect);
|
||||||
assert_eq!(inner.network.protocol.tcp.listen, true);
|
assert!(inner.network.protocol.tcp.listen);
|
||||||
assert_eq!(inner.network.protocol.tcp.max_connections, 32u32);
|
assert_eq!(inner.network.protocol.tcp.max_connections, 32u32);
|
||||||
assert_eq!(inner.network.protocol.tcp.listen_address, "");
|
assert_eq!(inner.network.protocol.tcp.listen_address, "");
|
||||||
assert_eq!(inner.network.protocol.tcp.public_address, None);
|
assert_eq!(inner.network.protocol.tcp.public_address, None);
|
||||||
assert_eq!(inner.network.protocol.ws.connect, false);
|
assert!(!inner.network.protocol.ws.connect);
|
||||||
assert_eq!(inner.network.protocol.ws.listen, false);
|
assert!(!inner.network.protocol.ws.listen);
|
||||||
assert_eq!(inner.network.protocol.ws.max_connections, 16u32);
|
assert_eq!(inner.network.protocol.ws.max_connections, 16u32);
|
||||||
assert_eq!(inner.network.protocol.ws.listen_address, "");
|
assert_eq!(inner.network.protocol.ws.listen_address, "");
|
||||||
assert_eq!(inner.network.protocol.ws.path, "ws");
|
assert_eq!(inner.network.protocol.ws.path, "ws");
|
||||||
assert_eq!(inner.network.protocol.ws.url, None);
|
assert_eq!(inner.network.protocol.ws.url, None);
|
||||||
assert_eq!(inner.network.protocol.wss.connect, false);
|
assert!(!inner.network.protocol.wss.connect);
|
||||||
assert_eq!(inner.network.protocol.wss.listen, false);
|
assert!(!inner.network.protocol.wss.listen);
|
||||||
assert_eq!(inner.network.protocol.wss.max_connections, 16u32);
|
assert_eq!(inner.network.protocol.wss.max_connections, 16u32);
|
||||||
assert_eq!(inner.network.protocol.wss.listen_address, "");
|
assert_eq!(inner.network.protocol.wss.listen_address, "");
|
||||||
assert_eq!(inner.network.protocol.wss.path, "ws");
|
assert_eq!(inner.network.protocol.wss.path, "ws");
|
||||||
|
@ -263,7 +263,7 @@ impl VeilidAPI {
|
|||||||
let rss = self.routing_table()?.route_spec_store();
|
let rss = self.routing_table()?.route_spec_store();
|
||||||
let r = rss
|
let r = rss
|
||||||
.allocate_route(
|
.allocate_route(
|
||||||
&crypto_kinds,
|
crypto_kinds,
|
||||||
stability,
|
stability,
|
||||||
sequencing,
|
sequencing,
|
||||||
default_route_hop_count,
|
default_route_hop_count,
|
||||||
@ -275,7 +275,7 @@ impl VeilidAPI {
|
|||||||
apibail_generic!("unable to allocate route");
|
apibail_generic!("unable to allocate route");
|
||||||
};
|
};
|
||||||
if !rss
|
if !rss
|
||||||
.test_route(route_id.clone())
|
.test_route(route_id)
|
||||||
.await
|
.await
|
||||||
.map_err(VeilidAPIError::no_connection)?
|
.map_err(VeilidAPIError::no_connection)?
|
||||||
{
|
{
|
||||||
|
@ -61,9 +61,9 @@ fn get_string(text: &str) -> Option<String> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn get_data(text: &str) -> Option<Vec<u8>> {
|
fn get_data(text: &str) -> Option<Vec<u8>> {
|
||||||
if text.starts_with("#") {
|
if let Some(stripped_text) = text.strip_prefix('#') {
|
||||||
hex::decode(&text[1..]).ok()
|
hex::decode(stripped_text).ok()
|
||||||
} else if text.starts_with("\"") || text.starts_with("'") {
|
} else if text.starts_with('"') || text.starts_with('\'') {
|
||||||
json::parse(text)
|
json::parse(text)
|
||||||
.ok()?
|
.ok()?
|
||||||
.as_str()
|
.as_str()
|
||||||
@ -86,7 +86,7 @@ fn get_route_id(
|
|||||||
allow_allocated: bool,
|
allow_allocated: bool,
|
||||||
allow_remote: bool,
|
allow_remote: bool,
|
||||||
) -> impl Fn(&str) -> Option<RouteId> {
|
) -> impl Fn(&str) -> Option<RouteId> {
|
||||||
return move |text: &str| {
|
move |text: &str| {
|
||||||
if text.is_empty() {
|
if text.is_empty() {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
@ -127,7 +127,7 @@ fn get_route_id(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
None
|
None
|
||||||
};
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_dht_schema(text: &str) -> Option<DHTSchema> {
|
fn get_dht_schema(text: &str) -> Option<DHTSchema> {
|
||||||
@ -140,7 +140,7 @@ fn get_safety_selection(routing_table: RoutingTable) -> impl Fn(&str) -> Option<
|
|||||||
let default_route_hop_count =
|
let default_route_hop_count =
|
||||||
routing_table.with_config(|c| c.network.rpc.default_route_hop_count as usize);
|
routing_table.with_config(|c| c.network.rpc.default_route_hop_count as usize);
|
||||||
|
|
||||||
if text.len() != 0 && &text[0..1] == "-" {
|
if !text.is_empty() && &text[0..1] == "-" {
|
||||||
// Unsafe
|
// Unsafe
|
||||||
let text = &text[1..];
|
let text = &text[1..];
|
||||||
let seq = get_sequencing(text).unwrap_or_default();
|
let seq = get_sequencing(text).unwrap_or_default();
|
||||||
@ -151,7 +151,7 @@ fn get_safety_selection(routing_table: RoutingTable) -> impl Fn(&str) -> Option<
|
|||||||
let mut hop_count = default_route_hop_count;
|
let mut hop_count = default_route_hop_count;
|
||||||
let mut stability = Stability::default();
|
let mut stability = Stability::default();
|
||||||
let mut sequencing = Sequencing::default();
|
let mut sequencing = Sequencing::default();
|
||||||
for x in text.split(",") {
|
for x in text.split(',') {
|
||||||
let x = x.trim();
|
let x = x.trim();
|
||||||
if let Some(pr) = get_route_id(rss.clone(), true, false)(x) {
|
if let Some(pr) = get_route_id(rss.clone(), true, false)(x) {
|
||||||
preferred_route = Some(pr)
|
preferred_route = Some(pr)
|
||||||
@ -179,7 +179,7 @@ fn get_safety_selection(routing_table: RoutingTable) -> impl Fn(&str) -> Option<
|
|||||||
|
|
||||||
fn get_node_ref_modifiers(mut node_ref: NodeRef) -> impl FnOnce(&str) -> Option<NodeRef> {
|
fn get_node_ref_modifiers(mut node_ref: NodeRef) -> impl FnOnce(&str) -> Option<NodeRef> {
|
||||||
move |text| {
|
move |text| {
|
||||||
for m in text.split("/") {
|
for m in text.split('/') {
|
||||||
if let Some(pt) = get_protocol_type(m) {
|
if let Some(pt) = get_protocol_type(m) {
|
||||||
node_ref.merge_filter(NodeRefFilter::new().with_protocol_type(pt));
|
node_ref.merge_filter(NodeRefFilter::new().with_protocol_type(pt));
|
||||||
} else if let Some(at) = get_address_type(m) {
|
} else if let Some(at) = get_address_type(m) {
|
||||||
@ -207,7 +207,7 @@ fn get_destination(
|
|||||||
} else {
|
} else {
|
||||||
(text.as_str(), None)
|
(text.as_str(), None)
|
||||||
};
|
};
|
||||||
if text.len() == 0 {
|
if text.is_empty() {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
if &text[0..1] == "#" {
|
if &text[0..1] == "#" {
|
||||||
@ -225,7 +225,7 @@ fn get_destination(
|
|||||||
} else {
|
} else {
|
||||||
let mut dc = DEBUG_CACHE.lock();
|
let mut dc = DEBUG_CACHE.lock();
|
||||||
let n = get_number(text)?;
|
let n = get_number(text)?;
|
||||||
let prid = dc.imported_routes.get(n)?.clone();
|
let prid = *dc.imported_routes.get(n)?;
|
||||||
let Some(private_route) = rss.best_remote_private_route(&prid) else {
|
let Some(private_route) = rss.best_remote_private_route(&prid) else {
|
||||||
// Remove imported route
|
// Remove imported route
|
||||||
dc.imported_routes.remove(n);
|
dc.imported_routes.remove(n);
|
||||||
@ -312,7 +312,7 @@ fn get_dht_key(
|
|||||||
} else {
|
} else {
|
||||||
(text, None)
|
(text, None)
|
||||||
};
|
};
|
||||||
if text.len() == 0 {
|
if text.is_empty() {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -528,13 +528,13 @@ pub fn print_data(data: &[u8], truncate_len: Option<usize>) -> String {
|
|||||||
let (data, truncated) = if truncate_len.is_some() && data.len() > truncate_len.unwrap() {
|
let (data, truncated) = if truncate_len.is_some() && data.len() > truncate_len.unwrap() {
|
||||||
(&data[0..64], true)
|
(&data[0..64], true)
|
||||||
} else {
|
} else {
|
||||||
(&data[..], false)
|
(data, false)
|
||||||
};
|
};
|
||||||
|
|
||||||
let strdata = if printable {
|
let strdata = if printable {
|
||||||
format!("{}", String::from_utf8_lossy(&data).to_string())
|
String::from_utf8_lossy(data).to_string()
|
||||||
} else {
|
} else {
|
||||||
let sw = shell_words::quote(&String::from_utf8_lossy(&data).to_string()).to_string();
|
let sw = shell_words::quote(String::from_utf8_lossy(data).as_ref()).to_string();
|
||||||
let h = hex::encode(data);
|
let h = hex::encode(data);
|
||||||
if h.len() < sw.len() {
|
if h.len() < sw.len() {
|
||||||
h
|
h
|
||||||
@ -1019,8 +1019,8 @@ impl VeilidAPI {
|
|||||||
let netman = self.network_manager()?;
|
let netman = self.network_manager()?;
|
||||||
let rpc = netman.rpc_processor();
|
let rpc = netman.rpc_processor();
|
||||||
|
|
||||||
let (call_id, data) = if args.starts_with("#") {
|
let (call_id, data) = if let Some(stripped_args) = args.strip_prefix('#') {
|
||||||
let (arg, rest) = args[1..].split_once(' ').unwrap_or((&args, ""));
|
let (arg, rest) = stripped_args.split_once(' ').unwrap_or((&args, ""));
|
||||||
let call_id =
|
let call_id =
|
||||||
OperationId::new(u64::from_str_radix(arg, 16).map_err(VeilidAPIError::generic)?);
|
OperationId::new(u64::from_str_radix(arg, 16).map_err(VeilidAPIError::generic)?);
|
||||||
let rest = rest.trim_start().to_owned();
|
let rest = rest.trim_start().to_owned();
|
||||||
@ -1097,7 +1097,7 @@ impl VeilidAPI {
|
|||||||
&[],
|
&[],
|
||||||
) {
|
) {
|
||||||
Ok(Some(v)) => format!("{}", v),
|
Ok(Some(v)) => format!("{}", v),
|
||||||
Ok(None) => format!("<unavailable>"),
|
Ok(None) => "<unavailable>".to_string(),
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
format!("Route allocation failed: {}", e)
|
format!("Route allocation failed: {}", e)
|
||||||
}
|
}
|
||||||
@ -1270,7 +1270,7 @@ impl VeilidAPI {
|
|||||||
let out = format!("Private route #{} imported: {}", n, route_id);
|
let out = format!("Private route #{} imported: {}", n, route_id);
|
||||||
dc.imported_routes.push(route_id);
|
dc.imported_routes.push(route_id);
|
||||||
|
|
||||||
return Ok(out);
|
Ok(out)
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn debug_route_test(&self, args: Vec<String>) -> VeilidAPIResult<String> {
|
async fn debug_route_test(&self, args: Vec<String>) -> VeilidAPIResult<String> {
|
||||||
@ -1298,7 +1298,7 @@ impl VeilidAPI {
|
|||||||
"FAILED".to_owned()
|
"FAILED".to_owned()
|
||||||
};
|
};
|
||||||
|
|
||||||
return Ok(out);
|
Ok(out)
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn debug_route(&self, args: String) -> VeilidAPIResult<String> {
|
async fn debug_route(&self, args: String) -> VeilidAPIResult<String> {
|
||||||
@ -1334,18 +1334,18 @@ impl VeilidAPI {
|
|||||||
let scope = get_debug_argument_at(&args, 1, "debug_record_list", "scope", get_string)?;
|
let scope = get_debug_argument_at(&args, 1, "debug_record_list", "scope", get_string)?;
|
||||||
let out = match scope.as_str() {
|
let out = match scope.as_str() {
|
||||||
"local" => {
|
"local" => {
|
||||||
let mut out = format!("Local Records:\n");
|
let mut out = "Local Records:\n".to_string();
|
||||||
out += &storage_manager.debug_local_records().await;
|
out += &storage_manager.debug_local_records().await;
|
||||||
out
|
out
|
||||||
}
|
}
|
||||||
"remote" => {
|
"remote" => {
|
||||||
let mut out = format!("Remote Records:\n");
|
let mut out = "Remote Records:\n".to_string();
|
||||||
out += &storage_manager.debug_remote_records().await;
|
out += &storage_manager.debug_remote_records().await;
|
||||||
out
|
out
|
||||||
}
|
}
|
||||||
_ => "Invalid scope\n".to_owned(),
|
_ => "Invalid scope\n".to_owned(),
|
||||||
};
|
};
|
||||||
return Ok(out);
|
Ok(out)
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn debug_record_purge(&self, args: Vec<String>) -> VeilidAPIResult<String> {
|
async fn debug_record_purge(&self, args: Vec<String>) -> VeilidAPIResult<String> {
|
||||||
@ -1359,7 +1359,7 @@ impl VeilidAPI {
|
|||||||
"remote" => storage_manager.purge_remote_records(bytes).await,
|
"remote" => storage_manager.purge_remote_records(bytes).await,
|
||||||
_ => "Invalid scope\n".to_owned(),
|
_ => "Invalid scope\n".to_owned(),
|
||||||
};
|
};
|
||||||
return Ok(out);
|
Ok(out)
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn debug_record_create(&self, args: Vec<String>) -> VeilidAPIResult<String> {
|
async fn debug_record_create(&self, args: Vec<String>) -> VeilidAPIResult<String> {
|
||||||
@ -1397,11 +1397,10 @@ impl VeilidAPI {
|
|||||||
// Get routing context with optional privacy
|
// Get routing context with optional privacy
|
||||||
let rc = self.routing_context();
|
let rc = self.routing_context();
|
||||||
let rc = if let Some(ss) = ss {
|
let rc = if let Some(ss) = ss {
|
||||||
let rcp = match rc.with_custom_privacy(ss) {
|
match rc.with_custom_privacy(ss) {
|
||||||
Err(e) => return Ok(format!("Can't use safety selection: {}", e)),
|
Err(e) => return Ok(format!("Can't use safety selection: {}", e)),
|
||||||
Ok(v) => v,
|
Ok(v) => v,
|
||||||
};
|
}
|
||||||
rcp
|
|
||||||
} else {
|
} else {
|
||||||
rc
|
rc
|
||||||
};
|
};
|
||||||
@ -1416,7 +1415,7 @@ impl VeilidAPI {
|
|||||||
Ok(v) => v,
|
Ok(v) => v,
|
||||||
};
|
};
|
||||||
debug!("DHT Record Created:\n{:#?}", record);
|
debug!("DHT Record Created:\n{:#?}", record);
|
||||||
return Ok(format!("{:?}", record));
|
Ok(format!("{:?}", record))
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn debug_record_get(&self, args: Vec<String>) -> VeilidAPIResult<String> {
|
async fn debug_record_get(&self, args: Vec<String>) -> VeilidAPIResult<String> {
|
||||||
@ -1456,11 +1455,10 @@ impl VeilidAPI {
|
|||||||
// Get routing context with optional privacy
|
// Get routing context with optional privacy
|
||||||
let rc = self.routing_context();
|
let rc = self.routing_context();
|
||||||
let rc = if let Some(ss) = ss {
|
let rc = if let Some(ss) = ss {
|
||||||
let rcp = match rc.with_custom_privacy(ss) {
|
match rc.with_custom_privacy(ss) {
|
||||||
Err(e) => return Ok(format!("Can't use safety selection: {}", e)),
|
Err(e) => return Ok(format!("Can't use safety selection: {}", e)),
|
||||||
Ok(v) => v,
|
Ok(v) => v,
|
||||||
};
|
}
|
||||||
rcp
|
|
||||||
} else {
|
} else {
|
||||||
rc
|
rc
|
||||||
};
|
};
|
||||||
@ -1497,7 +1495,7 @@ impl VeilidAPI {
|
|||||||
Err(e) => return Ok(format!("Can't close DHT record: {}", e)),
|
Err(e) => return Ok(format!("Can't close DHT record: {}", e)),
|
||||||
Ok(v) => v,
|
Ok(v) => v,
|
||||||
};
|
};
|
||||||
return Ok(out);
|
Ok(out)
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn debug_record_set(&self, args: Vec<String>) -> VeilidAPIResult<String> {
|
async fn debug_record_set(&self, args: Vec<String>) -> VeilidAPIResult<String> {
|
||||||
@ -1518,11 +1516,10 @@ impl VeilidAPI {
|
|||||||
// Get routing context with optional privacy
|
// Get routing context with optional privacy
|
||||||
let rc = self.routing_context();
|
let rc = self.routing_context();
|
||||||
let rc = if let Some(ss) = ss {
|
let rc = if let Some(ss) = ss {
|
||||||
let rcp = match rc.with_custom_privacy(ss) {
|
match rc.with_custom_privacy(ss) {
|
||||||
Err(e) => return Ok(format!("Can't use safety selection: {}", e)),
|
Err(e) => return Ok(format!("Can't use safety selection: {}", e)),
|
||||||
Ok(v) => v,
|
Ok(v) => v,
|
||||||
};
|
}
|
||||||
rcp
|
|
||||||
} else {
|
} else {
|
||||||
rc
|
rc
|
||||||
};
|
};
|
||||||
@ -1556,7 +1553,7 @@ impl VeilidAPI {
|
|||||||
Err(e) => return Ok(format!("Can't close DHT record: {}", e)),
|
Err(e) => return Ok(format!("Can't close DHT record: {}", e)),
|
||||||
Ok(v) => v,
|
Ok(v) => v,
|
||||||
};
|
};
|
||||||
return Ok(out);
|
Ok(out)
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn debug_record_delete(&self, args: Vec<String>) -> VeilidAPIResult<String> {
|
async fn debug_record_delete(&self, args: Vec<String>) -> VeilidAPIResult<String> {
|
||||||
@ -1568,7 +1565,7 @@ impl VeilidAPI {
|
|||||||
Err(e) => return Ok(format!("Can't delete DHT record: {}", e)),
|
Err(e) => return Ok(format!("Can't delete DHT record: {}", e)),
|
||||||
Ok(v) => v,
|
Ok(v) => v,
|
||||||
};
|
};
|
||||||
Ok(format!("DHT record deleted"))
|
Ok("DHT record deleted".to_string())
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn debug_record_info(&self, args: Vec<String>) -> VeilidAPIResult<String> {
|
async fn debug_record_info(&self, args: Vec<String>) -> VeilidAPIResult<String> {
|
||||||
@ -1595,7 +1592,7 @@ impl VeilidAPI {
|
|||||||
let ri = storage_manager.debug_remote_record_info(key).await;
|
let ri = storage_manager.debug_remote_record_info(key).await;
|
||||||
format!("Local Info:\n{}\n\nRemote Info:\n{}\n", li, ri)
|
format!("Local Info:\n{}\n\nRemote Info:\n{}\n", li, ri)
|
||||||
};
|
};
|
||||||
return Ok(out);
|
Ok(out)
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn debug_record(&self, args: String) -> VeilidAPIResult<String> {
|
async fn debug_record(&self, args: String) -> VeilidAPIResult<String> {
|
||||||
@ -1629,7 +1626,7 @@ impl VeilidAPI {
|
|||||||
let address_filter = network_manager.address_filter();
|
let address_filter = network_manager.address_filter();
|
||||||
|
|
||||||
let out = format!("Address Filter Punishments:\n{:#?}", address_filter);
|
let out = format!("Address Filter Punishments:\n{:#?}", address_filter);
|
||||||
return Ok(out);
|
Ok(out)
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn debug_punish(&self, args: String) -> VeilidAPIResult<String> {
|
async fn debug_punish(&self, args: String) -> VeilidAPIResult<String> {
|
||||||
|
@ -140,7 +140,7 @@ pub enum ResponseOp {
|
|||||||
},
|
},
|
||||||
GetState {
|
GetState {
|
||||||
#[serde(flatten)]
|
#[serde(flatten)]
|
||||||
result: ApiResult<VeilidState>,
|
result: ApiResult<Box<VeilidState>>,
|
||||||
},
|
},
|
||||||
Attach {
|
Attach {
|
||||||
#[serde(flatten)]
|
#[serde(flatten)]
|
||||||
@ -175,7 +175,7 @@ pub enum ResponseOp {
|
|||||||
NewRoutingContext {
|
NewRoutingContext {
|
||||||
value: u32,
|
value: u32,
|
||||||
},
|
},
|
||||||
RoutingContext(RoutingContextResponse),
|
RoutingContext(Box<RoutingContextResponse>),
|
||||||
// TableDb
|
// TableDb
|
||||||
OpenTableDb {
|
OpenTableDb {
|
||||||
#[serde(flatten)]
|
#[serde(flatten)]
|
||||||
|
@ -87,10 +87,10 @@ impl JsonRequestProcessor {
|
|||||||
let Some(routing_context) = inner.routing_contexts.get(&rc_id).cloned() else {
|
let Some(routing_context) = inner.routing_contexts.get(&rc_id).cloned() else {
|
||||||
return Err(Response {
|
return Err(Response {
|
||||||
id,
|
id,
|
||||||
op: ResponseOp::RoutingContext(RoutingContextResponse {
|
op: ResponseOp::RoutingContext(Box::new(RoutingContextResponse {
|
||||||
rc_id,
|
rc_id,
|
||||||
rc_op: RoutingContextResponseOp::InvalidId
|
rc_op: RoutingContextResponseOp::InvalidId,
|
||||||
})
|
})),
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
Ok(routing_context)
|
Ok(routing_context)
|
||||||
@ -100,7 +100,7 @@ impl JsonRequestProcessor {
|
|||||||
if inner.routing_contexts.remove(&id).is_none() {
|
if inner.routing_contexts.remove(&id).is_none() {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
return 1;
|
1
|
||||||
}
|
}
|
||||||
|
|
||||||
// TableDB
|
// TableDB
|
||||||
@ -120,8 +120,8 @@ impl JsonRequestProcessor {
|
|||||||
id,
|
id,
|
||||||
op: ResponseOp::TableDb(TableDbResponse {
|
op: ResponseOp::TableDb(TableDbResponse {
|
||||||
db_id,
|
db_id,
|
||||||
db_op: TableDbResponseOp::InvalidId
|
db_op: TableDbResponseOp::InvalidId,
|
||||||
})
|
}),
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
Ok(table_db)
|
Ok(table_db)
|
||||||
@ -131,7 +131,7 @@ impl JsonRequestProcessor {
|
|||||||
if inner.table_dbs.remove(&id).is_none() {
|
if inner.table_dbs.remove(&id).is_none() {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
return 1;
|
1
|
||||||
}
|
}
|
||||||
|
|
||||||
// TableDBTransaction
|
// TableDBTransaction
|
||||||
@ -155,8 +155,8 @@ impl JsonRequestProcessor {
|
|||||||
id,
|
id,
|
||||||
op: ResponseOp::TableDbTransaction(TableDbTransactionResponse {
|
op: ResponseOp::TableDbTransaction(TableDbTransactionResponse {
|
||||||
tx_id,
|
tx_id,
|
||||||
tx_op: TableDbTransactionResponseOp::InvalidId
|
tx_op: TableDbTransactionResponseOp::InvalidId,
|
||||||
})
|
}),
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
Ok(table_db_transaction)
|
Ok(table_db_transaction)
|
||||||
@ -166,7 +166,7 @@ impl JsonRequestProcessor {
|
|||||||
if inner.table_db_transactions.remove(&id).is_none() {
|
if inner.table_db_transactions.remove(&id).is_none() {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
return 1;
|
1
|
||||||
}
|
}
|
||||||
|
|
||||||
// CryptoSystem
|
// CryptoSystem
|
||||||
@ -186,8 +186,8 @@ impl JsonRequestProcessor {
|
|||||||
id,
|
id,
|
||||||
op: ResponseOp::CryptoSystem(CryptoSystemResponse {
|
op: ResponseOp::CryptoSystem(CryptoSystemResponse {
|
||||||
cs_id,
|
cs_id,
|
||||||
cs_op: CryptoSystemResponseOp::InvalidId
|
cs_op: CryptoSystemResponseOp::InvalidId,
|
||||||
})
|
}),
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
Ok(crypto_system)
|
Ok(crypto_system)
|
||||||
@ -197,7 +197,7 @@ impl JsonRequestProcessor {
|
|||||||
if inner.crypto_systems.remove(&id).is_none() {
|
if inner.crypto_systems.remove(&id).is_none() {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
return 1;
|
1
|
||||||
}
|
}
|
||||||
|
|
||||||
// Target
|
// Target
|
||||||
@ -280,13 +280,21 @@ impl JsonRequestProcessor {
|
|||||||
RoutingContextRequestOp::CreateDhtRecord { schema, kind } => {
|
RoutingContextRequestOp::CreateDhtRecord { schema, kind } => {
|
||||||
RoutingContextResponseOp::CreateDhtRecord {
|
RoutingContextResponseOp::CreateDhtRecord {
|
||||||
result: to_json_api_result(
|
result: to_json_api_result(
|
||||||
routing_context.create_dht_record(schema, kind).await,
|
routing_context
|
||||||
|
.create_dht_record(schema, kind)
|
||||||
|
.await
|
||||||
|
.map(Box::new),
|
||||||
),
|
),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
RoutingContextRequestOp::OpenDhtRecord { key, writer } => {
|
RoutingContextRequestOp::OpenDhtRecord { key, writer } => {
|
||||||
RoutingContextResponseOp::OpenDhtRecord {
|
RoutingContextResponseOp::OpenDhtRecord {
|
||||||
result: to_json_api_result(routing_context.open_dht_record(key, writer).await),
|
result: to_json_api_result(
|
||||||
|
routing_context
|
||||||
|
.open_dht_record(key, writer)
|
||||||
|
.await
|
||||||
|
.map(Box::new),
|
||||||
|
),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
RoutingContextRequestOp::CloseDhtRecord { key } => {
|
RoutingContextRequestOp::CloseDhtRecord { key } => {
|
||||||
@ -508,7 +516,7 @@ impl JsonRequestProcessor {
|
|||||||
&body,
|
&body,
|
||||||
&nonce,
|
&nonce,
|
||||||
&shared_secret,
|
&shared_secret,
|
||||||
associated_data.as_ref().map(|ad| ad.as_slice()),
|
associated_data.as_deref(),
|
||||||
)),
|
)),
|
||||||
},
|
},
|
||||||
CryptoSystemRequestOp::EncryptAead {
|
CryptoSystemRequestOp::EncryptAead {
|
||||||
@ -521,7 +529,7 @@ impl JsonRequestProcessor {
|
|||||||
&body,
|
&body,
|
||||||
&nonce,
|
&nonce,
|
||||||
&shared_secret,
|
&shared_secret,
|
||||||
associated_data.as_ref().map(|ad| ad.as_slice()),
|
associated_data.as_deref(),
|
||||||
)),
|
)),
|
||||||
},
|
},
|
||||||
CryptoSystemRequestOp::CryptNoAuth {
|
CryptoSystemRequestOp::CryptNoAuth {
|
||||||
@ -548,7 +556,7 @@ impl JsonRequestProcessor {
|
|||||||
))),
|
))),
|
||||||
},
|
},
|
||||||
RequestOp::GetState => ResponseOp::GetState {
|
RequestOp::GetState => ResponseOp::GetState {
|
||||||
result: to_json_api_result(self.api.get_state().await),
|
result: to_json_api_result(self.api.get_state().await.map(Box::new)),
|
||||||
},
|
},
|
||||||
RequestOp::Attach => ResponseOp::Attach {
|
RequestOp::Attach => ResponseOp::Attach {
|
||||||
result: to_json_api_result(self.api.attach().await),
|
result: to_json_api_result(self.api.attach().await),
|
||||||
@ -596,10 +604,10 @@ impl JsonRequestProcessor {
|
|||||||
Ok(v) => v,
|
Ok(v) => v,
|
||||||
Err(e) => return e,
|
Err(e) => return e,
|
||||||
};
|
};
|
||||||
ResponseOp::RoutingContext(
|
ResponseOp::RoutingContext(Box::new(
|
||||||
self.process_routing_context_request(routing_context, rcr)
|
self.process_routing_context_request(routing_context, rcr)
|
||||||
.await,
|
.await,
|
||||||
)
|
))
|
||||||
}
|
}
|
||||||
RequestOp::OpenTableDb { name, column_count } => {
|
RequestOp::OpenTableDb { name, column_count } => {
|
||||||
let table_store = match self.api.table_store() {
|
let table_store = match self.api.table_store() {
|
||||||
|
@ -110,11 +110,11 @@ pub enum RoutingContextResponseOp {
|
|||||||
},
|
},
|
||||||
CreateDhtRecord {
|
CreateDhtRecord {
|
||||||
#[serde(flatten)]
|
#[serde(flatten)]
|
||||||
result: ApiResult<DHTRecordDescriptor>,
|
result: ApiResult<Box<DHTRecordDescriptor>>,
|
||||||
},
|
},
|
||||||
OpenDhtRecord {
|
OpenDhtRecord {
|
||||||
#[serde(flatten)]
|
#[serde(flatten)]
|
||||||
result: ApiResult<DHTRecordDescriptor>,
|
result: ApiResult<Box<DHTRecordDescriptor>>,
|
||||||
},
|
},
|
||||||
CloseDhtRecord {
|
CloseDhtRecord {
|
||||||
#[serde(flatten)]
|
#[serde(flatten)]
|
||||||
|
@ -19,5 +19,5 @@ pub fn decompress_size_prepended(
|
|||||||
));
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Ok(block::decompress(input, uncompressed_size).map_err(VeilidAPIError::generic)?)
|
block::decompress(input, uncompressed_size).map_err(VeilidAPIError::generic)
|
||||||
}
|
}
|
||||||
|
@ -93,7 +93,7 @@ pub mod as_human_base64 {
|
|||||||
let base64 = String::deserialize(d)?;
|
let base64 = String::deserialize(d)?;
|
||||||
BASE64URL_NOPAD
|
BASE64URL_NOPAD
|
||||||
.decode(base64.as_bytes())
|
.decode(base64.as_bytes())
|
||||||
.map_err(|e| serde::de::Error::custom(e))
|
.map_err(serde::de::Error::custom)
|
||||||
} else {
|
} else {
|
||||||
Vec::<u8>::deserialize(d)
|
Vec::<u8>::deserialize(d)
|
||||||
}
|
}
|
||||||
@ -106,7 +106,7 @@ pub mod as_human_opt_base64 {
|
|||||||
|
|
||||||
pub fn serialize<S: Serializer>(v: &Option<Vec<u8>>, s: S) -> Result<S::Ok, S::Error> {
|
pub fn serialize<S: Serializer>(v: &Option<Vec<u8>>, s: S) -> Result<S::Ok, S::Error> {
|
||||||
if s.is_human_readable() {
|
if s.is_human_readable() {
|
||||||
let base64 = v.as_ref().map(|x| BASE64URL_NOPAD.encode(&x));
|
let base64 = v.as_ref().map(|x| BASE64URL_NOPAD.encode(x));
|
||||||
Option::<String>::serialize(&base64, s)
|
Option::<String>::serialize(&base64, s)
|
||||||
} else {
|
} else {
|
||||||
Option::<Vec<u8>>::serialize(v, s)
|
Option::<Vec<u8>>::serialize(v, s)
|
||||||
@ -120,7 +120,7 @@ pub mod as_human_opt_base64 {
|
|||||||
.map(|x| {
|
.map(|x| {
|
||||||
BASE64URL_NOPAD
|
BASE64URL_NOPAD
|
||||||
.decode(x.as_bytes())
|
.decode(x.as_bytes())
|
||||||
.map_err(|e| serde::de::Error::custom(e))
|
.map_err(serde::de::Error::custom)
|
||||||
})
|
})
|
||||||
.transpose()
|
.transpose()
|
||||||
} else {
|
} else {
|
||||||
|
@ -43,21 +43,21 @@ pub async fn test_fourcc() {
|
|||||||
|
|
||||||
pub async fn test_sequencing() {
|
pub async fn test_sequencing() {
|
||||||
let orig = Sequencing::PreferOrdered;
|
let orig = Sequencing::PreferOrdered;
|
||||||
let copy = deserialize_json(&serialize_json(&orig)).unwrap();
|
let copy = deserialize_json(&serialize_json(orig)).unwrap();
|
||||||
|
|
||||||
assert_eq!(orig, copy);
|
assert_eq!(orig, copy);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn test_stability() {
|
pub async fn test_stability() {
|
||||||
let orig = Stability::Reliable;
|
let orig = Stability::Reliable;
|
||||||
let copy = deserialize_json(&serialize_json(&orig)).unwrap();
|
let copy = deserialize_json(&serialize_json(orig)).unwrap();
|
||||||
|
|
||||||
assert_eq!(orig, copy);
|
assert_eq!(orig, copy);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn test_safetyselection() {
|
pub async fn test_safetyselection() {
|
||||||
let orig = SafetySelection::Unsafe(Sequencing::EnsureOrdered);
|
let orig = SafetySelection::Unsafe(Sequencing::EnsureOrdered);
|
||||||
let copy = deserialize_json(&serialize_json(&orig)).unwrap();
|
let copy = deserialize_json(&serialize_json(orig)).unwrap();
|
||||||
|
|
||||||
assert_eq!(orig, copy);
|
assert_eq!(orig, copy);
|
||||||
}
|
}
|
||||||
@ -178,7 +178,7 @@ pub async fn test_partialtunnel() {
|
|||||||
|
|
||||||
pub async fn test_veilidloglevel() {
|
pub async fn test_veilidloglevel() {
|
||||||
let orig = VeilidLogLevel::Info;
|
let orig = VeilidLogLevel::Info;
|
||||||
let copy = deserialize_json(&serialize_json(&orig)).unwrap();
|
let copy = deserialize_json(&serialize_json(orig)).unwrap();
|
||||||
|
|
||||||
assert_eq!(orig, copy);
|
assert_eq!(orig, copy);
|
||||||
}
|
}
|
||||||
@ -198,7 +198,7 @@ pub async fn test_veilidlog() {
|
|||||||
|
|
||||||
pub async fn test_attachmentstate() {
|
pub async fn test_attachmentstate() {
|
||||||
let orig = AttachmentState::FullyAttached;
|
let orig = AttachmentState::FullyAttached;
|
||||||
let copy = deserialize_json(&serialize_json(&orig)).unwrap();
|
let copy = deserialize_json(&serialize_json(orig)).unwrap();
|
||||||
|
|
||||||
assert_eq!(orig, copy);
|
assert_eq!(orig, copy);
|
||||||
}
|
}
|
||||||
@ -260,7 +260,7 @@ pub async fn test_veilidvaluechange() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub async fn test_veilidupdate() {
|
pub async fn test_veilidupdate() {
|
||||||
let orig = VeilidUpdate::ValueChange(fix_veilidvaluechange());
|
let orig = VeilidUpdate::ValueChange(Box::new(fix_veilidvaluechange()));
|
||||||
let copy = deserialize_json(&serialize_json(&orig)).unwrap();
|
let copy = deserialize_json(&serialize_json(&orig)).unwrap();
|
||||||
|
|
||||||
assert_eq!(orig, copy);
|
assert_eq!(orig, copy);
|
||||||
@ -268,20 +268,20 @@ pub async fn test_veilidupdate() {
|
|||||||
|
|
||||||
pub async fn test_veilidstate() {
|
pub async fn test_veilidstate() {
|
||||||
let orig = VeilidState {
|
let orig = VeilidState {
|
||||||
attachment: VeilidStateAttachment {
|
attachment: Box::new(VeilidStateAttachment {
|
||||||
state: AttachmentState::OverAttached,
|
state: AttachmentState::OverAttached,
|
||||||
public_internet_ready: true,
|
public_internet_ready: true,
|
||||||
local_network_ready: false,
|
local_network_ready: false,
|
||||||
},
|
}),
|
||||||
network: VeilidStateNetwork {
|
network: Box::new(VeilidStateNetwork {
|
||||||
started: true,
|
started: true,
|
||||||
bps_down: AlignedU64::from(14_400),
|
bps_down: AlignedU64::from(14_400),
|
||||||
bps_up: AlignedU64::from(1200),
|
bps_up: AlignedU64::from(1200),
|
||||||
peers: vec![fix_peertabledata()],
|
peers: vec![fix_peertabledata()],
|
||||||
},
|
}),
|
||||||
config: VeilidStateConfig {
|
config: Box::new(VeilidStateConfig {
|
||||||
config: fix_veilidconfiginner(),
|
config: fix_veilidconfiginner(),
|
||||||
},
|
}),
|
||||||
};
|
};
|
||||||
let copy = deserialize_json(&serialize_json(&orig)).unwrap();
|
let copy = deserialize_json(&serialize_json(&orig)).unwrap();
|
||||||
|
|
||||||
|
@ -61,7 +61,7 @@ impl TryFrom<&[u8]> for DHTSchemaDFLT {
|
|||||||
if b.len() != Self::FIXED_SIZE {
|
if b.len() != Self::FIXED_SIZE {
|
||||||
apibail_generic!("invalid size");
|
apibail_generic!("invalid size");
|
||||||
}
|
}
|
||||||
if &b[0..4] != &Self::FCC {
|
if b[0..4] != Self::FCC {
|
||||||
apibail_generic!("wrong fourcc");
|
apibail_generic!("wrong fourcc");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -101,7 +101,7 @@ impl TryFrom<&[u8]> for DHTSchemaSMPL {
|
|||||||
if b.len() < Self::FIXED_SIZE {
|
if b.len() < Self::FIXED_SIZE {
|
||||||
apibail_generic!("invalid size");
|
apibail_generic!("invalid size");
|
||||||
}
|
}
|
||||||
if &b[0..4] != &Self::FCC {
|
if b[0..4] != Self::FCC {
|
||||||
apibail_generic!("wrong fourcc");
|
apibail_generic!("wrong fourcc");
|
||||||
}
|
}
|
||||||
if (b.len() - Self::FIXED_SIZE) % (PUBLIC_KEY_LENGTH + 2) != 0 {
|
if (b.len() - Self::FIXED_SIZE) % (PUBLIC_KEY_LENGTH + 2) != 0 {
|
||||||
|
@ -32,10 +32,13 @@ impl FromStr for ValueSubkeyRangeSet {
|
|||||||
fn from_str(value: &str) -> Result<Self, Self::Err> {
|
fn from_str(value: &str) -> Result<Self, Self::Err> {
|
||||||
let mut data = RangeSetBlaze::<ValueSubkey>::new();
|
let mut data = RangeSetBlaze::<ValueSubkey>::new();
|
||||||
|
|
||||||
for r in value.split(",") {
|
for r in value.split(',') {
|
||||||
let r = r.trim();
|
let r = r.trim();
|
||||||
let Some((ss, es)) = r.split_once("..=") else {
|
let Some((ss, es)) = r.split_once("..=") else {
|
||||||
return Err(VeilidAPIError::parse_error("can not parse ValueSubkeyRangeSet", r));
|
return Err(VeilidAPIError::parse_error(
|
||||||
|
"can not parse ValueSubkeyRangeSet",
|
||||||
|
r,
|
||||||
|
));
|
||||||
};
|
};
|
||||||
let sn = ValueSubkey::from_str(ss)
|
let sn = ValueSubkey::from_str(ss)
|
||||||
.map_err(|e| VeilidAPIError::parse_error("could not parse ValueSubkey", e))?;
|
.map_err(|e| VeilidAPIError::parse_error("could not parse ValueSubkey", e))?;
|
||||||
|
@ -108,14 +108,14 @@ pub struct VeilidValueChange {
|
|||||||
#[cfg_attr(target_arch = "wasm32", derive(Tsify), tsify(into_wasm_abi))]
|
#[cfg_attr(target_arch = "wasm32", derive(Tsify), tsify(into_wasm_abi))]
|
||||||
#[serde(tag = "kind")]
|
#[serde(tag = "kind")]
|
||||||
pub enum VeilidUpdate {
|
pub enum VeilidUpdate {
|
||||||
Log(VeilidLog),
|
Log(Box<VeilidLog>),
|
||||||
AppMessage(VeilidAppMessage),
|
AppMessage(Box<VeilidAppMessage>),
|
||||||
AppCall(VeilidAppCall),
|
AppCall(Box<VeilidAppCall>),
|
||||||
Attachment(VeilidStateAttachment),
|
Attachment(Box<VeilidStateAttachment>),
|
||||||
Network(VeilidStateNetwork),
|
Network(Box<VeilidStateNetwork>),
|
||||||
Config(VeilidStateConfig),
|
Config(Box<VeilidStateConfig>),
|
||||||
RouteChange(VeilidRouteChange),
|
RouteChange(Box<VeilidRouteChange>),
|
||||||
ValueChange(VeilidValueChange),
|
ValueChange(Box<VeilidValueChange>),
|
||||||
Shutdown,
|
Shutdown,
|
||||||
}
|
}
|
||||||
from_impl_to_jsvalue!(VeilidUpdate);
|
from_impl_to_jsvalue!(VeilidUpdate);
|
||||||
@ -123,8 +123,8 @@ from_impl_to_jsvalue!(VeilidUpdate);
|
|||||||
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
|
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
|
||||||
#[cfg_attr(target_arch = "wasm32", derive(Tsify), tsify(into_wasm_abi))]
|
#[cfg_attr(target_arch = "wasm32", derive(Tsify), tsify(into_wasm_abi))]
|
||||||
pub struct VeilidState {
|
pub struct VeilidState {
|
||||||
pub attachment: VeilidStateAttachment,
|
pub attachment: Box<VeilidStateAttachment>,
|
||||||
pub network: VeilidStateNetwork,
|
pub network: Box<VeilidStateNetwork>,
|
||||||
pub config: VeilidStateConfig,
|
pub config: Box<VeilidStateConfig>,
|
||||||
}
|
}
|
||||||
from_impl_to_jsvalue!(VeilidState);
|
from_impl_to_jsvalue!(VeilidState);
|
||||||
|
@ -565,11 +565,11 @@ impl VeilidConfig {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_veilid_state(&self) -> VeilidStateConfig {
|
pub fn get_veilid_state(&self) -> Box<VeilidStateConfig> {
|
||||||
let inner = self.inner.read();
|
let inner = self.inner.read();
|
||||||
VeilidStateConfig {
|
Box::new(VeilidStateConfig {
|
||||||
config: inner.clone(),
|
config: inner.clone(),
|
||||||
}
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get(&self) -> RwLockReadGuard<VeilidConfigInner> {
|
pub fn get(&self) -> RwLockReadGuard<VeilidConfigInner> {
|
||||||
@ -612,7 +612,7 @@ impl VeilidConfig {
|
|||||||
// Make changes
|
// Make changes
|
||||||
let out = f(&mut editedinner)?;
|
let out = f(&mut editedinner)?;
|
||||||
// Validate
|
// Validate
|
||||||
Self::validate(&mut editedinner)?;
|
Self::validate(&editedinner)?;
|
||||||
// See if things have changed
|
// See if things have changed
|
||||||
if *inner == editedinner {
|
if *inner == editedinner {
|
||||||
// No changes, return early
|
// No changes, return early
|
||||||
@ -626,7 +626,9 @@ impl VeilidConfig {
|
|||||||
// Send configuration update to clients
|
// Send configuration update to clients
|
||||||
if let Some(update_cb) = &self.update_cb {
|
if let Some(update_cb) = &self.update_cb {
|
||||||
let safe_cfg = self.safe_config_inner();
|
let safe_cfg = self.safe_config_inner();
|
||||||
update_cb(VeilidUpdate::Config(VeilidStateConfig { config: safe_cfg }));
|
update_cb(VeilidUpdate::Config(Box::new(VeilidStateConfig {
|
||||||
|
config: safe_cfg,
|
||||||
|
})));
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(out)
|
Ok(out)
|
||||||
@ -680,7 +682,7 @@ impl VeilidConfig {
|
|||||||
// Replace subkey
|
// Replace subkey
|
||||||
let mut out = &mut jvc;
|
let mut out = &mut jvc;
|
||||||
for k in objkeypath {
|
for k in objkeypath {
|
||||||
if !out.has_key(*k) {
|
if !out.has_key(k) {
|
||||||
apibail_parse_error!(format!("invalid subkey in key '{}'", key), k);
|
apibail_parse_error!(format!("invalid subkey in key '{}'", key), k);
|
||||||
}
|
}
|
||||||
out = &mut out[*k];
|
out = &mut out[*k];
|
||||||
|
@ -150,7 +150,7 @@ impl ClientApi {
|
|||||||
|
|
||||||
// Process control messages for the server
|
// Process control messages for the server
|
||||||
async fn process_control(self, args: Vec<String>) -> VeilidAPIResult<String> {
|
async fn process_control(self, args: Vec<String>) -> VeilidAPIResult<String> {
|
||||||
if args.len() == 0 {
|
if args.is_empty() {
|
||||||
apibail_generic!("no control request specified");
|
apibail_generic!("no control request specified");
|
||||||
}
|
}
|
||||||
if args[0] == "Shutdown" {
|
if args[0] == "Shutdown" {
|
||||||
@ -207,7 +207,7 @@ impl ClientApi {
|
|||||||
|
|
||||||
// Avoid logging failed deserialization of large adversarial payloads from
|
// Avoid logging failed deserialization of large adversarial payloads from
|
||||||
// http://127.0.0.1:5959 by using an initial colon to force a parse error.
|
// http://127.0.0.1:5959 by using an initial colon to force a parse error.
|
||||||
let sanitized_line = if line.len() > MAX_NON_JSON_LOGGING && !line.starts_with("{") {
|
let sanitized_line = if line.len() > MAX_NON_JSON_LOGGING && !line.starts_with('{') {
|
||||||
":skipped long input that's not a JSON object".to_string()
|
":skipped long input that's not a JSON object".to_string()
|
||||||
} else {
|
} else {
|
||||||
line.to_string()
|
line.to_string()
|
||||||
@ -265,7 +265,7 @@ impl ClientApi {
|
|||||||
linebuf.clear();
|
linebuf.clear();
|
||||||
|
|
||||||
// Ignore newlines
|
// Ignore newlines
|
||||||
if line.len() == 0 {
|
if line.is_empty() {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -289,7 +289,7 @@ impl ClientApi {
|
|||||||
mut writer: W,
|
mut writer: W,
|
||||||
) -> VeilidAPIResult<Option<RequestLine>> {
|
) -> VeilidAPIResult<Option<RequestLine>> {
|
||||||
while let Ok(resp) = responses_rx.recv_async().await {
|
while let Ok(resp) = responses_rx.recv_async().await {
|
||||||
if let Err(_) = writer.write_all(resp.as_bytes()).await {
|
if (writer.write_all(resp.as_bytes()).await).is_err() {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -420,7 +420,7 @@ impl ClientApi {
|
|||||||
// Pass other updates to clients
|
// Pass other updates to clients
|
||||||
let inner = self.inner.lock();
|
let inner = self.inner.lock();
|
||||||
for ch in inner.update_channels.values() {
|
for ch in inner.update_channels.values() {
|
||||||
if let Err(_) = ch.send(veilid_update.clone()) {
|
if ch.send(veilid_update.clone()).is_err() {
|
||||||
// eprintln!("failed to send update: {}", e);
|
// eprintln!("failed to send update: {}", e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -20,7 +20,7 @@ use clap::{Args, Parser};
|
|||||||
use server::*;
|
use server::*;
|
||||||
use settings::LogLevel;
|
use settings::LogLevel;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::ffi::{OsStr, OsString};
|
use std::ffi::OsString;
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
use tools::*;
|
use tools::*;
|
||||||
@ -162,17 +162,11 @@ fn main() -> EyreResult<()> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Attempt to load configuration
|
// Attempt to load configuration
|
||||||
let settings_path: Option<&OsStr> = if let Some(config_file) = &args.config_file {
|
let settings_path: Option<OsString> = args
|
||||||
if Path::new(&config_file).exists() {
|
.config_file
|
||||||
Some(config_file)
|
.filter(|config_file| Path::new(&config_file).exists());
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
};
|
|
||||||
|
|
||||||
let settings = Settings::new(settings_path).wrap_err("configuration is invalid")?;
|
let settings = Settings::new(settings_path.as_deref()).wrap_err("configuration is invalid")?;
|
||||||
|
|
||||||
// write lock the settings
|
// write lock the settings
|
||||||
let mut settingsrw = settings.write();
|
let mut settingsrw = settings.write();
|
||||||
@ -303,7 +297,7 @@ fn main() -> EyreResult<()> {
|
|||||||
|
|
||||||
// --- Generate DHT Key ---
|
// --- Generate DHT Key ---
|
||||||
if let Some(ckstr) = args.generate_key_pair {
|
if let Some(ckstr) = args.generate_key_pair {
|
||||||
if ckstr == "" {
|
if ckstr.is_empty() {
|
||||||
let mut tks = veilid_core::TypedKeyGroup::new();
|
let mut tks = veilid_core::TypedKeyGroup::new();
|
||||||
let mut tss = veilid_core::TypedSecretGroup::new();
|
let mut tss = veilid_core::TypedSecretGroup::new();
|
||||||
for ck in veilid_core::VALID_CRYPTO_KINDS {
|
for ck in veilid_core::VALID_CRYPTO_KINDS {
|
||||||
@ -312,16 +306,12 @@ fn main() -> EyreResult<()> {
|
|||||||
tks.add(veilid_core::TypedKey::new(tkp.kind, tkp.value.key));
|
tks.add(veilid_core::TypedKey::new(tkp.kind, tkp.value.key));
|
||||||
tss.add(veilid_core::TypedSecret::new(tkp.kind, tkp.value.secret));
|
tss.add(veilid_core::TypedSecret::new(tkp.kind, tkp.value.secret));
|
||||||
}
|
}
|
||||||
println!(
|
println!("Public Keys:\n{}\nSecret Keys:\n{}\n", tks, tss);
|
||||||
"Public Keys:\n{}\nSecret Keys:\n{}\n",
|
|
||||||
tks.to_string(),
|
|
||||||
tss.to_string()
|
|
||||||
);
|
|
||||||
} else {
|
} else {
|
||||||
let ck: veilid_core::CryptoKind =
|
let ck: veilid_core::CryptoKind =
|
||||||
veilid_core::FourCC::from_str(&ckstr).wrap_err("couldn't parse crypto kind")?;
|
veilid_core::FourCC::from_str(&ckstr).wrap_err("couldn't parse crypto kind")?;
|
||||||
let tkp = veilid_core::Crypto::generate_keypair(ck).wrap_err("invalid crypto kind")?;
|
let tkp = veilid_core::Crypto::generate_keypair(ck).wrap_err("invalid crypto kind")?;
|
||||||
println!("{}", tkp.to_string());
|
println!("{}", tkp);
|
||||||
}
|
}
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
@ -48,8 +48,20 @@ pub async fn run_veilid_server_internal(
|
|||||||
) -> EyreResult<()> {
|
) -> EyreResult<()> {
|
||||||
trace!(?settings, ?server_mode);
|
trace!(?settings, ?server_mode);
|
||||||
|
|
||||||
|
let (
|
||||||
|
settings_auto_attach,
|
||||||
|
settings_client_api_enabled,
|
||||||
|
settings_client_api_listen_address_addrs,
|
||||||
|
) = {
|
||||||
let settingsr = settings.read();
|
let settingsr = settings.read();
|
||||||
|
|
||||||
|
(
|
||||||
|
settingsr.auto_attach,
|
||||||
|
settingsr.client_api.enabled,
|
||||||
|
settingsr.client_api.listen_address.addrs.clone(),
|
||||||
|
)
|
||||||
|
};
|
||||||
|
|
||||||
// Create client api state change pipe
|
// Create client api state change pipe
|
||||||
let (sender, receiver): (
|
let (sender, receiver): (
|
||||||
Sender<veilid_core::VeilidUpdate>,
|
Sender<veilid_core::VeilidUpdate>,
|
||||||
@ -72,20 +84,19 @@ pub async fn run_veilid_server_internal(
|
|||||||
.wrap_err("VeilidCore startup failed")?;
|
.wrap_err("VeilidCore startup failed")?;
|
||||||
|
|
||||||
// Start client api if one is requested
|
// Start client api if one is requested
|
||||||
let mut capi = if settingsr.client_api.enabled && matches!(server_mode, ServerMode::Normal) {
|
let mut capi = if settings_client_api_enabled && matches!(server_mode, ServerMode::Normal) {
|
||||||
let some_capi =
|
let some_capi =
|
||||||
client_api::ClientApi::new(veilid_api.clone(), veilid_logs.clone(), settings.clone());
|
client_api::ClientApi::new(veilid_api.clone(), veilid_logs.clone(), settings.clone());
|
||||||
some_capi
|
some_capi
|
||||||
.clone()
|
.clone()
|
||||||
.run(settingsr.client_api.listen_address.addrs.clone());
|
.run(settings_client_api_listen_address_addrs);
|
||||||
Some(some_capi)
|
Some(some_capi)
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
};
|
};
|
||||||
|
|
||||||
// Drop rwlock on settings
|
// Drop rwlock on settings
|
||||||
let auto_attach = settingsr.auto_attach || !matches!(server_mode, ServerMode::Normal);
|
let auto_attach = settings_auto_attach || !matches!(server_mode, ServerMode::Normal);
|
||||||
drop(settingsr);
|
|
||||||
|
|
||||||
// Process all updates
|
// Process all updates
|
||||||
let capi2 = capi.clone();
|
let capi2 = capi.clone();
|
||||||
|
@ -1,5 +1,3 @@
|
|||||||
#![allow(clippy::bool_assert_comparison)]
|
|
||||||
|
|
||||||
use clap::ValueEnum;
|
use clap::ValueEnum;
|
||||||
use directories::*;
|
use directories::*;
|
||||||
|
|
||||||
@ -714,62 +712,62 @@ impl Settings {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// bump client api port
|
// bump client api port
|
||||||
(*settingsrw).client_api.listen_address.offset_port(idx)?;
|
settingsrw.client_api.listen_address.offset_port(idx)?;
|
||||||
|
|
||||||
// bump protocol ports
|
// bump protocol ports
|
||||||
(*settingsrw)
|
settingsrw
|
||||||
.core
|
.core
|
||||||
.network
|
.network
|
||||||
.protocol
|
.protocol
|
||||||
.udp
|
.udp
|
||||||
.listen_address
|
.listen_address
|
||||||
.offset_port(idx)?;
|
.offset_port(idx)?;
|
||||||
(*settingsrw)
|
settingsrw
|
||||||
.core
|
.core
|
||||||
.network
|
.network
|
||||||
.protocol
|
.protocol
|
||||||
.tcp
|
.tcp
|
||||||
.listen_address
|
.listen_address
|
||||||
.offset_port(idx)?;
|
.offset_port(idx)?;
|
||||||
(*settingsrw)
|
settingsrw
|
||||||
.core
|
.core
|
||||||
.network
|
.network
|
||||||
.protocol
|
.protocol
|
||||||
.ws
|
.ws
|
||||||
.listen_address
|
.listen_address
|
||||||
.offset_port(idx)?;
|
.offset_port(idx)?;
|
||||||
if let Some(url) = &mut (*settingsrw).core.network.protocol.ws.url {
|
if let Some(url) = &mut settingsrw.core.network.protocol.ws.url {
|
||||||
url.offset_port(idx)?;
|
url.offset_port(idx)?;
|
||||||
}
|
}
|
||||||
(*settingsrw)
|
settingsrw
|
||||||
.core
|
.core
|
||||||
.network
|
.network
|
||||||
.protocol
|
.protocol
|
||||||
.wss
|
.wss
|
||||||
.listen_address
|
.listen_address
|
||||||
.offset_port(idx)?;
|
.offset_port(idx)?;
|
||||||
if let Some(url) = &mut (*settingsrw).core.network.protocol.wss.url {
|
if let Some(url) = &mut settingsrw.core.network.protocol.wss.url {
|
||||||
url.offset_port(idx)?;
|
url.offset_port(idx)?;
|
||||||
}
|
}
|
||||||
// bump application ports
|
// bump application ports
|
||||||
(*settingsrw)
|
settingsrw
|
||||||
.core
|
.core
|
||||||
.network
|
.network
|
||||||
.application
|
.application
|
||||||
.http
|
.http
|
||||||
.listen_address
|
.listen_address
|
||||||
.offset_port(idx)?;
|
.offset_port(idx)?;
|
||||||
if let Some(url) = &mut (*settingsrw).core.network.application.http.url {
|
if let Some(url) = &mut settingsrw.core.network.application.http.url {
|
||||||
url.offset_port(idx)?;
|
url.offset_port(idx)?;
|
||||||
}
|
}
|
||||||
(*settingsrw)
|
settingsrw
|
||||||
.core
|
.core
|
||||||
.network
|
.network
|
||||||
.application
|
.application
|
||||||
.https
|
.https
|
||||||
.listen_address
|
.listen_address
|
||||||
.offset_port(idx)?;
|
.offset_port(idx)?;
|
||||||
if let Some(url) = &mut (*settingsrw).core.network.application.https.url {
|
if let Some(url) = &mut settingsrw.core.network.application.https.url {
|
||||||
url.offset_port(idx)?;
|
url.offset_port(idx)?;
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
@ -1531,7 +1529,7 @@ mod tests {
|
|||||||
let settings = Settings::new(None).unwrap();
|
let settings = Settings::new(None).unwrap();
|
||||||
|
|
||||||
let s = settings.read();
|
let s = settings.read();
|
||||||
assert_eq!(s.daemon.enabled, false);
|
assert!(!s.daemon.enabled);
|
||||||
assert_eq!(s.daemon.pid_file, None);
|
assert_eq!(s.daemon.pid_file, None);
|
||||||
assert_eq!(s.daemon.chroot, None);
|
assert_eq!(s.daemon.chroot, None);
|
||||||
assert_eq!(s.daemon.working_directory, None);
|
assert_eq!(s.daemon.working_directory, None);
|
||||||
@ -1539,51 +1537,51 @@ mod tests {
|
|||||||
assert_eq!(s.daemon.group, None);
|
assert_eq!(s.daemon.group, None);
|
||||||
assert_eq!(s.daemon.stdout_file, None);
|
assert_eq!(s.daemon.stdout_file, None);
|
||||||
assert_eq!(s.daemon.stderr_file, None);
|
assert_eq!(s.daemon.stderr_file, None);
|
||||||
assert_eq!(s.client_api.enabled, true);
|
assert!(s.client_api.enabled);
|
||||||
assert_eq!(s.client_api.listen_address.name, "localhost:5959");
|
assert_eq!(s.client_api.listen_address.name, "localhost:5959");
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
s.client_api.listen_address.addrs,
|
s.client_api.listen_address.addrs,
|
||||||
listen_address_to_socket_addrs("localhost:5959").unwrap()
|
listen_address_to_socket_addrs("localhost:5959").unwrap()
|
||||||
);
|
);
|
||||||
assert_eq!(s.auto_attach, true);
|
assert!(s.auto_attach);
|
||||||
assert_eq!(s.logging.system.enabled, false);
|
assert!(!s.logging.system.enabled);
|
||||||
assert_eq!(s.logging.system.level, LogLevel::Info);
|
assert_eq!(s.logging.system.level, LogLevel::Info);
|
||||||
assert_eq!(s.logging.terminal.enabled, true);
|
assert!(s.logging.terminal.enabled);
|
||||||
assert_eq!(s.logging.terminal.level, LogLevel::Info);
|
assert_eq!(s.logging.terminal.level, LogLevel::Info);
|
||||||
assert_eq!(s.logging.file.enabled, false);
|
assert!(!s.logging.file.enabled);
|
||||||
assert_eq!(s.logging.file.path, "");
|
assert_eq!(s.logging.file.path, "");
|
||||||
assert_eq!(s.logging.file.append, true);
|
assert!(s.logging.file.append);
|
||||||
assert_eq!(s.logging.file.level, LogLevel::Info);
|
assert_eq!(s.logging.file.level, LogLevel::Info);
|
||||||
assert_eq!(s.logging.api.enabled, true);
|
assert!(s.logging.api.enabled);
|
||||||
assert_eq!(s.logging.api.level, LogLevel::Info);
|
assert_eq!(s.logging.api.level, LogLevel::Info);
|
||||||
assert_eq!(s.logging.otlp.enabled, false);
|
assert!(!s.logging.otlp.enabled);
|
||||||
assert_eq!(s.logging.otlp.level, LogLevel::Trace);
|
assert_eq!(s.logging.otlp.level, LogLevel::Trace);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
s.logging.otlp.grpc_endpoint,
|
s.logging.otlp.grpc_endpoint,
|
||||||
NamedSocketAddrs::from_str("localhost:4317").unwrap()
|
NamedSocketAddrs::from_str("localhost:4317").unwrap()
|
||||||
);
|
);
|
||||||
assert_eq!(s.logging.console.enabled, false);
|
assert!(!s.logging.console.enabled);
|
||||||
assert_eq!(s.testing.subnode_index, 0);
|
assert_eq!(s.testing.subnode_index, 0);
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
s.core.table_store.directory,
|
s.core.table_store.directory,
|
||||||
Settings::get_default_table_store_path()
|
Settings::get_default_table_store_path()
|
||||||
);
|
);
|
||||||
assert_eq!(s.core.table_store.delete, false);
|
assert!(!s.core.table_store.delete);
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
s.core.block_store.directory,
|
s.core.block_store.directory,
|
||||||
Settings::get_default_block_store_path()
|
Settings::get_default_block_store_path()
|
||||||
);
|
);
|
||||||
assert_eq!(s.core.block_store.delete, false);
|
assert!(!s.core.block_store.delete);
|
||||||
|
|
||||||
assert_eq!(s.core.protected_store.allow_insecure_fallback, true);
|
assert!(s.core.protected_store.allow_insecure_fallback);
|
||||||
assert_eq!(s.core.protected_store.always_use_insecure_storage, true);
|
assert!(s.core.protected_store.always_use_insecure_storage);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
s.core.protected_store.directory,
|
s.core.protected_store.directory,
|
||||||
Settings::get_default_protected_store_directory()
|
Settings::get_default_protected_store_directory()
|
||||||
);
|
);
|
||||||
assert_eq!(s.core.protected_store.delete, false);
|
assert!(!s.core.protected_store.delete);
|
||||||
assert_eq!(s.core.protected_store.device_encryption_key_password, "");
|
assert_eq!(s.core.protected_store.device_encryption_key_password, "");
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
s.core.protected_store.new_device_encryption_key_password,
|
s.core.protected_store.new_device_encryption_key_password,
|
||||||
@ -1633,8 +1631,8 @@ mod tests {
|
|||||||
2_000u32
|
2_000u32
|
||||||
);
|
);
|
||||||
//
|
//
|
||||||
assert_eq!(s.core.network.upnp, true);
|
assert!(s.core.network.upnp);
|
||||||
assert_eq!(s.core.network.detect_address_changes, true);
|
assert!(s.core.network.detect_address_changes);
|
||||||
assert_eq!(s.core.network.restricted_nat_retries, 0u32);
|
assert_eq!(s.core.network.restricted_nat_retries, 0u32);
|
||||||
//
|
//
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
@ -1647,7 +1645,7 @@ mod tests {
|
|||||||
);
|
);
|
||||||
assert_eq!(s.core.network.tls.connection_initial_timeout_ms, 2_000u32);
|
assert_eq!(s.core.network.tls.connection_initial_timeout_ms, 2_000u32);
|
||||||
//
|
//
|
||||||
assert_eq!(s.core.network.application.https.enabled, false);
|
assert!(!s.core.network.application.https.enabled);
|
||||||
assert_eq!(s.core.network.application.https.listen_address.name, ":443");
|
assert_eq!(s.core.network.application.https.listen_address.name, ":443");
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
s.core.network.application.https.listen_address.addrs,
|
s.core.network.application.https.listen_address.addrs,
|
||||||
@ -1658,7 +1656,7 @@ mod tests {
|
|||||||
std::path::PathBuf::from("app")
|
std::path::PathBuf::from("app")
|
||||||
);
|
);
|
||||||
assert_eq!(s.core.network.application.https.url, None);
|
assert_eq!(s.core.network.application.https.url, None);
|
||||||
assert_eq!(s.core.network.application.http.enabled, false);
|
assert!(!s.core.network.application.http.enabled);
|
||||||
assert_eq!(s.core.network.application.http.listen_address.name, ":80");
|
assert_eq!(s.core.network.application.http.listen_address.name, ":80");
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
s.core.network.application.http.listen_address.addrs,
|
s.core.network.application.http.listen_address.addrs,
|
||||||
@ -1670,23 +1668,23 @@ mod tests {
|
|||||||
);
|
);
|
||||||
assert_eq!(s.core.network.application.http.url, None);
|
assert_eq!(s.core.network.application.http.url, None);
|
||||||
//
|
//
|
||||||
assert_eq!(s.core.network.protocol.udp.enabled, true);
|
assert!(s.core.network.protocol.udp.enabled);
|
||||||
assert_eq!(s.core.network.protocol.udp.socket_pool_size, 0);
|
assert_eq!(s.core.network.protocol.udp.socket_pool_size, 0);
|
||||||
assert_eq!(s.core.network.protocol.udp.listen_address.name, "");
|
assert_eq!(s.core.network.protocol.udp.listen_address.name, "");
|
||||||
assert_eq!(s.core.network.protocol.udp.listen_address.addrs, vec![]);
|
assert_eq!(s.core.network.protocol.udp.listen_address.addrs, vec![]);
|
||||||
assert_eq!(s.core.network.protocol.udp.public_address, None);
|
assert_eq!(s.core.network.protocol.udp.public_address, None);
|
||||||
|
|
||||||
//
|
//
|
||||||
assert_eq!(s.core.network.protocol.tcp.connect, true);
|
assert!(s.core.network.protocol.tcp.connect);
|
||||||
assert_eq!(s.core.network.protocol.tcp.listen, true);
|
assert!(s.core.network.protocol.tcp.listen);
|
||||||
assert_eq!(s.core.network.protocol.tcp.max_connections, 32);
|
assert_eq!(s.core.network.protocol.tcp.max_connections, 32);
|
||||||
assert_eq!(s.core.network.protocol.tcp.listen_address.name, "");
|
assert_eq!(s.core.network.protocol.tcp.listen_address.name, "");
|
||||||
assert_eq!(s.core.network.protocol.tcp.listen_address.addrs, vec![]);
|
assert_eq!(s.core.network.protocol.tcp.listen_address.addrs, vec![]);
|
||||||
assert_eq!(s.core.network.protocol.tcp.public_address, None);
|
assert_eq!(s.core.network.protocol.tcp.public_address, None);
|
||||||
|
|
||||||
//
|
//
|
||||||
assert_eq!(s.core.network.protocol.ws.connect, true);
|
assert!(s.core.network.protocol.ws.connect);
|
||||||
assert_eq!(s.core.network.protocol.ws.listen, true);
|
assert!(s.core.network.protocol.ws.listen);
|
||||||
assert_eq!(s.core.network.protocol.ws.max_connections, 32);
|
assert_eq!(s.core.network.protocol.ws.max_connections, 32);
|
||||||
assert_eq!(s.core.network.protocol.ws.listen_address.name, "");
|
assert_eq!(s.core.network.protocol.ws.listen_address.name, "");
|
||||||
assert_eq!(s.core.network.protocol.ws.listen_address.addrs, vec![]);
|
assert_eq!(s.core.network.protocol.ws.listen_address.addrs, vec![]);
|
||||||
@ -1696,8 +1694,8 @@ mod tests {
|
|||||||
);
|
);
|
||||||
assert_eq!(s.core.network.protocol.ws.url, None);
|
assert_eq!(s.core.network.protocol.ws.url, None);
|
||||||
//
|
//
|
||||||
assert_eq!(s.core.network.protocol.wss.connect, true);
|
assert!(s.core.network.protocol.wss.connect);
|
||||||
assert_eq!(s.core.network.protocol.wss.listen, false);
|
assert!(!s.core.network.protocol.wss.listen);
|
||||||
assert_eq!(s.core.network.protocol.wss.max_connections, 32);
|
assert_eq!(s.core.network.protocol.wss.max_connections, 32);
|
||||||
assert_eq!(s.core.network.protocol.wss.listen_address.name, "");
|
assert_eq!(s.core.network.protocol.wss.listen_address.name, "");
|
||||||
assert_eq!(s.core.network.protocol.wss.listen_address.addrs, vec![]);
|
assert_eq!(s.core.network.protocol.wss.listen_address.addrs, vec![]);
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
use crate::*;
|
|
||||||
use crate::server::*;
|
use crate::server::*;
|
||||||
use crate::settings::Settings;
|
use crate::settings::Settings;
|
||||||
use crate::tools::*;
|
use crate::tools::*;
|
||||||
use crate::veilid_logs::*;
|
use crate::veilid_logs::*;
|
||||||
|
use crate::*;
|
||||||
use futures_util::StreamExt;
|
use futures_util::StreamExt;
|
||||||
use signal_hook::consts::signal::*;
|
use signal_hook::consts::signal::*;
|
||||||
use signal_hook_async_std::Signals;
|
use signal_hook_async_std::Signals;
|
||||||
@ -84,7 +84,7 @@ pub fn run_daemon(settings: Settings, _args: CmdlineArgs) -> EyreResult<()> {
|
|||||||
|
|
||||||
// Catch signals
|
// Catch signals
|
||||||
let signals =
|
let signals =
|
||||||
Signals::new(&[SIGHUP, SIGTERM, SIGINT, SIGQUIT]).wrap_err("failed to init signals")?;
|
Signals::new([SIGHUP, SIGTERM, SIGINT, SIGQUIT]).wrap_err("failed to init signals")?;
|
||||||
let handle = signals.handle();
|
let handle = signals.handle();
|
||||||
|
|
||||||
let signals_task = spawn(handle_signals(signals));
|
let signals_task = spawn(handle_signals(signals));
|
||||||
|
Loading…
Reference in New Issue
Block a user