use std::sync::Arc;
use base64::Engine as _;
use base64::engine::general_purpose::STANDARD;
use sha2::{Sha256, Digest};
use chrono::Utc;
use ed25519_dalek::{SigningKey, SecretKey, VerifyingKey};
use rand::{rngs::OsRng, RngCore};
use std::convert::TryFrom;
use super::store::MeStore;
use super::model::{Entry, GetFilter};
pub struct Me<S: MeStore> {
pub username: String,
pub public_key: String,
pub context_id: String,
#[allow(dead_code)]
private_key_raw: String,
pub store: Arc<S>,
}
impl<S: MeStore> Me<S> {
pub fn with_store(username: String, public_key: String, private_key_raw: String, store: Arc<S>) -> Self {
let mut hasher = Sha256::new();
hasher.update(&private_key_raw);
let context_id = STANDARD.encode(hasher.finalize());
Self { username, public_key, context_id, private_key_raw, store }
}
pub async fn create(
store: Arc<S>,
username: &str,
password: &str,
) -> Result<Self, Box<dyn std::error::Error + Send + Sync>> {
let mut csprng = OsRng {};
let mut secret_bytes = [0u8; 32];
csprng.fill_bytes(&mut secret_bytes);
let secret = SecretKey::try_from(&secret_bytes[..])
.map_err(|_| "Invalid secret key")?;
let signing_key = SigningKey::from(&secret);
let verify_key = VerifyingKey::from(&signing_key);
let public_key = STANDARD.encode(verify_key.to_bytes());
let private_key_raw = STANDARD.encode(signing_key.to_bytes());
let key = Self::derive_key(username, password)?;
let encoded_key = STANDARD.encode(&key);
let encrypted_binary = crate::utils::crypto::encrypt_string(&encoded_key, &private_key_raw)?;
let encrypted_private_key = STANDARD.encode(&encrypted_binary);
store.create_identity(username, &public_key, &encrypted_private_key).await?;
Ok(Self::with_store(
username.to_string(),
public_key,
private_key_raw,
store,
))
}
pub async fn create_identity(store: Arc<S>, username: &str, encrypted_private_key: &str, public_key: &str) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
store.create_identity(username, public_key, encrypted_private_key).await
}
pub async fn load(store: Arc<S>, username: &str, password: &str) -> Result<Self, Box<dyn std::error::Error + Send + Sync>> {
let (public_key, encrypted_private_key) = store.load_keys(username).await?;
let key = Self::derive_key(username, password)?;
let encoded_key = STANDARD.encode(&key);
let private_key_raw = crate::utils::crypto::decrypt_string(&encoded_key, &STANDARD.decode(encrypted_private_key)?)?;
Ok(Self::with_store(username.to_string(), public_key, private_key_raw, store))
}
pub async fn change_password(
&self,
new_password: &str,
) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
let key = Self::derive_key(&self.username, new_password)?;
let encoded_key = STANDARD.encode(&key);
let encrypted_binary = crate::utils::crypto::encrypt_string(&encoded_key, &self.private_key_raw)?;
let new_encrypted = STANDARD.encode(&encrypted_binary);
self.store
.update_encrypted_private(&self.username, &new_encrypted)
.await?;
Ok(())
}
fn derive_key(username: &str, password: &str) -> Result<Vec<u8>, Box<dyn std::error::Error + Send + Sync>> {
let mut hasher = Sha256::new();
hasher.update(username.as_bytes());
hasher.update(password.as_bytes());
Ok(hasher.finalize().to_vec())
}
pub async fn be(&self, context_id: &str, key: &str, value: &str) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
self.insert("be", context_id, key, value).await
}
pub async fn have(&self, context_id: &str, key: &str, value: &str) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
self.insert("have", context_id, key, value).await
}
pub async fn do_(&self, context_id: &str, key: &str, value: &str) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
self.insert("do_", context_id, key, value).await
}
pub async fn at(&self, context_id: &str, key: &str, value: &str) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
self.insert("at", context_id, key, value).await
}
pub async fn relate(&self, context_id: &str, key: &str, value: &str) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
self.insert("relate", context_id, key, value).await
}
pub async fn react(&self, context_id: &str, key: &str, value: &str) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
self.insert("react", context_id, key, value).await
}
pub async fn communicate(&self, context_id: &str, key: &str, value: &str) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
self.insert("communicate", context_id, key, value).await
}
async fn insert(&self, verb: &str, context_id: &str, key: &str, value: &str) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
let ts = Utc::now().to_rfc3339();
self.store.insert(verb, context_id, key, value, &ts).await
}
pub async fn get(&self, filter: &GetFilter) -> Result<Vec<Entry>, Box<dyn std::error::Error + Send + Sync>> {
self.store.get(filter).await
}
}