pull/19/head
parent
6878452ab3
commit
fc4924ac87
After Width: | Height: | Size: 136 KiB |
@ -0,0 +1,32 @@ |
|||||||
|
[package] |
||||||
|
name = "nextgraph" |
||||||
|
description = "NextGraph client library. Nextgraph is a decentralized, secure and local-first web 3.0 ecosystem based on Semantic Web and CRDTs" |
||||||
|
categories = ["asynchronous","text-editors","web-programming","development-tools","database-implementations"] |
||||||
|
version.workspace = true |
||||||
|
edition.workspace = true |
||||||
|
license.workspace = true |
||||||
|
authors.workspace = true |
||||||
|
repository.workspace = true |
||||||
|
homepage.workspace = true |
||||||
|
keywords.workspace = true |
||||||
|
documentation.workspace = true |
||||||
|
rust-version.workspace = true |
||||||
|
|
||||||
|
[badges] |
||||||
|
maintenance = { status = "actively-developed" } |
||||||
|
|
||||||
|
[dependencies] |
||||||
|
ng-repo = { path = "../ng-repo", version = "0.1.0" } |
||||||
|
ng-net = { path = "../ng-net", version = "0.1.0" } |
||||||
|
ng-wallet = { path = "../ng-wallet", version = "0.1.0" } |
||||||
|
ng-client-ws = { path = "../ng-client-ws", version = "0.1.0" } |
||||||
|
ng-verifier = { path = "../ng-verifier", version = "0.1.0" } |
||||||
|
async-once-cell = "0.5.3" |
||||||
|
once_cell = "1.17.1" |
||||||
|
serde = { version = "1.0", features = ["derive"] } |
||||||
|
serde_bare = "0.5.0" |
||||||
|
serde_bytes = "0.11.7" |
||||||
|
base64-url = "2.0.0" |
||||||
|
web-time = "0.2.0" |
||||||
|
async-std = { version = "1.12.0", features = ["attributes","unstable"] } |
||||||
|
zeroize = { version = "1.6.0", features = ["zeroize_derive"] } |
@ -0,0 +1,57 @@ |
|||||||
|
<p align="center"> |
||||||
|
<img src="../.github/header.png" alt="nextgraph-header" /> |
||||||
|
</p> |
||||||
|
|
||||||
|
# nextgraph |
||||||
|
|
||||||
|
![MSRV][rustc-image] |
||||||
|
[![Apache 2.0 Licensed][license-image]][license-link] |
||||||
|
[![MIT Licensed][license-image2]][license-link2] |
||||||
|
|
||||||
|
Rust client library of NextGraph |
||||||
|
|
||||||
|
This repository is in active development at [https://git.nextgraph.org/NextGraph/nextgraph-rs](https://git.nextgraph.org/NextGraph/nextgraph-rs), a Gitea instance. For bug reports, issues, merge requests, and in order to join the dev team, please visit the link above and create an account (you can do so with a github account). The [github repo](https://github.com/nextgraph-org/nextgraph-rs) is just a read-only mirror that does not accept issues. |
||||||
|
|
||||||
|
## NextGraph |
||||||
|
|
||||||
|
> NextGraph brings about the convergence between P2P and Semantic Web technologies, towards a decentralized, secure and privacy-preserving cloud, based on CRDTs. |
||||||
|
> |
||||||
|
> This open source ecosystem provides solutions for end-users and software developers alike, wishing to use or create **decentralized** apps featuring: **live collaboration** on rich-text documents, peer to peer communication with **end-to-end encryption**, offline-first, **local-first**, portable and interoperable data, total ownership of data and software, security and privacy. Centered on repositories containing **semantic data** (RDF), **rich text**, and structured data formats like **JSON**, synced between peers belonging to permissioned groups of users, it offers strong eventual consistency, thanks to the use of **CRDTs**. Documents can be linked together, signed, shared securely, queried using the **SPARQL** language and organized into sites and containers. |
||||||
|
> |
||||||
|
> More info here [https://nextgraph.org](https://nextgraph.org) |
||||||
|
|
||||||
|
## Support |
||||||
|
|
||||||
|
Documentation can be found here [https://docs.nextgraph.org](https://docs.nextgraph.org) |
||||||
|
|
||||||
|
And our community forum where you can ask questions is here [https://forum.nextgraph.org](https://forum.nextgraph.org) |
||||||
|
|
||||||
|
## How to use the library |
||||||
|
|
||||||
|
NextGraph is not ready yet. You can subscribe to [our newsletter](https://list.nextgraph.org/subscription/form) to get updates, and support us with a [donation](https://nextgraph.org/donate/). |
||||||
|
|
||||||
|
## License |
||||||
|
|
||||||
|
Licensed under either of |
||||||
|
|
||||||
|
- Apache License, Version 2.0 ([LICENSE-APACHE2](LICENSE-APACHE2) or http://www.apache.org/licenses/LICENSE-2.0) |
||||||
|
- MIT license ([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT) |
||||||
|
at your option. |
||||||
|
|
||||||
|
`SPDX-License-Identifier: Apache-2.0 OR MIT` |
||||||
|
|
||||||
|
### Contributions license |
||||||
|
|
||||||
|
Unless you explicitly state otherwise, any contribution intentionally submitted |
||||||
|
for inclusion in the work by you shall be dual licensed as below, without any |
||||||
|
additional terms or conditions. |
||||||
|
|
||||||
|
--- |
||||||
|
|
||||||
|
NextGraph received funding through the [NGI Assure Fund](https://nlnet.nl/project/NextGraph/index.html), a fund established by [NLnet](https://nlnet.nl/) with financial support from the European Commission's [Next Generation Internet](https://ngi.eu/) programme, under the aegis of DG Communications Networks, Content and Technology under grant agreement No 957073. |
||||||
|
|
||||||
|
[rustc-image]: https://img.shields.io/badge/rustc-1.64+-blue.svg |
||||||
|
[license-image]: https://img.shields.io/badge/license-Apache2.0-blue.svg |
||||||
|
[license-link]: https://git.nextgraph.org/NextGraph/nextgraph-rs/raw/branch/master/LICENSE-APACHE2 |
||||||
|
[license-image2]: https://img.shields.io/badge/license-MIT-blue.svg |
||||||
|
[license-link2]: https://git.nextgraph.org/NextGraph/nextgraph-rs/src/branch/master/LICENSE-MIT |
@ -0,0 +1 @@ |
|||||||
|
pub mod local_broker; |
@ -0,0 +1,751 @@ |
|||||||
|
// Copyright (c) 2022-2024 Niko Bonnieure, Par le Peuple, NextGraph.org developers
|
||||||
|
// All rights reserved.
|
||||||
|
// Licensed under the Apache License, Version 2.0
|
||||||
|
// <LICENSE-APACHE2 or http://www.apache.org/licenses/LICENSE-2.0>
|
||||||
|
// or the MIT license <LICENSE-MIT or http://opensource.org/licenses/MIT>,
|
||||||
|
// at your option. All files in the project carrying such
|
||||||
|
// notice may not be copied, modified, or distributed except
|
||||||
|
// according to those terms.
|
||||||
|
|
||||||
|
use async_once_cell::OnceCell; |
||||||
|
use async_std::sync::{Arc, RwLock}; |
||||||
|
use core::fmt; |
||||||
|
use ng_net::connection::{ClientConfig, IConnect, StartConfig}; |
||||||
|
use ng_net::types::ClientInfo; |
||||||
|
use once_cell::sync::Lazy; |
||||||
|
use serde_bare::to_vec; |
||||||
|
use std::collections::HashMap; |
||||||
|
use std::fs::{read, write, File, OpenOptions}; |
||||||
|
use std::path::PathBuf; |
||||||
|
use zeroize::{Zeroize, ZeroizeOnDrop}; |
||||||
|
|
||||||
|
use ng_net::broker::*; |
||||||
|
use ng_repo::errors::NgError; |
||||||
|
use ng_repo::log::*; |
||||||
|
use ng_repo::types::*; |
||||||
|
use ng_wallet::{create_wallet_v0, types::*}; |
||||||
|
|
||||||
|
#[cfg(not(target_arch = "wasm32"))] |
||||||
|
use ng_client_ws::remote_ws::ConnectionWebSocket; |
||||||
|
#[cfg(target_arch = "wasm32")] |
||||||
|
use ng_client_ws::remote_ws_wasm::ConnectionWebSocket; |
||||||
|
|
||||||
|
type JsStorageReadFn = dyn Fn(String) -> Result<String, NgError> + 'static + Sync + Send; |
||||||
|
type JsStorageWriteFn = dyn Fn(String, String) -> Result<(), NgError> + 'static + Sync + Send; |
||||||
|
type JsCallback = dyn Fn() + 'static + Sync + Send; |
||||||
|
|
||||||
|
pub struct JsStorageConfig { |
||||||
|
pub local_read: Box<JsStorageReadFn>, |
||||||
|
pub local_write: Box<JsStorageWriteFn>, |
||||||
|
pub session_read: Box<JsStorageReadFn>, |
||||||
|
pub session_write: Box<JsStorageWriteFn>, |
||||||
|
} |
||||||
|
|
||||||
|
impl fmt::Debug for JsStorageConfig { |
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
||||||
|
write!(f, "JsStorageConfig") |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
#[derive(Debug)] |
||||||
|
pub enum LocalBrokerConfig { |
||||||
|
InMemory, |
||||||
|
BasePath(PathBuf), |
||||||
|
JsStorage(JsStorageConfig), |
||||||
|
} |
||||||
|
|
||||||
|
impl LocalBrokerConfig { |
||||||
|
pub fn is_in_memory(&self) -> bool { |
||||||
|
match self { |
||||||
|
Self::InMemory => true, |
||||||
|
_ => false, |
||||||
|
} |
||||||
|
} |
||||||
|
pub fn is_js(&self) -> bool { |
||||||
|
match self { |
||||||
|
Self::JsStorage(_) => true, |
||||||
|
_ => false, |
||||||
|
} |
||||||
|
} |
||||||
|
pub fn js_config(&self) -> Option<&JsStorageConfig> { |
||||||
|
match self { |
||||||
|
Self::JsStorage(c) => Some(c), |
||||||
|
_ => None, |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
//type LastSeqFn = fn(PubKey, u16) -> Result<u64, NgError>;
|
||||||
|
pub type LastSeqFn = dyn Fn(PubKey, u16) -> Result<u64, NgError> + 'static + Sync + Send; |
||||||
|
|
||||||
|
/// peer_id: PubKey, seq_num:u64, event_ser: vec<u8>,
|
||||||
|
pub type OutboxWriteFn = |
||||||
|
dyn Fn(PubKey, u64, Vec<u8>) -> Result<(), NgError> + 'static + Sync + Send; |
||||||
|
|
||||||
|
/// peer_id: PubKey,
|
||||||
|
pub type OutboxReadFn = dyn Fn(PubKey) -> Result<Vec<Vec<u8>>, NgError> + 'static + Sync + Send; |
||||||
|
|
||||||
|
/// Session Config to initiate a session at a local broker V0
|
||||||
|
pub struct SessionConfigV0 { |
||||||
|
pub user_id: UserId, |
||||||
|
pub wallet_name: String, |
||||||
|
// pub last_seq_function: Box<LastSeqFn>,
|
||||||
|
// pub outbox_write_function: Box<OutboxWriteFn>,
|
||||||
|
// pub outbox_read_function: Box<OutboxReadFn>,
|
||||||
|
} |
||||||
|
|
||||||
|
/// Session Config to initiate a session at a local broker
|
||||||
|
pub enum SessionConfig { |
||||||
|
V0(SessionConfigV0), |
||||||
|
} |
||||||
|
|
||||||
|
#[derive(Debug)] |
||||||
|
struct Session { |
||||||
|
config: SessionConfig, |
||||||
|
peer_key: PrivKey, |
||||||
|
last_wallet_nonce: u64, |
||||||
|
//verifier,
|
||||||
|
} |
||||||
|
|
||||||
|
impl SessionConfig { |
||||||
|
pub fn user_id(&self) -> UserId { |
||||||
|
match self { |
||||||
|
Self::V0(v0) => v0.user_id, |
||||||
|
} |
||||||
|
} |
||||||
|
pub fn wallet_name(&self) -> String { |
||||||
|
match self { |
||||||
|
Self::V0(v0) => v0.wallet_name.clone(), |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
impl fmt::Debug for SessionConfigV0 { |
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
||||||
|
write!( |
||||||
|
f, |
||||||
|
"SessionConfigV0 user={} wallet={}", |
||||||
|
self.user_id, self.wallet_name |
||||||
|
) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
impl fmt::Debug for SessionConfig { |
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
||||||
|
match self { |
||||||
|
SessionConfig::V0(v0) => v0.fmt(f), |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
#[derive(Debug)] |
||||||
|
struct LocalBroker { |
||||||
|
pub config: LocalBrokerConfig, |
||||||
|
|
||||||
|
pub wallets: HashMap<String, LocalWalletStorageV0>, |
||||||
|
|
||||||
|
pub opened_wallets: HashMap<String, SensitiveWallet>, |
||||||
|
|
||||||
|
pub sessions: HashMap<UserId, SessionPeerStorageV0>, |
||||||
|
|
||||||
|
pub opened_sessions: HashMap<UserId, Session>, |
||||||
|
} |
||||||
|
|
||||||
|
impl ILocalBroker for LocalBroker {} |
||||||
|
|
||||||
|
impl LocalBroker { |
||||||
|
fn get_wallet_for_session(&self, config: &SessionConfig) -> Result<&SensitiveWallet, NgError> { |
||||||
|
match config { |
||||||
|
SessionConfig::V0(v0) => self |
||||||
|
.opened_wallets |
||||||
|
.get(&v0.wallet_name) |
||||||
|
.ok_or(NgError::WalletNotFound), |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
//static LOCAL_BROKER: OnceCell<Result<(), NgError>> = OnceCell::new();
|
||||||
|
|
||||||
|
static LOCAL_BROKER: OnceCell<Result<Arc<RwLock<LocalBroker>>, NgError>> = OnceCell::new(); //Lazy::new(|| Arc::new(RwLock::new(Broker::new())));
|
||||||
|
|
||||||
|
pub type ConfigInitFn = dyn Fn() -> LocalBrokerConfig + 'static + Sync + Send; |
||||||
|
|
||||||
|
async fn init_(config: LocalBrokerConfig) -> Result<Arc<RwLock<LocalBroker>>, NgError> { |
||||||
|
let wallets = match &config { |
||||||
|
LocalBrokerConfig::InMemory => HashMap::new(), |
||||||
|
LocalBrokerConfig::BasePath(base_path) => { |
||||||
|
// load the wallets and sessions from disk
|
||||||
|
let mut path = base_path.clone(); |
||||||
|
path.push("wallets"); |
||||||
|
let map_ser = read(path); |
||||||
|
if map_ser.is_ok() { |
||||||
|
let wallets = LocalWalletStorage::v0_from_vec(&map_ser.unwrap())?; |
||||||
|
let LocalWalletStorage::V0(wallets) = wallets; |
||||||
|
wallets |
||||||
|
} else { |
||||||
|
HashMap::new() |
||||||
|
} |
||||||
|
} |
||||||
|
LocalBrokerConfig::JsStorage(js_storage_config) => { |
||||||
|
// load the wallets from JsStorage
|
||||||
|
match (js_storage_config.local_read)("ng_wallets".to_string()) { |
||||||
|
Err(_) => HashMap::new(), |
||||||
|
Ok(wallets_string) => { |
||||||
|
let map_ser = base64_url::decode(&wallets_string) |
||||||
|
.map_err(|_| NgError::SerializationError)?; |
||||||
|
let wallets: LocalWalletStorage = serde_bare::from_slice(&map_ser)?; |
||||||
|
let LocalWalletStorage::V0(v0) = wallets; |
||||||
|
v0 |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
}; |
||||||
|
|
||||||
|
let local_broker = LocalBroker { |
||||||
|
config, |
||||||
|
wallets, |
||||||
|
opened_wallets: HashMap::new(), |
||||||
|
sessions: HashMap::new(), |
||||||
|
opened_sessions: HashMap::new(), |
||||||
|
}; |
||||||
|
//log_debug!("{:?}", &local_broker);
|
||||||
|
|
||||||
|
Ok(Arc::new(RwLock::new(local_broker))) |
||||||
|
} |
||||||
|
|
||||||
|
//-> &'static Result<Arc<RwLock<LocalBroker>>, NgError>
|
||||||
|
pub async fn init_local_broker_with_lazy(config_fn: &Lazy<Box<ConfigInitFn>>) { |
||||||
|
LOCAL_BROKER |
||||||
|
.get_or_init(async { |
||||||
|
let config = (&*config_fn)(); |
||||||
|
init_(config).await |
||||||
|
}) |
||||||
|
.await; |
||||||
|
} |
||||||
|
|
||||||
|
pub async fn init_local_broker(config_fn: Box<ConfigInitFn>) { |
||||||
|
LOCAL_BROKER |
||||||
|
.get_or_init(async { |
||||||
|
let config = (config_fn)(); |
||||||
|
init_(config).await |
||||||
|
}) |
||||||
|
.await; |
||||||
|
} |
||||||
|
|
||||||
|
pub async fn get_all_wallets() -> Result<HashMap<String, LocalWalletStorageV0>, NgError> { |
||||||
|
let broker = match LOCAL_BROKER.get() { |
||||||
|
Some(Err(e)) => { |
||||||
|
log_err!("LocalBrokerNotInitialized: {}", e); |
||||||
|
return Err(NgError::LocalBrokerNotInitialized); |
||||||
|
} |
||||||
|
None => { |
||||||
|
log_err!("Not initialized"); |
||||||
|
return Err(NgError::LocalBrokerNotInitialized); |
||||||
|
} |
||||||
|
Some(Ok(broker)) => broker.read().await, |
||||||
|
}; |
||||||
|
Ok(broker.wallets.clone()) |
||||||
|
} |
||||||
|
|
||||||
|
pub async fn wallet_create_v0(params: CreateWalletV0) -> Result<CreateWalletResultV0, NgError> { |
||||||
|
let res = create_wallet_v0(params)?; |
||||||
|
let lws: LocalWalletStorageV0 = (&res).into(); |
||||||
|
wallet_add(lws).await?; |
||||||
|
Ok(res) |
||||||
|
} |
||||||
|
|
||||||
|
pub async fn reload_wallets() -> Result<(), NgError> { |
||||||
|
let mut broker = match LOCAL_BROKER.get() { |
||||||
|
None | Some(Err(_)) => return Err(NgError::LocalBrokerNotInitialized), |
||||||
|
Some(Ok(broker)) => broker.write().await, |
||||||
|
}; |
||||||
|
match &broker.config { |
||||||
|
LocalBrokerConfig::JsStorage(js_config) => { |
||||||
|
// load the wallets from JsStorage
|
||||||
|
let wallets_string = (js_config.local_read)("ng_wallets".to_string())?; |
||||||
|
let map_ser = |
||||||
|
base64_url::decode(&wallets_string).map_err(|_| NgError::SerializationError)?; |
||||||
|
let wallets: LocalWalletStorage = serde_bare::from_slice(&map_ser)?; |
||||||
|
let LocalWalletStorage::V0(v0) = wallets; |
||||||
|
broker.wallets.extend(v0); |
||||||
|
} |
||||||
|
_ => {} |
||||||
|
} |
||||||
|
Ok(()) |
||||||
|
} |
||||||
|
|
||||||
|
pub async fn wallet_add(lws: LocalWalletStorageV0) -> Result<(), NgError> { |
||||||
|
let mut broker = match LOCAL_BROKER.get() { |
||||||
|
None | Some(Err(_)) => return Err(NgError::LocalBrokerNotInitialized), |
||||||
|
Some(Ok(broker)) => broker.write().await, |
||||||
|
}; |
||||||
|
if !lws.in_memory && broker.config.is_in_memory() { |
||||||
|
return Err(NgError::CannotSaveWhenInMemoryConfig); |
||||||
|
} |
||||||
|
if broker.wallets.get(&lws.wallet.name()).is_some() { |
||||||
|
return Err(NgError::WalletAlreadyAdded); |
||||||
|
} |
||||||
|
let in_memory = lws.in_memory; |
||||||
|
broker.wallets.insert(lws.wallet.name(), lws); |
||||||
|
if in_memory { |
||||||
|
// if broker.config.is_js() {
|
||||||
|
// (broker.config.js_config().unwrap().wallets_in_mem_changed)();
|
||||||
|
// }
|
||||||
|
} else { |
||||||
|
match &broker.config { |
||||||
|
LocalBrokerConfig::JsStorage(js_config) => { |
||||||
|
// JS save
|
||||||
|
let lws_ser = LocalWalletStorage::v0_to_vec(&broker.wallets); |
||||||
|
let encoded = base64_url::encode(&lws_ser); |
||||||
|
(js_config.local_write)("ng_wallets".to_string(), encoded)?; |
||||||
|
} |
||||||
|
LocalBrokerConfig::BasePath(base_path) => { |
||||||
|
// save on disk
|
||||||
|
// TODO: use https://lib.rs/crates/keyring instead of AppLocalData on Tauri apps
|
||||||
|
let mut path = base_path.clone(); |
||||||
|
std::fs::create_dir_all(path.clone()).unwrap(); |
||||||
|
path.push("wallets"); |
||||||
|
|
||||||
|
let lws_ser = LocalWalletStorage::v0_to_vec(&broker.wallets); |
||||||
|
let r = write(path.clone(), &lws_ser); |
||||||
|
if r.is_err() { |
||||||
|
log_debug!("write {:?} {}", path, r.unwrap_err()); |
||||||
|
return Err(NgError::IoError); |
||||||
|
} |
||||||
|
} |
||||||
|
_ => panic!("wrong LocalBrokerConfig"), |
||||||
|
} |
||||||
|
} |
||||||
|
Ok(()) |
||||||
|
} |
||||||
|
|
||||||
|
pub async fn wallet_read_file(file: Vec<u8>) -> Result<Wallet, NgError> { |
||||||
|
let ngf: NgFile = file.try_into()?; |
||||||
|
if let NgFile::V0(NgFileV0::Wallet(wallet)) = ngf { |
||||||
|
let broker = match LOCAL_BROKER.get() { |
||||||
|
None | Some(Err(_)) => return Err(NgError::LocalBrokerNotInitialized), |
||||||
|
Some(Ok(broker)) => broker.read().await, |
||||||
|
}; |
||||||
|
// check that the wallet is not already present in local_broker
|
||||||
|
let wallet_name = wallet.name(); |
||||||
|
if broker.wallets.get(&wallet_name).is_none() { |
||||||
|
Ok(wallet) |
||||||
|
} else { |
||||||
|
Err(NgError::WalletAlreadyAdded) |
||||||
|
} |
||||||
|
} else { |
||||||
|
Err(NgError::InvalidFileFormat) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
pub async fn wallet_download_file(wallet_name: &String) -> Result<Vec<u8>, NgError> { |
||||||
|
let broker = match LOCAL_BROKER.get() { |
||||||
|
None | Some(Err(_)) => return Err(NgError::LocalBrokerNotInitialized), |
||||||
|
Some(Ok(broker)) => broker.read().await, |
||||||
|
}; |
||||||
|
// check that the wallet exists
|
||||||
|
match broker.wallets.get(wallet_name) { |
||||||
|
None => Err(NgError::WalletNotFound), |
||||||
|
Some(lws) => Ok(to_vec(&NgFile::V0(NgFileV0::Wallet(lws.wallet.clone()))).unwrap()), |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
pub fn wallet_open_with_pazzle( |
||||||
|
wallet: Wallet, |
||||||
|
pazzle: Vec<u8>, |
||||||
|
pin: [u8; 4], |
||||||
|
) -> Result<SensitiveWallet, NgError> { |
||||||
|
let opened_wallet = ng_wallet::open_wallet_with_pazzle(wallet, pazzle, pin)?; |
||||||
|
|
||||||
|
Ok(opened_wallet) |
||||||
|
} |
||||||
|
|
||||||
|
pub async fn wallet_import( |
||||||
|
encrypted_wallet: Wallet, |
||||||
|
mut opened_wallet: SensitiveWallet, |
||||||
|
in_memory: bool, |
||||||
|
) -> Result<ClientV0, NgError> { |
||||||
|
{ |
||||||
|
// in a block to release lock before calling wallet_add
|
||||||
|
let broker = match LOCAL_BROKER.get() { |
||||||
|
None | Some(Err(_)) => return Err(NgError::LocalBrokerNotInitialized), |
||||||
|
Some(Ok(broker)) => broker.read().await, |
||||||
|
}; |
||||||
|
|
||||||
|
let wallet_name = encrypted_wallet.name(); |
||||||
|
if broker.wallets.get(&wallet_name).is_some() { |
||||||
|
return Err(NgError::WalletAlreadyOpened); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
let lws = opened_wallet.import_v0(encrypted_wallet, in_memory)?; |
||||||
|
|
||||||
|
wallet_add(lws).await?; |
||||||
|
|
||||||
|
wallet_was_opened(opened_wallet).await |
||||||
|
} |
||||||
|
|
||||||
|
pub async fn wallet_was_opened(mut wallet: SensitiveWallet) -> Result<ClientV0, NgError> { |
||||||
|
let mut broker = match LOCAL_BROKER.get() { |
||||||
|
None | Some(Err(_)) => return Err(NgError::LocalBrokerNotInitialized), |
||||||
|
Some(Ok(broker)) => broker.write().await, |
||||||
|
}; |
||||||
|
|
||||||
|
if broker.opened_wallets.get(&wallet.id()).is_some() { |
||||||
|
return Err(NgError::WalletAlreadyOpened); |
||||||
|
} |
||||||
|
|
||||||
|
match broker.wallets.get(&(wallet.id())) { |
||||||
|
Some(lws) => { |
||||||
|
if wallet.client().is_none() { |
||||||
|
// this case happens when the wallet is opened and not when it is imported (as the client is already there)
|
||||||
|
wallet.set_client(lws.to_client_v0(wallet.privkey())?); |
||||||
|
} |
||||||
|
} |
||||||
|
None => { |
||||||
|
return Err(NgError::WalletNotFound); |
||||||
|
} |
||||||
|
} |
||||||
|
let client = wallet.client().as_ref().unwrap().clone(); |
||||||
|
broker.opened_wallets.insert(wallet.id(), wallet); |
||||||
|
Ok(client) |
||||||
|
} |
||||||
|
|
||||||
|
pub async fn session_start(config: SessionConfig) -> Result<SessionPeerStorageV0, NgError> { |
||||||
|
let mut broker = match LOCAL_BROKER.get() { |
||||||
|
None | Some(Err(_)) => return Err(NgError::LocalBrokerNotInitialized), |
||||||
|
Some(Ok(broker)) => broker.write().await, |
||||||
|
}; |
||||||
|
|
||||||
|
let wallet_name = config.wallet_name(); |
||||||
|
let wallet_id: PubKey = (*wallet_name).try_into()?; |
||||||
|
let user_id = config.user_id(); |
||||||
|
|
||||||
|
match broker.opened_wallets.get(&wallet_name) { |
||||||
|
None => return Err(NgError::WalletNotFound), |
||||||
|
Some(wallet) => { |
||||||
|
if !wallet.has_user(&user_id) { |
||||||
|
return Err(NgError::NotFound); |
||||||
|
} |
||||||
|
|
||||||
|
let session = match broker.sessions.get(&user_id) { |
||||||
|
Some(session) => session, |
||||||
|
None => { |
||||||
|
// creating the session now
|
||||||
|
let closed_wallet = broker.wallets.get(&wallet_name).unwrap(); |
||||||
|
if closed_wallet.in_memory { |
||||||
|
let session = SessionPeerStorageV0::new(user_id); |
||||||
|
broker.sessions.insert(user_id, session); |
||||||
|
broker.sessions.get(&user_id).unwrap() |
||||||
|
} else { |
||||||
|
// first check if there is a saved SessionWalletStorage
|
||||||
|
let mut sws = match &broker.config { |
||||||
|
LocalBrokerConfig::InMemory => panic!("cannot open saved session"), |
||||||
|
LocalBrokerConfig::JsStorage(js_config) => { |
||||||
|
// read session wallet storage from JsStorage
|
||||||
|
let res = |
||||||
|
(js_config.session_read)(format!("ng_wallet@{}", wallet_name)); |
||||||
|
match res { |
||||||
|
Ok(string) => { |
||||||
|
let decoded = base64_url::decode(&string) |
||||||
|
.map_err(|_| NgError::SerializationError)?; |
||||||
|
Some(SessionWalletStorageV0::dec_session( |
||||||
|
wallet.privkey(), |
||||||
|
&decoded, |
||||||
|
)?) |
||||||
|
} |
||||||
|
Err(_) => None, |
||||||
|
} |
||||||
|
} |
||||||
|
LocalBrokerConfig::BasePath(base_path) => { |
||||||
|
// read session wallet storage from disk
|
||||||
|
let mut path = base_path.clone(); |
||||||
|
path.push("sessions"); |
||||||
|
path.push(wallet_name.clone()); |
||||||
|
let res = read(path); |
||||||
|
if res.is_ok() { |
||||||
|
Some(SessionWalletStorageV0::dec_session( |
||||||
|
wallet.privkey(), |
||||||
|
&res.unwrap(), |
||||||
|
)?) |
||||||
|
} else { |
||||||
|
None |
||||||
|
} |
||||||
|
} |
||||||
|
}; |
||||||
|
let (session, new_sws) = match &mut sws { |
||||||
|
None => { |
||||||
|
let (s, sws_ser) = SessionWalletStorageV0::create_new_session( |
||||||
|
&wallet_id, user_id, |
||||||
|
)?; |
||||||
|
broker.sessions.insert(user_id, s); |
||||||
|
(broker.sessions.get(&user_id).unwrap(), sws_ser) |
||||||
|
} |
||||||
|
Some(sws) => { |
||||||
|
match sws.users.get(&user_id.to_string()) { |
||||||
|
Some(sps) => { |
||||||
|
broker.sessions.insert(user_id, sps.clone()); |
||||||
|
(broker.sessions.get(&user_id).unwrap(), vec![]) |
||||||
|
} |
||||||
|
None => { |
||||||
|
// the user was not found in the SWS. we need to create a SPS, add it, encrypt and serialize the new SWS,
|
||||||
|
// add the SPS to broker.sessions, and return the newly created SPS and the new SWS encryped serialization
|
||||||
|
let sps = SessionPeerStorageV0::new(user_id); |
||||||
|
sws.users.insert(user_id.to_string(), sps.clone()); |
||||||
|
let encrypted = sws.enc_session(&wallet_id)?; |
||||||
|
broker.sessions.insert(user_id, sps); |
||||||
|
(broker.sessions.get(&user_id).unwrap(), encrypted) |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
}; |
||||||
|
// save the new sws
|
||||||
|
if new_sws.len() > 0 { |
||||||
|
match &broker.config { |
||||||
|
LocalBrokerConfig::InMemory => { |
||||||
|
panic!("cannot save session when InMemory mode") |
||||||
|
} |
||||||
|
LocalBrokerConfig::JsStorage(js_config) => { |
||||||
|
// save session wallet storage to JsStorage
|
||||||
|
let encoded = base64_url::encode(&new_sws); |
||||||
|
(js_config.session_write)( |
||||||
|
format!("ng_wallet@{}", wallet_name), |
||||||
|
encoded, |
||||||
|
)?; |
||||||
|
} |
||||||
|
LocalBrokerConfig::BasePath(base_path) => { |
||||||
|
// save session wallet storage to disk
|
||||||
|
let mut path = base_path.clone(); |
||||||
|
path.push("sessions"); |
||||||
|
std::fs::create_dir_all(path.clone()).unwrap(); |
||||||
|
path.push(wallet_name); |
||||||
|
//log_debug!("{}", path.clone().display());
|
||||||
|
write(path.clone(), &new_sws).map_err(|_| NgError::IoError)?; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
session |
||||||
|
} |
||||||
|
} |
||||||
|
}; |
||||||
|
let session = session.clone(); |
||||||
|
broker.opened_sessions.insert( |
||||||
|
user_id, |
||||||
|
Session { |
||||||
|
config, |
||||||
|
peer_key: session.peer_key.clone(), |
||||||
|
last_wallet_nonce: session.last_wallet_nonce, |
||||||
|
}, |
||||||
|
); |
||||||
|
// FIXME: is this return value useful ?
|
||||||
|
Ok(session) |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
use web_time::SystemTime; |
||||||
|
fn get_unix_time() -> f64 { |
||||||
|
SystemTime::now() |
||||||
|
.duration_since(SystemTime::UNIX_EPOCH) |
||||||
|
.unwrap() |
||||||
|
.as_millis() as f64 |
||||||
|
} |
||||||
|
|
||||||
|
/// Result is a list of (user_id, server_id, server_ip, error, since_date)
|
||||||
|
pub async fn user_connect( |
||||||
|
info: ClientInfo, |
||||||
|
user_id: UserId, |
||||||
|
location: Option<String>, |
||||||
|
) -> Result<Vec<(String, String, String, Option<String>, f64)>, NgError> { |
||||||
|
let local_broker = match LOCAL_BROKER.get() { |
||||||
|
None | Some(Err(_)) => return Err(NgError::LocalBrokerNotInitialized), |
||||||
|
Some(Ok(broker)) => broker.read().await, |
||||||
|
}; |
||||||
|
|
||||||
|
let session = local_broker |
||||||
|
.opened_sessions |
||||||
|
.get(&user_id) |
||||||
|
.ok_or(NgError::SessionNotFound)?; |
||||||
|
let wallet = local_broker.get_wallet_for_session(&session.config)?; |
||||||
|
|
||||||
|
let mut result: Vec<(String, String, String, Option<String>, f64)> = Vec::new(); |
||||||
|
let arc_cnx: Arc<Box<dyn IConnect>> = Arc::new(Box::new(ConnectionWebSocket {})); |
||||||
|
|
||||||
|
match wallet { |
||||||
|
SensitiveWallet::V0(wallet) => { |
||||||
|
let client = wallet.client.as_ref().unwrap(); |
||||||
|
let client_id = client.id; |
||||||
|
let client_priv = &client.sensitive_client_storage.priv_key; |
||||||
|
let client_name = &client.name; |
||||||
|
let auto_open = &client.auto_open; |
||||||
|
// log_info!(
|
||||||
|
// "XXXX {} name={:?} auto_open={:?} {:?}",
|
||||||
|
// client_id.to_string(),
|
||||||
|
// client_name,
|
||||||
|
// auto_open,
|
||||||
|
// wallet
|
||||||
|
// );
|
||||||
|
for user in auto_open { |
||||||
|
let user_id = user.to_string(); |
||||||
|
let peer_key = &session.peer_key; |
||||||
|
let peer_id = peer_key.to_pub(); |
||||||
|
let site = wallet.sites.get(&user_id); |
||||||
|
if site.is_none() { |
||||||
|
result.push(( |
||||||
|
user_id, |
||||||
|
"".into(), |
||||||
|
"".into(), |
||||||
|
Some("Site is missing".into()), |
||||||
|
get_unix_time(), |
||||||
|
)); |
||||||
|
continue; |
||||||
|
} |
||||||
|
let site = site.unwrap(); |
||||||
|
let user_priv = site.get_individual_user_priv_key().unwrap(); |
||||||
|
let core = site.cores[0]; //TODO: cycle the other cores if failure to connect (failover)
|
||||||
|
let server_key = core.0; |
||||||
|
let broker = wallet.brokers.get(&core.0.to_string()); |
||||||
|
if broker.is_none() { |
||||||
|
result.push(( |
||||||
|
user_id, |
||||||
|
core.0.to_string(), |
||||||
|
"".into(), |
||||||
|
Some("Broker is missing".into()), |
||||||
|
get_unix_time(), |
||||||
|
)); |
||||||
|
continue; |
||||||
|
} |
||||||
|
let brokers = broker.unwrap(); |
||||||
|
let mut tried: Option<(String, String, String, Option<String>, f64)> = None; |
||||||
|
//TODO: on tauri (or forward in local broker, or CLI), prefer a Public to a Domain. Domain always comes first though, so we need to reorder the list
|
||||||
|
//TODO: use site.bootstraps to order the list of brokerInfo.
|
||||||
|
for broker_info in brokers { |
||||||
|
match broker_info { |
||||||
|
BrokerInfoV0::ServerV0(server) => { |
||||||
|
let url = server.get_ws_url(&location).await; |
||||||
|
log_debug!("URL {:?}", url); |
||||||
|
//Option<(String, Vec<BindAddress>)>
|
||||||
|
if url.is_some() { |
||||||
|
let url = url.unwrap(); |
||||||
|
if url.1.len() == 0 { |
||||||
|
// TODO deal with Box(Dyn)Public -> tunnel, and on tauri/forward/CLIs, deal with all Box -> direct connections (when url.1.len is > 0)
|
||||||
|
let res = BROKER |
||||||
|
.write() |
||||||
|
.await |
||||||
|
.connect( |
||||||
|
arc_cnx.clone(), |
||||||
|
peer_key.clone(), |
||||||
|
peer_id, |
||||||
|
server_key, |
||||||
|
StartConfig::Client(ClientConfig { |
||||||
|
url: url.0.clone(), |
||||||
|
name: client_name.clone(), |
||||||
|
user_priv: user_priv.clone(), |
||||||
|
client_priv: client_priv.clone(), |
||||||
|
info: info.clone(), |
||||||
|
registration: Some(core.1), |
||||||
|
}), |
||||||
|
) |
||||||
|
.await; |
||||||
|
log_debug!("broker.connect : {:?}", res); |
||||||
|
|
||||||
|
tried = Some(( |
||||||
|
user_id.clone(), |
||||||
|
core.0.to_string(), |
||||||
|
url.0.into(), |
||||||
|
match &res { |
||||||
|
Ok(_) => None, |
||||||
|
Err(e) => Some(e.to_string()), |
||||||
|
}, |
||||||
|
get_unix_time(), |
||||||
|
)); |
||||||
|
} |
||||||
|
if tried.is_some() && tried.as_ref().unwrap().3.is_none() { |
||||||
|
// successful. we can stop here
|
||||||
|
break; |
||||||
|
} else { |
||||||
|
log_debug!("Failed connection {:?}", tried); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
// Core information is discarded
|
||||||
|
_ => {} |
||||||
|
} |
||||||
|
} |
||||||
|
if tried.is_none() { |
||||||
|
tried = Some(( |
||||||
|
user_id, |
||||||
|
core.0.to_string(), |
||||||
|
"".into(), |
||||||
|
Some("No broker found".into()), |
||||||
|
get_unix_time(), |
||||||
|
)); |
||||||
|
} |
||||||
|
result.push(tried.unwrap()); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
Ok(result) |
||||||
|
} |
||||||
|
|
||||||
|
pub async fn session_stop(user_id: UserId) -> Result<(), NgError> { |
||||||
|
let mut broker = match LOCAL_BROKER.get() { |
||||||
|
None | Some(Err(_)) => return Err(NgError::LocalBrokerNotInitialized), |
||||||
|
Some(Ok(broker)) => broker.write().await, |
||||||
|
}; |
||||||
|
|
||||||
|
if broker.opened_sessions.remove(&user_id).is_some() { |
||||||
|
// TODO: change the logic here once it will be possible to have several users connected at the same time
|
||||||
|
Broker::close_all_connections().await; |
||||||
|
} |
||||||
|
|
||||||
|
Ok(()) |
||||||
|
} |
||||||
|
|
||||||
|
pub async fn user_disconnect(user_id: UserId) -> Result<(), NgError> { |
||||||
|
let broker = match LOCAL_BROKER.get() { |
||||||
|
None | Some(Err(_)) => return Err(NgError::LocalBrokerNotInitialized), |
||||||
|
Some(Ok(broker)) => broker.read().await, |
||||||
|
}; |
||||||
|
|
||||||
|
if broker.opened_sessions.get(&user_id).is_some() { |
||||||
|
// TODO: change the logic here once it will be possible to have several users connected at the same time
|
||||||
|
Broker::close_all_connections().await; |
||||||
|
} |
||||||
|
|
||||||
|
Ok(()) |
||||||
|
} |
||||||
|
|
||||||
|
pub async fn wallet_close(wallet_name: String) -> Result<(), NgError> { |
||||||
|
let mut broker = match LOCAL_BROKER.get() { |
||||||
|
None | Some(Err(_)) => return Err(NgError::LocalBrokerNotInitialized), |
||||||
|
Some(Ok(broker)) => broker.write().await, |
||||||
|
}; |
||||||
|
|
||||||
|
match broker.opened_wallets.remove(&wallet_name) { |
||||||
|
Some(mut wallet) => { |
||||||
|
for user in wallet.sites() { |
||||||
|
let key: PubKey = (user.as_str()).try_into().unwrap(); |
||||||
|
broker.opened_sessions.remove(&key); |
||||||
|
} |
||||||
|
wallet.zeroize(); |
||||||
|
} |
||||||
|
None => return Err(NgError::WalletNotFound), |
||||||
|
} |
||||||
|
|
||||||
|
Broker::close_all_connections().await; |
||||||
|
|
||||||
|
Ok(()) |
||||||
|
} |
||||||
|
|
||||||
|
pub async fn wallet_remove(wallet_name: String) -> Result<(), NgError> { |
||||||
|
let mut broker = match LOCAL_BROKER.get() { |
||||||
|
None | Some(Err(_)) => return Err(NgError::LocalBrokerNotInitialized), |
||||||
|
Some(Ok(broker)) => broker.write().await, |
||||||
|
}; |
||||||
|
|
||||||
|
todo!(); |
||||||
|
// should close the wallet, then remove all the saved sessions and remove the wallet
|
||||||
|
|
||||||
|
Ok(()) |
||||||
|
} |
@ -1,17 +1,25 @@ |
|||||||
[package] |
[package] |
||||||
name = "p2p-broker" |
name = "ng-broker" |
||||||
version = "0.1.0" |
# version = "0.1.0" |
||||||
edition = "2021" |
description = "Broker library of NextGraph, a decentralized, secure and local-first web 3.0 ecosystem based on Semantic Web and CRDTs" |
||||||
license = "MIT/Apache-2.0" |
version.workspace = true |
||||||
authors = ["Niko PLP <niko@nextgraph.org>"] |
edition.workspace = true |
||||||
description = "P2P Broker module of NextGraph" |
license.workspace = true |
||||||
repository = "https://git.nextgraph.org/NextGraph/nextgraph-rs" |
authors.workspace = true |
||||||
|
repository.workspace = true |
||||||
|
homepage.workspace = true |
||||||
|
keywords.workspace = true |
||||||
|
documentation.workspace = true |
||||||
|
rust-version.workspace = true |
||||||
|
|
||||||
|
[badges] |
||||||
|
maintenance = { status = "actively-developed" } |
||||||
|
|
||||||
[dependencies] |
[dependencies] |
||||||
p2p-repo = { path = "../p2p-repo" } |
ng-repo = { path = "../ng-repo", version = "0.1.0" } |
||||||
p2p-net = { path = "../p2p-net" } |
ng-net = { path = "../ng-net", version = "0.1.0" } |
||||||
p2p-client-ws = { path = "../p2p-client-ws" } |
ng-client-ws = { path = "../ng-client-ws", version = "0.1.0" } |
||||||
stores-rocksdb = { path = "../stores-rocksdb" } |
ng-stores-rocksdb = { path = "../ng-stores-rocksdb", version = "0.1.0" } |
||||||
chacha20 = "0.9.0" |
chacha20 = "0.9.0" |
||||||
serde = { version = "1.0", features = ["derive"] } |
serde = { version = "1.0", features = ["derive"] } |
||||||
serde_bare = "0.5.0" |
serde_bare = "0.5.0" |
@ -0,0 +1,55 @@ |
|||||||
|
# ng-broker |
||||||
|
|
||||||
|
![MSRV][rustc-image] |
||||||
|
[![Apache 2.0 Licensed][license-image]][license-link] |
||||||
|
[![MIT Licensed][license-image2]][license-link2] |
||||||
|
|
||||||
|
Broker library of NextGraph |
||||||
|
|
||||||
|
This repository is in active development at [https://git.nextgraph.org/NextGraph/nextgraph-rs](https://git.nextgraph.org/NextGraph/nextgraph-rs), a Gitea instance. For bug reports, issues, merge requests, and in order to join the dev team, please visit the link above and create an account (you can do so with a github account). The [github repo](https://github.com/nextgraph-org/nextgraph-rs) is just a read-only mirror that does not accept issues. |
||||||
|
|
||||||
|
## NextGraph |
||||||
|
|
||||||
|
> NextGraph brings about the convergence between P2P and Semantic Web technologies, towards a decentralized, secure and privacy-preserving cloud, based on CRDTs. |
||||||
|
> |
||||||
|
> This open source ecosystem provides solutions for end-users and software developers alike, wishing to use or create **decentralized** apps featuring: **live collaboration** on rich-text documents, peer to peer communication with **end-to-end encryption**, offline-first, **local-first**, portable and interoperable data, total ownership of data and software, security and privacy. Centered on repositories containing **semantic data** (RDF), **rich text**, and structured data formats like **JSON**, synced between peers belonging to permissioned groups of users, it offers strong eventual consistency, thanks to the use of **CRDTs**. Documents can be linked together, signed, shared securely, queried using the **SPARQL** language and organized into sites and containers. |
||||||
|
> |
||||||
|
> More info here [https://nextgraph.org](https://nextgraph.org) |
||||||
|
|
||||||
|
## Support |
||||||
|
|
||||||
|
Documentation can be found here [https://docs.nextgraph.org](https://docs.nextgraph.org) |
||||||
|
|
||||||
|
And our community forum where you can ask questions is here [https://forum.nextgraph.org](https://forum.nextgraph.org) |
||||||
|
|
||||||
|
## How to use the library |
||||||
|
|
||||||
|
NextGraph is not ready yet. You can subscribe to [our newsletter](https://list.nextgraph.org/subscription/form) to get updates, and support us with a [donation](https://nextgraph.org/donate/). |
||||||
|
|
||||||
|
This library is used internally by [ngd](../ngd/README.md) the daemon/server of NextGraph. It could potentially be used too by external projects that want to embed the NextGraph daemon in their own program. |
||||||
|
|
||||||
|
## License |
||||||
|
|
||||||
|
Licensed under either of |
||||||
|
|
||||||
|
- Apache License, Version 2.0 ([LICENSE-APACHE2](LICENSE-APACHE2) or http://www.apache.org/licenses/LICENSE-2.0) |
||||||
|
- MIT license ([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT) |
||||||
|
at your option. |
||||||
|
|
||||||
|
`SPDX-License-Identifier: Apache-2.0 OR MIT` |
||||||
|
|
||||||
|
### Contributions license |
||||||
|
|
||||||
|
Unless you explicitly state otherwise, any contribution intentionally submitted |
||||||
|
for inclusion in the work by you shall be dual licensed as below, without any |
||||||
|
additional terms or conditions. |
||||||
|
|
||||||
|
--- |
||||||
|
|
||||||
|
NextGraph received funding through the [NGI Assure Fund](https://nlnet.nl/project/NextGraph/index.html), a fund established by [NLnet](https://nlnet.nl/) with financial support from the European Commission's [Next Generation Internet](https://ngi.eu/) programme, under the aegis of DG Communications Networks, Content and Technology under grant agreement No 957073. |
||||||
|
|
||||||
|
[rustc-image]: https://img.shields.io/badge/rustc-1.64+-blue.svg |
||||||
|
[license-image]: https://img.shields.io/badge/license-Apache2.0-blue.svg |
||||||
|
[license-link]: https://git.nextgraph.org/NextGraph/nextgraph-rs/raw/branch/master/LICENSE-APACHE2 |
||||||
|
[license-image2]: https://img.shields.io/badge/license-MIT-blue.svg |
||||||
|
[license-link2]: https://git.nextgraph.org/NextGraph/nextgraph-rs/src/branch/master/LICENSE-MIT |
@ -1,15 +1,20 @@ |
|||||||
[package] |
[package] |
||||||
name = "p2p-client-ws" |
name = "ng-client-ws" |
||||||
version = "0.1.0" |
# version = "0.1.0" |
||||||
edition = "2021" |
description = "Websocket client library of NextGraph, a decentralized, secure and local-first web 3.0 ecosystem based on Semantic Web and CRDTs" |
||||||
license = "MIT/Apache-2.0" |
version.workspace = true |
||||||
authors = ["Niko PLP <niko@nextgraph.org>"] |
edition.workspace = true |
||||||
description = "P2P Client module of NextGraph" |
license.workspace = true |
||||||
repository = "https://git.nextgraph.org/NextGraph/nextgraph-rs" |
authors.workspace = true |
||||||
|
repository.workspace = true |
||||||
|
homepage.workspace = true |
||||||
|
keywords.workspace = true |
||||||
|
documentation.workspace = true |
||||||
|
rust-version.workspace = true |
||||||
|
|
||||||
[dependencies] |
[dependencies] |
||||||
p2p-repo = { path = "../p2p-repo" } |
ng-repo = { path = "../ng-repo", version = "0.1.0" } |
||||||
p2p-net = { path = "../p2p-net" } |
ng-net = { path = "../ng-net", version = "0.1.0" } |
||||||
chacha20 = "0.9.0" |
chacha20 = "0.9.0" |
||||||
serde = { version = "1.0", features = ["derive"] } |
serde = { version = "1.0", features = ["derive"] } |
||||||
serde_bare = "0.5.0" |
serde_bare = "0.5.0" |
@ -0,0 +1,55 @@ |
|||||||
|
# ng-client-ws |
||||||
|
|
||||||
|
![MSRV][rustc-image] |
||||||
|
[![Apache 2.0 Licensed][license-image]][license-link] |
||||||
|
[![MIT Licensed][license-image2]][license-link2] |
||||||
|
|
||||||
|
Websocket client library of NextGraph |
||||||
|
|
||||||
|
This repository is in active development at [https://git.nextgraph.org/NextGraph/nextgraph-rs](https://git.nextgraph.org/NextGraph/nextgraph-rs), a Gitea instance. For bug reports, issues, merge requests, and in order to join the dev team, please visit the link above and create an account (you can do so with a github account). The [github repo](https://github.com/nextgraph-org/nextgraph-rs) is just a read-only mirror that does not accept issues. |
||||||
|
|
||||||
|
## NextGraph |
||||||
|
|
||||||
|
> NextGraph brings about the convergence between P2P and Semantic Web technologies, towards a decentralized, secure and privacy-preserving cloud, based on CRDTs. |
||||||
|
> |
||||||
|
> This open source ecosystem provides solutions for end-users and software developers alike, wishing to use or create **decentralized** apps featuring: **live collaboration** on rich-text documents, peer to peer communication with **end-to-end encryption**, offline-first, **local-first**, portable and interoperable data, total ownership of data and software, security and privacy. Centered on repositories containing **semantic data** (RDF), **rich text**, and structured data formats like **JSON**, synced between peers belonging to permissioned groups of users, it offers strong eventual consistency, thanks to the use of **CRDTs**. Documents can be linked together, signed, shared securely, queried using the **SPARQL** language and organized into sites and containers. |
||||||
|
> |
||||||
|
> More info here [https://nextgraph.org](https://nextgraph.org) |
||||||
|
|
||||||
|
## Support |
||||||
|
|
||||||
|
Documentation can be found here [https://docs.nextgraph.org](https://docs.nextgraph.org) |
||||||
|
|
||||||
|
And our community forum where you can ask questions is here [https://forum.nextgraph.org](https://forum.nextgraph.org) |
||||||
|
|
||||||
|
## How to use the library |
||||||
|
|
||||||
|
NextGraph is not ready yet. You can subscribe to [our newsletter](https://list.nextgraph.org/subscription/form) to get updates, and support us with a [donation](https://nextgraph.org/donate/). |
||||||
|
|
||||||
|
This library is used internally by [ngcli](../ngcli/README.md), [ng-app](../ng-app/README.md) and by [nextgraph, the Rust client library](../nextgraph/README.md) which you should be using instead. It is not meant to be used by other programs as-is. |
||||||
|
|
||||||
|
## License |
||||||
|
|
||||||
|
Licensed under either of |
||||||
|
|
||||||
|
- Apache License, Version 2.0 ([LICENSE-APACHE2](LICENSE-APACHE2) or http://www.apache.org/licenses/LICENSE-2.0) |
||||||
|
- MIT license ([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT) |
||||||
|
at your option. |
||||||
|
|
||||||
|
`SPDX-License-Identifier: Apache-2.0 OR MIT` |
||||||
|
|
||||||
|
### Contributions license |
||||||
|
|
||||||
|
Unless you explicitly state otherwise, any contribution intentionally submitted |
||||||
|
for inclusion in the work by you shall be dual licensed as below, without any |
||||||
|
additional terms or conditions. |
||||||
|
|
||||||
|
--- |
||||||
|
|
||||||
|
NextGraph received funding through the [NGI Assure Fund](https://nlnet.nl/project/NextGraph/index.html), a fund established by [NLnet](https://nlnet.nl/) with financial support from the European Commission's [Next Generation Internet](https://ngi.eu/) programme, under the aegis of DG Communications Networks, Content and Technology under grant agreement No 957073. |
||||||
|
|
||||||
|
[rustc-image]: https://img.shields.io/badge/rustc-1.64+-blue.svg |
||||||
|
[license-image]: https://img.shields.io/badge/license-Apache2.0-blue.svg |
||||||
|
[license-link]: https://git.nextgraph.org/NextGraph/nextgraph-rs/raw/branch/master/LICENSE-APACHE2 |
||||||
|
[license-image2]: https://img.shields.io/badge/license-MIT-blue.svg |
||||||
|
[license-link2]: https://git.nextgraph.org/NextGraph/nextgraph-rs/src/branch/master/LICENSE-MIT |
@ -0,0 +1,55 @@ |
|||||||
|
# ng-net |
||||||
|
|
||||||
|
![MSRV][rustc-image] |
||||||
|
[![Apache 2.0 Licensed][license-image]][license-link] |
||||||
|
[![MIT Licensed][license-image2]][license-link2] |
||||||
|
|
||||||
|
Network library of NextGraph |
||||||
|
|
||||||
|
This repository is in active development at [https://git.nextgraph.org/NextGraph/nextgraph-rs](https://git.nextgraph.org/NextGraph/nextgraph-rs), a Gitea instance. For bug reports, issues, merge requests, and in order to join the dev team, please visit the link above and create an account (you can do so with a github account). The [github repo](https://github.com/nextgraph-org/nextgraph-rs) is just a read-only mirror that does not accept issues. |
||||||
|
|
||||||
|
## NextGraph |
||||||
|
|
||||||
|
> NextGraph brings about the convergence between P2P and Semantic Web technologies, towards a decentralized, secure and privacy-preserving cloud, based on CRDTs. |
||||||
|
> |
||||||
|
> This open source ecosystem provides solutions for end-users and software developers alike, wishing to use or create **decentralized** apps featuring: **live collaboration** on rich-text documents, peer to peer communication with **end-to-end encryption**, offline-first, **local-first**, portable and interoperable data, total ownership of data and software, security and privacy. Centered on repositories containing **semantic data** (RDF), **rich text**, and structured data formats like **JSON**, synced between peers belonging to permissioned groups of users, it offers strong eventual consistency, thanks to the use of **CRDTs**. Documents can be linked together, signed, shared securely, queried using the **SPARQL** language and organized into sites and containers. |
||||||
|
> |
||||||
|
> More info here [https://nextgraph.org](https://nextgraph.org) |
||||||
|
|
||||||
|
## Support |
||||||
|
|
||||||
|
Documentation can be found here [https://docs.nextgraph.org](https://docs.nextgraph.org) |
||||||
|
|
||||||
|
And our community forum where you can ask questions is here [https://forum.nextgraph.org](https://forum.nextgraph.org) |
||||||
|
|
||||||
|
## How to use the library |
||||||
|
|
||||||
|
NextGraph is not ready yet. You can subscribe to [our newsletter](https://list.nextgraph.org/subscription/form) to get updates, and support us with a [donation](https://nextgraph.org/donate/). |
||||||
|
|
||||||
|
This library is used internally by [ngd](../ngd/README.md), [ngcli](../ngcli/README.md), [ng-app](../ng-app/README.md) and by [nextgraph, the Rust client library](../nextgraph/README.md) which you should be using instead. It is not meant to be used by other programs as-is. |
||||||
|
|
||||||
|
## License |
||||||
|
|
||||||
|
Licensed under either of |
||||||
|
|
||||||
|
- Apache License, Version 2.0 ([LICENSE-APACHE2](LICENSE-APACHE2) or http://www.apache.org/licenses/LICENSE-2.0) |
||||||
|
- MIT license ([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT) |
||||||
|
at your option. |
||||||
|
|
||||||
|
`SPDX-License-Identifier: Apache-2.0 OR MIT` |
||||||
|
|
||||||
|
### Contributions license |
||||||
|
|
||||||
|
Unless you explicitly state otherwise, any contribution intentionally submitted |
||||||
|
for inclusion in the work by you shall be dual licensed as below, without any |
||||||
|
additional terms or conditions. |
||||||
|
|
||||||
|
--- |
||||||
|
|
||||||
|
NextGraph received funding through the [NGI Assure Fund](https://nlnet.nl/project/NextGraph/index.html), a fund established by [NLnet](https://nlnet.nl/) with financial support from the European Commission's [Next Generation Internet](https://ngi.eu/) programme, under the aegis of DG Communications Networks, Content and Technology under grant agreement No 957073. |
||||||
|
|
||||||
|
[rustc-image]: https://img.shields.io/badge/rustc-1.64+-blue.svg |
||||||
|
[license-image]: https://img.shields.io/badge/license-Apache2.0-blue.svg |
||||||
|
[license-link]: https://git.nextgraph.org/NextGraph/nextgraph-rs/raw/branch/master/LICENSE-APACHE2 |
||||||
|
[license-image2]: https://img.shields.io/badge/license-MIT-blue.svg |
||||||
|
[license-link2]: https://git.nextgraph.org/NextGraph/nextgraph-rs/src/branch/master/LICENSE-MIT |
@ -0,0 +1,55 @@ |
|||||||
|
# ng-repo |
||||||
|
|
||||||
|
![MSRV][rustc-image] |
||||||
|
[![Apache 2.0 Licensed][license-image]][license-link] |
||||||
|
[![MIT Licensed][license-image2]][license-link2] |
||||||
|
|
||||||
|
Repository library of NextGraph |
||||||
|
|
||||||
|
This repository is in active development at [https://git.nextgraph.org/NextGraph/nextgraph-rs](https://git.nextgraph.org/NextGraph/nextgraph-rs), a Gitea instance. For bug reports, issues, merge requests, and in order to join the dev team, please visit the link above and create an account (you can do so with a github account). The [github repo](https://github.com/nextgraph-org/nextgraph-rs) is just a read-only mirror that does not accept issues. |
||||||
|
|
||||||
|
## NextGraph |
||||||
|
|
||||||
|
> NextGraph brings about the convergence between P2P and Semantic Web technologies, towards a decentralized, secure and privacy-preserving cloud, based on CRDTs. |
||||||
|
> |
||||||
|
> This open source ecosystem provides solutions for end-users and software developers alike, wishing to use or create **decentralized** apps featuring: **live collaboration** on rich-text documents, peer to peer communication with **end-to-end encryption**, offline-first, **local-first**, portable and interoperable data, total ownership of data and software, security and privacy. Centered on repositories containing **semantic data** (RDF), **rich text**, and structured data formats like **JSON**, synced between peers belonging to permissioned groups of users, it offers strong eventual consistency, thanks to the use of **CRDTs**. Documents can be linked together, signed, shared securely, queried using the **SPARQL** language and organized into sites and containers. |
||||||
|
> |
||||||
|
> More info here [https://nextgraph.org](https://nextgraph.org) |
||||||
|
|
||||||
|
## Support |
||||||
|
|
||||||
|
Documentation can be found here [https://docs.nextgraph.org](https://docs.nextgraph.org) |
||||||
|
|
||||||
|
And our community forum where you can ask questions is here [https://forum.nextgraph.org](https://forum.nextgraph.org) |
||||||
|
|
||||||
|
## How to use the library |
||||||
|
|
||||||
|
NextGraph is not ready yet. You can subscribe to [our newsletter](https://list.nextgraph.org/subscription/form) to get updates, and support us with a [donation](https://nextgraph.org/donate/). |
||||||
|
|
||||||
|
This library is used internally by [ngd](../ngd/README.md), [ngcli](../ngcli/README.md), [ng-app](../ng-app/README.md) and by [nextgraph, the Rust client library](../nextgraph/README.md) which you should be using instead. It is not meant to be used by other programs as-is. |
||||||
|
|
||||||
|
## License |
||||||
|
|
||||||
|
Licensed under either of |
||||||
|
|
||||||
|
- Apache License, Version 2.0 ([LICENSE-APACHE2](LICENSE-APACHE2) or http://www.apache.org/licenses/LICENSE-2.0) |
||||||
|
- MIT license ([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT) |
||||||
|
at your option. |
||||||
|
|
||||||
|
`SPDX-License-Identifier: Apache-2.0 OR MIT` |
||||||
|
|
||||||
|
### Contributions license |
||||||
|
|
||||||
|
Unless you explicitly state otherwise, any contribution intentionally submitted |
||||||
|
for inclusion in the work by you shall be dual licensed as below, without any |
||||||
|
additional terms or conditions. |
||||||
|
|
||||||
|
--- |
||||||
|
|
||||||
|
NextGraph received funding through the [NGI Assure Fund](https://nlnet.nl/project/NextGraph/index.html), a fund established by [NLnet](https://nlnet.nl/) with financial support from the European Commission's [Next Generation Internet](https://ngi.eu/) programme, under the aegis of DG Communications Networks, Content and Technology under grant agreement No 957073. |
||||||
|
|
||||||
|
[rustc-image]: https://img.shields.io/badge/rustc-1.64+-blue.svg |
||||||
|
[license-image]: https://img.shields.io/badge/license-Apache2.0-blue.svg |
||||||
|
[license-link]: https://git.nextgraph.org/NextGraph/nextgraph-rs/raw/branch/master/LICENSE-APACHE2 |
||||||
|
[license-image2]: https://img.shields.io/badge/license-MIT-blue.svg |
||||||
|
[license-link2]: https://git.nextgraph.org/NextGraph/nextgraph-rs/src/branch/master/LICENSE-MIT |
@ -1,7 +1,5 @@ |
|||||||
// Copyright (c) 2022-2024 Niko Bonnieure, Par le Peuple, NextGraph.org developers
|
// Copyright (c) 2022-2024 Niko Bonnieure, Par le Peuple, NextGraph.org developers
|
||||||
// All rights reserved.
|
// All rights reserved.
|
||||||
// This code is partly derived from work written by TG x Thoth from P2Pcollab.
|
|
||||||
// Copyright 2022 TG x Thoth
|
|
||||||
// Licensed under the Apache License, Version 2.0
|
// Licensed under the Apache License, Version 2.0
|
||||||
// <LICENSE-APACHE2 or http://www.apache.org/licenses/LICENSE-2.0>
|
// <LICENSE-APACHE2 or http://www.apache.org/licenses/LICENSE-2.0>
|
||||||
// or the MIT license <LICENSE-MIT or http://opensource.org/licenses/MIT>,
|
// or the MIT license <LICENSE-MIT or http://opensource.org/licenses/MIT>,
|
@ -0,0 +1,119 @@ |
|||||||
|
// Copyright (c) 2022-2024 Niko Bonnieure, Par le Peuple, NextGraph.org developers
|
||||||
|
// Licensed under the Apache License, Version 2.0
|
||||||
|
// <LICENSE-APACHE2 or http://www.apache.org/licenses/LICENSE-2.0>
|
||||||
|
// or the MIT license <LICENSE-MIT or http://opensource.org/licenses/MIT>,
|
||||||
|
// at your option. All files in the project carrying such
|
||||||
|
// notice may not be copied, modified, or distributed except
|
||||||
|
// according to those terms.
|
||||||
|
|
||||||
|
//! Event
|
||||||
|
|
||||||
|
use crate::errors::*; |
||||||
|
use crate::object::*; |
||||||
|
use crate::store::*; |
||||||
|
use crate::types::*; |
||||||
|
use crate::utils::*; |
||||||
|
use core::fmt; |
||||||
|
|
||||||
|
impl fmt::Display for Event { |
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
||||||
|
match self { |
||||||
|
Self::V0(v0) => { |
||||||
|
writeln!(f, "V0")?; |
||||||
|
writeln!(f, "topic_sig: {}", v0.topic_sig)?; |
||||||
|
writeln!(f, "peer_sig: {}", v0.peer_sig)?; |
||||||
|
write!(f, "content: {}", v0.content)?; |
||||||
|
Ok(()) |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
impl fmt::Display for EventContentV0 { |
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
||||||
|
writeln!(f, "V0")?; |
||||||
|
writeln!(f, "topic: {}", self.topic)?; |
||||||
|
writeln!(f, "publisher: {}", self.publisher)?; |
||||||
|
writeln!(f, "seq: {}", self.seq)?; |
||||||
|
writeln!(f, "blocks: {}", self.blocks.len())?; |
||||||
|
let mut i = 0; |
||||||
|
for block in &self.blocks { |
||||||
|
writeln!(f, "========== {:03}: {}", i, block.id())?; |
||||||
|
i += 1; |
||||||
|
} |
||||||
|
writeln!(f, "file ids: {}", self.file_ids.len())?; |
||||||
|
let mut i = 0; |
||||||
|
for file in &self.file_ids { |
||||||
|
writeln!(f, "========== {:03}: {}", i, file)?; |
||||||
|
i += 1; |
||||||
|
} |
||||||
|
writeln!(f, "key: {:?}", self.key)?; |
||||||
|
Ok(()) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
impl Event { |
||||||
|
pub fn new<'a>( |
||||||
|
publisher: &PrivKey, |
||||||
|
seq: &mut u64, |
||||||
|
commit: &Commit, |
||||||
|
additional_blocks: &Vec<BlockId>, |
||||||
|
topic_id: TopicId, |
||||||
|
branch_read_cap_secret: ReadCapSecret, |
||||||
|
topic_priv_key: &BranchWriteCapSecret, |
||||||
|
storage: &'a Box<dyn RepoStore + Send + Sync + 'a>, |
||||||
|
) -> Result<Event, NgError> { |
||||||
|
Ok(Event::V0(EventV0::new( |
||||||
|
publisher, |
||||||
|
seq, |
||||||
|
commit, |
||||||
|
additional_blocks, |
||||||
|
topic_id, |
||||||
|
branch_read_cap_secret, |
||||||
|
topic_priv_key, |
||||||
|
storage, |
||||||
|
)?)) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
impl EventV0 { |
||||||
|
pub fn new<'a>( |
||||||
|
publisher: &PrivKey, |
||||||
|
seq: &mut u64, |
||||||
|
commit: &Commit, |
||||||
|
additional_blocks: &Vec<BlockId>, |
||||||
|
topic_id: TopicId, |
||||||
|
branch_read_cap_secret: ReadCapSecret, |
||||||
|
topic_priv_key: &BranchWriteCapSecret, |
||||||
|
storage: &'a Box<dyn RepoStore + Send + Sync + 'a>, |
||||||
|
) -> Result<EventV0, NgError> { |
||||||
|
let mut blocks = vec![]; |
||||||
|
for bid in commit.blocks().iter() { |
||||||
|
blocks.push(storage.get(bid)?); |
||||||
|
} |
||||||
|
for bid in additional_blocks.iter() { |
||||||
|
blocks.push(storage.get(bid)?); |
||||||
|
} |
||||||
|
(*seq) += 1; |
||||||
|
let publisher_pubkey = publisher.to_pub(); |
||||||
|
let event_content = EventContentV0 { |
||||||
|
topic: topic_id, |
||||||
|
publisher: PeerId::Forwarded(publisher_pubkey), |
||||||
|
seq: *seq, |
||||||
|
blocks, |
||||||
|
file_ids: commit |
||||||
|
.header() |
||||||
|
.as_ref() |
||||||
|
.map_or_else(|| vec![], |h| h.files().to_vec()), |
||||||
|
key: vec![], // TODO
|
||||||
|
}; |
||||||
|
let event_content_ser = serde_bare::to_vec(&event_content).unwrap(); |
||||||
|
let topic_sig = sign(topic_priv_key, &topic_id, &event_content_ser)?; |
||||||
|
let peer_sig = sign(publisher, &publisher_pubkey, &event_content_ser)?; |
||||||
|
Ok(EventV0 { |
||||||
|
content: event_content, |
||||||
|
topic_sig, |
||||||
|
peer_sig, |
||||||
|
}) |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,574 @@ |
|||||||
|
// Copyright (c) 2022-2024 Niko Bonnieure, Par le Peuple, NextGraph.org developers
|
||||||
|
// All rights reserved.
|
||||||
|
// Licensed under the Apache License, Version 2.0
|
||||||
|
// <LICENSE-APACHE2 or http://www.apache.org/licenses/LICENSE-2.0>
|
||||||
|
// or the MIT license <LICENSE-MIT or http://opensource.org/licenses/MIT>,
|
||||||
|
// at your option. All files in the project carrying such
|
||||||
|
// notice may not be copied, modified, or distributed except
|
||||||
|
// according to those terms.
|
||||||
|
|
||||||
|
//! Repository serde implementation and in memory helper
|
||||||
|
|
||||||
|
use crate::errors::*; |
||||||
|
use crate::event::*; |
||||||
|
use crate::log::*; |
||||||
|
use crate::object::Object; |
||||||
|
use crate::store::*; |
||||||
|
use crate::types::*; |
||||||
|
use crate::utils::generate_keypair; |
||||||
|
use crate::utils::sign; |
||||||
|
use core::fmt; |
||||||
|
use rand::prelude::*; |
||||||
|
|
||||||
|
use std::collections::HashMap; |
||||||
|
use std::collections::HashSet; |
||||||
|
|
||||||
|
use threshold_crypto::{SecretKeySet, SecretKeyShare}; |
||||||
|
|
||||||
|
impl RepositoryV0 { |
||||||
|
pub fn new(id: &PubKey, metadata: &Vec<u8>) -> RepositoryV0 { |
||||||
|
RepositoryV0 { |
||||||
|
id: id.clone(), |
||||||
|
metadata: metadata.clone(), |
||||||
|
verification_program: vec![], |
||||||
|
creator: None, |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
impl Repository { |
||||||
|
pub fn new(id: &PubKey, metadata: &Vec<u8>) -> Repository { |
||||||
|
Repository::V0(RepositoryV0::new(id, metadata)) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
#[derive(Debug)] |
||||||
|
pub struct UserInfo { |
||||||
|
/// list of permissions granted to user, with optional metadata
|
||||||
|
pub permissions: HashMap<PermissionV0, Vec<u8>>, |
||||||
|
pub id: UserId, |
||||||
|
} |
||||||
|
|
||||||
|
impl UserInfo { |
||||||
|
pub fn has_any_perm(&self, perms: &HashSet<PermissionV0>) -> Result<(), NgError> { |
||||||
|
//log_debug!("perms {:?}", perms);
|
||||||
|
if self.has_perm(&PermissionV0::Owner).is_ok() { |
||||||
|
return Ok(()); |
||||||
|
} |
||||||
|
let is_admin = self.has_perm(&PermissionV0::Admin).is_ok(); |
||||||
|
//log_debug!("is_admin {}", is_admin);
|
||||||
|
//is_delegated_by_admin
|
||||||
|
let has_perms: HashSet<&PermissionV0> = self.permissions.keys().collect(); |
||||||
|
//log_debug!("has_perms {:?}", has_perms);
|
||||||
|
for perm in perms { |
||||||
|
if is_admin && perm.is_delegated_by_admin() || has_perms.contains(perm) { |
||||||
|
return Ok(()); |
||||||
|
} |
||||||
|
} |
||||||
|
// if has_perms.intersection(perms).count() > 0 {
|
||||||
|
// Ok(())
|
||||||
|
// } else {
|
||||||
|
Err(NgError::PermissionDenied) |
||||||
|
} |
||||||
|
pub fn has_perm(&self, perm: &PermissionV0) -> Result<&Vec<u8>, NgError> { |
||||||
|
self.permissions.get(perm).ok_or(NgError::PermissionDenied) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/// In memory Repository representation. With helper functions that access the underlying UserStore and keeps proxy of the values
|
||||||
|
pub struct Repo<'a> { |
||||||
|
/// Repo definition
|
||||||
|
pub repo_def: Repository, |
||||||
|
|
||||||
|
pub signer: Option<SignerCap>, |
||||||
|
|
||||||
|
pub members: HashMap<Digest, UserInfo>, |
||||||
|
|
||||||
|
storage: &'a Box<dyn RepoStore + Send + Sync + 'a>, |
||||||
|
} |
||||||
|
|
||||||
|
impl<'a> fmt::Display for Repo<'a> { |
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
||||||
|
writeln!(f, "====== Repo ======")?; |
||||||
|
|
||||||
|
write!(f, "== repo_def: {}", self.repo_def)?; |
||||||
|
|
||||||
|
if self.signer.is_some() { |
||||||
|
writeln!(f, "== signer: {:?}", self.signer)?; |
||||||
|
} |
||||||
|
|
||||||
|
writeln!(f, "== members: {:?}", self.members)?; |
||||||
|
|
||||||
|
Ok(()) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
impl<'a> Repo<'a> { |
||||||
|
/// returns the Repo and the last seq_num of the peer
|
||||||
|
pub fn new_default( |
||||||
|
creator: &UserId, |
||||||
|
creator_priv_key: &PrivKey, |
||||||
|
publisher_peer: &PrivKey, |
||||||
|
peer_last_seq_num: &mut u64, |
||||||
|
store_repo: &StoreRepo, |
||||||
|
store_secret: &ReadCapSecret, |
||||||
|
storage: &'a Box<dyn RepoStore + Send + Sync + 'a>, |
||||||
|
) -> Result<(Self, Vec<Event>), NgError> { |
||||||
|
let mut events = Vec::with_capacity(6); |
||||||
|
|
||||||
|
// creating the Repository commit
|
||||||
|
|
||||||
|
let (repo_priv_key, repo_pub_key) = generate_keypair(); |
||||||
|
|
||||||
|
//let overlay = store_repo.overlay_id_for_read_purpose();
|
||||||
|
|
||||||
|
let repository = Repository::V0(RepositoryV0 { |
||||||
|
id: repo_pub_key, |
||||||
|
verification_program: vec![], |
||||||
|
creator: None, |
||||||
|
metadata: vec![], |
||||||
|
}); |
||||||
|
|
||||||
|
let repository_commit_body = CommitBody::V0(CommitBodyV0::Repository(repository.clone())); |
||||||
|
|
||||||
|
let repository_commit = Commit::new_with_body_acks_deps_and_save( |
||||||
|
&repo_priv_key, |
||||||
|
&repo_pub_key, |
||||||
|
repo_pub_key, |
||||||
|
QuorumType::NoSigning, |
||||||
|
vec![], |
||||||
|
vec![], |
||||||
|
repository_commit_body, |
||||||
|
&store_repo, |
||||||
|
&store_secret, |
||||||
|
storage, |
||||||
|
)?; |
||||||
|
|
||||||
|
log_debug!("REPOSITORY COMMIT {}", repository_commit); |
||||||
|
|
||||||
|
let repository_commit_ref = repository_commit.reference().unwrap(); |
||||||
|
|
||||||
|
let (topic_priv_key, topic_pub_key) = generate_keypair(); |
||||||
|
|
||||||
|
// creating the RootBranch commit, acks to Repository commit
|
||||||
|
|
||||||
|
let repo_write_cap_secret = SymKey::random(); |
||||||
|
|
||||||
|
let root_branch_commit_body = |
||||||
|
CommitBody::V0(CommitBodyV0::RootBranch(RootBranch::V0(RootBranchV0 { |
||||||
|
id: repo_pub_key, |
||||||
|
repo: repository_commit_ref.clone(), |
||||||
|
store: store_repo.into(), |
||||||
|
store_sig: None, //TODO: the store signature
|
||||||
|
topic: topic_pub_key, |
||||||
|
topic_privkey: Branch::encrypt_topic_priv_key( |
||||||
|
&topic_priv_key, |
||||||
|
topic_pub_key, |
||||||
|
repo_pub_key, |
||||||
|
&repo_write_cap_secret, |
||||||
|
), |
||||||
|
inherit_perms_users_and_quorum_from_store: None, |
||||||
|
quorum: None, |
||||||
|
reconciliation_interval: RelTime::None, |
||||||
|
owners: vec![creator.clone()], |
||||||
|
metadata: vec![], |
||||||
|
}))); |
||||||
|
|
||||||
|
let root_branch_commit = Commit::new_with_body_acks_deps_and_save( |
||||||
|
&repo_priv_key, |
||||||
|
&repo_pub_key, |
||||||
|
repo_pub_key, |
||||||
|
QuorumType::NoSigning, |
||||||
|
vec![], |
||||||
|
vec![repository_commit_ref.clone()], |
||||||
|
root_branch_commit_body, |
||||||
|
&store_repo, |
||||||
|
&store_secret, |
||||||
|
storage, |
||||||
|
)?; |
||||||
|
|
||||||
|
log_debug!("ROOT_BRANCH COMMIT {}", root_branch_commit); |
||||||
|
|
||||||
|
// adding the 2 events for the Repository and Rootbranch commits
|
||||||
|
|
||||||
|
//peer_last_seq_num += 1;
|
||||||
|
events.push(Event::new( |
||||||
|
publisher_peer, |
||||||
|
peer_last_seq_num, |
||||||
|
&repository_commit, |
||||||
|
&vec![], |
||||||
|
topic_pub_key, |
||||||
|
root_branch_commit.key().unwrap(), |
||||||
|
&topic_priv_key, |
||||||
|
storage, |
||||||
|
)?); |
||||||
|
|
||||||
|
//peer_last_seq_num += 1;
|
||||||
|
events.push(Event::new( |
||||||
|
publisher_peer, |
||||||
|
peer_last_seq_num, |
||||||
|
&root_branch_commit, |
||||||
|
&vec![], |
||||||
|
topic_pub_key, |
||||||
|
root_branch_commit.key().unwrap(), |
||||||
|
&topic_priv_key, |
||||||
|
storage, |
||||||
|
)?); |
||||||
|
|
||||||
|
// creating the main branch
|
||||||
|
|
||||||
|
let (main_branch_priv_key, main_branch_pub_key) = generate_keypair(); |
||||||
|
|
||||||
|
let (main_branch_topic_priv_key, main_branch_topic_pub_key) = generate_keypair(); |
||||||
|
|
||||||
|
let main_branch_commit_body = CommitBody::V0(CommitBodyV0::Branch(Branch::V0(BranchV0 { |
||||||
|
id: main_branch_pub_key, |
||||||
|
repo: repository_commit_ref.clone(), |
||||||
|
root_branch_readcap_id: root_branch_commit.id().unwrap(), |
||||||
|
topic: main_branch_topic_pub_key, |
||||||
|
topic_privkey: Branch::encrypt_topic_priv_key( |
||||||
|
&main_branch_topic_priv_key, |
||||||
|
main_branch_topic_pub_key, |
||||||
|
main_branch_pub_key, |
||||||
|
&repo_write_cap_secret, |
||||||
|
), |
||||||
|
metadata: vec![], |
||||||
|
}))); |
||||||
|
|
||||||
|
let main_branch_commit = Commit::new_with_body_acks_deps_and_save( |
||||||
|
&main_branch_priv_key, |
||||||
|
&main_branch_pub_key, |
||||||
|
main_branch_pub_key, |
||||||
|
QuorumType::NoSigning, |
||||||
|
vec![], |
||||||
|
vec![], |
||||||
|
main_branch_commit_body, |
||||||
|
&store_repo, |
||||||
|
&store_secret, |
||||||
|
storage, |
||||||
|
)?; |
||||||
|
|
||||||
|
log_debug!("MAIN BRANCH COMMIT {}", main_branch_commit); |
||||||
|
|
||||||
|
// adding the event for the Branch commit
|
||||||
|
|
||||||
|
// peer_last_seq_num += 1;
|
||||||
|
events.push(Event::new( |
||||||
|
publisher_peer, |
||||||
|
peer_last_seq_num, |
||||||
|
&main_branch_commit, |
||||||
|
&vec![], |
||||||
|
main_branch_topic_pub_key, |
||||||
|
main_branch_commit.key().unwrap(), |
||||||
|
&main_branch_topic_priv_key, |
||||||
|
storage, |
||||||
|
)?); |
||||||
|
|
||||||
|
// creating the AddBranch commit (on root_branch), deps to the RootBranch commit
|
||||||
|
// author is the owner
|
||||||
|
|
||||||
|
let add_branch_commit_body = |
||||||
|
CommitBody::V0(CommitBodyV0::AddBranch(AddBranch::V0(AddBranchV0 { |
||||||
|
branch_type: BranchType::Main, |
||||||
|
topic_id: main_branch_topic_pub_key, |
||||||
|
branch_read_cap: main_branch_commit.reference().unwrap(), |
||||||
|
}))); |
||||||
|
|
||||||
|
let add_branch_commit = Commit::new_with_body_acks_deps_and_save( |
||||||
|
creator_priv_key, |
||||||
|
creator, |
||||||
|
repo_pub_key, |
||||||
|
QuorumType::Owners, |
||||||
|
vec![root_branch_commit.reference().unwrap()], |
||||||
|
vec![], |
||||||
|
add_branch_commit_body, |
||||||
|
&store_repo, |
||||||
|
&store_secret, |
||||||
|
storage, |
||||||
|
)?; |
||||||
|
|
||||||
|
log_debug!("ADD_BRANCH COMMIT {}", add_branch_commit); |
||||||
|
|
||||||
|
// TODO: optional AddMember and AddPermission, that should be added as deps to the SynSignature below (and to the commits of the SignatureContent)
|
||||||
|
// using the creator as author (and incrementing their peer's seq_num)
|
||||||
|
|
||||||
|
// preparing the threshold keys for the unique owner
|
||||||
|
let mut rng = rand::thread_rng(); |
||||||
|
let sk_set = SecretKeySet::random(0, &mut rng); |
||||||
|
let pk_set = sk_set.public_keys(); |
||||||
|
|
||||||
|
let sk_share = sk_set.secret_key_share(0); |
||||||
|
|
||||||
|
// creating signature for RootBranch, AddBranch and Branch commits
|
||||||
|
// signed with owner threshold signature (threshold = 0)
|
||||||
|
|
||||||
|
let signature_content = SignatureContent::V0(SignatureContentV0 { |
||||||
|
commits: vec![ |
||||||
|
root_branch_commit.id().unwrap(), |
||||||
|
add_branch_commit.id().unwrap(), |
||||||
|
main_branch_commit.id().unwrap(), |
||||||
|
], |
||||||
|
}); |
||||||
|
|
||||||
|
let signature_content_ser = serde_bare::to_vec(&signature_content).unwrap(); |
||||||
|
let sig_share = sk_share.sign(signature_content_ser); |
||||||
|
let sig = pk_set |
||||||
|
.combine_signatures([(0, &sig_share)]) |
||||||
|
.map_err(|_| NgError::IncompleteSignature)?; |
||||||
|
|
||||||
|
let threshold_sig = ThresholdSignatureV0::Owners((sig)); |
||||||
|
|
||||||
|
// creating root certificate of the repo
|
||||||
|
|
||||||
|
let cert_content = CertificateContentV0 { |
||||||
|
previous: repository_commit_ref, |
||||||
|
readcap_id: root_branch_commit.id().unwrap(), |
||||||
|
owners_pk_set: pk_set.public_key(), |
||||||
|
orders_pk_sets: OrdersPublicKeySetsV0::None, |
||||||
|
}; |
||||||
|
|
||||||
|
// signing the root certificate
|
||||||
|
let cert_content_ser = serde_bare::to_vec(&cert_content).unwrap(); |
||||||
|
let sig = sign(&repo_priv_key, &repo_pub_key, &cert_content_ser)?; |
||||||
|
let cert_sig = CertificateSignatureV0::Repo(sig); |
||||||
|
|
||||||
|
let cert = Certificate::V0(CertificateV0 { |
||||||
|
content: cert_content, |
||||||
|
sig: cert_sig, |
||||||
|
}); |
||||||
|
// saving the certificate
|
||||||
|
let cert_object = Object::new( |
||||||
|
ObjectContent::V0(ObjectContentV0::Certificate(cert)), |
||||||
|
None, |
||||||
|
0, |
||||||
|
&store_repo, |
||||||
|
&store_secret, |
||||||
|
); |
||||||
|
let mut cert_obj_blocks = cert_object.save(storage)?; |
||||||
|
|
||||||
|
// finally getting the signature:
|
||||||
|
|
||||||
|
let signature = Signature::V0(SignatureV0 { |
||||||
|
content: signature_content, |
||||||
|
threshold_sig, |
||||||
|
certificate_ref: cert_object.reference().unwrap(), |
||||||
|
}); |
||||||
|
|
||||||
|
// saving the signature
|
||||||
|
let sig_object = Object::new( |
||||||
|
ObjectContent::V0(ObjectContentV0::Signature(signature)), |
||||||
|
None, |
||||||
|
0, |
||||||
|
&store_repo, |
||||||
|
&store_secret, |
||||||
|
); |
||||||
|
let mut sig_obj_blocks = sig_object.save(storage)?; |
||||||
|
|
||||||
|
// keeping the Secret Key Share of the owner
|
||||||
|
let signer_cap = SignerCap { |
||||||
|
repo: repo_pub_key, |
||||||
|
epoch: root_branch_commit.id().unwrap(), |
||||||
|
owner: Some(threshold_crypto::serde_impl::SerdeSecret(sk_share)), |
||||||
|
total_order: None, |
||||||
|
partial_order: None, |
||||||
|
}; |
||||||
|
|
||||||
|
let sync_signature = SyncSignature::V0(sig_object.reference().unwrap()); |
||||||
|
|
||||||
|
// creating the SyncSignature for the root_branch with deps to the AddBranch and acks to the RootBranch commit as it is its direct causal future.
|
||||||
|
let sync_sig_commit_body = CommitBody::V0(CommitBodyV0::SyncSignature(sync_signature)); |
||||||
|
|
||||||
|
let sync_sig_on_root_branch_commit = Commit::new_with_body_acks_deps_and_save( |
||||||
|
creator_priv_key, |
||||||
|
creator, |
||||||
|
repo_pub_key, |
||||||
|
QuorumType::IamTheSignature, |
||||||
|
vec![add_branch_commit.reference().unwrap()], |
||||||
|
vec![root_branch_commit.reference().unwrap()], |
||||||
|
sync_sig_commit_body.clone(), |
||||||
|
&store_repo, |
||||||
|
&store_secret, |
||||||
|
storage, |
||||||
|
)?; |
||||||
|
|
||||||
|
// adding the event for the sync_sig_on_root_branch_commit
|
||||||
|
|
||||||
|
let mut additional_blocks = Vec::with_capacity( |
||||||
|
cert_obj_blocks.len() + sig_obj_blocks.len() + add_branch_commit.blocks().len(), |
||||||
|
); |
||||||
|
additional_blocks.extend(cert_obj_blocks.iter()); |
||||||
|
additional_blocks.extend(sig_obj_blocks.iter()); |
||||||
|
additional_blocks.extend(add_branch_commit.blocks().iter()); |
||||||
|
|
||||||
|
//peer_last_seq_num += 1;
|
||||||
|
events.push(Event::new( |
||||||
|
publisher_peer, |
||||||
|
peer_last_seq_num, |
||||||
|
&sync_sig_on_root_branch_commit, |
||||||
|
&additional_blocks, |
||||||
|
topic_pub_key, |
||||||
|
root_branch_commit.key().unwrap(), |
||||||
|
&topic_priv_key, |
||||||
|
storage, |
||||||
|
)?); |
||||||
|
|
||||||
|
// creating the SyncSignature for the main branch with deps to the Branch commit and acks also to this commit as it is its direct causal future.
|
||||||
|
|
||||||
|
let sync_sig_on_main_branch_commit = Commit::new_with_body_acks_deps_and_save( |
||||||
|
creator_priv_key, |
||||||
|
creator, |
||||||
|
main_branch_pub_key, |
||||||
|
QuorumType::IamTheSignature, |
||||||
|
vec![main_branch_commit.reference().unwrap()], |
||||||
|
vec![main_branch_commit.reference().unwrap()], |
||||||
|
sync_sig_commit_body, |
||||||
|
&store_repo, |
||||||
|
&store_secret, |
||||||
|
storage, |
||||||
|
)?; |
||||||
|
|
||||||
|
// adding the event for the sync_sig_on_main_branch_commit
|
||||||
|
|
||||||
|
let mut additional_blocks = |
||||||
|
Vec::with_capacity(cert_obj_blocks.len() + sig_obj_blocks.len()); |
||||||
|
additional_blocks.append(&mut cert_obj_blocks); |
||||||
|
additional_blocks.append(&mut sig_obj_blocks); |
||||||
|
|
||||||
|
// peer_last_seq_num += 1;
|
||||||
|
events.push(Event::new( |
||||||
|
publisher_peer, |
||||||
|
peer_last_seq_num, |
||||||
|
&sync_sig_on_main_branch_commit, |
||||||
|
&additional_blocks, |
||||||
|
main_branch_topic_pub_key, |
||||||
|
main_branch_commit.key().unwrap(), |
||||||
|
&main_branch_topic_priv_key, |
||||||
|
storage, |
||||||
|
)?); |
||||||
|
|
||||||
|
// TODO: add the CertificateRefresh event on main branch
|
||||||
|
|
||||||
|
// += 1;
|
||||||
|
|
||||||
|
// preparing the Repo
|
||||||
|
|
||||||
|
let repo = Repo { |
||||||
|
repo_def: repository, |
||||||
|
signer: Some(signer_cap), |
||||||
|
members: HashMap::new(), |
||||||
|
storage, |
||||||
|
}; |
||||||
|
|
||||||
|
Ok((repo, events)) |
||||||
|
} |
||||||
|
|
||||||
|
pub fn new_with_member( |
||||||
|
id: &PubKey, |
||||||
|
member: &UserId, |
||||||
|
perms: &[PermissionV0], |
||||||
|
overlay: OverlayId, |
||||||
|
storage: &'a Box<dyn RepoStore + Send + Sync + 'a>, |
||||||
|
) -> Self { |
||||||
|
let mut members = HashMap::new(); |
||||||
|
let permissions = HashMap::from_iter( |
||||||
|
perms |
||||||
|
.iter() |
||||||
|
.map(|p| (*p, vec![])) |
||||||
|
.collect::<Vec<(PermissionV0, Vec<u8>)>>() |
||||||
|
.iter() |
||||||
|
.cloned(), |
||||||
|
); |
||||||
|
members.insert( |
||||||
|
CommitContent::author_digest(member, overlay), |
||||||
|
UserInfo { |
||||||
|
id: *member, |
||||||
|
permissions, |
||||||
|
}, |
||||||
|
); |
||||||
|
Self { |
||||||
|
repo_def: Repository::new(id, &vec![]), |
||||||
|
members, |
||||||
|
storage, |
||||||
|
signer: None, |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
pub fn verify_permission(&self, commit: &Commit) -> Result<(), NgError> { |
||||||
|
let content_author = commit.content_v0().author; |
||||||
|
let body = commit.load_body(&self.storage)?; |
||||||
|
match self.members.get(&content_author) { |
||||||
|
Some(info) => return info.has_any_perm(&body.required_permission()), |
||||||
|
None => {} |
||||||
|
} |
||||||
|
Err(NgError::PermissionDenied) |
||||||
|
} |
||||||
|
|
||||||
|
pub fn member_pubkey(&self, hash: &Digest) -> Result<UserId, NgError> { |
||||||
|
match self.members.get(hash) { |
||||||
|
Some(user_info) => Ok(user_info.id), |
||||||
|
None => Err(NgError::NotFound), |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
pub fn get_storage(&self) -> &Box<dyn RepoStore + Send + Sync + 'a> { |
||||||
|
self.storage |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
#[cfg(test)] |
||||||
|
mod test { |
||||||
|
|
||||||
|
use crate::object::*; |
||||||
|
use crate::repo::*; |
||||||
|
|
||||||
|
struct Test<'a> { |
||||||
|
storage: Box<dyn RepoStore + Send + Sync + 'a>, |
||||||
|
} |
||||||
|
|
||||||
|
impl<'a> Test<'a> { |
||||||
|
fn storage(s: impl RepoStore + 'a) -> Self { |
||||||
|
Test { |
||||||
|
storage: Box::new(s), |
||||||
|
} |
||||||
|
} |
||||||
|
fn s(&self) -> &Box<dyn RepoStore + Send + Sync + 'a> { |
||||||
|
&self.storage |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
#[test] |
||||||
|
pub fn test_new_repo_default() { |
||||||
|
let (creator_priv_key, creator_pub_key) = generate_keypair(); |
||||||
|
|
||||||
|
let (publisher_privkey, publisher_pubkey) = generate_keypair(); |
||||||
|
let publisher_peer = PeerId::Forwarded(publisher_pubkey); |
||||||
|
|
||||||
|
let mut peer_last_seq_num = 10; |
||||||
|
|
||||||
|
let (store_repo, store_secret) = StoreRepo::dummy_public_v0(); |
||||||
|
let hashmap_storage = HashMapRepoStore::new(); |
||||||
|
let t = Test::storage(hashmap_storage); |
||||||
|
|
||||||
|
let (repo, events) = Repo::new_default( |
||||||
|
&creator_pub_key, |
||||||
|
&creator_priv_key, |
||||||
|
&publisher_privkey, |
||||||
|
&mut peer_last_seq_num, |
||||||
|
&store_repo, |
||||||
|
&store_secret, |
||||||
|
t.s(), |
||||||
|
) |
||||||
|
.expect("new_default"); |
||||||
|
|
||||||
|
log_debug!("REPO OBJECT {}", repo); |
||||||
|
|
||||||
|
log_debug!("events: {}\n", events.len()); |
||||||
|
let mut i = 0; |
||||||
|
for e in events { |
||||||
|
log_debug!("========== EVENT {:03}: {}", i, e); |
||||||
|
i += 1; |
||||||
|
} |
||||||
|
|
||||||
|
assert_eq!(peer_last_seq_num, 15); |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,138 @@ |
|||||||
|
/* |
||||||
|
* Copyright (c) 2022-2024 Niko Bonnieure, Par le Peuple, NextGraph.org developers |
||||||
|
* All rights reserved. |
||||||
|
* Licensed under the Apache License, Version 2.0 |
||||||
|
* <LICENSE-APACHE2 or http://www.apache.org/licenses/LICENSE-2.0>
|
||||||
|
* or the MIT license <LICENSE-MIT or http://opensource.org/licenses/MIT>,
|
||||||
|
* at your option. All files in the project carrying such |
||||||
|
* notice may not be copied, modified, or distributed except |
||||||
|
* according to those terms. |
||||||
|
*/ |
||||||
|
|
||||||
|
use crate::errors::NgError; |
||||||
|
use crate::types::*; |
||||||
|
use crate::utils::{generate_keypair, sign, verify}; |
||||||
|
|
||||||
|
impl SiteV0 { |
||||||
|
pub fn get_individual_user_priv_key(&self) -> Option<PrivKey> { |
||||||
|
match &self.site_type { |
||||||
|
SiteType::Individual((priv_key, _)) => Some(priv_key.clone()), |
||||||
|
_ => None, |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
pub fn create_personal( |
||||||
|
user_priv_key: PrivKey, |
||||||
|
private_store_read_cap: ReadCap, |
||||||
|
) -> Result<Self, NgError> { |
||||||
|
let site_pubkey = user_priv_key.to_pub(); |
||||||
|
|
||||||
|
let (public_store_privkey, public_store_pubkey) = generate_keypair(); |
||||||
|
|
||||||
|
let (protected_store_privkey, protected_store_pubkey) = generate_keypair(); |
||||||
|
|
||||||
|
let (private_store_privkey, private_store_pubkey) = generate_keypair(); |
||||||
|
|
||||||
|
let public = SiteStore { |
||||||
|
id: public_store_pubkey, |
||||||
|
store_type: SiteStoreType::Public, |
||||||
|
}; |
||||||
|
|
||||||
|
let protected = SiteStore { |
||||||
|
id: protected_store_pubkey, |
||||||
|
store_type: SiteStoreType::Protected, |
||||||
|
}; |
||||||
|
|
||||||
|
let private = SiteStore { |
||||||
|
id: private_store_pubkey, |
||||||
|
store_type: SiteStoreType::Private, |
||||||
|
}; |
||||||
|
|
||||||
|
Ok(Self { |
||||||
|
site_type: SiteType::Individual((user_priv_key, private_store_read_cap)), |
||||||
|
id: site_pubkey, |
||||||
|
name: SiteName::Personal, |
||||||
|
public, |
||||||
|
protected, |
||||||
|
private, |
||||||
|
cores: vec![], |
||||||
|
bootstraps: vec![], |
||||||
|
}) |
||||||
|
} |
||||||
|
|
||||||
|
pub fn create_individual( |
||||||
|
name: String, |
||||||
|
user_priv_key: PrivKey, |
||||||
|
private_store_read_cap: ReadCap, |
||||||
|
) -> Result<Self, NgError> { |
||||||
|
let site_pubkey = user_priv_key.to_pub(); |
||||||
|
|
||||||
|
let (public_store_privkey, public_store_pubkey) = generate_keypair(); |
||||||
|
|
||||||
|
let (protected_store_privkey, protected_store_pubkey) = generate_keypair(); |
||||||
|
|
||||||
|
let (private_store_privkey, private_store_pubkey) = generate_keypair(); |
||||||
|
|
||||||
|
let public = SiteStore { |
||||||
|
id: public_store_pubkey, |
||||||
|
store_type: SiteStoreType::Public, |
||||||
|
}; |
||||||
|
|
||||||
|
let protected = SiteStore { |
||||||
|
id: protected_store_pubkey, |
||||||
|
store_type: SiteStoreType::Protected, |
||||||
|
}; |
||||||
|
|
||||||
|
let private = SiteStore { |
||||||
|
id: private_store_pubkey, |
||||||
|
store_type: SiteStoreType::Private, |
||||||
|
}; |
||||||
|
|
||||||
|
Ok(Self { |
||||||
|
site_type: SiteType::Individual((user_priv_key, private_store_read_cap)), |
||||||
|
id: site_pubkey, |
||||||
|
name: SiteName::Name(name), |
||||||
|
public, |
||||||
|
protected, |
||||||
|
private, |
||||||
|
cores: vec![], |
||||||
|
bootstraps: vec![], |
||||||
|
}) |
||||||
|
} |
||||||
|
|
||||||
|
pub fn create_org(name: String) -> Result<Self, NgError> { |
||||||
|
let (site_privkey, site_pubkey) = generate_keypair(); |
||||||
|
|
||||||
|
let (public_store_privkey, public_store_pubkey) = generate_keypair(); |
||||||
|
|
||||||
|
let (protected_store_privkey, protected_store_pubkey) = generate_keypair(); |
||||||
|
|
||||||
|
let (private_store_privkey, private_store_pubkey) = generate_keypair(); |
||||||
|
|
||||||
|
let public = SiteStore { |
||||||
|
id: public_store_pubkey, |
||||||
|
store_type: SiteStoreType::Public, |
||||||
|
}; |
||||||
|
|
||||||
|
let protected = SiteStore { |
||||||
|
id: protected_store_pubkey, |
||||||
|
store_type: SiteStoreType::Protected, |
||||||
|
}; |
||||||
|
|
||||||
|
let private = SiteStore { |
||||||
|
id: private_store_pubkey, |
||||||
|
store_type: SiteStoreType::Private, |
||||||
|
}; |
||||||
|
|
||||||
|
Ok(Self { |
||||||
|
site_type: SiteType::Org, |
||||||
|
id: site_pubkey, |
||||||
|
name: SiteName::Name(name), |
||||||
|
public, |
||||||
|
protected, |
||||||
|
private, |
||||||
|
cores: vec![], |
||||||
|
bootstraps: vec![], |
||||||
|
}) |
||||||
|
} |
||||||
|
} |
@ -1,7 +1,5 @@ |
|||||||
// Copyright (c) 2022-2024 Niko Bonnieure, Par le Peuple, NextGraph.org developers
|
// Copyright (c) 2022-2024 Niko Bonnieure, Par le Peuple, NextGraph.org developers
|
||||||
// All rights reserved.
|
// All rights reserved.
|
||||||
// This code is partly derived from work written by TG x Thoth from P2Pcollab.
|
|
||||||
// Copyright 2022 TG x Thoth
|
|
||||||
// Licensed under the Apache License, Version 2.0
|
// Licensed under the Apache License, Version 2.0
|
||||||
// <LICENSE-APACHE2 or http://www.apache.org/licenses/LICENSE-2.0>
|
// <LICENSE-APACHE2 or http://www.apache.org/licenses/LICENSE-2.0>
|
||||||
// or the MIT license <LICENSE-MIT or http://opensource.org/licenses/MIT>,
|
// or the MIT license <LICENSE-MIT or http://opensource.org/licenses/MIT>,
|
File diff suppressed because it is too large
Load Diff
Before Width: | Height: | Size: 29 KiB After Width: | Height: | Size: 29 KiB |
@ -0,0 +1,201 @@ |
|||||||
|
Apache License |
||||||
|
Version 2.0, January 2004 |
||||||
|
http://www.apache.org/licenses/ |
||||||
|
|
||||||
|
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION |
||||||
|
|
||||||
|
1. Definitions. |
||||||
|
|
||||||
|
"License" shall mean the terms and conditions for use, reproduction, |
||||||
|
and distribution as defined by Sections 1 through 9 of this document. |
||||||
|
|
||||||
|
"Licensor" shall mean the copyright owner or entity authorized by |
||||||
|
the copyright owner that is granting the License. |
||||||
|
|
||||||
|
"Legal Entity" shall mean the union of the acting entity and all |
||||||
|
other entities that control, are controlled by, or are under common |
||||||
|
control with that entity. For the purposes of this definition, |
||||||
|
"control" means (i) the power, direct or indirect, to cause the |
||||||
|
direction or management of such entity, whether by contract or |
||||||
|
otherwise, or (ii) ownership of fifty percent (50%) or more of the |
||||||
|
outstanding shares, or (iii) beneficial ownership of such entity. |
||||||
|
|
||||||
|
"You" (or "Your") shall mean an individual or Legal Entity |
||||||
|
exercising permissions granted by this License. |
||||||
|
|
||||||
|
"Source" form shall mean the preferred form for making modifications, |
||||||
|
including but not limited to software source code, documentation |
||||||
|
source, and configuration files. |
||||||
|
|
||||||
|
"Object" form shall mean any form resulting from mechanical |
||||||
|
transformation or translation of a Source form, including but |
||||||
|
not limited to compiled object code, generated documentation, |
||||||
|
and conversions to other media types. |
||||||
|
|
||||||
|
"Work" shall mean the work of authorship, whether in Source or |
||||||
|
Object form, made available under the License, as indicated by a |
||||||
|
copyright notice that is included in or attached to the work |
||||||
|
(an example is provided in the Appendix below). |
||||||
|
|
||||||
|
"Derivative Works" shall mean any work, whether in Source or Object |
||||||
|
form, that is based on (or derived from) the Work and for which the |
||||||
|
editorial revisions, annotations, elaborations, or other modifications |
||||||
|
represent, as a whole, an original work of authorship. For the purposes |
||||||
|
of this License, Derivative Works shall not include works that remain |
||||||
|
separable from, or merely link (or bind by name) to the interfaces of, |
||||||
|
the Work and Derivative Works thereof. |
||||||
|
|
||||||
|
"Contribution" shall mean any work of authorship, including |
||||||
|
the original version of the Work and any modifications or additions |
||||||
|
to that Work or Derivative Works thereof, that is intentionally |
||||||
|
submitted to Licensor for inclusion in the Work by the copyright owner |
||||||
|
or by an individual or Legal Entity authorized to submit on behalf of |
||||||
|
the copyright owner. For the purposes of this definition, "submitted" |
||||||
|
means any form of electronic, verbal, or written communication sent |
||||||
|
to the Licensor or its representatives, including but not limited to |
||||||
|
communication on electronic mailing lists, source code control systems, |
||||||
|
and issue tracking systems that are managed by, or on behalf of, the |
||||||
|
Licensor for the purpose of discussing and improving the Work, but |
||||||
|
excluding communication that is conspicuously marked or otherwise |
||||||
|
designated in writing by the copyright owner as "Not a Contribution." |
||||||
|
|
||||||
|
"Contributor" shall mean Licensor and any individual or Legal Entity |
||||||
|
on behalf of whom a Contribution has been received by Licensor and |
||||||
|
subsequently incorporated within the Work. |
||||||
|
|
||||||
|
2. Grant of Copyright License. Subject to the terms and conditions of |
||||||
|
this License, each Contributor hereby grants to You a perpetual, |
||||||
|
worldwide, non-exclusive, no-charge, royalty-free, irrevocable |
||||||
|
copyright license to reproduce, prepare Derivative Works of, |
||||||
|
publicly display, publicly perform, sublicense, and distribute the |
||||||
|
Work and such Derivative Works in Source or Object form. |
||||||
|
|
||||||
|
3. Grant of Patent License. Subject to the terms and conditions of |
||||||
|
this License, each Contributor hereby grants to You a perpetual, |
||||||
|
worldwide, non-exclusive, no-charge, royalty-free, irrevocable |
||||||
|
(except as stated in this section) patent license to make, have made, |
||||||
|
use, offer to sell, sell, import, and otherwise transfer the Work, |
||||||
|
where such license applies only to those patent claims licensable |
||||||
|
by such Contributor that are necessarily infringed by their |
||||||
|
Contribution(s) alone or by combination of their Contribution(s) |
||||||
|
with the Work to which such Contribution(s) was submitted. If You |
||||||
|
institute patent litigation against any entity (including a |
||||||
|
cross-claim or counterclaim in a lawsuit) alleging that the Work |
||||||
|
or a Contribution incorporated within the Work constitutes direct |
||||||
|
or contributory patent infringement, then any patent licenses |
||||||
|
granted to You under this License for that Work shall terminate |
||||||
|
as of the date such litigation is filed. |
||||||
|
|
||||||
|
4. Redistribution. You may reproduce and distribute copies of the |
||||||
|
Work or Derivative Works thereof in any medium, with or without |
||||||
|
modifications, and in Source or Object form, provided that You |
||||||
|
meet the following conditions: |
||||||
|
|
||||||
|
(a) You must give any other recipients of the Work or |
||||||
|
Derivative Works a copy of this License; and |
||||||
|
|
||||||
|
(b) You must cause any modified files to carry prominent notices |
||||||
|
stating that You changed the files; and |
||||||
|
|
||||||
|
(c) You must retain, in the Source form of any Derivative Works |
||||||
|
that You distribute, all copyright, patent, trademark, and |
||||||
|
attribution notices from the Source form of the Work, |
||||||
|
excluding those notices that do not pertain to any part of |
||||||
|
the Derivative Works; and |
||||||
|
|
||||||
|
(d) If the Work includes a "NOTICE" text file as part of its |
||||||
|
distribution, then any Derivative Works that You distribute must |
||||||
|
include a readable copy of the attribution notices contained |
||||||
|
within such NOTICE file, excluding those notices that do not |
||||||
|
pertain to any part of the Derivative Works, in at least one |
||||||
|
of the following places: within a NOTICE text file distributed |
||||||
|
as part of the Derivative Works; within the Source form or |
||||||
|
documentation, if provided along with the Derivative Works; or, |
||||||
|
within a display generated by the Derivative Works, if and |
||||||
|
wherever such third-party notices normally appear. The contents |
||||||
|
of the NOTICE file are for informational purposes only and |
||||||
|
do not modify the License. You may add Your own attribution |
||||||
|
notices within Derivative Works that You distribute, alongside |
||||||
|
or as an addendum to the NOTICE text from the Work, provided |
||||||
|
that such additional attribution notices cannot be construed |
||||||
|
as modifying the License. |
||||||
|
|
||||||
|
You may add Your own copyright statement to Your modifications and |
||||||
|
may provide additional or different license terms and conditions |
||||||
|
for use, reproduction, or distribution of Your modifications, or |
||||||
|
for any such Derivative Works as a whole, provided Your use, |
||||||
|
reproduction, and distribution of the Work otherwise complies with |
||||||
|
the conditions stated in this License. |
||||||
|
|
||||||
|
5. Submission of Contributions. Unless You explicitly state otherwise, |
||||||
|
any Contribution intentionally submitted for inclusion in the Work |
||||||
|
by You to the Licensor shall be under the terms and conditions of |
||||||
|
this License, without any additional terms or conditions. |
||||||
|
Notwithstanding the above, nothing herein shall supersede or modify |
||||||
|
the terms of any separate license agreement you may have executed |
||||||
|
with Licensor regarding such Contributions. |
||||||
|
|
||||||
|
6. Trademarks. This License does not grant permission to use the trade |
||||||
|
names, trademarks, service marks, or product names of the Licensor, |
||||||
|
except as required for reasonable and customary use in describing the |
||||||
|
origin of the Work and reproducing the content of the NOTICE file. |
||||||
|
|
||||||
|
7. Disclaimer of Warranty. Unless required by applicable law or |
||||||
|
agreed to in writing, Licensor provides the Work (and each |
||||||
|
Contributor provides its Contributions) on an "AS IS" BASIS, |
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or |
||||||
|
implied, including, without limitation, any warranties or conditions |
||||||
|
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A |
||||||
|
PARTICULAR PURPOSE. You are solely responsible for determining the |
||||||
|
appropriateness of using or redistributing the Work and assume any |
||||||
|
risks associated with Your exercise of permissions under this License. |
||||||
|
|
||||||
|
8. Limitation of Liability. In no event and under no legal theory, |
||||||
|
whether in tort (including negligence), contract, or otherwise, |
||||||
|
unless required by applicable law (such as deliberate and grossly |
||||||
|
negligent acts) or agreed to in writing, shall any Contributor be |
||||||
|
liable to You for damages, including any direct, indirect, special, |
||||||
|
incidental, or consequential damages of any character arising as a |
||||||
|
result of this License or out of the use or inability to use the |
||||||
|
Work (including but not limited to damages for loss of goodwill, |
||||||
|
work stoppage, computer failure or malfunction, or any and all |
||||||
|
other commercial damages or losses), even if such Contributor |
||||||
|
has been advised of the possibility of such damages. |
||||||
|
|
||||||
|
9. Accepting Warranty or Additional Liability. While redistributing |
||||||
|
the Work or Derivative Works thereof, You may choose to offer, |
||||||
|
and charge a fee for, acceptance of support, warranty, indemnity, |
||||||
|
or other liability obligations and/or rights consistent with this |
||||||
|
License. However, in accepting such obligations, You may act only |
||||||
|
on Your own behalf and on Your sole responsibility, not on behalf |
||||||
|
of any other Contributor, and only if You agree to indemnify, |
||||||
|
defend, and hold each Contributor harmless for any liability |
||||||
|
incurred by, or claims asserted against, such Contributor by reason |
||||||
|
of your accepting any such warranty or additional liability. |
||||||
|
|
||||||
|
END OF TERMS AND CONDITIONS |
||||||
|
|
||||||
|
APPENDIX: How to apply the Apache License to your work. |
||||||
|
|
||||||
|
To apply the Apache License to your work, attach the following |
||||||
|
boilerplate notice, with the fields enclosed by brackets "[]" |
||||||
|
replaced with your own identifying information. (Don't include |
||||||
|
the brackets!) The text should be enclosed in the appropriate |
||||||
|
comment syntax for the file format. We also recommend that a |
||||||
|
file or class name and description of purpose be included on the |
||||||
|
same "printed page" as the copyright notice for easier |
||||||
|
identification within third-party archives. |
||||||
|
|
||||||
|
Copyright 2022-2024 Niko Bonnieure, Par le Peuple, NextGraph.org developers |
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License"); |
||||||
|
you may not use this file except in compliance with the License. |
||||||
|
You may obtain a copy of the License at |
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0 |
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software |
||||||
|
distributed under the License is distributed on an "AS IS" BASIS, |
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||||
|
See the License for the specific language governing permissions and |
||||||
|
limitations under the License. |
@ -0,0 +1,25 @@ |
|||||||
|
Copyright (c) 2022-2024 Niko Bonnieure, Par le Peuple, NextGraph.org developers |
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any |
||||||
|
person obtaining a copy of this software and associated |
||||||
|
documentation files (the "Software"), to deal in the |
||||||
|
Software without restriction, including without |
||||||
|
limitation the rights to use, copy, modify, merge, |
||||||
|
publish, distribute, sublicense, and/or sell copies of |
||||||
|
the Software, and to permit persons to whom the Software |
||||||
|
is furnished to do so, subject to the following |
||||||
|
conditions: |
||||||
|
|
||||||
|
The above copyright notice and this permission notice |
||||||
|
shall be included in all copies or substantial portions |
||||||
|
of the Software. |
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF |
||||||
|
ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED |
||||||
|
TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A |
||||||
|
PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT |
||||||
|
SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY |
||||||
|
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION |
||||||
|
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR |
||||||
|
IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER |
||||||
|
DEALINGS IN THE SOFTWARE. |
@ -0,0 +1,201 @@ |
|||||||
|
Apache License |
||||||
|
Version 2.0, January 2004 |
||||||
|
http://www.apache.org/licenses/ |
||||||
|
|
||||||
|
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION |
||||||
|
|
||||||
|
1. Definitions. |
||||||
|
|
||||||
|
"License" shall mean the terms and conditions for use, reproduction, |
||||||
|
and distribution as defined by Sections 1 through 9 of this document. |
||||||
|
|
||||||
|
"Licensor" shall mean the copyright owner or entity authorized by |
||||||
|
the copyright owner that is granting the License. |
||||||
|
|
||||||
|
"Legal Entity" shall mean the union of the acting entity and all |
||||||
|
other entities that control, are controlled by, or are under common |
||||||
|
control with that entity. For the purposes of this definition, |
||||||
|
"control" means (i) the power, direct or indirect, to cause the |
||||||
|
direction or management of such entity, whether by contract or |
||||||
|
otherwise, or (ii) ownership of fifty percent (50%) or more of the |
||||||
|
outstanding shares, or (iii) beneficial ownership of such entity. |
||||||
|
|
||||||
|
"You" (or "Your") shall mean an individual or Legal Entity |
||||||
|
exercising permissions granted by this License. |
||||||
|
|
||||||
|
"Source" form shall mean the preferred form for making modifications, |
||||||
|
including but not limited to software source code, documentation |
||||||
|
source, and configuration files. |
||||||
|
|
||||||
|
"Object" form shall mean any form resulting from mechanical |
||||||
|
transformation or translation of a Source form, including but |
||||||
|
not limited to compiled object code, generated documentation, |
||||||
|
and conversions to other media types. |
||||||
|
|
||||||
|
"Work" shall mean the work of authorship, whether in Source or |
||||||
|
Object form, made available under the License, as indicated by a |
||||||
|
copyright notice that is included in or attached to the work |
||||||
|
(an example is provided in the Appendix below). |
||||||
|
|
||||||
|
"Derivative Works" shall mean any work, whether in Source or Object |
||||||
|
form, that is based on (or derived from) the Work and for which the |
||||||
|
editorial revisions, annotations, elaborations, or other modifications |
||||||
|
represent, as a whole, an original work of authorship. For the purposes |
||||||
|
of this License, Derivative Works shall not include works that remain |
||||||
|
separable from, or merely link (or bind by name) to the interfaces of, |
||||||
|
the Work and Derivative Works thereof. |
||||||
|
|
||||||
|
"Contribution" shall mean any work of authorship, including |
||||||
|
the original version of the Work and any modifications or additions |
||||||
|
to that Work or Derivative Works thereof, that is intentionally |
||||||
|
submitted to Licensor for inclusion in the Work by the copyright owner |
||||||
|
or by an individual or Legal Entity authorized to submit on behalf of |
||||||
|
the copyright owner. For the purposes of this definition, "submitted" |
||||||
|
means any form of electronic, verbal, or written communication sent |
||||||
|
to the Licensor or its representatives, including but not limited to |
||||||
|
communication on electronic mailing lists, source code control systems, |
||||||
|
and issue tracking systems that are managed by, or on behalf of, the |
||||||
|
Licensor for the purpose of discussing and improving the Work, but |
||||||
|
excluding communication that is conspicuously marked or otherwise |
||||||
|
designated in writing by the copyright owner as "Not a Contribution." |
||||||
|
|
||||||
|
"Contributor" shall mean Licensor and any individual or Legal Entity |
||||||
|
on behalf of whom a Contribution has been received by Licensor and |
||||||
|
subsequently incorporated within the Work. |
||||||
|
|
||||||
|
2. Grant of Copyright License. Subject to the terms and conditions of |
||||||
|
this License, each Contributor hereby grants to You a perpetual, |
||||||
|
worldwide, non-exclusive, no-charge, royalty-free, irrevocable |
||||||
|
copyright license to reproduce, prepare Derivative Works of, |
||||||
|
publicly display, publicly perform, sublicense, and distribute the |
||||||
|
Work and such Derivative Works in Source or Object form. |
||||||
|
|
||||||
|
3. Grant of Patent License. Subject to the terms and conditions of |
||||||
|
this License, each Contributor hereby grants to You a perpetual, |
||||||
|
worldwide, non-exclusive, no-charge, royalty-free, irrevocable |
||||||
|
(except as stated in this section) patent license to make, have made, |
||||||
|
use, offer to sell, sell, import, and otherwise transfer the Work, |
||||||
|
where such license applies only to those patent claims licensable |
||||||
|
by such Contributor that are necessarily infringed by their |
||||||
|
Contribution(s) alone or by combination of their Contribution(s) |
||||||
|
with the Work to which such Contribution(s) was submitted. If You |
||||||
|
institute patent litigation against any entity (including a |
||||||
|
cross-claim or counterclaim in a lawsuit) alleging that the Work |
||||||
|
or a Contribution incorporated within the Work constitutes direct |
||||||
|
or contributory patent infringement, then any patent licenses |
||||||
|
granted to You under this License for that Work shall terminate |
||||||
|
as of the date such litigation is filed. |
||||||
|
|
||||||
|
4. Redistribution. You may reproduce and distribute copies of the |
||||||
|
Work or Derivative Works thereof in any medium, with or without |
||||||
|
modifications, and in Source or Object form, provided that You |
||||||
|
meet the following conditions: |
||||||
|
|
||||||
|
(a) You must give any other recipients of the Work or |
||||||
|
Derivative Works a copy of this License; and |
||||||
|
|
||||||
|
(b) You must cause any modified files to carry prominent notices |
||||||
|
stating that You changed the files; and |
||||||
|
|
||||||
|
(c) You must retain, in the Source form of any Derivative Works |
||||||
|
that You distribute, all copyright, patent, trademark, and |
||||||
|
attribution notices from the Source form of the Work, |
||||||
|
excluding those notices that do not pertain to any part of |
||||||
|
the Derivative Works; and |
||||||
|
|
||||||
|
(d) If the Work includes a "NOTICE" text file as part of its |
||||||
|
distribution, then any Derivative Works that You distribute must |
||||||
|
include a readable copy of the attribution notices contained |
||||||
|
within such NOTICE file, excluding those notices that do not |
||||||
|
pertain to any part of the Derivative Works, in at least one |
||||||
|
of the following places: within a NOTICE text file distributed |
||||||
|
as part of the Derivative Works; within the Source form or |
||||||
|
documentation, if provided along with the Derivative Works; or, |
||||||
|
within a display generated by the Derivative Works, if and |
||||||
|
wherever such third-party notices normally appear. The contents |
||||||
|
of the NOTICE file are for informational purposes only and |
||||||
|
do not modify the License. You may add Your own attribution |
||||||
|
notices within Derivative Works that You distribute, alongside |
||||||
|
or as an addendum to the NOTICE text from the Work, provided |
||||||
|
that such additional attribution notices cannot be construed |
||||||
|
as modifying the License. |
||||||
|
|
||||||
|
You may add Your own copyright statement to Your modifications and |
||||||
|
may provide additional or different license terms and conditions |
||||||
|
for use, reproduction, or distribution of Your modifications, or |
||||||
|
for any such Derivative Works as a whole, provided Your use, |
||||||
|
reproduction, and distribution of the Work otherwise complies with |
||||||
|
the conditions stated in this License. |
||||||
|
|
||||||
|
5. Submission of Contributions. Unless You explicitly state otherwise, |
||||||
|
any Contribution intentionally submitted for inclusion in the Work |
||||||
|
by You to the Licensor shall be under the terms and conditions of |
||||||
|
this License, without any additional terms or conditions. |
||||||
|
Notwithstanding the above, nothing herein shall supersede or modify |
||||||
|
the terms of any separate license agreement you may have executed |
||||||
|
with Licensor regarding such Contributions. |
||||||
|
|
||||||
|
6. Trademarks. This License does not grant permission to use the trade |
||||||
|
names, trademarks, service marks, or product names of the Licensor, |
||||||
|
except as required for reasonable and customary use in describing the |
||||||
|
origin of the Work and reproducing the content of the NOTICE file. |
||||||
|
|
||||||
|
7. Disclaimer of Warranty. Unless required by applicable law or |
||||||
|
agreed to in writing, Licensor provides the Work (and each |
||||||
|
Contributor provides its Contributions) on an "AS IS" BASIS, |
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or |
||||||
|
implied, including, without limitation, any warranties or conditions |
||||||
|
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A |
||||||
|
PARTICULAR PURPOSE. You are solely responsible for determining the |
||||||
|
appropriateness of using or redistributing the Work and assume any |
||||||
|
risks associated with Your exercise of permissions under this License. |
||||||
|
|
||||||
|
8. Limitation of Liability. In no event and under no legal theory, |
||||||
|
whether in tort (including negligence), contract, or otherwise, |
||||||
|
unless required by applicable law (such as deliberate and grossly |
||||||
|
negligent acts) or agreed to in writing, shall any Contributor be |
||||||
|
liable to You for damages, including any direct, indirect, special, |
||||||
|
incidental, or consequential damages of any character arising as a |
||||||
|
result of this License or out of the use or inability to use the |
||||||
|
Work (including but not limited to damages for loss of goodwill, |
||||||
|
work stoppage, computer failure or malfunction, or any and all |
||||||
|
other commercial damages or losses), even if such Contributor |
||||||
|
has been advised of the possibility of such damages. |
||||||
|
|
||||||
|
9. Accepting Warranty or Additional Liability. While redistributing |
||||||
|
the Work or Derivative Works thereof, You may choose to offer, |
||||||
|
and charge a fee for, acceptance of support, warranty, indemnity, |
||||||
|
or other liability obligations and/or rights consistent with this |
||||||
|
License. However, in accepting such obligations, You may act only |
||||||
|
on Your own behalf and on Your sole responsibility, not on behalf |
||||||
|
of any other Contributor, and only if You agree to indemnify, |
||||||
|
defend, and hold each Contributor harmless for any liability |
||||||
|
incurred by, or claims asserted against, such Contributor by reason |
||||||
|
of your accepting any such warranty or additional liability. |
||||||
|
|
||||||
|
END OF TERMS AND CONDITIONS |
||||||
|
|
||||||
|
APPENDIX: How to apply the Apache License to your work. |
||||||
|
|
||||||
|
To apply the Apache License to your work, attach the following |
||||||
|
boilerplate notice, with the fields enclosed by brackets "[]" |
||||||
|
replaced with your own identifying information. (Don't include |
||||||
|
the brackets!) The text should be enclosed in the appropriate |
||||||
|
comment syntax for the file format. We also recommend that a |
||||||
|
file or class name and description of purpose be included on the |
||||||
|
same "printed page" as the copyright notice for easier |
||||||
|
identification within third-party archives. |
||||||
|
|
||||||
|
Copyright 2022-2024 Niko Bonnieure, Par le Peuple, NextGraph.org developers |
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License"); |
||||||
|
you may not use this file except in compliance with the License. |
||||||
|
You may obtain a copy of the License at |
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0 |
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software |
||||||
|
distributed under the License is distributed on an "AS IS" BASIS, |
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||||
|
See the License for the specific language governing permissions and |
||||||
|
limitations under the License. |
@ -0,0 +1,25 @@ |
|||||||
|
Copyright (c) 2022-2024 Niko Bonnieure, Par le Peuple, NextGraph.org developers |
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any |
||||||
|
person obtaining a copy of this software and associated |
||||||
|
documentation files (the "Software"), to deal in the |
||||||
|
Software without restriction, including without |
||||||
|
limitation the rights to use, copy, modify, merge, |
||||||
|
publish, distribute, sublicense, and/or sell copies of |
||||||
|
the Software, and to permit persons to whom the Software |
||||||
|
is furnished to do so, subject to the following |
||||||
|
conditions: |
||||||
|
|
||||||
|
The above copyright notice and this permission notice |
||||||
|
shall be included in all copies or substantial portions |
||||||
|
of the Software. |
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF |
||||||
|
ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED |
||||||
|
TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A |
||||||
|
PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT |
||||||
|
SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY |
||||||
|
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION |
||||||
|
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR |
||||||
|
IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER |
||||||
|
DEALINGS IN THE SOFTWARE. |
@ -0,0 +1,26 @@ |
|||||||
|
[package] |
||||||
|
name = "ng-stores-lmdb" |
||||||
|
# version = "0.1.0" |
||||||
|
description = "Stores based on LMDB for NextGraph" |
||||||
|
version.workspace = true |
||||||
|
edition.workspace = true |
||||||
|
license.workspace = true |
||||||
|
authors.workspace = true |
||||||
|
repository.workspace = true |
||||||
|
homepage.workspace = true |
||||||
|
keywords.workspace = true |
||||||
|
documentation.workspace = true |
||||||
|
rust-version.workspace = true |
||||||
|
publish = false |
||||||
|
|
||||||
|
[dependencies] |
||||||
|
ng-repo = { path = "../ng-repo" } |
||||||
|
serde = { version = "1.0.142", features = ["derive"] } |
||||||
|
serde_bare = "0.5.0" |
||||||
|
tempfile = "3" |
||||||
|
hex = "0.4.3" |
||||||
|
|
||||||
|
[target.'cfg(not(target_arch = "wasm32"))'.dependencies.rkv] |
||||||
|
git = "https://git.nextgraph.org/NextGraph/rkv.git" |
||||||
|
rev = "c746abb443b7bb4541ebbef2b71e8d0f9eb39f6a" |
||||||
|
features = [ "lmdb" ] |
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in new issue