use crate::{free, Alpm, AlpmListMut, Db, Result};
use crate::{utils::*, Pkg};
use alpm_sys::_alpm_sigstatus_t::*;
use alpm_sys::_alpm_sigvalidity_t::*;
use alpm_sys::*;
use std::ffi::{c_void, CString};
use std::mem::transmute;
use std::{fmt, ptr, slice};
#[derive(Debug, Eq, PartialEq, Copy, Clone, Ord, PartialOrd, Hash)]
pub struct SignatureDecodeError;
impl fmt::Display for SignatureDecodeError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str("failed to decode signature")
}
}
impl std::error::Error for SignatureDecodeError {}
pub fn decode_signature<S: Into<Vec<u8>>>(
b64: S,
) -> std::result::Result<Vec<u8>, SignatureDecodeError> {
let b64 = CString::new(b64).unwrap();
let mut data = ptr::null_mut();
let mut len = 0;
let ret = unsafe { alpm_decode_signature(b64.as_ptr(), &mut data, &mut len) };
if ret != 0 {
return Err(SignatureDecodeError);
}
let buff = unsafe { slice::from_raw_parts(data, len) };
let v = buff.to_owned();
unsafe { free(data as *mut c_void) };
Ok(v)
}
#[repr(u32)]
#[derive(Debug, Eq, PartialEq, Copy, Clone, Ord, PartialOrd, Hash)]
pub enum SigStatus {
Valid = ALPM_SIGSTATUS_VALID as u32,
KeyExpired = ALPM_SIGSTATUS_KEY_EXPIRED as u32,
SigExpired = ALPM_SIGSTATUS_SIG_EXPIRED as u32,
KeyUnknown = ALPM_SIGSTATUS_KEY_UNKNOWN as u32,
KeyDisabled = ALPM_SIGSTATUS_KEY_DISABLED as u32,
Invalid = ALPM_SIGSTATUS_INVALID as u32,
}
#[repr(u32)]
#[derive(Debug, Eq, PartialEq, Copy, Clone, Ord, PartialOrd, Hash)]
pub enum SigValidity {
Full = ALPM_SIGVALIDITY_FULL as u32,
Marginal = ALPM_SIGVALIDITY_MARGINAL as u32,
Never = ALPM_SIGVALIDITY_NEVER as u32,
Unknown = ALPM_SIGVALIDITY_UNKNOWN as u32,
}
pub struct PgpKey {
pub(crate) inner: alpm_pgpkey_t,
}
impl fmt::Debug for PgpKey {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("PgpKey")
.field("name", &self.name())
.field("email", &self.email())
.field("uid", &self.uid())
.field("fingerprint", &self.fingerprint())
.field("created", &self.created())
.field("expires", &self.expires())
.field("length", &self.length())
.field("revoked", &self.revoked())
.field("pubkey_algo", &self.pubkey_algo())
.finish()
}
}
impl PgpKey {
pub fn fingerprint(&self) -> &str {
unsafe { from_cstr(self.inner.fingerprint) }
}
pub fn uid(&self) -> &str {
unsafe { from_cstr(self.inner.uid) }
}
pub fn name(&self) -> &str {
unsafe { from_cstr_optional2(self.inner.name) }
}
pub fn email(&self) -> &str {
unsafe { from_cstr_optional2(self.inner.email) }
}
pub fn created(&self) -> i64 {
self.inner.created
}
pub fn expires(&self) -> i64 {
self.inner.expires
}
pub fn length(&self) -> u32 {
self.inner.length
}
pub fn revoked(&self) -> u32 {
self.inner.revoked
}
pub fn pubkey_algo(&self) -> u8 {
self.inner.pubkey_algo as u8
}
}
#[repr(transparent)]
pub struct SigResult {
inner: alpm_sigresult_t,
}
impl fmt::Debug for SigResult {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("SigResult")
.field("key", &self.key())
.field("status", &self.status())
.field("validity", &self.validity())
.finish()
}
}
impl SigResult {
pub fn key(&self) -> PgpKey {
PgpKey {
inner: self.inner.key,
}
}
pub fn status(&self) -> SigStatus {
unsafe { transmute::<alpm_sigstatus_t, SigStatus>(self.inner.status) }
}
pub fn validity(&self) -> SigValidity {
unsafe { transmute::<alpm_sigvalidity_t, SigValidity>(self.inner.validity) }
}
}
pub struct SigList {
inner: alpm_siglist_t,
}
impl fmt::Debug for SigList {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_list().entries(self.results()).finish()
}
}
impl Drop for SigList {
fn drop(&mut self) {
unsafe { alpm_siglist_cleanup(&mut self.inner) };
}
}
impl Default for SigList {
fn default() -> SigList {
Self::new()
}
}
impl SigList {
pub fn new() -> SigList {
SigList {
inner: alpm_siglist_t {
count: 0,
results: ptr::null_mut(),
},
}
}
pub fn results(&self) -> &[SigResult] {
if self.inner.results.is_null() {
unsafe { slice::from_raw_parts(1 as *const SigResult, 0) }
} else {
unsafe {
slice::from_raw_parts(self.inner.results as *const SigResult, self.inner.count)
}
}
}
}
impl<'a> Pkg<'a> {
pub fn check_signature(&self) -> Result<(bool, SigList)> {
let mut siglist = SigList::new();
let ret = unsafe { alpm_pkg_check_pgp_signature(self.as_ptr(), &mut siglist.inner) };
let valid = match ret {
0 => true,
1 => false,
_ => return Err(self.handle.last_error()),
};
Ok((valid, siglist))
}
}
impl<'a> Db<'a> {
pub fn check_signature(&self) -> Result<(bool, SigList)> {
let mut siglist = SigList::new();
let ret = unsafe { alpm_db_check_pgp_signature(self.as_ptr(), &mut siglist.inner) };
let valid = match ret {
0 => true,
1 => false,
_ => return Err(self.handle.last_error()),
};
Ok((valid, siglist))
}
}
impl Alpm {
pub fn extract_keyid<'a, S: Into<Vec<u8>>>(
&'a self,
ident: S,
sig: &[u8],
) -> Result<AlpmListMut<'a, String>> {
let ident = CString::new(ident).unwrap();
let mut keys = ptr::null_mut();
let ret = unsafe {
alpm_extract_keyid(
self.as_ptr(),
ident.as_ptr(),
sig.as_ptr(),
sig.len(),
&mut keys,
)
};
self.check_ret(ret)?;
unsafe { Ok(AlpmListMut::from_parts(self, keys)) }
}
}