Système d'impression de billets développé avec Duniterpy

MERCI;
Ça fonctionne! Je vais maintenant essayer d’utiliser duniterpy directement.

Voici les commandes que je cherche à effectuer:

./silkaj/silkaj generate_auth_file -salt="$PHONE" -password="$PIN" => Initialise un wallet
./silkaj/silkaj amount "$RIB" => Montant du compte
./silkaj transaction --auth-scrypt -salt="$PHONE" -password="$PIN" --amount="$VIR" --output="$DESTRIB" => KO ou Montant restant
./silkaj/silkaj id "$MEMBERUID" => Clef Publique Membre

Je vais fouiller dans les exemples… Enfin, si veux m’aiguiller, je suis preneur.

Ils ne savaient pas que c’était impossible, alors ils l’ont fait

1 Like

Petit cadeau pour les fêtes.

Le script correspondant à ta première commande. Il contient les bases d’un code python 3.5 propre avec typage pour gérer les arguments passés en ligne de commande. Il est inspiré de l’exemple présent dans le dépôt Duniterpy, mais remplace l’interactivité avec l’utilisateur par des arguments.

Note l’importance que je donne aux commentaires et aux docstrings afin que le code soit immédiatement compréhensible par un dev python et aussi pour l’IDE qui affiche la doc des fonctions à partir des docstrings.

[EDIT] Créer un fichier gen_pubkey.py contenant le code suivant :

import sys
from duniterpy.key import SigningKey


def generate_public_key(salt: str, password: str) -> str:
    """
    Return public key from credentials

    :param salt: Salt passphrase, using quotes if space in it
    :param password: Password
    """
    # Create key object
    key = SigningKey(salt, password)

    return key.pubkey


if __name__ == '__main__':

    # if bad number of arguments...
    if len(sys.argv) != 3:

        # display command usage
        print("""
        Usage:
            python gen_pubkey.py salt password
        """)

        # exit with status code error
        exit(1)

    # capture arguments
    _salt = sys.argv[1]
    _password = sys.argv[2]

    # display the public key
    print(generate_public_key(_salt, _password))

    # exit with status code ok
    exit(0)

Profite, je ferai pas ça tous les jours ! :wink:

3 Likes

Merci Mister @vit !

A prioris , je peux aussi accéder aux profils cesium+ par duniterpy?

Je me posais la question des requêtes sur elasticsearch, est-il possible d’écrire un profil cesium+?
Comme ajouter un nom, une image associé au compte porte monnaie SMS créé…

Je voudrais faire une double authentification quand on déclare par SMS son pseudo de membre possesseur du porte-monnaie. Je pourrai envoyer code par email (saisi dans Cesium pour les notifications).
Mais là si j’ai bien compris, il faut une autorisation spéciale (la clef de l’opérateur de notification SMS) @kimamila?

Belle Année Libre

Maintenant que je me sens plus à l’aise avec python (quoi que), j’essaye de mettre au point G1sms+

Avec des framboises, un chapeau GSM, du script shell, du python et un essaim IPFS (ou Textile) pour dialoguer en toute égalité d’accès spatio-temporelle avec les données partagées…

https://www.g1sms.fr/fr/g1ipfs/g1smsplus

Après un casse tête sur l’accès au port série (que Raspbian s’allouait pour y coller une console), la V1 de G1sms tourne (en double). Voila le moment de la pimper un peu !!

Pour continuer…
Je tente de récupérer (avec duniterpy) mon profil Cesium+ mais badaboum.
Je me heurte à une incompatibilité de format json du résultat!! libsodium: Migrate from libnacl to PyNaCl (#83) · Issues · clients / python / DuniterPy · GitLab

Et @vit, quand j’essaye de lancer le gen_pubkey.py que tu m’as mis plus haut, voila que le gros serpent se rebiffe:

python3 gen_pubkey.py MAMA MIA

Traceback (most recent call last):
  File "gen_pubkey.py", line 37, in <module>
    print(generate_public_key(_salt, _password))
  File "gen_pubkey.py", line 13, in generate_public_key
    key = SigningKey(salt, password)
TypeError: __init__() takes 2 positional arguments but 3 were given

Ah lala…

Si tu remplaces la ligne 13 par :

    key = SigningKey.from_credentials(salt, password)

:slight_smile: :question:

3 Likes

Good!! J’ai encore du boulot avant de parler comme il faut python :wink:

1 Like

Il me reste à comprendre pourquoi ce que me retourne ce script n’est pas compatible json

import asyncio
from duniterpy.api.client import Client

ES_CORE_ENDPOINT = "ES_CORE_API g1.data.duniter.fr 443"
ES_USER_ENDPOINT = "ES_USER_API g1.data.duniter.fr 443"

async def main():
    """
    Main code (synchronous requests)
    """
    # Create Client from endpoint string in Duniter format
    client = Client(ES_USER_ENDPOINT)

    # prompt entry
    # pubkey = input("\nEnter a public key to get the user profile: ")
    pubkey = "DsEx1pS33vzYZg4MroyBV9hCw98j1gtHEhwiZ5tK7ech"

    # Get the profil of a public key (direct REST GET request)
    # print("\nGET user/profile/{0}/_source:".format(pubkey))
    response = await client.get('user/profile/{0}/_source'.format(pubkey.strip(' \n')))
    print(response)

    # Close client aiohttp session
    await client.close()

# Latest duniter-python-api is asynchronous and you have to use asyncio, an asyncio loop and a "as" on the data.
# ( https://docs.python.org/3/library/asyncio.html )
asyncio.get_event_loop().run_until_complete(main())

Je voudrai récupérer l’image (pour mettre sur les billets) et les coordonnées du membre pour une double authentification

Si tu as un doute sur un objet, une fonction, tu peux faire help(SigningKey) dans la console, ou encore SigningKey. et faire tab.

La sortie est le dump d’un objet dict de Python. Ça ressemble au JSON mais c’est pas exactement ça. Il y a une bibliothèque pour ça :

import json
print(json.dumps(response))

En fait ça pourrait être compatible, sauf que les lecteurs JSON veulent absolument que les noms soient délimités par des " plutôt que par des ':stuck_out_tongue:

3 Likes

Merci pour ce petit cours privé! Maintenant ça marche…
Et le rêve se réalise!! Je peux extraire des données de Cesium+ avec Duniterpy et jq :japanese_goblin:

python3 request_cesium_profile.py | jq '.geoPoint'
{
  "lat": 43.6044622,
  "lon": 1.4442469
}

Ah zut, parlé trop vite, sauf pour l’image :frowning_face:

python3 request_cesium_profile.py | jq '.avatar._content' > /tmp/image.png

Peut-être que @kimamila ou qq’un saurait comment m’aider à la remettre en png comme elle semble l’être:

python3 request_cesium_profile.py | jq '.avatar._content_type'
"image/png"

Si l’image est contenue dans le json elle est sûrement en format url, ce qui doit être de la base 64 je pense. Donc il faut la convertir en binaire d’abord.

Ah oui!! j’essaye… (envirant les ")

python3 request_cesium_profile.py | jq '.avatar._content' | sed 's/\"//g' | base64 -d > image.png

On peut aussi interroger Cesium+ directement en fait:

curl https://g1pod.madeinzion.org/user/profile/fW4xi1siLtSEN6BMXgCRfdeu28HSVWT15TQHmfmMA85 -s | jq '._source.avatar._content' | sed 's/\"//g' | base64 -d > image.png

Et ça fonctionne!!! MERCI @tuxmain
je t’envoi des LOVE dans la foulée (Vir 100 tuxmain)

2 Likes

Wow, j’admire le one-liner en bash… :slight_smile:

1 Like

J’adore piper les commandes :wink: Allez c’est l’heure de l’apéro à l’Anthropicafé

1 Like

Pow, tu me fait découvrir cette fonctionnalité, c’est juste trop ouf. Merci.

1 Like

Pas tant que ça, là tu avais un problème parce que Duniterpy a évolué en brisant la compatibilité avec les versions antérieures. Forcément tu ne peux pas le deviner à moins de fouiller le code…

Je t’invite vraiment à utiliser un IDE comme PyCharm (version community) qui t’apportera l’auto-completion automatique et t’aurais proposé la solution ! :sunglasses:

Grand merci à @tuxmain qui maîtrise python ET Duniterpy !

3 Likes

@vit Tu veux dire que Pycharm va me compléter le code?

Par exemple,

key = SigningKey.from_credentials(salt, password)
pubkey_from = key.pubkey

je voudrai accéder aussi à la clef privée. Après avoir écrit “key.” la liste de ce qui est possible apparaîtrait?

Pour standardiser le dialogue avec Duniter (et plus utiliser des awk avec silkaj qui pourraient pêter).
Je suis en train de vouloir utiliser duniterpy pour envoyer les TX de G1sms.
Je peux me fier à l’exemple?
https://git.duniter.org/clients/python/duniterpy/raw/dev/examples/send_transaction.py ?

Concernant les accès BMA, quels sont les serveurs à qui m’adresser pour la Ḡ1? J’ai mis:
BMAS_ENDPOINT = "BMAS g1.duniter.org 443"
TRANSACTION_VERSION = 10 est-il d’accualité?

1 Like

Tout les nœuds Duniter qui ont BMA tu peut les voir dans Cesium, il y en a beaucoup :slight_smile:

Par exemple le miens BMAS ts.g1.librelois.fr 443

Oui tout les documents (donc les transactiosn aussi) sont encore en version 10 :wink:

Dans l’exemple, https://git.duniter.org/clients/python/duniterpy/raw/dev/examples/send_transaction.py
Si je comprends bien, on se connecte à un noeud BMA, on récupère la dernière transaction et on y ajoute la notre.

Il me semble ne voir nulle part où est renseigné le montant de la TX crée…

    InputSource(
        amount=source['amount'],
        base=source['base'],
        source=source['type'],
        origin_id=source['identifier'],
        index=source['noffset']
    )

Comment doivent être renseignés ces paramètres?

Alors je n’ai pas lu le code python en question, mais je peut au moins te dire que les documents transaction n’ont pas d’attribut montant : une transaction ne correspond qu’a la destructions de sources en inputs et la création de nouvelles sources en output.

Pour que la transaction soit valide, il faut entre autre que la somme des montants des inputs soit strictement égale a la somme des montants en output.

Concernant le “montant” envoyé au destinataire de la transaction il s’agit du montant de l’output qui sera attribué au destinataire. (Il peut y avoir un 2ème output de “reste” que l’émetteur se renvoi a lui-même si les sources consommés en input atteignent un montant supérieur a celui qu’il souhaite envoyer).

Sur dup-tools-front tu a un exemple de chaque document, le document transaction d’exemple montre l’envoi de 20,04 G1 :slight_smile:

1 Like