You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

398 lines
12 KiB

  1. #!/usr/bin/python3.6
  2. # coding: utf8
  3. import locale
  4. from dialog import Dialog
  5. import os
  6. import pynginxconfig
  7. import re
  8. from goto import with_goto
  9. # import sys
  10. # import getopt
  11. import subprocess
  12. import shlex
  13. nginx_dir = "/etc/nginx"
  14. nginx_available_sites = nginx_dir + "/sites_available/"
  15. nginx_enabled_sites = nginx_dir + "/sites_enabled/"
  16. nginx_templates = nginx_dir + "/templates/"
  17. template_host = 'host.conf'
  18. template_ssl = 'host_ssl.conf'
  19. errcode = list()
  20. errcode.append(False)
  21. errcode.append(True)
  22. errcode.append("string can't be empty")
  23. errcode.append('English letters only. To issue for an Internationalized Domain Name, use Punycode.')
  24. errcode.append('string must be numerical')
  25. errcode.append('')
  26. def get_available():
  27. f = os.listdir(nginx_available_sites)
  28. return f
  29. def check_if_enabled(vhost_file):
  30. if os.path.exists(nginx_enabled_sites + vhost_file):
  31. return True
  32. else:
  33. return False
  34. def check_cert(domain):
  35. if os.path.isfile('/etc/letsencrypt/live/' + domain.split(' ')[0] + '/cert.pem'):
  36. return True
  37. else:
  38. return False
  39. def make_list(delete=False):
  40. t = tuple()
  41. x = get_available()
  42. a = list()
  43. for vhost in x:
  44. if delete is not True:
  45. t = (vhost, get_server_name(vhost), check_if_enabled(vhost))
  46. a.append(t)
  47. else:
  48. t = (vhost, get_server_name(vhost), False)
  49. a.append(t)
  50. s = sorted(a, key=lambda dom: dom[1])
  51. return s
  52. def enable_vhost(vhost):
  53. try:
  54. os.symlink(nginx_available_sites + vhost, nginx_enabled_sites + vhost)
  55. except FileExistsError:
  56. pass
  57. return True
  58. def renew_enabled(vhosts):
  59. a = get_available()
  60. for vhost in a:
  61. if vhost in vhosts:
  62. if check_if_enabled(vhost):
  63. pass
  64. else:
  65. enable_vhost(vhost)
  66. else:
  67. if check_if_enabled(vhost):
  68. os.unlink(nginx_enabled_sites + vhost)
  69. else:
  70. pass
  71. restart_nginx()
  72. return True
  73. def get_server_name(vhost_file):
  74. i = int()
  75. if vhost_file == 'default.conf':
  76. ret = 'default.conf'
  77. else:
  78. vhost = pynginxconfig.NginxConfig()
  79. vhost.loadf(nginx_available_sites + vhost_file)
  80. try:
  81. ret = vhost.get([('server',), 'server_name'])[1]
  82. except:
  83. ret = "None"
  84. return ret
  85. def enable_redirect(cfg):
  86. filename = cfg
  87. vhost = pynginxconfig.NginxConfig()
  88. vhost.loadf(nginx_available_sites + filename)
  89. vhost[0]['value'].insert(7, ('rewrite', '^ https://$http_host$request_uri? permanent'))
  90. vhost.savef(nginx_available_sites + filename)
  91. return
  92. def is_ascii(s):
  93. pattern = r'[^.a-zA-Z0-9- ]'
  94. if len(s) != 0:
  95. if re.search(pattern, s):
  96. return 3
  97. else:
  98. return 1
  99. else:
  100. return 2
  101. def is_num(s):
  102. pattern = r'[^0-9]'
  103. if len(s) != 0:
  104. if re.search(pattern, s):
  105. return 4
  106. else:
  107. return 1
  108. else:
  109. return 2
  110. def check_data(data):
  111. msg = list()
  112. ret = True
  113. rc = is_ascii(data['Domain'])
  114. if rc != True:
  115. ret = False
  116. msg.append("Domain: " + str(errcode[rc]))
  117. rc = is_ascii(data['SubDomain'])
  118. if data['SubDomain'] != '':
  119. if rc != True:
  120. ret = False
  121. msg.append("SubDomain: " + str(errcode[rc]))
  122. rc = is_ascii(data['Backend_Addr'])
  123. if rc != True:
  124. ret = False
  125. msg.append("Backend_Addr: " + str(errcode[rc]))
  126. rc = is_num(data['Backend_Port'])
  127. if rc != True:
  128. ret = False
  129. msg.append("Backend_Port: " + str(errcode[rc]))
  130. return ret, msg
  131. def delete_vhosts(vhosts):
  132. for vhost in vhosts:
  133. try:
  134. os.unlink(nginx_enabled_sites + vhost)
  135. except:
  136. pass
  137. try:
  138. os.unlink(nginx_available_sites + vhost)
  139. except:
  140. pass
  141. restart_nginx()
  142. def form_one():
  143. locale.setlocale(locale.LC_ALL, '')
  144. d = Dialog(dialog="dialog")
  145. d.set_background_title("NGINX domains managment")
  146. ret, tags = d.menu("Select action?", width=60, height=10,
  147. choices=[("Add", "Add new domain"),
  148. ("Enable/Disable", "Enable/Disable selected domains"),
  149. ("Delete", "Delete selected domains")],
  150. title="")
  151. return ret, tags
  152. def edit_form(domain='', subdomain='', backend_addr='', backend_port='80'):
  153. locale.setlocale(locale.LC_ALL, '')
  154. d = Dialog(dialog="dialog")
  155. 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,
  156. elements=[("Domain name", 1, 3, domain, 1, 22, 30, 255, 0),
  157. ("Additional domains", 2, 3, subdomain, 2, 22, 30, 65535, 0),
  158. ("Backend addr", 3, 3, backend_addr, 3, 22, 30, 255, 0),
  159. ("Backend port", 4, 3, backend_port, 4, 22, 30, 5, 0)]
  160. )
  161. if ret == 'ok':
  162. ret = show_yesno('Do you want to do automatically redirect from HTTP to HTTPS?')
  163. if ret == 'ok':
  164. values = {'Domain': val[0], 'SubDomain': val[1], 'Backend_Addr': val[2], 'Backend_Port': val[3], 'redirect': True}
  165. else:
  166. values = {'Domain': val[0], 'SubDomain': val[1], 'Backend_Addr': val[2], 'Backend_Port': val[3], 'redirect': False}
  167. return ret, values
  168. else:
  169. return ret, ""
  170. def select_form():
  171. vlist = make_list()
  172. locale.setlocale(locale.LC_ALL, '')
  173. d = Dialog(dialog="dialog")
  174. ret, dom_list = d.checklist("Enable or disable sites", height=30, width=120, list_height=30, choices=vlist)
  175. if ret == "ok":
  176. show_info("Please wait. Work in progress")
  177. renew_enabled(dom_list)
  178. return ret
  179. def delete_form():
  180. vlist = make_list(True)
  181. locale.setlocale(locale.LC_ALL, '')
  182. d = Dialog(dialog="dialog")
  183. ret, dom_list = d.checklist("Select to delete:", height=30, width=120, list_height=30, choices=vlist)
  184. if ret == "ok":
  185. if show_yesno('Are you sure?\n\nThese domains will be deleted:\n\n' + '\n'.join(dom_list)) == "ok":
  186. show_info("Please wait. Work in progress")
  187. delete_vhosts(dom_list)
  188. else:
  189. return ret
  190. def show_yesno(msg):
  191. locale.setlocale(locale.LC_ALL, '')
  192. d = Dialog(dialog="dialog")
  193. ret = d.yesno(msg, height=10, width=60)
  194. return ret
  195. def create_domain(vhost, ssl=False):
  196. if ssl is not True:
  197. filename = vhost['Domain'] + '.conf'
  198. template = nginx_templates + template_host
  199. else:
  200. filename = vhost['Domain'] + '_ssl.conf'
  201. template = nginx_templates + template_ssl
  202. domains = vhost['Domain'] + ' '
  203. for dom in vhost['SubDomain']:
  204. domains += dom
  205. vconfig = pynginxconfig.NginxConfig()
  206. vconfig.loadf(template)
  207. server_str = vconfig.get([('server',), 'server_name'])[1].replace('[domain_names]', domains)
  208. log_str = vconfig.get([('server',), 'error_log'])[1].replace('[domain_name]', vhost['Domain'])
  209. if ssl:
  210. cert_str = vconfig.get([('server',), 'ssl_certificate'])[1].replace('[domain_name]', vhost['Domain'])
  211. cert_key_str = vconfig.get([('server',), 'ssl_certificate_key'])[1].replace('[domain_name]', vhost['Domain'])
  212. vconfig.set([('server',), 'ssl_certificate'], cert_str)
  213. vconfig.set([('server',), 'ssl_certificate_key'], cert_key_str)
  214. backend_str = vconfig.get([('server',), 'set'])[1].replace('[host_name]', vhost['Backend_Addr']).replace('[host_port]', vhost['Backend_Port'])
  215. vconfig.set([('server',), 'server_name'], server_str)
  216. vconfig.set([('server',), 'error_log'], log_str)
  217. vconfig.set([('server',), 'set'], backend_str)
  218. #if vhost['redirect'] is not True:
  219. # vconfig.remove([('server',), 'rewrite'])
  220. vconfig.savef(nginx_available_sites + filename)
  221. return domains, filename
  222. def create_cert(domains):
  223. if check_cert(domains) is not True:
  224. cmd = 'certbot certonly --agree-tos --email admin@shopband.ru --webroot -w /var/www/lets -d ' + domains.rstrip().replace(' ', ' -d ')
  225. ret = subprocess.run(shlex.split(cmd), stdout=subprocess.PIPE, stderr=subprocess.PIPE)
  226. if ret.returncode != 0:
  227. msg = "Error getting ssl certs\nThe SSL configuration is written to " + nginx_available_sites + ", " \
  228. "but not enabled.\nGet SSL certs manualy and make symlink to " + nginx_enabled_sites
  229. show_error(msg + "\nLog saved into " + domains.split(' ')[0] + ".log")
  230. f = open('./' + domains.split(' ')[0] + ".log", 'w')
  231. f.write(ret.stderr.decode("utf-8"))
  232. f.close()
  233. return False
  234. elif ret.returncode == 0:
  235. return True
  236. else:
  237. return False
  238. else:
  239. return True
  240. def restart_nginx():
  241. ret = subprocess.run(shlex.split('/usr/sbin/nginx -t -c /etc/nginx/nginx.conf'), stdout=subprocess.PIPE, stderr=subprocess.PIPE)
  242. if ret.returncode != 0:
  243. show_error(ret.stderr.decode("utf-8"))
  244. return False
  245. elif ret.returncode == 0:
  246. ret = subprocess.run(shlex.split('service nginx restart'), stdout=subprocess.PIPE, stderr=subprocess.PIPE)
  247. if ret.returncode != 0:
  248. show_error(ret.stderr.decode("utf-8"))
  249. return False
  250. return True
  251. def show_info(msg):
  252. s_width = len(msg)
  253. if s_width > 56:
  254. s_width = 56
  255. d = Dialog(dialog="dialog")
  256. d.infobox(msg, height=3, width=s_width+4)
  257. return
  258. def show_error(msg):
  259. txt = ''
  260. if isinstance(msg, list):
  261. for err in msg:
  262. txt = txt + err + '\n'
  263. else:
  264. txt = msg
  265. locale.setlocale(locale.LC_ALL, '')
  266. d = Dialog(dialog="dialog")
  267. d.msgbox(text=txt, width=80, height=20)
  268. return txt
  269. def enable_site(cfg, domains='', ssl=False):
  270. if ssl is True:
  271. if create_cert(domains):
  272. enable_vhost(cfg)
  273. else:
  274. return False
  275. else:
  276. enable_vhost(cfg)
  277. if restart_nginx():
  278. return True
  279. else:
  280. return False
  281. # if ssl:
  282. # ret_code = create_cert(domains)
  283. # if ret_code:
  284. # enable_vhost(filename)
  285. # else:
  286. # show_error(msg)
  287. # else:
  288. # enable_vhost(filename)
  289. pass
  290. @with_goto
  291. def start_it():
  292. label .start
  293. vals = {'Domain': '', 'SubDomain': '', 'Backend_Addr': '', 'Backend_Port': '80'}
  294. rc, action = form_one()
  295. if rc == 'ok':
  296. if action == "Add":
  297. label .add
  298. ret, vals = edit_form(vals['Domain'], vals['SubDomain'], vals['Backend_Addr'], vals['Backend_Port'])
  299. if ret is not 'ok':
  300. goto .start
  301. else:
  302. ret_code, msg = check_data(vals)
  303. if ret_code is not True:
  304. show_error(msg)
  305. goto .add
  306. else:
  307. # Create HTTP config
  308. domains, cfg = create_domain(vals)
  309. show_info("Please wait. Work in progress")
  310. if enable_site(cfg) is not True:
  311. goto .start
  312. else:
  313. http_config = cfg
  314. # Create HTTPS config
  315. domains, cfg = create_domain(vals, True)
  316. show_info("Please wait. Work in progress")
  317. if enable_site(cfg, domains, True) is not True:
  318. print("false")
  319. goto .start
  320. else:
  321. if vals['redirect'] is True:
  322. enable_redirect(http_config)
  323. restart_nginx()
  324. goto .start
  325. elif action == "Enable/Disable":
  326. label .endis
  327. ret = select_form()
  328. goto .start
  329. elif action == "Delete":
  330. label .delete
  331. delete_form()
  332. goto .start
  333. start_it()

Powered by TurnKey Linux.