mirror of
https://github.com/fluencelabs/trust-graph-test
synced 2025-04-24 23:02:32 +00:00
commit
2dc5df28cc
2
Cargo.lock
generated
2
Cargo.lock
generated
@ -406,6 +406,7 @@ dependencies = [
|
||||
"serde_json",
|
||||
"serde_with",
|
||||
"signature",
|
||||
"thiserror",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -1428,6 +1429,7 @@ dependencies = [
|
||||
"serde_json",
|
||||
"serde_with",
|
||||
"signature",
|
||||
"thiserror",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -21,3 +21,4 @@ ed25519-dalek = { version = "1.0.1", features = ["serde"] }
|
||||
rand = "0.7.0"
|
||||
signature = "1.3.0"
|
||||
serde_with = "1.6.0"
|
||||
thiserror = "1.0.23"
|
||||
|
@ -1,5 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
fce build
|
||||
mv target/wasm32-wasi/debug/trust-graph.wasm artifacts/
|
||||
RUST_LOG="info" fce-repl Config.toml
|
@ -1,58 +0,0 @@
|
||||
use crate::storage_impl::get_data;
|
||||
use fluence::fce;
|
||||
use fluence_identity::KeyPair;
|
||||
use std::time::Duration;
|
||||
use trust_graph::Certificate;
|
||||
use std::str::FromStr;
|
||||
|
||||
struct InsertResult {
|
||||
ret_code: u32,
|
||||
error: String,
|
||||
}
|
||||
|
||||
// TODO: some sort of auth?
|
||||
fn insert_cert(certificate: String, duration: u64) -> InsertResult {
|
||||
|
||||
let duration = Duration::from_millis(duration);
|
||||
let certificate = Certificate::from_str(&certificate).unwrap();
|
||||
|
||||
let mut tg = get_data().lock();
|
||||
tg.add(certificate, duration).unwrap();
|
||||
|
||||
return InsertResult {
|
||||
ret_code: 0,
|
||||
error: "".to_string()
|
||||
}
|
||||
}
|
||||
|
||||
#[fce]
|
||||
fn looper() {
|
||||
let mut a = 0;
|
||||
while true {
|
||||
a = a + 1;
|
||||
log::info!("{}", a)
|
||||
}
|
||||
}
|
||||
|
||||
#[fce]
|
||||
fn test() -> String {
|
||||
let mut tg = get_data().lock();
|
||||
|
||||
let root_kp = KeyPair::generate();
|
||||
let root_kp2 = KeyPair::generate();
|
||||
let second_kp = KeyPair::generate();
|
||||
|
||||
let expires_at = Duration::new(15, 15);
|
||||
let issued_at = Duration::new(5, 5);
|
||||
|
||||
let cert = Certificate::issue_root(&root_kp, second_kp.public_key(), expires_at, issued_at);
|
||||
tg.add_root_weight(root_kp.public().into(), 0);
|
||||
tg.add_root_weight(root_kp2.public().into(), 1);
|
||||
tg.add(cert, Duration::new(10, 10));
|
||||
|
||||
let a = tg.get(second_kp.public_key());
|
||||
let str = format!("{:?}", a);
|
||||
log::info!("{}", &str);
|
||||
|
||||
str
|
||||
}
|
@ -1,192 +0,0 @@
|
||||
// store list of trusts
|
||||
// check if trust is already in list before adding
|
||||
// if there is an older trust - don't add received trust
|
||||
|
||||
use core::convert::TryFrom;
|
||||
use fluence_identity::public_key::PublicKey;
|
||||
use once_cell::sync::OnceCell;
|
||||
use parking_lot::Mutex;
|
||||
use fce_sqlite_connector;
|
||||
use fce_sqlite_connector::Connection;
|
||||
use fce_sqlite_connector::Value;
|
||||
use std::str::FromStr;
|
||||
use std::time::Duration;
|
||||
use trust_graph::{Auth, PublicKeyHashable, Revoke, Storage, TrustGraph, TrustNode, Weight};
|
||||
use std::ops::Deref;
|
||||
|
||||
static INSTANCE: OnceCell<Mutex<TrustGraph>> = OnceCell::new();
|
||||
|
||||
pub fn get_data() -> &'static Mutex<TrustGraph> {
|
||||
INSTANCE.get_or_init(|| {
|
||||
let db_path = "/tmp/users123123.sqlite";
|
||||
let connection = fce_sqlite_connector::open(db_path).unwrap();
|
||||
|
||||
let init_sql = "CREATE TABLE IF NOT EXISTS trustnodes(
|
||||
public_key TEXT PRIMARY KEY,
|
||||
trustnode BLOB NOT NULL
|
||||
);
|
||||
CREATE TABLE IF NOT EXISTS roots(
|
||||
public_key TEXT,
|
||||
weight INTEGER
|
||||
);";
|
||||
|
||||
connection.execute(init_sql).expect("cannot connect to db");
|
||||
|
||||
Mutex::new(TrustGraph::new(Box::new(SqliteStorage::new(connection))))
|
||||
})
|
||||
}
|
||||
|
||||
pub struct SqliteStorage {
|
||||
connection: Connection,
|
||||
}
|
||||
|
||||
impl SqliteStorage {
|
||||
pub fn new(connection: Connection) -> SqliteStorage {
|
||||
SqliteStorage { connection }
|
||||
}
|
||||
}
|
||||
|
||||
impl Storage for SqliteStorage {
|
||||
fn get(&self, pk: &PublicKeyHashable) -> Option<TrustNode> {
|
||||
let mut cursor = self
|
||||
.connection
|
||||
.prepare("SELECT trustnode FROM trustnodes WHERE public_key = ?")
|
||||
.expect("unexpected: 'get' request should be correct")
|
||||
.cursor();
|
||||
|
||||
cursor
|
||||
.bind(&[Value::String(format!("{}", pk))])
|
||||
.expect("unexpected: 'public_key' field should be string");
|
||||
|
||||
match cursor.next().unwrap() {
|
||||
Some(r) => {
|
||||
log::info!("row: {:?}", r);
|
||||
let tn_bin: &[u8] = r[0]
|
||||
.as_binary()
|
||||
.expect("unexpected: 'trustnode' in a table should be as binary");
|
||||
|
||||
log::info!("binary: {:?}", tn_bin);
|
||||
|
||||
let trust_node: TrustNode = rmp_serde::from_read_ref(tn_bin)
|
||||
// let trust_node: TrustNode = bincode::deserialize(tn_bin)
|
||||
// let trust_node: TrustNode = serde_bencode::de::from_bytes(tn_bin)
|
||||
.expect("unexpected: 'trustnode' should be as correct binary");
|
||||
|
||||
log::info!("trustnode: {:?}", trust_node);
|
||||
|
||||
Some(trust_node)
|
||||
}
|
||||
|
||||
None => None,
|
||||
}
|
||||
}
|
||||
|
||||
fn insert(&mut self, pk: PublicKeyHashable, node: TrustNode) {
|
||||
let mut cursor = self
|
||||
.connection
|
||||
.prepare("INSERT OR REPLACE INTO trustnodes VALUES (?, ?)")
|
||||
.unwrap()
|
||||
.cursor();
|
||||
|
||||
let tn_vec = rmp_serde::to_vec(&node).unwrap();
|
||||
// let tn_vec = bincode::serialize(&node).unwrap();
|
||||
let tn_vec = serde_bencode::to_bytes(&node).unwrap();
|
||||
|
||||
log::info!("insert: {:?}", tn_vec);
|
||||
|
||||
cursor
|
||||
.bind(&[Value::String(format!("{}", pk)), Value::Binary(tn_vec)])
|
||||
.unwrap();
|
||||
|
||||
cursor.next().unwrap();
|
||||
}
|
||||
|
||||
fn get_root_weight(&self, pk: &PublicKeyHashable) -> Option<Weight> {
|
||||
let mut cursor = self
|
||||
.connection
|
||||
.prepare("SELECT public_key,weight FROM roots WHERE public_key = ?")
|
||||
.unwrap()
|
||||
.cursor();
|
||||
|
||||
cursor.bind(&[Value::String(format!("{}", pk))]).unwrap();
|
||||
|
||||
if let Some(row) = cursor.next().unwrap() {
|
||||
log::info!("row: {:?}", row);
|
||||
|
||||
let w = u32::try_from(row[1].as_integer().unwrap()).unwrap();
|
||||
|
||||
Some(w)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
fn add_root_weight(&mut self, pk: PublicKeyHashable, weight: Weight) {
|
||||
log::info!("add root: {} weight: {}", pk, weight);
|
||||
let mut cursor = self
|
||||
.connection
|
||||
.prepare("INSERT OR REPLACE INTO roots VALUES (?, ?)")
|
||||
.unwrap()
|
||||
.cursor();
|
||||
|
||||
cursor
|
||||
.bind(&[
|
||||
Value::String(format!("{}", pk)),
|
||||
Value::Integer(i64::from(weight)),
|
||||
])
|
||||
.unwrap();
|
||||
|
||||
cursor.next().unwrap();
|
||||
}
|
||||
|
||||
fn root_keys(&self) -> Vec<PublicKeyHashable> {
|
||||
let mut cursor = self
|
||||
.connection
|
||||
.prepare("SELECT public_key,weight FROM roots")
|
||||
.unwrap()
|
||||
.cursor();
|
||||
|
||||
let mut roots = vec![];
|
||||
|
||||
while let Some(row) = cursor.next().unwrap() {
|
||||
log::info!("row: {:?}", row);
|
||||
let pk: PublicKeyHashable =
|
||||
PublicKeyHashable::from_str(row[0].as_string().unwrap()).unwrap();
|
||||
|
||||
roots.push(pk)
|
||||
}
|
||||
|
||||
roots
|
||||
}
|
||||
|
||||
fn revoke(&mut self, pk: &PublicKeyHashable, revoke: Revoke) -> Result<(), String> {
|
||||
match self.get(&pk) {
|
||||
Some(mut trust_node) => {
|
||||
trust_node.update_revoke(revoke);
|
||||
self.insert(pk.clone(), trust_node);
|
||||
Ok(())
|
||||
}
|
||||
None => Err("There is no trust with such PublicKey".to_string()),
|
||||
}
|
||||
}
|
||||
|
||||
fn update_auth(
|
||||
&mut self,
|
||||
pk: &PublicKeyHashable,
|
||||
auth: Auth,
|
||||
issued_for: &PublicKey,
|
||||
cur_time: Duration,
|
||||
) {
|
||||
match self.get(&pk) {
|
||||
Some(mut trust_node) => {
|
||||
trust_node.update_auth(auth);
|
||||
self.insert(pk.clone(), trust_node)
|
||||
}
|
||||
None => {
|
||||
let mut trust_node = TrustNode::new(issued_for.clone(), cur_time);
|
||||
trust_node.update_auth(auth);
|
||||
self.insert(pk.clone(), trust_node);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
1
identity/Cargo.lock
generated
1
identity/Cargo.lock
generated
@ -344,6 +344,7 @@ dependencies = [
|
||||
"serde_json",
|
||||
"serde_with",
|
||||
"signature",
|
||||
"thiserror",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -16,3 +16,4 @@ rand = "0.7.0"
|
||||
signature = "1.3.0"
|
||||
ed25519 = "1.0.3"
|
||||
serde_with = "1.6.0"
|
||||
thiserror = "1.0.23"
|
||||
|
@ -79,11 +79,10 @@ impl KeyPair {
|
||||
}
|
||||
|
||||
/// Verify the Ed25519 signature on a message using the public key.
|
||||
pub fn verify(pk: &PublicKey, msg: &[u8], signature: &Signature) -> Result<(), String> {
|
||||
pub fn verify(pk: &PublicKey, msg: &[u8], signature: &Signature) -> Result<(), SignatureError> {
|
||||
// let signature = ed25519_dalek::Signature::from_bytes(signature)
|
||||
// .map_err(|err| format!("Cannot convert bytes to a signature: {:?}", err))?;
|
||||
pk.verify_strict(msg, signature)
|
||||
.map_err(|err| format!("Signature verification failed: {:?}", err))
|
||||
}
|
||||
}
|
||||
|
||||
@ -144,8 +143,8 @@ impl<'de> serde::Deserialize<'de> for KeyPair {
|
||||
|
||||
impl Clone for KeyPair {
|
||||
fn clone(&self) -> KeyPair {
|
||||
let mut sk_bytes = self.key_pair.secret.to_bytes();
|
||||
let secret = ed25519_dalek::SecretKey::from_bytes(&mut sk_bytes)
|
||||
let sk_bytes = self.key_pair.secret.to_bytes();
|
||||
let secret = ed25519_dalek::SecretKey::from_bytes(&sk_bytes)
|
||||
.expect("ed25519::SecretKey::from_bytes(to_bytes(k)) != k");
|
||||
let public = ed25519_dalek::PublicKey::from_bytes(&self.key_pair.public.to_bytes())
|
||||
.expect("ed25519::PublicKey::from_bytes(to_bytes(k)) != k");
|
||||
|
@ -14,10 +14,20 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
use crate::public_key::PKError::{FromBase58Error, FromBytesError};
|
||||
use crate::signature::Signature;
|
||||
use core::fmt::Debug;
|
||||
use ed25519_dalek::SignatureError;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use thiserror::Error as ThisError;
|
||||
|
||||
#[derive(ThisError, Debug)]
|
||||
pub enum PKError {
|
||||
#[error("Cannot decode public key from bytes: {0}")]
|
||||
FromBytesError(#[source] SignatureError),
|
||||
#[error("Cannot decode public key from base58 format: {0}")]
|
||||
FromBase58Error(#[source] bs58::decode::Error),
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Default, Eq, PartialEq, Serialize, Deserialize)]
|
||||
pub struct PublicKey(pub(crate) ed25519_dalek::PublicKey);
|
||||
@ -37,9 +47,13 @@ impl PublicKey {
|
||||
self.0.verify_strict(message, &signature.0)
|
||||
}
|
||||
|
||||
pub fn from_bytes(bytes: &[u8]) -> Result<PublicKey, SignatureError> {
|
||||
let pk = ed25519_dalek::PublicKey::from_bytes(bytes)?;
|
||||
pub fn from_base58(str: &str) -> Result<PublicKey, PKError> {
|
||||
let bytes = bs58::decode(str).into_vec().map_err(FromBase58Error)?;
|
||||
Self::from_bytes(&bytes)
|
||||
}
|
||||
|
||||
pub fn from_bytes(bytes: &[u8]) -> Result<PublicKey, PKError> {
|
||||
let pk = ed25519_dalek::PublicKey::from_bytes(bytes).map_err(FromBytesError)?;
|
||||
Ok(PublicKey(pk))
|
||||
}
|
||||
|
||||
|
@ -15,7 +15,19 @@
|
||||
*/
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
use signature::Error as SigError;
|
||||
use signature::Signature as SigSignature;
|
||||
use thiserror::Error as ThisError;
|
||||
|
||||
#[derive(ThisError, Debug)]
|
||||
pub enum SignatureError {
|
||||
#[error("{0}")]
|
||||
Error(
|
||||
#[from]
|
||||
#[source]
|
||||
SigError,
|
||||
),
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
|
||||
pub struct Signature(pub ed25519_dalek::Signature);
|
||||
@ -33,8 +45,8 @@ impl Signature {
|
||||
self.0.to_bytes()
|
||||
}
|
||||
|
||||
pub fn from_bytes(bytes: &[u8]) -> Result<Self, String> {
|
||||
let sig = ed25519_dalek::Signature::from_bytes(bytes).map_err(|err| err.to_string())?;
|
||||
pub fn from_bytes(bytes: &[u8]) -> Result<Self, SignatureError> {
|
||||
let sig = ed25519_dalek::Signature::from_bytes(bytes)?;
|
||||
Ok(Signature(sig))
|
||||
}
|
||||
}
|
||||
|
@ -14,11 +14,17 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
use crate::trust::{Trust, TRUST_LEN};
|
||||
use crate::certificate::CertificateError::{
|
||||
CertificateLengthError, DecodeError, DecodeTrustError, ExpirationError, IncorrectByteLength,
|
||||
IncorrectCertificateFormat, KeyInCertificateError, MalformedRoot, NoTrustedRoot,
|
||||
VerificationError,
|
||||
};
|
||||
use crate::trust::{Trust, TrustError, TRUST_LEN};
|
||||
use fluence_identity::key_pair::KeyPair;
|
||||
use fluence_identity::public_key::PublicKey;
|
||||
use std::str::FromStr;
|
||||
use std::time::Duration;
|
||||
use thiserror::Error as ThisError;
|
||||
|
||||
/// Serialization format of a certificate.
|
||||
/// TODO
|
||||
@ -33,6 +39,35 @@ pub struct Certificate {
|
||||
pub chain: Vec<Trust>,
|
||||
}
|
||||
|
||||
#[derive(ThisError, Debug)]
|
||||
pub enum CertificateError {
|
||||
#[error("Incorrect format of the certificate: {0}")]
|
||||
IncorrectCertificateFormat(String),
|
||||
#[error("Incorrect length of an array. Should be 2 bytes of a format, 4 bytes of a version and 104 bytes for each trust")]
|
||||
IncorrectByteLength,
|
||||
#[error("Error while decoding a trust in a certificate: {0}")]
|
||||
DecodeError(#[source] TrustError),
|
||||
#[error("Certificate is expired. Issued at {issued_at} and expired at {expires_at}")]
|
||||
ExpirationError {
|
||||
expires_at: String,
|
||||
issued_at: String,
|
||||
},
|
||||
#[error("Certificate does not contain a trusted root.")]
|
||||
NoTrustedRoot,
|
||||
#[error("Root trust did not pass verification: {0}")]
|
||||
MalformedRoot(#[source] TrustError),
|
||||
#[error("There is no `issued_by` public key in a certificate")]
|
||||
KeyInCertificateError,
|
||||
#[error("The certificate must have at least 1 trust")]
|
||||
CertificateLengthError,
|
||||
#[error("Cannot convert trust number {0} from string: {1}")]
|
||||
DecodeTrustError(usize, #[source] TrustError),
|
||||
#[error("Trust {0} in chain did not pass verification: {1}")]
|
||||
VerificationError(usize, #[source] TrustError),
|
||||
#[error("there cannot be paths without any nodes after adding verified certificates")]
|
||||
Unexpected,
|
||||
}
|
||||
|
||||
impl Certificate {
|
||||
pub fn new_unverified(chain: Vec<Trust>) -> Self {
|
||||
Self { chain }
|
||||
@ -65,17 +100,16 @@ impl Certificate {
|
||||
expires_at: Duration,
|
||||
issued_at: Duration,
|
||||
cur_time: Duration,
|
||||
) -> Result<Self, String> {
|
||||
) -> Result<Self, CertificateError> {
|
||||
if expires_at.lt(&issued_at) {
|
||||
return Err("Expiration time should be greater than issued time.".to_string());
|
||||
return Err(ExpirationError {
|
||||
expires_at: format!("{:?}", expires_at),
|
||||
issued_at: format!("{:?}", issued_at),
|
||||
});
|
||||
}
|
||||
|
||||
// first, verify given certificate
|
||||
Certificate::verify(
|
||||
extend_cert,
|
||||
&[extend_cert.chain[0].issued_for.clone()],
|
||||
cur_time,
|
||||
)?;
|
||||
Certificate::verify(extend_cert, &[extend_cert.chain[0].issued_for], cur_time)?;
|
||||
|
||||
let issued_by_pk = issued_by.public_key();
|
||||
|
||||
@ -88,7 +122,7 @@ impl Certificate {
|
||||
}
|
||||
|
||||
if previous_trust_num == -1 {
|
||||
return Err("Your public key should be in certificate.".to_string());
|
||||
return Err(KeyInCertificateError);
|
||||
};
|
||||
|
||||
// splitting old chain to add new trust after given public key
|
||||
@ -110,19 +144,18 @@ impl Certificate {
|
||||
cert: &Certificate,
|
||||
trusted_roots: &[PublicKey],
|
||||
cur_time: Duration,
|
||||
) -> Result<(), String> {
|
||||
) -> Result<(), CertificateError> {
|
||||
let chain = &cert.chain;
|
||||
|
||||
if chain.is_empty() {
|
||||
return Err("The certificate must have at least 1 trust".to_string());
|
||||
return Err(CertificateLengthError);
|
||||
}
|
||||
|
||||
// check root trust and its existence in trusted roots list
|
||||
let root = &chain[0];
|
||||
Trust::verify(root, &root.issued_for, cur_time)
|
||||
.map_err(|e| format!("Root trust did not pass verification: {}", e))?;
|
||||
Trust::verify(root, &root.issued_for, cur_time).map_err(MalformedRoot)?;
|
||||
if !trusted_roots.contains(&root.issued_for) {
|
||||
return Err("Certificate does not contain a trusted root.".to_string());
|
||||
return Err(NoTrustedRoot);
|
||||
}
|
||||
|
||||
// check if every element in a chain is not expired and has the correct signature
|
||||
@ -131,12 +164,8 @@ impl Certificate {
|
||||
|
||||
let trust_giver = &chain[trust_id - 1];
|
||||
|
||||
Trust::verify(trust, &trust_giver.issued_for, cur_time).map_err(|e| {
|
||||
format!(
|
||||
"Trust {} in chain did not pass verification: {}",
|
||||
trust_id, e
|
||||
)
|
||||
})?;
|
||||
Trust::verify(trust, &trust_giver.issued_for, cur_time)
|
||||
.map_err(|e| VerificationError(trust_id, e))?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
@ -159,16 +188,16 @@ impl Certificate {
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub fn decode(arr: &[u8]) -> Result<Self, String> {
|
||||
pub fn decode(arr: &[u8]) -> Result<Self, CertificateError> {
|
||||
let trusts_offset = arr.len() - 2 - 4;
|
||||
if trusts_offset % TRUST_LEN != 0 {
|
||||
return Err("Incorrect length of an array. Should be 2 bytes of a format, 4 bytes of a version and 104 bytes for each trust. ".to_string());
|
||||
return Err(IncorrectByteLength);
|
||||
}
|
||||
|
||||
let number_of_trusts = trusts_offset / TRUST_LEN;
|
||||
|
||||
if number_of_trusts < 2 {
|
||||
return Err("The certificate must have at least 2 trusts.".to_string());
|
||||
return Err(CertificateLengthError);
|
||||
}
|
||||
|
||||
// TODO do match different formats and versions
|
||||
@ -181,7 +210,7 @@ impl Certificate {
|
||||
let from = i * TRUST_LEN + 6;
|
||||
let to = (i + 1) * TRUST_LEN + 6;
|
||||
let slice = &arr[from..to];
|
||||
let t = Trust::decode(slice)?;
|
||||
let t = Trust::decode(slice).map_err(DecodeError)?;
|
||||
chain.push(t);
|
||||
}
|
||||
|
||||
@ -201,7 +230,7 @@ impl std::fmt::Display for Certificate {
|
||||
}
|
||||
|
||||
impl FromStr for Certificate {
|
||||
type Err = String;
|
||||
type Err = CertificateError;
|
||||
|
||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||
let str_lines: Vec<&str> = s.lines().collect();
|
||||
@ -211,7 +240,7 @@ impl FromStr for Certificate {
|
||||
let _version = str_lines[1];
|
||||
|
||||
if (str_lines.len() - 2) % 4 != 0 {
|
||||
return Err(format!("Incorrect format of the certificate: {}", s));
|
||||
return Err(IncorrectCertificateFormat(s.to_string()));
|
||||
}
|
||||
|
||||
let num_of_trusts = (str_lines.len() - 2) / 4;
|
||||
@ -223,7 +252,8 @@ impl FromStr for Certificate {
|
||||
str_lines[i + 1],
|
||||
str_lines[i + 2],
|
||||
str_lines[i + 3],
|
||||
)?;
|
||||
)
|
||||
.map_err(|e| DecodeTrustError(i, e))?;
|
||||
|
||||
trusts.push(trust);
|
||||
}
|
||||
|
@ -36,11 +36,11 @@ mod trust_graph;
|
||||
mod trust_graph_storage;
|
||||
mod trust_node;
|
||||
|
||||
pub use crate::certificate::Certificate;
|
||||
pub use crate::certificate::{Certificate, CertificateError};
|
||||
pub use crate::misc::current_time;
|
||||
pub use crate::public_key_hashable::PublicKeyHashable;
|
||||
pub use crate::revoke::Revoke;
|
||||
pub use crate::trust::Trust;
|
||||
pub use crate::trust_graph::{TrustGraph, Weight};
|
||||
pub use crate::trust_graph_storage::Storage;
|
||||
pub use crate::trust_graph::{TrustGraph, TrustGraphError, Weight};
|
||||
pub use crate::trust_graph_storage::{Storage, StorageError};
|
||||
pub use crate::trust_node::{Auth, TrustNode};
|
||||
|
@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
use fluence_identity::public_key::PublicKey;
|
||||
use fluence_identity::public_key::{PKError, PublicKey};
|
||||
|
||||
use core::fmt;
|
||||
use ref_cast::RefCast;
|
||||
@ -82,15 +82,10 @@ impl Display for PublicKeyHashable {
|
||||
}
|
||||
|
||||
impl FromStr for PublicKeyHashable {
|
||||
type Err = String;
|
||||
type Err = PKError;
|
||||
|
||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||
let bytes = bs58::decode(s)
|
||||
.into_vec()
|
||||
.map_err(|err| format!("Invalid string '{}': {}", s, err))?;
|
||||
|
||||
let pk = PublicKey::from_bytes(&bytes)
|
||||
.map_err(|err| format!("Invalid bytes {:?}: {}", bytes, err))?;
|
||||
let pk = PublicKey::from_base58(s)?;
|
||||
Ok(PublicKeyHashable::from(pk))
|
||||
}
|
||||
}
|
||||
|
@ -14,12 +14,21 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
use crate::revoke::RevokeError::IncorrectSignature;
|
||||
use crate::trust::{EXPIRATION_LEN, PK_LEN};
|
||||
use ed25519_dalek::SignatureError;
|
||||
use fluence_identity::key_pair::KeyPair;
|
||||
use fluence_identity::public_key::PublicKey;
|
||||
use fluence_identity::signature::Signature;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::time::Duration;
|
||||
use thiserror::Error as ThisError;
|
||||
|
||||
#[derive(ThisError, Debug)]
|
||||
pub enum RevokeError {
|
||||
#[error("Signature is incorrect: {0}")]
|
||||
IncorrectSignature(#[source] SignatureError),
|
||||
}
|
||||
|
||||
/// "A document" that cancels trust created before.
|
||||
/// TODO delete pk from Revoke (it is already in a trust node)
|
||||
@ -69,13 +78,13 @@ impl Revoke {
|
||||
}
|
||||
|
||||
/// Verifies that revocation is cryptographically correct.
|
||||
pub fn verify(revoke: &Revoke) -> Result<(), String> {
|
||||
pub fn verify(revoke: &Revoke) -> Result<(), RevokeError> {
|
||||
let msg = Revoke::signature_bytes(&revoke.pk, revoke.revoked_at);
|
||||
|
||||
revoke
|
||||
.revoked_by
|
||||
.verify_strict(msg.as_slice(), &revoke.signature)
|
||||
.map_err(|err| format!("Revoke has incorrect signature: {:?}", err))
|
||||
.map_err(IncorrectSignature)
|
||||
}
|
||||
}
|
||||
|
||||
|
105
src/trust.rs
105
src/trust.rs
@ -14,13 +14,18 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
use crate::trust::TrustError::{
|
||||
Base58DecodeError, DecodePublicKeyError, IncorrectTrustLength, ParseError, SignatureError,
|
||||
};
|
||||
use derivative::Derivative;
|
||||
use fluence_identity::key_pair::KeyPair;
|
||||
use fluence_identity::public_key::PublicKey;
|
||||
use fluence_identity::signature::Signature;
|
||||
use fluence_identity::public_key::{PKError, PublicKey};
|
||||
use fluence_identity::signature::{Signature, SignatureError as SigError};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::convert::TryInto;
|
||||
use std::num::ParseIntError;
|
||||
use std::time::Duration;
|
||||
use thiserror::Error as ThisError;
|
||||
|
||||
pub const SIG_LEN: usize = 64;
|
||||
pub const PK_LEN: usize = 32;
|
||||
@ -55,6 +60,46 @@ fn show_sig(sig: &Signature, f: &mut std::fmt::Formatter<'_>) -> Result<(), std:
|
||||
write!(f, "{}", bs58::encode(&sig.to_bytes()).into_string())
|
||||
}
|
||||
|
||||
#[derive(ThisError, Debug)]
|
||||
pub enum TrustError {
|
||||
/// Errors occurred when 'expires_at' date is later then current time.
|
||||
#[error("Trust is expired at: '{0:?}', current time: '{1:?}'")]
|
||||
Expired(Duration, Duration),
|
||||
|
||||
/// Errors occured on signature verification
|
||||
#[error("{0}")]
|
||||
SignatureError(
|
||||
#[from]
|
||||
#[source]
|
||||
ed25519_dalek::SignatureError,
|
||||
),
|
||||
|
||||
/// Errors occured on trust decoding from differrent formats
|
||||
#[error("Cannot decode the public key: {0} in the trust: {1}")]
|
||||
DecodePublicKeyError(String, #[source] PKError),
|
||||
|
||||
#[error("Cannot parse `{0}` field in the trust '{1}': {2}")]
|
||||
ParseError(String, String, #[source] ParseIntError),
|
||||
|
||||
#[error("Cannot decode `{0}` from base58 format in the trust '{1}': {2}")]
|
||||
Base58DecodeError(String, String, #[source] bs58::decode::Error),
|
||||
|
||||
#[error("Cannot decode a signature from bytes: {0}")]
|
||||
SignatureFromBytesError(#[from] SigError),
|
||||
|
||||
#[error("{0}")]
|
||||
PublicKeyError(
|
||||
#[from]
|
||||
#[source]
|
||||
PKError,
|
||||
),
|
||||
|
||||
#[error(
|
||||
"Trust length should be 104: public key(32) + signature(64) + expiration date(8), was: {0}"
|
||||
)]
|
||||
IncorrectTrustLength(usize),
|
||||
}
|
||||
|
||||
impl Trust {
|
||||
#[allow(dead_code)]
|
||||
pub fn new(
|
||||
@ -90,15 +135,19 @@ impl Trust {
|
||||
}
|
||||
|
||||
/// Verifies that authorization is cryptographically correct.
|
||||
pub fn verify(trust: &Trust, issued_by: &PublicKey, cur_time: Duration) -> Result<(), String> {
|
||||
pub fn verify(
|
||||
trust: &Trust,
|
||||
issued_by: &PublicKey,
|
||||
cur_time: Duration,
|
||||
) -> Result<(), TrustError> {
|
||||
if trust.expires_at < cur_time {
|
||||
return Err("Trust in chain is expired.".to_string());
|
||||
return Err(TrustError::Expired(trust.expires_at, cur_time));
|
||||
}
|
||||
|
||||
let msg: &[u8] =
|
||||
&Self::metadata_bytes(&trust.issued_for, trust.expires_at, trust.issued_at);
|
||||
|
||||
KeyPair::verify(issued_by, msg, &trust.signature)?;
|
||||
KeyPair::verify(issued_by, msg, &trust.signature).map_err(SignatureError)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
@ -132,17 +181,15 @@ impl Trust {
|
||||
|
||||
/// Decode a trust from a byte array as produced by `encode`.
|
||||
#[allow(dead_code)]
|
||||
pub fn decode(arr: &[u8]) -> Result<Self, String> {
|
||||
pub fn decode(arr: &[u8]) -> Result<Self, TrustError> {
|
||||
if arr.len() != TRUST_LEN {
|
||||
return Err(
|
||||
format!("Trust length should be 104: public key(32) + signature(64) + expiration date(8), was: {}", arr.len()),
|
||||
);
|
||||
return Err(IncorrectTrustLength(arr.len()));
|
||||
}
|
||||
|
||||
let pk = PublicKey::from_bytes(&arr[0..PK_LEN]).map_err(|err| err.to_string())?;
|
||||
let pk = PublicKey::from_bytes(&arr[0..PK_LEN])?;
|
||||
|
||||
let signature = &arr[PK_LEN..PK_LEN + SIG_LEN];
|
||||
let signature = Signature::from_bytes(signature).map_err(|err| err.to_string())?;
|
||||
let signature = Signature::from_bytes(signature)?;
|
||||
|
||||
let expiration_bytes = &arr[PK_LEN + SIG_LEN..PK_LEN + SIG_LEN + EXPIRATION_LEN];
|
||||
let expiration_date = u64::from_le_bytes(expiration_bytes.try_into().unwrap());
|
||||
@ -154,28 +201,22 @@ impl Trust {
|
||||
|
||||
Ok(Self {
|
||||
issued_for: pk,
|
||||
signature: signature,
|
||||
signature,
|
||||
expires_at: expiration_date,
|
||||
issued_at: issued_date,
|
||||
})
|
||||
}
|
||||
|
||||
fn bs58_str_to_vec(str: &str, field: &str) -> Result<Vec<u8>, String> {
|
||||
bs58::decode(str).into_vec().map_err(|e| {
|
||||
format!(
|
||||
"Cannot decode `{}` from base58 format in the trust '{}': {}",
|
||||
field, str, e
|
||||
)
|
||||
})
|
||||
fn bs58_str_to_vec(str: &str, field: &str) -> Result<Vec<u8>, TrustError> {
|
||||
bs58::decode(str)
|
||||
.into_vec()
|
||||
.map_err(|e| Base58DecodeError(field.to_string(), str.to_string(), e))
|
||||
}
|
||||
|
||||
fn str_to_duration(str: &str, field: &str) -> Result<Duration, String> {
|
||||
let secs = str.parse().map_err(|e| {
|
||||
format!(
|
||||
"Cannot parse `{}` field in the trust '{}': {}",
|
||||
field, str, e
|
||||
)
|
||||
})?;
|
||||
fn str_to_duration(str: &str, field: &str) -> Result<Duration, TrustError> {
|
||||
let secs = str
|
||||
.parse()
|
||||
.map_err(|e| ParseError(field.to_string(), str.to_string(), e))?;
|
||||
Ok(Duration::from_secs(secs))
|
||||
}
|
||||
|
||||
@ -184,19 +225,15 @@ impl Trust {
|
||||
signature: &str,
|
||||
expires_at: &str,
|
||||
issued_at: &str,
|
||||
) -> Result<Self, String> {
|
||||
) -> Result<Self, TrustError> {
|
||||
// PublicKey
|
||||
let issued_for_bytes = Self::bs58_str_to_vec(issued_for, "issued_for")?;
|
||||
let issued_for = PublicKey::from_bytes(issued_for_bytes.as_slice()).map_err(|e| {
|
||||
format!(
|
||||
"Cannot decode the public key: {} in the trust '{}'",
|
||||
issued_for, e
|
||||
)
|
||||
})?;
|
||||
let issued_for = PublicKey::from_bytes(issued_for_bytes.as_slice())
|
||||
.map_err(|e| DecodePublicKeyError(issued_for.to_string(), e))?;
|
||||
|
||||
// 64 bytes signature
|
||||
let signature = Self::bs58_str_to_vec(signature, "signature")?;
|
||||
let signature = Signature::from_bytes(&signature).map_err(|err| err.to_string())?;
|
||||
let signature = Signature::from_bytes(&signature)?;
|
||||
|
||||
// Duration
|
||||
let expires_at = Self::str_to_duration(expires_at, "expires_at")?;
|
||||
|
@ -14,16 +14,25 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
use crate::certificate::Certificate;
|
||||
use crate::public_key_hashable::PublicKeyHashable;
|
||||
use crate::certificate::CertificateError::{CertificateLengthError, Unexpected};
|
||||
use crate::certificate::{Certificate, CertificateError};
|
||||
use crate::public_key_hashable::PublicKeyHashable as PK;
|
||||
use crate::revoke::Revoke;
|
||||
use crate::revoke::RevokeError;
|
||||
use crate::trust::Trust;
|
||||
use crate::trust_graph::TrustGraphError::{
|
||||
CertificateCheckError, EmptyChain, InternalStorageError, NoRoot,
|
||||
};
|
||||
use crate::trust_graph_storage::Storage;
|
||||
use crate::trust_node::{Auth, TrustNode};
|
||||
use crate::StorageError;
|
||||
use fluence_identity::public_key::PublicKey;
|
||||
use std::borrow::Borrow;
|
||||
use std::collections::{HashSet, VecDeque};
|
||||
use std::convert::{From, Into};
|
||||
use std::result::Result;
|
||||
use std::time::Duration;
|
||||
use thiserror::Error as ThisError;
|
||||
|
||||
/// for simplicity, we store `n` where Weight = 1/n^2
|
||||
pub type Weight = u32;
|
||||
@ -32,35 +41,75 @@ pub type Weight = u32;
|
||||
/// TODO serialization/deserialization
|
||||
/// TODO export a certificate from graph
|
||||
#[allow(dead_code)]
|
||||
pub struct TrustGraph {
|
||||
storage: Box<dyn Storage + Send + Sync>,
|
||||
pub struct TrustGraph<S>
|
||||
where
|
||||
S: Storage,
|
||||
{
|
||||
storage: Box<S>,
|
||||
}
|
||||
|
||||
#[derive(ThisError, Debug)]
|
||||
pub enum TrustGraphError {
|
||||
#[error("Internal storage error: {0}")]
|
||||
InternalStorageError(Box<dyn StorageError>),
|
||||
#[error("There is no root for this certificate.")]
|
||||
NoRoot,
|
||||
#[error("Chain is empty")]
|
||||
EmptyChain,
|
||||
#[error("Certificate check error: {0}")]
|
||||
CertificateCheckError(
|
||||
#[from]
|
||||
#[source]
|
||||
CertificateError,
|
||||
),
|
||||
#[error("Error on revoking a trust: {0}")]
|
||||
RevokeCheckError(
|
||||
#[from]
|
||||
#[source]
|
||||
RevokeError,
|
||||
),
|
||||
}
|
||||
|
||||
impl<T: StorageError + 'static> From<T> for TrustGraphError {
|
||||
fn from(err: T) -> Self {
|
||||
InternalStorageError(Box::new(err))
|
||||
}
|
||||
}
|
||||
|
||||
impl From<TrustGraphError> for String {
|
||||
fn from(err: TrustGraphError) -> Self {
|
||||
format!("{}", err)
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
impl TrustGraph {
|
||||
pub fn new(storage: Box<dyn Storage + Send + Sync>) -> Self {
|
||||
Self { storage: storage }
|
||||
impl<S> TrustGraph<S>
|
||||
where
|
||||
S: Storage,
|
||||
{
|
||||
pub fn new(storage: Box<S>) -> Self {
|
||||
Self { storage }
|
||||
}
|
||||
|
||||
/// Insert new root weight
|
||||
pub fn add_root_weight(&mut self, pk: PublicKeyHashable, weight: Weight) {
|
||||
self.storage.add_root_weight(pk, weight)
|
||||
pub fn add_root_weight(&mut self, pk: PK, weight: Weight) -> Result<(), TrustGraphError> {
|
||||
Ok(self.storage.add_root_weight(pk, weight)?)
|
||||
}
|
||||
|
||||
/// Get trust by public key
|
||||
pub fn get(&self, pk: PublicKey) -> Option<TrustNode> {
|
||||
self.storage.get(&pk.into())
|
||||
pub fn get(&self, pk: PublicKey) -> Result<Option<TrustNode>, TrustGraphError> {
|
||||
Ok(self.storage.get(&pk.into())?)
|
||||
}
|
||||
|
||||
// TODO: remove cur_time from api, leave it for tests only
|
||||
/// Certificate is a chain of trusts, add this chain to graph
|
||||
pub fn add<C>(&mut self, cert: C, cur_time: Duration) -> Result<(), String>
|
||||
pub fn add<C>(&mut self, cert: C, cur_time: Duration) -> Result<(), TrustGraphError>
|
||||
where
|
||||
C: Borrow<Certificate>,
|
||||
{
|
||||
let roots: Vec<PublicKey> = self
|
||||
.storage
|
||||
.root_keys()
|
||||
.root_keys()?
|
||||
.iter()
|
||||
.cloned()
|
||||
.map(Into::into)
|
||||
@ -69,18 +118,18 @@ impl TrustGraph {
|
||||
Certificate::verify(cert.borrow(), roots.as_slice(), cur_time)?;
|
||||
|
||||
let mut chain = cert.borrow().chain.iter();
|
||||
let root_trust = chain.next().ok_or("empty chain")?;
|
||||
let root_pk: PublicKeyHashable = root_trust.issued_for.clone().into();
|
||||
let root_trust = chain.next().ok_or(EmptyChain)?;
|
||||
let root_pk: PK = root_trust.issued_for.clone().into();
|
||||
|
||||
// Insert new TrustNode for this root_pk if there wasn't one
|
||||
if self.storage.get(&root_pk).is_none() {
|
||||
let mut trust_node = TrustNode::new(root_trust.issued_for.clone(), cur_time);
|
||||
if self.storage.get(&root_pk)?.is_none() {
|
||||
let mut trust_node = TrustNode::new(root_trust.issued_for, cur_time);
|
||||
let root_auth = Auth {
|
||||
trust: root_trust.clone(),
|
||||
issued_by: root_trust.issued_for.clone(),
|
||||
issued_by: root_trust.issued_for,
|
||||
};
|
||||
trust_node.update_auth(root_auth);
|
||||
self.storage.insert(root_pk, trust_node);
|
||||
self.storage.insert(root_pk, trust_node)?;
|
||||
}
|
||||
|
||||
// Insert remaining trusts to the graph
|
||||
@ -90,11 +139,11 @@ impl TrustGraph {
|
||||
|
||||
let auth = Auth {
|
||||
trust: trust.clone(),
|
||||
issued_by: previous_trust.issued_for.clone(),
|
||||
issued_by: previous_trust.issued_for,
|
||||
};
|
||||
|
||||
self.storage
|
||||
.update_auth(&pk, auth, &root_trust.issued_for, cur_time);
|
||||
.update_auth(&pk, auth, &root_trust.issued_for, cur_time)?;
|
||||
|
||||
previous_trust = trust;
|
||||
}
|
||||
@ -103,31 +152,31 @@ impl TrustGraph {
|
||||
}
|
||||
|
||||
/// Get the maximum weight of trust for one public key.
|
||||
pub fn weight<P>(&self, pk: P) -> Option<Weight>
|
||||
pub fn weight<P>(&self, pk: P) -> Result<Option<Weight>, TrustGraphError>
|
||||
where
|
||||
P: Borrow<PublicKey>,
|
||||
{
|
||||
if let Some(weight) = self.storage.get_root_weight(pk.borrow().as_ref()) {
|
||||
return Some(weight);
|
||||
if let Some(weight) = self.storage.get_root_weight(pk.borrow().as_ref())? {
|
||||
return Ok(Some(weight));
|
||||
}
|
||||
|
||||
let roots: Vec<PublicKey> = self
|
||||
.storage
|
||||
.root_keys()
|
||||
.root_keys()?
|
||||
.iter()
|
||||
.map(|pk| pk.clone().into())
|
||||
.collect();
|
||||
|
||||
// get all possible certificates from the given public key to all roots in the graph
|
||||
let certs = self.get_all_certs(pk, roots.as_slice());
|
||||
self.certificates_weight(certs)
|
||||
let certs = self.get_all_certs(pk, roots.as_slice())?;
|
||||
Ok(self.certificates_weight(certs)?)
|
||||
}
|
||||
|
||||
/// Calculate weight from given certificates
|
||||
/// Returns None if there is no such public key
|
||||
/// or some trust between this key and a root key is revoked.
|
||||
/// TODO handle non-direct revocations
|
||||
pub fn certificates_weight<C, I>(&self, certs: I) -> Option<Weight>
|
||||
pub fn certificates_weight<C, I>(&self, certs: I) -> Result<Option<Weight>, TrustGraphError>
|
||||
where
|
||||
C: Borrow<Certificate>,
|
||||
I: IntoIterator<Item = C>,
|
||||
@ -135,25 +184,31 @@ impl TrustGraph {
|
||||
let mut certs = certs.into_iter().peekable();
|
||||
// if there are no certificates for the given public key, there is no info about this public key
|
||||
// or some elements of possible certificate chains was revoked
|
||||
certs.peek()?;
|
||||
if certs.peek().is_none() {
|
||||
return Ok(None);
|
||||
}
|
||||
|
||||
let mut weight = std::u32::MAX;
|
||||
|
||||
for cert in certs {
|
||||
let cert = cert.borrow();
|
||||
let c = cert.borrow();
|
||||
|
||||
let first = c
|
||||
.chain
|
||||
.first()
|
||||
.ok_or(CertificateCheckError(CertificateLengthError))?;
|
||||
|
||||
let root_weight = self
|
||||
.storage
|
||||
.get_root_weight(cert.chain.first()?.issued_for.as_ref())
|
||||
// This panic shouldn't happen // TODO: why?
|
||||
.expect("first trust in chain must be in root_weights");
|
||||
.get_root_weight(first.issued_for.as_ref())?
|
||||
.ok_or(NoRoot)?;
|
||||
|
||||
// certificate weight = root weight + 1 * every other element in the chain
|
||||
// (except root, so the formula is `root weight + chain length - 1`)
|
||||
weight = std::cmp::min(weight, root_weight + cert.chain.len() as u32 - 1)
|
||||
weight = std::cmp::min(weight, root_weight + c.chain.len() as u32 - 1)
|
||||
}
|
||||
|
||||
Some(weight)
|
||||
Ok(Some(weight))
|
||||
}
|
||||
|
||||
/// BF search for all converging paths (chains) in the graph
|
||||
@ -162,8 +217,8 @@ impl TrustGraph {
|
||||
fn bf_search_paths(
|
||||
&self,
|
||||
node: &TrustNode,
|
||||
roots: HashSet<&PublicKeyHashable>,
|
||||
) -> Vec<Vec<Auth>> {
|
||||
roots: HashSet<&PK>,
|
||||
) -> Result<Vec<Vec<Auth>>, TrustGraphError> {
|
||||
// queue to collect all chains in the trust graph (each chain is a path in the trust graph)
|
||||
let mut chains_queue: VecDeque<Vec<Auth>> = VecDeque::new();
|
||||
|
||||
@ -187,10 +242,8 @@ impl TrustGraph {
|
||||
|
||||
let auths: Vec<Auth> = self
|
||||
.storage
|
||||
.get(&last.issued_by.clone().into())
|
||||
.expect(
|
||||
"there cannot be paths without any nodes after adding verified certificates",
|
||||
)
|
||||
.get(&last.issued_by.clone().into())?
|
||||
.ok_or(CertificateCheckError(Unexpected))?
|
||||
.authorizations()
|
||||
.cloned()
|
||||
.collect();
|
||||
@ -212,7 +265,7 @@ impl TrustGraph {
|
||||
// - that trust must converge to one of the root weights
|
||||
// - there should be more than 1 trust in the chain
|
||||
let self_signed = last.issued_by == last.trust.issued_for;
|
||||
let issued_by: &PublicKeyHashable = last.issued_by.as_ref();
|
||||
let issued_by: &PK = last.issued_by.as_ref();
|
||||
let converges_to_root = roots.contains(issued_by);
|
||||
|
||||
if self_signed && converges_to_root && cur_chain.len() > 1 {
|
||||
@ -220,26 +273,30 @@ impl TrustGraph {
|
||||
}
|
||||
}
|
||||
|
||||
terminated_chains
|
||||
Ok(terminated_chains)
|
||||
}
|
||||
|
||||
// TODO: remove `roots` argument from api, leave it for tests and internal usage only
|
||||
/// Get all possible certificates where `issued_for` will be the last element of the chain
|
||||
/// and one of the destinations is the root of this chain.
|
||||
pub fn get_all_certs<P>(&self, issued_for: P, roots: &[PublicKey]) -> Vec<Certificate>
|
||||
pub fn get_all_certs<P>(
|
||||
&self,
|
||||
issued_for: P,
|
||||
roots: &[PublicKey],
|
||||
) -> Result<Vec<Certificate>, TrustGraphError>
|
||||
where
|
||||
P: Borrow<PublicKey>,
|
||||
{
|
||||
// get all auths (edges) for issued public key
|
||||
let issued_for_node = self.storage.get(issued_for.borrow().as_ref());
|
||||
let issued_for_node = self.storage.get(issued_for.borrow().as_ref())?;
|
||||
|
||||
let roots = roots.iter().map(|pk| pk.as_ref());
|
||||
let keys = self.storage.root_keys();
|
||||
let keys = self.storage.root_keys()?;
|
||||
let roots = keys.iter().chain(roots).collect();
|
||||
|
||||
match issued_for_node {
|
||||
Some(node) => self
|
||||
.bf_search_paths(&node, roots)
|
||||
Some(node) => Ok(self
|
||||
.bf_search_paths(&node, roots)?
|
||||
.iter()
|
||||
.map(|auths| {
|
||||
// TODO: can avoid cloning here by returning &Certificate
|
||||
@ -256,18 +313,18 @@ impl TrustGraph {
|
||||
);
|
||||
c.chain.len() > 1
|
||||
})
|
||||
.collect(),
|
||||
None => Vec::new(),
|
||||
.collect()),
|
||||
None => Ok(Vec::new()),
|
||||
}
|
||||
}
|
||||
|
||||
/// Mark public key as revoked.
|
||||
pub fn revoke(&mut self, revoke: Revoke) -> Result<(), String> {
|
||||
pub fn revoke(&mut self, revoke: Revoke) -> Result<(), TrustGraphError> {
|
||||
Revoke::verify(&revoke)?;
|
||||
|
||||
let pk: PublicKeyHashable = revoke.pk.clone().into();
|
||||
let pk: PK = revoke.pk.clone().into();
|
||||
|
||||
self.storage.revoke(&pk, revoke)
|
||||
Ok(self.storage.revoke(&pk, revoke)?)
|
||||
}
|
||||
|
||||
/// Check information about new certificates and about revoked certificates.
|
||||
@ -313,7 +370,7 @@ mod tests {
|
||||
keys: HashMap<usize, KeyPair>,
|
||||
expires_at: Duration,
|
||||
issued_at: Duration,
|
||||
) -> (Vec<KeyPair>, Certificate) {
|
||||
) -> Result<(Vec<KeyPair>, Certificate), TrustGraphError> {
|
||||
assert!(len > 2);
|
||||
|
||||
let root_kp = KeyPair::generate();
|
||||
@ -335,18 +392,17 @@ mod tests {
|
||||
// TODO: why `issued_at = issued_at - 60 seconds`?
|
||||
issued_at.checked_sub(Duration::from_secs(60)).unwrap(),
|
||||
current_time(),
|
||||
)
|
||||
.unwrap();
|
||||
)?;
|
||||
key_pairs.push(kp);
|
||||
}
|
||||
|
||||
(key_pairs, cert)
|
||||
Ok((key_pairs, cert))
|
||||
}
|
||||
|
||||
fn generate_cert_with_len(
|
||||
len: usize,
|
||||
keys: HashMap<usize, KeyPair>,
|
||||
) -> (Vec<KeyPair>, Certificate) {
|
||||
) -> Result<(Vec<KeyPair>, Certificate), TrustGraphError> {
|
||||
let cur_time = current_time();
|
||||
let far_future = cur_time.checked_add(one_minute()).unwrap();
|
||||
|
||||
@ -390,7 +446,8 @@ mod tests {
|
||||
chain_keys.insert(5, key_pair1.clone());
|
||||
chain_keys.insert(6, key_pair2.clone());
|
||||
|
||||
let (key_pairs1, cert1) = generate_cert_with(10, chain_keys, far_future * 2, far_future);
|
||||
let (key_pairs1, cert1) =
|
||||
generate_cert_with(10, chain_keys, far_future * 2, far_future).expect("");
|
||||
|
||||
// Use key_pair1 and key_pair2 for 7th and 8th trust in the cert chain
|
||||
let mut chain_keys = HashMap::new();
|
||||
@ -398,7 +455,7 @@ mod tests {
|
||||
chain_keys.insert(8, key_pair2.clone());
|
||||
|
||||
let (key_pairs2, cert2) =
|
||||
generate_cert_with(10, chain_keys, far_far_future * 2, far_far_future);
|
||||
generate_cert_with(10, chain_keys, far_far_future * 2, far_far_future).unwrap();
|
||||
|
||||
let st = Box::new(InMemoryStorage::new());
|
||||
let mut graph = TrustGraph::new(st);
|
||||
@ -408,7 +465,7 @@ mod tests {
|
||||
graph.add_root_weight(root2_pk.into(), 0);
|
||||
graph.add(cert1, cur_time).unwrap();
|
||||
|
||||
let node2 = graph.get(key_pair2.public_key()).unwrap();
|
||||
let node2 = graph.get(key_pair2.public_key()).unwrap().unwrap();
|
||||
let auth_by_kp1 = node2
|
||||
.authorizations()
|
||||
.find(|a| a.issued_by == key_pair1.public_key())
|
||||
@ -418,7 +475,7 @@ mod tests {
|
||||
|
||||
graph.add(cert2, cur_time).unwrap();
|
||||
|
||||
let node2 = graph.get(key_pair2.public_key()).unwrap();
|
||||
let node2 = graph.get(key_pair2.public_key()).unwrap().unwrap();
|
||||
let auth_by_kp1 = node2
|
||||
.authorizations()
|
||||
.find(|a| a.issued_by == key_pair1.public_key())
|
||||
@ -429,7 +486,7 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn test_one_cert_in_graph() {
|
||||
let (key_pairs, cert1) = generate_cert_with_len(10, HashMap::new());
|
||||
let (key_pairs, cert1) = generate_cert_with_len(10, HashMap::new()).unwrap();
|
||||
let last_trust = cert1.chain[9].clone();
|
||||
|
||||
let st = Box::new(InMemoryStorage::new());
|
||||
@ -440,16 +497,16 @@ mod tests {
|
||||
|
||||
graph.add(cert1, current_time()).unwrap();
|
||||
|
||||
let w1 = graph.weight(key_pairs[0].public_key()).unwrap();
|
||||
let w1 = graph.weight(key_pairs[0].public_key()).unwrap().unwrap();
|
||||
assert_eq!(w1, 1);
|
||||
|
||||
let w2 = graph.weight(key_pairs[1].public_key()).unwrap();
|
||||
let w2 = graph.weight(key_pairs[1].public_key()).unwrap().unwrap();
|
||||
assert_eq!(w2, 2);
|
||||
|
||||
let w3 = graph.weight(key_pairs[9].public_key()).unwrap();
|
||||
let w3 = graph.weight(key_pairs[9].public_key()).unwrap().unwrap();
|
||||
assert_eq!(w3, 10);
|
||||
|
||||
let node = graph.get(key_pairs[9].public_key()).unwrap();
|
||||
let node = graph.get(key_pairs[9].public_key()).unwrap().unwrap();
|
||||
let auths: Vec<&Auth> = node.authorizations().collect();
|
||||
|
||||
assert_eq!(auths.len(), 1);
|
||||
@ -467,14 +524,14 @@ mod tests {
|
||||
chain_keys.insert(5, key_pair2.clone());
|
||||
chain_keys.insert(7, key_pair3.clone());
|
||||
|
||||
let (key_pairs1, cert1) = generate_cert_with_len(10, chain_keys);
|
||||
let (key_pairs1, cert1) = generate_cert_with_len(10, chain_keys).unwrap();
|
||||
|
||||
let mut chain_keys = HashMap::new();
|
||||
chain_keys.insert(7, key_pair1.clone());
|
||||
chain_keys.insert(6, key_pair2.clone());
|
||||
chain_keys.insert(5, key_pair3.clone());
|
||||
|
||||
let (key_pairs2, cert2) = generate_cert_with_len(10, chain_keys);
|
||||
let (key_pairs2, cert2) = generate_cert_with_len(10, chain_keys).unwrap();
|
||||
|
||||
let st = Box::new(InMemoryStorage::new());
|
||||
let mut graph = TrustGraph::new(st);
|
||||
@ -494,12 +551,12 @@ mod tests {
|
||||
let revoke2 = Revoke::create(&key_pairs2[5], key_pairs2[6].public_key(), current_time());
|
||||
graph.revoke(revoke2).unwrap();
|
||||
|
||||
let w1 = graph.weight(key_pair1.public_key()).unwrap();
|
||||
let w1 = graph.weight(key_pair1.public_key()).unwrap().unwrap();
|
||||
// all upper trusts are revoked for this public key
|
||||
let w2 = graph.weight(key_pair2.public_key());
|
||||
let w3 = graph.weight(key_pair3.public_key()).unwrap();
|
||||
let w_last1 = graph.weight(last_pk1).unwrap();
|
||||
let w_last2 = graph.weight(last_pk2).unwrap();
|
||||
let w2 = graph.weight(key_pair2.public_key()).unwrap();
|
||||
let w3 = graph.weight(key_pair3.public_key()).unwrap().unwrap();
|
||||
let w_last1 = graph.weight(last_pk1).unwrap().unwrap();
|
||||
let w_last2 = graph.weight(last_pk2).unwrap().unwrap();
|
||||
|
||||
assert_eq!(w1, 4);
|
||||
assert_eq!(w2.is_none(), true);
|
||||
@ -510,7 +567,7 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn test_get_one_cert() {
|
||||
let (key_pairs, cert) = generate_cert_with_len(5, HashMap::new());
|
||||
let (key_pairs, cert) = generate_cert_with_len(5, HashMap::new()).unwrap();
|
||||
|
||||
let st = Box::new(InMemoryStorage::new());
|
||||
let mut graph = TrustGraph::new(st);
|
||||
@ -519,7 +576,9 @@ mod tests {
|
||||
|
||||
graph.add(cert.clone(), current_time()).unwrap();
|
||||
|
||||
let certs = graph.get_all_certs(key_pairs.last().unwrap().public_key(), &[root1_pk]);
|
||||
let certs = graph
|
||||
.get_all_certs(key_pairs.last().unwrap().public_key(), &[root1_pk])
|
||||
.unwrap();
|
||||
|
||||
assert_eq!(certs.len(), 1);
|
||||
assert_eq!(certs[0], cert);
|
||||
@ -527,7 +586,7 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn test_chain_from_root_to_another_root() {
|
||||
let (_, cert) = generate_cert_with_len(6, HashMap::new());
|
||||
let (_, cert) = generate_cert_with_len(6, HashMap::new()).unwrap();
|
||||
|
||||
let st = Box::new(InMemoryStorage::new());
|
||||
let mut graph = TrustGraph::new(st);
|
||||
@ -539,7 +598,7 @@ mod tests {
|
||||
graph.add(cert.clone(), current_time()).unwrap();
|
||||
|
||||
let t = cert.chain[5].clone();
|
||||
let certs = graph.get_all_certs(t.issued_for, &[]);
|
||||
let certs = graph.get_all_certs(t.issued_for, &[]).unwrap();
|
||||
|
||||
assert_eq!(certs.len(), 1);
|
||||
}
|
||||
@ -555,21 +614,21 @@ mod tests {
|
||||
chain_keys.insert(3, key_pair2.clone());
|
||||
chain_keys.insert(4, key_pair3.clone());
|
||||
|
||||
let (key_pairs1, cert1) = generate_cert_with_len(5, chain_keys);
|
||||
let (key_pairs1, cert1) = generate_cert_with_len(5, chain_keys).unwrap();
|
||||
|
||||
let mut chain_keys = HashMap::new();
|
||||
chain_keys.insert(4, key_pair1.clone());
|
||||
chain_keys.insert(3, key_pair2.clone());
|
||||
chain_keys.insert(2, key_pair3.clone());
|
||||
|
||||
let (key_pairs2, cert2) = generate_cert_with_len(5, chain_keys);
|
||||
let (key_pairs2, cert2) = generate_cert_with_len(5, chain_keys).unwrap();
|
||||
|
||||
let mut chain_keys = HashMap::new();
|
||||
chain_keys.insert(3, key_pair1.clone());
|
||||
chain_keys.insert(4, key_pair2.clone());
|
||||
chain_keys.insert(2, key_pair3.clone());
|
||||
|
||||
let (key_pairs3, cert3) = generate_cert_with_len(5, chain_keys);
|
||||
let (key_pairs3, cert3) = generate_cert_with_len(5, chain_keys).unwrap();
|
||||
|
||||
let st = Box::new(InMemoryStorage::new());
|
||||
let mut graph = TrustGraph::new(st);
|
||||
@ -586,17 +645,23 @@ mod tests {
|
||||
|
||||
let roots_values = [root1_pk, root2_pk, root3_pk];
|
||||
|
||||
let certs1 = graph.get_all_certs(key_pair1.public_key(), &roots_values);
|
||||
let certs1 = graph
|
||||
.get_all_certs(key_pair1.public_key(), &roots_values)
|
||||
.unwrap();
|
||||
let lenghts1: Vec<usize> = certs1.iter().map(|c| c.chain.len()).collect();
|
||||
let check_lenghts1: Vec<usize> = vec![3, 4, 4, 5, 5];
|
||||
assert_eq!(lenghts1, check_lenghts1);
|
||||
|
||||
let certs2 = graph.get_all_certs(key_pair2.public_key(), &roots_values);
|
||||
let certs2 = graph
|
||||
.get_all_certs(key_pair2.public_key(), &roots_values)
|
||||
.unwrap();
|
||||
let lenghts2: Vec<usize> = certs2.iter().map(|c| c.chain.len()).collect();
|
||||
let check_lenghts2: Vec<usize> = vec![4, 4, 4, 5, 5];
|
||||
assert_eq!(lenghts2, check_lenghts2);
|
||||
|
||||
let certs3 = graph.get_all_certs(key_pair3.public_key(), &roots_values);
|
||||
let certs3 = graph
|
||||
.get_all_certs(key_pair3.public_key(), &roots_values)
|
||||
.unwrap();
|
||||
let lenghts3: Vec<usize> = certs3.iter().map(|c| c.chain.len()).collect();
|
||||
let check_lenghts3: Vec<usize> = vec![3, 3, 5];
|
||||
assert_eq!(lenghts3, check_lenghts3);
|
||||
|
@ -1,32 +1,39 @@
|
||||
use crate::public_key_hashable::PublicKeyHashable;
|
||||
use crate::public_key_hashable::PublicKeyHashable as PK;
|
||||
use crate::revoke::Revoke;
|
||||
use crate::trust_graph::Weight;
|
||||
use crate::trust_graph_storage::InMemoryStorageError::RevokeError;
|
||||
use crate::trust_node::{Auth, TrustNode};
|
||||
use fluence_identity::public_key::PublicKey;
|
||||
use std::collections::HashMap;
|
||||
use std::fmt::Display;
|
||||
use std::time::Duration;
|
||||
use thiserror::Error as ThisError;
|
||||
|
||||
pub trait StorageError: std::error::Error + Display {}
|
||||
|
||||
pub trait Storage {
|
||||
fn get(&self, pk: &PublicKeyHashable) -> Option<TrustNode>;
|
||||
fn insert(&mut self, pk: PublicKeyHashable, node: TrustNode);
|
||||
type Error: StorageError + 'static;
|
||||
|
||||
fn get_root_weight(&self, pk: &PublicKeyHashable) -> Option<Weight>;
|
||||
fn add_root_weight(&mut self, pk: PublicKeyHashable, weight: Weight);
|
||||
fn root_keys(&self) -> Vec<PublicKeyHashable>;
|
||||
fn revoke(&mut self, pk: &PublicKeyHashable, revoke: Revoke) -> Result<(), String>;
|
||||
fn get(&self, pk: &PK) -> Result<Option<TrustNode>, Self::Error>;
|
||||
fn insert(&mut self, pk: PK, node: TrustNode) -> Result<(), Self::Error>;
|
||||
|
||||
fn get_root_weight(&self, pk: &PK) -> Result<Option<Weight>, Self::Error>;
|
||||
fn add_root_weight(&mut self, pk: PK, weight: Weight) -> Result<(), Self::Error>;
|
||||
fn root_keys(&self) -> Result<Vec<PK>, Self::Error>;
|
||||
fn revoke(&mut self, pk: &PK, revoke: Revoke) -> Result<(), Self::Error>;
|
||||
fn update_auth(
|
||||
&mut self,
|
||||
pk: &PublicKeyHashable,
|
||||
pk: &PK,
|
||||
auth: Auth,
|
||||
issued_for: &PublicKey,
|
||||
cur_time: Duration,
|
||||
);
|
||||
) -> Result<(), Self::Error>;
|
||||
}
|
||||
|
||||
#[derive(Debug, Default)]
|
||||
pub struct InMemoryStorage {
|
||||
nodes: HashMap<PublicKeyHashable, TrustNode>,
|
||||
root_weights: HashMap<PublicKeyHashable, Weight>,
|
||||
nodes: HashMap<PK, TrustNode>,
|
||||
root_weights: HashMap<PK, Weight>,
|
||||
}
|
||||
|
||||
impl InMemoryStorage {
|
||||
@ -38,7 +45,7 @@ impl InMemoryStorage {
|
||||
.collect();
|
||||
Self {
|
||||
nodes: HashMap::new(),
|
||||
root_weights: root_weights,
|
||||
root_weights,
|
||||
}
|
||||
}
|
||||
|
||||
@ -51,52 +58,68 @@ impl InMemoryStorage {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(ThisError, Debug)]
|
||||
pub enum InMemoryStorageError {
|
||||
#[error("InMemoryStorageError::RevokeError {0:?}")]
|
||||
RevokeError(String),
|
||||
}
|
||||
|
||||
impl StorageError for InMemoryStorageError {}
|
||||
|
||||
impl Storage for InMemoryStorage {
|
||||
fn get(&self, pk: &PublicKeyHashable) -> Option<TrustNode> {
|
||||
self.nodes.get(pk).cloned()
|
||||
type Error = InMemoryStorageError;
|
||||
|
||||
fn get(&self, pk: &PK) -> Result<Option<TrustNode>, Self::Error> {
|
||||
Ok(self.nodes.get(pk).cloned())
|
||||
}
|
||||
|
||||
fn insert(&mut self, pk: PublicKeyHashable, node: TrustNode) {
|
||||
&self.nodes.insert(pk, node);
|
||||
fn insert(&mut self, pk: PK, node: TrustNode) -> Result<(), Self::Error> {
|
||||
self.nodes.insert(pk, node);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn get_root_weight(&self, pk: &PublicKeyHashable) -> Option<Weight> {
|
||||
self.root_weights.get(pk).cloned()
|
||||
fn get_root_weight(&self, pk: &PK) -> Result<Option<Weight>, Self::Error> {
|
||||
Ok(self.root_weights.get(pk).cloned())
|
||||
}
|
||||
|
||||
fn add_root_weight(&mut self, pk: PublicKeyHashable, weight: Weight) {
|
||||
&self.root_weights.insert(pk, weight);
|
||||
fn add_root_weight(&mut self, pk: PK, weight: Weight) -> Result<(), Self::Error> {
|
||||
self.root_weights.insert(pk, weight);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn root_keys(&self) -> Vec<PublicKeyHashable> {
|
||||
self.root_weights.keys().cloned().map(Into::into).collect()
|
||||
fn root_keys(&self) -> Result<Vec<PK>, Self::Error> {
|
||||
Ok(self.root_weights.keys().cloned().map(Into::into).collect())
|
||||
}
|
||||
|
||||
fn revoke(&mut self, pk: &PublicKeyHashable, revoke: Revoke) -> Result<(), String> {
|
||||
fn revoke(&mut self, pk: &PK, revoke: Revoke) -> Result<(), Self::Error> {
|
||||
match self.nodes.get_mut(&pk) {
|
||||
Some(trust_node) => {
|
||||
trust_node.update_revoke(revoke);
|
||||
Ok(())
|
||||
}
|
||||
None => Err("There is no trust with such PublicKey".to_string()),
|
||||
None => Err(RevokeError(
|
||||
"There is no trust with such PublicKey".to_string(),
|
||||
)),
|
||||
}
|
||||
}
|
||||
|
||||
fn update_auth(
|
||||
&mut self,
|
||||
pk: &PublicKeyHashable,
|
||||
pk: &PK,
|
||||
auth: Auth,
|
||||
issued_for: &PublicKey,
|
||||
cur_time: Duration,
|
||||
) {
|
||||
) -> Result<(), Self::Error> {
|
||||
match self.nodes.get_mut(&pk) {
|
||||
Some(trust_node) => {
|
||||
trust_node.update_auth(auth);
|
||||
Ok(())
|
||||
}
|
||||
None => {
|
||||
let mut trust_node = TrustNode::new(issued_for.clone(), cur_time);
|
||||
let mut trust_node = TrustNode::new(*issued_for, cur_time);
|
||||
trust_node.update_auth(auth);
|
||||
self.nodes.insert(pk.clone(), trust_node);
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
3
bin/Cargo.lock → wasm/Cargo.lock
generated
3
bin/Cargo.lock → wasm/Cargo.lock
generated
@ -441,6 +441,7 @@ dependencies = [
|
||||
"serde_json",
|
||||
"serde_with",
|
||||
"signature",
|
||||
"thiserror",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -1537,6 +1538,7 @@ dependencies = [
|
||||
"serde_json",
|
||||
"serde_with",
|
||||
"signature",
|
||||
"thiserror",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -1556,6 +1558,7 @@ dependencies = [
|
||||
"rmp-serde",
|
||||
"serde_bencode",
|
||||
"serde_json",
|
||||
"thiserror",
|
||||
"trust-graph",
|
||||
]
|
||||
|
@ -25,3 +25,4 @@ bs58 = "0.3.1"
|
||||
rmp-serde = "0.15.0"
|
||||
bincode = "1.3.1"
|
||||
serde_bencode = "^0.2.3"
|
||||
thiserror = "1.0.23"
|
8
wasm/run-repl.sh
Executable file
8
wasm/run-repl.sh
Executable file
@ -0,0 +1,8 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
fce build
|
||||
|
||||
rm artifacts/trust-graph.wasm
|
||||
mv -f target/wasm32-wasi/debug/trust-graph.wasm artifacts/
|
||||
RUST_LOG="info" fce-repl Config.toml
|
101
wasm/src/dto.rs
Normal file
101
wasm/src/dto.rs
Normal file
@ -0,0 +1,101 @@
|
||||
use fluence::fce;
|
||||
use fluence_identity::public_key::PKError;
|
||||
use fluence_identity::signature::SignatureError;
|
||||
use fluence_identity::{PublicKey, Signature};
|
||||
use std::convert::TryFrom;
|
||||
use std::time::Duration;
|
||||
use thiserror::Error as ThisError;
|
||||
|
||||
#[derive(ThisError, Debug)]
|
||||
pub enum DtoConversionError {
|
||||
#[error("Cannot convert base58 string to bytes: {0}")]
|
||||
Base58Error(
|
||||
#[from]
|
||||
#[source]
|
||||
bs58::decode::Error,
|
||||
),
|
||||
#[error("Cannot convert string to PublicKey: {0}")]
|
||||
PublicKeyDecodeError(
|
||||
#[from]
|
||||
#[source]
|
||||
PKError,
|
||||
),
|
||||
#[error("Cannot convert string to PublicKey: {0}")]
|
||||
SignatureDecodeError(
|
||||
#[from]
|
||||
#[source]
|
||||
SignatureError,
|
||||
),
|
||||
}
|
||||
|
||||
#[fce]
|
||||
pub struct Certificate {
|
||||
pub chain: Vec<Trust>,
|
||||
}
|
||||
|
||||
impl From<trust_graph::Certificate> for Certificate {
|
||||
fn from(c: trust_graph::Certificate) -> Self {
|
||||
let chain: Vec<Trust> = c.chain.into_iter().map(|t| t.into()).collect();
|
||||
return Certificate { chain };
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<Certificate> for trust_graph::Certificate {
|
||||
type Error = DtoConversionError;
|
||||
|
||||
fn try_from(c: Certificate) -> Result<Self, Self::Error> {
|
||||
let chain: Result<Vec<trust_graph::Trust>, DtoConversionError> = c
|
||||
.chain
|
||||
.into_iter()
|
||||
.map(|t| trust_graph::Trust::try_from(t))
|
||||
.collect();
|
||||
let chain = chain?;
|
||||
return Ok(trust_graph::Certificate { chain });
|
||||
}
|
||||
}
|
||||
|
||||
#[fce]
|
||||
pub struct Trust {
|
||||
/// For whom this certificate is issued, base58
|
||||
pub issued_for: String,
|
||||
/// Expiration date of a trust, in secs
|
||||
pub expires_at: u64,
|
||||
/// Signature of a previous trust in a chain.
|
||||
/// Signature is self-signed if it is a root trust, base58
|
||||
pub signature: String,
|
||||
/// Creation time of a trust, in secs
|
||||
pub issued_at: u64,
|
||||
}
|
||||
|
||||
impl TryFrom<Trust> for trust_graph::Trust {
|
||||
type Error = DtoConversionError;
|
||||
|
||||
fn try_from(t: Trust) -> Result<Self, Self::Error> {
|
||||
let issued_for = PublicKey::from_base58(&t.issued_for)?;
|
||||
let signature = bs58::decode(&t.signature).into_vec()?;
|
||||
let signature = Signature::from_bytes(&signature)?;
|
||||
let expires_at = Duration::from_secs(t.expires_at);
|
||||
let issued_at = Duration::from_secs(t.issued_at);
|
||||
return Ok(trust_graph::Trust {
|
||||
issued_for,
|
||||
expires_at,
|
||||
signature,
|
||||
issued_at,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
impl From<trust_graph::Trust> for Trust {
|
||||
fn from(t: trust_graph::Trust) -> Self {
|
||||
let issued_for = bs58::encode(t.issued_for.to_bytes()).into_string();
|
||||
let signature = bs58::encode(t.signature.to_bytes()).into_string();
|
||||
let expires_at = t.expires_at.as_secs();
|
||||
let issued_at = t.issued_at.as_secs();
|
||||
return Trust {
|
||||
issued_for,
|
||||
expires_at,
|
||||
signature,
|
||||
issued_at,
|
||||
};
|
||||
}
|
||||
}
|
@ -1,6 +1,9 @@
|
||||
use fluence::WasmLoggerBuilder;
|
||||
|
||||
mod dto;
|
||||
mod results;
|
||||
mod service_api;
|
||||
mod service_impl;
|
||||
mod storage_impl;
|
||||
|
||||
pub fn main() {
|
93
wasm/src/results.rs
Normal file
93
wasm/src/results.rs
Normal file
@ -0,0 +1,93 @@
|
||||
use crate::dto::Certificate;
|
||||
use crate::service_impl::ServiceError;
|
||||
use fluence::fce;
|
||||
|
||||
#[fce]
|
||||
pub struct InsertResult {
|
||||
pub ret_code: u32,
|
||||
pub error: String,
|
||||
}
|
||||
|
||||
impl From<Result<(), ServiceError>> for InsertResult {
|
||||
fn from(result: Result<(), ServiceError>) -> Self {
|
||||
match result {
|
||||
Ok(()) => InsertResult {
|
||||
ret_code: 0,
|
||||
error: "".to_string(),
|
||||
},
|
||||
Err(e) => InsertResult {
|
||||
ret_code: 1,
|
||||
error: format!("{}", e),
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[fce]
|
||||
pub struct WeightResult {
|
||||
pub ret_code: u32,
|
||||
pub weight: Vec<u32>,
|
||||
pub error: String,
|
||||
}
|
||||
|
||||
impl From<Result<Option<u32>, ServiceError>> for WeightResult {
|
||||
fn from(result: Result<Option<u32>, ServiceError>) -> Self {
|
||||
match result {
|
||||
Ok(wo) => WeightResult {
|
||||
ret_code: 0,
|
||||
weight: wo.map(|w| vec![w]).unwrap_or(vec![]),
|
||||
error: "".to_string(),
|
||||
},
|
||||
Err(e) => WeightResult {
|
||||
ret_code: 1,
|
||||
weight: vec![],
|
||||
error: format!("{}", e),
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[fce]
|
||||
pub struct AllCertsResult {
|
||||
pub ret_code: u32,
|
||||
pub certificates: Vec<Certificate>,
|
||||
pub error: String,
|
||||
}
|
||||
|
||||
impl From<Result<Vec<Certificate>, ServiceError>> for AllCertsResult {
|
||||
fn from(result: Result<Vec<Certificate>, ServiceError>) -> Self {
|
||||
match result {
|
||||
Ok(certs) => AllCertsResult {
|
||||
ret_code: 0,
|
||||
certificates: certs,
|
||||
error: "".to_string(),
|
||||
},
|
||||
Err(e) => AllCertsResult {
|
||||
ret_code: 1,
|
||||
certificates: vec![],
|
||||
error: format!("{}", e),
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[fce]
|
||||
pub struct AddRootResult {
|
||||
pub ret_code: u32,
|
||||
pub error: String,
|
||||
}
|
||||
|
||||
impl From<Result<(), ServiceError>> for AddRootResult {
|
||||
fn from(result: Result<(), ServiceError>) -> Self {
|
||||
match result {
|
||||
Ok(()) => AddRootResult {
|
||||
ret_code: 0,
|
||||
error: "".to_string(),
|
||||
},
|
||||
Err(e) => AddRootResult {
|
||||
ret_code: 1,
|
||||
error: format!("{}", e),
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
75
wasm/src/service_api.rs
Normal file
75
wasm/src/service_api.rs
Normal file
@ -0,0 +1,75 @@
|
||||
use crate::dto::Certificate;
|
||||
use crate::results::{AddRootResult, AllCertsResult, InsertResult, WeightResult};
|
||||
use crate::service_impl::{
|
||||
add_root_impl, get_all_certs_impl, get_weight_impl, insert_cert_impl, insert_cert_impl_raw,
|
||||
};
|
||||
use fluence::{fce, CallParameters};
|
||||
|
||||
#[fce]
|
||||
/// add a certificate in string representation to trust graph if it is valid
|
||||
/// see `trust_graph::Certificate` class for string encoding/decoding
|
||||
// TODO change `current_time` to time service
|
||||
fn insert_cert_raw(certificate: String, current_time: u64) -> InsertResult {
|
||||
insert_cert_impl_raw(certificate, current_time).into()
|
||||
}
|
||||
|
||||
#[fce]
|
||||
/// add a certificate in JSON representation to trust graph if it is valid
|
||||
/// see `dto::Certificate` class for structure
|
||||
fn insert_cert(certificate: Certificate, current_time: u64) -> InsertResult {
|
||||
insert_cert_impl(certificate, current_time).into()
|
||||
}
|
||||
|
||||
#[fce]
|
||||
fn get_weight(public_key: String) -> WeightResult {
|
||||
get_weight_impl(public_key).into()
|
||||
}
|
||||
|
||||
#[fce]
|
||||
fn get_all_certs(issued_for: String) -> AllCertsResult {
|
||||
get_all_certs_impl(issued_for).into()
|
||||
}
|
||||
|
||||
#[fce]
|
||||
/// could add only a host of a trust graph service
|
||||
fn add_root(pk: String, weight: u32) -> AddRootResult {
|
||||
let call_parameters: CallParameters = fluence::get_call_parameters();
|
||||
let init_peer_id = call_parameters.init_peer_id.clone();
|
||||
if call_parameters.host_id == init_peer_id {
|
||||
add_root_impl(pk, weight).into()
|
||||
} else {
|
||||
return AddRootResult {
|
||||
ret_code: 1,
|
||||
error: "Root could add only a host of trust graph service".to_string(),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
// TODO rewrite test after #[fce_test] will be implemented
|
||||
// #[fce]
|
||||
// fn test() -> String {
|
||||
// let mut tg = get_data().lock();
|
||||
//
|
||||
// let root_kp = KeyPair::generate();
|
||||
// let root_kp2 = KeyPair::generate();
|
||||
// let second_kp = KeyPair::generate();
|
||||
//
|
||||
// let expires_at = Duration::new(15, 15);
|
||||
// let issued_at = Duration::new(5, 5);
|
||||
//
|
||||
// let cert = trust_graph::Certificate::issue_root(
|
||||
// &root_kp,
|
||||
// second_kp.public_key(),
|
||||
// expires_at,
|
||||
// issued_at,
|
||||
// );
|
||||
// tg.add_root_weight(root_kp.public().into(), 0).unwrap();
|
||||
// tg.add_root_weight(root_kp2.public().into(), 1).unwrap();
|
||||
// tg.add(cert, Duration::new(10, 10)).unwrap();
|
||||
//
|
||||
// let a = tg.get(second_kp.public_key()).unwrap();
|
||||
// let str = format!("{:?}", a);
|
||||
// log::info!("{}", &str);
|
||||
//
|
||||
// str
|
||||
// }
|
86
wasm/src/service_impl.rs
Normal file
86
wasm/src/service_impl.rs
Normal file
@ -0,0 +1,86 @@
|
||||
use crate::dto::{Certificate, DtoConversionError};
|
||||
use crate::storage_impl::get_data;
|
||||
use fluence_identity::public_key::PKError;
|
||||
use fluence_identity::PublicKey;
|
||||
use std::convert::{Into, TryInto};
|
||||
use std::str::FromStr;
|
||||
use std::time::Duration;
|
||||
use thiserror::Error as ThisError;
|
||||
use trust_graph::{CertificateError, TrustGraphError};
|
||||
|
||||
#[derive(ThisError, Debug)]
|
||||
pub enum ServiceError {
|
||||
#[error("{0}")]
|
||||
PublicKeyDecodeError(
|
||||
#[from]
|
||||
#[source]
|
||||
PKError,
|
||||
),
|
||||
#[error("{0}")]
|
||||
TGError(
|
||||
#[from]
|
||||
#[source]
|
||||
TrustGraphError,
|
||||
),
|
||||
#[error("{0}")]
|
||||
CertError(
|
||||
#[from]
|
||||
#[source]
|
||||
CertificateError,
|
||||
),
|
||||
#[error("{0}")]
|
||||
DtoError(
|
||||
#[from]
|
||||
#[source]
|
||||
DtoConversionError,
|
||||
),
|
||||
}
|
||||
|
||||
pub fn get_weight_impl(public_key: String) -> Result<Option<u32>, ServiceError> {
|
||||
let tg = get_data().lock();
|
||||
let public_key = string_to_public_key(public_key)?;
|
||||
let weight = tg.weight(public_key)?;
|
||||
Ok(weight)
|
||||
}
|
||||
|
||||
fn add_cert(certificate: trust_graph::Certificate, duration: u64) -> Result<(), ServiceError> {
|
||||
let duration = Duration::from_millis(duration);
|
||||
let mut tg = get_data().lock();
|
||||
tg.add(certificate, duration)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn insert_cert_impl_raw(certificate: String, duration: u64) -> Result<(), ServiceError> {
|
||||
let certificate = trust_graph::Certificate::from_str(&certificate)?;
|
||||
|
||||
add_cert(certificate, duration)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn string_to_public_key(public_key: String) -> Result<PublicKey, ServiceError> {
|
||||
let public_key = PublicKey::from_base58(&public_key)?;
|
||||
|
||||
Ok(public_key)
|
||||
}
|
||||
|
||||
pub fn get_all_certs_impl(issued_for: String) -> Result<Vec<Certificate>, ServiceError> {
|
||||
let tg = get_data().lock();
|
||||
|
||||
let public_key = string_to_public_key(issued_for)?;
|
||||
let certs = tg.get_all_certs(public_key, &[])?;
|
||||
Ok(certs.into_iter().map(|c| c.into()).collect())
|
||||
}
|
||||
|
||||
pub fn insert_cert_impl(certificate: Certificate, duration: u64) -> Result<(), ServiceError> {
|
||||
let certificate: trust_graph::Certificate = certificate.try_into()?;
|
||||
|
||||
add_cert(certificate, duration)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn add_root_impl(pk: String, weight: u32) -> Result<(), ServiceError> {
|
||||
let mut tg = get_data().lock();
|
||||
let pk = PublicKey::from_base58(&pk)?.into();
|
||||
tg.add_root_weight(pk, weight)?;
|
||||
Ok(())
|
||||
}
|
229
wasm/src/storage_impl.rs
Normal file
229
wasm/src/storage_impl.rs
Normal file
@ -0,0 +1,229 @@
|
||||
// store list of trusts
|
||||
// check if trust is already in list before adding
|
||||
// if there is an older trust - don't add received trust
|
||||
|
||||
use crate::storage_impl::SQLiteStorageError::{
|
||||
PublcKeyNotFound, PublicKeyConversion, PublicKeyFromStr, TrustNodeConversion,
|
||||
WeightConversionDB,
|
||||
};
|
||||
use core::convert::TryFrom;
|
||||
use fce_sqlite_connector;
|
||||
use fce_sqlite_connector::Connection;
|
||||
use fce_sqlite_connector::Error as InternalSqliteError;
|
||||
use fce_sqlite_connector::Value;
|
||||
use fluence_identity::public_key::PublicKey;
|
||||
use once_cell::sync::OnceCell;
|
||||
use parking_lot::Mutex;
|
||||
use rmp_serde::decode::Error as RmpDecodeError;
|
||||
use rmp_serde::encode::Error as RmpEncodeError;
|
||||
use std::convert::From;
|
||||
use std::str::FromStr;
|
||||
use std::time::Duration;
|
||||
use thiserror::Error as ThisError;
|
||||
use trust_graph::{
|
||||
Auth, PublicKeyHashable as PK, Revoke, Storage, StorageError, TrustGraph, TrustNode, Weight,
|
||||
};
|
||||
|
||||
static INSTANCE: OnceCell<Mutex<TrustGraph<SQLiteStorage>>> = OnceCell::new();
|
||||
|
||||
pub fn get_data() -> &'static Mutex<TrustGraph<SQLiteStorage>> {
|
||||
INSTANCE.get_or_init(|| {
|
||||
let db_path = "/tmp/users123123.sqlite";
|
||||
let connection = fce_sqlite_connector::open(db_path).unwrap();
|
||||
|
||||
let init_sql = "CREATE TABLE IF NOT EXISTS trustnodes(
|
||||
public_key TEXT PRIMARY KEY,
|
||||
trustnode BLOB NOT NULL
|
||||
);
|
||||
CREATE TABLE IF NOT EXISTS roots(
|
||||
public_key TEXT,
|
||||
weight INTEGER
|
||||
);";
|
||||
|
||||
connection.execute(init_sql).expect("cannot connect to db");
|
||||
|
||||
Mutex::new(TrustGraph::new(Box::new(SQLiteStorage::new(connection))))
|
||||
})
|
||||
}
|
||||
|
||||
pub struct SQLiteStorage {
|
||||
connection: Connection,
|
||||
}
|
||||
|
||||
impl SQLiteStorage {
|
||||
pub fn new(connection: Connection) -> SQLiteStorage {
|
||||
SQLiteStorage { connection }
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(ThisError, Debug)]
|
||||
pub enum SQLiteStorageError {
|
||||
#[error("{0}")]
|
||||
SQLiteError(
|
||||
#[from]
|
||||
#[source]
|
||||
InternalSqliteError,
|
||||
),
|
||||
#[error("{0}")]
|
||||
PublicKeyFromStr(String),
|
||||
#[error("{0}")]
|
||||
EncodeError(
|
||||
#[from]
|
||||
#[source]
|
||||
RmpEncodeError,
|
||||
),
|
||||
#[error("{0}")]
|
||||
DecodeError(
|
||||
#[from]
|
||||
#[source]
|
||||
RmpDecodeError,
|
||||
),
|
||||
#[error("Cannot convert weight as integer from DB")]
|
||||
WeightConversionDB,
|
||||
#[error("Cannot convert public key as binary from DB")]
|
||||
PublicKeyConversion,
|
||||
#[error("Cannot convert trust node as binary from DB")]
|
||||
TrustNodeConversion,
|
||||
#[error("Cannot revoke. There is no trust with such PublicKey")]
|
||||
PublcKeyNotFound,
|
||||
}
|
||||
|
||||
impl From<SQLiteStorageError> for String {
|
||||
fn from(err: SQLiteStorageError) -> Self {
|
||||
err.into()
|
||||
}
|
||||
}
|
||||
|
||||
impl StorageError for SQLiteStorageError {}
|
||||
|
||||
impl Storage for SQLiteStorage {
|
||||
type Error = SQLiteStorageError;
|
||||
|
||||
fn get(&self, pk: &PK) -> Result<Option<TrustNode>, Self::Error> {
|
||||
let mut cursor = self
|
||||
.connection
|
||||
.prepare("SELECT trustnode FROM trustnodes WHERE public_key = ?")?
|
||||
.cursor();
|
||||
|
||||
cursor.bind(&[Value::String(format!("{}", pk))])?;
|
||||
|
||||
match cursor.next().unwrap() {
|
||||
Some(r) => {
|
||||
log::info!("row: {:?}", r);
|
||||
let tn_bin: &[u8] = r[0].as_binary().ok_or(TrustNodeConversion)?;
|
||||
|
||||
log::info!("binary: {:?}", tn_bin);
|
||||
|
||||
let trust_node: TrustNode = rmp_serde::from_read_ref(tn_bin)?;
|
||||
|
||||
log::info!("trustnode: {:?}", trust_node);
|
||||
|
||||
Ok(Some(trust_node))
|
||||
}
|
||||
|
||||
None => Ok(None),
|
||||
}
|
||||
}
|
||||
|
||||
fn insert(&mut self, pk: PK, node: TrustNode) -> Result<(), Self::Error> {
|
||||
let mut cursor = self
|
||||
.connection
|
||||
.prepare("INSERT OR REPLACE INTO trustnodes VALUES (?, ?)")?
|
||||
.cursor();
|
||||
|
||||
let tn_vec = rmp_serde::to_vec(&node)?;
|
||||
|
||||
log::info!("insert: {:?}", tn_vec);
|
||||
|
||||
cursor.bind(&[Value::String(format!("{}", pk)), Value::Binary(tn_vec)])?;
|
||||
|
||||
cursor.next()?;
|
||||
Ok({})
|
||||
}
|
||||
|
||||
fn get_root_weight(&self, pk: &PK) -> Result<Option<Weight>, Self::Error> {
|
||||
let mut cursor = self
|
||||
.connection
|
||||
.prepare("SELECT public_key,weight FROM roots WHERE public_key = ?")?
|
||||
.cursor();
|
||||
|
||||
cursor.bind(&[Value::String(format!("{}", pk))])?;
|
||||
|
||||
if let Some(row) = cursor.next()? {
|
||||
log::info!("row: {:?}", row);
|
||||
|
||||
let w = u32::try_from(row[1].as_integer().ok_or(WeightConversionDB)?)
|
||||
.map_err(|_e| WeightConversionDB)?;
|
||||
|
||||
Ok(Some(w))
|
||||
} else {
|
||||
Ok(None)
|
||||
}
|
||||
}
|
||||
|
||||
fn add_root_weight(&mut self, pk: PK, weight: Weight) -> Result<(), Self::Error> {
|
||||
log::info!("add root: {} weight: {}", pk, weight);
|
||||
let mut cursor = self
|
||||
.connection
|
||||
.prepare("INSERT OR REPLACE INTO roots VALUES (?, ?)")?
|
||||
.cursor();
|
||||
|
||||
cursor.bind(&[
|
||||
Value::String(format!("{}", pk)),
|
||||
Value::Integer(i64::from(weight)),
|
||||
])?;
|
||||
|
||||
cursor.next()?;
|
||||
Ok({})
|
||||
}
|
||||
|
||||
fn root_keys(&self) -> Result<Vec<PK>, Self::Error> {
|
||||
let mut cursor = self
|
||||
.connection
|
||||
.prepare("SELECT public_key,weight FROM roots")?
|
||||
.cursor();
|
||||
|
||||
let mut roots = vec![];
|
||||
|
||||
while let Some(row) = cursor.next()? {
|
||||
log::info!("row: {:?}", row);
|
||||
let pk = row[0].as_string().ok_or(PublicKeyConversion)?;
|
||||
let pk: PK = PK::from_str(pk).map_err(|e| PublicKeyFromStr(e.to_string()))?;
|
||||
|
||||
roots.push(pk)
|
||||
}
|
||||
|
||||
Ok(roots)
|
||||
}
|
||||
|
||||
fn revoke(&mut self, pk: &PK, revoke: Revoke) -> Result<(), Self::Error> {
|
||||
match self.get(&pk)? {
|
||||
Some(mut trust_node) => {
|
||||
trust_node.update_revoke(revoke);
|
||||
self.insert(pk.clone(), trust_node)?;
|
||||
Ok(())
|
||||
}
|
||||
None => Err(PublcKeyNotFound),
|
||||
}
|
||||
}
|
||||
|
||||
fn update_auth(
|
||||
&mut self,
|
||||
pk: &PK,
|
||||
auth: Auth,
|
||||
issued_for: &PublicKey,
|
||||
cur_time: Duration,
|
||||
) -> Result<(), Self::Error> {
|
||||
match self.get(&pk)? {
|
||||
Some(mut trust_node) => {
|
||||
trust_node.update_auth(auth);
|
||||
self.insert(pk.clone(), trust_node)
|
||||
}
|
||||
None => {
|
||||
let mut trust_node = TrustNode::new(issued_for.clone(), cur_time);
|
||||
trust_node.update_auth(auth);
|
||||
self.insert(pk.clone(), trust_node)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user