#![feature(macro_metavar_expr)]
use std::path::{Path, PathBuf};
use aok::{Error, Result, OK};
use blake3::Hasher;
use ed25519_dalek::{Signer, SigningKey, SECRET_KEY_LENGTH};
use rand::rngs::OsRng;
use tokio::{
fs::{write, File},
io::AsyncReadExt,
};
use trt::join;
pub async fn key(key: impl AsRef<Path>, create: bool) -> Result<SigningKey> {
let key = key.as_ref();
match File::open(key).await {
Ok(mut k) => {
let mut signing_key_bytes: [u8; SECRET_KEY_LENGTH] = Default::default();
k.read_exact(&mut signing_key_bytes).await?;
Ok::<_, Error>(SigningKey::from_bytes(&signing_key_bytes))
}
Err(err) => {
if create && err.kind() == tokio::io::ErrorKind::NotFound {
let mut csprng = OsRng;
let signing_key: SigningKey = SigningKey::generate(&mut csprng);
let key_str = key.as_os_str().to_string_lossy();
let pk_fp = if key_str.ends_with(".sk") {
key_str[..key_str.len() - 2].to_owned() + "pk"
} else {
(key_str + ".pk").into()
};
write(pk_fp, signing_key.verifying_key().as_bytes()).await?;
write(key, signing_key.as_bytes()).await?;
Ok(signing_key)
} else {
Err(err.into())
}
}
}
}
pub async fn hash(path: impl AsRef<Path>) -> Result<[u8; 32], std::io::Error> {
let mut hasher = Hasher::new();
let mut file = File::open(path).await?;
let mut buf = [0; 4096];
loop {
let n = file.read(&mut buf).await?;
if n == 0 {
break;
}
hasher.update(&buf[..n]);
}
Ok(*hasher.finalize().as_bytes())
}
pub async fn b3s(fp: impl AsRef<Path>, key: SigningKey) -> Result<()> {
let fp = fp.as_ref();
let hash = hash(fp).await?;
let fp: PathBuf = fp.into();
let sign = key.sign(&hash).to_bytes();
join!(
write(fp.with_extension("b3"), hash),
write(fp.with_extension("b3s"), sign)
);
OK
}