Refactor acme.sh integration
This commit is contained in:
@@ -10,11 +10,12 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
|||||||
|
|
||||||
#### Changed
|
#### Changed
|
||||||
|
|
||||||
- [APP] WordOps dashboard updated to v1.2. Shipped as a html file, it can be used without PHP stack
|
- [APP] WordOps dashboard updated to v1.2, shipped as a html file, it can be used without PHP stack
|
||||||
|
|
||||||
#### Fixed
|
#### Fixed
|
||||||
|
|
||||||
- `wo stack purge --all` failure if mysql isn't installed
|
- `wo stack purge --all` failure if mysql isn't installed
|
||||||
|
- Fix EEv3 files cleanup
|
||||||
|
|
||||||
### v3.9.8.12 - 2019-09-20
|
### v3.9.8.12 - 2019-09-20
|
||||||
|
|
||||||
|
|||||||
@@ -1,9 +1,7 @@
|
|||||||
# """WordOps site controller."""
|
|
||||||
import glob
|
import glob
|
||||||
import json
|
import json
|
||||||
import os
|
import os
|
||||||
import subprocess
|
import subprocess
|
||||||
from subprocess import Popen
|
|
||||||
|
|
||||||
from cement.core import handler, hook
|
from cement.core import handler, hook
|
||||||
from cement.core.controller import CementBaseController, expose
|
from cement.core.controller import CementBaseController, expose
|
||||||
@@ -11,6 +9,7 @@ from cement.core.controller import CementBaseController, expose
|
|||||||
from wo.cli.plugins.site_functions import *
|
from wo.cli.plugins.site_functions import *
|
||||||
from wo.cli.plugins.sitedb import (addNewSite, deleteSiteInfo, getAllsites,
|
from wo.cli.plugins.sitedb import (addNewSite, deleteSiteInfo, getAllsites,
|
||||||
getSiteInfo, updateSiteInfo)
|
getSiteInfo, updateSiteInfo)
|
||||||
|
from wo.core.acme import WOAcme
|
||||||
from wo.core.domainvalidate import WODomain
|
from wo.core.domainvalidate import WODomain
|
||||||
from wo.core.fileutils import WOFileUtils
|
from wo.core.fileutils import WOFileUtils
|
||||||
from wo.core.git import WOGit
|
from wo.core.git import WOGit
|
||||||
@@ -58,7 +57,8 @@ class WOSiteController(CementBaseController):
|
|||||||
|
|
||||||
pargs.site_name = pargs.site_name.strip()
|
pargs.site_name = pargs.site_name.strip()
|
||||||
# validate domain name
|
# validate domain name
|
||||||
(wo_domain, wo_www_domain) = WODomain.validatedomain(self, pargs.site_name)
|
(wo_domain,
|
||||||
|
wo_www_domain) = WODomain.validatedomain(self, pargs.site_name)
|
||||||
|
|
||||||
# check if site exists
|
# check if site exists
|
||||||
if not check_domain_exists(self, wo_domain):
|
if not check_domain_exists(self, wo_domain):
|
||||||
@@ -136,8 +136,10 @@ class WOSiteController(CementBaseController):
|
|||||||
Log.debug(self, str(e))
|
Log.debug(self, str(e))
|
||||||
Log.error(self, 'could not input site name')
|
Log.error(self, 'could not input site name')
|
||||||
pargs.site_name = pargs.site_name.strip()
|
pargs.site_name = pargs.site_name.strip()
|
||||||
(wo_domain, wo_www_domain) = WODomain.validatedomain(self, pargs.site_name)
|
(wo_domain,
|
||||||
(wo_domain_type, wo_root_domain) = WODomain.getdomainlevel(self, wo_domain)
|
wo_www_domain) = WODomain.validatedomain(self, pargs.site_name)
|
||||||
|
(wo_domain_type,
|
||||||
|
wo_root_domain) = WODomain.getdomainlevel(self, wo_domain)
|
||||||
wo_db_name = ''
|
wo_db_name = ''
|
||||||
wo_db_user = ''
|
wo_db_user = ''
|
||||||
wo_db_pass = ''
|
wo_db_pass = ''
|
||||||
@@ -188,7 +190,8 @@ class WOSiteController(CementBaseController):
|
|||||||
def log(self):
|
def log(self):
|
||||||
pargs = self.app.pargs
|
pargs = self.app.pargs
|
||||||
pargs.site_name = pargs.site_name.strip()
|
pargs.site_name = pargs.site_name.strip()
|
||||||
(wo_domain, wo_www_domain) = WODomain.validatedomain(self, pargs.site_name)
|
(wo_domain,
|
||||||
|
wo_www_domain) = WODomain.validatedomain(self, pargs.site_name)
|
||||||
wo_site_webroot = getSiteInfo(self, wo_domain).site_path
|
wo_site_webroot = getSiteInfo(self, wo_domain).site_path
|
||||||
|
|
||||||
if not check_domain_exists(self, wo_domain):
|
if not check_domain_exists(self, wo_domain):
|
||||||
@@ -210,7 +213,8 @@ class WOSiteController(CementBaseController):
|
|||||||
Log.error(self, 'could not input site name')
|
Log.error(self, 'could not input site name')
|
||||||
# TODO Write code for wo site edit command here
|
# TODO Write code for wo site edit command here
|
||||||
pargs.site_name = pargs.site_name.strip()
|
pargs.site_name = pargs.site_name.strip()
|
||||||
(wo_domain, wo_www_domain) = WODomain.validatedomain(self, pargs.site_name)
|
(wo_domain,
|
||||||
|
wo_www_domain) = WODomain.validatedomain(self, pargs.site_name)
|
||||||
|
|
||||||
if not check_domain_exists(self, wo_domain):
|
if not check_domain_exists(self, wo_domain):
|
||||||
Log.error(self, "site {0} does not exist".format(wo_domain))
|
Log.error(self, "site {0} does not exist".format(wo_domain))
|
||||||
@@ -241,7 +245,8 @@ class WOSiteController(CementBaseController):
|
|||||||
Log.error(self, 'Unable to read input, please try again')
|
Log.error(self, 'Unable to read input, please try again')
|
||||||
|
|
||||||
pargs.site_name = pargs.site_name.strip()
|
pargs.site_name = pargs.site_name.strip()
|
||||||
(wo_domain, wo_www_domain) = WODomain.validatedomain(self, pargs.site_name)
|
(wo_domain,
|
||||||
|
wo_www_domain) = WODomain.validatedomain(self, pargs.site_name)
|
||||||
|
|
||||||
if not check_domain_exists(self, wo_domain):
|
if not check_domain_exists(self, wo_domain):
|
||||||
Log.error(self, "site {0} does not exist".format(wo_domain))
|
Log.error(self, "site {0} does not exist".format(wo_domain))
|
||||||
@@ -281,7 +286,8 @@ class WOSiteEditController(CementBaseController):
|
|||||||
Log.error(self, 'Unable to read input, Please try again')
|
Log.error(self, 'Unable to read input, Please try again')
|
||||||
|
|
||||||
pargs.site_name = pargs.site_name.strip()
|
pargs.site_name = pargs.site_name.strip()
|
||||||
(wo_domain, wo_www_domain) = WODomain.validatedomain(self, pargs.site_name)
|
(wo_domain,
|
||||||
|
wo_www_domain) = WODomain.validatedomain(self, pargs.site_name)
|
||||||
|
|
||||||
if not check_domain_exists(self, wo_domain):
|
if not check_domain_exists(self, wo_domain):
|
||||||
Log.error(self, "site {0} does not exist".format(wo_domain))
|
Log.error(self, "site {0} does not exist".format(wo_domain))
|
||||||
@@ -422,7 +428,8 @@ class WOSiteCreateController(CementBaseController):
|
|||||||
Log.error(self, "Unable to input site name, Please try again!")
|
Log.error(self, "Unable to input site name, Please try again!")
|
||||||
|
|
||||||
pargs.site_name = pargs.site_name.strip()
|
pargs.site_name = pargs.site_name.strip()
|
||||||
(wo_domain, wo_www_domain) = WODomain.validatedomain(self, pargs.site_name)
|
(wo_domain,
|
||||||
|
wo_www_domain) = WODomain.validatedomain(self, pargs.site_name)
|
||||||
if not wo_domain.strip():
|
if not wo_domain.strip():
|
||||||
Log.error(self, "Invalid domain name, "
|
Log.error(self, "Invalid domain name, "
|
||||||
"Provide valid domain name")
|
"Provide valid domain name")
|
||||||
@@ -715,31 +722,52 @@ class WOSiteCreateController(CementBaseController):
|
|||||||
"`tail /var/log/wo/wordops.log` and please try again")
|
"`tail /var/log/wo/wordops.log` and please try again")
|
||||||
|
|
||||||
if pargs.letsencrypt:
|
if pargs.letsencrypt:
|
||||||
(wo_domain_type, wo_root_domain) = WODomain.getdomainlevel(self,
|
acme_domains = []
|
||||||
wo_domain)
|
(wo_domain_type,
|
||||||
|
wo_root_domain) = WODomain.getdomainlevel(self,
|
||||||
|
wo_domain)
|
||||||
data['letsencrypt'] = True
|
data['letsencrypt'] = True
|
||||||
letsencrypt = True
|
letsencrypt = True
|
||||||
if data['letsencrypt'] is True:
|
if data['letsencrypt'] is True:
|
||||||
|
Log.debug(self, "Going to issue Let's Encrypt certificate")
|
||||||
|
acmedata = dict(acme_domains, dns=False, acme_dns='dns_cf')
|
||||||
if pargs.dns:
|
if pargs.dns:
|
||||||
wo_acme_dns = pargs.dns
|
Log.debug(self, "DNS validation enabled")
|
||||||
wo_dns = True
|
acmedata['dns'] = True
|
||||||
else:
|
if not pargs.dns == 'dns_cf':
|
||||||
wo_acme_dns = ''
|
Log.debug(self, "DNS API : {0}".format(pargs.dns))
|
||||||
wo_dns = False
|
acmedata['acme_dns'] = pargs.dns
|
||||||
|
|
||||||
|
# detect subdomain and set subdomain variable
|
||||||
if pargs.letsencrypt == "subdomain":
|
if pargs.letsencrypt == "subdomain":
|
||||||
wo_subdomain = True
|
Log.warn(
|
||||||
wo_wildcard = False
|
self, 'Flag --letsencrypt=subdomain is '
|
||||||
|
'deprecated and not required anymore.')
|
||||||
|
acme_subdomain = True
|
||||||
|
acme_wildcard = False
|
||||||
elif pargs.letsencrypt == "wildcard":
|
elif pargs.letsencrypt == "wildcard":
|
||||||
wo_wildcard = True
|
acme_wildcard = True
|
||||||
wo_subdomain = False
|
acme_subdomain = False
|
||||||
|
acmedata['dns'] = True
|
||||||
else:
|
else:
|
||||||
wo_wildcard = False
|
if ((wo_domain_type == 'subdomain')):
|
||||||
wo_subdomain = False
|
Log.debug(self, "Domain type = {0}"
|
||||||
Log.debug(self, "Domain type = {0}"
|
.format(wo_domain_type))
|
||||||
.format(wo_domain_type))
|
acme_subdomain = True
|
||||||
if ((wo_domain_type == 'subdomain') and
|
else:
|
||||||
(not pargs.letsencrypt == 'wildcard')):
|
acme_subdomain = False
|
||||||
wo_subdomain = True
|
acme_wildcard = False
|
||||||
|
|
||||||
|
if acme_subdomain is True:
|
||||||
|
acme_domains = acme_domains + ['{0}'.format(wo_domain)]
|
||||||
|
elif acme_wildcard is True:
|
||||||
|
acme_domains = acme_domains + ['{0}'.format(wo_domain),
|
||||||
|
'*.{0}'.format(wo_domain)]
|
||||||
|
else:
|
||||||
|
acme_domains = acme_domains + ['{0}'.format(wo_domain),
|
||||||
|
'www.{0}'.format(wo_domain)]
|
||||||
|
|
||||||
|
if acme_subdomain is True:
|
||||||
# check if a wildcard cert for the root domain exist
|
# check if a wildcard cert for the root domain exist
|
||||||
Log.debug(self, "checkWildcardExist on *.{0}"
|
Log.debug(self, "checkWildcardExist on *.{0}"
|
||||||
.format(wo_root_domain))
|
.format(wo_root_domain))
|
||||||
@@ -757,12 +785,15 @@ class WOSiteCreateController(CementBaseController):
|
|||||||
else:
|
else:
|
||||||
Log.debug(self, "Setup Cert with acme.sh for {0}"
|
Log.debug(self, "Setup Cert with acme.sh for {0}"
|
||||||
.format(wo_domain))
|
.format(wo_domain))
|
||||||
setupLetsEncrypt(self, wo_domain, wo_subdomain,
|
Log.info(self, "Certificate type: Subdomain")
|
||||||
wo_wildcard, wo_dns, wo_acme_dns)
|
if WOAcme.setupletsencrypt(
|
||||||
|
self, acme_domains, acmedata):
|
||||||
|
WOAcme.deploycert(self, wo_domain)
|
||||||
else:
|
else:
|
||||||
setupLetsEncrypt(self, wo_domain, wo_subdomain,
|
if WOAcme.setupletsencrypt(
|
||||||
wo_wildcard, wo_dns, wo_acme_dns)
|
self, acme_domains, acmedata):
|
||||||
httpsRedirect(self, wo_domain, True, wo_wildcard)
|
WOAcme.deploycert(self, wo_domain)
|
||||||
|
httpsRedirect(self, wo_domain, True, acme_wildcard)
|
||||||
|
|
||||||
if pargs.hsts:
|
if pargs.hsts:
|
||||||
SSL.setuphsts(self, wo_domain)
|
SSL.setuphsts(self, wo_domain)
|
||||||
@@ -928,7 +959,8 @@ class WOSiteUpdateController(CementBaseController):
|
|||||||
Log.error(self, 'Unable to input site name, Please try again!')
|
Log.error(self, 'Unable to input site name, Please try again!')
|
||||||
|
|
||||||
pargs.site_name = pargs.site_name.strip()
|
pargs.site_name = pargs.site_name.strip()
|
||||||
(wo_domain, wo_www_domain) = WODomain.validatedomain(self, pargs.site_name)
|
(wo_domain,
|
||||||
|
wo_www_domain) = WODomain.validatedomain(self, pargs.site_name)
|
||||||
wo_site_webroot = WOVariables.wo_webroot + wo_domain
|
wo_site_webroot = WOVariables.wo_webroot + wo_domain
|
||||||
check_site = getSiteInfo(self, wo_domain)
|
check_site = getSiteInfo(self, wo_domain)
|
||||||
|
|
||||||
@@ -1126,44 +1158,47 @@ class WOSiteUpdateController(CementBaseController):
|
|||||||
pargs.php73 = False
|
pargs.php73 = False
|
||||||
|
|
||||||
if pargs.letsencrypt:
|
if pargs.letsencrypt:
|
||||||
(wo_domain_type, wo_root_domain) = WODomain.getdomainlevel(self,
|
acme_domains = []
|
||||||
wo_domain)
|
acmedata = dict(acme_domains, dns=False, acme_dns='dns_cf')
|
||||||
|
(wo_domain_type,
|
||||||
|
wo_root_domain) = WODomain.getdomainlevel(self, wo_domain)
|
||||||
|
|
||||||
if pargs.letsencrypt == 'on':
|
if pargs.letsencrypt == 'on':
|
||||||
data['letsencrypt'] = True
|
data['letsencrypt'] = True
|
||||||
letsencrypt = True
|
letsencrypt = True
|
||||||
if ((wo_domain_type == 'subdomain') and
|
if (wo_domain_type == 'subdomain'):
|
||||||
(not pargs.letsencrypt == 'wildcard')):
|
acme_subdomain = True
|
||||||
wo_subdomain = True
|
|
||||||
else:
|
else:
|
||||||
wo_subdomain = False
|
acme_subdomain = False
|
||||||
wo_wildcard = False
|
acme_wildcard = False
|
||||||
elif pargs.letsencrypt == 'subdomain':
|
elif pargs.letsencrypt == 'subdomain':
|
||||||
data['letsencrypt'] = True
|
data['letsencrypt'] = True
|
||||||
letsencrypt = True
|
letsencrypt = True
|
||||||
wo_subdomain = True
|
acme_subdomain = True
|
||||||
wo_wildcard = False
|
acme_wildcard = False
|
||||||
elif pargs.letsencrypt == 'wildcard':
|
elif pargs.letsencrypt == 'wildcard':
|
||||||
data['letsencrypt'] = True
|
data['letsencrypt'] = True
|
||||||
letsencrypt = True
|
letsencrypt = True
|
||||||
wo_wildcard = True
|
acme_wildcard = True
|
||||||
wo_subdomain = False
|
acme_subdomain = False
|
||||||
|
acmedata['dns'] = True
|
||||||
elif pargs.letsencrypt == 'off':
|
elif pargs.letsencrypt == 'off':
|
||||||
data['letsencrypt'] = False
|
data['letsencrypt'] = False
|
||||||
letsencrypt = False
|
letsencrypt = False
|
||||||
wo_subdomain = False
|
acme_subdomain = False
|
||||||
wo_wildcard = False
|
acme_wildcard = False
|
||||||
elif pargs.letsencrypt == 'clean':
|
elif pargs.letsencrypt == 'clean':
|
||||||
data['letsencrypt'] = False
|
data['letsencrypt'] = False
|
||||||
letsencrypt = False
|
letsencrypt = False
|
||||||
wo_subdomain = False
|
acme_subdomain = False
|
||||||
wo_wildcard = False
|
acme_wildcard = False
|
||||||
elif pargs.letsencrypt == 'purge':
|
elif pargs.letsencrypt == 'purge':
|
||||||
data['letsencrypt'] = False
|
data['letsencrypt'] = False
|
||||||
letsencrypt = False
|
letsencrypt = False
|
||||||
wo_subdomain = False
|
acme_subdomain = False
|
||||||
wo_wildcard = False
|
acme_wildcard = False
|
||||||
|
|
||||||
if not wo_subdomain:
|
if not (acme_subdomain is True):
|
||||||
if letsencrypt is check_ssl:
|
if letsencrypt is check_ssl:
|
||||||
if letsencrypt is False:
|
if letsencrypt is False:
|
||||||
Log.error(self, "SSl is not configured for given "
|
Log.error(self, "SSl is not configured for given "
|
||||||
@@ -1268,13 +1303,12 @@ class WOSiteUpdateController(CementBaseController):
|
|||||||
data['php73'] = False
|
data['php73'] = False
|
||||||
php73 = False
|
php73 = False
|
||||||
|
|
||||||
if pargs.letsencrypt == "on" or pargs.php73 == "on":
|
if pargs.php73 == "on":
|
||||||
if pargs.php73 == "on":
|
data['php73'] = True
|
||||||
data['php73'] = True
|
php73 = True
|
||||||
php73 = True
|
else:
|
||||||
else:
|
data['php73'] = False
|
||||||
data['php73'] = False
|
php73 = False
|
||||||
php73 = False
|
|
||||||
|
|
||||||
if pargs.wpredis and data['currcachetype'] != 'wpredis':
|
if pargs.wpredis and data['currcachetype'] != 'wpredis':
|
||||||
data['wpredis'] = True
|
data['wpredis'] = True
|
||||||
@@ -1345,20 +1379,31 @@ class WOSiteUpdateController(CementBaseController):
|
|||||||
|
|
||||||
if pargs.letsencrypt:
|
if pargs.letsencrypt:
|
||||||
if data['letsencrypt'] is True:
|
if data['letsencrypt'] is True:
|
||||||
|
# DNS API configuration
|
||||||
if pargs.dns:
|
if pargs.dns:
|
||||||
wo_acme_dns = pargs.dns
|
Log.debug(self, "DNS validation enabled")
|
||||||
wo_dns = True
|
acmedata['dns'] = True
|
||||||
|
if not pargs.dns == 'dns_cf':
|
||||||
|
Log.debug(self, "DNS API : {0}".format(pargs.dns))
|
||||||
|
acmedata['acme_dns'] = pargs.dns
|
||||||
|
# Set list of domains to secure
|
||||||
|
if acme_subdomain is True:
|
||||||
|
acme_domains = acme_domains + ['{0}'.format(wo_domain)]
|
||||||
|
elif acme_wildcard is True:
|
||||||
|
acme_domains = acme_domains + ['{0}'.format(wo_domain),
|
||||||
|
'*.{0}'.format(wo_domain)]
|
||||||
else:
|
else:
|
||||||
wo_acme_dns = ''
|
acme_domains = acme_domains + ['{0}'.format(wo_domain),
|
||||||
wo_dns = False
|
'www.{0}'.format(wo_domain)]
|
||||||
if wo_subdomain:
|
|
||||||
|
if acme_subdomain:
|
||||||
# check if a wildcard cert for the root domain exist
|
# check if a wildcard cert for the root domain exist
|
||||||
Log.debug(self, "checkWildcardExist on *.{0}"
|
Log.debug(self, "checkWildcardExist on *.{0}"
|
||||||
.format(wo_root_domain))
|
.format(wo_root_domain))
|
||||||
iswildcard = SSL.checkwildcardexist(self, wo_root_domain)
|
iswildcard = SSL.checkwildcardexist(self, wo_root_domain)
|
||||||
Log.debug(self, "iswildcard = {0}".format(iswildcard))
|
Log.debug(self, "iswildcard = {0}".format(iswildcard))
|
||||||
if not os.path.isfile("{0}/conf/nginx/ssl.conf.disabled"):
|
if not os.path.isfile("{0}/conf/nginx/ssl.conf.disabled"):
|
||||||
if wo_subdomain:
|
if acme_subdomain:
|
||||||
if iswildcard:
|
if iswildcard:
|
||||||
Log.info(self, "Using existing Wildcard SSL "
|
Log.info(self, "Using existing Wildcard SSL "
|
||||||
"certificate from {0} to secure {1}"
|
"certificate from {0} to secure {1}"
|
||||||
@@ -1371,11 +1416,10 @@ class WOSiteUpdateController(CementBaseController):
|
|||||||
else:
|
else:
|
||||||
Log.debug(self, "Setup Cert with acme.sh for {0}"
|
Log.debug(self, "Setup Cert with acme.sh for {0}"
|
||||||
.format(wo_domain))
|
.format(wo_domain))
|
||||||
setupLetsEncrypt(self, wo_domain, wo_subdomain,
|
WOAcme.setupletsencrypt(
|
||||||
wo_wildcard, wo_dns, wo_acme_dns)
|
self, acme_domains, acmedata)
|
||||||
else:
|
else:
|
||||||
setupLetsEncrypt(self, wo_domain, wo_subdomain,
|
WOAcme.setupletsencrypt(self, acme_domains, acmedata)
|
||||||
wo_wildcard, wo_dns, wo_acme_dns)
|
|
||||||
else:
|
else:
|
||||||
WOFileUtils.mvfile(self, "{0}/conf/nginx/ssl.conf.disabled"
|
WOFileUtils.mvfile(self, "{0}/conf/nginx/ssl.conf.disabled"
|
||||||
.format(wo_site_webroot),
|
.format(wo_site_webroot),
|
||||||
@@ -1387,7 +1431,7 @@ class WOSiteUpdateController(CementBaseController):
|
|||||||
'/etc/nginx/conf.d/force-ssl-{0}.conf'
|
'/etc/nginx/conf.d/force-ssl-{0}.conf'
|
||||||
.format(wo_domain))
|
.format(wo_domain))
|
||||||
|
|
||||||
httpsRedirect(self, wo_domain, True, wo_wildcard)
|
httpsRedirect(self, wo_domain, True, acme_wildcard)
|
||||||
SSL.siteurlhttps(self, wo_domain)
|
SSL.siteurlhttps(self, wo_domain)
|
||||||
|
|
||||||
if not WOService.reload_service(self, 'nginx'):
|
if not WOService.reload_service(self, 'nginx'):
|
||||||
@@ -1396,7 +1440,7 @@ class WOSiteUpdateController(CementBaseController):
|
|||||||
Log.info(self, "Congratulations! Successfully "
|
Log.info(self, "Congratulations! Successfully "
|
||||||
"Configured SSL for Site "
|
"Configured SSL for Site "
|
||||||
" https://{0}".format(wo_domain))
|
" https://{0}".format(wo_domain))
|
||||||
if wo_subdomain and iswildcard:
|
if acme_subdomain and iswildcard:
|
||||||
if (SSL.getexpirationdays(self, wo_root_domain) > 0):
|
if (SSL.getexpirationdays(self, wo_root_domain) > 0):
|
||||||
Log.info(
|
Log.info(
|
||||||
self, "Your cert will expire within " +
|
self, "Your cert will expire within " +
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ from wo.core.services import WOService
|
|||||||
from wo.core.shellexec import CommandExecutionError, WOShellExec
|
from wo.core.shellexec import CommandExecutionError, WOShellExec
|
||||||
from wo.core.sslutils import SSL
|
from wo.core.sslutils import SSL
|
||||||
from wo.core.variables import WOVariables
|
from wo.core.variables import WOVariables
|
||||||
|
from wo.core.acme import WOAcme
|
||||||
|
|
||||||
|
|
||||||
class SiteError(Exception):
|
class SiteError(Exception):
|
||||||
@@ -1348,129 +1349,6 @@ def doCleanupAction(self, domain='', webroot='', dbname='', dbuser='',
|
|||||||
|
|
||||||
# setup letsencrypt for domain + www.domain
|
# setup letsencrypt for domain + www.domain
|
||||||
|
|
||||||
|
|
||||||
def setupLetsEncrypt(self, wo_domain_name, subdomain=False, wildcard=False,
|
|
||||||
wo_dns=False, wo_acme_dns='dns_cf'):
|
|
||||||
|
|
||||||
if os.path.isfile("/etc/letsencrypt/"
|
|
||||||
"renewal/{0}_ecc/"
|
|
||||||
"fullchain.cer".format(wo_domain_name)):
|
|
||||||
Log.debug(self, "Let's Encrypt certificate "
|
|
||||||
"found for the domain: {0}"
|
|
||||||
.format(wo_domain_name))
|
|
||||||
ssl = archivedCertificateHandle(self, wo_domain_name)
|
|
||||||
else:
|
|
||||||
keylenght = "{0}".format(self.app.config.get('letsencrypt',
|
|
||||||
'keylength'))
|
|
||||||
wo_acme_exec = ("/etc/letsencrypt/acme.sh --config-home "
|
|
||||||
"'/etc/letsencrypt/config'")
|
|
||||||
if wo_dns:
|
|
||||||
acme_mode = "--dns {0}".format(wo_acme_dns)
|
|
||||||
validation_mode = "DNS with {0}".format(wo_acme_dns)
|
|
||||||
Log.debug(
|
|
||||||
self, "Validation : DNS mode with {0}".format(wo_acme_dns))
|
|
||||||
else:
|
|
||||||
acme_mode = "-w /var/www/html"
|
|
||||||
validation_mode = "Webroot challenge"
|
|
||||||
Log.debug(self, "Validation : Webroot mode")
|
|
||||||
if subdomain:
|
|
||||||
Log.info(self, "Certificate type: Subdomain")
|
|
||||||
Log.info(self, "Validation mode : {0}".format(validation_mode))
|
|
||||||
Log.wait(self, "Issuing SSL cert with acme.sh")
|
|
||||||
ssl = WOShellExec.cmd_exec(self, "{0} ".format(wo_acme_exec) +
|
|
||||||
"--issue "
|
|
||||||
"-d {0} {1} "
|
|
||||||
"-k {2} -f"
|
|
||||||
.format(wo_domain_name,
|
|
||||||
acme_mode,
|
|
||||||
keylenght))
|
|
||||||
elif wildcard:
|
|
||||||
Log.info(self, "Certificate type: Wildcard")
|
|
||||||
Log.info(self, "Validation mode : {0}".format(validation_mode))
|
|
||||||
Log.wait(self, "Issuing SSL cert with acme.sh")
|
|
||||||
ssl = WOShellExec.cmd_exec(self, "{0} ".format(wo_acme_exec) +
|
|
||||||
"--issue "
|
|
||||||
"-d {0} -d '*.{0}' --dns {1} "
|
|
||||||
"-k {2} -f"
|
|
||||||
.format(wo_domain_name,
|
|
||||||
wo_acme_dns,
|
|
||||||
keylenght))
|
|
||||||
else:
|
|
||||||
Log.info(self, "Certificate type: Domain + www")
|
|
||||||
Log.info(self, "Validation mode : {0}".format(validation_mode))
|
|
||||||
Log.wait(self, "Issuing SSL cert with acme.sh")
|
|
||||||
ssl = WOShellExec.cmd_exec(self, "{0} ".format(wo_acme_exec) +
|
|
||||||
"--issue "
|
|
||||||
"-d {0} -d www.{0} {1} "
|
|
||||||
"-k {2} -f"
|
|
||||||
.format(wo_domain_name,
|
|
||||||
acme_mode, keylenght))
|
|
||||||
if ssl:
|
|
||||||
Log.valide(self, "Issuing SSL cert with acme.sh")
|
|
||||||
Log.wait(self, "Deploying SSL cert")
|
|
||||||
Log.debug(self, "Cert deployment for domain: {0}"
|
|
||||||
.format(wo_domain_name))
|
|
||||||
try:
|
|
||||||
|
|
||||||
WOShellExec.cmd_exec(self, "mkdir -p {0}/{1} && "
|
|
||||||
"/etc/letsencrypt/acme.sh "
|
|
||||||
"--config-home "
|
|
||||||
"'/etc/letsencrypt/config' "
|
|
||||||
"--install-cert -d {1} --ecc "
|
|
||||||
"--cert-file {0}/{1}/cert.pem "
|
|
||||||
"--key-file {0}/{1}/key.pem "
|
|
||||||
"--fullchain-file "
|
|
||||||
"{0}/{1}/fullchain.pem "
|
|
||||||
"--ca-file {0}/{1}/ca.pem "
|
|
||||||
"--reloadcmd "
|
|
||||||
"\"nginx -t && "
|
|
||||||
"service nginx restart\" "
|
|
||||||
.format(WOVariables.wo_ssl_live,
|
|
||||||
wo_domain_name))
|
|
||||||
Log.valide(self, "Deploying SSL cert")
|
|
||||||
if os.path.isdir('/var/www/{0}/conf/nginx'
|
|
||||||
.format(wo_domain_name)):
|
|
||||||
|
|
||||||
sslconf = open("/var/www/{0}/conf/nginx/ssl.conf"
|
|
||||||
.format(wo_domain_name),
|
|
||||||
encoding='utf-8', mode='w')
|
|
||||||
sslconf.write(
|
|
||||||
"listen 443 ssl http2;\n"
|
|
||||||
"listen [::]:443 ssl http2;\n"
|
|
||||||
"ssl_certificate {0}/{1}/fullchain.pem;\n"
|
|
||||||
"ssl_certificate_key {0}/{1}/key.pem;\n"
|
|
||||||
"ssl_trusted_certificate {0}/{1}/ca.pem;\n"
|
|
||||||
"ssl_stapling_verify on;\n"
|
|
||||||
.format(WOVariables.wo_ssl_live, wo_domain_name))
|
|
||||||
sslconf.close()
|
|
||||||
# updateSiteInfo(self, wo_domain_name, ssl=True)
|
|
||||||
if not WOFileUtils.grep(self, '/var/www/22222/conf/nginx/ssl.conf',
|
|
||||||
'/etc/letsencrypt'):
|
|
||||||
Log.info(self, "Securing WordOps backend with {0} certificate"
|
|
||||||
.format(wo_domain_name))
|
|
||||||
sslconf = open("/var/www/22222/conf/nginx/ssl.conf",
|
|
||||||
encoding='utf-8', mode='w')
|
|
||||||
sslconf.write("ssl_certificate {0}/{1}/fullchain.pem;\n"
|
|
||||||
"ssl_certificate_key {0}/{1}/key.pem;\n"
|
|
||||||
"ssl_trusted_certificate {0}/{1}/ca.pem;\n"
|
|
||||||
"ssl_stapling_verify on;\n"
|
|
||||||
.format(WOVariables.wo_ssl_live, wo_domain_name))
|
|
||||||
sslconf.close()
|
|
||||||
|
|
||||||
WOGit.add(self, ["/etc/letsencrypt"],
|
|
||||||
msg="Adding letsencrypt folder")
|
|
||||||
|
|
||||||
except IOError as e:
|
|
||||||
Log.debug(self, str(e))
|
|
||||||
Log.debug(self, "Error occured while generating "
|
|
||||||
"ssl.conf")
|
|
||||||
else:
|
|
||||||
Log.error(self, "Unable to install certificate", False)
|
|
||||||
Log.error(self, "Please make sure that your site is pointed to \n"
|
|
||||||
"same server on which "
|
|
||||||
"you are running Let\'s Encrypt Client "
|
|
||||||
"\n to allow it to verify the site automatically.")
|
|
||||||
|
|
||||||
# copy wildcard certificate to a subdomain
|
# copy wildcard certificate to a subdomain
|
||||||
|
|
||||||
|
|
||||||
@@ -1616,14 +1494,16 @@ def httpsRedirect(self, wo_domain_name, redirect=True, wildcard=False):
|
|||||||
|
|
||||||
|
|
||||||
def archivedCertificateHandle(self, domain):
|
def archivedCertificateHandle(self, domain):
|
||||||
Log.warn(self, "You already have an existing certificate "
|
Log.warn(
|
||||||
"for the domain requested.\n"
|
self, "You already have an existing certificate "
|
||||||
"(ref: {0}/"
|
"for the domain requested.\n"
|
||||||
"{1}_ecc/{1}.conf)".format(WOVariables.wo_ssl_archive, domain) +
|
"(ref: {0}/"
|
||||||
"\nPlease select an option from below?"
|
"{1}_ecc/{1}.conf)".format(WOVariables.wo_ssl_archive, domain) +
|
||||||
"\n\t1: Reinstall existing certificate"
|
"\nPlease select an option from below?"
|
||||||
"\n\t2: Renew & replace the certificate (limit ~5 per 7 days)"
|
"\n\t1: Reinstall existing certificate"
|
||||||
"")
|
"\n\t2: Issue a new certificate to replace "
|
||||||
|
"the current one (limit ~5 per 7 days)"
|
||||||
|
"")
|
||||||
check_prompt = input(
|
check_prompt = input(
|
||||||
"\nType the appropriate number [1-2] or any other key to cancel: ")
|
"\nType the appropriate number [1-2] or any other key to cancel: ")
|
||||||
if not os.path.isfile("{0}/{1}/fullchain.pem"
|
if not os.path.isfile("{0}/{1}/fullchain.pem"
|
||||||
@@ -1634,20 +1514,7 @@ def archivedCertificateHandle(self, domain):
|
|||||||
|
|
||||||
if check_prompt == "1":
|
if check_prompt == "1":
|
||||||
Log.info(self, "Reinstalling SSL cert with acme.sh")
|
Log.info(self, "Reinstalling SSL cert with acme.sh")
|
||||||
ssl = WOShellExec.cmd_exec(self, "mkdir -p {0}/{1} && "
|
ssl = WOAcme.deploycert(self, domain)
|
||||||
"/etc/letsencrypt/acme.sh "
|
|
||||||
"--config-home "
|
|
||||||
"'/etc/letsencrypt/config' "
|
|
||||||
"--install-cert -d {1} --ecc "
|
|
||||||
"--cert-file {0}/{1}/cert.pem "
|
|
||||||
"--key-file {0}/{1}/key.pem "
|
|
||||||
"--fullchain-file "
|
|
||||||
"{0}/{1}/fullchain.pem "
|
|
||||||
"--ca-file {0}/{1}/ca.pem "
|
|
||||||
"--reloadcmd "
|
|
||||||
"\"nginx -t && service nginx restart\" "
|
|
||||||
.format(WOVariables.wo_ssl_live,
|
|
||||||
domain))
|
|
||||||
if ssl:
|
if ssl:
|
||||||
|
|
||||||
try:
|
try:
|
||||||
|
|||||||
129
wo/core/acme.py
Normal file
129
wo/core/acme.py
Normal file
@@ -0,0 +1,129 @@
|
|||||||
|
import os
|
||||||
|
|
||||||
|
import requests
|
||||||
|
|
||||||
|
from wo.core.fileutils import WOFileUtils
|
||||||
|
from wo.core.git import WOGit
|
||||||
|
from wo.core.logging import Log
|
||||||
|
from wo.core.shellexec import WOShellExec
|
||||||
|
from wo.core.variables import WOVariables
|
||||||
|
|
||||||
|
|
||||||
|
class WOAcme:
|
||||||
|
"""Acme.sh utilities for WordOps"""
|
||||||
|
|
||||||
|
def setupletsencrypt(self, acme_domain, acmedata):
|
||||||
|
"""issue SSL certificates with acme.sh"""
|
||||||
|
all_domains = '\' -d \''.join(acme_domain)
|
||||||
|
wo_acme_dns = acmedata['acme_dns']
|
||||||
|
keylenght = "{0}".format(self.app.config.get('letsencrypt',
|
||||||
|
'keylength'))
|
||||||
|
wo_acme_exec = ("/etc/letsencrypt/acme.sh --config-home "
|
||||||
|
"'/etc/letsencrypt/config'")
|
||||||
|
if acmedata['dns'] is True:
|
||||||
|
acme_mode = "--dns {0}".format(wo_acme_dns)
|
||||||
|
validation_mode = "DNS mode with {0}".format(wo_acme_dns)
|
||||||
|
else:
|
||||||
|
acme_mode = "-w /var/www/html"
|
||||||
|
validation_mode = "Webroot challenge"
|
||||||
|
Log.debug(self, "Validation : Webroot mode")
|
||||||
|
|
||||||
|
Log.info(self, "Validation mode : {0}".format(validation_mode))
|
||||||
|
Log.wait(self, "Issuing SSL cert with acme.sh")
|
||||||
|
try:
|
||||||
|
WOShellExec.cmd_exec(
|
||||||
|
self, "{0} ".format(wo_acme_exec) +
|
||||||
|
"--issue -d '{0}' {1} -k {2} -f"
|
||||||
|
.format(all_domains, acme_mode, keylenght))
|
||||||
|
except Exception as e:
|
||||||
|
Log.failed(self, "Issuing SSL cert with acme.sh")
|
||||||
|
Log.debug(self, str(e))
|
||||||
|
Log.error(self, "Unable to issue certificate", False)
|
||||||
|
if acmedata['dns'] is True:
|
||||||
|
Log.warn(
|
||||||
|
self, "Please make sure your properly "
|
||||||
|
"set your DNS API credentials for acme.sh")
|
||||||
|
else:
|
||||||
|
server_ip = requests.get('http://v4.wordops.eu/').text
|
||||||
|
for domain in wo_domain:
|
||||||
|
domain_ip = requests.get('http://v4.wordops.eu/dns/{0}/'
|
||||||
|
.format(domain)).text
|
||||||
|
if(not domain_ip == server_ip):
|
||||||
|
Log.warn(
|
||||||
|
self, "{0} is not pointing to your server IP"
|
||||||
|
.format(domain))
|
||||||
|
Log.error(
|
||||||
|
self, "You have to add the "
|
||||||
|
"proper DNS record", False)
|
||||||
|
break
|
||||||
|
else:
|
||||||
|
Log.error(
|
||||||
|
self, "Your domain is properly configured "
|
||||||
|
"but acme.sh was unable to issue certificate.\n"
|
||||||
|
"You can find more informations in "
|
||||||
|
"/var/log/wo/wordops.log", False)
|
||||||
|
return False
|
||||||
|
Log.valide(self, "Issuing SSL cert with acme.sh")
|
||||||
|
return True
|
||||||
|
|
||||||
|
def deploycert(self, wo_domain_name):
|
||||||
|
wo_acme_exec = ("/etc/letsencrypt/acme.sh --config-home "
|
||||||
|
"'/etc/letsencrypt/config'")
|
||||||
|
if not os.path.isfile('/etc/letsencrypt/{0}_ecc/fullchain.cer'
|
||||||
|
.format(wo_domain_name)):
|
||||||
|
Log.error(self, 'Certificate not found. Deployment canceled')
|
||||||
|
|
||||||
|
Log.debug(self, "Cert deployment for domain: {0}"
|
||||||
|
.format(wo_domain_name))
|
||||||
|
|
||||||
|
try:
|
||||||
|
Log.wait(self, "Deploying SSL cert")
|
||||||
|
if WOShellExec.cmd_exec(
|
||||||
|
self, "mkdir -p {0}/{1} && {2} --install-cert -d {1} --ecc "
|
||||||
|
"--cert-file {0}/{1}/cert.pem --key-file {0}/{1}/key.pem "
|
||||||
|
"--fullchain-file {0}/{1}/fullchain.pem "
|
||||||
|
"--ca-file {0}/{1}/ca.pem --reloadcmd \"nginx -t && "
|
||||||
|
"service nginx restart\" "
|
||||||
|
.format(WOVariables.wo_ssl_live,
|
||||||
|
wo_domain_name, wo_acme_exec)):
|
||||||
|
Log.valide(self, "Deploying SSL cert")
|
||||||
|
else:
|
||||||
|
Log.failed(self, "Deploying SSL cert")
|
||||||
|
Log.error(self, "Unable to deploy certificate")
|
||||||
|
|
||||||
|
if os.path.isdir('/var/www/{0}/conf/nginx'
|
||||||
|
.format(wo_domain_name)):
|
||||||
|
|
||||||
|
sslconf = open("/var/www/{0}/conf/nginx/ssl.conf"
|
||||||
|
.format(wo_domain_name),
|
||||||
|
encoding='utf-8', mode='w')
|
||||||
|
sslconf.write(
|
||||||
|
"listen 443 ssl http2;\n"
|
||||||
|
"listen [::]:443 ssl http2;\n"
|
||||||
|
"ssl_certificate {0}/{1}/fullchain.pem;\n"
|
||||||
|
"ssl_certificate_key {0}/{1}/key.pem;\n"
|
||||||
|
"ssl_trusted_certificate {0}/{1}/ca.pem;\n"
|
||||||
|
"ssl_stapling_verify on;\n"
|
||||||
|
.format(WOVariables.wo_ssl_live, wo_domain_name))
|
||||||
|
sslconf.close()
|
||||||
|
|
||||||
|
if not WOFileUtils.grep(self, '/var/www/22222/conf/nginx/ssl.conf',
|
||||||
|
'/etc/letsencrypt'):
|
||||||
|
Log.info(self, "Securing WordOps backend with current cert"
|
||||||
|
.format(wo_domain_name))
|
||||||
|
sslconf = open("/var/www/22222/conf/nginx/ssl.conf",
|
||||||
|
encoding='utf-8', mode='w')
|
||||||
|
sslconf.write("ssl_certificate {0}/{1}/fullchain.pem;\n"
|
||||||
|
"ssl_certificate_key {0}/{1}/key.pem;\n"
|
||||||
|
"ssl_trusted_certificate {0}/{1}/ca.pem;\n"
|
||||||
|
"ssl_stapling_verify on;\n"
|
||||||
|
.format(WOVariables.wo_ssl_live, wo_domain_name))
|
||||||
|
sslconf.close()
|
||||||
|
|
||||||
|
WOGit.add(self, ["/etc/letsencrypt"],
|
||||||
|
msg="Adding letsencrypt folder")
|
||||||
|
|
||||||
|
except IOError as e:
|
||||||
|
Log.debug(self, str(e))
|
||||||
|
Log.debug(self, "Error occured while generating "
|
||||||
|
"ssl.conf")
|
||||||
Reference in New Issue
Block a user