Генератор паролей на python
Не так давно стал изучать python и сейчас пытаюсь сделать первый пет-проект как генератор паролей. Основную функцию выполняет хорошо, но развить его дальше не могу. Мне нужно, чтобы изначально был выбор: сделать пароль автоматически, либо самостоятельно указывать необходимые регистры(цифры, буквы заглавные/прописные, спец. символы). Изначально делал на обычных if, сейчас пробую реализовать через for, но что-то делаю неверно и в итоге приходится постоянно лично указывать используемые символы.
from random import choice digits = '0123456789' uppercase = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' lowercase = 'abcdefghijklmnopqrstuvwxyz' punctuation = '!#$%&*+-=?@^_' ally = digits + uppercase + lowercase + punctuation chars = '' pwd_pass = ['pwd_auto', 'pwd_digits', 'pwd_uppercase', 'pwd_lowercase', 'pwd_punctuation'] pwd_length = int(input('Введите желаемую длину пароля: ')) pwd_auto = input('Сгенерировать пароль автоматически? (y, n): ') pwd_digits = input('Включить цифры (y, n): ') pwd_uppercase = input('Включить uppercase (y, n): ') pwd_lowercase = input('Включить цифры (y, n): ') pwd_punctuation = input('Включить спец. символы (y, n): ') for i in pwd_pass: if pwd_auto == 'y': chars += ally break else: if pwd_digits == 'y': chars += digits if pwd_uppercase == 'y': chars += uppercase if pwd_lowercase == 'y': chars += lowercase if pwd_punctuation == 'y': chars += punctuation password = '' for i in range(pwd_length): password += choice(chars) print('\n', password, '\n', sep='')
Отслеживать
задан 6 ноя 2021 в 12:24
1 1 1 серебряный знак 7 7 бронзовых знаков
Пожалуйста, уточните вашу конкретную проблему или приведите более подробную информацию о том, что именно вам нужно. В текущем виде сложно понять, что именно вы спрашиваете.
ildarkhasanshin / password.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
| import random |
| num = input ( ‘login ‘ ) |
| pas = » |
| for x in range ( 16 ): #Количество символов (16) |
| pas = pas + random . choice ( list ( ‘1234567890abcdefghigklmnopqrstuvyxwzABCDEFGHIGKLMNOPQRSTUVYXWZ’ )) #Символы, из которых будет составлен пароль |
| print ( ‘Hello, ‘ , num , ‘your password is: ‘ , pas ) |
Статья Пишем простой генератор сложных паролей
Тема не новая, генераторов существует множество, однако такой простой код и глазу приятен, и место не занимает.
Для начала вставим в шапку кодировку и версию питона. Импортируем модуль random для генерации случайной последовательности. Зададим переменную chars и вобьём буквы в разном регистре, цифры и какие-нибудь спецсимволы для получения максимально взломостойкого пароля.
# -*- coding:utf -8 -*- #!/usr/bin/python3 import random chars = '+-/*!&$#?=@<>abcdefghijklnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890'
Чтобы программа тупо не генерила один пароль или строго заданное количество, разрешим пользователю самому решать сколько паролей он хочет сгенерировать. Кроме этого дадим возможность определять и длину пароля.
number = input('количество паролей?'+ "\n") length = input('длина пароля?'+ "\n") number = int(number) length = int(length)
Осталось добавить самое главное — цикл случайной генерации символов, букв и цифр из нашей переменной, согласно параметрам введённым пользователем.
for n in range(number): password ='' for i in range(length): password += random.choice(chars) print(password)
Вот собственно и всё — простой генератор сложных паролей готов.
Код полностью:
# -*- coding:utf -8 -*- #!/usr/bin/python3 import random chars = '+-/*!&$#?=@<>abcdefghijklnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890' number = input('количество паролей?'+ "\n") length = input('длина пароля?'+ "\n") number = int(number) length = int(length) for n in range(number): password ='' for i in range(length): password += random.choice(chars) print(password)
Результат работы:
Не нужно искать сложных путей, если есть простые решения
explorer
Pentest Group
Platinum
- Сообщения 1 093
- Реакции 2 506
Азиз
Green Team
30.05.2018 224 74
Тема не новая, генераторов существует множество, однако такой простой код и глазу приятен, и место не занимает.
Для начала вставим в шапку кодировку и версию питона. Импортируем модуль random для генерации случайной последовательности. Зададим переменную chars и вобьём буквы в разном регистре, цифры и какие-нибудь спецсимволы для получения максимально взломостойкого пароля.
# -*- coding:utf -8 -*- #!/usr/bin/python3 import random chars = '+-/*!&$#?=@<>abcdefghijklnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890'
Чтобы программа тупо не генерила один пароль или строго заданное количество, разрешим пользователю самому решать сколько паролей он хочет сгенерировать. Кроме этого дадим возможность определять и длину пароля.
number = input('количество паролей?'+ "\n") length = input('длина пароля?'+ "\n") number = int(number) length = int(length)
Осталось добавить самое главное — цикл случайной генерации символов, букв и цифр из нашей переменной, согласно параметрам введённым пользователем.
for n in range(number): password ='' for i in range(length): password += random.choice(chars) print(password)
Вот собственно и всё — простой генератор сложных паролей готов.
Код полностью:
# -*- coding:utf -8 -*- #!/usr/bin/python3 import random chars = '+-/*!&$#?=@<>abcdefghijklnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890' number = input('количество паролей?'+ "\n") length = input('длина пароля?'+ "\n") number = int(number) length = int(length) for n in range(number): password ='' for i in range(length): password += random.choice(chars) print(password)
Не нужно искать сложных путей, если есть простые решения
С меня плюсик. И еще, во избежания лишних строк кода — советую:
number = input('количество паролей?'+ "\n") length = input('длина пароля?'+ "\n") number = int(number) length = int(length)
number = int(input('количество паролей?'+ "\n")) length = int(input('длина пароля?'+ "\n"))
Не нужно искать сложных путей, если есть простые решения
Последнее редактирование: 01.09.2018
NeskO
Green Team
10.01.2018 115 52
Можно еще написать пребор по таким паролям. те сначала набираеться словарь до указаного пользователем количества паролей и сразу же брут им через гидру.
explorer
Platinum
05.08.2018 1 093 2 506
number = int(input('количество паролей?'+ "\n")) length = int(input('длина пароля?'+ "\n"))
Можно еще написать пребор по таким паролям. те сначала набираеться словарь до указаного пользователем количества паролей и сразу же брут им через гидру.
Конечно. Пилить любой скрипт можно бесконечно. И чтобы сделать мега-программу многофункциональную, нужно сначала наклепать небольщих скриптиков, наподобие этого. Ну и потом скрестить, разумеется они должны быть одной направленности, чтобы дополнять друг друга. Иначе получится смесь бульдога с носорогом )
explorer
Platinum
05.08.2018 1 093 2 506
Чего-то сегодня под вечер на меня нашло, и я решил переписать эту утилиту с оконным интерфейсом. Так гораздо удобнее, можно сразу в одном окне набить паролей разной длины.
В общем пошаманил, и получил следующий код на выходе:
# -*- coding:utf -8 -*- #!/usr/bin/python3 from tkinter import * import random import string root = Tk() root.resizable(width=False, height=False) root.title("Генератор паролей") root.geometry("420x338+300+300") calculated_text = Text(root,height=15, width=50) def erase(): calculated_text.delete('1.0', END) chars = '+-/*!&$#?=@<>abcdefghijklnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890' def password(): for n in range(int(number_entry.get())): password ='' for i in range(int(length_entry.get())): password += random.choice(chars) calculated_text.insert(END, password + "\n") display_button = Button(text="Сгенерить", command=password) erase_button = Button(text="Очистить", command=erase) number_entry = Entry(width=10, justify=CENTER) length_entry = Entry(width=10, justify=CENTER) number_entry.insert(0, "8") length_entry.insert(0, "25") number_label = Label(text=" Количество паролей") length_label = Label(text=" Длина пароля") number_label.grid(row=0, column=0, sticky="w") length_label.grid(row=1, column=0, sticky="w") number_entry.grid(row=0,column=1, padx=1, pady=5) length_entry.grid(row=1,column=1, padx=1, pady=5) display_button.grid(row=2, column=0, padx=5, pady=5, sticky="e") erase_button.grid(row=2, column=2, padx=15, pady=5, sticky="w") calculated_text.grid(row=4, column=0, sticky='nsew', columnspan=3) scrollb = Scrollbar(root, command=calculated_text.yview) scrollb.grid(row=4, column=4, sticky='nsew') calculated_text.configure(yscrollcommand=scrollb.set) root.mainloop()
Valkiria
Количество паролей — 5
Количество символов — 18.
А получилась какая-то каша.
Это тест на внимательность ?
explorer
Platinum
05.08.2018 1 093 2 506
Количество паролей — 5
Количество символов — 18.
А получилась какая-то каша.
Это тест на внимательность ?
Ну если тест на внимательность — то внимательнее читать нужно ))) ВЫше написано — можно сразу в одном окне набить паролей разной длины. Что на скрине и видно, сначала 25 знаков, потом 18. Чтобы каши не было, есть кнопка «очистить».
Азиз
Green Team
30.05.2018 224 74
Советую добавить немного отступов, и ещё добавить типо:
Пароль 1 — 7377283891
Пароль 2 — hsjsjaklaji28
Так все будет намного понятней
explorer
Platinum
05.08.2018 1 093 2 506
Советую добавить немного отступов, и ещё добавить типо:
Пароль 1 — 7377283891
Пароль 2 — hsjsjaklaji28
Так все будет намного понятней
Любые разделители можно по желанию поставить отредактировав строку 23. Пронумеровать тоже можно, но тогда нумерация будет повторяться с каждым новым циклом.
z3RoTooL
Grey Team
28.02.2016 802 696
а вот мой вариант )
┌─╼[~] └────╼ cat /bin/passgen read -p "Длинна пароля: " number echo pwgen -sncB -1 "$number" 10 echo
fuzscore
Grey Team
21.09.2016 77 181
а почему не добавить при каждой новой генерации очистку предыдущей?
explorer
Platinum
05.08.2018 1 093 2 506
а почему не добавить при каждой новой генерации очистку предыдущей?
Я так задумал просто, чтобы именно разной длины набить сразу в окно можно было. А если это не понадобится, то сделал кнопку «очистить».
Все мы по разному воспринимаем и мыслим
А так кучу всего другого можно туда добавить — например отправку в текстовый файл, чтобы ручками не копипастить и т.д.
Tayrus
Red Team
13.04.2017 365 786
Решил написать свой вариант:
import datetime import base64 import random def Revers(string): string = string[::-1] return string def CorrectPass(password): for x in password: password = password.replace(x,"") if len(password) == passwordlen: break return password #Get data timer = datetime.datetime.now() #Morph str timer = str(timer) timer = timer.replace('-','') timer = timer.replace(' ','') timer = timer.replace(':','') timer = timer.replace('.','') #Revers or not realrandom = random.choice([1,2]) if realrandom == 1: timer = Revers(timer) #Encode str timer = base64.b64encode(bytes(timer, "utf-8")) #Morph timer = str(timer) timer = timer.replace("b'","") timer = timer.replace("='","") #Len passwordlen = 15 #Change this if passwordlen != len(timer): timer = CorrectPass(timer) #Check while True: #Если в выводе ничего не получили, то запустите скрипт еще раз, до тех пор пока не получите. if timer == '': timer = CorrectPass(timer) break print (timer)
explorer
Platinum
05.08.2018 1 093 2 506
Решил написать свой вариант
Я уж было обрадовался, что кто-то ещё свои творения выкладывает, но к сожалению консольный скрипт получился длиннющий, не всегда срабатывает, и длина пароля жёстко задана, и выдаёт в 1 экземпляре.
z3RoTooL
Grey Team
28.02.2016 802 696
сделал своё творение немного приятней глазу
┌─╼[~] └────╼ cat /bin/passgen #!/bin/bash # Скрипт генератор паролей pwgen + параметры запуска echo echo Генератор паролей pwgen с параметрами запуска echo echo ∗ Генерировать полностью случайные пароли echo ∗ Включить хотя бы один номер в пароле echo ∗ Включить хотя бы одну заглавную букву в пароле echo ∗ Не включать двусмысленные символы в пароле echo read -p "⏵ Введите кол-во символов для пароля: " number echo ──────────────────────╼ pwgen -1sncB "$number" 10 echo ──────────────────────╼

Tayrus
Red Team
13.04.2017 365 786
Я уж было обрадовался, что кто-то ещё свои творения выкладывает, но к сожалению консольный скрипт получился длиннющий, не всегда срабатывает, и длина пароля жёстко задана, и выдаёт в 1 экземпляре.
Длину пароля можно поменять(там комментарий измени меня), а размер скрипта имеет значение(это глупо сравнить качество по количеству строк в коде)? Мне лень было фиксить эту проблему(не всегда срабатывает).
explorer
Platinum
05.08.2018 1 093 2 506
Ну раз я сам заикнулся о варианте с сохранением в файл, то решил добавить эту функцию в программу. Теперь можно сгенерированные списки паролей сохранять.
# -*- coding:utf -8 -*- #!/usr/bin/python3 __version__ = 'Version: 1.1' from tkinter import * import random import string from tkinter import filedialog as fd root = Tk() root.resizable(width=False, height=False) root.title("Генератор паролей " +str(__version__)) root.geometry("450x324+300+300") calculated_text = Text(root,height=14, width=50) def erase(): calculated_text.delete('1.0', END) chars = '+-/*!&$#?=@<>abcdefghijklnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890' def password(): for n in range(int(number_entry.get())): password ='' for i in range(int(length_entry.get())): password += random.choice(chars) calculated_text.insert(END, password + "\n") def savepass(): file_name = fd.asksaveasfilename(filetypes=(("TXT files", "*.txt"), ("All files", "*.*")),defaultextension='') f = open(file_name, 'w') s = calculated_text.get(1.0, END) f.write(s) f.close() display_button = Button(text="Сгенерить", command=password) erase_button = Button(text="Очистить", command=erase) save = Button(text="Сохранить", command=savepass) number_entry = Entry(width=10, justify=CENTER) length_entry = Entry(width=10, justify=CENTER) number_entry.insert(0, "8") length_entry.insert(0, "25") number_label = Label(text=" Количество паролей") length_label = Label(text=" Длина пароля") number_label.grid(row=0, column=0, sticky="w") length_label.grid(row=1, column=0, sticky="w") number_entry.grid(row=0,column=1, padx=1, pady=5) length_entry.grid(row=1,column=1, padx=1, pady=5) save.grid(row=3, column=2, padx=50, pady=5, sticky="w") display_button.grid(row=3, column=0, padx=30, pady=5, sticky="e") erase_button.grid(row=3, column=1, padx=30, pady=5, sticky="e") scrollb = Scrollbar(root, command=calculated_text.yview) scrollb.grid(row=4, column=3, sticky='nsew') calculated_text.grid(row=4, column=0, sticky='nsew', columnspan=3) calculated_text.configure(yscrollcommand=scrollb.set) root.mainloop()
GUI Генератор паролей на Python

Штош. В этой статье я научу вас делать кроссплатформенное приложение генератор паролей с графическим интерфейсом. Мы будем использовать язык Python и библиотеку PySide6 — привязку к инструментарию фреймворка Qt.
Приложение умеет генерировать пароли, скрывать и копировать их в буфер обмена. Длина задается с помощью слайдера и счетчика. Пул допустимых символов меняется кнопками. Сила пароля рассчитывается по информационной энтропии.
В статье я постарался затронуть все моменты создания и сборки приложения. Ознакомиться с проектом можно на GitHub.
Устанавливаем все необходимое
Скачайте и установите Python последней версии (желательно). Приложение должно работать с Python версии 3.7+
Создадим директорию проекта password-generator и виртуальное окружение, в моем случае venvPasswordGenerator
pip install pyside6
Создаем интерфейс
Переходим к созданию интерфейса. Для этого нам понадобится программа Qt Designer. Её можно найти в папке установленной ранее библиотеки.

Создаем MainWindow . Убираем menubar и statusbar

Сразу сохраняем файл интерфейса. Я называю его main.ui , потому что в будущем я могу захотеть сделать отдельную форму для настроек или еще чего-то.
Сначала закинем 4 Horizontal Layout для компоновки элементов. Скопировать элемент можно перетаскиванием с зажатой клавишей Ctrl .

Выберем вертикальное расположение для центрального виджета. centralwidget -> Lay Out Vertically

Компоновка выбора символов
Закинем одну кнопку выбора символов в нижнюю горизонтальную компоновку.

Чтобы кнопка имела 2 состояния, нужно поставить свойство checkable

Скопируем кнопку 3 раза. Поставим текст. Я думаю, так должно быть понятно, за какой набор символов отвечает каждая отдельная кнопка.

Дадим элементам осмысленные имена.

Проставим свойство checked на всех символах, кроме специальных.

Компоновка длины пароля
Здесь будет указываться длина пароля с помощью слайдера и счетчика. Компоновку я назову layout_length , слайдер — slider_length , счетчик — spinbox_length

Компоновка энтропии и сложности пароля

Ставим горизонтальное выравнивание по центру.

Копируем элемент и вводим примерный текст.

Компоновка пароля
Перед нами встает интересная задача. Как поместить кнопку видимости пароля в элемент Line Edit? К сожалению, встроенных в Qt Designer методов для такого действия я не нашел. Лучшим решением я посчитал поместить поле и кнопку рядом во фрейме. Если вы знаете способ лучше, поделитесь в комментариях.
Widget Box -> Containers -> Frame

Поставим горизонтальное выравнивание для фрейма.

Добавим 2 кнопки в горизонтальную компоновку, а не во фрейм. Перетаскивать элемент нужно в самый правый край компоновки.

Еще я захотел поставить сверху изображение замка. На удивление, в Qt Designer это тоже реализовано через одно место, в котором никто не хочет побывать. Есть способ с помощью лейбла и его свойства pixmap , но в таком случае нельзя изменять размер изображения. Поэтому я решил сделать через иконку заблокированной кнопки.

Иконки Material Icons
Возьмем иконки для приложения. Я буду использовать бесплатные Material Icons.
Скачаем белую векторную иконку замка. Я выберу первый вид — Outlined. Вы можете взять другой, как вам приятнее.

Для повторной генерации возьмем Refresh. Копирование в буфер обмена — Content Copy. Видимость пароля — Visibility и Visibility Off. Для иконки приложения возьмем черную иконку ключа в формате png и сконвертируем её в формат для иконок ico

Создаем файл ресурсов
Создадим файл ресурсов, который будет хранить иконки. Позже мы сконвертируем его в Python код. Resource Browser -> Edit Resources -> New Resource File -> resources.qrc
Добавляем префикс icons

Добавляем все файлы иконок.


Проставляем иконки
В заблокированную кнопку ставим иконку замка с помощью свойства icon -> Disabled On . Выбираем иконку с помощью Choose Resource

Для кнопки видимости выбираем свойство checkable , так как она тоже имеет 2 состояния. Сразу проставим checked по умолчанию.

В Normal Off берем иконку невидимости, в Normal On — видимости.

Остальные иконки проставляем в Normal On

Стилизуем интерфейс
Для стилизации приложения я буду использовать урезанный язык CSS. Писать советую в каком-нибудь редакторе. Я пишу в Visual Studio Code, конечно же.
Главное окно
Создадим файл QMainWindow.css . Для главного виджета поставим цвет фона #121212 , белый цвет текста, шрифт Verdana с размером 16 поинтов и внешний отступ 10 пикселей.
QWidget
Для кнопок ставим сплошную серую границу 2 пикселя с радиусом границы 5 пикселей.
QPushButton
Вставим код в элемент MainWindow с помощью опции Change styleSheet

Отдельно для кнопок символов я поставлю внутренний отступ 10 пикселей, текст располагается слишком близко к границам.
QPushButton#btn_lower, #btn_upper, #btn_digits, #btn_special
При наведении на кнопку цвет границ будет меняться на зеленый #090 .
QPushButton:hover
При нажатии граница будет увеличиваться до 4 пикселей.
QPushButton:pressed
Для отмеченного состояния кнопки поставим на фон темно-зеленый цвет #006300 .
QPushButton:checked
QMainWindow.css
QWidget < background-color: #121212; color: white; font-family: Verdana; font-size: 16pt; margin: 10px; >QPushButton < border: 2px solid gray; border-radius: 5px; >QPushButton#btn_lower, #btn_upper, #btn_digits, #btn_special < padding: 10px; >QPushButton:hover < border-color: #090; >QPushButton:pressed < border: 4px solid #090; border-radius: 5px; >QPushButton:checked
Чтобы посмотреть превью интерфейса, нужно нажать сочетание клавиш Ctrl + R

Иконка замка
Уберем границы с помощью стиля border: none;
Поставим размер 100 на 100 пикселей.

Фрейм пароля
Поставим для фрейма пароля такую же границу, как и для кнопок. Уберем отступ до правого элемента.
QFrame < border: 2px solid gray; border-radius: 5px; margin-right: 0; >QFrame:hover
Поставим вертикальную политику Maximum

Поле пароля
Для поля пароля уберем границы и внешние отступы. Поставим размер шрифта 20 поинтов.
QLineEdit
Кнопка видимости
Для кнопки видимости пароля так же уберем границы и внешние отступы. Еще поставим прозрачный фон и размер 30 на 30 пикселей.
QPushButton

Кнопка генерации пароля
Для кнопки генерации пароля поставим размер иконки 52 на 52 пикселя. Так границы кнопки будут идти ровно по границам фрейма. Уберем правый и левый внешний отступ.
QPushButton

Кнопка копирования пароля в буфер обмена
Почему-то иконка копирования очень плотно прилегает к границам. Я нашел размер 42 на 42 пикселя и внутренний отступ 5 пикселей. Уберем отступ до левого элемента.
QPushButton

Слайдер
Для псевдоэлемента groove уберем цвет и поставим высоту 5 пикселей. Грув — это линия слайдера, или «желобок», «канавка», «борозда», если верить гугл переводчику.
QSlider::groove:horizontal
Слева от ручки слайдера будет зеленый цвет. Для этого используется селектор псевдоэлемента sub-page
QSlider::sub-page:horizontal
Справа от ручки будет серый цвет. Псевдоэлемент add-page
QSlider::add-page:horizontal
Ручку слайдера я сделаю белой с шириной 22 пикселя, радиусом 10 пикселей и внешними отступами снизу и сверху по -8 пикселей.
QSlider::handle:horizontal
Поставим максимум 100 пикселей и значение по умолчанию 12.

Счетчик
Счетчик похож на кнопки.
QSpinBox < border: 2px solid gray; border-radius: 5px; background: transparent; padding: 2px; >QSpinBox:hover
Поставим значения, как у слайдера. Сделаем горизонтальное выравнивание по центру и уберем эти отвратительные стрелочки.

Лейблы информации
Если растягивать окно интерфейса по вертикали, большую часть будут занимать лейблы информации. Мы этого не хотим, и поэтому ставим у двух лейблов вертикальную политику Maximum

Делаем последние штрихи
Поставим размер приложения по умолчанию. Мне нравится 542 на 418 пикселей. Можете сделать круглые числа, как вам угодно.

Напишем название приложения в свойстве windowTitle . Поставим иконку в windowIcon

Поставим курсор Pointing Hand для кнопок и слайдера.

Уберем демонстрационный текст из лейблов. Он будет генерироваться программой.
Штош. Интерфейс готов, переходим к следующему этапу.

Конвертируем файл ресурсов и интерфейса
Для того, чтобы сконвертировать файл ресурсов, нужно написать в терминал pyside6-rcc , название файла ресурсов, флаг -o и название файла на выходе.
pyside6-rcc resources.qrc -o resources.py
Файл интерфейса конвертируется таким же образом, только с помощью приложения pyside6-uic
pyside6-uic main.ui -o ui_main.py
Этот файл хочет, чтобы я добавлял в конце _rc к файлу ресурсов, а я не хочу. Поменяем import resources_rc на import resources
Пишем код
Рекомендую писать код в среде разработки PyCharm или Visual Studio Code. Vim-еры, не бейте.
Для начала создадим модуль приложения — app.py . Я вставлю готовый сниппет для запуска приложения с файлом дизайна.
import sys from PySide6.QtWidgets import QApplication, QMainWindow from ui_main import Ui_MainWindow class App(QMainWindow): def __init__(self): super(App, self).__init__() self.ui = Ui_MainWindow() self.ui.setupUi(self) if __name__ == "__main__": app = QApplication(sys.argv) window = App() window.show() sys.exit(app.exec())
Поменяю название класса App на PasswordGenerator
Модуль кнопок
Давайте сделаем отдельный модуль с привязкой сущностей к кнопкам — buttons.py . В стандартной библиотеке string есть строковые переменные для пула символов. Возьмем ascii_lowercase, ascii_uppercase, digits и punctuation.
from string import ascii_lowercase, ascii_uppercase, digits, punctuation
Вот так они выглядят.
ascii_lowercase = 'abcdefghijklmnopqrstuvwxyz' ascii_uppercase = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' digits = '0123456789' punctuation = r"""!"#$%&'()*+,-./:;?@[\]^_`<|>~"""
Давайте сделаем перечисление, которое привязывает кнопки выбора символов к этим строковым переменным.
from enum import Enum class Characters(Enum): btn_upper = ascii_uppercase btn_lower = ascii_lowercase btn_digits = digits btn_special = punctuation
Сразу создадим словарь с количеством символов на каждый пул. Нам это пригодится для расчета энтропии.
CHARACTER_NUMBER =
Модуль генерации пароля
Давайте сделаем модуль генерации паролей без привязки к интерфейсу — password.py . Напишем функцию создания нового пароля. Аргументами будут длина пароля и все используемые символы в виде строки.
Для генерации безопасного пароля мы будем использовать библиотеку secrets. Сделаем генератор из случайно выбранных символов и соединим их в строку с помощью метода join
import secrets def create_new(length: int, characters: str) -> str: return "".join(secrets.choice(characters) for _ in range(length))
Получаем энтропию пароля
Теперь сделаем функцию для получения энтропии. В нее нужно будет передавать длину пароля и количество символов. Формула энтропии пароля выглядит следующим образом:
где N — это количество возможных символов, а L — количество символов в пароле. H измеряется в битах.
Давайте импортируем логарифм по основанию 2 из библиотеки math.
from math import log2
Возвращаем значение, округленное до 2 знаков после запятой.
def get_entropy(length: int, character_number: int) -> float: entropy = length * log2(character_number) return round(entropy, 2)
Перечисление для сложности пароля
Создадим целочисленное перечисление сложности пароля к его энтропии по нижней границе. Я не нашел единого стандарта, в разных генераторах сила пароля считается по-разному, поэтому сделаю так: ничтожный пароль от 0 до 30 бит, слабый после 30, хороший после 50, сильный после 70 и замечательный после 120.
from enum import IntEnum class StrengthToEntropy(IntEnum): Pathetic = 0 Weak = 30 Good = 50 Strong = 70 Excellent = 120
Связываем значения слайдера и счетчика
Давайте сделаем метод класса приложения, который будет связывать значения слайдера и счетчика. Для этого соединим сигнал изменения значения valueChanged с установкой значения другого элемента.
def connect_slider_to_spinbox(self) -> None: self.ui.slider_length.valueChanged.connect(self.ui.spinbox_length.setValue) self.ui.spinbox_length.valueChanged.connect(self.ui.slider_length.setValue)
Не забудьте прописать метод в конструкторе класса.
class PasswordGenerator(QMainWindow): def __init__(self): . self.connect_slider_to_spinbox()
Получаем символы для пароля
Создадим новый метод для получения символов отмеченных кнопок. Объявим пустую строку chars . Для каждой кнопки в перечислении добавляем её символы в строку, если она отмечена.
def get_characters(self) -> str: chars = "" for btn in buttons.Characters: if getattr(self.ui, btn.name).isChecked(): chars += btn.value return chars
Ставим пароль
Ну и наконец-то, метод установки пароля. Ставим в элемент line_password новый пароль с помощью метода setText . Длину берем из слайдера или счетчика, не имеет значения.
def set_password(self) -> None: self.ui.line_password.setText( password.create_new( length=self.ui.slider_length.value(), characters=self.get_characters()) )
Добавим метод в конструктор. Приложение должно сгенерировать пароль при запуске.
Соединим изменение слайдера или счетчика с установкой пароля.
def connect_slider_to_spinbox(self) -> None: . self.ui.spinbox_length.valueChanged.connect(self.set_password)
Позалипаем на быстрое изменение паролей :3
Когда не нажата ни одна кнопка символов, происходит IndexError . Обработаем этот случай, просто очищая поле пароля.
def set_password(self) -> None: try: self.ui.line_password.setText( password.create_new( length=self.ui.slider_length.value(), characters=self.get_characters()) ) except IndexError: self.ui.line_password.clear()
Получаем количество символов
Принцип тот же, что и у получения строки символов, только в этот раз мы работаем со словарем, а не с перечислением.
def get_character_number(self) -> int: num = 0 for btn in buttons.CHARACTER_NUMBER.items(): if getattr(self.ui, btn[0]).isChecked(): num += btn[1] return num
Ставим энтропию пароля
Делаем метод для лейбла энтропии. Берем длину из текста пароля, а не из слайдера или счетчика, так нужно. Ставим в лейбл выражение с помощью f-строки.
def set_entropy(self) -> None: length = len(self.ui.line_password.text()) char_num = self.get_character_number() self.ui.label_entropy.setText( f"Entropy: bit" )
Добавим установку энтропии в конце метода установки пароля.
def set_password(self) -> None: . self.set_entropy()
Без отмеченных кнопок символов получается ValueError . Обработаем эту ошибку в функции get_entropy модуля password . В таком случае она будет возвращать 0.0.
def get_entropy(length: int, character_number: int) -> float: try: entropy = length * log2(character_number) except ValueError: return 0.0 return round(entropy, 2)
Ставим сообщение о сложности пароля
Теперь сделаем метод для лейбла сложности пароля. Для каждой сложности из перечисления сравниваем энтропию со значением.
def set_strength(self) -> None: length = len(self.ui.line_password.text()) char_num = self.get_character_number() for strength in password.StrengthToEntropy: if password.get_entropy(length, char_num) >= strength.value: self.ui.label_strength.setText(f"Strength: ")
Добавим в конец метода установки пароля.
Ставим генерацию пароля на кнопки
Запишу в модуль buttons кортеж с именами кнопок, при нажатии на которые будет генерироваться новый пароль.
GENERATE_PASSWORD = ( 'btn_refresh', 'btn_lower', 'btn_upper', 'btn_digits', 'btn_special' )
Теперь соединим кнопки с методом в конструкторе класса.
for btn in buttons.GENERATE_PASSWORD: getattr(self.ui, btn).clicked.connect(self.set_password)
Изменяем видимость пароля
Напишем метод для изменения видимости пароля. Если кнопка отмечена, ставим нормальный эхо мод, иначе ставим эхо мод пароля.
from PySide6.QtWidgets import QApplication, QMainWindow, QLineEdit . def change_password_visibility(self) -> None: if self.ui.btn_visibility.isChecked(): self.ui.line_password.setEchoMode(QLineEdit.Normal) else: self.ui.line_password.setEchoMode(QLineEdit.Password)
Соединим нажатие кнопки с методом в конструкторе класса.
class PasswordGenerator(QMainWindow): def __init__(self): . self.ui.btn_visibility.clicked.connect(self.change_password_visibility)
Копируем в буфер обмена
Чтобы скопировать текст в буфер обмена, нужно вызвать метод clipboard класса QApplication и поставить в него текст.
def copy_to_clipboard(self) -> None: QApplication.clipboard().setText(self.ui.line_password.text())
Так же соединим нажатие кнопки с методом в конструкторе класса. Я думаю, вы справитесь.
Очищаем буфер обмена при закрытии приложения
Для того, чтобы делать что-либо при закрытии приложения, нам нужна функция этого события. В Qt это событие называется QCloseEvent. В PySide6 пишем closeEvent
Событие не нужно ни с чем соединять в конструкторе. Оно работает сразу при объявлении соответствующего метода в классе приложения.
from PySide6.QtGui import QCloseEvent def closeEvent(self, event: QCloseEvent) -> None: QApplication.clipboard().clear()
Меняем лейблы при ручном изменении пароля
Остался последний штрих. При ручном изменении пароля энтропия не меняется. Решить проблему можно с помощью сигнала редактирования текста textEdited
def do_when_password_edit(self) -> None: self.ui.line_password.textEdited.connect(self.set_entropy) self.ui.line_password.textEdited.connect(self.set_strength)
Фишка в том, что это будет не совсем правильная энтропия, потому что количество допустимых символов берется по прежнему из отмеченных кнопок. Предлагаю вам самим решить эту проблему.
from string import ascii_lowercase, ascii_uppercase, digits, punctuation from enum import Enum class Characters(Enum): btn_lower = ascii_lowercase btn_upper = ascii_uppercase btn_digits = digits btn_special = punctuation CHARACTER_NUMBER = < 'btn_lower': len(Characters.btn_lower.value), 'btn_upper': len(Characters.btn_upper.value), 'btn_digits': len(Characters.btn_digits.value), 'btn_special': len(Characters.btn_special.value) >GENERATE_PASSWORD = ( 'btn_refresh', 'btn_lower', 'btn_upper', 'btn_digits', 'btn_special' )
password.py
from enum import IntEnum from math import log2 import secrets class StrengthToEntropy(IntEnum): Pathetic = 0 Weak = 30 Good = 50 Strong = 70 Excellent = 120 def create_new(length: int, characters: str) -> str: return ''.join(secrets.choice(characters) for _ in range(length)) def get_entropy(length: int, character_number: int) -> float: try: entropy = length * log2(character_number) except ValueError: return 0.0 return round(entropy, 2)
Меняем структуру проекта
Штош. Давайте поменяем структуру проекта. Поместим все файлы в папку password-generator. Здесь создадим папку ui, в которую поместим все файлы, связанные с интерфейсом. Поменяем импортирование модулей, чтобы все работало. Из ui_main.py я убрал импортирование ресурсов и добавил его в главный модуль приложения.
from ui.ui_main import Ui_MainWindow import ui.resources
import sys from PySide6.QtWidgets import QApplication, QMainWindow, QLineEdit from PySide6.QtGui import QCloseEvent import buttons import password from ui.ui_main import Ui_MainWindow import ui.resources class PasswordGenerator(QMainWindow): def __init__(self): super(PasswordGenerator, self).__init__() self.ui = Ui_MainWindow() self.ui.setupUi(self) self.connect_slider_to_spinbox() self.set_password() self.do_when_password_edit() for btn in buttons.GENERATE_PASSWORD: getattr(self.ui, btn).clicked.connect(self.set_password) self.ui.btn_visibility.clicked.connect(self.change_password_visibility) self.ui.btn_copy.clicked.connect(self.copy_to_clipboard) def connect_slider_to_spinbox(self) -> None: self.ui.slider_length.valueChanged.connect(self.ui.spinbox_length.setValue) self.ui.spinbox_length.valueChanged.connect(self.ui.slider_length.setValue) self.ui.spinbox_length.valueChanged.connect(self.set_password) def do_when_password_edit(self) -> None: self.ui.line_password.textEdited.connect(self.set_entropy) self.ui.line_password.textEdited.connect(self.set_strength) def get_characters(self) -> str: chars = '' for btn in buttons.Characters: if getattr(self.ui, btn.name).isChecked(): chars += btn.value return chars def set_password(self) -> None: try: self.ui.line_password.setText( password.create_new( length=self.ui.slider_length.value(), characters=self.get_characters()) ) except IndexError: self.ui.line_password.clear() self.set_entropy() self.set_strength() def get_character_number(self) -> int: num = 0 for btn in buttons.CHARACTER_NUMBER.items(): if getattr(self.ui, btn[0]).isChecked(): num += btn[1] return num def set_entropy(self) -> None: length = len(self.ui.line_password.text()) char_num = self.get_character_number() self.ui.label_entropy.setText( f'Entropy: bit' ) def set_strength(self) -> None: length = len(self.ui.line_password.text()) char_num = self.get_character_number() for strength in password.StrengthToEntropy: if password.get_entropy(length, char_num) >= strength.value: self.ui.label_strength.setText(f'Strength: ') def change_password_visibility(self) -> None: if self.ui.btn_visibility.isChecked(): self.ui.line_password.setEchoMode(QLineEdit.Normal) else: self.ui.line_password.setEchoMode(QLineEdit.Password) def copy_to_clipboard(self) -> None: QApplication.clipboard().setText(self.ui.line_password.text()) def closeEvent(self, event: QCloseEvent) -> None: QApplication.clipboard().clear() if __name__ == "__main__": app = QApplication(sys.argv) window = PasswordGenerator() window.show() sys.exit(app.exec())
Создаем файл зависимостей
Создадим файл зависимостей с помощью команды pip freeze > requirements.txt
PySide6==6.3.1 PySide6-Addons==6.3.1 PySide6-Essentials==6.3.1 shiboken6==6.3.1
Система контроля версий
Инициализируем систему контроля версий, конечно же Git. Установите систему, если вы еще этого не сделали. Пропишите в терминал git init из корневого каталога или используйте удобный графический интерфейс в PyCharm.
Создадим файл .gitignore . Будем игнорировать любую папку виртуального окружения, папку PyCharm в моем случае и питонячий кэш. Для VS Code можно прописать .vscode
venv* .idea .vscode __pycache__
Теперь можно сделать первый коммит. Опять же, в PyCharm это делается очень удобно, но если вы любите работать в терминале, то пропишите команды:
git commit -m «Initial commit»
Собираем приложение для Windows
Переходим к созданию исполняемых файлов. У Qt есть понятная документация, в которой собраны разные способы дистрибуции приложения. Самый простой способ — это PyInstaller. Нет, вру, самый простой способ — это PyInstaller с интерфейсом, auto-py-to-exe. Все эти библиотеки хороши своей понятностью и легкостью, но обычно на выходе получаются небезопасные и тяжелые бинарники.
Я решил показать вам инструмент получше — компилятор Nuitka. Он доступен для всех версий Qt, работает на всех платформах и распространяется по свободной лицензии MIT.
Установим библиотеку с помощью команды pip install nuitka . Для сборки приложения в один файл понадобится библиотека zstandard , добавим ее в команду через пробел.
Пишем команду компиляции. Собираем приложение в один файл с помощью флага —onefile . Флаг —follow-imports нужен для соблюдения всех импортов. Добавляем плагин PySide6 с помощью флага —enable-plugin=pyside6 . Чтобы убрать консольное окно в системе Windows добавим —windows-disable-console . Добавим иконку с помощью флага —windows-icon-from-ico
Чтобы убрать все генерируемые нуиткой папки сборки добавим флаг —remove-output
Можно указать название файла через флаг -o , но это вообще необязательно, всегда можно просто переименовать файл. В конце напишем путь к файлу скрипта, который мы собираемся собирать.
nuitka —onefile —follow-imports —enable-plugin=pyside6 —windows-disable-console —windows-icon-from-ico=ui\icons\app-icon.ico —remove-output -o password-generator.exe app.py
На выходе получилось приложение с размером 16.7 мегабайт.

Собираем приложение для Linux
Я использовал дистрибутив Ubuntu версии 22.04. С нуиткой вышло громадное приложение в 145 мегабайт. Если вы знаете, как сделать меньше — пишите в комментарии.
python -m nuitka —onefile —follow-imports —enable-plugin=pyside6 —remove-output app.py
Я попробовал собрать приложение с PyInstaller, получилось уже получше, 57,6 мегабайт. С иконкой в докбаре и проводнике вообще беда, она просто не хотела ставиться.
pyinstaller —name=»Password Generator» —windowed app.py
Собираем приложение для macOS
Я использовал версию 10.15 Catalina. Для сборки приложения под macOS нужно прописать специальный параметр —macos-create-app-bundle
python3 -m nuitka —onefile —follow-imports —enable-plugin=pyside6 —macos-create-app-bundle —remove-output -o password-generator.app app.py
Вышло почти так же компактно, как и на винде — 18 мегабайт. С иконкой тоже возникли проблемы, поэтому собирал без нее.
Штош
Надеюсь, вам понравился такой комплексный туториал. Генерируйте сильные пароли, дегенерируйте слабые, и будет вам счастье. До встречи.
