diff --git a/onionr/api.py b/onionr/api.py index e542bd35..7e552355 100755 --- a/onionr/api.py +++ b/onionr/api.py @@ -27,6 +27,7 @@ from onionrblockapi import Block import onionrutils, onionrexceptions, onionrcrypto, blockimporter, onionrevents as events, logger, config import httpapi from httpapi import friendsapi, simplecache +from onionrservices import httpheaders import onionr class FDSafeHandler(WSGIHandler): @@ -92,17 +93,9 @@ class PublicAPI: @app.after_request def sendHeaders(resp): '''Send api, access control headers''' - resp.headers['Date'] = 'Thu, 1 Jan 1970 00:00:00 GMT' # Clock info is probably useful to attackers. Set to unix epoch, since we can't fully remove the header. - # CSP to prevent XSS. Mainly for client side attacks (if hostname protection could somehow be bypassed) - resp.headers["Content-Security-Policy"] = "default-src 'none'; script-src 'none'; object-src 'none'; style-src data: 'unsafe-inline'; img-src data:; media-src 'none'; frame-src 'none'; font-src 'none'; connect-src 'none'" - # Prevent click jacking - resp.headers['X-Frame-Options'] = 'deny' - # No sniff is possibly not needed - resp.headers['X-Content-Type-Options'] = "nosniff" + resp = httpheaders.set_default_onionr_http_headers(resp) # Network API version resp.headers['X-API'] = onionr.API_VERSION - # Close connections to limit FD use - resp.headers['Connection'] = "close" self.lastRequest = clientAPI._core._utils.getRoundedEpoch(roundS=5) return resp @@ -300,15 +293,11 @@ class API: @app.after_request def afterReq(resp): # Security headers + resp = httpheaders.set_default_onionr_http_headers(resp) if request.endpoint == 'site': resp.headers['Content-Security-Policy'] = "default-src 'none'; style-src data: 'unsafe-inline'; img-src data:" else: resp.headers['Content-Security-Policy'] = "default-src 'none'; script-src 'self'; object-src 'none'; style-src 'self'; img-src 'self'; media-src 'none'; frame-src 'none'; font-src 'none'; connect-src 'self'" - resp.headers['X-Frame-Options'] = 'deny' - resp.headers['X-Content-Type-Options'] = "nosniff" - resp.headers['Server'] = '' - resp.headers['Date'] = 'Thu, 1 Jan 1970 00:00:00 GMT' # Clock info is probably useful to attackers. Set to unix epoch. - resp.headers['Connection'] = "close" return resp @app.route('/board/', endpoint='board') diff --git a/onionr/communicator.py b/onionr/communicator.py index bb56ca19..47f8e5d6 100755 --- a/onionr/communicator.py +++ b/onionr/communicator.py @@ -111,6 +111,7 @@ class OnionrCommunicatorDaemon: if config.get('general.socket_servers', False): self.services = onionrservices.OnionrServices(self._core) self.active_services = [] + self.service_greenlets = [] OnionrCommunicatorTimers(self, servicecreator.service_creator, 5, maxThreads=50, myArgs=(self,)) else: self.services = None @@ -148,7 +149,8 @@ class OnionrCommunicatorDaemon: pass logger.info('Goodbye.') - self._core.killSockets = True + for server in self.service_greenlets: + server.stop() self._core._utils.localCommand('shutdown') # shutdown the api time.sleep(0.5) diff --git a/onionr/onionrservices/bootstrapservice.py b/onionr/onionrservices/bootstrapservice.py index 95ae0158..292df4ed 100644 --- a/onionr/onionrservices/bootstrapservice.py +++ b/onionr/onionrservices/bootstrapservice.py @@ -37,6 +37,12 @@ def bootstrap_client_service(peer, core_inst=None, bootstrap_timeout=300): bootstrap_port = getOpenPort() bootstrap_app = Flask(__name__) http_server = WSGIServer(('127.0.0.1', bootstrap_port), bootstrap_app, log=None) + try: + core_inst.onionrInst.communicatorInst + except AttributeError: + pass + else: + core_inst.onionrInst.communicatorInst.service_greenlets.append(http_server) bootstrap_address = '' shutdown = False diff --git a/onionr/onionrservices/connectionserver.py b/onionr/onionrservices/connectionserver.py index d8a5f773..6b04645c 100644 --- a/onionr/onionrservices/connectionserver.py +++ b/onionr/onionrservices/connectionserver.py @@ -40,6 +40,7 @@ class ConnectionServer: service_port = getOpenPort() service_ip = api.setBindIP() http_server = WSGIServer(('127.0.0.1', service_port), service_app, log=None) + core_inst.onionrInst.communicatorInst.service_greenlets.append(http_server) # TODO define basic endpoints useful for direct connections like stats # TODO load endpoints from plugins @@ -53,6 +54,6 @@ class ConnectionServer: # Create the v3 onion service response = controller.create_ephemeral_hidden_service({80: service_port}, await_publication = True, key_type='NEW', key_content = 'ED25519-V3') self.core_inst._utils.doPostRequest('http://' + address + '/bs/' + response.service_id, port=socks) - logger.info('hosting on ' + response.service_id) + logger.info('hosting on %s with %s' % (response.service_id, peer)) http_server.serve_forever() http_server.stop() \ No newline at end of file