Expand description
Discret: Create local first, peer to peer application (P2P) using a GraphQL inspired API
Discret hides the complexity of peer to peer networks and reduces it to a data access problem.
The API allows you to:
- manage your data using a GraphQL syntax,
- add access right to your data (in graphQL too),
- create and accept invites from other peers.
Discret will synchronize your data with other peers, depending on the access right you have given to those peers.
More details and tutorials are available in the documentation site
§Example
The following example creates a very basic chat application. If you build and run this program on several different folder or local network devices you should be able to chat with yourself.
use std::{io, path::PathBuf};
use discret::{
derive_pass_phrase, zero_uid, Configuration, Discret,
Parameters, ParametersAdd, ResultParser,
};
use serde::Deserialize;
//the application unique identifier
const APPLICATION_KEY: &str = "github.com/discretlib/rust_example_simple_chat";
#[tokio::main]
async fn main() {
//define a datamodel
let model = "chat {
Message{
content:String
}
}";
//this struct is used to parse the query result
#[derive(Deserialize)]
struct Chat {
pub id: String,
pub mdate: i64,
pub content: String,
}
let path: PathBuf = "test_data".into(); //where data is stored
//used to derives all necessary secrets
let key_material: [u8; 32] = derive_pass_phrase("my login", "my password");
//start the discret application
let app: Discret = Discret::new(
model,
APPLICATION_KEY,
&key_material,
path,
Configuration::default(),
)
.await
.unwrap();
//listen for events
let mut events = app.subscribe_for_events().await;
let event_app: Discret = app.clone();
tokio::spawn(async move {
let mut last_date = 0;
let mut last_id = zero_uid();
let private_room: String = event_app.private_room();
while let Ok(event) = events.recv().await {
match event {
//triggered when data is modified
discret::Event::DataChanged(_) => {
let mut param = Parameters::new();
param.add("mdate", last_date).unwrap();
param.add("id", last_id.clone()).unwrap();
param.add("room_id", private_room.clone()).unwrap();
//get the latest data, the result is in the JSON format
let result: String = event_app
.query(
"query {
res: chat.Message(
order_by(mdate asc, id asc),
after($mdate, $id),
room_id = $room_id
) {
id
mdate
content
}
}",
Some(param),
)
.await
.unwrap();
let mut query_result = ResultParser::new(&result).unwrap();
let res: Vec<Chat> = query_result.take_array("res").unwrap();
for msg in res {
last_date = msg.mdate;
last_id = msg.id;
println!("you said: {}", msg.content);
}
}
_ => {} //ignores other events
}
}
});
//data is inserted in your private room
let private_room: String = app.private_room();
let stdin = io::stdin();
let mut line = String::new();
println!("{}", "Write Something!");
loop {
stdin.read_line(&mut line).unwrap();
if line.starts_with("/q") {
break;
}
line.pop();
let mut params = Parameters::new();
params.add("message", line.clone()).unwrap();
params.add("room_id", private_room.clone()).unwrap();
app.mutate(
"mutate {
chat.Message {
room_id:$room_id
content: $message
}
}",
Some(params),
)
.await
.unwrap();
line.clear();
}
}
§Features
Discret provides a blocking (DiscretBlocking) and a non blocking (Discret) API.
On local network, peer connection happens without requiring any server. For peer to peer connection over the Internet, a discovery server is needed to allow peers to discover each others. The discret lib provides an implementation of the discovery server named Beacon.
The library provides strong security features out of the box:
- data is encrypted at rest by using the SQLCipher database
- encrypted communication using the QUIC protocol
- data integrity: each rows is signed with the peer signing key, making it very hard to synchronize bad data
- access control via Rooms
§Limitations
As data lives on your devices, Discret should only be used for applications with data generated by “real person”, with hundreds of peers at most. It is not suited for large scale applications and communities with thousands of peoples.
It currently only supports text data but supports for file synchronization is planned.
Connection over the internet is not 100% guaranteed to work, because certain types of enterprise firewalls will block the connection attempts.
Please, be warned that P2P connections leaks your IP adress and should only be used with trusted peer. This leak exposes you to the following threats:
- Distributed denial of service (DDOS)
- Leak of your “Real World” location via geolocation services.
- State sponsored surveillance: A state watching the network could determine which peer connect to which, giving a lot of knowledge about your social network.
§Platform Support
- Linux: Tested
- Windows: Tested
- macOS: not tested, should work
- Android: works on arch64 architecture. Architectures i686 and x86_64 have some low level linker issues when working with Flutter.
- iOS: not tested
Structs§
- Beacon
- Provides a Beacon service that allow peers to discover each others on the Internet
- Beacon
Config - A beacon server
- Configuration
- Global configuration for the discret lib
- Data
Modification - DataModification is the struct sent by the Event::DataChanged event the room map contains:
- Default
Room - When creating an invitation, you may specify a default room and authorisation. A new peer using this invitation will be provided access to this room.
- Discret
- The main entry point for the Discret Library
- Discret
Blocking - The main entry point for the Discret Library, with a blocking API Provides a blocking API
- Parameters
- This struct is used to pass parameter to queries
- Result
Parser - Helper structure to parse the JSON results
- Room
- Room is the root of the authorisation model
Enums§
- Error
- Defines every errors that can be triggered by the discret lib
- Event
- The list of events that are sent by Discret
Traits§
- Parameters
Add - The traits that allows adding parameters
Functions§
- base64_
decode - decode a base 64 String into bytes
- base64_
encode - encode bytes into a base 64 String
- database_
exists - Verify that the Discret database defined by the parameters exists in the folder
- derive_
pass_ phrase - Derive a password using argon2id using parameters slighly greater than the minimum recommended by OSWAP https://cheatsheetseries.owasp.org/cheatsheets/Password_Storage_Cheat_Sheet.html
- generate_
x509_ certificate - generates a self signed certificate
- hash
- hash a byte array using the Blake3 hash function
- random_
domain_ name - The quick connection initiate connection with a domain name used during TLS negociations to avoid man in the middle attack. As we are using p2p and self signed certificates, we don’t have a domain name to connect to we have to generate one.
- zero_
uid - returns the zero filled uid in base bas64