From ea994a40522f944305840003dc80442fce590d4b Mon Sep 17 00:00:00 2001 From: James Kasten Date: Wed, 14 Nov 2012 17:52:08 -0500 Subject: [PATCH] Added interactive challenge client-side code --- trustify/client/client.py | 50 ++++++++++++++---------- trustify/client/interactive_challenge.py | 40 +++++++++++++++++++ trustify/client/payment_challenge.py | 9 ++--- 3 files changed, 72 insertions(+), 27 deletions(-) create mode 100644 trustify/client/interactive_challenge.py diff --git a/trustify/client/client.py b/trustify/client/client.py index bdb726aec..0b56e62ad 100644 --- a/trustify/client/client.py +++ b/trustify/client/client.py @@ -60,9 +60,9 @@ def choice_of_ca(): # XXX This is a stub d = dialog.Dialog() choices = get_cas() - #choices = [("EFF", "The EFF Trustify CA"), ("UMich", "The Michigan Trustify CA")] - random.shuffle(choices) + #random.shuffle(choices) result = d.menu("Pick a Certificate Authority. They're all unique and special!", width=70, choices=choices) + return result def get_cas(): with open("trustify/client/.ca_offerings") as f: @@ -107,21 +107,22 @@ def by_default(): sys.exit(1) return result[1] == "Secure" -class progress_shower(object): +# should be taken out if it doesn't break anything +#class progress_shower(object): # As in "that which shows", not like a rain shower. - def __init__(self, firstmessage="", height=18, width=70): - self.content = firstmessage - self.d = dialog.Dialog() - self.height = height - self.width = width - self.show() + # def __init__(self, firstmessage="", height=18, width=70): + # self.content = firstmessage + # self.d = dialog.Dialog() + # self.height = height + # self.width = width + # self.show() - def add(self, s): - self.content += s - self.show() + #def add(self, s): + # self.content += s + # self.show() - def show(self): - self.d.infobox(self.content, self.height, self.width) + #def show(self): + # self.d.infobox(self.content, self.height, self.width) def is_hostname_sane(hostname): """ @@ -288,16 +289,20 @@ def challenge_factory(r, req_filepath, key_filepath, config): sni_todo.append( (chall.name, dvsni_y, dvsni_nonce, dvsni_ext) ) # TODO: This domain name list is inelegant and the info should be - # gathered from the challenge itself + # gathered from the challenge list itself dn.append(chall.name) - if chall.type == r.Payment: - url, reason = chall.data - challenges.append(Payment_Challenge(url, reason)) + #if chall.type == r.Payment: + # url, reason = chall.data + # challenges.append(Payment_Challenge(url, reason)) + + #if chall.type == r.Interactive: + # message = chall.data + # challenges.append(Interactive_Challenge(message) if sni_todo: # SNI_Challenge can satisfy many sni challenges at once so only - # one "challenge" is issued for all sni_challenges + # one "challenge object" is issued for all sni_challenges challenges.append(SNI_Challenge(sni_todo, req_filepath, key_filepath, config)) logger.debug(sni_todo) @@ -305,6 +310,9 @@ def challenge_factory(r, req_filepath, key_filepath, config): def send_request(key_pem, csr_pem, names, quiet=curses): + ''' + Sends the request to the CA and returns a response + ''' global server upstream = "https://%s/chocolate.py" % server k=chocolatemessage() @@ -428,7 +436,7 @@ def authenticate(): if curses: names = filter_names(names) - choice_of_ca() + choice = choice_of_ca() logger.setLogger(logger.NcursesLogger()) logger.setLogLevel(logger.INFO) else: @@ -457,7 +465,7 @@ def authenticate(): challenges, dn = challenge_factory(r, os.path.abspath(req_file), os.path.abspath(key_file), config) - # Find virtual hosts to deploy certificates too + # Find set of virtual hosts to deploy certificates too vhost = set() for name in dn: host = config.choose_virtual_host(name) diff --git a/trustify/client/interactive_challenge.py b/trustify/client/interactive_challenge.py new file mode 100644 index 000000000..a18ba1eaa --- /dev/null +++ b/trustify/client/interactive_challenge.py @@ -0,0 +1,40 @@ +from trustify.client.challenge import Challenge +from trustify.client import logger +import textwrap + +############################################################ +# Possible addition to challenge structure: priority parameter +# If only DVSNI and Payment are required, the user might want +# to be validated before submitting payment, allowing the user +# to gain confidence in the system. If things do go poorly the +# user has less invested in that particular session/transaction. +############################################################# + +########################################################### +# Interactive challlenge displays the string sent by the CA +# formatted to fit on the screen of the client +# The Challenge also adds proper instructions for how the +# client should continue the trustify process +########################################################### + +class Interactive_Challenge(Challenge): + BOX_SIZE = 70 + + def __init__(self, string): + self.string = string + + def perform(self, quiet=True): + if quiet: + dialog.Dialog().msgbox(get_display_string(), width=BOX_SIZE) + else: + print get_display_string() + raw_input('') + + return True + + + def get_display_string(self): + return textwrap.fill(self.string, width=BOX_SIZE) + "\n\nPlease Press Enter to Continue" + + def formatted_reasons(self): + return "\n\t* %s\n", self.reason diff --git a/trustify/client/payment_challenge.py b/trustify/client/payment_challenge.py index d01e44a1d..0a5d38d6a 100644 --- a/trustify/client/payment_challenge.py +++ b/trustify/client/payment_challenge.py @@ -1,9 +1,6 @@ from trustify.client.challenge import Challenge from trustify.client import logger -# TODO: How is this determined? -curses = True; - ############################################################ # Possible addition to challenge structure: priority parameter # If only DVSNI and Payment are required, the user might want @@ -21,7 +18,7 @@ class Payment_Challenge(Challenge): self.times_performed = 0 def perform(self, quiet=True): - if curses: + if quiet: dialog.Dialog().msgbox(get_display_string(), width=70) else: print get_display_string() @@ -31,7 +28,7 @@ class Payment_Challenge(Challenge): return True - def get_display_string(): + def get_display_string(self): if self.times_performed == 0: return "You are buying " + formatted_reasons() + " You will need to visit " + self.url + " to submit your payment\nPlease press enter once your payment has been submitted" @@ -40,6 +37,6 @@ class Payment_Challenge(Challenge): 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(): + def formatted_reasons(self): return "\n\t* %s\n", self.reason