acme: use proxmox-acme-plugins and load schema from there
Signed-off-by: Thomas Lamprecht <t.lamprecht@proxmox.com>
This commit is contained in:
parent
60643023ad
commit
d308dc8af7
|
@ -113,6 +113,7 @@ Architecture: any
|
||||||
Depends: fonts-font-awesome,
|
Depends: fonts-font-awesome,
|
||||||
libjs-extjs (>= 6.0.1),
|
libjs-extjs (>= 6.0.1),
|
||||||
libjs-qrcodejs (>= 1.20201119),
|
libjs-qrcodejs (>= 1.20201119),
|
||||||
|
libproxmox-acme-plugins,
|
||||||
libsgutils2-2,
|
libsgutils2-2,
|
||||||
libzstd1 (>= 1.3.8),
|
libzstd1 (>= 1.3.8),
|
||||||
lvm2,
|
lvm2,
|
||||||
|
|
|
@ -3,6 +3,7 @@ Architecture: any
|
||||||
Depends: fonts-font-awesome,
|
Depends: fonts-font-awesome,
|
||||||
libjs-extjs (>= 6.0.1),
|
libjs-extjs (>= 6.0.1),
|
||||||
libjs-qrcodejs (>= 1.20201119),
|
libjs-qrcodejs (>= 1.20201119),
|
||||||
|
libproxmox-acme-plugins,
|
||||||
libsgutils2-2,
|
libsgutils2-2,
|
||||||
libzstd1 (>= 1.3.8),
|
libzstd1 (>= 1.3.8),
|
||||||
lvm2,
|
lvm2,
|
||||||
|
|
|
@ -1,6 +1,10 @@
|
||||||
|
use std::fs;
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
|
use std::sync::{Arc, Mutex};
|
||||||
|
use std::time::SystemTime;
|
||||||
|
|
||||||
use anyhow::{bail, format_err, Error};
|
use anyhow::{bail, format_err, Error};
|
||||||
|
use lazy_static::lazy_static;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use serde_json::{json, Value};
|
use serde_json::{json, Value};
|
||||||
|
|
||||||
|
@ -386,6 +390,43 @@ fn get_directories() -> Result<&'static [KnownAcmeDirectory], Error> {
|
||||||
Ok(crate::config::acme::KNOWN_ACME_DIRECTORIES)
|
Ok(crate::config::acme::KNOWN_ACME_DIRECTORIES)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Wrapper for efficient Arc use when returning the ACME challenge-plugin schema for serializing
|
||||||
|
struct ChallengeSchemaWrapper {
|
||||||
|
inner: Arc<Vec<AcmeChallengeSchema>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Serialize for ChallengeSchemaWrapper {
|
||||||
|
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||||
|
where
|
||||||
|
S: serde::Serializer,
|
||||||
|
{
|
||||||
|
self.inner.serialize(serializer)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_cached_challenge_schemas() -> Result<ChallengeSchemaWrapper, Error> {
|
||||||
|
lazy_static! {
|
||||||
|
static ref CACHE: Mutex<Option<(Arc<Vec<AcmeChallengeSchema>>, SystemTime)>> =
|
||||||
|
Mutex::new(None);
|
||||||
|
}
|
||||||
|
|
||||||
|
// the actual loading code
|
||||||
|
let mut last = CACHE.lock().unwrap();
|
||||||
|
|
||||||
|
let actual_mtime = fs::metadata(crate::config::acme::ACME_DNS_SCHEMA_FN)?.modified()?;
|
||||||
|
|
||||||
|
let schema = match &*last {
|
||||||
|
Some((schema, cached_mtime)) if *cached_mtime >= actual_mtime => schema.clone(),
|
||||||
|
_ => {
|
||||||
|
let new_schema = Arc::new(crate::config::acme::load_dns_challenge_schema()?);
|
||||||
|
*last = Some((Arc::clone(&new_schema), actual_mtime));
|
||||||
|
new_schema
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
Ok(ChallengeSchemaWrapper { inner: schema })
|
||||||
|
}
|
||||||
|
|
||||||
#[api(
|
#[api(
|
||||||
access: {
|
access: {
|
||||||
permission: &Permission::Anybody,
|
permission: &Permission::Anybody,
|
||||||
|
@ -397,18 +438,8 @@ fn get_directories() -> Result<&'static [KnownAcmeDirectory], Error> {
|
||||||
},
|
},
|
||||||
)]
|
)]
|
||||||
/// Get named known ACME directory endpoints.
|
/// Get named known ACME directory endpoints.
|
||||||
fn get_challenge_schema() -> Result<Vec<AcmeChallengeSchema>, Error> {
|
fn get_challenge_schema() -> Result<ChallengeSchemaWrapper, Error> {
|
||||||
let mut out = Vec::new();
|
get_cached_challenge_schemas()
|
||||||
crate::config::acme::foreach_dns_plugin(|id| {
|
|
||||||
out.push(AcmeChallengeSchema {
|
|
||||||
id: id.to_owned(),
|
|
||||||
name: id.to_owned(),
|
|
||||||
ty: "dns",
|
|
||||||
schema: Value::Object(Default::default()),
|
|
||||||
});
|
|
||||||
ControlFlow::Continue(())
|
|
||||||
})?;
|
|
||||||
Ok(out)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[api]
|
#[api]
|
||||||
|
|
|
@ -2,12 +2,14 @@ use std::collections::HashMap;
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
|
|
||||||
use anyhow::{bail, format_err, Error};
|
use anyhow::{bail, format_err, Error};
|
||||||
|
use serde_json::Value;
|
||||||
|
|
||||||
use proxmox::sys::error::SysError;
|
use proxmox::sys::error::SysError;
|
||||||
use proxmox::tools::fs::CreateOptions;
|
use proxmox::tools::fs::{CreateOptions, file_read_string};
|
||||||
|
|
||||||
use crate::api2::types::{
|
use crate::api2::types::{
|
||||||
PROXMOX_SAFE_ID_REGEX,
|
PROXMOX_SAFE_ID_REGEX,
|
||||||
|
AcmeChallengeSchema,
|
||||||
KnownAcmeDirectory,
|
KnownAcmeDirectory,
|
||||||
AcmeAccountName,
|
AcmeAccountName,
|
||||||
};
|
};
|
||||||
|
@ -16,6 +18,8 @@ use crate::tools::ControlFlow;
|
||||||
pub(crate) const ACME_DIR: &str = configdir!("/acme");
|
pub(crate) const ACME_DIR: &str = configdir!("/acme");
|
||||||
pub(crate) const ACME_ACCOUNT_DIR: &str = configdir!("/acme/accounts");
|
pub(crate) const ACME_ACCOUNT_DIR: &str = configdir!("/acme/accounts");
|
||||||
|
|
||||||
|
pub(crate) const ACME_DNS_SCHEMA_FN: &str = "/usr/share/proxmox-acme/dns-challenge-schema.json";
|
||||||
|
|
||||||
pub mod plugin;
|
pub mod plugin;
|
||||||
|
|
||||||
// `const fn`ify this once it is supported in `proxmox`
|
// `const fn`ify this once it is supported in `proxmox`
|
||||||
|
@ -141,6 +145,25 @@ pub fn mark_account_deactivated(name: &str) -> Result<(), Error> {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn load_dns_challenge_schema() -> Result<Vec<AcmeChallengeSchema>, Error> {
|
||||||
|
let raw = file_read_string(&ACME_DNS_SCHEMA_FN)?;
|
||||||
|
let schemas: serde_json::Map<String, Value> = serde_json::from_str(&raw)?;
|
||||||
|
|
||||||
|
Ok(schemas
|
||||||
|
.iter()
|
||||||
|
.map(|(id, schema)| AcmeChallengeSchema {
|
||||||
|
id: id.to_owned(),
|
||||||
|
name: schema
|
||||||
|
.get("name")
|
||||||
|
.and_then(Value::as_str)
|
||||||
|
.unwrap_or(id)
|
||||||
|
.to_owned(),
|
||||||
|
ty: "dns",
|
||||||
|
schema: schema.to_owned(),
|
||||||
|
})
|
||||||
|
.collect())
|
||||||
|
}
|
||||||
|
|
||||||
pub fn complete_acme_account(_arg: &str, _param: &HashMap<String, String>) -> Vec<String> {
|
pub fn complete_acme_account(_arg: &str, _param: &HashMap<String, String>) -> Vec<String> {
|
||||||
let mut out = Vec::new();
|
let mut out = Vec::new();
|
||||||
let _ = foreach_acme_account(|name| {
|
let _ = foreach_acme_account(|name| {
|
||||||
|
|
Loading…
Reference in New Issue