1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141
|
# Copyright 2014-2022 Vincent Texier <vit@free.fr>
#
# DuniterPy is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# DuniterPy is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import getpass
import os
from typing import Optional
from duniterpy.api import bma
from duniterpy.api.client import Client
from duniterpy.documents import Identity, Revocation
from duniterpy.key import SigningKey
if "XDG_CONFIG_HOME" in os.environ:
home_path = os.environ["XDG_CONFIG_HOME"]
elif "HOME" in os.environ:
home_path = os.environ["HOME"]
elif "APPDATA" in os.environ:
home_path = os.environ["APPDATA"]
else:
home_path = os.path.dirname(__file__)
# CONFIG #######################################
# You can either use a complete defined endpoint : [NAME_OF_THE_API] [DOMAIN] [IPv4] [IPv6] [PORT] [PATH]
# or the simple definition : [NAME_OF_THE_API] [DOMAIN] [PORT] [PATH]
# Here we use the secure BASIC_MERKLED_API (BMAS)
BMAS_ENDPOINT = "BMAS g1-test.duniter.org 443"
# WARNING : Hide this file in a safe and secure place
# If one day you forget your credentials,
# you'll have to use your private key instead
REVOCATION_DOCUMENT_FILE_PATH = os.path.join(
home_path, "duniter_account_revocation_document.txt"
)
################################################
def get_identity_document(
client: Client, current_block: dict, pubkey: str
) -> Optional[Identity]:
"""
Get the identity document of the pubkey
:param client: Client to connect to the api
:param current_block: Current block data
:param pubkey: UID/Public key
:rtype: Identity
"""
# Here we request for the path wot/lookup/pubkey
lookup_response = client(bma.wot.lookup, pubkey)
return Identity.from_bma_lookup_response(
current_block["currency"], pubkey, lookup_response
)
def get_signed_raw_revocation_document(
identity: Identity, salt: str, password: str
) -> str:
"""
Generate account revocation document for given identity
:param identity: Self Certification of the identity
:param salt: Salt
:param password: Password
:rtype: str
"""
key = SigningKey.from_credentials(salt, password)
revocation = Revocation(identity, key, currency=identity.currency)
return revocation.signed_raw()
def save_revoke_document():
"""
Main code
"""
# Create Client from endpoint string in Duniter format
client = Client(BMAS_ENDPOINT)
# Get the node summary infos to test the connection
response = client(bma.node.summary)
print(response)
# prompt hidden user entry
salt = getpass.getpass("Enter your passphrase (salt): ")
# prompt hidden user entry
password = getpass.getpass("Enter your password: ")
# prompt public key
pubkey = input("Enter your public key: ")
# init signer instance
signer = SigningKey.from_credentials(salt, password)
# check public key
if signer.pubkey != pubkey:
print("Bad credentials!")
return
# capture current block to get currency name
current_block = client(bma.blockchain.current)
# create our Identity document to sign the revocation document
identity = get_identity_document(client, current_block, pubkey)
if identity is None:
print(f"Identity not found for pubkey {pubkey}")
# Close client aiohttp session
return
# get the revoke document
revocation_signed_raw_document = get_signed_raw_revocation_document(
identity, salt, password
)
# save revoke document in a file
with open(REVOCATION_DOCUMENT_FILE_PATH, "w", encoding="utf-8") as fp:
fp.write(revocation_signed_raw_document)
# document saved
print(f"Revocation document saved in {REVOCATION_DOCUMENT_FILE_PATH}")
if __name__ == "__main__":
save_revoke_document()
|