config-digest: split out config digest api type into separate crate

Signed-off-by: Dietmar Maurer <dietmar@proxmox.com>
This commit is contained in:
Dietmar Maurer 2024-05-29 17:59:03 +02:00
parent 3497e9edc7
commit 34b21106dd
7 changed files with 223 additions and 0 deletions

View File

@ -9,6 +9,7 @@ members = [
"proxmox-borrow",
"proxmox-client",
"proxmox-compression",
"proxmox-config-digest",
"proxmox-http",
"proxmox-http-error",
"proxmox-human-byte",
@ -113,6 +114,7 @@ proxmox-io = { version = "1.0.0", path = "proxmox-io" }
proxmox-lang = { version = "1.1", path = "proxmox-lang" }
proxmox-login = { version = "0.1.0", path = "proxmox-login" }
proxmox-product-config = { version = "0.1.0", path = "proxmox-product-config" }
proxmox-config-digest = { version = "0.1.0", path = "proxmox-config-digest" }
proxmox-rest-server = { version = "0.5.2", path = "proxmox-rest-server" }
proxmox-router = { version = "2.1.3", path = "proxmox-router" }
proxmox-schema = { version = "3.1.1", path = "proxmox-schema" }

View File

@ -0,0 +1,20 @@
[package]
name = "proxmox-config-digest"
version = "0.1.0"
authors.workspace = true
edition.workspace = true
license.workspace = true
repository.workspace = true
description = "Configuration file digest API type."
exclude.workspace = true
[dependencies]
anyhow.workspace = true
hex.workspace = true
serde.workspace = true
serde_plain.workspace = true
proxmox-schema = { workspace = true, features = ["api-types"] }
# feature "openssl", allows to compute the SHA256 digest
openssl = { workspace = true, optional = true }

View File

@ -0,0 +1,5 @@
rust-proxmox-config-digest (0.1.0-1) bookworm; urgency=medium
* initial packaging (split out from proxmox-product-config)
-- Proxmox Support Team <support@proxmox.com> Wed, 29 May 2024 17:49:33 +0200

View File

@ -0,0 +1,59 @@
Source: rust-proxmox-config-digest
Section: rust
Priority: optional
Build-Depends: debhelper (>= 12),
dh-cargo (>= 25),
cargo:native <!nocheck>,
rustc:native <!nocheck>,
libstd-rust-dev <!nocheck>,
librust-anyhow-1+default-dev <!nocheck>,
librust-hex-0.4+default-dev <!nocheck>,
librust-proxmox-schema-3+api-types-dev (>= 3.1.1-~~) <!nocheck>,
librust-proxmox-schema-3+default-dev (>= 3.1.1-~~) <!nocheck>,
librust-serde-1+default-dev <!nocheck>,
librust-serde-plain-1+default-dev <!nocheck>
Maintainer: Proxmox Support Team <support@proxmox.com>
Standards-Version: 4.6.2
Vcs-Git: git://git.proxmox.com/git/proxmox.git
Vcs-Browser: https://git.proxmox.com/?p=proxmox.git
X-Cargo-Crate: proxmox-config-digest
Rules-Requires-Root: no
Package: librust-proxmox-config-digest-dev
Architecture: any
Multi-Arch: same
Depends:
${misc:Depends},
librust-anyhow-1+default-dev,
librust-hex-0.4+default-dev,
librust-proxmox-schema-3+api-types-dev (>= 3.1.1-~~),
librust-proxmox-schema-3+default-dev (>= 3.1.1-~~),
librust-serde-1+default-dev,
librust-serde-plain-1+default-dev
Suggests:
librust-proxmox-config-digest+openssl-dev (= ${binary:Version})
Provides:
librust-proxmox-config-digest+default-dev (= ${binary:Version}),
librust-proxmox-config-digest-0-dev (= ${binary:Version}),
librust-proxmox-config-digest-0+default-dev (= ${binary:Version}),
librust-proxmox-config-digest-0.1-dev (= ${binary:Version}),
librust-proxmox-config-digest-0.1+default-dev (= ${binary:Version}),
librust-proxmox-config-digest-0.1.0-dev (= ${binary:Version}),
librust-proxmox-config-digest-0.1.0+default-dev (= ${binary:Version})
Description: Configuration file digest API type - Rust source code
Source code for Debianized Rust crate "proxmox-config-digest"
Package: librust-proxmox-config-digest+openssl-dev
Architecture: any
Multi-Arch: same
Depends:
${misc:Depends},
librust-proxmox-config-digest-dev (= ${binary:Version}),
librust-openssl-0.10+default-dev
Provides:
librust-proxmox-config-digest-0+openssl-dev (= ${binary:Version}),
librust-proxmox-config-digest-0.1+openssl-dev (= ${binary:Version}),
librust-proxmox-config-digest-0.1.0+openssl-dev (= ${binary:Version})
Description: Configuration file digest API type - feature "openssl"
This metapackage enables feature "openssl" for the Rust proxmox-config-digest
crate, by pulling in any additional dependencies needed by that feature.

View File

@ -0,0 +1,18 @@
Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/
Files:
*
Copyright: 2019 - 2023 Proxmox Server Solutions GmbH <support@proxmox.com>
License: AGPL-3.0-or-later
This program is free software: you can redistribute it and/or modify it under
the terms of the GNU Affero General Public License as published by the Free
Software Foundation, either version 3 of the License, or (at your option) any
later version.
.
This program is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
details.
.
You should have received a copy of the GNU Affero General Public License along
with this program. If not, see <https://www.gnu.org/licenses/>.

View File

@ -0,0 +1,7 @@
overlay = "."
crate_src_path = ".."
maintainer = "Proxmox Support Team <support@proxmox.com>"
[source]
vcs_git = "git://git.proxmox.com/git/proxmox.git"
vcs_browser = "https://git.proxmox.com/?p=proxmox.git"

View File

@ -0,0 +1,112 @@
use anyhow::{bail, Error};
#[cfg(feature = "openssl")]
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 = "openssl")]
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);