mirror of
https://github.com/certbot/certbot.git
synced 2026-08-01 18:56:55 +02:00
Removed trailing whitespace as well as unused imports
This commit is contained in:
+7
-7
@@ -16,10 +16,10 @@ def main():
|
|||||||
sys.exit("\nOnly root can run letsencrypt.\n")
|
sys.exit("\nOnly root can run letsencrypt.\n")
|
||||||
# Parse options
|
# Parse options
|
||||||
try:
|
try:
|
||||||
opts, args = getopt.getopt(sys.argv[1:], "", ["text", "test",
|
opts, args = getopt.getopt(sys.argv[1:], "", ["text", "test",
|
||||||
"view-checkpoints",
|
"view-checkpoints",
|
||||||
"privkey=", "csr=",
|
"privkey=", "csr=",
|
||||||
"server=", "rollback=",
|
"server=", "rollback=",
|
||||||
"revoke", "agree-eula",
|
"revoke", "agree-eula",
|
||||||
"redirect",
|
"redirect",
|
||||||
"no-redirect",
|
"no-redirect",
|
||||||
@@ -82,10 +82,10 @@ def main():
|
|||||||
display.setDisplay(display.NcursesDisplay())
|
display.setDisplay(display.NcursesDisplay())
|
||||||
else:
|
else:
|
||||||
display.setDisplay(display.FileDisplay(sys.stdout))
|
display.setDisplay(display.FileDisplay(sys.stdout))
|
||||||
|
|
||||||
if not server:
|
if not server:
|
||||||
server = ACME_SERVER
|
server = ACME_SERVER
|
||||||
|
|
||||||
c = client.Client(server, csr, privkey, curses)
|
c = client.Client(server, csr, privkey, curses)
|
||||||
if flag_revoke:
|
if flag_revoke:
|
||||||
c.list_certs_keys()
|
c.list_certs_keys()
|
||||||
@@ -108,7 +108,7 @@ def print_options():
|
|||||||
"view-checkpoints (Used to view available checkpoints and " +
|
"view-checkpoints (Used to view available checkpoints and " +
|
||||||
"see what configuration changes have been made)",
|
"see what configuration changes have been made)",
|
||||||
"rollback=X (Revert the configuration X number of checkpoints)",
|
"rollback=X (Revert the configuration X number of checkpoints)",
|
||||||
"redirect (Automatically redirect all HTTP traffic to " +
|
"redirect (Automatically redirect all HTTP traffic to " +
|
||||||
"HTTPS for the newly authenticated vhost)",
|
"HTTPS for the newly authenticated vhost)",
|
||||||
"no-redirect (Skip the HTTPS redirect question, " +
|
"no-redirect (Skip the HTTPS redirect question, " +
|
||||||
"allowing both HTTP and HTTPS)",
|
"allowing both HTTP and HTTPS)",
|
||||||
|
|||||||
@@ -10,4 +10,4 @@ class Challenge(object):
|
|||||||
logger.error("Error - base class challenge.generate_response()")
|
logger.error("Error - base class challenge.generate_response()")
|
||||||
def clean(self):
|
def clean(self):
|
||||||
logger.error("Error - base class challenge.clean()")
|
logger.error("Error - base class challenge.clean()")
|
||||||
|
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
import M2Crypto
|
import M2Crypto
|
||||||
import json
|
import json
|
||||||
import os, grp, pwd, sys, time, random, sys, shutil
|
import os, time, sys, shutil
|
||||||
|
|
||||||
# This line suppresses the no logging found for module 'jose' warning
|
# This line suppresses the no logging found for module 'jose' warning
|
||||||
# TODO: Check out this module and see if we should be using it for our
|
# TODO: Check out this module and see if we should be using it for our
|
||||||
@@ -12,22 +12,15 @@ logging.basicConfig(filename="/dev/null", level=logging.ERROR)
|
|||||||
|
|
||||||
|
|
||||||
import jose, csv
|
import jose, csv
|
||||||
import subprocess
|
|
||||||
from M2Crypto import EVP, X509, RSA
|
|
||||||
from Crypto.Random import get_random_bytes
|
|
||||||
from Crypto.PublicKey import RSA
|
|
||||||
from Crypto.Signature import PKCS1_v1_5
|
|
||||||
from Crypto.Hash import SHA256
|
|
||||||
|
|
||||||
import requests
|
import requests
|
||||||
|
|
||||||
from letsencrypt.client.acme import acme_object_validate
|
from letsencrypt.client.acme import acme_object_validate
|
||||||
from letsencrypt.client.sni_challenge import SNI_Challenge
|
from letsencrypt.client.sni_challenge import SNI_Challenge
|
||||||
from letsencrypt.client.payment_challenge import Payment_Challenge
|
|
||||||
from letsencrypt.client import configurator
|
from letsencrypt.client import configurator
|
||||||
from letsencrypt.client import logger, display
|
from letsencrypt.client import logger, display
|
||||||
from letsencrypt.client import le_util, crypto_util, display
|
from letsencrypt.client import le_util, crypto_util
|
||||||
from letsencrypt.client.CONFIG import NONCE_SIZE, RSA_KEY_SIZE, CERT_PATH
|
from letsencrypt.client.CONFIG import RSA_KEY_SIZE, CERT_PATH
|
||||||
from letsencrypt.client.CONFIG import CHAIN_PATH, SERVER_ROOT, KEY_DIR, CERT_DIR
|
from letsencrypt.client.CONFIG import CHAIN_PATH, SERVER_ROOT, KEY_DIR, CERT_DIR
|
||||||
from letsencrypt.client.CONFIG import CERT_KEY_BACKUP
|
from letsencrypt.client.CONFIG import CERT_KEY_BACKUP
|
||||||
from letsencrypt.client.CONFIG import CHALLENGE_PREFERENCES, EXCLUSIVE_CHALLENGES
|
from letsencrypt.client.CONFIG import CHALLENGE_PREFERENCES, EXCLUSIVE_CHALLENGES
|
||||||
@@ -50,7 +43,7 @@ class Client(object):
|
|||||||
self.config = configurator.Configurator(SERVER_ROOT)
|
self.config = configurator.Configurator(SERVER_ROOT)
|
||||||
|
|
||||||
self.server = ca_server
|
self.server = ca_server
|
||||||
|
|
||||||
self.csr_file = cert_signing_request
|
self.csr_file = cert_signing_request
|
||||||
self.key_file = private_key
|
self.key_file = private_key
|
||||||
|
|
||||||
@@ -70,7 +63,7 @@ class Client(object):
|
|||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|
||||||
self.redirect = redirect
|
self.redirect = redirect
|
||||||
|
|
||||||
# Display preview warning
|
# Display preview warning
|
||||||
if not eula:
|
if not eula:
|
||||||
with open('EULA') as f:
|
with open('EULA') as f:
|
||||||
@@ -202,7 +195,7 @@ class Client(object):
|
|||||||
os.remove(c['backup_cert_file'])
|
os.remove(c['backup_cert_file'])
|
||||||
os.remove(c['backup_key_file'])
|
os.remove(c['backup_key_file'])
|
||||||
|
|
||||||
|
|
||||||
def list_certs_keys(self):
|
def list_certs_keys(self):
|
||||||
list_file = CERT_KEY_BACKUP + "LIST"
|
list_file = CERT_KEY_BACKUP + "LIST"
|
||||||
certs = []
|
certs = []
|
||||||
@@ -214,10 +207,10 @@ class Client(object):
|
|||||||
c_sha1_vh = {}
|
c_sha1_vh = {}
|
||||||
for x in self.config.get_all_certs_keys():
|
for x in self.config.get_all_certs_keys():
|
||||||
try:
|
try:
|
||||||
c_sha1_vh[M2Crypto.X509.load_cert(x[0]).get_fingerprint(md='sha1')] = x[2]
|
c_sha1_vh[M2Crypto.X509.load_cert(x[0]).get_fingerprint(md='sha1')] = x[2]
|
||||||
except:
|
except:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
with open(list_file, 'rb') as csvfile:
|
with open(list_file, 'rb') as csvfile:
|
||||||
csvreader = csv.reader(csvfile)
|
csvreader = csv.reader(csvfile)
|
||||||
for row in csvreader:
|
for row in csvreader:
|
||||||
@@ -315,7 +308,7 @@ class Client(object):
|
|||||||
#if self.ocsp_stapling:
|
#if self.ocsp_stapling:
|
||||||
# TODO enable OCSP Stapling
|
# TODO enable OCSP Stapling
|
||||||
# continue
|
# continue
|
||||||
|
|
||||||
|
|
||||||
def certificate_request(self, csr_der, key):
|
def certificate_request(self, csr_der, key):
|
||||||
logger.info("Preparing and sending CSR..")
|
logger.info("Preparing and sending CSR..")
|
||||||
|
|||||||
@@ -3,18 +3,16 @@ import subprocess
|
|||||||
import re
|
import re
|
||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
import stat
|
|
||||||
import socket
|
import socket
|
||||||
import time
|
import time
|
||||||
import shutil
|
import shutil
|
||||||
import errno
|
|
||||||
|
|
||||||
from letsencrypt.client.CONFIG import SERVER_ROOT, BACKUP_DIR
|
from letsencrypt.client.CONFIG import SERVER_ROOT, BACKUP_DIR
|
||||||
from letsencrypt.client.CONFIG import REWRITE_HTTPS_ARGS, CONFIG_DIR, WORK_DIR
|
from letsencrypt.client.CONFIG import REWRITE_HTTPS_ARGS, CONFIG_DIR, WORK_DIR
|
||||||
from letsencrypt.client.CONFIG import TEMP_CHECKPOINT_DIR, IN_PROGRESS_DIR
|
from letsencrypt.client.CONFIG import TEMP_CHECKPOINT_DIR, IN_PROGRESS_DIR
|
||||||
from letsencrypt.client.CONFIG import OPTIONS_SSL_CONF, LE_VHOST_EXT
|
from letsencrypt.client.CONFIG import OPTIONS_SSL_CONF, LE_VHOST_EXT
|
||||||
from letsencrypt.client import logger, le_util
|
from letsencrypt.client import logger, le_util
|
||||||
#from CONFIG import SERVER_ROOT, BACKUP_DIR, REWRITE_HTTPS_ARGS, CONFIG_DIR,
|
#from CONFIG import SERVER_ROOT, BACKUP_DIR, REWRITE_HTTPS_ARGS, CONFIG_DIR,
|
||||||
#from CONFIG import WORK_DIR, TEMP_CHECKPOINT_DIR, IN_PROGRESS_DIR, OPTIONS_SSL_CONF, TRUSTIFY_VHOST_EXT
|
#from CONFIG import WORK_DIR, TEMP_CHECKPOINT_DIR, IN_PROGRESS_DIR, OPTIONS_SSL_CONF, TRUSTIFY_VHOST_EXT
|
||||||
#import logger, le_util
|
#import logger, le_util
|
||||||
|
|
||||||
@@ -38,7 +36,7 @@ from letsencrypt.client import logger, le_util
|
|||||||
# Note: This protocol works for filenames with spaces in it, the sites are
|
# Note: This protocol works for filenames with spaces in it, the sites are
|
||||||
# properly set up and directives are changed appropriately, but Apache won't
|
# properly set up and directives are changed appropriately, but Apache won't
|
||||||
# recognize names in sites-enabled that have spaces. These are not added to the
|
# recognize names in sites-enabled that have spaces. These are not added to the
|
||||||
# Apache configuration. It may be wise to warn the user if they are trying
|
# Apache configuration. It may be wise to warn the user if they are trying
|
||||||
# to use vhost filenames that contain spaces and offer to change ' ' to '_'
|
# to use vhost filenames that contain spaces and offer to change ' ' to '_'
|
||||||
|
|
||||||
# Note: FILEPATHS and changes to files are transactional. They are copied
|
# Note: FILEPATHS and changes to files are transactional. They are copied
|
||||||
@@ -69,24 +67,24 @@ class Configurator(object):
|
|||||||
|
|
||||||
This class was originally developed for Apache 2.2 and has not seen a
|
This class was originally developed for Apache 2.2 and has not seen a
|
||||||
an overhaul to include proper setup of new Apache configurations.
|
an overhaul to include proper setup of new Apache configurations.
|
||||||
The biggest changes have been the IncludeOptional directive, the
|
The biggest changes have been the IncludeOptional directive, the
|
||||||
deprecation of the NameVirtualHost directive, and the name change of
|
deprecation of the NameVirtualHost directive, and the name change of
|
||||||
mod_ssl.c to ssl_module. Although these changes
|
mod_ssl.c to ssl_module. Although these changes
|
||||||
have not been implemented yet, they will be shortly.
|
have not been implemented yet, they will be shortly.
|
||||||
That being said, this class can still adequately configure most typical
|
That being said, this class can still adequately configure most typical
|
||||||
Apache 2.4 servers as the deprecated NameVirtualHost has no effect
|
Apache 2.4 servers as the deprecated NameVirtualHost has no effect
|
||||||
and the typical directories are parsed by the Augeas configuration
|
and the typical directories are parsed by the Augeas configuration
|
||||||
parser automatically.
|
parser automatically.
|
||||||
|
|
||||||
The API of this class will change in the coming weeks as the exact
|
The API of this class will change in the coming weeks as the exact
|
||||||
needs of client's are clarified with the new and developing protocol.
|
needs of client's are clarified with the new and developing protocol.
|
||||||
|
|
||||||
This class will eventually derive from a generic Configurator class
|
This class will eventually derive from a generic Configurator class
|
||||||
so that other Configurators (like Nginx) can be developed and interoperate
|
so that other Configurators (like Nginx) can be developed and interoperate
|
||||||
with the client.
|
with the client.
|
||||||
"""
|
"""
|
||||||
def __init__(self, server_root=SERVER_ROOT):
|
def __init__(self, server_root=SERVER_ROOT):
|
||||||
# TODO: this instantiation can be optimized to only load Httd
|
# TODO: this instantiation can be optimized to only load Httd
|
||||||
# relevant files - I believe -> NO_MODL_AUTOLOAD
|
# relevant files - I believe -> NO_MODL_AUTOLOAD
|
||||||
|
|
||||||
self.server_root = server_root
|
self.server_root = server_root
|
||||||
@@ -103,7 +101,7 @@ class Configurator(object):
|
|||||||
self.check_parsing_errors()
|
self.check_parsing_errors()
|
||||||
# This problem has been fixed in Augeas 1.0
|
# This problem has been fixed in Augeas 1.0
|
||||||
self.standardize_excl()
|
self.standardize_excl()
|
||||||
|
|
||||||
# Determine user's main config file
|
# Determine user's main config file
|
||||||
self.__set_user_config_file()
|
self.__set_user_config_file()
|
||||||
|
|
||||||
@@ -114,20 +112,20 @@ class Configurator(object):
|
|||||||
self.assoc = dict()
|
self.assoc = dict()
|
||||||
# Verify that all directories and files exist with proper permissions
|
# Verify that all directories and files exist with proper permissions
|
||||||
self.verify_setup()
|
self.verify_setup()
|
||||||
|
|
||||||
# Note: initialization doesn't check to see if the config is correct
|
# Note: initialization doesn't check to see if the config is correct
|
||||||
# by Apache's standards. This should be done by the client (client.py)
|
# by Apache's standards. This should be done by the client (client.py)
|
||||||
# if it is desired. There may be instances where correct configuration
|
# if it is desired. There may be instances where correct configuration
|
||||||
# isn't required on startup.
|
# isn't required on startup.
|
||||||
|
|
||||||
# TODO: This function can be improved to ensure that the final directives
|
# TODO: This function can be improved to ensure that the final directives
|
||||||
# are being modified whether that be in the include files or in the
|
# are being modified whether that be in the include files or in the
|
||||||
# virtualhost declaration - these directives can be overwritten
|
# virtualhost declaration - these directives can be overwritten
|
||||||
def deploy_cert(self, vhost, cert, key, cert_chain=None):
|
def deploy_cert(self, vhost, cert, key, cert_chain=None):
|
||||||
"""
|
"""
|
||||||
Currently tries to find the last directives to deploy the cert in
|
Currently tries to find the last directives to deploy the cert in
|
||||||
the given virtualhost. If it can't find the directives, it searches
|
the given virtualhost. If it can't find the directives, it searches
|
||||||
the "included" confs. The function verifies that it has located
|
the "included" confs. The function verifies that it has located
|
||||||
the three directives and finally modifies them to point to the correct
|
the three directives and finally modifies them to point to the correct
|
||||||
destination
|
destination
|
||||||
TODO: Make sure last directive is changed
|
TODO: Make sure last directive is changed
|
||||||
@@ -136,23 +134,23 @@ class Configurator(object):
|
|||||||
"""
|
"""
|
||||||
search = {}
|
search = {}
|
||||||
path = {}
|
path = {}
|
||||||
|
|
||||||
path["cert_file"] = self.find_directive(self.case_i("SSLCertificateFile"), None, vhost.path)
|
path["cert_file"] = self.find_directive(self.case_i("SSLCertificateFile"), None, vhost.path)
|
||||||
path["cert_key"] = self.find_directive(self.case_i("SSLCertificateKeyFile"), None, vhost.path)
|
path["cert_key"] = self.find_directive(self.case_i("SSLCertificateKeyFile"), None, vhost.path)
|
||||||
|
|
||||||
# Only include if a certificate chain is specified
|
# Only include if a certificate chain is specified
|
||||||
if cert_chain is not None:
|
if cert_chain is not None:
|
||||||
path["cert_chain"] = self.find_directive(self.case_i("SSLCertificateChainFile"), None, vhost.path)
|
path["cert_chain"] = self.find_directive(self.case_i("SSLCertificateChainFile"), None, vhost.path)
|
||||||
|
|
||||||
if len(path["cert_file"]) == 0 or len(path["cert_key"]) == 0:
|
if len(path["cert_file"]) == 0 or len(path["cert_key"]) == 0:
|
||||||
# Throw some "can't find all of the directives error"
|
# Throw some "can't find all of the directives error"
|
||||||
logger.warn("Warn: cannot find a cert or key directive in " + vhost.path)
|
logger.warn("Warn: cannot find a cert or key directive in " + vhost.path)
|
||||||
logger.warn("VirtualHost was not modified")
|
logger.warn("VirtualHost was not modified")
|
||||||
# Presumably break here so that the virtualhost is not modified
|
# Presumably break here so that the virtualhost is not modified
|
||||||
return False
|
return False
|
||||||
|
|
||||||
logger.info("Deploying Certificate to VirtualHost %s" % vhost.file)
|
logger.info("Deploying Certificate to VirtualHost %s" % vhost.file)
|
||||||
|
|
||||||
self.aug.set(path["cert_file"][0], cert)
|
self.aug.set(path["cert_file"][0], cert)
|
||||||
self.aug.set(path["cert_key"][0], key)
|
self.aug.set(path["cert_key"][0], key)
|
||||||
if cert_chain is not None:
|
if cert_chain is not None:
|
||||||
@@ -160,7 +158,7 @@ class Configurator(object):
|
|||||||
self.add_dir(vhost.path, "SSLCertificateChainFile", cert_chain)
|
self.add_dir(vhost.path, "SSLCertificateChainFile", cert_chain)
|
||||||
else:
|
else:
|
||||||
self.aug.set(path["cert_chain"][0], cert_chain)
|
self.aug.set(path["cert_chain"][0], cert_chain)
|
||||||
|
|
||||||
self.save_notes += "Changed vhost at %s with addresses of %s\n" % (vhost.file, vhost.addrs)
|
self.save_notes += "Changed vhost at %s with addresses of %s\n" % (vhost.file, vhost.addrs)
|
||||||
self.save_notes += "\tSSLCertificateFile %s\n" % cert
|
self.save_notes += "\tSSLCertificateFile %s\n" % cert
|
||||||
self.save_notes += "\tSSLCertificateKeyFile %s\n" % key
|
self.save_notes += "\tSSLCertificateKeyFile %s\n" % key
|
||||||
@@ -218,7 +216,7 @@ class Configurator(object):
|
|||||||
"""
|
"""
|
||||||
self.assoc[dn] = vh
|
self.assoc[dn] = vh
|
||||||
return
|
return
|
||||||
|
|
||||||
def get_all_names(self):
|
def get_all_names(self):
|
||||||
"""
|
"""
|
||||||
Returns all names found in the Apache Configuration
|
Returns all names found in the Apache Configuration
|
||||||
@@ -259,7 +257,7 @@ class Configurator(object):
|
|||||||
|
|
||||||
#def __is_private_ip(ipaddr):
|
#def __is_private_ip(ipaddr):
|
||||||
# re.compile()
|
# re.compile()
|
||||||
|
|
||||||
|
|
||||||
def __add_servernames(self, host):
|
def __add_servernames(self, host):
|
||||||
"""
|
"""
|
||||||
@@ -270,7 +268,7 @@ class Configurator(object):
|
|||||||
args = self.aug.match(name + "/*")
|
args = self.aug.match(name + "/*")
|
||||||
for arg in args:
|
for arg in args:
|
||||||
host.add_name(self.aug.get(arg))
|
host.add_name(self.aug.get(arg))
|
||||||
|
|
||||||
|
|
||||||
def __create_vhost(self, path):
|
def __create_vhost(self, path):
|
||||||
"""
|
"""
|
||||||
@@ -307,13 +305,13 @@ class Configurator(object):
|
|||||||
addr: string
|
addr: string
|
||||||
"""
|
"""
|
||||||
# search for NameVirtualHost directive for ip_addr
|
# search for NameVirtualHost directive for ip_addr
|
||||||
# check httpd.conf, ports.conf,
|
# check httpd.conf, ports.conf,
|
||||||
# note ip_addr can be FQDN although Apache does not recommend it
|
# note ip_addr can be FQDN although Apache does not recommend it
|
||||||
paths = self.find_directive(self.case_i("NameVirtualHost"), None)
|
paths = self.find_directive(self.case_i("NameVirtualHost"), None)
|
||||||
name_vh = []
|
name_vh = []
|
||||||
for p in paths:
|
for p in paths:
|
||||||
name_vh.append(self.aug.get(p))
|
name_vh.append(self.aug.get(p))
|
||||||
|
|
||||||
# Mixed and matched wildcard NameVirtualHost with VirtualHost
|
# Mixed and matched wildcard NameVirtualHost with VirtualHost
|
||||||
# behavior is undefined. Make sure that an exact match exists
|
# behavior is undefined. Make sure that an exact match exists
|
||||||
|
|
||||||
@@ -321,7 +319,7 @@ class Configurator(object):
|
|||||||
for vh in name_vh:
|
for vh in name_vh:
|
||||||
if vh == addr:
|
if vh == addr:
|
||||||
return True
|
return True
|
||||||
|
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def add_name_vhost(self, addr):
|
def add_name_vhost(self, addr):
|
||||||
@@ -332,17 +330,17 @@ class Configurator(object):
|
|||||||
"""
|
"""
|
||||||
aug_file_path = "/files%sports.conf" % self.server_root
|
aug_file_path = "/files%sports.conf" % self.server_root
|
||||||
self.add_dir_to_ifmodssl(aug_file_path, "NameVirtualHost", addr)
|
self.add_dir_to_ifmodssl(aug_file_path, "NameVirtualHost", addr)
|
||||||
|
|
||||||
if len(self.find_directive(self.case_i("NameVirtualHost"), self.case_i(addr))) == 0:
|
if len(self.find_directive(self.case_i("NameVirtualHost"), self.case_i(addr))) == 0:
|
||||||
logger.warn("ports.conf is not included in your Apache config...")
|
logger.warn("ports.conf is not included in your Apache config...")
|
||||||
logger.warn("Adding NameVirtualHost directive to httpd.conf")
|
logger.warn("Adding NameVirtualHost directive to httpd.conf")
|
||||||
self.add_dir_to_ifmodssl("/files" + self.server_root + "httpd.conf", "NameVirtualHost", addr)
|
self.add_dir_to_ifmodssl("/files" + self.server_root + "httpd.conf", "NameVirtualHost", addr)
|
||||||
|
|
||||||
self.save_notes += 'Setting %s to be NameBasedVirtualHost\n' % addr
|
self.save_notes += 'Setting %s to be NameBasedVirtualHost\n' % addr
|
||||||
|
|
||||||
def add_dir_to_ifmodssl(self, aug_conf_path, directive, val):
|
def add_dir_to_ifmodssl(self, aug_conf_path, directive, val):
|
||||||
"""
|
"""
|
||||||
Adds given directived and value along configuration path within
|
Adds given directived and value along configuration path within
|
||||||
an IfMod mod_ssl.c block. If the IfMod block does not exist in
|
an IfMod mod_ssl.c block. If the IfMod block does not exist in
|
||||||
the file, it is created.
|
the file, it is created.
|
||||||
"""
|
"""
|
||||||
@@ -377,7 +375,7 @@ class Configurator(object):
|
|||||||
# Check for NameVirtualHost
|
# Check for NameVirtualHost
|
||||||
# First see if any of the vhost addresses is a _default_ addr
|
# First see if any of the vhost addresses is a _default_ addr
|
||||||
for addr in vhost.addrs:
|
for addr in vhost.addrs:
|
||||||
tup = addr.partition(":")
|
tup = addr.partition(":")
|
||||||
if tup[0] == "_default_":
|
if tup[0] == "_default_":
|
||||||
if not self.is_name_vhost(default_addr):
|
if not self.is_name_vhost(default_addr):
|
||||||
logger.debug("Setting all VirtualHosts on " + default_addr + " to be name based virtual hosts")
|
logger.debug("Setting all VirtualHosts on " + default_addr + " to be name based virtual hosts")
|
||||||
@@ -389,7 +387,7 @@ class Configurator(object):
|
|||||||
if not self.is_name_vhost(addr):
|
if not self.is_name_vhost(addr):
|
||||||
logger.debug("Setting VirtualHost at" + addr + "to be a name based virtual host")
|
logger.debug("Setting VirtualHost at" + addr + "to be a name based virtual host")
|
||||||
self.add_name_vhost(addr)
|
self.add_name_vhost(addr)
|
||||||
|
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def get_ifmod(self, aug_conf_path, mod):
|
def get_ifmod(self, aug_conf_path, mod):
|
||||||
@@ -404,7 +402,7 @@ class Configurator(object):
|
|||||||
ifMods = self.aug.match("%s/IfModule/*[self::arg='%s']" % (aug_conf_path, mod))
|
ifMods = self.aug.match("%s/IfModule/*[self::arg='%s']" % (aug_conf_path, mod))
|
||||||
# Strip off "arg" at end of first ifmod path
|
# Strip off "arg" at end of first ifmod path
|
||||||
return ifMods[0][:len(ifMods[0]) - 3]
|
return ifMods[0][:len(ifMods[0]) - 3]
|
||||||
|
|
||||||
def add_dir(self, aug_conf_path, directive, arg):
|
def add_dir(self, aug_conf_path, directive, arg):
|
||||||
"""
|
"""
|
||||||
Appends directive to end of file given by aug_conf_path
|
Appends directive to end of file given by aug_conf_path
|
||||||
@@ -414,9 +412,9 @@ class Configurator(object):
|
|||||||
self.aug.set(aug_conf_path + "/directive[last()]/arg", arg)
|
self.aug.set(aug_conf_path + "/directive[last()]/arg", arg)
|
||||||
else:
|
else:
|
||||||
for i in range(len(arg)):
|
for i in range(len(arg)):
|
||||||
self.aug.set(aug_conf_path + "/directive[last()]/arg["+str(i+1)+"]", arg[i])
|
self.aug.set(aug_conf_path + "/directive[last()]/arg["+str(i+1)+"]", arg[i])
|
||||||
|
|
||||||
|
|
||||||
def find_directive(self, directive, arg=None, start=""):
|
def find_directive(self, directive, arg=None, start=""):
|
||||||
"""
|
"""
|
||||||
Recursively searches through config files to find directives
|
Recursively searches through config files to find directives
|
||||||
@@ -424,17 +422,17 @@ class Configurator(object):
|
|||||||
TODO: arg should probably be a list
|
TODO: arg should probably be a list
|
||||||
|
|
||||||
Note: Augeas is inherently case sensitive while Apache is case
|
Note: Augeas is inherently case sensitive while Apache is case
|
||||||
insensitive. Augeas 1.0 allows case insensitive regexes like
|
insensitive. Augeas 1.0 allows case insensitive regexes like
|
||||||
regexp(/Listen/, 'i'), however the version currently supported
|
regexp(/Listen/, 'i'), however the version currently supported
|
||||||
by Ubuntu 0.10 does not. Thus I have included my own case insensitive
|
by Ubuntu 0.10 does not. Thus I have included my own case insensitive
|
||||||
transformation by calling case_i() on everything to maintain
|
transformation by calling case_i() on everything to maintain
|
||||||
compatibility.
|
compatibility.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
# Cannot place member variable in the definition of the function so...
|
# Cannot place member variable in the definition of the function so...
|
||||||
if not start:
|
if not start:
|
||||||
start = "/files%sapache2.conf" % self.server_root
|
start = "/files%sapache2.conf" % self.server_root
|
||||||
|
|
||||||
#Debug code
|
#Debug code
|
||||||
#print "find_dir:", directive, "arg:", arg, " | Looking in:", start
|
#print "find_dir:", directive, "arg:", arg, " | Looking in:", start
|
||||||
# No regexp code
|
# No regexp code
|
||||||
@@ -442,20 +440,20 @@ class Configurator(object):
|
|||||||
# matches = self.aug.match(start + "//*[self::directive='"+directive+"']/arg")
|
# matches = self.aug.match(start + "//*[self::directive='"+directive+"']/arg")
|
||||||
# else:
|
# else:
|
||||||
# matches = self.aug.match(start + "//*[self::directive='" + directive+"']/* [self::arg='" + arg + "']")
|
# matches = self.aug.match(start + "//*[self::directive='" + directive+"']/* [self::arg='" + arg + "']")
|
||||||
|
|
||||||
# includes = self.aug.match(start + "//* [self::directive='Include']/* [label()='arg']")
|
# includes = self.aug.match(start + "//* [self::directive='Include']/* [label()='arg']")
|
||||||
|
|
||||||
if arg is None:
|
if arg is None:
|
||||||
matches = self.aug.match(start + "//*[self::directive=~regexp('%s')]/arg" % directive)
|
matches = self.aug.match(start + "//*[self::directive=~regexp('%s')]/arg" % directive)
|
||||||
else:
|
else:
|
||||||
matches = self.aug.match(start + "//*[self::directive=~regexp('%s')]/*[self::arg=~regexp('%s')]" % (directive, arg))
|
matches = self.aug.match(start + "//*[self::directive=~regexp('%s')]/*[self::arg=~regexp('%s')]" % (directive, arg))
|
||||||
|
|
||||||
includes = self.aug.match(start + "//* [self::directive=~regexp('%s')]/* [label()='arg']" % self.case_i('Include'))
|
includes = self.aug.match(start + "//* [self::directive=~regexp('%s')]/* [label()='arg']" % self.case_i('Include'))
|
||||||
|
|
||||||
for include in includes:
|
for include in includes:
|
||||||
# start[6:] to strip off /files
|
# start[6:] to strip off /files
|
||||||
matches.extend(self.find_directive(directive, arg, self.get_include_path(self.strip_dir(start[6:]), self.aug.get(include))))
|
matches.extend(self.find_directive(directive, arg, self.get_include_path(self.strip_dir(start[6:]), self.aug.get(include))))
|
||||||
|
|
||||||
return matches
|
return matches
|
||||||
|
|
||||||
def case_i(self, string):
|
def case_i(self, string):
|
||||||
@@ -463,15 +461,15 @@ class Configurator(object):
|
|||||||
Returns a sloppy, but necessary version of a case insensitive regex.
|
Returns a sloppy, but necessary version of a case insensitive regex.
|
||||||
Any string should be able to be submitted and the string is
|
Any string should be able to be submitted and the string is
|
||||||
escaped and then made case insensitive.
|
escaped and then made case insensitive.
|
||||||
May be replaced by a more proper /i once augeas 1.0 is widely
|
May be replaced by a more proper /i once augeas 1.0 is widely
|
||||||
supported.
|
supported.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
return "".join(["["+c.upper()+c.lower()+"]" if c.isalpha() else c for c in re.escape(string)])
|
return "".join(["["+c.upper()+c.lower()+"]" if c.isalpha() else c for c in re.escape(string)])
|
||||||
|
|
||||||
def strip_dir(self, path):
|
def strip_dir(self, path):
|
||||||
"""
|
"""
|
||||||
Precondition: file_path is a file path, ie. not an augeas section
|
Precondition: file_path is a file path, ie. not an augeas section
|
||||||
or directive path
|
or directive path
|
||||||
Returns the current directory from a file_path along with the file
|
Returns the current directory from a file_path along with the file
|
||||||
"""
|
"""
|
||||||
@@ -483,7 +481,7 @@ class Configurator(object):
|
|||||||
|
|
||||||
def get_include_path(self, cur_dir, arg):
|
def get_include_path(self, cur_dir, arg):
|
||||||
"""
|
"""
|
||||||
Converts an Apache Include directive argument into an Augeas
|
Converts an Apache Include directive argument into an Augeas
|
||||||
searchable path
|
searchable path
|
||||||
Returns path string
|
Returns path string
|
||||||
"""
|
"""
|
||||||
@@ -493,11 +491,11 @@ class Configurator(object):
|
|||||||
# If the attacker can Include anything though... and this function
|
# If the attacker can Include anything though... and this function
|
||||||
# only operates on Apache real config data... then the attacker has
|
# only operates on Apache real config data... then the attacker has
|
||||||
# already won.
|
# already won.
|
||||||
# Perhaps it is better to simply check the permissions on all
|
# Perhaps it is better to simply check the permissions on all
|
||||||
# included files?
|
# included files?
|
||||||
# check_config to validate apache config doesn't work because it
|
# check_config to validate apache config doesn't work because it
|
||||||
# would create a race condition between the check and this input
|
# would create a race condition between the check and this input
|
||||||
|
|
||||||
# TODO: Fix this
|
# TODO: Fix this
|
||||||
# Check to make sure only expected characters are used <- maybe remove
|
# Check to make sure only expected characters are used <- maybe remove
|
||||||
# validChars = re.compile("[a-zA-Z0-9.*?_-/]*")
|
# validChars = re.compile("[a-zA-Z0-9.*?_-/]*")
|
||||||
@@ -513,10 +511,10 @@ class Configurator(object):
|
|||||||
elif arg.startswith("conf/"):
|
elif arg.startswith("conf/"):
|
||||||
arg = self.server_root + arg[5:]
|
arg = self.server_root + arg[5:]
|
||||||
# TODO: Test if Apache allows ../ or ~/ for Includes
|
# TODO: Test if Apache allows ../ or ~/ for Includes
|
||||||
|
|
||||||
# Attempts to add a transform to the file if one does not already exist
|
# Attempts to add a transform to the file if one does not already exist
|
||||||
self.parse_file(arg)
|
self.parse_file(arg)
|
||||||
|
|
||||||
# Argument represents an fnmatch regular expression, convert it
|
# Argument represents an fnmatch regular expression, convert it
|
||||||
# Split up the path and convert each into an Augeas accepted regex
|
# Split up the path and convert each into an Augeas accepted regex
|
||||||
# then reassemble
|
# then reassemble
|
||||||
@@ -524,14 +522,14 @@ class Configurator(object):
|
|||||||
postfix = ""
|
postfix = ""
|
||||||
splitArg = arg.split("/")
|
splitArg = arg.split("/")
|
||||||
for idx, split in enumerate(splitArg):
|
for idx, split in enumerate(splitArg):
|
||||||
# * and ? are the two special fnmatch characters
|
# * and ? are the two special fnmatch characters
|
||||||
if "*" in split or "?" in split:
|
if "*" in split or "?" in split:
|
||||||
# Turn it into a augeas regex
|
# Turn it into a augeas regex
|
||||||
# TODO: Can this instead be an augeas glob instead of regex
|
# TODO: Can this instead be an augeas glob instead of regex
|
||||||
splitArg[idx] = "* [label()=~regexp('%s')]" % self.fnmatch_to_re(split)
|
splitArg[idx] = "* [label()=~regexp('%s')]" % self.fnmatch_to_re(split)
|
||||||
# Reassemble the argument
|
# Reassemble the argument
|
||||||
arg = "/".join(splitArg)
|
arg = "/".join(splitArg)
|
||||||
|
|
||||||
# If the include is a directory, just return the directory as a file
|
# If the include is a directory, just return the directory as a file
|
||||||
if arg.endswith("/"):
|
if arg.endswith("/"):
|
||||||
return "/files" + arg[:len(arg)-1]
|
return "/files" + arg[:len(arg)-1]
|
||||||
@@ -563,7 +561,7 @@ class Configurator(object):
|
|||||||
ssl_fp = avail_fp[:-(len(".conf"))] + LE_VHOST_EXT
|
ssl_fp = avail_fp[:-(len(".conf"))] + LE_VHOST_EXT
|
||||||
else:
|
else:
|
||||||
ssl_fp = avail_fp + LE_VHOST_EXT
|
ssl_fp = avail_fp + LE_VHOST_EXT
|
||||||
|
|
||||||
# First register the creation so that it is properly removed if
|
# First register the creation so that it is properly removed if
|
||||||
# configuration is rolled back
|
# configuration is rolled back
|
||||||
self.register_file_creation(False, ssl_fp)
|
self.register_file_creation(False, ssl_fp)
|
||||||
@@ -617,7 +615,7 @@ class Configurator(object):
|
|||||||
logger.info("Created an SSL vhost at %s" % ssl_fp)
|
logger.info("Created an SSL vhost at %s" % ssl_fp)
|
||||||
self.save_notes += 'Created ssl vhost at %s\n' % ssl_fp
|
self.save_notes += 'Created ssl vhost at %s\n' % ssl_fp
|
||||||
self.save()
|
self.save()
|
||||||
|
|
||||||
# We know the length is one because of the assertion above
|
# We know the length is one because of the assertion above
|
||||||
ssl_vhost = self.__create_vhost(vh_p[0])
|
ssl_vhost = self.__create_vhost(vh_p[0])
|
||||||
self.vhosts.append(ssl_vhost)
|
self.vhosts.append(ssl_vhost)
|
||||||
@@ -633,7 +631,7 @@ class Configurator(object):
|
|||||||
self.add_name_vhost(ssl_addrs[i])
|
self.add_name_vhost(ssl_addrs[i])
|
||||||
logger.info("Enabling NameVirtualHosts on " + ssl_addrs[i])
|
logger.info("Enabling NameVirtualHosts on " + ssl_addrs[i])
|
||||||
need_to_save = True
|
need_to_save = True
|
||||||
|
|
||||||
if need_to_save:
|
if need_to_save:
|
||||||
self.save()
|
self.save()
|
||||||
|
|
||||||
@@ -699,14 +697,14 @@ class Configurator(object):
|
|||||||
return True, 0
|
return True, 0
|
||||||
# Rewrite path exists but is not a letsencrypt https rule
|
# Rewrite path exists but is not a letsencrypt https rule
|
||||||
return True, 2
|
return True, 2
|
||||||
|
|
||||||
def create_redirect_vhost(self, ssl_vhost):
|
def create_redirect_vhost(self, ssl_vhost):
|
||||||
# Consider changing this to a dictionary check
|
# Consider changing this to a dictionary check
|
||||||
# Make sure adding the vhost will be safe
|
# Make sure adding the vhost will be safe
|
||||||
conflict, hostOrAddrs = self.__conflicting_host(ssl_vhost)
|
conflict, hostOrAddrs = self.__conflicting_host(ssl_vhost)
|
||||||
if conflict:
|
if conflict:
|
||||||
return False, hostOrAddrs
|
return False, hostOrAddrs
|
||||||
|
|
||||||
redirect_addrs = hostOrAddrs
|
redirect_addrs = hostOrAddrs
|
||||||
|
|
||||||
# get servernames and serveraliases
|
# get servernames and serveraliases
|
||||||
@@ -729,7 +727,7 @@ RewriteRule ^.*$ https://%{SERVER_NAME}%{REQUEST_URI} [L,R=permanent]\n\
|
|||||||
ErrorLog /var/log/apache2/redirect.error.log \n\
|
ErrorLog /var/log/apache2/redirect.error.log \n\
|
||||||
LogLevel warn \n\
|
LogLevel warn \n\
|
||||||
</VirtualHost>\n"
|
</VirtualHost>\n"
|
||||||
|
|
||||||
# Write out the file
|
# Write out the file
|
||||||
# This is the default name
|
# This is the default name
|
||||||
redirect_filename = "letsencrypt-redirect.conf"
|
redirect_filename = "letsencrypt-redirect.conf"
|
||||||
@@ -758,12 +756,12 @@ LogLevel warn \n\
|
|||||||
new_fp = self.server_root + "sites-available/" + redirect_filename
|
new_fp = self.server_root + "sites-available/" + redirect_filename
|
||||||
new_vhost = self.__create_vhost("/files" + new_fp)
|
new_vhost = self.__create_vhost("/files" + new_fp)
|
||||||
self.vhosts.append(new_vhost)
|
self.vhosts.append(new_vhost)
|
||||||
|
|
||||||
# Finally create documentation for the change
|
# Finally create documentation for the change
|
||||||
self.save_notes += 'Created a port 80 vhost, %s, for redirection to ssl vhost %s\n' % (new_vhost.file, ssl_vhost.file)
|
self.save_notes += 'Created a port 80 vhost, %s, for redirection to ssl vhost %s\n' % (new_vhost.file, ssl_vhost.file)
|
||||||
|
|
||||||
return True, new_vhost
|
return True, new_vhost
|
||||||
|
|
||||||
def __conflicting_host(self, ssl_vhost):
|
def __conflicting_host(self, ssl_vhost):
|
||||||
'''
|
'''
|
||||||
Checks for a conflicting host, such that a new port 80 host could not
|
Checks for a conflicting host, such that a new port 80 host could not
|
||||||
@@ -798,7 +796,7 @@ LogLevel warn \n\
|
|||||||
redirect_addrs = redirect_addrs + ssl_a_vhttp
|
redirect_addrs = redirect_addrs + ssl_a_vhttp
|
||||||
|
|
||||||
return False, redirect_addrs
|
return False, redirect_addrs
|
||||||
|
|
||||||
def __general_vhost(self, ssl_vhost):
|
def __general_vhost(self, ssl_vhost):
|
||||||
"""
|
"""
|
||||||
Function needs to be thoroughly tested and perhaps improved
|
Function needs to be thoroughly tested and perhaps improved
|
||||||
@@ -811,7 +809,7 @@ LogLevel warn \n\
|
|||||||
ssl_addrs = ssl_vhost.addrs
|
ssl_addrs = ssl_vhost.addrs
|
||||||
if ssl_addrs == ["_default_:443"]:
|
if ssl_addrs == ["_default_:443"]:
|
||||||
ssl_addrs = ["*:443"]
|
ssl_addrs = ["*:443"]
|
||||||
|
|
||||||
for vh in self.vhosts:
|
for vh in self.vhosts:
|
||||||
found = 0
|
found = 0
|
||||||
# Not the same vhost, and same number of addresses
|
# Not the same vhost, and same number of addresses
|
||||||
@@ -826,7 +824,7 @@ LogLevel warn \n\
|
|||||||
if test_tup[2] == "80" or test_tup[2] == "" or test_tup[2] == "*":
|
if test_tup[2] == "80" or test_tup[2] == "" or test_tup[2] == "*":
|
||||||
found += 1
|
found += 1
|
||||||
break
|
break
|
||||||
# Check to make sure all addresses were found
|
# Check to make sure all addresses were found
|
||||||
# and names are equal
|
# and names are equal
|
||||||
if found == len(ssl_vhost.addrs) and set(vh.names) == set(ssl_vhost.names):
|
if found == len(ssl_vhost.addrs) and set(vh.names) == set(ssl_vhost.names):
|
||||||
return vh
|
return vh
|
||||||
@@ -875,7 +873,7 @@ LogLevel warn \n\
|
|||||||
continue
|
continue
|
||||||
break
|
break
|
||||||
return avail_fp
|
return avail_fp
|
||||||
|
|
||||||
def is_site_enabled(self, avail_fp):
|
def is_site_enabled(self, avail_fp):
|
||||||
"""
|
"""
|
||||||
Checks to see if the given site is enabled
|
Checks to see if the given site is enabled
|
||||||
@@ -903,15 +901,15 @@ LogLevel warn \n\
|
|||||||
self.save_notes += 'Enabled site %s\n' % vhost.file
|
self.save_notes += 'Enabled site %s\n' % vhost.file
|
||||||
return True
|
return True
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def enable_mod(self, mod_name):
|
def enable_mod(self, mod_name):
|
||||||
"""
|
"""
|
||||||
Enables mod_ssl
|
Enables mod_ssl
|
||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
# Use check_output so the command will finish before reloading
|
# Use check_output so the command will finish before reloading
|
||||||
subprocess.check_call(["sudo", "a2enmod", mod_name], stdout=open("/dev/null", 'w'), stderr=open("/dev/null", 'w'))
|
subprocess.check_call(["sudo", "a2enmod", mod_name], stdout=open("/dev/null", 'w'), stderr=open("/dev/null", 'w'))
|
||||||
# Hopefully this waits for output
|
# Hopefully this waits for output
|
||||||
subprocess.check_call(["sudo", "/etc/init.d/apache2", "restart"], stdout=open("/dev/null", 'w'), stderr=open("/dev/null", 'w'))
|
subprocess.check_call(["sudo", "/etc/init.d/apache2", "restart"], stdout=open("/dev/null", 'w'), stderr=open("/dev/null", 'w'))
|
||||||
except:
|
except:
|
||||||
logger.error("Error enabling mod_" + mod_name)
|
logger.error("Error enabling mod_" + mod_name)
|
||||||
@@ -949,12 +947,12 @@ LogLevel warn \n\
|
|||||||
#self.aug.add_transform("Httpd.lns", self.httpd_incl, None, self.httpd_excl)
|
#self.aug.add_transform("Httpd.lns", self.httpd_incl, None, self.httpd_excl)
|
||||||
self.__add_httpd_transform(file_path)
|
self.__add_httpd_transform(file_path)
|
||||||
self.aug.load()
|
self.aug.load()
|
||||||
|
|
||||||
def save_apache_config(self):
|
def save_apache_config(self):
|
||||||
# Not currently used
|
# Not currently used
|
||||||
# Should be safe because it is a protected directory
|
# Should be safe because it is a protected directory
|
||||||
shutil.copytree(self.server_root, BACKUP_DIR + "apache2-" + str(time.time()))
|
shutil.copytree(self.server_root, BACKUP_DIR + "apache2-" + str(time.time()))
|
||||||
|
|
||||||
def recovery_routine(self):
|
def recovery_routine(self):
|
||||||
"""
|
"""
|
||||||
Revert all previously modified files. First, any changes found in
|
Revert all previously modified files. First, any changes found in
|
||||||
@@ -997,13 +995,13 @@ LogLevel warn \n\
|
|||||||
except IOError:
|
except IOError:
|
||||||
logger.fatal("Unable to remove filepaths contained within %s" % file_list)
|
logger.fatal("Unable to remove filepaths contained within %s" % file_list)
|
||||||
sys.exit(41)
|
sys.exit(41)
|
||||||
|
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def verify_setup(self):
|
def verify_setup(self):
|
||||||
'''
|
'''
|
||||||
Make sure that files/directories are setup with appropriate permissions
|
Make sure that files/directories are setup with appropriate permissions
|
||||||
Aim for defensive coding... make sure all input files
|
Aim for defensive coding... make sure all input files
|
||||||
have permissions of root
|
have permissions of root
|
||||||
'''
|
'''
|
||||||
le_util.make_or_verify_dir(CONFIG_DIR, 0755)
|
le_util.make_or_verify_dir(CONFIG_DIR, 0755)
|
||||||
@@ -1025,7 +1023,7 @@ LogLevel warn \n\
|
|||||||
# This is a hack... work around... submit to augeas if still not fixed
|
# This is a hack... work around... submit to augeas if still not fixed
|
||||||
|
|
||||||
excl = ["*.augnew", "*.augsave", "*.dpkg-dist", "*.dpkg-bak", "*.dpkg-new", "*.dpkg-old", "*.rpmsave", "*.rpmnew", "*~", self.server_root + "*.augsave", self.server_root + "*~", self.server_root + "*/*augsave", self.server_root + "*/*~", self.server_root + "*/*/*.augsave", self.server_root + "*/*/*~"]
|
excl = ["*.augnew", "*.augsave", "*.dpkg-dist", "*.dpkg-bak", "*.dpkg-new", "*.dpkg-old", "*.rpmsave", "*.rpmnew", "*~", self.server_root + "*.augsave", self.server_root + "*~", self.server_root + "*/*augsave", self.server_root + "*/*~", self.server_root + "*/*/*.augsave", self.server_root + "*/*/*~"]
|
||||||
|
|
||||||
for i in range(len(excl)):
|
for i in range(len(excl)):
|
||||||
self.aug.set("/augeas/load/Httpd/excl[%d]" % (i+1), excl[i])
|
self.aug.set("/augeas/load/Httpd/excl[%d]" % (i+1), excl[i])
|
||||||
|
|
||||||
@@ -1040,7 +1038,7 @@ LogLevel warn \n\
|
|||||||
|
|
||||||
for e in error_files:
|
for e in error_files:
|
||||||
# Check to see if it was an error resulting from the use of
|
# Check to see if it was an error resulting from the use of
|
||||||
# the httpd lens
|
# the httpd lens
|
||||||
lens_path = self.aug.get(e + '/lens')
|
lens_path = self.aug.get(e + '/lens')
|
||||||
# As aug.get may return null
|
# As aug.get may return null
|
||||||
if lens_path and 'httpd.aug' in lens_path:
|
if lens_path and 'httpd.aug' in lens_path:
|
||||||
@@ -1072,7 +1070,7 @@ LogLevel warn \n\
|
|||||||
try:
|
try:
|
||||||
p = subprocess.Popen(['/etc/init.d/apache2', 'restart'], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
|
p = subprocess.Popen(['/etc/init.d/apache2', 'restart'], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
|
||||||
text = p.communicate()
|
text = p.communicate()
|
||||||
|
|
||||||
|
|
||||||
if p.returncode != 0:
|
if p.returncode != 0:
|
||||||
# Enter recovery routine...
|
# Enter recovery routine...
|
||||||
@@ -1118,7 +1116,7 @@ LogLevel warn \n\
|
|||||||
Saves all changes to the configuration files
|
Saves all changes to the configuration files
|
||||||
This function is not transactional
|
This function is not transactional
|
||||||
TODO: Instead rely on challenge to backup all files before modifications
|
TODO: Instead rely on challenge to backup all files before modifications
|
||||||
|
|
||||||
title: string - The title of the save. If a title is given, the
|
title: string - The title of the save. If a title is given, the
|
||||||
configuration will be saved as a new checkpoint
|
configuration will be saved as a new checkpoint
|
||||||
and put in a timestamped directory.
|
and put in a timestamped directory.
|
||||||
@@ -1148,7 +1146,7 @@ LogLevel warn \n\
|
|||||||
return False
|
return False
|
||||||
|
|
||||||
# Retrieve list of modified files
|
# Retrieve list of modified files
|
||||||
# Note: Noop saves can cause the file to be listed twice, I used a
|
# Note: Noop saves can cause the file to be listed twice, I used a
|
||||||
# set to remove this possibility. This is a known augeas 0.10 error.
|
# set to remove this possibility. This is a known augeas 0.10 error.
|
||||||
save_paths = self.aug.match("/augeas/events/saved")
|
save_paths = self.aug.match("/augeas/events/saved")
|
||||||
|
|
||||||
@@ -1172,7 +1170,7 @@ LogLevel warn \n\
|
|||||||
self.add_to_checkpoint(TEMP_CHECKPOINT_DIR, save_files)
|
self.add_to_checkpoint(TEMP_CHECKPOINT_DIR, save_files)
|
||||||
else:
|
else:
|
||||||
self.add_to_checkpoint(IN_PROGRESS_DIR, save_files)
|
self.add_to_checkpoint(IN_PROGRESS_DIR, save_files)
|
||||||
|
|
||||||
|
|
||||||
if title and not temporary and os.path.isdir(IN_PROGRESS_DIR):
|
if title and not temporary and os.path.isdir(IN_PROGRESS_DIR):
|
||||||
success = self.__finalize_checkpoint(IN_PROGRESS_DIR, title)
|
success = self.__finalize_checkpoint(IN_PROGRESS_DIR, title)
|
||||||
@@ -1181,7 +1179,7 @@ LogLevel warn \n\
|
|||||||
# This will be hopefully be cleaned up on the recovery
|
# This will be hopefully be cleaned up on the recovery
|
||||||
# routine startup
|
# routine startup
|
||||||
sys.exit(9)
|
sys.exit(9)
|
||||||
|
|
||||||
|
|
||||||
self.aug.set("/augeas/save", save_state)
|
self.aug.set("/augeas/save", save_state)
|
||||||
self.save_notes = ""
|
self.save_notes = ""
|
||||||
@@ -1213,7 +1211,7 @@ LogLevel warn \n\
|
|||||||
|
|
||||||
def add_to_checkpoint(self, cp_dir, save_files):
|
def add_to_checkpoint(self, cp_dir, save_files):
|
||||||
le_util.make_or_verify_dir(cp_dir, 0755)
|
le_util.make_or_verify_dir(cp_dir, 0755)
|
||||||
|
|
||||||
existing_filepaths = []
|
existing_filepaths = []
|
||||||
op_fd = None
|
op_fd = None
|
||||||
# Open up FILEPATHS differently depending on if it already exists
|
# Open up FILEPATHS differently depending on if it already exists
|
||||||
@@ -1226,7 +1224,7 @@ LogLevel warn \n\
|
|||||||
idx = len(existing_filepaths)
|
idx = len(existing_filepaths)
|
||||||
for filename in save_files:
|
for filename in save_files:
|
||||||
if filename not in existing_filepaths:
|
if filename not in existing_filepaths:
|
||||||
# Tag files with index so multiple files can
|
# Tag files with index so multiple files can
|
||||||
# have the same filename
|
# have the same filename
|
||||||
logger.debug("Creating backup of %s" % filename)
|
logger.debug("Creating backup of %s" % filename)
|
||||||
shutil.copy2(filename, cp_dir + os.path.basename(filename) + "_" + str(idx))
|
shutil.copy2(filename, cp_dir + os.path.basename(filename) + "_" + str(idx))
|
||||||
@@ -1252,7 +1250,7 @@ LogLevel warn \n\
|
|||||||
|
|
||||||
if len(backups) < rollback:
|
if len(backups) < rollback:
|
||||||
logger.error("Unable to rollback %d checkpoints, only %d exist" % (rollback, len(backups)))
|
logger.error("Unable to rollback %d checkpoints, only %d exist" % (rollback, len(backups)))
|
||||||
|
|
||||||
while rollback > 0 and backups:
|
while rollback > 0 and backups:
|
||||||
cp_dir = BACKUP_DIR + backups.pop()
|
cp_dir = BACKUP_DIR + backups.pop()
|
||||||
result = self.__recover_checkpoint(cp_dir)
|
result = self.__recover_checkpoint(cp_dir)
|
||||||
@@ -1266,11 +1264,11 @@ LogLevel warn \n\
|
|||||||
def __recover_checkpoint(self, cp_dir):
|
def __recover_checkpoint(self, cp_dir):
|
||||||
"""
|
"""
|
||||||
Recover a specific checkpoint provided by cp_dir
|
Recover a specific checkpoint provided by cp_dir
|
||||||
Note: this function does not reload augeas.
|
Note: this function does not reload augeas.
|
||||||
|
|
||||||
returns: 0 success, 1 Unable to revert, -1 Unable to delete
|
returns: 0 success, 1 Unable to revert, -1 Unable to delete
|
||||||
"""
|
"""
|
||||||
|
|
||||||
if os.path.isfile(cp_dir + "/FILEPATHS"):
|
if os.path.isfile(cp_dir + "/FILEPATHS"):
|
||||||
try:
|
try:
|
||||||
with open(cp_dir + "/FILEPATHS") as f:
|
with open(cp_dir + "/FILEPATHS") as f:
|
||||||
@@ -1328,13 +1326,13 @@ LogLevel warn \n\
|
|||||||
print time.ctime(float(bu))
|
print time.ctime(float(bu))
|
||||||
with open(BACKUP_DIR + bu + "/CHANGES_SINCE") as f:
|
with open(BACKUP_DIR + bu + "/CHANGES_SINCE") as f:
|
||||||
print f.read()
|
print f.read()
|
||||||
|
|
||||||
print "Affected files:"
|
print "Affected files:"
|
||||||
with open(BACKUP_DIR + bu + "/FILEPATHS") as f:
|
with open(BACKUP_DIR + bu + "/FILEPATHS") as f:
|
||||||
filepaths = f.read().splitlines()
|
filepaths = f.read().splitlines()
|
||||||
for fp in filepaths:
|
for fp in filepaths:
|
||||||
print " %s" % fp
|
print " %s" % fp
|
||||||
|
|
||||||
try:
|
try:
|
||||||
with open(BACKUP_DIR + bu + "/NEW_FILES") as f:
|
with open(BACKUP_DIR + bu + "/NEW_FILES") as f:
|
||||||
print "New Configuration Files:"
|
print "New Configuration Files:"
|
||||||
@@ -1356,7 +1354,7 @@ LogLevel warn \n\
|
|||||||
cp_dir = TEMP_CHECKPOINT_DIR
|
cp_dir = TEMP_CHECKPOINT_DIR
|
||||||
else:
|
else:
|
||||||
cp_dir = IN_PROGRESS_DIR
|
cp_dir = IN_PROGRESS_DIR
|
||||||
|
|
||||||
le_util.make_or_verify_dir(cp_dir)
|
le_util.make_or_verify_dir(cp_dir)
|
||||||
try:
|
try:
|
||||||
with open(cp_dir + "NEW_FILES", 'a') as fd:
|
with open(cp_dir + "NEW_FILES", 'a') as fd:
|
||||||
@@ -1364,8 +1362,8 @@ LogLevel warn \n\
|
|||||||
fd.write("%s\n" % f)
|
fd.write("%s\n" % f)
|
||||||
except:
|
except:
|
||||||
logger.error("ERROR: Unable to register file creation")
|
logger.error("ERROR: Unable to register file creation")
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
config = Configurator()
|
config = Configurator()
|
||||||
@@ -1379,7 +1377,7 @@ def main():
|
|||||||
print name
|
print name
|
||||||
"""
|
"""
|
||||||
print config.find_directive(config.case_i("NameVirtualHost"), config.case_i("holla:443"))
|
print config.find_directive(config.case_i("NameVirtualHost"), config.case_i("holla:443"))
|
||||||
|
|
||||||
"""
|
"""
|
||||||
for m in config.find_directive("Listen", "443"):
|
for m in config.find_directive("Listen", "443"):
|
||||||
print "Directive Path:", m, "Value:", config.aug.get(m)
|
print "Directive Path:", m, "Value:", config.aug.get(m)
|
||||||
@@ -1417,7 +1415,7 @@ def main():
|
|||||||
if vh.addrs[0] == "23.20.47.131:80":
|
if vh.addrs[0] == "23.20.47.131:80":
|
||||||
print "Here we go"
|
print "Here we go"
|
||||||
ssl_vh = config.make_vhost_ssl(vh)
|
ssl_vh = config.make_vhost_ssl(vh)
|
||||||
|
|
||||||
config.redirect_all_ssl(ssl_vh)
|
config.redirect_all_ssl(ssl_vh)
|
||||||
"""
|
"""
|
||||||
"""
|
"""
|
||||||
@@ -1425,6 +1423,6 @@ def main():
|
|||||||
if len(vh.names) > 0:
|
if len(vh.names) > 0:
|
||||||
config.deploy_cert(vh, "/home/james/Documents/apache_choc/req.pem", "/home/james/Documents/apache_choc/key.pem", "/home/james/Downloads/sub.class1.server.ca.pem")
|
config.deploy_cert(vh, "/home/james/Documents/apache_choc/req.pem", "/home/james/Documents/apache_choc/key.pem", "/home/james/Downloads/sub.class1.server.ca.pem")
|
||||||
"""
|
"""
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
main()
|
main()
|
||||||
|
|||||||
@@ -8,7 +8,6 @@ from Crypto.Hash import SHA256
|
|||||||
from M2Crypto import EVP, X509, ASN1
|
from M2Crypto import EVP, X509, ASN1
|
||||||
|
|
||||||
|
|
||||||
from letsencrypt.client import logger
|
|
||||||
from letsencrypt.client.CONFIG import NONCE_SIZE, RSA_KEY_SIZE
|
from letsencrypt.client.CONFIG import NONCE_SIZE, RSA_KEY_SIZE
|
||||||
|
|
||||||
|
|
||||||
@@ -59,7 +58,7 @@ def make_key(bits=RSA_KEY_SIZE):
|
|||||||
#rsa = M2Crypto.RSA.gen_key(bits, 65537)
|
#rsa = M2Crypto.RSA.gen_key(bits, 65537)
|
||||||
#key_pem = rsa.as_pem(cipher=None)
|
#key_pem = rsa.as_pem(cipher=None)
|
||||||
#rsa = None # should not be freed here
|
#rsa = None # should not be freed here
|
||||||
|
|
||||||
return key.exportKey(format='PEM')
|
return key.exportKey(format='PEM')
|
||||||
|
|
||||||
|
|
||||||
@@ -147,7 +146,7 @@ def get_cert_info(filename):
|
|||||||
d["san"] = x.get_ext("subjectAltName").get_value()
|
d["san"] = x.get_ext("subjectAltName").get_value()
|
||||||
except:
|
except:
|
||||||
d["san"] = ""
|
d["san"] = ""
|
||||||
|
|
||||||
d["serial"] = x.get_serial_number()
|
d["serial"] = x.get_serial_number()
|
||||||
d["pub_key"] = "RSA " + str(x.get_pubkey().size() * 8)
|
d["pub_key"] = "RSA " + str(x.get_pubkey().size() * 8)
|
||||||
return d
|
return d
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ class Display(SingletonD):
|
|||||||
raise Exception("Error no display defined")
|
raise Exception("Error no display defined")
|
||||||
def success_installation(self, domains):
|
def success_installation(self, domains):
|
||||||
raise Exception("Error no display defined")
|
raise Exception("Error no display defined")
|
||||||
|
|
||||||
def gen_https_names(self, domains):
|
def gen_https_names(self, domains):
|
||||||
"""
|
"""
|
||||||
Returns a string of the domains formatted nicely with https:// prepended
|
Returns a string of the domains formatted nicely with https:// prepended
|
||||||
@@ -94,12 +94,12 @@ class NcursesDisplay(Display):
|
|||||||
|
|
||||||
def generic_input(self, message):
|
def generic_input(self, message):
|
||||||
return self.d.inputbox(message)
|
return self.d.inputbox(message)
|
||||||
|
|
||||||
def generic_yesno(self, message, yes = "Yes", no = "No"):
|
def generic_yesno(self, message, yes = "Yes", no = "No"):
|
||||||
a = self.d.yesno(message, HEIGHT, WIDTH)
|
a = self.d.yesno(message, HEIGHT, WIDTH)
|
||||||
|
|
||||||
return a == self.d.DIALOG_OK
|
return a == self.d.DIALOG_OK
|
||||||
|
|
||||||
def filter_names(self, names):
|
def filter_names(self, names):
|
||||||
choices = [(n, "", 0) for n in names]
|
choices = [(n, "", 0) for n in names]
|
||||||
c, s = self.d.checklist("Which names would you like to activate \
|
c, s = self.d.checklist("Which names would you like to activate \
|
||||||
@@ -115,12 +115,12 @@ class NcursesDisplay(Display):
|
|||||||
def display_certs(self, certs):
|
def display_certs(self, certs):
|
||||||
list_choices = [
|
list_choices = [
|
||||||
(str(i+1),
|
(str(i+1),
|
||||||
"%s | %s | %s" %
|
"%s | %s | %s" %
|
||||||
(str(c["cn"].ljust(WIDTH - 39)),
|
(str(c["cn"].ljust(WIDTH - 39)),
|
||||||
c["not_before"].strftime("%m-%d-%y"),
|
c["not_before"].strftime("%m-%d-%y"),
|
||||||
"Installed" if c["installed"] else ""))
|
"Installed" if c["installed"] else ""))
|
||||||
for i, c in enumerate(certs)]
|
for i, c in enumerate(certs)]
|
||||||
|
|
||||||
code, s = self.d.menu("Which certificates would you like to revoke?",
|
code, s = self.d.menu("Which certificates would you like to revoke?",
|
||||||
choices = list_choices, help_button=True,
|
choices = list_choices, help_button=True,
|
||||||
help_label="More Info", ok_label="Revoke",
|
help_label="More Info", ok_label="Revoke",
|
||||||
@@ -204,7 +204,7 @@ class FileDisplay(Display):
|
|||||||
menu_choices = [(str(i+1), str(c["cn"]) + " - " + c["pub_key"] +
|
menu_choices = [(str(i+1), str(c["cn"]) + " - " + c["pub_key"] +
|
||||||
" - " + str(c["not_before"])[:-6])
|
" - " + str(c["not_before"])[:-6])
|
||||||
for i, c in enumerate(certs)]
|
for i, c in enumerate(certs)]
|
||||||
|
|
||||||
self.outfile.write("Which certificate would you like to revoke?\n")
|
self.outfile.write("Which certificate would you like to revoke?\n")
|
||||||
for c in menu_choices:
|
for c in menu_choices:
|
||||||
wm = textwrap.fill("%s: %s - %s Signed (UTC): %s\n" %
|
wm = textwrap.fill("%s: %s - %s Signed (UTC): %s\n" %
|
||||||
@@ -243,9 +243,9 @@ class FileDisplay(Display):
|
|||||||
s_f = '*' * (79)
|
s_f = '*' * (79)
|
||||||
wm = textwrap.fill(("Congratulations! You have successfully " +
|
wm = textwrap.fill(("Congratulations! You have successfully " +
|
||||||
"enabled %s!") % self.gen_https_names(domains))
|
"enabled %s!") % self.gen_https_names(domains))
|
||||||
msg = "%s\n%s\n%s\n"
|
msg = "%s\n%s\n%s\n"
|
||||||
self.outfile.write(msg % (s_f, wm, s_f))
|
self.outfile.write(msg % (s_f, wm, s_f))
|
||||||
|
|
||||||
def confirm_revocation(self, cert):
|
def confirm_revocation(self, cert):
|
||||||
self.outfile.write("Are you sure you would like to revoke \
|
self.outfile.write("Are you sure you would like to revoke \
|
||||||
the following certificate:\n")
|
the following certificate:\n")
|
||||||
@@ -300,10 +300,10 @@ def redirect_by_default():
|
|||||||
choices = [
|
choices = [
|
||||||
("Easy", "Allow both HTTP and HTTPS access to these sites"),
|
("Easy", "Allow both HTTP and HTTPS access to these sites"),
|
||||||
("Secure", "Make all requests redirect to secure HTTPS access")]
|
("Secure", "Make all requests redirect to secure HTTPS access")]
|
||||||
|
|
||||||
result = display.generic_menu("Please choose whether HTTPS access " +
|
result = display.generic_menu("Please choose whether HTTPS access " +
|
||||||
"is required or optional.",
|
"is required or optional.",
|
||||||
choices,
|
choices,
|
||||||
"Please enter the appropriate number",
|
"Please enter the appropriate number",
|
||||||
width = WIDTH)
|
width = WIDTH)
|
||||||
|
|
||||||
|
|||||||
@@ -1,13 +1,12 @@
|
|||||||
from letsencrypt.client.challenge import Challenge
|
from letsencrypt.client.challenge import Challenge
|
||||||
from letsencrypt.client import logger
|
|
||||||
import textwrap
|
import textwrap
|
||||||
|
|
||||||
############################################################
|
############################################################
|
||||||
# Possible addition to challenge structure: priority parameter
|
# Possible addition to challenge structure: priority parameter
|
||||||
# If only DVSNI and Payment are required, the user might want
|
# If only DVSNI and Payment are required, the user might want
|
||||||
# to be validated before submitting payment, allowing the user
|
# to be validated before submitting payment, allowing the user
|
||||||
# to gain confidence in the system. If things do go poorly the
|
# to gain confidence in the system. If things do go poorly the
|
||||||
# user has less invested in that particular session/transaction.
|
# user has less invested in that particular session/transaction.
|
||||||
#############################################################
|
#############################################################
|
||||||
|
|
||||||
###########################################################
|
###########################################################
|
||||||
@@ -22,7 +21,7 @@ class Interactive_Challenge(Challenge):
|
|||||||
|
|
||||||
def __init__(self, string):
|
def __init__(self, string):
|
||||||
self.string = string
|
self.string = string
|
||||||
|
|
||||||
def perform(self, quiet=True):
|
def perform(self, quiet=True):
|
||||||
if quiet:
|
if quiet:
|
||||||
dialog.Dialog().msgbox(get_display_string(), width=BOX_SIZE)
|
dialog.Dialog().msgbox(get_display_string(), width=BOX_SIZE)
|
||||||
@@ -31,7 +30,7 @@ class Interactive_Challenge(Challenge):
|
|||||||
raw_input('')
|
raw_input('')
|
||||||
|
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
|
||||||
def get_display_string(self):
|
def get_display_string(self):
|
||||||
return textwrap.fill(self.string, width=BOX_SIZE) + "\n\nPlease Press Enter to Continue"
|
return textwrap.fill(self.string, width=BOX_SIZE) + "\n\nPlease Press Enter to Continue"
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
import sys
|
|
||||||
import time
|
import time
|
||||||
from letsencrypt.client import display
|
from letsencrypt.client import display
|
||||||
|
|
||||||
@@ -55,20 +54,20 @@ class FileLogger(Logger):
|
|||||||
import dialog
|
import dialog
|
||||||
class NcursesLogger(Logger):
|
class NcursesLogger(Logger):
|
||||||
|
|
||||||
def __init__(self,
|
def __init__(self,
|
||||||
firstmessage="",
|
firstmessage="",
|
||||||
height = display.HEIGHT,
|
height = display.HEIGHT,
|
||||||
width = display.WIDTH - 4):
|
width = display.WIDTH - 4):
|
||||||
self.lines = []
|
self.lines = []
|
||||||
self.all_content = ""
|
self.all_content = ""
|
||||||
self.d = dialog.Dialog()
|
self.d = dialog.Dialog()
|
||||||
self.height = height
|
self.height = height
|
||||||
self.width = width
|
self.width = width
|
||||||
self.add(firstmessage)
|
self.add(firstmessage)
|
||||||
|
|
||||||
'''
|
'''
|
||||||
Only show the last (self.height) lines;
|
Only show the last (self.height) lines;
|
||||||
note that lines can wrap at self.width, so
|
note that lines can wrap at self.width, so
|
||||||
a single line could actually be multiple lines
|
a single line could actually be multiple lines
|
||||||
'''
|
'''
|
||||||
def add(self, s):
|
def add(self, s):
|
||||||
@@ -93,7 +92,7 @@ class NcursesLogger(Logger):
|
|||||||
if cur_out != '':
|
if cur_out != '':
|
||||||
self.lines.append(cur_out)
|
self.lines.append(cur_out)
|
||||||
|
|
||||||
|
|
||||||
# show last 16 lines
|
# show last 16 lines
|
||||||
self.content = '\n'.join(self.lines[-self.height:])
|
self.content = '\n'.join(self.lines[-self.height:])
|
||||||
self.show()
|
self.show()
|
||||||
@@ -110,7 +109,7 @@ log_instance = None
|
|||||||
def setLogger(log_inst):
|
def setLogger(log_inst):
|
||||||
global log_instance
|
global log_instance
|
||||||
log_instance = log_inst
|
log_instance = log_inst
|
||||||
|
|
||||||
def setLogLevel(log_level):
|
def setLogLevel(log_level):
|
||||||
global log_instance
|
global log_instance
|
||||||
log_instance.level = log_level
|
log_instance.level = log_level
|
||||||
@@ -140,7 +139,7 @@ def fatal(data):
|
|||||||
|
|
||||||
def none(data):
|
def none(data):
|
||||||
# Uh...what?
|
# Uh...what?
|
||||||
pass
|
pass
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
# Unit test/example usage:
|
# Unit test/example usage:
|
||||||
@@ -165,7 +164,7 @@ if __name__ == "__main__":
|
|||||||
time.sleep(0.3)
|
time.sleep(0.3)
|
||||||
|
|
||||||
|
|
||||||
# Alternatively, use
|
# Alternatively, use
|
||||||
logger.error("errrrr")
|
logger.error("errrrr")
|
||||||
|
|
||||||
logger.trace("some trace data: %d - %f - %s" % (5, 8.3, 'cows'))
|
logger.trace("some trace data: %d - %f - %s" % (5, 8.3, 'cows'))
|
||||||
|
|||||||
@@ -1,13 +1,12 @@
|
|||||||
from letsencrypt.client.challenge import Challenge
|
from letsencrypt.client.challenge import Challenge
|
||||||
from letsencrypt.client import logger
|
|
||||||
import dialog
|
import dialog
|
||||||
|
|
||||||
############################################################
|
############################################################
|
||||||
# Possible addition to challenge structure: priority parameter
|
# Possible addition to challenge structure: priority parameter
|
||||||
# If only DVSNI and Payment are required, the user might want
|
# If only DVSNI and Payment are required, the user might want
|
||||||
# to be validated before submitting payment, allowing the user
|
# to be validated before submitting payment, allowing the user
|
||||||
# to gain confidence in the system. If things do go poorly the
|
# to gain confidence in the system. If things do go poorly the
|
||||||
# user has less invested in that particular session/transaction.
|
# user has less invested in that particular session/transaction.
|
||||||
#############################################################
|
#############################################################
|
||||||
|
|
||||||
class Payment_Challenge(Challenge):
|
class Payment_Challenge(Challenge):
|
||||||
@@ -21,7 +20,7 @@ class Payment_Challenge(Challenge):
|
|||||||
def cleanup(self):
|
def cleanup(self):
|
||||||
# Currently, payment challenges do not appear to require any cleanup.
|
# Currently, payment challenges do not appear to require any cleanup.
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def perform(self, quiet=True):
|
def perform(self, quiet=True):
|
||||||
if quiet:
|
if quiet:
|
||||||
dialog.Dialog().msgbox(self.get_display_string(), width=70)
|
dialog.Dialog().msgbox(self.get_display_string(), width=70)
|
||||||
@@ -31,7 +30,7 @@ class Payment_Challenge(Challenge):
|
|||||||
|
|
||||||
self.times_performed += 1
|
self.times_performed += 1
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
|
||||||
def get_display_string(self):
|
def get_display_string(self):
|
||||||
if self.times_performed == 0:
|
if self.times_performed == 0:
|
||||||
@@ -40,7 +39,7 @@ class Payment_Challenge(Challenge):
|
|||||||
# The user has tried at least once... display a different message
|
# The user has tried at least once... display a different message
|
||||||
else:
|
else:
|
||||||
return "The CA did not record your payment, please visit " + self.url + " for more information or to finish processing your transaction.\nPress Enter to continue"
|
return "The CA did not record your payment, please visit " + self.url + " for more information or to finish processing your transaction.\nPress Enter to continue"
|
||||||
|
|
||||||
|
|
||||||
def formatted_reasons(self):
|
def formatted_reasons(self):
|
||||||
return "\n\t* %s\n" % self.reason
|
return "\n\t* %s\n" % self.reason
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ from letsencrypt.client.CONFIG import RECOVERY_TOKEN_EXT
|
|||||||
import dialog
|
import dialog
|
||||||
|
|
||||||
class RecoveryContact(Challenge):
|
class RecoveryContact(Challenge):
|
||||||
|
|
||||||
def __init__(self, activationURL = "", successURL = "", contact = "", poll_delay = 3):
|
def __init__(self, activationURL = "", successURL = "", contact = "", poll_delay = 3):
|
||||||
self.token = ""
|
self.token = ""
|
||||||
self.activationURL = activationURL
|
self.activationURL = activationURL
|
||||||
@@ -24,14 +24,14 @@ class RecoveryContact(Challenge):
|
|||||||
exit, self.token = d.inputbox(self.get_display_string()))
|
exit, self.token = d.inputbox(self.get_display_string()))
|
||||||
if exit != d.OK:
|
if exit != d.OK:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
else:
|
else:
|
||||||
print self.get_display_string()
|
print self.get_display_string()
|
||||||
if successURL:
|
if successURL:
|
||||||
return self.poll(10, quiet)
|
return self.poll(10, quiet)
|
||||||
else:
|
else:
|
||||||
self.token = raw_input("Enter the recovery token:")
|
self.token = raw_input("Enter the recovery token:")
|
||||||
|
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def cleanup(self):
|
def cleanup(self):
|
||||||
@@ -46,7 +46,7 @@ class RecoveryContact(Challenge):
|
|||||||
string += " or respond to the recovery email sent to " + self.contact
|
string += " or respond to the recovery email sent to " + self.contact
|
||||||
elif self.contact:
|
elif self.contact:
|
||||||
string += "Recovery email sent to" + self.contact
|
string += "Recovery email sent to" + self.contact
|
||||||
|
|
||||||
def poll(self, rounds = 10, quiet = True):
|
def poll(self, rounds = 10, quiet = True):
|
||||||
for i in range(rounds):
|
for i in range(rounds):
|
||||||
if requests.get(self.successURL).status_code != 200:
|
if requests.get(self.successURL).status_code != 200:
|
||||||
|
|||||||
@@ -1,18 +1,16 @@
|
|||||||
from letsencrypt.client.challenge import Challenge
|
from letsencrypt.client.challenge import Challenge
|
||||||
from letsencrypt.client import logger
|
|
||||||
from letsencrypt.client.CONFIG import RECOVERY_TOKEN_EXT
|
|
||||||
|
|
||||||
class RecoveryToken(Challenge):
|
class RecoveryToken(Challenge):
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.token = ""
|
self.token = ""
|
||||||
|
|
||||||
def perform(self, quiet = True):
|
def perform(self, quiet = True):
|
||||||
|
|
||||||
cancel, self.token = dialog.generic_input("Please Input Recovery Token: ")
|
cancel, self.token = dialog.generic_input("Please Input Recovery Token: ")
|
||||||
if cancel == 1:
|
if cancel == 1:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def cleanup(self):
|
def cleanup(self):
|
||||||
|
|||||||
@@ -1,22 +1,18 @@
|
|||||||
#!/usr/bin/env python
|
#!/usr/bin/env python
|
||||||
|
|
||||||
import subprocess
|
|
||||||
import M2Crypto
|
import M2Crypto
|
||||||
from Crypto import Random
|
from Crypto import Random
|
||||||
import hmac
|
|
||||||
import hashlib
|
import hashlib
|
||||||
from shutil import move
|
from os import path
|
||||||
from os import remove, close, path
|
|
||||||
import sys
|
import sys
|
||||||
import binascii
|
import binascii
|
||||||
import augeas
|
|
||||||
import jose
|
import jose
|
||||||
|
|
||||||
from letsencrypt.client import configurator
|
from letsencrypt.client import configurator
|
||||||
|
|
||||||
from letsencrypt.client.CONFIG import CONFIG_DIR, WORK_DIR, SERVER_ROOT
|
from letsencrypt.client.CONFIG import CONFIG_DIR, WORK_DIR, SERVER_ROOT
|
||||||
from letsencrypt.client.CONFIG import OPTIONS_SSL_CONF, APACHE_CHALLENGE_CONF, INVALID_EXT
|
from letsencrypt.client.CONFIG import OPTIONS_SSL_CONF, APACHE_CHALLENGE_CONF, INVALID_EXT
|
||||||
from letsencrypt.client.CONFIG import S_SIZE, NONCE_SIZE
|
from letsencrypt.client.CONFIG import S_SIZE
|
||||||
from letsencrypt.client import logger, crypto_util
|
from letsencrypt.client import logger, crypto_util
|
||||||
from letsencrypt.client.challenge import Challenge
|
from letsencrypt.client.challenge import Challenge
|
||||||
|
|
||||||
@@ -41,7 +37,7 @@ class SNI_Challenge(Challenge):
|
|||||||
self.key = key_filepath
|
self.key = key_filepath
|
||||||
self.configurator = config
|
self.configurator = config
|
||||||
self.s = None
|
self.s = None
|
||||||
|
|
||||||
|
|
||||||
def getDvsniCertFile(self, nonce):
|
def getDvsniCertFile(self, nonce):
|
||||||
"""
|
"""
|
||||||
@@ -117,7 +113,7 @@ DocumentRoot " + CONFIG_DIR + "challenge_page/ \n \
|
|||||||
|
|
||||||
def checkForApacheConfInclude(self, mainConfig):
|
def checkForApacheConfInclude(self, mainConfig):
|
||||||
"""
|
"""
|
||||||
Adds DVSNI challenge include file if it does not already exist
|
Adds DVSNI challenge include file if it does not already exist
|
||||||
within mainConfig
|
within mainConfig
|
||||||
|
|
||||||
mainConfig: string - file path to main user apache config file
|
mainConfig: string - file path to main user apache config file
|
||||||
@@ -147,7 +143,7 @@ DocumentRoot " + CONFIG_DIR + "challenge_page/ \n \
|
|||||||
|
|
||||||
#print ["openssl", "x509", "-req", "-days", "21", "-extfile", CHOC_CERT_CONF, "-extensions", "v3_ca", "-signkey", key, "-out", self.getDvsniCertFile(nonce), "-in", csr]
|
#print ["openssl", "x509", "-req", "-days", "21", "-extfile", CHOC_CERT_CONF, "-extensions", "v3_ca", "-signkey", key, "-out", self.getDvsniCertFile(nonce), "-in", csr]
|
||||||
|
|
||||||
|
|
||||||
#subprocess.call(["openssl", "x509", "-req", "-days", "21", "-extfile", CHOC_CERT_CONF, "-extensions", "v3_ca", "-signkey", key, "-out", self.getDvsniCertFile(nonce), "-in", csr], stdout=open("/dev/null", 'w'), stderr=open("/dev/null", 'w'))
|
#subprocess.call(["openssl", "x509", "-req", "-days", "21", "-extfile", CHOC_CERT_CONF, "-extensions", "v3_ca", "-signkey", key, "-out", self.getDvsniCertFile(nonce), "-in", csr], stdout=open("/dev/null", 'w'), stderr=open("/dev/null", 'w'))
|
||||||
|
|
||||||
|
|
||||||
@@ -179,7 +175,7 @@ DocumentRoot " + CONFIG_DIR + "challenge_page/ \n \
|
|||||||
h = hashlib.new('sha256')
|
h = hashlib.new('sha256')
|
||||||
h.update(r)
|
h.update(r)
|
||||||
h.update(s)
|
h.update(s)
|
||||||
|
|
||||||
return h.hexdigest() + INVALID_EXT
|
return h.hexdigest() + INVALID_EXT
|
||||||
|
|
||||||
def byteToHex(self, byteStr):
|
def byteToHex(self, byteStr):
|
||||||
@@ -205,7 +201,7 @@ DocumentRoot " + CONFIG_DIR + "challenge_page/ \n \
|
|||||||
"""
|
"""
|
||||||
self.configurator.revert_challenge_config()
|
self.configurator.revert_challenge_config()
|
||||||
self.configurator.restart(True)
|
self.configurator.restart(True)
|
||||||
|
|
||||||
def generate_response(self):
|
def generate_response(self):
|
||||||
"""
|
"""
|
||||||
Generates a response for a completed challenge
|
Generates a response for a completed challenge
|
||||||
@@ -275,14 +271,14 @@ def main():
|
|||||||
logger.setLogLevel(logger.INFO)
|
logger.setLogLevel(logger.INFO)
|
||||||
|
|
||||||
testkey = M2Crypto.RSA.load_key(key)
|
testkey = M2Crypto.RSA.load_key(key)
|
||||||
|
|
||||||
#r = Random.get_random_bytes(S_SIZE)
|
#r = Random.get_random_bytes(S_SIZE)
|
||||||
r = "testValueForR"
|
r = "testValueForR"
|
||||||
#nonce = Random.get_random_bytes(NONCE_SIZE)
|
#nonce = Random.get_random_bytes(NONCE_SIZE)
|
||||||
nonce = "nonce"
|
nonce = "nonce"
|
||||||
r2 = "testValueForR2"
|
r2 = "testValueForR2"
|
||||||
nonce2 = "nonce2"
|
nonce2 = "nonce2"
|
||||||
|
|
||||||
r = jose.b64encode_url(r)
|
r = jose.b64encode_url(r)
|
||||||
r2 = jose.b64encode_url(r2)
|
r2 = jose.b64encode_url(r2)
|
||||||
|
|
||||||
@@ -296,7 +292,7 @@ def main():
|
|||||||
|
|
||||||
nonce = binascii.hexlify(nonce)
|
nonce = binascii.hexlify(nonce)
|
||||||
nonce2 = binascii.hexlify(nonce2)
|
nonce2 = binascii.hexlify(nonce2)
|
||||||
|
|
||||||
config = configurator.Configurator()
|
config = configurator.Configurator()
|
||||||
|
|
||||||
challenges = [("client.theobroma.info", r, nonce), ("foo.theobroma.info",r2, nonce2)]
|
challenges = [("client.theobroma.info", r, nonce), ("foo.theobroma.info",r2, nonce2)]
|
||||||
|
|||||||
Reference in New Issue
Block a user