Skip to content
Snippets Groups Projects
test_idty_tools.py 13.83 KiB
# 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 re
import urllib

import pendulum
import pytest
from duniterpy.api import bma
from duniterpy.documents.block_id import BlockID
from duniterpy.documents.identity import Identity

from patched.idty_tools import (
    idty1,
    idty2,
    idty_block,
    lookup_one,
    lookup_three,
    lookup_two,
)
from silkaj import idty_tools
from silkaj.constants import ALL, PUBKEY_PATTERN
from silkaj.tui import gen_pubkey_checksum

# used test identities

id_moul_test_1 = Identity(
    currency="g1-test",
    pubkey="5B8iMAzq1dNmFe3ZxFTBQkqhq4fsztg1gZvxHXCk1XYH",
    uid="moul-test",
    block_id=BlockID.from_str(
        "167750-0000A51FF952B76AAA594A46CA0C8156A56988D2B2B57BE18ECB4F3CFC25CEC2"
    ),
)
id_moul_test_1.signature = "/15YBc4JDPvKD4c8nWD6C0XN0krrS32uDRSH6rJvM\
Fih/H5nPc8oiCgL27bA7P3NPnp+oCqbS12QygQRnhoDDQ=="

id_elois_test = Identity(
    currency="g1-test",
    pubkey="D7CYHJXjaH4j7zRdWngUbsURPnSnjsCYtvo6f8dvW3C",
    uid="elois",
    block_id=BlockID.from_str(
        "0-E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855"
    ),
)
id_elois_test.signature = "HFmZy01XSXSSsqRWYKR+nIsaReBruJUqYHqJh3EtdR\
kHV3i30S2lM32pM2w4GHYXNIiOf4+NXzcmuEQVkewBAA=="

id_moul_test_3 = Identity(
    version=10,
    currency="g1-test",
    pubkey="2M3Et298TDYXDcsixp82iEc4ijzuiyQtsiQac2QjCRgA",
    uid="moul-test",
    block_id=BlockID.from_str(
        "287573-00003674E9A2B5127327542CFA36BCB95D05E8EBD8AAF9C684B19EB7502161D4"
    ),
)
id_moul_test_3.signature = "BB1Ete898yN/ZwQn4H7o0gsS1JD05zZBSd7qdU2Am\
SSZLtjG199fN0Z5jKjQi7S2IVvrH0G5cft74sufVS3+Cw=="

# idty lists for following tests
ids_list_for_merge_lists = [
    id_moul_test_1,
    id_elois_test,
    id_moul_test_3,
]

ids_list_for_lookups_test = [
    id_moul_test_1,
    id_elois_test,
]

# invalid identity
id_claudius_maximus = Identity(
    currency="g1-test",
    pubkey="6upqFiJ66WV6N3bPc8x8y7rXT3syqKRmwnVyunCtEj7o",
    uid="Claudius Maximus",
    block_id=BlockID.from_str(
        "7334-002A45E751DCA7535D4F0A082F493E2C8EFF07612683525EB5DA92B6D17C30BD"
    ),
)
id_claudius_maximus.signature = (
    "wrong_sig_x4PZODx0Wf+xdXAJTmYD+yqdyZBsPF7UwqdaCA4N+yHj7+09Gjsttl0i9GtWzodyJ6mBE1q7jcAw==",
)


def test_display_alternate_ids():
    """
    Tests the display of identities table.
    When using pytest `-s` option, this test only works on terminal default width of 80.
    """
    ids_list = [
        id_moul_test_1,
        id_elois_test,
        id_claudius_maximus,
    ]

    expected = "+------------------+--------------------------------------------+--------------+\n\
|       uid        |                 public key                 |  timestamp   |\n\
+==================+============================================+==============+\n\
| moul-test        | 5B8iMAzq1dNmFe3ZxFTBQkqhq4fsztg1gZvxHXCk1X | 167750-0000A |\n\
|                  | YH:baK                                     |              |\n\
+------------------+--------------------------------------------+--------------+\n\
| elois            | D7CYHJXjaH4j7zRdWngUbsURPnSnjsCYtvo6f8dvW3 | 0-E3B0C44298 |\n\
|                  | C:6Ns                                      |              |\n\
+------------------+--------------------------------------------+--------------+\n\
| Claudius Maximus | 6upqFiJ66WV6N3bPc8x8y7rXT3syqKRmwnVyunCtEj | 7334-002A45E |\n\
|                  | 7o:7xo                                     |              |\n\
+------------------+--------------------------------------------+--------------+"

    table = idty_tools.display_alternate_ids(ids_list)
    assert expected == table.draw()


@pytest.mark.parametrize(
    "lookups_pubkey, lookups_uid, currency, expected",
    [
        (
            [
                {
                    "pubkey": "5B8iMAzq1dNmFe3ZxFTBQkqhq4fsztg1gZvxHXCk1XYH",
                    "uids": [
                        {
                            "uid": "moul-test",
                            "meta": {
                                "timestamp": "167750-0000A51FF952B76A\
AA594A46CA0C8156A56988D2B2B57BE18ECB4F3CFC25CEC2"
                            },
                            "revoked": False,
                            "revoked_on": None,
                            "revocation_sig": None,
                            "self": "/15YBc4JDPvKD4c8nWD6C0XN0krrS32u\
DRSH6rJvMFih/H5nPc8oiCgL27bA7P3NPnp+oCqbS12QygQRnhoDDQ==",
                            "others": [],
                        }
                    ],
                    "signed": [],
                },
                {
                    "pubkey": "D7CYHJXjaH4j7zRdWngUbsURPnSnjsCYtvo6f8dvW3C",
                    "uids": [
                        {
                            "uid": "elois",
                            "meta": {
                                "timestamp": "0-E3B0C44298FC1C149AFBF\
4C8996FB92427AE41E4649B934CA495991B7852B855"
                            },
                            "revoked": True,
                            "revoked_on": 1540589179,
                            "revocation_sig": None,
                            "self": "HFmZy01XSXSSsqRWYKR+nIsaReBruJUq\
YHqJh3EtdRkHV3i30S2lM32pM2w4GHYXNIiOf4+NXzcmuEQVkewBAA==",
                            "others": [],
                        }
                    ],
                    "signed": [],
                },
            ],
            [
                {
                    "pubkey": "5B8iMAzq1dNmFe3ZxFTBQkqhq4fsztg1gZvxHXCk1XYH",
                    "uids": [
                        {
                            "uid": "moul-test",
                            "meta": {
                                "timestamp": "167750-0000A51FF952B76A\
AA594A46CA0C8156A56988D2B2B57BE18ECB4F3CFC25CEC2"
                            },
                            "revoked": False,
                            "revoked_on": None,
                            "revocation_sig": None,
                            "self": "/15YBc4JDPvKD4c8nWD6C0XN0krrS32u\
DRSH6rJvMFih/H5nPc8oiCgL27bA7P3NPnp+oCqbS12QygQRnhoDDQ==",
                            "others": [],
                        }
                    ],
                    "signed": [],
                },
                {
                    "pubkey": "2M3Et298TDYXDcsixp82iEc4ijzuiyQtsiQac2QjCRgA",
                    "uids": [
                        {
                            "uid": "moul-test",
                            "meta": {
                                "timestamp": "287573-00003674E9A2B512\
7327542CFA36BCB95D05E8EBD8AAF9C684B19EB7502161D4"
                            },
                            "revoked": True,
                            "revoked_on": 1544923049,
                            "revocation_sig": "oRBunChfKUUMqZLCB+0QO8\
LpQcpx9FZJNXIt79Q/zRPpi9X1hNUPKV4myMxHBSVI6YbPB+gBw/Bb+n3kaIuRAg==",
                            "self": "BB1Ete898yN/ZwQn4H7o0gsS1JD05zZB\
Sd7qdU2AmSSZLtjG199fN0Z5jKjQi7S2IVvrH0G5cft74sufVS3+Cw==",
                            "others": [],
                        }
                    ],
                    "signed": [],
                },
            ],
            "g1-test",
            ids_list_for_merge_lists,
        ),
    ],
)
def test_merge_ids_lists(lookups_pubkey, lookups_uid, currency, expected):
    for element, expect in zip(
        idty_tools.merge_ids_lists(lookups_pubkey, lookups_uid, currency), expected
    ):
        assert element.signed_raw() == expect.signed_raw()


@pytest.mark.parametrize(
    "lookups, currency, expected",
    [
        (
            [
                {
                    "pubkey": "5B8iMAzq1dNmFe3ZxFTBQkqhq4fsztg1gZvxHXCk1XYH",
                    "uids": [
                        {
                            "uid": "moul-test",
                            "meta": {
                                "timestamp": "167750-0000A51FF952B76A\
AA594A46CA0C8156A56988D2B2B57BE18ECB4F3CFC25CEC2"
                            },
                            "revoked": False,
                            "revoked_on": None,
                            "revocation_sig": None,
                            "self": "/15YBc4JDPvKD4c8nWD6C0XN0krrS32u\
DRSH6rJvMFih/H5nPc8oiCgL27bA7P3NPnp+oCqbS12QygQRnhoDDQ==",
                            "others": [],
                        }
                    ],
                    "signed": [],
                },
                {
                    "pubkey": "D7CYHJXjaH4j7zRdWngUbsURPnSnjsCYtvo6f8dvW3C",
                    "uids": [
                        {
                            "uid": "elois",
                            "meta": {
                                "timestamp": "0-E3B0C44298FC1C149AFBF\
4C8996FB92427AE41E4649B934CA495991B7852B855"
                            },
                            "revoked": True,
                            "revoked_on": 1540589179,
                            "revocation_sig": None,
                            "self": "HFmZy01XSXSSsqRWYKR+nIsaReBruJUq\
YHqJh3EtdRkHV3i30S2lM32pM2w4GHYXNIiOf4+NXzcmuEQVkewBAA==",
                            "others": [],
                        }
                    ],
                    "signed": [],
                },
            ],
            "g1-test",
            ids_list_for_lookups_test,
        ),
    ],
)
def test_ids_list_from_lookups(lookups, currency, expected):
    for element, expect in zip(
        idty_tools.ids_list_from_lookups(lookups, currency), expected
    ):
        assert element.signed_raw() == expect.signed_raw()


# test display_identity
@pytest.mark.parametrize("idty", [(idty1)])
def test_display_identity(idty, monkeypatch, capsys):
    def patch_get_id_block(node, number):
        return idty_block

    monkeypatch.setattr(bma.blockchain, "block", patch_get_id_block)
    idty_table = idty_tools.display_identity(idty)
    result = idty_table.draw()
    assert "| Public key | 6upqFiJ66WV6N3bPc8x8y7rXT3syqKRmwnVyunCtEj7o:7xo" in result
    assert "| User ID    | Claude" in result
    assert "| Blockstamp | 597334" in result
    # idty_block returns a block at timestamp 1594980185,.
    creation_time = pendulum.from_timestamp(idty_block["time"], tz="local").format(ALL)
    assert creation_time in result


@pytest.mark.parametrize(
    "idty, lookup_pk, lookup_uid, expected, expect_bool",
    [
        # normal case : 1 same lookup on pubkey and uid
        (
            idty1,
            lookup_one,
            lookup_one,
            None,
            True,
        ),
        # 2 lookups on pubkey, one on uid, match similar.
        (
            idty1,
            lookup_one,
            lookup_two,
            [
                "One matching identity!",
                "Similar identities:",
                "Claudia",
            ],
            True,
        ),
        # 2 lookups on pubkey, one on uid, no match similar.
        (
            idty2,
            lookup_one,
            lookup_two,
            [
                "Identity document does not match any valid identity.",
                "Claude",
                "Claudia",
            ],
            False,
        ),
        # 1 lookup on pubkey, 2 on uid, match.
        (
            idty1,
            lookup_one,
            lookup_three,
            [
                "One matching identity!",
                "Similar identities:",
                "Claude",
                "XXXX",
            ],
            True,
        ),
        # 1 lookup on pubkey, 2 on uid, no match.
        (
            idty2,
            lookup_one,
            lookup_three,
            [
                "Identity document does not match any valid identity.",
                "Similar identities:",
                "Claude",
                "XXXX",
            ],
            False,
        ),
        # no lookup found.
        (
            idty1,
            None,
            None,
            [
                f"Identity document does not match any valid identity.\n\
uid: {idty1.uid}\npubkey: {gen_pubkey_checksum(idty1.pubkey)}"
            ],
            False,
        ),
    ],
)
def test_check_many_identities(
    idty, lookup_pk, lookup_uid, expected, expect_bool, monkeypatch, capsys
):

    # Patch BMA lookup so it returns different lookups if we request a pk or a uid
    def patched_bma_lookup(whatever_node, lookup):
        # raise errors if no matching identity
        http_error = urllib.error.HTTPError(
            url="this.is/a/test/url",
            code=404,
            msg="Not Found TEST",
            hdrs={},
            fp=None,
        )
        if re.search(PUBKEY_PATTERN, lookup):
            if not lookup_pk:
                raise http_error
            return lookup_pk
        if not lookup_uid:
            raise http_error
        return lookup_uid

    monkeypatch.setattr(bma.wot, "lookup", patched_bma_lookup)

    # identity does not exist
    if expected == [
        f"Identity document does not match any valid identity.\
\nuid: {idty.uid}\npubkey: {gen_pubkey_checksum(idty.pubkey)}"
    ]:
        with pytest.raises(SystemExit) as pytest_exit:
            result = idty_tools.check_many_identities(idty)
        assert pytest_exit.type == SystemExit
        assert expected[0] == str(pytest_exit.value.code)
    # test cases with an identity
    else:
        result = idty_tools.check_many_identities(idty)
        assert result == expect_bool
        display_result = capsys.readouterr().out
        if expected:
            for expect in expected:
                assert expect in display_result