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