1 use std::{
2     ffi::CStr,
3     fmt,
4     marker::PhantomData,
5     str::Utf8Error,
6     time::{Duration, SystemTime, UNIX_EPOCH},
7 };
8 
9 use ffi::{self, require_gpgme_ver};
10 
11 use crate::{
12     notation::SignatureNotations, Error, KeyAlgorithm, KeyListMode, NonNull, Protocol, Validity,
13 };
14 
15 /// Upstream documentation:
16 /// [`gpgme_key_t`](https://www.gnupg.org/documentation/manuals/gpgme/Key-objects.html#index-gpgme_005fkey_005ft)
17 pub struct Key(NonNull<ffi::gpgme_key_t>);
18 
19 unsafe impl Send for Key {}
20 unsafe impl Sync for Key {}
21 
22 impl Drop for Key {
23     #[inline]
drop(&mut self)24     fn drop(&mut self) {
25         unsafe {
26             ffi::gpgme_key_unref(self.as_raw());
27         }
28     }
29 }
30 
31 impl Clone for Key {
32     #[inline]
clone(&self) -> Key33     fn clone(&self) -> Key {
34         unsafe {
35             ffi::gpgme_key_ref(self.as_raw());
36             Key(self.0)
37         }
38     }
39 }
40 
41 impl Key {
42     impl_wrapper!(ffi::gpgme_key_t);
43 
44     #[inline]
is_bad(&self) -> bool45     pub fn is_bad(&self) -> bool {
46         self.is_revoked() || self.is_expired() || self.is_disabled() || self.is_invalid()
47     }
48 
49     #[inline]
is_revoked(&self) -> bool50     pub fn is_revoked(&self) -> bool {
51         unsafe { (*self.as_raw()).revoked() }
52     }
53 
54     #[inline]
is_expired(&self) -> bool55     pub fn is_expired(&self) -> bool {
56         unsafe { (*self.as_raw()).expired() }
57     }
58 
59     #[inline]
is_disabled(&self) -> bool60     pub fn is_disabled(&self) -> bool {
61         unsafe { (*self.as_raw()).disabled() }
62     }
63 
64     #[inline]
is_invalid(&self) -> bool65     pub fn is_invalid(&self) -> bool {
66         unsafe { (*self.as_raw()).invalid() }
67     }
68 
69     #[inline]
can_encrypt(&self) -> bool70     pub fn can_encrypt(&self) -> bool {
71         unsafe { (*self.as_raw()).can_encrypt() }
72     }
73 
74     #[inline]
can_sign(&self) -> bool75     pub fn can_sign(&self) -> bool {
76         unsafe { (*self.as_raw()).can_sign() }
77     }
78 
79     #[inline]
can_certify(&self) -> bool80     pub fn can_certify(&self) -> bool {
81         unsafe { (*self.as_raw()).can_certify() }
82     }
83 
84     #[inline]
can_authenticate(&self) -> bool85     pub fn can_authenticate(&self) -> bool {
86         unsafe { (*self.as_raw()).can_authenticate() }
87     }
88 
89     #[inline]
is_qualified(&self) -> bool90     pub fn is_qualified(&self) -> bool {
91         unsafe { (*self.as_raw()).is_qualified() }
92     }
93 
94     #[inline]
is_de_vs(&self) -> bool95     pub fn is_de_vs(&self) -> bool {
96         self.subkeys().all(|x| x.is_de_vs())
97     }
98 
99     #[inline]
has_secret(&self) -> bool100     pub fn has_secret(&self) -> bool {
101         unsafe { (*self.as_raw()).secret() }
102     }
103 
104     #[inline]
is_root(&self) -> bool105     pub fn is_root(&self) -> bool {
106         if let (Some(fpr), Some(chain_id)) = (self.fingerprint_raw(), self.chain_id_raw()) {
107             fpr.to_bytes().eq_ignore_ascii_case(chain_id.to_bytes())
108         } else {
109             false
110         }
111     }
112 
113     #[inline]
owner_trust(&self) -> Validity114     pub fn owner_trust(&self) -> Validity {
115         unsafe { Validity::from_raw((*self.as_raw()).owner_trust) }
116     }
117 
118     #[inline]
protocol(&self) -> Protocol119     pub fn protocol(&self) -> Protocol {
120         unsafe { Protocol::from_raw((*self.as_raw()).protocol) }
121     }
122 
123     #[inline]
issuer_serial(&self) -> Result<&str, Option<Utf8Error>>124     pub fn issuer_serial(&self) -> Result<&str, Option<Utf8Error>> {
125         self.issuer_serial_raw()
126             .map_or(Err(None), |s| s.to_str().map_err(Some))
127     }
128 
129     #[inline]
issuer_serial_raw(&self) -> Option<&CStr>130     pub fn issuer_serial_raw(&self) -> Option<&CStr> {
131         unsafe {
132             (*self.as_raw())
133                 .issuer_serial
134                 .as_ref()
135                 .map(|s| CStr::from_ptr(s))
136         }
137     }
138 
139     #[inline]
issuer_name(&self) -> Result<&str, Option<Utf8Error>>140     pub fn issuer_name(&self) -> Result<&str, Option<Utf8Error>> {
141         self.issuer_name_raw()
142             .map_or(Err(None), |s| s.to_str().map_err(Some))
143     }
144 
145     #[inline]
issuer_name_raw(&self) -> Option<&CStr>146     pub fn issuer_name_raw(&self) -> Option<&CStr> {
147         unsafe {
148             (*self.as_raw())
149                 .issuer_name
150                 .as_ref()
151                 .map(|s| CStr::from_ptr(s))
152         }
153     }
154 
155     #[inline]
chain_id(&self) -> Result<&str, Option<Utf8Error>>156     pub fn chain_id(&self) -> Result<&str, Option<Utf8Error>> {
157         self.chain_id_raw()
158             .map_or(Err(None), |s| s.to_str().map_err(Some))
159     }
160 
161     #[inline]
chain_id_raw(&self) -> Option<&CStr>162     pub fn chain_id_raw(&self) -> Option<&CStr> {
163         unsafe {
164             (*self.as_raw())
165                 .chain_id
166                 .as_ref()
167                 .map(|s| CStr::from_ptr(s))
168         }
169     }
170 
171     #[inline]
id(&self) -> Result<&str, Option<Utf8Error>>172     pub fn id(&self) -> Result<&str, Option<Utf8Error>> {
173         self.primary_key().map_or(Err(None), |k| k.id())
174     }
175 
176     #[inline]
id_raw(&self) -> Option<&CStr>177     pub fn id_raw(&self) -> Option<&CStr> {
178         self.primary_key()?.id_raw()
179     }
180 
181     #[inline]
short_id(&self) -> Result<&str, Option<Utf8Error>>182     pub fn short_id(&self) -> Result<&str, Option<Utf8Error>> {
183         self.short_id_raw()
184             .map_or(Err(None), |s| s.to_str().map_err(Some))
185     }
186 
187     #[inline]
short_id_raw(&self) -> Option<&CStr>188     pub fn short_id_raw(&self) -> Option<&CStr> {
189         self.id_raw().map(|s| {
190             let bytes = s.to_bytes_with_nul();
191             if bytes.len() >= 9 {
192                 // One extra for the null terminator
193                 unsafe { CStr::from_bytes_with_nul_unchecked(&bytes[(bytes.len() - 9)..]) }
194             } else {
195                 s
196             }
197         })
198     }
199 
200     #[inline]
fingerprint(&self) -> Result<&str, Option<Utf8Error>>201     pub fn fingerprint(&self) -> Result<&str, Option<Utf8Error>> {
202         self.fingerprint_raw()
203             .map_or(Err(None), |s| s.to_str().map_err(Some))
204     }
205 
206     #[inline]
fingerprint_raw(&self) -> Option<&CStr>207     pub fn fingerprint_raw(&self) -> Option<&CStr> {
208         require_gpgme_ver! {
209             (1, 7) => {
210                 unsafe {
211                     (*self.as_raw())
212                         .fpr
213                         .as_ref()
214                         .map(|s| CStr::from_ptr(s))
215                         .or_else(|| self.primary_key()?.fingerprint_raw())
216                 }
217             } else {
218                 self.primary_key()?.fingerprint_raw()
219             }
220         }
221     }
222 
223     #[inline]
key_list_mode(&self) -> KeyListMode224     pub fn key_list_mode(&self) -> KeyListMode {
225         unsafe { KeyListMode::from_bits_truncate((*self.as_raw()).keylist_mode) }
226     }
227 
228     #[inline]
origin(&self) -> crate::KeyOrigin229     pub fn origin(&self) -> crate::KeyOrigin {
230         unsafe { crate::KeyOrigin::from_raw((*self.as_raw()).origin()) }
231     }
232 
233     #[inline]
primary_key(&self) -> Option<Subkey<'_>>234     pub fn primary_key(&self) -> Option<Subkey<'_>> {
235         self.subkeys().next()
236     }
237 
238     #[inline]
user_ids(&self) -> UserIds<'_>239     pub fn user_ids(&self) -> UserIds<'_> {
240         unsafe { UserIds::from_list((*self.as_raw()).uids) }
241     }
242 
243     #[inline]
subkeys(&self) -> Subkeys<'_>244     pub fn subkeys(&self) -> Subkeys<'_> {
245         unsafe { Subkeys::from_list((*self.as_raw()).subkeys) }
246     }
247 
248     #[inline]
last_update(&self) -> SystemTime249     pub fn last_update(&self) -> SystemTime {
250         let timestamp = unsafe { (*self.as_raw()).last_update };
251         UNIX_EPOCH + Duration::from_secs(timestamp.into())
252     }
253 
254     #[inline]
update(&mut self) -> crate::Result<()>255     pub fn update(&mut self) -> crate::Result<()> {
256         *self = self.updated()?;
257         Ok(())
258     }
259 
260     #[inline]
updated(&self) -> crate::Result<Key>261     pub fn updated(&self) -> crate::Result<Key> {
262         let mut ctx = crate::Context::from_protocol(self.protocol())?;
263         let _ = ctx.set_key_list_mode(self.key_list_mode());
264         ctx.refresh_key(self)
265     }
266 }
267 
268 impl fmt::Debug for Key {
fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result269     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
270         f.debug_struct("Key")
271             .field("raw", &self.as_raw())
272             .field("fingerprint", &self.fingerprint_raw())
273             .field("protocol", &self.protocol())
274             .field("owner_trust", &self.owner_trust())
275             .field("issuer", &self.issuer_name_raw())
276             .field("origin", &self.origin())
277             .field("last_update", &self.last_update())
278             .field("list_mode", &self.key_list_mode())
279             .field("has_secret", &self.has_secret())
280             .field("expired", &self.is_expired())
281             .field("revoked", &self.is_revoked())
282             .field("invalid", &self.is_invalid())
283             .field("disabled", &self.is_disabled())
284             .field("can_sign", &self.can_sign())
285             .field("can_encrypt", &self.can_encrypt())
286             .field("can_certify", &self.can_certify())
287             .field("can_auth", &self.can_authenticate())
288             .field("user_ids", &self.user_ids())
289             .field("subkeys", &self.subkeys())
290             .finish()
291     }
292 }
293 
294 /// Upstream documentation: [`gpgme_subkey_t`](https://www.gnupg.org/documentation/manuals/gpgme/Key-objects.html#index-gpgme_005fsubkey_005ft)
295 #[derive(Copy, Clone)]
296 pub struct Subkey<'key>(NonNull<ffi::gpgme_subkey_t>, PhantomData<&'key Key>);
297 
298 unsafe impl Send for Subkey<'_> {}
299 unsafe impl Sync for Subkey<'_> {}
300 
301 impl<'key> Subkey<'key> {
302     impl_wrapper!(ffi::gpgme_subkey_t, PhantomData);
303 
304     #[inline]
id(&self) -> Result<&'key str, Option<Utf8Error>>305     pub fn id(&self) -> Result<&'key str, Option<Utf8Error>> {
306         self.id_raw()
307             .map_or(Err(None), |s| s.to_str().map_err(Some))
308     }
309 
310     #[inline]
id_raw(&self) -> Option<&'key CStr>311     pub fn id_raw(&self) -> Option<&'key CStr> {
312         unsafe { (*self.as_raw()).keyid.as_ref().map(|s| CStr::from_ptr(s)) }
313     }
314 
315     #[inline]
fingerprint(&self) -> Result<&'key str, Option<Utf8Error>>316     pub fn fingerprint(&self) -> Result<&'key str, Option<Utf8Error>> {
317         self.fingerprint_raw()
318             .map_or(Err(None), |s| s.to_str().map_err(Some))
319     }
320 
321     #[inline]
fingerprint_raw(&self) -> Option<&'key CStr>322     pub fn fingerprint_raw(&self) -> Option<&'key CStr> {
323         unsafe { (*self.as_raw()).fpr.as_ref().map(|s| CStr::from_ptr(s)) }
324     }
325 
326     #[inline]
creation_time(&self) -> Option<SystemTime>327     pub fn creation_time(&self) -> Option<SystemTime> {
328         let timestamp = unsafe { (*self.as_raw()).timestamp };
329         if timestamp > 0 {
330             Some(UNIX_EPOCH + Duration::from_secs(timestamp as u64))
331         } else {
332             None
333         }
334     }
335 
336     #[inline]
expiration_time(&self) -> Option<SystemTime>337     pub fn expiration_time(&self) -> Option<SystemTime> {
338         let expires = unsafe { (*self.as_raw()).expires };
339         if expires > 0 {
340             Some(UNIX_EPOCH + Duration::from_secs(expires as u64))
341         } else {
342             None
343         }
344     }
345 
346     #[inline]
never_expires(&self) -> bool347     pub fn never_expires(&self) -> bool {
348         self.expiration_time().is_none()
349     }
350 
351     #[inline]
is_bad(&self) -> bool352     pub fn is_bad(&self) -> bool {
353         self.is_revoked() || self.is_expired() || self.is_disabled() || self.is_invalid()
354     }
355 
356     #[inline]
is_revoked(&self) -> bool357     pub fn is_revoked(&self) -> bool {
358         unsafe { (*self.as_raw()).revoked() }
359     }
360 
361     #[inline]
is_expired(&self) -> bool362     pub fn is_expired(&self) -> bool {
363         unsafe { (*self.as_raw()).expired() }
364     }
365 
366     #[inline]
is_invalid(&self) -> bool367     pub fn is_invalid(&self) -> bool {
368         unsafe { (*self.as_raw()).invalid() }
369     }
370 
371     #[inline]
is_disabled(&self) -> bool372     pub fn is_disabled(&self) -> bool {
373         unsafe { (*self.as_raw()).disabled() }
374     }
375 
376     #[inline]
can_encrypt(&self) -> bool377     pub fn can_encrypt(&self) -> bool {
378         unsafe { (*self.as_raw()).can_encrypt() }
379     }
380 
381     #[inline]
can_sign(&self) -> bool382     pub fn can_sign(&self) -> bool {
383         unsafe { (*self.as_raw()).can_sign() }
384     }
385 
386     #[inline]
can_certify(&self) -> bool387     pub fn can_certify(&self) -> bool {
388         unsafe { (*self.as_raw()).can_certify() }
389     }
390 
391     #[inline]
can_authenticate(&self) -> bool392     pub fn can_authenticate(&self) -> bool {
393         unsafe { (*self.as_raw()).can_authenticate() }
394     }
395 
396     #[inline]
is_qualified(&self) -> bool397     pub fn is_qualified(&self) -> bool {
398         unsafe { (*self.as_raw()).is_qualified() }
399     }
400 
401     #[inline]
is_card_key(&self) -> bool402     pub fn is_card_key(&self) -> bool {
403         unsafe { (*self.as_raw()).is_cardkey() }
404     }
405 
406     #[inline]
is_secret(&self) -> bool407     pub fn is_secret(&self) -> bool {
408         unsafe { (*self.as_raw()).secret() }
409     }
410 
411     #[inline]
is_de_vs(&self) -> bool412     pub fn is_de_vs(&self) -> bool {
413         unsafe { (*self.as_raw()).is_de_vs() }
414     }
415 
416     #[inline]
algorithm(&self) -> KeyAlgorithm417     pub fn algorithm(&self) -> KeyAlgorithm {
418         unsafe { KeyAlgorithm::from_raw((*self.as_raw()).pubkey_algo) }
419     }
420 
421     /// Upstream documentation: [`gpgme_pubkey_algo_string`](https://www.gnupg.org/documentation/manuals/gpgme/Public-Key-Algorithms.html#index-gpgme_005fpubkey_005falgo_005fstring)
422     #[inline]
algorithm_name(&self) -> crate::Result<String>423     pub fn algorithm_name(&self) -> crate::Result<String> {
424         unsafe {
425             match ffi::gpgme_pubkey_algo_string(self.as_raw()).as_mut() {
426                 Some(raw) => {
427                     let result = CStr::from_ptr(raw)
428                         .to_str()
429                         .expect("algorithm name is not valid utf-8")
430                         .to_owned();
431                     ffi::gpgme_free(raw as *mut _ as *mut _);
432                     Ok(result)
433                 }
434                 None => Err(Error::last_os_error()),
435             }
436         }
437     }
438 
439     #[inline]
keygrip(&self) -> Result<&'key str, Option<Utf8Error>>440     pub fn keygrip(&self) -> Result<&'key str, Option<Utf8Error>> {
441         self.keygrip_raw()
442             .map_or(Err(None), |s| s.to_str().map_err(Some))
443     }
444 
445     #[inline]
keygrip_raw(&self) -> Option<&'key CStr>446     pub fn keygrip_raw(&self) -> Option<&'key CStr> {
447         require_gpgme_ver! {
448             (1, 7) => {
449                 unsafe { (*self.as_raw()).keygrip.as_ref().map(|s| CStr::from_ptr(s)) }
450             } else {
451                 None
452             }
453         }
454     }
455 
456     #[inline]
length(&self) -> usize457     pub fn length(&self) -> usize {
458         unsafe { (*self.as_raw()).length as usize }
459     }
460 
461     #[inline]
card_serial_number(&self) -> Result<&'key str, Option<Utf8Error>>462     pub fn card_serial_number(&self) -> Result<&'key str, Option<Utf8Error>> {
463         self.card_serial_number_raw()
464             .map_or(Err(None), |s| s.to_str().map_err(Some))
465     }
466 
467     #[inline]
card_serial_number_raw(&self) -> Option<&'key CStr>468     pub fn card_serial_number_raw(&self) -> Option<&'key CStr> {
469         unsafe {
470             (*self.as_raw())
471                 .card_number
472                 .as_ref()
473                 .map(|s| CStr::from_ptr(s))
474         }
475     }
476 
477     #[inline]
curve(&self) -> Result<&'key str, Option<Utf8Error>>478     pub fn curve(&self) -> Result<&'key str, Option<Utf8Error>> {
479         self.curve_raw()
480             .map_or(Err(None), |s| s.to_str().map_err(Some))
481     }
482 
483     #[inline]
curve_raw(&self) -> Option<&'key CStr>484     pub fn curve_raw(&self) -> Option<&'key CStr> {
485         require_gpgme_ver! {
486             (1,5) => {
487                 unsafe { (*self.as_raw()).curve.as_ref().map(|s| CStr::from_ptr(s)) }
488             } else {
489                 None
490             }
491         }
492     }
493 }
494 
495 impl fmt::Debug for Subkey<'_> {
fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result496     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
497         f.debug_struct("Subkey")
498             .field("raw", &self.as_raw())
499             .field("fingerprint", &self.fingerprint_raw())
500             .field("secret", &self.is_secret())
501             .field("algorithm", &self.algorithm())
502             .field("expired", &self.is_expired())
503             .field("creation_time", &self.creation_time())
504             .field("expiration_time", &self.expiration_time())
505             .field("curve", &self.curve_raw())
506             .field("length", &self.length())
507             .field("card_key", &self.is_card_key())
508             .field("card_serial_number", &self.card_serial_number_raw())
509             .field("revoked", &self.is_revoked())
510             .field("invalid", &self.is_invalid())
511             .field("disabled", &self.is_disabled())
512             .field("can_sign", &self.can_sign())
513             .field("can_encrypt", &self.can_encrypt())
514             .field("can_certify", &self.can_certify())
515             .field("can_auth", &self.can_authenticate())
516             .finish()
517     }
518 }
519 
520 impl_list_iterator!(pub struct Subkeys(Subkey: ffi::gpgme_subkey_t));
521 
522 /// Upstream documentation: [`gpgme_user_id_t`](https://www.gnupg.org/documentation/manuals/gpgme/Key-objects.html#index-gpgme_005fuser_005fid_005ft)
523 #[derive(Copy, Clone)]
524 pub struct UserId<'key>(NonNull<ffi::gpgme_user_id_t>, PhantomData<&'key Key>);
525 
526 unsafe impl Send for UserId<'_> {}
527 unsafe impl Sync for UserId<'_> {}
528 
529 impl<'key> UserId<'key> {
530     impl_wrapper!(ffi::gpgme_user_id_t, PhantomData);
531 
532     #[inline]
id(&self) -> Result<&'key str, Option<Utf8Error>>533     pub fn id(&self) -> Result<&'key str, Option<Utf8Error>> {
534         self.id_raw()
535             .map_or(Err(None), |s| s.to_str().map_err(Some))
536     }
537 
538     #[inline]
id_raw(&self) -> Option<&'key CStr>539     pub fn id_raw(&self) -> Option<&'key CStr> {
540         unsafe { (*self.as_raw()).uid.as_ref().map(|s| CStr::from_ptr(s)) }
541     }
542 
543     #[inline]
name(&self) -> Result<&'key str, Option<Utf8Error>>544     pub fn name(&self) -> Result<&'key str, Option<Utf8Error>> {
545         self.name_raw()
546             .map_or(Err(None), |s| s.to_str().map_err(Some))
547     }
548 
549     #[inline]
name_raw(&self) -> Option<&'key CStr>550     pub fn name_raw(&self) -> Option<&'key CStr> {
551         unsafe { (*self.as_raw()).name.as_ref().map(|s| CStr::from_ptr(s)) }
552     }
553 
554     #[inline]
email(&self) -> Result<&'key str, Option<Utf8Error>>555     pub fn email(&self) -> Result<&'key str, Option<Utf8Error>> {
556         self.email_raw()
557             .map_or(Err(None), |s| s.to_str().map_err(Some))
558     }
559 
560     #[inline]
email_raw(&self) -> Option<&'key CStr>561     pub fn email_raw(&self) -> Option<&'key CStr> {
562         unsafe { (*self.as_raw()).email.as_ref().map(|s| CStr::from_ptr(s)) }
563     }
564 
565     #[inline]
comment(&self) -> Result<&'key str, Option<Utf8Error>>566     pub fn comment(&self) -> Result<&'key str, Option<Utf8Error>> {
567         self.comment_raw()
568             .map_or(Err(None), |s| s.to_str().map_err(Some))
569     }
570 
571     #[inline]
comment_raw(&self) -> Option<&'key CStr>572     pub fn comment_raw(&self) -> Option<&'key CStr> {
573         unsafe { (*self.as_raw()).comment.as_ref().map(|s| CStr::from_ptr(s)) }
574     }
575 
576     #[inline]
uidhash(&self) -> Result<&'key str, Option<Utf8Error>>577     pub fn uidhash(&self) -> Result<&'key str, Option<Utf8Error>> {
578         self.uidhash_raw()
579             .map_or(Err(None), |s| s.to_str().map_err(Some))
580     }
581 
582     #[inline]
uidhash_raw(&self) -> Option<&'key CStr>583     pub fn uidhash_raw(&self) -> Option<&'key CStr> {
584         require_gpgme_ver! {
585             (1, 14) => {
586                 unsafe { (*self.as_raw()).uidhash.as_ref().map(|s| CStr::from_ptr(s)) }
587             } else {
588                 None
589             }
590         }
591     }
592 
593     #[inline]
address(&self) -> Result<&'key str, Option<Utf8Error>>594     pub fn address(&self) -> Result<&'key str, Option<Utf8Error>> {
595         self.address_raw()
596             .map_or(Err(None), |s| s.to_str().map_err(Some))
597     }
598 
599     #[inline]
address_raw(&self) -> Option<&'key CStr>600     pub fn address_raw(&self) -> Option<&'key CStr> {
601         unsafe { (*self.as_raw()).address.as_ref().map(|s| CStr::from_ptr(s)) }
602     }
603 
604     #[inline]
validity(&self) -> Validity605     pub fn validity(&self) -> Validity {
606         unsafe { Validity::from_raw((*self.as_raw()).validity) }
607     }
608 
609     #[inline]
is_bad(&self) -> bool610     pub fn is_bad(&self) -> bool {
611         self.is_revoked() || self.is_invalid()
612     }
613 
614     #[inline]
is_revoked(&self) -> bool615     pub fn is_revoked(&self) -> bool {
616         unsafe { (*self.as_raw()).revoked() }
617     }
618 
619     #[inline]
is_invalid(&self) -> bool620     pub fn is_invalid(&self) -> bool {
621         unsafe { (*self.as_raw()).invalid() }
622     }
623 
624     #[inline]
origin(&self) -> crate::KeyOrigin625     pub fn origin(&self) -> crate::KeyOrigin {
626         unsafe { crate::KeyOrigin::from_raw((*self.as_raw()).origin()) }
627     }
628 
629     require_gpgme_ver! {
630         (1, 8) => {
631             #[inline]
632             pub fn last_update(&self) -> SystemTime {
633                 let timestamp = unsafe { (*self.as_raw()).last_update };
634                 UNIX_EPOCH + Duration::from_secs(timestamp.into())
635             }
636         }
637     }
638 
639     #[inline]
signature(&self, key: &Key) -> Option<UserIdSignature<'key>>640     pub fn signature(&self, key: &Key) -> Option<UserIdSignature<'key>> {
641         if key.protocol() != Protocol::OpenPgp {
642             return None;
643         }
644 
645         self.signatures()
646             .filter(|s| {
647                 s.signer_key_id_raw() == key.id_raw()
648                     && !(s.is_bad() || s.is_revocation())
649                     && (s.status() == Error::NO_ERROR)
650             })
651             .max_by_key(|s| s.creation_time())
652     }
653 
654     #[inline]
signatures(&self) -> UserIdSignatures<'key>655     pub fn signatures(&self) -> UserIdSignatures<'key> {
656         unsafe { UserIdSignatures::from_list((*self.as_raw()).signatures) }
657     }
658 
659     #[inline]
tofu_info(&self) -> Option<crate::TofuInfo<'key>>660     pub fn tofu_info(&self) -> Option<crate::TofuInfo<'key>> {
661         require_gpgme_ver! {
662             (1,7) => {
663                 unsafe {
664                     (*self.as_raw())
665                         .tofu
666                         .as_mut()
667                         .map(|t| crate::TofuInfo::from_raw(t))
668                 }
669             } else {
670                 None
671             }
672         }
673     }
674 }
675 
676 impl fmt::Debug for UserId<'_> {
fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result677     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
678         f.debug_struct("UserId")
679             .field("raw", &self.as_raw())
680             .field("name", &self.name_raw())
681             .field("email", &self.email_raw())
682             .field("comment", &self.comment_raw())
683             .field("validity", &self.validity())
684             .field("revoked", &self.is_revoked())
685             .field("invalid", &self.is_invalid())
686             .field("origin", &self.origin())
687             .field("tofu_info", &self.tofu_info())
688             .field("signatures", &self.signatures())
689             .finish()
690     }
691 }
692 
693 impl fmt::Display for UserId<'_> {
fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result694     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
695         f.write_str(
696             &*self
697                 .id_raw()
698                 .map(|s| s.to_string_lossy())
699                 .unwrap_or("".into()),
700         )
701     }
702 }
703 
704 impl_list_iterator!(pub struct UserIds(UserId: ffi::gpgme_user_id_t));
705 
706 #[derive(Debug)]
707 pub enum SignatureTrust {
708     None,
709     Partial,
710     Complete,
711 }
712 
713 /// Upstream documentation: [`gpgme_key_sig_t`](https://www.gnupg.org/documentation/manuals/gpgme/Key-objects.html#index-gpgme_005fkey_005fsig_005ft)
714 #[derive(Copy, Clone)]
715 pub struct UserIdSignature<'key>(NonNull<ffi::gpgme_key_sig_t>, PhantomData<&'key Key>);
716 
717 unsafe impl Send for UserIdSignature<'_> {}
718 unsafe impl Sync for UserIdSignature<'_> {}
719 
720 impl<'key> UserIdSignature<'key> {
721     impl_wrapper!(ffi::gpgme_key_sig_t, PhantomData);
722 
723     #[inline]
signer_key_id(&self) -> Result<&'key str, Option<Utf8Error>>724     pub fn signer_key_id(&self) -> Result<&'key str, Option<Utf8Error>> {
725         self.signer_key_id_raw()
726             .map_or(Err(None), |s| s.to_str().map_err(Some))
727     }
728 
729     #[inline]
signer_key_id_raw(&self) -> Option<&'key CStr>730     pub fn signer_key_id_raw(&self) -> Option<&'key CStr> {
731         unsafe { (*self.as_raw()).keyid.as_ref().map(|s| CStr::from_ptr(s)) }
732     }
733 
734     #[inline]
algorithm(&self) -> KeyAlgorithm735     pub fn algorithm(&self) -> KeyAlgorithm {
736         unsafe { KeyAlgorithm::from_raw((*self.as_raw()).pubkey_algo) }
737     }
738 
739     #[inline]
creation_time(&self) -> Option<SystemTime>740     pub fn creation_time(&self) -> Option<SystemTime> {
741         let timestamp = unsafe { (*self.as_raw()).timestamp };
742         if timestamp > 0 {
743             Some(UNIX_EPOCH + Duration::from_secs(timestamp as u64))
744         } else {
745             None
746         }
747     }
748 
749     #[inline]
expiration_time(&self) -> Option<SystemTime>750     pub fn expiration_time(&self) -> Option<SystemTime> {
751         let expires = unsafe { (*self.as_raw()).expires };
752         if expires > 0 {
753             Some(UNIX_EPOCH + Duration::from_secs(expires as u64))
754         } else {
755             None
756         }
757     }
758 
759     #[inline]
never_expires(&self) -> bool760     pub fn never_expires(&self) -> bool {
761         self.expiration_time().is_none()
762     }
763 
764     #[inline]
is_bad(&self) -> bool765     pub fn is_bad(&self) -> bool {
766         self.is_expired() || self.is_invalid()
767     }
768 
769     #[inline]
is_revocation(&self) -> bool770     pub fn is_revocation(&self) -> bool {
771         unsafe { (*self.as_raw()).revoked() }
772     }
773 
774     #[inline]
is_invalid(&self) -> bool775     pub fn is_invalid(&self) -> bool {
776         unsafe { (*self.as_raw()).invalid() }
777     }
778 
779     #[inline]
is_expired(&self) -> bool780     pub fn is_expired(&self) -> bool {
781         unsafe { (*self.as_raw()).expired() }
782     }
783 
784     #[inline]
is_exportable(&self) -> bool785     pub fn is_exportable(&self) -> bool {
786         unsafe { (*self.as_raw()).exportable() }
787     }
788 
789     #[inline]
signer_user_id(&self) -> Result<&'key str, Option<Utf8Error>>790     pub fn signer_user_id(&self) -> Result<&'key str, Option<Utf8Error>> {
791         self.signer_user_id_raw()
792             .map_or(Err(None), |s| s.to_str().map_err(Some))
793     }
794 
795     #[inline]
signer_user_id_raw(&self) -> Option<&'key CStr>796     pub fn signer_user_id_raw(&self) -> Option<&'key CStr> {
797         unsafe { (*self.as_raw()).uid.as_ref().map(|s| CStr::from_ptr(s)) }
798     }
799 
800     #[inline]
signer_name(&self) -> Result<&'key str, Option<Utf8Error>>801     pub fn signer_name(&self) -> Result<&'key str, Option<Utf8Error>> {
802         self.signer_name_raw()
803             .map_or(Err(None), |s| s.to_str().map_err(Some))
804     }
805 
806     #[inline]
signer_name_raw(&self) -> Option<&'key CStr>807     pub fn signer_name_raw(&self) -> Option<&'key CStr> {
808         unsafe { (*self.as_raw()).name.as_ref().map(|s| CStr::from_ptr(s)) }
809     }
810 
811     #[inline]
signer_email(&self) -> Result<&'key str, Option<Utf8Error>>812     pub fn signer_email(&self) -> Result<&'key str, Option<Utf8Error>> {
813         self.signer_email_raw()
814             .map_or(Err(None), |s| s.to_str().map_err(Some))
815     }
816 
817     #[inline]
signer_email_raw(&self) -> Option<&'key CStr>818     pub fn signer_email_raw(&self) -> Option<&'key CStr> {
819         unsafe { (*self.as_raw()).email.as_ref().map(|s| CStr::from_ptr(s)) }
820     }
821 
822     #[inline]
signer_comment(&self) -> Result<&'key str, Option<Utf8Error>>823     pub fn signer_comment(&self) -> Result<&'key str, Option<Utf8Error>> {
824         self.signer_comment_raw()
825             .map_or(Err(None), |s| s.to_str().map_err(Some))
826     }
827 
828     #[inline]
signer_comment_raw(&self) -> Option<&'key CStr>829     pub fn signer_comment_raw(&self) -> Option<&'key CStr> {
830         unsafe { (*self.as_raw()).comment.as_ref().map(|s| CStr::from_ptr(s)) }
831     }
832 
833     #[inline]
cert_class(&self) -> u64834     pub fn cert_class(&self) -> u64 {
835         unsafe { (*self.as_raw()).sig_class.into() }
836     }
837 
838     #[inline]
status(&self) -> Error839     pub fn status(&self) -> Error {
840         unsafe { Error::new((*self.as_raw()).status) }
841     }
842 
843     #[inline]
policy_url(&self) -> Result<&'key str, Option<Utf8Error>>844     pub fn policy_url(&self) -> Result<&'key str, Option<Utf8Error>> {
845         self.policy_url_raw()
846             .map_or(Err(None), |s| s.to_str().map_err(Some))
847     }
848 
849     #[inline]
policy_url_raw(&self) -> Option<&'key CStr>850     pub fn policy_url_raw(&self) -> Option<&'key CStr> {
851         self.notations().find_map(|n| {
852             if n.name_raw().is_none() {
853                 n.value_raw()
854             } else {
855                 None
856             }
857         })
858     }
859 
860     #[inline]
remark(&self) -> Result<&'key str, Option<Utf8Error>>861     pub fn remark(&self) -> Result<&'key str, Option<Utf8Error>> {
862         self.remark_raw()
863             .map_or(Err(None), |s| s.to_str().map_err(Some))
864     }
865 
866     #[inline]
remark_raw(&self) -> Option<&'key CStr>867     pub fn remark_raw(&self) -> Option<&'key CStr> {
868         self.notations().find_map(|n| {
869             if n.name() == Ok("rem@gnupg.org") {
870                 n.value_raw()
871             } else {
872                 None
873             }
874         })
875     }
876 
877     #[inline]
notations(&self) -> SignatureNotations<'key>878     pub fn notations(&self) -> SignatureNotations<'key> {
879         unsafe { SignatureNotations::from_list((*self.as_raw()).notations) }
880     }
881 
882     require_gpgme_ver! {
883         (1, 16) => {
884             #[inline]
885             pub fn is_trust_signature(&self) -> bool {
886                 self.trust_depth() != 0
887             }
888 
889             #[inline]
890             pub fn trust_value(&self) -> SignatureTrust {
891                 let value = unsafe {
892                     (*self.as_raw()).trust_value()
893                 };
894                 if !self.is_trust_signature() {
895                     SignatureTrust::None
896                 } else if value >= 120 {
897                     SignatureTrust::Complete
898                 } else {
899                     SignatureTrust::Partial
900                 }
901             }
902 
903             #[inline]
904             pub fn trust_depth(&self) -> u8 {
905                 unsafe {
906                     (*self.as_raw()).trust_depth()
907                 }
908             }
909 
910             #[inline]
911             pub fn trust_scope(&self) -> Result<&'key str, Option<Utf8Error>> {
912                 self.trust_scope_raw().map_or(Err(None), |s| s.to_str().map_err(Some))
913             }
914 
915             #[inline]
916             pub fn trust_scope_raw(&self) -> Option<&'key CStr> {
917                 unsafe {
918                     (*self.as_raw()).trust_scope.as_ref().map(|s| CStr::from_ptr(s))
919                 }
920             }
921         }
922     }
923 }
924 
925 impl fmt::Debug for UserIdSignature<'_> {
fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result926     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
927         f.debug_struct("UserIdSignature")
928             .field("raw", &self.as_raw())
929             .field("signer_key", &self.signer_key_id_raw())
930             .field("signer", &self.signer_user_id_raw())
931             .field("algorithm", &self.algorithm())
932             .field("expired", &self.is_expired())
933             .field("creation_time", &self.creation_time())
934             .field("expiration_time", &self.expiration_time())
935             .field("invalid", &self.is_invalid())
936             .field("revoked", &self.is_revocation())
937             .field("exportable", &self.is_exportable())
938             .field("status", &self.status())
939             .field("notations", &self.notations())
940             .finish()
941     }
942 }
943 
944 impl_list_iterator!(pub struct UserIdSignatures(UserIdSignature: ffi::gpgme_key_sig_t));
945