"
- from Site import SiteAnnouncer # importing at the top of the file breaks plugins
+ from Site import SiteAnnouncer # importing at the top of the file breaks plugins
for tracker_address, tracker_stat in sorted(SiteAnnouncer.global_stats.items()):
yield self.formatTableRow([
("%s", tracker_address),
@@ -143,13 +167,12 @@ def renderTrackers(self):
])
yield "
"
- def renderTor(self):
- import main
+ # Tor hidden services
yield "
Tor hidden services (status: %s): " % main.file_server.tor_manager.status
for site_address, onion in list(main.file_server.tor_manager.site_onions.items()):
yield "- %-34s: %s " % (site_address, onion)
- def renderDbStats(self):
+ # Db
yield "
Db: "
for db in Db.opened_dbs:
tables = [row["name"] for row in db.execute("SELECT name FROM sqlite_master WHERE type = 'table'").fetchall()]
@@ -161,7 +184,8 @@ def renderDbStats(self):
time.time() - db.last_query_time, db.db_path, db_size, json.dumps(table_rows, sort_keys=True)
)
- def renderSites(self):
+
+ # Sites
yield "
"
- def renderBigfiles(self):
+ # Big files
yield "
Big files: "
for site in list(self.server.sites.values()):
if not site.settings.get("has_bigfile"):
@@ -225,8 +249,7 @@ def renderBigfiles(self):
yield ""
yield "
"
+ t = time.time()
- def formatTableText(self, *rows):
- for row in rows:
- yield " "
- for col in row:
- yield " " + str(col)
- yield "\n"
-
- def testEnv(self, format="text"):
- import gevent
- import msgpack
- import pkg_resources
- import importlib
- import coincurve
- import sqlite3
+ # CryptBitcoin
+ yield " CryptBitcoin: "
from Crypt import CryptBitcoin
- yield "\n"
-
- yield from self.formatTable(
- ["ZeroNet version:", "%s rev%s" % (config.version, config.rev)],
- ["Python:", "%s" % sys.version],
- ["Platform:", "%s" % sys.platform],
- ["Crypt verify lib:", "%s" % CryptBitcoin.lib_verify_best],
- ["OpenSSL:", "%s" % CryptBitcoin.sslcrypto.ecc.get_backend()],
- ["Libsecp256k1:", "%s" % type(coincurve._libsecp256k1.lib).__name__],
- ["SQLite:", "%s, API: %s" % (sqlite3.sqlite_version, sqlite3.version)],
- format=format
- )
-
-
- yield self.formatHead("Libraries:")
- rows = []
- for lib_name in ["gevent", "greenlet", "msgpack", "base58", "merkletools", "rsa", "socks", "pyasn1", "gevent_ws", "websocket", "maxminddb"]:
+ # seed = CryptBitcoin.newSeed()
+ # yield "- Seed: %s " % seed
+ seed = "e180efa477c63b0f2757eac7b1cce781877177fe0966be62754ffd4c8592ce38"
+
+ with benchmark("hdPrivatekey x 10", 0.7):
+ for i in range(10):
+ privatekey = CryptBitcoin.hdPrivatekey(seed, i * 10)
+ yield "."
+ valid = "5JsunC55XGVqFQj5kPGK4MWgTL26jKbnPhjnmchSNPo75XXCwtk"
+ assert privatekey == valid, "%s != %s" % (privatekey, valid)
+
+ data = "Hello" * 1024 # 5k
+ with benchmark("sign x 10", 0.35):
+ for i in range(10):
+ yield "."
+ sign = CryptBitcoin.sign(data, privatekey)
+ valid = "G1GXaDauZ8vX/N9Jn+MRiGm9h+I94zUhDnNYFaqMGuOiBHB+kp4cRPZOL7l1yqK5BHa6J+W97bMjvTXtxzljp6w="
+ assert sign == valid, "%s != %s" % (sign, valid)
+
+ address = CryptBitcoin.privatekeyToAddress(privatekey)
+ for lib_verify in ["btctools", "openssl", "libsecp256k1"]:
try:
- module = importlib.import_module(lib_name)
- if "__version__" in dir(module):
- version = module.__version__
- elif "version" in dir(module):
- version = module.version
- else:
- version = "unknown version"
-
- if type(version) is tuple:
- version = ".".join(map(str, version))
-
- rows.append(["- %s:" % lib_name, version, "at " + module.__file__])
- except Exception as err:
- rows.append(["! Error importing %s:", repr(err)])
-
- """
- try:
- yield " - %s " % html.escape(repr(pkg_resources.get_distribution(lib_name)))
+ CryptBitcoin.loadLib(lib_verify)
+ loaded = True
+ if lib_verify == "openssl":
+ yield "+ Loaded lib: %s " % html.escape(str(CryptBitcoin.bitcoin.core.key._ssl))
+ elif lib_verify == "libsecp256k1":
+ import coincurve
+ yield "+ Loaded lib: %s " % type(coincurve._libsecp256k1.lib).__name__
except Exception as err:
- yield " ! %s " % html.escape(repr(err))
- """
+ yield "- Error loading %s: %s " % (lib_verify, err)
+ loaded = False
+ if not loaded:
+ continue
+ with benchmark("%s verify x 100" % lib_verify, 0.37):
+ for i in range(100):
+ if i % 10 == 0:
+ yield "."
+ ok = CryptBitcoin.verify(data, address, sign, lib_verify=lib_verify)
+ assert ok, "does not verify from %s" % address
+
+ # CryptHash
+ yield " CryptHash: "
+ from Crypt import CryptHash
+ import io
+
+ data = io.BytesIO(b"Hello" * 1024 * 1024) # 5m
+ with benchmark("sha256 5M x 10", 0.6):
+ for i in range(10):
+ data.seek(0)
+ hash = CryptHash.sha256sum(data)
+ yield "."
+ valid = "8cd629d9d6aff6590da8b80782a5046d2673d5917b99d5603c3dcb4005c45ffa"
+ assert hash == valid, "%s != %s" % (hash, valid)
+
+ data = io.BytesIO(b"Hello" * 1024 * 1024) # 5m
+ with benchmark("sha512 5M x 10", 0.6):
+ for i in range(10):
+ data.seek(0)
+ hash = CryptHash.sha512sum(data)
+ yield "."
+ valid = "9ca7e855d430964d5b55b114e95c6bbb114a6d478f6485df93044d87b108904d"
+ assert hash == valid, "%s != %s" % (hash, valid)
+
+ with benchmark("os.urandom(256) x 1000", 0.0065):
+ for i in range(10):
+ for y in range(100):
+ data = os.urandom(256)
+ yield "."
+
+ # Msgpack
+ from util import Msgpack
+ yield " Msgpack: (version: %s) " % ".".join(map(str, Msgpack.msgpack.version))
+ binary = b'fqv\xf0\x1a"e\x10,\xbe\x9cT\x9e(\xa5]u\x072C\x8c\x15\xa2\xa8\x93Sw)\x19\x02\xdd\t\xfb\xf67\x88\xd9\xee\x86\xa1\xe4\xb6,\xc6\x14\xbb\xd7$z\x1d\xb2\xda\x85\xf5\xa0\x97^\x01*\xaf\xd3\xb0!\xb7\x9d\xea\x89\xbbh8\xa1"\xa7]e(@\xa2\xa5g\xb7[\xae\x8eE\xc2\x9fL\xb6s\x19\x19\r\xc8\x04S\xd0N\xe4]?/\x01\xea\xf6\xec\xd1\xb3\xc2\x91\x86\xd7\xf4K\xdf\xc2lV\xf4\xe8\x80\xfc\x8ep\xbb\x82\xb3\x86\x98F\x1c\xecS\xc8\x15\xcf\xdc\xf1\xed\xfc\xd8\x18r\xf9\x80\x0f\xfa\x8cO\x97(\x0b]\xf1\xdd\r\xe7\xbf\xed\x06\xbd\x1b?\xc5\xa0\xd7a\x82\xf3\xa8\xe6@\xf3\ri\xa1\xb10\xf6\xd4W\xbc\x86\x1a\xbb\xfd\x94!bS\xdb\xaeM\x92\x00#\x0b\xf7\xad\xe9\xc2\x8e\x86\xbfi![%\xd31]\xc6\xfc2\xc9\xda\xc6v\x82P\xcc\xa9\xea\xb9\xff\xf6\xc8\x17iD\xcf\xf3\xeeI\x04\xe9\xa1\x19\xbb\x01\x92\xf5nn4K\xf8\xbb\xc6\x17e>\xa7 \xbbv'
+ data = OrderedDict(
+ sorted({"int": 1024 * 1024 * 1024, "float": 12345.67890, "text": "hello" * 1024, "binary": binary}.items())
+ )
+ data_packed_valid = b'\x84\xa6binary\xc5\x01\x00fqv\xf0\x1a"e\x10,\xbe\x9cT\x9e(\xa5]u\x072C\x8c\x15\xa2\xa8\x93Sw)\x19\x02\xdd\t\xfb\xf67\x88\xd9\xee\x86\xa1\xe4\xb6,\xc6\x14\xbb\xd7$z\x1d\xb2\xda\x85\xf5\xa0\x97^\x01*\xaf\xd3\xb0!\xb7\x9d\xea\x89\xbbh8\xa1"\xa7]e(@\xa2\xa5g\xb7[\xae\x8eE\xc2\x9fL\xb6s\x19\x19\r\xc8\x04S\xd0N\xe4]?/\x01\xea\xf6\xec\xd1\xb3\xc2\x91\x86\xd7\xf4K\xdf\xc2lV\xf4\xe8\x80\xfc\x8ep\xbb\x82\xb3\x86\x98F\x1c\xecS\xc8\x15\xcf\xdc\xf1\xed\xfc\xd8\x18r\xf9\x80\x0f\xfa\x8cO\x97(\x0b]\xf1\xdd\r\xe7\xbf\xed\x06\xbd\x1b?\xc5\xa0\xd7a\x82\xf3\xa8\xe6@\xf3\ri\xa1\xb10\xf6\xd4W\xbc\x86\x1a\xbb\xfd\x94!bS\xdb\xaeM\x92\x00#\x0b\xf7\xad\xe9\xc2\x8e\x86\xbfi![%\xd31]\xc6\xfc2\xc9\xda\xc6v\x82P\xcc\xa9\xea\xb9\xff\xf6\xc8\x17iD\xcf\xf3\xeeI\x04\xe9\xa1\x19\xbb\x01\x92\xf5nn4K\xf8\xbb\xc6\x17e>\xa7 \xbbv\xa5float\xcb@\xc8\x1c\xd6\xe61\xf8\xa1\xa3int\xce@\x00\x00\x00\xa4text\xda\x14\x00hellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohello'
+ with benchmark("pack 5K x 10 000", 0.78):
+ for i in range(10):
+ for y in range(1000):
+ data_packed = Msgpack.pack(data)
+ yield "."
+ assert data_packed == data_packed_valid, "%s != %s" % (repr(data_packed), repr(data_packed_valid))
+
+ with benchmark("unpack 5K x 10 000", 1.2):
+ for i in range(10):
+ for y in range(1000):
+ data_unpacked = Msgpack.unpack(data_packed, decode=False)
+ yield "."
+ assert data == data_unpacked, "%s != %s" % (data_unpacked, data)
+
+ for fallback in [True, False]:
+ with benchmark("streaming unpack 5K x 10 000 (fallback: %s)" % fallback, 1.4):
+ for i in range(10):
+ unpacker = Msgpack.getUnpacker(decode=False, fallback=fallback)
+ for y in range(1000):
+ unpacker.feed(data_packed)
+ for data_unpacked in unpacker:
+ pass
+ yield "."
+ assert data == data_unpacked, "%s != %s" % (data_unpacked, data)
+
+ # Db
+ import sqlite3
+ yield " Db: (version: %s, API: %s) " % (sqlite3.sqlite_version, sqlite3.version)
+
+ schema = {
+ "db_name": "TestDb",
+ "db_file": "%s/benchmark.db" % config.data_dir,
+ "maps": {
+ ".*": {
+ "to_table": {
+ "test": "test"
+ }
+ }
+ },
+ "tables": {
+ "test": {
+ "cols": [
+ ["test_id", "INTEGER"],
+ ["title", "TEXT"],
+ ["json_id", "INTEGER REFERENCES json (json_id)"]
+ ],
+ "indexes": ["CREATE UNIQUE INDEX test_key ON test(test_id, json_id)"],
+ "schema_changed": 1426195822
+ }
+ }
+ }
+
+ if os.path.isfile("%s/benchmark.db" % config.data_dir):
+ os.unlink("%s/benchmark.db" % config.data_dir)
+
+ with benchmark("Open x 10", 0.13):
+ for i in range(10):
+ db = Db.Db(schema, "%s/benchmark.db" % config.data_dir)
+ db.checkTables()
+ db.close()
+ yield "."
+
+ db = Db.Db(schema, "%s/benchmark.db" % config.data_dir)
+ db.checkTables()
+ import json
+
+ with benchmark("Insert x 10 x 1000", 1.0):
+ for u in range(10): # 10 user
+ data = {"test": []}
+ for i in range(1000): # 1000 line of data
+ data["test"].append({"test_id": i, "title": "Testdata for %s message %s" % (u, i)})
+ json.dump(data, open("%s/test_%s.json" % (config.data_dir, u), "w"))
+ db.updateJson("%s/test_%s.json" % (config.data_dir, u))
+ os.unlink("%s/test_%s.json" % (config.data_dir, u))
+ yield "."
+
+ with benchmark("Buffered insert x 100 x 100", 1.3):
+ cur = db.getCursor()
+ cur.logging = False
+ for u in range(100, 200): # 100 user
+ data = {"test": []}
+ for i in range(100): # 1000 line of data
+ data["test"].append({"test_id": i, "title": "Testdata for %s message %s" % (u, i)})
+ json.dump(data, open("%s/test_%s.json" % (config.data_dir, u), "w"))
+ db.updateJson("%s/test_%s.json" % (config.data_dir, u), cur=cur)
+ os.unlink("%s/test_%s.json" % (config.data_dir, u))
+ if u % 10 == 0:
+ yield "."
+
+ yield " + Total rows in db: %s " % db.execute("SELECT COUNT(*) AS num FROM test").fetchone()[0]
+
+ with benchmark("Indexed query x 1000", 0.25):
+ found = 0
+ cur = db.getCursor()
+ cur.logging = False
+ for i in range(1000): # 1000x by test_id
+ res = cur.execute("SELECT * FROM test WHERE test_id = %s" % i)
+ for row in res:
+ found += 1
+ if i % 100 == 0:
+ yield "."
+
+ assert found == 20000, "Found: %s != 20000" % found
+
+ with benchmark("Not indexed query x 100", 0.6):
+ found = 0
+ cur = db.getCursor()
+ cur.logging = False
+ for i in range(100): # 1000x by test_id
+ res = cur.execute("SELECT * FROM test WHERE json_id = %s" % i)
+ for row in res:
+ found += 1
+ if i % 10 == 0:
+ yield "."
+
+ assert found == 18900, "Found: %s != 18900" % found
+
+ with benchmark("Like query x 100", 1.8):
+ found = 0
+ cur = db.getCursor()
+ cur.logging = False
+ for i in range(100): # 1000x by test_id
+ res = cur.execute("SELECT * FROM test WHERE title LIKE '%%message %s%%'" % i)
+ for row in res:
+ found += 1
+ if i % 10 == 0:
+ yield "."
+
+ assert found == 38900, "Found: %s != 11000" % found
+
+ db.close()
+ if os.path.isfile("%s/benchmark.db" % config.data_dir):
+ os.unlink("%s/benchmark.db" % config.data_dir)
- yield from self.formatTable(*rows, format=format)
+ gc.collect() # Implicit grabage collection
- yield self.formatHead("Library config:", format=format)
+ # Zip
+ yield " Compression: "
+ import zipfile
+ test_data = b"Test" * 1024
+ file_name = b"\xc3\x81rv\xc3\xadzt\xc5\xb0r\xc5\x91t\xc3\xbck\xc3\xb6r\xc3\xb3g\xc3\xa9p\xe4\xb8\xad\xe5\x8d\x8e%s.txt".decode("utf8")
+
+ with benchmark("Zip pack x 10", 0.12):
+ for i in range(10):
+ with zipfile.ZipFile('%s/test.zip' % config.data_dir, 'w') as archive:
+ for y in range(100):
+ zip_info = zipfile.ZipInfo(file_name % y, (1980,1,1,0,0,0))
+ zip_info.compress_type = zipfile.ZIP_DEFLATED
+ zip_info.create_system = 3
+ zip_info.flag_bits = 0
+ zip_info.external_attr = 25165824
+ archive.writestr(zip_info, test_data)
+ yield "."
+
+ hash = CryptHash.sha512sum(open("%s/test.zip" % config.data_dir, "rb"))
+ valid = "f630fece29fff1cc8dbf454e47a87fea2746a4dbbd2ceec098afebab45301562"
+ assert hash == valid, "Invalid hash: %s != %s " % (hash, valid)
+
+ with benchmark("Zip unpack x 10", 0.2):
+ for i in range(10):
+ with zipfile.ZipFile('%s/test.zip' % config.data_dir) as archive:
+ for y in range(100):
+ data = archive.open(file_name % y).read()
+ assert archive.open(file_name % y).read() == test_data, "Invalid data: %s..." % data[0:30]
+ yield "."
+
+ if os.path.isfile("%s/test.zip" % config.data_dir):
+ os.unlink("%s/test.zip" % config.data_dir)
+
+ # gz, bz2, xz
+ import tarfile
+ import gzip
+
+ # Monkey patch _init_write_gz to use fixed date in order to keep the hash independent from datetime
+ def nodate_write_gzip_header(self):
+ self._write_mtime = 0
+ original_write_gzip_header(self)
+
+ original_write_gzip_header = gzip.GzipFile._write_gzip_header
+ gzip.GzipFile._write_gzip_header = nodate_write_gzip_header
+
+ test_data_io = io.BytesIO(b"Test" * 1024)
+ archive_formats = {
+ "gz": {"hash": "4704ebd8c987ed6f833059f1de9c475d443b0539b8d4c4cb8b49b26f7bbf2d19", "time_pack": 0.3, "time_unpack": 0.2},
+ "bz2": {"hash": "90cba0b4d9abaa37b830bf37e4adba93bfd183e095b489ebee62aaa94339f3b5", "time_pack": 2.0, "time_unpack": 0.5},
+ "xz": {"hash": "37abc16d552cfd4a495cb2acbf8b1d5877631d084f6571f4d6544bc548c69bae", "time_pack": 1.4, "time_unpack": 0.2}
+ }
+ for ext, format_data in archive_formats.items():
+ archive_path = '%s/test.tar.%s' % (config.data_dir, ext)
+ with benchmark("Tar.%s pack x 10" % ext, format_data["time_pack"]):
+ for i in range(10):
+ with tarfile.open(archive_path, 'w:%s' % ext) as archive:
+ for y in range(100):
+ test_data_io.seek(0)
+ tar_info = tarfile.TarInfo(file_name % y)
+ tar_info.size = 4 * 1024
+ archive.addfile(tar_info, test_data_io)
+ yield "."
+
+ hash = CryptHash.sha512sum(open("%s/test.tar.%s" % (config.data_dir, ext), "rb"))
+ valid = format_data["hash"]
+ assert hash == valid, "Invalid hash: %s != %s " % (hash, valid)
+
+ archive_size = os.path.getsize(archive_path) / 1024
+ with benchmark("Tar.%s unpack (%.2fkB) x 10" % (ext, archive_size), format_data["time_unpack"]):
+ for i in range(10):
+ with tarfile.open(archive_path, 'r:%s' % ext) as archive:
+ for y in range(100):
+ assert archive.extractfile(file_name % y).read() == test_data
+ yield "."
+
+ if os.path.isfile(archive_path):
+ os.unlink(archive_path)
+
+ yield " Done. Total: %.2fs" % (time.time() - t)
- yield from self.formatTable(
- ["- gevent:", gevent.config.loop.__module__],
- ["- msgpack unpacker:", msgpack.Unpacker.__module__],
- format=format
- )
+ @helper.encodeResponse
+ def actionGcCollect(self):
+ import gc
+ self.sendHeader()
+ yield str(gc.collect())
diff --git a/plugins/TranslateSite/TranslateSitePlugin.py b/plugins/TranslateSite/TranslateSitePlugin.py
index d82d0ebe0..ccb524aef 100644
--- a/plugins/TranslateSite/TranslateSitePlugin.py
+++ b/plugins/TranslateSite/TranslateSitePlugin.py
@@ -25,8 +25,6 @@ def actionSiteMedia(self, path, **kwargs):
file_generator = super(UiRequestPlugin, self).actionSiteMedia(path, **kwargs)
if "__next__" in dir(file_generator): # File found and generator returned
site = self.server.sites.get(path_parts["address"])
- if not site or not site.content_manager.contents.get("content.json"):
- return file_generator
return self.actionPatchFile(site, path_parts["inner_path"], file_generator)
else:
return file_generator
@@ -46,7 +44,7 @@ def actionUiMedia(self, path):
return file_generator
def actionPatchFile(self, site, inner_path, file_generator):
- content_json = site.content_manager.contents.get("content.json")
+ content_json = site.content_manager.contents["content.json"]
lang_file = "languages/%s.json" % translate.lang
lang_file_exist = False
if site.settings.get("own"): # My site, check if the file is exist (allow to add new lang without signing)
diff --git a/plugins/Trayicon/TrayiconPlugin.py b/plugins/Trayicon/TrayiconPlugin.py
index 2dc3a5c67..794ced777 100644
--- a/plugins/Trayicon/TrayiconPlugin.py
+++ b/plugins/Trayicon/TrayiconPlugin.py
@@ -32,14 +32,17 @@ def main(self):
)
self.icon = icon
- self.console = False
+ if not config.debug: # Hide console if not in debug mode
+ notificationicon.hideConsole()
+ self.console = False
+ else:
+ self.console = True
@atexit.register
def hideIcon():
- try:
- icon.die()
- except Exception as err:
- print("Error removing trayicon: %s" % err)
+ if not config.debug:
+ notificationicon.showConsole()
+ icon.die()
ui_ip = config.ui_ip if config.ui_ip != "*" else "127.0.0.1"
@@ -132,30 +135,25 @@ def formatAutorun(self):
else:
cwd = os.path.dirname(sys.executable)
- ignored_args = [
- "--open_browser", "default_browser",
- "--dist_type", "bundle_win64"
- ]
-
if sys.platform == 'win32':
- args = ['"%s"' % arg for arg in args if arg and arg not in ignored_args]
+ args = ['"%s"' % arg for arg in args if arg]
cmd = " ".join(args)
# Dont open browser on autorun
- cmd = cmd.replace("start.py", "zeronet.py").strip()
+ cmd = cmd.replace("start.py", "zeronet.py").replace('"--open_browser"', "").replace('"default_browser"', "").strip()
cmd += ' --open_browser ""'
- return "\r\n".join([
- '@echo off',
- 'chcp 65001 > nul',
- 'set PYTHONIOENCODING=utf-8',
- 'cd /D \"%s\"' % cwd,
- 'start "" %s' % cmd
- ])
+ return """
+ @echo off
+ chcp 65001 > nul
+ set PYTHONIOENCODING=utf-8
+ cd /D \"%s\"
+ start "" %s
+ """ % (cwd, cmd)
def isAutorunEnabled(self):
path = self.getAutorunPath()
- return os.path.isfile(path) and open(path, "rb").read().decode("utf8") == self.formatAutorun()
+ return os.path.isfile(path) and open(path).read() == self.formatAutorun()
def titleAutorun(self):
translate = _["Start ZeroNet when Windows starts"]
@@ -168,4 +166,4 @@ def toggleAutorun(self):
if self.isAutorunEnabled():
os.unlink(self.getAutorunPath())
else:
- open(self.getAutorunPath(), "wb").write(self.formatAutorun().encode("utf8"))
+ open(self.getAutorunPath(), "w").write(self.formatAutorun())
diff --git a/plugins/Trayicon/languages/fr.json b/plugins/Trayicon/languages/fr.json
index a6fca7691..ec3353185 100644
--- a/plugins/Trayicon/languages/fr.json
+++ b/plugins/Trayicon/languages/fr.json
@@ -2,7 +2,7 @@
"ZeroNet Twitter": "ZeroNet Twitter",
"ZeroNet Reddit": "ZeroNet Reddit",
"ZeroNet Github": "ZeroNet Github",
- "Report bug/request feature": "Rapport d'erreur/Demander une fonctionnalité",
+ "Report bug/request feature": "Rapport d'erreur/Demanger une fonctionnalité",
"!Open ZeroNet": "!Ouvrir ZeroNet",
"Quit": "Quitter",
"(active)": "(actif)",
diff --git a/plugins/Trayicon/lib/notificationicon.py b/plugins/Trayicon/lib/notificationicon.py
index 8b913f83e..57a4ddd66 100644
--- a/plugins/Trayicon/lib/notificationicon.py
+++ b/plugins/Trayicon/lib/notificationicon.py
@@ -566,11 +566,10 @@ def _run(self):
# print "NotificationIcon error", err, message
message = MSG()
time.sleep(0.125)
- print("Icon thread stopped, removing icon (hicon: %s, hwnd: %s)..." % (self._hicon, self._hwnd))
+ print("Icon thread stopped, removing icon...")
Shell_NotifyIcon(NIM_DELETE, ctypes.cast(ctypes.pointer(iconinfo), ctypes.POINTER(NOTIFYICONDATA)))
ctypes.windll.user32.DestroyWindow(self._hwnd)
- ctypes.windll.user32.DestroyIcon.argtypes = [ctypes.wintypes.HICON]
ctypes.windll.user32.DestroyIcon(self._hicon)
diff --git a/plugins/UiConfig/languages/pt-br.json b/plugins/UiConfig/languages/pt-br.json
index 6235606ed..7595c2f78 100644
--- a/plugins/UiConfig/languages/pt-br.json
+++ b/plugins/UiConfig/languages/pt-br.json
@@ -13,7 +13,7 @@
"Disable": "Desativar",
"Enable": "Ativar",
- "Always": "Sempre",
+ "Sempre": "Mindig",
"Use Tor bridges": "Usar pontes do Tor",
"Use obfuscated bridge relays to avoid network level Tor block (even slower)": "Usar relays de ponte ofuscados para evitar o bloqueio de Tor de nível de rede (ainda mais lento)",
@@ -26,31 +26,8 @@
"Proxy for tracker connections": "Proxy para conexões de tracker",
- "configuration item value changed": " valor do item de configuração foi alterado",
+ " configuration item value changed": " valor do item de configuração foi alterado",
"Save settings": "Salvar configurações",
"Some changed settings requires restart": "Algumas configurações alteradas requrem reinicialização",
- "Restart ZeroNet client": "Reiniciar cliente da ZeroNet",
-
- "Offline mode": "Modo offline",
- "Disable network communication.": "Desativar a comunicação em rede.",
- "File server network": "Rede do servidor de arquivos",
- "Accept incoming peers using IPv4 or IPv6 address. (default: dual)": "Aceite pontos de entrada usando o endereço IPv4 ou IPv6. (padrão: dual)",
- "File server external ip": "IP externo do servidor de arquivos",
- "Performance": "Desempenho",
- "Level of logging to file": "Nível de registro no arquivo",
- "Everything": "Tudo",
- "Only important messages": "Apenas mensagens importantes",
- "Only errors": "Apenas erros",
-
- "Threads for async file system reads": "Threads para leituras de sistema de arquivos assíncronas",
- "Threads for async file system writes": "Threads para gravações do sistema de arquivos assíncrono",
- "Threads for cryptographic functions": "Threads para funções criptográficas",
- "Threads for database operations": "Threads para operações de banco de dados",
- "Sync execution": "Execução de sincronização",
- "Custom": "Personalizado",
- "Custom socks proxy address for trackers": "Endereço de proxy de meias personalizadas para trackers",
- "Your file server is accessible on these ips. (default: detect automatically)": "Seu servidor de arquivos está acessível nesses ips. (padrão: detectar automaticamente)",
- "Detect automatically": "Detectar automaticamente",
- " configuration item value changed": " valor do item de configuração alterado"
-
+ "Restart ZeroNet client": "Reiniciar cliente da ZeroNet"
}
diff --git a/plugins/UiConfig/languages/zh.json b/plugins/UiConfig/languages/zh.json
index 9240b2496..6d6e9f809 100644
--- a/plugins/UiConfig/languages/zh.json
+++ b/plugins/UiConfig/languages/zh.json
@@ -41,19 +41,6 @@
"Everything": "记录全部",
"Only important messages": "仅记录重要信息",
"Only errors": "仅记录错误",
- "Threads for async file system reads": "文件系统异步读取线程",
- "Threads for async file system writes": "文件系统异步写入线程",
- "Threads for cryptographic functions": "密码函数线程",
- "Threads for database operations": "数据库操作线程",
- "Sync read": "同步读取",
- "Sync write": "同步写入",
- "Sync execution": "同步执行",
- "1 thread": "1个线程",
- "2 threads": "2个线程",
- "3 threads": "3个线程",
- "4 threads": "4个线程",
- "5 threads": "5个线程",
- "10 threads": "10个线程",
" configuration item value changed": " 个配置值已经改变",
"Save settings": "保存配置",
diff --git a/plugins/UiConfig/media/js/ConfigStorage.coffee b/plugins/UiConfig/media/js/ConfigStorage.coffee
index 923270017..83275bd6b 100644
--- a/plugins/UiConfig/media/js/ConfigStorage.coffee
+++ b/plugins/UiConfig/media/js/ConfigStorage.coffee
@@ -32,13 +32,6 @@ class ConfigStorage extends Class
return value.split("\n")
if type == "boolean" and not value
return false
- else if type == "number"
- if typeof(value) == "number"
- return value.toString()
- else if not value
- return "0"
- else
- return value
else
return value
@@ -75,7 +68,7 @@ class ConfigStorage extends Class
title: "File server port"
type: "text"
valid_pattern: /[0-9]*/
- description: "Other peers will use this port to reach your served sites. (default: randomize)"
+ description: "Other peers will use this port to reach your served sites. (default: 15441)"
section.items.push
key: "ip_external"
@@ -118,7 +111,7 @@ class ConfigStorage extends Class
key: "trackers_file"
type: "textarea"
description: "Load additional list of torrent trackers dynamically, from a file"
- placeholder: "Eg.: {data_dir}/trackers.json"
+ placeholder: "Eg.: data/trackers.json"
value_pos: "fullwidth"
section.items.push
@@ -156,62 +149,6 @@ class ConfigStorage extends Class
{title: "Only errors", value: "ERROR"}
]
- section.items.push
- key: "threads_fs_read"
- title: "Threads for async file system reads"
- type: "select"
- options: [
- {title: "Sync read", value: 0}
- {title: "1 thread", value: 1}
- {title: "2 threads", value: 2}
- {title: "3 threads", value: 3}
- {title: "4 threads", value: 4}
- {title: "5 threads", value: 5}
- {title: "10 threads", value: 10}
- ]
-
- section.items.push
- key: "threads_fs_write"
- title: "Threads for async file system writes"
- type: "select"
- options: [
- {title: "Sync write", value: 0}
- {title: "1 thread", value: 1}
- {title: "2 threads", value: 2}
- {title: "3 threads", value: 3}
- {title: "4 threads", value: 4}
- {title: "5 threads", value: 5}
- {title: "10 threads", value: 10}
- ]
-
- section.items.push
- key: "threads_crypt"
- title: "Threads for cryptographic functions"
- type: "select"
- options: [
- {title: "Sync execution", value: 0}
- {title: "1 thread", value: 1}
- {title: "2 threads", value: 2}
- {title: "3 threads", value: 3}
- {title: "4 threads", value: 4}
- {title: "5 threads", value: 5}
- {title: "10 threads", value: 10}
- ]
-
- section.items.push
- key: "threads_db"
- title: "Threads for database operations"
- type: "select"
- options: [
- {title: "Sync execution", value: 0}
- {title: "1 thread", value: 1}
- {title: "2 threads", value: 2}
- {title: "3 threads", value: 3}
- {title: "4 threads", value: 4}
- {title: "5 threads", value: 5}
- {title: "10 threads", value: 10}
- ]
-
createSection: (title) =>
section = {}
section.title = title
diff --git a/plugins/UiConfig/media/js/ConfigView.coffee b/plugins/UiConfig/media/js/ConfigView.coffee
index 64b86e5e9..a110a17da 100644
--- a/plugins/UiConfig/media/js/ConfigView.coffee
+++ b/plugins/UiConfig/media/js/ConfigView.coffee
@@ -118,7 +118,7 @@ class ConfigView extends Class
renderValueSelect: (item) =>
h("select.input-select", {config_key: item.key, oninput: @handleInputChange},
item.options.map (option) =>
- h("option", {selected: option.value.toString() == @values[item.key], value: option.value}, option.title)
+ h("option", {selected: option.value == @values[item.key], value: option.value}, option.title)
)
window.ConfigView = ConfigView
\ No newline at end of file
diff --git a/plugins/UiConfig/media/js/UiConfig.coffee b/plugins/UiConfig/media/js/UiConfig.coffee
index bc1ac6978..4ee3a1c6c 100644
--- a/plugins/UiConfig/media/js/UiConfig.coffee
+++ b/plugins/UiConfig/media/js/UiConfig.coffee
@@ -57,8 +57,9 @@ class UiConfig extends ZeroFrame
for item, i in changed_values
last = i == changed_values.length - 1
value = @config_storage.deformatValue(item.value, typeof(@config[item.key].default))
- default_value = @config_storage.deformatValue(@config[item.key].default, typeof(@config[item.key].default))
- value_same_as_default = JSON.stringify(default_value) == JSON.stringify(value)
+ value_same_as_default = JSON.stringify(@config[item.key].default) == JSON.stringify(value)
+ if value_same_as_default
+ value = null
if @config[item.key].item.valid_pattern and not @config[item.key].item.isHidden?()
match = value.match(@config[item.key].item.valid_pattern)
@@ -68,9 +69,6 @@ class UiConfig extends ZeroFrame
cb(false)
break
- if value_same_as_default
- value = null
-
@saveValue(item.key, value, if last then cb else null)
saveValue: (key, value, cb) =>
diff --git a/plugins/UiConfig/media/js/all.js b/plugins/UiConfig/media/js/all.js
index cb3b553fe..4bf524e09 100644
--- a/plugins/UiConfig/media/js/all.js
+++ b/plugins/UiConfig/media/js/all.js
@@ -1336,14 +1336,6 @@
}
if (type === "boolean" && !value) {
return false;
- } else if (type === "number") {
- if (typeof value === "number") {
- return value.toString();
- } else if (!value) {
- return "0";
- } else {
- return value;
- }
} else {
return value;
}
@@ -1387,7 +1379,7 @@
title: "File server port",
type: "text",
valid_pattern: /[0-9]*/,
- description: "Other peers will use this port to reach your served sites. (default: randomize)"
+ description: "Other peers will use this port to reach your served sites. (default: 15441)"
});
section.items.push({
key: "ip_external",
@@ -1434,7 +1426,7 @@
key: "trackers_file",
type: "textarea",
description: "Load additional list of torrent trackers dynamically, from a file",
- placeholder: "Eg.: {data_dir}/trackers.json",
+ placeholder: "Eg.: data/trackers.json",
value_pos: "fullwidth"
});
section.items.push({
@@ -1472,7 +1464,7 @@
})(this)
});
section = this.createSection("Performance");
- section.items.push({
+ return section.items.push({
key: "log_level",
title: "Level of logging to file",
type: "select",
@@ -1489,122 +1481,6 @@
}
]
});
- section.items.push({
- key: "threads_fs_read",
- title: "Threads for async file system reads",
- type: "select",
- options: [
- {
- title: "Sync read",
- value: 0
- }, {
- title: "1 thread",
- value: 1
- }, {
- title: "2 threads",
- value: 2
- }, {
- title: "3 threads",
- value: 3
- }, {
- title: "4 threads",
- value: 4
- }, {
- title: "5 threads",
- value: 5
- }, {
- title: "10 threads",
- value: 10
- }
- ]
- });
- section.items.push({
- key: "threads_fs_write",
- title: "Threads for async file system writes",
- type: "select",
- options: [
- {
- title: "Sync write",
- value: 0
- }, {
- title: "1 thread",
- value: 1
- }, {
- title: "2 threads",
- value: 2
- }, {
- title: "3 threads",
- value: 3
- }, {
- title: "4 threads",
- value: 4
- }, {
- title: "5 threads",
- value: 5
- }, {
- title: "10 threads",
- value: 10
- }
- ]
- });
- section.items.push({
- key: "threads_crypt",
- title: "Threads for cryptographic functions",
- type: "select",
- options: [
- {
- title: "Sync execution",
- value: 0
- }, {
- title: "1 thread",
- value: 1
- }, {
- title: "2 threads",
- value: 2
- }, {
- title: "3 threads",
- value: 3
- }, {
- title: "4 threads",
- value: 4
- }, {
- title: "5 threads",
- value: 5
- }, {
- title: "10 threads",
- value: 10
- }
- ]
- });
- return section.items.push({
- key: "threads_db",
- title: "Threads for database operations",
- type: "select",
- options: [
- {
- title: "Sync execution",
- value: 0
- }, {
- title: "1 thread",
- value: 1
- }, {
- title: "2 threads",
- value: 2
- }, {
- title: "3 threads",
- value: 3
- }, {
- title: "4 threads",
- value: 4
- }, {
- title: "5 threads",
- value: 5
- }, {
- title: "10 threads",
- value: 10
- }
- ]
- });
};
ConfigStorage.prototype.createSection = function(title) {
@@ -1813,7 +1689,7 @@
}, item.options.map((function(_this) {
return function(option) {
return h("option", {
- selected: option.value.toString() === _this.values[item.key],
+ selected: option.value === _this.values[item.key],
value: option.value
}, option.title);
};
@@ -1942,15 +1818,17 @@
};
UiConfig.prototype.saveValues = function(cb) {
- var base, changed_values, default_value, i, item, j, last, len, match, message, results, value, value_same_as_default;
+ var base, changed_values, i, item, j, last, len, match, message, results, value, value_same_as_default;
changed_values = this.getValuesChanged();
results = [];
for (i = j = 0, len = changed_values.length; j < len; i = ++j) {
item = changed_values[i];
last = i === changed_values.length - 1;
value = this.config_storage.deformatValue(item.value, typeof this.config[item.key]["default"]);
- default_value = this.config_storage.deformatValue(this.config[item.key]["default"], typeof this.config[item.key]["default"]);
- value_same_as_default = JSON.stringify(default_value) === JSON.stringify(value);
+ value_same_as_default = JSON.stringify(this.config[item.key]["default"]) === JSON.stringify(value);
+ if (value_same_as_default) {
+ value = null;
+ }
if (this.config[item.key].item.valid_pattern && !(typeof (base = this.config[item.key].item).isHidden === "function" ? base.isHidden() : void 0)) {
match = value.match(this.config[item.key].item.valid_pattern);
if (!match || match[0] !== value) {
@@ -1960,9 +1838,6 @@
break;
}
}
- if (value_same_as_default) {
- value = null;
- }
results.push(this.saveValue(item.key, value, last ? cb : null));
}
return results;
@@ -2063,4 +1938,4 @@
window.Page.createProjector();
-}).call(this);
+}).call(this);
\ No newline at end of file
diff --git a/plugins/Zeroname/UiRequestPlugin.py b/plugins/Zeroname/UiRequestPlugin.py
new file mode 100644
index 000000000..b0230524a
--- /dev/null
+++ b/plugins/Zeroname/UiRequestPlugin.py
@@ -0,0 +1,30 @@
+import re
+
+from Plugin import PluginManager
+
+
+@PluginManager.registerTo("UiRequest")
+class UiRequestPlugin(object):
+
+ def __init__(self, *args, **kwargs):
+ from Site import SiteManager
+ self.site_manager = SiteManager.site_manager
+ super(UiRequestPlugin, self).__init__(*args, **kwargs)
+
+ # Media request
+ def actionSiteMedia(self, path, **kwargs):
+ match = re.match(r"/media/(?P[A-Za-z0-9-]+\.[A-Za-z0-9\.-]+)(?P/.*|$)", path)
+ if match: # Its a valid domain, resolve first
+ domain = match.group("address")
+ address = self.site_manager.resolveDomain(domain)
+ if address:
+ path = "/media/" + address + match.group("inner_path")
+ return super(UiRequestPlugin, self).actionSiteMedia(path, **kwargs) # Get the wrapper frame output
+
+@PluginManager.registerTo("ConfigPlugin")
+class ConfigPlugin(object):
+ def createArguments(self):
+ group = self.parser.add_argument_group("Zeroname plugin")
+ group.add_argument('--bit_resolver', help='ZeroNet site to resolve .bit domains', default="1Name2NXVi1RDPDgf5617UoW7xA6YrhM9F", metavar="address")
+
+ return super(ConfigPlugin, self).createArguments()
diff --git a/plugins/ZeronameEx/SiteManagerPlugin.py b/plugins/ZeronameEx/SiteManagerPlugin.py
new file mode 100644
index 000000000..48e25668b
--- /dev/null
+++ b/plugins/ZeronameEx/SiteManagerPlugin.py
@@ -0,0 +1,1087 @@
+import logging
+import re
+import time
+import os
+import json
+import gevent
+
+from Config import config
+from Plugin import PluginManager
+
+allow_reload = False # No reload supported
+
+log = logging.getLogger("ZeronameExPlugin")
+
+loggerx = log
+
+@PluginManager.registerTo("SiteManager")
+class SiteManagerPlugin(object):
+ def initZeroNameCachedPlugin(self, *args, **kwargs):
+ self.debugme = True
+ self.logme = loggerx
+ if not self.debugme:
+ def _debug(message):
+ return
+ self.logme.debug = _debug
+
+ self.zero_names = []
+ self.count = 0
+ self.dcr = re.compile(r"(.*?)([A-Za-z0-9_-]+\.bit)$")
+ self.acr = re.compile("^[A-Za-z0-9]{26,35}$")
+ self.my_db_domains = {}
+ self.zero_db_domains = {}
+ self.zero_content_json_domains = {}
+ self.zero_yo_domains = {}
+ self.load_cache()
+
+ def loadZeroNameCachedPlugin(self, *args, **kwargs):
+ self.load_cache()
+ self.count = self.count + 1
+ self.logme.debug("ZeroNameExPlugin bit_resolver count: " + str(self.count))
+ if not self.zero_names:
+ self.zero_names = []
+ def get_zero_name_obj():
+ zero_name_obj = {
+ "site_zeroname": None,
+ "site_zeroname_modified": 0,
+ "db_domains": {},
+ "db_domains_modified": 0,
+ "bit_resolver": None,
+ "loaded": False
+ }
+ class ZeroNameObj(object):
+ def __init__(self, *args, **kwargs):
+ self.__dict__.update(zero_name_obj)
+ return ZeroNameObj
+
+ self.create_zno = get_zero_name_obj()
+
+ for bit_resolver in self.zero_cache["resolvers"]:
+ zno = self.create_zno()
+ self.logme.debug("ZeroNameCachedPlugin bit_resolver: " + bit_resolver)
+ zno.bit_resolver = bit_resolver
+ zno.site_zeroname = self.need(bit_resolver)
+ self.zero_names.append(zno)
+ self.update_cache()
+
+ def __init__(self, *args, **kwargs):
+ super(SiteManagerPlugin, self).__init__(*args, **kwargs)
+ self.initZeroNameCachedPlugin()
+
+ def get_yo_domains(self):
+ return {
+ 'katian-blog.zn': 'http://127.0.0.1:43110/1DgZjVXNqyq9ScsNcz48Df5iVFpf3RgFfd/',
+ 'katian.zn': '12245YXgK5vAbcrhzT84yQVW3XSQDLfeuA',
+ 'lastone.zn': '1LJ3r1Zf1F3qFXw3E4QBvgaNzsFhAixQL2',
+ '0clock.yo': '1zatLeyRNeBoYfFJP3j9Jywwcz68fheR6',
+ 'ns-game.yu': '12bD4na9Ux7fbfzcmfBRuLWbjMWTAiuaLk',
+ 'ns-game.yo': '12bD4na9Ux7fbfzcmfBRuLWbjMWTAiuaLk',
+ 'ns-game.zn': '12bD4na9Ux7fbfzcmfBRuLWbjMWTAiuaLk',
+ '3dporno.yo': '16cYTZiW45hZ1tQCVVth5ZVqNe2ZZAWUFk',
+ '3dporno.zn': '16cYTZiW45hZ1tQCVVth5ZVqNe2ZZAWUFk',
+ 'krylov.zn': '127.0.0.1',
+ 'ns-game.of': '12bD4na9Ux7fbfzcmfBRuLWbjMWTAiuaLk',
+ 'ruzerotalk.yu': '1Apr5ba6u9Nz6eFASmFrefGvyBKkM76QgE',
+ 'ruzerotalk.zn': '1Apr5ba6u9Nz6eFASmFrefGvyBKkM76QgE',
+ '0clock.zn': '1zatLeyRNeBoYfFJP3j9Jywwcz68fheR6',
+ 'paper.yo': '1LJ3r1Zf1F3qFXw3E4QBvgaNzsFhAixQL2',
+ 'one.zn': '1LJ3r1Zf1F3qFXw3E4QBvgaNzsFhAixQL2',
+ 'ruzerotalk.yo': '1Apr5ba6u9Nz6eFASmFrefGvyBKkM76QgE',
+ 'gledos.zn': '12g7awE9MuhtHzv4o1PukjiaQdtvvbpxbP',
+ '3dporno.list': '16cYTZiW45hZ1tQCVVth5ZVqNe2ZZAWUFk',
+ 'zero-wiki-fr.zn': '135qYXdNpf5kTWYuTJ8uautsUi91Bhvcck',
+ '3dporno.inf': '16cYTZiW45hZ1tQCVVth5ZVqNe2ZZAWUFk',
+ '3dporno.of': '16cYTZiW45hZ1tQCVVth5ZVqNe2ZZAWUFk',
+ '3dporno.yu': '16cYTZiW45hZ1tQCVVth5ZVqNe2ZZAWUFk',
+ '2048.zn': '14CJiCfKCbALS3HnwfFV6GJ6ixXKdzDz2g',
+ 'gay.3dporno.zn': '1Gay3DR1K69PoqMukjShz9sPiWqUSLtVxt',
+ 'g6534gf546g5.yo': 'http://127.0.0.1:43110/Talk.ZeroNetwork.bit',
+ 'qqqqqqqqqqqqq.yo': 'qqqqqqqqq',
+ 'qqqqqqqqqqqqqqqqq.yo': 'qqqqqqqqqqqq',
+ 'qqqqqqqqqqqqqqqqqqqqqqq.yo': 'qqqqqqqqqqqqqqqqqqq',
+ 'xxx.list': '127.0.0.1',
+ 'kxonetwork.yo': '1GTVetvjTEriCMzKzWSP9FahYoMPy6BG1P',
+ 'shirukatutorials.yo': '1KGXoRuM7Q4rYHcTZod442HQhq95UEFW5',
+ 'tui.yu': '1BzpRTB6DHjdCkfSRW8sU2V5GuFMnhWkGK',
+ 'filips.yo': 'TODO',
+ 'donda.yo': '17dqsM2zdrkAn2HGPxad6sExBut8U3cajc',
+ 'ua.list': '1UkrrSpnJmuiig6r5v88Kn3isaR64Fbh3',
+ 'zeroframe.zn': 'TODO',
+ 'peermessage.zn': 'TODO, mail gitcenter@mail.zeronetwork.bit if this TODO has been here for a year',
+ 'kaffie.zn': '1A83ijw3boqTtqdLz8me7AqeK1nEK8yxeu',
+ 'kaffiene.zn': '1Mr5rX9TauvaGReB4RjCaE6D37FJQaY5Ba',
+ 'blog.kaffie.zn': '1N6zp6jCXPBktNMPfe7UJBpQGyfCq7k2M8',
+ 'spam.list': '1CufK1ZtvekbFXEpSyKT2gDjf9jnqW8KwG',
+ 'news.zn': '1NEwsvyrAoEWU64ZozwdfgEUQhwxiCrh1t',
+ 'galleries.zn': '1PGaLLNiadMzrmw6MMMnpZnskwFcdgZoS4',
+ 'block.list': '127.0.0.1',
+ 'black.list': '127.0.0.1',
+ 'white.list': '127.0.0.1',
+ 'shit.list': '127.0.0.1',
+ 'galleryhub.zn': '14NFfVBBAFbNdqX4nyGjyBF1BRSz7jn2QP',
+ 'anshorei.zn': '13T79X7tG8Fi3EZCev3xU1wYTtFHHnqWGQ',
+ 'play.zn': '1Ag6xidDHiPgWoDKhfSx4xFQr6WC3NqxZg',
+ 'arkid.zn': 'ARKidcu9P7HTpig7htMsxTgEuUAp3h34qg',
+ 'kxoid.zn': '12F5SvxoPR128aiudte78h8pY7mobroG6V',
+ 'vacation.zn': '1HcLPSR5ss1ehsqP8kU2Sa2TJyDVcGADTp',
+ 'alotaplot.zn': '1G8VWDQc5fXLkRiijJB4EZerDLmDVY75MZ',
+ 'monitor.peermessage.zn': '1E7AmfXMkfbV2Gg83Harp4PHan7BdvSuEg',
+ 'hentaitalk.zn': '1KcWtJi2YSvL9DwouGymLZPKy9N6rTGXLt',
+ 'anthology.zn': 'TODO Anthology.jp/zn releasing later this year',
+ 'p.zn': '1PLAYgDQboKojowD3kwdb3CtWmWaokXvfp',
+ 'polbooks.zn': '1BGYb8Qyq5ApUG6ZNkASczzePf8c87Li82',
+ 'anshorei.yu': '13T79X7tG8Fi3EZCev3xU1wYTtFHHnqWGQ',
+ 'gohzer.yo': 'localhost',
+ 'sw0gger.yo': 'localhost',
+ 'name.yo': '1NAMEz7stUPZErkV1d3yLkVWQFa4PTqDNv',
+ 'kiwipedia.yo': '1KiwiBCVBUcuypVm8FEmUW9YT6fJDXkN9r',
+ 'gitcenter.yo': '1GitLiXB6t5r8vuU2zC6a8GYj9ME6HMQ4t',
+ 'index.gitcenter.yo': '1iNDExENNBsfHc6SKmy1HaeasHhm3RPcL',
+ 'repo.gitcenter.yo': '1RepoXU8bQE9m7ssNwL4nnxBnZVejHCc6',
+ 'ivanq.yu': '1FwH89xyniDgy3t6fCWrggLs22MnGPZ5K5',
+ 'zplace.yo': '1D6f2CvDRhPeEeBAcmqGt3X9z2CkLpmv2V',
+ 'coder.yo': '1CodEr7T9xNXSPcwbsvf5fHTqsixDMwDzL',
+ 'sands.yo': '1M6a1JXxdYWjNXZUuFk4SJdG5xWRRjBU4a',
+ 'gc.yo': 'reserved',
+ 'zeroup.balancer.yu': '1J8rt5k5QPLmAtRw5QAGmgKxi4qC7Lk166',
+ 'talk.balancer.yu': '15zr8fG5h9FZu6dt5CC9kQ1F7PMpiGu6Tm',
+ 'diy.balancer.yu': '1ApsfuUfnyJm19qZguDzzqj7se41Ggxzrt',
+ 'zeronet.balancer.yu': '1PxNZqJ3R3aUt171foqtzbhgZZ6JaggaAi',
+ 'military.balancer.yu': '14UqHSCXV6mF5UKcqg1cR7eg4uUPCSGZtP',
+ 'wiki.balancer.yu': '1NbzP9dgYhuY71bde9G1LuVGaCE69venzR',
+ 'flood.balancer.yu': '1GmoFQHVjYj4xDZZ5oMNnkGhvnfY1w3pPM',
+ 'blocklist.balancer.yu': '1HnyzU52qiJBW4LxHHzDJHiTceWrqMhh69',
+ 'pol.balancer.yu': '17ogL1aD6546DYwtb6UnMhF4hETaHBj6yD',
+ 'balancer.yu': '1MaQ4W5D6G52TpBfPACU9k9QcB1DxvHZ5v',
+ 'en.balancer.yu': '144W6itCd6jUqHDx5SDjbFaRdTnh4gRBBA',
+ 'mem.balancer.yu': '1BFvnf2QHmMsjZ8dnfT89WfW8mVX7FrQj7',
+ 'micro.balancer.yu': '1bmicr2VRXvcGZ8xE4bvtuhfvQRhfquAf',
+ 'infonesy.balancer.yu': '1GQkPB8mFgxH7GQQbkNPJtvRaZZpVi65u1',
+ 'info.balancer.yu': '18i1Ra9wePfmwhMCyhmLXXShxcSha5YAns',
+ 'tanzpol.balancer.yu': '1Anxiq4y8oJUBisB7igP8jKQNK1DPGiSR1',
+ 'bors.balancer.yu': '1AdhUSJLmpUE7Aq5nPBkUuxgcWaUfqtS84',
+ 'kaliningrad.balancer.yu': '1kgdheAxeoeK6R7MMmTV6neAihUYf9pJ1',
+ 'lor.yo': '1BpFtPez7mSiShtXfb4wPfMT1dZTuRybfZ',
+ 'airbase.yo': '1Jb5ZdmvTzVnHpa2hayjQk3H2kZgNVbmBb',
+ 'infonesy.yo': '1F4WVHDpQYxuJL6xEY3EZTYkZds9TTjVHC',
+ 'in.yu': '127.0.0.1',
+ 'of.yu': '127.0.0.1',
+ 'chan.yo': '1ADQAHsqsie5PBeQhQgjcKmUu3qdPFg6aA',
+ 'thunderwave.yo': '1CWkZv7fQAKxTVjZVrLZ8VHcrN6YGGcdky',
+ 'thundote.yo': '14PEBop2eFFvYFv2D3owaBpb98nsW7BCLH',
+ 'lightstar.yu': '1MdwanV12uDDiVsgrsifDFdSsigLRD9dzu',
+ 'zerolstn.yo': '1MQveQ3RPpimXX2wjW2geAGkNJ1GdXkvJ3',
+ 'xiamis.yo': '16KpwxZmLs4XzdJrjwBguxFNqhFmnMbZYQ',
+ 'xiamis.yu': '16KpwxZmLs4XzdJrjwBguxFNqhFmnMbZYQ',
+ 'h.yo': '19WTvkdL8rUnAqZNtg3XaPTiDsCAcc22eB',
+ 'kxonet.yo': '1GTVetvjTEriCMzKzWSP9FahYoMPy6BG1P',
+ 'ucadia.yo': 'ucadia',
+ 'fuck.yu': '127.0.0.1',
+ 'scru.yu': '127.0.0.1',
+ 'crazy.yo': '1NtQvrYd8rJzQYP3j1snmi28mPn8wSXX4X',
+ 'crazy.yu': '1NtQvrYd8rJzQYP3j1snmi28mPn8wSXX4X',
+ 'peerco.yo': '147RqkK3WP9FXJq4fXxSKjojYHw4Wrmy8A',
+ 'crazy.of': '1NtQvrYd8rJzQYP3j1snmi28mPn8wSXX4X',
+ 'crazy.inf': '1NtQvrYd8rJzQYP3j1snmi28mPn8wSXX4X',
+ 'crazy.zn': '1NtQvrYd8rJzQYP3j1snmi28mPn8wSXX4X',
+ 'crazy.list': '1NtQvrYd8rJzQYP3j1snmi28mPn8wSXX4X',
+ 'tcjy.zn': '134Lv2kVHAynALDkFaP98mia1JKr4gxc3N',
+ 'emnet.zn': '16JySL65beXjeEjrhBQgosWg7tQwuNq93L',
+ 'vdmnet.zn': '1G5RZoqRh4NTwq6v9KF1AZ8woVfuNRFsrr',
+ 'mg0.zn': '1D6QfsBSZHmYWbuCxKG5ya31BiTczoZiES',
+ 'rexresearch.zn': '1D6QfsBSZHmYWbuCxKG5ya31BiTczoZiES',
+ 'timvanduin.zn': '1HZwkjkeaoZfTSaJxDw6aKkxp45agDiEzN',
+ 'vendelinek.yo': '1DBc3iFh94wdqmMhjBjh1wpYBc64wq2t4o',
+ 'fantpril.zn': '1N77kxgd29cR8w9xt481JDJEtYdX1hCqAR',
+ 'fantpril.yo': '1N77kxgd29cR8w9xt481JDJEtYdX1hCqAR',
+ 'fantpril.yu': '1N77kxgd29cR8w9xt481JDJEtYdX1hCqAR',
+ 'fantpril.of': '1N77kxgd29cR8w9xt481JDJEtYdX1hCqAR',
+ 'fantpril.inf': '1N77kxgd29cR8w9xt481JDJEtYdX1hCqAR',
+ 'fantpril.list': '1N77kxgd29cR8w9xt481JDJEtYdX1hCqAR',
+ 'zn.zn': '1N77kxgd29cR8w9xt481JDJEtYdX1hCqAR',
+ 'yo.yo': '1N77kxgd29cR8w9xt481JDJEtYdX1hCqAR',
+ 'yu.yu': '1N77kxgd29cR8w9xt481JDJEtYdX1hCqAR',
+ 'of.of': '1N77kxgd29cR8w9xt481JDJEtYdX1hCqAR',
+ 'inf.inf': '1N77kxgd29cR8w9xt481JDJEtYdX1hCqAR',
+ 'list.list': '1N77kxgd29cR8w9xt481JDJEtYdX1hCqAR',
+ 'zilizili.zn': '127.0.0.1',
+ 'kaffie.it': '1A83ijw3boqTtqdLz8me7AqeK1nEK8yxeu',
+ 'kaffiene.it': '1Mr5rX9TauvaGReB4RjCaE6D37FJQaY5Ba',
+ 'kaffie.me': '1A83ijw3boqTtqdLz8me7AqeK1nEK8yxeu',
+ 'search.it': '1Mr5rX9TauvaGReB4RjCaE6D37FJQaY5Ba',
+ 'vendelinek.yu': '1DBc3iFh94wdqmMhjBjh1wpYBc64wq2t4o',
+ 'zerotalk.peerco.yo': '1LUrvRXuPxH5ENgWeCbhrpUYfxCwnFYFDJ',
+ 'zerome.peerco.yo': '1KjwPbyQTYgmLGJZZH25ZGGrCYrH2ULVVv',
+ 'myzeroblog.peerco.yo': '1Dtm44Lz74NzdPsEyG4rvXpC9rgojHeYGY',
+ 'youtube.peerco.yo': '18GzzygX2uFDxrHmV1kUfKpPPY2FDMz7YF',
+ 'helblindi.yu': 'reserved',
+ 'myzerowiki.peerco.yo': '1QK2jJrdG3qqgXidd9eW6d81TfLqGCXhoe',
+ 'google.yo': '1Mr5rX9TauvaGReB4RjCaE6D37FJQaY5Ba',
+ 'google.yu': '1Mr5rX9TauvaGReB4RjCaE6D37FJQaY5Ba',
+ 'google.of': '1Mr5rX9TauvaGReB4RjCaE6D37FJQaY5Ba',
+ 'google.inf': '1Mr5rX9TauvaGReB4RjCaE6D37FJQaY5Ba',
+ 'google.zn': '1Mr5rX9TauvaGReB4RjCaE6D37FJQaY5Ba',
+ 'google.list': '1Mr5rX9TauvaGReB4RjCaE6D37FJQaY5Ba',
+ 'o.of': '127.0.0.1',
+ 'pill.zn': '17p9vyd7FXm7FMgrirNeKKc3dXnp9dMD4q',
+ 'zerogamingtalking.yo': '1J789oNvwoawy3xjfhfxEfvTeNk61JYf4Y',
+ 'zerogamingtalk.yo': '1J789oNvwoawy3xjfhfxEfvTeNk61JYf4Y',
+ 'zerogamingtalk.yu': '1J789oNvwoawy3xjfhfxEfvTeNk61JYf4Y',
+ 'zerogamingtalk.of': '1J789oNvwoawy3xjfhfxEfvTeNk61JYf4Y',
+ 'zerogamingtalk.inf': '1J789oNvwoawy3xjfhfxEfvTeNk61JYf4Y',
+ 'zerogamingtalk.zn': '1J789oNvwoawy3xjfhfxEfvTeNk61JYf4Y',
+ 'zerogamingtalk.list': '1J789oNvwoawy3xjfhfxEfvTeNk61JYf4Y',
+ 'zerochatplus.yo': '1FbZQrfoXk4JkbtnAjt1FiyKTTAoECug7r',
+ 'zerositesplus.yo': '1NcCnWssDSyP7xja9rDMGrEwUWDdCSC9n2',
+ 'zerogamingtalkplus.yo': '1J789oNvwoawy3xjfhfxEfvTeNk61JYf4Y',
+ 'nickwawebtorrent.yo': '1HZBz6gsiPgYCJFD7MvBUZ5jKUt5Ag8dTF',
+ 'zerogamingtalkplus.yu': '1J789oNvwoawy3xjfhfxEfvTeNk61JYf4Y',
+ 'zerogamingtalkplus.of': '1J789oNvwoawy3xjfhfxEfvTeNk61JYf4Y',
+ 'zerogamingtalkplus.inf': '1J789oNvwoawy3xjfhfxEfvTeNk61JYf4Y',
+ 'zerogamingtalkplus.zn': '1J789oNvwoawy3xjfhfxEfvTeNk61JYf4Y',
+ 'zerogamingtalkplus.list': '1J789oNvwoawy3xjfhfxEfvTeNk61JYf4Y',
+ 'tcjy.list': '127.0.0.1',
+ 'xn--ur0a479b.zn': '1HeLLo4uzjaLetFx6NH3PMwFP3qbRbTf3D',
+ 'xkcd.yo': '1XKCDh5XeLm5eN4jM8b1Mk4wKrnUJxV12',
+ 'fant.yo': '1N77kxgd29cR8w9xt481JDJEtYdX1hCqAR',
+ 'fant.yu': '1N77kxgd29cR8w9xt481JDJEtYdX1hCqAR',
+ 'fant.of': '1N77kxgd29cR8w9xt481JDJEtYdX1hCqAR',
+ 'fant.inf': '1N77kxgd29cR8w9xt481JDJEtYdX1hCqAR',
+ 'fant.zn': '1N77kxgd29cR8w9xt481JDJEtYdX1hCqAR',
+ 'fant.list': '1N77kxgd29cR8w9xt481JDJEtYdX1hCqAR',
+ 'mayvaneday.yo': '1MeeJWbbQHArbqD6UUHSjh9EVycvnTUBFa',
+ 'mayvaneday.yu': '1MeeJWbbQHArbqD6UUHSjh9EVycvnTUBFa',
+ 'mayvaneday.of': '1MeeJWbbQHArbqD6UUHSjh9EVycvnTUBFa',
+ 'mayvaneday.inf': '1MeeJWbbQHArbqD6UUHSjh9EVycvnTUBFa',
+ 'mayvaneday.zn': '1MeeJWbbQHArbqD6UUHSjh9EVycvnTUBFa',
+ 'mayvaneday.list': '1MeeJWbbQHArbqD6UUHSjh9EVycvnTUBFa',
+ 'arkhello.zn': 'AHeLLoZZeps5VTxmKvuD49AS7X9ruNy5C8',
+ 'r.yu': 'r.yu',
+ 'r.yo': 'r.yo',
+ 'r.zn': 'r.zn',
+ 'ark.zn': 'ark.zn',
+ 'ark.list': 'ark.list',
+ 'audiobooks.zn': '1N77kxgd29cR8w9xt481JDJEtYdX1hCqAR',
+ 'audiobooks.list': '1N77kxgd29cR8w9xt481JDJEtYdX1hCqAR',
+ 'audiobooks.inf': '1N77kxgd29cR8w9xt481JDJEtYdX1hCqAR',
+ 'audiobooks.of': '1N77kxgd29cR8w9xt481JDJEtYdX1hCqAR',
+ 'mfs.zn': '1PSckqU7wo7oyALSWpePxUEmLpv3K6fwYb',
+ 'myzlog.zn': '1N7fJq4Ka65jpSpf9X2xf1YcCSqdCBdoc6',
+ 'fuk.yu': '1N7fJq4Ka65jpSpf9X2xf1YcCSqdCBdoc6',
+ 'guidovon.list': '1N7fJq4Ka65jpSpf9X2xf1YcCSqdCBdoc6',
+ 'a.zn': 'bicatpfsdeoco42pm5hcqsoo72x4gnfd6u7kpsamyve5c5ufuyea.b32.i2p',
+ 'doxbin.yo': '1DoxbinuaNEdDagSpPmbCEkKHB1FW9RzzJ',
+ 'zerodox.yo': '1DoxbinuaNEdDagSpPmbCEkKHB1FW9RzzJ',
+ 'zerodox.zn': '1DoxbinuaNEdDagSpPmbCEkKHB1FW9RzzJ',
+ 'doxbin.zn': '1DoxbinuaNEdDagSpPmbCEkKHB1FW9RzzJ',
+ '08chan.yo': '1DdPHedr5Tz55EtQWxqvsbEXPdc4uCVi9D',
+ '08chan.zn': '1DdPHedr5Tz55EtQWxqvsbEXPdc4uCVi9D',
+ '8chan.yo': '1DdPHedr5Tz55EtQWxqvsbEXPdc4uCVi9D',
+ '8chan.zn': '1DdPHedr5Tz55EtQWxqvsbEXPdc4uCVi9D',
+ '8ch.yo': '1DdPHedr5Tz55EtQWxqvsbEXPdc4uCVi9D',
+ '8ch.zn': '1DdPHedr5Tz55EtQWxqvsbEXPdc4uCVi9D',
+ '8.yo': '1DdPHedr5Tz55EtQWxqvsbEXPdc4uCVi9D',
+ '8.zn': '1DdPHedr5Tz55EtQWxqvsbEXPdc4uCVi9D',
+ '08.zn': '1DdPHedr5Tz55EtQWxqvsbEXPdc4uCVi9D',
+ '08.yo': '1DdPHedr5Tz55EtQWxqvsbEXPdc4uCVi9D',
+ 'millchan.yo': '1ADQAHsqsie5PBeQhQgjcKmUu3qdPFg6aA',
+ 'millchan.zn': '1ADQAHsqsie5PBeQhQgjcKmUu3qdPFg6aA',
+ 'mill.yo': '1ADQAHsqsie5PBeQhQgjcKmUu3qdPFg6aA',
+ 'mill.zn': '1ADQAHsqsie5PBeQhQgjcKmUu3qdPFg6aA',
+ 'hello.zn': '1HeLLo4uzjaLetFx6NH3PMwFP3qbRbTf3D',
+ 'hello.yo': '1HeLLo4uzjaLetFx6NH3PMwFP3qbRbTf3D',
+ 'me.yo': '1FantoiURYdv9he66jhcMvmqy96oVEppVK',
+ 'me.zn': '1FantoiURYdv9he66jhcMvmqy96oVEppVK',
+ 'fanto.yo': '1FantoiURYdv9he66jhcMvmqy96oVEppVK',
+ 'fanto.zn': '1FantoiURYdv9he66jhcMvmqy96oVEppVK',
+ 'fantoski.yo': '1FantoiURYdv9he66jhcMvmqy96oVEppVK',
+ 'fantoski.zn': '1FantoiURYdv9he66jhcMvmqy96oVEppVK',
+ '0.yo': '1FantoiURYdv9he66jhcMvmqy96oVEppVK',
+ '0.yu': '1FantoiURYdv9he66jhcMvmqy96oVEppVK',
+ '0.of': '1FantoiURYdv9he66jhcMvmqy96oVEppVK',
+ '0.inf': '1FantoiURYdv9he66jhcMvmqy96oVEppVK',
+ '0.zn': '1FantoiURYdv9he66jhcMvmqy96oVEppVK',
+ '0.list': '1FantoiURYdv9he66jhcMvmqy96oVEppVK',
+ 'zero.yo': '1FantoiURYdv9he66jhcMvmqy96oVEppVK',
+ 'zero.yu': '1FantoiURYdv9he66jhcMvmqy96oVEppVK',
+ 'zero.of': '1FantoiURYdv9he66jhcMvmqy96oVEppVK',
+ 'zero.inf': '1FantoiURYdv9he66jhcMvmqy96oVEppVK',
+ 'zero.zn': '1FantoiURYdv9he66jhcMvmqy96oVEppVK',
+ 'zero.list': '1FantoiURYdv9he66jhcMvmqy96oVEppVK',
+ 'porn.yo': '1NZNtZQZHQRJXafvJpmY5jgqwRaCEZMsUc',
+ 'porn.yu': '1NZNtZQZHQRJXafvJpmY5jgqwRaCEZMsUc',
+ 'porn.of': '1NZNtZQZHQRJXafvJpmY5jgqwRaCEZMsUc',
+ 'porn.inf': '1NZNtZQZHQRJXafvJpmY5jgqwRaCEZMsUc',
+ 'porn.zn': '1NZNtZQZHQRJXafvJpmY5jgqwRaCEZMsUc',
+ 'porn.list': '1NZNtZQZHQRJXafvJpmY5jgqwRaCEZMsUc',
+ 'sex.yo': '1NZNtZQZHQRJXafvJpmY5jgqwRaCEZMsUc',
+ 'sex.yu': '1NZNtZQZHQRJXafvJpmY5jgqwRaCEZMsUc',
+ 'sex.of': '1NZNtZQZHQRJXafvJpmY5jgqwRaCEZMsUc',
+ 'sex.inf': '1NZNtZQZHQRJXafvJpmY5jgqwRaCEZMsUc',
+ 'sex.zn': '1NZNtZQZHQRJXafvJpmY5jgqwRaCEZMsUc',
+ 'sex.list': '1NZNtZQZHQRJXafvJpmY5jgqwRaCEZMsUc',
+ 'robloxo.of': 'bicatpfsdeoco42pm5hcqsoo72x4gnfd6u7kpsamyve5c5ufuyea.b32.i2p',
+ 'reasonsilovemyniece.list': '1N7fJq4Ka65jpSpf9X2xf1YcCSqdCBdoc6',
+ 'purpleblog.zn': 'http://127.0.0.1:43110/1LcAzdXV162HNrNFm77uVihYzWwthGM2vr/',
+ 'abooks.yo': '1N77kxgd29cR8w9xt481JDJEtYdX1hCqAR',
+ 'abooks.yu': '1N77kxgd29cR8w9xt481JDJEtYdX1hCqAR',
+ 'abooks.of': '1N77kxgd29cR8w9xt481JDJEtYdX1hCqAR',
+ 'abooks.inf': '1N77kxgd29cR8w9xt481JDJEtYdX1hCqAR',
+ 'abooks.zn': '1N77kxgd29cR8w9xt481JDJEtYdX1hCqAR',
+ 'abooks.list': '1N77kxgd29cR8w9xt481JDJEtYdX1hCqAR',
+ 'audiobooks.yo': '1N77kxgd29cR8w9xt481JDJEtYdX1hCqAR',
+ 'audiobooks.yu': '1N77kxgd29cR8w9xt481JDJEtYdX1hCqAR',
+ 'kusoneko.yo': '1JT1qoXhg4JugdzXVnGcV6gaiXX3P4LwSj',
+ 'kusoneko.yu': '1JT1qoXhg4JugdzXVnGcV6gaiXX3P4LwSj',
+ 'kusoneko.of': '1JT1qoXhg4JugdzXVnGcV6gaiXX3P4LwSj',
+ 'kusoneko.inf': '1JT1qoXhg4JugdzXVnGcV6gaiXX3P4LwSj',
+ 'kusoneko.zn': '1JT1qoXhg4JugdzXVnGcV6gaiXX3P4LwSj',
+ 'kusoneko.list': '1JT1qoXhg4JugdzXVnGcV6gaiXX3P4LwSj',
+ 'blog.kusoneko.yo': '1JT1qoXhg4JugdzXVnGcV6gaiXX3P4LwSj',
+ 'blog.kusoneko.yu': '1JT1qoXhg4JugdzXVnGcV6gaiXX3P4LwSj',
+ 'blog.kusoneko.of': '1JT1qoXhg4JugdzXVnGcV6gaiXX3P4LwSj',
+ 'blog.kusoneko.inf': '1JT1qoXhg4JugdzXVnGcV6gaiXX3P4LwSj',
+ 'blog.kusoneko.zn': '1JT1qoXhg4JugdzXVnGcV6gaiXX3P4LwSj',
+ 'blog.kusoneko.list': '1JT1qoXhg4JugdzXVnGcV6gaiXX3P4LwSj',
+ 'id.kusoneko.yo': '1223AWa3Xikhn3q1d2UmCBx1NeJYx7tvE1',
+ 'id.kusoneko.yu': '1223AWa3Xikhn3q1d2UmCBx1NeJYx7tvE1',
+ 'id.kusoneko.of': '1223AWa3Xikhn3q1d2UmCBx1NeJYx7tvE1',
+ 'id.kusoneko.inf': '1223AWa3Xikhn3q1d2UmCBx1NeJYx7tvE1',
+ 'id.kusoneko.zn': '1223AWa3Xikhn3q1d2UmCBx1NeJYx7tvE1',
+ 'id.kusoneko.list': '1223AWa3Xikhn3q1d2UmCBx1NeJYx7tvE1',
+ 'tcmeta.yo': '15tek1Cg2VshZ7Hkxi97P27TYtdNpA5v5d',
+ 'obermui.yo': '15VuKHSRKpgyGAX87mCHYF2L95vad33SPY',
+ 'obermui.inf': '15VuKHSRKpgyGAX87mCHYF2L95vad33SPY',
+ 'obermui.zn': '15VuKHSRKpgyGAX87mCHYF2L95vad33SPY',
+ 'obermui.list': '15VuKHSRKpgyGAX87mCHYF2L95vad33SPY',
+ 'obermui.of': '15VuKHSRKpgyGAX87mCHYF2L95vad33SPY',
+ 'obermui.yu': '15VuKHSRKpgyGAX87mCHYF2L95vad33SPY',
+ '0sh.yo': '1GNTAKCimBv5xEnt7QvkDn8sTkEPj7ZYTL',
+ 'hk.yo': '1tADtGnuPx5wBbxP5dosqcAt82PitUmKZ',
+ 'furry.yo': '16Bbqixe9ABsyhueWLBKwQXEWdCF6ARoSQ',
+ 'regularflolloping.yo': 'null',
+ 'regularflolloping.yu': 'null',
+ 'regularflolloping.of': 'null',
+ 'regularflolloping.inf': 'null',
+ 'regularflolloping.zn': 'null',
+ 'regularflolloping.list': 'null',
+ 'zeronetia.yo': '12xozBV7dYskrNQ2G5srnzsTgStaX6Coph',
+ 'china.yo': '1CuGFe64XH3XLCiEPkSkwRprrfqZzdAjpp',
+ '1024.yo': '1CuGFe64XH3XLCiEPkSkwRprrfqZzdAjpp',
+ 'usa.yo': '1CuGFe64XH3XLCiEPkSkwRprrfqZzdAjpp',
+ 'cn.yo': '1CuGFe64XH3XLCiEPkSkwRprrfqZzdAjpp',
+ 'chinese.yo': '1CuGFe64XH3XLCiEPkSkwRprrfqZzdAjpp',
+ 'dinucentra.yo': '1AFwap4UEsTP5gvnzw5byRcTHGxSWCaRWA',
+ 'dinucentra.yu': '1AFwap4UEsTP5gvnzw5byRcTHGxSWCaRWA',
+ 'dinucentra.of': '1AFwap4UEsTP5gvnzw5byRcTHGxSWCaRWA',
+ 'dinucentra.inf': '1AFwap4UEsTP5gvnzw5byRcTHGxSWCaRWA',
+ 'dinucentra.zn': '1AFwap4UEsTP5gvnzw5byRcTHGxSWCaRWA',
+ 'dinucentra.list': '1AFwap4UEsTP5gvnzw5byRcTHGxSWCaRWA',
+ 'kxovid.yo': '14c5LUN73J7KKMznp9LvZWkxpZFWgE1sDz',
+ 'x.thunderwave.yo': '1LdeDdtifLpRwizQkzYmWWVuUpuDhrGz4f',
+ 'bigtable.yo': '1FxEVWeV5MjWXD1b4JtRcqj6piXvNbRjbJ',
+ 'bigtable.of': '1FxEVWeV5MjWXD1b4JtRcqj6piXvNbRjbJ',
+ 'spyware.inf': '1SpyWkvtp8bXz5x7K8EreCBt23tUaoXgz',
+ 'domenicotoscano.yo': '1Bo3BB2J9KipLxrkZ4RWBdTCoHgMwMXYR4',
+ 'cyberbuddah.yo': '1FH3PnVUkgYt1EaFnYDbw7V6QHSAofPPBX',
+ 'kave.yo': 'http://127.0.0.1:43110/1KN5zRytGbGqLNdemuoLC6gS44fwM9h38s/',
+ 'moab.list': 'http://127.0.0.1:43110/1LgqZfbtr6dukbjHdjWBEmmthq1shEv3y1/',
+ 'syncronite.yo': 'http://127.0.0.1:43110/15CEFKBRHFfAP9rmL6hhLmHoXrrgmw4B5o/',
+ 'app0.yo': 'http://127.0.0.1:43110/1E7wdLyfWBZAJoPtk7t7dxBAdVFDkWpKrX/',
+ 'live.list': '166qaA2XQYrdEEyTBm2xgAN9AWEhtJrES3',
+ 'live.of': '166qaA2XQYrdEEyTBm2xgAN9AWEhtJrES3',
+ 'live.zn': '166qaA2XQYrdEEyTBm2xgAN9AWEhtJrES3',
+ 'fashion.list': '166qaA2XQYrdEEyTBm2xgAN9AWEhtJrES3',
+ 'fashion.yo': '166qaA2XQYrdEEyTBm2xgAN9AWEhtJrES3',
+ 'fashion.zn': '166qaA2XQYrdEEyTBm2xgAN9AWEhtJrES3',
+ 'taobao.zn': '166qaA2XQYrdEEyTBm2xgAN9AWEhtJrES3',
+ 'taobao.list': '166qaA2XQYrdEEyTBm2xgAN9AWEhtJrES3',
+ 'amazon.list': '166qaA2XQYrdEEyTBm2xgAN9AWEhtJrES3',
+ 'amazon.yo': '166qaA2XQYrdEEyTBm2xgAN9AWEhtJrES3',
+ 'link.yo': '1LinksxxdxzzmqSYH3nF2Diwq4xrdMK3MH',
+ 'link.yu': '1LinksxxdxzzmqSYH3nF2Diwq4xrdMK3MH',
+ 'link.zn': '1LinksxxdxzzmqSYH3nF2Diwq4xrdMK3MH',
+ 'link.of': '1NAMEz7stUPZErkV1d3yLkVWQFa4PTqDNv',
+ 'link.inf': '1LinksxxdxzzmqSYH3nF2Diwq4xrdMK3MH',
+ 'link.list': '1LinksxxdxzzmqSYH3nF2Diwq4xrdMK3MH',
+ 'links.yo': '1LinksxxdxzzmqSYH3nF2Diwq4xrdMK3MH',
+ 'links.yu': '1LinksxxdxzzmqSYH3nF2Diwq4xrdMK3MH',
+ 'links.of': '1LinksxxdxzzmqSYH3nF2Diwq4xrdMK3MH',
+ 'links.inf': '1LinksxxdxzzmqSYH3nF2Diwq4xrdMK3MH',
+ 'links.zn': '1LinksxxdxzzmqSYH3nF2Diwq4xrdMK3MH',
+ 'links.list': '1LinksxxdxzzmqSYH3nF2Diwq4xrdMK3MH',
+ 'start.list': '1HeLLo4uzjaLetFx6NH3PMwFP3qbRbTf3D',
+ 'zerowikiuk.zn': '1Ewfx8U1QvPs61QoKvoCdx775CLv1xbC7',
+ 'js.zeroframe.zn': '1HJS6quLaqNLYxHVM9nL2rfmAsRvumqC1H',
+ 'py.zeroframe.zn': '178UMrEt8vxf5Z6LPxkrcWFPXPfD9XNNH7',
+ 'zero86.yo': '1z86z5jCaCQpgabfbQFJTLcKBLJdTtGYD',
+ 'dreamworks.yo': '1JBFNPrAGp1nQX6RsAN6oRqCfvtoeWoion',
+ 'id.emnet.zn': '15abcKj3RQn7LYDvTt55rc8ZmNwQLqHu5q',
+ 'lianna.yo': '1LiannAaMFCegAwz3dNUpRAC9Zj5XeAJjA',
+ 'lianna.yu': '1LiannAaMFCegAwz3dNUpRAC9Zj5XeAJjA',
+ 'lianna.of': '1LiannAaMFCegAwz3dNUpRAC9Zj5XeAJjA',
+ 'lianna.inf': '1LiannAaMFCegAwz3dNUpRAC9Zj5XeAJjA',
+ 'lianna.zn': '1LiannAaMFCegAwz3dNUpRAC9Zj5XeAJjA',
+ 'lianna.list': '1LiannAaMFCegAwz3dNUpRAC9Zj5XeAJjA',
+ 'javadoc12.yo': '12nKKTRJUmAvBL4WrNMAda5Sm58vNqjgU4',
+ 'streamz.yo': '1BTZh5pymEKzMYr3qgDtgr4dMmap77QvEs',
+ 'sogola.yo': '15CTUyQvz1qT4dqjWT2Wmd4XbV5hesrMtL',
+ 'schizo.yo': '15Aj7PkCPHfCHqNFUnEMoKBDwqHAJ7b9Q6',
+ 'wakaranai.yo': '17inszH5US5BfQMg66ChXSaT3oFKYAmGa1',
+ 'up.wakaranai.yo': '1VRSozLAjUfrdk8CN3coECyHckXqfmXww',
+ 'auth.wakaranai.yo': '1Evwaps3GXZJ6a78QBNaReHbVAucjZW2Dn',
+ 'mars.yo': '1MrwmugtdphP3CfYxXEgdefyjJV3LKMsW2',
+ 'mars.yu': '1MrwmugtdphP3CfYxXEgdefyjJV3LKMsW2',
+ 'mars.of': '1MrwmugtdphP3CfYxXEgdefyjJV3LKMsW2',
+ 'mars.inf': '1MrwmugtdphP3CfYxXEgdefyjJV3LKMsW2',
+ 'mars.zn': '1MrwmugtdphP3CfYxXEgdefyjJV3LKMsW2',
+ 'mars.list': '1MrwmugtdphP3CfYxXEgdefyjJV3LKMsW2',
+ 'marusu.yo': '1MrwmugtdphP3CfYxXEgdefyjJV3LKMsW2',
+ 'marusu.yu': '1MrwmugtdphP3CfYxXEgdefyjJV3LKMsW2',
+ 'marusu.of': '1MrwmugtdphP3CfYxXEgdefyjJV3LKMsW2',
+ 'marusu.inf': '1MrwmugtdphP3CfYxXEgdefyjJV3LKMsW2',
+ 'marusu.zn': '1MrwmugtdphP3CfYxXEgdefyjJV3LKMsW2',
+ 'marusu.list': '1MrwmugtdphP3CfYxXEgdefyjJV3LKMsW2',
+ 'aytolis.yo': 'reserved',
+ 'aytolis.yu': 'reserved',
+ 'aytolis.of': 'reserved',
+ 'aytolis.inf': 'reserved',
+ 'aytolis.zn': 'reserved',
+ 'aytolis.list': 'reserved',
+ 'iodine.yo': '16QJqCTaNceFbosyCP1deKqzWwT9BwYH3E',
+ 'iodine.yu': '16QJqCTaNceFbosyCP1deKqzWwT9BwYH3E',
+ 'iodine.of': '16QJqCTaNceFbosyCP1deKqzWwT9BwYH3E',
+ 'iodine.inf': '16QJqCTaNceFbosyCP1deKqzWwT9BwYH3E',
+ 'iodine.zn': '16QJqCTaNceFbosyCP1deKqzWwT9BwYH3E',
+ 'iodine.list': '16QJqCTaNceFbosyCP1deKqzWwT9BwYH3E',
+ 'cetra.yo': 'reserved',
+ 'cetra.yu': 'reserved',
+ 'cetra.of': 'reserved',
+ 'cetra.inf': 'reserved',
+ 'cetra.zn': 'reserved',
+ 'cetra.list': 'reserved',
+ 'iodine.cetra.yo': '16QJqCTaNceFbosyCP1deKqzWwT9BwYH3E',
+ 'iodine.cetra.yu': '16QJqCTaNceFbosyCP1deKqzWwT9BwYH3E',
+ 'iodine.cetra.of': '16QJqCTaNceFbosyCP1deKqzWwT9BwYH3E',
+ 'iodine.cetra.inf': '16QJqCTaNceFbosyCP1deKqzWwT9BwYH3E',
+ 'iodine.cetra.zn': '16QJqCTaNceFbosyCP1deKqzWwT9BwYH3E',
+ 'iodine.cetra.list': '16QJqCTaNceFbosyCP1deKqzWwT9BwYH3E',
+ 'mars.cetra.yo': '1MrwmugtdphP3CfYxXEgdefyjJV3LKMsW2',
+ 'mars.cetra.yu': '1MrwmugtdphP3CfYxXEgdefyjJV3LKMsW2',
+ 'mars.cetra.of': '1MrwmugtdphP3CfYxXEgdefyjJV3LKMsW2',
+ 'mars.cetra.inf': '1MrwmugtdphP3CfYxXEgdefyjJV3LKMsW2',
+ 'mars.cetra.zn': '1MrwmugtdphP3CfYxXEgdefyjJV3LKMsW2',
+ 'mars.cetra.list': '1MrwmugtdphP3CfYxXEgdefyjJV3LKMsW2',
+ 'systemspace.yo': '182vtVTeNuSt62iQRTiUbdV5VJhzdLrc1W',
+ 'testanothernet.yo': '1LCSoFMccgL3RuUkXGfvz42QwmWNQeSwxW',
+ 'testzeronet.yo': '1LCSoFMccgL3RuUkXGfvz42QwmWNQeSwxW',
+ 'cqega.list': '127.0.0.1',
+ 'akapen.yo': 'http://127.0.0.1:43110/1G6sNT5QbsMQ1i8M53bV9T1CBfPH3BqgW1',
+ 'syncronite2.yo': '15CEFKBRHFfAP9rmL6hhLmHoXrrgmw4B5o',
+ 'systemspace.yu': 'null',
+ 'systemspace.of': 'null',
+ 'systemspace.inf': 'null',
+ 'systemspace.zn': 'null',
+ 'systemspace.list': 'null',
+ 'erin.yo': 'reserved',
+ 'erin.yu': 'reserved',
+ 'erin.of': 'reserved',
+ 'erin.inf': 'reserved',
+ 'erin.zn': 'reserved',
+ 'erin.list': 'reserved',
+ 'null.yo': '1LiannAaMFCegAwz3dNUpRAC9Zj5XeAJjA',
+ 'null.yu': '1LiannAaMFCegAwz3dNUpRAC9Zj5XeAJjA',
+ 'null.of': '1LiannAaMFCegAwz3dNUpRAC9Zj5XeAJjA',
+ 'null.inf': '1LiannAaMFCegAwz3dNUpRAC9Zj5XeAJjA',
+ 'null.zn': '1LiannAaMFCegAwz3dNUpRAC9Zj5XeAJjA',
+ 'null.list': '1LiannAaMFCegAwz3dNUpRAC9Zj5XeAJjA',
+ 'grave.yo': '1LiannAaMFCegAwz3dNUpRAC9Zj5XeAJjA',
+ 'grave.yu': '1LiannAaMFCegAwz3dNUpRAC9Zj5XeAJjA',
+ 'grave.of': '1LiannAaMFCegAwz3dNUpRAC9Zj5XeAJjA',
+ 'grave.inf': '1LiannAaMFCegAwz3dNUpRAC9Zj5XeAJjA',
+ 'grave.zn': '1LiannAaMFCegAwz3dNUpRAC9Zj5XeAJjA',
+ 'grave.list': '1LiannAaMFCegAwz3dNUpRAC9Zj5XeAJjA',
+ 'death.yo': '1LiannAaMFCegAwz3dNUpRAC9Zj5XeAJjA',
+ 'death.yu': '1LiannAaMFCegAwz3dNUpRAC9Zj5XeAJjA',
+ 'death.of': '1LiannAaMFCegAwz3dNUpRAC9Zj5XeAJjA',
+ 'death.inf': '1LiannAaMFCegAwz3dNUpRAC9Zj5XeAJjA',
+ 'death.zn': '1LiannAaMFCegAwz3dNUpRAC9Zj5XeAJjA',
+ 'death.list': '1LiannAaMFCegAwz3dNUpRAC9Zj5XeAJjA',
+ 'vclv.yo': '1MeeJWbbQHArbqD6UUHSjh9EVycvnTUBFa',
+ 'vclv.yu': '1MeeJWbbQHArbqD6UUHSjh9EVycvnTUBFa',
+ 'vclv.of': '1MeeJWbbQHArbqD6UUHSjh9EVycvnTUBFa',
+ 'vclv.inf': '1MeeJWbbQHArbqD6UUHSjh9EVycvnTUBFa',
+ 'vclv.zn': '1MeeJWbbQHArbqD6UUHSjh9EVycvnTUBFa',
+ 'vclv.list': '1MeeJWbbQHArbqD6UUHSjh9EVycvnTUBFa',
+ 'operapresto.yo': '1J3xKsavhVCXDA7VnZU2jsdY4Szbfa6AzN',
+ 'zeronetmobile.yo': '15UYrA7aXr2Nto1Gg4yWXpY3EAJwafMTNk',
+ 'zeronetmobile.zn': '15UYrA7aXr2Nto1Gg4yWXpY3EAJwafMTNk',
+ 'zeronetmobile.inf': '15UYrA7aXr2Nto1Gg4yWXpY3EAJwafMTNk',
+ 'zeronetmobile.of': '15UYrA7aXr2Nto1Gg4yWXpY3EAJwafMTNk',
+ 'zeronetmobile.yu': '15UYrA7aXr2Nto1Gg4yWXpY3EAJwafMTNk',
+ 'zeronetmobile.list': '15UYrA7aXr2Nto1Gg4yWXpY3EAJwafMTNk',
+ 'tcmeta.zn': '15tek1Cg2VshZ7Hkxi97P27TYtdNpA5v5d',
+ 'xcwosjw.zn': '1KAEyHUkv7xxMToKcUrEp4sP6yNTgoPCT8',
+ 'xcwosjw.yo': '15nQ3ZjGyKNZf4iSLfQGgbxkZQjPp7Tdap',
+ 'esperanto.yo': '1YwB6u3f9TUfre8H9scXkbPyeuMaJSJio',
+ 'esperanto.zn': '1YwB6u3f9TUfre8H9scXkbPyeuMaJSJio',
+ 'eo.zn': '1YwB6u3f9TUfre8H9scXkbPyeuMaJSJio',
+ 'eo.yo': '1YwB6u3f9TUfre8H9scXkbPyeuMaJSJio',
+ 'talk.esperanto.yo': '1YwB6u3f9TUfre8H9scXkbPyeuMaJSJio',
+ 'talk.esperanto.zn': '1YwB6u3f9TUfre8H9scXkbPyeuMaJSJio',
+ 'up.esperanto.yo': '12ZQUJ8yUka4h3gKNRq5LyCAH4tLxcTRWK',
+ 'up.esperanto.zn': '12ZQUJ8yUka4h3gKNRq5LyCAH4tLxcTRWK',
+ 'runpark.yo': '18M55ymFNbi6d2KSY7qTp7WuE7gJSyRaPW',
+ 'runpark.zn': '18M55ymFNbi6d2KSY7qTp7WuE7gJSyRaPW',
+ 'ru.zn': '1RuZntipLvXcLKFEjT6Fr7ZA3GuywYfr5',
+ 'ru.yo': '1RuZntipLvXcLKFEjT6Fr7ZA3GuywYfr5',
+ 'ihome.yo': '1Hw1Aa8JnQnUxs1fjBX4eT1vz7Ppow2NTU',
+ 'opennews.yo': '1Nowr5oVEdbU5ZTQBriRd2jJVj2vhsDJd4',
+ 'opennews.zn': '1Nowr5oVEdbU5ZTQBriRd2jJVj2vhsDJd4',
+ 'ailinux.inf': '67.210.147.173',
+ 'binchan2.yu': '1EiMAqhd6sMjPG2tznkkGXxhdwFBDdeqT9',
+ 'share.binchan2.yu': '1Dphm8Mth9WYN9fPm1yxj8Y4WhcKRhYXJJ',
+ 'gallery.binchan2.yu': '1D2C23aAoHeoJsvPjZZxS9bt3i93uRVfUP',
+ 'git.binchan2.yu': '13zzNGxEXDeLxHEGZdG3mE7G8dChf45LrV',
+ 'social.binchan2.yu': '1G9wPKCvqdzZVRzZizcsExhYufMpAxbh6U',
+ 'binchan.yu': '1EiMAqhd6sMjPG2tznkkGXxhdwFBDdeqT9',
+ 'gallery.binchan.yu': '1D2C23aAoHeoJsvPjZZxS9bt3i93uRVfUP',
+ 'git.binchan.yu': '13zzNGxEXDeLxHEGZdG3mE7G8dChf45LrV',
+ 'social.binchan.yu': '1G9wPKCvqdzZVRzZizcsExhYufMpAxbh6U',
+ 'share.binchan.yu': '1Dphm8Mth9WYN9fPm1yxj8Y4WhcKRhYXJJ',
+ 'srdsa.yo': 'http://127.0.0.1:43110/1Mv6N3tZD8txahjwRCKXWe5U86wWYzfnLB/',
+ 'strec.yo': '1D7ck8Ny1CrmBdWj3HgvkDj5azYqxfeRYG',
+ 'bunkerid.zn': '14NnbuAssiqZzYMwJJU3YQFVqg8FbXTTCH',
+ 'zeromeluna.yo': '1KKhuA3VHmMkbqK5zGfiXSG8cqPFts6TJH',
+ 'syncronite.zn': '15CEFKBRHFfAP9rmL6hhLmHoXrrgmw4B5o',
+ 'eternalword.inf': '1Mjd9zn88kNX1QEkFaq2MrWeMthnR15Fga',
+ 'moab.zn': '1LgqZfbtr6dukbjHdjWBEmmthq1shEv3y1',
+ 'app0.zn': '1E7wdLyfWBZAJoPtk7t7dxBAdVFDkWpKrX',
+ 'kave.zn': '1KN5zRytGbGqLNdemuoLC6gS44fwM9h38s',
+ 'zeromeluna.zn': '1KKhuA3VHmMkbqK5zGfiXSG8cqPFts6TJH',
+ 'kaftask.yo': '1PCceXgXcZqWZnxBvAJbUd5mnZE5FFx57t',
+ 'aassddff.yo': '157WDHELkDXEiejUonxka3UjetaMJi9bsK',
+ 'mu.aassddff.yo': '157WDHELkDXEiejUonxka3UjetaMJi9bsK',
+ 'pol.aassddff.yo': '17uqpm3ihgX955fqunzKWvbXytjYtUrxZd',
+ 'blog.kaftask.yo': '1EjXC6WCpvGarxhc762MKhevbCHgRepEdM',
+ 'qrcg.zn': '15mfebHgwT7DGkDqjg9Jc7PWGJdzLN3Keh',
+ 'lang.kaftask.yo': '15xWNd1GgK2rrk1xu1vrxyMHU5kmXUjAk1',
+ 'xmojtesting.yo': '47.97.230.153',
+ 'xerthes.yo': '1D6vw8r3vXbTsRWqzie9GHKZpFLLzXB6F7',
+ 'zmd.zn': '18QPAtqyoxriNcNAi4mkCHyoLENwTEbFyw',
+ 'taos.zn': '1NNGrbXrWjPVnV6pxkuKGngRP116VaAFtm',
+ 'sogola.yu': '15CTUyQvz1qT4dqjWT2Wmd4XbV5hesrMtL',
+ 'sogola.of': '15CTUyQvz1qT4dqjWT2Wmd4XbV5hesrMtL',
+ 'sogola.inf': '15CTUyQvz1qT4dqjWT2Wmd4XbV5hesrMtL',
+ 'sogola.zn': '15CTUyQvz1qT4dqjWT2Wmd4XbV5hesrMtL',
+ 'sogola.list': '15CTUyQvz1qT4dqjWT2Wmd4XbV5hesrMtL',
+ 'pinapplehead.yo': '1QB9CpRMkYQNmngfegWCKxmy7Tna5DjXAf',
+ 'merith.zn': '1JyMUCtShELPTKSF1HR3XUj4QEZx58Jcwy',
+ 'youngchina.yo': '19UYGrRyBASeTHSHvqZ9SYJTZxmnojA6kx',
+ 'youngchina.yu': '19UYGrRyBASeTHSHvqZ9SYJTZxmnojA6kx',
+ 'youngchina.of': '19UYGrRyBASeTHSHvqZ9SYJTZxmnojA6kx',
+ 'youngchina.inf': '19UYGrRyBASeTHSHvqZ9SYJTZxmnojA6kx',
+ 'youngchina.zn': '19UYGrRyBASeTHSHvqZ9SYJTZxmnojA6kx',
+ 'youngchina.list': '19UYGrRyBASeTHSHvqZ9SYJTZxmnojA6kx',
+ 'zalex.yo': '1JChcgVVMqBy5fmN4er6afLhcoD7YzRDP6',
+ 'zalex.zn': '1JChcgVVMqBy5fmN4er6afLhcoD7YzRDP6',
+ 'ogame.yo': 'Me.ZeroNetwork.bit/?Profile/1KNmG5rJUGhgUJGFbLkv2B5isaqu9PrZqi/1KBkXs64bRMnZoTXzq5gdrsd1ZupSfMrwE/',
+ 'ogame.list': 'ogame.yo',
+ 'yeoldpaperblog.yo': '17aap8PVCLfDQYkmwPLrotnggjLEiNang4',
+ 'erg.yo': '18QTZ451KzvydQdCPS8KT4zob1hPw4zkRD',
+ 'yuzueabuilds.list': '1FBWiqA722gM8YqPqyXGvadskR77CAtBdm',
+ 'erkan.yo': '1HR2mJHeC1vs3XTTcX2X6BDcdRZZDNXZKV',
+ 'forum.yo': '17PEJfM9tdKs1JTxAMbcKzmYzrKJcUwMk5',
+ 'forum.inf': '17PEJfM9tdKs1JTxAMbcKzmYzrKJcUwMk5',
+ 'forum.zn': '17PEJfM9tdKs1JTxAMbcKzmYzrKJcUwMk5',
+ 'mokshanets.yo': '1MQ2e26P3v7Fb2rDPzNP83pfgERCtA92S5',
+ 'ifsplus.zn': '1BLnYeYMYhCQUiCVQKesJwa22Jzpcdd3Y6',
+ 'theciaproject.yo': '1HYzCVkN8pdQzdMdJptjSdEp6ADDP5XBZ4',
+ 'markdown.zn': '1J9bM4MbnTgsNcLWGnyKxT3m9jFQThxhkj',
+ 'kill.list': '1NAMEz7stUPZErkV1d3yLkVWQFa4PTqDNv',
+ 'attraversamenti.yo': '1GBsk92HdiofXvoa7pxH2ak7jZNnR3svxk',
+ 'socks.list': '1HZLvwrcxebTNZv3q5bNHiB5QAkQy2DR7i',
+ 'ss13.zn': '1MADyUhyzDBxNn6Ww2NheL6Q2g4knpEV7',
+ 'nwo.inf': '1CooGPdLMarc56bF5mZgFQtqVBQbKjpm8e',
+ 'zeronet.zn': 'todo',
+ 'foxden.zn': 'http://127.0.0.1:43110/1DFnD5okB2BvXwPGtDY9KvCHtW1d8YYB9z/',
+ 'foxden.yo': '1LbrCJF2CEXzZZLvXyLH9Kt5msywU5AwFF',
+ 'astrr.yo': '1AV33QMZbXpkS9yU65qFwuykiLNo3rJs7M',
+ 'zeroseed1.yo': '104.171.122.70',
+ 'mix22.yo': '1246yWDRZVb85dexD5RU85uvaiuM6uZARv',
+ 'i-say-hi.yo': '1PNs1BYT8ZW2YnQL2wsCyVviiGTpdPBGBZ',
+ 'pc.yo': '161Aw5FXqB1WHzvQsQVfJooxK7YqmsT1BX',
+ 'videos.nwo.inf': '15Q1YyzZeAzL1PyyhDp8oNxQznsUPZ8eoP',
+ 'e.list': '1BTLVyQm5ugNdpWcEDMZK9giZnuFpsYqXV',
+ 'e.yo': '1BTLVyQm5ugNdpWcEDMZK9giZnuFpsYqXV',
+ 'truepi.inf': '1EKQALAZwz2LYKJGJmqjMcHFELjR8wA138',
+ 'covid19facts.inf': '1LUMdYx1yPsVuZthvmSr5RUKTbvuuc1A75',
+ 'truthircchat.zn': '1L1PnQwGfU6XinBcGv8ysCjduuzx2p7Huw',
+ 'sites.list': '1NAMEz7stUPZErkV1d3yLkVWQFa4PTqDNv',
+ 'ratbrowser.yo': '14CFnCexfT3Xoj1SzWunNUNWDT7WqE3oUm',
+ 'bats.list': '19i7hXiRRz5vRqHmrUELKjzRofGPpAiFRv',
+ 'wasd1234.yo': '1JgMPiX13nD4C28ZY97EWjiVru9qFfiNgq',
+ 'astrr.zn': '1AV33QMZbXpkS9yU65qFwuykiLNo3rJs7M',
+ 'ifs.zn': '1BLnYeYMYhCQUiCVQKesJwa22Jzpcdd3Y6',
+ 'kopykate.zn': '1GPxQe1Qd76NpKNfCB2x1KnQLdZFuWFEAo',
+ 'zeroforums.zn': '1GutXgoFpA4B6DbCDsaSh9MzYf31iSfqf3',
+ 'zeroforum.zn': '1GutXgoFpA4B6DbCDsaSh9MzYf31iSfqf3',
+ 'pervertededucation.zn': '1PKW6qWBgVWRE3EkvJQaFv8uVpg2p1oYDQ',
+ 'trust.yo': '1PtFxzJ8NECkYQzziGWoEfzScD6NiEgqDY',
+ 'ruzero.zn': '1HKsGQWHbR33LjzqtoPfUBANXuYDy32hXp',
+ 'caoom.yo': '15art7pVw4pDaNZRugTxcMUEHPBC1mU2ZM',
+ 'z.yo': '1NAMEz7stUPZErkV1d3yLkVWQFa4PTqDNv',
+ 'szdcsdvszv.yo': '1NAMEz7stUPZErkV1d3yLkVWQFa4PTqDNv',
+ 'zheng.zn': '10.147.17.84',
+ 'zheng.yo': '10.147.17.84',
+ 'kaffiene.yo': '1Mr5rX9TauvaGReB4RjCaE6D37FJQaY5Ba',
+ 'chat.yo': '1Keke3V7Fn8bPt82QyhNHkv5gx5NnK9Umu',
+ 'chat.yu': '1Keke3V7Fn8bPt82QyhNHkv5gx5NnK9Umu',
+ 'dimitrisapostolou.yo': '17u2fjXwkMKcUJkH9j4kXD2ha9pNsJPn1A',
+ 'dimitrisapostolou.zn': '17u2fjXwkMKcUJkH9j4kXD2ha9pNsJPn1A',
+ 'dimitrisapostolou.yu': '17u2fjXwkMKcUJkH9j4kXD2ha9pNsJPn1A',
+ 'dimitrisapostolou.of': '17u2fjXwkMKcUJkH9j4kXD2ha9pNsJPn1A',
+ 'dimitrisapostolou.inf': '17u2fjXwkMKcUJkH9j4kXD2ha9pNsJPn1A',
+ 'dimitrisapostolou.list': '17u2fjXwkMKcUJkH9j4kXD2ha9pNsJPn1A',
+ 'zeronetx.yo': '1HELLoE3sFD9569CLCbHEAVqvqV7U2Ri9d',
+ 'zeronetx.yu': '1HELLoE3sFD9569CLCbHEAVqvqV7U2Ri9d',
+ 'zeronetx.zn': '1HELLoE3sFD9569CLCbHEAVqvqV7U2Ri9d',
+ 'zeronetx.of': '1HELLoE3sFD9569CLCbHEAVqvqV7U2Ri9d',
+ 'zeronetx.inf': '1HELLoE3sFD9569CLCbHEAVqvqV7U2Ri9d',
+ 'zeronetx.list': '1HELLoE3sFD9569CLCbHEAVqvqV7U2Ri9d',
+ 'moviebuzz.zn': '1HKGxbiYxmX68PcrLLKpyMVKE1SUdNfqRZ',
+ 'sh.zn': '1Ciwsxcy7XjH2EBzhDTfMExjTiBK4kYzeZ',
+ 'alexandr-monada.yo': '127.0.0.1',
+ 'zerotalkx.yo': '15UYrA7aXr2Nto1Gg4yWXpY3EAJwafMTNk',
+ 'zerotalkx.yu': '15UYrA7aXr2Nto1Gg4yWXpY3EAJwafMTNk',
+ 'zerotalkx.of': '15UYrA7aXr2Nto1Gg4yWXpY3EAJwafMTNk',
+ 'zerotalkx.inf': '15UYrA7aXr2Nto1Gg4yWXpY3EAJwafMTNk',
+ 'zerotalkx.zn': '15UYrA7aXr2Nto1Gg4yWXpY3EAJwafMTNk',
+ 'zerotalkx.list': '15UYrA7aXr2Nto1Gg4yWXpY3EAJwafMTNk',
+ 'compiler.yo': '14nKr6su4QvsVZNZAKt2YMTYQr755EkYys',
+ 'monkic.yo': '1vwuCChcRPJ6D1YqTK5UFmv8UWQAn6ptN',
+ 'about.yo': '19scCr6HceYeuGKADK4Qtz1USjNmUHqF5B',
+ 'natewrench.yo': '1AQ3tZW4GCzoiR7FzdbwYMHW4bQgyJCYkr',
+ 'natewrench.list': '1AQ3tZW4GCzoiR7FzdbwYMHW4bQgyJCYkr',
+ 'scribe.yo': '1SCribeHs1nz8m3vXipP84oyXUy4nf2ZD',
+ 'scribe.zn': '1SCribeHs1nz8m3vXipP84oyXUy4nf2ZD',
+ 'scribe.list': '1SCribeHs1nz8m3vXipP84oyXUy4nf2ZD',
+ 'scribe.inf': '1SCribeHs1nz8m3vXipP84oyXUy4nf2ZD',
+ 'scribe.of': '1SCribeHs1nz8m3vXipP84oyXUy4nf2ZD',
+ 'scribe.yu': '1SCribeHs1nz8m3vXipP84oyXUy4nf2ZD',
+ 'threadit.yo': '15UYrA7aXr2Nto1Gg4yWXpY3EAJwafMTNk',
+ 'threadit.zn': '15UYrA7aXr2Nto1Gg4yWXpY3EAJwafMTNk',
+ 'threadit.list': '15UYrA7aXr2Nto1Gg4yWXpY3EAJwafMTNk',
+ 'threadit.inf': '15UYrA7aXr2Nto1Gg4yWXpY3EAJwafMTNk',
+ 'threadit.of': '15UYrA7aXr2Nto1Gg4yWXpY3EAJwafMTNk',
+ 'threadit.yu': '15UYrA7aXr2Nto1Gg4yWXpY3EAJwafMTNk',
+ '3dfxglide.yo': '13dfxGLmVKbiK25MFJHgR9Nr1hmGAGjWbP',
+ 'ratbrowser.zn': '1NFjL6KmJYwojYMat8RXCPo2JWMvNzfHAk',
+ 'merlin.of': '1Mer3VhxoePJN7tqHvEAgMCuq4LLtU1N4k',
+ 'disable-donate.yo': '1JFuiZvpL9NKoggbW6M5GWeZWoucNvRLTX',
+ 'irantalk.zn': '1AS355T7MGApApoBeE9JgxvvvDxf33Eyh1',
+ 'farsiroom.zn': '1Ebc6bHBq7Ewgczuc9pqYh2jPFeC7vAwL7',
+ 'xerome.zn': '1JgcgZQ5a2Gxc4Cfy32szBJC68mMGusBjC',
+ 'darkasnight.zn': '1DbaVzv27GUx2LqXnMdrQCtzKcyS2zxdEd',
+ 'zeronetpersian.yo': 'http://127.0.0.1:43110/1NLMuTNWRKmfntZXmYyJWnoP85RHuzAWZW/',
+ 'zeronetpersian.zn': 'http://127.0.0.1:43110/1NLMuTNWRKmfntZXmYyJWnoP85RHuzAWZW/',
+ 'musthave.zn': '1LgjqcYMyhdEE81QZPCsBNnSKk8nzTg7tZ',
+ 'free-zone.zn': '17VhUiHjg34DfT2mZnCVr1RmU6sEJmscV2',
+ 'fitmisc.zn': '15Z5QHc3ajeHPGNHkWoBaCqpybe48A9meB',
+ 'files.free-zone.zn': '1DF26VGtsJrmNLfRfCqBbH4v4Godegh6B2',
+ 'fa.zn': '13dpeEht6Ztbu3EpUVUyj9eLJwPJLiPrT1',
+ 'me.fa.zn': '1JgcgZQ5a2Gxc4Cfy32szBJC68mMGusBjC',
+ 'talk.fa.zn': '1AS355T7MGApApoBeE9JgxvvvDxf33Eyh1',
+ 'hub.fa.zn': '13YccBekYK3S5LE1sva2wE2cUo6tk3BaWV',
+ 'chat.fa.zn': '1Ebc6bHBq7Ewgczuc9pqYh2jPFeC7vAwL7',
+ 'blog.fa.zn': '1DbaVzv27GUx2LqXnMdrQCtzKcyS2zxdEd',
+ 'fa.yo': '13dpeEht6Ztbu3EpUVUyj9eLJwPJLiPrT1',
+ 'toldyouso.yo': 'toldyouso',
+ 'toldyouso.yu': 'toldyouso',
+ 'toldyouso.zn': 'toldyouso',
+ 'toldyouso.list': 'toldyouso',
+ 'test.ivanq.yu': 'test3',
+ 'letsgo.zn': '1ETsGoB5HjhVV3r2MNtcKox8rcjtsLz77T',
+ 'eddyle.yo': '1KxakekWHCku9xeUZPfHXcsRqXCKZZrnJe',
+ '0netfarsi.zn': '1NLMuTNWRKmfntZXmYyJWnoP85RHuzAWZW/',
+ '0netfa.yo': '1NLMuTNWRKmfntZXmYyJWnoP85RHuzAWZW',
+ 'parishan.zn': '17mid9iAabJ7SKSGL6LiaABmbmesA1vohB',
+ 'znfa.zn': '1NLMuTNWRKmfntZXmYyJWnoP85RHuzAWZW',
+ '0index.inf': '1C3XRn6awmJvTCwTgTE88YzAzTfV8xFk9V',
+ '0index.zn': '1it4GjtNTkrFDX5pSXToqLYbEfxfqvPSR',
+ '00.zn': '1C3XRn6awmJvTCwTgTE88YzAzTfV8xFk9V',
+ '0netmirror.yo': '1LRb9GK6z3VEYwxtANCsszm3XDmQV3XT2G',
+ 'bbs.runpark.zn': '129Lxtnj45HkSnV9cGWmpBMNXffbeiG5RY',
+ 'bbs.runpark.yo': '129Lxtnj45HkSnV9cGWmpBMNXffbeiG5RY',
+ 'yaddasht.list': '1B5t5iPNdFvoegP3Z53tFfUHnw2wJp27iz',
+ 'iranproxy.yo': '1LKSyzSjccKWjgb8hNzALbYi8Q1sXCnmhN',
+ 'atlasft.yo': '1MAMEA17CHmFVeAWYmfBt6PWupozhufwic',
+ 'meme-beta.yo': '155xNWmKGzHqmy278pFK4NXRNDfaeGoHVU',
+ '1heal.yo': 'https://1heal.org',
+ '1heal.yu': 'https://1heal.org',
+ '1heal.zn': 'https://1heal.org',
+ '1heal.list': 'https://1heal.org',
+ 'kraken.zn': '1NAMEz7stUPZErkV1d3yLkVWQFa4PTqDNv',
+ 'krn.inf': '1NAMEz7stUPZErkV1d3yLkVWQFa4PTqDNv',
+ 'ultravoxtalk.yo': '1DmPuYVLGCmqguvoFFkUcogBu12weot56G',
+ 'test00110011.yo': '1HELLoE3sFD9569CLCbHEAVqvqV7U2Ri9d',
+ 'iran.inf': '1Lhiv2fCT6sB33A7p2GJCresA8aEZ84pHw',
+ 'teamsds.yo': '1NBtw2bYJw6TCr6CJwfbi3a7C1p61hmCVg',
+ 'teamsds.yu': '1NBtw2bYJw6TCr6CJwfbi3a7C1p61hmCVg',
+ 'teamsds.of': '1NBtw2bYJw6TCr6CJwfbi3a7C1p61hmCVg',
+ 'teamsds.inf': '1NBtw2bYJw6TCr6CJwfbi3a7C1p61hmCVg',
+ 'teamsds.zn': '1NBtw2bYJw6TCr6CJwfbi3a7C1p61hmCVg',
+ 'teamsds.list': '1NBtw2bYJw6TCr6CJwfbi3a7C1p61hmCVg',
+ 'madari.yo': '16QUxodsgcaRbJQtmKAUtNooF34Rxyg8EA',
+ 'madari.inf': '16QUxodsgcaRbJQtmKAUtNooF34Rxyg8EA',
+ 'yoxel.yo': '12kU1Esb8cTdPJkkZRCXkTcNExihFAzbmQ',
+ 'proxy.yo': '15V6KSMNc7X3hofZHy64s5LHtbVgrpYzSu',
+ 'paperhatsociety.zn': '1AbmBjhZ18UAMHMMhwp7LK9zrqAEKJ7iKA',
+ 'miceweb.yo': '1MiceWebdn35s6pUd3EM54uNveUJNSHsMr',
+ 'miceweb.zn': '1MiceWebdn35s6pUd3EM54uNveUJNSHsMr',
+ 'miceweb.inf': '1MiceWebdn35s6pUd3EM54uNveUJNSHsMr',
+ 'denny.inf': '1NAMEz7stUPZErkV1d3yLkVWQFa4PTqDNv',
+ 'hot.list': '1NAMEz7stUPZErkV1d3yLkVWQFa4PTqDNv',
+ 'best.of': '1NAMEz7stUPZErkV1d3yLkVWQFa4PTqDNv',
+ 'free.list': '1NAMEz7stUPZErkV1d3yLkVWQFa4PTqDNv',
+ 'travel.list': '1NAMEz7stUPZErkV1d3yLkVWQFa4PTqDNv',
+ 'cheap.list': '1NAMEz7stUPZErkV1d3yLkVWQFa4PTqDNv',
+ 'ads.list': '1NAMEz7stUPZErkV1d3yLkVWQFa4PTqDNv',
+ 'adblock.list': '1NAMEz7stUPZErkV1d3yLkVWQFa4PTqDNv',
+ 'adult.list': '1NAMEz7stUPZErkV1d3yLkVWQFa4PTqDNv',
+ 'file.list': '1NAMEz7stUPZErkV1d3yLkVWQFa4PTqDNv',
+ 'top.list': '1NAMEz7stUPZErkV1d3yLkVWQFa4PTqDNv',
+ 'domain.list': '1NAMEz7stUPZErkV1d3yLkVWQFa4PTqDNv',
+ 'opusx.yo': '1NAMEz7stUPZErkV1d3yLkVWQFa4PTqDNv',
+ 'bucket.list': '1NAMEz7stUPZErkV1d3yLkVWQFa4PTqDNv',
+ 'denny.yo': '1NAMEz7stUPZErkV1d3yLkVWQFa4PTqDNv',
+ 'my.list': '1NAMEz7stUPZErkV1d3yLkVWQFa4PTqDNv',
+ 'your.list': '1NAMEz7stUPZErkV1d3yLkVWQFa4PTqDNv',
+ 'private.zn': '1NAMEz7stUPZErkV1d3yLkVWQFa4PTqDNv',
+ 'tracker.list': '1NAMEz7stUPZErkV1d3yLkVWQFa4PTqDNv',
+ 'proxy.list': '1NAMEz7stUPZErkV1d3yLkVWQFa4PTqDNv',
+ 'wish.list': '1NAMEz7stUPZErkV1d3yLkVWQFa4PTqDNv',
+ 'free.zn': '1NAMEz7stUPZErkV1d3yLkVWQFa4PTqDNv',
+ 'voip.inf': '1NAMEz7stUPZErkV1d3yLkVWQFa4PTqDNv',
+ 'voip.list': '1NAMEz7stUPZErkV1d3yLkVWQFa4PTqDNv',
+ 'todo.list': '1NAMEz7stUPZErkV1d3yLkVWQFa4PTqDNv',
+ 'my.inf': '1NAMEz7stUPZErkV1d3yLkVWQFa4PTqDNv',
+ 'ma.yo': '1NAMEz7stUPZErkV1d3yLkVWQFa4PTqDNv',
+ 'lots.of': '1NAMEz7stUPZErkV1d3yLkVWQFa4PTqDNv',
+ 'freeware.list': '1NAMEz7stUPZErkV1d3yLkVWQFa4PTqDNv',
+ 'software.list': '1NAMEz7stUPZErkV1d3yLkVWQFa4PTqDNv',
+ 'apps.list': '1NAMEz7stUPZErkV1d3yLkVWQFa4PTqDNv',
+ 'mostwanted.list': '1NAMEz7stUPZErkV1d3yLkVWQFa4PTqDNv',
+ 'task.list': '1NAMEz7stUPZErkV1d3yLkVWQFa4PTqDNv',
+ 'freebies.list': '1NAMEz7stUPZErkV1d3yLkVWQFa4PTqDNv',
+ 'coupons.list': '1NAMEz7stUPZErkV1d3yLkVWQFa4PTqDNv',
+ 'makeuse.of': '1NAMEz7stUPZErkV1d3yLkVWQFa4PTqDNv',
+ 'way.of': '1NAMEz7stUPZErkV1d3yLkVWQFa4PTqDNv',
+ 'e.of': '1NAMEz7stUPZErkV1d3yLkVWQFa4PTqDNv',
+ 'code.of': '1NAMEz7stUPZErkV1d3yLkVWQFa4PTqDNv',
+ 'get.list': '1NAMEz7stUPZErkV1d3yLkVWQFa4PTqDNv',
+ 'hey.yo': '1NAMEz7stUPZErkV1d3yLkVWQFa4PTqDNv',
+ 'zeronet.inf': '1NAMEz7stUPZErkV1d3yLkVWQFa4PTqDNv',
+ 'big.list': '1NAMEz7stUPZErkV1d3yLkVWQFa4PTqDNv',
+ 'small.list': '1NAMEz7stUPZErkV1d3yLkVWQFa4PTqDNv',
+ 'tiny.list': '1NAMEz7stUPZErkV1d3yLkVWQFa4PTqDNv',
+ 'giant.list': '1NAMEz7stUPZErkV1d3yLkVWQFa4PTqDNv',
+ 'huge.list': '1NAMEz7stUPZErkV1d3yLkVWQFa4PTqDNv',
+ 'monster.list': '1NAMEz7stUPZErkV1d3yLkVWQFa4PTqDNv',
+ 'friend.of': '1NAMEz7stUPZErkV1d3yLkVWQFa4PTqDNv',
+ 'friends.of': '1NAMEz7stUPZErkV1d3yLkVWQFa4PTqDNv',
+ 'domain.of': '1NAMEz7stUPZErkV1d3yLkVWQFa4PTqDNv',
+ 'site.of': '1NAMEz7stUPZErkV1d3yLkVWQFa4PTqDNv',
+ 'url.of': '1NAMEz7stUPZErkV1d3yLkVWQFa4PTqDNv',
+ 'favorites.list': '1NAMEz7stUPZErkV1d3yLkVWQFa4PTqDNv',
+ 'bookmarks.list': '1NAMEz7stUPZErkV1d3yLkVWQFa4PTqDNv',
+ 'hidden.list': '1NAMEz7stUPZErkV1d3yLkVWQFa4PTqDNv',
+ 'shopping.list': '1NAMEz7stUPZErkV1d3yLkVWQFa4PTqDNv',
+ 'dingdong.yo': '1NAMEz7stUPZErkV1d3yLkVWQFa4PTqDNv',
+ 'my.zn': '1NAMEz7stUPZErkV1d3yLkVWQFa4PTqDNv',
+ 'co.yo': '1NAMEz7stUPZErkV1d3yLkVWQFa4PTqDNv',
+ 'com.yo': '1NAMEz7stUPZErkV1d3yLkVWQFa4PTqDNv',
+ 'co.list': '1NAMEz7stUPZErkV1d3yLkVWQFa4PTqDNv',
+ 'com.list': '1NAMEz7stUPZErkV1d3yLkVWQFa4PTqDNv',
+ 'org.yo': '1NAMEz7stUPZErkV1d3yLkVWQFa4PTqDNv',
+ 'org.zn': '1NAMEz7stUPZErkV1d3yLkVWQFa4PTqDNv',
+ 'net.yo': '1NAMEz7stUPZErkV1d3yLkVWQFa4PTqDNv',
+ 'net.zn': '1NAMEz7stUPZErkV1d3yLkVWQFa4PTqDNv',
+ 'shared.list': '1NAMEz7stUPZErkV1d3yLkVWQFa4PTqDNv',
+ 'co.zn': '1NAMEz7stUPZErkV1d3yLkVWQFa4PTqDNv',
+ 'com.zn': '1NAMEz7stUPZErkV1d3yLkVWQFa4PTqDNv',
+ 'bump.of': '1NAMEz7stUPZErkV1d3yLkVWQFa4PTqDNv',
+ 'joy.of': '1NAMEz7stUPZErkV1d3yLkVWQFa4PTqDNv',
+ 'name.of': '1NAMEz7stUPZErkV1d3yLkVWQFa4PTqDNv',
+ 'short.of': '1NAMEz7stUPZErkV1d3yLkVWQFa4PTqDNv',
+ 'best.list': '1NAMEz7stUPZErkV1d3yLkVWQFa4PTqDNv',
+ '18.yo': '1NAMEz7stUPZErkV1d3yLkVWQFa4PTqDNv',
+ '16.yo': '1NAMEz7stUPZErkV1d3yLkVWQFa4PTqDNv',
+ '21.yo': '1NAMEz7stUPZErkV1d3yLkVWQFa4PTqDNv',
+ 'made.of': '1NAMEz7stUPZErkV1d3yLkVWQFa4PTqDNv',
+ 'cam.list': '1NAMEz7stUPZErkV1d3yLkVWQFa4PTqDNv',
+ 'cams.list': '1NAMEz7stUPZErkV1d3yLkVWQFa4PTqDNv',
+ 'webcam.list': '1NAMEz7stUPZErkV1d3yLkVWQFa4PTqDNv',
+ 'webcams.list': '1NAMEz7stUPZErkV1d3yLkVWQFa4PTqDNv',
+ 'sexcam.list': '1NAMEz7stUPZErkV1d3yLkVWQFa4PTqDNv',
+ 'sexcams.list': '1NAMEz7stUPZErkV1d3yLkVWQFa4PTqDNv',
+ 'a.list': '1NAMEz7stUPZErkV1d3yLkVWQFa4PTqDNv',
+ 'secret.list': '1NAMEz7stUPZErkV1d3yLkVWQFa4PTqDNv',
+ 'nya.yo': '1BuUkkXsAzPHdEK78nxNZjiVcvUS12LBks',
+ 'galactichan.yo': '19HKdTAeBh5nRiKn791czY7TwRB1QNrf1Q',
+ 'galactichan.yu': '19HKdTAeBh5nRiKn791czY7TwRB1QNrf1Q',
+ 'galactichan.zn': '19HKdTAeBh5nRiKn791czY7TwRB1QNrf1Q',
+ 'galactichan.of': '19HKdTAeBh5nRiKn791czY7TwRB1QNrf1Q',
+ 'galactichan.inf': '19HKdTAeBh5nRiKn791czY7TwRB1QNrf1Q',
+ 'galactichan.list': '19HKdTAeBh5nRiKn791czY7TwRB1QNrf1Q',
+ 'electroperra.yo': '1EoakGCUsHZrjMe9V86PBktkzn8T7LK2rG',
+ 'electroperra.list': '1EoakGCUsHZrjMe9V86PBktkzn8T7LK2rG',
+ 'electroperra.yu': '1EoakGCUsHZrjMe9V86PBktkzn8T7LK2rG',
+ 'electroperra.of': '1EoakGCUsHZrjMe9V86PBktkzn8T7LK2rG',
+ 'electroperra.inf': '1EoakGCUsHZrjMe9V86PBktkzn8T7LK2rG',
+ 'electroperra.zn': '1EoakGCUsHZrjMe9V86PBktkzn8T7LK2rG',
+ 'aznet.zn': '1Gwm9zviPznj2BuvmS2sHko9m3uupW27JR'
+ };
+
+ def load_cache(self):
+ if hasattr(self, "zero_cache"):
+ return
+
+ self.cache_file_path = os.path.dirname(os.path.abspath(__file__)) + "/ZeroNameExPlugin.json"
+ if not os.path.isfile(self.cache_file_path):
+ zero_cache = {
+ "domains": {},
+ "yo_domains": self.get_yo_domains(),
+ "content_json_addresses": {},
+ "content_json_domains": {},
+ "update_interval": 3600 * 5, # 5 hours is really enough and not too much, real dns resolvers need 24 hours by the way >.<
+ "last_updated": 0,
+ "update_time": 0,
+ "use_cache": True,
+ "resolvers": config.bit_resolvers,
+ "main_resolver": config.bit_resolver
+ }
+ with open(self.cache_file_path, 'w') as f:
+ json.dump(zero_cache, f, indent=2, sort_keys=True)
+
+ with open(self.cache_file_path, 'r') as f:
+ self.zero_cache = json.load(f)
+
+ def update_cache_content_json(self):
+ self.load_cache()
+ if not self.cache_need_update():
+ return
+
+ content_json_domains = self.filter_domains(self.zero_cache["content_json_domains"])
+ self.zero_cache["content_json_domains"] = content_json_domains
+ self.zero_content_json_domains = self.zero_cache["content_json_domains"]
+ self.zero_cache["last_updated"] = time.time()
+ self.update_cache_file()
+
+ def update_cache(self):
+ self.load_cache()
+ if not self.cache_need_update():
+ return
+
+ zero_names_len = len(self.zero_names)
+ for i in range(0, zero_names_len):
+ self.loadZeroName(i)
+ self.update_cache_resolver(i)
+
+ content_json_domains = self.filter_domains(self.zero_cache["content_json_domains"])
+
+ self.zero_db_domains = self.zero_cache["domains"]
+ self.zero_yo_domains = self.zero_cache["yo_domains"]
+ self.zero_content_json_domains = self.zero_cache["content_json_domains"]
+ self.zero_cache["content_json_domains"] = content_json_domains
+ self.zero_cache["last_updated"] = time.time()
+ self.update_cache_file()
+
+ def update_cache_resolver(self, i):
+ self.load_cache()
+ self.zero_cache["domains"].update(self.zero_names[i].db_domains)
+ domains = self.filter_domains(self.zero_cache["domains"])
+ self.zero_cache["domains"] = domains
+ self.zero_cache["last_updated"] = time.time()
+
+ def update_cache_file(self):
+ try:
+ self.load_cache()
+ with open(self.cache_file_path, 'w') as f:
+ json.dump(self.zero_cache, f, indent=2, sort_keys=True)
+ except:
+ pass
+
+ def cache_need_update(self):
+ self.load_cache()
+ last_updated = self.zero_cache["last_updated"]
+ update_interval = self.zero_cache["update_interval"]
+ if update_interval <= 0:
+ return True
+
+ if last_updated <= 0:
+ return True
+
+ last_updated = last_updated + update_interval
+ if time.time() >= last_updated:
+ return True
+
+ return False
+
+ def get_item_from_zero_cache(self, item):
+ self.update_cache()
+ return self.zero_db_domains.get(item)
+
+ def filter_domains(self, my_dict):
+ result = filter(lambda x: self.dcr.match(x[0]) and self.acr.match(x[1]) and (x[0], x[1]) or False, my_dict.items())
+ result = dict(result)
+ return my_dict
+
+ # Return: Site object or None if not found
+ def fast_get(self, address):
+ return self.sites.get(address) or self.sites.get(address.lower())
+
+ # Return or create site and start download site files
+ def fast_need(self, address, all_file=True, settings=None):
+ site = self.fast_get(address)
+ from Site.Site import Site
+ if not site: # Site not exist yet
+ self.sites_changed = int(time.time())
+ if not self.acr.match(address):
+ return False # Not address: %s % address
+ self.logme.debug("Added new site: %s" % address)
+ config.loadTrackersFile()
+ site = Site(address, settings=settings)
+ self.sites[address] = site
+ if not site.settings["serving"]: # Maybe it was deleted before
+ site.settings["serving"] = True
+ site.saveSettings()
+ if all_file: # Also download user files on first sync
+ site.download(check_size=True, blind_includes=True)
+
+ return site
+
+ #Return: see resolveBitDomain from the ZeroName Plugin
+ def loadZeroName(self, i):
+ zno = self.zero_names[i]
+
+ #self.logme.debug("ZeroNameCachedPlugin zno: " + zno)
+ self.logme.debug("ZeroNameCached: Resolve from : %s" % zno.bit_resolver)
+ if not zno.site_zeroname:
+ zno.site_zeroname = self.fast_need(zno.bit_resolver)
+ self.logme.debug("ZeroNameCached: Load site site_zeroname : %s" % zno.bit_resolver)
+
+ zno.site_zeroname_modified = zno.site_zeroname.content_manager.contents.get("content.json", {}).get("modified", 0)
+ self.logme.debug("ZeroNameCached: test zno.db_domains_modified != zno.site_zeroname_modified ")
+ if (not zno.loaded) or (zno.db_domains_modified != zno.site_zeroname_modified):
+ zno.site_zeroname.needFile("data/names.json", priority=10)
+ self.logme.debug("ZeroNameCached: needFile")
+ s = time.time()
+ try:
+ zno.db_domains = self.filter_domains(zno.site_zeroname.storage.loadJson("data/names.json"))
+ zno.loaded = True
+ zno.db_domains_modified = zno.site_zeroname_modified
+ self.logme.debug(
+ "ZeroNameCached: Domain db with %s entries loaded in %.3fs (modification: %s -> %s)" %
+ (len(zno.db_domains), time.time() - s, zno.db_domains_modified, zno.site_zeroname_modified)
+ )
+ except Exception as err:
+ log.error("ZeroNameCached: Error loading names.json: %s" % err)
+ zno.loaded = False
+
+ self.zero_names[i] = zno
+
+ def load(self, *args, **kwargs):
+ super(SiteManagerPlugin, self).load(*args, **kwargs)
+ self.loadZeroNameCachedPlugin()
+
+ # Turn domain into address
+ def resolveDomain(self, domain):
+ log.debug("resolve domain " + domain)
+ old_my_db_domains_modified = 0
+ new_my_db_domains_modified = 0
+ has_db_domains_modified = "db_domains_modified" in super(SiteManagerPlugin, self).__dict__
+ if has_db_domains_modified:
+ old_my_db_domains_modified = super(SiteManagerPlugin, self).__dict__["db_domains_modified"]
+ resolve = super(SiteManagerPlugin, self).resolveDomain(domain)
+ if has_db_domains_modified:
+ new_my_db_domains_modified = super(SiteManagerPlugin, self).__dict__["db_domains_modified"]
+
+ log.debug("old_my_db_domains_modified " + str(old_my_db_domains_modified))
+ log.debug("new_my_db_domains_modified " + str(new_my_db_domains_modified))
+
+ if self.cache_need_update():
+ self.update_cache()
+ self.my_db_domains = {}
+ old_my_db_domains_modified = 0
+ new_my_db_domains_modified = 0
+
+ if new_my_db_domains_modified != old_my_db_domains_modified or len(self.my_db_domains) == 0:
+ has_db_domains = "db_domains" in super(SiteManagerPlugin, self).__dict__
+ if has_db_domains:
+ my_db_domains = super(SiteManagerPlugin, self).__dict__["db_domains"]
+ if my_db_domains == None:
+ log.debug("my_db_domains is None")
+ return resolve
+ new_domains = {}
+ new_domains.update(self.zero_content_json_domains)
+ new_domains.update(self.zero_yo_domains)
+ new_domains.update(self.zero_db_domains)
+ new_domains.update(my_db_domains)
+ self.my_db_domains = my_db_domains
+ super(SiteManagerPlugin, self).__dict__["db_domains"] = self.my_db_domains
+ log.debug("my_db_domains is funzed yayy yay yaayy")
+ return self.my_db_domains.get(domain)
+ else:
+ return resolve
+ return resolve
+
+ # Return: True if the address is domain
+ def isDomain(self, address):
+ log.debug("is domain " + address)
+ isDomainZite = super(SiteManagerPlugin, self).isDomain(address)
+ if not isDomainZite:
+ if self.zero_cache["content_json_addresses"].get(address):
+ return isDomainZite
+ has_sites = "sites" in super(SiteManagerPlugin, self).__dict__
+ if not has_sites:
+ return isDomainZite
+
+ sites = super(SiteManagerPlugin, self).__dict__["sites"]
+
+ site = sites.get(address)
+ if not site:
+ return isDomainZite
+
+ contentJson = site.content_manager.contents.get("content.json")
+ if not contentJson:
+ return isDomainZite
+
+ domain = contentJson.get("domain")
+ if not domain:
+ return isDomainZite
+
+ if not self.zero_cache["content_json_domains"].get(domain):
+ nd = {}
+ nd[domain] = address
+ na = {}
+ na[address] = domain
+ self.zero_cache["content_json_domains"].update(nd)
+ self.zero_cache["content_json_addresses"].update(na)
+ self.zero_content_json_domains = self.zero_cache["content_json_domains"]
+ self.zero_cache["last_updated"] = 0
+
+ return isDomainZite
+
+
+@PluginManager.registerTo("ConfigPlugin")
+class ConfigPlugin(object):
+ def createArguments(self):
+ group = self.parser.add_argument_group("ZeronameExPlugin")
+ group.add_argument(
+ "--bit_resolvers", help="ZeroNameEx: ZeroNet sites to resolve .bit domains",
+ default=["1Name2NXVi1RDPDgf5617UoW7xA6YrhM9F", "1SitesVCdgNfHojzf2aGKQrD4dteAZR1k", "1E97TpiDiCj1WGhZWxoKjBV9KkVty1PFsq"], nargs='+', metavar="0net_addresses"
+ ) # zeronet resolver, # zeronetx resolver # zeronet is nice resolver
+
+ log.debug("ZeroNameEx has created the arguments for you!")
+ return super(ConfigPlugin, self).createArguments()
\ No newline at end of file
diff --git a/plugins/ZeronameEx/__init__.py b/plugins/ZeronameEx/__init__.py
new file mode 100644
index 000000000..b3edf998d
--- /dev/null
+++ b/plugins/ZeronameEx/__init__.py
@@ -0,0 +1 @@
+from . import SiteManagerPlugin
\ No newline at end of file
diff --git a/plugins/disabled-Bootstrapper/BootstrapperDb.py b/plugins/disabled-Bootstrapper/BootstrapperDb.py
index 0866dc3e8..3c47b76d8 100644
--- a/plugins/disabled-Bootstrapper/BootstrapperDb.py
+++ b/plugins/disabled-Bootstrapper/BootstrapperDb.py
@@ -79,8 +79,8 @@ def createTables(self):
def getHashId(self, hash):
if hash not in self.hash_ids:
self.log.debug("New hash: %s" % repr(hash))
- res = self.execute("INSERT OR IGNORE INTO hash ?", {"hash": hash})
- self.hash_ids[hash] = res.lastrowid
+ self.execute("INSERT OR IGNORE INTO hash ?", {"hash": hash})
+ self.hash_ids[hash] = self.cur.cursor.lastrowid
return self.hash_ids[hash]
def peerAnnounce(self, ip_type, address, port=None, hashes=[], onion_signed=False, delete_missing_hashes=False):
@@ -100,8 +100,8 @@ def peerAnnounce(self, ip_type, address, port=None, hashes=[], onion_signed=Fals
self.log.debug("New peer: %s signed: %s" % (address, onion_signed))
if ip_type == "onion" and not onion_signed:
return len(hashes)
- res = self.execute("INSERT INTO peer ?", {"type": ip_type, "address": address, "port": port, "date_announced": now})
- peer_id = res.lastrowid
+ self.execute("INSERT INTO peer ?", {"type": ip_type, "address": address, "port": port, "date_announced": now})
+ peer_id = self.cur.cursor.lastrowid
# Check user's hashes
res = self.execute("SELECT * FROM peer_to_hash WHERE ?", {"peer_id": peer_id})
diff --git a/plugins/disabled-Bootstrapper/BootstrapperPlugin.py b/plugins/disabled-Bootstrapper/BootstrapperPlugin.py
index 59e7af7b6..474f79c10 100644
--- a/plugins/disabled-Bootstrapper/BootstrapperPlugin.py
+++ b/plugins/disabled-Bootstrapper/BootstrapperPlugin.py
@@ -150,7 +150,7 @@ def actionStatsBootstrapper(self):
).fetchall()
yield " %s (added: %s, peers: %s) " % (
- str(hash_row["hash"]).encode().hex(), hash_row["date_added"], len(peer_rows)
+ str(hash_row["hash"]).encode("hex"), hash_row["date_added"], len(peer_rows)
)
for peer_row in peer_rows:
- yield " - {type} {address}:{port} added: {date_added}, announced: {date_announced} ".format(**dict(peer_row))
+ yield " - {ip4: <30} {onion: <30} added: {date_added}, announced: {date_announced} ".format(**dict(peer_row))
diff --git a/plugins/disabled-Multiuser/MultiuserPlugin.py b/plugins/disabled-Multiuser/MultiuserPlugin.py
index 799c3337d..8a8ee8f21 100644
--- a/plugins/disabled-Multiuser/MultiuserPlugin.py
+++ b/plugins/disabled-Multiuser/MultiuserPlugin.py
@@ -7,7 +7,7 @@
from Crypt import CryptBitcoin
from . import UserPlugin
from util.Flag import flag
-from Translate import translate as _
+
# We can only import plugin host clases after the plugins are loaded
@PluginManager.afterLoad
@@ -114,8 +114,6 @@ def formatServerInfo(self):
server_info["multiuser"] = True
if "ADMIN" in self.site.settings["permissions"]:
server_info["master_address"] = self.user.master_address
- is_multiuser_admin = config.multiuser_local or self.user.master_address in local_master_addresses
- server_info["multiuser_admin"] = is_multiuser_admin
return server_info
# Show current user's master seed
@@ -144,52 +142,6 @@ def actionUserLogout(self, to):
else:
self.response(to, "User not found")
- @flag.admin
- def actionUserSet(self, to, master_address):
- user_manager = UserManager.user_manager
- user = user_manager.get(master_address)
- if not user:
- raise Exception("No user found")
-
- script = "document.cookie = 'master_address=%s;path=/;max-age=2592000;';" % master_address
- script += "zeroframe.cmd('wrapperReload', ['login=done']);"
- self.cmd("notification", ["done", "Successful login, reloading page..."])
- self.cmd("injectScript", script)
-
- self.response(to, "ok")
-
- @flag.admin
- def actionUserSelectForm(self, to):
- if not config.multiuser_local:
- raise Exception("Only allowed in multiuser local mode")
- user_manager = UserManager.user_manager
- body = "" + "Change account:" + ""
- for master_address, user in user_manager.list().items():
- is_active = self.user.master_address == master_address
- if user.certs:
- first_cert = next(iter(user.certs.keys()))
- title = "%s@%s" % (user.certs[first_cert]["auth_user_name"], first_cert)
- else:
- title = user.master_address
- if len(user.sites) < 2 and not is_active: # Avoid listing ad-hoc created users
- continue
- if is_active:
- css_class = "active"
- else:
- css_class = "noclass"
- body += "%s" % (css_class, user.master_address, title)
-
- script = """
- $(".notification .select.user").on("click", function() {
- $(".notification .select").removeClass('active')
- zeroframe.response(%s, this.title)
- return false
- })
- """ % self.next_message_id
-
- self.cmd("notification", ["ask", body], lambda master_address: self.actionUserSet(to, master_address))
- self.cmd("injectScript", script)
-
# Show login form
def actionUserLoginForm(self, to):
self.cmd("prompt", ["Login Your private key:", "password", "Login"], self.responseUserLogin)
@@ -213,7 +165,7 @@ def hasCmdPermission(self, cmd):
flags = flag.db.get(self.getCmdFuncName(cmd), ())
is_public_proxy_user = not config.multiuser_local and self.user.master_address not in local_master_addresses
if is_public_proxy_user and "no_multiuser" in flags:
- self.cmd("notification", ["info", _("This function ({cmd}) is disabled on this proxy!")])
+ self.cmd("notification", ["info", "This function is disabled on this proxy!"])
return False
else:
return super(UiWebsocketPlugin, self).hasCmdPermission(cmd)
@@ -256,8 +208,7 @@ def actionCertAdd(self, *args, **kwargs):
self.cmd("injectScript", script)
def actionPermissionAdd(self, to, permission):
- is_public_proxy_user = not config.multiuser_local and self.user.master_address not in local_master_addresses
- if permission == "NOSANDBOX" and is_public_proxy_user:
+ if permission == "NOSANDBOX":
self.cmd("notification", ["info", "You can't disable sandbox on this proxy!"])
self.response(to, {"error": "Denied by proxy"})
return False
diff --git a/plugins/disabled-UiPassword/UiPasswordPlugin.py b/plugins/disabled-UiPassword/UiPasswordPlugin.py
index e8a4e4fec..1962d5e6d 100644
--- a/plugins/disabled-UiPassword/UiPasswordPlugin.py
+++ b/plugins/disabled-UiPassword/UiPasswordPlugin.py
@@ -14,7 +14,6 @@
if "sessions" not in locals().keys(): # To keep sessions between module reloads
sessions = {}
- whitelisted_client_ids = {}
def showPasswordAdvice(password):
@@ -29,26 +28,8 @@ def showPasswordAdvice(password):
@PluginManager.registerTo("UiRequest")
class UiRequestPlugin(object):
sessions = sessions
- whitelisted_client_ids = whitelisted_client_ids
last_cleanup = time.time()
- def getClientId(self):
- return self.env["REMOTE_ADDR"] + " - " + self.env["HTTP_USER_AGENT"]
-
- def whitelistClientId(self, session_id=None):
- if not session_id:
- session_id = self.getCookies().get("session_id")
- client_id = self.getClientId()
- if client_id in self.whitelisted_client_ids:
- self.whitelisted_client_ids[client_id]["updated"] = time.time()
- return False
-
- self.whitelisted_client_ids[client_id] = {
- "added": time.time(),
- "updated": time.time(),
- "session_id": session_id
- }
-
def route(self, path):
# Restict Ui access by ip
if config.ui_restrict and self.env['REMOTE_ADDR'] not in config.ui_restrict:
@@ -58,25 +39,13 @@ def route(self, path):
else:
if config.ui_password:
if time.time() - self.last_cleanup > 60 * 60: # Cleanup expired sessions every hour
- self.sessionCleanup()
+ self.cleanup()
# Validate session
session_id = self.getCookies().get("session_id")
- if session_id not in self.sessions and self.getClientId() not in self.whitelisted_client_ids:
- # Invalid session id and not whitelisted ip: display login
+ if session_id not in self.sessions: # Invalid session id, display login
return self.actionLogin()
return super(UiRequestPlugin, self).route(path)
- def actionWrapper(self, path, *args, **kwargs):
- if config.ui_password and self.isWrapperNecessary(path):
- session_id = self.getCookies().get("session_id")
- if session_id not in self.sessions:
- # We only accept cookie based auth on wrapper
- return self.actionLogin()
- else:
- self.whitelistClientId()
-
- return super().actionWrapper(path, *args, **kwargs)
-
# Action: Login
@helper.encodeResponse
def actionLogin(self):
@@ -84,14 +53,13 @@ def actionLogin(self):
self.sendHeader()
posted = self.getPosted()
if posted: # Validate http posted data
- if self.sessionCheckPassword(posted.get("password")):
+ if self.checkPassword(posted.get("password")):
# Valid password, create session
session_id = self.randomString(26)
self.sessions[session_id] = {
"added": time.time(),
"keep": posted.get("keep")
}
- self.whitelistClientId(session_id)
# Redirect to homepage or referer
url = self.env.get("HTTP_REFERER", "")
@@ -106,45 +74,34 @@ def actionLogin(self):
template = template.replace("{result}", "bad_password")
yield template
- def randomString(self, nchars):
- return ''.join(random.choice(string.ascii_uppercase + string.ascii_lowercase + string.digits) for _ in range(nchars))
-
- def sessionCheckPassword(self, password):
+ def checkPassword(self, password):
return password == config.ui_password
- def sessionDelete(self, session_id):
- del self.sessions[session_id]
-
- for client_id in list(self.whitelisted_client_ids):
- if self.whitelisted_client_ids[client_id]["session_id"] == session_id:
- del self.whitelisted_client_ids[client_id]
+ def randomString(self, nchars):
+ return ''.join(random.choice(string.ascii_uppercase + string.ascii_lowercase + string.digits) for _ in range(nchars))
- def sessionCleanup(self):
- self.last_cleanup = time.time()
- for session_id, session in list(self.sessions.items()):
+ @classmethod
+ def cleanup(cls):
+ cls.last_cleanup = time.time()
+ for session_id, session in list(cls.sessions.items()):
if session["keep"] and time.time() - session["added"] > 60 * 60 * 24 * 60: # Max 60days for keep sessions
- self.sessionDelete(session_id)
+ del(cls.sessions[session_id])
elif not session["keep"] and time.time() - session["added"] > 60 * 60 * 24: # Max 24h for non-keep sessions
- self.sessionDelete(session_id)
+ del(cls.sessions[session_id])
# Action: Display sessions
- @helper.encodeResponse
def actionSessions(self):
self.sendHeader()
yield "
"
yield json.dumps(self.sessions, indent=4)
- yield "\r\n"
- yield json.dumps(self.whitelisted_client_ids, indent=4)
# Action: Logout
- @helper.encodeResponse
def actionLogout(self):
# Session id has to passed as get parameter or called without referer to avoid remote logout
session_id = self.getCookies().get("session_id")
if not self.env.get("HTTP_REFERER") or session_id == self.get.get("session_id"):
if session_id in self.sessions:
- self.sessionDelete(session_id)
-
+ del self.sessions[session_id]
self.start_response('301 Redirect', [
('Location', "/"),
('Set-Cookie', "session_id=deleted; path=/; expires=Thu, 01 Jan 1970 00:00:00 GMT")