android: Fix XML form filter.
[qpwmc.git] / pwmdGenPassWidget.cpp
blobe09d278a4e3e9c6048cf8eb9fb76c47e2c7f95cd
1 /*
2 Copyright (C) 2010-2023 Ben Kibbey <bjk@luxsci.net>
4 This file is part of qpwmc.
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.
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.
16 You should have received a copy of the GNU Lesser General Public
17 License along with this library; if not, write to the Free Software
18 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
19 USA
21 #include <QApplication>
22 #include <QClipboard>
23 #include <QDateTime>
24 #include <QSettings>
25 #include <QRandomGenerator>
26 #include <sys/types.h>
27 #include <unistd.h>
28 #include "pwmdGenPassWidget.h"
29 #include <libpwmd.h>
31 PwmdGenPassWidget::PwmdGenPassWidget (QWidget * p) : QFrame (p)
33 ui.setupUi (this);
34 connect (ui.ck_showPassword, SIGNAL (clicked ()), this,
35 SLOT (slotShowPassword ()));
36 connect (ui.pb_generate, SIGNAL (clicked ()), this,
37 SLOT (slotGeneratePassword ()));
38 connect (ui.generateComboBox, SIGNAL (activated (int)), this,
39 SLOT (slotGenerateTypeChanged (int)));
40 connect (ui.pb_clipboard, SIGNAL (clicked ()), this,
41 SLOT (slotClipboardPassword ()));
43 connect (ui.constraintsComboBox, SIGNAL (activated (int)), this,
44 SLOT (slotConstraintsTypeChanged (int)));
45 connect (ui.le_constraints, SIGNAL (textChanged (const QString &)), this,
46 SLOT (slotConstraintsTextChanged (const QString &)));
48 if (!(pwmd_features () & PWMD_FEATURE_QUALITY))
49 ui.pg_strength->setHidden (true);
50 else
52 connect (ui.le_password, SIGNAL (textChanged (const QString &)), this,
53 SLOT (slotPasswordTextChanged (const QString &)));
54 connect (ui.le_password, SIGNAL (textEdited (const QString &)), this,
55 SLOT (slotPasswordTextChanged (const QString &)));
58 ui.le_constraints->setValidator (new QRegularExpressionValidator (QRegularExpression ("[^ ]*"), this));
59 ui.pb_clipboard->setEnabled (false);
60 _modified = false;
63 unsigned
64 PwmdGenPassWidget::quality (const QString &str, unsigned max, double &bits)
66 if (!(pwmd_features () & PWMD_FEATURE_QUALITY))
67 return 0;
69 int r;
70 bits = 0;
71 (void)pwmd_test_quality (str.toUtf8 ().data (), &bits);
73 r = (int)((bits/max)*100);
74 if (r > 100)
75 r = 100;
77 return r;
80 void
81 PwmdGenPassWidget::slotConstraintsTextChanged (const QString &)
83 setModified ();
86 void
87 PwmdGenPassWidget::slotPasswordTextChanged (const QString &str)
89 double bits = 0;
90 unsigned n = quality (str.toUtf8 ().data (), PwmdGenPassWidget::MaxEntropyBits, bits);
92 ui.pg_strength->setValue (n);
93 ui.pg_strength->setFormat (QString (tr ("Strength %p% (%1 bits)")).arg (bits));
94 ui.pb_clipboard->setEnabled (!str.isEmpty ());
95 ui.lengthSpinBox->setValue (str.isEmpty () ? 16 : str.length ());
96 setModified ();
99 void
100 PwmdGenPassWidget::setPassword (const QString &s, bool ro)
102 ui.le_password->setText (s);
103 ui.le_password->setReadOnly (ro);
106 void
107 PwmdGenPassWidget::slotShowPassword ()
109 bool b = ui.ck_showPassword->isChecked ();
111 ui.le_password->setEchoMode (!b ? QLineEdit::Password : QLineEdit::Normal);
114 QString
115 PwmdGenPassWidget::constraints (const QString &s, bool &invert)
117 QString constraint = ui.le_constraints->text ();
118 invert = false;
120 if (constraint.isEmpty ())
121 return s;
123 if (ui.constraintsComboBox->currentIndex () == 0)
124 return s;
125 else if (ui.constraintsComboBox->currentIndex () == 1)
126 return s.isEmpty () ? constraint : s + "," + constraint;
127 else
129 invert = true;
130 return s.isEmpty () ? "! " + constraint : s + ",! " + constraint;
133 return QString ();
136 void
137 PwmdGenPassWidget::slotGeneratePassword ()
139 QString result = QString ();
140 bool invert = false;
141 QString constraint = constraints (QString (), invert);
143 switch (ui.generateComboBox->currentIndex ())
145 case 0:
146 result = PwmdGenPassWidget::generate (PwmdGenPassWidget::Any,
147 ui.lengthSpinBox->value (),
148 constraint, invert);
149 break;
150 case 1:
151 result = PwmdGenPassWidget::generate (PwmdGenPassWidget::AlphaNumeric,
152 ui.lengthSpinBox->value (),
153 constraint, invert);
154 break;
155 case 2:
156 result = PwmdGenPassWidget::generate (PwmdGenPassWidget::Alpha,
157 ui.lengthSpinBox->value (),
158 constraint, invert);
159 break;
160 case 3:
161 result = PwmdGenPassWidget::generate (PwmdGenPassWidget::Numeric,
162 ui.lengthSpinBox->value (),
163 constraint, invert);
164 break;
165 default:
166 break;
169 ui.le_password->setText (result);
170 slotClipboardPassword ();
173 void
174 PwmdGenPassWidget::slotConstraintsTypeChanged (int idx)
176 ui.le_constraints->setEnabled (idx != 0);
177 if (!idx)
178 ui.le_constraints->setText ("");
179 setModified ();
182 void
183 PwmdGenPassWidget::slotGenerateTypeChanged (int)
185 setModified ();
188 QString
189 PwmdGenPassWidget::type ()
191 bool invert;
193 if (ui.generateComboBox->currentIndex () == 1)
194 return constraints ("alnum", invert);
195 else if (ui.generateComboBox->currentIndex () == 2)
196 return constraints ("alpha", invert);
197 else if (ui.generateComboBox->currentIndex () == 3)
198 return constraints ("numeric", invert);
200 return constraints (QString (), invert);
203 void
204 PwmdGenPassWidget::setType (const QString &s)
206 QStringList t = s.split (',');
207 QString type = t.count () ? t.at (0) : QString ();
208 QString constraint = !t.isEmpty () && t.count () > 1 ? t.at (1) : QString ();
210 if (type == "alnum")
211 ui.generateComboBox->setCurrentIndex (1);
212 else if (type == "alpha")
213 ui.generateComboBox->setCurrentIndex (2);
214 else if (type == "numeric")
215 ui.generateComboBox->setCurrentIndex (3);
216 else
218 if (t.count () == 1)
219 constraint = s;
220 ui.generateComboBox->setCurrentIndex (0);
223 ui.le_constraints->setEnabled (!constraint.isEmpty ());
225 if (constraint.isEmpty ())
226 ui.constraintsComboBox->setCurrentIndex (0);
227 else if (constraint.at (0) != '!'
228 || (constraint.at (0) == '!' && constraint.at (1) != ' '))
229 ui.constraintsComboBox->setCurrentIndex (1);
230 else
232 ui.constraintsComboBox->setCurrentIndex (2);
233 constraint = constraint.mid (2);
236 ui.le_constraints->setText (constraint);
239 // Generate a passphrase of length 'len' from the characters in 'str'. The
240 // constraint adds characters after generating or removes in the case 'invert'
241 // is true.
242 QString
243 PwmdGenPassWidget::generate (const QString & str, int len, QString constraint,
244 bool invert)
246 QString s = QString ();
247 int max = 0;
248 QSettings cfg ("qpwmc");
249 int freq = cfg.value ("constraintsFreq", 30).toInt ();
251 // Replace 30 percent of random characters in str of 'len' with the
252 // constraint when not inverted.
253 if (!constraint.isEmpty ())
255 max = len * freq / 100;
256 if (!max)
257 max++;
260 // Prevent inifinate loop when all characters of the constraint match some
261 // order in 'str'.
262 if (invert && !constraint.isEmpty ())
264 int n = 0;
266 foreach (QChar c, constraint)
268 if (str.contains (c))
269 n++;
272 if (n == str.length ())
274 constraint = QString ();
275 invert = false;
279 for (int i = 0; i < len; i++)
281 QChar c;
283 // Don't include characters in 'constraint'.
286 c = str.at (QRandomGenerator::system ()->generate () % str.length ());
287 } while (invert && !constraint.isEmpty () && constraint.contains (c));
289 s.append (c);
292 if (!invert && !constraint.isEmpty ())
294 QList <int> list;
295 int count = 0;
297 // Put 'max' random characters of the constraint in the result.
300 int n;
303 n = QRandomGenerator::system ()->generate () % s.length ();
304 } while (list.contains (n) && list.length () < len);
306 QChar c = constraint.at
307 (QRandomGenerator::system ()->generate () % constraint.length ());
308 s.replace (n, 1, c);
309 list.append (n);
310 if (list.length () == len - 1)
311 break;
313 while (++count < max);
316 return s;
319 QString
320 PwmdGenPassWidget::generate (Type t, int len, const QString &constraint,
321 bool invert)
323 QString result = QString ();
325 switch (t)
327 case Any:
328 result =
329 generate (tr
330 ("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789`~-_=+!@#$%^&*()][\\{}|';\":?></.,"),
331 len, constraint, invert);
332 break;
333 case AlphaNumeric:
335 QRegularExpression re_n ("[0-9]+");
336 QRegularExpression re_a ("[a-z]+", QRegularExpression::CaseInsensitiveOption);
340 result = generate (tr ("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"), len, constraint, invert);
341 } while (len > 1 && !invert
342 && (constraint.isEmpty () || (!constraint.isEmpty () && len >= constraint.length ()))
343 && (!result.contains (re_n) || !result.contains (re_a)));
345 break;
346 case Alpha:
347 result =
348 generate (tr
349 ("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"),
350 len, constraint, invert);
351 break;
352 case Numeric:
353 result = generate (tr ("0123456789"), len, constraint, invert);
354 break;
355 default:
356 break;
359 return result;
362 QString
363 PwmdGenPassWidget::password ()
365 return ui.le_password->text ();
368 void
369 PwmdGenPassWidget::clipboardPassword ()
371 slotClipboardPassword ();
374 void
375 PwmdGenPassWidget::slotClipboardPassword ()
377 QClipboard *c = QApplication::clipboard ();
379 if (c->supportsSelection ())
380 c->setText (ui.le_password->text (), QClipboard::Selection);
381 c->setText (ui.le_password->text ());
383 emit clipboardTimer ();
386 void
387 PwmdGenPassWidget::setModified (bool b)
389 _modified = b;
390 if (b)
391 emit modified ();
394 bool
395 PwmdGenPassWidget::isModified ()
397 return _modified;
400 void
401 PwmdGenPassWidget::setEditable (bool b)
403 ui.gr_generate->setEnabled (b);
404 ui.le_password->setReadOnly (!b);