forked from pinae/ctSESAM-pyside
-
Notifications
You must be signed in to change notification settings - Fork 0
/
password_strength_selector.py
180 lines (157 loc) · 6.37 KB
/
password_strength_selector.py
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
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
#!/usr/bin/python3
# -*- coding: utf-8 -*-
from PySide import QtGui, QtCore
import math
class PasswordStrengthSelector(QtGui.QWidget, object):
strength_changed = QtCore.Signal((int, int))
"""
This Widget is used for selecting a password strength. The x direction implies the length of the password while
the y direction expresses the complexity in 6 steps.
"""
def __init__(self):
super(PasswordStrengthSelector, self).__init__()
self.setMinimumSize(8, 8)
self.min_length = 4
self.max_length = 10
self.length = 0
self.complexity = -1
self.color_matrix = []
self.digit_count = 10
self.lower_count = 36
self.upper_count = 36
self.extra_count = 24
self.calculate_width()
def set_min_length(self, min_length):
"""
Sets the minimum password length. This also changes the minimum size of the widget.
:param min_length: minimum password length
:type min_length: int
"""
self.min_length = min_length
self.calculate_width()
def set_max_length(self, max_length):
"""
Sets the maximum password length. This also changes the minimum size of the widget.
:param max_length: maximum password length
:type max_length: int
"""
self.max_length = max_length
self.calculate_width()
def set_extra_count(self, extra_count):
"""
Sets the number of extra characters. This is used for the coloring.
:param extra_count: number of extra characters
:type extra_count: int
"""
self.extra_count = extra_count
self.calculate_width()
self.repaint()
def calculate_width(self):
"""
Calculate the minimum width and the color matrix
"""
self.setMinimumWidth(self.max_length - self.min_length)
self.color_matrix = []
complexity = [self.digit_count,
self.lower_count,
self.upper_count,
self.digit_count + self.lower_count,
self.lower_count + self.upper_count,
self.lower_count + self.upper_count + self.digit_count,
self.lower_count + self.upper_count + self.digit_count + self.extra_count]
complexity.reverse()
for i in range(self.max_length-self.min_length+1):
line = []
for comp in complexity:
s = 20
tianhe2_years = (pow(comp, (i+self.min_length))*0.4/3120000)/(60*60*24*365)
strength_red = 1-s/(s+math.log(tianhe2_years+1, 50))
strength_green = 1-s/(s+math.log(tianhe2_years+1, 1.2))
color = QtGui.QColor(int(round(215*(1.0-strength_red))), int(round(190*strength_green)), 0)
line.append(color)
self.color_matrix.append(line)
def paintEvent(self, *args):
qp = QtGui.QPainter()
qp.begin(self)
self.draw(qp)
qp.end()
def draw(self, qp):
size = self.size()
x_coords = [0, size.width()-1]
for i in range(1, self.max_length-self.min_length+1):
x_coords.insert(-1, int(round(i*(size.width()-1)/(self.max_length-self.min_length+1))))
y_coords = [0, size.height()-1]
for i in range(1, 7):
y_coords.insert(-1, int(round(i*(size.height()-1)/7)))
for i in range(1, len(x_coords)):
for j in range(1, len(y_coords)):
color = self.color_matrix[i-1][j-1]
pen = QtGui.QPen(color, 1, QtCore.Qt.SolidLine)
qp.setPen(pen)
qp.setBrush(color)
qp.drawRect(x_coords[i-1], y_coords[j-1], x_coords[i]-x_coords[i-1], y_coords[j]-y_coords[j-1])
pen = QtGui.QPen(QtGui.QColor(140, 140, 140), 1, QtCore.Qt.SolidLine)
qp.setPen(pen)
qp.setBrush(QtCore.Qt.NoBrush)
qp.drawRect(0, 0, size.width()-1, size.height()-1)
if self.length > 0 and self.complexity >= 0:
pen = QtGui.QPen(QtGui.QColor(0, 0, 0), 1, QtCore.Qt.SolidLine)
qp.setPen(pen)
qp.setBrush(QtCore.Qt.NoBrush)
qp.drawRect(x_coords[self.length-self.min_length],
y_coords[6-self.complexity],
x_coords[self.length-self.min_length+1]-x_coords[self.length-self.min_length],
y_coords[7-self.complexity]-y_coords[6-self.complexity])
def mousePressEvent(self, event):
size = self.size()
self.length = max(
self.min_length,
min(self.max_length,
int(math.floor(event.pos().x()/(size.width()-2) *
(self.max_length-self.min_length+1) +
self.min_length))))
self.complexity = max(0, min(6, int(math.floor(7-event.pos().y()/(size.height()-2)*7))))
self.repaint()
self.strength_changed.emit(self.complexity, self.length)
def mouseMoveEvent(self, event):
self.mousePressEvent(event)
def get_length(self):
"""
Returns the selected length. If no length is selected it returns 0.
:return: selected length
:rtype: int
"""
return self.length
def set_length(self, length):
"""
Sets the length. If smaller than min_length or negative or bigger than max_length the selection is removed.
:param length: new length or 0 for no selection
:type length: int
"""
if self.min_length <= length <= self.max_length:
self.length = length
else:
self.length = 0
self.complexity = -1
self.repaint()
self.strength_changed.emit(self.complexity, self.length)
def get_complexity(self):
"""
Returns the complexity or -1 if nothing is selected.
:return: selected complexity
:rtype: int
"""
return self.complexity
def set_complexity(self, complexity):
"""
Sets the complexity if in the range 0-6 or removes the selection otherwise.
:param complexity: complexity if in the range 0-6
:type complexity: int
"""
if 0 <= complexity <= 6:
self.complexity = complexity
else:
self.complexity = -1
self.length = 0
self.repaint()
self.strength_changed.emit(self.complexity, self.length)