From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from firstgate.proxmox.com (firstgate.proxmox.com [212.224.123.68]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits)) (No client certificate requested) by lists.proxmox.com (Postfix) with ESMTPS id 3F76FBA725 for ; Wed, 20 Mar 2024 11:04:01 +0100 (CET) Received: from firstgate.proxmox.com (localhost [127.0.0.1]) by firstgate.proxmox.com (Proxmox) with ESMTP id 1CCEBD432 for ; Wed, 20 Mar 2024 11:04:01 +0100 (CET) Received: from druiddev.proxmox.com (unknown [94.136.29.99]) by firstgate.proxmox.com (Proxmox) with ESMTP for ; Wed, 20 Mar 2024 11:03:57 +0100 (CET) Received: by druiddev.proxmox.com (Postfix, from userid 1000) id 9A1428040A; Wed, 20 Mar 2024 11:03:57 +0100 (CET) From: Dietmar Maurer To: pbs-devel@lists.proxmox.com Date: Wed, 20 Mar 2024 11:03:55 +0100 Message-Id: <20240320100355.436143-1-dietmar@proxmox.com> X-Mailer: git-send-email 2.39.2 MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-SPAM-LEVEL: Spam detection results: 0 AWL -0.544 Adjusted score from AWL reputation of From: address BAYES_00 -1.9 Bayes spam probability is 0 to 1% DMARC_MISSING 0.1 Missing DMARC policy KAM_DMARC_STATUS 0.01 Test Rule for DKIM or SPF Failure with Strict Alignment KAM_LAZY_DOMAIN_SECURITY 1 Sending domain does not have any anti-forgery methods RDNS_NONE 0.793 Delivered to internal network by a host with no rDNS SPF_HELO_NONE 0.001 SPF: HELO does not publish an SPF Record SPF_NONE 0.001 SPF: sender does not publish an SPF Record T_SCC_BODY_TEXT_LINE -0.01 - Subject: [pbs-devel] [PATCH proxmox-backup] pbs-api-types: use const_format and new api-types from proxmox-schema X-BeenThere: pbs-devel@lists.proxmox.com X-Mailman-Version: 2.1.29 Precedence: list List-Id: Proxmox Backup Server development discussion List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Wed, 20 Mar 2024 10:04:01 -0000 Signed-off-by: Dietmar Maurer --- Cargo.toml | 2 + pbs-api-types/Cargo.toml | 1 + pbs-api-types/src/acl.rs | 5 +- pbs-api-types/src/common_regex.rs | 78 --------- pbs-api-types/src/datastore.rs | 29 ++-- pbs-api-types/src/jobs.rs | 11 +- pbs-api-types/src/lib.rs | 274 +++++++----------------------- pbs-api-types/src/tape/mod.rs | 8 +- pbs-config/src/network/helper.rs | 7 - pbs-config/src/network/parser.rs | 2 +- src/api2/node/dns.rs | 6 +- 11 files changed, 105 insertions(+), 318 deletions(-) delete mode 100644 pbs-api-types/src/common_regex.rs diff --git a/Cargo.toml b/Cargo.toml index 00dc4d86..676d76ad 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -108,6 +108,7 @@ bitflags = "1.2.1" bytes = "1.0" cidr = "0.2.1" crc32fast = "1" +const_format = "0.2" crossbeam-channel = "0.5" endian_trait = { version = "0.6", features = ["arrays"] } env_logger = "0.10" @@ -158,6 +159,7 @@ base64.workspace = true bitflags.workspace = true bytes.workspace = true cidr.workspace = true +const_format.workspace = true crc32fast.workspace = true crossbeam-channel.workspace = true endian_trait.workspace = true diff --git a/pbs-api-types/Cargo.toml b/pbs-api-types/Cargo.toml index 31b69f62..94ab583b 100644 --- a/pbs-api-types/Cargo.toml +++ b/pbs-api-types/Cargo.toml @@ -7,6 +7,7 @@ description = "general API type helpers for PBS" [dependencies] anyhow.workspace = true +const_format.workspace = true hex.workspace = true lazy_static.workspace = true percent-encoding.workspace = true diff --git a/pbs-api-types/src/acl.rs b/pbs-api-types/src/acl.rs index 8bbd2958..b2583b6a 100644 --- a/pbs-api-types/src/acl.rs +++ b/pbs-api-types/src/acl.rs @@ -2,14 +2,17 @@ use std::str::FromStr; use serde::de::{value, IntoDeserializer}; use serde::{Deserialize, Serialize}; +use const_format::concatcp; use proxmox_lang::constnamedbitmap; use proxmox_schema::{ api, const_regex, ApiStringFormat, BooleanSchema, EnumEntry, Schema, StringSchema, }; +use crate::PROXMOX_SAFE_ID_REGEX_STR; + const_regex! { - pub ACL_PATH_REGEX = concat!(r"^(?:/|", r"(?:/", PROXMOX_SAFE_ID_REGEX_STR!(), ")+", r")$"); + pub ACL_PATH_REGEX = concatcp!(r"^(?:/|", r"(?:/", PROXMOX_SAFE_ID_REGEX_STR, ")+", r")$"); } // define Privilege bitfield diff --git a/pbs-api-types/src/common_regex.rs b/pbs-api-types/src/common_regex.rs deleted file mode 100644 index 8fe30673..00000000 --- a/pbs-api-types/src/common_regex.rs +++ /dev/null @@ -1,78 +0,0 @@ -//! Predefined Regular Expressions -//! -//! This is a collection of useful regular expressions - -use lazy_static::lazy_static; -use regex::Regex; - -#[rustfmt::skip] -#[macro_export] -macro_rules! IPV4OCTET { () => (r"(?:25[0-5]|(?:2[0-4]|1[0-9]|[1-9])?[0-9])") } -#[rustfmt::skip] -#[macro_export] -macro_rules! IPV6H16 { () => (r"(?:[0-9a-fA-F]{1,4})") } -#[rustfmt::skip] -#[macro_export] -macro_rules! IPV6LS32 { () => (concat!(r"(?:(?:", IPV4RE!(), "|", IPV6H16!(), ":", IPV6H16!(), "))" )) } - -/// Returns the regular expression string to match IPv4 addresses -#[rustfmt::skip] -#[macro_export] -macro_rules! IPV4RE { () => (concat!(r"(?:(?:", IPV4OCTET!(), r"\.){3}", IPV4OCTET!(), ")")) } - -/// Returns the regular expression string to match IPv6 addresses -#[rustfmt::skip] -#[macro_export] -macro_rules! IPV6RE { () => (concat!(r"(?:", - r"(?:(?:", r"(?:", IPV6H16!(), r":){6})", IPV6LS32!(), r")|", - r"(?:(?:", r"::(?:", IPV6H16!(), r":){5})", IPV6LS32!(), r")|", - r"(?:(?:(?:", IPV6H16!(), r")?::(?:", IPV6H16!(), r":){4})", IPV6LS32!(), r")|", - r"(?:(?:(?:(?:", IPV6H16!(), r":){0,1}", IPV6H16!(), r")?::(?:", IPV6H16!(), r":){3})", IPV6LS32!(), r")|", - r"(?:(?:(?:(?:", IPV6H16!(), r":){0,2}", IPV6H16!(), r")?::(?:", IPV6H16!(), r":){2})", IPV6LS32!(), r")|", - r"(?:(?:(?:(?:", IPV6H16!(), r":){0,3}", IPV6H16!(), r")?::(?:", IPV6H16!(), r":){1})", IPV6LS32!(), r")|", - r"(?:(?:(?:(?:", IPV6H16!(), r":){0,4}", IPV6H16!(), r")?::", ")", IPV6LS32!(), r")|", - r"(?:(?:(?:(?:", IPV6H16!(), r":){0,5}", IPV6H16!(), r")?::", ")", IPV6H16!(), r")|", - r"(?:(?:(?:(?:", IPV6H16!(), r":){0,6}", IPV6H16!(), r")?::", ")))")) -} - -/// Returns the regular expression string to match IP addresses (v4 or v6) -#[rustfmt::skip] -#[macro_export] -macro_rules! IPRE { () => (concat!(r"(?:", IPV4RE!(), "|", IPV6RE!(), ")")) } - -/// Regular expression string to match IP addresses where IPv6 addresses require brackets around -/// them, while for IPv4 they are forbidden. -#[rustfmt::skip] -#[macro_export] -macro_rules! IPRE_BRACKET { () => ( - concat!(r"(?:", - IPV4RE!(), - r"|\[(?:", - IPV6RE!(), - r")\]", - r")")) -} - -lazy_static! { - pub static ref IP_REGEX: Regex = Regex::new(concat!(r"^", IPRE!(), r"$")).unwrap(); - pub static ref IP_BRACKET_REGEX: Regex = - Regex::new(concat!(r"^", IPRE_BRACKET!(), r"$")).unwrap(); - pub static ref SHA256_HEX_REGEX: Regex = Regex::new(r"^[a-f0-9]{64}$").unwrap(); - pub static ref SYSTEMD_DATETIME_REGEX: Regex = - Regex::new(r"^\d{4}-\d{2}-\d{2}( \d{2}:\d{2}(:\d{2})?)?$").unwrap(); -} - -#[test] -fn test_regexes() { - assert!(IP_REGEX.is_match("127.0.0.1")); - assert!(IP_REGEX.is_match("::1")); - assert!(IP_REGEX.is_match("2014:b3a::27")); - assert!(IP_REGEX.is_match("2014:b3a::192.168.0.1")); - assert!(IP_REGEX.is_match("2014:b3a:0102:adf1:1234:4321:4afA:BCDF")); - - assert!(IP_BRACKET_REGEX.is_match("127.0.0.1")); - assert!(IP_BRACKET_REGEX.is_match("[::1]")); - assert!(IP_BRACKET_REGEX.is_match("[2014:b3a::27]")); - assert!(IP_BRACKET_REGEX.is_match("[2014:b3a::192.168.0.1]")); - assert!(IP_BRACKET_REGEX.is_match("[2014:b3a:0102:adf1:1234:4321:4afA:BCDF]")); -} diff --git a/pbs-api-types/src/datastore.rs b/pbs-api-types/src/datastore.rs index cce9888b..5e13c157 100644 --- a/pbs-api-types/src/datastore.rs +++ b/pbs-api-types/src/datastore.rs @@ -2,6 +2,7 @@ use std::fmt; use std::path::PathBuf; use anyhow::{bail, format_err, Error}; +use const_format::concatcp; use serde::{Deserialize, Serialize}; use proxmox_schema::{ @@ -10,31 +11,33 @@ use proxmox_schema::{ }; use crate::{ - Authid, CryptMode, Fingerprint, GroupFilter, MaintenanceMode, Userid, - DATASTORE_NOTIFY_STRING_SCHEMA, GC_SCHEDULE_SCHEMA, PROXMOX_SAFE_ID_FORMAT, - PRUNE_SCHEDULE_SCHEMA, SHA256_HEX_REGEX, SINGLE_LINE_COMMENT_SCHEMA, UPID, + Authid, CryptMode, Fingerprint, GroupFilter, MaintenanceMode, Userid, BACKUP_ID_RE, + BACKUP_NS_RE, BACKUP_TIME_RE, BACKUP_TYPE_RE, DATASTORE_NOTIFY_STRING_SCHEMA, + GC_SCHEDULE_SCHEMA, GROUP_OR_SNAPSHOT_PATH_REGEX_STR, PROXMOX_SAFE_ID_FORMAT, + PROXMOX_SAFE_ID_REGEX_STR, PRUNE_SCHEDULE_SCHEMA, SHA256_HEX_REGEX, SINGLE_LINE_COMMENT_SCHEMA, + SNAPSHOT_PATH_REGEX_STR, UPID, }; const_regex! { - pub BACKUP_NAMESPACE_REGEX = concat!(r"^", BACKUP_NS_RE!(), r"$"); + pub BACKUP_NAMESPACE_REGEX = concatcp!(r"^", BACKUP_NS_RE, r"$"); - pub BACKUP_TYPE_REGEX = concat!(r"^(", BACKUP_TYPE_RE!(), r")$"); + pub BACKUP_TYPE_REGEX = concatcp!(r"^(", BACKUP_TYPE_RE, r")$"); - pub BACKUP_ID_REGEX = concat!(r"^", BACKUP_ID_RE!(), r"$"); + pub BACKUP_ID_REGEX = concatcp!(r"^", BACKUP_ID_RE, r"$"); - pub BACKUP_DATE_REGEX = concat!(r"^", BACKUP_TIME_RE!() ,r"$"); + pub BACKUP_DATE_REGEX = concatcp!(r"^", BACKUP_TIME_RE ,r"$"); - pub GROUP_PATH_REGEX = concat!( - r"^(", BACKUP_TYPE_RE!(), ")/", - r"(", BACKUP_ID_RE!(), r")$", + pub GROUP_PATH_REGEX = concatcp!( + r"^(", BACKUP_TYPE_RE, ")/", + r"(", BACKUP_ID_RE, r")$", ); pub BACKUP_FILE_REGEX = r"^.*\.([fd]idx|blob)$"; - pub SNAPSHOT_PATH_REGEX = concat!(r"^", SNAPSHOT_PATH_REGEX_STR!(), r"$"); - pub GROUP_OR_SNAPSHOT_PATH_REGEX = concat!(r"^", GROUP_OR_SNAPSHOT_PATH_REGEX_STR!(), r"$"); + pub SNAPSHOT_PATH_REGEX = concatcp!(r"^", SNAPSHOT_PATH_REGEX_STR, r"$"); + pub GROUP_OR_SNAPSHOT_PATH_REGEX = concatcp!(r"^", GROUP_OR_SNAPSHOT_PATH_REGEX_STR, r"$"); - pub DATASTORE_MAP_REGEX = concat!(r"^(?:", PROXMOX_SAFE_ID_REGEX_STR!(), r"=)?", PROXMOX_SAFE_ID_REGEX_STR!(), r"$"); + pub DATASTORE_MAP_REGEX = concatcp!(r"^(?:", PROXMOX_SAFE_ID_REGEX_STR, r"=)?", PROXMOX_SAFE_ID_REGEX_STR, r"$"); } pub const CHUNK_DIGEST_FORMAT: ApiStringFormat = ApiStringFormat::Pattern(&SHA256_HEX_REGEX); diff --git a/pbs-api-types/src/jobs.rs b/pbs-api-types/src/jobs.rs index 80578d80..6fb9b187 100644 --- a/pbs-api-types/src/jobs.rs +++ b/pbs-api-types/src/jobs.rs @@ -1,6 +1,7 @@ use std::str::FromStr; use anyhow::bail; +use const_format::concatcp; use regex::Regex; use serde::{Deserialize, Serialize}; @@ -8,17 +9,17 @@ use proxmox_schema::*; use crate::{ Authid, BackupNamespace, BackupType, RateLimitConfig, Userid, BACKUP_GROUP_SCHEMA, - BACKUP_NAMESPACE_SCHEMA, DATASTORE_SCHEMA, DRIVE_NAME_SCHEMA, MEDIA_POOL_NAME_SCHEMA, - NS_MAX_DEPTH_REDUCED_SCHEMA, PROXMOX_SAFE_ID_FORMAT, REMOTE_ID_SCHEMA, - SINGLE_LINE_COMMENT_SCHEMA, + BACKUP_NAMESPACE_SCHEMA, BACKUP_NS_RE, DATASTORE_SCHEMA, DRIVE_NAME_SCHEMA, + MEDIA_POOL_NAME_SCHEMA, NS_MAX_DEPTH_REDUCED_SCHEMA, PROXMOX_SAFE_ID_FORMAT, + PROXMOX_SAFE_ID_REGEX_STR, REMOTE_ID_SCHEMA, SINGLE_LINE_COMMENT_SCHEMA, }; const_regex! { /// Regex for verification jobs 'DATASTORE:ACTUAL_JOB_ID' - pub VERIFICATION_JOB_WORKER_ID_REGEX = concat!(r"^(", PROXMOX_SAFE_ID_REGEX_STR!(), r"):"); + pub VERIFICATION_JOB_WORKER_ID_REGEX = concatcp!(r"^(", PROXMOX_SAFE_ID_REGEX_STR, r"):"); /// Regex for sync jobs '(REMOTE|\-):REMOTE_DATASTORE:LOCAL_DATASTORE:(?:LOCAL_NS_ANCHOR:)ACTUAL_JOB_ID' - pub SYNC_JOB_WORKER_ID_REGEX = concat!(r"^(", PROXMOX_SAFE_ID_REGEX_STR!(), r"|\-):(", PROXMOX_SAFE_ID_REGEX_STR!(), r"):(", PROXMOX_SAFE_ID_REGEX_STR!(), r")(?::(", BACKUP_NS_RE!(), r"))?:"); + pub SYNC_JOB_WORKER_ID_REGEX = concatcp!(r"^(", PROXMOX_SAFE_ID_REGEX_STR, r"|\-):(", PROXMOX_SAFE_ID_REGEX_STR, r"):(", PROXMOX_SAFE_ID_REGEX_STR, r")(?::(", BACKUP_NS_RE, r"))?:"); } pub const JOB_ID_SCHEMA: Schema = StringSchema::new("Job ID.") diff --git a/pbs-api-types/src/lib.rs b/pbs-api-types/src/lib.rs index 88e8f44d..7eb836ed 100644 --- a/pbs-api-types/src/lib.rs +++ b/pbs-api-types/src/lib.rs @@ -1,10 +1,8 @@ //! Basic API types used by most of the PBS code. +use const_format::concatcp; use serde::{Deserialize, Serialize}; -use proxmox_auth_api::{APITOKEN_ID_REGEX_STR, USER_ID_REGEX_STR}; - -pub mod common_regex; pub mod percent_encoding; use proxmox_schema::{ @@ -12,59 +10,78 @@ use proxmox_schema::{ }; use proxmox_time::parse_daily_duration; -#[rustfmt::skip] -#[macro_export] -macro_rules! PROXMOX_SAFE_ID_REGEX_STR { () => { r"(?:[A-Za-z0-9_][A-Za-z0-9._\-]*)" }; } +use proxmox_auth_api::types::{APITOKEN_ID_REGEX_STR, USER_ID_REGEX_STR}; + +pub use proxmox_schema::api_types::SAFE_ID_FORMAT as PROXMOX_SAFE_ID_FORMAT; +pub use proxmox_schema::api_types::SAFE_ID_REGEX as PROXMOX_SAFE_ID_REGEX; +pub use proxmox_schema::api_types::SAFE_ID_REGEX_STR as PROXMOX_SAFE_ID_REGEX_STR; +pub use proxmox_schema::api_types::{ + BLOCKDEVICE_DISK_AND_PARTITION_NAME_REGEX, BLOCKDEVICE_NAME_REGEX, +}; +pub use proxmox_schema::api_types::{DNS_ALIAS_REGEX, DNS_NAME_OR_IP_REGEX, DNS_NAME_REGEX}; +pub use proxmox_schema::api_types::{FINGERPRINT_SHA256_REGEX, SHA256_HEX_REGEX}; +pub use proxmox_schema::api_types::{ + GENERIC_URI_REGEX, HOSTNAME_REGEX, HOST_PORT_REGEX, HTTP_URL_REGEX, +}; +pub use proxmox_schema::api_types::{MULTI_LINE_COMMENT_REGEX, SINGLE_LINE_COMMENT_REGEX}; +pub use proxmox_schema::api_types::{PASSWORD_REGEX, SYSTEMD_DATETIME_REGEX, UUID_REGEX}; + +pub use proxmox_schema::api_types::{CIDR_FORMAT, CIDR_REGEX}; +pub use proxmox_schema::api_types::{CIDR_V4_FORMAT, CIDR_V4_REGEX}; +pub use proxmox_schema::api_types::{CIDR_V6_FORMAT, CIDR_V6_REGEX}; +pub use proxmox_schema::api_types::{IPRE_STR, IP_FORMAT, IP_REGEX}; +pub use proxmox_schema::api_types::{IPV4RE_STR, IP_V4_FORMAT, IP_V4_REGEX}; +pub use proxmox_schema::api_types::{IPV6RE_STR, IP_V6_FORMAT, IP_V6_REGEX}; + +pub use proxmox_schema::api_types::COMMENT_SCHEMA as SINGLE_LINE_COMMENT_SCHEMA; +pub use proxmox_schema::api_types::HOSTNAME_SCHEMA; +pub use proxmox_schema::api_types::HOST_PORT_SCHEMA; +pub use proxmox_schema::api_types::HTTP_URL_SCHEMA; +pub use proxmox_schema::api_types::MULTI_LINE_COMMENT_SCHEMA; +pub use proxmox_schema::api_types::NODE_SCHEMA; +pub use proxmox_schema::api_types::SINGLE_LINE_COMMENT_FORMAT; +pub use proxmox_schema::api_types::{ + BLOCKDEVICE_DISK_AND_PARTITION_NAME_SCHEMA, BLOCKDEVICE_NAME_SCHEMA, +}; +pub use proxmox_schema::api_types::{CERT_FINGERPRINT_SHA256_SCHEMA, FINGERPRINT_SHA256_FORMAT}; +pub use proxmox_schema::api_types::{DISK_ARRAY_SCHEMA, DISK_LIST_SCHEMA}; +pub use proxmox_schema::api_types::{DNS_ALIAS_FORMAT, DNS_NAME_FORMAT, DNS_NAME_OR_IP_SCHEMA}; +pub use proxmox_schema::api_types::{PASSWORD_FORMAT, PASSWORD_SCHEMA}; +pub use proxmox_schema::api_types::{SERVICE_ID_SCHEMA, UUID_FORMAT}; +pub use proxmox_schema::api_types::{SYSTEMD_DATETIME_FORMAT, TIME_ZONE_SCHEMA}; + +use proxmox_schema::api_types::{DNS_NAME_STR, IPRE_BRACKET_STR}; #[rustfmt::skip] -#[macro_export] -macro_rules! BACKUP_ID_RE { () => (r"[A-Za-z0-9_][A-Za-z0-9._\-]*") } +pub const BACKUP_ID_RE: &str = r"[A-Za-z0-9_][A-Za-z0-9._\-]*"; #[rustfmt::skip] -#[macro_export] -macro_rules! BACKUP_TYPE_RE { () => (r"(?:host|vm|ct)") } +pub const BACKUP_TYPE_RE: &str = r"(?:host|vm|ct)"; #[rustfmt::skip] -#[macro_export] -macro_rules! BACKUP_TIME_RE { () => (r"[0-9]{4}-[0-9]{2}-[0-9]{2}T[0-9]{2}:[0-9]{2}:[0-9]{2}Z") } +pub const BACKUP_TIME_RE: &str = r"[0-9]{4}-[0-9]{2}-[0-9]{2}T[0-9]{2}:[0-9]{2}:[0-9]{2}Z"; #[rustfmt::skip] -#[macro_export] -macro_rules! BACKUP_NS_RE { - () => ( - concat!("(?:", - "(?:", PROXMOX_SAFE_ID_REGEX_STR!(), r"/){0,7}", PROXMOX_SAFE_ID_REGEX_STR!(), - ")?") - ); -} +pub const BACKUP_NS_RE: &str = + concatcp!("(?:", + "(?:", PROXMOX_SAFE_ID_REGEX_STR, r"/){0,7}", PROXMOX_SAFE_ID_REGEX_STR, + ")?"); #[rustfmt::skip] -#[macro_export] -macro_rules! BACKUP_NS_PATH_RE { - () => ( - concat!(r"(?:ns/", PROXMOX_SAFE_ID_REGEX_STR!(), r"/){0,7}ns/", PROXMOX_SAFE_ID_REGEX_STR!(), r"/") - ); -} +pub const BACKUP_NS_PATH_RE: &str = + concatcp!(r"(?:ns/", PROXMOX_SAFE_ID_REGEX_STR, r"/){0,7}ns/", PROXMOX_SAFE_ID_REGEX_STR, r"/"); #[rustfmt::skip] -#[macro_export] -macro_rules! SNAPSHOT_PATH_REGEX_STR { - () => ( - concat!( - r"(", BACKUP_TYPE_RE!(), ")/(", BACKUP_ID_RE!(), ")/(", BACKUP_TIME_RE!(), r")", - ) +pub const SNAPSHOT_PATH_REGEX_STR: &str = + concatcp!( + r"(", BACKUP_TYPE_RE, ")/(", BACKUP_ID_RE, ")/(", BACKUP_TIME_RE, r")", ); -} #[rustfmt::skip] -#[macro_export] -macro_rules! GROUP_OR_SNAPSHOT_PATH_REGEX_STR { - () => { - concat!( - r"(", BACKUP_TYPE_RE!(), ")/(", BACKUP_ID_RE!(), ")(?:/(", BACKUP_TIME_RE!(), r"))?", - ) - }; -} +pub const GROUP_OR_SNAPSHOT_PATH_REGEX_STR: &str = + concatcp!( + r"(", BACKUP_TYPE_RE, ")/(", BACKUP_ID_RE, ")(?:/(", BACKUP_TIME_RE, r"))?", + ); mod acl; pub use acl::*; @@ -128,102 +145,28 @@ pub use zfs::*; mod metrics; pub use metrics::*; -#[rustfmt::skip] -#[macro_use] -mod local_macros { - macro_rules! DNS_LABEL { () => (r"(?:[a-zA-Z0-9](?:[a-zA-Z0-9\-]*[a-zA-Z0-9])?)") } - macro_rules! DNS_NAME { () => (concat!(r"(?:(?:", DNS_LABEL!() , r"\.)*", DNS_LABEL!(), ")")) } - macro_rules! CIDR_V4_REGEX_STR { () => (concat!(r"(?:", IPV4RE!(), r"/\d{1,2})$")) } - macro_rules! CIDR_V6_REGEX_STR { () => (concat!(r"(?:", IPV6RE!(), r"/\d{1,3})$")) } - macro_rules! DNS_ALIAS_LABEL { () => (r"(?:[a-zA-Z0-9_](?:[a-zA-Z0-9\-]*[a-zA-Z0-9])?)") } - macro_rules! DNS_ALIAS_NAME { - () => (concat!(r"(?:(?:", DNS_ALIAS_LABEL!() , r"\.)*", DNS_ALIAS_LABEL!(), ")")) - } - macro_rules! PORT_REGEX_STR { () => (r"(?:[0-9]{1,4}|[1-5][0-9]{4}|6[0-4][0-9]{3}|65[0-4][0-9]{2}|655[0-2][0-9]|6553[0-5])") } -} - const_regex! { - pub IP_V4_REGEX = concat!(r"^", IPV4RE!(), r"$"); - pub IP_V6_REGEX = concat!(r"^", IPV6RE!(), r"$"); - pub IP_REGEX = concat!(r"^", IPRE!(), r"$"); - pub CIDR_V4_REGEX = concat!(r"^", CIDR_V4_REGEX_STR!(), r"$"); - pub CIDR_V6_REGEX = concat!(r"^", CIDR_V6_REGEX_STR!(), r"$"); - pub CIDR_REGEX = concat!(r"^(?:", CIDR_V4_REGEX_STR!(), "|", CIDR_V6_REGEX_STR!(), r")$"); - pub HOSTNAME_REGEX = r"^(?:[a-zA-Z0-9](?:[a-zA-Z0-9\-]*[a-zA-Z0-9])?)$"; - pub DNS_NAME_REGEX = concat!(r"^", DNS_NAME!(), r"$"); - pub DNS_ALIAS_REGEX = concat!(r"^", DNS_ALIAS_NAME!(), r"$"); - pub DNS_NAME_OR_IP_REGEX = concat!(r"^(?:", DNS_NAME!(), "|", IPRE!(), r")$"); - pub HOST_PORT_REGEX = concat!(r"^(?:", DNS_NAME!(), "|", IPRE_BRACKET!(), "):", PORT_REGEX_STR!() ,"$"); - pub HTTP_URL_REGEX = concat!(r"^https?://(?:(?:(?:", DNS_NAME!(), "|", IPRE_BRACKET!(), ")(?::", PORT_REGEX_STR!() ,")?)|", IPV6RE!(),")(?:/[^\x00-\x1F\x7F]*)?$"); - - pub SHA256_HEX_REGEX = r"^[a-f0-9]{64}$"; // fixme: define in common_regex ? - - pub PASSWORD_REGEX = r"^[[:^cntrl:]]*$"; // everything but control characters - - pub UUID_REGEX = r"^[0-9a-f]{8}(?:-[0-9a-f]{4}){3}-[0-9a-f]{12}$"; - - pub SYSTEMD_DATETIME_REGEX = r"^\d{4}-\d{2}-\d{2}( \d{2}:\d{2}(:\d{2})?)?$"; // fixme: define in common_regex ? - - pub FINGERPRINT_SHA256_REGEX = r"^(?:[0-9a-fA-F][0-9a-fA-F])(?::[0-9a-fA-F][0-9a-fA-F]){31}$"; - // just a rough check - dummy acceptor is used before persisting pub OPENSSL_CIPHERS_REGEX = r"^[0-9A-Za-z_:, +!\-@=.]+$"; - /// Regex for safe identifiers. - /// - /// This - /// [article](https://dwheeler.com/essays/fixing-unix-linux-filenames.html) - /// contains further information why it is reasonable to restict - /// names this way. This is not only useful for filenames, but for - /// any identifier command line tools work with. - pub PROXMOX_SAFE_ID_REGEX = concat!(r"^", PROXMOX_SAFE_ID_REGEX_STR!(), r"$"); - - /// Regex that (loosely) matches URIs according to [RFC 2396](https://www.rfc-editor.org/rfc/rfc2396.txt) - /// This does not completely match a URI, but rather disallows all the prohibited characters - /// specified in the RFC. - pub GENERIC_URI_REGEX = r#"^[^\x00-\x1F\x7F <>#"]*$"#; - - pub SINGLE_LINE_COMMENT_REGEX = r"^[[:^cntrl:]]*$"; - - pub MULTI_LINE_COMMENT_REGEX = r"(?m)^([[:^cntrl:]]*)$"; - - pub BACKUP_REPO_URL_REGEX = concat!( + pub BACKUP_REPO_URL_REGEX = concatcp!( r"^^(?:(?:(", - USER_ID_REGEX_STR!(), "|", APITOKEN_ID_REGEX_STR!(), + USER_ID_REGEX_STR, "|", APITOKEN_ID_REGEX_STR, ")@)?(", - DNS_NAME!(), "|", IPRE_BRACKET!(), - "):)?(?:([0-9]{1,5}):)?(", PROXMOX_SAFE_ID_REGEX_STR!(), r")$" + DNS_NAME_STR, "|", IPRE_BRACKET_STR, + "):)?(?:([0-9]{1,5}):)?(", PROXMOX_SAFE_ID_REGEX_STR, r")$" ); - pub BLOCKDEVICE_NAME_REGEX = r"^(?:(?:h|s|x?v)d[a-z]+)|(?:nvme\d+n\d+)$"; - pub BLOCKDEVICE_DISK_AND_PARTITION_NAME_REGEX = r"^(?:(?:h|s|x?v)d[a-z]+\d*)|(?:nvme\d+n\d+(p\d+)?)$"; - pub SUBSCRIPTION_KEY_REGEX = concat!(r"^pbs(?:[cbsp])-[0-9a-f]{10}$"); + pub SUBSCRIPTION_KEY_REGEX = concat!(r"^pbs(?:[cbsp])-[0-9a-f]{10}$"); } -pub const IP_V4_FORMAT: ApiStringFormat = ApiStringFormat::Pattern(&IP_V4_REGEX); -pub const IP_V6_FORMAT: ApiStringFormat = ApiStringFormat::Pattern(&IP_V6_REGEX); -pub const IP_FORMAT: ApiStringFormat = ApiStringFormat::Pattern(&IP_REGEX); -pub const CIDR_V4_FORMAT: ApiStringFormat = ApiStringFormat::Pattern(&CIDR_V4_REGEX); -pub const CIDR_V6_FORMAT: ApiStringFormat = ApiStringFormat::Pattern(&CIDR_V6_REGEX); -pub const CIDR_FORMAT: ApiStringFormat = ApiStringFormat::Pattern(&CIDR_REGEX); pub const PVE_CONFIG_DIGEST_FORMAT: ApiStringFormat = ApiStringFormat::Pattern(&SHA256_HEX_REGEX); -pub const PASSWORD_FORMAT: ApiStringFormat = ApiStringFormat::Pattern(&PASSWORD_REGEX); -pub const UUID_FORMAT: ApiStringFormat = ApiStringFormat::Pattern(&UUID_REGEX); -pub const BLOCKDEVICE_NAME_FORMAT: ApiStringFormat = - ApiStringFormat::Pattern(&BLOCKDEVICE_NAME_REGEX); -pub const BLOCKDEVICE_DISK_AND_PARTITION_NAME_FORMAT: ApiStringFormat = - ApiStringFormat::Pattern(&BLOCKDEVICE_DISK_AND_PARTITION_NAME_REGEX); + pub const SUBSCRIPTION_KEY_FORMAT: ApiStringFormat = ApiStringFormat::Pattern(&SUBSCRIPTION_KEY_REGEX); -pub const SYSTEMD_DATETIME_FORMAT: ApiStringFormat = - ApiStringFormat::Pattern(&SYSTEMD_DATETIME_REGEX); -pub const HOSTNAME_FORMAT: ApiStringFormat = ApiStringFormat::Pattern(&HOSTNAME_REGEX); + pub const OPENSSL_CIPHERS_TLS_FORMAT: ApiStringFormat = ApiStringFormat::Pattern(&OPENSSL_CIPHERS_REGEX); -pub const HOST_PORT_FORMAT: ApiStringFormat = ApiStringFormat::Pattern(&HOST_PORT_REGEX); -pub const HTTP_URL_FORMAT: ApiStringFormat = ApiStringFormat::Pattern(&HTTP_URL_REGEX); - -pub const DNS_ALIAS_FORMAT: ApiStringFormat = ApiStringFormat::Pattern(&DNS_ALIAS_REGEX); pub const DAILY_DURATION_FORMAT: ApiStringFormat = ApiStringFormat::VerifyFn(|s| parse_daily_duration(s).map(drop)); @@ -243,10 +186,6 @@ pub const THIRD_DNS_SERVER_SCHEMA: Schema = StringSchema::new("Third name server .format(&IP_FORMAT) .schema(); -pub const HOSTNAME_SCHEMA: Schema = StringSchema::new("Hostname (as defined in RFC1123).") - .format(&HOSTNAME_FORMAT) - .schema(); - pub const OPENSSL_CIPHERS_TLS_1_2_SCHEMA: Schema = StringSchema::new("OpenSSL cipher list used by the proxy for TLS <= 1.2") .format(&OPENSSL_CIPHERS_TLS_FORMAT) @@ -257,62 +196,6 @@ pub const OPENSSL_CIPHERS_TLS_1_3_SCHEMA: Schema = .format(&OPENSSL_CIPHERS_TLS_FORMAT) .schema(); -pub const DNS_NAME_FORMAT: ApiStringFormat = ApiStringFormat::Pattern(&DNS_NAME_REGEX); - -pub const DNS_NAME_OR_IP_FORMAT: ApiStringFormat = ApiStringFormat::Pattern(&DNS_NAME_OR_IP_REGEX); - -pub const DNS_NAME_OR_IP_SCHEMA: Schema = StringSchema::new("DNS name or IP address.") - .format(&DNS_NAME_OR_IP_FORMAT) - .schema(); - -pub const HOST_PORT_SCHEMA: Schema = - StringSchema::new("host:port combination (Host can be DNS name or IP address).") - .format(&HOST_PORT_FORMAT) - .schema(); - -pub const HTTP_URL_SCHEMA: Schema = StringSchema::new("HTTP(s) url with optional port.") - .format(&HTTP_URL_FORMAT) - .schema(); - -pub const NODE_SCHEMA: Schema = StringSchema::new("Node name (or 'localhost')") - .format(&HOSTNAME_FORMAT) - .schema(); - -pub const TIME_ZONE_SCHEMA: Schema = StringSchema::new( - "Time zone. The file '/usr/share/zoneinfo/zone.tab' contains the list of valid names.", -) -.format(&SINGLE_LINE_COMMENT_FORMAT) -.min_length(2) -.max_length(64) -.schema(); - -pub const BLOCKDEVICE_NAME_SCHEMA: Schema = - StringSchema::new("Block device name (/sys/block/).") - .format(&BLOCKDEVICE_NAME_FORMAT) - .min_length(3) - .max_length(64) - .schema(); - -pub const BLOCKDEVICE_DISK_AND_PARTITION_NAME_SCHEMA: Schema = - StringSchema::new("(Partition) block device name (/sys/class/block/).") - .format(&BLOCKDEVICE_DISK_AND_PARTITION_NAME_FORMAT) - .min_length(3) - .max_length(64) - .schema(); - -pub const DISK_ARRAY_SCHEMA: Schema = - ArraySchema::new("Disk name list.", &BLOCKDEVICE_NAME_SCHEMA).schema(); - -pub const DISK_LIST_SCHEMA: Schema = StringSchema::new("A list of disk names, comma separated.") - .format(&ApiStringFormat::PropertyString(&DISK_ARRAY_SCHEMA)) - .schema(); - -pub const PASSWORD_SCHEMA: Schema = StringSchema::new("Password.") - .format(&PASSWORD_FORMAT) - .min_length(1) - .max_length(1024) - .schema(); - pub const PBS_PASSWORD_SCHEMA: Schema = StringSchema::new("User Password.") .format(&PASSWORD_FORMAT) .min_length(5) @@ -325,31 +208,6 @@ pub const REALM_ID_SCHEMA: Schema = StringSchema::new("Realm name.") .max_length(32) .schema(); -pub const FINGERPRINT_SHA256_FORMAT: ApiStringFormat = - ApiStringFormat::Pattern(&FINGERPRINT_SHA256_REGEX); - -pub const CERT_FINGERPRINT_SHA256_SCHEMA: Schema = - StringSchema::new("X509 certificate fingerprint (sha256).") - .format(&FINGERPRINT_SHA256_FORMAT) - .schema(); - -pub const PROXMOX_SAFE_ID_FORMAT: ApiStringFormat = - ApiStringFormat::Pattern(&PROXMOX_SAFE_ID_REGEX); - -pub const SINGLE_LINE_COMMENT_FORMAT: ApiStringFormat = - ApiStringFormat::Pattern(&SINGLE_LINE_COMMENT_REGEX); - -pub const SINGLE_LINE_COMMENT_SCHEMA: Schema = StringSchema::new("Comment (single line).") - .format(&SINGLE_LINE_COMMENT_FORMAT) - .schema(); - -pub const MULTI_LINE_COMMENT_FORMAT: ApiStringFormat = - ApiStringFormat::Pattern(&MULTI_LINE_COMMENT_REGEX); - -pub const MULTI_LINE_COMMENT_SCHEMA: Schema = StringSchema::new("Comment (multiple lines).") - .format(&MULTI_LINE_COMMENT_FORMAT) - .schema(); - pub const SUBSCRIPTION_KEY_SCHEMA: Schema = StringSchema::new("Proxmox Backup Server subscription key.") .format(&SUBSCRIPTION_KEY_FORMAT) @@ -357,8 +215,6 @@ pub const SUBSCRIPTION_KEY_SCHEMA: Schema = .max_length(16) .schema(); -pub const SERVICE_ID_SCHEMA: Schema = StringSchema::new("Service ID.").max_length(256).schema(); - 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 \ diff --git a/pbs-api-types/src/tape/mod.rs b/pbs-api-types/src/tape/mod.rs index 99d7cb74..6a9d56bc 100644 --- a/pbs-api-types/src/tape/mod.rs +++ b/pbs-api-types/src/tape/mod.rs @@ -22,15 +22,19 @@ pub use media_location::*; mod media; pub use media::*; +use const_format::concatcp; use serde::{Deserialize, Serialize}; use proxmox_schema::{api, const_regex, ApiStringFormat, Schema, StringSchema}; use proxmox_uuid::Uuid; -use crate::{BackupType, BACKUP_ID_SCHEMA, FINGERPRINT_SHA256_FORMAT}; +use crate::{ + BackupType, BACKUP_ID_SCHEMA, BACKUP_NS_PATH_RE, FINGERPRINT_SHA256_FORMAT, + PROXMOX_SAFE_ID_REGEX_STR, SNAPSHOT_PATH_REGEX_STR, +}; const_regex! { - pub TAPE_RESTORE_SNAPSHOT_REGEX = concat!(r"^", PROXMOX_SAFE_ID_REGEX_STR!(), r":(?:", BACKUP_NS_PATH_RE!(),")?", SNAPSHOT_PATH_REGEX_STR!(), r"$"); + pub TAPE_RESTORE_SNAPSHOT_REGEX = concatcp!(r"^", PROXMOX_SAFE_ID_REGEX_STR, r":(?:", BACKUP_NS_PATH_RE,")?", SNAPSHOT_PATH_REGEX_STR, r"$"); } pub const TAPE_RESTORE_SNAPSHOT_FORMAT: ApiStringFormat = diff --git a/pbs-config/src/network/helper.rs b/pbs-config/src/network/helper.rs index 7180aaaa..1cf41431 100644 --- a/pbs-config/src/network/helper.rs +++ b/pbs-config/src/network/helper.rs @@ -89,13 +89,6 @@ pub fn check_netmask(mask: u8, is_v6: bool) -> Result<(), Error> { // parse ip address with optional cidr mask pub fn parse_address_or_cidr(cidr: &str) -> Result<(String, Option, bool), Error> { - lazy_static! { - pub static ref CIDR_V4_REGEX: Regex = - Regex::new(concat!(r"^(", IPV4RE!(), r")(?:/(\d{1,2}))?$")).unwrap(); - pub static ref CIDR_V6_REGEX: Regex = - Regex::new(concat!(r"^(", IPV6RE!(), r")(?:/(\d{1,3}))?$")).unwrap(); - } - if let Some(caps) = CIDR_V4_REGEX.captures(cidr) { let address = &caps[1]; if let Some(mask) = caps.get(2) { diff --git a/pbs-config/src/network/parser.rs b/pbs-config/src/network/parser.rs index 2cff6587..ec2c64eb 100644 --- a/pbs-config/src/network/parser.rs +++ b/pbs-config/src/network/parser.rs @@ -192,7 +192,7 @@ impl NetworkParser { self.eat(Token::Gateway)?; let gateway = self.next_text()?; - if pbs_api_types::common_regex::IP_REGEX.is_match(&gateway) { + if pbs_api_types::IP_REGEX.is_match(&gateway) { if gateway.contains(':') { set_gateway_v6(interface, gateway)?; } else { diff --git a/src/api2/node/dns.rs b/src/api2/node/dns.rs index 4f6822d8..87a11738 100644 --- a/src/api2/node/dns.rs +++ b/src/api2/node/dns.rs @@ -2,12 +2,14 @@ use std::sync::{Arc, Mutex}; use ::serde::{Deserialize, Serialize}; use anyhow::Error; +use const_format::concatcp; use lazy_static::lazy_static; use openssl::sha; use regex::Regex; use serde_json::{json, Value}; -use pbs_api_types::{IPRE, IPV4OCTET, IPV4RE, IPV6H16, IPV6LS32, IPV6RE}; +use pbs_api_types::IPRE_STR; + use proxmox_router::{ApiMethod, Permission, Router, RpcEnvironment}; use proxmox_schema::api; use proxmox_sys::fs::{file_get_contents, replace_file, CreateOptions}; @@ -47,7 +49,7 @@ pub fn read_etc_resolv_conf() -> Result { lazy_static! { static ref DOMAIN_REGEX: Regex = Regex::new(r"^\s*(?:search|domain)\s+(\S+)\s*").unwrap(); static ref SERVER_REGEX: Regex = - Regex::new(concat!(r"^\s*nameserver\s+(", IPRE!(), r")\s*")).unwrap(); + Regex::new(concatcp!(r"^\s*nameserver\s+(", IPRE_STR, r")\s*")).unwrap(); } let mut options = String::new(); -- 2.39.2