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;
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  {
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 
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"
Q_OBJECTQ_OBJECT
bool isNull() const
Test if this key is empty (null)
T & first()
QString id() const
The ID associated with the key stored in this object.
virtual bool event(QEvent *ev) override
QString storeName() const
The name of the KeyStore for this key object.
Q_SLOTSQ_SLOTS
int removeAll(const T &value)
QObject * sender() const const
@ KeyStore
KeyStore generated the event.
Definition: qca_core.h:1418
void tokenOkay(int id)
function to call to indicate that the token has been inserted by the user.
QString name() const
The name associated with the key stored in this object.
KIOFILEWIDGETS_EXPORT QStringList list(const QString &fileClass)
QMetaObject::Connection connect(const QObject *sender, const char *signal, const QObject *receiver, const char *method, Qt::ConnectionType type)
@ StylePassphrase
User should be prompted for a "Passphrase".
Definition: qca_core.h:1433
@ Token
Asking for a token.
Definition: qca_core.h:1401
virtual bool event(QEvent *e)
@ Password
Asking for a password, PIN or passphrase.
Definition: qca_core.h:1400
@ StylePIN
User should be prompted for a "PIN".
Definition: qca_core.h:1434
T takeFirst()
QStringList keyStores() const
A list of all the key stores.
void removeFirst()
QByteArray toUtf8() const const
QCoreApplication * instance()
QString getText(QWidget *parent, const QString &title, const QString &label, QLineEdit::EchoMode mode, const QString &text, bool *ok, Qt::WindowFlags flags, Qt::InputMethodHints inputMethodHints)
virtual void accept()
QueuedConnection
bool isEmpty() const const
AKONADI_CALENDAR_EXPORT KCalendarCore::Event::Ptr event(const Akonadi::Item &item)
QString id() const
The ID associated with the KeyStore.
void reject(int id)
function to call to indicate that the user declined to provide a password, passphrase,...
void submitPassword(int id, const SecureArray &password)
function to call to return the user provided password, passphrase or PIN.
void start()
mandatory function to call after connecting the signal to a slot in your application specific passwor...
VehicleSection::Type type(QStringView coachNumber, QStringView coachClassification)
QString arg(qlonglong a, int fieldWidth, int base, QChar fillChar) const const
@ SmartCard
for smartcards
Definition: qca_keystore.h:428
QString name(StandardShortcut id)
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)
bool isAvailable() const
Test if the key is available for use.
void startAsynchronousMode()
Turns on asynchronous mode for this KeyStore instance.
QString tr(const char *sourceText, const char *disambiguation, int n)
bool isEmpty() const
Test if the array contains any bytes.
const QList< QKeySequence > & end()
QList< KeyStoreEntry > entryList() const
A list of the KeyStoreEntry objects in this store.
This file is part of the KDE documentation.
Documentation copyright © 1996-2022 The KDE developers.
Generated on Mon Sep 26 2022 04:10:45 by doxygen 1.8.17 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.