debt-pirate/key-rotater/src/main.rs

80 lines
2 KiB
Rust

use std::{
env,
io::{self, BufRead, Write},
process,
time::{Duration, SystemTime},
};
use base64::prelude::*;
use humantime::format_rfc3339_seconds;
use pasetors::{
keys::SymmetricKey,
paserk::{FormatAsPaserk, Id},
version4::V4,
};
fn main() {
let encoded_secret = read_secret();
let secret = if let Ok(secret) = decode_secret(encoded_secret) {
secret
} else {
eprintln!("Not a valid 32-byte, base64 encoded string.");
process::exit(1);
};
let (id, key) = generate_local_key(secret.as_slice());
let mut id_string = String::new();
id.fmt(&mut id_string).unwrap();
let one_year: Duration = Duration::from_secs_f64(60_f64 * 60_f64 * 24_f64 * 365.25_f64);
let expiration = format_rfc3339_seconds(SystemTime::now() + one_year);
println!("ID: {id_string}\nKey: {key}\nExpiration: {expiration}");
}
fn read_secret() -> String {
let secret_arg = env::args().skip(1).last();
let secret = if let Some(secret) = secret_arg {
secret
} else {
print!("Enter a 32-byte, base64 encoded string: ");
let _ = io::stdout().flush();
let mut buffer = String::with_capacity(32);
let stdin = io::stdin();
stdin.lock().read_line(&mut buffer).unwrap();
buffer
.strip_suffix("\r\n")
.or(buffer.strip_suffix("\n"))
.map(|buffer| buffer.to_owned())
.unwrap_or(buffer)
};
secret
}
fn decode_secret(secret: String) -> Result<Vec<u8>, ()> {
BASE64_STANDARD
.decode(secret)
.map_err(|_| ())
.and_then(|secret| {
if secret.len() != 32 {
Err(())
} else {
Ok(secret)
}
})
}
fn generate_local_key(secret: &[u8]) -> (Id, String) {
let key = SymmetricKey::<V4>::from(secret).unwrap();
let mut serialized_key = String::with_capacity(54);
let _ = key.fmt(&mut serialized_key);
let id = Id::from(&key);
(id, serialized_key)
}