@ -0,0 +1,398 @@ | |||
#!/usr/bin/python3.6 | |||
# coding: utf8 | |||
import locale | |||
from dialog import Dialog | |||
import os | |||
import pynginxconfig | |||
import re | |||
from goto import with_goto | |||
# import sys | |||
# import getopt | |||
import subprocess | |||
import shlex | |||
nginx_dir = "/etc/nginx" | |||
nginx_available_sites = nginx_dir + "/sites_available/" | |||
nginx_enabled_sites = nginx_dir + "/sites_enabled/" | |||
nginx_templates = nginx_dir + "/templates/" | |||
template_host = 'host.conf' | |||
template_ssl = 'host_ssl.conf' | |||
errcode = list() | |||
errcode.append(False) | |||
errcode.append(True) | |||
errcode.append("string can't be empty") | |||
errcode.append('English letters only. To issue for an Internationalized Domain Name, use Punycode.') | |||
errcode.append('string must be numerical') | |||
errcode.append('') | |||
def get_available(): | |||
f = os.listdir(nginx_available_sites) | |||
return f | |||
def check_if_enabled(vhost_file): | |||
if os.path.exists(nginx_enabled_sites + vhost_file): | |||
return True | |||
else: | |||
return False | |||
def check_cert(domain): | |||
if os.path.isfile('/etc/letsencrypt/live/' + domain.split(' ')[0] + '/cert.pem'): | |||
return True | |||
else: | |||
return False | |||
def make_list(delete=False): | |||
t = tuple() | |||
x = get_available() | |||
a = list() | |||
for vhost in x: | |||
if delete is not True: | |||
t = (vhost, get_server_name(vhost), check_if_enabled(vhost)) | |||
a.append(t) | |||
else: | |||
t = (vhost, get_server_name(vhost), False) | |||
a.append(t) | |||
s = sorted(a, key=lambda dom: dom[1]) | |||
return s | |||
def enable_vhost(vhost): | |||
try: | |||
os.symlink(nginx_available_sites + vhost, nginx_enabled_sites + vhost) | |||
except FileExistsError: | |||
pass | |||
return True | |||
def renew_enabled(vhosts): | |||
a = get_available() | |||
for vhost in a: | |||
if vhost in vhosts: | |||
if check_if_enabled(vhost): | |||
pass | |||
else: | |||
enable_vhost(vhost) | |||
else: | |||
if check_if_enabled(vhost): | |||
os.unlink(nginx_enabled_sites + vhost) | |||
else: | |||
pass | |||
restart_nginx() | |||
return True | |||
def get_server_name(vhost_file): | |||
i = int() | |||
if vhost_file == 'default.conf': | |||
ret = 'default.conf' | |||
else: | |||
vhost = pynginxconfig.NginxConfig() | |||
vhost.loadf(nginx_available_sites + vhost_file) | |||
try: | |||
ret = vhost.get([('server',), 'server_name'])[1] | |||
except: | |||
ret = "None" | |||
return ret | |||
def enable_redirect(cfg): | |||
filename = cfg | |||
vhost = pynginxconfig.NginxConfig() | |||
vhost.loadf(nginx_available_sites + filename) | |||
vhost[0]['value'].insert(7, ('rewrite', '^ https://$http_host$request_uri? permanent')) | |||
vhost.savef(nginx_available_sites + filename) | |||
return | |||
def is_ascii(s): | |||
pattern = r'[^.a-zA-Z0-9- ]' | |||
if len(s) != 0: | |||
if re.search(pattern, s): | |||
return 3 | |||
else: | |||
return 1 | |||
else: | |||
return 2 | |||
def is_num(s): | |||
pattern = r'[^0-9]' | |||
if len(s) != 0: | |||
if re.search(pattern, s): | |||
return 4 | |||
else: | |||
return 1 | |||
else: | |||
return 2 | |||
def check_data(data): | |||
msg = list() | |||
ret = True | |||
rc = is_ascii(data['Domain']) | |||
if rc != True: | |||
ret = False | |||
msg.append("Domain: " + str(errcode[rc])) | |||
rc = is_ascii(data['SubDomain']) | |||
if data['SubDomain'] != '': | |||
if rc != True: | |||
ret = False | |||
msg.append("SubDomain: " + str(errcode[rc])) | |||
rc = is_ascii(data['Backend_Addr']) | |||
if rc != True: | |||
ret = False | |||
msg.append("Backend_Addr: " + str(errcode[rc])) | |||
rc = is_num(data['Backend_Port']) | |||
if rc != True: | |||
ret = False | |||
msg.append("Backend_Port: " + str(errcode[rc])) | |||
return ret, msg | |||
def delete_vhosts(vhosts): | |||
for vhost in vhosts: | |||
try: | |||
os.unlink(nginx_enabled_sites + vhost) | |||
except: | |||
pass | |||
try: | |||
os.unlink(nginx_available_sites + vhost) | |||
except: | |||
pass | |||
restart_nginx() | |||
def form_one(): | |||
locale.setlocale(locale.LC_ALL, '') | |||
d = Dialog(dialog="dialog") | |||
d.set_background_title("NGINX domains managment") | |||
ret, tags = d.menu("Select action?", width=60, height=10, | |||
choices=[("Add", "Add new domain"), | |||
("Enable/Disable", "Enable/Disable selected domains"), | |||
("Delete", "Delete selected domains")], | |||
title="") | |||
return ret, tags | |||
def edit_form(domain='', subdomain='', backend_addr='', backend_port='80'): | |||
locale.setlocale(locale.LC_ALL, '') | |||
d = Dialog(dialog="dialog") | |||
ret, val = d.mixedform("Fill the form:\n \n Enter additional domians separate by space\n (for example: www.domain.ru xxx.domain.ru)", height=14, width=60, | |||
elements=[("Domain name", 1, 3, domain, 1, 22, 30, 255, 0), | |||
("Additional domains", 2, 3, subdomain, 2, 22, 30, 65535, 0), | |||
("Backend addr", 3, 3, backend_addr, 3, 22, 30, 255, 0), | |||
("Backend port", 4, 3, backend_port, 4, 22, 30, 5, 0)] | |||
) | |||
if ret == 'ok': | |||
ret = show_yesno('Do you want to do automatically redirect from HTTP to HTTPS?') | |||
if ret == 'ok': | |||
values = {'Domain': val[0], 'SubDomain': val[1], 'Backend_Addr': val[2], 'Backend_Port': val[3], 'redirect': True} | |||
else: | |||
values = {'Domain': val[0], 'SubDomain': val[1], 'Backend_Addr': val[2], 'Backend_Port': val[3], 'redirect': False} | |||
return ret, values | |||
else: | |||
return ret, "" | |||
def select_form(): | |||
vlist = make_list() | |||
locale.setlocale(locale.LC_ALL, '') | |||
d = Dialog(dialog="dialog") | |||
ret, dom_list = d.checklist("Enable or disable sites", height=30, width=120, list_height=30, choices=vlist) | |||
if ret == "ok": | |||
show_info("Please wait. Work in progress") | |||
renew_enabled(dom_list) | |||
return ret | |||
def delete_form(): | |||
vlist = make_list(True) | |||
locale.setlocale(locale.LC_ALL, '') | |||
d = Dialog(dialog="dialog") | |||
ret, dom_list = d.checklist("Select to delete:", height=30, width=120, list_height=30, choices=vlist) | |||
if ret == "ok": | |||
if show_yesno('Are you sure?\n\nThese domains will be deleted:\n\n' + '\n'.join(dom_list)) == "ok": | |||
show_info("Please wait. Work in progress") | |||
delete_vhosts(dom_list) | |||
else: | |||
return ret | |||
def show_yesno(msg): | |||
locale.setlocale(locale.LC_ALL, '') | |||
d = Dialog(dialog="dialog") | |||
ret = d.yesno(msg, height=10, width=60) | |||
return ret | |||
def create_domain(vhost, ssl=False): | |||
if ssl is not True: | |||
filename = vhost['Domain'] + '.conf' | |||
template = nginx_templates + template_host | |||
else: | |||
filename = vhost['Domain'] + '_ssl.conf' | |||
template = nginx_templates + template_ssl | |||
domains = vhost['Domain'] + ' ' | |||
for dom in vhost['SubDomain']: | |||
domains += dom | |||
vconfig = pynginxconfig.NginxConfig() | |||
vconfig.loadf(template) | |||
server_str = vconfig.get([('server',), 'server_name'])[1].replace('[domain_names]', domains) | |||
log_str = vconfig.get([('server',), 'error_log'])[1].replace('[domain_name]', vhost['Domain']) | |||
if ssl: | |||
cert_str = vconfig.get([('server',), 'ssl_certificate'])[1].replace('[domain_name]', vhost['Domain']) | |||
cert_key_str = vconfig.get([('server',), 'ssl_certificate_key'])[1].replace('[domain_name]', vhost['Domain']) | |||
vconfig.set([('server',), 'ssl_certificate'], cert_str) | |||
vconfig.set([('server',), 'ssl_certificate_key'], cert_key_str) | |||
backend_str = vconfig.get([('server',), 'set'])[1].replace('[host_name]', vhost['Backend_Addr']).replace('[host_port]', vhost['Backend_Port']) | |||
vconfig.set([('server',), 'server_name'], server_str) | |||
vconfig.set([('server',), 'error_log'], log_str) | |||
vconfig.set([('server',), 'set'], backend_str) | |||
#if vhost['redirect'] is not True: | |||
# vconfig.remove([('server',), 'rewrite']) | |||
vconfig.savef(nginx_available_sites + filename) | |||
return domains, filename | |||
def create_cert(domains): | |||
if check_cert(domains) is not True: | |||
cmd = 'certbot certonly --agree-tos --email admin@shopband.ru --webroot -w /var/www/lets -d ' + domains.rstrip().replace(' ', ' -d ') | |||
ret = subprocess.run(shlex.split(cmd), stdout=subprocess.PIPE, stderr=subprocess.PIPE) | |||
if ret.returncode != 0: | |||
msg = "Error getting ssl certs\nThe SSL configuration is written to " + nginx_available_sites + ", " \ | |||
"but not enabled.\nGet SSL certs manualy and make symlink to " + nginx_enabled_sites | |||
show_error(msg + "\nLog saved into " + domains.split(' ')[0] + ".log") | |||
f = open('./' + domains.split(' ')[0] + ".log", 'w') | |||
f.write(ret.stderr.decode("utf-8")) | |||
f.close() | |||
return False | |||
elif ret.returncode == 0: | |||
return True | |||
else: | |||
return False | |||
else: | |||
return True | |||
def restart_nginx(): | |||
ret = subprocess.run(shlex.split('/usr/sbin/nginx -t -c /etc/nginx/nginx.conf'), stdout=subprocess.PIPE, stderr=subprocess.PIPE) | |||
if ret.returncode != 0: | |||
show_error(ret.stderr.decode("utf-8")) | |||
return False | |||
elif ret.returncode == 0: | |||
ret = subprocess.run(shlex.split('service nginx restart'), stdout=subprocess.PIPE, stderr=subprocess.PIPE) | |||
if ret.returncode != 0: | |||
show_error(ret.stderr.decode("utf-8")) | |||
return False | |||
return True | |||
def show_info(msg): | |||
s_width = len(msg) | |||
if s_width > 56: | |||
s_width = 56 | |||
d = Dialog(dialog="dialog") | |||
d.infobox(msg, height=3, width=s_width+4) | |||
return | |||
def show_error(msg): | |||
txt = '' | |||
if isinstance(msg, list): | |||
for err in msg: | |||
txt = txt + err + '\n' | |||
else: | |||
txt = msg | |||
locale.setlocale(locale.LC_ALL, '') | |||
d = Dialog(dialog="dialog") | |||
d.msgbox(text=txt, width=80, height=20) | |||
return txt | |||
def enable_site(cfg, domains='', ssl=False): | |||
if ssl is True: | |||
if create_cert(domains): | |||
enable_vhost(cfg) | |||
else: | |||
return False | |||
else: | |||
enable_vhost(cfg) | |||
if restart_nginx(): | |||
return True | |||
else: | |||
return False | |||
# if ssl: | |||
# ret_code = create_cert(domains) | |||
# if ret_code: | |||
# enable_vhost(filename) | |||
# else: | |||
# show_error(msg) | |||
# else: | |||
# enable_vhost(filename) | |||
pass | |||
@with_goto | |||
def start_it(): | |||
label .start | |||
vals = {'Domain': '', 'SubDomain': '', 'Backend_Addr': '', 'Backend_Port': '80'} | |||
rc, action = form_one() | |||
if rc == 'ok': | |||
if action == "Add": | |||
label .add | |||
ret, vals = edit_form(vals['Domain'], vals['SubDomain'], vals['Backend_Addr'], vals['Backend_Port']) | |||
if ret is not 'ok': | |||
goto .start | |||
else: | |||
ret_code, msg = check_data(vals) | |||
if ret_code is not True: | |||
show_error(msg) | |||
goto .add | |||
else: | |||
# Create HTTP config | |||
domains, cfg = create_domain(vals) | |||
show_info("Please wait. Work in progress") | |||
if enable_site(cfg) is not True: | |||
goto .start | |||
else: | |||
http_config = cfg | |||
# Create HTTPS config | |||
domains, cfg = create_domain(vals, True) | |||
show_info("Please wait. Work in progress") | |||
if enable_site(cfg, domains, True) is not True: | |||
print("false") | |||
goto .start | |||
else: | |||
if vals['redirect'] is True: | |||
enable_redirect(http_config) | |||
restart_nginx() | |||
goto .start | |||
elif action == "Enable/Disable": | |||
label .endis | |||
ret = select_form() | |||
goto .start | |||
elif action == "Delete": | |||
label .delete | |||
delete_form() | |||
goto .start | |||
start_it() |
Powered by TurnKey Linux.