diff --git a/jaklis.py b/jaklis.py index 24ffc17..2561599 100755 --- a/jaklis.py +++ b/jaklis.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python3 +#!/usr/bin/env python3.9 import argparse, sys, os, getpass, string, random from os.path import join, dirname @@ -37,6 +37,7 @@ deleteoffer_cmd = subparsers.add_parser('deleteoffer', help="Supprimer une annon pay_cmd = subparsers.add_parser('pay', help="Payer en Ḡ1") history_cmd = subparsers.add_parser('history', help="Voir l'historique des transactions d'un compte Ḡ1") balance_cmd = subparsers.add_parser('balance', help="Voir le solde d'un compte Ḡ1") +id_cmd = subparsers.add_parser('id', help="Voir l'identité d'une clé publique/username") # Messages management read_cmd.add_argument('-n', '--number',type=int, default=3, help="Affiche les NUMBER derniers messages") @@ -94,6 +95,8 @@ history_cmd.add_argument('--nocolors', action='store_true', help="Affiche le r balance_cmd.add_argument('-p', '--pubkey', help="Clé publique du compte visé") balance_cmd.add_argument('-m', '--mempool', action='store_true', help="Utilise les sources en Mempool") +id_cmd.add_argument('-p', '--pubkey', help="Clé publique du compte visé") +id_cmd.add_argument('-u', '--username', help="Username du compte visé") args = parser.parse_args() @@ -220,7 +223,7 @@ if cmd in ("read","send","delete","set","get","erase","stars","unstars","getoffe cesium.deleteOffer(args.id) # Construct GVA object -elif cmd in ("pay","history","balance"): +elif cmd in ("pay","history","balance","id"): from lib.gva import GvaApi if args.node: @@ -239,10 +242,12 @@ elif cmd in ("pay","history","balance"): if cmd == "pay": gva.pay(args.amount, args.comment, args.mempool, args.verbose) - if cmd == "history": + elif cmd == "history": gva.history(args.json, args.nocolors, args.number) - if cmd == "balance": + elif cmd == "balance": gva.balance(args.mempool) + elif cmd == "id": + gva.id(args.pubkey, args.username) if keyPath: diff --git a/lib/cesium.py b/lib/cesium.py index e755519..4254fea 100755 --- a/lib/cesium.py +++ b/lib/cesium.py @@ -100,13 +100,14 @@ class CesiumPlus(CesiumCommon): document = setOffer.configDocSet(title, description, city, localisation, category, price, picture) result = setOffer.sendDocumentSet(document,'set') - print(result) + # print(result) return result def getOffer(self, id, avatar=None): getOffer = Offers(self.dunikey, self.pod, self.noNeedDunikey) - + resultJSON = getOffer.sendDocumentGet(id, 'get') + # print(resultJSON) result = getOffer.parseJSON(resultJSON) print(result) diff --git a/lib/gva.py b/lib/gva.py index 0ec1ad6..3e08609 100755 --- a/lib/gva.py +++ b/lib/gva.py @@ -3,6 +3,7 @@ from lib.natools import get_privkey from lib.gvaPay import Transaction, PUBKEY_REGEX from lib.gvaHistory import History from lib.gvaBalance import Balance +from lib.gvaID import Id class GvaApi(): def __init__(self, dunikey, node, pubkey, noNeedDunikey=False): @@ -57,3 +58,8 @@ class GvaApi(): gva = Balance(self.dunikey, self.node, self.destPubkey, useMempool) balanceValue = gva.sendDoc() print(balanceValue) + + def id(self, pubkey, username): + gva = Id(self.dunikey, self.node, pubkey, username) + result = gva.sendDoc() + print(result) diff --git a/lib/gvaID.py b/lib/gvaID.py new file mode 100644 index 0000000..4e6626b --- /dev/null +++ b/lib/gvaID.py @@ -0,0 +1,54 @@ +#!/usr/bin/env python3 + +import sys, re, os.path, json, ast +from termcolor import colored +from lib.natools import fmt, sign, get_privkey +from gql import gql, Client +from gql.transport.aiohttp import AIOHTTPTransport + +PUBKEY_REGEX = "(?![OIl])[1-9A-Za-z]{42,45}" + +class Id: + + def __init__(self, dunikey, node, pubkey='', username=''): + self.dunikey = dunikey + self.pubkey = pubkey if pubkey else get_privkey(dunikey, "pubsec").pubkey + self.pubkey = pubkey + self.username = username + if not re.match(PUBKEY_REGEX, self.pubkey) or len(self.pubkey) > 45: + sys.stderr.write("La clé publique n'est pas au bon format.\n") + sys.exit(1) + + # Define Duniter GVA node + transport = AIOHTTPTransport(url=node) + self.client = Client(transport=transport, fetch_schema_from_transport=True) + + def sendDoc(self): + # Build balance generation document + queryBuild = gql( + """ + query ($pubkey: String!){ + idty (pubkey: $pubkey) { + isMember + username + } + } + """ + ) + paramsBuild = { + "pubkey": self.pubkey + } + + # Send balance document + try: + IDResult = self.client.execute(queryBuild, variable_values=paramsBuild) + except Exception as e: + message = ast.literal_eval(str(e))["message"] + sys.stderr.write("Echec de récupération du solde:\n" + message + "\n") + sys.exit(1) + + jsonBrut = IDResult['idty'] + username = IDResult['idty']['username'] + isMember = IDResult['idty']['isMember'] + + return json.dumps(jsonBrut, indent=2) diff --git a/lib/offers.py b/lib/offers.py index 10dfe98..5af44f4 100644 --- a/lib/offers.py +++ b/lib/offers.py @@ -94,11 +94,13 @@ class Offers(CesiumCommon): if type == 'set': reqQuery = '{0}/market/record'.format(self.pod) elif type == 'get': - reqQuery = '{0}/market/record/{1}?_source=category,title,description,issuer,time,creationTime,location,address,city,price,unit,currency,thumbnail._content_type,picturesCount,type,stock,fees,feesCurrency,geoPoint,pubkey,freePrice'.format(self.pod, id) + reqQuery = '{0}/market/record/{1}?_source=category,title,description,issuer,time,creationTime,location,address,city,price,unit,currency,thumbnail._content_type,thumbnail._content,picturesCount,type,stock,fees,feesCurrency,geoPoint,pubkey,freePrice'.format(self.pod, id) elif type == 'erase': reqQuery = '{0}/market/delete'.format(self.pod) + result = requests.get(reqQuery, headers=headers) + # print(result) if result.status_code == 200: # print(result.text) return result.text diff --git a/lib/qrcode-reader.py b/lib/qrcode-reader.py new file mode 100755 index 0000000..f92bfcd --- /dev/null +++ b/lib/qrcode-reader.py @@ -0,0 +1,86 @@ +#!/usr/bin/env python3 + +from io import BytesIO +import base64, base58, varint, os, json +# from lib.cesium import CesiumPlus as cs + +## BytesIO adds a stream interface to bytes +## Exemple: +qr = BytesIO(bytes.fromhex("8316140212c28e52e034ecaf684fa3e5d755db519074f27ad086bddffd26b386e55f3b623ca01f0177c0f8ce5f6a69764c7bc10263ec")) + +## Read from a file: +# qr = open("qrcode-AXfA-M5faml2THvBAmPs.bin","rb") +# qr = BytesIO(qr.read()) + +## Check magic number +assert qr.read(3) == b"\x83\x16\x14" + +## Read data type +data_type = varint.decode_stream(qr) + +## Read price type +raw_price_type = varint.decode_stream(qr) +price_type = raw_price_type >> 4 +amount_len = raw_price_type & 0b1111 + +## Read pubkey +pubkey = qr.read(32) +pubkey_b58 = base58.b58encode(pubkey) +# print("Pubkey: {}".format(pubkey_b58.decode("utf-8"))) + +## Read amount + +if price_type == 0: # Free price, ignore amount + qr.read(amount_len) + print("Free price") + +elif price_type == 1: # Units + amount = varint.decode_stream(qr) + # print("Price: {} Ğ1".format(amount/100)) + +elif price_type == 2: # UD + amount_n = varint.decode_stream(qr) + amount_e = varint.decode_stream(qr) + amount = amount_n * 10 ** -amount_e + # print("Price: {} UD_Ğ1".format(amount.decode("utf-8"))) + +else: + qr.read(amount_len) + print("Error: unknown price type, ignoring price") + +## Read data + +if data_type == 0: # No data + data = None + print("There is no data") + +elif data_type == 1: # Plain text + data = qr.read() + print("Data:") + print(data) + +elif data_type == 2: # Ğchange ad + data = base64.urlsafe_b64encode(qr.read(16)) + # print("Ğchange ad ID: {}".format(data.decode("utf-8"))) + + +## Get gchange-pod datas + +item = os.popen("./../jaklis/jaklis.py getoffer -i {0}".format(data.decode("utf-8"))) +# item = cs.getOffer(id) + + +jsonR = json.load(item) +item_time = jsonR['creationTime'] +item_name = jsonR['title'] +item_description = jsonR['description'] +item_image = jsonR['thumbnail'] +isImage = '_content' in item_image +if (isImage): + print(item_image['_content']) + +# print(jsonR) +print(item_time) +print(item_name) +print(item_description) +