Coverage for silkaj/wot/tools.py: 81%

59 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 contextlib 

17import time 

18import urllib 

19from typing import Dict, List, Optional, Tuple 

20from urllib.error import HTTPError 

21 

22import rich_click as click 

23from duniterpy.api.bma import wot 

24 

25from silkaj.constants import BMA_SLEEP 

26from silkaj.network import client_instance, exit_on_http_error 

27from silkaj.public_key import gen_pubkey_checksum 

28from silkaj.tui import Table 

29 

30 

31def identity_of(pubkey_uid: str) -> Dict: 

32 """ 

33 Only works for members 

34 Not able to get corresponding uid from a non-member identity 

35 Able to know if an identity is member or not 

36 """ 

37 client = client_instance() 

38 return client(wot.identity_of, pubkey_uid) 

39 

40 

41def is_member(pubkey_uid: str) -> Optional[Dict]: 

42 """ 

43 Check identity is member 

44 If member, return corresponding identity, else: False 

45 """ 

46 try: 

47 return identity_of(pubkey_uid) 

48 except HTTPError: 

49 return None 

50 

51 

52def wot_lookup(identifier: str) -> List: 

53 """ 

54 :identifier: identity or pubkey in part or whole 

55 Return received and sent certifications lists of matching identities 

56 if one identity found 

57 """ 

58 client = client_instance() 

59 return (client(wot.lookup, identifier))["results"] 

60 

61 

62def identities_from_pubkeys(pubkeys: List[str], uids: bool) -> List: 

63 """ 

64 Make list of pubkeys unique, and remove empty strings 

65 Request identities 

66 """ 

67 if not uids: 

68 return [] 

69 

70 uniq_pubkeys = list(filter(None, set(pubkeys))) 

71 identities = [] 

72 for pubkey in uniq_pubkeys: 

73 time.sleep(BMA_SLEEP) 

74 with contextlib.suppress(HTTPError): 

75 identities.append(identity_of(pubkey)) 

76 return identities 

77 

78 

79def choose_identity(pubkey_uid: str) -> Tuple[Dict, str, List]: 

80 """ 

81 Get lookup from a pubkey or an uid 

82 Loop over the double lists: pubkeys, then uids 

83 If there is one uid, returns it 

84 If there is multiple uids, prompt a selector 

85 """ 

86 

87 try: 

88 lookups = wot_lookup(pubkey_uid) 

89 except urllib.error.HTTPError as e: 

90 exit_on_http_error(e, 404, f"No identity found for {pubkey_uid}") 

91 

92 # Generate table containing the choices 

93 identities_choices = { 

94 "id": [], 

95 "uid": [], 

96 "pubkey": [], 

97 "timestamp": [], 

98 } # type: Dict 

99 for pubkey_index, lookup in enumerate(lookups): 

100 for uid_index, identity in enumerate(lookup["uids"]): 

101 identities_choices["id"].append(str(pubkey_index) + str(uid_index)) 

102 identities_choices["pubkey"].append(gen_pubkey_checksum(lookup["pubkey"])) 

103 identities_choices["uid"].append(identity["uid"]) 

104 identities_choices["timestamp"].append( 

105 identity["meta"]["timestamp"][:20] + "…", 

106 ) 

107 

108 identities = len(identities_choices["uid"]) 

109 if identities == 1: 

110 pubkey_index = 0 

111 uid_index = 0 

112 elif identities > 1: 

113 table = Table().set_cols_dtype(["t", "t", "t", "t"]) 

114 table.fill_from_dict(identities_choices) 

115 click.echo(table.draw()) 

116 # Loop till the passed value is in identities_choices 

117 message = "Which identity would you like to select (id)?" 

118 selected_id = None 

119 while selected_id not in identities_choices["id"]: 

120 selected_id = click.prompt(message) 

121 

122 pubkey_index = int(str(selected_id)[:-1]) 

123 uid_index = int(str(selected_id)[-1:]) 

124 

125 return ( 

126 lookups[pubkey_index]["uids"][uid_index], 

127 lookups[pubkey_index]["pubkey"], 

128 lookups[pubkey_index]["signed"], 

129 )