forked from Proxmox/proxmox
product-config: remove digest implementation (move to proxmox-config-digest crate)
And use the new proxmox-config-digest crate instead. Signed-off-by: Dietmar Maurer <dietmar@proxmox.com>
This commit is contained in:
parent
34b21106dd
commit
4768ad2200
@ -12,19 +12,15 @@ description = "ACME API implementation"
|
||||
anyhow.workspace = true
|
||||
serde = { workspace = true, features = ["derive"] }
|
||||
serde_json = { workspace = true }
|
||||
|
||||
base64 = { workspace = true, optional = true }
|
||||
hex = { workspace = true, optional = true }
|
||||
|
||||
|
||||
tokio = { workspace = true, optional = true, features = ["fs"] }
|
||||
hyper = { workspace = true, optional = true }
|
||||
futures = { workspace = true, optional = true }
|
||||
http = { workspace = true, optional = true }
|
||||
log = { workspace = true, optional = true }
|
||||
nix = { workspace = true, optional = true }
|
||||
openssl = { workspace = true, optional = true }
|
||||
lazy_static = { workspace = true, optional = true }
|
||||
|
||||
proxmox-serde = { workspace = true, optional = true }
|
||||
proxmox-section-config = { workspace = true, optional = true }
|
||||
proxmox-rest-server = { workspace = true, optional = true }
|
||||
@ -32,6 +28,7 @@ proxmox-router = { workspace = true, optional = true }
|
||||
proxmox-sys = { workspace = true, optional = true }
|
||||
proxmox-schema = { workspace = true, features = ["api-macro", "api-types"] }
|
||||
proxmox-acme = { workspace = true, optional = true, features = ["api-types"] }
|
||||
proxmox-config-digest = { workspace = true, optional = true }
|
||||
proxmox-product-config = { workspace = true, optional = true }
|
||||
|
||||
[features]
|
||||
@ -39,13 +36,14 @@ default = ["api-types"]
|
||||
api-types = ["dep:proxmox-acme", "dep:proxmox-serde"]
|
||||
impl = [
|
||||
"api-types",
|
||||
"dep:proxmox-config-digest",
|
||||
"proxmox-config-digest?/openssl",
|
||||
"dep:proxmox-product-config",
|
||||
"proxmox-product-config?/impl",
|
||||
"dep:proxmox-acme",
|
||||
"proxmox-acme?/impl",
|
||||
"proxmox-acme?/async-client",
|
||||
"dep:proxmox-section-config",
|
||||
"dep:openssl",
|
||||
#"dep:openssl",
|
||||
"dep:lazy_static",
|
||||
"dep:log",
|
||||
"dep:nix",
|
||||
@ -57,5 +55,4 @@ impl = [
|
||||
"dep:proxmox-rest-server",
|
||||
"dep:proxmox-router",
|
||||
"dep:base64",
|
||||
"dep:hex",
|
||||
]
|
||||
|
@ -1,12 +1,12 @@
|
||||
//! ACME plugin configuration API implementation
|
||||
|
||||
use anyhow::{bail, format_err, Error};
|
||||
use hex::FromHex;
|
||||
|
||||
use serde::Deserialize;
|
||||
use serde_json::Value;
|
||||
|
||||
use proxmox_schema::param_bail;
|
||||
use proxmox_config_digest::ConfigDigest;
|
||||
|
||||
use crate::types::{
|
||||
DeletablePluginProperty, DnsPlugin, DnsPluginCore, DnsPluginCoreUpdater, PluginConfig,
|
||||
@ -17,7 +17,7 @@ use proxmox_router::{http_bail, RpcEnvironment};
|
||||
pub fn list_plugins(rpcenv: &mut dyn RpcEnvironment) -> Result<Vec<PluginConfig>, Error> {
|
||||
let (plugins, digest) = super::plugin_config::plugin_config()?;
|
||||
|
||||
rpcenv["digest"] = hex::encode(digest).into();
|
||||
rpcenv["digest"] = digest.to_hex().into();
|
||||
Ok(plugins
|
||||
.iter()
|
||||
.map(|(id, (ty, data))| modify_cfg_for_api(id, ty, data))
|
||||
@ -29,7 +29,7 @@ pub fn get_plugin(
|
||||
rpcenv: &mut dyn RpcEnvironment,
|
||||
) -> Result<PluginConfig, Error> {
|
||||
let (plugins, digest) = super::plugin_config::plugin_config()?;
|
||||
rpcenv["digest"] = hex::encode(digest).into();
|
||||
rpcenv["digest"] = digest.to_hex().into();
|
||||
|
||||
match plugins.get(&id) {
|
||||
Some((ty, data)) => Ok(modify_cfg_for_api(&id, ty, data)),
|
||||
@ -69,7 +69,7 @@ pub fn update_plugin(
|
||||
update: DnsPluginCoreUpdater,
|
||||
data: Option<String>,
|
||||
delete: Option<Vec<DeletablePluginProperty>>,
|
||||
digest: Option<String>,
|
||||
digest: Option<ConfigDigest>,
|
||||
) -> Result<(), Error> {
|
||||
let data = data
|
||||
.as_deref()
|
||||
@ -83,12 +83,7 @@ pub fn update_plugin(
|
||||
|
||||
let (mut plugins, expected_digest) = super::plugin_config::plugin_config()?;
|
||||
|
||||
if let Some(digest) = digest {
|
||||
let digest = <[u8; 32]>::from_hex(digest)?;
|
||||
if digest != expected_digest {
|
||||
bail!("detected modified configuration - file changed by other user? Try again.");
|
||||
}
|
||||
}
|
||||
expected_digest.detect_modification(digest.as_ref())?;
|
||||
|
||||
match plugins.get_mut(&id) {
|
||||
Some((ty, ref mut entry)) => {
|
||||
|
@ -6,6 +6,7 @@ use serde_json::Value;
|
||||
|
||||
use proxmox_schema::{ApiType, Schema};
|
||||
use proxmox_section_config::{SectionConfig, SectionConfigData, SectionConfigPlugin};
|
||||
use proxmox_config_digest::ConfigDigest;
|
||||
use proxmox_product_config::{ApiLockGuard, open_api_lockfile, replace_config};
|
||||
|
||||
use crate::types::{DnsPlugin, StandalonePlugin, PLUGIN_ID_SCHEMA};
|
||||
@ -60,13 +61,13 @@ pub(crate) fn lock_plugin_config() -> Result<ApiLockGuard, Error> {
|
||||
open_api_lockfile(plugin_cfg_lockfile, None, true)
|
||||
}
|
||||
|
||||
pub(crate) fn plugin_config() -> Result<(PluginData, [u8; 32]), Error> {
|
||||
pub(crate) fn plugin_config() -> Result<(PluginData, ConfigDigest), Error> {
|
||||
let plugin_cfg_filename = super::config::plugin_cfg_filename();
|
||||
|
||||
let content =
|
||||
proxmox_sys::fs::file_read_optional_string(&plugin_cfg_filename)?.unwrap_or_default();
|
||||
|
||||
let digest = openssl::sha::sha256(content.as_bytes());
|
||||
let digest = ConfigDigest::from_slice(content.as_bytes());
|
||||
let mut data = CONFIG.parse(&plugin_cfg_filename, &content)?;
|
||||
|
||||
if data.sections.get("standalone").is_none() {
|
||||
|
@ -12,14 +12,6 @@ exclude.workspace = true
|
||||
[dependencies]
|
||||
anyhow.workspace = true
|
||||
hex.workspace = true
|
||||
log = { workspace = true, optional = true }
|
||||
nix = { workspace = true, optional = true }
|
||||
openssl = { workspace = true, optional = true }
|
||||
serde.workspace = true
|
||||
serde_plain.workspace = true
|
||||
proxmox-sys = { workspace = true, optional = true, features = ["timer"] }
|
||||
proxmox-schema = { workspace = true, features = ["api-types"] }
|
||||
|
||||
[features]
|
||||
default = []
|
||||
impl = ["dep:log", "dep:nix", "dep:openssl", "dep:proxmox-sys"]
|
||||
log.workspace = true
|
||||
nix.workspace = true
|
||||
proxmox-sys = { workspace = true, features = ["timer"] }
|
||||
|
@ -1,112 +0,0 @@
|
||||
use anyhow::{bail, Error};
|
||||
|
||||
#[cfg(feature = "impl")]
|
||||
use openssl::sha;
|
||||
|
||||
use proxmox_schema::api_types::SHA256_HEX_REGEX;
|
||||
use proxmox_schema::ApiStringFormat;
|
||||
use proxmox_schema::ApiType;
|
||||
use proxmox_schema::Schema;
|
||||
use proxmox_schema::StringSchema;
|
||||
|
||||
pub const PROXMOX_CONFIG_DIGEST_FORMAT: ApiStringFormat =
|
||||
ApiStringFormat::Pattern(&SHA256_HEX_REGEX);
|
||||
|
||||
pub const PROXMOX_CONFIG_DIGEST_SCHEMA: Schema = StringSchema::new(
|
||||
"Prevent changes if current configuration file has different \
|
||||
SHA256 digest. This can be used to prevent concurrent \
|
||||
modifications.",
|
||||
)
|
||||
.format(&PROXMOX_CONFIG_DIGEST_FORMAT)
|
||||
.schema();
|
||||
|
||||
#[derive(Clone, Debug, Eq, PartialEq)]
|
||||
/// A configuration digest - a SHA256 hash.
|
||||
pub struct ConfigDigest([u8; 32]);
|
||||
|
||||
impl ConfigDigest {
|
||||
pub fn to_hex(&self) -> String {
|
||||
hex::encode(&self.0[..])
|
||||
}
|
||||
|
||||
#[cfg(feature = "impl")]
|
||||
pub fn from_slice<T: AsRef<[u8]>>(data: T) -> ConfigDigest {
|
||||
let digest = sha::sha256(data.as_ref());
|
||||
ConfigDigest(digest)
|
||||
}
|
||||
|
||||
/// Detect modified configuration files
|
||||
///
|
||||
/// This function fails with a reasonable error message if checksums do not match.
|
||||
pub fn detect_modification(&self, user_digest: Option<&Self>) -> Result<(), Error> {
|
||||
if let Some(user_digest) = user_digest {
|
||||
if user_digest != self {
|
||||
bail!("detected modified configuration - file changed by other user? Try again.");
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl ApiType for ConfigDigest {
|
||||
const API_SCHEMA: Schema = PROXMOX_CONFIG_DIGEST_SCHEMA;
|
||||
}
|
||||
|
||||
impl From<[u8; 32]> for ConfigDigest {
|
||||
#[inline]
|
||||
fn from(digest: [u8; 32]) -> Self {
|
||||
Self(digest)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<ConfigDigest> for [u8; 32] {
|
||||
#[inline]
|
||||
fn from(digest: ConfigDigest) -> Self {
|
||||
digest.0
|
||||
}
|
||||
}
|
||||
|
||||
impl AsRef<[u8]> for ConfigDigest {
|
||||
fn as_ref(&self) -> &[u8] {
|
||||
&self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl AsRef<[u8; 32]> for ConfigDigest {
|
||||
fn as_ref(&self) -> &[u8; 32] {
|
||||
&self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl std::ops::Deref for ConfigDigest {
|
||||
type Target = [u8; 32];
|
||||
|
||||
fn deref(&self) -> &[u8; 32] {
|
||||
&self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl std::ops::DerefMut for ConfigDigest {
|
||||
fn deref_mut(&mut self) -> &mut [u8; 32] {
|
||||
&mut self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl std::fmt::Display for ConfigDigest {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
write!(f, "{}", self.to_hex())
|
||||
}
|
||||
}
|
||||
|
||||
impl std::str::FromStr for ConfigDigest {
|
||||
type Err = hex::FromHexError;
|
||||
|
||||
fn from_str(s: &str) -> Result<Self, hex::FromHexError> {
|
||||
let mut digest = [0u8; 32];
|
||||
hex::decode_to_slice(s, &mut digest)?;
|
||||
Ok(ConfigDigest(digest))
|
||||
}
|
||||
}
|
||||
|
||||
serde_plain::derive_deserialize_from_fromstr!(ConfigDigest, "valid configuration digest");
|
||||
serde_plain::derive_serialize_from_display!(ConfigDigest);
|
@ -1,12 +1,5 @@
|
||||
mod digest;
|
||||
pub use digest::{ConfigDigest, PROXMOX_CONFIG_DIGEST_FORMAT, PROXMOX_CONFIG_DIGEST_SCHEMA};
|
||||
|
||||
#[cfg(feature = "impl")]
|
||||
mod filesystem_helpers;
|
||||
#[cfg(feature = "impl")]
|
||||
pub use filesystem_helpers::*;
|
||||
|
||||
#[cfg(feature = "impl")]
|
||||
mod product_config;
|
||||
#[cfg(feature = "impl")]
|
||||
pub use product_config::*;
|
||||
|
@ -23,37 +23,37 @@ log = { workspace = true, optional = true }
|
||||
proxmox-sys = { workspace = true, optional = true }
|
||||
proxmox-schema = { workspace = true, features = ["api-macro", "api-types"] }
|
||||
proxmox-time = { workspace = true, optional = true }
|
||||
proxmox-config-digest = { workspace = true, optional = true }
|
||||
proxmox-product-config = { workspace = true, optional = true }
|
||||
|
||||
[features]
|
||||
default = []
|
||||
dns-api-types = ["dep:proxmox-product-config"]
|
||||
dns-api-types = ["dep:proxmox-config-digest"]
|
||||
dns-impl = [
|
||||
"dns-api-types",
|
||||
"dep:proxmox-product-config",
|
||||
"proxmox-product-config?/impl",
|
||||
"dep:proxmox-config-digest",
|
||||
"proxmox-config-digest?/openssl",
|
||||
"dep:proxmox-sys",
|
||||
"dep:proxmox-time",
|
||||
]
|
||||
time-api-types = []
|
||||
time-impl = [
|
||||
"time-api-types",
|
||||
"dep:proxmox-config-digest",
|
||||
"proxmox-config-digest?/openssl",
|
||||
"dep:proxmox-product-config",
|
||||
"proxmox-product-config?/impl",
|
||||
"dep:proxmox-sys",
|
||||
"dep:proxmox-time",
|
||||
]
|
||||
network-api-types = []
|
||||
network-impl = [
|
||||
"network-api-types",
|
||||
"dep:proxmox-config-digest",
|
||||
"proxmox-config-digest?/openssl",
|
||||
"dep:proxmox-product-config",
|
||||
"proxmox-product-config?/impl",
|
||||
"dep:nix",
|
||||
"dep:libc",
|
||||
"dep:proxmox-sys",
|
||||
]
|
||||
syslog-api-types = []
|
||||
syslog-impl = [
|
||||
"syslog-api-types",
|
||||
"dep:log",
|
||||
]
|
||||
syslog-impl = ["syslog-api-types", "dep:log"]
|
||||
|
@ -5,7 +5,7 @@ use proxmox_schema::api_types::IP_FORMAT;
|
||||
use proxmox_schema::Schema;
|
||||
use proxmox_schema::StringSchema;
|
||||
|
||||
use proxmox_product_config::ConfigDigest;
|
||||
use proxmox_config_digest::ConfigDigest;
|
||||
|
||||
pub const SEARCH_DOMAIN_SCHEMA: Schema =
|
||||
StringSchema::new("Search domain for host-name lookup.").schema();
|
||||
|
@ -4,7 +4,7 @@ use std::sync::Mutex;
|
||||
use anyhow::Error;
|
||||
use const_format::concatcp;
|
||||
use lazy_static::lazy_static;
|
||||
use proxmox_product_config::ConfigDigest;
|
||||
use proxmox_config_digest::ConfigDigest;
|
||||
use regex::Regex;
|
||||
|
||||
use proxmox_sys::fs::file_get_contents;
|
||||
|
@ -1,6 +1,6 @@
|
||||
use anyhow::{bail, Error};
|
||||
|
||||
use proxmox_product_config::ConfigDigest;
|
||||
use proxmox_config_digest::ConfigDigest;
|
||||
|
||||
use crate::network::{self, parse_vlan_id_from_name, parse_vlan_raw_device_from_name};
|
||||
use crate::network::{
|
||||
|
@ -20,9 +20,8 @@ use helper::compute_file_diff;
|
||||
use helper::get_network_interfaces;
|
||||
use parser::NetworkParser;
|
||||
|
||||
use proxmox_product_config::{
|
||||
open_api_lockfile, replace_system_config, ApiLockGuard, ConfigDigest,
|
||||
};
|
||||
use proxmox_config_digest::ConfigDigest;
|
||||
use proxmox_product_config::{open_api_lockfile, replace_system_config, ApiLockGuard};
|
||||
|
||||
lazy_static! {
|
||||
static ref PHYSICAL_NIC_REGEX: Regex = Regex::new(r"^(?:eth\d+|en[^:.]+|ib\d+)$").unwrap();
|
||||
|
Loading…
Reference in New Issue
Block a user