• Skip to content
  • Skip to link menu
  • KDE API Reference
  • kdelibs-4.14.38 API Reference
  • KDE Home
  • Contact Us
 

KNewStuff

  • knewstuff
  • knewstuff2
  • core
knewstuff2/core/security.cpp
Go to the documentation of this file.
1/*
2 This file is part of KNewStuff2.
3 Copyright (c) 2004, 2005 Andras Mantia <amantia@kde.org>
4 Copyright (c) 2007 Josef Spillner <spillner@kde.org>
5
6 This library is free software; you can redistribute it and/or
7 modify it under the terms of the GNU Lesser General Public
8 License as published by the Free Software Foundation; either
9 version 2.1 of the License, or (at your option) any later version.
10
11 This library is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 Lesser General Public License for more details.
15
16 You should have received a copy of the GNU Lesser General Public
17 License along with this library. If not, see <http://www.gnu.org/licenses/>.
18*/
19
20//app includes
21#include "security.h"
22
23//qt includes
24#include <QtCore/QFile>
25#include <QtCore/QFileInfo>
26#include <QtCore/QPointer>
27#include <QtCore/QStringList>
28#include <QtCore/QTextIStream>
29#include <QtCore/QTimer>
30
31//kde includes
32#include <kdebug.h>
33#include <kinputdialog.h>
34#include <klocale.h>
35#include <kcodecs.h>
36#include <kmessagebox.h>
37#include <kpassworddialog.h>
38#include <kprocess.h>
39#include <kstandarddirs.h>
40
41using namespace KNS;
42
43static QString gpgExecutable()
44{
45 QString gpgExe = KStandardDirs::findExe( "gpg" );
46 if ( gpgExe.isEmpty() )
47 gpgExe = KStandardDirs::findExe( "gpg2" );
48 if ( gpgExe.isEmpty() )
49 return QLatin1String( "gpg" );
50 return gpgExe;
51}
52
53Security::Security()
54{
55 m_keysRead = false;
56 m_gpgRunning = false;
57 readKeys();
58 readSecretKeys();
59}
60
61
62Security::~Security()
63{
64}
65
66void Security::readKeys()
67{
68 if (m_gpgRunning) {
69 QTimer::singleShot(5, this, SLOT(readKeys()));
70 return;
71 }
72 m_runMode = List;
73 m_keys.clear();
74 m_process = new KProcess();
75 *m_process << gpgExecutable()
76 << "--no-secmem-warning"
77 << "--no-tty"
78 << "--with-colon"
79 << "--list-keys";
80 connect(m_process, SIGNAL(finished(int,QProcess::ExitStatus)),
81 this, SLOT(slotFinished(int,QProcess::ExitStatus)));
82 connect(m_process, SIGNAL(readyReadStandardOutput()),
83 this, SLOT(slotReadyReadStandardOutput()));
84 m_process->start();
85 if (!m_process->waitForStarted()) {
86 KMessageBox::error(0L, i18n("<qt>Cannot start <i>gpg</i> and retrieve the available keys. Make sure that <i>gpg</i> is installed, otherwise verification of downloaded resources will not be possible.</qt>"));
87 delete m_process;
88 m_process = 0;
89 } else
90 m_gpgRunning = true;
91}
92
93void Security::readSecretKeys()
94{
95 if (m_gpgRunning) {
96 QTimer::singleShot(5, this, SLOT(readSecretKeys()));
97 return;
98 }
99 m_runMode = ListSecret;
100 m_process = new KProcess();
101 *m_process << gpgExecutable()
102 << "--no-secmem-warning"
103 << "--no-tty"
104 << "--with-colon"
105 << "--list-secret-keys";
106 connect(m_process, SIGNAL(finished(int,QProcess::ExitStatus)),
107 this, SLOT(slotFinished(int,QProcess::ExitStatus)));
108 connect(m_process, SIGNAL(readyReadStandardOutput()),
109 this, SLOT(slotReadyReadStandardOutput()));
110 m_process->start();
111 if (!m_process->waitForStarted()) {
112 delete m_process;
113 m_process = 0;
114 } else
115 m_gpgRunning = true;
116}
117
118void Security::slotFinished(int exitCode, QProcess::ExitStatus exitStatus)
119{
120 if (exitStatus != QProcess::NormalExit) {
121 m_gpgRunning = false;
122 delete m_process;
123 m_process = 0;
124 return;
125 }
126 switch (m_runMode) {
127 case ListSecret:
128 m_keysRead = true;
129 break;
130 case Verify: emit validityResult(m_result);
131 break;
132 case Sign: emit fileSigned(m_result);
133 break;
134
135 }
136 m_gpgRunning = false;
137 delete m_process;
138 m_process = 0;
139
140 Q_UNUSED(exitCode);
141}
142
143void Security::slotReadyReadStandardOutput()
144{
145 QString data;
146 while (m_process->canReadLine()) {
147 data = QString::fromLocal8Bit(m_process->readLine());
148 switch (m_runMode) {
149 case List:
150 case ListSecret:
151 if (data.startsWith(QLatin1String("pub")) || data.startsWith(QLatin1String("sec"))) {
152 KeyStruct key;
153 if (data.startsWith(QLatin1String("pub")))
154 key.secret = false;
155 else
156 key.secret = true;
157 QStringList line = data.split(':', QString::KeepEmptyParts);
158 key.id = line[4];
159 QString shortId = key.id.right(8);
160 QString trustStr = line[1];
161 key.trusted = false;
162 if (trustStr == "u" || trustStr == "f")
163 key.trusted = true;
164 data = line[9];
165 key.mail = data.section('<', -1, -1);
166 key.mail.truncate(key.mail.length() - 1);
167 key.name = data.section('<', 0, 0);
168 if (key.name.contains("("))
169 key.name = key.name.section('(', 0, 0);
170 m_keys[shortId] = key;
171 }
172 break;
173 case Verify:
174 data = data.section(']', 1, -1).trimmed();
175 if (data.startsWith(QLatin1String("GOODSIG"))) {
176 m_result &= SIGNED_BAD_CLEAR;
177 m_result |= SIGNED_OK;
178 QString id = data.section(' ', 1 , 1).right(8);
179 if (!m_keys.contains(id)) {
180 m_result |= UNKNOWN;
181 } else {
182 m_signatureKey = m_keys[id];
183 }
184 } else
185 if (data.startsWith(QLatin1String("NO_PUBKEY"))) {
186 m_result &= SIGNED_BAD_CLEAR;
187 m_result |= UNKNOWN;
188 } else
189 if (data.startsWith(QLatin1String("BADSIG"))) {
190 m_result |= SIGNED_BAD;
191 QString id = data.section(' ', 1 , 1).right(8);
192 if (!m_keys.contains(id)) {
193 m_result |= UNKNOWN;
194 } else {
195 m_signatureKey = m_keys[id];
196 }
197 } else
198 if (data.startsWith(QLatin1String("TRUST_ULTIMATE"))) {
199 m_result &= SIGNED_BAD_CLEAR;
200 m_result |= TRUSTED;
201 }
202 break;
203
204 case Sign:
205 if (data.contains("passphrase.enter")) {
206 KeyStruct key = m_keys[m_secretKey];
207 QPointer<KPasswordDialog> dlg = new KPasswordDialog(NULL);
208 dlg->setPrompt(i18n("<qt>Enter passphrase for key <b>0x%1</b>, belonging to<br /><i>%2&lt;%3&gt;</i><br />:</qt>", m_secretKey, key.name, key.mail));
209 if (dlg->exec()) {
210 m_process->write(dlg->password().toLocal8Bit() + '\n');
211 } else {
212 m_result |= BAD_PASSPHRASE;
213 m_process->kill();
214 delete dlg;
215 return;
216 }
217 delete dlg;
218 } else
219 if (data.contains("BAD_PASSPHRASE")) {
220 m_result |= BAD_PASSPHRASE;
221 }
222 break;
223 }
224 }
225}
226
227void Security::checkValidity(const QString& filename)
228{
229 m_fileName = filename;
230 slotCheckValidity();
231}
232
233void Security::slotCheckValidity()
234{
235 if (!m_keysRead || m_gpgRunning) {
236 QTimer::singleShot(5, this, SLOT(slotCheckValidity()));
237 return;
238 }
239 if (m_keys.count() == 0) {
240 emit validityResult(-1);
241 return;
242 }
243
244 m_result = 0;
245 m_runMode = Verify;
246 QFileInfo f(m_fileName);
247 //check the MD5 sum
248 QString md5sum;
249 const char* c = "";
250 KMD5 context(c);
251 QFile file(m_fileName);
252 if (file.open(QIODevice::ReadOnly)) {
253 context.reset();
254 context.update(file);
255 md5sum = context.hexDigest();
256 file.close();
257 }
258 file.setFileName(f.path() + "/md5sum");
259 if (file.open(QIODevice::ReadOnly)) {
260 QByteArray md5sum_file;
261 file.readLine(md5sum_file.data(), 50);
262 if (!md5sum_file.isEmpty() && QString(md5sum_file).startsWith(md5sum))
263 m_result |= MD5_OK;
264 file.close();
265 }
266 m_result |= SIGNED_BAD;
267 m_signatureKey.id = "";
268 m_signatureKey.name = "";
269 m_signatureKey.mail = "";
270 m_signatureKey.trusted = false;
271
272 //verify the signature
273 m_process = new KProcess();
274 *m_process << gpgExecutable()
275 << "--no-secmem-warning"
276 << "--status-fd=2"
277 << "--command-fd=0"
278 << "--verify"
279 << f.path() + "/signature"
280 << m_fileName;
281 connect(m_process, SIGNAL(finished(int,QProcess::ExitStatus)),
282 this, SLOT(slotFinished(int,QProcess::ExitStatus)));
283 connect(m_process, SIGNAL(readyReadStandardOutput()),
284 this, SLOT(slotReadyReadStandardOutput()));
285 m_process->start();
286 if (m_process->waitForStarted())
287 m_gpgRunning = true;
288 else {
289 KMessageBox::error(0L, i18n("<qt>Cannot start <i>gpg</i> and check the validity of the file. Make sure that <i>gpg</i> is installed, otherwise verification of downloaded resources will not be possible.</qt>"));
290 emit validityResult(0);
291 delete m_process;
292 m_process = 0;
293 }
294}
295
296void Security::signFile(const QString &fileName)
297{
298 m_fileName = fileName;
299 slotSignFile();
300}
301
302void Security::slotSignFile()
303{
304 if (!m_keysRead || m_gpgRunning) {
305 QTimer::singleShot(5, this, SLOT(slotSignFile()));
306 return;
307 }
308
309 QStringList secretKeys;
310 for (QMap<QString, KeyStruct>::Iterator it = m_keys.begin(); it != m_keys.end(); ++it) {
311 if (it.value().secret)
312 secretKeys.append(it.key());
313 }
314
315 if (secretKeys.count() == 0) {
316 emit fileSigned(-1);
317 return;
318 }
319
320 m_result = 0;
321 QFileInfo f(m_fileName);
322
323 //create the MD5 sum
324 QString md5sum;
325 const char* c = "";
326 KMD5 context(c);
327 QFile file(m_fileName);
328 if (file.open(QIODevice::ReadOnly)) {
329 context.reset();
330 context.update(file);
331 md5sum = context.hexDigest();
332 file.close();
333 }
334 file.setFileName(f.path() + "/md5sum");
335 if (file.open(QIODevice::WriteOnly)) {
336 QTextStream stream(&file);
337 stream << md5sum;
338 m_result |= MD5_OK;
339 file.close();
340 }
341
342 if (secretKeys.count() > 1) {
343 bool ok;
344 secretKeys = KInputDialog::getItemList(i18n("Select Signing Key"), i18n("Key used for signing:"), secretKeys, QStringList(secretKeys[0]), false, &ok);
345 if (ok)
346 m_secretKey = secretKeys[0];
347 else {
348 emit fileSigned(0);
349 return;
350 }
351 } else
352 m_secretKey = secretKeys[0];
353
354 //verify the signature
355 m_process = new KProcess();
356 *m_process << gpgExecutable()
357 << "--no-secmem-warning"
358 << "--status-fd=2"
359 << "--command-fd=0"
360 << "--no-tty"
361 << "--detach-sign"
362 << "-u"
363 << m_secretKey
364 << "-o"
365 << f.path() + "/signature"
366 << m_fileName;
367 connect(m_process, SIGNAL(finished(int,QProcess::ExitStatus)),
368 this, SLOT(slotFinished(int,QProcess::ExitStatus)));
369 connect(m_process, SIGNAL(readyReadStandardOutput()),
370 this, SLOT(slotReadyReadStandardOutput()));
371 m_runMode = Sign;
372 m_process->start();
373 if (m_process->waitForStarted())
374 m_gpgRunning = true;
375 else {
376 KMessageBox::error(0L, i18n("<qt>Cannot start <i>gpg</i> and sign the file. Make sure that <i>gpg</i> is installed, otherwise signing of the resources will not be possible.</qt>"));
377 emit fileSigned(0);
378 delete m_process;
379 m_process = 0;
380 }
381}
382
383#include "security.moc"
KMD5
KMD5::update
void update(const char *in, int len=-1)
KMD5::hexDigest
QByteArray hexDigest()
KMD5::reset
void reset()
KMessageBox::error
static void error(QWidget *parent, const QString &text, const QString &caption=QString(), Options options=Notify)
KNS::Security::readSecretKeys
void readSecretKeys()
Reads the available secret keys.
Definition: knewstuff2/core/security.cpp:93
KNS::Security::readKeys
void readKeys()
Reads the available public keys.
Definition: knewstuff2/core/security.cpp:66
KNS::Security::fileSigned
void fileSigned(int result)
Sent when the signing is done.
KNS::Security::checkValidity
void checkValidity(const QString &fileName)
Verifies the integrity and the signature of a tarball file.
Definition: knewstuff2/core/security.cpp:227
KNS::Security::UNKNOWN
@ UNKNOWN
The signature is trusted.
Definition: knewstuff2/core/security.h:89
KNS::Security::TRUSTED
@ TRUSTED
The file is signed with a bad signature.
Definition: knewstuff2/core/security.h:88
KNS::Security::BAD_PASSPHRASE
@ BAD_PASSPHRASE
used to clear the SIGNED_BAD flag
Definition: knewstuff2/core/security.h:91
KNS::Security::SIGNED_OK
@ SIGNED_OK
The MD5 sum check is OK.
Definition: knewstuff2/core/security.h:86
KNS::Security::MD5_OK
@ MD5_OK
Definition: knewstuff2/core/security.h:85
KNS::Security::SIGNED_BAD
@ SIGNED_BAD
The file is signed with a good signature.
Definition: knewstuff2/core/security.h:87
KNS::Security::SIGNED_BAD_CLEAR
@ SIGNED_BAD_CLEAR
The key is unknown.
Definition: knewstuff2/core/security.h:90
KNS::Security::slotCheckValidity
void slotCheckValidity()
Verifies the integrity and the signature of a tarball file (see m_fileName).
Definition: knewstuff2/core/security.cpp:233
KNS::Security::~Security
~Security()
Definition: knewstuff2/core/security.cpp:62
KNS::Security::validityResult
void validityResult(int result)
Sent when the validity check is done.
KNS::Security::signFile
void signFile(const QString &fileName)
Creates a signature and an md5sum file for the fileName and packs everything into a gzipped tarball.
Definition: knewstuff2/core/security.cpp:296
KNS::Security::slotSignFile
void slotSignFile()
Creates a signature and an md5sum file for the m_fileName and packs everything into a gzipped tarball...
Definition: knewstuff2/core/security.cpp:302
KPasswordDialog
KProcess
KProcess::start
void start()
KStandardDirs::findExe
static QString findExe(const QString &appname, const QString &pathstr=QString(), SearchOptions options=NoSearchOptions)
QMap
kcodecs.h
kdebug.h
kinputdialog.h
klocale.h
i18n
QString i18n(const char *text)
kmessagebox.h
gpgExecutable
static QString gpgExecutable()
Definition: knewstuff2/core/security.cpp:43
security.h
kpassworddialog.h
kprocess.h
kstandarddirs.h
KInputDialog::getItemList
QStringList getItemList(const QString &caption, const QString &label, const QStringList &list=QStringList(), const QStringList &select=QStringList(), bool multiple=false, bool *ok=0, QWidget *parent=0)
KNS
Definition: knewstuff2/core/author.h:27
ok
KGuiItem ok()
KeyStruct
Definition: knewstuff2/core/security.h:27
KeyStruct::mail
QString mail
Definition: knewstuff2/core/security.h:30
KeyStruct::trusted
bool trusted
Definition: knewstuff2/core/security.h:31
KeyStruct::name
QString name
Definition: knewstuff2/core/security.h:29
KeyStruct::id
QString id
Definition: knewstuff2/core/security.h:28
KeyStruct::secret
bool secret
Definition: knewstuff2/core/security.h:32
This file is part of the KDE documentation.
Documentation copyright © 1996-2023 The KDE developers.
Generated on Mon Feb 20 2023 00:00:00 by doxygen 1.9.6 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.

KNewStuff

Skip menu "KNewStuff"
  • Main Page
  • Namespace List
  • Namespace Members
  • Alphabetical List
  • Class List
  • Class Hierarchy
  • Class Members
  • File List
  • File Members
  • Related Pages

kdelibs-4.14.38 API Reference

Skip menu "kdelibs-4.14.38 API Reference"
  • DNSSD
  • Interfaces
  •   KHexEdit
  •   KMediaPlayer
  •   KSpeech
  •   KTextEditor
  • kconf_update
  • KDE3Support
  •   KUnitTest
  • KDECore
  • KDED
  • KDEsu
  • KDEUI
  • KDEWebKit
  • KDocTools
  • KFile
  • KHTML
  • KImgIO
  • KInit
  • kio
  • KIOSlave
  • KJS
  •   KJS-API
  •   WTF
  • kjsembed
  • KNewStuff
  • KParts
  • KPty
  • Kross
  • KUnitConversion
  • KUtils
  • Nepomuk
  • Plasma
  • Solid
  • Sonnet
  • ThreadWeaver
Report problems with this website to our bug tracking system.
Contact the specific authors with questions and comments about the page contents.

KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal