1 | #include "mypgpkeycontext.h" |
2 | #include "gpgop.h" |
3 | #include "utils.h" |
4 | #include <QDir> |
5 | #include <QTemporaryFile> |
6 | |
7 | using namespace QCA; |
8 | |
9 | namespace gpgQCAPlugin { |
10 | |
11 | MyPGPKeyContext::MyPGPKeyContext(Provider *p) |
12 | : PGPKeyContext(p) |
13 | { |
14 | // zero out the props |
15 | _props.isSecret = false; |
16 | _props.inKeyring = true; |
17 | _props.isTrusted = false; |
18 | } |
19 | |
20 | Provider::Context *MyPGPKeyContext::clone() const |
21 | { |
22 | return new MyPGPKeyContext(*this); |
23 | } |
24 | |
25 | const PGPKeyContextProps *MyPGPKeyContext::props() const |
26 | { |
27 | return &_props; |
28 | } |
29 | |
30 | QByteArray MyPGPKeyContext::toBinary() const |
31 | { |
32 | if (_props.inKeyring) { |
33 | GpgOp gpg(find_bin()); |
34 | gpg.setAsciiFormat(false); |
35 | gpg.doExport(key_id: _props.keyId); |
36 | gpg_waitForFinished(gpg: &gpg); |
37 | gpg_keyStoreLog(str: gpg.readDiagnosticText()); |
38 | if (!gpg.success()) |
39 | return QByteArray(); |
40 | return gpg.read(); |
41 | } else |
42 | return cacheExportBinary; |
43 | } |
44 | |
45 | ConvertResult MyPGPKeyContext::fromBinary(const QByteArray &a) |
46 | { |
47 | GpgOp::Key key; |
48 | bool sec = false; |
49 | |
50 | // temporary keyrings |
51 | QString pubname, secname; |
52 | |
53 | QTemporaryFile pubtmp(QDir::tempPath() + QLatin1String("/qca_gnupg_tmp.XXXXXX.gpg" )); |
54 | if (!pubtmp.open()) |
55 | return ErrorDecode; |
56 | |
57 | QTemporaryFile sectmp(QDir::tempPath() + QLatin1String("/qca_gnupg_tmp.XXXXXX.gpg" )); |
58 | if (!sectmp.open()) |
59 | return ErrorDecode; |
60 | |
61 | pubname = pubtmp.fileName(); |
62 | secname = sectmp.fileName(); |
63 | |
64 | // we turn off autoRemove so that we can close the files |
65 | // without them getting deleted |
66 | pubtmp.setAutoRemove(false); |
67 | sectmp.setAutoRemove(false); |
68 | pubtmp.close(); |
69 | sectmp.close(); |
70 | |
71 | // import key into temporary keyring |
72 | GpgOp gpg(find_bin()); |
73 | gpg.setKeyrings(pubfile: pubname, secfile: secname); |
74 | gpg.doImport(in: a); |
75 | gpg_waitForFinished(gpg: &gpg); |
76 | gpg_keyStoreLog(str: gpg.readDiagnosticText()); |
77 | // comment this out. apparently gpg will report failure for |
78 | // an import if there are trust issues, even though the |
79 | // key actually did get imported |
80 | /*if(!gpg.success()) |
81 | { |
82 | cleanup_temp_keyring(pubname); |
83 | cleanup_temp_keyring(secname); |
84 | return ErrorDecode; |
85 | }*/ |
86 | |
87 | // now extract the key from gpg like normal |
88 | |
89 | // is it a public key? |
90 | gpg.doPublicKeys(); |
91 | gpg_waitForFinished(gpg: &gpg); |
92 | gpg_keyStoreLog(str: gpg.readDiagnosticText()); |
93 | if (!gpg.success()) { |
94 | cleanup_temp_keyring(name: pubname); |
95 | cleanup_temp_keyring(name: secname); |
96 | return ErrorDecode; |
97 | } |
98 | |
99 | const GpgOp::KeyList pubkeys = gpg.keys(); |
100 | if (!pubkeys.isEmpty()) { |
101 | key = pubkeys.first(); |
102 | } else { |
103 | // is it a secret key? |
104 | gpg.doSecretKeys(); |
105 | gpg_waitForFinished(gpg: &gpg); |
106 | gpg_keyStoreLog(str: gpg.readDiagnosticText()); |
107 | if (!gpg.success()) { |
108 | cleanup_temp_keyring(name: pubname); |
109 | cleanup_temp_keyring(name: secname); |
110 | return ErrorDecode; |
111 | } |
112 | |
113 | const GpgOp::KeyList seckeys = gpg.keys(); |
114 | if (!seckeys.isEmpty()) { |
115 | key = seckeys.first(); |
116 | sec = true; |
117 | } else { |
118 | // no keys found |
119 | cleanup_temp_keyring(name: pubname); |
120 | cleanup_temp_keyring(name: secname); |
121 | return ErrorDecode; |
122 | } |
123 | } |
124 | |
125 | // export binary/ascii and cache |
126 | |
127 | gpg.setAsciiFormat(false); |
128 | gpg.doExport(key_id: key.keyItems.first().id); |
129 | gpg_waitForFinished(gpg: &gpg); |
130 | gpg_keyStoreLog(str: gpg.readDiagnosticText()); |
131 | if (!gpg.success()) { |
132 | cleanup_temp_keyring(name: pubname); |
133 | cleanup_temp_keyring(name: secname); |
134 | return ErrorDecode; |
135 | } |
136 | cacheExportBinary = gpg.read(); |
137 | |
138 | gpg.setAsciiFormat(true); |
139 | gpg.doExport(key_id: key.keyItems.first().id); |
140 | gpg_waitForFinished(gpg: &gpg); |
141 | gpg_keyStoreLog(str: gpg.readDiagnosticText()); |
142 | if (!gpg.success()) { |
143 | cleanup_temp_keyring(name: pubname); |
144 | cleanup_temp_keyring(name: secname); |
145 | return ErrorDecode; |
146 | } |
147 | cacheExportAscii = QString::fromLocal8Bit(ba: gpg.read()); |
148 | |
149 | // all done |
150 | |
151 | cleanup_temp_keyring(name: pubname); |
152 | cleanup_temp_keyring(name: secname); |
153 | |
154 | set(i: key, isSecret: sec, inKeyring: false, isTrusted: false); |
155 | return ConvertGood; |
156 | } |
157 | |
158 | QString MyPGPKeyContext::toAscii() const |
159 | { |
160 | if (_props.inKeyring) { |
161 | GpgOp gpg(find_bin()); |
162 | gpg.setAsciiFormat(true); |
163 | gpg.doExport(key_id: _props.keyId); |
164 | gpg_waitForFinished(gpg: &gpg); |
165 | gpg_keyStoreLog(str: gpg.readDiagnosticText()); |
166 | if (!gpg.success()) |
167 | return QString(); |
168 | return QString::fromLocal8Bit(ba: gpg.read()); |
169 | } else { |
170 | return cacheExportAscii; |
171 | } |
172 | } |
173 | |
174 | ConvertResult MyPGPKeyContext::fromAscii(const QString &s) |
175 | { |
176 | // GnuPG does ascii/binary detection for imports, so for |
177 | // simplicity we consider an ascii import to just be a |
178 | // binary import that happens to be comprised of ascii |
179 | return fromBinary(a: s.toLocal8Bit()); |
180 | } |
181 | |
182 | void MyPGPKeyContext::set(const GpgOp::Key &i, bool isSecret, bool inKeyring, bool isTrusted) |
183 | { |
184 | const GpgOp::KeyItem &ki = i.keyItems.first(); |
185 | |
186 | _props.keyId = ki.id; |
187 | _props.userIds = i.userIds; |
188 | _props.isSecret = isSecret; |
189 | _props.creationDate = ki.creationDate; |
190 | _props.expirationDate = ki.expirationDate; |
191 | _props.fingerprint = ki.fingerprint.toLower(); |
192 | _props.inKeyring = inKeyring; |
193 | _props.isTrusted = isTrusted; |
194 | } |
195 | |
196 | void MyPGPKeyContext::cleanup_temp_keyring(const QString &name) |
197 | { |
198 | QFile::remove(fileName: name); |
199 | QFile::remove(fileName: name + QLatin1Char('~')); // remove possible backup file |
200 | } |
201 | |
202 | } // end namespace gpgQCAPlugin |
203 | |