keepassxc

Форк
0
/
TestPasswordGenerator.cpp 
283 строки · 13.5 Кб
1
/*
2
 *  Copyright (C) 2018 KeePassXC Team <team@keepassxc.org>
3
 *
4
 *  This program is free software: you can redistribute it and/or modify
5
 *  it under the terms of the GNU General Public License as published by
6
 *  the Free Software Foundation, either version 2 or (at your option)
7
 *  version 3 of the License.
8
 *
9
 *  This program is distributed in the hope that it will be useful,
10
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
11
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12
 *  GNU General Public License for more details.
13
 *
14
 *  You should have received a copy of the GNU General Public License
15
 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
16
 */
17

18
#include "TestPasswordGenerator.h"
19
#include "crypto/Crypto.h"
20

21
#include <QRegularExpression>
22
#include <QTest>
23

24
QTEST_GUILESS_MAIN(TestPasswordGenerator)
25

26
Q_DECLARE_METATYPE(PasswordGenerator::CharClasses)
27
Q_DECLARE_METATYPE(PasswordGenerator::GeneratorFlags)
28

29
namespace
30
{
31
    PasswordGenerator::CharClasses to_flags(PasswordGenerator::CharClass x)
32
    {
33
        return x;
34
    }
35

36
    PasswordGenerator::GeneratorFlags to_flags(PasswordGenerator::GeneratorFlag x)
37
    {
38
        return x;
39
    }
40
} // namespace
41

42
void TestPasswordGenerator::initTestCase()
43
{
44
    QVERIFY(Crypto::init());
45
}
46

47
void TestPasswordGenerator::init()
48
{
49
    m_generator.reset();
50
}
51

52
void TestPasswordGenerator::testCustomCharacterSet_data()
53
{
54
    QTest::addColumn<PasswordGenerator::CharClasses>("activeCharacterClasses");
55
    QTest::addColumn<QString>("customCharacterSet");
56
    QTest::addColumn<QRegularExpression>("expected");
57

58
    QTest::addRow("With active classes") << to_flags(PasswordGenerator::CharClass::UpperLetters) << "abc"
59
                                         << QRegularExpression("^[abcA-Z]{2000}$");
60
    QTest::addRow("Without any active class")
61
        << to_flags(PasswordGenerator::CharClass::NoClass) << "abc" << QRegularExpression("^[abc]{2000}$");
62
}
63

64
void TestPasswordGenerator::testCustomCharacterSet()
65
{
66
    QFETCH(PasswordGenerator::CharClasses, activeCharacterClasses);
67
    QFETCH(QString, customCharacterSet);
68
    QFETCH(QRegularExpression, expected);
69

70
    m_generator.setCharClasses(activeCharacterClasses);
71
    m_generator.setCustomCharacterSet(customCharacterSet);
72
    m_generator.setLength(2000);
73

74
    QVERIFY(m_generator.isValid());
75
    QString password = m_generator.generatePassword();
76
    QCOMPARE(password.size(), 2000);
77
    QVERIFY(expected.match(password).hasMatch());
78
}
79

80
void TestPasswordGenerator::testCharClasses_data()
81
{
82
    QTest::addColumn<PasswordGenerator::CharClasses>("activeCharacterClasses");
83
    QTest::addColumn<QRegularExpression>("expected");
84

85
    QTest::addRow("Lower Letters") << to_flags(PasswordGenerator::CharClass::LowerLetters)
86
                                   << QRegularExpression(R"(^[a-z]{2000}$)");
87
    QTest::addRow("Upper Letters") << to_flags(PasswordGenerator::CharClass::UpperLetters)
88
                                   << QRegularExpression(R"(^[A-Z]{2000}$)");
89
    QTest::addRow("Numbers") << to_flags(PasswordGenerator::CharClass::Numbers) << QRegularExpression(R"(^\d{2000}$)");
90
    QTest::addRow("Braces") << to_flags(PasswordGenerator::CharClass::Braces)
91
                            << QRegularExpression(R"(^[\(\)\[\]\{\}]{2000}$)");
92
    QTest::addRow("Punctuation") << to_flags(PasswordGenerator::CharClass::Punctuation)
93
                                 << QRegularExpression(R"(^[\.,:;]{2000}$)");
94
    QTest::addRow("Quotes") << to_flags(PasswordGenerator::CharClass::Quotes) << QRegularExpression(R"(^["']{2000}$)");
95
    QTest::addRow("Dashes") << to_flags(PasswordGenerator::CharClass::Dashes)
96
                            << QRegularExpression(R"(^[\-/\\_|]{2000}$)");
97
    QTest::addRow("Math") << to_flags(PasswordGenerator::CharClass::Math) << QRegularExpression(R"(^[!\*\+\-<=>\?]+$)");
98
    QTest::addRow("Logograms") << to_flags(PasswordGenerator::CharClass::Logograms)
99
                               << QRegularExpression(R"(^[#`~%&^$@]{2000}$)");
100
    QTest::addRow("Extended ASCII") << to_flags(PasswordGenerator::CharClass::EASCII)
101
                                    << QRegularExpression(R"(^[^a-zA-Z0-9\.,:;"'\-/\\_|!\*\+\-<=>\?#`~%&^$@]{2000}$)");
102
    QTest::addRow("Combinations 1") << (PasswordGenerator::CharClass::LowerLetters
103
                                        | PasswordGenerator::CharClass::UpperLetters
104
                                        | PasswordGenerator::CharClass::Braces)
105
                                    << QRegularExpression(R"(^[a-zA-Z\(\)\[\]\{\}]{2000}$)");
106
    QTest::addRow("Combinations 2") << (PasswordGenerator::CharClass::Quotes | PasswordGenerator::CharClass::Numbers
107
                                        | PasswordGenerator::CharClass::Dashes)
108
                                    << QRegularExpression(R"(^["'\d\-/\\_|]{2000}$)");
109
}
110

111
void TestPasswordGenerator::testCharClasses()
112
{
113

114
    QFETCH(PasswordGenerator::CharClasses, activeCharacterClasses);
115
    QFETCH(QRegularExpression, expected);
116

117
    m_generator.setCharClasses(activeCharacterClasses);
118
    m_generator.setLength(2000);
119

120
    QVERIFY(m_generator.isValid());
121
    QString password = m_generator.generatePassword();
122
    QCOMPARE(password.size(), 2000);
123
    QVERIFY(expected.match(password).hasMatch());
124
}
125

126
void TestPasswordGenerator::testLookalikeExclusion_data()
127
{
128
    QTest::addColumn<PasswordGenerator::CharClasses>("activeCharacterClasses");
129
    QTest::addColumn<QRegularExpression>("expected");
130
    QTest::addRow("Upper Letters") << (PasswordGenerator::CharClass::LowerLetters
131
                                       | PasswordGenerator::CharClass::UpperLetters)
132
                                   << QRegularExpression("^[^lBGIO]{2000}$");
133

134
    QTest::addRow("Letters and Numbers") << (PasswordGenerator::CharClass::LowerLetters
135
                                             | PasswordGenerator::CharClass::UpperLetters
136
                                             | PasswordGenerator::CharClass::Numbers)
137
                                         << QRegularExpression("^[^lBGIO0168]{2000}$");
138

139
    QTest::addRow("Letters, Numbers and extended ASCII")
140
        << (PasswordGenerator::CharClass::LowerLetters | PasswordGenerator::CharClass::UpperLetters
141
            | PasswordGenerator::CharClass::Numbers | PasswordGenerator::CharClass::EASCII)
142
        << QRegularExpression("^[^lBGIO0168﹒]{2000}$");
143
}
144

145
void TestPasswordGenerator::testLookalikeExclusion()
146
{
147
    QFETCH(PasswordGenerator::CharClasses, activeCharacterClasses);
148
    QFETCH(QRegularExpression, expected);
149

150
    m_generator.setFlags(PasswordGenerator::ExcludeLookAlike);
151
    m_generator.setCharClasses(activeCharacterClasses);
152
    m_generator.setLength(2000);
153

154
    QVERIFY(m_generator.isValid());
155
    QString password = m_generator.generatePassword();
156
    QCOMPARE(password.size(), 2000);
157
    QVERIFY(expected.match(password).hasMatch());
158
}
159

160
void TestPasswordGenerator::testValidity_data()
161
{
162
    QTest::addColumn<PasswordGenerator::CharClasses>("activeCharacterClasses");
163
    QTest::addColumn<PasswordGenerator::GeneratorFlags>("generatorFlags");
164
    QTest::addColumn<QString>("customCharacterSet");
165
    QTest::addColumn<QString>("excludedCharacters");
166
    QTest::addColumn<int>("length");
167
    QTest::addColumn<bool>("isValid");
168

169
    QTest::addRow("No active class") << to_flags(PasswordGenerator::CharClass::NoClass)
170
                                     << PasswordGenerator::GeneratorFlags() << QString() << QString()
171
                                     << PasswordGenerator::DefaultLength << false;
172
    QTest::addRow("0 length") << to_flags(PasswordGenerator::CharClass::DefaultCharset)
173
                              << PasswordGenerator::GeneratorFlags() << QString() << QString() << 0 << false;
174
    QTest::addRow("All active classes excluded")
175
        << to_flags(PasswordGenerator::CharClass::Numbers) << PasswordGenerator::GeneratorFlags() << QString()
176
        << QString("0123456789") << PasswordGenerator::DefaultLength << false;
177
    QTest::addRow("All active classes excluded")
178
        << to_flags(PasswordGenerator::CharClass::NoClass) << PasswordGenerator::GeneratorFlags() << QString()
179
        << QString("0123456789") << PasswordGenerator::DefaultLength << false;
180
    QTest::addRow("One from every class with too few classes")
181
        << (PasswordGenerator::CharClass::LowerLetters | PasswordGenerator::CharClass::UpperLetters)
182
        << to_flags(PasswordGenerator::GeneratorFlag::CharFromEveryGroup) << QString() << QString() << 1 << false;
183
    QTest::addRow("One from every class with excluded classes")
184
        << (PasswordGenerator::CharClass::LowerLetters | PasswordGenerator::CharClass::UpperLetters
185
            | PasswordGenerator::CharClass::Numbers)
186
        << to_flags(PasswordGenerator::GeneratorFlag::CharFromEveryGroup) << QString() << QString("0123456789") << 2
187
        << true;
188
    QTest::addRow("Defaults valid") << to_flags(PasswordGenerator::CharClass::DefaultCharset)
189
                                    << to_flags(PasswordGenerator::GeneratorFlag::DefaultFlags)
190
                                    << PasswordGenerator::DefaultCustomCharacterSet
191
                                    << PasswordGenerator::DefaultExcludedChars << PasswordGenerator::DefaultLength
192
                                    << true;
193
    QTest::addRow("No active classes but custom charset")
194
        << to_flags(PasswordGenerator::CharClass::NoClass) << to_flags(PasswordGenerator::GeneratorFlag::DefaultFlags)
195
        << QString("a") << QString() << 1 << true;
196
}
197

198
void TestPasswordGenerator::testValidity()
199
{
200
    QFETCH(PasswordGenerator::CharClasses, activeCharacterClasses);
201
    QFETCH(PasswordGenerator::GeneratorFlags, generatorFlags);
202
    QFETCH(QString, customCharacterSet);
203
    QFETCH(QString, excludedCharacters);
204
    QFETCH(int, length);
205
    QFETCH(bool, isValid);
206

207
    m_generator.setCharClasses(activeCharacterClasses);
208
    m_generator.setFlags(generatorFlags);
209
    m_generator.setCustomCharacterSet(customCharacterSet);
210
    m_generator.setExcludedCharacterSet(excludedCharacters);
211
    m_generator.setLength(length);
212
    QCOMPARE(m_generator.isValid(), isValid);
213
}
214

215
void TestPasswordGenerator::testMinLength_data()
216
{
217
    QTest::addColumn<PasswordGenerator::CharClasses>("activeCharacterClasses");
218
    QTest::addColumn<PasswordGenerator::GeneratorFlags>("generatorFlags");
219
    QTest::addColumn<QString>("customCharacterSet");
220
    QTest::addColumn<QString>("excludedCharacters");
221
    QTest::addColumn<int>("expectedMinLength");
222

223
    QTest::addRow("No restriction without charsFromEveryGroup")
224
        << to_flags(PasswordGenerator::CharClass::Numbers)
225
        << to_flags(PasswordGenerator::GeneratorFlag::CharFromEveryGroup)
226
        << PasswordGenerator::DefaultCustomCharacterSet << PasswordGenerator::DefaultExcludedChars << 1;
227

228
    QTest::addRow("Min length should equal number of active classes")
229
        << (PasswordGenerator::CharClass::LowerLetters | PasswordGenerator::CharClass::UpperLetters
230
            | PasswordGenerator::CharClass::Numbers)
231
        << to_flags(PasswordGenerator::GeneratorFlag::CharFromEveryGroup) << QString() << QString() << 3;
232
    QTest::addRow("Classes fully excluded by excluded characters do not count towards min length")
233
        << (PasswordGenerator::CharClass::Numbers | PasswordGenerator::LowerLetters
234
            | PasswordGenerator::CharClass::UpperLetters)
235
        << to_flags(PasswordGenerator::GeneratorFlag::CharFromEveryGroup) << QString() << QString("0123456789") << 2;
236

237
    QTest::addRow("Custom charset counts as class")
238
        << to_flags(PasswordGenerator::CharClass::UpperLetters)
239
        << to_flags(PasswordGenerator::GeneratorFlag::CharFromEveryGroup) << QString("a") << QString() << 2;
240
    QTest::addRow("Custom characters count even if included by an active class already")
241
        << (PasswordGenerator::CharClass::LowerLetters | PasswordGenerator::CharClass::UpperLetters
242
            | PasswordGenerator::CharClass::Numbers)
243
        << to_flags(PasswordGenerator::GeneratorFlag::CharFromEveryGroup) << QString("012345") << QString() << 4;
244
}
245

246
void TestPasswordGenerator::testMinLength()
247
{
248
    QFETCH(PasswordGenerator::CharClasses, activeCharacterClasses);
249
    QFETCH(PasswordGenerator::GeneratorFlags, generatorFlags);
250
    QFETCH(QString, customCharacterSet);
251
    QFETCH(QString, excludedCharacters);
252
    QFETCH(int, expectedMinLength);
253

254
    m_generator.setCharClasses(activeCharacterClasses);
255
    m_generator.setFlags(generatorFlags);
256
    m_generator.setCustomCharacterSet(customCharacterSet);
257
    m_generator.setExcludedCharacterSet(excludedCharacters);
258
    QCOMPARE(m_generator.getMinLength(), expectedMinLength);
259
}
260

261
void TestPasswordGenerator::testReset()
262
{
263
    PasswordGenerator default_generator;
264

265
    // Modify generator
266
    m_generator.setCharClasses(PasswordGenerator::CharClass::NoClass);
267
    m_generator.setFlags(PasswordGenerator::GeneratorFlag::NoFlags);
268
    m_generator.setCustomCharacterSet("avc");
269
    m_generator.setExcludedCharacterSet("asdv");
270
    m_generator.setLength(m_generator.getLength() + 1);
271

272
    Q_ASSERT(m_generator.getActiveClasses() != default_generator.getActiveClasses());
273
    Q_ASSERT(m_generator.getFlags() != default_generator.getFlags());
274
    Q_ASSERT(m_generator.getCustomCharacterSet() != default_generator.getCustomCharacterSet());
275
    Q_ASSERT(m_generator.getExcludedCharacterSet() != default_generator.getExcludedCharacterSet());
276

277
    m_generator.reset();
278
    QCOMPARE(m_generator.getActiveClasses(), default_generator.getActiveClasses());
279
    QCOMPARE(m_generator.getFlags(), default_generator.getFlags());
280
    QCOMPARE(m_generator.getCustomCharacterSet(), default_generator.getCustomCharacterSet());
281
    QCOMPARE(m_generator.getExcludedCharacterSet(), default_generator.getExcludedCharacterSet());
282
    QCOMPARE(m_generator.getLength(), default_generator.getLength());
283
}
284

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.