def check_ssl_certificates(): issue_name = 'expiring-certificate' ports = get_setting('port') if isinstance(ports, int): ports = [ports] elif isinstance(ports, dict): ports = list(ports.keys()) problem_hosts = [] for port in ports: certificate_file = get_port_setting(port, 'ssl:certificate') if not get_port_setting(port, 'ssl:enabled', bool(certificate_file)): continue try: subprocess.check_output( ('openssl', 'x509', '-in', certificate_file, '-checkend', str(60 * 60 * 24 * 7)), stderr=subprocess.STDOUT) except subprocess.CalledProcessError: hostname = 'server-port-{}'.format(port) problem_hosts.append(hostname) if open_issue(hostname, issue_name): log.info('Opened {} issue for {}', issue_name, hostname) for doc in close_issue({'$not': {'$in': list(problem_hosts)}}, issue_name): log.info('Closed {} issue for {}', issue_name, doc['hostname'])
def startServer(port, pipes_arg, local_only=False): global log, pipes, encryptors # To enable keep-alive WSGIRequestHandler.protocol_version = 'HTTP/1.1' # To prevent DoS attacks by opening connections and not closing them and # consuming resources and filling all our connection slots in the kernel. WSGIRequestHandler.timeout = 10 log = get_logger('server') pipes = pipes_arg encryptors = defaultdict(dict) clean_up_encryptors() werkzeug._internal._logger = logging.getLogger(log.name) if not local_only: app.config['deprecated_port'] = get_port_setting( port, 'deprecated', False) # Logbook will handle all logging, via the root handler installed by # `get_logger` when it alls `logbook.compat.redirect_logging()`. del app.logger.handlers[:] app.logger.propagate = True # Werkzeug has a bug which causes sockets to get stuck in TCP CLOSE_WAIT # state. Eventually, there are so many stuck sockets that the kernel stops # allowing new connections to the port, and then attempts to connect to the # port by clients hang. The "real" way to fix this is to run the server # under a different WSGI framework, but all of them are more of a pain to # set up than werkzeug, so I'm hoping that we can solve this problem just # by handling each request in a separate process so the socket for each # request will get closed properly when its process exits. # More info: https://stackoverflow.com/questions/31403261/\ # flask-werkzeug-sockets-stuck-in-close-wait kwargs = {'processes': 10} if local_only: host = '127.0.0.1' else: host = '0.0.0.0' ssl_certificate = get_port_setting(port, 'ssl:certificate', None) ssl_key = get_port_setting(port, 'ssl:key', None) ssl_enabled = get_port_setting(port, 'ssl:enabled', bool(ssl_certificate)) if bool(ssl_certificate) + bool(ssl_key) == 1: raise Exception( 'You must specify both certificate and key for SSL!') if ssl_enabled: kwargs['ssl_context'] = (ssl_certificate, ssl_key) run_simple(host, port, app, **kwargs)
def port_config(port): config = {} config['deprecated'] = get_port_setting(port, 'deprecated', False) if get_port_setting(port, 'ssl'): config['ssl'] = {} cert = get_port_setting(port, 'ssl:certificate') config['ssl']['certificate'] = cert or 'MISSING' config['ssl']['enabled'] = get_port_setting( port, 'ssl:enabled', bool(cert)) config['ssl']['key'] = \ get_port_setting(port, 'ssl:key') or 'MISSING' return config
def configure_client(args): changed = False url = get_client_setting('server_url') if url: url = list(urlparse(url)) else: url = ['', '', '', '', '', ''] if ':' in url[1]: hostname, port = url[1].split(':') port = int(port) else: hostname = url[1] port = 443 if url[0] == 'https' else 80 if args.hostname: if hostname != args.hostname: hostname = args.hostname changed = True if args.port: if port != args.port: port = args.port changed = True if port == 443 and args.ssl is None: args.ssl = True if args.ssl: if url[0] != 'https': url[0] = 'https' changed = True elif args.ssl is False: if url[0] != 'http': url[0] = 'http' changed = True if port == 443 and url[0] != 'https': print("\n" "WARNING: Are you sure you don't want to use SSL on port 443?\n") verbose_port = port or 80 try: server_port_ssl = get_port_setting( verbose_port, 'ssl:enabled', bool(get_port_setting(verbose_port, 'ssl:certificate'))) except: server_port_ssl = False if server_port_ssl and url[0] != 'https': print('\n' 'WARNING: Port {} on the server is using SSL.\n' ' Does the client need to?\n'.format(verbose_port)) elif not server_port_ssl and url[0] != 'http': print('\n' 'WARNING: Port {} on the server is not using SSL.\n' ' Are you sure the client should?\n'.format( verbose_port)) if not hostname: sys.exit('You must specify hostname.') if url[0] not in ('http', 'https'): changed = True url[0] = 'https' if port == 443 else 80 if port and ((url[0] == 'http' and port != 80) or (url[0] == 'https' and port != 443)): loc = '{}:{}'.format(hostname, port) if url[1] != loc: changed = True url[1] = loc else: url[1] = hostname if args.ssl_ca_file is False: if get_client_setting('ssl:ca_path'): set_client_setting('ssl:ca_path', None) changed = True elif args.ssl_ca_file: try: server_port = int(args.ssl_ca_file) except: pass else: args.ssl_ca_file = get_port_setting(server_port, 'ssl:certificate') if not args.ssl_ca_file: sys.exit('Server port {} does not have an SSL certificate.' .format(server_port)) client_file = os.path.join('client', 'cacert.pem') if not os.path.exists(args.ssl_ca_file): sys.exit('The file {} does not exist.'.format(args.ssl_ca_file)) if not (os.path.exists(client_file) and filecmp.cmp(args.ssl_ca_file, client_file)): shutil.copy(args.ssl_ca_file, client_file) changed = True if get_client_setting('ssl:ca_path') != client_file: set_client_setting('ssl:ca_path', client_file) changed = True url = urlunparse(url) url = re.sub(r'/+$', '', url) if changed: set_client_setting('server_url', url) save_client_settings() print('Updated client configuration.') show_configuration(args) print("\n" "WARNING: Don't forget to build a new client release.\n") else: print('Client configuration unchanged.')