Я собираюсь сделать этот код ниже во втором выпуске моей библиотеки, но я хочу убедиться, что ничего не пропустил. Если есть какие-то улучшения, я бы хотел их реализовать.
Этот код также на GitHub.
import random
import secrets
import string
import urllib.request
class Simple():
def __init__(self, length: int, characters = None):
'''A simple password'''
self.length = length
self.characters = characters
self.output = []
def generate(self, num_of_passwords: int):
'''
Generates a password depending on the num_of_passwords
and the arugments provided in the simple class
'''
characters=""
if self.characters is None:
characters = string.ascii_letters + string.digits
else:
characters = self.characters
for i in range(num_of_passwords):
password = ''
for c in range(self.length):
password += secrets.choice(characters)
self.output.append(password)
return self.output
def return_result(self, index: int):
'''
Returns the password which is at the specified index
in the output list.
'''
try:
return self.output[index]
except IndexError:
print(f'Incorrect index specified. Please provide an index relevant to the number of passwords generated')
def clear_results(self):
'''Clears the output list if you want to make way for new passwords'''
self.output.clear()
class Complex(Simple):
def __init__(self, length, string_method, numbers=True, special_chars=False):
'''
Creates a customisable password depending on length,
string_method, numbers and special_chars
'''
characters=""
self.output = []
methods: dict = {
"upper": string.ascii_uppercase,
"lower": string.ascii_lowercase,
"both": string.ascii_letters,
}
characters += methods[string_method]
if numbers:
characters += string.digits
if special_chars:
characters += string.punctuation
super().__init__(length=length, characters=characters)
class Memorable(Simple):
def __init__(self, numbers=True):
'''A memorable password'''
self.numbers = numbers
self.output = []
def generate(self, num_of_passwords: int):
'''Gets some random words'''
word_url = "http://svnweb.freebsd.org/csrg/share/dict/words?view=co&content-type=text/plain"
headers = {'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; Win64; x64)'}
req = urllib.request.Request(word_url, headers=headers)
response = response = urllib.request.urlopen(req)
long_txt = response.read().decode()
words = long_txt.splitlines()
'''
Generates the password containing 2 words
and numbers if self.numbers == True
'''
for i in range(num_of_passwords):
password = ''
two_words=""
for i in range(2):
two_words += secrets.choice(words).title()
password = two_words
if self.numbers == True:
for i in range(random.randint(3, 4)):
password += secrets.choice(string.digits)
self.output.append(password)
return self.output
# Test Scenarios
if __name__ == "__main__":
var = Memorable()
print(var.generate(3))
1 ответ
1. Добавьте еще больше набора текста
Хорошо, что вы используете некоторые аннотации базового типа, но вы должны использовать их везде, а не только для нескольких выбранных параметров. Взгляните на typing модуль, особенно если вы хотите поддерживать версии Python до 3.9. Например, сигнатуры ваших функций могут быть
def __init__(self, length: int, characters: Optional[str] = None):
def generate(self, num_of_passwords: int) -> None:
def __init__(self, length: int, string_method: Literal["upper", "lower", "both"], numbers: bool = True, special_chars: bool = False):
2. Параметры только для ключевых слов.
Это личное предложение, и я уверен, что вы найдете людей, которые со мной не согласны. В вашем текущем коде Complex(5, "lower", True, False) это действительный звонок; однако для читателя это совершенно бессмысленно. Сделав последние два параметра только по ключевым словам, вы заставляете пользователя быть более выразительным: Complex(5, "lower", numbers=True, special_chars=False).
В этой связи я предлагаю дать параметрам более выразительные имена, например include_numbers и include_special_characters.
3. Добавьте более качественные строки документации.
Вы должны спросить себя: для кого вы пишете документацию по коду? Прямо сейчас комментарии вроде «Простой пароль» никому не дают много полезной информации, кроме, может быть, вас самих. Что делает пароль «простым»? Он содержит только цифры и буквы? Это коротко? Легко ли запомнить? То же самое можно сказать о «сложных», «запоминающихся» и других терминах. Я сам сделаю бесстыдную пробку последнее сообщение в блоге по этой теме для получения дополнительной информации.
4. Безопасность
В контексте «паролей» всегда следует упоминать «безопасность», даже если вы чувствуете, что для вашей конкретной цели она вам на самом деле не нужна. Тоби Спейт уже отмечал, что получение слов из словаря в Интернете с жестко заданным URL-адресом является довольно хорошей целью для злоумышленников. Простым и независимым от платформы обходным путем было бы включение полного словаря слов в сам пакет, чтобы не было необходимости получать его через HTTP.
Другая проблема может возникнуть из-за того, что random, который вы используете для создания паролей, не является криптографически безопасным. В secrets модуль, который вы также использовали, уже является лучшей альтернативой.
5. Перечисления
Этот момент, опять же, может быть немного спорным. Вместо использования строк «метода» "upper", "lower", и "both", Я бы предложил вместо этого использовать класс перечисления, который упростит вашей IDE помощь вам и быстрее выдает ошибки, если вы попытаетесь использовать несуществующее значение.
class PasswordGenerationStrategy(enum.Enum):
Upper = "upper"
Lower = "lower"
Both = "both"
