diff --git a/silkaj/cert.py b/silkaj/cert.py index 869e07655ee522d59cc731badf1935561ac863e1..8b12b0510bef8fc2d33bfb5926b428e73e250596 100644 --- a/silkaj/cert.py +++ b/silkaj/cert.py @@ -23,7 +23,7 @@ from duniterpy.documents import Block, BlockID, Certification, Identity, get_blo from duniterpy.key import SigningKey from pendulum import from_timestamp, now -from silkaj import tui, wot +from silkaj import tui from silkaj import wot_tools as wt from silkaj.auth import auth_method from silkaj.blockchain import tools as bc_tools @@ -31,6 +31,7 @@ from silkaj.constants import ALL, DATE from silkaj.g1_monetary_license import license_approval from silkaj.network import client_instance, send_document from silkaj.public_key import gen_pubkey_checksum, is_pubkey_and_check +from silkaj.wot import tools as wot_tools @click.command("cert", help="Send certification") @@ -44,7 +45,7 @@ def send_certification(ctx: click.Context, uid_pubkey_to_certify: str) -> None: uid_pubkey_to_certify = str(checked_pubkey) # pylint: disable=unused-variable - idty_to_certify, pubkey_to_certify, send_certs = wot.choose_identity( + idty_to_certify, pubkey_to_certify, send_certs = wot_tools.choose_identity( uid_pubkey_to_certify ) diff --git a/silkaj/cli.py b/silkaj/cli.py index c80ccac52be41dcdcffc000b8f4b220bcbd08d80..98941c0bdfc372bd49c4d8bc48511e245a64c7e7 100644 --- a/silkaj/cli.py +++ b/silkaj/cli.py @@ -36,7 +36,8 @@ from silkaj.membership import send_membership from silkaj.money.balance import cmd_amount from silkaj.money.history import transaction_history from silkaj.money.transfer import send_transaction -from silkaj.wot import id_pubkey_correspondence, received_sent_certifications +from silkaj.wot.lookup import id_pubkey_correspondence +from silkaj.wot.wot import received_sent_certifications @group() diff --git a/silkaj/membership.py b/silkaj/membership.py index ef280e8e3935892865d5934266086e7b1b997a95..8ab075f7d6320629c8c58cd9c6fb403c191f8474 100644 --- a/silkaj/membership.py +++ b/silkaj/membership.py @@ -22,12 +22,13 @@ from duniterpy.api import bma from duniterpy.documents import BlockID, Membership, get_block_id from duniterpy.key import SigningKey -from silkaj import auth, tui, wot +from silkaj import auth, tui from silkaj.blockchain import tools as bc_tools from silkaj.constants import DATE, SUCCESS_EXIT_STATUS from silkaj.g1_monetary_license import license_approval from silkaj.network import client_instance, send_document from silkaj.public_key import gen_pubkey_checksum +from silkaj.wot import tools as w_tools @click.command( @@ -45,7 +46,7 @@ def send_membership(ctx: click.Context) -> None: # Get the identity information head_block = bc_tools.get_head_block() membership_block_id = BlockID(head_block["number"], head_block["hash"]) - identity = (wot.choose_identity(key.pubkey))[0] + identity = (w_tools.choose_identity(key.pubkey))[0] identity_uid = identity["uid"] identity_block_id = get_block_id(identity["meta"]["timestamp"]) diff --git a/silkaj/revocation.py b/silkaj/revocation.py index 837cd9e4a43a00252a4af3f786107ce86229fcbd..deaab09f0897868fc6e90abb6fec89257d03b842 100644 --- a/silkaj/revocation.py +++ b/silkaj/revocation.py @@ -26,10 +26,11 @@ from duniterpy.documents.identity import Identity from duniterpy.documents.revocation import Revocation from duniterpy.key.verifying_key import VerifyingKey -from silkaj import auth, idty_tools, network, tui, wot +from silkaj import auth, idty_tools, network, tui from silkaj.blockchain.tools import get_currency from silkaj.constants import FAILURE_EXIT_STATUS, SUCCESS_EXIT_STATUS from silkaj.public_key import gen_pubkey_checksum +from silkaj.wot import tools as w_tools REVOCATION_LOCAL_PATH = "revocation.txt" @@ -48,7 +49,7 @@ def save(ctx: click.Context, file: str) -> None: key = auth.auth_method() gen_pubkey_checksum(key.pubkey) - _id = (wot.choose_identity(key.pubkey))[0] + _id = (w_tools.choose_identity(key.pubkey))[0] rev_doc = create_revocation_doc(_id, key.pubkey, currency) rev_doc.sign(key) @@ -80,7 +81,7 @@ def revoke_now(ctx: click.Context) -> None: key = auth.auth_method() gen_pubkey_checksum(key.pubkey) - _id = (wot.choose_identity(key.pubkey))[0] + _id = (w_tools.choose_identity(key.pubkey))[0] rev_doc = create_revocation_doc(_id, key.pubkey, currency) rev_doc.sign(key) diff --git a/silkaj/wot/__init__.py b/silkaj/wot/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..58426bbc2bbfc951dc181bdd19b5b2569c074af0 --- /dev/null +++ b/silkaj/wot/__init__.py @@ -0,0 +1,14 @@ +# Copyright 2016-2022 Maël Azimi <m.a@moul.re> +# +# Silkaj is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# Silkaj 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 Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with Silkaj. If not, see <https://www.gnu.org/licenses/>. diff --git a/silkaj/wot/lookup.py b/silkaj/wot/lookup.py new file mode 100644 index 0000000000000000000000000000000000000000..88c3b0b8a0e9a9b4855431f5dadcb245e0f68fc0 --- /dev/null +++ b/silkaj/wot/lookup.py @@ -0,0 +1,42 @@ +# Copyright 2016-2022 Maël Azimi <m.a@moul.re> +# +# Silkaj is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# Silkaj 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 Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with Silkaj. If not, see <https://www.gnu.org/licenses/>. + +import urllib + +import click + +from silkaj import wot_tools as wt +from silkaj.network import exit_on_http_error +from silkaj.public_key import gen_pubkey_checksum, is_pubkey_and_check + + +@click.command("lookup", help="User identifier and public key lookup") +@click.argument("uid_pubkey") +def id_pubkey_correspondence(uid_pubkey: str) -> None: + checked_pubkey = is_pubkey_and_check(uid_pubkey) + if checked_pubkey: + uid_pubkey = str(checked_pubkey) + + try: + lookups = wt.wot_lookup(uid_pubkey) + except urllib.error.HTTPError as e: + exit_on_http_error(e, 404, f"No identity found for {uid_pubkey}") + + content = f"Public keys or user id found matching '{uid_pubkey}':\n" + for lookup in lookups: + for identity in lookup["uids"]: + pubkey_checksum = gen_pubkey_checksum(lookup["pubkey"]) + content += f'\n→ {pubkey_checksum} ↔ {identity["uid"]}' + click.echo(content) diff --git a/silkaj/wot/tools.py b/silkaj/wot/tools.py new file mode 100644 index 0000000000000000000000000000000000000000..2830208b72f07432f172801139f3e88a7b3d53c6 --- /dev/null +++ b/silkaj/wot/tools.py @@ -0,0 +1,77 @@ +# Copyright 2016-2022 Maël Azimi <m.a@moul.re> +# +# Silkaj is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# Silkaj 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 Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with Silkaj. If not, see <https://www.gnu.org/licenses/>. + +import urllib +from typing import Dict, List, Tuple + +import click + +from silkaj import wot_tools as wt +from silkaj.network import exit_on_http_error +from silkaj.public_key import gen_pubkey_checksum +from silkaj.tui import Table + + +def choose_identity(pubkey_uid: str) -> Tuple[Dict, str, List]: + """ + Get lookup from a pubkey or an uid + Loop over the double lists: pubkeys, then uids + If there is one uid, returns it + If there is multiple uids, prompt a selector + """ + + try: + lookups = wt.wot_lookup(pubkey_uid) + except urllib.error.HTTPError as e: + exit_on_http_error(e, 404, f"No identity found for {pubkey_uid}") + + # Generate table containing the choices + identities_choices = { + "id": [], + "uid": [], + "pubkey": [], + "timestamp": [], + } # type: Dict + for pubkey_index, lookup in enumerate(lookups): + for uid_index, identity in enumerate(lookup["uids"]): + identities_choices["id"].append(str(pubkey_index) + str(uid_index)) + identities_choices["pubkey"].append(gen_pubkey_checksum(lookup["pubkey"])) + identities_choices["uid"].append(identity["uid"]) + identities_choices["timestamp"].append( + identity["meta"]["timestamp"][:20] + "…" + ) + + identities = len(identities_choices["uid"]) + if identities == 1: + pubkey_index = 0 + uid_index = 0 + elif identities > 1: + table = Table().set_cols_dtype(["t", "t", "t", "t"]) + table.fill_from_dict(identities_choices) + click.echo(table.draw()) + # Loop till the passed value is in identities_choices + message = "Which identity would you like to select (id)?" + selected_id = None + while selected_id not in identities_choices["id"]: + selected_id = click.prompt(message) + + pubkey_index = int(str(selected_id)[:-1]) + uid_index = int(str(selected_id)[-1:]) + + return ( + lookups[pubkey_index]["uids"][uid_index], + lookups[pubkey_index]["pubkey"], + lookups[pubkey_index]["signed"], + ) diff --git a/silkaj/wot.py b/silkaj/wot/wot.py similarity index 66% rename from silkaj/wot.py rename to silkaj/wot/wot.py index 9e14c70c1321a22160a88e1808fe126d2e9a0c8a..635bdc436c231ad6ac0002e00ca8f26e2ca2a423 100644 --- a/silkaj/wot.py +++ b/silkaj/wot/wot.py @@ -13,7 +13,6 @@ # You should have received a copy of the GNU Affero General Public License # along with Silkaj. If not, see <https://www.gnu.org/licenses/>. -import urllib from collections import OrderedDict from typing import Dict, List, Tuple @@ -24,9 +23,10 @@ from pendulum import from_timestamp, now from silkaj import wot_tools as wt from silkaj.blockchain.tools import get_blockchain_parameters from silkaj.constants import DATE -from silkaj.network import client_instance, exit_on_http_error +from silkaj.network import client_instance from silkaj.public_key import gen_pubkey_checksum, is_pubkey_and_check from silkaj.tui import Table +from silkaj.wot import tools as w_tools def get_sent_certifications( @@ -65,7 +65,7 @@ def received_sent_certifications(uid_pubkey: str) -> None: if checked_pubkey: uid_pubkey = str(checked_pubkey) - identity, pubkey, signed = choose_identity(uid_pubkey) + identity, pubkey, signed = w_tools.choose_identity(uid_pubkey) certifications = OrderedDict() # type: OrderedDict params = get_blockchain_parameters() @@ -149,76 +149,3 @@ def expiration_date_from_block_id( def date_approximation(block_id, time_first_block, avgentime): return time_first_block + block_id * avgentime - - -@click.command("lookup", help="User identifier and public key lookup") -@click.argument("uid_pubkey") -def id_pubkey_correspondence(uid_pubkey: str) -> None: - checked_pubkey = is_pubkey_and_check(uid_pubkey) - if checked_pubkey: - uid_pubkey = str(checked_pubkey) - - try: - lookups = wt.wot_lookup(uid_pubkey) - except urllib.error.HTTPError as e: - exit_on_http_error(e, 404, f"No identity found for {uid_pubkey}") - - content = f"Public keys or user id found matching '{uid_pubkey}':\n" - for lookup in lookups: - for identity in lookup["uids"]: - pubkey_checksum = gen_pubkey_checksum(lookup["pubkey"]) - content += f'\n→ {pubkey_checksum} ↔ {identity["uid"]}' - click.echo(content) - - -def choose_identity(pubkey_uid: str) -> Tuple[Dict, str, List]: - """ - Get lookup from a pubkey or an uid - Loop over the double lists: pubkeys, then uids - If there is one uid, returns it - If there is multiple uids, prompt a selector - """ - - try: - lookups = wt.wot_lookup(pubkey_uid) - except urllib.error.HTTPError as e: - exit_on_http_error(e, 404, f"No identity found for {pubkey_uid}") - - # Generate table containing the choices - identities_choices = { - "id": [], - "uid": [], - "pubkey": [], - "timestamp": [], - } # type: Dict - for pubkey_index, lookup in enumerate(lookups): - for uid_index, identity in enumerate(lookup["uids"]): - identities_choices["id"].append(str(pubkey_index) + str(uid_index)) - identities_choices["pubkey"].append(gen_pubkey_checksum(lookup["pubkey"])) - identities_choices["uid"].append(identity["uid"]) - identities_choices["timestamp"].append( - identity["meta"]["timestamp"][:20] + "…" - ) - - identities = len(identities_choices["uid"]) - if identities == 1: - pubkey_index = 0 - uid_index = 0 - elif identities > 1: - table = Table().set_cols_dtype(["t", "t", "t", "t"]) - table.fill_from_dict(identities_choices) - click.echo(table.draw()) - # Loop till the passed value is in identities_choices - message = "Which identity would you like to select (id)?" - selected_id = None - while selected_id not in identities_choices["id"]: - selected_id = click.prompt(message) - - pubkey_index = int(str(selected_id)[:-1]) - uid_index = int(str(selected_id)[-1:]) - - return ( - lookups[pubkey_index]["uids"][uid_index], - lookups[pubkey_index]["pubkey"], - lookups[pubkey_index]["signed"], - ) diff --git a/tests/test_membership.py b/tests/test_membership.py index 77a5cd7c4593e86437b173c2601297c066cd8f20..81dde12396a37ecfeabe4cef7ab454017452d21b 100644 --- a/tests/test_membership.py +++ b/tests/test_membership.py @@ -22,12 +22,13 @@ from duniterpy.api import bma from duniterpy.documents import Membership, get_block_id from duniterpy.key import SigningKey -from silkaj import auth, membership, tui, wot +from silkaj import auth, membership, tui from silkaj.blockchain import tools as bc_tools from silkaj.cli import cli from silkaj.constants import DATE from silkaj.network import client_instance from silkaj.public_key import gen_pubkey_checksum +from silkaj.wot import tools as w_tools from tests.patched.blockchain_tools import ( currency, fake_block_id, @@ -75,7 +76,7 @@ def test_membership_cmd(dry_run, display, confirmation, monkeypatch): # Monkeypatch and Mock monkeypatch.setattr(auth, "auth_method", patched_auth_method) monkeypatch.setattr(bc_tools, "get_head_block", patched_get_head_block) - monkeypatch.setattr(wot, "choose_identity", patched_choose_identity) + monkeypatch.setattr(w_tools, "choose_identity", patched_choose_identity) patched_display_confirmation_table = Mock() monkeypatch.setattr( diff --git a/tests/test_revocation.py b/tests/test_revocation.py index 3ed44f966729c1b86b0bbcb046e2f1de1202160b..08c575c23dd001a6e8d3bd4c0a01d5397917db50 100644 --- a/tests/test_revocation.py +++ b/tests/test_revocation.py @@ -24,12 +24,13 @@ from click.testing import CliRunner from duniterpy.api import bma from duniterpy.documents.revocation import Revocation -from silkaj import auth, idty_tools, revocation, wot +from silkaj import auth, idty_tools, revocation from silkaj.blockchain import tools as bc_tools from silkaj.cli import cli from silkaj.constants import FAILURE_EXIT_STATUS, SUCCESS_EXIT_STATUS from silkaj.network import client_instance from silkaj.public_key import gen_pubkey_checksum +from silkaj.wot import tools as w_tools from tests.patched.auth import patched_auth_method from tests.patched.blockchain_tools import patched_get_head_block_gtest from tests.patched.idty_tools import idty1, idty2, idty_block, lookup_one, lookup_two @@ -165,7 +166,7 @@ def test_revocation_cli_dry_run(subcommand, expected_warn, monkeypatch): """ monkeypatch.setattr(auth, "auth_method", patched_auth_method_Claude) monkeypatch.setattr(bc_tools, "get_head_block", patched_get_head_block_gtest) - monkeypatch.setattr(wot, "choose_identity", patched_choose_identity) + monkeypatch.setattr(w_tools, "choose_identity", patched_choose_identity) monkeypatch.setattr(bma.blockchain, "block", patch_get_id_block) monkeypatch.setattr( idty_tools, "check_many_identities", patch_check_many_identities @@ -286,7 +287,7 @@ def test_revocation_cli_dry_run(subcommand, expected_warn, monkeypatch): def test_revocation_cli_save(display, dry_run, file, user_input, expected, monkeypatch): monkeypatch.setattr(auth, "auth_method", patched_auth_method_Claude) monkeypatch.setattr(bc_tools, "get_head_block", patched_get_head_block_gtest) - monkeypatch.setattr(wot, "choose_identity", patched_choose_identity) + monkeypatch.setattr(w_tools, "choose_identity", patched_choose_identity) monkeypatch.setattr(bma.blockchain, "block", patch_get_id_block) patched_save_doc = Mock() monkeypatch.setattr( @@ -843,7 +844,7 @@ def test_revocation_cli_revoke( ): monkeypatch.setattr(auth, "auth_method", patched_auth_method_Claude) monkeypatch.setattr(bc_tools, "get_head_block", patched_get_head_block_gtest) - monkeypatch.setattr(wot, "choose_identity", patched_choose_identity) + monkeypatch.setattr(w_tools, "choose_identity", patched_choose_identity) monkeypatch.setattr(bma.blockchain, "block", patch_get_id_block) patched_send_bma_revoke = Mock() monkeypatch.setattr(bma.wot, "revoke", patched_send_bma_revoke) @@ -892,7 +893,7 @@ def test_revocation_cli_revoke_errors(display, user_input, doc, expected, monkey monkeypatch.setattr(auth, "auth_method", patched_auth_method_Claude) monkeypatch.setattr(bc_tools, "get_head_block", patched_get_head_block_gtest) - monkeypatch.setattr(wot, "choose_identity", patched_choose_identity) + monkeypatch.setattr(w_tools, "choose_identity", patched_choose_identity) monkeypatch.setattr(bma.blockchain, "block", patch_get_id_block) monkeypatch.setattr(bma.wot, "revoke", patched_send_bma_revoke_error) diff --git a/tests/wot/__init__.py b/tests/wot/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..58426bbc2bbfc951dc181bdd19b5b2569c074af0 --- /dev/null +++ b/tests/wot/__init__.py @@ -0,0 +1,14 @@ +# Copyright 2016-2022 Maël Azimi <m.a@moul.re> +# +# Silkaj is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# Silkaj 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 Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with Silkaj. If not, see <https://www.gnu.org/licenses/>. diff --git a/tests/test_wot.py b/tests/wot/test_tools.py similarity index 97% rename from tests/test_wot.py rename to tests/wot/test_tools.py index 6647379e00753c2c3bd0e1c8d2161c430f888644..2e0aa4eae4695577320808ae0a4abf87f6a7decd 100644 --- a/tests/test_wot.py +++ b/tests/wot/test_tools.py @@ -16,7 +16,8 @@ import click import pytest -from silkaj import wot, wot_tools +from silkaj import wot_tools +from silkaj.wot import tools as w_tools pubkey_titi_tata = "B4RoF48cTxzmsQDB3UjodKdZ2cVymKSKzgiPVRoMeA88" pubkey_toto_tutu = "totoF48cTxzmsQDB3UjodKdZ2cVymKSKzgiPVRoMeA88" @@ -147,7 +148,7 @@ def test_choose_identity( monkeypatch.setattr(wot_tools, "wot_lookup", patched_lookup) monkeypatch.setattr(click, "prompt", patched_prompt) # pylint: disable=unused-variable - idty_card, get_pubkey, signed = wot.choose_identity(pubkey) + idty_card, get_pubkey, signed = w_tools.choose_identity(pubkey) expected_pubkey = pubkey.split(":")[0] assert expected_pubkey == get_pubkey assert selected_uid == idty_card["uid"]