Seite 1 von 1
Passwortprüfer/generator
Verfasst: Samstag 24. April 2021, 12:42
von Domroon
Hallo Leute,
ich möchte gerne gut lesbaren, den Python-Richtlinien entsprechenden und effizienten Code schreiben.
Ich würde euch bitten den Code unter diesen Gesichtspunkten zu überprüfen. Ich hoffe, dass ich mithilfe eurer Anmerkungen und eurer Kritik ein guter Python-Programmierer werde.
Vielen Dank euch im voraus
Hier der Code:
Code: Alles auswählen
import time
import string
import random
GERMAN = {
"welcome" : "\nHerzlich Willkommen!\n",
"requirements" : "\nFolgende Anforderungen sollte das Passwort haben:\n"
"- Mindestens 8 Zeichen\n"
"- Mindestens ein Großbuchstabe\n"
"- Mindestens ein Kleinbuchstabe\n"
"- Mindestens eine Zahl\n"
"- Mindestens eine Sonderzeichen\n",
"main_menu" : "\n1 - Passwort Überprüfer\n"
"2 - Passwort Generator\n"
"q - Programm beenden\n",
"wrong_input" : "\nBitte gib einen gültigen Wert ein\n",
"password_input" : "\nBitte geben Sie ein Passwort ein: ",
"success" : "\nDas Passwort ist OK!",
"wrong_length" : "- Zu Kurz",
"no_uppercase" : "- Kein Großbuchstabe enthalten",
"no_lowercase" : "- Kein Kleinbuchstabe enthalten",
"no_digit" : "- Keine Zahl enthalten",
"no_special" : "- Kein Sonderzeichen enthalten",
"length" : "Passwortlänge(8-20): "
}
ENGLISH = {
"welcome" : "\nwelcome!\n",
"requirements" : "\nThe password should have the following requirements:\n"
"- At least 8 characters\n"
"- At least one capital letter\n"
"- At least one lowercase letter\n"
"- At least one number\n"
"- At least one special character\n",
"main_menu" : "\n1 - Password checker\n"
"2 - Password generator\n"
"q - Exit program\n",
"wrong_input": "\nPlease enter a valid value\n",
"password_input": "\nPlease enter a password: ",
"success": "\nThe password is OK!",
"wrong_length": "- Too short",
"no_uppercase": "- No capital letter",
"no_lowercase": "- Contains no lower case letter",
"no_digit": "- Does not contain a number",
"no_special": "- No special characters included",
"length" : "Password length (8-20): "
}
class InputError(Exception):
"""Exception raised for errors in the input.
Attributes:
expression -- input expression in which the error occurred
message -- explanation of the error
"""
def __init__(self, expression, message):
self.expression = expression
self.message = message
def language_selection():
print(f'Choose your language: ')
print(f'1 - English')
print(f'2 - German')
user_input = input()
if (user_input != '1') and (user_input != '2'):
raise InputError(user_input, ' is not a valid Input')
return user_input
def password_verification(password, sentences, give_return=False):
length = False
uppercase_letter = False
lowercase_letter = False
digit = False
special_char = False
if len(password) >= 8:
length = True
for letter in password:
if letter in string.ascii_uppercase + "ÄÖÜ":
uppercase_letter = True
if letter in string.ascii_lowercase + "äöüß":
lowercase_letter = True
if letter in string.digits:
digit = True
if letter in string.punctuation:
special_char = True
if not give_return:
if not length:
print(sentences["wrong_length"])
if not uppercase_letter:
print(sentences["no_uppercase"])
if not lowercase_letter:
print(sentences["no_lowercase"])
if not digit:
print(sentences["no_digit"])
if not special_char:
print(sentences["no_special"])
if length and uppercase_letter and lowercase_letter and digit and special_char:
if give_return:
return True
print(sentences["success"])
time.sleep(1)
if give_return:
return False
def password_generation(length, sentences):
if length < 8 or length > 20:
raise InputError(length, ' is not a valid Input')
password=""
while not password_verification(password, sentences, True):
for i in range(length):
random_char_type = random.randint(0, 3)
char_types = {
0 : string.ascii_uppercase[random.randint(0, len(string.ascii_uppercase)-1)],
1 : string.ascii_lowercase[random.randint(0, len(string.ascii_lowercase)-1)],
2 : string.digits[random.randint(0, len(string.digits)-1)],
3 : string.punctuation[random.randint(0, len(string.punctuation)-1)]
}
password = password + char_types[random_char_type]
print("\n" + password + "\n")
def main():
user_input = None
sentences = None
# Language Menu
while user_input != "q":
while True:
try:
if language_selection() == '1':
sentences = ENGLISH.copy()
else:
sentences = GERMAN.copy()
break
except InputError:
print('\nPlease enter a valid Input\n')
time.sleep(1)
print(sentences["welcome"])
# Main Menu
print(sentences["main_menu"])
while True:
user_input = input('input: ')
if user_input == '1':
password_verification(input(sentences["password_input"]), sentences)
time.sleep(1)
print(sentences["main_menu"])
elif user_input == '2':
while True:
try:
length = int(input(sentences["length"]))
password_generation(length, sentences)
break
except InputError:
print(sentences["wrong_input"])
print(sentences["main_menu"])
elif user_input == 'q':
break
else:
print(sentences["wrong_input"])
time.sleep(1)
if __name__ == '__main__':
main()
Re: Passwortprüfer/generator
Verfasst: Samstag 24. April 2021, 22:22
von Sirius3
Die Strings sind etwas weit eingerückt. Üblich sind vier Leerzeichen. Funktionen werden nach Tätigkeiten benannt, also select_language oder verify_password.
In language_selection benutzt du Formatstrings obwohl gar nichts zu formatieren ist. Die Klammern um die Bedingungen sind überflüssig, hier wäre der in-Operator besser.
In password_verification benutzt du am besten Sets statt der for-Schleife. Die vielen Vergleiche mit give_return sind verwirrend; das sleep nervig.
In password_generation brauchst du einen Dummy-Wert für password damit die while-Schleife startet. Das ist ein Fall für eine while-true-Schleife mit Abbruchbedingung am Ende. Schau dir random.choice an. Da Satzzeichen genauso oft vorkommenden wie Buchstaben, sind die Passwörter sehr unzufällig.
In main hat du wieder eine while-Schleife die eine while-true-Schleife sein sollte. Das copy ist unsinnig.
Re: Passwortprüfer/generator
Verfasst: Sonntag 25. April 2021, 14:18
von Domroon
@Sirius3:
Vielen Dank für Deine Tipps
Folgendes habe ich nun verbessert:
- Strings ordentlich eingerückt
- password_verification in verify_password umbenannt
- language_selection in select_language umbenannt, Klammern um Bedigungen entfernt und in-Operator benutzt
- Formatstrings aus 'select_language()' durch normale strings ersetzt
- in verify_password() habe ich die for-Schleife durch mehrere Sets ersetzt:
-> Habe ich das gut umgesetzt?
- alle 'time.sleep()' wurden entfernt
- in 'password_generation' habe ich alle zu überprüfenden Zeichen zu einer Liste hinzugefügt und dann mit 'choice' immer wieder ein zufälliges Zeichen einem String angehängt
-> Ist auch diese Umsetzung gut?
- in main() wurde das das unnötige copy() entfernt und die while schleife wurde zu einer while-true-Schleife umgewandelt
Über eine kurze Rückmeldung von Dir würde ich mich sehr freuen.
Hier also der korrigierte Code:
Code: Alles auswählen
import string
from random import choice
GERMAN = {
"welcome" : "\nHerzlich Willkommen!\n",
"requirements" : "\nFolgende Anforderungen sollte das Passwort haben:\n"
"- Mindestens 8 Zeichen\n"
"- Mindestens ein Großbuchstabe\n"
"- Mindestens ein Kleinbuchstabe\n"
"- Mindestens eine Zahl\n"
"- Mindestens eine Sonderzeichen\n",
"main_menu" : "\n1 - Passwort Überprüfer\n"
"2 - Passwort Generator\n"
"q - Programm beenden\n",
"wrong_input" : "\nBitte gib einen gültigen Wert ein\n",
"password_input" : "\nBitte geben Sie ein Passwort ein: ",
"success" : "\nDas Passwort ist OK!",
"wrong_length" : "- Zu Kurz",
"no_uppercase" : "- Kein Großbuchstabe enthalten",
"no_lowercase" : "- Kein Kleinbuchstabe enthalten",
"no_digit" : "- Keine Zahl enthalten",
"no_special" : "- Kein Sonderzeichen enthalten",
"length" : "Passwortlänge(8-20): "}
ENGLISH = {
"welcome" : "\nwelcome!\n",
"requirements" : "\nThe password should have the following requirements:\n"
"- At least 8 characters\n"
"- At least one capital letter\n"
"- At least one lowercase letter\n"
"- At least one number\n"
"- At least one special character\n",
"main_menu" : "\n1 - Password checker\n"
"2 - Password generator\n"
"q - Exit program\n",
"wrong_input": "\nPlease enter a valid value\n",
"password_input": "\nPlease enter a password: ",
"success": "\nThe password is OK!",
"wrong_length": "- Too short",
"no_uppercase": "- No capital letter",
"no_lowercase": "- Contains no lower case letter",
"no_digit": "- Does not contain a number",
"no_special": "- No special characters included",
"length" : "Password length (8-20): " }
class InputError(Exception):
"""Exception raised for errors in the input.
Attributes:
expression -- input expression in which the error occurred
message -- explanation of the error
"""
def __init__(self, expression, message):
self.expression = expression
self.message = message
def select_language():
print("Choose your language: ")
print("1 - English")
print("2 - German")
user_input = input()
if '1' not in user_input and '2' not in user_input:
raise InputError(user_input, ' is not a valid Input')
return user_input
def verify_password(password, sentences, give_return=False):
length = False
uppercase_letter = False
lowercase_letter = False
digit = False
special_char = False
if len(password) >= 8:
length = True
# check whether all necessary characters are included
password = set(password)
if password.intersection(set(string.ascii_uppercase + "ÄÖÜ")):
uppercase_letter = True
if password.intersection(set(string.ascii_lowercase + "äöüß")):
lowercase_letter = True
if password.intersection(set(string.digits)):
digit = True
if password.intersection(set(string.punctuation)):
special_char = True
# should only be issued if required
if not give_return:
if not length:
print(sentences["wrong_length"])
if not uppercase_letter:
print(sentences["no_uppercase"])
if not lowercase_letter:
print(sentences["no_lowercase"])
if not digit:
print(sentences["no_digit"])
if not special_char:
print(sentences["no_special"])
if length and uppercase_letter and lowercase_letter and digit and special_char:
if give_return:
return True
print(sentences["success"])
# the return is not necessary if the print functions have been issued
if give_return:
return False
def password_generation(length, sentences):
if length < 8 or length > 20:
raise InputError(length, ' is not a valid Input')
password = ""
while True:
for i in range(length):
all_signs = string.ascii_uppercase
all_signs += string.ascii_lowercase
all_signs += string.digits
all_signs += string.punctuation
password = password + choice(all_signs)
if verify_password(password, sentences, True):
break
print("\n" + password + "\n")
def main():
user_input = None
sentences = None
# Language Menu
while True:
while True:
try:
if select_language() == '1':
sentences = ENGLISH
else:
sentences = GERMAN
break
except InputError:
print('\nPlease enter a valid Input\n')
print(sentences["welcome"])
# Main Menu
print(sentences["main_menu"])
while True:
user_input = input('input: ')
if user_input == '1':
verify_password(input(sentences["password_input"]), sentences)
print(sentences["main_menu"])
elif user_input == '2':
while True:
try:
length = int(input(sentences["length"]))
password_generation(length, sentences)
break
except InputError:
print(sentences["wrong_input"])
print(sentences["main_menu"])
elif user_input == 'q':
break
else:
print(sentences["wrong_input"])
if user_input == "q":
break
if __name__ == '__main__':
main()
Re: Passwortprüfer/generator
Verfasst: Sonntag 25. April 2021, 14:47
von __blackjack__
@Domroon: Die `verify_password()` ist zu umständlich und von der API nicht gut. Wenn ein Argument entscheidet ob eine Funktion Ausgaben macht und nichts zurück gibt, oder keine Ausgaben macht und einen Rückgabewert hat, dann sind das eigentlich zwei Funktionen. Wobei die eine sich eventuell auf die andere abstützen kann.
Aber erst einmal zum zu umständlich: Wenn man in einem ``if``-Zweig einzig und alleine eine Variablen auf `True` setzt falls die Bedingung wahr ist, kann man auch einfach die Bedingung auswerten und das Ergebnis an den Namen binden, ganz ohne ``if``. Beispiel:
Code: Alles auswählen
length = False
if len(password) >= 8:
length = True
# =>
length = len(password) >= 8
Letztendlich braucht man die Wahrheitswerte aber auch überhaupt gar nicht wenn man beispielsweise die zutreffenden Sätze einfach in einer Liste sammeln würde. Mit dieser Liste kann man dann sowohl eine Ausgabe machen was alles nicht erfüllt wurde, als auch ganz einfach feststellen ob alles erfüllt wurde oder nicht wenn man sich die Länge/den ”Wahrheitswert” der Liste anschaut.
Code: Alles auswählen
def verify_password(password):
password = set(password)
return [
message_key
for test_result, message_key in [
(len(password) >= 8, "wrong_length"),
*(
(password.intersection(characters), message_key)
for characters, message_key in [
(string.ascii_uppercase + "ÄÖÜ", "no_uppercase"),
(string.ascii_lowercase + "äöüß", "no_lowercase"),
(string.digits, "no_digit"),
(string.punctuation, "no_special"),
]
),
]
if not test_result
]
Umwandlung des Ergebnisses in eine natürliche Sprache und Ausgabe des Ergebnisses gehört nicht in so eine Testfunktion.
Re: Passwortprüfer/generator
Verfasst: Montag 26. April 2021, 08:30
von Sirius3
Das mit dem in-Operator hast Du falsch verstanden:
Code: Alles auswählen
def select_language():
print("Choose your language: ")
print("1 - English")
print("2 - German")
user_input = input()
if user_input not in ('1', '2'):
raise InputError(user_input, ' is not a valid Input')
return user_input
Besser noch, wäre es das ganze Sprachgewurstel in einer Funktion abzuhandeln:
Code: Alles auswählen
SENCTENCES = {
'English': {
"welcome" : "\nwelcome!\n",
"requirements" : "\nThe password should have the following requirements:\n"
"- At least 8 characters\n"
"- At least one capital letter\n"
"- At least one lowercase letter\n"
"- At least one number\n"
"- At least one special character\n",
"main_menu" : "\n1 - Password checker\n"
"2 - Password generator\n"
"q - Exit program\n",
"wrong_input": "\nPlease enter a valid value\n",
"password_input": "\nPlease enter a password: ",
"success": "\nThe password is OK!",
"wrong_length": "- Too short",
"no_uppercase": "- No capital letter",
"no_lowercase": "- Contains no lower case letter",
"no_digit": "- Does not contain a number",
"no_special": "- No special characters included",
"length" : "Password length (8-20): "
},
'German': {
"welcome" : "\nHerzlich Willkommen!\n",
"requirements" : "\nFolgende Anforderungen sollte das Passwort haben:\n"
"- Mindestens 8 Zeichen\n"
"- Mindestens ein Großbuchstabe\n"
"- Mindestens ein Kleinbuchstabe\n"
"- Mindestens eine Zahl\n"
"- Mindestens eine Sonderzeichen\n",
"main_menu" : "\n1 - Passwort Überprüfer\n"
"2 - Passwort Generator\n"
"q - Programm beenden\n",
"wrong_input" : "\nBitte gib einen gültigen Wert ein\n",
"password_input" : "\nBitte geben Sie ein Passwort ein: ",
"success" : "\nDas Passwort ist OK!",
"wrong_length" : "- Zu Kurz",
"no_uppercase" : "- Kein Großbuchstabe enthalten",
"no_lowercase" : "- Kein Kleinbuchstabe enthalten",
"no_digit" : "- Keine Zahl enthalten",
"no_special" : "- Kein Sonderzeichen enthalten",
"length" : "Passwortlänge(8-20): "
}
}
def select_language():
languages = list(SENCTENCES)
while True:
print("Choose your language: ")
for index, language in enumerate(languages, 1):
print(f"{index} - {language}")
user_input = input()
try:
index = int(user_input) - 1
if 0 <= index < len(languages):
break
except ValueError:
pass
return SENCTENCES[languages[index]]
Re: Passwortprüfer/generator
Verfasst: Montag 26. April 2021, 08:44
von Domroon
@__blackjack__:
vielen dank für die verbesserte verifiy_password - Funktion

Diese hat meinen Kopf ganz schön zum Rauchen gebracht. Nach vielem nachlesen habe ich diese nun aber Verstanden. Zum einen war ich zunächst über die zwei Iteratoren "test_result" und "message_key" verwirrt, da ich nicht wusste, dass man auch zwei verwenden kann
Auch "message_key" vor der "for-Schleife" hat mich aus der Bahn geworfen, meine es aber nun verstanden zu haben.
In den ganzen sets die du erstellst gibt es also immer zwei Elemente: Ein boolean und einen String. Da du message_key vor die for-schleife geschrieben hast, wird der jeweilige string immer in die liste geschrieben, mit der Vorraussetzung, dass "test_result" nicht richtig ist.
Ich habe Deine Funktion ausprobiert und Sie funktioniert natürlich. Sie gibt mir eine Liste mit "Fehler-Strings" aus die ich außerhalb der Funktion vernünftig auswerten kann.
Nur eine Sache: Kannst Du mir einen Link zu Generatoren schicken, welcher mir diesen Teil das Programms genauer beschreibt:
Code: Alles auswählen
[message_key for test_result, message_key in liste if not test_result]
Meine Literatur konnte diesen Codesschnipsel leider nicht ausreichend beleuchten, bzw. ich bekomme diesen Schnipsel nicht getestet
Re: Passwortprüfer/generator
Verfasst: Montag 26. April 2021, 09:37
von __blackjack__
„List comprehensions“ werden im Tutorial in der Python-Dokumentation hier erklärt:
https://docs.python.org/3.6/tutorial/da ... rehensions
Re: Passwortprüfer/generator
Verfasst: Montag 26. April 2021, 17:20
von Domroon
@Sirius3:
Auch Deine bessere Version von der Funktion 'select_language()' hat mein Hirn zum schmelzen gebracht
Ich finde Deine Version super, da ich nun "SENTENCES" in eine einzige Textdatei auslagern könnte und außerdem beliebig viele andere Sprachen hinzufügen kann ohne etwas am Code anpassen zu müssen.
Ich meine Deine Version von 'select_language()' verstanden zu haben. Du hast folgendes gemacht:
- zunächst hast du alle Sätze in zwei separate Dictionarys (English und German) gesteckt, welche du wiederum in ein Dictionary 'SENTENCES' gesteckt hast
- dies gibt Dir nun die Möglichkeit die Sprachen mit enumerate() zu nummerieren und ordentlich auszugeben
- durch Deine while-Schleife in Kombination mit dem try-except-Block erreichst Du, dass das Benutzer so lange "festhängt" bis er eine gültige Eingabe macht
- ist die Eingabe gültig, so gibt die Funktion das Dictionary 'English' oder 'German' zurück (und bei Bedarf noch viele andere Sprachen)
Dementsprechend habe ich nun die main-Funktion angepasst (diese ist durch diese Lösung nun wesentlich kleiner geworden):
Code: Alles auswählen
def main():
user_input = None
sentences = None
# Language Menu
sentences = select_language()
print(sentences["welcome"])
# Main Menu
print(sentences["main_menu"])
while True:
user_input = input('input: ')
if user_input == '1':
message_list = verify_password(input(sentences["password_input"]))
for message in message_list:
print(sentences[message])
if message_list == []:
print(sentences["success"])
print(sentences["main_menu"])
elif user_input == '2':
while True:
try:
length = int(input(sentences["length"]))
password_generation(length, sentences)
break
except InputError:
print(sentences["wrong_input"])
print(sentences["main_menu"])
elif user_input == 'q':
break
else:
print(sentences["wrong_input"])
if user_input == "q":
break
Re: Passwortprüfer/generator
Verfasst: Montag 26. April 2021, 19:33
von Domroon
Hallo nochmal,
bei der Konstanten 'SENTENCES' kam mir direkt JSON in den Sinn, weil diese fast die gleich Struktur besitzt. Also habe ich mit ein paar kleinen Änderungen eine 'languages.json'-Datei erstellt.
Damit ich diese in mein Programm laden kann habe ich eine Funktion 'load_languages()' erstellt.
dict.fromkeys(seq, [value]) schien mir sehr passend zu sein um die json-Datei in ein "2 Dimensionales" Dictionary umzuformen.
Ich habe keinen Weg gefunden verschiedene Werte(in meinem Fall natürlich Dictionaries) für unterschiedliche Keys zuzuweisen.
Nachfolgend der betroffene Code:
languages.json:
Code: Alles auswählen
{
"English": {
"welcome" : "\nwelcome!\n",
"requirements" : "\nThe password should have the following requirements:\n- At least 8 characters\n- At least one capital letter\n- At least one lowercase letter\n- At least one number\n- At least one special character\n",
"main_menu" : "\n1 - Password checker\n2 - Password generator\nq - Exit program\n",
"wrong_input": "\nPlease enter a valid value\n",
"password_input": "\nPlease enter a password: ",
"success": "\nThe password is OK!",
"wrong_length": "- Too short",
"no_uppercase": "- No capital letter",
"no_lowercase": "- Contains no lower case letter",
"no_digit": "- Does not contain a number",
"no_special": "- No special characters included",
"length" : "Password length (8-20): "
},
"German" : {
"welcome" : "\nHerzlich Willkommen!\n",
"requirements" : "\nFolgende Anforderungen sollte das Passwort haben:\n- Mindestens 8 Zeichen\n- Mindestens ein Großbuchstabe\n- Mindestens ein Kleinbuchstabe\n- Mindestens eine Zahl\n- Mindestens eine Sonderzeichen\n",
"main_menu" : "\n1 - Passwort Überprüfer\n2 - Passwort Generator\nq - Programm beenden\n",
"wrong_input" : "\nBitte gib einen gültigen Wert ein\n",
"password_input" : "\nBitte geben Sie ein Passwort ein: ",
"success" : "\nDas Passwort ist OK!",
"wrong_length" : "- Zu Kurz",
"no_uppercase" : "- Kein Großbuchstabe enthalten",
"no_lowercase" : "- Kein Kleinbuchstabe enthalten",
"no_digit" : "- Keine Zahl enthalten",
"no_special" : "- Kein Sonderzeichen enthalten",
"length" : "Passwortlänge(8-20): "
}
}
Nachfolgend die Funktion, welche natürlich nicht wie gewünscht funktioniert. Der Wert von Englischen Key wird einfach vom Deutsch Key überschrieben
load_languages():
Code: Alles auswählen
def load_languages():
with open('languages.json', 'r') as file:
data = json.load(file)
# convert data to right dictionary-structure
selected_languages = ["English", "German"]
for language in selected_languages:
languages = dict.fromkeys(selected_languages, data[language])
return languages
Re: Passwortprüfer/generator
Verfasst: Montag 26. April 2021, 19:55
von Sirius3
Die Struktur ist schon richtig. Kein Bedarf, da was zu modifizieren:
Code: Alles auswählen
def load_languages():
with open('languages.json', 'rb') as file:
return json.load(file)
Re: Passwortprüfer/generator
Verfasst: Dienstag 27. April 2021, 08:02
von Domroon
@ Sirius3:
Wow das war einfach
Ich habe "load_languages()" entsprechend verändert und musste daher in "select_language()" nur SENTENCES durch "load_languages()" austauschen und zusätzlich muss ich das dictionary ohne in einer Liste verpackt zu sein in eine Variable 'sentences' speichern. Schöne Sache. Vielen Dank

Die Konstante "SENTENCES" kann ich somit aus dem Programm entfernen
Code: Alles auswählen
def select_language():
languages = list(load_languages())
sentences = load_languages()
while True:
print("Choose you language: ")
for index, language in enumerate(languages, 1):
print(f"{index} - {language}")
user_input = input()
try:
index = int(user_input) - 1
if 0 <= index < len(languages):
break
except ValueError:
pass
return sentences[languages[index]]
Re: Passwortprüfer/generator
Verfasst: Dienstag 27. April 2021, 08:35
von Domroon
Ich habe einen kleinen Bug in 'password_generation()' korrigiert. Das Problem war, dass das generierte Passwort manchmal zu lang war. Wenn man zum Beispiel die Eingabe '8' tätigte so kam es vor, dass das Passwort teilweise bis zu 24-Zeichen lang war. Dies hing damit zusammen, dass die Funktion so lange ein neues Passwort generiert bis es alle Kriterien erfüllt ein gutes Passwort zu sein. Ich habe den Fehler gemacht diese "Versuche" mit an den Passwort-String anzuhängen
Die Verbesserung: Jedesmal wenn das Passwort nicht die Kriterien erfüllt wird der Variable 'password' ein leerer String zugewiesen:
Code: Alles auswählen
def password_generation(length, sentences):
if length < 8 or length > 20:
raise InputError(length, ' is not a valid Input')
password = ""
while True:
for i in range(length):
all_signs = string.ascii_uppercase
all_signs += string.ascii_lowercase
all_signs += string.digits
all_signs += string.punctuation
password = password + choice(all_signs)
if verify_password(password) == []:
break
else:
password = ""
print("\n" + password + "\n")
Re: Passwortprüfer/generator
Verfasst: Dienstag 27. April 2021, 08:58
von Sirius3
In `select_language` lädst Du die Datei jetzt unnötigerweise zwei mal.
Auch in `password_generation` machst Du Dinge mehrfach, die nicht nötig wären. Variablen initialisiert man und resetted sie nicht.
Code: Alles auswählen
ALL_SIGNS = (string.ascii_uppercase
+ string.ascii_lowercase
+ string.digits
+ string.punctuation
)
def password_generation(length, sentences):
if not 8 <= length <= 20:
raise InputError(length, ' is not a valid Input')
while True:
password = ""
for i in range(length):
password += choice(ALL_SIGNS)
if verify_password(password) == []:
break
print(f"\n{password}\n")
Die Schleife kann man noch einsparen:
Code: Alles auswählen
password = "".join(random.choices(ALL_SIGNS, k=length))
Re: Passwortprüfer/generator
Verfasst: Dienstag 27. April 2021, 11:15
von Domroon
@Sirius3:
Die Datei wird in 'select_language()' nun nur noch einmal geladen:
Code: Alles auswählen
def select_language():
sentences = load_languages()
languages = list(sentences)
while True:
print("Choose you language: ")
for index, language in enumerate(languages, 1):
print(f"{index} - {language}")
user_input = input()
try:
index = int(user_input) - 1
if 0 <= index < len(languages):
break
except ValueError:
pass
return sentences[languages[index]]
'password_generation()' habe ich nun mit all deinen Tipps verbessert. Die Konstante 'ALL_SIGNS' habe ich in die Funktion gepackt, weil ich sie in keiner anderen Funktion brauche. Oder hattest Du eine bestimme Intention diese global verfügbar zu machen?
Code: Alles auswählen
def password_generation(length):
ALL_SIGNS = (string.ascii_uppercase
+ string.ascii_lowercase
+ string.digits
+ string.punctuation
)
if not 8 <= length <= 20:
raise InputError(length, ' is not a valid Input')
while True:
password = "".join(choices(ALL_SIGNS, k=length))
if verify_password(password) == []:
break
print(f"\n{password}\n")
Ich finde es krass wie viel Code man durch gute Überlegungen in Python einsparen kann. Danke das ihr mir dabei helft. Das bringt mich jedes mal ein Stück näher zu besserem zukünftigen Code

Re: Passwortprüfer/generator
Verfasst: Dienstag 27. April 2021, 11:29
von Sirius3
Die main-Funktion ist noch viel zu lang.
Die Initialisierung von `user_input` und `sentences` mit None wird nicht gebraucht.
`main_menu` kommt drei mal im Code vor. Und ›user_input == 'q'‹ wird zweimal abgefragt.
Code: Alles auswählen
def select_main_menu(sentences):
print(sentences["main_menu"])
while True:
user_input = input('input: ')
if user_input in ["1", "2", "q"]:
break
print(sentences["wrong_input"])
return user_input
def check_password(sentences):
password = input(sentences["password_input"])
messages = verify_password(password)
if not messages:
print(sentences["success"])
else:
for message in messages:
print(sentences[message])
def generate_password(sentences):
while True:
try:
length = int(input(sentences["length"]))
password_generation(length, sentences)
break
except (InputError, ValueError):
print(sentences["wrong_input"])
def main():
# Language Menu
sentences = select_language()
print(sentences["welcome"])
while True:
user_input = select_main_menu(sentences)
if user_input == '1':
check_password(sentences)
elif user_input == '2':
generate_password(sentences)
elif user_input == 'q':
break
else:
assert False, "not possible"
Re: Passwortprüfer/generator
Verfasst: Dienstag 27. April 2021, 19:16
von Domroon
@Sirius3:
Super! Durch diese "Wrapper-Funktionen" (wenn man Sie so nennen kann) sieht die main-Funktion gleich viel aufgeräumter und eleganter aus

Hab alles implementiert und es funktioniert super. Vielen Dank!
Mir ist beim weiteren austesten ein weiterer Bug aufgefallen. Nehmen wir zum Beispiel das Passwort "a!1aAa87a". Dies ist ja eigentlich ein gültig Passwort und "Zu kurz" ist es auf keinen Fall

Genau das aber zeigte mir das Programm an. Das Problem konnte ich in der Funktion 'verify_password()' ausmachen. Hier wurde die Variable 'password' etwas "zu früh" in ein Set umgewandelt. In einem Set kann ja nichts doppelt vorkommen und dementsprechend werden die vielen kleinen 'a' in dem Passwort nicht mitgezählt uns das Passwort ist schlicht zu kurz
Hier der verbesserte Code (in 'password_length' speicher ich die Länge des Strings bevor er zu einem set umgewandelt wird):
Code: Alles auswählen
def verify_password(password):
password_length = len(password)
password = set(password)
return [
message_key
for test_result, message_key in [
(password_length >= 8, "wrong_length"),
*(
(password.intersection(characters), message_key)
for characters, message_key in [
(string.ascii_uppercase + "ÄÖÜ", "no_uppercase"),
(string.ascii_lowercase + "äöüß", "no_lowercase"),
(string.digits, "no_digit"),
(string.punctuation, "no_special"),
]
)
]
if not test_result
]
Re: Passwortprüfer/generator
Verfasst: Dienstag 27. April 2021, 20:19
von ThomasL
Ich bin kein Experte für Kryptographie aber mein gesunder Sachverstand sagt mir, dass "a!1aAa87a" kein gutes Passwort ist.
Das kleine a kommt da imho zu oft drin vor. Ich würde keine gleichen Zeichen erlauben.
Re: Passwortprüfer/generator
Verfasst: Dienstag 27. April 2021, 20:25
von __blackjack__
@ThomasL: Das würde den Suchraum aber deutlich Einschränken wenn der Angreifer weiss, dass kein Zeichen mehr als Einmal vorkommen kann.
Re: Passwortprüfer/generator
Verfasst: Mittwoch 28. April 2021, 06:18
von ThomasL
Stimmt, nicht bedacht.