2 Copyright (C) 2010-2024 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
21 #include <QApplication>
25 #include <QRandomGenerator>
26 #include <sys/types.h>
28 #include "pwmdGenPassWidget.h"
31 PwmdGenPassWidget::PwmdGenPassWidget (QWidget
* p
) : QFrame (p
)
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);
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);
64 PwmdGenPassWidget::quality (const QString
&str
, unsigned max
, double &bits
)
66 if (!(pwmd_features () & PWMD_FEATURE_QUALITY
))
71 (void)pwmd_test_quality (str
.toUtf8 ().data (), &bits
);
73 r
= (int)((bits
/max
)*100);
81 PwmdGenPassWidget::slotConstraintsTextChanged (const QString
&)
87 PwmdGenPassWidget::slotPasswordTextChanged (const QString
&str
)
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 ());
100 PwmdGenPassWidget::setPassword (const QString
&s
, bool ro
)
102 ui
.le_password
->setText (s
);
103 ui
.le_password
->setReadOnly (ro
);
107 PwmdGenPassWidget::slotShowPassword ()
109 bool b
= ui
.ck_showPassword
->isChecked ();
111 ui
.le_password
->setEchoMode (!b
? QLineEdit::Password
: QLineEdit::Normal
);
115 PwmdGenPassWidget::constraints (const QString
&s
, bool &invert
)
117 QString constraint
= ui
.le_constraints
->text ();
120 if (constraint
.isEmpty ())
123 if (ui
.constraintsComboBox
->currentIndex () == 0)
125 else if (ui
.constraintsComboBox
->currentIndex () == 1)
126 return s
.isEmpty () ? constraint
: s
+ "," + constraint
;
130 return s
.isEmpty () ? "! " + constraint
: s
+ ",! " + constraint
;
137 PwmdGenPassWidget::slotGeneratePassword ()
139 QString result
= QString ();
141 QString constraint
= constraints (QString (), invert
);
143 switch (ui
.generateComboBox
->currentIndex ())
146 result
= PwmdGenPassWidget::generate (PwmdGenPassWidget::Any
,
147 ui
.lengthSpinBox
->value (),
151 result
= PwmdGenPassWidget::generate (PwmdGenPassWidget::AlphaNumeric
,
152 ui
.lengthSpinBox
->value (),
156 result
= PwmdGenPassWidget::generate (PwmdGenPassWidget::Alpha
,
157 ui
.lengthSpinBox
->value (),
161 result
= PwmdGenPassWidget::generate (PwmdGenPassWidget::Numeric
,
162 ui
.lengthSpinBox
->value (),
169 ui
.le_password
->setText (result
);
170 slotClipboardPassword ();
174 PwmdGenPassWidget::slotConstraintsTypeChanged (int idx
)
176 ui
.le_constraints
->setEnabled (idx
!= 0);
178 ui
.le_constraints
->setText ("");
183 PwmdGenPassWidget::slotGenerateTypeChanged (int)
189 PwmdGenPassWidget::type ()
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
);
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 ();
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);
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);
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'
243 PwmdGenPassWidget::generate (const QString
& str
, int len
, QString constraint
,
246 QString s
= QString ();
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;
260 // Prevent inifinate loop when all characters of the constraint match some
262 if (invert
&& !constraint
.isEmpty ())
266 foreach (QChar c
, constraint
)
268 if (str
.contains (c
))
272 if (n
== str
.length ())
274 constraint
= QString ();
279 for (int i
= 0; i
< len
; i
++)
283 // Don't include characters in 'constraint'.
286 c
= str
.at (QRandomGenerator::system ()->generate () % str
.length ());
287 } while (invert
&& !constraint
.isEmpty () && constraint
.contains (c
));
292 if (!invert
&& !constraint
.isEmpty ())
297 // Put 'max' random characters of the constraint in the result.
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 ());
310 if (list
.length () == len
- 1)
313 while (++count
< max
);
320 PwmdGenPassWidget::generate (Type t
, int len
, const QString
&constraint
,
323 QString result
= QString ();
330 ("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789`~-_=+!@#$%^&*()][\\{}|';\":?></.,"),
331 len
, constraint
, invert
);
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
)));
349 ("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"),
350 len
, constraint
, invert
);
353 result
= generate (tr ("0123456789"), len
, constraint
, invert
);
363 PwmdGenPassWidget::password ()
365 return ui
.le_password
->text ();
369 PwmdGenPassWidget::clipboardPassword ()
371 slotClipboardPassword ();
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 ();
387 PwmdGenPassWidget::setModified (bool b
)
395 PwmdGenPassWidget::isModified ()
401 PwmdGenPassWidget::setEditable (bool b
)
403 ui
.generateLabel
->setEnabled (b
);
404 ui
.generateComboBox
->setEnabled (b
);
405 ui
.constraintsLabel
->setEnabled (b
);
406 ui
.constraintsComboBox
->setEnabled (b
);
407 ui
.le_constraints
->setEnabled (b
);
408 ui
.lengthSpinBox
->setEnabled (b
);
409 ui
.lengthLabel
->setEnabled (b
);
410 ui
.pb_generate
->setEnabled (b
);
411 ui
.pb_clipboard
->setEnabled (true);
412 ui
.le_password
->setReadOnly (!b
);