Pulled out all display code out of client and arranged code into a curses and stdout Singleton

This commit is contained in:
James Kasten 2014-11-10 22:55:01 -08:00
parent 66b5b7a0c5
commit 66c37a2d40
2 changed files with 171 additions and 56 deletions

View file

@ -34,12 +34,7 @@ class Client(object):
def __init__(self, ca_server, domains=[], cert_signing_request=None, private_key=None, use_curses=True):
global dialog
self.curses = use_curses
if self.curses:
import dialog
self.d = dialog.Dialog()
# Logger needs to be initialized before Configurator
self.init_logger()
@ -74,8 +69,12 @@ class Client(object):
sys.exit(1)
# Display screen to select domains to validate
self.names = self.filter_names(self.names)
self.names = [self.names[0]]
code, self.names = display.filter_names(self.names)
if code == display.OK:
# TODO: Allow multiple names once it is setup
self.names = [self.names[0]]
else:
sys.exit(0)
# Display choice of CA screen
# TODO: Use correct server depending on CA
@ -135,7 +134,7 @@ class Client(object):
revocation_dict = self.is_expected_msg(revocation_dict, "revocation")
self.d.msgbox("You have successfully revoked the certificate for %s" % c["cn"], width=70, height=16)
dialog.generic_notification("You have successfully revoked the certificate for %s" % c["cn"])
self.remove_cert_key(c)
sys.exit(0)
@ -207,27 +206,21 @@ class Client(object):
c["idx"] = int(row[0])
certs.append(c)
if certs:
self.__display_certs(certs)
self.choose_certs(certs)
else:
logger.info("There are not any trusted Let's Encrypt certificates for this server.")
display.generic_notification("There are not any trusted Let's Encrypt certificates for this server.")
def __display_certs(self, certs):
def choose_certs(self, certs):
while True:
menu_choices = [(str(i+1), str(c["cn"]) + " - " + c["pub_key"] + " - " + str(c["not_before"])[:-6]) for i, c in enumerate(certs)]
if self.curses:
code, selection = self.d.menu("Which certificate would you like to revoke?", choices = menu_choices,
help_button=True, help_label="More Info", ok_label="Revoke",
width=70, height=16)
if code == self.d.DIALOG_OK:
if display.confirm_revocation(certs[int(selection)-1]):
self.revoke(c)
code, selection = display.display_certs(certs)
if code == display.OK:
if display.confirm_revocation(certs[int(selection)-1]):
self.revoke(c)
elif code == self.d.DIALOG_CANCEL:
exit(0)
elif code == "help":
display.more_info_cert(certs[int(selection)-1])
elif code == display.CANCEL:
exit(0)
elif code == display.HELP:
display.more_info_cert(certs[int(selection)-1])
@ -340,6 +333,12 @@ class Client(object):
return responses, challenge_objs
def gen_challenge_path(self, challenges, combos):
"""
Generate a plan to get authority over the identity
TODO: Make sure that the challenges are feasible...
TODO Example: Do you have the recovery key?
"""
if combos:
return self.__find_smart_path(challenges, combos)
@ -504,23 +503,17 @@ class Client(object):
return key_pem, csr_pem
def filter_names(self, names):
choices = [(n, "", 0) for n in names]
result = self.d.checklist("Which names would you like to activate HTTPS for?", choices=choices)
if result[0] != 0 or not result[1]:
sys.exit(1)
return result[1]
def choice_of_ca(self):
choices = self.get_cas()
message = "Pick a Certificate Authority. They're all unique and special!"
in_txt = "Enter the number of a Certificate Authority (c to cancel): "
code, selection = display.generic_menu(message, choices, in_txt)
result = self.d.menu("Pick a Certificate Authority. They're all unique and special!", width=70, choices=choices)
if code != display.OK:
sys.exit(0)
if result[0] != 0:
sys.exit(1)
return result
return selection
def get_cas(self):
DV_choices = []
@ -542,6 +535,7 @@ class Client(object):
# random.shuffle(OV_choices)
# random.shuffle(EV_choices)
choices = DV_choices + OV_choices + EV_choices
choices = [(l[0], l[1]) for l in choices]
except IOError as e:
logger.fatal("Unable to find .ca_offerings file")

View file

@ -2,8 +2,7 @@ import dialog
from trustify.client import logger
WIDTH = 70
WIDTH = 70
HEIGHT = 16
class SingletonD(object):
@ -16,6 +15,12 @@ class SingletonD(object):
class Display(SingletonD):
def generic_notification(self, message):
raise Exception("Error no display defined")
def generic_menu(self, message, choices, input_text):
raise Exception("Error no display defined")
def filter_names(self, names):
raise Exception("Error no display defined")
def success_installation(self, domains):
raise Exception("Error no display defined")
def redirect_by_default(self):
@ -37,10 +42,12 @@ class Display(SingletonD):
return result
def display_certs(self, certs):
raise Exception("Error no display define")
def confirm_revocation(self, cert):
raise Exception("Error no display defined")
def cert_info_frame(self, cert):
text = "-" * (WIDTH - 4) + "\n"
text += self.cert_info_string(cert)
@ -60,27 +67,61 @@ class Display(SingletonD):
def more_info_cert(self, cert):
raise Exception("Error no display defined")
import dialog
class NcursesDisplay(Display):
import dialog
def __init__(self):
self.d = dialog.Dialog()
def generic_notification(self, message):
self.d.msgbox(message, width=WIDTH, height=HEIGHT)
def generic_menu(self, message, choices, input_text):
return self.d.menu(message, choices = choices,
width=WIDTH, height=HEIGHT)
def filter_names(self, names):
choices = [(n, "", 0) for n in names]
c, s = self.d.checklist("Which names would you like to activate \
HTTPS for?", choices=choices)
return c, s
def success_installation(self, domains):
self.d.msgbox("\nCongratulations! You have successfully enabled " + self.gen_https_names(domains) + "!", width=WIDTH)
self.d.msgbox("\nCongratulations! You have successfully enabled "
+ self.gen_https_names(domains) + "!", width=WIDTH)
def display_certs(self, certs):
menu_choices = [(str(i+1), str(c["cn"]) + " - " + c["pub_key"] + " - " +
str(c["not_before"])[:-6])
for i, c in enumerate(certs)]
c, s = self.d.menu("Which certificate would you like to revoke?",
choices = menu_choices, help_button=True,
help_label="More Info", ok_label="Revoke",
width=WIDTH, height=HEIGHT)
return c, s
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.d.menu("Please choose whether HTTPS access is required or optional.", width=WIDTH, choices=choices)
choices = [
("Easy", "Allow both HTTP and HTTPS access to these sites"),
("Secure", "Make all requests redirect to secure HTTPS access")]
result = self.d.menu("Please choose whether HTTPS access is required \
or optional.", width=WIDTH, choices=choices)
if result[0] != 0:
return False
return result[1] == "Secure"
return result[1] == "Secure"
def confirm_revocation(self, cert):
text = "Are you sure you would like to revoke the following certificate:\n"
text = "Are you sure you would like to revoke the following \
certificate:\n"
text += self.cert_info_frame(cert)
text += "This action cannot be reversed!"
a = self.d.yesno(text, width=WIDTH, height=HEIGHT)
@ -96,30 +137,110 @@ class FileDisplay(Display):
def __init__(self, outfile):
self.outfile = outfile
def generic_notification(self, message):
side_frame = '-' * WIDTH - 4
self.outfile.write("\n%s\n%s\n%s\n" % (side_frame, message, side_frame))
def generic_menu(self, message, choices, input_text):
self.outfile.write("\n%s\n" % message)
side_frame = '-' * (WIDTH - 4)
self.outfile.write("%s\n" % side_frame)
for i, c in enumerate(choices):
self.outfile.write("%d: %s\n" % (i, c))
self.outfile.write("%s\n" % side_frame)
code, selection = self.__get_valid_int_ans("Enter the number of a \
Certificate Authority (c to cancel): ")
return code, selection
def filter_names(self, names):
c, s = self.generic_menu(
"Choose the names would you like to upgrade to HTTPS?",
names,
"Select the number of the name (c to cancel): ")
# Make sure to return a list...
return c, [s]
def display_certs(self, certs):
menu_choices = [(str(i+1), str(c["cn"]) + " - " + c["pub_key"] +
" - " + str(c["not_before"])[:-6])
for i, c in enumerate(certs)]
self.outfile.write("Which certificate would you like to revoke?\n")
for c in menu_choices:
self.outfile.write("%s: %s - %s Signed (UTC): %s\n"
% (c[0], c[1], c[2], c[3]))
return self.__get_valid_int_ans("Revoke Number (c to cancel): ")
def __get_valid_int_ans(self, input_string):
valid_ans = False
while not valid_ans:
ans = raw_input(input_string)
if ans.startswith('c') or ans.startswith('C'):
code = CANCEL
selection = -1
else:
try:
selection = int(ans)
code = OK
except ValueError:
self.outfile("Please input a number, \
or the letter c to cancel")
valid_ans = True
return code, selection
def success_installation(self, domains):
outfile.write("Congratulations! You have successfully enabled " + self.gen_https_names(domains) + "!\n")
self.outfile.write("Congratulations! You have successfully enabled " +
self.gen_https_names(domains) + "!\n")
def redirect_by_default(self):
ans = raw_input("Would you like to redirect all normal HTTP traffic to HTTPS? y/n")
ans = raw_input("Would you like to redirect all \
normal HTTP traffic to HTTPS? y/n")
return ans.startswith('y') or ans.startswith('Y')
def confirm_revocation(self, cert):
outfile.write("Are you sure you would like to revoke the following certificate:\n")
outfile.write(self.cert_info_frame(cert))
outfile("This action cannot be reversed!\n");
self.outfile.write("Are you sure you would like to revoke \
the following certificate:\n")
self.outfile.write(self.cert_info_frame(cert))
self.outfile("This action cannot be reversed!\n");
ans = raw_input("y/n")
return ans.startswith('y') or ans.startswith('Y')
def more_info_cert(self, cert):
outfile.write("\nCertificate Information:\n")
outfile.write(self.cert_info_frame(cert))
self.outfile.write("\nCertificate Information:\n")
self.outfile.write(self.cert_info_frame(cert))
display = None
OK = 0
CANCEL = 1
HELP = "help"
def setDisplay(display_inst):
global display
display = display_inst
def generic_notification(message):
display.generic_notification(message)
def generic_menu(message, choices, input_text):
return display.generic_menu(message, choices, input_text)
def filter_names(names):
return display.filter_names(names)
def display_certs(certs):
return display.display_certs(certs)
def cert_info_string(cert):
return display.cert_info_string(cert)