use std::collections::HashMap;
use rustolio_rpc::prelude::*;
use rustolio_utils::{
bytes::{
encoding::{self, encode_to_bytes},
hex, Bytes,
},
crypto,
};
use rustolio_web::prelude::*;
use serde::de;
use crate::{client::CLIENT, Key, Value};
const DB_TEAMS: &str = "DB_TEAMS";
global! {
static TEAMS: GlobalSignal<Teams> = GlobalSignal::new(Teams(HashMap::new()));
Effect::new(|| {
Teams::init().unwrap();
});
}
#[derive(Clone)]
pub struct Teams(HashMap<crate::Key, (crypto::encryption::Cipher, crypto::encryption::Key)>);
impl Teams {
fn init() -> rustolio_web::Result<()> {
let storage = super::storage()?;
let Some(teams) = storage.get_item(DB_TEAMS).unwrap() else {
return Ok(());
};
let teams: HashMap<crate::Key, (crypto::encryption::Cipher, crypto::encryption::Key)> =
encoding::decode_from_bytes::<Vec<(crate::Key, crypto::encryption::Key)>>(
hex::decode(&teams).context("Failed to decode teams")?,
)
.context("Failed to decode teams")?
.into_iter()
.map(|(k, ek)| {
let c = crypto::encryption::Cipher::new(&ek);
Ok((k, (c, ek)))
})
.collect::<rustolio_web::Result<_>>()?;
TEAMS.update(|t| t.0 = teams);
Ok(())
}
fn save(
teams: impl IntoIterator<Item = (crate::Key, crypto::encryption::Key)>,
) -> rustolio_web::Result<()> {
let storage = super::storage()?;
let teams: Vec<_> = teams.into_iter().collect();
let teams =
hex::encode(encode_to_bytes(&teams).context("Failed to encode teams to bytes")?);
storage.set(DB_TEAMS, &teams)?;
Ok(())
}
pub(super) fn login(client: super::Client) -> rustolio_web::Result<()> {
let encrypted_teams = todo!();
let teams = {
let password_hash = crypto::hash::Hasher::once_raw(password.as_bytes());
let password_key = crypto::encryption::Key::from_bytes(password_hash.as_ref())
.context("Failed to create encryption key from password")?;
let cipher = crypto::encryption::Cipher::new(&password_key);
cipher
.decrypt(encrypted_teams)
.context("Failed to decrypt private key")?
};
let teams: Vec<(crate::Key, crypto::encryption::Key)> =
encoding::decode_from_bytes(teams).context("Failed to decode teams")?;
Self::save(teams);
let teams: HashMap<crate::Key, (crypto::encryption::Cipher, crypto::encryption::Key)> =
teams
.into_iter()
.map(|(k, ck)| {
let c = crypto::encryption::Cipher::new(&ck);
Ok((k, (c, ck)))
})
.collect::<rustolio_web::Result<_>>()?;
TEAMS.update(|t| {
t.0 = teams;
});
Ok(())
}
pub fn create_team(teamname: &str) -> rustolio_web::Result<()> {
let team_key = crate::Key::builder()
.update("teamname")
.update(teamname)
.build();
let encryption_key = crypto::encryption::Key::generate()
.context("Failed to create a team encryption key")?;
CLIENT.update(|c| {
let Some(c) = c else {
return;
};
c.teams
.insert(team_key, crypto::encryption::Cipher::new(&encryption_key));
});
Ok(())
}
pub fn add_team_member(teamname: &str) -> rustolio_web::Result<()> {}
pub(super) fn logout() -> rustolio_web::Result<()> {
TEAMS.update(|t| {
t.0.clear();
});
let storage = super::storage()?;
storage.delete(DB_TEAMS)?;
Ok(())
}
}