Skip to content

Commit

Permalink
Colorize Strengthbar; closes #10
Browse files Browse the repository at this point in the history
- Use color different colors for bar and comment
- Update UI
  • Loading branch information
hsbasu committed Feb 7, 2022
2 parents a076291 + 99632e6 commit 292c5d9
Show file tree
Hide file tree
Showing 5 changed files with 490 additions and 28 deletions.
172 changes: 155 additions & 17 deletions usr/lib/simple-pwgen/common.py
100755 → 100644
Original file line number Diff line number Diff line change
Expand Up @@ -26,11 +26,12 @@
import configparser
import gettext
import locale
import math
import os
import random
import string
import threading
from gi.repository import GObject
from string import ascii_uppercase, ascii_lowercase, digits, punctuation


# Used as a decorator to run things in the background
Expand Down Expand Up @@ -62,7 +63,7 @@ def wrapper(*args):


# This is the backend.
# It contains utility functions generate
# It contains utility functions to generate
# passwords.
class PasswordGenerator():

Expand All @@ -78,6 +79,7 @@ def __init__(self):

self.config = configparser.ConfigParser()
self.save_config()
self.pool = ascii_lowercase+ascii_uppercase+digits+punctuation

def load_config(self):
"""Loads configurations from config file.
Expand Down Expand Up @@ -189,7 +191,7 @@ def includeonlyChars(self):

if self.lowercase == True:
if self.lowercase_num >0:
Lowercaselist = list(string.ascii_lowercase)
Lowercaselist = list(ascii_lowercase)
excludelist = list(self.excludeLowercase)
for i in excludelist:
del(Lowercaselist[Lowercaselist.index(i)])
Expand All @@ -199,7 +201,7 @@ def includeonlyChars(self):

if self.uppercase == True:
if self.uppercase_num >0:
Uppercaselist = list(string.ascii_uppercase)
Uppercaselist = list(ascii_uppercase)
excludelist = list(self.excludeUppercase)
for i in excludelist:
del(Uppercaselist[Uppercaselist.index(i)])
Expand All @@ -209,7 +211,7 @@ def includeonlyChars(self):

if self.digit == True:
if self.digit_num >0:
Digitslist = list(string.digits)
Digitslist = list(digits)
excludelist = list(self.excludeDigit)
for i in excludelist:
del(Digitslist[Digitslist.index(i)])
Expand All @@ -219,7 +221,7 @@ def includeonlyChars(self):

if self.symbol == True:
if self.symbol_num >0:
Symbollist = list(string.punctuation)
Symbollist = list(punctuation)
excludelist = list(self.excludeSymbol)
for i in excludelist:
del(Symbollist[Symbollist.index(i)])
Expand Down Expand Up @@ -305,32 +307,168 @@ def GeneratePW(self):
includechars = PasswordGenerator.includeonlyChars(self)
includecases = PasswordGenerator.includeCases(self, self.pwlength)

pool = "".join(includechars["Lowercases"] + includechars["Uppercases"] + includechars["Digits"] + includechars["Symbols"]) # don't include symbol
self.pool = "".join(includechars["Lowercases"] + includechars["Uppercases"] + includechars["Digits"] + includechars["Symbols"])

password = '' # empty string for password

for i in range(self.pwlength):
if i in includecases["Lowercases"]: # this is to ensure there is at least one uppercase
# this is to ensure there is minimum number of lowercases desired by user
if i in includecases["Lowercases"]:
password += self.TrueRand.choice(includechars["Lowercases"])

elif i in includecases["Uppercases"]: # this is to ensure there is at least one uppercase
# this is to ensure there is minimum number of uppercases desired by user
elif i in includecases["Uppercases"]:
password += self.TrueRand.choice(includechars["Uppercases"])

elif i in includecases["Digits"]: # this is to ensure there is at least one uppercase
# this is to ensure there is minimum number of digits desired by user
elif i in includecases["Digits"]:
password += self.TrueRand.choice(includechars["Digits"])

elif i in includecases["Symbols"]: # this is to ensure there is at least one symbol
# this is to ensure there is minimum number of symbols/characters desired by user
elif i in includecases["Symbols"]:
password += self.TrueRand.choice(includechars["Symbols"])

else: # adds a random character from pool
password += self.TrueRand.choice(pool)

# password=self.TrueRand.choice(password)

password += self.TrueRand.choice(self.pool)

# shuffle the password again
password = list(password)
random.shuffle(password)
password = ''.join(password)

return password # returns the password string

def check_pwstrength(self, passwd):
score = 0
comment = _("Bad Password.")
if len(passwd) <6:
comment += _(" Password is too short!")
score += 0
elif len(passwd) <8:
score += 20
elif len(passwd) <10:
score += 40
else:
score += 60

if any(c in ascii_lowercase for c in passwd):
# check for lower case in password
score += 10
if passwd == passwd.lower():
# check if password is only lower case
comment += _(" Only lower case used.")
score -= 5
else:
comment += _(" No lower case used.")

if any(c in ascii_uppercase for c in passwd):
# check for upper case in password
score += 10
if passwd == passwd.upper():
# check if password is only upper case
comment += _(" Only UPPER case used.")
score -= 5
else:
comment += _(" No UPPER case used.")

if any(c in punctuation for c in passwd):
score += 10
else:
comment += _(" No special character used.")

if any(c in digits for c in passwd):
# check for digits in password
score += 10
if passwd.isdigit():
# check if password is only digit
comment += _(" Only digits used. Is It a PIN?")
score -= 5
else:
comment += _(" No digit used.")

if (score >90):
comment = _("Looks like you know how to generate a Good Password. All types of characters are used.")

if score <=10:
color = "#ff0000"
elif score > 10 and score <=20:
color = "#ff6a00"
elif score > 20 and score <=30:
color = "#ffd500"
elif score > 30 and score <=40:
color = "#bfff00"
elif score > 40 and score <=50:
color = "#55ff00"
elif score > 50 and score <=60:
color = "#00ff15"
elif score > 60 and score <=70:
color = "#00ff80"
elif score > 70 and score <=80:
color = "#00ffea"
elif score > 80 and score <=90:
color = "#00aaff"
elif score > 90 and score <=100:
color = "#0040ff"

return [score, comment, color]

def check_pwentrpy(self, passwd):
strength_comment = ["Very Weak", "Weak", "Reasonable", "Fairly Strong", "Strong", "Very Strong", "Super Strong"]
length = len(passwd)
pool_size = len(self.pool)
entropy = length*math.log2(pool_size)
strength = strength_comment[0]

if entropy < 28:
# Might keep out family members
strength = strength_comment[0]
elif (entropy >= 28 and entropy < 36):
# Should keep out most people, often good for desktop login passwords
strength = strength_comment[1]
elif (entropy >= 36 and entropy < 64):
# Fairly secure passwords for network and company passwords
strength = strength_comment[2]
elif (entropy >= 64 and entropy < 80):
# Suitable for guarding financial information
strength = strength_comment[3]
elif (entropy >= 80 and entropy < 100):
# Suitable for guarding financial information
strength = strength_comment[4]
elif (entropy >= 100 and entropy < 128):
# Suitable for guarding financial information
strength = strength_comment[5]
elif entropy >= 128:
# Suitable for guarding financial information
strength = strength_comment[6]

num_guess = round(pow(2, (entropy-1)))
timerq_sc = num_guess/1e15 # Time taken by a modern supecomputer to guess the password with 50% probability
if (num_guess > 1e8):
# in case number of guess is greater than 1e8, use scientific notation
num_guess = "{:e}".format(num_guess)

minute, secnd = divmod(timerq_sc, 60)
hour, minute = divmod(minute, 60)
day, hour = divmod(hour, 24)
month, day = divmod(day, 30)
year, month = divmod(month, 12)
timerq = _("%s years %s months %s days %s hours %s minutes %s seconds") % (year, month, day, hour, minute, secnd)

return [strength, entropy, num_guess, timerq]

if __name__ == "__main__":
generator = PasswordGenerator()
passw = generator.GeneratePW()
print(passw)
passwd = generator.GeneratePW()
[pw_score, pw_comment, color] = generator.check_pwstrength(passwd)
[pw_strength, pw_entropy, num_guess_crack, timerq_crack] = generator.check_pwentrpy(passwd)

print("Generated Password: "+str(passwd))
print("")
print("Strength: "+str(pw_strength))
print("Score: "+str(pw_score))
print("Entropy: "+str(pw_entropy))
print("Number of Guesses: "+str(num_guess_crack))
print("Time required to crack: "+str(timerq_crack))
print("Comment: "+str(pw_comment))
print("")

40 changes: 37 additions & 3 deletions usr/lib/simple-pwgen/simple-pwgen.py
100755 → 100644
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,13 @@ def __init__(self, application):

# output values
self.passwordfield = self.builder.get_object("passwordfield")
self.strength_bar = self.builder.get_object("strength_bar")
self.pw_strength_field = self.builder.get_object("pw_strength_field")
self.pw_score_field = self.builder.get_object("pw_score_field")
self.pw_guesses_field = self.builder.get_object("pw_guesses_field")
self.pw_entropy_field = self.builder.get_object("pw_entropy_field")
self.pw_crack_time_field = self.builder.get_object("pw_crack_time_field")
self.pw_comment_field = self.builder.get_object("pw_comment_field")

# Buttons
self.reset_button = self.builder.get_object("reset_button")
Expand All @@ -114,6 +121,7 @@ def __init__(self, application):
self.showhide_button.connect("clicked", self.on_showhide_button)
self.copy_button.connect("clicked", self.on_copy_button)
self.quit_button.connect("clicked", self.on_quit)
self.passwordfield.connect("changed", self.show_pwstrength)

# Menubar
accel_group = Gtk.AccelGroup()
Expand All @@ -132,7 +140,7 @@ def __init__(self, application):
item.set_image(Gtk.Image.new_from_icon_name("help-about-symbolic", Gtk.IconSize.MENU))
item.set_label(_("About"))
item.connect("activate", self.open_about)
key, mod = Gtk.accelerator_parse("F1")
key, mod = Gtk.accelerator_parse("<Control>F1")
item.add_accelerator("activate", accel_group, key, mod, Gtk.AccelFlags.VISIBLE)
menu.append(item)
# Add "Quit" option in drop-down menu
Expand All @@ -149,6 +157,7 @@ def __init__(self, application):
menu.show_all()

self.load_conf()
self.load_css(color="inherit")

def load_conf(self):

Expand Down Expand Up @@ -195,7 +204,6 @@ def load_conf(self):
self.minsymbol_num.set_sensitive(True)
self.excludesymbol_field.set_sensitive(True)

@staticmethod
def open_keyboard_shortcuts(self, widget):
gladefile = "/usr/share/simple-pwgen/shortcuts.ui"
builder = Gtk.Builder()
Expand All @@ -216,7 +224,7 @@ def open_about(self, widget):
dlg.set_version("__DEB_VERSION__")
dlg.set_comments(_("Very simple Python3-based GUI application to generate secure and random password."))
dlg.set_website("https://hsbasu.github.io/simple-pwgen")
dlg.set_copyright("Copyright \xa9 2021 Himadri Sekhar Basu")
dlg.set_copyright("Copyright \xa9 2022 Himadri Sekhar Basu")
dlg.set_authors(["Himadri Sekhar Basu <https://hsbasu.github.io>"])
dlg.set_documenters(["Himadri Sekhar Basu <https://hsbasu.github.io>"])
try:
Expand Down Expand Up @@ -331,6 +339,32 @@ def on_copy_button(self, widget):
self.clipboard = Gtk.Clipboard.get(Gdk.SELECTION_CLIPBOARD)
self.clipboard.set_text(self.password, -1)

def load_css(self, color: str):
css_provider = Gtk.CssProvider()
Priority = Gtk.STYLE_PROVIDER_PRIORITY_USER
css = open('/usr/share/simple-pwgen/style.css', 'r')
css_rawdata = css.read() % (color, color)
# print(css_rawdata)
css_data = bytes(css_rawdata, 'utf-8')
css.close()
css_provider.load_from_data(css_data)
Gtk.StyleContext.add_provider_for_screen(Gdk.Screen.get_default(), css_provider, Priority)

def show_pwstrength(self, widget):
password = self.passwordfield.get_text()
[pw_score, pw_comment, color] = self.generator.check_pwstrength(password)
[pw_strength, pw_entropy, num_guess_crack, timerq_crack] = self.generator.check_pwentrpy(password)

self.load_css(color)

self.strength_bar.set_value(pw_score/10)
self.pw_strength_field.set_text(pw_strength)
self.pw_score_field.set_text(str(pw_score))
self.pw_guesses_field.set_text(str(num_guess_crack))
self.pw_entropy_field.set_text(str(pw_entropy))
self.pw_crack_time_field.set_text(str(timerq_crack))
self.pw_comment_field.set_text(pw_comment)


if __name__ == "__main__":
application = simple_pwgen("org.x.simple-pwgen", Gio.ApplicationFlags.FLAGS_NONE)
Expand Down
22 changes: 21 additions & 1 deletion usr/share/simple-pwgen/shortcuts.ui
Original file line number Diff line number Diff line change
Expand Up @@ -62,14 +62,34 @@ Author: Himadri Sekhar Basu <hsb10@iitbbs.ac.in>
</child>
</object>
</child>
<child>
<object class="GtkShortcutsGroup">
<property name="visible">1</property>
<property name="title" translatable="yes">Settings</property>
<child>
<object class="GtkShortcutsShortcut">
<property name="visible">1</property>
<property name="accelerator">&lt;ctrl&gt;R</property>
<property name="title" translatable="yes">Reset</property>
</object>
</child>
<child>
<object class="GtkShortcutsShortcut">
<property name="visible">1</property>
<property name="accelerator">&lt;ctrl&gt;S</property>
<property name="title" translatable="yes">Save</property>
</object>
</child>
</object>
</child>
<child>
<object class="GtkShortcutsGroup">
<property name="visible">1</property>
<property name="title" translatable="yes">Other Shortcuts</property>
<child>
<object class="GtkShortcutsShortcut">
<property name="visible">1</property>
<property name="accelerator">F1</property>
<property name="accelerator">&lt;ctrl&gt;F1</property>
<property name="title" translatable="yes">About</property>
</object>
</child>
Expand Down
Loading

0 comments on commit 292c5d9

Please sign in to comment.