#!/usr/bin/env python3 # SPDX-FileCopyrightText: 2022 Citadel and contributors # # SPDX-License-Identifier: GPL-3.0-or-later try: import crossplane except ImportError: print("Crossplane not found. Please run 'sudo pip3 install crossplane'") exit(1) import os import argparse import shutil import json def parse_dotenv(file_path): envVars: dict = {} with open(file_path, 'r') as file: for line in file: line = line.strip() if line.startswith('#') or len(line) == 0: continue if '=' in line: key, value = line.split('=', 1) value = value.strip('"').strip("'") envVars[key] = value else: print("Error: Invalid line in {}: {}".format(file_path, line)) print( "Line should be in the format KEY=VALUE or KEY=\"VALUE\" or KEY='VALUE'") exit(1) return envVars # Usage: add-https --service service_name --cert path_to_certificate --key path_to_key --domain domain_name parser = argparse.ArgumentParser( description='Create an HTTPS proxy for an app on Citadel') parser.add_argument('--service', required=True, help='The service to add HTTPS to') parser.add_argument('--cert', required=True, help='The path to the SSL certificate (.pem)') parser.add_argument('--key', required=True, help='The path to the SSL key (.key)') parser.add_argument('--domain', required=True, help='The domain name') args = parser.parse_args() domain = args.domain service = args.service cert = args.cert key = args.key node_root = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) nginx_config_file = os.path.join(node_root, 'nginx', 'nginx.conf') registry_file = os.path.join(node_root, 'apps', 'registry.json') with open(registry_file) as file: registry = json.load(file) port = None for app in registry: if app['name'] == service: if "internalPort" in app: port = app['internalPort'] break original_config = crossplane.parse(nginx_config_file) parsedConfig = original_config["config"][0]["parsed"] ip_env_var = "APP_{}_WEB_IP".format( service.upper().replace("-", "_") ) ip_alt_env_var = "APP_{}_MAIN_IP".format( service.upper().replace("-", "_") ) port_env_var = "APP_{}_WEB_PORT".format( service.upper().replace("-", "_") ) port_alt_env_var = "APP_{}_MAIN_PORT".format( service.upper().replace("-", "_") ) env = parse_dotenv(os.path.join(node_root, '.env')) ip=None if ip_env_var in env: ip = env[ip_env_var] elif ip_alt_env_var in env: ip = env[ip_alt_env_var] else: print("Error: No IP found for {}".format(service)) exit(1) if port == None: if port_env_var in env: port = env[port_env_var] elif port_alt_env_var in env: port = env[port_alt_env_var] else: print("Error: No port found for {}".format(service)) exit(1) if service == "btcpay-server": port = 1234 if service == "lnme": port = 1323 actual_url="http://{}:{}".format(ip, port) # Get the first element of config where the directive property is 'http' http_element = next(x for x in parsedConfig if x["directive"] == "http") config = { "directive": "server", "args": [], "block": [ { "directive": "listen", "args": ["443", "ssl", "http2"] }, { "directive": "server_name", "args": [domain] }, { "directive": "ssl_certificate", "args": [domain + ".pem"] }, { "directive": "ssl_certificate_key", "args": [domain + ".key"] }, { "directive": "ssl_protocols", "args": ["TLSv1", "TLSv1.1", "TLSv1.2"] }, { "directive": "ssl_ciphers", "args": ["HIGH:!aNULL:!MD5"] }, { "directive": "location", "args": ["/"], "block": [ { "directive": "proxy_pass", "args": [actual_url] }, { "directive": "proxy_http_version", "args": ["1.1"] }, { "directive": "proxy_set_header", "args": ["Upgrade", "$http_upgrade"] }, { "directive": "proxy_set_header", "args": ["Connection", "upgrade"] }, { "directive": "proxy_set_header", "args": ["Host", "$host"] }, { "directive": "proxy_set_header", "args": ["X-Real-IP", "$remote_addr"] }, { "directive": "proxy_set_header", "args": ["X-Forwarded-For", "$remote_addr"] }, { "directive": "proxy_set_header", "args": ["X-Forwarded-Proto", "$scheme"] } ] } ] } redirect_config = { "directive": "server", "args": [], "block": [ { "directive": "listen", "args": ["433"] }, { "directive": "server_name", "args": [domain] }, { "directive": "return", "args": ["301", "https://$host$request_uri"] }, ] } # Now, copy the given certificate and key to the correct location newCertLocation = os.path.join(node_root, 'nginx', domain + '.pem') newKeyLocation = os.path.join(node_root, 'nginx', domain + '.key') shutil.copy(cert, newCertLocation) shutil.copy(key, newKeyLocation) http_element["block"].append(config) http_element["block"].append(redirect_config) newConfig = crossplane.build(parsedConfig) # Write newConfig to nginx_config_file with open(nginx_config_file, 'w') as file: file.write(newConfig) print("Configuration successful!") print("To increase security, we recommend not exposing our IP by using services like cloudflare.") print("Also, please restart nginx using this command: sudo docker restart nginx")