mirror of
https://github.com/fluencelabs/trust-graph
synced 2025-03-15 12:50:48 +00:00
broken wip wip wip
This commit is contained in:
parent
88b6f5f3fe
commit
0e7f22b6e0
1
Cargo.lock
generated
1
Cargo.lock
generated
@ -1428,6 +1428,7 @@ dependencies = [
|
|||||||
"serde_json",
|
"serde_json",
|
||||||
"serde_with",
|
"serde_with",
|
||||||
"signature",
|
"signature",
|
||||||
|
"thiserror",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -21,3 +21,4 @@ ed25519-dalek = { version = "1.0.1", features = ["serde"] }
|
|||||||
rand = "0.7.0"
|
rand = "0.7.0"
|
||||||
signature = "1.3.0"
|
signature = "1.3.0"
|
||||||
serde_with = "1.6.0"
|
serde_with = "1.6.0"
|
||||||
|
thiserror = "1.0.23"
|
||||||
|
38
bin/Cargo.lock
generated
38
bin/Cargo.lock
generated
@ -984,6 +984,12 @@ version = "0.1.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184"
|
checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "pkg-config"
|
||||||
|
version = "0.3.19"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "3831453b3449ceb48b6d9c7ad7c96d5ea673e9b470a1dc578c2ce6521230884c"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ppv-lite86"
|
name = "ppv-lite86"
|
||||||
version = "0.2.10"
|
version = "0.2.10"
|
||||||
@ -1415,6 +1421,36 @@ version = "0.5.2"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d"
|
checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "sqlite"
|
||||||
|
version = "0.25.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "35f759dc2e373e1edd0a27da87aa9136416360c5077a23643fcd6fcdc9cb9e31"
|
||||||
|
dependencies = [
|
||||||
|
"libc",
|
||||||
|
"sqlite3-sys",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "sqlite3-src"
|
||||||
|
version = "0.2.12"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "b8bb25e66d026488228a97e0ad21e3d15ec5998dcd9ad73c97cc277c56a6b314"
|
||||||
|
dependencies = [
|
||||||
|
"cc",
|
||||||
|
"pkg-config",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "sqlite3-sys"
|
||||||
|
version = "0.12.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "71fec807a1534bd13eeaaec396175d67c79bdc68df55e18a452726ec62a8fb08"
|
||||||
|
dependencies = [
|
||||||
|
"libc",
|
||||||
|
"sqlite3-src",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "static_assertions"
|
name = "static_assertions"
|
||||||
version = "1.1.0"
|
version = "1.1.0"
|
||||||
@ -1537,6 +1573,7 @@ dependencies = [
|
|||||||
"serde_json",
|
"serde_json",
|
||||||
"serde_with",
|
"serde_with",
|
||||||
"signature",
|
"signature",
|
||||||
|
"thiserror",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -1556,6 +1593,7 @@ dependencies = [
|
|||||||
"rmp-serde",
|
"rmp-serde",
|
||||||
"serde_bencode",
|
"serde_bencode",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
|
"sqlite",
|
||||||
"trust-graph",
|
"trust-graph",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@ -25,3 +25,4 @@ bs58 = "0.3.1"
|
|||||||
rmp-serde = "0.15.0"
|
rmp-serde = "0.15.0"
|
||||||
bincode = "1.3.1"
|
bincode = "1.3.1"
|
||||||
serde_bencode = "^0.2.3"
|
serde_bencode = "^0.2.3"
|
||||||
|
sqlite = "0.25.3"
|
||||||
|
@ -1,5 +1,8 @@
|
|||||||
#!/bin/bash
|
#!/usr/bin/env bash
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
fce build
|
fce build
|
||||||
mv target/wasm32-wasi/debug/trust-graph.wasm artifacts/
|
|
||||||
|
rm artifacts/trust-graph.wasm
|
||||||
|
mv -f target/wasm32-wasi/debug/trust-graph.wasm artifacts/
|
||||||
RUST_LOG="info" fce-repl Config.toml
|
RUST_LOG="info" fce-repl Config.toml
|
||||||
|
@ -27,8 +27,12 @@ fn insert_cert(certificate: String, duration: u64) -> InsertResult {
|
|||||||
|
|
||||||
#[fce]
|
#[fce]
|
||||||
fn looper() {
|
fn looper() {
|
||||||
|
|
||||||
|
let second = std::time::Duration::from_millis(1000);
|
||||||
|
|
||||||
let mut a = 0;
|
let mut a = 0;
|
||||||
while true {
|
while true {
|
||||||
|
std::thread::sleep(second);
|
||||||
a = a + 1;
|
a = a + 1;
|
||||||
log::info!("{}", a)
|
log::info!("{}", a)
|
||||||
}
|
}
|
||||||
|
@ -33,6 +33,17 @@ pub struct Certificate {
|
|||||||
pub chain: Vec<Trust>,
|
pub chain: Vec<Trust>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub enum CerificateError {
|
||||||
|
DecodeError(String),
|
||||||
|
ExpirationError {
|
||||||
|
expires_at: String,
|
||||||
|
issued_at: String
|
||||||
|
},
|
||||||
|
KeyInCertificateError,
|
||||||
|
CertificateLengthError,
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
impl Certificate {
|
impl Certificate {
|
||||||
pub fn new_unverified(chain: Vec<Trust>) -> Self {
|
pub fn new_unverified(chain: Vec<Trust>) -> Self {
|
||||||
Self { chain }
|
Self { chain }
|
||||||
@ -65,7 +76,7 @@ impl Certificate {
|
|||||||
expires_at: Duration,
|
expires_at: Duration,
|
||||||
issued_at: Duration,
|
issued_at: Duration,
|
||||||
cur_time: Duration,
|
cur_time: Duration,
|
||||||
) -> Result<Self, String> {
|
) -> Result<Self, CerificateError> {
|
||||||
if expires_at.lt(&issued_at) {
|
if expires_at.lt(&issued_at) {
|
||||||
return Err("Expiration time should be greater than issued time.".to_string());
|
return Err("Expiration time should be greater than issued time.".to_string());
|
||||||
}
|
}
|
||||||
@ -110,7 +121,7 @@ impl Certificate {
|
|||||||
cert: &Certificate,
|
cert: &Certificate,
|
||||||
trusted_roots: &[PublicKey],
|
trusted_roots: &[PublicKey],
|
||||||
cur_time: Duration,
|
cur_time: Duration,
|
||||||
) -> Result<(), String> {
|
) -> Result<(), CerificateError> {
|
||||||
let chain = &cert.chain;
|
let chain = &cert.chain;
|
||||||
|
|
||||||
if chain.is_empty() {
|
if chain.is_empty() {
|
||||||
@ -159,7 +170,7 @@ impl Certificate {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
pub fn decode(arr: &[u8]) -> Result<Self, String> {
|
pub fn decode(arr: &[u8]) -> Result<Self, CerificateError> {
|
||||||
let trusts_offset = arr.len() - 2 - 4;
|
let trusts_offset = arr.len() - 2 - 4;
|
||||||
if trusts_offset % TRUST_LEN != 0 {
|
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("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());
|
||||||
|
18
src/lib.rs
18
src/lib.rs
@ -16,15 +16,15 @@
|
|||||||
|
|
||||||
#![recursion_limit = "512"]
|
#![recursion_limit = "512"]
|
||||||
#![warn(rust_2018_idioms)]
|
#![warn(rust_2018_idioms)]
|
||||||
#![deny(
|
// #![deny(
|
||||||
dead_code,
|
// dead_code,
|
||||||
nonstandard_style,
|
// nonstandard_style,
|
||||||
unused_imports,
|
// unused_imports,
|
||||||
unused_mut,
|
// unused_mut,
|
||||||
unused_variables,
|
// unused_variables,
|
||||||
unused_unsafe,
|
// unused_unsafe,
|
||||||
unreachable_patterns
|
// unreachable_patterns
|
||||||
)]
|
// )]
|
||||||
|
|
||||||
mod certificate;
|
mod certificate;
|
||||||
pub mod certificate_serde;
|
pub mod certificate_serde;
|
||||||
|
52
src/trust.rs
52
src/trust.rs
@ -21,6 +21,8 @@ use fluence_identity::signature::Signature;
|
|||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use std::convert::TryInto;
|
use std::convert::TryInto;
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
|
use thiserror::Error as ThisError;
|
||||||
|
use crate::trust::TrustError::{SignatureError, DecodeError};
|
||||||
|
|
||||||
pub const SIG_LEN: usize = 64;
|
pub const SIG_LEN: usize = 64;
|
||||||
pub const PK_LEN: usize = 32;
|
pub const PK_LEN: usize = 32;
|
||||||
@ -55,6 +57,21 @@ fn show_sig(sig: &Signature, f: &mut std::fmt::Formatter<'_>) -> Result<(), std:
|
|||||||
write!(f, "{}", bs58::encode(&sig.to_bytes()).into_string())
|
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(String),
|
||||||
|
|
||||||
|
/// Errors occured on trust decoding from differrent formats
|
||||||
|
#[error("{0:?}")]
|
||||||
|
DecodeError(String)
|
||||||
|
}
|
||||||
|
|
||||||
impl Trust {
|
impl Trust {
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
pub fn new(
|
pub fn new(
|
||||||
@ -90,15 +107,15 @@ impl Trust {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Verifies that authorization is cryptographically correct.
|
/// 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 {
|
if trust.expires_at < cur_time {
|
||||||
return Err("Trust in chain is expired.".to_string());
|
return TrustError::Expired(trust.expires_at, cur_time);
|
||||||
}
|
}
|
||||||
|
|
||||||
let msg: &[u8] =
|
let msg: &[u8] =
|
||||||
&Self::metadata_bytes(&trust.issued_for, trust.expires_at, trust.issued_at);
|
&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(|e| SignatureError(e))?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@ -132,17 +149,20 @@ impl Trust {
|
|||||||
|
|
||||||
/// Decode a trust from a byte array as produced by `encode`.
|
/// Decode a trust from a byte array as produced by `encode`.
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
pub fn decode(arr: &[u8]) -> Result<Self, String> {
|
pub fn decode(arr: &[u8]) -> Result<Self, TrustError> {
|
||||||
if arr.len() != TRUST_LEN {
|
if arr.len() != TRUST_LEN {
|
||||||
return Err(
|
return DecodeError(
|
||||||
format!("Trust length should be 104: public key(32) + signature(64) + expiration date(8), was: {}", arr.len()),
|
format!("Trust length should be 104: public key(32) + signature(64) + expiration date(8), was: {}",
|
||||||
|
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])
|
||||||
|
.map_err(|err| DecodeError(format!("Cannot decode a public key: {}", err.to_string())))?;
|
||||||
|
|
||||||
let signature = &arr[PK_LEN..PK_LEN + SIG_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)
|
||||||
|
.map_err(|err| DecodeError(format!("Cannot decode a signature: {}", err.to_string())))?;
|
||||||
|
|
||||||
let expiration_bytes = &arr[PK_LEN + SIG_LEN..PK_LEN + SIG_LEN + EXPIRATION_LEN];
|
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());
|
let expiration_date = u64::from_le_bytes(expiration_bytes.try_into().unwrap());
|
||||||
@ -160,7 +180,7 @@ impl Trust {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn bs58_str_to_vec(str: &str, field: &str) -> Result<Vec<u8>, String> {
|
fn bs58_str_to_vec(str: &str, field: &str) -> Result<Vec<u8>, TrustError> {
|
||||||
bs58::decode(str).into_vec().map_err(|e| {
|
bs58::decode(str).into_vec().map_err(|e| {
|
||||||
format!(
|
format!(
|
||||||
"Cannot decode `{}` from base58 format in the trust '{}': {}",
|
"Cannot decode `{}` from base58 format in the trust '{}': {}",
|
||||||
@ -169,12 +189,12 @@ impl Trust {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn str_to_duration(str: &str, field: &str) -> Result<Duration, String> {
|
fn str_to_duration(str: &str, field: &str) -> Result<Duration, TrustError> {
|
||||||
let secs = str.parse().map_err(|e| {
|
let secs = str.parse().map_err(|e| {
|
||||||
format!(
|
DecodeError(format!(
|
||||||
"Cannot parse `{}` field in the trust '{}': {}",
|
"Cannot parse `{}` field in the trust '{}': {}",
|
||||||
field, str, e
|
field, str, e
|
||||||
)
|
))
|
||||||
})?;
|
})?;
|
||||||
Ok(Duration::from_secs(secs))
|
Ok(Duration::from_secs(secs))
|
||||||
}
|
}
|
||||||
@ -184,19 +204,19 @@ impl Trust {
|
|||||||
signature: &str,
|
signature: &str,
|
||||||
expires_at: &str,
|
expires_at: &str,
|
||||||
issued_at: &str,
|
issued_at: &str,
|
||||||
) -> Result<Self, String> {
|
) -> Result<Self, TrustError> {
|
||||||
// PublicKey
|
// PublicKey
|
||||||
let issued_for_bytes = Self::bs58_str_to_vec(issued_for, "issued_for")?;
|
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| {
|
let issued_for = PublicKey::from_bytes(issued_for_bytes.as_slice()).map_err(|e| {
|
||||||
format!(
|
DecodeError(format!(
|
||||||
"Cannot decode the public key: {} in the trust '{}'",
|
"Cannot decode the public key: {} in the trust '{}'",
|
||||||
issued_for, e
|
issued_for, e
|
||||||
)
|
))
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
// 64 bytes signature
|
// 64 bytes signature
|
||||||
let signature = Self::bs58_str_to_vec(signature, "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).map_err(|err| DecodeError(err.to_string()))?;
|
||||||
|
|
||||||
// Duration
|
// Duration
|
||||||
let expires_at = Self::str_to_duration(expires_at, "expires_at")?;
|
let expires_at = Self::str_to_duration(expires_at, "expires_at")?;
|
||||||
|
@ -14,16 +14,17 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
use crate::certificate::Certificate;
|
use crate::certificate::{Certificate, CerificateError};
|
||||||
use crate::public_key_hashable::PublicKeyHashable;
|
use crate::public_key_hashable::PublicKeyHashable;
|
||||||
use crate::revoke::Revoke;
|
use crate::revoke::Revoke;
|
||||||
use crate::trust::Trust;
|
use crate::trust::Trust;
|
||||||
use crate::trust_graph_storage::Storage;
|
use crate::trust_graph_storage::{Storage, StorageError};
|
||||||
use crate::trust_node::{Auth, TrustNode};
|
use crate::trust_node::{Auth, TrustNode};
|
||||||
use fluence_identity::public_key::PublicKey;
|
use fluence_identity::public_key::PublicKey;
|
||||||
use std::borrow::Borrow;
|
use std::borrow::Borrow;
|
||||||
use std::collections::{HashSet, VecDeque};
|
use std::collections::{HashSet, VecDeque};
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
|
use crate::trust_graph::TrustGraphError::{InternalStorageError, CertificateCheckError};
|
||||||
|
|
||||||
/// for simplicity, we store `n` where Weight = 1/n^2
|
/// for simplicity, we store `n` where Weight = 1/n^2
|
||||||
pub type Weight = u32;
|
pub type Weight = u32;
|
||||||
@ -32,48 +33,60 @@ pub type Weight = u32;
|
|||||||
/// TODO serialization/deserialization
|
/// TODO serialization/deserialization
|
||||||
/// TODO export a certificate from graph
|
/// TODO export a certificate from graph
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
pub struct TrustGraph {
|
pub struct TrustGraph<S> where S: Storage {
|
||||||
storage: Box<dyn Storage + Send + Sync>,
|
storage: Box<S>,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub enum TrustGraphError {
|
||||||
|
InternalStorageError(String),
|
||||||
|
CertificateCheckError(CerificateError)
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Into<TrustGraphError> for CerificateError {
|
||||||
|
fn into(self) -> TrustGraphError {
|
||||||
|
CertificateCheckError(self)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
impl TrustGraph {
|
impl<S> TrustGraph<S> where S: Storage {
|
||||||
pub fn new(storage: Box<dyn Storage + Send + Sync>) -> Self {
|
pub fn new(storage: Box<S>) -> Self {
|
||||||
Self { storage: storage }
|
Self { storage: storage }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Insert new root weight
|
/// Insert new root weight
|
||||||
pub fn add_root_weight(&mut self, pk: PublicKeyHashable, weight: Weight) {
|
pub fn add_root_weight(&mut self, pk: PublicKeyHashable, weight: Weight) -> Result<(), TrustGraphError> {
|
||||||
self.storage.add_root_weight(pk, weight)
|
self.storage.add_root_weight(pk, weight).map_err(|e| InternalStorageError(e.into()))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get trust by public key
|
/// Get trust by public key
|
||||||
pub fn get(&self, pk: PublicKey) -> Option<TrustNode> {
|
pub fn get(&self, pk: PublicKey) -> Result<Option<TrustNode>, TrustGraphError> {
|
||||||
self.storage.get(&pk.into())
|
self.storage.get(&pk.into()).map_err(|e| InternalStorageError(e.into()))
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: remove cur_time from api, leave it for tests only
|
// TODO: remove cur_time from api, leave it for tests only
|
||||||
/// Certificate is a chain of trusts, add this chain to graph
|
/// 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
|
where
|
||||||
C: Borrow<Certificate>,
|
C: Borrow<Certificate>,
|
||||||
{
|
{
|
||||||
let roots: Vec<PublicKey> = self
|
let roots: Vec<PublicKey> = self
|
||||||
.storage
|
.storage
|
||||||
.root_keys()
|
.root_keys()
|
||||||
|
.map_err(|e| InternalStorageError(e.into()))?
|
||||||
.iter()
|
.iter()
|
||||||
.cloned()
|
.cloned()
|
||||||
.map(Into::into)
|
.map(Into::into)
|
||||||
.collect();
|
.collect();
|
||||||
// Check that certificate is valid and converges to one of the known roots
|
// Check that certificate is valid and converges to one of the known roots
|
||||||
Certificate::verify(cert.borrow(), roots.as_slice(), cur_time)?;
|
Certificate::verify(cert.borrow(), roots.as_slice(), cur_time).map_err(|e| e.into())?;
|
||||||
|
|
||||||
let mut chain = cert.borrow().chain.iter();
|
let mut chain = cert.borrow().chain.iter();
|
||||||
let root_trust = chain.next().ok_or("empty chain")?;
|
let root_trust = chain.next().ok_or("empty chain").map_err(|e| InternalStorageError(e.into()))?;
|
||||||
let root_pk: PublicKeyHashable = root_trust.issued_for.clone().into();
|
let root_pk: PublicKeyHashable = root_trust.issued_for.clone().into();
|
||||||
|
|
||||||
// Insert new TrustNode for this root_pk if there wasn't one
|
// Insert new TrustNode for this root_pk if there wasn't one
|
||||||
if self.storage.get(&root_pk).is_none() {
|
if self.storage.get(&root_pk).map_err(|e| InternalStorageError(e.into()))?.is_none() {
|
||||||
let mut trust_node = TrustNode::new(root_trust.issued_for.clone(), cur_time);
|
let mut trust_node = TrustNode::new(root_trust.issued_for.clone(), cur_time);
|
||||||
let root_auth = Auth {
|
let root_auth = Auth {
|
||||||
trust: root_trust.clone(),
|
trust: root_trust.clone(),
|
||||||
@ -103,31 +116,32 @@ impl TrustGraph {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Get the maximum weight of trust for one public key.
|
/// 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
|
where
|
||||||
P: Borrow<PublicKey>,
|
P: Borrow<PublicKey>,
|
||||||
{
|
{
|
||||||
if let Some(weight) = self.storage.get_root_weight(pk.borrow().as_ref()) {
|
if let Some(weight) = self.storage.get_root_weight(pk.borrow().as_ref()).map_err(|e| InternalStorageError(e.into()))? {
|
||||||
return Some(weight);
|
return Ok(Some(weight));
|
||||||
}
|
}
|
||||||
|
|
||||||
let roots: Vec<PublicKey> = self
|
let roots: Vec<PublicKey> = self
|
||||||
.storage
|
.storage
|
||||||
.root_keys()
|
.root_keys()
|
||||||
|
.map_err(|e| InternalStorageError(e.into()))?
|
||||||
.iter()
|
.iter()
|
||||||
.map(|pk| pk.clone().into())
|
.map(|pk| pk.clone().into())
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
// get all possible certificates from the given public key to all roots in the graph
|
// 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());
|
let certs = self.get_all_certs(pk, roots.as_slice());
|
||||||
self.certificates_weight(certs)
|
Ok(self.certificates_weight(certs)?)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Calculate weight from given certificates
|
/// Calculate weight from given certificates
|
||||||
/// Returns None if there is no such public key
|
/// Returns None if there is no such public key
|
||||||
/// or some trust between this key and a root key is revoked.
|
/// or some trust between this key and a root key is revoked.
|
||||||
/// TODO handle non-direct revocations
|
/// 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
|
where
|
||||||
C: Borrow<Certificate>,
|
C: Borrow<Certificate>,
|
||||||
I: IntoIterator<Item = C>,
|
I: IntoIterator<Item = C>,
|
||||||
@ -135,7 +149,9 @@ impl TrustGraph {
|
|||||||
let mut certs = certs.into_iter().peekable();
|
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
|
// 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
|
// 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;
|
let mut weight = std::u32::MAX;
|
||||||
|
|
||||||
@ -146,14 +162,14 @@ impl TrustGraph {
|
|||||||
.storage
|
.storage
|
||||||
.get_root_weight(cert.chain.first()?.issued_for.as_ref())
|
.get_root_weight(cert.chain.first()?.issued_for.as_ref())
|
||||||
// This panic shouldn't happen // TODO: why?
|
// This panic shouldn't happen // TODO: why?
|
||||||
.expect("first trust in chain must be in root_weights");
|
.map_err(|e| InternalStorageError(e.into()))?;
|
||||||
|
|
||||||
// certificate weight = root weight + 1 * every other element in the chain
|
// certificate weight = root weight + 1 * every other element in the chain
|
||||||
// (except root, so the formula is `root weight + chain length - 1`)
|
// (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 + cert.chain.len() as u32 - 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
Some(weight)
|
Ok(Some(weight))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// BF search for all converging paths (chains) in the graph
|
/// BF search for all converging paths (chains) in the graph
|
||||||
|
@ -5,22 +5,31 @@ use crate::trust_node::{Auth, TrustNode};
|
|||||||
use fluence_identity::public_key::PublicKey;
|
use fluence_identity::public_key::PublicKey;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
|
use thiserror::Error as ThisError;
|
||||||
|
use crate::trust_graph_storage::InMemoryStorageError::RevokeError;
|
||||||
|
|
||||||
|
pub trait StorageError {}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
pub trait Storage {
|
pub trait Storage {
|
||||||
fn get(&self, pk: &PublicKeyHashable) -> Option<TrustNode>;
|
|
||||||
fn insert(&mut self, pk: PublicKeyHashable, node: TrustNode);
|
|
||||||
|
|
||||||
fn get_root_weight(&self, pk: &PublicKeyHashable) -> Option<Weight>;
|
type Error: StorageError + Into<String>;
|
||||||
fn add_root_weight(&mut self, pk: PublicKeyHashable, weight: Weight);
|
|
||||||
fn root_keys(&self) -> Vec<PublicKeyHashable>;
|
fn get(&self, pk: &PublicKeyHashable) -> Result<Option<TrustNode>, Self::Error>;
|
||||||
fn revoke(&mut self, pk: &PublicKeyHashable, revoke: Revoke) -> Result<(), String>;
|
fn insert(&mut self, pk: PublicKeyHashable, node: TrustNode) -> Result<(), Self::Error>;
|
||||||
|
|
||||||
|
fn get_root_weight(&self, pk: &PublicKeyHashable) -> Result<Option<Weight>, Self::Error>;
|
||||||
|
fn add_root_weight(&mut self, pk: PublicKeyHashable, weight: Weight) -> Result<(), Self::Error>;
|
||||||
|
fn root_keys(&self) -> Result<Vec<PublicKeyHashable>, Self::Error>;
|
||||||
|
fn revoke(&mut self, pk: &PublicKeyHashable, revoke: Revoke) -> Result<(), Self::Error>;
|
||||||
fn update_auth(
|
fn update_auth(
|
||||||
&mut self,
|
&mut self,
|
||||||
pk: &PublicKeyHashable,
|
pk: &PublicKeyHashable,
|
||||||
auth: Auth,
|
auth: Auth,
|
||||||
issued_for: &PublicKey,
|
issued_for: &PublicKey,
|
||||||
cur_time: Duration,
|
cur_time: Duration,
|
||||||
);
|
) -> Result<(), Self::Error>;
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Default)]
|
#[derive(Debug, Default)]
|
||||||
@ -51,34 +60,47 @@ impl InMemoryStorage {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(ThisError, Debug)]
|
||||||
|
pub enum InMemoryStorageError {
|
||||||
|
|
||||||
|
#[error("{0:?}")]
|
||||||
|
RevokeError(String)
|
||||||
|
}
|
||||||
|
|
||||||
|
impl StorageError for InMemoryStorage {}
|
||||||
|
|
||||||
impl Storage for InMemoryStorage {
|
impl Storage for InMemoryStorage {
|
||||||
fn get(&self, pk: &PublicKeyHashable) -> Option<TrustNode> {
|
|
||||||
self.nodes.get(pk).cloned()
|
type Error = InMemoryStorageError;
|
||||||
|
|
||||||
|
fn get(&self, pk: &PublicKeyHashable) -> Result<Option<TrustNode>, Self::Error> {
|
||||||
|
Ok(self.nodes.get(pk).cloned())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn insert(&mut self, pk: PublicKeyHashable, node: TrustNode) {
|
fn insert(&mut self, pk: PublicKeyHashable, node: TrustNode) -> Result<(), Self::Error> {
|
||||||
&self.nodes.insert(pk, node);
|
&self.nodes.insert(pk, node);
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_root_weight(&self, pk: &PublicKeyHashable) -> Option<Weight> {
|
fn get_root_weight(&self, pk: &PublicKeyHashable) -> Result<Option<Weight>, Self::Error> {
|
||||||
self.root_weights.get(pk).cloned()
|
Ok(self.root_weights.get(pk).cloned())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn add_root_weight(&mut self, pk: PublicKeyHashable, weight: Weight) {
|
fn add_root_weight(&mut self, pk: PublicKeyHashable, weight: Weight) -> Result<(), Self::Error> {
|
||||||
&self.root_weights.insert(pk, weight);
|
Ok(&self.root_weights.insert(pk, weight));
|
||||||
}
|
}
|
||||||
|
|
||||||
fn root_keys(&self) -> Vec<PublicKeyHashable> {
|
fn root_keys(&self) -> Result<Vec<PublicKeyHashable>, Self::Error> {
|
||||||
self.root_weights.keys().cloned().map(Into::into).collect()
|
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: &PublicKeyHashable, revoke: Revoke) -> Result<(), Self::Error> {
|
||||||
match self.nodes.get_mut(&pk) {
|
match self.nodes.get_mut(&pk) {
|
||||||
Some(trust_node) => {
|
Some(trust_node) => {
|
||||||
trust_node.update_revoke(revoke);
|
trust_node.update_revoke(revoke);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
None => Err("There is no trust with such PublicKey".to_string()),
|
None => RevokeError("There is no trust with such PublicKey".to_string()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user