use std::ffi::CString;
use std::fmt;
use std::os::unix::ffi::OsStrExt;
use std::path::Path;
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
#[repr(transparent)]
pub struct SignFlags(u32);
impl SignFlags {
pub const NONE: Self = Self(librpmsign_sys::rpmSignFlags_e_RPMSIGN_FLAG_NONE);
pub const IMA: Self = Self(librpmsign_sys::rpmSignFlags_e_RPMSIGN_FLAG_IMA);
#[cfg(has_rpmsignflag_rpmv3)]
pub const RPMV3: Self = Self(librpmsign_sys::rpmSignFlags_e_RPMSIGN_FLAG_RPMV3);
#[cfg(has_rpmsignflag_fsverity)]
pub const FSVERITY: Self = Self(librpmsign_sys::rpmSignFlags_e_RPMSIGN_FLAG_FSVERITY);
#[cfg(has_rpmsignflag_resign)]
pub const RESIGN: Self = Self(librpmsign_sys::rpmSignFlags_e_RPMSIGN_FLAG_RESIGN);
#[cfg(has_rpmsignflag_rpmv4)]
pub const RPMV4: Self = Self(librpmsign_sys::rpmSignFlags_e_RPMSIGN_FLAG_RPMV4);
#[cfg(has_rpmsignflag_rpmv6)]
pub const RPMV6: Self = Self(librpmsign_sys::rpmSignFlags_e_RPMSIGN_FLAG_RPMV6);
}
impl std::ops::BitOr for SignFlags {
type Output = Self;
fn bitor(self, rhs: Self) -> Self {
Self(self.0 | rhs.0)
}
}
impl std::ops::BitOrAssign for SignFlags {
fn bitor_assign(&mut self, rhs: Self) {
self.0 |= rhs.0;
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
#[repr(transparent)]
pub struct HashAlgo(u32);
impl HashAlgo {
pub const SHA1: Self = Self(librpmsign_sys::pgpHashAlgo_e_PGPHASHALGO_SHA1);
pub const SHA256: Self = Self(librpmsign_sys::pgpHashAlgo_e_PGPHASHALGO_SHA256);
pub const SHA384: Self = Self(librpmsign_sys::pgpHashAlgo_e_PGPHASHALGO_SHA384);
pub const SHA512: Self = Self(librpmsign_sys::pgpHashAlgo_e_PGPHASHALGO_SHA512);
#[cfg(has_pgphashalgo_sha3_256)]
pub const SHA3_256: Self = Self(librpmsign_sys::pgpHashAlgo_e_PGPHASHALGO_SHA3_256);
#[cfg(has_pgphashalgo_sha3_512)]
pub const SHA3_512: Self = Self(librpmsign_sys::pgpHashAlgo_e_PGPHASHALGO_SHA3_512);
}
pub struct SignArgs {
key_id_c: Option<CString>,
hashalgo: u32,
signflags: u32,
}
impl SignArgs {
pub fn new() -> Self {
SignArgs {
key_id_c: None,
hashalgo: 0,
signflags: 0,
}
}
pub fn key_id(mut self, key_id: &str) -> Self {
self.key_id_c = Some(CString::new(key_id).expect("key ID contains NUL byte"));
self
}
pub fn hash_algo(mut self, algo: HashAlgo) -> Self {
self.hashalgo = algo.0;
self
}
pub fn flags(mut self, flags: SignFlags) -> Self {
self.signflags = flags.0;
self
}
fn to_raw(&self) -> librpmsign_sys::rpmSignArgs {
librpmsign_sys::rpmSignArgs {
keyid: self
.key_id_c
.as_ref()
.map_or(std::ptr::null_mut(), |c| c.as_ptr().cast_mut()),
hashalgo: self.hashalgo,
signflags: self.signflags,
}
}
}
impl Default for SignArgs {
fn default() -> Self {
Self::new()
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct SignError;
impl fmt::Display for SignError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "RPM signing operation failed")
}
}
impl std::error::Error for SignError {}
pub fn sign_package(path: impl AsRef<Path>, args: Option<&SignArgs>) -> Result<(), SignError> {
let path_c =
CString::new(path.as_ref().as_os_str().as_bytes()).expect("path contains NUL byte");
let raw_args;
let args_ptr = match args {
Some(a) => {
raw_args = a.to_raw();
&raw_args
}
None => std::ptr::null(),
};
let rc = unsafe { librpmsign_sys::rpmPkgSign(path_c.as_ptr(), args_ptr) };
if rc == 0 { Ok(()) } else { Err(SignError) }
}
pub fn del_sign(path: impl AsRef<Path>, args: Option<&SignArgs>) -> Result<(), SignError> {
let path_c =
CString::new(path.as_ref().as_os_str().as_bytes()).expect("path contains NUL byte");
let raw_args;
let args_ptr = match args {
Some(a) => {
raw_args = a.to_raw();
&raw_args
}
None => std::ptr::null(),
};
let rc = unsafe { librpmsign_sys::rpmPkgDelSign(path_c.as_ptr(), args_ptr) };
if rc == 0 { Ok(()) } else { Err(SignError) }
}
#[cfg(has_rpmpkg_delfilesign)]
pub fn del_file_sign(path: impl AsRef<Path>, args: Option<&SignArgs>) -> Result<(), SignError> {
let path_c =
CString::new(path.as_ref().as_os_str().as_bytes()).expect("path contains NUL byte");
let raw_args;
let args_ptr = match args {
Some(a) => {
raw_args = a.to_raw();
&raw_args
}
None => std::ptr::null(),
};
let rc = unsafe { librpmsign_sys::rpmPkgDelFileSign(path_c.as_ptr(), args_ptr) };
if rc == 0 { Ok(()) } else { Err(SignError) }
}