prs_lib/crypto/backend/gpgme/
context.rs1use std::env;
4
5use anyhow::Result;
6use gpgme::{Context as GpgmeContext, PinentryMode, Protocol};
7use thiserror::Error;
8
9use super::raw;
10use crate::crypto::{Config, IsContext, Key, Proto, proto};
11use crate::{Ciphertext, Plaintext, Recipients, util};
12
13const PROTO: Protocol = Protocol::OpenPgp;
15
16pub fn context(config: &Config) -> Result<Context, Err> {
18 if config.gpg_tty
20 && !util::env::has_gpg_tty()
21 && let Some(tty) = util::tty::get_tty()
22 {
23 unsafe { env::set_var("GPG_TTY", tty) };
25 }
26
27 let mut context = gpgme::Context::from_protocol(PROTO).map_err(Err::Context)?;
28
29 if config.gpg_tty {
31 context
32 .set_pinentry_mode(PinentryMode::Loopback)
33 .map_err(Err::Context)?;
34 }
35
36 Ok(Context::from(context))
37}
38
39pub struct Context {
41 context: GpgmeContext,
43}
44
45impl Context {
46 pub fn from(context: GpgmeContext) -> Self {
47 Self { context }
48 }
49}
50
51impl IsContext for Context {
52 fn encrypt(&mut self, recipients: &Recipients, plaintext: Plaintext) -> Result<Ciphertext> {
53 let fingerprints: Vec<String> = recipients
54 .keys()
55 .iter()
56 .map(|key| key.fingerprint(false))
57 .collect();
58 let fingerprints: Vec<&str> = fingerprints.iter().map(|fp| fp.as_str()).collect();
59 raw::encrypt(&mut self.context, &fingerprints, plaintext)
60 }
61
62 fn decrypt(&mut self, ciphertext: Ciphertext) -> Result<Plaintext> {
63 raw::decrypt(&mut self.context, ciphertext)
64 }
65
66 fn can_decrypt(&mut self, ciphertext: Ciphertext) -> Result<bool> {
67 raw::can_decrypt(&mut self.context, ciphertext)
68 }
69
70 fn keys_public(&mut self) -> Result<Vec<Key>> {
71 Ok(raw::public_keys(&mut self.context)?
72 .into_iter()
73 .map(|key| {
74 Key::Gpg(proto::gpg::Key {
75 fingerprint: key.0,
76 user_ids: key.1,
77 })
78 })
79 .collect())
80 }
81
82 fn keys_private(&mut self) -> Result<Vec<Key>> {
83 Ok(raw::private_keys(&mut self.context)?
84 .into_iter()
85 .map(|key| {
86 Key::Gpg(proto::gpg::Key {
87 fingerprint: key.0,
88 user_ids: key.1,
89 })
90 })
91 .collect())
92 }
93
94 fn import_key(&mut self, key: &[u8]) -> Result<()> {
95 raw::import_key(&mut self.context, key)
96 }
97
98 fn export_key(&mut self, key: Key) -> Result<Vec<u8>> {
99 raw::export_key(&mut self.context, &key.fingerprint(false))
100 }
101
102 fn supports_proto(&self, proto: Proto) -> bool {
103 proto == Proto::Gpg
104 }
105}
106
107#[derive(Debug, Error)]
109pub enum Err {
110 #[error("failed to obtain GPGME cryptography context")]
111 Context(#[source] gpgme::Error),
112}