QCA

prompter.cpp
1/*
2 Copyright (C) 2007 Justin Karneges <justin@affinix.com>
3
4 Permission is hereby granted, free of charge, to any person obtaining a copy
5 of this software and associated documentation files (the "Software"), to deal
6 in the Software without restriction, including without limitation the rights
7 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 copies of the Software, and to permit persons to whom the Software is
9 furnished to do so, subject to the following conditions:
10
11 The above copyright notice and this permission notice shall be included in
12 all copies or substantial portions of the Software.
13
14 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
18 AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
19 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
20*/
21
22#include "prompter.h"
23
24#include <QApplication>
25#include <QInputDialog>
26#include <QMessageBox>
27#include <QtCore>
28#include <QtCrypto>
29#include <QtGui>
30
31class Prompter::Private : public QObject
32{
34public:
35 Prompter *q;
36
37 class Item
38 {
39 public:
40 int id;
41 QCA::Event event;
42 };
43
44 QCA::EventHandler handler;
45 QList<Item> pending;
46 bool prompting;
47 QMessageBox *token_prompt;
48 bool auto_accept;
49
51 QList<QCA::KeyStore *> keyStores;
52
53 Private(Prompter *_q)
54 : QObject(_q)
55 , q(_q)
56 , handler(this)
57 , prompting(false)
58 , token_prompt(0)
59 , ksm(this)
60 {
61 connect(&handler, SIGNAL(eventReady(int, const QCA::Event &)), SLOT(ph_eventReady(int, const QCA::Event &)));
62 handler.start();
63
64 connect(&ksm, SIGNAL(keyStoreAvailable(const QString &)), SLOT(ks_available(const QString &)));
65 foreach (const QString &keyStoreId, ksm.keyStores())
66 ks_available(keyStoreId);
67 }
68
69 ~Private()
70 {
71 qDeleteAll(keyStores);
72
73 while (!pending.isEmpty())
74 handler.reject(pending.takeFirst().id);
75 }
76
77private Q_SLOTS:
78 void ph_eventReady(int id, const QCA::Event &event)
79 {
80 Item i;
81 i.id = id;
82 i.event = event;
83 pending += i;
84 nextEvent();
85 }
86
87 void nextEvent()
88 {
89 if (prompting || pending.isEmpty())
90 return;
91
92 prompting = true;
93
94 const Item &i = pending.first();
95 const int &id = i.id;
96 const QCA::Event &event = i.event;
97
98 if (event.type() == QCA::Event::Password) {
99 QCA::SecureArray known = q->knownPassword(event);
100 if (!known.isEmpty()) {
101 handler.submitPassword(id, known);
102 goto end;
103 }
104
105 QString type = Prompter::tr("password");
106 if (event.passwordStyle() == QCA::Event::StylePassphrase)
107 type = Prompter::tr("passphrase");
108 else if (event.passwordStyle() == QCA::Event::StylePIN)
109 type = Prompter::tr("PIN");
110
111 QString str;
112 if (event.source() == QCA::Event::KeyStore) {
114 QCA::KeyStoreEntry entry = event.keyStoreEntry();
115 if (!entry.isNull()) {
116 name = entry.name();
117 } else {
118 if (event.keyStoreInfo().type() == QCA::KeyStore::SmartCard)
119 name = Prompter::tr("the '%1' token").arg(event.keyStoreInfo().name());
120 else
121 name = event.keyStoreInfo().name();
122 }
123 str = Prompter::tr("Enter %1 for %2").arg(type, name);
124 } else if (!event.fileName().isEmpty()) {
125 QFileInfo fi(event.fileName());
126 str = Prompter::tr("Enter %1 for %2:").arg(type, fi.fileName());
127 } else
128 str = Prompter::tr("Enter %1:").arg(type);
129
130 bool ok;
132 QApplication::instance()->applicationName() + ": " + tr("Prompt"),
133 str,
135 QString(),
136 &ok);
137 if (ok) {
138 QCA::SecureArray password = pass.toUtf8();
139 q->userSubmitted(password, event);
140 handler.submitPassword(id, password);
141 } else
142 handler.reject(id);
143 } else if (event.type() == QCA::Event::Token) {
144 // even though we're being prompted for a missing token,
145 // we should still check if the token is present, due to
146 // a possible race between insert and token request.
147 bool found = false;
148
149 // token-only
150 if (event.keyStoreEntry().isNull()) {
151 foreach (QCA::KeyStore *ks, keyStores) {
152 if (ks->id() == event.keyStoreInfo().id()) {
153 found = true;
154 break;
155 }
156 }
157 }
158 // token-entry
159 else {
160 QCA::KeyStoreEntry kse = event.keyStoreEntry();
161
162 QCA::KeyStore *ks = 0;
163 foreach (QCA::KeyStore *i, keyStores) {
164 if (i->id() == event.keyStoreInfo().id()) {
165 ks = i;
166 break;
167 }
168 }
169 if (ks) {
171 foreach (const QCA::KeyStoreEntry &e, list) {
172 if (e.id() == kse.id() && kse.isAvailable()) {
173 found = true;
174 break;
175 }
176 }
177 }
178 }
179 if (found) {
180 // auto-accept
181 handler.tokenOkay(id);
182 return;
183 }
184
185 QCA::KeyStoreEntry entry = event.keyStoreEntry();
187 if (!entry.isNull()) {
188 name = Prompter::tr("Please make %1 (of %2) available").arg(entry.name(), entry.storeName());
189 } else {
190 name = Prompter::tr("Please insert the '%1' token").arg(event.keyStoreInfo().name());
191 }
192
193 QString str = Prompter::tr("%1 and click OK.").arg(name);
194
196 QApplication::instance()->applicationName() + ": " + tr("Prompt"),
197 str,
199 0);
200 token_prompt = &msgBox;
201 auto_accept = false;
202 if (msgBox.exec() == QMessageBox::Ok || auto_accept)
203 handler.tokenOkay(id);
204 else
205 handler.reject(id);
206 token_prompt = 0;
207 } else
208 handler.reject(id);
209
210 end:
211 pending.removeFirst();
212 prompting = false;
213
214 if (!pending.isEmpty())
216 }
217
218 void ks_available(const QString &keyStoreId)
219 {
220 QCA::KeyStore *ks = new QCA::KeyStore(keyStoreId, &ksm);
221 connect(ks, SIGNAL(updated()), SLOT(ks_updated()));
222 connect(ks, SIGNAL(unavailable()), SLOT(ks_unavailable()));
223 keyStores += ks;
225
226 // are we currently in a token-only prompt?
227 if (token_prompt && pending.first().event.type() == QCA::Event::Token &&
228 pending.first().event.keyStoreEntry().isNull()) {
229 // was the token we're looking for just inserted?
230 if (pending.first().event.keyStoreInfo().id() == keyStoreId) {
231 // auto-accept
232 auto_accept = true;
233 token_prompt->accept();
234 }
235 }
236 }
237
238 void ks_unavailable()
239 {
241 keyStores.removeAll(ks);
242 delete ks;
243 }
244
245 void ks_updated()
246 {
248
249 // are we currently in a token-entry prompt?
250 if (token_prompt && pending.first().event.type() == QCA::Event::Token &&
251 !pending.first().event.keyStoreEntry().isNull()) {
252 QCA::KeyStoreEntry kse = pending.first().event.keyStoreEntry();
253
254 // was the token of the entry we're looking for updated?
255 if (pending.first().event.keyStoreInfo().id() == ks->id()) {
256 // is the entry available?
257 bool avail = false;
259 foreach (const QCA::KeyStoreEntry &e, list) {
260 if (e.id() == kse.id()) {
261 avail = kse.isAvailable();
262 break;
263 }
264 }
265 if (avail) {
266 // auto-accept
267 auto_accept = true;
268 token_prompt->accept();
269 }
270 }
271 }
272 }
273};
274
275Prompter::Prompter(QObject *parent)
276 : QObject(parent)
277{
278 d = new Private(this);
279}
280
281Prompter::~Prompter()
282{
283 delete d;
284}
285
286QCA::SecureArray Prompter::knownPassword(const QCA::Event &event)
287{
288 Q_UNUSED(event);
289 return QCA::SecureArray();
290}
291
292void Prompter::userSubmitted(const QCA::SecureArray &password, const QCA::Event &event)
293{
294 Q_UNUSED(password);
295 Q_UNUSED(event);
296}
297
298#include "prompter.moc"
Interface class for password / passphrase / PIN and token handlers.
Definition qca_core.h:1579
void submitPassword(int id, const SecureArray &password)
function to call to return the user provided password, passphrase or PIN.
void reject(int id)
function to call to indicate that the user declined to provide a password, passphrase,...
void tokenOkay(int id)
function to call to indicate that the token has been inserted by the user.
void start()
mandatory function to call after connecting the signal to a slot in your application specific passwor...
An asynchronous event.
Definition qca_core.h:1391
@ KeyStore
KeyStore generated the event.
Definition qca_core.h:1418
@ Password
Asking for a password, PIN or passphrase.
Definition qca_core.h:1400
@ Token
Asking for a token.
Definition qca_core.h:1401
@ StylePIN
User should be prompted for a "PIN".
Definition qca_core.h:1434
@ StylePassphrase
User should be prompted for a "Passphrase".
Definition qca_core.h:1433
Single entry in a KeyStore.
bool isAvailable() const
Test if the key is available for use.
QString name() const
The name associated with the key stored in this object.
QString storeName() const
The name of the KeyStore for this key object.
QString id() const
The ID associated with the key stored in this object.
bool isNull() const
Test if this key is empty (null)
Access keystores, and monitor keystores for changes.
QStringList keyStores() const
A list of all the key stores.
General purpose key storage object.
QString id() const
The ID associated with the KeyStore.
QList< KeyStoreEntry > entryList() const
A list of the KeyStoreEntry objects in this store.
void startAsynchronousMode()
Turns on asynchronous mode for this KeyStore instance.
@ SmartCard
for smartcards
Secure array of bytes.
Definition qca_tools.h:317
bool isEmpty() const
Test if the array contains any bytes.
Type type(const QSqlDatabase &db)
KIOCORE_EXPORT QStringList list(const QString &fileClass)
const QList< QKeySequence > & end()
QString name(StandardShortcut id)
QCoreApplication * instance()
virtual void accept()
QString getText(QWidget *parent, const QString &title, const QString &label, QLineEdit::EchoMode mode, const QString &text, bool *ok, Qt::WindowFlags flags, Qt::InputMethodHints inputMethodHints)
T & first()
bool isEmpty() const const
qsizetype removeAll(const AT &t)
void removeFirst()
value_type takeFirst()
bool invokeMethod(QObject *context, Functor &&function, FunctorReturnType *ret)
Q_OBJECTQ_OBJECT
Q_SLOTSQ_SLOTS
QMetaObject::Connection connect(const QObject *sender, PointerToMemberFunction signal, Functor functor)
virtual bool event(QEvent *e)
QObject * sender() const const
QString tr(const char *sourceText, const char *disambiguation, int n)
virtual bool event(QEvent *ev) override
QString arg(Args &&... args) const const
QByteArray toUtf8() const const
QueuedConnection
This file is part of the KDE documentation.
Documentation copyright © 1996-2024 The KDE developers.
Generated on Tue Mar 26 2024 11:18:26 by doxygen 1.10.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.