From d2fdc1e4aaa736d881b7d8f7933e9a781c48532d Mon Sep 17 00:00:00 2001 From: "contact@grandville.net" Date: Thu, 18 Jun 2020 13:59:59 +0200 Subject: [PATCH 1/5] Avoid reset status to FINISHED when calling getstatus_scan If all threads are finished, change state to FINISHED only if current state is SCANNING to preserve state set to ERROR. --- PatrowlEnginesUtils/PatrowlEngine.py | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/PatrowlEnginesUtils/PatrowlEngine.py b/PatrowlEnginesUtils/PatrowlEngine.py index 87b60cb..9ea75d6 100644 --- a/PatrowlEnginesUtils/PatrowlEngine.py +++ b/PatrowlEnginesUtils/PatrowlEngine.py @@ -179,21 +179,26 @@ def getstatus_scan(self, scan_id): if scan_id not in self.scans.keys(): raise PatrowlEngineExceptions(1002,"scan_id '{}' not found".format(scan_id)) - all_threads_finished = False + all_threads_finished = True for t in self.scans[scan_id]['threads']: if t.isAlive(): - self.scans[scan_id]['status'] = "SCANNING" all_threads_finished = False break - else: - all_threads_finished = True + if all_threads_finished and len(self.scans[scan_id]['threads']) >= 1: - self.scans[scan_id]['status'] = "FINISHED" - self.scans[scan_id]['finished_at'] = int(time.time() * 1000) + + if self.scans[scan_id]['status'] == "SCANNING": + # all threads are finished, ensure scan status is no more SCANNING + self.scans[scan_id]['status'] = "FINISHED" + + if not 'finished_at' in self.scans[scan_id].keys(): + # update finished time if not already set + self.scans[scan_id]['finished_at'] = int(time.time() * 1000) return jsonify({"status": self.scans[scan_id]['status']}) + def getstatus(self): """Get the status of the engine and all its scans.""" res = {"page": "status"} From 04ce3a829b60e1c88d68ecb34712819fe354dddb Mon Sep 17 00:00:00 2001 From: agrandville Date: Sat, 5 Sep 2020 17:29:46 +0200 Subject: [PATCH 2/5] add TLS support 3 new optionals parameters --cert=CERTFILE certificate filename --key=KEYFILE private key filename --password=KEYPASS private key password --- PatrowlEnginesUtils/PatrowlEngine.py | 26 +++++++++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) diff --git a/PatrowlEnginesUtils/PatrowlEngine.py b/PatrowlEnginesUtils/PatrowlEngine.py index 9ea75d6..c52952b 100644 --- a/PatrowlEnginesUtils/PatrowlEngine.py +++ b/PatrowlEnginesUtils/PatrowlEngine.py @@ -78,11 +78,20 @@ def run_app(self, app_debug=DEFAULT_APP_DEBUG, app_host=DEFAULT_APP_HOST, parser.add_option( "-d", "--debug", action="store_true", dest="debug", help=optparse.SUPPRESS_HELP) + parser.add_option( + "", "--cert", dest='certfile', default=None, + help="certificate filename") + parser.add_option( + "", "--key", dest='keyfile', default=None, + help="private key filename") + parser.add_option( + "", "--password", dest='keypass', default=None, + help="private key password") options, _ = parser.parse_args() self.app.run( debug=options.debug, host=options.host, port=int(options.port), - threaded=threaded) + threaded=threaded, ssl_context=self._getsslcontext(options)) def liveness(self): """Return the liveness status.""" @@ -130,6 +139,21 @@ def _loadconfig(self): self.status = "ERROR" return {"status": "ERROR", "reason": "config file not found"} + def _getsslcontext(self, options): + import ssl + + context = ssl.SSLContext(ssl.PROTOCOL_TLSv1_2) + + # set password to empty string not None to + # avoid prompt if private key is protected + # this had no effect if private key is not protected + if options.keypass is None: + options.keypass="" + + context.load_cert_chain(certfile=options.certfile,keyfile=options.keyfile,password=options.keypass) + + return context + def reloadconfig(self): """Reload the configuration file.""" res = {"page": "reloadconfig"} From c0a825fd6a2b0b6a8a990f5ff9e49571a929e140 Mon Sep 17 00:00:00 2001 From: agrandville Date: Sat, 5 Sep 2020 17:51:49 +0200 Subject: [PATCH 3/5] update VERSION and change log --- CHANGELOG.md | 5 +++++ README.md | 1 + VERSION | 2 +- 3 files changed, 7 insertions(+), 1 deletion(-) create mode 100644 CHANGELOG.md diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..c379d17 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,5 @@ +## Change Log + +### Features implemented / improvements in 1.0.0dev + +* Add support for TLS diff --git a/README.md b/README.md index 9c34f72..4ead2f1 100644 --- a/README.md +++ b/README.md @@ -4,3 +4,4 @@ rm -rf dist/ build/ PatrowlEnginesUtils.egg-info python setup.py sdist bdist_wheel twine upload dist/* + diff --git a/VERSION b/VERSION index 17e51c3..11524f9 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -0.1.1 +1.0.0dev From d05a2564545e65e7c5d5820962714ad3aaf24146 Mon Sep 17 00:00:00 2001 From: agrandville Date: Sat, 5 Sep 2020 18:57:30 +0200 Subject: [PATCH 4/5] Add --auto-tls flag Start service with a dummy auto-generated certificate --- PatrowlEnginesUtils/PatrowlEngine.py | 30 +++++++++++++++++++--------- 1 file changed, 21 insertions(+), 9 deletions(-) diff --git a/PatrowlEnginesUtils/PatrowlEngine.py b/PatrowlEnginesUtils/PatrowlEngine.py index c52952b..c99b832 100644 --- a/PatrowlEnginesUtils/PatrowlEngine.py +++ b/PatrowlEnginesUtils/PatrowlEngine.py @@ -88,7 +88,18 @@ def run_app(self, app_debug=DEFAULT_APP_DEBUG, app_host=DEFAULT_APP_HOST, "", "--password", dest='keypass', default=None, help="private key password") + parser.add_option( + "","--auto-tls", dest='tls', action="store_true", + help="enable TLS with dummy certificate") + options, _ = parser.parse_args() + + if options.certfile and options.tls: + parser.error("options --cert and --auto-tls are mutually exclusive") + + if options.certfile and not options.keyfile: + parser.error("option --key missing") + self.app.run( debug=options.debug, host=options.host, port=int(options.port), threaded=threaded, ssl_context=self._getsslcontext(options)) @@ -140,20 +151,21 @@ def _loadconfig(self): return {"status": "ERROR", "reason": "config file not found"} def _getsslcontext(self, options): - import ssl - context = ssl.SSLContext(ssl.PROTOCOL_TLSv1_2) - # set password to empty string not None to - # avoid prompt if private key is protected - # this had no effect if private key is not protected - if options.keypass is None: - options.keypass="" + if options.tls: + context = 'adhoc' + else: + # set password to empty string (not None) to + # avoid prompt if private key is protected. + # this had no effect if private key is not protected + if options.keypass is None: + options.keypass="" - context.load_cert_chain(certfile=options.certfile,keyfile=options.keyfile,password=options.keypass) + context.load_cert_chain(certfile=options.certfile,keyfile=options.keyfile,password=options.keypass) return context - + def reloadconfig(self): """Reload the configuration file.""" res = {"page": "reloadconfig"} From f90c3681b3c43163f4698cd28e63c8aa7eb03b9e Mon Sep 17 00:00:00 2001 From: agrandville Date: Sun, 6 Sep 2020 17:39:32 +0200 Subject: [PATCH 5/5] TLS is disable by default Without --auto-tls or --cert and --key, protocol is http --- PatrowlEnginesUtils/PatrowlEngine.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/PatrowlEnginesUtils/PatrowlEngine.py b/PatrowlEnginesUtils/PatrowlEngine.py index c99b832..114bad5 100644 --- a/PatrowlEnginesUtils/PatrowlEngine.py +++ b/PatrowlEnginesUtils/PatrowlEngine.py @@ -155,14 +155,16 @@ def _getsslcontext(self, options): if options.tls: context = 'adhoc' - else: - # set password to empty string (not None) to - # avoid prompt if private key is protected. + elif options.certfile: + # set password to empty string not None to + # avoid prompt if private key is protected # this had no effect if private key is not protected if options.keypass is None: options.keypass="" context.load_cert_chain(certfile=options.certfile,keyfile=options.keyfile,password=options.keypass) + else: + context = None return context