use std::path::PathBuf;
use iroh::{PublicKey, SecretKey};
use iroh_rings::{Permission, RedbRegistry, Registry};
use tracing::{debug, instrument};
use crate::{GitOp, keys::load_or_create_key};
#[instrument(err)]
pub(super) fn open_db(config_dir: &PathBuf) -> Result<RedbRegistry, anyhow::Error> {
let db_path = config_dir.join("auth.db");
debug!(?db_path, "opening auth db");
Ok(RedbRegistry::open(db_path)?)
}
pub const SINGLE_REPO_RESOURCE: &'static str = "<repo>";
pub(super) struct AuthAdmin {
reg: RedbRegistry,
pub(super) key: SecretKey,
pub(super) key_file: PathBuf,
}
impl AuthAdmin {
pub(super) fn new(config_dir: &PathBuf, git_dir: &PathBuf) -> Result<Self, anyhow::Error> {
let reg = open_db(&config_dir)?;
let (key_file, key) = load_or_create_key(config_dir, git_dir)?;
Ok(Self { reg, key, key_file })
}
#[instrument(skip(self), err)]
pub(super) fn add_peer(
&self,
ring_name: &str,
peer_name: &str,
id: &str,
) -> Result<(), anyhow::Error> {
match self.reg.create_ring(ring_name) {
Ok(()) => {
self.reg.add_ring_to_resource(
GitOp::ClientPushServerFetch.resource_id(SINGLE_REPO_RESOURCE),
ring_name,
&[Permission::Write],
)?;
self.reg.add_ring_to_resource(
GitOp::ClientFetchServerPush.resource_id(SINGLE_REPO_RESOURCE),
ring_name,
&[Permission::Read],
)?;
Ok(())
}
Err(iroh_rings::Error::RingAlreadyExists(_)) => Ok(()),
res => res,
}?;
self.reg
.add_peer_to_ring(ring_name, PublicKey::from_z32(id)?, Some(peer_name))?;
Ok(())
}
#[instrument(skip(self), err)]
pub(super) fn list_peers(&self, ring_name: &str) -> Result<(), anyhow::Error> {
let unnamed = "?".to_string();
for (public_key, name) in self.reg.list_ring_peers(ring_name)?.iter() {
println!(
"{} {}",
name.as_ref().unwrap_or(&unnamed),
public_key.to_z32()
);
}
Ok(())
}
#[instrument(skip(self), err)]
pub(super) fn list_rings(&self) -> Result<(), anyhow::Error> {
for ring in self.reg.list_rings()?.iter() {
println!("{}", ring.as_str());
}
Ok(())
}
}