2015-02-10 00:08:25 +01:00
|
|
|
import time, re, os, mimetypes, json, cgi
|
2015-01-12 02:03:45 +01:00
|
|
|
from Config import config
|
|
|
|
from Site import SiteManager
|
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 User import UserManager
|
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 Plugin import PluginManager
|
2015-01-12 02:03:45 +01:00
|
|
|
from Ui.UiWebsocket import UiWebsocket
|
|
|
|
|
|
|
|
status_texts = {
|
|
|
|
200: "200 OK",
|
|
|
|
400: "400 Bad Request",
|
|
|
|
403: "403 Forbidden",
|
|
|
|
404: "404 Not Found",
|
version 0.2.8, Namecoin domains using internal resolver site, --disable_zeromq option to skip backward compatiblity layer and save some memory, connectionserver firstchar error fixes, missing unpacker crash fix, sitemanager class to allow extensions, add loaded plugin list to websocket api, faster content publishing, mark updating file as bad, remove coppersurfer tracker add eddie4, internal server error with error displaying, allow site domains in UiRequest, better progress bar, wait for siteinfo before before using localstorage, csslater hide only if opacity is 0
2015-03-30 23:44:29 +02:00
|
|
|
500: "500 Internal Server Error",
|
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
|
|
|
@PluginManager.acceptPlugins
|
|
|
|
class UiRequest(object):
|
2015-04-12 23:59:22 +02:00
|
|
|
def __init__(self, server, get, env, start_response):
|
2015-01-12 02:03:45 +01:00
|
|
|
if server:
|
|
|
|
self.server = server
|
|
|
|
self.log = server.log
|
2015-04-12 23:59:22 +02:00
|
|
|
self.get = get # Get parameters
|
|
|
|
self.env = env # Enviroment settings
|
|
|
|
self.start_response = start_response # Start response function
|
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
|
|
|
self.user = None
|
2015-01-12 02:03:45 +01:00
|
|
|
|
|
|
|
|
|
|
|
# Call the request handler function base on path
|
|
|
|
def route(self, path):
|
2015-04-19 15:38:41 +02:00
|
|
|
if config.ui_restrict and self.env['REMOTE_ADDR'] not in config.ui_restrict: # Restict Ui access by ip
|
2015-01-12 02:03:45 +01:00
|
|
|
return self.error403()
|
|
|
|
|
2015-04-20 02:56:33 +02:00
|
|
|
path = re.sub("^http://zero[/]+", "/", path) # Remove begining http://zero/ for chrome extension
|
|
|
|
path = re.sub("^http://", "/", path) # Remove begining http for chrome extension .bit access
|
|
|
|
|
2015-01-12 02:03:45 +01:00
|
|
|
if path == "/":
|
|
|
|
return self.actionIndex()
|
2015-04-20 02:56:33 +02:00
|
|
|
elif path.endswith("favicon.ico"):
|
2015-01-12 02:03:45 +01:00
|
|
|
return self.actionFile("src/Ui/media/img/favicon.ico")
|
|
|
|
# Media
|
|
|
|
elif path.startswith("/uimedia/"):
|
|
|
|
return self.actionUiMedia(path)
|
|
|
|
elif path.startswith("/media"):
|
|
|
|
return self.actionSiteMedia(path)
|
|
|
|
# Websocket
|
|
|
|
elif path == "/Websocket":
|
|
|
|
return self.actionWebsocket()
|
|
|
|
# Debug
|
|
|
|
elif path == "/Debug" and config.debug:
|
|
|
|
return self.actionDebug()
|
|
|
|
elif path == "/Console" and config.debug:
|
|
|
|
return self.actionConsole()
|
|
|
|
# Site media wrapper
|
|
|
|
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
|
|
|
body = self.actionWrapper(path)
|
|
|
|
if body:
|
|
|
|
return body
|
|
|
|
else:
|
|
|
|
func = getattr(self, "action"+path.lstrip("/"), None) # Check if we have action+request_path function
|
|
|
|
if func:
|
|
|
|
return func()
|
|
|
|
else:
|
|
|
|
return self.error404(path)
|
2015-01-12 02:03:45 +01:00
|
|
|
|
|
|
|
|
2015-04-20 02:56:33 +02:00
|
|
|
# The request is proxied by chrome extension
|
|
|
|
def isProxyRequest(self):
|
|
|
|
return self.env["PATH_INFO"].startswith("http://")
|
|
|
|
|
|
|
|
|
2015-04-20 22:31:29 +02:00
|
|
|
def isAjaxRequest(self):
|
|
|
|
return self.env.get("HTTP_X_REQUESTED_WITH") == "XMLHttpRequest"
|
|
|
|
|
|
|
|
|
2015-01-12 02:03:45 +01:00
|
|
|
# Get mime by filename
|
|
|
|
def getContentType(self, file_name):
|
|
|
|
content_type = mimetypes.guess_type(file_name)[0]
|
|
|
|
if not content_type:
|
|
|
|
if file_name.endswith("json"): # Correct json header
|
|
|
|
content_type = "application/json"
|
|
|
|
else:
|
|
|
|
content_type = "application/octet-stream"
|
|
|
|
return content_type
|
|
|
|
|
|
|
|
|
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
|
|
|
# Returns: <dict> Cookies based on self.env
|
|
|
|
def getCookies(self):
|
|
|
|
raw_cookies = self.env.get('HTTP_COOKIE')
|
|
|
|
if raw_cookies:
|
|
|
|
cookies = cgi.parse_qsl(raw_cookies)
|
|
|
|
return {key.strip(): val for key, val in cookies}
|
|
|
|
else:
|
|
|
|
return {}
|
|
|
|
|
|
|
|
|
|
|
|
def getCurrentUser(self):
|
|
|
|
if self.user: return self.user # Cache
|
|
|
|
self.user = UserManager.user_manager.get() # Get user
|
|
|
|
if not self.user:
|
|
|
|
self.user = UserManager.user_manager.create()
|
|
|
|
return self.user
|
|
|
|
|
|
|
|
|
2015-01-12 02:03:45 +01:00
|
|
|
# Send response headers
|
2015-01-24 19:14:29 +01:00
|
|
|
def sendHeader(self, status=200, content_type="text/html", extra_headers=[]):
|
|
|
|
if content_type == "text/html": content_type = "text/html; charset=utf-8"
|
2015-01-12 02:03:45 +01:00
|
|
|
headers = []
|
|
|
|
headers.append(("Version", "HTTP/1.1"))
|
|
|
|
headers.append(("Access-Control-Allow-Origin", "*")) # Allow json access
|
2015-04-20 22:31:29 +02:00
|
|
|
if self.env["REQUEST_METHOD"] == "OPTIONS":
|
|
|
|
headers.append(("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept")) # Allow json access
|
|
|
|
|
2015-04-24 02:36:00 +02:00
|
|
|
if (self.env["REQUEST_METHOD"] == "OPTIONS" or not self.isAjaxRequest()) and status == 200 and (content_type == "text/css" or content_type.startswith("application") or self.env["REQUEST_METHOD"] == "OPTIONS" or content_type.startswith("image")): # Cache Css, Js, Image files for 10min
|
2015-04-20 22:31:29 +02:00
|
|
|
headers.append(("Cache-Control", "public, max-age=600")) # Cache 10 min
|
|
|
|
else: # Images, Css, Js
|
|
|
|
headers.append(("Cache-Control", "no-cache, no-store, private, must-revalidate, max-age=0")) # No caching at all
|
2015-01-12 02:03:45 +01:00
|
|
|
#headers.append(("Cache-Control", "public, max-age=604800")) # Cache 1 week
|
|
|
|
headers.append(("Content-Type", content_type))
|
|
|
|
for extra_header in extra_headers:
|
|
|
|
headers.append(extra_header)
|
2015-04-18 03:02:08 +02:00
|
|
|
return self.start_response(status_texts[status], headers)
|
2015-01-12 02:03:45 +01:00
|
|
|
|
|
|
|
|
|
|
|
# Renders a template
|
|
|
|
def render(self, template_path, *args, **kwargs):
|
|
|
|
#template = SimpleTemplate(open(template_path), lookup=[os.path.dirname(template_path)])
|
|
|
|
#yield str(template.render(*args, **kwargs).encode("utf8"))
|
2015-01-26 01:43:39 +01:00
|
|
|
template = open(template_path).read().decode("utf8")
|
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
|
|
|
return template.format(**kwargs).encode("utf8")
|
2015-01-12 02:03:45 +01:00
|
|
|
|
|
|
|
|
|
|
|
# - Actions -
|
|
|
|
|
|
|
|
# Redirect to an url
|
|
|
|
def actionRedirect(self, url):
|
|
|
|
self.start_response('301 Redirect', [('Location', url)])
|
|
|
|
yield "Location changed: %s" % url
|
|
|
|
|
|
|
|
|
|
|
|
def actionIndex(self):
|
|
|
|
return self.actionRedirect("/"+config.homepage)
|
|
|
|
|
|
|
|
|
|
|
|
# Render a file from media with iframe site wrapper
|
version 0.2.8, Namecoin domains using internal resolver site, --disable_zeromq option to skip backward compatiblity layer and save some memory, connectionserver firstchar error fixes, missing unpacker crash fix, sitemanager class to allow extensions, add loaded plugin list to websocket api, faster content publishing, mark updating file as bad, remove coppersurfer tracker add eddie4, internal server error with error displaying, allow site domains in UiRequest, better progress bar, wait for siteinfo before before using localstorage, csslater hide only if opacity is 0
2015-03-30 23:44:29 +02:00
|
|
|
def actionWrapper(self, path, extra_headers=None):
|
|
|
|
if not extra_headers: extra_headers = []
|
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 self.get.get("wrapper") == "False": return self.actionSiteMedia("/media"+path) # Only serve html files with frame
|
2015-01-12 02:03:45 +01:00
|
|
|
|
version 0.2.8, Namecoin domains using internal resolver site, --disable_zeromq option to skip backward compatiblity layer and save some memory, connectionserver firstchar error fixes, missing unpacker crash fix, sitemanager class to allow extensions, add loaded plugin list to websocket api, faster content publishing, mark updating file as bad, remove coppersurfer tracker add eddie4, internal server error with error displaying, allow site domains in UiRequest, better progress bar, wait for siteinfo before before using localstorage, csslater hide only if opacity is 0
2015-03-30 23:44:29 +02:00
|
|
|
match = re.match("/(?P<address>[A-Za-z0-9\._-]+)(?P<inner_path>/.*|$)", path)
|
2015-01-12 02:03:45 +01:00
|
|
|
if match:
|
version 0.2.8, Namecoin domains using internal resolver site, --disable_zeromq option to skip backward compatiblity layer and save some memory, connectionserver firstchar error fixes, missing unpacker crash fix, sitemanager class to allow extensions, add loaded plugin list to websocket api, faster content publishing, mark updating file as bad, remove coppersurfer tracker add eddie4, internal server error with error displaying, allow site domains in UiRequest, better progress bar, wait for siteinfo before before using localstorage, csslater hide only if opacity is 0
2015-03-30 23:44:29 +02:00
|
|
|
address = match.group("address")
|
2015-01-12 02:03:45 +01:00
|
|
|
inner_path = match.group("inner_path").lstrip("/")
|
version 0.2.8, Namecoin domains using internal resolver site, --disable_zeromq option to skip backward compatiblity layer and save some memory, connectionserver firstchar error fixes, missing unpacker crash fix, sitemanager class to allow extensions, add loaded plugin list to websocket api, faster content publishing, mark updating file as bad, remove coppersurfer tracker add eddie4, internal server error with error displaying, allow site domains in UiRequest, better progress bar, wait for siteinfo before before using localstorage, csslater hide only if opacity is 0
2015-03-30 23:44:29 +02:00
|
|
|
if "." in inner_path and not inner_path.endswith(".html"): return self.actionSiteMedia("/media"+path) # Only serve html files with frame
|
|
|
|
if self.env.get("HTTP_X_REQUESTED_WITH"): return self.error403("Ajax request not allowed to load wrapper") # No ajax allowed on wrapper
|
|
|
|
|
2015-04-20 02:56:33 +02:00
|
|
|
file_inner_path = inner_path
|
|
|
|
if not file_inner_path: file_inner_path = "index.html" # If inner path defaults to index.html
|
|
|
|
|
|
|
|
if not inner_path and not path.endswith("/"): inner_path = address+"/" # Fix relative resources loading if missing / end of site address
|
|
|
|
inner_path = re.sub(".*/(.+)", "\\1", inner_path) # Load innerframe relative to current url
|
2015-01-12 02:03:45 +01:00
|
|
|
|
version 0.2.8, Namecoin domains using internal resolver site, --disable_zeromq option to skip backward compatiblity layer and save some memory, connectionserver firstchar error fixes, missing unpacker crash fix, sitemanager class to allow extensions, add loaded plugin list to websocket api, faster content publishing, mark updating file as bad, remove coppersurfer tracker add eddie4, internal server error with error displaying, allow site domains in UiRequest, better progress bar, wait for siteinfo before before using localstorage, csslater hide only if opacity is 0
2015-03-30 23:44:29 +02:00
|
|
|
site = SiteManager.site_manager.get(address)
|
|
|
|
|
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
|
|
|
if site and site.content_manager.contents.get("content.json") and (not site.getReachableBadFiles() or site.settings["own"]): # Its downloaded or own
|
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
|
|
|
title = site.content_manager.contents["content.json"]["title"]
|
2015-01-12 02:03:45 +01:00
|
|
|
else:
|
version 0.2.8, Namecoin domains using internal resolver site, --disable_zeromq option to skip backward compatiblity layer and save some memory, connectionserver firstchar error fixes, missing unpacker crash fix, sitemanager class to allow extensions, add loaded plugin list to websocket api, faster content publishing, mark updating file as bad, remove coppersurfer tracker add eddie4, internal server error with error displaying, allow site domains in UiRequest, better progress bar, wait for siteinfo before before using localstorage, csslater hide only if opacity is 0
2015-03-30 23:44:29 +02:00
|
|
|
title = "Loading %s..." % address
|
|
|
|
site = SiteManager.site_manager.need(address) # Start download site
|
|
|
|
|
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
|
|
|
if not site: return False
|
|
|
|
|
version 0.3.0, rev187, Trusted authorization sites support, --publish option on signing, cryptSign command line option, OpenSSL enabled on OSX, Crypto verify allows list of valid addresses, Option for version 2 json DB tables, DbCursor SELECT parameters bugfix, Add peer to site on ListModified, Download blind includes when new site added, Publish command better messages, Multi-threaded announce, New http Torrent trackers, Wait for dbschema.json on query, Handle json import errors, More compact writeJson storage command, Testcase for signing and verifying, Workaround to make non target=_top links work, More clean UiWebsocket command route, Send cert_user_id on siteinfo, Notify other local clients on local file modify, Option to wait for file download before sql query, File rules websocket API command, Cert add and select, set websocket API command, Put focus on innerframe, innerloaded wrapper api command to add hashtag, Allow more file error on big sites, Keep worker running after stuked on done task, New more stable openSSL layer that works on OSX, Noparallel parameter bugfix, RateLimit allowed again interval bugfix, Updater skips non-writeable files, Try to close openssl dll before update
2015-05-25 01:26:33 +02:00
|
|
|
#extra_headers.append(("X-Frame-Options", "DENY"))
|
2015-01-12 02:03:45 +01:00
|
|
|
|
version 0.2.8, Namecoin domains using internal resolver site, --disable_zeromq option to skip backward compatiblity layer and save some memory, connectionserver firstchar error fixes, missing unpacker crash fix, sitemanager class to allow extensions, add loaded plugin list to websocket api, faster content publishing, mark updating file as bad, remove coppersurfer tracker add eddie4, internal server error with error displaying, allow site domains in UiRequest, better progress bar, wait for siteinfo before before using localstorage, csslater hide only if opacity is 0
2015-03-30 23:44:29 +02:00
|
|
|
self.sendHeader(extra_headers=extra_headers[:])
|
2015-01-24 19:14:29 +01:00
|
|
|
|
|
|
|
# Wrapper variable inits
|
2015-02-10 00:08:25 +01:00
|
|
|
query_string = ""
|
2015-01-24 19:14:29 +01:00
|
|
|
body_style = ""
|
2015-02-10 00:08:25 +01:00
|
|
|
meta_tags = ""
|
|
|
|
|
2015-04-20 02:56:33 +02:00
|
|
|
if self.env.get("QUERY_STRING"): query_string = "?"+self.env["QUERY_STRING"]+"&wrapper=False"
|
|
|
|
else: query_string = "?wrapper=False"
|
|
|
|
|
|
|
|
if self.isProxyRequest(): # Its a remote proxy request
|
|
|
|
server_url = "http://%s:%s" % (self.env["SERVER_NAME"], self.env["SERVER_PORT"])
|
|
|
|
homepage = "http://zero/"+config.homepage
|
|
|
|
else: # Use relative path
|
|
|
|
server_url = ""
|
|
|
|
homepage = "/"+config.homepage
|
|
|
|
|
2015-02-10 00:08:25 +01:00
|
|
|
if site.content_manager.contents.get("content.json") : # Got content.json
|
|
|
|
content = site.content_manager.contents["content.json"]
|
|
|
|
if content.get("background-color"):
|
|
|
|
body_style += "background-color: "+cgi.escape(site.content_manager.contents["content.json"]["background-color"], True)+";"
|
|
|
|
if content.get("viewport"):
|
|
|
|
meta_tags += '<meta name="viewport" id="viewport" content="%s">' % cgi.escape(content["viewport"], True)
|
2015-01-24 19:14:29 +01:00
|
|
|
|
2015-01-12 02:03:45 +01:00
|
|
|
return self.render("src/Ui/template/wrapper.html",
|
2015-04-20 02:56:33 +02:00
|
|
|
server_url=server_url,
|
2015-01-12 02:03:45 +01:00
|
|
|
inner_path=inner_path,
|
2015-04-20 22:31:29 +02:00
|
|
|
file_inner_path=file_inner_path,
|
version 0.2.8, Namecoin domains using internal resolver site, --disable_zeromq option to skip backward compatiblity layer and save some memory, connectionserver firstchar error fixes, missing unpacker crash fix, sitemanager class to allow extensions, add loaded plugin list to websocket api, faster content publishing, mark updating file as bad, remove coppersurfer tracker add eddie4, internal server error with error displaying, allow site domains in UiRequest, better progress bar, wait for siteinfo before before using localstorage, csslater hide only if opacity is 0
2015-03-30 23:44:29 +02:00
|
|
|
address=address,
|
2015-01-12 02:03:45 +01:00
|
|
|
title=title,
|
2015-01-24 19:14:29 +01:00
|
|
|
body_style=body_style,
|
2015-02-10 00:08:25 +01:00
|
|
|
meta_tags=meta_tags,
|
2015-01-24 19:14:29 +01:00
|
|
|
query_string=query_string,
|
2015-01-18 22:52:19 +01:00
|
|
|
wrapper_key=site.settings["wrapper_key"],
|
2015-01-12 02:03:45 +01:00
|
|
|
permissions=json.dumps(site.settings["permissions"]),
|
2015-04-20 02:56:33 +02:00
|
|
|
show_loadingscreen=json.dumps(not site.storage.isFile(file_inner_path)),
|
2015-05-25 01:41:14 +02:00
|
|
|
rev=config.rev,
|
2015-04-20 02:56:33 +02:00
|
|
|
homepage=homepage
|
2015-01-12 02:03:45 +01:00
|
|
|
)
|
|
|
|
|
|
|
|
else: # Bad url
|
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
|
|
|
return False
|
2015-01-12 02:03:45 +01:00
|
|
|
|
|
|
|
|
version 0.2.8, Namecoin domains using internal resolver site, --disable_zeromq option to skip backward compatiblity layer and save some memory, connectionserver firstchar error fixes, missing unpacker crash fix, sitemanager class to allow extensions, add loaded plugin list to websocket api, faster content publishing, mark updating file as bad, remove coppersurfer tracker add eddie4, internal server error with error displaying, allow site domains in UiRequest, better progress bar, wait for siteinfo before before using localstorage, csslater hide only if opacity is 0
2015-03-30 23:44:29 +02:00
|
|
|
# Returns if media request allowed from that referer
|
|
|
|
def isMediaRequestAllowed(self, site_address, referer):
|
|
|
|
referer_path = re.sub("http[s]{0,1}://.*?/", "/", referer).replace("/media", "") # Remove site address
|
|
|
|
return referer_path.startswith("/"+site_address)
|
|
|
|
|
|
|
|
|
2015-01-12 02:03:45 +01:00
|
|
|
# Serve a media for site
|
|
|
|
def actionSiteMedia(self, path):
|
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
|
|
|
path = path.replace("/index.html/", "/") # Base Backward compatibility fix
|
2015-04-20 02:56:33 +02:00
|
|
|
if path.endswith("/"): path = path+"index.html"
|
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
|
|
|
|
version 0.2.8, Namecoin domains using internal resolver site, --disable_zeromq option to skip backward compatiblity layer and save some memory, connectionserver firstchar error fixes, missing unpacker crash fix, sitemanager class to allow extensions, add loaded plugin list to websocket api, faster content publishing, mark updating file as bad, remove coppersurfer tracker add eddie4, internal server error with error displaying, allow site domains in UiRequest, better progress bar, wait for siteinfo before before using localstorage, csslater hide only if opacity is 0
2015-03-30 23:44:29 +02:00
|
|
|
match = re.match("/media/(?P<address>[A-Za-z0-9\._-]+)/(?P<inner_path>.*)", path)
|
2015-01-12 02:03:45 +01:00
|
|
|
|
|
|
|
referer = self.env.get("HTTP_REFERER")
|
version 0.2.8, Namecoin domains using internal resolver site, --disable_zeromq option to skip backward compatiblity layer and save some memory, connectionserver firstchar error fixes, missing unpacker crash fix, sitemanager class to allow extensions, add loaded plugin list to websocket api, faster content publishing, mark updating file as bad, remove coppersurfer tracker add eddie4, internal server error with error displaying, allow site domains in UiRequest, better progress bar, wait for siteinfo before before using localstorage, csslater hide only if opacity is 0
2015-03-30 23:44:29 +02:00
|
|
|
if referer and match: # Only allow same site to receive media
|
|
|
|
if not self.isMediaRequestAllowed(match.group("address"), referer):
|
2015-04-14 02:37:31 +02:00
|
|
|
return self.error403("Media referrer error") # Referrer not starts same address as requested path
|
2015-01-12 02:03:45 +01:00
|
|
|
|
|
|
|
if match: # Looks like a valid path
|
version 0.2.8, Namecoin domains using internal resolver site, --disable_zeromq option to skip backward compatiblity layer and save some memory, connectionserver firstchar error fixes, missing unpacker crash fix, sitemanager class to allow extensions, add loaded plugin list to websocket api, faster content publishing, mark updating file as bad, remove coppersurfer tracker add eddie4, internal server error with error displaying, allow site domains in UiRequest, better progress bar, wait for siteinfo before before using localstorage, csslater hide only if opacity is 0
2015-03-30 23:44:29 +02:00
|
|
|
address = match.group("address")
|
2015-05-31 15:52:21 +02:00
|
|
|
file_path = "%s/%s/%s" % (config.data_dir, address, match.group("inner_path"))
|
|
|
|
allowed_dir = os.path.abspath("%s/%s" % (config.data_dir, address)) # Only files within data/sitehash allowed
|
2015-04-01 03:05:09 +02:00
|
|
|
data_dir = os.path.abspath("data") # No files from data/ allowed
|
|
|
|
if ".." in file_path or not os.path.dirname(os.path.abspath(file_path)).startswith(allowed_dir) or allowed_dir == data_dir: # File not in allowed path
|
2015-01-12 02:03:45 +01:00
|
|
|
return self.error403()
|
|
|
|
else:
|
|
|
|
if config.debug and file_path.split("/")[-1].startswith("all."): # When debugging merge *.css to all.css and *.js to all.js
|
version 0.2.8, Namecoin domains using internal resolver site, --disable_zeromq option to skip backward compatiblity layer and save some memory, connectionserver firstchar error fixes, missing unpacker crash fix, sitemanager class to allow extensions, add loaded plugin list to websocket api, faster content publishing, mark updating file as bad, remove coppersurfer tracker add eddie4, internal server error with error displaying, allow site domains in UiRequest, better progress bar, wait for siteinfo before before using localstorage, csslater hide only if opacity is 0
2015-03-30 23:44:29 +02:00
|
|
|
site = self.server.sites.get(address)
|
2015-01-12 02:03:45 +01:00
|
|
|
if site.settings["own"]:
|
|
|
|
from Debug import DebugMedia
|
|
|
|
DebugMedia.merge(file_path)
|
|
|
|
if os.path.isfile(file_path): # File exits
|
2015-04-12 23:59:22 +02:00
|
|
|
#self.sendHeader(content_type=self.getContentType(file_path)) # ?? Get Exception without this
|
2015-01-12 02:03:45 +01:00
|
|
|
return self.actionFile(file_path)
|
|
|
|
else: # File not exits, try to download
|
version 0.2.8, Namecoin domains using internal resolver site, --disable_zeromq option to skip backward compatiblity layer and save some memory, connectionserver firstchar error fixes, missing unpacker crash fix, sitemanager class to allow extensions, add loaded plugin list to websocket api, faster content publishing, mark updating file as bad, remove coppersurfer tracker add eddie4, internal server error with error displaying, allow site domains in UiRequest, better progress bar, wait for siteinfo before before using localstorage, csslater hide only if opacity is 0
2015-03-30 23:44:29 +02:00
|
|
|
site = SiteManager.site_manager.need(address, all_file=False)
|
2015-01-14 02:41:13 +01:00
|
|
|
result = site.needFile(match.group("inner_path"), priority=1) # Wait until file downloads
|
2015-04-12 23:59:22 +02:00
|
|
|
if result:
|
|
|
|
#self.sendHeader(content_type=self.getContentType(file_path))
|
|
|
|
return self.actionFile(file_path)
|
|
|
|
else:
|
|
|
|
self.log.debug("File not found: %s" % match.group("inner_path"))
|
2015-04-18 03:02:08 +02:00
|
|
|
return self.error404(match.group("inner_path"))
|
2015-01-12 02:03:45 +01:00
|
|
|
|
|
|
|
else: # Bad url
|
|
|
|
return self.error404(path)
|
|
|
|
|
|
|
|
|
|
|
|
# Serve a media for ui
|
|
|
|
def actionUiMedia(self, path):
|
|
|
|
match = re.match("/uimedia/(?P<inner_path>.*)", path)
|
|
|
|
if match: # Looks like a valid path
|
|
|
|
file_path = "src/Ui/media/%s" % match.group("inner_path")
|
|
|
|
allowed_dir = os.path.abspath("src/Ui/media") # Only files within data/sitehash allowed
|
|
|
|
if ".." in file_path or not os.path.dirname(os.path.abspath(file_path)).startswith(allowed_dir): # File not in allowed path
|
|
|
|
return self.error403()
|
|
|
|
else:
|
|
|
|
if config.debug and match.group("inner_path").startswith("all."): # When debugging merge *.css to all.css and *.js to all.js
|
|
|
|
from Debug import DebugMedia
|
|
|
|
DebugMedia.merge(file_path)
|
|
|
|
return self.actionFile(file_path)
|
|
|
|
else: # Bad url
|
|
|
|
return self.error400()
|
|
|
|
|
|
|
|
|
|
|
|
# Stream a file to client
|
|
|
|
def actionFile(self, file_path, block_size = 64*1024):
|
|
|
|
if os.path.isfile(file_path):
|
|
|
|
# Try to figure out content type by extension
|
|
|
|
content_type = self.getContentType(file_path)
|
|
|
|
|
|
|
|
self.sendHeader(content_type = content_type) # TODO: Dont allow external access: extra_headers=[("Content-Security-Policy", "default-src 'unsafe-inline' data: http://localhost:43110 ws://localhost:43110")]
|
|
|
|
if self.env["REQUEST_METHOD"] != "OPTIONS":
|
|
|
|
file = open(file_path, "rb")
|
|
|
|
while 1:
|
|
|
|
try:
|
|
|
|
block = file.read(block_size)
|
|
|
|
if block:
|
|
|
|
yield block
|
|
|
|
else:
|
|
|
|
raise StopIteration
|
|
|
|
except StopIteration:
|
|
|
|
file.close()
|
|
|
|
break
|
|
|
|
else: # File not exits
|
|
|
|
yield self.error404(file_path)
|
|
|
|
|
|
|
|
|
|
|
|
# On websocket connection
|
|
|
|
def actionWebsocket(self):
|
|
|
|
ws = self.env.get("wsgi.websocket")
|
|
|
|
if ws:
|
2015-01-18 22:52:19 +01:00
|
|
|
wrapper_key = self.get["wrapper_key"]
|
2015-01-27 19:24:24 +01:00
|
|
|
# Find site by wrapper_key
|
2015-01-12 02:03:45 +01:00
|
|
|
site = None
|
|
|
|
for site_check in self.server.sites.values():
|
2015-01-18 22:52:19 +01:00
|
|
|
if site_check.settings["wrapper_key"] == wrapper_key: site = site_check
|
2015-01-12 02:03:45 +01:00
|
|
|
|
2015-01-18 22:52:19 +01:00
|
|
|
if site: # Correct wrapper key
|
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
|
|
|
user = self.getCurrentUser()
|
|
|
|
if not user:
|
|
|
|
self.log.error("No user found")
|
|
|
|
return self.error403()
|
|
|
|
ui_websocket = UiWebsocket(ws, site, self.server, user)
|
2015-01-12 02:03:45 +01:00
|
|
|
site.websockets.append(ui_websocket) # Add to site websockets to allow notify on events
|
|
|
|
ui_websocket.start()
|
|
|
|
for site_check in self.server.sites.values(): # Remove websocket from every site (admin sites allowed to join other sites event channels)
|
|
|
|
if ui_websocket in site_check.websockets:
|
|
|
|
site_check.websockets.remove(ui_websocket)
|
|
|
|
return "Bye."
|
2015-01-18 22:52:19 +01:00
|
|
|
else: # No site found by wrapper key
|
2015-01-27 19:24:24 +01:00
|
|
|
self.log.error("Wrapper key not found: %s" % wrapper_key)
|
2015-01-12 02:03:45 +01:00
|
|
|
return self.error403()
|
|
|
|
else:
|
|
|
|
start_response("400 Bad Request", [])
|
|
|
|
return "Not a websocket!"
|
|
|
|
|
|
|
|
|
|
|
|
# Debug last error
|
|
|
|
def actionDebug(self):
|
|
|
|
# Raise last error from DebugHook
|
|
|
|
import 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
|
|
|
last_error = sys.modules["main"].DebugHook.last_error
|
2015-01-12 02:03:45 +01:00
|
|
|
if last_error:
|
|
|
|
raise last_error[0], last_error[1], last_error[2]
|
|
|
|
else:
|
|
|
|
self.sendHeader()
|
2015-04-12 23:59:22 +02:00
|
|
|
return "No error! :)"
|
2015-01-12 02:03:45 +01:00
|
|
|
|
|
|
|
|
|
|
|
# Just raise an error to get console
|
|
|
|
def actionConsole(self):
|
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
|
|
|
import sys
|
2015-01-17 18:50:56 +01:00
|
|
|
sites = self.server.sites
|
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
|
|
|
main = sys.modules["main"]
|
2015-01-12 02:03:45 +01:00
|
|
|
raise Exception("Here is your console")
|
|
|
|
|
|
|
|
|
|
|
|
# - Tests -
|
|
|
|
|
|
|
|
def actionTestStream(self):
|
|
|
|
self.sendHeader()
|
|
|
|
yield " "*1080 # Overflow browser's buffer
|
|
|
|
yield "He"
|
|
|
|
time.sleep(1)
|
|
|
|
yield "llo!"
|
|
|
|
yield "Running websockets: %s" % len(self.server.websockets)
|
|
|
|
self.server.sendMessage("Hello!")
|
|
|
|
|
|
|
|
|
|
|
|
# - Errors -
|
|
|
|
|
|
|
|
# Send bad request error
|
|
|
|
def error400(self):
|
|
|
|
self.sendHeader(400)
|
|
|
|
return "Bad Request"
|
|
|
|
|
|
|
|
|
|
|
|
# You are not allowed to access this
|
version 0.2.8, Namecoin domains using internal resolver site, --disable_zeromq option to skip backward compatiblity layer and save some memory, connectionserver firstchar error fixes, missing unpacker crash fix, sitemanager class to allow extensions, add loaded plugin list to websocket api, faster content publishing, mark updating file as bad, remove coppersurfer tracker add eddie4, internal server error with error displaying, allow site domains in UiRequest, better progress bar, wait for siteinfo before before using localstorage, csslater hide only if opacity is 0
2015-03-30 23:44:29 +02:00
|
|
|
def error403(self, message="Forbidden"):
|
2015-01-12 02:03:45 +01:00
|
|
|
self.sendHeader(403)
|
version 0.2.8, Namecoin domains using internal resolver site, --disable_zeromq option to skip backward compatiblity layer and save some memory, connectionserver firstchar error fixes, missing unpacker crash fix, sitemanager class to allow extensions, add loaded plugin list to websocket api, faster content publishing, mark updating file as bad, remove coppersurfer tracker add eddie4, internal server error with error displaying, allow site domains in UiRequest, better progress bar, wait for siteinfo before before using localstorage, csslater hide only if opacity is 0
2015-03-30 23:44:29 +02:00
|
|
|
return message
|
2015-01-12 02:03:45 +01:00
|
|
|
|
|
|
|
|
|
|
|
# Send file not found error
|
|
|
|
def error404(self, path = None):
|
|
|
|
self.sendHeader(404)
|
2015-04-20 02:56:33 +02:00
|
|
|
return "Not Found: %s" % path.encode("utf8")
|
2015-01-12 02:03:45 +01:00
|
|
|
|
version 0.2.8, Namecoin domains using internal resolver site, --disable_zeromq option to skip backward compatiblity layer and save some memory, connectionserver firstchar error fixes, missing unpacker crash fix, sitemanager class to allow extensions, add loaded plugin list to websocket api, faster content publishing, mark updating file as bad, remove coppersurfer tracker add eddie4, internal server error with error displaying, allow site domains in UiRequest, better progress bar, wait for siteinfo before before using localstorage, csslater hide only if opacity is 0
2015-03-30 23:44:29 +02:00
|
|
|
|
|
|
|
# Internal server error
|
|
|
|
def error500(self, message = ":("):
|
|
|
|
self.sendHeader(500)
|
|
|
|
return "<h1>Server error</h1>%s" % cgi.escape(message)
|
|
|
|
|
|
|
|
|
2015-04-12 23:59:22 +02:00
|
|
|
# - Reload for eaiser developing -
|
|
|
|
#def reload():
|
|
|
|
#import imp, sys
|
|
|
|
#global UiWebsocket
|
|
|
|
#UiWebsocket = imp.load_source("UiWebsocket", "src/Ui/UiWebsocket.py").UiWebsocket
|
|
|
|
#reload(sys.modules["User.UserManager"])
|
|
|
|
#UserManager.reloadModule()
|
|
|
|
#self.user = UserManager.user_manager.getCurrent()
|