Skip to content

Commit d0376c1

Browse files
committed
Created check-password.py
1 parent 06c01ad commit d0376c1

File tree

1 file changed

+257
-0
lines changed

1 file changed

+257
-0
lines changed

Password-Checker/check-password.py

Lines changed: 257 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,257 @@
1+
#!/usr/bin/env python
2+
import re
3+
import sys
4+
import random
5+
from getpass import getpass
6+
7+
# ANSI escape codes for colors
8+
COLOR = {
9+
"RED": '\033[91m',
10+
"YELLOW": '\033[93m',
11+
"GREEN": '\033[92m',
12+
"BLUE": '\033[94m',
13+
"RESET": '\033[0m'
14+
}
15+
16+
KEYBOARD_PATTERNS = ['qwerty', 'asdfgh', 'zxcvbn']
17+
COMMON_SUBSTITUTIONS = {
18+
'@': 'a', '4': 'a', '3': 'e', '0': 'o',
19+
'1': 'i', '$': 's', '7': 't'
20+
}
21+
22+
COMMON_WORDS = {
23+
'adjectives': ['Happy', 'Clever', 'Swift', 'Brave', 'Bright'],
24+
'nouns': ['Tiger', 'River', 'Mountain', 'Storm', 'Star'],
25+
'numbers': ['365', '42', '777', '314', '999'],
26+
'separators': ['_', '.', '#', '*', '@']
27+
}
28+
29+
PATTERNS = {
30+
'uppercase': re.compile(r'[A-Z]'),
31+
'lowercase': re.compile(r'[a-z]'),
32+
'numbers': re.compile(r'\d'),
33+
'special': re.compile(r'[!@#$%^&*(),.?":{}|<>]')
34+
}
35+
36+
37+
def format_to_header(
38+
msg: str,
39+
*,
40+
rep: float = 1,
41+
new_line_at_end: bool = False,
42+
is_main_header: bool = False):
43+
if not isinstance(msg, str):
44+
raise TypeError("msg must be a string")
45+
46+
res_str = "\n"
47+
no_of_hypens = int(len(msg)*rep)
48+
49+
if is_main_header:
50+
no_of_hypens += 4
51+
msg = f"| {msg.upper()} |"
52+
53+
header_str = [
54+
'-'*no_of_hypens,
55+
msg,
56+
'-'*no_of_hypens,
57+
]
58+
59+
res_str += "\n".join(header_str)
60+
if new_line_at_end:
61+
res_str += "\n"
62+
return res_str
63+
64+
65+
def check_password_strength(password):
66+
score = 0
67+
suggestions = []
68+
69+
# Check length
70+
if len(password) < 12:
71+
suggestions.append("Password should be at least 12 characters long.")
72+
elif len(password) >= 16:
73+
score += 2
74+
else:
75+
score += 1
76+
77+
# Check for uppercase
78+
if not PATTERNS['uppercase'].search(password):
79+
suggestions.append("Add uppercase letters.")
80+
else:
81+
score += 1
82+
83+
# Check for lowercase
84+
if not PATTERNS['lowercase'].search(password):
85+
suggestions.append("Add lowercase letters.")
86+
else:
87+
score += 1
88+
89+
# Check for numbers
90+
if not PATTERNS['numbers'].search(password):
91+
suggestions.append("Add numbers.")
92+
else:
93+
score += 1
94+
95+
# Check for special characters
96+
if not PATTERNS['special'].search(password):
97+
suggestions.append("Add special characters.")
98+
else:
99+
score += 1
100+
101+
# Check for repeated patterns (like 'testtest')
102+
half_length = len(password) // 2
103+
for i in range(2, half_length + 1):
104+
if password[:i] * (len(password) // i) == password[:len(password) // i * i]:
105+
suggestions.append("Avoid repeating patterns in your password.")
106+
score -= 1
107+
break
108+
109+
# Check for keyboard patterns
110+
lower_pass = password.lower()
111+
for pattern in KEYBOARD_PATTERNS:
112+
if pattern in lower_pass:
113+
suggestions.append("Avoid common keyboard patterns")
114+
score -= 1
115+
break
116+
117+
# Check for simple character substitutions
118+
substituted = password.lower()
119+
for k, v in COMMON_SUBSTITUTIONS.items():
120+
substituted = substituted.replace(k, v)
121+
if substituted.isalpha() and len(substituted) > 3:
122+
suggestions.append(
123+
"Using symbol substitutions (like '@' for 'a') isn't very secure.")
124+
score -= 1
125+
126+
# Ensure score doesn't go below 0
127+
score = max(0, score)
128+
129+
return score, suggestions
130+
131+
132+
def categorize_password(score):
133+
if score < 2:
134+
return "WEAK", COLOR["RED"]
135+
if score < 4:
136+
return "GOOD", COLOR["YELLOW"]
137+
return "STRONG", COLOR["GREEN"]
138+
139+
140+
def create_memorable_suggestion(base_word):
141+
adj = random.choice(COMMON_WORDS['adjectives'])
142+
noun = random.choice(COMMON_WORDS['nouns'])
143+
num = random.choice(COMMON_WORDS['numbers'])
144+
sep = random.choice(COMMON_WORDS['separators'])
145+
146+
# Use the base word if it's good enough (not too short and has letters)
147+
if len(base_word) >= 4 and any(c.isalpha() for c in base_word):
148+
base = base_word.capitalize()
149+
else:
150+
base = noun
151+
152+
patterns = [
153+
f"{adj}{sep}{base}{num}",
154+
f"{base}{sep}{noun}{num}",
155+
f"{num}{sep}{adj}{base}"
156+
]
157+
158+
return random.choice(patterns)
159+
160+
161+
def suggest_better_password(password):
162+
# If password is very weak, create a completely new memorable one
163+
score, _ = check_password_strength(password)
164+
if score < 2:
165+
return create_memorable_suggestion(password)
166+
167+
suggestion = password
168+
169+
# Smart character substitutions (maintain readability)
170+
smart_subs = {
171+
'a': '@', 'e': '3', 'i': '!', 'o': '0', 's': '$',
172+
'ate': '8', 'to': '2', 'for': '4'
173+
}
174+
175+
# Apply substitutions intelligently
176+
for word, replacement in smart_subs.items():
177+
if word in suggestion.lower() and random.random() < 0.5: # 50% chance
178+
suggestion = suggestion.replace(word, replacement)
179+
180+
# Ensure at least one capital letter in a natural position
181+
if not any(c.isupper() for c in suggestion):
182+
words = suggestion.split()
183+
if words:
184+
words[0] = words[0].capitalize()
185+
suggestion = ''.join(words)
186+
187+
# Add complexity if needed while keeping it memorable
188+
if len(suggestion) < 12:
189+
suggestion += random.choice(COMMON_WORDS['numbers'])
190+
191+
if not re.search(r'[!@#$%^&*(),.?":{}|<>]', suggestion):
192+
suggestion += random.choice(COMMON_WORDS['separators'])
193+
194+
return suggestion
195+
196+
197+
def input_handler():
198+
if len(sys.argv) > 1:
199+
password = sys.argv[1]
200+
print(
201+
f"{COLOR['RED']}It is recommended to avoid entering passwords directly on the command line,{COLOR['RESET']}")
202+
print(
203+
f"{COLOR['RED']}as they may be visible to others and recorded in the shell history.{COLOR['RESET']}")
204+
return password
205+
print(
206+
format_to_header(
207+
"Password Strength Checker",
208+
new_line_at_end=True,
209+
is_main_header=True
210+
)
211+
)
212+
print("For enhanced security, your input will be hidden.")
213+
print("Hence, you may not see the characters as you type.")
214+
try:
215+
password = getpass("\nEnter password to check: ")
216+
except KeyboardInterrupt:
217+
print("\nExiting...")
218+
sys.exit(0)
219+
return password
220+
221+
222+
def output_handler(password, category, color, suggestions):
223+
print(f"\nPassword Strength: {color}{category}{COLOR['RESET']}")
224+
225+
if suggestions:
226+
print(format_to_header("Suggestions to improve:"))
227+
for suggestion in suggestions:
228+
print(f"{COLOR['BLUE']}- {suggestion}{COLOR['RESET']}")
229+
230+
# Add this block to show suggested password
231+
if category != "STRONG":
232+
better_password = suggest_better_password(password)
233+
print(
234+
f"\nSuggested stronger password: {COLOR['GREEN']}{better_password}{COLOR['RESET']}")
235+
236+
points_to_remember = [
237+
"Never use your personal information while creating a password.",
238+
"Consider using a passphrase made up of multiple words for better security.",
239+
"Avoid using common phrases or easily guessable patterns.",
240+
"Avoid using the same password for multiple accounts.",
241+
"Regularly update your passwords to enhance security.",
242+
"Use a reputable password manager to generate and store complex passwords securely."
243+
]
244+
print(format_to_header('Points to Remember:'))
245+
for points in points_to_remember:
246+
print(f"{COLOR['BLUE']}- {points}{COLOR['RESET']}")
247+
248+
249+
def main():
250+
password = input_handler()
251+
score, suggestions = check_password_strength(password)
252+
category, color = categorize_password(score)
253+
output_handler(password, category, color, suggestions)
254+
255+
256+
if __name__ == "__main__":
257+
main()

0 commit comments

Comments
 (0)