Пример #1
0
async def cmd_amount(ctx, pubkeys):
    client = ClientInstance().client
    if not has_auth_method():
        if not pubkeys:
            message_exit("You should specify one or many pubkeys")
        pubkey_list = list()
        for pubkey in pubkeys:
            if check_pubkey_format(pubkey):
                pubkey_list.append(validate_checksum(pubkey))
            else:
                pubkey_list.append(pubkey)
        total = [0, 0]
        for pubkey in pubkey_list:
            inputs_balance = await get_amount_from_pubkey(pubkey)
            await show_amount_from_pubkey(pubkey, inputs_balance)
            total[0] += inputs_balance[0]
            total[1] += inputs_balance[1]
        if len(pubkey_list) > 1:
            await show_amount_from_pubkey("Total", total)
    else:
        key = auth_method()
        pubkey = key.pubkey
        await show_amount_from_pubkey(pubkey, await
                                      get_amount_from_pubkey(pubkey))
    await client.close()
Пример #2
0
async def id_pubkey_correspondence(id_pubkey):
    client = ClientInstance().client
    # determine if id_pubkey is a pubkey
    checked_pubkey = is_pubkey_and_check(id_pubkey)
    if checked_pubkey:
        id_pubkey = checked_pubkey
        try:
            idty = await identity_of(id_pubkey)
            print(
                "{} public key corresponds to identity: {}".format(
                    display_pubkey_and_checksum(id_pubkey), idty["uid"]
                )
            )
        except:
            message_exit("No matching identity")
    # if not ; then it is a uid
    else:
        pubkeys = await wot_lookup(id_pubkey)
        print("Public keys found matching '{}':\n".format(id_pubkey))
        for pubkey in pubkeys:
            print("→", display_pubkey_and_checksum(pubkey["pubkey"]), end=" ")
            try:
                corresponding_id = await client(wot.identity_of, pubkey["pubkey"])
                print("↔ " + corresponding_id["uid"])
            except:
                print("")
    await client.close()
Пример #3
0
def auth_by_auth_file(ctx):
    """
    Uses an authentication file to generate the key
    Authfile can either be:
    * A seed in hexadecimal encoding
    * PubSec format with public and private key in base58 encoding
    """
    file = ctx.obj["AUTH_FILE_PATH"]
    authfile = Path(file)
    if not authfile.is_file():
        message_exit('Error: the file "' + file + '" does not exist')
    filetxt = authfile.open("r").read()

    # two regural expressions for the PubSec format
    regex_pubkey = re.compile(PUBSEC_PUBKEY_PATTERN, re.MULTILINE)
    regex_signkey = re.compile(PUBSEC_SIGNKEY_PATTERN, re.MULTILINE)

    # Seed hexadecimal format
    if re.search(re.compile(SEED_HEX_PATTERN), filetxt):
        return SigningKey.from_seedhex_file(file)
    # PubSec format
    elif re.search(regex_pubkey, filetxt) and re.search(
            regex_signkey, filetxt):
        return SigningKey.from_pubsec_file(file)
    else:
        message_exit("Error: the format of the file is invalid")
Пример #4
0
def cmd_transaction(cli_args):
    """
    Retrieve values from command line interface
    """
    if not (
        cli_args.contains_definitions("amount")
        or cli_args.contains_definitions("amountUD")
    ):
        message_exit("--amount or --amountUD is not set")
    if not cli_args.contains_definitions("output"):
        message_exit("--output is not set")

    if cli_args.contains_definitions("amount"):
        tx_amount = float(cli_args.get_definition("amount")) * 100
    if cli_args.contains_definitions("amountUD"):
        tx_amount = float(cli_args.get_definition("amountUD")) * UDValue().ud_value

    output = cli_args.get_definition("output")
    comment = (
        cli_args.get_definition("comment")
        if cli_args.contains_definitions("comment")
        else ""
    )
    allSources = cli_args.contains_switches("allSources")

    if cli_args.contains_definitions("outputBackChange"):
        outputBackChange = cli_args.get_definition("outputBackChange")
    else:
        outputBackChange = None
    return tx_amount, output, comment, allSources, outputBackChange
Пример #5
0
def auth_by_auth_file(cli_args):
    if cli_args.contains_definitions("file"):
        file = cli_args.get_definition("file")
    else:
        file = "authfile"
    if not path.isfile(file):
        message_exit('Error: the file "' + file + '" does not exist')
    with open(file) as f:
        filetxt = f.read()

    regex_seed = compile("^[0-9a-fA-F]{64}$")
    regex_gannonce = compile(
        "^pub: [1-9A-HJ-NP-Za-km-z]{43,44}\nsec: [1-9A-HJ-NP-Za-km-z]{88,90}.*$"
    )
    # Seed Format
    if search(regex_seed, filetxt):
        seed = filetxt[0:64]
    # gannonce.duniter.org Format
    elif search(regex_gannonce, filetxt):
        private_key = filetxt.split("sec: ")[1].split("\n")[0]
        seed = encoding.HexEncoder.encode(
            b58_decode(private_key))[0:64].decode("utf-8")
    else:
        message_exit("Error: the format of the file is invalid")
    return seed
Пример #6
0
def set_network_sort_keys(some_keys):
    global network_sort_keys
    if some_keys.endswith(","):
        message_exit(
            "Argument 'sort' ends with a comma, you have probably inserted a space after the comma, which is incorrect."
        )
    network_sort_keys = some_keys.split(",")
Пример #7
0
def auth_by_scrypt(cli_args):
    salt = getpass("Please enter your Scrypt Salt (Secret identifier): ")
    password = getpass("Please enter your Scrypt password (masked): ")

    if (cli_args.contains_definitions("n")
            and cli_args.contains_definitions("r")
            and cli_args.contains_definitions("p")):
        n, r, p = (
            cli_args.get_definition("n"),
            cli_args.get_definition("r"),
            cli_args.get_definition("p"),
        )
        if n.isnumeric() and r.isnumeric() and p.isnumeric():
            n, r, p = int(n), int(r), int(p)
            if n <= 0 or n > 65536 or r <= 0 or r > 512 or p <= 0 or p > 32:
                message_exit(
                    "Error: the values of Scrypt parameters are not good")
        else:
            message_exit("one of n, r or p is not a number")
    else:
        print(
            "Using default values. Scrypt parameters not specified or wrong format"
        )
        n, r, p = 4096, 16, 1
    print("Scrypt parameters used: N: {0}, r: {1}, p: {2}".format(n, r, p))

    return get_seed_from_scrypt(salt, password, n, r, p)
Пример #8
0
def checkComment(Comment):
    if len(Comment) > 255:
        message_exit("Error: Comment is too long")
    regex = compile(
        "^[0-9a-zA-Z\\ \\-\\_\\:\\/\\;\\*\\[\\]\\(\\)\\?\\!\\^\\+\\=\\@\\&\\~\\#\\{\\}\\|\\\\<\\>\\%\\.]*$"
    )
    if not search(regex, Comment):
        message_exit("Error: the format of the comment is invalid")
Пример #9
0
def checkComment(Comment):
    if len(Comment) > 255:
        message_exit("Error: Comment is too long")
    regex = compile(
        "^[0-9a-zA-Z\ \-\_\:\/\;\*\[\]\(\)\?\!\^\+\=\@\&\~\#\{\}\|\\\<\>\%\.]*$"
    )
    if not search(regex, Comment):
        message_exit("Error: the format of the comment is invalid")
Пример #10
0
def auth_by_wif():
    wif_hex = getpass("Enter your WIF or Encrypted WIF address (masked): ")
    password = getpass(
        "(Leave empty in case WIF format) Enter the Encrypted WIF password (masked): "
    )
    try:
        return SigningKey.from_wif_or_ewif_hex(wif_hex, password)
    except Exception as error:
        message_exit(error)
Пример #11
0
async def send_transaction(amounts, amountsud, allsources, recipients, comment,
                           outputbackchange, yes):
    """
    Main function
    """
    if not (amounts or amountsud or allsources):
        message_exit("Error: amount, amountUD or allSources is not set.")
    if allsources and len(recipients) > 1:
        message_exit(
            "Error: the --allSources option can only be used with one recipient."
        )
    # compute amounts and amountsud
    if not allsources:
        tx_amounts = await transaction_amount(amounts, amountsud, recipients)

    key = auth_method()
    issuer_pubkey = key.pubkey

    pubkey_amount = await money.get_amount_from_pubkey(issuer_pubkey)
    if allsources:
        tx_amounts = [pubkey_amount[0]]

    recipients = list(recipients)
    outputbackchange = check_transaction_values(
        comment,
        recipients,
        outputbackchange,
        pubkey_amount[0] < sum(tx_amounts),
        issuer_pubkey,
    )

    if (yes or input(
            tabulate(
                await transaction_confirmation(
                    issuer_pubkey,
                    pubkey_amount[0],
                    tx_amounts,
                    recipients,
                    outputbackchange,
                    comment,
                ),
                tablefmt="fancy_grid",
            ) + "\nDo you confirm sending this transaction? [yes/no]: ")
            == "yes"):
        await handle_intermediaries_transactions(
            key,
            issuer_pubkey,
            tx_amounts,
            recipients,
            comment,
            outputbackchange,
        )
    else:
        client = ClientInstance().client
        await client.close()
Пример #12
0
def check_pubkey_format(pubkey, display_error=True):
    """
    Checks if a pubkey has a checksum.
    Exits if the pubkey is invalid.
    """
    if re.search(re.compile(PUBKEY_DELIMITED_PATTERN), pubkey):
        return False
    elif re.search(re.compile(PUBKEY_CHECKSUM_PATTERN), pubkey):
        return True
    elif display_error:
        message_exit("Error: bad format for following public key: " + pubkey)
    return
Пример #13
0
def get_seed_from_ewifv1(ewif, password):
    regex = compile("^[1-9A-HJ-NP-Za-km-z]*$")
    if not search(regex, ewif):
        message_exit("Error: the format of EWIF is invalid")

    wif_bytes = b58_decode(ewif)
    if len(wif_bytes) != 39:
        message_exit("Error: the size of EWIF is invalid")

    wif_no_checksum = wif_bytes[0:-2]
    checksum_from_ewif = wif_bytes[-2:]
    fi = wif_bytes[0:1]
    salt = wif_bytes[1:5]
    encryptedhalf1 = wif_bytes[5:21]
    encryptedhalf2 = wif_bytes[21:37]

    if fi != b"\x02":
        message_exit("Error: It's not a EWIF format")

    # Checksum Control
    checksum = nacl.hash.sha256(
        nacl.hash.sha256(wif_no_checksum, encoding.RawEncoder),
        encoding.RawEncoder)[0:2]
    if checksum_from_ewif != checksum:
        message_exit("Error: bad checksum of EWIF address")

    # SCRYPT
    password = password.encode("utf-8")
    scrypt_seed = hash(password, salt, 16384, 8, 8, 64)
    derivedhalf1 = scrypt_seed[0:32]
    derivedhalf2 = scrypt_seed[32:64]

    # AES
    aes = pyaes.AESModeOfOperationECB(derivedhalf2)
    decryptedhalf1 = aes.decrypt(encryptedhalf1)
    decryptedhalf2 = aes.decrypt(encryptedhalf2)

    # XOR
    seed1 = xor_bytes(decryptedhalf1, derivedhalf1[0:16])
    seed2 = xor_bytes(decryptedhalf2, derivedhalf1[16:32])
    seed = seed1 + seed2
    seedhex = encoding.HexEncoder.encode(seed).decode("utf-8")

    # Password Control
    salt_from_seed = nacl.hash.sha256(
        nacl.hash.sha256(b58_decode(get_publickey_from_seed(seedhex)),
                         encoding.RawEncoder),
        encoding.RawEncoder,
    )[0:4]
    if salt_from_seed != salt:
        message_exit("Error: bad Password of EWIF address")

    return seedhex
Пример #14
0
def validate_checksum(pubkey_checksum):
    """
    Check pubkey checksum after the pubkey, delimited by ":".
    If check pass: return pubkey
    Else: exit.
    """
    pubkey, checksum = pubkey_checksum.split(":")
    if checksum == gen_checksum(pubkey):
        return pubkey
    message_exit("Error: public key '" + pubkey +
                 "' does not match checksum '" + checksum +
                 "'.\nPlease verify the public key.")
Пример #15
0
async def check_passed_blocks_range(client, from_block, to_block):
    head_number = (await client(bma.blockchain.current))["number"]
    if to_block == 0:
        to_block = head_number
    if to_block > head_number:
        await client.close()
        message_exit(
            "Passed TO_BLOCK argument is bigger than the head block: " +
            str(head_number))
    if from_block > to_block:
        await client.close()
        message_exit("TO_BLOCK should be bigger or equal to FROM_BLOCK")
    return to_block
Пример #16
0
def get_informations_for_identity(id):
    """
    Check that the id is present on the network
    many identities could match
    return the one searched
    """
    certs_req = get_informations_for_identities(id)
    if certs_req == NO_MATCHING_ID:
        message_exit(NO_MATCHING_ID)
    for certs_id in certs_req:
        if certs_id["uids"][0]["uid"].lower() == id.lower():
            return certs_id
    message_exit(NO_MATCHING_ID)
Пример #17
0
async def wot_lookup(identifier):
    """
    :identifier: identity or pubkey in part or whole
    Return received and sent certifications lists of matching identities
    if one identity found
    """
    client = ClientInstance().client
    try:
        results = await client(wot.lookup, identifier)
        return results["results"]
    except DuniterError as e:
        message_exit(e.message)
    except ValueError as e:
        pass
Пример #18
0
def get_seed_from_wifv1(wif):
    regex = compile("^[1-9A-HJ-NP-Za-km-z]*$")
    if not search(regex, wif):
        message_exit("Error: the format of WIF is invalid")

    wif_bytes = b58_decode(wif)
    if len(wif_bytes) != 35:
        message_exit("Error: the size of WIF is invalid")

    checksum_from_wif = wif_bytes[-2:]
    fi = wif_bytes[0:1]
    seed = wif_bytes[1:-2]
    seed_fi = wif_bytes[0:-2]

    if fi != b"\x01":
        message_exit("Error: It's not a WIF format")

    # checksum control
    checksum = nacl.hash.sha256(nacl.hash.sha256(seed_fi, encoding.RawEncoder),
                                encoding.RawEncoder)[0:2]
    if checksum_from_wif != checksum:
        message_exit("Error: bad checksum of the WIF")

    seedhex = encoding.HexEncoder.encode(seed).decode("utf-8")
    return seedhex
Пример #19
0
def compute_amounts(amounts, multiplicator):
    """
    Computes the amounts(UD) and returns a list.
    Multiplicator should be either CENT_MULT_TO_UNIT or UD_Value.
    If relative amount, check that amount is superior to minimal amount.
    """
    # Create amounts list
    amounts_list = list()
    for amount in amounts:
        computed_amount = amount * multiplicator
        # check if relative amounts are high enough
        if (multiplicator != CENT_MULT_TO_UNIT) and (
                computed_amount < (MINIMAL_TX_AMOUNT * CENT_MULT_TO_UNIT)):
            message_exit("Error: amount {0} is too low.".format(amount))
        amounts_list.append(round(computed_amount))
    return amounts_list
Пример #20
0
def auth_by_wif():
    wif = input("Please enter your WIF or Encrypted WIF address: ")

    regex = compile("^[1-9A-HJ-NP-Za-km-z]*$")
    if not search(regex, wif):
        message_exit("Error: the format of WIF is invalid")

    wif_bytes = b58_decode(wif)
    fi = wif_bytes[0:1]

    if fi == b"\x01":
        return get_seed_from_wifv1(wif)
    elif fi == b"\x02":
        password = getpass("Please enter the " + "password of WIF (masked): ")
        return get_seed_from_ewifv1(wif, password)

    message_exit("Error: the format of WIF is invalid or unknown")
Пример #21
0
async def transaction_amount(amounts, UDs_amounts, outputAddresses):
    """
    Check that the number of passed amounts(UD) and recipients are the same
    Returns a list of amounts.
    """
    # Create amounts list
    if amounts:
        amounts_list = compute_amounts(amounts, CENT_MULT_TO_UNIT)
    elif UDs_amounts:
        UD_value = await money.UDValue().ud_value
        amounts_list = compute_amounts(UDs_amounts, UD_value)
    if len(amounts_list) != len(outputAddresses) and len(amounts_list) != 1:
        message_exit(
            "Error: The number of passed recipients is not the same as the passed amounts."
        )
    # In case one amount is passed with multiple recipients
    # generate list containing multiple time the same amount
    if len(amounts_list) == 1 and len(outputAddresses) > 1:
        amounts_list = [amounts_list[0]] * len(outputAddresses)
    return amounts_list
Пример #22
0
def check_transaction_values(comment, outputAddresses, outputBackChange,
                             enough_source, issuer_pubkey):
    """
    Check the comment format
    Check the pubkeys and the checksums of the recipients and the outputbackchange
    In case of a valid checksum, assign and return the pubkey without the checksum
    Check the balance is big enough for the transaction
    """
    checkComment(comment)
    for i, outputAddress in enumerate(outputAddresses):
        if check_pubkey_format(outputAddress):
            outputAddresses[i] = validate_checksum(outputAddress)
    if outputBackChange:
        if check_pubkey_format(outputBackChange):
            outputBackChange = validate_checksum(outputBackChange)
    if enough_source:
        message_exit(
            display_pubkey_and_checksum(issuer_pubkey) +
            " pubkey doesn’t have enough money for this transaction.")
    return outputBackChange
Пример #23
0
async def get_list_input_for_transaction(pubkey, TXamount):
    listinput, amount = await money.get_sources(pubkey)

    # generate final list source
    listinputfinal = []
    totalAmountInput = 0
    intermediatetransaction = False
    for input in listinput:
        listinputfinal.append(input)
        totalAmountInput += money.amount_in_current_base(input)
        TXamount -= money.amount_in_current_base(input)
        # if more than 40 sources, it's an intermediate transaction
        if len(listinputfinal) >= SOURCES_PER_TX:
            intermediatetransaction = True
            break
        if TXamount <= 0:
            break
    if TXamount > 0 and not intermediatetransaction:
        message_exit("Error: you don't have enough money")
    return listinputfinal, totalAmountInput, intermediatetransaction
Пример #24
0
def get_list_input_for_transaction(pubkey, TXamount, allinput=False):
    listinput, amount = get_sources(pubkey)

    # generate final list source
    listinputfinal = []
    totalAmountInput = 0
    intermediatetransaction = False
    for input in listinput:
        listinputfinal.append(input)
        inputsplit = input.split(":")
        totalAmountInput += int(inputsplit[0]) * 10 ** int(inputsplit[1])
        TXamount -= int(inputsplit[0]) * 10 ** int(inputsplit[1])
        # if more 40 sources, it's an intermediate transaction
        if len(listinputfinal) >= 40:
            intermediatetransaction = True
            break
        if TXamount <= 0 and not allinput:
            break
    if TXamount > 0 and not intermediatetransaction:
        message_exit("Error: you don't have enough money")
    return listinputfinal, totalAmountInput, intermediatetransaction
Пример #25
0
def send_certification(cli_args):
    id_to_certify = get_informations_for_identity(cli_args.subsubcmd)
    main_id_to_certify = id_to_certify["uids"][0]

    # Display license and ask for confirmation
    license_approval(HeadBlock().head_block["currency"])

    # Authentication
    seed = auth_method(cli_args)

    # Check whether current user is member
    issuer_pubkey = get_publickey_from_seed(seed)
    issuer_id = get_uid_from_pubkey(issuer_pubkey)
    if not is_member(issuer_pubkey, issuer_id):
        message_exit("Current identity is not member.")

    if issuer_pubkey == id_to_certify["pubkey"]:
        message_exit("You can’t certify yourself!")

    for certifier in main_id_to_certify["others"]:
        if certifier["pubkey"] == issuer_pubkey:
            message_exit("Identity already certified by " + issuer_id)

    # Certification confirmation
    if not certification_confirmation(issuer_id, issuer_pubkey, id_to_certify,
                                      main_id_to_certify):
        return
    cert_doc = generate_certification_document(issuer_pubkey, id_to_certify,
                                               main_id_to_certify)
    cert_doc += sign_document_from_seed(cert_doc, seed) + "\n"

    # Send certification document
    post_request("wot/certify", "cert=" + urllib.parse.quote_plus(cert_doc))
    print("Certification successfully sent.")
Пример #26
0
async def generate_and_send_transaction(
    key,
    issuers,
    tx_amounts,
    listinput_and_amount,
    outputAddresses,
    Comment,
    OutputbackChange=None,
):
    """
    Display sent transaction
    Generate, sign, and send transaction document
    """
    intermediate_tx = listinput_and_amount[2]
    if intermediate_tx:
        print("Generate Change Transaction")
    else:
        print("Generate Transaction:")
    print("   - From:    " + display_pubkey_and_checksum(issuers))
    for tx_amount, outputAddress in zip(tx_amounts, outputAddresses):
        display_sent_tx(outputAddress, tx_amount)
    print("   - Total:   " + str(sum(tx_amounts) / 100))

    client = ClientInstance().client
    transaction = await generate_transaction_document(
        issuers,
        tx_amounts,
        listinput_and_amount,
        outputAddresses,
        Comment,
        OutputbackChange,
    )
    transaction.sign([key])
    response = await client(process, transaction.signed_raw())
    if response.status == 200:
        print("Transaction successfully sent.")
    else:
        message_exit("Error while publishing transaction: {0}".format(
            await response.text()))
Пример #27
0
def check_transaction_values(
    comment, outputAddresses, outputBackChange, enough_source, issuer_pubkey
):
    checkComment(comment)
    for outputAddress in outputAddresses:
        if check_public_key(outputAddress, True) is False:
            message_exit(outputAddress)
    if outputBackChange:
        outputBackChange = check_public_key(outputBackChange, True)
        if check_public_key(outputBackChange, True) is False:
            message_exit(outputBackChange)
    if enough_source:
        message_exit(
            issuer_pubkey + " pubkey doesn’t have enough money for this transaction."
        )
Пример #28
0
def auth_by_scrypt(ctx):
    salt = getpass("Please enter your Scrypt Salt (Secret identifier): ")
    password = getpass("Please enter your Scrypt password (masked): ")

    if ctx.obj["AUTH_SCRYPT_PARAMS"]:
        n, r, p = ctx.obj["AUTH_SCRYPT_PARAMS"].split(",")

        if n.isnumeric() and r.isnumeric() and p.isnumeric():
            n, r, p = int(n), int(r), int(p)
            if n <= 0 or n > 65536 or r <= 0 or r > 512 or p <= 0 or p > 32:
                message_exit(
                    "Error: the values of Scrypt parameters are not good")
            scrypt_params = ScryptParams(n, r, p)
        else:
            message_exit("one of n, r or p is not a number")
    else:
        scrypt_params = None

    try:
        return SigningKey.from_credentials(salt, password, scrypt_params)
    except ValueError as error:
        message_exit(error)
Пример #29
0
def auth_by_seed():
    seed = input("Please enter your seed on hex format: ")
    regex = compile("^[0-9a-fA-F]{64}$")
    if not search(regex, seed):
        message_exit("Error: the format of the seed is invalid")
    return seed
Пример #30
0
def auth_by_seed():
    seedhex = getpass("Please enter your seed on hex format: ")
    try:
        return SigningKey.from_seedhex(seedhex)
    except Exception as error:
        message_exit(error)