Include the key-rotater project in the monorepo
This commit is contained in:
parent
878ff48d95
commit
42d2705a84
4 changed files with 100 additions and 0 deletions
1
key-rotater/.gitignore
vendored
Normal file
1
key-rotater/.gitignore
vendored
Normal file
|
@ -0,0 +1 @@
|
||||||
|
/target
|
10
key-rotater/Cargo.toml
Normal file
10
key-rotater/Cargo.toml
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
[package]
|
||||||
|
name = "debt-pirate-key-rotater"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2021"
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
base64 = "0.22.1"
|
||||||
|
clap = { version = "4.5", features = ["derive"] }
|
||||||
|
humantime = "2.1"
|
||||||
|
pasetors = "0.7"
|
9
key-rotater/README.md
Normal file
9
key-rotater/README.md
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
# Debt Pirate Key Rotater
|
||||||
|
|
||||||
|
Creates new PASETO keys for use in the API
|
||||||
|
|
||||||
|
## Example
|
||||||
|
|
||||||
|
```
|
||||||
|
$ dd if=/dev/urandom bs=32 count=1 2>/dev/null | base64 | xargs cargo run --
|
||||||
|
```
|
80
key-rotater/src/main.rs
Normal file
80
key-rotater/src/main.rs
Normal file
|
@ -0,0 +1,80 @@
|
||||||
|
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)
|
||||||
|
}
|
Loading…
Add table
Reference in a new issue