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

77 statements  

« prev     ^ index     » next       coverage.py v7.4.4, created at 2024-04-17 17:03 +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 List, 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} \ 

68 \npubkey: \ 

69{gen_pubkey_checksum(idty.pubkey)}", 

70 ) 

71 

72 # get all matching identities 

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

74 match = False 

75 for n, lookup in enumerate(lookup_ids): 

76 if idty == lookup: 

77 lookup_ids.pop(n) 

78 match = True 

79 break 

80 alternate_ids = display_alternate_ids(lookup_ids).draw() 

81 if match: 

82 if len(lookup_ids) >= 1: 

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

84 return True 

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

86 return False 

87 

88 

89def display_alternate_ids(ids_list: List) -> Texttable: 

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

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

92 table.header(labels) 

93 for _id in ids_list: 

94 table.add_row( 

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

96 ) 

97 return table 

98 

99 

100def merge_ids_lists(lookups_pubkey: List, lookups_uid: List, currency: str) -> List: 

101 """ 

102 merge two lists of identities and remove duplicate identities. 

103 """ 

104 ids = ids_list_from_lookups(lookups_pubkey, currency) 

105 ids_uid = ids_list_from_lookups(lookups_uid, currency) 

106 for _id in ids_uid: 

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

108 for listed_id in ids: 

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

110 id_in_ids = True 

111 break 

112 id_in_ids = False 

113 if not id_in_ids: 

114 ids.append(_id) 

115 return ids 

116 

117 

118def ids_list_from_lookups(lookups: List, currency: str) -> List: 

119 ids = [] 

120 for lookup in lookups: 

121 pubkey = lookup["pubkey"] 

122 lookup_ids = lookup["uids"] 

123 for _id in lookup_ids: 

124 appended_id = Identity( 

125 currency=currency, 

126 pubkey=pubkey, 

127 uid=_id["uid"], 

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

129 ) 

130 appended_id.signature = _id["self"] 

131 ids.append(appended_id) 

132 return ids