forked from Corollarium/localtls
-
Notifications
You must be signed in to change notification settings - Fork 0
/
httpserver.py
133 lines (117 loc) · 4.5 KB
/
httpserver.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
#-*- coding: utf-8 -*-
import os
import sys
import confs
import cherrypy
import subprocess
import logging
from cherrypy.lib import static
INDEX_HTML='<html><body>Hi.</body></html>'
CERT_PATH='/etc/letsencrypt/live/' + confs.BASE_DOMAIN
logger = logging.getLogger('localtls')
class Root(object):
@cherrypy.expose
def index(self):
return INDEX_HTML
@cherrypy.expose
def fullchain(self):
return static.serve_file(os.path.join(CERT_PATH, 'fullchain.pem'), 'application/x-download', 'attachment')
@cherrypy.expose
def key(self):
return static.serve_file(os.path.join(CERT_PATH, 'privkey.pem'), 'application/x-download', 'attachment')
@cherrypy.expose
def cert(self):
return static.serve_file(os.path.join(CERT_PATH, 'cert.pem'), 'application/x-download', 'attachment')
@cherrypy.expose
def chain(self):
return static.serve_file(os.path.join(CERT_PATH, 'chain.pem'), 'application/x-download', 'attachment')
@cherrypy.expose
@cherrypy.tools.json_out()
def keys(self):
privkey = cert = chain = fullchain = ''
try:
with open(os.path.join(CERT_PATH, 'cert.pem')) as f:
cert = f.read()
with open(os.path.join(CERT_PATH, 'chain.pem')) as f:
chain = f.read()
with open(os.path.join(CERT_PATH, 'fullchain.pem')) as f:
fullchain = f.read()
with open(os.path.join(CERT_PATH, 'privkey.pem')) as f:
privkey = f.read()
except ValueError as e:
cherrypy.log(str(e))
except FileNotFoundError as e:
cherrypy.log(str(e))
except:
cherrypy.log("Unexpected error:", sys.exc_info()[0])
return {'privkey': privkey, 'cert': cert, 'chain': chain, 'fullchain': fullchain}
@cherrypy.expose
def favicon_ico(self):
raise cherrypy.HTTPError(404)
def listCertificates():
command = [
'certbot', 'certificates'
]
output = subprocess.Popen(command, stdout=subprocess.PIPE, bufsize=1, universal_newlines=True)
current_certificate = ''
current_domain = ''
paths = {}
for line in iter(output.stdout.readline,''):
if line.find('Certificate Name') > -1:
current_certificate = line.split(':')[1].strip()
continue
elif line.find('Domains') > -1:
domains = line.split(':')[1].strip()
current_domain = domains
elif line.find('Certificate Path') > -1:
p = line.split(':')[1].strip()
paths[domains] = os.path.dirname(p)
return paths
def force_tls(self=None):
# check if url is in https and redirect if http
if cherrypy.request.scheme == "http":
raise cherrypy.HTTPRedirect(cherrypy.url().replace("http:", "https:"), status=301)
def run(port, index, certpath=''):
global INDEX_HTML, CERT_PATH
try:
with open(index) as f:
INDEX_HTML=bytes(f.read(), "utf8")
except:
pass
# get certificates
try:
paths = listCertificates()
if ('*.' + confs.BASE_DOMAIN) in paths:
CERT_PATH = paths['*.' + confs.BASE_DOMAIN]
else:
logger.critical("Cannot find wildcard certificate. Run certbotdns.py now and then restart this. Meanwhile HTTP will not work.")
return
except:
logger.critical("Cannot list certificates: {}. Is certbot installed?".format(sys.exc_info()[0]))
#return
cherrypy.config.update({
'log.screen': False,
'log.access_file': '',
'log.error_file': 'http_error_log',
'environment': 'production',
'server.socket_host': '::',
'server.socket_port': int(port)
})
if port == 443 and confs.BASE_DOMAIN in paths:
logger.info('Starting TLS server.')
cert = paths[confs.BASE_DOMAIN]
cherrypy.tools.force_tls = cherrypy.Tool("before_handler", force_tls)
cherrypy.config.update({
'server.ssl_module': 'builtin',
'server.ssl_certificate': os.path.join(cert, "cert.pem"),
'server.ssl_private_key': os.path.join(cert, "privkey.pem"),
'server.ssl_certificate_chain': os.path.join(cert, "fullchain.pem"),
'tools.force_tls.on': True
})
# extra server instance to dispatch HTTP
server = cherrypy._cpserver.Server()
server.socket_host = '::'
server.socket_port = 80
server.subscribe()
logger.info('Starting HTTP server.')
cherrypy.quickstart(Root(), '/')