diff --git a/img/QR_oasis_OASIS.png b/img/QR_oasis_OASIS.png new file mode 100644 index 0000000..7114693 Binary files /dev/null and b/img/QR_oasis_OASIS.png differ diff --git a/sms/jaklis/lib/currentUd.py b/sms/jaklis/lib/currentUd.py new file mode 100644 index 0000000..f038ac5 --- /dev/null +++ b/sms/jaklis/lib/currentUd.py @@ -0,0 +1,40 @@ +#!/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 + +class currentUd: + + def __init__(self, node): + # Define Duniter GVA node + transport = AIOHTTPTransport(url=node) + self.client = Client(transport=transport, fetch_schema_from_transport=True) + + def sendDoc(self): + # Build UD generation document + queryBuild = gql( + """ + query { + currentUd { + amount + } + } + """ + ) + paramsBuild = { + } + + # Send UD document + try: + udValue = 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 DU:\n" + message + "\n") + sys.exit(1) + + udValueFinal = udValue['currentUd']['amount'] + + return udValueFinal diff --git a/sms/jaklis/lib/gvaID.py b/sms/jaklis/lib/gvaID.py new file mode 100644 index 0000000..023a144 --- /dev/null +++ b/sms/jaklis/lib/gvaID.py @@ -0,0 +1,81 @@ +#!/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.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, getBalance=False): + # Build balance generation document + if (getBalance): + queryBuild = gql( + """ + query ($pubkey: PubKeyGva!, $script: PkOrScriptGva!){ + idty (pubkey: $pubkey) { + isMember + username + } + balance(script: $script) { + amount + } + } + """ + ) + else: + queryBuild = gql( + """ + query ($pubkey: PubKeyGva!){ + idty (pubkey: $pubkey) { + isMember + username + } + } + """ + ) + + paramsBuild = { + "pubkey": self.pubkey, + "script": f"SIG({self.pubkey})" + } + + # Send balance document + try: + queryResult = self.client.execute(queryBuild, variable_values=paramsBuild) + except Exception as e: + sys.stderr.write("Echec de récupération du solde:\n" + str(e) + "\n") + sys.exit(1) + + jsonBrut = queryResult + + if (getBalance): + if (queryResult['balance'] == None): + jsonBrut['balance'] = {"amount": 0.0} + else: + jsonBrut['balance'] = queryResult['balance']['amount']/100 + + if (queryResult['idty'] == None): + username = 'Matiou' + isMember = False + else: + username = queryResult['idty']['username'] + isMember = queryResult['idty']['isMember'] + + return json.dumps(jsonBrut, indent=2) diff --git a/sms/jaklis/lib/qrcode-reader.py b/sms/jaklis/lib/qrcode-reader.py new file mode 100755 index 0000000..f92bfcd --- /dev/null +++ b/sms/jaklis/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) + diff --git a/sms/jaklis/lib/stars.py b/sms/jaklis/lib/stars.py new file mode 100755 index 0000000..5eee339 --- /dev/null +++ b/sms/jaklis/lib/stars.py @@ -0,0 +1,242 @@ +import os, sys, ast, requests, json, base58, base64, time, string, random, re +from lib.natools import fmt, sign, get_privkey, box_decrypt, box_encrypt +from time import sleep +from hashlib import sha256 +from datetime import datetime +from termcolor import colored +from lib.cesiumCommon import CesiumCommon, PUBKEY_REGEX + +class ReadLikes(CesiumCommon): + # Configure JSON document to send + def configDoc(self, profile): + if not profile: profile = self.pubkey + + data = {} + data['query'] = {} + data['query']['bool'] = {} + data['query']['bool']['filter'] = [ + {'term': {'index': 'user'}}, + {'term': {'type': 'profile'}}, + {'term': {'id': profile}}, + {'term': {'kind': 'STAR'}} + ] + # data['query']['bool']['should'] = {'term':{'issuer': self.issuer}} + data['size'] = 5000 + data['_source'] = ['issuer','level'] + data['aggs'] = { + 'level_sum': { + 'sum': { + 'field': 'level' + } + } + } + + return json.dumps(data) + + def sendDocument(self, document): + + headers = { + 'Content-type': 'application/json', + } + + # Send JSON document and get JSON result + result = requests.post('{0}/like/record/_search'.format(self.pod), headers=headers, data=document) + + if result.status_code == 200: + # print(result.text) + return result.text + else: + sys.stderr.write("Echec de l'envoi du document de lecture des messages...\n" + result.text + '\n') + + def parseResult(self, result): + result = json.loads(result) + totalLikes = result['hits']['total'] + totalValue = result['aggregations']['level_sum']['value'] + if totalLikes: + score = totalValue/totalLikes + else: + score = 0 + raw = result['hits']['hits'] + finalPrint = {} + finalPrint['likes'] = [] + for i in raw: + issuer = i['_source']['issuer'] + # print(issuer) + gProfile = self.getProfile(issuer) + try: + pseudo = gProfile['title'] + except: + pseudo = '' + try: + payTo = gProfile['pubkey'] + except: + payTo = '' + id = i['_id'] + level = i['_source']['level'] + if issuer == self.pubkey: + finalPrint['yours'] = { 'id' : id, 'pseudo' : pseudo, 'payTo' : payTo, 'level' : level } + else: + finalPrint['likes'].append({ 'issuer' : issuer, 'pseudo' : pseudo, 'payTo' : payTo, 'level' : level }) + finalPrint['score'] = score + + return json.dumps(finalPrint) + + def getProfile(self, profile): + headers = { + 'Content-type': 'application/json', + } + + data = {} + data['query'] = {} + data['query']['bool'] = {} + data['query']['bool']['filter'] = [ + {'term': {'_index': 'user'}}, + {'term': {'_type': 'profile'}}, + {'term': {'_id': profile}} + ] + data['_source'] = ['title','pubkey'] + + data = json.dumps(data) + + result = requests.post('{0}/user/profile/_search'.format(self.pod), headers=headers, data=data) + result = json.loads(result.text)['hits']['hits'] + for i in result: + return i['_source'] + + +#################### Like class #################### + + +class SendLikes(CesiumCommon): + # Configure JSON document to send + def configDoc(self, profile, likes): + if not profile: profile = self.pubkey + if likes not in range(0, 6): + sys.stderr.write(colored('Votre like doit être compris entre 0 et 5.\n', 'red')) + return False + + + timeSent = int(time.time()) + + data = {} + data['version'] = 2 + data['index'] = "user" + data['type'] = "profile" + data['id'] = profile + data['kind'] = "STAR" + data['level'] = likes + data['time'] = timeSent + data['issuer'] = self.pubkey + + document = json.dumps(data) + + # Generate hash of document + hashDoc = sha256(document.encode()).hexdigest().upper() + + # Generate signature of document + signature = fmt["64"](sign(hashDoc.encode(), get_privkey(self.dunikey, "pubsec"))[:-len(hashDoc.encode())]).decode() + + # Build final document + data = {} + data['hash'] = hashDoc + data['signature'] = signature + signJSON = json.dumps(data) + finalJSON = {**json.loads(signJSON), **json.loads(document)} + finalDoc = json.dumps(finalJSON) + + return finalDoc + + def sendDocument(self, document, pubkey): + + headers = { + 'Content-type': 'application/json', + } + + # Send JSON document and get JSON result + result = requests.post('{0}/user/profile/:id/_like'.format(self.pod), headers=headers, data=document) + + if result.status_code == 200: + print(colored("Profile liké avec succès !", 'green')) + return result.text + elif result.status_code == 400: + resultJson = json.loads(result.text) + if 'DuplicatedDocumentException' in resultJson['error']: + rmLike = UnLikes(self.dunikey, self.pod) + idLike = rmLike.checkLike(pubkey) + if idLike: + document = rmLike.configDoc(idLike) + rmLike.sendDocument(document, True) + sleep(0.5) + self.sendDocument(document, pubkey) + return resultJson['error'] + else: + sys.stderr.write("Echec de l'envoi du document de lecture des messages...\n" + resultJson['error'] + '\n') + else: + resultJson = json.loads(result.text) + sys.stderr.write("Echec de l'envoi du document de lecture des messages...\n" + resultJson['error'] + '\n') + + +#################### Unlike class #################### + + +class UnLikes(CesiumCommon): + # Check if you liked this profile + def checkLike(self, pubkey): + readProfileLikes = ReadLikes(self.dunikey, self.pod) + document = readProfileLikes.configDoc(pubkey) + result = readProfileLikes.sendDocument(document) + result = readProfileLikes.parseResult(result) + result = json.loads(result) + + if 'yours' in result: + myLike = result['yours']['id'] + return myLike + else: + sys.stderr.write("Vous n'avez pas liké ce profile\n") + return False + + # Configure JSON document to send + def configDoc(self, idLike): + timeSent = int(time.time()) + + data = {} + data['version'] = 2 + data['index'] = "like" + data['type'] = "record" + data['id'] = idLike + data['issuer'] = self.pubkey + data['time'] = timeSent + + document = json.dumps(data) + + # Generate hash of document + hashDoc = sha256(document.encode()).hexdigest().upper() + + # Generate signature of document + signature = fmt["64"](sign(hashDoc.encode(), get_privkey(self.dunikey, "pubsec"))[:-len(hashDoc.encode())]).decode() + + # Build final document + data = {} + data['hash'] = hashDoc + data['signature'] = signature + signJSON = json.dumps(data) + finalJSON = {**json.loads(signJSON), **json.loads(document)} + finalDoc = json.dumps(finalJSON) + + return finalDoc + + def sendDocument(self, document, silent): + + headers = { + 'Content-type': 'application/json', + } + + # Send JSON document and get JSON result + result = requests.post('{0}/history/delete'.format(self.pod), headers=headers, data=document) + + if result.status_code == 200: + if not silent: + print(colored("Like supprimé avec succès !", 'green')) + return result.text + else: + sys.stderr.write("Echec de l'envoi du document de lecture des messages...\n" + result.text + '\n')