### 1 - Ouvrir un fichier pour lire la liste des mots
**Objectif :** Créer une fonction qui ira lire les mots dans un fichier et utiliser cette liste pour générer des passphrases en français
```admonish travail
1. Dans votre module `mdp`, créer une nouvelle fonction `get_word_list_from_file`. Cette fonction prendra un paramètre `filename` et la valeur par défaut `"wordlist_fr.txt"`.
1. Ouvrir le fichier à l'aide d'un **gestionnaire de contexte**
1. Lire toutes les lignes du fichier, et les stocker dans la variable `lines` et retourner cette variable
1. Remplacer l'appel à la fonction `get_word_list` dans votre fonction `generer_passphrase` par votre nouvelle fonction.
1. Vérifier que votre programme génère désormais des passphrases en français.
```
```admonish help title="Aide"
Un gestionnaire de contexte est la méthode recommandée par Python pour ouvrir et fermer un fichier en toute sécurité. La syntaxe est la suivante:
~~~python
with open(filename, mode) as file:
# Actions sur le fichier
~~~
Cette syntaxe présente l'avantage de fermer systématiquement votre fichier à la sortie du bloc de contexte, et évite donc de nombreux risques de bugs pour votre application. Elle définit une variable `file` qui sera détruite une fois sorti du bloc de contexte.
```
```admonish note title="Dans le compte rendu"
1. Donnez le code de votre fonction
2. Si nous n'avions pas utilisé de gestionnaire de contexte (`with ... as ...:`), qu'aurait-on dû absolument faire après avoir travaillé avec notre fichier ? Quelle méthode aurions-nous dû utiliser pour ça ?
```
### 2 - Écrire dans un fichier
**Objectif :** Écrire un mot de passe généré dans un fichier au lieu de l'afficher en console
```admonish travail
1. Dans votre module principal (`main.py`), créer une fonction `write_password_in_file` qui prendra en paramètres :
-`password`
-`filename` avec une valeur par défaut `passwords.txt`
2. Dans cette fonction, ouvrir votre fichier en mode "append" avec un gestionnaire de contexte.
3. Écrire le contenu de la variable `password` dans le fichier
4. Créer une nouvelle entrée dans votre menu intitulée `5 - Générer un fichier avec des passphrases`.
- Adapter votre fonction `choix_utilisateur` pour gérer ce nouveau cas.
- Vous ferez appel aux fonctions `generer_passphrase` et `write_password_in_file` pour écrire votre passphrase dans un fichier.
5. Testez votre programme pour vérifier que vos passphrases s'écrivent bien dans le fichier.
```
```admonish note title="Dans le compte rendu"
1. Donnez le code de votre nouvelle fonction
1. Que constatez-vous dans le fichier si vous appelez plusieurs fois votre programme à la suite ?
2. Quelle est la différence entre le mode "write" et le mode "append" ?
3. Quel mode puis-je utiliser si je veux à la fois lire et écrire dans mon fichier ?
```
### 3 - Faire un vrai jet de dés
```admonish warning title="Attention"
Dans la suite, nous allons aller au bout du processus "diceware" décrit par l'EFF dans le document du TP3. C'était déjà l'objet de l'étape 6 du TP précédent.
Les personnes ayant terminé l'étape 6 dans le TP précédent (celle qui vous faisait tirer les dés et manipuler des dictionnaires) :
- Dans votre compte-rendu, aux parties 3 et 4, répondez aux questions et ajoutez votre code déjà réalisé
- Passez ensuite au bonus `Lire le dictionnaire à partir d'un fichier` de ce TP.
- Vous pourrez ensuite réaliser les bonus des TP précédents.
```
**Objectif :** Tirer 5 dés et les assembler en une chaîne de caractères
```admonish travail
1. Créer une nouvelle fonction `tirer_les_des` dans votre module `mdp`.
2. Dans cette fonction, commencer par créer une variable `dice` qui sera une chaîne de caractères vide.
3. Créer une boucle qui fera 5 itérations. Dans cette boucle :
- Tirer au sort un nombre entre 1 et 6. Vous utiliserez pour cela [`secrets.randbelow`](https://docs.python.org/3/library/secrets.html#secrets.randbelow).
- Lisez la documentation de `secrets.randbelow` pour comprendre son fonctionnement
- Ajouter ce nombre sous forme de chaîne de caractères à votre variable `dice`
4. A la fin de la boucle, retourner la valeur de `dice`
5. Vérifiez que votre fonction retourne une chaîne de caractères aléatoire ressemblant à `"12345"`
```
```admonish help title="Aide"
-`secrets.randbelow` retourne un nombre entier. Vous aurez besoin d'une chaine de caractères. Pensez à vos conversions si vous rencontrez l'erreur suivante :
~~~
TypeError: can only concatenate str (not "int") to str
~~~
-`secrets.randbelow(n)` retourne un nombre compris entre `0` et `n-1`. Pour avoir un nombre compris entre `1` et `n`, il vous faudra ajouter 1 au résultat.
```
```admonish note title="Dans le compte rendu"
1. Mettez le code de votre fonction `tirer_les_des`
```
### 4 - Générer une passphrase tirée aux dés
**Objectif :** Utiliser votre tirage de dés pour sélectionner les mots dans un dictionnaire Python
```admonish travail
1. Créer une fonction `generer_dice_passphrase` qui sera une copie de `generer_passphrase` pour commencer
1. Remplacer l'appel à `get_word_list_from_file` par `get_word_dict` du module `eff_words`. Cette fonction retourne un dictionnaire dont les **clés** sont les tirages de dés et les **valeurs** sont les mots.
1. Modifier la boucle de `generer_dice_passphrase` pour
- appeler `tirer_les_des` et récupérer le jet de dés dans une variable `dice`
- utiliser l'une des deux syntaxes possibles permettant de récupérer une valeur dans un dictionnaire à l'aide de la clé. Votre but est de récupérer le mot à partir du tirage de dés
- Ajoutez ce mot à votre liste `passphrase_words`
6. Remplacez l'appel à `generer_passphrase` dans votre menu par un appel à `generer_dice_passphrase` et validez que votre programme fonctionne toujours correctement.
```
```admonish note title="Dans le compte rendu"
1. Donnez le code de votre nouvelle fonction `generer_dice_passphrase`
1. Quelle est la différence entre la syntaxe `mon_dict[key]` et `mon_dict.get(key)`, sachant que `mon_dict` est un dictionnaire python ?
```
## Pour aller plus loin
### Bonus facile - Docstrings au format Numpy
**Objectif**: Documenter votre code en ajoutant des docstrings au format Numpy
### Bonus - Lire les dictionnaires à partir d'un fichier
**Objectif** : Lire le dictionnaire utilisé dans votre fonction `generer_dice_passphrase` depuis le fichier `bonus_wordlist_fr.txt`
```admonish travail
1. Dans votre module `mdp`, créer une nouvelle fonction `get_word_dict_from_file`. Cette fonction prendra un paramètre `filename` et la valeur par défaut `"wordlist_fr.txt"`.
1. Ouvrir le fichier à l'aide d'un **gestionnaire de contexte**
1. Lire toutes les lignes du fichier, et les stocker dans la variable `lines`
1. Il va falloir maintenant construire votre dictionnaire à partir des lignes lues. Chaque ligne est composée de la manière suivante : `12345 mot\n` (5 chiffres représentant le tirage de dés, un espace puis un mot, et enfin un retour à la ligne)
1. Retournez votre dictionnaire
1. Remplacer l'appel à la fonction `get_word_dict` dans votre fonction `generer_dice_passphrase` par votre nouvelle fonction.
1. Vérifier que votre programme génère désormais des passphrases en français.
```
```admonish help title="Aide"
- Pour séparer une chaine de caractères, on peut utiliser la méthode [`split`](https://docs.python.org/3/library/stdtypes.html#str.split) sur la chaîne de caractères.
- Pour retirer les espaces et autres passages à la ligne autour des mots, on peut utiliser la méthode [`strip`](https://docs.python.org/3/library/stdtypes.html#str.strip)
- Pour construire votre dictionnaire, vous devrez boucler sur vos lignes, séparer les deux mots et les nettoyer. Puis vous pourrez les ajouter au dictionnaire avec la syntaxe `mon_dict[key] = value`. N'oubliez pas d'initialiser un dictionnaire vide (`{}`) avant votre boucle.
```
### Ressources
- [Liste de mots diceware en français](https://github.com/mbelivo/diceware-wordlists-fr/tree/master)