Forking what is left of ZeroNet and hopefully adding an AT Proto Frontend/Proxy
1import hashlib
2import os
3
4import pytest
5
6from Bootstrapper import BootstrapperPlugin
7from Bootstrapper.BootstrapperDb import BootstrapperDb
8from Peer import Peer
9from Crypt import CryptRsa
10from util import helper
11
12
13@pytest.fixture()
14def bootstrapper_db(request):
15 BootstrapperPlugin.db.close()
16 BootstrapperPlugin.db = BootstrapperDb()
17 BootstrapperPlugin.db.createTables() # Reset db
18 BootstrapperPlugin.db.cur.logging = True
19
20 def cleanup():
21 BootstrapperPlugin.db.close()
22 os.unlink(BootstrapperPlugin.db.db_path)
23
24 request.addfinalizer(cleanup)
25 return BootstrapperPlugin.db
26
27
28@pytest.mark.usefixtures("resetSettings")
29class TestBootstrapper:
30 def testHashCache(self, file_server, bootstrapper_db):
31 ip_type = helper.getIpType(file_server.ip)
32 peer = Peer(file_server.ip, 1544, connection_server=file_server)
33 hash1 = hashlib.sha256(b"site1").digest()
34 hash2 = hashlib.sha256(b"site2").digest()
35 hash3 = hashlib.sha256(b"site3").digest()
36
37 # Verify empty result
38 res = peer.request("announce", {
39 "hashes": [hash1, hash2],
40 "port": 15441, "need_types": [ip_type], "need_num": 10, "add": [ip_type]
41 })
42
43 assert len(res["peers"][0][ip_type]) == 0 # Empty result
44
45 hash_ids_before = bootstrapper_db.hash_ids.copy()
46
47 bootstrapper_db.updateHashCache()
48
49 assert hash_ids_before == bootstrapper_db.hash_ids
50
51
52 def testBootstrapperDb(self, file_server, bootstrapper_db):
53 ip_type = helper.getIpType(file_server.ip)
54 peer = Peer(file_server.ip, 1544, connection_server=file_server)
55 hash1 = hashlib.sha256(b"site1").digest()
56 hash2 = hashlib.sha256(b"site2").digest()
57 hash3 = hashlib.sha256(b"site3").digest()
58
59 # Verify empty result
60 res = peer.request("announce", {
61 "hashes": [hash1, hash2],
62 "port": 15441, "need_types": [ip_type], "need_num": 10, "add": [ip_type]
63 })
64
65 assert len(res["peers"][0][ip_type]) == 0 # Empty result
66
67 # Verify added peer on previous request
68 bootstrapper_db.peerAnnounce(ip_type, file_server.ip_external, port=15441, hashes=[hash1, hash2], delete_missing_hashes=True)
69
70 res = peer.request("announce", {
71 "hashes": [hash1, hash2],
72 "port": 15441, "need_types": [ip_type], "need_num": 10, "add": [ip_type]
73 })
74 assert len(res["peers"][0][ip_type]) == 1
75 assert len(res["peers"][1][ip_type]) == 1
76
77 # hash2 deleted from 1.2.3.4
78 bootstrapper_db.peerAnnounce(ip_type, file_server.ip_external, port=15441, hashes=[hash1], delete_missing_hashes=True)
79 res = peer.request("announce", {
80 "hashes": [hash1, hash2],
81 "port": 15441, "need_types": [ip_type], "need_num": 10, "add": [ip_type]
82 })
83 assert len(res["peers"][0][ip_type]) == 1
84 assert len(res["peers"][1][ip_type]) == 0
85
86 # Announce 3 hash again
87 bootstrapper_db.peerAnnounce(ip_type, file_server.ip_external, port=15441, hashes=[hash1, hash2, hash3], delete_missing_hashes=True)
88 res = peer.request("announce", {
89 "hashes": [hash1, hash2, hash3],
90 "port": 15441, "need_types": [ip_type], "need_num": 10, "add": [ip_type]
91 })
92 assert len(res["peers"][0][ip_type]) == 1
93 assert len(res["peers"][1][ip_type]) == 1
94 assert len(res["peers"][2][ip_type]) == 1
95
96 # Single hash announce
97 res = peer.request("announce", {
98 "hashes": [hash1], "port": 15441, "need_types": [ip_type], "need_num": 10, "add": [ip_type]
99 })
100 assert len(res["peers"][0][ip_type]) == 1
101
102 # Test DB cleanup
103 assert [row[0] for row in bootstrapper_db.execute("SELECT address FROM peer").fetchall()] == [file_server.ip_external] # 127.0.0.1 never get added to db
104
105 # Delete peers
106 bootstrapper_db.execute("DELETE FROM peer WHERE address = ?", [file_server.ip_external])
107 assert bootstrapper_db.execute("SELECT COUNT(*) AS num FROM peer_to_hash").fetchone()["num"] == 0
108
109 assert bootstrapper_db.execute("SELECT COUNT(*) AS num FROM hash").fetchone()["num"] == 3 # 3 sites
110 assert bootstrapper_db.execute("SELECT COUNT(*) AS num FROM peer").fetchone()["num"] == 0 # 0 peer
111
112 def testPassive(self, file_server, bootstrapper_db):
113 peer = Peer(file_server.ip, 1544, connection_server=file_server)
114 ip_type = helper.getIpType(file_server.ip)
115 hash1 = hashlib.sha256(b"hash1").digest()
116
117 bootstrapper_db.peerAnnounce(ip_type, address=None, port=15441, hashes=[hash1])
118 res = peer.request("announce", {
119 "hashes": [hash1], "port": 15441, "need_types": [ip_type], "need_num": 10, "add": []
120 })
121
122 assert len(res["peers"][0]["ipv4"]) == 0 # Empty result
123
124 def testAddOnion(self, file_server, site, bootstrapper_db, tor_manager):
125 onion1 = tor_manager.addOnion()
126 onion2 = tor_manager.addOnion()
127 peer = Peer(file_server.ip, 1544, connection_server=file_server)
128 hash1 = hashlib.sha256(b"site1").digest()
129 hash2 = hashlib.sha256(b"site2").digest()
130 hash3 = hashlib.sha256(b"site3").digest()
131
132 bootstrapper_db.peerAnnounce(ip_type="ipv4", address="1.2.3.4", port=1234, hashes=[hash1, hash2, hash3])
133 res = peer.request("announce", {
134 "onions": [onion1, onion1, onion2],
135 "hashes": [hash1, hash2, hash3], "port": 15441, "need_types": ["ipv4", "onion"], "need_num": 10, "add": ["onion"]
136 })
137 assert len(res["peers"][0]["ipv4"]) == 1
138
139 # Onion address not added yet
140 site_peers = bootstrapper_db.peerList(address="1.2.3.4", port=1234, hash=hash1)
141 assert len(site_peers["onion"]) == 0
142 assert "onion_sign_this" in res
143
144 # Sign the nonces
145 sign1 = CryptRsa.sign(res["onion_sign_this"].encode(), tor_manager.getPrivatekey(onion1))
146 sign2 = CryptRsa.sign(res["onion_sign_this"].encode(), tor_manager.getPrivatekey(onion2))
147
148 # Bad sign (different address)
149 res = peer.request("announce", {
150 "onions": [onion1], "onion_sign_this": res["onion_sign_this"],
151 "onion_signs": {tor_manager.getPublickey(onion2): sign2},
152 "hashes": [hash1], "port": 15441, "need_types": ["ipv4", "onion"], "need_num": 10, "add": ["onion"]
153 })
154 assert "onion_sign_this" in res
155 site_peers1 = bootstrapper_db.peerList(address="1.2.3.4", port=1234, hash=hash1)
156 assert len(site_peers1["onion"]) == 0 # Not added
157
158 # Bad sign (missing one)
159 res = peer.request("announce", {
160 "onions": [onion1, onion1, onion2], "onion_sign_this": res["onion_sign_this"],
161 "onion_signs": {tor_manager.getPublickey(onion1): sign1},
162 "hashes": [hash1, hash2, hash3], "port": 15441, "need_types": ["ipv4", "onion"], "need_num": 10, "add": ["onion"]
163 })
164 assert "onion_sign_this" in res
165 site_peers1 = bootstrapper_db.peerList(address="1.2.3.4", port=1234, hash=hash1)
166 assert len(site_peers1["onion"]) == 0 # Not added
167
168 # Good sign
169 res = peer.request("announce", {
170 "onions": [onion1, onion1, onion2], "onion_sign_this": res["onion_sign_this"],
171 "onion_signs": {tor_manager.getPublickey(onion1): sign1, tor_manager.getPublickey(onion2): sign2},
172 "hashes": [hash1, hash2, hash3], "port": 15441, "need_types": ["ipv4", "onion"], "need_num": 10, "add": ["onion"]
173 })
174 assert "onion_sign_this" not in res
175
176 # Onion addresses added
177 site_peers1 = bootstrapper_db.peerList(address="1.2.3.4", port=1234, hash=hash1)
178 assert len(site_peers1["onion"]) == 1
179 site_peers2 = bootstrapper_db.peerList(address="1.2.3.4", port=1234, hash=hash2)
180 assert len(site_peers2["onion"]) == 1
181 site_peers3 = bootstrapper_db.peerList(address="1.2.3.4", port=1234, hash=hash3)
182 assert len(site_peers3["onion"]) == 1
183
184 assert site_peers1["onion"][0] == site_peers2["onion"][0]
185 assert site_peers2["onion"][0] != site_peers3["onion"][0]
186 assert helper.unpackOnionAddress(site_peers1["onion"][0])[0] == onion1 + ".onion"
187 assert helper.unpackOnionAddress(site_peers2["onion"][0])[0] == onion1 + ".onion"
188 assert helper.unpackOnionAddress(site_peers3["onion"][0])[0] == onion2 + ".onion"
189
190 tor_manager.delOnion(onion1)
191 tor_manager.delOnion(onion2)
192
193 def testRequestPeers(self, file_server, site, bootstrapper_db, tor_manager):
194 site.connection_server = file_server
195 file_server.tor_manager = tor_manager
196 hash = hashlib.sha256(site.address.encode()).digest()
197
198 # Request peers from tracker
199 assert len(site.peers) == 0
200 bootstrapper_db.peerAnnounce(ip_type="ipv4", address="1.2.3.4", port=1234, hashes=[hash])
201 site.announcer.announceTracker("zero://%s:%s" % (file_server.ip, file_server.port))
202 assert len(site.peers) == 1
203
204 # Test onion address store
205 bootstrapper_db.peerAnnounce(ip_type="onion", address="bka4ht2bzxchy44r", port=1234, hashes=[hash], onion_signed=True)
206 site.announcer.announceTracker("zero://%s:%s" % (file_server.ip, file_server.port))
207 assert len(site.peers) == 2
208 assert "bka4ht2bzxchy44r.onion:1234" in site.peers
209
210 @pytest.mark.slow
211 def testAnnounce(self, file_server, tor_manager):
212 file_server.tor_manager = tor_manager
213 hash1 = hashlib.sha256(b"1Nekos4fiBqfcazyG1bAxdBT5oBvA76Z").digest()
214 hash2 = hashlib.sha256(b"1EU1tbG9oC1A8jz2ouVwGZyQ5asrNsE4Vr").digest()
215 peer = Peer("zero.booth.moe", 443, connection_server=file_server)
216 assert peer.request("ping")
217 peer = Peer("boot3rdez4rzn36x.onion", 15441, connection_server=file_server)
218 assert peer.request("ping")
219 res = peer.request("announce", {
220 "hashes": [hash1, hash2],
221 "port": 15441, "need_types": ["ip4", "onion"], "need_num": 100, "add": [""]
222 })
223
224 assert res
225
226 def testBackwardCompatibility(self, file_server, bootstrapper_db):
227 peer = Peer(file_server.ip, 1544, connection_server=file_server)
228 hash1 = hashlib.sha256(b"site1").digest()
229
230 bootstrapper_db.peerAnnounce("ipv4", file_server.ip_external, port=15441, hashes=[hash1], delete_missing_hashes=True)
231
232 # Test with ipv4 need type
233 res = peer.request("announce", {
234 "hashes": [hash1],
235 "port": 15441, "need_types": ["ipv4"], "need_num": 10, "add": []
236 })
237
238 assert len(res["peers"][0]["ipv4"]) == 1
239
240 # Test with ip4 need type
241 res = peer.request("announce", {
242 "hashes": [hash1],
243 "port": 15441, "need_types": ["ip4"], "need_num": 10, "add": []
244 })
245
246 assert len(res["peers"][0]["ip4"]) == 1