diff --git a/Readme.md b/Readme.md index 2d33c286df09734cbf0eee510e4cd6b8bbdbcfc1..f61f8461749284a50e5e27227923db94c96c2332 100644 --- a/Readme.md +++ b/Readme.md @@ -18,7 +18,8 @@ ## Todo -+ [ ] Traduction ++ [X] Commentaires ++ [X] Traduction + [ ] Nom + [ ] Readme + [X] Licence AGPL @@ -29,6 +30,8 @@ + [X] Noms + [ ] Packages + [ ] Installeur ++ [ ] Service systemd ++ [ ] Tests ## Licences diff --git a/src/console.py b/src/console.py index b8dc59c1616ffd73214c1a171d582876de409f3d..223f74ee394947f9e4d9e27cd0f00b74041fb8df 100644 --- a/src/console.py +++ b/src/console.py @@ -30,6 +30,4 @@ while True: break user_inputs.append(word) -lines = test_pass(passwd, user_inputs) -for line in lines: - print(line) +print(test_pass(passwd, user_inputs)) diff --git a/src/index.py b/src/index.py index 029e8acf607d3496b204dae4c568de9fef60e70d..5fda04d2a43ba235e4654f4edff0b6b50aea33f5 100755 --- a/src/index.py +++ b/src/index.py @@ -18,6 +18,7 @@ import cgi import re +from markdown import markdown from test_pass import test_pass form = cgi.FieldStorage() @@ -44,7 +45,9 @@ Tetras Pass if form.getvalue("password") is None: # Password not defined => show the form passwordPrompt = "Veuillez saisir le mot de passe à tester ci dessous :" - inputsPrompt = "Veuillez saisir une liste d'indices : mots ou de dates au format jj/mm/yyyy, un indice par ligne:" + inputsPrompt = """Veuillez entrer des indices pour aider à trouver le mot de passe.<br /> + Les indicides peuvent être des mots ou des dates au format jj/mm/yyyy.<br/> + Entrez un indice par ligne:""" sendPrompt = "Lancer le test" html += """ @@ -70,31 +73,14 @@ else: else: inputs = None # Retrieve results - lines = test_pass(form.getvalue("password"), inputs) - # Process results for the web - html += "<h2> {} </h2>".format(lines.pop(0)) - inlist = False - for line in lines: - line = re.sub('\*\*(.*)\*\*', '<em>\g<1></em>', line) - if line[0] == "\t": - if inlist: - html += "<li>{}</li>".format(line) - else: - inlist = True - html += "<ul><li>{}</li>".format(line) - elif line[0] != "\n": - if inlist: - html += "</ul>" - inlist = False - html += "<h3>{}</h3>".format(line) + html += markdown(test_pass(form.getvalue("password"), inputs)) html += """ -</div> -</div> </body> <foot> +<div id="foot"> <p> -<a href="https://gitlab.tetras-libre.fr/tetras-libre/tetras-pass">Tetra Pass</a> est Logiciel développé par +<a href="https://gitlab.tetras-libre.fr/tetras-libre/tetras-pass">Tetras Pass</a> est Logiciel développé par <a href="http://tetras-libre.fr">Tetras Libre</a>, distribué sous Licence <a href="https://www.gnu.org/licenses/agpl.html">AGPL</a> V3.0. </p> @@ -107,7 +93,10 @@ Le testeur de mot de passe est basé sur la bibliothèque Les listes de mots et noms français proviennent de <a href="http://www.lexique.org/">lexique.org</a> et sont distribués sous licence <a href="https://www.gnu.org/licenses/gpl-3.0.txt">GPL</a>. </p> +</div> </foot> +</div> +</div> </html> """ diff --git a/src/test_pass.py b/src/test_pass.py index 2ffdcb995205d106b86b0785159e5ccbaece429b..c951158ef56d8cf7daa55f9526ac4f548cbffb5d 100644 --- a/src/test_pass.py +++ b/src/test_pass.py @@ -23,6 +23,20 @@ from zxcvbn import zxcvbn from zxcvbn.matching import add_frequency_lists from translations import tr +comments = { + 'offline_fast_hashing_1e10_per_second': + "L'attaquant.e a accès à une base de donnée d'un site sur lequel vous êtes inscrit et cette base de donnée " + "est mal protégée", + 'offline_slow_hashing_1e4_per_second': + "L'attaquant.e a accès à une base de donnée d'un site sur lequel vous êtes inscrit et cette base de donnée est " + "bien protégée", + 'online_no_throttling_10_per_second': + "L'attaquant.e essaye de forcer votre mot de passe en ligne, aucune protection anti brute force n'est activée", + 'online_throttling_100_per_hour': + "L'attaquant.e essaye de forcer votre mot de passe en ligne, une protection anti brute force n'est activée", +} + + def add_dictionnaries(): dicts = {} directory = os.path.dirname(os.path.realpath(__file__))+'/../data' @@ -38,7 +52,7 @@ def add_dictionnaries(): # Process user inputs: # Generate all possibile combinations of 2 parts of dates def process_input(inputs): - try : + try: dates = [] words = [] for i in inputs: @@ -55,56 +69,72 @@ def process_input(inputs): return None +# Print results formated in markdown def test_pass(password, inputs): # Read input add_dictionnaries() results = zxcvbn(password, process_input(inputs)) - lines = [] + lines = "" - lines.append("Résultats du test\n") - lines.append("Nombre de tentatives : {}".format(results["guesses"])) + lines += "## Résultats du test\n\n" + lines += "\n\n" + + valeur = ["Très faible", "Faible", "Tolérable", "Correct", "Bon"] + lines += "\n### Qualité du mot de passe \n\n" + lines += "+\tNombre de tentatives pour trouver votre mot de passe : **{}**\n".format(results["guesses"]) + lines += "+\tScore : **{}/4**\n".format(results["score"]) + lines += "+\tJugement : **{}**\n".format(valeur[results["score"]]) - lines.append("Temps requis pour craquer votre mot de passe") - for key, value in results["crack_times_display"].items(): - lines.append("\t "+tr(key).capitalize()+" :\t **"+tr(value)+"**") - lines.append("\n") - lines.append("Methode de hack utilisées") + lines += "### Temps requis pour craquer votre mot de passe selon le type d'attaque\n" + lines += "\n\n" + for key, value in sorted(results["crack_times_display"].items()): + lines += "+\t"+tr(key).capitalize()+" :\t **"+tr(value)+"**\n\n" + lines += "\t*Expliquation :* "+comments[key]+", l'attaquant.e vise votre utilisateur en particulier.\n\n" + + lines += "\n\n" + lines += "### Methode de hack utilisées\n" + lines += "\n\n" + lines += "Voici la liste des techniques utilisées pour trouver votre mot de passe : \n\n" + prefix = "Votre mot de pass ou une partie de votre mot de passe a été trouvé" # Print hack methods for seq in results["sequence"]: if seq["pattern"] == "bruteforce": - lines.append("\tMot de passe trouvé par force brute") + lines += "+\tMot de passe trouvé par force brute\n\n" + lines += "\t{} en testant différentes combinaisons\n\n".format(prefix) elif seq["pattern"] == "repeat": for match in seq["base_matches"]: - line = "\tMot de passe trouvé par répétitions depuis" + line = "+\tMot de passe trouvé par répétitions depuis" try: line += "le dictionnaire '{}'".format(tr(match["dictionary_name"])) except: line += "le motif '{}'".format(tr(match["token"])) finally: - lines.append(line) + lines += line+"\n" + lines += "\t{} en répétant un motif ou mot connu\n\n".format(prefix) elif seq["pattern"] == "date": - lines.append("\tMot de passe trouvé par essai de dates") + lines += "+\tMot de passe trouvé par essai de dates\n\n" + lines += "\t{} est une date, récente facile à deviner\n\n".format(prefix) elif seq["pattern"] == "sequence": - lines.append("\tMot proche trouvé dans la séquence : '{}'".format(tr(seq["sequence_name"]))) + lines += "+\tMot proche trouvé dans la séquence : '{}'\n\n".format(tr(seq["sequence_name"])) + lines += "\t{} est une séquence de caractères facile à deviner\n\n".format(prefix) else: - lines.append("\tMot proche trouvé dans le dictionnaire : '{}'".format(tr(seq["dictionary_name"]))) + lines += "+\tMot proche trouvé dans le dictionnaire : '{}'\n\n".format(tr(seq["dictionary_name"])) + lines += "\t{} est dans un dictionnaire de mots connus\n\n".format(prefix) - lines.append("\n") + lines += "\n### Problemes et conseils\n" for key, values in results["feedback"].items(): if values != [] and values != "": - lines.append("{} :".format(tr(key).capitalize())) + lines += "\n\n" + lines += "#### {}\n\n".format(tr(key).capitalize()) else: continue if not isinstance(values, list): # Simplify things by always using lists values = [values] for val in values: - lines.append("\t{}".format(tr(val))) - - valeur = ["Très faible", "Faible", "Tolérable", "Correct", "Bon"] - lines.append("Score Global {}/4 : {}".format(results["score"], valeur[results["score"]])) + lines += "+\t{}\n".format(tr(val)) return lines diff --git a/src/translations.py b/src/translations.py index 1dac12b30b195228213bf280c0eb0ce0b50b25d3..e9b77f36b45e49389cc594d7fd8215d72aa6cb8b 100644 --- a/src/translations.py +++ b/src/translations.py @@ -27,7 +27,7 @@ translations = { 'online_throttling_100_per_hour': 'Essai en ligne avec protection anti brute force', 'passwords': 'mots de passes', 'surnames': 'nom de famille', - 'user_input': "indices données par l'attaquant.e", + 'user_inputs': "indices données par l'attaquant.e", 'suggestions': 'conseils', 'warning': 'problèmes', 'less than a second': "moins d'une seconde", @@ -77,15 +77,14 @@ substitutions = { 'All-uppercase is almost as easy to guess as all-lowercase': 'Les mots en majuscules sont aussi simple à deviner que ceux en minuscules', "Reversed words aren't much harder to guess": 'Les mots inversés ne sont pas beaucoup plus dur à deviner', - } def tr(text): try: - return translations[text] + text = translations[text] except: - # Todo use regex for pattern, sub in substitutions.items(): text = re.sub(pattern, sub, text) + finally: return text