1use crate::{utils::*, LIBRARY, Library};
2use crate::{free, Alpm, AlpmListMut, Db, Package, Result};
3
4use alpm_sys_ll::_alpm_sigstatus_t::*;
5use alpm_sys_ll::_alpm_sigvalidity_t::*;
6use alpm_sys_ll::*;
7
8use std::ffi::{c_void, CString};
9use std::mem::transmute;
10use std::{fmt, ptr, slice};
11
12#[derive(Debug, Eq, PartialEq, Copy, Clone, Ord, PartialOrd, Hash)]
13pub struct SignatureDecodeError;
14
15impl fmt::Display for SignatureDecodeError {
16 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
17 f.write_str("failed to decode signature")
18 }
19}
20
21impl std::error::Error for SignatureDecodeError {}
22
23pub fn decode_signature<S: Into<Vec<u8>>>(
24 b64: S,
25) -> std::result::Result<Vec<u8>, SignatureDecodeError> {
26 let b64 = CString::new(b64).unwrap();
27 let mut data = ptr::null_mut();
28 let mut len = 0;
29 let ret = unsafe { LIBRARY.force_load().alpm_decode_signature(b64.as_ptr(), &mut data, &mut len) };
30 if ret != 0 {
31 return Err(SignatureDecodeError);
32 }
33
34 let buff = unsafe { slice::from_raw_parts(data, len) };
35 let v = buff.to_owned();
36
37 unsafe { free(data as *mut c_void) };
38 Ok(v)
39}
40
41#[repr(u32)]
42#[derive(Debug, Eq, PartialEq, Copy, Clone, Ord, PartialOrd, Hash)]
43pub enum SigStatus {
44 Valid = ALPM_SIGSTATUS_VALID as u32,
45 KeyExpired = ALPM_SIGSTATUS_KEY_EXPIRED as u32,
46 SigExpired = ALPM_SIGSTATUS_SIG_EXPIRED as u32,
47 KeyUnknown = ALPM_SIGSTATUS_KEY_UNKNOWN as u32,
48 KeyDisabled = ALPM_SIGSTATUS_KEY_DISABLED as u32,
49 Invalid = ALPM_SIGSTATUS_INVALID as u32,
50}
51
52#[repr(u32)]
53#[derive(Debug, Eq, PartialEq, Copy, Clone, Ord, PartialOrd, Hash)]
54pub enum SigValidity {
55 Full = ALPM_SIGVALIDITY_FULL as u32,
56 Marginal = ALPM_SIGVALIDITY_MARGINAL as u32,
57 Never = ALPM_SIGVALIDITY_NEVER as u32,
58 Unknown = ALPM_SIGVALIDITY_UNKNOWN as u32,
59}
60
61pub struct PgpKey {
62 pub(crate) inner: alpm_pgpkey_t,
63}
64
65impl fmt::Debug for PgpKey {
66 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
67 f.debug_struct("PgpKey")
68 .field("name", &self.name())
69 .field("email", &self.email())
70 .field("uid", &self.uid())
71 .field("fingerprint", &self.fingerprint())
72 .field("created", &self.created())
73 .field("expires", &self.expires())
74 .field("length", &self.length())
75 .field("revoked", &self.revoked())
76 .field("pubkey_algo", &self.pubkey_algo())
77 .finish()
78 }
79}
80
81impl PgpKey {
82 pub fn fingerprint(&self) -> &str {
83 unsafe { from_cstr(self.inner.fingerprint) }
84 }
85
86 pub fn uid(&self) -> &str {
87 unsafe { from_cstr(self.inner.uid) }
88 }
89
90 pub fn name(&self) -> &str {
91 unsafe { from_cstr_optional2(self.inner.name) }
92 }
93
94 pub fn email(&self) -> &str {
95 unsafe { from_cstr_optional2(self.inner.email) }
96 }
97
98 pub fn created(&self) -> i64 {
99 self.inner.created
100 }
101
102 pub fn expires(&self) -> i64 {
103 self.inner.expires
104 }
105
106 pub fn length(&self) -> u32 {
107 self.inner.length
108 }
109
110 pub fn revoked(&self) -> u32 {
111 self.inner.revoked
112 }
113
114 pub fn pubkey_algo(&self) -> u8 {
115 self.inner.pubkey_algo as u8
116 }
117}
118
119#[repr(transparent)]
120pub struct SigResult {
121 inner: alpm_sigresult_t,
122}
123
124impl fmt::Debug for SigResult {
125 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
126 f.debug_struct("SigResult")
127 .field("key", &self.key())
128 .field("status", &self.status())
129 .field("validity", &self.validity())
130 .finish()
131 }
132}
133
134impl SigResult {
135 pub fn key(&self) -> PgpKey {
136 PgpKey {
137 inner: self.inner.key,
138 }
139 }
140
141 pub fn status(&self) -> SigStatus {
142 unsafe { transmute::<alpm_sigstatus_t, SigStatus>(self.inner.status) }
143 }
144
145 pub fn validity(&self) -> SigValidity {
146 unsafe { transmute::<alpm_sigvalidity_t, SigValidity>(self.inner.validity) }
147 }
148}
149
150pub struct SigList {
151 inner: alpm_siglist_t,
152}
153
154impl fmt::Debug for SigList {
155 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
156 f.debug_list().entries(self.results()).finish()
157 }
158}
159
160impl Drop for SigList {
161 fn drop(&mut self) {
162 unsafe { LIBRARY.force_load().alpm_siglist_cleanup(&mut self.inner) };
163 }
164}
165
166impl Default for SigList {
167 fn default() -> SigList {
168 Self::new()
169 }
170}
171
172impl SigList {
173 pub fn new() -> SigList {
174 SigList {
175 inner: alpm_siglist_t {
176 count: 0,
177 results: ptr::null_mut(),
178 },
179 }
180 }
181
182 pub fn results(&self) -> &[SigResult] {
183 if self.inner.results.is_null() {
184 unsafe { slice::from_raw_parts(1 as *const SigResult, 0) }
185 } else {
186 unsafe {
187 slice::from_raw_parts(self.inner.results as *const SigResult, self.inner.count)
188 }
189 }
190 }
191}
192
193impl<'a> Package<'a> {
194 pub fn check_signature(&self) -> Result<(bool, SigList)> {
195 let mut siglist = SigList::new();
196 let ret = unsafe { LIBRARY.force_load().alpm_pkg_check_pgp_signature(self.pkg.as_ptr(), &mut siglist.inner) };
197 let valid = match ret {
198 0 => true,
199 1 => false,
200 _ => return Err(self.handle.last_error()),
201 };
202
203 Ok((valid, siglist))
204 }
205}
206
207impl<'a> Db<'a> {
208 pub fn check_signature(&self) -> Result<(bool, SigList)> {
209 let mut siglist = SigList::new();
210 let ret = unsafe { LIBRARY.force_load().alpm_db_check_pgp_signature(self.as_ptr(), &mut siglist.inner) };
211 let valid = match ret {
212 0 => true,
213 1 => false,
214 _ => return Err(self.handle.last_error()),
215 };
216
217 Ok((valid, siglist))
218 }
219}
220
221impl Alpm {
222 pub fn extract_keyid<'a, S: Into<Vec<u8>>>(
223 &'a self,
224 ident: S,
225 sig: &[u8],
226 ) -> Result<AlpmListMut<'a, String>> {
227 let ident = CString::new(ident).unwrap();
228 let mut keys = ptr::null_mut();
229
230 let ret = unsafe {
231 self.lib.alpm_extract_keyid(
232 self.as_ptr(),
233 ident.as_ptr(),
234 sig.as_ptr(),
235 sig.len(),
236 &mut keys,
237 )
238 };
239
240 self.check_ret(ret)?;
241 unsafe { Ok(AlpmListMut::from_parts(self, keys)) }
242 }
243}