Coverage for silkaj/wot/idty_tools.py: 100%

77 statements  

« prev     ^ index     » next       coverage.py v7.6.3, created at 2024-10-18 04:28 +0000

1# Copyright 2016-2024 Maël Azimi <m.a@moul.re> 

2# 

3# Silkaj is free software: you can redistribute it and/or modify 

4# it under the terms of the GNU Affero General Public License as published by 

5# the Free Software Foundation, either version 3 of the License, or 

6# (at your option) any later version. 

7# 

8# Silkaj is distributed in the hope that it will be useful, 

9# but WITHOUT ANY WARRANTY; without even the implied warranty of 

10# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 

11# GNU Affero General Public License for more details. 

12# 

13# You should have received a copy of the GNU Affero General Public License 

14# along with Silkaj. If not, see <https://www.gnu.org/licenses/>. 

15 

16import shutil 

17import sys 

18import urllib 

19from typing import Union 

20 

21import pendulum 

22import rich_click as click 

23from duniterpy.api import bma 

24from duniterpy.documents import BlockID, Identity, Revocation 

25from texttable import Texttable 

26 

27from silkaj.constants import ALL 

28from silkaj.network import client_instance 

29from silkaj.public_key import gen_pubkey_checksum 

30from silkaj.wot.tools import wot_lookup 

31 

32 

33def display_identity(idty: Identity) -> Texttable: 

34 """ 

35 Creates a table containing the identity infos 

36 """ 

37 client = client_instance() 

38 id_table = [] 

39 id_table.append(["Public key", gen_pubkey_checksum(idty.pubkey)]) 

40 id_table.append(["User ID", idty.uid]) 

41 id_table.append(["Blockstamp", str(idty.block_id)]) 

42 creation_block = client(bma.blockchain.block, idty.block_id.number) 

43 creation_date = pendulum.from_timestamp(creation_block["time"], tz="local").format( 

44 ALL, 

45 ) 

46 id_table.append(["Created on", creation_date]) 

47 # display infos 

48 table = Texttable(max_width=shutil.get_terminal_size().columns) 

49 table.add_rows(id_table, header=False) 

50 return table 

51 

52 

53def check_many_identities(document: Union[Identity, Revocation]) -> bool: 

54 """ 

55 Checks if many identities match the one looked after. 

56 Returns True if the same identity is found, False if not. 

57 """ 

58 doc_type = document.__class__.__name__ 

59 error_no_identical_id = f"{doc_type} document does not match any valid identity." 

60 idty = document if doc_type == "Identity" else document.identity 

61 

62 try: 

63 results_pubkey = wot_lookup(idty.pubkey) 

64 results_uid = wot_lookup(idty.uid) 

65 except urllib.error.HTTPError: 

66 sys.exit( 

67 f"{error_no_identical_id}\nuid: {idty.uid}\npubkey: \ 

68{gen_pubkey_checksum(idty.pubkey)}", 

69 ) 

70 

71 # get all matching identities 

72 lookup_ids = merge_ids_lists(results_pubkey, results_uid, idty.currency) 

73 match = False 

74 for n, lookup in enumerate(lookup_ids): 

75 if idty == lookup: 

76 lookup_ids.pop(n) 

77 match = True 

78 break 

79 alternate_ids = display_alternate_ids(lookup_ids).draw() 

80 if match: 

81 if len(lookup_ids) >= 1: 

82 click.echo(f"One matching identity!\nSimilar identities:\n{alternate_ids}") 

83 return True 

84 click.echo(f"{error_no_identical_id}\nSimilar identities:\n{alternate_ids}") 

85 return False 

86 

87 

88def display_alternate_ids(ids_list: list) -> Texttable: 

89 labels = ["uid", "public key", "timestamp"] 

90 table = Texttable(max_width=shutil.get_terminal_size().columns) 

91 table.header(labels) 

92 for _id in ids_list: 

93 table.add_row( 

94 [_id.uid, gen_pubkey_checksum(_id.pubkey), str(_id.block_id)[:12]], 

95 ) 

96 return table 

97 

98 

99def merge_ids_lists(lookups_pubkey: list, lookups_uid: list, currency: str) -> list: 

100 """ 

101 merge two lists of identities and remove duplicate identities. 

102 """ 

103 ids = ids_list_from_lookups(lookups_pubkey, currency) 

104 ids_uid = ids_list_from_lookups(lookups_uid, currency) 

105 for _id in ids_uid: 

106 # __equal__ does not work. This is condition "id in ids". 

107 for listed_id in ids: 

108 if _id.signed_raw() == listed_id.signed_raw(): 

109 id_in_ids = True 

110 break 

111 id_in_ids = False 

112 if not id_in_ids: 

113 ids.append(_id) 

114 return ids 

115 

116 

117def ids_list_from_lookups(lookups: list, currency: str) -> list: 

118 ids = [] 

119 for lookup in lookups: 

120 pubkey = lookup["pubkey"] 

121 lookup_ids = lookup["uids"] 

122 for _id in lookup_ids: 

123 appended_id = Identity( 

124 currency=currency, 

125 pubkey=pubkey, 

126 uid=_id["uid"], 

127 block_id=BlockID.from_str(_id["meta"]["timestamp"]), 

128 ) 

129 appended_id.signature = _id["self"] 

130 ids.append(appended_id) 

131 return ids