TestBootstrapper.py 11 KB

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