Forking what is left of ZeroNet and hopefully adding an AT Proto Frontend/Proxy
at main 156 lines 5.5 kB view raw
1import time 2 3from util import helper 4 5from Plugin import PluginManager 6from .BootstrapperDb import BootstrapperDb 7from Crypt import CryptRsa 8from Config import config 9 10if "db" not in locals().keys(): # Share during reloads 11 db = BootstrapperDb() 12 13 14@PluginManager.registerTo("FileRequest") 15class FileRequestPlugin(object): 16 def checkOnionSigns(self, onions, onion_signs, onion_sign_this): 17 if not onion_signs or len(onion_signs) != len(set(onions)): 18 return False 19 20 if time.time() - float(onion_sign_this) > 3 * 60: 21 return False # Signed out of allowed 3 minutes 22 23 onions_signed = [] 24 # Check onion signs 25 for onion_publickey, onion_sign in onion_signs.items(): 26 if CryptRsa.verify(onion_sign_this.encode(), onion_publickey, onion_sign): 27 onions_signed.append(CryptRsa.publickeyToOnion(onion_publickey)) 28 else: 29 break 30 31 # Check if the same onion addresses signed as the announced onces 32 if sorted(onions_signed) == sorted(set(onions)): 33 return True 34 else: 35 return False 36 37 def actionAnnounce(self, params): 38 time_started = time.time() 39 s = time.time() 40 # Backward compatibility 41 if "ip4" in params["add"]: 42 params["add"].append("ipv4") 43 if "ip4" in params["need_types"]: 44 params["need_types"].append("ipv4") 45 46 hashes = params["hashes"] 47 48 all_onions_signed = self.checkOnionSigns(params.get("onions", []), params.get("onion_signs"), params.get("onion_sign_this")) 49 50 time_onion_check = time.time() - s 51 52 ip_type = helper.getIpType(self.connection.ip) 53 54 if ip_type == "onion" or self.connection.ip in config.ip_local: 55 is_port_open = False 56 elif ip_type in params["add"]: 57 is_port_open = True 58 else: 59 is_port_open = False 60 61 s = time.time() 62 # Separatley add onions to sites or at once if no onions present 63 i = 0 64 onion_to_hash = {} 65 for onion in params.get("onions", []): 66 if onion not in onion_to_hash: 67 onion_to_hash[onion] = [] 68 onion_to_hash[onion].append(hashes[i]) 69 i += 1 70 71 hashes_changed = 0 72 for onion, onion_hashes in onion_to_hash.items(): 73 hashes_changed += db.peerAnnounce( 74 ip_type="onion", 75 address=onion, 76 port=params["port"], 77 hashes=onion_hashes, 78 onion_signed=all_onions_signed 79 ) 80 time_db_onion = time.time() - s 81 82 s = time.time() 83 84 if is_port_open: 85 hashes_changed += db.peerAnnounce( 86 ip_type=ip_type, 87 address=self.connection.ip, 88 port=params["port"], 89 hashes=hashes, 90 delete_missing_hashes=params.get("delete") 91 ) 92 time_db_ip = time.time() - s 93 94 s = time.time() 95 # Query sites 96 back = {} 97 peers = [] 98 if params.get("onions") and not all_onions_signed and hashes_changed: 99 back["onion_sign_this"] = "%.0f" % time.time() # Send back nonce for signing 100 101 if len(hashes) > 500 or not hashes_changed: 102 limit = 5 103 order = False 104 else: 105 limit = 30 106 order = True 107 for hash in hashes: 108 if time.time() - time_started > 1: # 1 sec limit on request 109 self.connection.log("Announce time limit exceeded after %s/%s sites" % (len(peers), len(hashes))) 110 break 111 112 hash_peers = db.peerList( 113 hash, 114 address=self.connection.ip, onions=list(onion_to_hash.keys()), port=params["port"], 115 limit=min(limit, params["need_num"]), need_types=params["need_types"], order=order 116 ) 117 if "ip4" in params["need_types"]: # Backward compatibility 118 hash_peers["ip4"] = hash_peers["ipv4"] 119 del(hash_peers["ipv4"]) 120 peers.append(hash_peers) 121 time_peerlist = time.time() - s 122 123 back["peers"] = peers 124 self.connection.log( 125 "Announce %s sites (onions: %s, onion_check: %.3fs, db_onion: %.3fs, db_ip: %.3fs, peerlist: %.3fs, limit: %s)" % 126 (len(hashes), len(onion_to_hash), time_onion_check, time_db_onion, time_db_ip, time_peerlist, limit) 127 ) 128 self.response(back) 129 130 131@PluginManager.registerTo("UiRequest") 132class UiRequestPlugin(object): 133 @helper.encodeResponse 134 def actionStatsBootstrapper(self): 135 self.sendHeader() 136 137 # Style 138 yield """ 139 <style> 140 * { font-family: monospace; white-space: pre } 141 table td, table th { text-align: right; padding: 0px 10px } 142 </style> 143 """ 144 145 hash_rows = db.execute("SELECT * FROM hash").fetchall() 146 for hash_row in hash_rows: 147 peer_rows = db.execute( 148 "SELECT * FROM peer LEFT JOIN peer_to_hash USING (peer_id) WHERE hash_id = :hash_id", 149 {"hash_id": hash_row["hash_id"]} 150 ).fetchall() 151 152 yield "<br>%s (added: %s, peers: %s)<br>" % ( 153 str(hash_row["hash"]).encode().hex(), hash_row["date_added"], len(peer_rows) 154 ) 155 for peer_row in peer_rows: 156 yield " - {type} {address}:{port} added: {date_added}, announced: {date_announced}<br>".format(**dict(peer_row))