mirror of
https://github.com/certbot/certbot.git
synced 2026-05-28 04:34:11 -04:00
git push origin masterMerge branch 'kuba-zope.interface-display'
This commit is contained in:
commit
684a9aae9d
9 changed files with 106 additions and 138 deletions
|
|
@ -9,13 +9,14 @@ import string
|
|||
import sys
|
||||
|
||||
import M2Crypto
|
||||
import zope.component
|
||||
|
||||
from letsencrypt.client import acme
|
||||
from letsencrypt.client import challenge
|
||||
from letsencrypt.client import CONFIG
|
||||
from letsencrypt.client import crypto_util
|
||||
from letsencrypt.client import display
|
||||
from letsencrypt.client import errors
|
||||
from letsencrypt.client import interfaces
|
||||
from letsencrypt.client import le_util
|
||||
from letsencrypt.client import network
|
||||
|
||||
|
|
@ -206,7 +207,8 @@ class Client(object):
|
|||
# sites may have been enabled / final cleanup
|
||||
self.installer.restart()
|
||||
|
||||
display.success_installation(self.names)
|
||||
zope.component.getUtility(
|
||||
interfaces.IDisplay).success_installation(self.names)
|
||||
|
||||
return vhost
|
||||
|
||||
|
|
@ -223,7 +225,8 @@ class Client(object):
|
|||
|
||||
"""
|
||||
if redirect is None:
|
||||
redirect = display.redirect_by_default()
|
||||
redirect = zope.component.getUtility(
|
||||
interfaces.IDisplay).redirect_by_default()
|
||||
|
||||
if redirect:
|
||||
self.redirect_to_ssl(vhost)
|
||||
|
|
|
|||
|
|
@ -1,73 +1,37 @@
|
|||
import textwrap
|
||||
|
||||
import dialog
|
||||
import zope.interface
|
||||
|
||||
from letsencrypt.client import interfaces
|
||||
|
||||
|
||||
WIDTH = 72
|
||||
HEIGHT = 20
|
||||
|
||||
|
||||
class SingletonD(object):
|
||||
_instance = None
|
||||
class NcursesDisplay(object):
|
||||
zope.interface.implements(interfaces.IDisplay)
|
||||
|
||||
def __new__(cls, *args, **kwargs):
|
||||
if not cls._instance:
|
||||
cls._instance = super(SingletonD, cls).__new__(
|
||||
cls, *args, **kwargs)
|
||||
return cls._instance
|
||||
|
||||
|
||||
class Display(SingletonD):
|
||||
"""Generic display."""
|
||||
|
||||
def generic_notification(self, message, width=WIDTH, height=HEIGHT):
|
||||
raise NotImplementedError()
|
||||
|
||||
def generic_menu(self, message, choices, input_text="",
|
||||
width=WIDTH, height=HEIGHT):
|
||||
raise NotImplementedError()
|
||||
|
||||
def generic_input(self, message):
|
||||
raise NotImplementedError()
|
||||
|
||||
def generic_yesno(self, message, yes_label="Yes", no_label="No"):
|
||||
raise NotImplementedError()
|
||||
|
||||
def filter_names(self, names):
|
||||
raise NotImplementedError()
|
||||
|
||||
def success_installation(self, domains):
|
||||
raise NotImplementedError()
|
||||
|
||||
def display_certs(self, certs):
|
||||
raise NotImplementedError()
|
||||
|
||||
def confirm_revocation(self, cert):
|
||||
raise NotImplementedError()
|
||||
|
||||
def more_info_cert(self, cert):
|
||||
raise NotImplementedError()
|
||||
|
||||
|
||||
class NcursesDisplay(Display):
|
||||
|
||||
def __init__(self):
|
||||
def __init__(self, width=WIDTH, height=HEIGHT):
|
||||
super(NcursesDisplay, self).__init__()
|
||||
self.dialog = dialog.Dialog()
|
||||
self.width = width
|
||||
self.height = height
|
||||
|
||||
def generic_notification(self, message, w=WIDTH, h=HEIGHT):
|
||||
self.dialog.msgbox(message, width=w, height=h)
|
||||
def generic_notification(self, message):
|
||||
self.dialog.msgbox(message, width=self.width)
|
||||
|
||||
def generic_menu(self, message, choices, input_text="", width=WIDTH,
|
||||
height=HEIGHT):
|
||||
def generic_menu(self, message, choices, input_text=""):
|
||||
# Can accept either tuples or just the actual choices
|
||||
if choices and isinstance(choices[0], tuple):
|
||||
code, selection = self.dialog.menu(
|
||||
message, choices=choices, width=WIDTH, height=HEIGHT)
|
||||
message, choices=choices, width=self.width, height=self.height)
|
||||
return code, str(selection)
|
||||
else:
|
||||
choices = list(enumerate(choices, 1))
|
||||
code, tag = self.dialog.menu(
|
||||
message, choices=choices, width=WIDTH, height=HEIGHT)
|
||||
message, choices=choices, width=self.width, height=self.height)
|
||||
|
||||
return code(int(tag) - 1)
|
||||
|
||||
|
|
@ -76,7 +40,7 @@ class NcursesDisplay(Display):
|
|||
|
||||
def generic_yesno(self, message, yes="Yes", no="No"):
|
||||
return self.dialog.DIALOG_OK == self.dialog.yesno(
|
||||
message, HEIGHT, WIDTH, yes_label=yes, no_label=no)
|
||||
message, self.height, self.width, yes_label=yes, no_label=no)
|
||||
|
||||
def filter_names(self, names):
|
||||
choices = [(n, "", 0) for n in names]
|
||||
|
|
@ -88,12 +52,12 @@ class NcursesDisplay(Display):
|
|||
def success_installation(self, domains):
|
||||
self.dialog.msgbox(
|
||||
"\nCongratulations! You have successfully enabled "
|
||||
+ gen_https_names(domains) + "!", width=WIDTH)
|
||||
+ gen_https_names(domains) + "!", width=self.width)
|
||||
|
||||
def display_certs(self, certs):
|
||||
list_choices = [
|
||||
(str(i+1), "%s | %s | %s" %
|
||||
(str(c["cn"].ljust(WIDTH - 39)),
|
||||
(str(c["cn"].ljust(self.width - 39)),
|
||||
c["not_before"].strftime("%m-%d-%y"),
|
||||
"Installed" if c["installed"] else ""))
|
||||
for i, c in enumerate(certs)]
|
||||
|
|
@ -102,7 +66,7 @@ class NcursesDisplay(Display):
|
|||
"Which certificates would you like to revoke?",
|
||||
choices=list_choices, help_button=True,
|
||||
help_label="More Info", ok_label="Revoke",
|
||||
width=WIDTH, height=HEIGHT)
|
||||
width=self.width, height=self.height)
|
||||
if not tag:
|
||||
tag = -1
|
||||
return code, (int(tag) - 1)
|
||||
|
|
@ -113,29 +77,45 @@ class NcursesDisplay(Display):
|
|||
text += cert_info_frame(cert)
|
||||
text += "This action cannot be reversed!"
|
||||
return self.dialog.DIALOG_OK == self.dialog.yesno(
|
||||
text, width=WIDTH, height=HEIGHT)
|
||||
text, width=self.width, height=self.height)
|
||||
|
||||
def more_info_cert(self, cert):
|
||||
text = "Certificate Information:\n"
|
||||
text += cert_info_frame(cert)
|
||||
print text
|
||||
self.dialog.msgbox(text, width=WIDTH, height=HEIGHT)
|
||||
self.dialog.msgbox(text, width=self.width, height=self.height)
|
||||
|
||||
def redirect_by_default(self):
|
||||
choices = [
|
||||
("Easy", "Allow both HTTP and HTTPS access to these sites"),
|
||||
("Secure", "Make all requests redirect to secure HTTPS access")]
|
||||
|
||||
result = self.generic_menu(
|
||||
"Please choose whether HTTPS access is required or optional.",
|
||||
choices, "Please enter the appropriate number")
|
||||
|
||||
if result[0] != OK:
|
||||
return False
|
||||
|
||||
# different answer for each type of display
|
||||
return str(result[1]) == "Secure" or result[1] == 1
|
||||
|
||||
|
||||
class FileDisplay(Display):
|
||||
class FileDisplay(object):
|
||||
zope.interface.implements(interfaces.IDisplay)
|
||||
|
||||
def __init__(self, outfile):
|
||||
super(FileDisplay, self).__init__()
|
||||
self.outfile = outfile
|
||||
|
||||
def generic_notification(self, message, width=WIDTH, height=HEIGHT):
|
||||
def generic_notification(self, message):
|
||||
side_frame = '-' * (79)
|
||||
wm = textwrap.fill(message, 80)
|
||||
text = "\n%s\n%s\n%s\n" % (side_frame, wm, side_frame)
|
||||
self.outfile.write(text)
|
||||
raw_input("Press Enter to Continue")
|
||||
|
||||
def generic_menu(self, message, choices, input_text="",
|
||||
width=WIDTH, height=HEIGHT):
|
||||
def generic_menu(self, message, choices, input_text=""):
|
||||
# Can take either tuples or single items in choices list
|
||||
if choices and isinstance(choices[0], tuple):
|
||||
choices = ["%s - %s" % (c[0], c[1]) for c in choices]
|
||||
|
|
@ -232,41 +212,11 @@ class FileDisplay(Display):
|
|||
self.outfile.write("\nCertificate Information:\n")
|
||||
self.outfile.write(cert_info_frame(cert))
|
||||
|
||||
display = None
|
||||
OK = "ok"
|
||||
CANCEL = "cancel"
|
||||
HELP = "help"
|
||||
|
||||
|
||||
def set_display(display_inst):
|
||||
global display
|
||||
display = display_inst
|
||||
|
||||
|
||||
def generic_notification(message, width=WIDTH, height=HEIGHT):
|
||||
display.generic_notification(message, width, height)
|
||||
|
||||
|
||||
def generic_menu(message, choices, input_text="", width=WIDTH, height=HEIGHT):
|
||||
return display.generic_menu(message, choices, input_text, width, height)
|
||||
|
||||
|
||||
def generic_input(message):
|
||||
return display.generic_message(message)
|
||||
|
||||
|
||||
def generic_yesno(message, yes_label="Yes", no_label="No"):
|
||||
return display.generic_yesno(message, yes_label, no_label)
|
||||
|
||||
|
||||
def filter_names(names):
|
||||
return display.filter_names(names)
|
||||
|
||||
|
||||
def display_certs(certs):
|
||||
return display.display_certs(certs)
|
||||
|
||||
|
||||
def cert_info_frame(cert):
|
||||
text = "-" * (WIDTH - 4) + "\n"
|
||||
text += cert_info_string(cert)
|
||||
|
|
@ -303,33 +253,3 @@ def gen_https_names(domains):
|
|||
result = result + "https://" + domains[len(domains)-1]
|
||||
|
||||
return result
|
||||
|
||||
|
||||
def success_installation(domains):
|
||||
return display.success_installation(domains)
|
||||
|
||||
|
||||
def redirect_by_default():
|
||||
choices = [
|
||||
("Easy", "Allow both HTTP and HTTPS access to these sites"),
|
||||
("Secure", "Make all requests redirect to secure HTTPS access")]
|
||||
|
||||
result = display.generic_menu("Please choose whether HTTPS access " +
|
||||
"is required or optional.",
|
||||
choices,
|
||||
"Please enter the appropriate number",
|
||||
width=WIDTH)
|
||||
|
||||
if result[0] != OK:
|
||||
return False
|
||||
|
||||
# different answer for each type of display
|
||||
return str(result[1]) == "Secure" or result[1] == 1
|
||||
|
||||
|
||||
def confirm_revocation(cert):
|
||||
return display.confirm_revocation(cert)
|
||||
|
||||
|
||||
def more_info_cert(cert):
|
||||
return display.more_info_cert(cert)
|
||||
|
|
|
|||
|
|
@ -110,6 +110,40 @@ class IInstaller(zope.interface.Interface):
|
|||
"""Restart or refresh the server content."""
|
||||
|
||||
|
||||
class IDisplay(zope.interface.Interface):
|
||||
"""Generic display."""
|
||||
|
||||
def generic_notification(message):
|
||||
pass
|
||||
|
||||
def generic_menu(message, choices, input_text=""):
|
||||
pass
|
||||
|
||||
def generic_input(message):
|
||||
pass
|
||||
|
||||
def generic_yesno(message, yes_label="Yes", no_label="No"):
|
||||
pass
|
||||
|
||||
def filter_names(names):
|
||||
pass
|
||||
|
||||
def success_installation(domains):
|
||||
pass
|
||||
|
||||
def display_certs(certs):
|
||||
pass
|
||||
|
||||
def confirm_revocation(cert):
|
||||
pass
|
||||
|
||||
def more_info_cert(cert):
|
||||
pass
|
||||
|
||||
def redirect_by_default():
|
||||
pass
|
||||
|
||||
|
||||
class IValidator(object):
|
||||
"""Configuration validator."""
|
||||
|
||||
|
|
|
|||
|
|
@ -3,9 +3,9 @@
|
|||
.. note:: This challenge has not been implemented into the project yet
|
||||
|
||||
"""
|
||||
import zope.component
|
||||
import zope.interface
|
||||
|
||||
from letsencrypt.client import display
|
||||
from letsencrypt.client import interfaces
|
||||
|
||||
|
||||
|
|
@ -22,8 +22,9 @@ class RecoveryToken(object):
|
|||
self.token = ""
|
||||
|
||||
def perform(self, quiet=True):
|
||||
cancel, self.token = display.generic_input(
|
||||
"Please Input Recovery Token: ")
|
||||
cancel, self.token = zope.component.getUtility(
|
||||
interfaces.IDisplay).generic_input(
|
||||
"Please Input Recovery Token: ")
|
||||
return cancel != 1
|
||||
|
||||
def cleanup(self):
|
||||
|
|
|
|||
|
|
@ -5,11 +5,13 @@ import os
|
|||
import shutil
|
||||
|
||||
import M2Crypto
|
||||
import zope.component
|
||||
|
||||
from letsencrypt.client import acme
|
||||
from letsencrypt.client import CONFIG
|
||||
from letsencrypt.client import crypto_util
|
||||
from letsencrypt.client import display
|
||||
from letsencrypt.client import interfaces
|
||||
from letsencrypt.client import network
|
||||
|
||||
|
||||
|
|
@ -35,9 +37,9 @@ class Revoker(object):
|
|||
revocation = self.network.send_and_receive_expected(
|
||||
acme.revocation_request(cert_der, key), "revocation")
|
||||
|
||||
display.generic_notification(
|
||||
zope.component.getUtility(interfaces.IDisplay).generic_notification(
|
||||
"You have successfully revoked the certificate for "
|
||||
"%s" % cert["cn"], width=70, height=9)
|
||||
"%s" % cert["cn"])
|
||||
|
||||
self.remove_cert_key(cert)
|
||||
self.list_certs_keys()
|
||||
|
|
@ -84,7 +86,7 @@ class Revoker(object):
|
|||
if certs:
|
||||
self.choose_certs(certs)
|
||||
else:
|
||||
display.generic_notification(
|
||||
zope.component.getUtility(interfaces.IDisplay).generic_notification(
|
||||
"There are not any trusted Let's Encrypt "
|
||||
"certificates for this server.")
|
||||
|
||||
|
|
@ -94,17 +96,18 @@ class Revoker(object):
|
|||
:param list certs: List of cert dicts.
|
||||
|
||||
"""
|
||||
code, tag = display.display_certs(certs)
|
||||
displayer = zope.component.getUtility(interfaces.IDisplay)
|
||||
code, tag = displayer.display_certs(certs)
|
||||
|
||||
if code == display.OK:
|
||||
cert = certs[tag]
|
||||
if display.confirm_revocation(cert):
|
||||
if displayer.confirm_revocation(cert):
|
||||
self.acme_revocation(cert)
|
||||
else:
|
||||
self.choose_certs(certs)
|
||||
elif code == display.HELP:
|
||||
cert = certs[tag]
|
||||
display.more_info_cert(cert)
|
||||
displayer.more_info_cert(cert)
|
||||
self.choose_certs(certs)
|
||||
else:
|
||||
exit(0)
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ import shutil
|
|||
import unittest
|
||||
|
||||
import mock
|
||||
import zope.component
|
||||
|
||||
from letsencrypt.client import display
|
||||
from letsencrypt.client import errors
|
||||
|
|
@ -20,7 +21,7 @@ class TwoVhost80Test(unittest.TestCase):
|
|||
"""Test two standard well configured HTTP vhosts."""
|
||||
|
||||
def setUp(self):
|
||||
display.set_display(display.NcursesDisplay())
|
||||
zope.component.provideUtility(display.NcursesDisplay())
|
||||
|
||||
self.temp_dir, self.config_dir, self.work_dir = config_util.dir_setup(
|
||||
"debian_apache_2_4/two_vhost_80")
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ import unittest
|
|||
|
||||
import augeas
|
||||
import mock
|
||||
import zope.component
|
||||
|
||||
from letsencrypt.client import display
|
||||
from letsencrypt.client import errors
|
||||
|
|
@ -15,7 +16,7 @@ from letsencrypt.client.tests import config_util
|
|||
class ApacheParserTest(unittest.TestCase):
|
||||
|
||||
def setUp(self):
|
||||
display.set_display(display.FileDisplay(sys.stdout))
|
||||
zope.component.provideUtility(display.FileDisplay(sys.stdout))
|
||||
|
||||
self.temp_dir, self.config_dir, self.work_dir = config_util.dir_setup(
|
||||
"debian_apache_2_4/two_vhost_80")
|
||||
|
|
|
|||
|
|
@ -5,6 +5,8 @@ import logging
|
|||
import os
|
||||
import sys
|
||||
|
||||
import zope.component
|
||||
|
||||
from letsencrypt.client import CONFIG
|
||||
from letsencrypt.client import client
|
||||
from letsencrypt.client import display
|
||||
|
|
@ -68,9 +70,10 @@ def main():
|
|||
logger.setLevel(logging.INFO)
|
||||
if args.use_curses:
|
||||
logger.addHandler(log.DialogHandler())
|
||||
display.set_display(display.NcursesDisplay())
|
||||
displayer = display.NcursesDisplay()
|
||||
else:
|
||||
display.set_display(display.FileDisplay(sys.stdout))
|
||||
displayer = display.FileDisplay(sys.stdout)
|
||||
zope.component.provideUtility(displayer)
|
||||
|
||||
installer = determine_installer()
|
||||
server = CONFIG.ACME_SERVER if args.server is None else args.server
|
||||
|
|
@ -129,7 +132,7 @@ def main():
|
|||
def display_eula():
|
||||
"""Displays the end user agreement."""
|
||||
with open('EULA') as eula_file:
|
||||
if not display.generic_yesno(
|
||||
if not zope.component.getUtility(interfaces.IDisplay).generic_yesno(
|
||||
eula_file.read(), "Agree", "Cancel"):
|
||||
sys.exit(0)
|
||||
|
||||
|
|
@ -144,7 +147,8 @@ def choose_names(installer):
|
|||
# This function adds all names
|
||||
# found within the config to self.names
|
||||
# Then filters them based on user selection
|
||||
code, names = display.filter_names(get_all_names(installer))
|
||||
code, names = zope.component.getUtility(
|
||||
interfaces.IDisplay).filter_names(get_all_names(installer))
|
||||
if code == display.OK and names:
|
||||
# TODO: Allow multiple names once it is setup
|
||||
return [names[0]]
|
||||
|
|
|
|||
1
setup.py
1
setup.py
|
|
@ -11,6 +11,7 @@ install_requires = [
|
|||
'python-augeas',
|
||||
'python2-pythondialog',
|
||||
'requests',
|
||||
'zope.component',
|
||||
'zope.interface',
|
||||
]
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue