2015-01-12 02:03:45 +01:00
|
|
|
import os, sys
|
version 0.2.7, plugin system, multiuser plugin for zeroproxies, reworked imports, cookie parse, stats moved to plugin, usermanager class, dont generate site auth on listing, multiline notifications, allow server side prompt from user, update script keep plugins disabled status
2015-03-24 01:33:09 +01:00
|
|
|
update_after_shutdown = False # If set True then update and restart zeronet after main loop ended
|
2015-01-12 02:03:45 +01:00
|
|
|
|
2015-01-12 19:11:35 +01:00
|
|
|
# Create necessary files and dirs
|
|
|
|
if not os.path.isdir("log"): os.mkdir("log")
|
|
|
|
if not os.path.isdir("data"): os.mkdir("data")
|
|
|
|
if not os.path.isfile("data/sites.json"): open("data/sites.json", "w").write("{}")
|
version 0.2.0, new lib for bitcoin ecc, dont display or track notify errors, dont reload again within 1 sec, null peer ip fix, signingmoved to ContentManager, content.json include support, content.json multisig ready, content.json proper bitcoincore compatible signing, content.json include permissions, multithreaded publish, publish timeout 60s, no exception on invalid bitcoin address, testcase for new lib, bip32 based persite privatekey generation, multiuser ready, simple json database query command, websocket api fileGet, wrapper loading title stuck bugfix
2015-02-09 02:09:02 +01:00
|
|
|
if not os.path.isfile("data/users.json"): open("data/users.json", "w").write("{}")
|
2015-01-12 19:11:35 +01:00
|
|
|
|
2015-01-12 02:03:45 +01:00
|
|
|
# Load config
|
|
|
|
from Config import config
|
|
|
|
|
version 0.2.7, plugin system, multiuser plugin for zeroproxies, reworked imports, cookie parse, stats moved to plugin, usermanager class, dont generate site auth on listing, multiline notifications, allow server side prompt from user, update script keep plugins disabled status
2015-03-24 01:33:09 +01:00
|
|
|
# Setup logging
|
2015-01-12 02:03:45 +01:00
|
|
|
import logging
|
|
|
|
if config.action == "main":
|
|
|
|
if os.path.isfile("log/debug.log"): # Simple logrotate
|
|
|
|
if os.path.isfile("log/debug-last.log"): os.unlink("log/debug-last.log")
|
|
|
|
os.rename("log/debug.log", "log/debug-last.log")
|
|
|
|
logging.basicConfig(format='[%(asctime)s] %(levelname)-8s %(name)s %(message)s', level=logging.DEBUG, filename="log/debug.log")
|
|
|
|
else:
|
|
|
|
logging.basicConfig(level=logging.DEBUG, stream=open(os.devnull,"w")) # No file logging if action is not main
|
|
|
|
|
2015-01-17 18:50:56 +01:00
|
|
|
# Console logger
|
2015-01-12 02:03:45 +01:00
|
|
|
console_log = logging.StreamHandler()
|
2015-01-17 18:50:56 +01:00
|
|
|
if config.action == "main": # Add time if main action
|
|
|
|
console_log.setFormatter(logging.Formatter('[%(asctime)s] %(name)s %(message)s', "%H:%M:%S"))
|
|
|
|
else:
|
|
|
|
console_log.setFormatter(logging.Formatter('%(name)s %(message)s', "%H:%M:%S"))
|
|
|
|
|
2015-01-12 02:03:45 +01:00
|
|
|
logging.getLogger('').addHandler(console_log) # Add console logger
|
|
|
|
logging.getLogger('').name = "-" # Remove root prefix
|
|
|
|
|
version 0.2.7, plugin system, multiuser plugin for zeroproxies, reworked imports, cookie parse, stats moved to plugin, usermanager class, dont generate site auth on listing, multiline notifications, allow server side prompt from user, update script keep plugins disabled status
2015-03-24 01:33:09 +01:00
|
|
|
|
2015-01-12 02:03:45 +01:00
|
|
|
# Debug dependent configuration
|
version 0.2.0, new lib for bitcoin ecc, dont display or track notify errors, dont reload again within 1 sec, null peer ip fix, signingmoved to ContentManager, content.json include support, content.json multisig ready, content.json proper bitcoincore compatible signing, content.json include permissions, multithreaded publish, publish timeout 60s, no exception on invalid bitcoin address, testcase for new lib, bip32 based persite privatekey generation, multiuser ready, simple json database query command, websocket api fileGet, wrapper loading title stuck bugfix
2015-02-09 02:09:02 +01:00
|
|
|
from Debug import DebugHook
|
2015-01-12 02:03:45 +01:00
|
|
|
if config.debug:
|
version 0.2.7, plugin system, multiuser plugin for zeroproxies, reworked imports, cookie parse, stats moved to plugin, usermanager class, dont generate site auth on listing, multiline notifications, allow server side prompt from user, update script keep plugins disabled status
2015-03-24 01:33:09 +01:00
|
|
|
console_log.setLevel(logging.DEBUG) # Display everything to console
|
2015-01-12 02:03:45 +01:00
|
|
|
from gevent import monkey; monkey.patch_all(thread=False) # thread=False because of pyfilesystem
|
|
|
|
else:
|
version 0.2.7, plugin system, multiuser plugin for zeroproxies, reworked imports, cookie parse, stats moved to plugin, usermanager class, dont generate site auth on listing, multiline notifications, allow server side prompt from user, update script keep plugins disabled status
2015-03-24 01:33:09 +01:00
|
|
|
console_log.setLevel(logging.INFO) # Display only important info to console
|
|
|
|
from gevent import monkey; monkey.patch_all() # Make time, thread, socket gevent compatible
|
|
|
|
|
2015-01-12 02:03:45 +01:00
|
|
|
import gevent
|
|
|
|
import time
|
|
|
|
|
version 0.2.7, plugin system, multiuser plugin for zeroproxies, reworked imports, cookie parse, stats moved to plugin, usermanager class, dont generate site auth on listing, multiline notifications, allow server side prompt from user, update script keep plugins disabled status
2015-03-24 01:33:09 +01:00
|
|
|
# Log current config
|
2015-03-19 21:19:14 +01:00
|
|
|
logging.debug("Config: %s" % config)
|
2015-01-12 02:03:45 +01:00
|
|
|
|
version 0.2.7, plugin system, multiuser plugin for zeroproxies, reworked imports, cookie parse, stats moved to plugin, usermanager class, dont generate site auth on listing, multiline notifications, allow server side prompt from user, update script keep plugins disabled status
2015-03-24 01:33:09 +01:00
|
|
|
|
2015-04-12 23:59:22 +02:00
|
|
|
# Socks Proxy monkey patch
|
|
|
|
if config.proxy:
|
|
|
|
from util import SocksProxy
|
|
|
|
import urllib2
|
|
|
|
logging.info("Patching sockets to socks proxy: %s" % config.proxy)
|
|
|
|
config.disable_zeromq = True # ZeroMQ doesnt support proxy
|
|
|
|
config.fileserver_ip = '127.0.0.1' # Do not accept connections anywhere but localhost
|
|
|
|
SocksProxy.monkeyPath(*config.proxy.split(":"))
|
|
|
|
|
|
|
|
|
version 0.2.7, plugin system, multiuser plugin for zeroproxies, reworked imports, cookie parse, stats moved to plugin, usermanager class, dont generate site auth on listing, multiline notifications, allow server side prompt from user, update script keep plugins disabled status
2015-03-24 01:33:09 +01:00
|
|
|
# Load plugins
|
|
|
|
from Plugin import PluginManager
|
|
|
|
PluginManager.plugin_manager.loadPlugins()
|
|
|
|
|
|
|
|
|
|
|
|
# -- Actions --
|
|
|
|
|
2015-01-12 19:11:35 +01:00
|
|
|
# Starts here when running zeronet.py
|
|
|
|
def start():
|
|
|
|
action_func = globals()[config.action] # Function reference
|
|
|
|
action_kwargs = config.getActionArguments() # non-config arguments when calling zeronet.py
|
|
|
|
|
|
|
|
action_func(**action_kwargs)
|
|
|
|
|
2015-01-12 02:03:45 +01:00
|
|
|
|
|
|
|
# Start serving UiServer and PeerServer
|
|
|
|
def main():
|
2015-03-19 21:19:14 +01:00
|
|
|
logging.info("Version: %s, Python %s, Gevent: %s" % (config.version, sys.version, gevent.__version__))
|
2015-02-20 01:37:12 +01:00
|
|
|
global ui_server, file_server
|
2015-01-12 02:03:45 +01:00
|
|
|
from File import FileServer
|
|
|
|
from Ui import UiServer
|
|
|
|
logging.info("Creating UiServer....")
|
|
|
|
ui_server = UiServer()
|
|
|
|
|
|
|
|
logging.info("Creating FileServer....")
|
|
|
|
file_server = FileServer()
|
|
|
|
|
|
|
|
logging.info("Starting servers....")
|
|
|
|
gevent.joinall([gevent.spawn(ui_server.start), gevent.spawn(file_server.start)])
|
|
|
|
|
|
|
|
|
|
|
|
# Site commands
|
|
|
|
|
|
|
|
def siteCreate():
|
|
|
|
logging.info("Generating new privatekey...")
|
version 0.2.7, plugin system, multiuser plugin for zeroproxies, reworked imports, cookie parse, stats moved to plugin, usermanager class, dont generate site auth on listing, multiline notifications, allow server side prompt from user, update script keep plugins disabled status
2015-03-24 01:33:09 +01:00
|
|
|
from Crypt import CryptBitcoin
|
2015-01-12 02:03:45 +01:00
|
|
|
privatekey = CryptBitcoin.newPrivatekey()
|
2015-01-20 02:47:00 +01:00
|
|
|
logging.info("----------------------------------------------------------------------")
|
|
|
|
logging.info("Site private key: %s" % privatekey)
|
|
|
|
logging.info(" !!! ^ Save it now, required to modify the site ^ !!!")
|
2015-01-12 02:03:45 +01:00
|
|
|
address = CryptBitcoin.privatekeyToAddress(privatekey)
|
2015-01-20 02:47:00 +01:00
|
|
|
logging.info("Site address: %s" % address)
|
|
|
|
logging.info("----------------------------------------------------------------------")
|
|
|
|
|
|
|
|
while True:
|
|
|
|
if raw_input("? Have you secured your private key? (yes, no) > ").lower() == "yes": break
|
|
|
|
else: logging.info("Please, secure it now, you going to need it to modify your site!")
|
2015-01-12 02:03:45 +01:00
|
|
|
|
|
|
|
logging.info("Creating directory structure...")
|
|
|
|
from Site import Site
|
|
|
|
os.mkdir("data/%s" % address)
|
|
|
|
open("data/%s/index.html" % address, "w").write("Hello %s!" % address)
|
|
|
|
|
|
|
|
logging.info("Creating content.json...")
|
|
|
|
site = Site(address)
|
version 0.2.0, new lib for bitcoin ecc, dont display or track notify errors, dont reload again within 1 sec, null peer ip fix, signingmoved to ContentManager, content.json include support, content.json multisig ready, content.json proper bitcoincore compatible signing, content.json include permissions, multithreaded publish, publish timeout 60s, no exception on invalid bitcoin address, testcase for new lib, bip32 based persite privatekey generation, multiuser ready, simple json database query command, websocket api fileGet, wrapper loading title stuck bugfix
2015-02-09 02:09:02 +01:00
|
|
|
site.content_manager.sign(privatekey=privatekey)
|
2015-01-14 02:41:13 +01:00
|
|
|
site.settings["own"] = True
|
|
|
|
site.saveSettings()
|
2015-01-12 02:03:45 +01:00
|
|
|
|
|
|
|
logging.info("Site created!")
|
|
|
|
|
|
|
|
|
version 0.2.0, new lib for bitcoin ecc, dont display or track notify errors, dont reload again within 1 sec, null peer ip fix, signingmoved to ContentManager, content.json include support, content.json multisig ready, content.json proper bitcoincore compatible signing, content.json include permissions, multithreaded publish, publish timeout 60s, no exception on invalid bitcoin address, testcase for new lib, bip32 based persite privatekey generation, multiuser ready, simple json database query command, websocket api fileGet, wrapper loading title stuck bugfix
2015-02-09 02:09:02 +01:00
|
|
|
def siteSign(address, privatekey=None, inner_path="content.json"):
|
2015-01-12 02:03:45 +01:00
|
|
|
from Site import Site
|
|
|
|
logging.info("Signing site: %s..." % address)
|
|
|
|
site = Site(address, allow_create = False)
|
|
|
|
|
|
|
|
if not privatekey: # If no privatekey in args then ask it now
|
|
|
|
import getpass
|
|
|
|
privatekey = getpass.getpass("Private key (input hidden):")
|
2015-04-08 01:57:55 +02:00
|
|
|
site.content_manager.sign(inner_path=inner_path, privatekey=privatekey, update_changed_files=True)
|
2015-01-12 02:03:45 +01:00
|
|
|
|
|
|
|
|
|
|
|
def siteVerify(address):
|
|
|
|
from Site import Site
|
|
|
|
logging.info("Verifing site: %s..." % address)
|
|
|
|
site = Site(address)
|
|
|
|
|
version 0.2.0, new lib for bitcoin ecc, dont display or track notify errors, dont reload again within 1 sec, null peer ip fix, signingmoved to ContentManager, content.json include support, content.json multisig ready, content.json proper bitcoincore compatible signing, content.json include permissions, multithreaded publish, publish timeout 60s, no exception on invalid bitcoin address, testcase for new lib, bip32 based persite privatekey generation, multiuser ready, simple json database query command, websocket api fileGet, wrapper loading title stuck bugfix
2015-02-09 02:09:02 +01:00
|
|
|
for content_inner_path in site.content_manager.contents:
|
|
|
|
logging.info("Verifing %s signature..." % content_inner_path)
|
2015-03-19 21:19:14 +01:00
|
|
|
if site.content_manager.verifyFile(content_inner_path, site.storage.open(content_inner_path, "rb"), ignore_same=False) == True:
|
version 0.2.0, new lib for bitcoin ecc, dont display or track notify errors, dont reload again within 1 sec, null peer ip fix, signingmoved to ContentManager, content.json include support, content.json multisig ready, content.json proper bitcoincore compatible signing, content.json include permissions, multithreaded publish, publish timeout 60s, no exception on invalid bitcoin address, testcase for new lib, bip32 based persite privatekey generation, multiuser ready, simple json database query command, websocket api fileGet, wrapper loading title stuck bugfix
2015-02-09 02:09:02 +01:00
|
|
|
logging.info("[OK] %s signed by address %s!" % (content_inner_path, address))
|
|
|
|
else:
|
|
|
|
logging.error("[ERROR] %s not signed by address %s!" % (content_inner_path, address))
|
2015-01-12 02:03:45 +01:00
|
|
|
|
|
|
|
logging.info("Verifying site files...")
|
2015-03-19 21:19:14 +01:00
|
|
|
bad_files = site.storage.verifyFiles()
|
2015-01-12 02:03:45 +01:00
|
|
|
if not bad_files:
|
2015-01-18 22:52:19 +01:00
|
|
|
logging.info("[OK] All file sha512sum matches!")
|
2015-01-12 02:03:45 +01:00
|
|
|
else:
|
|
|
|
logging.error("[ERROR] Error during verifying site files!")
|
|
|
|
|
|
|
|
|
2015-03-19 21:19:14 +01:00
|
|
|
def dbRebuild(address):
|
|
|
|
from Site import Site
|
|
|
|
logging.info("Rebuilding site sql cache: %s..." % address)
|
|
|
|
site = Site(address)
|
|
|
|
s = time.time()
|
|
|
|
site.storage.rebuildDb()
|
|
|
|
logging.info("Done in %.3fs" % (time.time()-s))
|
|
|
|
|
|
|
|
|
|
|
|
def dbQuery(address, query):
|
|
|
|
from Site import Site
|
|
|
|
import json
|
|
|
|
site = Site(address)
|
|
|
|
result = []
|
|
|
|
for row in site.storage.query(query):
|
|
|
|
result.append(dict(row))
|
|
|
|
print json.dumps(result, indent=4)
|
|
|
|
|
|
|
|
|
2015-01-12 02:03:45 +01:00
|
|
|
def siteAnnounce(address):
|
|
|
|
from Site.Site import Site
|
|
|
|
logging.info("Announcing site %s to tracker..." % address)
|
|
|
|
site = Site(address)
|
|
|
|
|
|
|
|
s = time.time()
|
|
|
|
site.announce()
|
|
|
|
print "Response time: %.3fs" % (time.time()-s)
|
|
|
|
print site.peers
|
|
|
|
|
|
|
|
|
|
|
|
def siteNeedFile(address, inner_path):
|
|
|
|
from Site import Site
|
|
|
|
site = Site(address)
|
|
|
|
site.announce()
|
|
|
|
print site.needFile(inner_path, update=True)
|
|
|
|
|
|
|
|
|
version 0.2.0, new lib for bitcoin ecc, dont display or track notify errors, dont reload again within 1 sec, null peer ip fix, signingmoved to ContentManager, content.json include support, content.json multisig ready, content.json proper bitcoincore compatible signing, content.json include permissions, multithreaded publish, publish timeout 60s, no exception on invalid bitcoin address, testcase for new lib, bip32 based persite privatekey generation, multiuser ready, simple json database query command, websocket api fileGet, wrapper loading title stuck bugfix
2015-02-09 02:09:02 +01:00
|
|
|
def sitePublish(address, peer_ip=None, peer_port=15441, inner_path="content.json"):
|
version 0.2.4, peerPing and peerGetFile commands, old content update bugfix, new network code and protocol, connection share between sites, connection reuse, dont retry bad file more than 3 times in 20 min, multi threaded include file download, shuffle peers before publish, simple internal stats page, dont retry on failed peers, more than 10 peers publish bugfix
2015-02-23 23:33:31 +01:00
|
|
|
global file_server
|
2015-01-12 02:03:45 +01:00
|
|
|
from Site import Site
|
|
|
|
from File import FileServer # We need fileserver to handle incoming file requests
|
version 0.2.4, peerPing and peerGetFile commands, old content update bugfix, new network code and protocol, connection share between sites, connection reuse, dont retry bad file more than 3 times in 20 min, multi threaded include file download, shuffle peers before publish, simple internal stats page, dont retry on failed peers, more than 10 peers publish bugfix
2015-02-23 23:33:31 +01:00
|
|
|
|
2015-01-12 02:03:45 +01:00
|
|
|
logging.info("Creating FileServer....")
|
|
|
|
file_server = FileServer()
|
|
|
|
file_server_thread = gevent.spawn(file_server.start, check_sites=False) # Dont check every site integrity
|
|
|
|
file_server.openport()
|
|
|
|
if file_server.port_opened == False:
|
|
|
|
logging.info("Port not opened, passive publishing not supported yet :(")
|
|
|
|
return
|
|
|
|
site = file_server.sites[address]
|
|
|
|
site.settings["serving"] = True # Serving the site even if its disabled
|
2015-01-16 11:52:42 +01:00
|
|
|
if peer_ip: # Announce ip specificed
|
|
|
|
site.addPeer(peer_ip, peer_port)
|
|
|
|
else: # Just ask the tracker
|
|
|
|
logging.info("Gathering peers from tracker")
|
|
|
|
site.announce() # Gather peers
|
version 0.2.0, new lib for bitcoin ecc, dont display or track notify errors, dont reload again within 1 sec, null peer ip fix, signingmoved to ContentManager, content.json include support, content.json multisig ready, content.json proper bitcoincore compatible signing, content.json include permissions, multithreaded publish, publish timeout 60s, no exception on invalid bitcoin address, testcase for new lib, bip32 based persite privatekey generation, multiuser ready, simple json database query command, websocket api fileGet, wrapper loading title stuck bugfix
2015-02-09 02:09:02 +01:00
|
|
|
site.publish(20, inner_path) # Push to 20 peers
|
2015-04-12 23:59:22 +02:00
|
|
|
time.sleep(3)
|
2015-04-08 01:57:55 +02:00
|
|
|
logging.info("Serving files...")
|
2015-01-12 02:03:45 +01:00
|
|
|
gevent.joinall([file_server_thread])
|
2015-04-08 01:57:55 +02:00
|
|
|
logging.info("Done.")
|
|
|
|
|
2015-01-12 02:03:45 +01:00
|
|
|
|
|
|
|
|
|
|
|
# Crypto commands
|
|
|
|
|
|
|
|
def cryptoPrivatekeyToAddress(privatekey=None):
|
version 0.2.7, plugin system, multiuser plugin for zeroproxies, reworked imports, cookie parse, stats moved to plugin, usermanager class, dont generate site auth on listing, multiline notifications, allow server side prompt from user, update script keep plugins disabled status
2015-03-24 01:33:09 +01:00
|
|
|
from Crypt import CryptBitcoin
|
2015-01-12 02:03:45 +01:00
|
|
|
if not privatekey: # If no privatekey in args then ask it now
|
|
|
|
import getpass
|
|
|
|
privatekey = getpass.getpass("Private key (input hidden):")
|
|
|
|
|
|
|
|
print CryptBitcoin.privatekeyToAddress(privatekey)
|
|
|
|
|
|
|
|
|
|
|
|
# Peer
|
|
|
|
|
version 0.2.4, peerPing and peerGetFile commands, old content update bugfix, new network code and protocol, connection share between sites, connection reuse, dont retry bad file more than 3 times in 20 min, multi threaded include file download, shuffle peers before publish, simple internal stats page, dont retry on failed peers, more than 10 peers publish bugfix
2015-02-23 23:33:31 +01:00
|
|
|
def peerPing(peer_ip, peer_port):
|
|
|
|
logging.info("Opening a simple connection server")
|
|
|
|
global file_server
|
|
|
|
from Connection import ConnectionServer
|
|
|
|
file_server = ConnectionServer("127.0.0.1", 1234)
|
|
|
|
|
2015-01-12 02:03:45 +01:00
|
|
|
from Peer import Peer
|
2015-04-12 23:59:22 +02:00
|
|
|
logging.info("Pinging 5 times peer: %s:%s..." % (peer_ip, int(peer_port)))
|
version 0.2.4, peerPing and peerGetFile commands, old content update bugfix, new network code and protocol, connection share between sites, connection reuse, dont retry bad file more than 3 times in 20 min, multi threaded include file download, shuffle peers before publish, simple internal stats page, dont retry on failed peers, more than 10 peers publish bugfix
2015-02-23 23:33:31 +01:00
|
|
|
peer = Peer(peer_ip, peer_port)
|
2015-01-12 02:03:45 +01:00
|
|
|
for i in range(5):
|
|
|
|
s = time.time()
|
|
|
|
print peer.ping(),
|
|
|
|
print "Response time: %.3fs" % (time.time()-s)
|
|
|
|
time.sleep(1)
|
|
|
|
|
|
|
|
|
version 0.2.4, peerPing and peerGetFile commands, old content update bugfix, new network code and protocol, connection share between sites, connection reuse, dont retry bad file more than 3 times in 20 min, multi threaded include file download, shuffle peers before publish, simple internal stats page, dont retry on failed peers, more than 10 peers publish bugfix
2015-02-23 23:33:31 +01:00
|
|
|
def peerGetFile(peer_ip, peer_port, site, filename):
|
|
|
|
logging.info("Opening a simple connection server")
|
|
|
|
global file_server
|
|
|
|
from Connection import ConnectionServer
|
|
|
|
file_server = ConnectionServer()
|
|
|
|
|
2015-01-12 02:03:45 +01:00
|
|
|
from Peer import Peer
|
version 0.2.4, peerPing and peerGetFile commands, old content update bugfix, new network code and protocol, connection share between sites, connection reuse, dont retry bad file more than 3 times in 20 min, multi threaded include file download, shuffle peers before publish, simple internal stats page, dont retry on failed peers, more than 10 peers publish bugfix
2015-02-23 23:33:31 +01:00
|
|
|
logging.info("Getting %s/%s from peer: %s:%s..." % (site, filename, peer_ip, peer_port))
|
|
|
|
peer = Peer(peer_ip, peer_port)
|
2015-01-12 02:03:45 +01:00
|
|
|
s = time.time()
|
|
|
|
print peer.getFile(site, filename).read()
|
|
|
|
print "Response time: %.3fs" % (time.time()-s)
|
|
|
|
|