1. Contrasenyes antigues (3,5 punts)

Un servei web havia utilitzat durant anys uns criteris molt febles per acceptar contrasenyes. Ara l’equip de seguretat vol estudiar l’històric de contrasenyes acceptades i aplicar-hi unes regles noves.

  1. Volem calcular la puntuació d’una contrasenya segons les noves regles. Inicialment, la contrasenya rep un nombre de punts iguals al doble del nombre de caràcters que conté i es resten punts de la manera següent:

    • 1 punt si totes les lletres de la contrasenya són minúscules (en cas que tingui alguna lletra; si no, no resta).

    • 3 punts si la contrasenya conté l’string '1234' o l’string 'admin'.

    • 5 punts si els tres últims caràcters no són tots dígits.

    Dissenya la funció puntua_contrasenya(cont) que donada una contrasenya cont (string) retorna la puntuació de la contrasenya segons les regles anteriors.

    Els següents doctests mostren exemples del que ha de fer la funció:

    >>> puntua_contrasenya("Clau123")
    14
    >>> puntua_contrasenya("clau123")
    13
    >>> puntua_contrasenya("Clau12")
    7
    

    Disposeu de més tests al fitxer test-puntua.txt

    Desa la funció al fitxer contrasenyes.py

  2. Dissenya la funció primera_valida(lcont, lintents, min_punt) que donat una llista d’strings lcont que representen contrasenyes, una llista d’enters lintents que representen intents i una puntuació mínima min_punt, retorna una tupla amb:

    • la primera contrasenya de la llista amb una puntuació igual o superior a min_punt i acceptada en menys de 3 intents.

    • el nombre d’intents per a aquesta contrasenya.

    El nombre d’intents de cada contrasenya a la posició i de lcont es troba a la mateixa posició i de lintents.

    Si no hi ha cap contrasenya vàlida, la funció ha de retornar una tupla amb un string buit i -1.

    Aquesta funció ha de cridar la funció puntua_contrasenya.

    Els següents doctests mostren exemples del que ha de fer la funció:

    >>> primera_valida(["clau12", "ClauA2", "ABCD12B"], [2, 3, 1], 8)
    ('ABCD12B', 1)
    >>> primera_valida(["clau12", "admin12"], [5, 1], 11)
    ('', -1)
    >>> primera_valida(["admin12", "Porta34"], [2, 1], 8)
    ('Porta34', 1)
    

    Disposeu de més tests al fitxer test-primera-valida.txt

    Desa la funció al fitxer contrasenyes.py

  3. Representem l’històric de contrasenyes dels usuaris com una llista de tuples. Cada tupla conté el nom d’un usuari i la llista de contrasenyes que aquest usuari ha tingut al llarg del temps. Per exemple:

    >>> lusuaris1 = [
    ...     ("anna", ["clau12", "ClauA2", "ABCD12B"]),
    ...     ("bernat", ["admin12", "Porta34"]), ("carla", ["AAA99", "casa22"])]
    

    També disposem d’un diccionari d’intents. Cada clau és un nom d’usuari i cada valor una llista d’enters amb els intents que va necessitar l’usuari perquè la contrasenya que es troba a la mateixa posició de l’històric per aquest usuari fos acceptada. Per exemple:

    >>> dintents1 = {
    ...     "anna": [2, 3, 1], "bernat": [2, 1], "carla": [2, 1]}
    

    Així, la contrasenya "ClauA2" de l’usuari "anna" va ser acceptada després de 3 intents, i la contrasenya "AAA99" de l’usuari "carla" va ser acceptada després de 2 intents.

    Podeu suposar que tots els usuaris que apareixen a la llista lusuaris també apareixen com a claus del diccionari dintents. També podeu suposar que, per a cada usuari, la llista de contrasenyes i la llista d’intents corresponent tenen la mateixa longitud.

    Dissenya la funció resum_valides(lhistoric, dintents, min_punt) que donada un històric de contrasenyes lhistoric, un diccionari d’intents dintents i una puntuació mínima min_punt, retorna una llista de tuples amb la forma (usuari, contrasenya, intents), on contrasenya és la primera contrasenya vàlida de l’històric d’aquell usuari i intents és el nombre d’intents associat a aquesta contrasenya.

    Els usuaris que no tenen cap contrasenya vàlida no han d’aparèixer a la llista resultat. L’ordre dels elements de la llista resultat ha de ser el mateix que l’ordre dels usuaris a lhistoric.

    Aquesta funció ha de cridar la funció primera_valida.

    Els següents doctests mostren exemples del que ha de fer la funció:

    >>> lusuaris1 = [
    ...     ("anna", ["clau12", "ClauA2", "ABCD12B"]),
    ...     ("bernat", ["admin12", "Porta34"]), ("carla", ["AAA99", "casa22"])]
    
    >>> dintents1 = {
    ...     "anna": [2, 3, 1], "bernat": [2, 1], "carla": [2, 1]}
    
    >>> resum_valides(lusuaris1, dintents1, 8)
    [('anna', 'ABCD12B', 1), ('bernat', 'Porta34', 1)]
    
    >>> dintents1b = {
    ...     "anna": [2, 3, 1], "bernat": [2, 3], "carla": [2, 1]}
    
    >>> resum_valides(lusuaris1, dintents1b, 8)
    [('anna', 'ABCD12B', 1)]
    

    Disposeu de més tests al fitxer test-resum-valides.txt

    Desa la funció al fitxer contrasenyes.py

  4. Definim la qualitat d’una contrasenya com la diferència entre la puntuació de la contrasenya i el nombre d’intents per acceptar-la.

    Dissenya la funció modificadora ordena(ll) que donada una llista ll de tuples de la forma (usuari, contrasenya, intents) modifiqui la llista ordenant-la de forma descendent segons la qualitat de cada contrasenya.

    Els següents doctests mostren exemples del que ha de fer la funció:

    >>> ll1 = [('anna', 'ABCD123', 1), ('bernat', 'Porta345', 1),
    ... ('carla', 'Clau999', 0)]
    >>> ordena(ll1)
    >>> ll1
    [('bernat', 'Porta345', 1), ('carla', 'Clau999', 0), ('anna', 'ABCD123', 1)]
    

    Disposeu de més tests al fitxer test-ordena.txt

    Desa la funció al fitxer contrasenyes.py

    Disposes de solucions al fitxer contrasenyes.py.