AcmeFactory
This commit is contained in:
parent
602c7f7ebe
commit
3c2434eb66
5 changed files with 165 additions and 72 deletions
|
|
@ -2,22 +2,43 @@ use std::error::Error;
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use std::fs::File as FsFile;
|
use std::fs::File as FsFile;
|
||||||
use std::io::Write;
|
use std::io::Write;
|
||||||
use std::path::PathBuf;
|
use std::path::{Path, PathBuf};
|
||||||
|
|
||||||
use crate::command_runner::CommandRunner;
|
use crate::command_runner::CommandRunner;
|
||||||
use crate::resources::Resource;
|
use crate::resources::Resource;
|
||||||
use crate::symbols::{Action, OwnedSymbolAction, Symbol, SymbolAction, SymbolRunner};
|
use crate::symbols::{Action, OwnedSymbolAction, Symbol, SymbolAction, SymbolRunner};
|
||||||
|
|
||||||
pub struct AcmeCert<'a, D: AsRef<str>, C: CommandRunner> {
|
pub struct AcmeCert<
|
||||||
|
'a,
|
||||||
|
D: AsRef<str>,
|
||||||
|
R: AsRef<Path>,
|
||||||
|
C: CommandRunner,
|
||||||
|
K: AsRef<Path>,
|
||||||
|
CH: AsRef<Path>,
|
||||||
|
> {
|
||||||
domain: D,
|
domain: D,
|
||||||
command_runner: &'a C,
|
command_runner: &'a C,
|
||||||
|
root_cert_path: R,
|
||||||
|
account_key_path: K,
|
||||||
|
challenges_path: CH,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, D: AsRef<str>, C: CommandRunner> AcmeCert<'a, D, C> {
|
impl<'a, D: AsRef<str>, R: AsRef<Path>, C: CommandRunner, K: AsRef<Path>, CH: AsRef<Path>>
|
||||||
pub fn new(domain: D, command_runner: &'a C) -> Self {
|
AcmeCert<'a, D, R, C, K, CH>
|
||||||
|
{
|
||||||
|
pub fn new(
|
||||||
|
domain: D,
|
||||||
|
command_runner: &'a C,
|
||||||
|
root_cert_path: R,
|
||||||
|
account_key_path: K,
|
||||||
|
challenges_path: CH,
|
||||||
|
) -> Self {
|
||||||
AcmeCert {
|
AcmeCert {
|
||||||
domain,
|
domain,
|
||||||
command_runner,
|
command_runner,
|
||||||
|
root_cert_path,
|
||||||
|
account_key_path,
|
||||||
|
challenges_path,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -30,7 +51,9 @@ impl<'a, D: AsRef<str>, C: CommandRunner> AcmeCert<'a, D, C> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, D: AsRef<str>, C: CommandRunner> fmt::Display for AcmeCert<'a, D, C> {
|
impl<'a, D: AsRef<str>, R: AsRef<Path>, C: CommandRunner, K: AsRef<Path>, CH: AsRef<Path>>
|
||||||
|
fmt::Display for AcmeCert<'a, D, R, C, K, CH>
|
||||||
|
{
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
write!(f, "AcmeCert {}", self.domain.as_ref())
|
write!(f, "AcmeCert {}", self.domain.as_ref())
|
||||||
}
|
}
|
||||||
|
|
@ -38,7 +61,9 @@ impl<'a, D: AsRef<str>, C: CommandRunner> fmt::Display for AcmeCert<'a, D, C> {
|
||||||
|
|
||||||
const DAYS_IN_SECONDS: u32 = 24 * 60 * 60;
|
const DAYS_IN_SECONDS: u32 = 24 * 60 * 60;
|
||||||
|
|
||||||
impl<'a, D: AsRef<str>, C: CommandRunner> Symbol for AcmeCert<'a, D, C> {
|
impl<'a, D: AsRef<str>, R: AsRef<Path>, C: CommandRunner, K: AsRef<Path>, CH: AsRef<Path>> Symbol
|
||||||
|
for AcmeCert<'a, D, R, C, K, CH>
|
||||||
|
{
|
||||||
fn target_reached(&self) -> Result<bool, Box<dyn Error>> {
|
fn target_reached(&self) -> Result<bool, Box<dyn Error>> {
|
||||||
if !self.get_cert_path().exists() {
|
if !self.get_cert_path().exists() {
|
||||||
return Ok(false);
|
return Ok(false);
|
||||||
|
|
@ -72,7 +97,7 @@ impl<'a, D: AsRef<str>, C: CommandRunner> Symbol for AcmeCert<'a, D, C> {
|
||||||
args![
|
args![
|
||||||
"verify",
|
"verify",
|
||||||
"--untrusted",
|
"--untrusted",
|
||||||
"/home/acme/lets_encrypt_x3_cross_signed.pem",
|
self.root_cert_path.as_ref(),
|
||||||
self.get_cert_path(),
|
self.get_cert_path(),
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
|
|
@ -97,11 +122,11 @@ impl<'a, D: AsRef<str>, C: CommandRunner> Symbol for AcmeCert<'a, D, C> {
|
||||||
"acme-tiny",
|
"acme-tiny",
|
||||||
args![
|
args![
|
||||||
"--account-key",
|
"--account-key",
|
||||||
"/home/acme/account.key",
|
self.account_key_path.as_ref(),
|
||||||
"--csr",
|
"--csr",
|
||||||
self.get_csr_path(),
|
self.get_csr_path(),
|
||||||
"--acme-dir",
|
"--acme-dir",
|
||||||
"/home/acme/challenges/",
|
self.challenges_path.as_ref(),
|
||||||
],
|
],
|
||||||
)?;
|
)?;
|
||||||
let mut file = FsFile::create(self.get_cert_path())?;
|
let mut file = FsFile::create(self.get_cert_path())?;
|
||||||
|
|
|
||||||
|
|
@ -2,22 +2,24 @@ use std::error::Error;
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use std::fs::File as FsFile;
|
use std::fs::File as FsFile;
|
||||||
use std::io::Write;
|
use std::io::Write;
|
||||||
use std::path::PathBuf;
|
use std::path::{Path, PathBuf};
|
||||||
|
|
||||||
use crate::command_runner::CommandRunner;
|
use crate::command_runner::CommandRunner;
|
||||||
use crate::resources::Resource;
|
use crate::resources::Resource;
|
||||||
use crate::symbols::{Action, OwnedSymbolAction, Symbol, SymbolAction, SymbolRunner};
|
use crate::symbols::{Action, OwnedSymbolAction, Symbol, SymbolAction, SymbolRunner};
|
||||||
|
|
||||||
pub struct AcmeCertChain<'a, D: AsRef<str>, C: CommandRunner> {
|
pub struct AcmeCertChain<'a, D: AsRef<str>, R: AsRef<Path>, C: CommandRunner> {
|
||||||
domain: D,
|
domain: D,
|
||||||
command_runner: &'a C,
|
command_runner: &'a C,
|
||||||
|
root_cert: R,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, D: AsRef<str>, C: CommandRunner> AcmeCertChain<'a, D, C> {
|
impl<'a, D: AsRef<str>, R: AsRef<Path>, C: CommandRunner> AcmeCertChain<'a, D, R, C> {
|
||||||
pub fn new(domain: D, command_runner: &'a C) -> Self {
|
pub fn new(domain: D, command_runner: &'a C, root_cert: R) -> Self {
|
||||||
AcmeCertChain {
|
AcmeCertChain {
|
||||||
domain,
|
domain,
|
||||||
command_runner,
|
command_runner,
|
||||||
|
root_cert,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -30,7 +32,9 @@ impl<'a, D: AsRef<str>, C: CommandRunner> AcmeCertChain<'a, D, C> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, D: AsRef<str>, C: CommandRunner> fmt::Display for AcmeCertChain<'a, D, C> {
|
impl<'a, D: AsRef<str>, R: AsRef<Path>, C: CommandRunner> fmt::Display
|
||||||
|
for AcmeCertChain<'a, D, R, C>
|
||||||
|
{
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
write!(f, "AcmeCertChain {}", self.domain.as_ref())
|
write!(f, "AcmeCertChain {}", self.domain.as_ref())
|
||||||
}
|
}
|
||||||
|
|
@ -38,7 +42,7 @@ impl<'a, D: AsRef<str>, C: CommandRunner> fmt::Display for AcmeCertChain<'a, D,
|
||||||
|
|
||||||
const DAYS_IN_SECONDS: u32 = 24 * 60 * 60;
|
const DAYS_IN_SECONDS: u32 = 24 * 60 * 60;
|
||||||
|
|
||||||
impl<'a, D: AsRef<str>, C: CommandRunner> Symbol for AcmeCertChain<'a, D, C> {
|
impl<'a, D: AsRef<str>, R: AsRef<Path>, C: CommandRunner> Symbol for AcmeCertChain<'a, D, R, C> {
|
||||||
fn target_reached(&self) -> Result<bool, Box<dyn Error>> {
|
fn target_reached(&self) -> Result<bool, Box<dyn Error>> {
|
||||||
if !self.get_cert_chain_path().exists() {
|
if !self.get_cert_chain_path().exists() {
|
||||||
return Ok(false);
|
return Ok(false);
|
||||||
|
|
@ -74,7 +78,7 @@ impl<'a, D: AsRef<str>, C: CommandRunner> Symbol for AcmeCertChain<'a, D, C> {
|
||||||
args![
|
args![
|
||||||
"verify",
|
"verify",
|
||||||
"-untrusted",
|
"-untrusted",
|
||||||
"/home/acme/lets_encrypt_x3_cross_signed.pem",
|
self.root_cert.as_ref(),
|
||||||
self.get_cert_chain_path(),
|
self.get_cert_chain_path(),
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
|
|
@ -85,10 +89,7 @@ impl<'a, D: AsRef<str>, C: CommandRunner> Symbol for AcmeCertChain<'a, D, C> {
|
||||||
fn execute(&self) -> Result<(), Box<dyn Error>> {
|
fn execute(&self) -> Result<(), Box<dyn Error>> {
|
||||||
let output = self.command_runner.get_output(
|
let output = self.command_runner.get_output(
|
||||||
"cat",
|
"cat",
|
||||||
args![
|
args![self.get_single_cert_path(), self.root_cert.as_ref(),],
|
||||||
self.get_single_cert_path(),
|
|
||||||
"/home/acme/lets_encrypt_x3_cross_signed.pem",
|
|
||||||
],
|
|
||||||
)?;
|
)?;
|
||||||
let mut file = FsFile::create(self.get_cert_chain_path())?;
|
let mut file = FsFile::create(self.get_cert_chain_path())?;
|
||||||
file.write_all(&output)?;
|
file.write_all(&output)?;
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,97 @@
|
||||||
|
use std::borrow::Cow;
|
||||||
|
use std::path::{Path, PathBuf};
|
||||||
|
|
||||||
|
use crate::command_runner::CommandRunner;
|
||||||
|
use crate::command_runner::SetuidCommandRunner;
|
||||||
|
use crate::symbols::dir::Dir;
|
||||||
|
use crate::symbols::file::File;
|
||||||
|
use crate::symbols::list::List;
|
||||||
|
use crate::symbols::owner::Owner;
|
||||||
|
use crate::symbols::Symbol;
|
||||||
|
|
||||||
mod account_key;
|
mod account_key;
|
||||||
mod cert;
|
mod cert;
|
||||||
mod chain;
|
mod chain;
|
||||||
mod user;
|
|
||||||
|
|
||||||
pub use self::account_key::AcmeAccountKey;
|
pub use self::account_key::AcmeAccountKey;
|
||||||
pub use self::cert::AcmeCert;
|
pub use self::cert::AcmeCert;
|
||||||
pub use self::chain::AcmeCertChain;
|
pub use self::chain::AcmeCertChain;
|
||||||
pub use self::user::new as newAcmeUser;
|
|
||||||
|
const ROOT_CERT_FILE_NAME: &str = "lets_encrypt_x3_cross_signed.pem";
|
||||||
|
const ACCOUNT_KEY_FILE_NAME: &str = "account.key";
|
||||||
|
|
||||||
|
pub struct Factory<'a, U: AsRef<str>, H: AsRef<Path>, C: AsRef<str>, R: CommandRunner> {
|
||||||
|
user_name: U,
|
||||||
|
home_dir: H,
|
||||||
|
cert: C,
|
||||||
|
command_runner: &'a R,
|
||||||
|
acme_command_runner: SetuidCommandRunner<'a, U, R>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, U: Clone + AsRef<str>, H: AsRef<Path>, C: AsRef<str>, R: CommandRunner>
|
||||||
|
Factory<'a, U, H, C, R>
|
||||||
|
{
|
||||||
|
pub fn new(user_name: U, home_dir: H, cert: C, command_runner: &'a R) -> Self {
|
||||||
|
let acme_command_runner = SetuidCommandRunner::new(user_name.clone(), command_runner);
|
||||||
|
Self {
|
||||||
|
user_name,
|
||||||
|
home_dir,
|
||||||
|
cert,
|
||||||
|
command_runner,
|
||||||
|
acme_command_runner,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub fn get_challenges_dir(&'a self) -> Cow<Path> {
|
||||||
|
[self.home_dir.as_ref(), "challenges".as_ref()]
|
||||||
|
.iter()
|
||||||
|
.collect::<PathBuf>()
|
||||||
|
.into()
|
||||||
|
}
|
||||||
|
pub fn get_init(&'a self) -> impl Symbol + 'a {
|
||||||
|
let root_cert_path: PathBuf = [self.home_dir.as_ref(), ROOT_CERT_FILE_NAME.as_ref()]
|
||||||
|
.iter()
|
||||||
|
.collect();
|
||||||
|
let account_key_file: PathBuf = [self.home_dir.as_ref(), ACCOUNT_KEY_FILE_NAME.as_ref()]
|
||||||
|
.iter()
|
||||||
|
.collect();
|
||||||
|
List::from((
|
||||||
|
AcmeAccountKey::new(account_key_file.clone(), self.command_runner),
|
||||||
|
Owner::new(
|
||||||
|
account_key_file,
|
||||||
|
self.user_name.clone(),
|
||||||
|
self.command_runner,
|
||||||
|
),
|
||||||
|
Dir::new(self.get_challenges_dir()),
|
||||||
|
Owner::new(
|
||||||
|
self.get_challenges_dir(),
|
||||||
|
self.user_name.clone(),
|
||||||
|
self.command_runner,
|
||||||
|
),
|
||||||
|
Dir::new("/etc/ssl/local_certs"),
|
||||||
|
Owner::new(
|
||||||
|
"/etc/ssl/local_certs",
|
||||||
|
self.user_name.clone(),
|
||||||
|
self.command_runner,
|
||||||
|
),
|
||||||
|
File::new(root_cert_path, self.cert.as_ref()),
|
||||||
|
))
|
||||||
|
}
|
||||||
|
pub fn get_cert<HOST: 'a + Clone + AsRef<str>>(&'a self, host: HOST) -> impl Symbol + 'a {
|
||||||
|
let root_cert_path: PathBuf = [self.home_dir.as_ref(), ROOT_CERT_FILE_NAME.as_ref()]
|
||||||
|
.iter()
|
||||||
|
.collect();
|
||||||
|
let account_key_path: PathBuf = [self.home_dir.as_ref(), ACCOUNT_KEY_FILE_NAME.as_ref()]
|
||||||
|
.iter()
|
||||||
|
.collect();
|
||||||
|
List::from((
|
||||||
|
AcmeCert::new(
|
||||||
|
host.clone(),
|
||||||
|
&self.acme_command_runner,
|
||||||
|
root_cert_path.clone(),
|
||||||
|
account_key_path,
|
||||||
|
self.get_challenges_dir(),
|
||||||
|
),
|
||||||
|
AcmeCertChain::new(host, &self.acme_command_runner, root_cert_path),
|
||||||
|
))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,28 +0,0 @@
|
||||||
use std::path::{Path, PathBuf};
|
|
||||||
|
|
||||||
use crate::command_runner::CommandRunner;
|
|
||||||
use crate::symbols::acme::AcmeAccountKey;
|
|
||||||
use crate::symbols::dir::Dir;
|
|
||||||
use crate::symbols::file::File;
|
|
||||||
use crate::symbols::list::List;
|
|
||||||
use crate::symbols::owner::Owner;
|
|
||||||
use crate::symbols::Symbol;
|
|
||||||
|
|
||||||
pub fn new<'a, R: CommandRunner, C: 'a + AsRef<str>, U: 'a + AsRef<str> + Clone, H: AsRef<Path>>(
|
|
||||||
command_runner: &'a R,
|
|
||||||
cert: C,
|
|
||||||
user_name: U,
|
|
||||||
home: H,
|
|
||||||
) -> impl Symbol + 'a {
|
|
||||||
let path = |rel: &str| [home.as_ref(), rel.as_ref()].iter().collect::<PathBuf>();
|
|
||||||
let account_key_file = path("account.key");
|
|
||||||
List::from((
|
|
||||||
AcmeAccountKey::new(account_key_file.clone(), command_runner),
|
|
||||||
Owner::new(account_key_file, user_name.clone(), command_runner),
|
|
||||||
Dir::new(path("challenges")),
|
|
||||||
Owner::new(path("challenges"), user_name.clone(), command_runner),
|
|
||||||
Dir::new("/etc/ssl/local_certs"),
|
|
||||||
Owner::new("/etc/ssl/local_certs", user_name, command_runner),
|
|
||||||
File::new(path("lets_encrypt_x3_cross_signed.pem"), cert),
|
|
||||||
))
|
|
||||||
}
|
|
||||||
|
|
@ -2,9 +2,9 @@ use std::borrow::Cow;
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
|
|
||||||
use crate::command_runner::{CommandRunner, SetuidCommandRunner};
|
use crate::command_runner::CommandRunner;
|
||||||
use crate::storage::{SimpleStorage, Storage};
|
use crate::storage::{SimpleStorage, Storage};
|
||||||
use crate::symbols::acme::{newAcmeUser, AcmeCert, AcmeCertChain};
|
use crate::symbols::acme::Factory as AcmeFactory;
|
||||||
use crate::symbols::cron::Cron;
|
use crate::symbols::cron::Cron;
|
||||||
use crate::symbols::file::File;
|
use crate::symbols::file::File;
|
||||||
use crate::symbols::git::checkout::GitCheckout;
|
use crate::symbols::git::checkout::GitCheckout;
|
||||||
|
|
@ -29,27 +29,37 @@ pub trait Policy {
|
||||||
fn socket_path(&self, user_name: &str, service_name: &str) -> PathBuf {
|
fn socket_path(&self, user_name: &str, service_name: &str) -> PathBuf {
|
||||||
format!("/var/tmp/{}-{}.socket", user_name, service_name).into()
|
format!("/var/tmp/{}-{}.socket", user_name, service_name).into()
|
||||||
}
|
}
|
||||||
|
fn acme_user(&self) -> Cow<str> {
|
||||||
|
"acme".into()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct DefaultPolicy;
|
pub struct DefaultPolicy;
|
||||||
|
|
||||||
impl Policy for DefaultPolicy {}
|
impl Policy for DefaultPolicy {}
|
||||||
|
|
||||||
pub struct SymbolFactory<'a, C: 'a + CommandRunner, R: 'a + SymbolRunner, P: 'a + Policy> {
|
pub struct SymbolFactory<
|
||||||
|
'a,
|
||||||
|
C: 'a + CommandRunner,
|
||||||
|
R: 'a + SymbolRunner,
|
||||||
|
P: 'a + Policy,
|
||||||
|
> {
|
||||||
command_runner: &'a C,
|
command_runner: &'a C,
|
||||||
acme_command_runner: SetuidCommandRunner<'a, Cow<'a, str>, C>,
|
acme_factory: AcmeFactory<'a, Cow<'a, str>, PathBuf, &'a str, C>,
|
||||||
symbol_runner: &'a R,
|
symbol_runner: &'a R,
|
||||||
policy: &'a P,
|
policy: &'a P,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'b, C: 'b + CommandRunner, R: 'b + SymbolRunner, P: 'b + Policy> SymbolFactory<'b, C, R, P> {
|
impl<'b, C: 'b + CommandRunner, R: 'b + SymbolRunner, P: 'b + Policy>
|
||||||
pub fn new(command_runner: &'b C, symbol_runner: &'b R, policy: &'b P) -> Self {
|
SymbolFactory<'b, C, R, P>
|
||||||
let acme_user = "acme"; // FIXME: CONFIG
|
{
|
||||||
|
pub fn new(command_runner: &'b C, symbol_runner: &'b R, policy: &'b P, cert: &'b str) -> Self {
|
||||||
let acme_command_runner = SetuidCommandRunner::new(acme_user.into(), command_runner);
|
let acme_user = policy.acme_user();
|
||||||
|
let acme_home = policy.home_for_user(&acme_user);
|
||||||
|
let acme_factory = AcmeFactory::new(acme_user, acme_home, cert, command_runner);
|
||||||
SymbolFactory {
|
SymbolFactory {
|
||||||
command_runner,
|
command_runner,
|
||||||
acme_command_runner,
|
acme_factory,
|
||||||
symbol_runner,
|
symbol_runner,
|
||||||
policy,
|
policy,
|
||||||
}
|
}
|
||||||
|
|
@ -66,9 +76,8 @@ impl<'b, C: 'b + CommandRunner, R: 'b + SymbolRunner, P: 'b + Policy> SymbolFact
|
||||||
nginx_server_symbol,
|
nginx_server_symbol,
|
||||||
ReloadService::new("nginx", self.command_runner),
|
ReloadService::new("nginx", self.command_runner),
|
||||||
),
|
),
|
||||||
AcmeCert::new(host, &self.acme_command_runner),
|
|
||||||
Hook::new(
|
Hook::new(
|
||||||
AcmeCertChain::new(host, &self.acme_command_runner),
|
self.acme_factory.get_cert(host),
|
||||||
ReloadService::new("nginx", self.command_runner),
|
ReloadService::new("nginx", self.command_runner),
|
||||||
),
|
),
|
||||||
))
|
))
|
||||||
|
|
@ -76,10 +85,13 @@ impl<'b, C: 'b + CommandRunner, R: 'b + SymbolRunner, P: 'b + Policy> SymbolFact
|
||||||
pub fn get_nginx_acme_challenge_config<'a>(&'a self) -> impl Symbol + 'a {
|
pub fn get_nginx_acme_challenge_config<'a>(&'a self) -> impl Symbol + 'a {
|
||||||
File::new(
|
File::new(
|
||||||
"/etc/nginx/snippets/acme-challenge.conf",
|
"/etc/nginx/snippets/acme-challenge.conf",
|
||||||
"location ^~ /.well-known/acme-challenge/ {
|
format!(
|
||||||
alias /home/acme/challenges/;
|
"location ^~ /.well-known/acme-challenge/ {{
|
||||||
|
alias {}/challenges/;
|
||||||
try_files $uri =404;
|
try_files $uri =404;
|
||||||
}",
|
}}",
|
||||||
|
self.acme_factory.get_challenges_dir().to_str().unwrap()
|
||||||
|
),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -340,13 +352,8 @@ env[PATH] = /usr/local/bin:/usr/bin:/bin
|
||||||
Cron::new(user, content, self.command_runner)
|
Cron::new(user, content, self.command_runner)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_acme_user<'a, S: 'a + AsRef<str> + Clone, D: 'a + AsRef<str>>(
|
pub fn get_acme_user<'a>(&'a self) -> impl Symbol + 'a {
|
||||||
&'a self,
|
self.acme_factory.get_init()
|
||||||
cert: D,
|
|
||||||
user_name: S,
|
|
||||||
) -> impl Symbol + 'a {
|
|
||||||
let home = self.policy.home_for_user(user_name.as_ref());
|
|
||||||
newAcmeUser(self.command_runner, cert, user_name.clone(), home)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_systemd_user_service<'a>(
|
pub fn get_systemd_user_service<'a>(
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue