-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathComboPasswordStrength.php
More file actions
120 lines (99 loc) · 3.9 KB
/
ComboPasswordStrength.php
File metadata and controls
120 lines (99 loc) · 3.9 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
<?php
/**
* JBZoo Toolbox - Csv-Blueprint.
*
* This file is part of the JBZoo Toolbox project.
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*
* @license MIT
* @copyright Copyright (C) JBZoo.com, All rights reserved.
* @see https://github.com/JBZoo/Csv-Blueprint
*/
declare(strict_types=1);
namespace JBZoo\CsvBlueprint\Rules\Cell;
final class ComboPasswordStrength extends AbstractCellRuleCombo
{
protected const NAME = 'password strength';
public function getHelpMeta(): array
{
return [
[
'Password strength calculation criteria include: Length (max 5 points, +1 every 2 characters),',
'presence of uppercase letters (+1), lowercase letters (+1), numbers (+1), special characters (+1),',
'spaces (+1), and penalties for consecutive sequences of uppercase, lowercase, or',
'numbers (-0.5 each), repetitive sequences (-0.75 each), common weak passwords like "qwerty",',
'and passwords under 6 characters (-2). Adjust scores to a 0 to 10 scale, with a minimum score of 0.',
],
[
self::MIN => ['1', 'x >= 1'],
self::GREATER => ['2', 'x > 2'],
self::NOT => ['0', 'x != 0'],
self::EQ => ['7', 'x == 7'],
self::LESS => ['8', 'x < 8'],
self::MAX => ['9', 'x <= 9'],
],
];
}
/**
* Calculates the score of a password based on various criteria.
* Passwords are assigned a score ranging from 0 to 10, with higher scores indicating stronger passwords.
* @param string $password the password to calculate the score for
* @return int the score of the password on a scale of 0 to 10
*/
public static function passwordScore(string $password): int
{
$score = 0;
// Length: +1 point for every 2 characters, max 5 points
$score += \min(5, \strlen($password) / 2);
// Uppercase letters: +1 point if at least one
if (\preg_match('/[A-Z]/', $password) !== 0) { // NOSONAR
$score++;
}
// Lowercase letters: +1 point if at least one
if (\preg_match('/[a-z]/', $password) !== 0) { // NOSONAR
$score++;
}
// Numbers: +1 point if at least one
if (\preg_match('/\d/', $password) !== 0) {
$score++;
}
// Special characters: +1 point if at least one
if (\preg_match('/[^a-zA-Z0-9]/', $password) !== 0) { // NOSONAR
$score++;
}
if (\str_contains($password, ' ')) {
$score++;
}
// Additional complexity: consecutive uppercase, lowercase, or numerical sequences
// Deduct -0.75 point for each found, minimum score is 0
$deductions = 0;
if (\preg_match('/(.)\1+/', $password) !== 0) {
$deductions++;
}
$deductions += (int)\preg_match_all('/01|12|23|34|45|56|67|78|89|90/', $password);
$deductions += (int)\preg_match_all(
'/abc|bcd|cde|def|efg|fgh|ghi|hij|ijk|jkl|klm|lmn|mno|nop|opq|pqr|qrs|rst|stu|tuv|uvw|vwx|wxy|xyz/',
\strtolower($password),
);
if (\preg_match('/qwerty|pass|password/i', $password) !== 0) {
$deductions += 5;
}
$minLength = 6;
if (\strlen($password) < $minLength) {
$deductions += 2;
}
$score -= ($deductions * 0.75);
$score = \max(0, $score); // Ensure score does not go below 0
// Adjust to fit into 0 to 10 scale
return (int)\round($score, 0);
}
protected function getExpected(): float
{
return $this->getOptionAsInt();
}
protected function getActualCell(string $cellValue): float
{
return self::passwordScore($cellValue);
}
}