WIP
This commit is contained in:
parent
a7e74ac5dd
commit
95a8fac7dc
127
Cargo.lock
generated
127
Cargo.lock
generated
@ -2,6 +2,24 @@
|
||||
# It is not intended for manual editing.
|
||||
version = 3
|
||||
|
||||
[[package]]
|
||||
name = "acme2"
|
||||
version = "0.5.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "453e534d4f46dcdddd7aa8619e9a664e153f34383d14710db0b0d76c2964db89"
|
||||
dependencies = [
|
||||
"base64 0.13.1",
|
||||
"hyper",
|
||||
"openssl",
|
||||
"reqwest",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"thiserror",
|
||||
"tokio",
|
||||
"tracing",
|
||||
"tracing-futures",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "adler"
|
||||
version = "1.0.2"
|
||||
@ -107,6 +125,12 @@ version = "1.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
|
||||
|
||||
[[package]]
|
||||
name = "base64"
|
||||
version = "0.13.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8"
|
||||
|
||||
[[package]]
|
||||
name = "base64"
|
||||
version = "0.21.0"
|
||||
@ -360,6 +384,7 @@ dependencies = [
|
||||
name = "domiply"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"acme2",
|
||||
"clap",
|
||||
"futures",
|
||||
"gix",
|
||||
@ -369,6 +394,7 @@ dependencies = [
|
||||
"hyper",
|
||||
"mime_guess",
|
||||
"mockall",
|
||||
"openssl",
|
||||
"rust-embed",
|
||||
"serde",
|
||||
"serde_json",
|
||||
@ -495,6 +521,21 @@ version = "1.0.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1"
|
||||
|
||||
[[package]]
|
||||
name = "foreign-types"
|
||||
version = "0.3.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1"
|
||||
dependencies = [
|
||||
"foreign-types-shared",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "foreign-types-shared"
|
||||
version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b"
|
||||
|
||||
[[package]]
|
||||
name = "form_urlencoded"
|
||||
version = "1.1.0"
|
||||
@ -1147,7 +1188,7 @@ version = "0.31.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f01c2bf7b989c679695ef635fc7d9e80072e08101be4b53193c8e8b649900102"
|
||||
dependencies = [
|
||||
"base64",
|
||||
"base64 0.21.0",
|
||||
"bstr",
|
||||
"gix-command",
|
||||
"gix-credentials",
|
||||
@ -1768,6 +1809,44 @@ version = "1.17.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b7e5500299e16ebb147ae15a00a942af264cf3688f47923b8fc2cd5858f23ad3"
|
||||
|
||||
[[package]]
|
||||
name = "openssl"
|
||||
version = "0.10.52"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "01b8574602df80f7b85fdfc5392fa884a4e3b3f4f35402c070ab34c3d3f78d56"
|
||||
dependencies = [
|
||||
"bitflags 1.3.2",
|
||||
"cfg-if",
|
||||
"foreign-types",
|
||||
"libc",
|
||||
"once_cell",
|
||||
"openssl-macros",
|
||||
"openssl-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "openssl-macros"
|
||||
version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.15",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "openssl-sys"
|
||||
version = "0.9.87"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8e17f59264b2809d77ae94f0e1ebabc434773f370d6ca667bd223ea10e06cc7e"
|
||||
dependencies = [
|
||||
"cc",
|
||||
"libc",
|
||||
"pkg-config",
|
||||
"vcpkg",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "parking_lot"
|
||||
version = "0.12.1"
|
||||
@ -1841,6 +1920,26 @@ dependencies = [
|
||||
"sha2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pin-project"
|
||||
version = "1.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c95a7476719eab1e366eaf73d0260af3021184f18177925b07f54b30089ceead"
|
||||
dependencies = [
|
||||
"pin-project-internal",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pin-project-internal"
|
||||
version = "1.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "39407670928234ebc5e6e580247dd567ad73a3578460c5990f9503df207e8f07"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.15",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pin-project-lite"
|
||||
version = "0.2.9"
|
||||
@ -1853,6 +1952,12 @@ version = "0.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184"
|
||||
|
||||
[[package]]
|
||||
name = "pkg-config"
|
||||
version = "0.3.27"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "26072860ba924cbfa98ea39c8c19b4dd6a4a25423dbdf219c1eca91aa0cf6964"
|
||||
|
||||
[[package]]
|
||||
name = "ppv-lite86"
|
||||
version = "0.2.17"
|
||||
@ -2078,7 +2183,7 @@ version = "0.11.17"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "13293b639a097af28fc8a90f22add145a9c954e49d77da06263d58cf44d5fb91"
|
||||
dependencies = [
|
||||
"base64",
|
||||
"base64 0.21.0",
|
||||
"bytes",
|
||||
"encoding_rs",
|
||||
"futures-core",
|
||||
@ -2203,7 +2308,7 @@ version = "1.0.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d194b56d58803a43635bdc398cd17e383d6f71f9182b9a192c127ca42494a59b"
|
||||
dependencies = [
|
||||
"base64",
|
||||
"base64 0.21.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -2579,6 +2684,16 @@ dependencies = [
|
||||
"once_cell",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tracing-futures"
|
||||
version = "0.2.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "97d095ae15e245a057c8e8451bab9b3ee1e1f68e9ba2b4fbc18d0ac5237835f2"
|
||||
dependencies = [
|
||||
"pin-project",
|
||||
"tracing",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "trust-dns-client"
|
||||
version = "0.22.0"
|
||||
@ -2730,6 +2845,12 @@ version = "0.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a"
|
||||
|
||||
[[package]]
|
||||
name = "vcpkg"
|
||||
version = "0.2.15"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426"
|
||||
|
||||
[[package]]
|
||||
name = "version_check"
|
||||
version = "0.9.4"
|
||||
|
@ -32,3 +32,5 @@ hyper = { version = "0.14.26", features = [ "server" ]}
|
||||
http = "0.2.9"
|
||||
serde_urlencoded = "0.7.1"
|
||||
tokio-util = "0.7.8"
|
||||
acme2 = "0.5.1"
|
||||
openssl = "0.10.52"
|
||||
|
16
flake.nix
16
flake.nix
@ -23,24 +23,32 @@
|
||||
rustc = toolchain;
|
||||
};
|
||||
|
||||
opensslEnv = {
|
||||
OPENSSL_STATIC = "1";
|
||||
OPENSSL_LIB_DIR = "${pkgs.pkgsStatic.openssl.out}/lib";
|
||||
OPENSSL_INCLUDE_DIR = "${pkgs.pkgsStatic.openssl.dev}/include";
|
||||
};
|
||||
|
||||
in
|
||||
{
|
||||
defaultPackage = naersk-lib.buildPackage {
|
||||
defaultPackage = naersk-lib.buildPackage ({
|
||||
src = ./.;
|
||||
doCheck = false;
|
||||
nativeBuildInputs = [ pkgs.pkgsStatic.stdenv.cc ];
|
||||
CARGO_BUILD_TARGET = "x86_64-unknown-linux-musl";
|
||||
CARGO_BUILD_RUSTFLAGS = "-C target-feature=+crt-static";
|
||||
};
|
||||
} // opensslEnv);
|
||||
|
||||
devShell = pkgs.mkShell {
|
||||
devShell = pkgs.mkShell ({
|
||||
nativeBuildInputs = [
|
||||
pkgs.stdenv.cc
|
||||
pkgs.openssl
|
||||
toolchain
|
||||
];
|
||||
shellHook = ''
|
||||
source $(pwd)/.env.dev
|
||||
export CARGO_HOME=$(pwd)/.cargo
|
||||
'';
|
||||
};
|
||||
} // opensslEnv);
|
||||
});
|
||||
}
|
||||
|
@ -1,3 +1,4 @@
|
||||
pub mod acme;
|
||||
pub mod checker;
|
||||
pub mod config;
|
||||
pub mod manager;
|
||||
|
4
src/domain/acme.rs
Normal file
4
src/domain/acme.rs
Normal file
@ -0,0 +1,4 @@
|
||||
pub mod client;
|
||||
pub mod manager;
|
||||
|
||||
pub type AccountKey = openssl::pkey::PKey<openssl::pkey::Private>;
|
45
src/domain/acme/manager.rs
Normal file
45
src/domain/acme/manager.rs
Normal file
@ -0,0 +1,45 @@
|
||||
use std::sync;
|
||||
|
||||
use crate::domain::acme;
|
||||
use crate::error;
|
||||
use crate::error::{MapUnexpected, ToUnexpected};
|
||||
|
||||
const LETS_ENCRYPT_URL: &'static str = "https://acme-v02.api.letsencrypt.org/directory";
|
||||
|
||||
#[mockall::automock]
|
||||
pub trait Manager {}
|
||||
|
||||
pub trait BoxedManager: Manager + Send + Sync + Clone {}
|
||||
|
||||
struct ManagerImpl<Store>
|
||||
where
|
||||
Store: acme::BoxedStore,
|
||||
{
|
||||
store: Store,
|
||||
account: sync::Arc<acme2::Account>,
|
||||
}
|
||||
|
||||
pub async fn new<Store>(
|
||||
store: Store,
|
||||
contact_email: &str,
|
||||
) -> Result<impl BoxedManager, error::Unexpected>
|
||||
where
|
||||
Store: acme::BoxedStore,
|
||||
{
|
||||
let dir = acme2::DirectoryBuilder::new(LETS_ENCRYPT_URL.to_string())
|
||||
.build()
|
||||
.await
|
||||
.map_unexpected()?;
|
||||
|
||||
let mut builder = acme2::AccountBuilder::new(dir);
|
||||
builder.private_key(account_key);
|
||||
builder.contact(vec![contact_email.to_string()]);
|
||||
builder.terms_of_service_agreed(true);
|
||||
let account = builder.build().await.map_unexpected()?;
|
||||
|
||||
Ok(sync::Arc::new(ManagerImpl { account }))
|
||||
}
|
||||
|
||||
impl BoxedManager for sync::Arc<ManagerImpl> {}
|
||||
|
||||
impl Manager for sync::Arc<ManagerImpl> {}
|
94
src/domain/acme/store.rs
Normal file
94
src/domain/acme/store.rs
Normal file
@ -0,0 +1,94 @@
|
||||
use std::io::{Read, Write};
|
||||
use std::{fs, io, path, sync};
|
||||
|
||||
use crate::domain::acme::AccountKey;
|
||||
use crate::error;
|
||||
use crate::error::{MapUnexpected, ToUnexpected};
|
||||
|
||||
#[derive(thiserror::Error, Debug)]
|
||||
pub enum GetAccountKeyError {
|
||||
#[error("not found")]
|
||||
NotFound,
|
||||
|
||||
#[error(transparent)]
|
||||
Unexpected(#[from] error::Unexpected),
|
||||
}
|
||||
|
||||
#[mockall::automock]
|
||||
pub trait Store {
|
||||
fn set_account_key(&self, k: &AccountKey) -> Result<(), error::Unexpected>;
|
||||
fn get_account_key(&self) -> Result<AccountKey, GetAccountKeyError>;
|
||||
}
|
||||
|
||||
pub trait BoxedStore: Store + Send + Sync + Clone {}
|
||||
|
||||
struct FSStore {
|
||||
dir_path: path::PathBuf,
|
||||
}
|
||||
|
||||
pub fn new(dir_path: &path::Path) -> Result<impl BoxedStore, error::Unexpected> {
|
||||
fs::create_dir_all(dir_path).map_unexpected()?;
|
||||
Ok(sync::Arc::new(FSStore {
|
||||
dir_path: dir_path.into(),
|
||||
}))
|
||||
}
|
||||
|
||||
impl FSStore {
|
||||
fn account_key_path(&self) -> path::PathBuf {
|
||||
self.dir_path.join("account.key")
|
||||
}
|
||||
}
|
||||
|
||||
impl BoxedStore for sync::Arc<FSStore> {}
|
||||
|
||||
impl Store for sync::Arc<FSStore> {
|
||||
fn set_account_key(&self, k: &AccountKey) -> Result<(), error::Unexpected> {
|
||||
let mut file = fs::File::create(self.account_key_path()).map_unexpected()?;
|
||||
let pem = k.private_key_to_pem_pkcs8().map_unexpected()?;
|
||||
file.write_all(&pem).map_unexpected()?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn get_account_key(&self) -> Result<AccountKey, GetAccountKeyError> {
|
||||
let mut file = fs::File::open(self.account_key_path()).map_err(|e| match e.kind() {
|
||||
io::ErrorKind::NotFound => GetAccountKeyError::NotFound,
|
||||
_ => e.to_unexpected().into(),
|
||||
})?;
|
||||
|
||||
let mut pem = Vec::<u8>::new();
|
||||
file.read_to_end(&mut pem).map_unexpected()?;
|
||||
|
||||
let k = AccountKey::private_key_from_pem(&pem).map_unexpected()?;
|
||||
Ok(k)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use tempdir::TempDir;
|
||||
|
||||
#[test]
|
||||
fn account_key() {
|
||||
let tmp_dir = TempDir::new("domain_config_store").unwrap();
|
||||
let store = new(tmp_dir.path()).expect("store created");
|
||||
|
||||
assert!(matches!(
|
||||
store.get_account_key(),
|
||||
Err::<AccountKey, GetAccountKeyError>(GetAccountKeyError::NotFound)
|
||||
));
|
||||
|
||||
let k = acme2::gen_rsa_private_key(4096).expect("private key generated");
|
||||
|
||||
store.set_account_key(&k).expect("account private key set");
|
||||
|
||||
assert_eq!(
|
||||
k.private_key_to_pem_pkcs8().unwrap(),
|
||||
store
|
||||
.get_account_key()
|
||||
.expect("account private key retrieved")
|
||||
.private_key_to_pem_pkcs8()
|
||||
.unwrap()
|
||||
);
|
||||
}
|
||||
}
|
@ -3,6 +3,12 @@ use std::fmt;
|
||||
use std::fmt::Write;
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
/// Unexpected is a String which implements the Error trait. It is intended to be used in
|
||||
/// situations where the caller is being given an error they can't really handle, except to pass it
|
||||
/// along or log it.
|
||||
///
|
||||
/// The error is intended to also implement Send + Sync + Clone, such that it is easy to use in
|
||||
/// async situations.
|
||||
pub struct Unexpected(String);
|
||||
|
||||
impl fmt::Display for Unexpected {
|
||||
|
@ -315,7 +315,7 @@ mod tests {
|
||||
|
||||
let descr = origin::Descr::Git {
|
||||
url: curr_dir.clone(),
|
||||
branch_name: String::from("master"),
|
||||
branch_name: String::from("main"),
|
||||
};
|
||||
|
||||
let other_descr = origin::Descr::Git {
|
||||
|
Loading…
Reference in New Issue
Block a user