init
This commit is contained in:
96
src/certs.rs
Normal file
96
src/certs.rs
Normal file
@@ -0,0 +1,96 @@
|
||||
use anyhow::Context;
|
||||
use ssh_key::{Certificate, PublicKey};
|
||||
use std::path::{Path, PathBuf};
|
||||
use tokio::fs;
|
||||
use tracing::trace;
|
||||
|
||||
pub async fn read_certs(
|
||||
ca: &PublicKey,
|
||||
path: impl AsRef<Path>,
|
||||
) -> anyhow::Result<Vec<Certificate>> {
|
||||
read_dir(path.as_ref().join(ca_dir(ca))).await
|
||||
}
|
||||
|
||||
pub async fn read_dir(path: impl AsRef<Path>) -> anyhow::Result<Vec<Certificate>> {
|
||||
let mut dir = fs::read_dir(path.as_ref())
|
||||
.await
|
||||
.context("read certs dir")?;
|
||||
let mut certs = Vec::new();
|
||||
while let Some(entry) = dir.next_entry().await? {
|
||||
//TODO: investigate why path().ends_with doesn't work
|
||||
if !entry
|
||||
.file_name()
|
||||
.into_string()
|
||||
.unwrap()
|
||||
.ends_with("-cert.pub")
|
||||
{
|
||||
trace!(
|
||||
"skipped {:?} due to missing '-cert.pub' extension",
|
||||
entry.path()
|
||||
);
|
||||
continue;
|
||||
}
|
||||
let contents = fs::read(&entry.path())
|
||||
.await
|
||||
.with_context(|| format!("read {:?}", entry.path()))?;
|
||||
let string_repr = parse_utf8(contents)?;
|
||||
let cert = Certificate::from_openssh(&string_repr)
|
||||
.with_context(|| format!("parse {:?} as openssh certificate", entry.path()))?;
|
||||
certs.push(cert);
|
||||
}
|
||||
Ok(certs)
|
||||
}
|
||||
|
||||
fn parse_utf8(bytes: Vec<u8>) -> anyhow::Result<String> {
|
||||
String::from_utf8(bytes).context("invalid utf-8")
|
||||
}
|
||||
|
||||
pub async fn read_pubkey(path: impl AsRef<Path>) -> anyhow::Result<PublicKey> {
|
||||
let contents = fs::read(&path)
|
||||
.await
|
||||
.with_context(|| format!("read {:?}", path.as_ref()))?;
|
||||
let string_repr = parse_utf8(contents)?;
|
||||
PublicKey::from_openssh(&string_repr)
|
||||
.with_context(|| format!("parse '{}' as public key", string_repr))
|
||||
}
|
||||
|
||||
fn ca_dir(ca: &PublicKey) -> String {
|
||||
ca.comment().to_string()
|
||||
}
|
||||
|
||||
fn cert_path(ca: &PublicKey, identifier: &str) -> String {
|
||||
let _ca_fingerprint = ca.fingerprint(Default::default());
|
||||
format!("{}/{}-cert.pub", ca_dir(ca), identifier)
|
||||
}
|
||||
|
||||
pub async fn store_cert(
|
||||
cert_dir: impl AsRef<Path>,
|
||||
ca: &PublicKey,
|
||||
cert: &Certificate,
|
||||
) -> anyhow::Result<PathBuf> {
|
||||
// TODO: proper store
|
||||
let path = cert_dir.as_ref().join(cert_path(&ca, cert.key_id()));
|
||||
if let Some(parent) = path.parent() {
|
||||
fs::create_dir_all(parent).await?;
|
||||
}
|
||||
fs::write(&path, cert.to_openssh().context("encode cert")?).await?;
|
||||
Ok(path)
|
||||
}
|
||||
|
||||
pub async fn load_cert(
|
||||
cert_dir: impl AsRef<Path>,
|
||||
ca: &PublicKey,
|
||||
identifier: &str,
|
||||
) -> anyhow::Result<Option<Certificate>> {
|
||||
let path = cert_dir.as_ref().join(cert_path(ca, identifier));
|
||||
if !path.exists() {
|
||||
return Ok(None);
|
||||
}
|
||||
let contents = fs::read(&path)
|
||||
.await
|
||||
.with_context(|| format!("read {:?}", &path))?;
|
||||
let string_repr = parse_utf8(contents)?;
|
||||
Ok(Some(Certificate::from_openssh(&string_repr).with_context(
|
||||
|| format!("parse {:?} as openssh certificate", &path),
|
||||
)?))
|
||||
}
|
Reference in New Issue
Block a user