mj_controller/server/api/
token.rs1use super::*;
2
3pub fn api_token_path() -> PathBuf {
7 mj_core::config::data_dir().join(API_TOKEN_FILE)
8}
9
10pub fn load_or_create_api_token(path: &std::path::Path) -> AnyResult<String> {
16 match std::fs::read_to_string(path) {
17 Ok(token) if token.trim().len() >= 32 => return Ok(token.trim().to_owned()),
18 Ok(token) => tracing::warn!(
19 path = %path.display(),
20 bytes = token.trim().len(),
21 "Mjolnir API token is too short; generating a new one revokes the old token"
22 ),
23 Err(error) if error.kind() == std::io::ErrorKind::NotFound => {}
24 Err(error) => tracing::warn!(
25 path = %path.display(),
26 "could not read the Mjolnir API token ({error}); generating a new one revokes the old token"
27 ),
28 }
29 let mut bytes = [0_u8; API_TOKEN_BYTES];
30 getrandom::fill(&mut bytes)
31 .map_err(|error| anyhow::anyhow!("generate Mjolnir API token: {error}"))?;
32 let token = mj_core::hex::lower_hex(bytes);
33 mj_core::config::atomic_write(path, token.as_bytes())
34 .with_context(|| format!("persist Mjolnir API token {}", path.display()))?;
35 Ok(token)
36}
37
38pub fn certificate_der_sha256(der: &[u8]) -> String {
41 use sha2::Digest;
42 mj_core::hex::lower_hex(sha2::Sha256::digest(der))
43}
44
45pub fn served_certificate_sha256(pem: &[u8]) -> AnyResult<String> {
51 use rustls::pki_types::CertificateDer;
52 use rustls::pki_types::pem::PemObject;
53 let leaf = CertificateDer::pem_slice_iter(pem)
54 .next()
55 .context("the certificate file holds no PEM certificate")?
56 .context("parse the PEM certificate")?;
57 Ok(certificate_der_sha256(&leaf))
58}
59
60