QCA

prompter.cpp
1 /*
2  Copyright (C) 2007 Justin Karneges <[email protected]>
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 
31 class Prompter::Private : public QObject
32 {
33  Q_OBJECT
34 public:
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 
77 private 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) {
113  QString name;
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();
186  QString name;
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;
224  ks->startAsynchronousMode();
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  {
240  QCA::KeyStore *ks = (QCA::KeyStore *)sender();
241  keyStores.removeAll(ks);
242  delete ks;
243  }
244 
245  void ks_updated()
246  {
247  QCA::KeyStore *ks = (QCA::KeyStore *)sender();
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 
275 Prompter::Prompter(QObject *parent)
276  : QObject(parent)
277 {
278  d = new Private(this);
279 }
280 
281 Prompter::~Prompter()
282 {
283  delete d;
284 }
285 
286 QCA::SecureArray Prompter::knownPassword(const QCA::Event &event)
287 {
288  Q_UNUSED(event);
289  return QCA::SecureArray();
290 }
291 
292 void 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"
An asynchronous event.
Definition: qca_core.h:1390
void startAsynchronousMode()
Turns on asynchronous mode for this KeyStore instance.
void tokenOkay(int id)
function to call to indicate that the token has been inserted by the user.
QString name(const QVariant &location)
void reject(int id)
function to call to indicate that the user declined to provide a password, passphrase, PIN or token.
void removeFirst()
bool isNull() const
Test if this key is empty (null)
bool isAvailable() const
Test if the key is available for use.
QString name() const
The name associated with the key stored in this object.
Interface class for password / passphrase / PIN and token handlers.
Definition: qca_core.h:1578
Asking for a password, PIN or passphrase.
Definition: qca_core.h:1400
QString tr(const char *sourceText, const char *disambiguation, int n)
User should be prompted for a "PIN".
Definition: qca_core.h:1434
QList< KeyStoreEntry > entryList() const
A list of the KeyStoreEntry objects in this store.
void submitPassword(int id, const SecureArray &password)
function to call to return the user provided password, passphrase or PIN.
Q_OBJECTQ_OBJECT
Type type(const QSqlDatabase &db)
User should be prompted for a "Passphrase".
Definition: qca_core.h:1433
General purpose key storage object.
Definition: qca_keystore.h:416
bool isEmpty() const const
QStringList keyStores() const
A list of all the key stores.
int removeAll(const T &value)
void start()
mandatory function to call after connecting the signal to a slot in your application specific passwor...
QCoreApplication * instance()
KeyStore generated the event.
Definition: qca_core.h:1418
T & first()
Access keystores, and monitor keystores for changes.
Definition: qca_keystore.h:709
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)
Single entry in a KeyStore.
Definition: qca_keystore.h:140
bool invokeMethod(QObject *obj, const char *member, Qt::ConnectionType type, QGenericReturnArgument ret, QGenericArgument val0, QGenericArgument val1, QGenericArgument val2, QGenericArgument val3, QGenericArgument val4, QGenericArgument val5, QGenericArgument val6, QGenericArgument val7, QGenericArgument val8, QGenericArgument val9)
Asking for a token.
Definition: qca_core.h:1401
Secure array of bytes.
Definition: qca_tools.h:316
const QList< QKeySequence > & end()
T takeFirst()
QString arg(qlonglong a, int fieldWidth, int base, QChar fillChar) const const
QString id() const
The ID associated with the key stored in this object.
bool isEmpty() const
Test if the array contains any bytes.
QString id() const
The ID associated with the KeyStore.
QueuedConnection
QString storeName() const
The name of the KeyStore for this key object.
KIOFILEWIDGETS_EXPORT QStringList list(const QString &fileClass)
QByteArray toUtf8() const const
This file is part of the KDE documentation.
Documentation copyright © 1996-2021 The KDE developers.
Generated on Sat Sep 25 2021 23:05:35 by doxygen 1.8.11 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.