Commit 4805f238 authored by matograine's avatar matograine

Merge branch 'packaging' into 'dev'

Package 0.0.3

See merge request !1
parents 610e3663 ca3b9c69
__pycache__/
qtcreator/
\ No newline at end of file
qtcreator/
publish.sh
### from Silkaj
# ---> Python
# Byte-compiled / optimized / DLL files
__pycache__/
*.py[cod]
*$py.class
# C extensions
*.so
# Distribution / packaging
.Python
env/
build/
develop-eggs/
dist/
downloads/
eggs/
.eggs/
lib/
lib64/
parts/
sdist/
var/
*.egg-info/
.installed.cfg
*.egg
# PyInstaller
# Usually these files are written by a python script from a template
# before PyInstaller builds the exe, so as to inject date/other infos into it.
*.manifest
*.spec
# Installer logs
pip-log.txt
pip-delete-this-directory.txt
# Unit test / coverage reports
htmlcov/
.tox/
.coverage
.coverage.*
.cache
nosetests.xml
coverage.xml
*,cover
.pytest_cache/
# Translations
*.mo
*.pot
# Django stuff:
*.log
# Sphinx documentation
docs/_build/
# PyBuilder
target/
# Idea
.idea
# Vim swap files
*~
*.swp
*.swo
Licence Ğ1 - v0.2.8
===================
:date: 2017-04-04 12:59
:modified: 2018-02-24 09:30
**Licence de la monnaie et engagement de responsabilité.**
Toute opération de certification d'un nouveau membre de Ğ1 doit préalablement s'accompagner de la transmission de cette licence de la monnaie Ğ1 dont le certificateur doit s'assurer qu'elle a été étudiée, comprise et acceptée par la personne qui sera certifiée.
Tout événement de rencontre concernant Ğ1 devrait s'accompagner de la transmission de cette licence, qui peut être lue à haute voix, et transmise par tout moyen.
Toile de confiance Ğ1 (TdC Ğ1)
------------------------------
**Avertissement :** Certifier n'est pas uniquement s'assurer que vous avez rencontré la personne, c'est assurer à la communauté Ğ1 que vous connaissez suffisamment bien la personne certifiée et que vous saurez ainsi la contacter facilement, et être en mesure de repérer un double compte effectué par une personne certifiée par vous-même, ou d'autres types de problèmes (disparition...), en effectuant des recoupements qui permettront de révéler le problème le cas échéant.
**Conseils fortement recommandés**
Bien connaître une personne suppose que vous êtes en mesure de la contacter par plusieurs moyens différents (physique, électronique, autre...) mais aussi que vous connaissez aussi plusieurs personnes qui la connaissent tout aussi bien et sont donc aussi en mesure de la contacter de même. Notamment si vous ne connaissez pas bien aucun de ses autres certifieurs c'est une indication forte que vous ne connaissez pas bien la personne et une certification de ce type déclenche une alerte vers toute la communauté Ğ1. En cas de connaissance insuffisante il convient de ne surtout pas certifier.
Ne certifiez jamais seul, mais accompagné d'au moins un autre membre de la TdC Ğ1 afin d'éviter toute erreur de manipulation. En cas d'erreur, prévenez immédiatement d'autres membres de la TdC Ğ1.
Avant toute certification, assurez vous de vérifier si son compte (qu'il soit en cours de validation ou déjà membre) a déjà reçu une ou plusieurs certifications. Le cas échéant demandez des informations pour entrer en contact avec ces autres certifieurs afin de vérifier ensemble que vous connaissez bien la personne concernée par la création du nouveau compte, ainsi que la clé publique correspondante.
Vérifiez que le futur certifié maîtrise bien son compte : un bon moyen de vérifier cela est de transférer quelques Ğ1 vers le compte cible, et de demander ensuite un renvoi vers votre propre compte, cela assure de la bonne maîtrise par le futur certifié de sa clé privée.
Vérifiez que vos contacts ont bien étudié et compris la licence Ğ1 à jour.
Si vous vous rendez compte qu'un certifieur effectif ou potentiel du compte concerné ne connaît pas la personne concernée, alertez immédiatement des experts du sujet au sein de vos connaissance de la TdC Ğ1, afin que la procédure de validation soit vérifiée par la TdC Ğ1.
Lorsque vous êtes membre de la TdC Ğ1 et que vous vous apprêtez à certifier un nouveau compte :
**Vous êtes vous assuré :**
1°) De suffisamment bien connaître (pas seulement de la connaître "de visu") la personne qui déclare gérer cette clé publique (nouveau compte). Voir les conseils fortement recommandés ci-dessus pour s'assurer de "bien connaître".
2°) D'avoir personnellement vérifié avec elle qu'il s'agit bien de cette clé publique que vous vous apprêtez à certifier (voir conseils ci-dessus).
3°) D'avoir bien vérifié avec la personne concernée qu'elle a bien généré son document Duniter de révocation de compte qui lui permettra le cas échéant de pouvoir désactiver son statut de membre (cas d'un vol de compte, d'un changement de ID, d'un compte créé à tort etc.).
4a°) De rencontrer la personne physiquement pour vous assurer que c'est bien elle que vous connaissez bien et qui gère cette clé publique.
4b°) Ou bien de vérifer à distance le lien personne / clé publique en contactant la personne par plusieurs moyens de communication différents, comme courrier papier + réseau social + forum + mail + vidéo conférence + téléphone (reconnaître la voix). Car si l'on peut pirater un compte mail ou un compte forum, il sera bien plus difficile d'imaginer pirater quatre moyens de communication distincts, et imiter l'apparence (vidéo) ainsi que la voix de la personne en plus.
Le 4a°) restant toutefois préférable au 4b°), tandis que les points 1°) 2°) et 3°) sont préalablement indispensables.
**Règles abrégées de la TdC :**
Chaque membre a un stock de 100 certifications possibles, qu'il ne peut émettre qu'au rythme de 1 certification / 5 jours.
Valable 2 mois, une certification pour un nouveau membre n'est définitivement adoptée que si le certifié possède au moins 4 autres certifications au bout de ces 2 mois, sinon le processus d'entrée devra être relancé.
Pour devenir un nouveau membre de la TdC Ğ1 il faut donc obtenir 5 certifications et ne pas se trouver à une distance < 5 de 80% des membres référents de la TdC.
Un membre de la TdC Ğ1 est membre référent lorsqu'il a reçu et émis au moins Y[N] certifications où N est le nombre de membres de la TdC et Y[N] = plafond N^(1/5). Exemples :
* Pour 1024 < N ≤ 3125 on a Y[N] = 5
* Pour 7776 < N ≤ 16807 on a Y[N] = 7
* pour 59049 < N ≤ 100 000 on a Y[N] = 10
Une fois que le nouveau membre est partie prenante de la TdC Ğ1 ses certifications restent valables 2 ans.
Pour rester membre il faut renouveler son accord régulièrement avec sa clé privée (tous les 12 mois) et s'assurer d'avoir toujours au moins 5 certifications valides au delà des 2 ans.
Monnaie Ğ1
----------
Ğ1 se produit via un Dividende Universel (DU) pour tout être humain membre de la Toile de Confiance Ğ1, qui est de la forme :
* 1 DU par personne et par jour
**Code de la monnaie Ğ1**
Le montant en Ğ1 du DU est identique chaque jour jusqu'au prochain équinoxe où le DU sera alors réévalué selon la formule (avec 1 jour = 86 400 secondes) :
* DUjour(équinoxe suivant) = DUjour(équinoxe) + c² (M/N)(équinoxe) / (182,625 jours)
Avec comme paramètres :
* c = 4,88% / équinoxe
* DU(0) = 10,00 Ğ1
Et comme variables :
* *M* la masse monétaire totale à l'équinoxe
* *N* le nombre de membres à l'équinoxe
Logiciels Ğ1 et licence Ğ1
--------------------------
Les logiciels Ğ1 permettant aux utilisateurs de gérer leur utilisation de Ğ1 doivent transmettre cette licence avec le logiciel ainsi que l'ensemble des paramètres techniques de la monnaie Ğ1 et de la TdC Ğ1 qui sont inscrits dans le bloc 0 de Ğ1. Un logiciel qui ne remplirait pas ces obigations de la licence n'est pas compatible Ğ1.
Pour plus de précisions dans les détails techniques il est possible de consulter directement le code de Duniter qui est un logiciel libre ansi que les données de la blockchain Ğ1 en la récupérant via une instance (ou noeud) Duniter Ğ1.
Plus d'informations sur le site de l'équipe Duniter https://www.duniter.org
This diff is collapsed.
This diff is collapsed.
include gdon/objects/recto.png
include gdon/objects/Roboto-Medium.ttf
include gdon/objects/verso.png
include gdon/objects/wordlist.txt
......@@ -3,13 +3,11 @@ url = "https://pypi.python.org/simple"
verify_ssl = true
name = "pypi"
[packages]
duniterpy = ">=0.54.3"
Pillow = ">=6.0.0"
qrcode = ">=6.1"
reportlab = ">=3.5.23"
[dev-packages]
[requires]
python_version = "3.7"
[packages.e1839a8]
path = "."
editable = true
This diff is collapsed.
# Présentation
G1pourboire est un outil permettant de générer des pourboires en Ğ1.
En développement, ceci est une version Alpha.
En phase de développement, ceci est une version Alpha.
Il est fonctionnel en ligne de commande, mais pas (encore ?) en interface graphique. Cette contribution est bienvenue !
# Installation
Le logiciel n'est pas encore packagé, vous devez l'installer à la main.
Le logiciel est empaqueté et référencé avec Pypi-test pour le moment.
## Installation des dépendances DEBIAN
- `python3`
- `pip3`
- `git`
Nous avons rencontré des soucis sur ces dépendances :
- `tkinter` -> installer le paquet python3-tk (sur Debian Buster)
### Debian :
```
$ sudo apt-get install python3 python3-pip git python3-qrcode python3-reportlab python3-pil ; sudo python3.5 -m pip install duniterpy
$ sudo apt-get install python3 python3-pip
$ python3 -m pip install --index-url https://test.pypi.org/simple/ gdon # à tester
# ajouter .local/bin à votre PATH
$ echo 'export PATH="/home/$USER/.local/bin:$PATH"' >> .bash_aliases
```
## Installation de G1pourboire
## Installation pour les devs :
Désolé, le dépôt est encore nommé "Ğ1pourboire", ancien nom du projet
```
$ git clone https://git.duniter.org/Darks/g1pourboire.git
# apt install pipenv
$ git clone https://git.duniter.org/matograine/g1pourboire.git
$ cd g1pourboire
$ pip3 install -r requirements.txt
$ pipenv install '-e .'
$ pipenv run gdon
```
# Utilisation
Actuellement le logiciel se lance en ligne de commande :
Générer des dons : "generer <montant> <nombre_pages> <peremption_date_JJ/MM/AAAA>"
Récupérer des dons : "recuperer"
Récupérer des dons depuis un dossier : "recuperer <dossier>"
Récupérer des dons depuis un fichier : "recuperer fichier <fichier>"
En cas de mauvaise récupération, tenter une récupération des backups : "recuperer backup <année>"
La récupération des backups est possible à plusieurs reprises.
Configurer le noeud Duniter : "noeud <noeud> <port>"
Les Ğ1Dons sont enregistrés dans ~/Documents/G1pourboire/.
Les fichiers de récupération sont enregistrés dans ~/Documents/G1pourboire/Recuperation_ne_pas_supprimer/.
Lors d'une récupération, les fichiers récupérés sont enregistrés dans ~/Documents/G1pourboire/.backup/<année> en cas de transaction mal effectuée.
* Pour générer et remplir des Ğ1Pourboires :
* Générer et remplir des Ğ1Dons :
Les Ğ1Dons seront bloqués jusqu'à la péremption.
Le compte depuis lequel vous crééez les Ğ1Dons vous sera nécessaire pour les récupérer.
```
$ gdon generer <montant> <nombre_pages> <peremption_date_JJ/MM/AAAA>
```
$ ./main.py generate <amount> <pages_number> <delay>
* Récupérer le contenu de Ğ1Dons :
```
* Pour récupérer le contenu de Ğ1Pourboires :
$ gdon recuperer
```
* Récupérer des Ğ1Dons depuis un dossier de sauvegarde:
```
$ ./main.py retrieve <path/to/file> <your_pubkey>
gdon recuperer<dossier>
```
Les pourboires générés sont stockés dans `~/Documents/G1pourboire/`. Deux fichiers sont créés :
* Récupérer des Ğ1Dons depuis un fichier:
```
recuperer fichier <fichier>
```
* Si la récupération s'est mal passée :
```
recuperer backup <année>
```
* Configurer le noeud Duniter :
```
gdon noeud <noeud> <port>
```
- PDF : fichier à imprimer puis découper
- Json : sauvegarde des identifiants de comptes
Les dons générés sont stockés dans `~/Documents/G1dons/` en pdf.
Les fichiers de récupération sont dans ~/Documents/G1dons/Récupération. Ne pas le supprimer !
**Attention !** Actuellement, les fichiers de sortie ont pour nom la date et l'heure courante, à la minute près. Il n'y a pas de vérification si un fichier du même nom existe. Cela veut dire qu'une seconde génération dans la même minute écrasera la génération précédente.
# TODO
- Inteface graphique
- Provisionnement automatique
- Interface graphique
- Suivi des pourboires générés
X Récupération du solde des pourboires expirés
- Paquet stand-alone pour Windows
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
from gdon.common import Creating # Generator
from gdon.retrieve import Retrieve, BackupRetrieve
from gdon.utils import CheckConfig
from gdon.constants import DEFAULT_FOLDER, WALLETS_FOLDER, BACKUP_FOLDER
from sys import argv
def help():
print ("\nUtiliser Ğ1Dons\n===============")
print ("Générer des dons : \"generer <montant> <nombre_pages> <peremption_date_JJ/MM/AAAA>\"")
print ("Récupérer des dons : \"recuperer\"")
print ("Récupérer des dons depuis un dossier : \"recuperer <dossier>\"")
print ("Récupérer des dons depuis un fichier : \"recuperer fichier <fichier>\"")
print ("En cas de mauvaise récupération, tenter une récupération des backups : \"recuperer backup <année>\"")
print ("La récupération des backups est possible à plusieurs reprises.")
print ("Configurer le noeud Duniter : \"noeud <noeud> <port>\"")
print ("\nLes Ğ1Dons sont enregistrés dans {0}.".format(DEFAULT_FOLDER))
print ("Les fichiers de récupération sont enregistrés dans {0}.".format(DEFAULT_FOLDER + WALLETS_FOLDER))
print ("Lors d'une récupération, les fichiers récupérés sont enregistrés dans {0}<année> en cas de transaction mal effectuée.\n".format(DEFAULT_FOLDER + BACKUP_FOLDER))
# main
if __name__ == "__main__":
if len(argv) > 1:
if argv[1] == "generer":
if len(argv) > 5 or len(argv) < 4:
print ("Erreur : information mal formatées.")
help()
else:
amount = float(argv[2])
pages = int(argv[3])
date = str(argv[4])
Creating (amount, date, pages).create()
elif argv[1] == "recuperer":
if len(argv) == 2:
Retrieve().retrieve()
elif len(argv) == 3:
Retrieve(folder=argv[2]).retrieve()
elif len(argv) == 4 and argv[2] == "fichier":
Retrieve(_file=argv[3]).retrieve()
elif len(argv) == 4 and argv[2] == "backup":
copy = BackupRetrieve(argv[3])
Retrieve(folder=copy.dest).retrieve()
copy.delete()
else:
print ("Erreur : information mal formatées.")
help()
elif argv[1] == "noeud":
if len(argv) != 4:
print ("Erreur : information mal formatées.")
help()
else:
CheckConfig().check_node_conf(argv[2], int(argv[3]))
else:
help()
else :
help()
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
from utils.common import Creating # Generator
from utils.retrieve import Retrieve, BackupRetrieve
from utils.utils import CheckConfig
from utils.constants import DEFAULT_FOLDER, WALLETS_FOLDER, BACKUP_FOLDER
from sys import argv
def help():
print ("\nUtiliser Ğ1Dons\n===============")
print ("Générer des dons : \"generer <montant> <nombre_pages> <peremption_date_JJ/MM/AAAA>\"")
print ("Récupérer des dons : \"recuperer\"")
print ("Récupérer des dons depuis un dossier : \"recuperer <dossier>\"")
print ("Récupérer des dons depuis un fichier : \"recuperer fichier <fichier>\"")
print ("En cas de mauvaise récupération, tenter une récupération des backups : \"recuperer backup <année>\"")
print ("La récupération des backups est possible à plusieurs reprises.")
print ("Configurer le noeud Duniter : \"noeud <noeud> <port>\"")
print ("\nLes Ğ1Dons sont enregistrés dans {0}.".format(DEFAULT_FOLDER))
print ("Les fichiers de récupération sont enregistrés dans {0}.".format(DEFAULT_FOLDER + WALLETS_FOLDER))
print ("Lors d'une récupération, les fichiers récupérés sont enregistrés dans {0}<année> en cas de transaction mal effectuée.\n".format(DEFAULT_FOLDER + BACKUP_FOLDER))
# main
if __name__ == "__main__":
if len(argv) > 1:
if argv[1] == "generer":
if len(argv) > 5 or len(argv) < 4:
print ("Erreur : information mal formatées.")
help()
else:
amount = float(argv[2])
pages = int(argv[3])
date = str(argv[4])
Creating (amount, date, pages).create()
elif argv[1] == "recuperer":
if len(argv) == 2:
Retrieve().retrieve()
elif len(argv) == 3:
Retrieve(folder=argv[2]).retrieve()
elif len(argv) == 4 and argv[2] == "fichier":
Retrieve(_file=argv[3]).retrieve()
elif len(argv) == 4 and argv[2] == "backup":
copy = BackupRetrieve(argv[3])
Retrieve(folder=copy.dest).retrieve()
copy.delete()
else:
print ("Erreur : information mal formatées.")
help()
elif argv[1] == "noeud":
if len(argv) != 4:
print ("Erreur : information mal formatées.")
help()
else:
CheckConfig().write_node_conf(argv[2], int(argv[3]))
else:
help()
else :
help()
import datetime
import re
import os
import json
from gdon.generator import Generator
from gdon.transfer import Transfer
from gdon.constants import DEFAULT_FOLDER, WALLETS_FOLDER, BACKUP_FOLDER, PDF_EXTENSION, SIGNED_EXTENSION, CONF_FILE, MAX_PAGES
from gdon.utils import CheckConfig, check_date
from gdon.silkaj.tools import coroutine, message_exit
from gdon.silkaj.auth import auth_by_scrypt
from duniterpy.key import SigningKey, ascii_armor
# Generate and fill Tips
class Creating:
"""Generating, filling wallets"""
def __init__(self, amount, given_date, pages=1):
if pages > MAX_PAGES:
message_exit("Erreur : Ğ1Don gère un maximum de 10 pages.")
self.pages = pages
self.amount = amount
conf = CheckConfig()
conf.check()
self.folder, self.wallets_folder, self.backup_folder = conf.folder, conf.wallets_folder, conf.backup_folder
self.output = datetime.datetime.now().strftime(
"Ğ1Don_%Y-%m-%dT%Hh%M"
)
self.pdf_output = self.folder + self.output + PDF_EXTENSION
self.signed_output = self.wallets_folder + self.output + SIGNED_EXTENSION
if os.path.isfile(self.pdf_output) or os.path.isfile(self.signed_output):
message_exit("ERREUR : {0}{1}/{2} existe déjà. Attendez une minute et recommencez.".format(self.output, PDF_EXTENSION, SIGNED_EXTENSION))
self.wallets = []
# Check date format
self.date = check_date(given_date)
self.key = auth_by_scrypt(None)
def __call__(self):
return self
def create(self):
""" Generating, filling wallets."""
#self.transfer = False
if self.key and self.pages <= MAX_PAGES:
print ("Création des Ğ1Dons...")
Generator(self.pdf_output, self.wallets, self.amount, self.date, self.pages).generate()
try:
self.save_json()
transfer = Transfer(self.amount, self.pages, self.wallets, self.date)
if self.amount > 0:
print ("Transferts...")
transfer.transfer(self.key)
except:
self.transfer_error()
def transfer_error(self):
"""
transfer the newly created files to the backup folder.
"""
os.rename(self.pdf_output, self.backup_folder + self.output + PDF_EXTENSION)
os.rename(self.signed_output, self.backup_folder + self.output + SIGNED_EXTENSION)
print ("\nERREUR : Quelque chose s'est mal passé durant le transfert.\nLes fichiers {0}{1}/{2} ont été déplacés dans le dossier {3}.\nVérifiez si le transfert a bien eu lieu.\nVérifiez que le noeud Duniter est disponible.\n".format(self.output, PDF_EXTENSION, SIGNED_EXTENSION, self.backup_folder))
def save_json(self):
"""
write wallets data in an encrypted json file.
"""
# create and encrypt wallet list
wallet_data = [
{
"pubkey": w["pubkey"],
"salt": w["salt"],
"password": w["password"],
}
for w in self.wallets
]
clear_json = json.dumps(wallet_data)
encrypted_wallets = ascii_armor.AsciiArmor.create(clear_json, self.key.pubkey)
# add date and creator info
data = {
"creator_pubkey": self.key.pubkey,
"peremption_date": self.date.isoformat(),
"wallets": encrypted_wallets,
}
data = json.dumps(data)
# sign the whole document
signed_data = ascii_armor.AsciiArmor.create(data, signing_keys=[self.key])
with open(
self.signed_output, "a"
) as f:
f.write(signed_data)
SUGGESTED_AMOUNT = 10
MAX_AMOUNT = 1000000000
SUGGESTED_DEV_PERCENT = 5
DATE_FORMAT = "[0-9]{2}/[0-9]{2}/[0-9]{4}"
PUBKEY_FORMAT = "[1-9A-HJ-NP-Za-km-z]{43,44}"
DEFAULT_FOLDER = "~/Documents/G1dons/"
WALLETS_FOLDER = "Recuperation_ne_pas_supprimer/"
BACKUP_FOLDER = ".backup/"
PDF_BACKUP_FOLDER = "pdf/"
PDF_EXTENSION = ".pdf"
SIGNED_EXTENSION = ".json.signed"
CONF_FILE = ".config"
MAX_PAGES = 10
MAX_ISSUERS = 18
COMMENT = "G1Don"
......@@ -2,8 +2,16 @@
# DO NOT USE IT FOR STRONG CRYPTOGRAPHIC PURPOSE!
from random import choice
import sys
import os
def diceware(N, wordlist="objects/wordlist.txt", separator="", camelcase=True):
# set the wordlist path
wordlist = "objects/wordlist.txt"
parent_dir = os.path.abspath(os.path.dirname(__file__))
wordlist_path = os.path.join(parent_dir, wordlist)
def diceware(N, wordlist=wordlist_path, separator="", camelcase=True):
with open(wordlist, "r") as f:
words = f.read().split('\n')
out = []
......
from PIL import Image, ImageFont, ImageDraw
from reportlab.pdfgen import canvas
from reportlab.lib.units import cm
from duniterpy.key import SigningKey
from datetime import datetime
from utils.diceware import diceware
from duniterpy.key import SigningKey, ascii_armor
from gdon.diceware import diceware
from gdon.silkaj.constants import G1_SYMBOL
import os
import json
import qrcode
import datetime
# Utiliser help(module) dans une console python pour avoir de l'aide.
# Dictionnaire : https://science-emergence.com/Articles/Utiliser-les-dictionnaires-de-python-tutoriel/
# Json : https://gist.github.com/YannBouyeron/39fafc26b94dfc459589c8d9e82637b6
## En fait, vu que ce programme est beaucoup moins complexe que Silkaj, j'ai peut-être intérêt à copier certaines parties de Silkaj,
## Et écrire directement les fichiers de tx.
## Juste les fonctions nécessaires pour :
## * Balance depuisune pubkey
## * send multi-tx
## * send multi-inputs
## De façon à enlever le besoin de Click.
## Avant ça, faut séparer les fonctions pour que ce soit plus propre.
recto_file = "objects/recto.png"
verso_file = "objects/verso.png"
typo_file = "objects/Roboto-Medium.ttf"
class Generator:
"""Generate some wallets, create the pdf to print"""
def __init__(self, output, wallets, pages=1):
def __init__(self, output, wallets, amount, date, pages=1):
self.pages = pages
self.output = output
self.wallets = wallets
self.amount = amount
self.date = date
self.c = None
# set objects dir
par_dir = os.path.abspath(os.path.dirname(__file__))
#wordlist_path = os.path.join(parent_dir, wordlist)
self.recto = os.path.join(par_dir, recto_file)
self.verso = os.path.join(par_dir, verso_file)
self.typo = os.path.join(par_dir, typo_file)
def generate(self):
"""
generate tips wallets ; then create the pdf file
"""
for i in range(self.pages):
for j in range(6): # 6 wallets per pages
self.new_wallet()
......@@ -40,22 +43,53 @@ class Generator:
self.make_pdf()
def new_wallet(self):
# Generating credetials
"""
generate one wallet with the associated images
"""
# Generating credentials
salt = diceware(3, separator="-", camelcase=False)
password = diceware(3, separator="-", camelcase=False)
# Generating public key from credentials
# Generating key from credentials
key = SigningKey.from_credentials(salt, password)
# Url to redirect to in the public QR code
account_url = "https://g1.duniter.fr/#/app/wot/tx/" + key.pubkey + "/"
# Generating wif data
key.save_wif_file("privatekey.wif")
wif_data = open("privatekey.wif").readlines()[-1].split(": ")[1]
#try add a \n after wif
wif_data.join(["\n"])
os.remove("privatekey.wif")
# Creating the QR codes
qr_pub = qrcode.make(account_url)
qr_priv = qrcode.make(wif_data)
# Open images
recto = Image.open("objects/recto.png")
verso = Image.open("objects/verso.png")
recto = Image.open(self.recto)
verso = Image.open(self.verso)
# Pasting QR codes
recto.paste(qr_pub.resize((200, 200)), (435, 15)) # 36))
verso.paste(qr_priv.resize((180, 180)), (580, 6))
# Setting font
font = ImageFont.truetype("objects/Roboto-Medium.ttf", 18)
# font = ImageFont.truetype("objects/Roboto-Medium.ttf", 18)
font = ImageFont.truetype(self.typo, 18)
# Writing amount
if self.amount > 0:
draw = ImageDraw.Draw(recto)
txt = "\n".join([str(self.amount) + G1_SYMBOL])