Projet: programme création de mot de passe

Hello!

Je travaille sur un programme qui permet de générer un mot de passe fort à partir de 3 (ou 2 ou 5) mots faciles à retenir, l’intérêt c’est surtout de créer des mots de passe destinés aux programmes gestionnaires de mots de passe (Firefox, Tunderbird…), car soit on utilise des mots de passe « biscornus » pour éviter qu’un programme espion vienne casser le cryptage mais très ch…t à l’utilisation, soit on utilise un mot de passe très intuitif qui pourrait être facilement casé en force brute.

C’est donc ce que je souhaite solutionner avec ce programme.
Je n’espère évidement pas rivaliser avec un cryptage au sens propre du terme

j’ai déjà avancé « pas mal », il manque 2 fonctions que je voudrait ajouter:

  • un étage de passage en majuscule/minuscule
  • un étage de « personnalisation » pour que le mot de passe généré soit « unique » pour un utilisateur donné
#!/usr/bin/env python3
# coding: utf-8
# la 1e ligne indique au systéme que le programme est écrit en Python3, ce n'est pas un commentaire
# la 2e ligne permet de declarer le codage du texte, ce n'est pas un commentaire
version= "v0.2i+"
date_version= "14/12/2020 "
# paramétres par défaut
# nombre de mots en entrée:
NbrePsw=3
# définition de la langue par défaut:
lang="fr"
# "fr" : français
# "es" : espanol
# "en" : english
# prise en charge linguistique 
# messages dédiés à une seule langue
description_fr="programme de fusion de mots de passe pour en obtenir un meilleur"
description_es="programa para fusionar password y tener un mejor"
description_en="melting password program to create a better one"
hlp_fr="en langue française"
hlp_es="en idioma espagnola"
hlp_en="in english"
# messages d'aide traduits en plusieurs langues
if   lang=="fr":
    description= description_fr
    hlp_ver    = "affiche la version"
    hlp_vinfo  = "affiche les notes de version"
    hlp_stat   = "affiche les statistiques"
    hlp_stat0  = "n'affiche pas les statistiques"
    hlp_stat1  = "affiche les statistiques (résumé)"
    hlp_stat2  = "affiche les statistiques (complets)"
    hlp_notice = "affiche la notice d'utilisation"
    hlp_c2     = "mot de passe créé avec 2 mots en entrée"
    hlp_c3     = "mot de passe créé avec 3 mots en entrée"
    hlp_c5     = "mot de passe créé avec 5 mots en entrée"
elif lang=="es":
    description= description_es+"\ntraduccion inconpleta"
    hlp_ver    = "muestra la version"
    hlp_vinfo  = "affiche les notes de version"
    hlp_stat   = "indica las statisticas"
    hlp_stat0  = "no indica las statisticas"
    hlp_stat1  = "indica las statisticas (resumen)"
    hlp_stat2  = "indica las statisticas (todos)"
    hlp_notice = "indica la noticia de utilisation"
    hlp_c2     = "mot de passe créé avec 2 mots en entrée"
    hlp_c3     = "mot de passe créé avec 3 mots en entrée"
    hlp_c5     = "mot de passe créé avec 5 mots en entrée"
elif lang=="en":
    description= description_en+"\ntranslation incomplet"
    hlp_ver    = "display version"
    hlp_vinfo  = "affiche les notes de version"
    hlp_stat   = "display statistics"
    hlp_stat0  = "no indica las statisticas"
    hlp_stat1  = "display statistics (resumen)"
    hlp_stat2  = "display statistics (todos)"
    hlp_notice = "display notice of use"
    hlp_c2     = "password created with 2 word given"
    hlp_c3     = "password created with 3 word given"
    hlp_c5     = "password created with 5 word given"
# définition des modes de fonctionnement par défaut
# affichage des statistiques
# (0:non, 1:résumé, 2:complets):
stat=0
# affichage de l'évolution du mot de passe
# (1:oui, 0:non):
evol=1
# autorisation message humouristique
fun=1
# initialisation
import argparse
import sys
parser = argparse.ArgumentParser(description=description)
# la description est visible lors de l'utilisation de -h ou --help
parser.add_argument("-notice" , help=hlp_notice, action="store_true")
parser.add_argument("-c2"     , help=hlp_c2   , action="store_true")
parser.add_argument("-c3"     , help=hlp_c3   , action="store_true")
parser.add_argument("-c5"     , help=hlp_c5   , action="store_true")
parser.add_argument("-fr"     , help=hlp_fr   , action="store_true")
parser.add_argument("-es"     , help=hlp_es   , action="store_true")
parser.add_argument("-en"     , help=hlp_en   , action="store_true")
parser.add_argument("-stat"   , help=hlp_stat , action="store_true")
parser.add_argument("-stat0"  , help=hlp_stat0, action="store_true")
parser.add_argument("-stat1"  , help=hlp_stat1, action="store_true")
parser.add_argument("-stat2"  , help=hlp_stat2, action="store_true")
parser.add_argument("-ver"    , help=hlp_ver  , action="store_true")
parser.add_argument("-verinfo", help=hlp_vinfo, action="store_true")
args = parser.parse_args()
# définition des messages, prise en charge linguistique
if not args.fr and not args.es and not args.en:
    if   lang=="fr": args.fr=1
    elif lang=="es": args.es=1
    elif lang=="en": args.en=1
if   args.fr: 
    lang="fr"
    description = description_fr
    errFatal_msg="erreur fatale: arret du programme"
    XPsolve_msg ="solution expérimentale non optimale"
    if fun:
        DdeIncoé_msg="bah, il faudrait se décider!"
    else:
        DdeIncoé_msg="demande incohérente"
elif args.es:
    lang="es"
    description = description_es
    errFatal_msg="falta critica: asi para el programa"
    XPsolve_msg ="tratamiento experimental non optimale"
    if fun:
        DdeIncoé_msg="bah, il faudrait se décider!"
    else:
        DdeIncoé_msg="demande incohérente"
elif args.en:
    lang="en"
    description = description_en
    errFatal_msg="erreur fatale: end of program"
    XPsolve_msg ="experimental way non optimal"
    if fun:
        DdeIncoé_msg="hey, what do you ask me?"
    else:
        DdeIncoé_msg="demande incohérente"
# message de démarrage
print(description)
print("FusePassWord", version,"du",date_version)
# affichage numéro de version et notes de version:
if args.ver or args.verinfo or args.notice:
    # no version et date de la version déjà indiqués
    if args.notice:
        print("intérêt du programme:\n génére un mot de passe fort à partir de mots faciles à retenir")
        print("attention l'ordre des mots compte! (pour l'instant)")
        print(' option "-c2" => 2 mots 5 à  8=> 1 mot de 10 à >15 ~ >200 *10^ 6 combinaisons')
        print(' option "-c3" => 3 mots 6 à 12=> 1 mot de 18 à >36 ~ >15  *10^12 combinaisons') 
        print(' option "-c5" => 5 mots 6 à 18=> 1 mot de 30 à >90 ~ > 9  *10^21 combinaisons')
# https://motsavec.fr/
#1: estimé sur la base de 15000 mots de 5 caractéres dans le dico français
#2: estimé sur la base de 25000 mots de 6 caractéres dans le dico français
        print('Notes:\n -la longueur maximale du mot est évaluée sur le nombre de caractéres différents, pas sur le nombre total')
        print(' -les espaces ne comptent pas, ils sont immédiatement supprimés')
        print('conseils:\n -éviter les dates (sur 4 caractéres: 365 combinaisons, comparé à 7000 mots français)')
    if args.verinfo:
        if lang=="en": print("yes... the programateur is français, j'écris en français! :p ")
        if lang=="es": print("hola amig@! perdoname no traducir este parafo...")
        print("un + à la fin => évolution ajoutée à la version indiquée\n")
        # print("un - à la fin => évolution pour préparer la version indiquée \n")
        print("v0.1 : premiére version fonctionnelle (incompatible avec futures versions)")
        print("v0.2 : amélioration méthode de fusion + création d'une gestion de mots en entrée de taille trés différentes")
        print("v0.2a -> v0.2f: versions expérimentales, améliorations")
        print("v0.2g: version expérimentale fonctionelle, mise en place de fonctions intégrées")
        print("v0.2h: version expérimentale fonctionelle, sauvegarde avant mise en service d'une boucle")
        print("v0.2i: version expérimentale fonctionelle, sauvegarde après mise en service d'une boucle")
    sys.exit(1)
# sélection de l'affichage des infos statistiques
if args.stat or args.stat0 or args.stat1 or args.stat2:
    if args.stat + args.stat0 + args.stat1 + args.stat2>1:
        print(DdeIncoé_msg)
        stat=2
    elif args.stat:
        stat=1
    elif args.stat0:
        stat=0
    elif args.stat1:
        stat=1
    elif args.stat2:
        stat=2
# sélection du nombre de mots en entrée
if args.c2 or args.c3 or args.c5:
    if args.c2 + args.c3 + args.c5>1:
        print(DdeIncoé_msg)
        print(errFatal_msg)
        sys.exit(1)
    elif args.c2:
        NbrePsw=2
    elif args.c3:
        NbrePsw=3
    elif args.c5:
        NbrePsw=5
if   NbrePsw==2:
    lenmotmin=5
    lenmotmax=8
elif NbrePsw==3:
    lenmotmin=6
    lenmotmax=12
elif NbrePsw==5:
    lenmotmin=6
    lenmotmax=18
nombre   ="0123456789"
majuscule="ABCDEFGHIJKLMNOPQRSTUVWXYZ"
minuscule="abcedfghijklmnopqrstuvwxyz"
# symboles supprimés:
symbolSup=[" ",":","/","'",","]
# symboles conservés:
symbolCon=["@"]
# lettres accuentuées:
accentsFr="éèêà"
# codes internes
# modifier ces codes permettent de personnaliser le programme
# mais les mots de passe générés ne seront plus forcément les mêmes
Cin=[]    
Cin.append("Gi8eclH3fd5")
Cin.append("dlcfixhj4g9")
Cin.append("16485273590")
Cin.append("hxGKEZNXFQLkdj")
Cin.append("mdebosicbqkkgwkdbs")
# matrice numérique type "sudoku":
# 9 suites de 10 chiffres différents
# aucune suite ne posséde un numéro à la même place qu'une autre suite
Cnum=[]     
#Cnum.append(2586479310) #1
#Cnum.append(5014928731) #2
#Cnum.append(8627514093) #3
#Cnum.append(72493816 5) #4
#Cnum.append(6351705428) #5
#Cnum.append(1860932974) #6
#Cnum.append(4192863507) #7
#Cnum.append(9735147286) #8
#Cnum.append(3478690152) #9
#pas encore prêt...
# definition de la fonction de comptage
def compte_all(x):
    Dif     = [numDif, minDif   , majDif]
    Id      = [numId , numId    , majId ]
    variable =[nombre, minuscule, majuscule]
    for y in range (0,3):
        if x>0:
            Dif[y].append(0)
            Id[y].append([0]) # crée une liste dans la liste (de la liste) -ça marche pas
        for var in variable[y]:
            if var in psw[x]: 
                Dif[y][x] +=1
                identique = size[x] - len( str(psw[x]).replace(var,"") )
                if identique>1:
                    if x>0: Id[y][x].append(identique)
                    # x>0 : création d'un nouvel élement dans la liste car ajout d'un mot
                    else  : Id[y][x]=identique
                    # x=0 : bilan la liste est déjà créée
def IdSumIn0(x):
    minId[x][0]=sum(minId[x])-len(minId[x])+1
    majId[x][0]=sum(majId[x])-len(majId[x])+1
    numId[x][0]=sum(numId[x])-len(numId[x])+1
ok=0
while not ok:
    # initialisation des variables
    ok=0
    psw   =[0]  #mot de passe
    size  =[0]  #taille du mot de passe
    numDif=[0]  #nombre de chiffres différents
    minDif=[0]  #nombre de lettres minuscules différentes
    majDif=[0]  #nombre de lettres majuscules différentes
    allDif=[0]  #nombre de caractéres         différents
    numId =[0]  #nombre de chiffres identiques
    minId =[0]  #nombre de lettres minuscules identiques
    majId =[0]  #nombre de lettres majuscules identiques
    allId =[0]  #nombre de caractéres         identiques

    # demande des mots de passe de départ
    for x in range (1,NbrePsw+1):
        ok=0
        while not ok:
            old=1
            while old:
                if   lang=="fr": msg="e mot de passe: "
                elif lang=="es": msg="a palabra: "
                elif lang=="en": msg="st password: "
                msg=str(x)+str(msg)
                new=input(msg)
                old= new in psw
                if old:
                    if   lang=="fr": print("mot déjà utilisé, en choisir un autre")
                    elif lang=="es": print("palabra ya utilisada, elegir una otra")
                    elif lang=="en": print("word yet given, change")
                # vérification si le mot correspond à un autre à l'envers ou avec exactement les mêmes lettres qu'un autre
                # Fonction supprimée
            psw.append(new)
            for var in symbolSup:
                if var in psw[x]:
                    psw[x]=psw[x].replace(var,"")
            size.append( len( str(psw[x]) ) )
            if size[x]<lenmotmin:
                if   lang=="fr": msg="min, ce mot est trop court"
                elif lang=="es": msg="min, esta palabra es demasiada corta"
                elif lang=="en": msg="min, word too small"
                print("",lenmotmin,msg)
            else:
                ok=1
            # nombres
            numDif.append(0)
            numId.append([0]) # crée une liste dans la liste
            for var in nombre:
                if var in psw[x]:
                    numDif[x] +=1
                    identique = size[x] - len( str(psw[x]).replace(var,"") )
                    if identique>1:
                        numId[x].append(identique)
            # minuscules
            minDif.append(0)
            minId.append([0]) # crée une liste dans la liste
            for var in minuscule:
                if var in psw[x]: 
                    minDif[x] +=1
                    identique = size[x] - len( str(psw[x]).replace(var,"") )
                    if identique>1:
                        minId[x].append(identique)
            # majuscules
            majDif.append(0)
            majId.append([0]) # crée une liste dans la liste
            for var in majuscule:
                if var in psw[x]: 
                    majDif[x] +=1
                    identique = size[x] - len( str(psw[x]).replace(var,"") )
                    if identique>1:
                        majId[x].append(identique)
            # calcul et évaluation du mot
            # caractéres identiques
            IdSumIn0(x)
            allId.append( minId[x][0] + majId[x][0] + numId[x][0] )
            # caractéres différents
            allDif.append( minDif[x] + majDif[x] + numDif[x] )
            if   allDif[x]> lenmotmax:
                if   lang=="fr": msg="max, ce mot est trop long"
                elif lang=="es": msg="max, esta palabra es demasiada larga"
                elif lang=="en": msg="max, this word is too long"
                print("",lenmotmax,msg)
                ok=0
            if   allDif[x]> 20: melt=1
            elif numDif[x]>  8: melt=1
            elif   size[x]<= 6 and allDif[x]>= 0.75*size[x]: melt=1
            elif   size[x]<=16 and allDif[x]>=10/16*size[x]: melt=1
            elif   size[x]<=20 and allDif[x]>=12/20*size[x]: melt=1
            elif   size[x]<=25 and allDif[x]>=14/25*size[x]: melt=1
            else:
                if   lang=="fr": print(" ce mot est trop monotone")
                elif lang=="es": print(" esta palabra es demasiada monotona")
                elif lang=="en": print(" this word is too ...")
                ok=0
            if stat:
                print("statistiques du mot d'entrée:")
                print(" -longueur du mot       :",  size[x])
                if stat==2:
                    print(" -chiffres   différents :",numDif[x])
                    print(" -minuscules différentes:",minDif[x])
                    print(" -majuscules différentes:",majDif[x])
                    print(" -caractéres différents :",allDif[x])
                elif stat==1:
                    print(" -caractéres différents :",allDif[x])
                if stat==2:
                    print(" -chiffres   identiques :",numId[x])
                    print(" -minuscules identiques :",minId[x])
                    print(" -majuscules identiques :",majId[x])
                print(" -caractéres identiques :",allId[x])
            if not ok:
                if   lang=="fr": print("\033[33m mot refusé\033[0m, on recommence")
                elif lang=="es": print("\033[33m palabra denegada\033[0m, vamos de nuevo")
                elif lang=="en": print("\033[33m word refused\033[0m, i come back")
                # \033[33m couleur \033[0m => couleur est écrit en orange
                # suppession du mot refusé et des données du mot refusé
                del psw[x]
                del size[x]
                del numDif[x]
                del minDif[x]
                del majDif[x]
                del allDif[x]
                del minId[x]
                del majId[x]
                del numId[x]
                del allId[x]
            else:
                if   lang=="fr": print("\033[32m mot accepté\033[0m")
                elif lang=="es": print("\033[32m palabra aceptada\033[0m")
                elif lang=="en": print("\033[32m word accepted\033[0m")
                # \033[32m couleur \033[0m => couleur est écrit en vert
        if x<NbrePsw: 
                if   lang=="fr": print("=>suivant")
                elif lang=="es": print("=>suivant")
                elif lang=="en": print("=>next")
        else: 
            if   lang=="fr": print("=>prépation au mixage...")
            elif lang=="es": print("=>preparación al mezcla...")
            elif lang=="en": print("=>preparing the mix...")
    # calcul et évaluation globale
    size[0]=sum(size)
    var=""
    for x in range (1,len(psw)):
        var = var + str(psw[x])
    psw[0]= var
    x=0
    compte_all(0)
    #IdSumIn0(0)
    allDif[0]= minDif[0] + majDif[0] + numDif[0]
    if   allDif[x]> 30: melt=1
    elif   size[x]<=16 and allDif[x]>=10/16*size[x]: melt=1
    elif   size[x]<=20 and allDif[x]>=12/20*size[x]: melt=1
    elif   size[x]<=25 and allDif[x]>=14/25*size[x]: melt=1
    elif   NbrePsw== 2 and allDif[x]>=10: melt=1
    elif   NbrePsw== 3 and allDif[x]>=15: melt=1
    else:
        if   lang=="fr": print(" cette combinaison est trop monotone")
        elif lang=="es": print(" esta combinación es demasiada monotona")
        elif lang=="en": print(" this combination is too ...")
        ok=0
    if stat:
        print("statistiques globales:")
        print(" -longueur cumulée des mots:",size)
        if stat==2:
            print(" -chiffres   différents    :",numDif)
            print(" -minuscules différentes   :",minDif)
            print(" -majuscules différentes   :",majDif)
        print(" -caractéres différents    :",allDif)
        if stat==2:
            print(" -chiffres   identiques    :",numId)
            print(" -minuscules identiques    :",minId)
            print(" -majuscules identiques    :",majId)
        print(" -caractéres identiques    :",allId)
    if not ok:
        if   lang=="fr": print("\033[33m combinaison refusée\033[0m, on recommence")
        elif lang=="es": print("\033[33m combinación denegada\033[0m, vamos de nuevo")
        elif lang=="en": print("\033[33m combination refused\033[0m, i come back")
        # \033[33m couleur \033[0m => couleur est écrit en orange
        # suppession du mot refusé et des données du mot refusé
        #initialise()
    else:
        if   lang=="fr": print("\033[32m combinaison accepté\033[0m")
        elif lang=="es": print("\033[32m combinación aceptada\033[0m")
        elif lang=="en": print("\033[32m combination accepted\033[0m")
        # \033[32m couleur \033[0m => couleur est écrit en vert
        ok=1
if evol:
    print("données initiales:")
    print(psw)
# calcul sur les longueurs des mots entrés
# la méthode "liste.index(valeur)" indique la position de la valeur recherchée dans la liste
if 1:
#def sizeCalc(size):
    lst=[]
    var=[]
    for x in range (1,len(size)):
        var=size[x]
        lst.append(var)
    maxSize   =max(lst)
    maxSizeIn =size.index(maxSize)
    minSize   =min(lst)
    minSizeIn =size.index(minSize)
    DeltaSize =maxSize-minSize
    otherSize =size[0]-maxSize
    # otherSize: taille des autres mots
    #return(maxSize, maxSizeIn, minSize, minSizeIn, DeltaSize)
#sizeCalc(size)
# définition de la fonction
def reducePsw(x):
    # suppression des caractéres identiques dans le mot
    if 0<x<NbrePsw:
        msg=str(x)+"e mot"
        if evol: print("réduction ",msg)
        for var in str(minuscule)+str(majuscule)+str(nombre):
            if var in psw[x]:
                identique = len(psw[x]) - len( str(psw[x]).replace(var,"") )
                if identique>1:
                    psw[x]=psw[x].replace(var,"")
            # correction de la longueur de la nouvelle chaine:
            size[x]=len( str(psw[x]) )
            # mise à jour des calculs sur les longueurs des mots entrés:
            #sizeCalc()
    else:
        if evol: print("erreur l'index",x," est refusé par la fonction \"reducePsw\" ")
    return(size,psw)
revlst=[]
reduceAsk=0
# gestion avec 2 mots entrés
if NbrePsw==2:
    if DeltaSize==0:
        revlst=2
    elif DeltaSize<minSize:
        revlst.append(maxSizeIn)
    else:
        print(XPsolve_msg)
        revlst=[minSizeIn]
        reducePsw(maxSizeIn)
# gestion de la taille des mots:
if NbrePsw>2:
    if maxSize>otherSize+1:
    # si le mot le plus grand dépase la somme des autres
        if allDif(maxSizeIn)<otherSize:
            reduceAsk=1
if reduceAsk:
    reducePsw(maxSizeIn)
    #sizeCalc()
# gestion des différences de longueur:
if NbrePsw==3:
    revlst=[1,3] # valeur par défaut
    if   maxSizeIn in [1,3]:
        if DeltaSize<3:
            revlst=[1,3]
        else:
            print(XPsolve_msg)
            revlst=[1,3]      
    else:#  maxSizeIn in [2]:
        if   size[1]+size[3]>size[2]:
            revlst=[1,3]
        elif size[1]+size[3]<size[2]:
            #allDif = minDif[2] + majDif[2] + numDif[2]
            if size[1]+size[3]>=allDif:
                revlst=[1,3]
                reducePsw(maxSizeIn)
            else:
               print("mot trop long par rapport aux autres")
               print(errFatal_msg)
               sys.exit(2)
        elif size[1]+size[3]==size[2]:
            revlst=[2]
if evol: print("liste inversion:",revlst,"\n",psw)
# inversion 
for x in range (1,NbrePsw+1):
    if x in revlst:
        reverse="" # mot à l'envers
        y=0
        for var in reversed(psw[x]):
            y +=1
            reverse=str(reverse)+str(var)
            if size[x]==y:
                psw[x]=reverse
if evol: print("inversion:","\n",psw)
#vérification qu'un mot inversé ne soit pas identique à un mot non inversé
ok=0
while not ok:
    for x in range (1,NbrePsw+1):
        for y in range (1,NbrePsw+1):
            if not x==y:
                if psw[x]==psw[y]:
                    print("erreur: égalité de 2 mots lors de l'inversion")
                    print("",XPsolve_msg,":")
                    if NbrePsw>2:
                        print("","avertissement: faiblesse possible")
                    else:
                        print("",errFatal_msg)
                        sys.exit(2)
    ok=1  
# ne fonctionne pas bien
if evol: print("contrôle anti-égalité après inversion:","\n",psw)
# fusion des x mots de passe (résultat provisoire) 
# x: numéro dans la liste des mots entrés
# y: numéro dans la chaine du mot  entré
# la "bidouille" maxSize est nécésaire sinon le plus grand mot n'est pas "pris en sandwich" et donc pas "déformé"
def Xor(A,B):
    """ou exclusif"""
    Xor=(A and not B) or (B and not A)
    return(Xor)
if maxSizeIn==1: lstDebut=[maxSizeIn,2,4]
if maxSizeIn==2: lstDebut=[maxSizeIn,1,3]
if maxSizeIn==3: lstDebut=[maxSizeIn,2,4]
var=""
for y in range (1,maxSize+1):
    for x in range (1,NbrePsw+1):
        # print(Xor(x%2, maxSizeIn%2),end="-")
        #if (x%2): # si x est impair
        #if Xor(x%2, maxSizeIn%2):
        if x in lstDebut:
            if y<=size[x]:
                var=str(var)+str( str(psw[x])[y-1] )
                # l'écriture commence au début
        else:
            debut= maxSize-len(str(psw[x]))
            if y>=debut:
                var=str(var)+str( str(psw[x])[y-debut-1] )
                # l'écriture se termine à la fin (enfin théoriquement!)
psw[0]=var
if evol:
    print("fusion:")
    print(psw[0])
size[0]= len( str(psw[0]) )
if   lang=="fr": print("\033[34mrésultat final\033[0m (",size[0],"caractéres ):")
elif lang=="es": print("\033[34mrésultado final\033[0m (",size[0],"caractéres ):")
elif lang=="en": print("\033[34mfinal result\033[0m (",size[0],"caractéres ):")
# \033[34m couleur \033[0m => couleur est écrit en bleu
print("",psw[0])

Je sais pas si ça va passer très bien au travers du formatage forum.
Évidement, je demande à personne une solution « tout cuit », par contre quelques pistes/critiques (constructives et pas trop assasines :stuck_out_tongue_closed_eyes:) seraient les bienvenues.

C’est… horrible !

Désolé de te le dire ainsi mais c’est illisible

Tu fais des imports au milieu de rien (cela se fait au départ)

Les programmes ont (généralement) une fonction main() qui est celle qui « dirige » le programme.
Il n’y a aucune fonction (ou si elles existent elles sont perdues au milieu de tout.

Elles se mettent également au début, tu fabriques tes outils puis tu les utilisent dans ta fonction principale (c’est pas 100% ca mais on va simplifier).

En gros le schéma doit être

IMPORTS
VARIABLE GOBALES (même si c’est pas bien à utiliser)
FONCTIONS

PROGRAMME principale

Refait ton code depuis zéro en mode « papier/crayon »

Que dois-je faire? Comment s’appelera ma fonction (avec ses paramètres en entrée, ses paramètres en sortie)

Fait un schéma clair de ce que tu veux faire.

En parcourant ton code je n’ai… aucune idée de ce que cela doit faire, malgré tes commentaires

Et si jamais ce que tu tentes de faire s’appelle un « passphrase » et généralement cela consiste en 4-5mots à la suite sans lien pour faire un mot de passe par exemple :
cheval-pomme-ciel-bouteille
C’est facile à retenir et c’est sécurisé (la longueur fait que c’est complexe à craquer)

Enfin voilà, programmer c’est bien mais il te manque visiblement beaucoup de base, alors reprend à 0, gentiment sans partir dans tout les sens.

Ce n’est que mon avis bien sur

Enfait il te manque 2 types de notions, les bases du langages (le python) et de l’algorithmie.

Commence par comprendre le fonctionne de base d’un programme, sa structure, ses entrées/sorties, puis construit là dessus.

Tout n’est pas mauvais mais il y des cases essentielles qui te manquent et du coup c’est indigeste

C’est vrai que j’ai l’impression d’avoir allourdi le truc au fur et à mesure, même pour moi…

Oui, mais dans ton schéma:

  • quand tu définis des « paramètres par défaut » au travers de variables, tu les place où? Sauf erreur, on est bien obligé de les placer avant « l’import » (si ça s’appelle un import) des « options » de commande. non?
  • c’est la 1ere fois que je me lance dans un programme tri-lingue. On est bien obligé de définir les messages d’aide avant le lancement du menu d’aide, non?

Oui, c’est ça! Mais je pense qu’un truc du style « A1Z2E3R4T5Y6 », c’est plus solide que « AZERTY123456 », c’est ce que fait le programme.

Désolé, mais globalement je suis assez d’accord avec Gpapig :confused:

Je rajouterai les remarques suivantes :

  • Tu devrais faire un choix fort concernant la casse de tes noms de variables/fontions. Ou bien du camelCase (c’est pas trop la norme en python) ou bien du snake_case (c’est plus la norme en python). Perso je te conseils le snake case, c’est beaucoup plus lisible.
  • Tu devrais mieux nommer tes variables, NbrePsw par exemple c’est très trompeur comme nom.
  • J’ai dit cette phrase un nombre incroyable de fois, mais je continue à trouver que c’est le meilleur conseil à donner : personne ne te feras payer 10 centimes par espace ou saut de ligne, alors hésites pas à les utiliser.
  • L’internationalisation ne devrait pas se faire comme ça. Je te conseils de virer l’internationalisation pour l’instant pour te concentrer sur l’anglais uniquement. Et tant qu’à la faire comme ça, tu devrais aller au bout de la logique et que tous les textes soient stockés dans des variables (ou mieux, dans un tableau), ça évitera d’avoir des elseif partout.
  • Tu devrais versionner au lieu de garder des vieux bouts de code en commentaire. Globalement d’ailleurs, pour ce type de partage, ça serait plus simple que tu fasses un lien vers un git plutot que de mettre tout le fichier dans un post sur le forum.
  • J’ai l’impression que tu utilises beaucoup de str() sans raison.
  • Tu commentes trop de trucs sans intérêt et pas assez des points de logiques flous (ex, le # gestion avec 2 mots entrés est évident pour toute personne sachant lire l’égalité et ce qu’est la variable NbrePsw en revanche, la ligne identique = size[x] - len( str(psw[x]).replace(var,"") ) est globalement incompréhensible - la variable est pas trop mal nommée néanmoins donc j’en déduis globalement l’objectif recherché)

Plus globalement, je suis très dubitatif sur l’outil. Le travail autour du chiffrement ou de la génération de complexité et globalement un des plus compliqué du domaine informatique, et les tentatives maisons se soldent presque toujours par une diminution de la difficulté réelle.

Si j’ai bien compris ton programme envisage de se baser sur un dictionnaire de mots ? Dans ce cas, si tu prends 3 mot dans une liste de 7000 dans le dico pour généré ton pass, tu auras dans les fait 7000³ combinaisons. Soit, beaucoup moins que 15 lettres minuscules tapées au hasard… Je suis en revanche d’accord qu’il sera potentiellement plus simple de retenir 3 mots que 15 lettres aléatoires. Mais dans ce cas, autant que l’utilisateur prenne directement trois mots au hasard, plutôt que de passer par un programme…

Je n’ai pas lu tout le code, parce-que honnêtement c’est difficilement lisible, donc je ne peux pas dire si je vois d’autres trucs du genre, mais je ne serais pas surpris du tout, parce-que pour être honnête, tu n’as probablement pas le niveau pour un outil fiable de ce type. Ni moi d’ailleurs, ni probablement personne ici :confused:.

J’en profites pour te mettre sur la piste de gettext gettext — Services d'internationalisation multilingue — Documentation Python 3.11.4, et une petite reflexion vis à vis de l’internationalisation : Digital – Sam et Max.

Concernant les imports, ça désigne la ligne import nom_de_ta_lib, tu peux les faire avant d’utiliser la lib ou de définir des variables sans problèmes. Les imports ça se fait toujours au début.

Les fonctions, elles, ne doivent travailler qu’avec les données d’entrée dont elles disposent (plus éventuellement les constantes), mais ne seront interprétées qu’au moment de l’appel, donc elles peuvent aussi êtres définie avant de définir les données qu’elle recevront, tant qu’elle sont appelée plus tard).

À noter néanmoins, je ne suis pas d’accord avec Gpapig quand il dit :

Les variables globales sont très adaptées à certains cas, principalement le stockage de configuration. Mais souvent ont utiliseras avec avantage des constantes globales plutôt que des variables.

Les constantes je suis pour, les variables, je suis contre :slight_smile:
Mais bon on est d’accord, ca peut servir :smiley:

hello,

en python on a toujours des constantes variables ? ( ou j’ai loupé un épisode :pleading_face: )
y a t il une manière de les rendre « vraiment » constante ( non modifiable donc ) ?

Oui il n’y a pas de vraies constantes, seulement des variables que on ne modifie pas

Actuellement, je me prépare à une collaboration Franco-Espagnole, dans ce cadre, c’est l’Anglais qui n’est pas indispensable.

Surtout pas! une des supériorités de l’esprit humain sur la machine, c’est l’imagination. Un gros dico serait très rébarbatif à l’usage, un petit dico ouvrirait la porte à un cassage facile de code. De plus, actuellement (ou presque, un nouveau bug est apparu) le programme accepte des mots ou des groupes de mots.

L’intérêt est recherché au niveau de la collaboration, une grande suite aléatoire, c’est (très) agaçant à taper pour une personne à qui tu l’impose, par contre, taper 3 mots courants, ça passe mieux.

J’avais discuté avec @jmbc au sujet de la possibilité d’importer, le minimum (donc « argparse ») juste avant le traitement de la fonction d’aide et d’importer le reste juste après, afin que l’utilisateur puisque quand même avoir accès à la fonction d’aide, même en cas de librairie(s) manquante(s). Il m’avait répondu que ce n’était pas la méthode habituelle, mais que c’était acceptable. Si je comprends bien, vous n’êtes pas de cet avis?

J’en ai rajouté à plusieurs endroits ou j’avais pensé au départ qu’il ne servaient à rien et ou leur ajout à résolut des bugs, je ne sais pas si tu parles de ceux-là.

Au sujet des fonctions, j’ai un problème, vous arrivez probablement à créer des fonctions qui fonctionnent du premier coup (ou presque), pas moi. Au départ, j’ai écrit le programme sans fonction et j’essaye maintenant de regrouper des trucs répétitif pour en faire des fonctions.

Un problème que j’ai rencontré plusieurs fois, qui doit être courant (?) Au départ, le programme/process est une « suite » logique d’actions en « ligne droite » et au fur et à mesure qu’on ajoute des vérifications de données d’entrée avec des tests de validité, on est obligé d’ajouter des boucles, donc de déplacer des initialisation de variables qui étaient en début de programme et quand c’est complexe, ça devient une soupe immonde ou même le programmateur (débutant que je suis) s’emmêle les pinceaux. Vous gérez ça comment en général?

Si jamais, Téléchargement des dictionnaires DELA

Un lien permettant de télécharger un dictionnaire en format ± csv

Et je trouve pertinent la remarque de @RaspberryPiFR de générer le mot de passe aléatoirement plutot que de se baser sur les mots des utilisateurs (qui seront certainement moins variés que le dico :smiley: )

En fait ton fichier de départ était un script (déroulement linéaire) et c’est devenu un programme.

TOUT ton code (hormis les initialisations/imports du début doit être dans des fonctions (alors je simplifie à l’extrême mais l’idée est là)

Une fonction (enfin généralement plusieurs, mais on va dire une va piloter le tout)

Imports
CONSTANTES

def read_param(param_name):
	[...]
	return param
	
def generate_password(language):
	[...]
	word1 = read_random_words(fr_dico)
	word2 = read_random_words(fr_dico)
	return word1+word2
	
def read_random_words(dictionnary):
	mydic = open(dico)
	myword = choose_random_word(mydic)
	return myword
	
def verify_complexity(password):
	return true/false
	
def main():
	if read_param = fr:
		new_password = generate_password(fr)
		if verify_complexity(new_password):
			print ("Voici votre password : " + new_password:
		else:
			blablabla
			
			
main()

Voilà à quoi ressemble un programme basique (j’ai fais ça en 2 minutes, tout n’es pas cohérent mais ca te donnera une idée de la structure « classique »

Bon, je reprends ce que j’avais fait.
des améliorations, mais je retombe sur quelque chose de similaire…

(pourquoi) le schéma suivant ne vous parait pas cohérent?

  1. description
  2. paramètres par défaut (donc variables)
  3. docstring (=menu d’aide)
  4. import
  5. constantes (donc variables)
  6. def fonction
  7. programme principal

Bonjour,

Pour ma part, je pense que l’essentiel, c’est que le programme fonctionne.
Toutefois, il est d’usage si l’on souhaite partager/diffuser son code de respecter autant que possible la PEP8 (sans que ça ne soit aucunement une obligation). Ainsi, en cas d’analyse/débug par d’autres développeurs Python, ils peuvent se concentrent sur le contenu et ne sont pas distraits par la forme.

https://www.codeflow.site/fr/article/python-pep8

Bonne lecture.

EDIT PS: Il arrive bien souvent que l’on fasse partie nous même des autres développeurs quand on reprends un programme que l’on écrit il y a qqs temps. Et quand c’est un peu brouillon, on se dit pendant longtemps, « mais qu’est-ce que j’ai voulu faire là? » :grimacing:

A+

1 « J'aime »

Le problème que j’ai, c’est surtout quand je veux rajouter une/des fonction(s) à un de mes programmes, j’ai l’impression de partir d’un truc simple que je comprends bien pour le transformer en un truc immangeable.

Bonjour,

J’ai aussi cette problématique dans bien des domaines. La première idée pour faire un projet est souvent bien tordue. Je dit souvent:
« Il faut parfois réfléchir longtemps pour faire quelque chose de simple. »

Bon courage.

A+