Commit 4f45bd39 authored by matograine's avatar matograine

remove WIF ; change base images ; rework file organization ; begin the funding functions.

parent 13d1ddef
[[source]]
name = "pypi"
url = "https://pypi.org/simple"
verify_ssl = true
[dev-packages]
[packages]
duniterpy = "*"
reportlab = "*"
qrcode = "*"
black = "*"
[requires]
python_version = "3.5"
......@@ -8,23 +8,13 @@ En phase de développement, ceci est une version Alpha.
Le logiciel n'est pas encore packagé, vous devez l'installer à la main.
## Installation des dépendances
## Installation des dépendances DEBIAN
- `python3`
- `pip3`
- `git`
### Debian :
```
$ sudo apt-get install python3 python3-pip git
$ sudo apt-get install python3 python3-pip git python3-qrcode python3-reportlab python3-pil ; sudo python3.5 -m pip install duniterpy
```
### Arch Linux
```
$ sudo pacman -S python python-pip git
```
## Installation de G1pourboire
......
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
from tkinter import *
from generator import Generator
## Variables ##
## Classes ##
## Fonctions ##
def logger (texte) :
logs.config (state = NORMAL)
logs.insert (END, texte + "\n")
logs.config (state = DISABLED)
def generer () :
nombre = nbr_feuille.get ()
g = Generator(int(nombre))
g.generate()
logger ("Les Ğ1Pourboires ont été générés.\nVous les trouverez dans le dossier ~/Documents/G1pourboires.")
def generer_evt (evt) :
generer ()
## Fenêtre ##
root = Tk () # création de la fenêtre principale
root.title ("Ğ1pourboire")
# Premier frame (générateur)
f1 = LabelFrame (root, text = "Générateur de Ğ1Pourboires", width = 80, borderwidth = 2, relief = GROOVE, padx = 10 , pady = 10)
f1.pack ()
q_nombre = Label (f1, text = "Les pourboires sont générés par pages de 6.\nCombien de pages voulez-vous créer ?", width = 40)
q_nombre.pack (side = LEFT)
nbr_feuille = Entry (f1, width = 10)
nbr_feuille.pack (side = LEFT, padx = 5)
nbr_feuille.bind ( "<Return>" , generer_evt )
nbr_feuille.focus_set ()
bouton = Button (f1, text = "Générer", width = 10, command = generer )
bouton.pack (side = LEFT, padx = 50)
bouton.bind ("<Return>", generer_evt)
# Second frame (logs)
f3 = LabelFrame (root, text = "Logs" , width = 1000, borderwidth = 2, relief = GROOVE, padx = 10 , pady = 10)
f3.pack ()
logs = Text (f3, height = 10, bg = "white")
logs.pack ()
logs.config (state = DISABLED)
# Fin de la fenêtre
root.mainloop ()
from generator import Generator
import tkinter as tk # import de tkinter
#!/usr/bin/env python3
#def generator () :
# nombre = nombre_pages.get
# g = Generator(int(nombre))
# g.generate()
root = tk.Tk () # création de la fenêtre principale
titre = tk.Label (text = "Vous allez générer des Ğ1Pourboires")
titre.grid (column = 0 , row = 0) # on ajoute l'objet à la fenêtre principale
q_nombre = tk.Label (text = "Les pourboires sont générés par pages de 6. Combien de pages voulez-vous créer ?")
q_nombre.grid (column = 0 , row = 1)
nbr_feuille = tk.Entry ()
nbr_feuille.grid (column = 1 , row = 1)
bouton = tk.Button (text = "Générer")
bouton.grid (column = 2 , row = 1)
#bouton.config (command = generator () )
root.mainloop () # on affiche enfin la fenêtre principal et on attend
# les événements (souris, clic, clavier)
from PIL import Image, ImageFont, ImageDraw
from reportlab.pdfgen import canvas
from reportlab.lib.units import cm
#from silkaj.money import get_amount_from_pubkey #th
#from silkaj.tx import send_transaction #th
from duniterpy.key import SigningKey
from datetime import datetime
import os
......@@ -9,10 +11,15 @@ import qrcode
from diceware import diceware
class Generator():
"""Generate some wallets, create the pdf to print"""
def __init__(self, pages=1):
## Fonctions utilez à plusieurs classes :
# Nom du fichier
class Creating():
"""Generating, filling wallets"""
def __init__(self, amount=10, pages=1): # ajouter delay=6months
self.pages = pages
self.amount = amount
self.folder = os.path.expanduser('~/Documents/G1pourboire/')
self.output = self.folder \
+ datetime.now().strftime("G1pourboire_%Y-%m-%dT%Hh%M")
......@@ -23,13 +30,40 @@ class Generator():
if not os.path.exists(self.folder):
os.makedirs(self.folder)
def create(self):
# tip_date(self.wallets, self.delay) #calculer la date et l'inclure dans le json
Generator(self.output, self.wallets, self.pages).generate()
Transfer(self.amount, self.pages, self.wallets, self.output).transfer()
#Ajouter la date au json
def tip_date(wallets):
date = datetime.now().strftime("%Y-%m-%dT%Hh%M")
# expiring_date = datetime... #Ajouter $time
wallets.append({
'date': date,
# 'expiring_date': expiring_date
})
class Generator():
"""Generate some wallets, create the pdf to print"""
def __init__(self, output, wallets, pages=1):
self.pages = pages
self.output = output
self.wallets = wallets
self.c = None
def generate(self):
for i in range(self.pages):
for j in range(6): # 6 wallets per pages
self.new_wallet()
self.make_pdf()
self.save_json()
# self.save_json()
def new_wallet(self):
# Generating credetials
......@@ -38,26 +72,26 @@ class Generator():
# Generating public 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]
os.remove("privatekey.wif")
# key.save_wif_file("privatekey.wif")
# wif_data = open("privatekey.wif").readlines()[-1].split(": ")[1]
# os.remove("privatekey.wif")
# Creating the QR codes
qr_pub = qrcode.make(account_url)
qr_priv = qrcode.make(wif_data)
# qr_priv = qrcode.make(wif_data)
# Open images
recto = Image.open('recto.png')
verso = Image.open('verso.png')
# Pasting QR codes
recto.paste(qr_pub.resize((200, 200)), (435, 36))
verso.paste(qr_priv.resize((180, 180)), (580, 6))
recto.paste(qr_pub.resize((200, 200)), (435, 15)) #36))
# verso.paste(qr_priv.resize((180, 180)), (580, 6))
# Setting font
font = ImageFont.truetype("Roboto-Medium.ttf", 18)
......@@ -71,7 +105,7 @@ class Generator():
draw = ImageDraw.Draw(verso)
draw.text((570, 230), "ID : "+salt, (0,0,0), font=font)
draw.text((570, 250), "PW : "+password, (0,0,0), font=font)
# Add data to wallets
self.wallets.append({
'salt': salt,
......@@ -80,7 +114,7 @@ class Generator():
'date': 0,
'recto': recto,
'verso': verso,
'wif': wif_data,
'transfer': 'false',
})
def gen_page(self, wallets):
......@@ -100,7 +134,7 @@ class Generator():
for i, w in enumerate(wallets):
self.c.drawInlineImage(w['verso'], (21*cm-width)/2, 24.2*cm-i*height, width, height)
self.c.showPage()
def make_pdf(self):
def chunks(l, n):
"""Yield successive n-sized chunks from l."""
......@@ -115,8 +149,72 @@ class Generator():
data = [{
'pubkey': w['pubkey'],
'salt': w['salt'],
'password': w['password']
'password': w['password'],
'date': w['date']
} for w in self.wallets]
with open(self.output + ".json", 'w') as f:
f.write(json.dumps(data, indent=4))
class Transfer():
"""Create a transfer wallet, send amount to tips"""
def __init__(self, amount, pages, wallets, output):
self.output = output
self.wallets = wallets
self.pages = pages
self.amount = amount
# Credentials
self.salt = diceware(3, separator="-", camelcase=False)
self.password = diceware(3, separator="-", camelcase=False)
# Generating public key from credentials
self.key = SigningKey.from_credentials(self.salt, self.password)
def transfer(self):
total_amount = self.amount * 6 * self.pages
self.add_transfer_wallet()
self.save_json() # A verifier
print ("Send ", total_amount, "Ğ1 to : ", self.key.pubkey)
a = 0
while a == 0:
self.wait_funding(total_amount)
if 0: # attendre que wait_funding soit à true
a = 1
self.transfer_tips()
def add_transfer_wallet(self):
# Add data to wallets
self.wallets.append({
'salt': self.salt,
'password': self.password,
'pubkey': self.key.pubkey,
'transfer': 'true',
})
def wait_funding(self, total_amount):
#Attendre le paiement sur la clef de transfert self.key
# verifier le montant
# si le montant est different, renvoyer et redemander versement.
# si le montant est OK, return true.
return 0 # pour 1e test
def transfer_tips(self):
# envoyer mulitoutput sur toutes les pubkeys.
# si le montant est supérieur, renvoyer le restant sur la clef d'envoi.
# print ("Tips have been filled. A fork might occur, please check in a few hour.")
return 0 # pour 1e test
def save_json(self): # vérifier si je peux écrire des variables vides
data = [{
'transfer' : w['transfer'],
'pubkey': w['pubkey'],
'salt': w['salt'],
'password': w['password'],
} for w in self.wallets]
with open(self.output + ".json", 'w') as f:
f.write(json.dumps(data, indent=4))
#!/usr/bin/env python3
from generator import Generator
# -*- coding: utf-8 -*-
# Voir https://stackoverflow.com/questions/42009202/how-to-call-a-async-function-contained-in-a-class
# et : https://www.blog.pythonlibrary.org/2016/07/26/python-3-an-intro-to-asyncio/
# Pour le asyncio
# voir https://stackoverflow.com/questions/56042757/can-i-use-a-context-value-as-a-click-option-default
# pour le click context
from utils.common import Creating # Generator
from sys import argv
import asyncio
import aiohttp
import async_timeout
amount = float(argv[1])
pages = int(argv[2])
async def main(loop, amount, pages):
async with aiohttp.ClientSession(loop=loop) as session:
tasks = [create(session, amount, pages)]
await asyncio.gather(*tasks)
async def create(session, amount, pages):
with async_timeout.timeout(10):
# async with session.Creating(amount, pages).create() as response:
# return await response.release()
await Creating(amount, pages).create()
if __name__ == "__main__":
loop = asyncio.get_event_loop()
loop.run_until_complete(main(loop, amount, pages))
# await Creating(amount, pages).create()
g = Generator(int(argv[1]))
g.generate()
# c=Creating(float(argv[1]), int(argv[2]))
# await c.create()
python>=3.7
duniterpy>=0.54.3
Pillow>=6.0.0
qrcode>=6.1
reportlab>=3.5.23
silkaj==0.6.5
from duniterpy.key import SigningKey
from datetime import datetime
from utils.generator import Generator
from utils.transfer import Transfer
import os
import json
# Generate and fill Tips
class Creating:
"""Generating, filling wallets"""
def __init__(self, amount=10, pages=1, delay=6): # ajouter delay=6months
self.delay = delay
self.pages = pages
self.amount = amount
self.folder = os.path.expanduser("~/Documents/G1pourboire/")
self.output = self.folder + datetime.now().strftime(
"G1pourboire_%Y-%m-%dT%Hh%M"
)
self.wallets = []
# Create the folder
if not os.path.exists(self.folder):
os.makedirs(self.folder)
async def create(self):
""" Generating, filling wallets."""
self.tip_date()
Generator(self.output, self.wallets, self.pages).generate()
await Transfer(self.amount, self.pages, self.wallets, self.output).transfer()
# Ajouter la date au json
def tip_date(self):
"""
Set an expiring_date to custom delay.
Default is 6months.
"""
expiring_date = datetime.now().strftime("%Y-%m-%dT%Hh%M") # calculer + le délai
data = [{"expiring_date": expiring_date}] # for d in date] #self.wallets]
with open(self.output + "DATE_DEBUG_" + ".json", "w") as f:
f.write(json.dumps(data, indent=4))
#constants
G1_SYMBOL = "Ğ1"
GTEST_SYMBOL = "ĞTest"
G1_DEFAULT_ENDPOINT = "g1.duniter.org", "443"
G1_TEST_DEFAULT_ENDPOINT = "ts.gt.librelois.fr", "443"
CONNECTION_TIMEOUT = 10
ASYNC_SLEEP = 0.1
SOURCES_PER_TX = 50
......@@ -3,7 +3,7 @@
from random import choice
def diceware(N, wordlist="wordlist.txt", separator="", camelcase=True):
def diceware(N, wordlist="objects/wordlist.txt", 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
import os
import json
import qrcode
# 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.
class Generator:
"""Generate some wallets, create the pdf to print"""
def __init__(self, output, wallets, pages=1):
self.pages = pages
self.output = output
self.wallets = wallets
self.c = None
def generate(self):
for i in range(self.pages):
for j in range(6): # 6 wallets per pages
self.new_wallet()
self.make_pdf()
def new_wallet(self):
# Generating credetials
salt = diceware(3, separator="-", camelcase=False)
password = diceware(3, separator="-", camelcase=False)
# Generating public 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 + "/"
# Creating the QR codes
qr_pub = qrcode.make(account_url)
# Open images
recto = Image.open("objects/recto.png")
verso = Image.open("objects/verso.png")
# Pasting QR codes
recto.paste(qr_pub.resize((200, 200)), (435, 15)) # 36))
# Setting font
font = ImageFont.truetype("objects/Roboto-Medium.ttf", 18)
# Writing public key
draw = ImageDraw.Draw(recto)
txt = "\n".join([key.pubkey[i : i + 10] for i in range(0, len(key.pubkey), 10)])
draw.text((665, 80), txt, (0, 0, 0), font=font)
# Writing private keys
draw = ImageDraw.Draw(verso)
draw.text((570, 230), "ID : " + salt, (0, 0, 0), font=font)
draw.text((570, 250), "PW : " + password, (0, 0, 0), font=font)
# Add data to wallets
self.wallets.append(
{
"salt": salt,
"password": password,
"pubkey": key.pubkey,
"date": 0,
"recto": recto,
"verso": verso,
"transfer": "false",
}
)
def gen_page(self, wallets):
# Create a new canvas
if self.c == None:
self.c = canvas.Canvas(self.output + ".pdf")
# Size of wallets. You may not edit those values until you know what you do
width = 19 * cm
height = width * 302 / 1270
# Print recto
for i, w in enumerate(wallets):
self.c.drawInlineImage(
w["recto"], (21 * cm - width) / 2, 24.2 * cm - i * height, width, height
)
self.c.showPage()
# And verso
for i, w in enumerate(wallets):
self.c.drawInlineImage(
w["verso"], (21 * cm - width) / 2, 24.2 * cm - i * height, width, height
)
self.c.showPage()
def make_pdf(self):
def chunks(l, n):
"""Yield successive n-sized chunks from l."""
for i in range(0, len(l), n):
yield l[i : i + n]
# Create pages
for wallets in chunks(self.wallets, 6):
self.gen_page(wallets)
self.c.save()
def save_json(self): #Is this function still necessary ?
data = [
{"pubkey": w["pubkey"], "salt": w["salt"], "password": w["password"]}
for w in self.wallets
]
with open(self.output + ".json", "w") as f:
f.write(json.dumps(data, indent=4))
# This file wil contain the money-related functions :
# asking for account balance
# creating transactions files ( transfer tips, get back tips)
# sign transactions
# It should be more efficient to rewrite this than to use silkaj as a module (it needs a click context).
# This file should contain functions used for network :
# establish a connection with BMA
# close a connection with BMA
# send documents
# receive documents (?)
# This file should contain functions to get back tips after expiring_date.
from duniterpy.key import SigningKey
from datetime import datetime
from utils.diceware import diceware
import os
import json
class Transfer:
"""Create a transfer wallet, send amount to tips"""
def __init__(self, amount, pages, wallets, output):
self.output = output
self.wallets = wallets
self.pages = pages
self.amount = amount
# Credentials
self.salt = diceware(3, separator="-", camelcase=False)
self.password = diceware(3, separator="-", camelcase=False)
# Generating public key from credentials
self.key = SigningKey.from_credentials(self.salt, self.password)
async def transfer(self):
"""
Ask for transferring the total amount on an intermediary account,
transfer the money to tips
"""
total_amount = round(self.amount * 6 * self.pages, 2)
self.add_transfer_wallet()
self.save_json() # A verifier
print("Send ", total_amount, "Ğ1 to : ", self.key.pubkey)
await self.wait_funding(total_amount, self.key.pubkey)
await self.transfer_tips()
def add_transfer_wallet(self):
""" Add data for transfer_wallet to wallets"""
self.wallets.append(
{
"salt": self.salt,
"password": self.password,
"pubkey": self.key.pubkey,
"transfer": "true",
}
)
async def wait_funding(self, amount, key):
"""
Wait for payment on transfer_account
check that the amount is correct
send back incorrect amounts.
"""
print("FALSE Waiting for payment on ", key)
# pubkey_amount = await balance (key)
# check amount
# if pubkey_amount != amount:
# print ("Waiting for reception of ", amount, " Ğ1 on account : ", key, ". Waiting 3 minutes.")
# sleep 180
# else :
return 0 # TEST
async def transfer_tips(self):
"""
create the output list
send the tx with many outputs and one amount
"""
print("FALSE Payment received.\nSending ", self.amount, " Ğ1 on ", 6 * self.pages, " Tips.")
# create outputs list
tx_outputs = []
for w in self.wallets:
if w["transfer"] == "true":
pass
else:
tx_outputs.append (w["pubkey"])
print ("FALSE sending on key : ", w["pubkey"])
# await send(txoutputs, amount, "Tip")
print("FALSE Tips have been sent.\nYou can leave now, or wait a few minuts more : we check if the transactions are written on the Blockchain. This may take a while.")
await self.wait_funding(self.amount, tx_outputs[1])
print("FALSE Tips have been filled. A fork might occur, please check in a few hour.")
return 0 # TEST
def save_json(self): # find how to add the expiring_date info
"""
write wallets data in a json file.
"""
data = [
{
"transfer": w["transfer"],
"pubkey": w["pubkey"],
"salt": w["salt"],
"password": w["password"],
}
for w in self.wallets
]
with open(
self.output + ".json", "a"
) as f:
f.write(json.dumps(data, indent=4))
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment