-
Notifications
You must be signed in to change notification settings - Fork 18
bond-cli: implement https support to bond-cli, added security levels for https-insecure and https #67
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: trunk
Are you sure you want to change the base?
bond-cli: implement https support to bond-cli, added security levels for https-insecure and https #67
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,6 +1,8 @@ | ||
| import datetime | ||
| import os | ||
| import time | ||
| import ssl | ||
| import socket | ||
| from http.server import HTTPServer, SimpleHTTPRequestHandler | ||
| from pathlib import Path | ||
| from queue import Queue | ||
|
|
@@ -13,7 +15,6 @@ | |
|
|
||
| Q = Queue() | ||
|
|
||
|
|
||
| class ChunkedRequestHandler(SimpleHTTPRequestHandler): | ||
| def do_PUT(self): | ||
| self.send_response(200) | ||
|
|
@@ -45,35 +46,91 @@ def do_PUT(self): | |
| break | ||
| Q.put(path) | ||
|
|
||
| def handle(self): | ||
| if hasattr(self.connection, 'version'): | ||
| ssl_version = self.connection.version() | ||
| print(f"Connected using TLS version: {ssl_version}") | ||
| else: | ||
| print("No TLS connection or non-SSL connection detected.") | ||
| super().handle() | ||
|
|
||
| def start_daemon(port): | ||
| def start_daemon(port, protocol="http"): | ||
| print(f"Starting server on port {port} with protocol {protocol}") | ||
| os.chdir(DB_DIRNAME) | ||
| httpd = HTTPServer(("0.0.0.0", port), ChunkedRequestHandler) | ||
| print("Serving at port:", httpd.server_port) | ||
| Thread(target=httpd.serve_forever, daemon=True).start() | ||
| handler = ChunkedRequestHandler | ||
| print(f"Handler assigned: {handler}") | ||
|
|
||
| if protocol in ["https", "https-insecure"]: | ||
| # Need to add certificate with name cert.pem and key with name key.pem for | ||
| # testing https connection. | ||
| base_dir = os.path.dirname(os.path.abspath(__file__)) # current script directory | ||
| cert_path = os.path.join(base_dir, "cert.pem") | ||
| key_path = os.path.join(base_dir, "key.pem") | ||
|
|
||
| context = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER) | ||
| if protocol == "https-insecure": | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. What is the difference here? Is it even possible for the server-side of a TLS connection to verify the client in this way? And even if so, I do not see how it would work with a Bond on the local network. Please just support the http/https.
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @chrismerck This context will be used to handle encrypted communications between server and client. And server side must have key and cert for session key creation. After this, they switch to a secure channel, where data transmission occurs using a symmetric encryption algorithm. |
||
| context.check_hostname = False | ||
| context.verify_mode = ssl.CERT_NONE | ||
| context.set_ciphers("DEFAULT") | ||
| context.load_cert_chain(certfile=cert_path, keyfile=key_path) | ||
|
|
||
| # HTTPS Server start | ||
| httpd=HTTPServer(('0.0.0.0', port), handler) | ||
| print("Wrapping socket with SSL...") | ||
| httpd.socket = context.wrap_socket(httpd.socket, server_side=True) | ||
| print(f"Serving at https://0.0.0.0:{port}") | ||
| Thread(target=httpd.serve_forever, daemon=True).start() | ||
|
|
||
| else: | ||
| # HTTP Server start | ||
| httpd=HTTPServer(('0.0.0.0', port), handler) | ||
| print(f"Serving at http://0.0.0.0:{port}") | ||
| Thread(target=httpd.serve_forever, daemon=True).start() | ||
|
|
||
| def wait_upload(timeout=None): | ||
| return Q.get(timeout=timeout) | ||
|
|
||
|
|
||
| class BackupCommand(object): | ||
| subcmd = "backup" | ||
| help = """Backup a Bond""" | ||
| arguments = { | ||
| "--bond-id": {"help": "ignore selected Bond and use provided"}, | ||
| "--protocol": {"help": "Choose protocol: http, https, https-insecure", "choices": ["http", "https", "https-insecure"]}, | ||
| } | ||
|
|
||
| def run(self, args): | ||
| start_daemon(4444) | ||
| protocol = args.protocol or "http" | ||
| start_daemon(4444, protocol) | ||
| bondid = args.bond_id or BondDatabase.get_assert_selected_bondid() | ||
| timestamp = str(int(time.time())) | ||
| body = { | ||
| security_level = 0 | ||
| if protocol == "https-insecure": | ||
| security_level = 1 | ||
| body = { | ||
| "backup": 1, | ||
| "https_port": "4444", | ||
| "path": "", | ||
| "timestamp": timestamp, | ||
| "security": security_level, | ||
| } | ||
| elif protocol == "https": | ||
| security_level = 2 | ||
| body = { | ||
| "backup": 1, | ||
| "https_port": "4444", | ||
| "path": "", | ||
| "timestamp": timestamp, | ||
| "security": security_level, | ||
| } | ||
| else: | ||
| body = { | ||
| "backup": 1, | ||
| "http_port": "4444", | ||
| "path": "", | ||
| "timestamp": timestamp, | ||
| "security": security_level, | ||
| } | ||
|
|
||
| rsp = bond.proto.put(bondid, topic="sys/backup", body=body) | ||
| print(rsp) | ||
| if rsp["s"] != 200: | ||
|
|
@@ -134,10 +191,13 @@ class RestoreCommand(object): | |
| "help": "Only for test purposes. May cause unexpected behavior.", | ||
| "action": "store_true", | ||
| }, | ||
| "--bond-id": {"help": "ignore selected Bond and use provided"}, | ||
| "--bond-id": {"help": "ignore selected Bond and use provided", | ||
| }, | ||
| "--protocol": {"help": "Choose protocol: http, https, https-insecure", "choices": ["http", "https", "https-insecure"]}, | ||
| } | ||
|
|
||
| def run(self, args): # noqa: C901 | ||
| protocol = args.protocol or "http" | ||
| file_list = get_file_list() | ||
| if args.list or not (args.file or args.latest) or len(file_list) == 0: | ||
| if len(file_list) == 0: | ||
|
|
@@ -154,15 +214,36 @@ def run(self, args): # noqa: C901 | |
| return | ||
| args.file = file_list[-1]["file"] | ||
|
|
||
| start_daemon(4444) | ||
| start_daemon(4444, protocol) | ||
| bondid = args.bond_id or BondDatabase.get_assert_selected_bondid() | ||
| # timestamp = str(int(time.time())) | ||
| body = { | ||
| "restore": 1, | ||
| "http_port": "4444", | ||
| "path": "", | ||
| "filename": args.file, | ||
| } | ||
| security_level = 0 | ||
| if protocol == "https-insecure": | ||
| security_level = 1 | ||
| body = { | ||
| "restore": 1, | ||
| "https_port": "4444", | ||
| "path": "", | ||
| "filename": args.file, | ||
| "security": security_level, | ||
| } | ||
| elif protocol == "https": | ||
| security_level = 2 | ||
| body = { | ||
| "restore": 1, | ||
| "https_port": "4444", | ||
| "path": "", | ||
| "filename": args.file, | ||
| "security": security_level, | ||
| } | ||
| else: | ||
| body = { | ||
| "restore": 1, | ||
| "http_port": "4444", | ||
| "path": "", | ||
| "filename": args.file, | ||
| "security": security_level, | ||
| } | ||
| rsp = bond.proto.put(bondid, topic="sys/backup", body=body) | ||
| print(rsp) | ||
| if rsp["s"] != 200: | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@AliakseiSubach will you add these files to the project?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@chrismerck i can push my files. But its self-signed certificate. Everyone can create it using cmd: "openssl req -x509 -newkey rsa:2048 -keyout key.pem -out cert.pem -days 365 -nodes". Do you need this for testing?