Separate http server for site content WIP
This resolves issue introduced by 14e8130acb
by having wrapper and iframe exist in different origins
Note that this does introduce minor UX issue: copying links now shows them
with a different port
This commit is contained in:
parent
75ecd895e7
commit
a4cc2eeb9f
4 changed files with 37 additions and 14 deletions
|
@ -51,11 +51,11 @@ class SecurityError(Exception):
|
|||
@PluginManager.acceptPlugins
|
||||
class UiRequest:
|
||||
|
||||
def __init__(self, server, get, env, start_response):
|
||||
def __init__(self, server, env, start_response, is_data_request=False):
|
||||
if server:
|
||||
self.server = server
|
||||
self.log = server.log
|
||||
self.get = get # Get parameters
|
||||
self.get = dict(urllib.parse.parse_qsl(env.get('QUERY_STRING', '')))
|
||||
self.env = env # Enviroment settings
|
||||
# ['CONTENT_LENGTH', 'CONTENT_TYPE', 'GATEWAY_INTERFACE', 'HTTP_ACCEPT', 'HTTP_ACCEPT_ENCODING', 'HTTP_ACCEPT_LANGUAGE',
|
||||
# 'HTTP_COOKIE', 'HTTP_CACHE_CONTROL', 'HTTP_HOST', 'HTTP_HTTPS', 'HTTP_ORIGIN', 'HTTP_PROXY_CONNECTION', 'HTTP_REFERER',
|
||||
|
@ -66,6 +66,7 @@ class UiRequest:
|
|||
self.start_response = start_response # Start response function
|
||||
self.user = None
|
||||
self.script_nonce = None # Nonce for script tags in wrapper html
|
||||
self.is_data_request = is_data_request
|
||||
|
||||
def learnHost(self, host):
|
||||
self.server.allowed_hosts.add(host)
|
||||
|
@ -142,8 +143,21 @@ class UiRequest:
|
|||
we'd want something else..
|
||||
"""
|
||||
|
||||
is_navigate = self.env.get('HTTP_SEC_FETCH_MODE') == 'navigate'
|
||||
is_iframe = self.env.get('HTTP_SEC_FETCH_DEST') == 'iframe'
|
||||
|
||||
if is_navigate and not is_iframe and self.is_data_request:
|
||||
# remove port from host
|
||||
host = ':'.join(self.env['HTTP_HOST'].split(':')[:-1])
|
||||
path_info = self.env['PATH_INFO']
|
||||
query_string = self.env['QUERY_STRING']
|
||||
protocol = self.env['wsgi.url_scheme']
|
||||
return self.actionRedirect(f'{protocol}://{host}:43110{path_info}?{query_string}')
|
||||
|
||||
if self.isCrossOriginRequest():
|
||||
return self.error404()
|
||||
# we are still exposed by answering on port
|
||||
self.log.warning('Cross-origin request detected. Someone might be trying to analyze your 0net usage')
|
||||
return []
|
||||
|
||||
# Restict Ui access by ip
|
||||
if config.ui_restrict and self.env['REMOTE_ADDR'] not in config.ui_restrict:
|
||||
|
@ -341,13 +355,12 @@ class UiRequest:
|
|||
headers["Version"] = "HTTP/1.1"
|
||||
headers["Connection"] = "Keep-Alive"
|
||||
headers["Keep-Alive"] = "max=25, timeout=30"
|
||||
headers["X-Frame-Options"] = "SAMEORIGIN"
|
||||
headers["Referrer-Policy"] = "same-origin"
|
||||
|
||||
if noscript:
|
||||
headers["Content-Security-Policy"] = "default-src 'none'; sandbox allow-top-navigation allow-forms; img-src *; font-src * data:; media-src *; style-src * 'unsafe-inline';"
|
||||
elif script_nonce:
|
||||
headers["Content-Security-Policy"] = "default-src 'none'; script-src 'nonce-{0}'; img-src 'self' blob: data:; style-src 'self' blob: 'unsafe-inline'; connect-src *; frame-src 'self' blob:".format(script_nonce)
|
||||
headers["Content-Security-Policy"] = f"default-src 'none'; script-src 'nonce-{script_nonce}'; img-src 'self' blob: data:; style-src 'self' blob: 'unsafe-inline'; connect-src *; frame-src 'self' blob: http://127.0.0.1:43111"
|
||||
|
||||
if allow_ajax:
|
||||
headers["Access-Control-Allow-Origin"] = "null"
|
||||
|
@ -618,6 +631,7 @@ class UiRequest:
|
|||
|
||||
return self.render(
|
||||
"src/Ui/template/wrapper.html",
|
||||
site_file_server='http://127.0.0.1:43111',
|
||||
server_url=server_url,
|
||||
inner_path=inner_path,
|
||||
file_url=xescape(file_url),
|
||||
|
|
|
@ -29,7 +29,7 @@ class UiWSGIHandler(WebSocketHandler):
|
|||
import main
|
||||
main.DebugHook.handleError()
|
||||
else:
|
||||
ui_request = UiRequest(self.server, {}, self.environ, self.start_response)
|
||||
ui_request = UiRequest(self.server, self.environ, self.start_response, is_data_request=False)
|
||||
block_gen = ui_request.error500("UiWSGIHandler error: %s" % Debug.formatExceptionMessage(err))
|
||||
for block in block_gen:
|
||||
self.write(block)
|
||||
|
@ -96,11 +96,7 @@ class UiServer:
|
|||
# Handle WSGI request
|
||||
def handleRequest(self, env, start_response):
|
||||
path = bytes(env["PATH_INFO"], "raw-unicode-escape").decode("utf8")
|
||||
if env.get("QUERY_STRING"):
|
||||
get = dict(urllib.parse.parse_qsl(env['QUERY_STRING']))
|
||||
else:
|
||||
get = {}
|
||||
ui_request = UiRequest(self, get, env, start_response)
|
||||
ui_request = UiRequest(self, env, start_response, is_data_request=False)
|
||||
if config.debug: # Let the exception catched by werkezung
|
||||
return ui_request.route(path)
|
||||
else: # Catch and display the error
|
||||
|
@ -158,6 +154,19 @@ class UiServer:
|
|||
main.file_server.stop()
|
||||
self.log.debug("Stopped.")
|
||||
|
||||
def handleSiteRequest(self, env, start_response):
|
||||
path = bytes(env["PATH_INFO"], "raw-unicode-escape").decode("utf8")
|
||||
ui_request = UiRequest(self, env, start_response, is_data_request=True)
|
||||
try:
|
||||
return ui_request.route(path)
|
||||
except Exception as err:
|
||||
logging.debug(f"UiRequest @ site error: {Debug.formatException(err)}")
|
||||
return ui_request.error500('Error while trying to server site data')
|
||||
|
||||
def startSiteServer(self):
|
||||
self.site_server = WSGIServer((self.ip, 43111), self.handleSiteRequest, log=self.log)
|
||||
self.site_server.serve_forever()
|
||||
|
||||
def stop(self):
|
||||
self.log.debug("Stopping...")
|
||||
# Close WS sockets
|
||||
|
|
|
@ -74,11 +74,11 @@ else if (window.opener && window.opener.location.toString()) {
|
|||
|
||||
|
||||
<!-- Site Iframe -->
|
||||
<iframe src='about:blank' id='inner-iframe' sandbox="allow-forms allow-scripts allow-top-navigation allow-popups allow-modals allow-presentation allow-pointer-lock allow-popups-to-escape-sandbox allow-same-origin {sandbox_permissions}" allowfullscreen="true" webkitallowfullscreen="true" mozallowfullscreen="true" oallowfullscreen="true" msallowfullscreen="true" referrerpolicy="same-origin"></iframe>
|
||||
<iframe src='about:blank' id='inner-iframe' sandbox="allow-forms allow-scripts allow-top-navigation allow-popups allow-modals allow-presentation allow-pointer-lock allow-popups-to-escape-sandbox allow-same-origin {sandbox_permissions}" allowfullscreen="true"></iframe>
|
||||
|
||||
<!-- Site info -->
|
||||
<script id="script_init" nonce="{script_nonce}">
|
||||
iframe_src = "{file_url}{query_string}"
|
||||
iframe_src = "{site_file_server}{file_url}{query_string}"
|
||||
console.log("Changing url from " + document.getElementById("inner-iframe").src + " to " + iframe_src)
|
||||
document.getElementById("inner-iframe").src = document.getElementById("inner-iframe").src // Workaround for Firefox back button bug
|
||||
document.getElementById("inner-iframe").src = iframe_src
|
||||
|
|
|
@ -230,7 +230,7 @@ class Actions:
|
|||
|
||||
import threading
|
||||
self.gevent_quit = threading.Event()
|
||||
launched_greenlets = [gevent.spawn(ui_server.start), gevent.spawn(file_server.start)]
|
||||
launched_greenlets = [gevent.spawn(ui_server.start), gevent.spawn(file_server.start), gevent.spawn(ui_server.startSiteServer)]
|
||||
|
||||
# if --repl, start ipython thread
|
||||
# FIXME: Unfortunately this leads to exceptions on exit so use with care
|
||||
|
|
Loading…
Reference in a new issue