#!/usr/bin/env python3 import string import random import easymacro as app from stats import PasswordStats _ = None PREFIX = 'zazpass' DEFAULT_LENGTH = 25 DEFAULT_CHARACTERS = ( string.ascii_uppercase + string.ascii_lowercase + string.digits + string.punctuation) def main(id_extension, args, path_locales): global _ if args == 'insert': _password_insert() return if args == 'copy': _password_copy() return _ = app.install_locales(path_locales) _password_generate(id_extension) return def _from_config(): characters = '' config = app.get_config('setting', PREFIX) length = config.get('length', DEFAULT_LENGTH) if config: if config['letters']: characters += string.ascii_uppercase if config['letters2']: characters += string.ascii_lowercase if config['digits']: characters += string.digits if config['punctuation']: characters += string.punctuation else: characters = DEFAULT_CHARACTERS return list(characters), length def _from_controls(dialog): characters = '' length = int(dialog.txt_length.value) if dialog.chk_letters.value: characters += string.ascii_uppercase if dialog.chk_letters2.value: characters += string.ascii_lowercase if dialog.chk_digits.value: characters += string.digits if dialog.chk_punctuation.value: characters += string.punctuation if not characters: dialog.chk_letters.value = True characters = string.ascii_uppercase return list(characters), length def _get_data(dialog): if dialog is None: characters, lenght = _from_config() else: characters, lenght = _from_controls(dialog) return characters, lenght def _generate(dialog=None): characters, length = _get_data(dialog) random.shuffle(characters) password = [random.choice(characters) for i in range(length)] random.shuffle(password) password = ''.join(password) return password def _password_insert(): for cell in app.selection: cell.str = _generate() return def _password_copy(): app.clipboard.set(_generate()) return def _get_quality(strength): if strength <= 0.33: quality = _('Week') elif strength <= 0.66: quality = _('Medium') else: quality = _('Excellent') return quality def _password_generate(id_extension): config = app.get_config('setting', prefix=PREFIX) dialog = _create_dialog(id_extension) length = config.get('length', DEFAULT_LENGTH) letters = True letters2 = True digits = True punctuation = True if config: letters = config['letters'] letters2 = config['letters2'] digits = config['digits'] punctuation = config['punctuation'] dialog.chk_letters.value = letters dialog.chk_letters2.value = letters2 dialog.chk_digits.value = digits dialog.chk_punctuation.value = punctuation dialog.txt_length.value = length stats = PasswordStats(_generate(dialog)) dialog.txt_password.value = stats.password dialog.lbl_quality.value = _get_quality(stats.strength()) dialog.open() return class Controllers(object): def __init__(self, dialog): self.d = dialog def cmd_close_action(self, event): self.d.close() return def cmd_switch_action(self, event): char = self.d.txt_password.echochar name_image = 'eye-close.svg' if char == '*': self.d.txt_password.echochar = '' name_image = 'eye-open.svg' else: self.d.txt_password.echochar = '*' path_image = app.paths.join(self.d.path_images, name_image) self.d.cmd_switch.image = path_image self.d.txt_password.set_focus() return def cmd_insert_action(self, event): for cell in app.selection: cell.str = self.d.txt_password.value self.d.close() return def _save_config(self): data = dict( length = self.d.txt_length.int, letters = self.d.chk_letters.value, letters2 = self.d.chk_letters2.value, digits = self.d.chk_digits.value, punctuation = self.d.chk_punctuation.value, ) app.set_config('setting', data, PREFIX) return def _new_password(self, save=True): stats = PasswordStats(_generate(self.d)) self.d.txt_password.value = stats.password self.d.lbl_quality.value = _get_quality(stats.strength()) if save: self._save_config() return def cmd_new_action(self, event): self._new_password(False) return def txt_length_after_click(self, event): self._new_password() return def chk_letters_after_click(self, event): self._new_password() return def chk_letters2_after_click(self, event): self._new_password() return def chk_digits_after_click(self, event): self._new_password() return def chk_punctuation_after_click(self, event): self._new_password() return @app.catch_exception def _create_dialog(id_extension): BUTTON_WH = 16 CHK_HEIGHT = 10 CHK_WIDTH = 25 attr = dict( Name = 'Dialog', Title = _('Generate Password'), Width = 200, Height = 120, ) dialog = app.create_dialog(attr) dialog.id = id_extension dialog.events = Controllers attr = dict( Type = 'Text', Name = 'txt_password', Width = 150, Height = 12, X = 5, Y = 10, EchoChar = ord('*'), ) dialog.add_control(attr) attr = dict( Type = 'Button', Name = 'cmd_switch', Width = BUTTON_WH, Height = BUTTON_WH, ImageURL = 'eye-close.svg', FocusOnClick = True, ) dialog.add_control(attr) attr = dict( Type = 'Button', Name = 'cmd_new', Width = BUTTON_WH, Height = BUTTON_WH, ImageURL = 'new.svg', ) dialog.add_control(attr) attr = dict( Type = 'Label', Name = 'lbl_title_length', Label = _('Length: '), Width = 50, Height = BUTTON_WH, Border = 1, Align = 2, VerticalAlign = 1, ) dialog.add_control(attr) attr = dict( Type = 'Numeric', Name = 'txt_length', Width = 50, Height = BUTTON_WH, DecimalAccuracy = 0, Spin = True, Value = 25, ValueStep = 1, ValueMin = 5, ValueMax = 100, ) dialog.add_control(attr) attr = dict( Type = 'CheckBox', Name = 'chk_letters', Label = 'A-Z', Width = CHK_WIDTH, Height = CHK_HEIGHT, ) dialog.add_control(attr) attr = dict( Type = 'CheckBox', Name = 'chk_letters2', Label = 'a-z', Width = CHK_WIDTH, Height = CHK_HEIGHT, ) dialog.add_control(attr) attr = dict( Type = 'CheckBox', Name = 'chk_digits', Label = '0-9', Width = CHK_WIDTH, Height = CHK_HEIGHT, ) dialog.add_control(attr) attr = dict( Type = 'CheckBox', Name = 'chk_punctuation', Label = string.punctuation, Width = CHK_WIDTH * 4, Height = CHK_HEIGHT, ) dialog.add_control(attr) attr = dict( Type = 'Label', Name = 'lbl_title_quality', Label = _('Password Quality:'), Width = 75, Height = BUTTON_WH, Border = app.Border.BORDER, Align = app.RIGHT, VerticalAlign = app.MIDDLE, ) dialog.add_control(attr) attr = dict( Type = 'Label', Name = 'lbl_quality', Label = _('Poor'), Width = 35, Height = BUTTON_WH, Border = app.Border.BORDER, Align = app.CENTER, VerticalAlign = app.MIDDLE, ) dialog.add_control(attr) attr = dict( Type = 'Button', Name = 'cmd_insert', Label = _('~Insert'), Width = 70, Height = BUTTON_WH, ImageURL = 'insert.svg', ImagePosition = 1, ) dialog.add_control(attr) attr = dict( Type = 'Button', Name = 'cmd_close', Label = _('~Close'), Width = 70, Height = BUTTON_WH, ImageURL = 'close.svg', ImagePosition = 1, ) dialog.add_control(attr) dialog.cmd_switch.move(dialog.txt_password, x=3, y=-2) dialog.cmd_new.move(dialog.cmd_switch, x=3, y=0) dialog.lbl_title_length.move(dialog.txt_password) dialog.txt_length.move(dialog.lbl_title_length, x=3, y=0) dialog.chk_letters.move(dialog.lbl_title_length) dialog.chk_letters2.move(dialog.chk_letters, x=3, y=0) dialog.chk_digits.move(dialog.chk_letters2, x=3, y=0) dialog.chk_punctuation.move(dialog.chk_digits, x=3, y=0) dialog.lbl_title_quality.move(dialog.chk_letters) dialog.lbl_quality.move(dialog.lbl_title_quality, x=3, y=0) dialog.center(dialog.cmd_insert, y=-5) dialog.center(dialog.cmd_close, y=-5) dialog.center((dialog.cmd_close, dialog.cmd_insert)) return dialog