def add_fingerprint(self, from_user): ''' Add the fingerprint for each type of crypto used to the email message header. ''' try: encryption_software_list = contacts.get_encryption_names(from_user) if len(encryption_software_list) <= 0: self.log_message( "Not adding fingerprint for {} because no crypto software". format(from_user)) else: for encryption_name in encryption_software_list: fingerprint, __, active = contacts.get_fingerprint( from_user, encryption_name) if active and fingerprint is not None and len( fingerprint.strip()) > 0: self.email_message.add_header( constants.PUBLIC_FINGERPRINT_HEADER.format( encryption_name.upper()), format_fingerprint(fingerprint)) self.log_message( 'added {} fingerprint'.format(encryption_name)) except: record_exception() self.log_message('EXCEPTION - see syr.exception.log for details')
def add_contacts_crypto(contact, encryption_software, fingerprint=None, source=None): ''' Add a contact's crypto record. >>> contacts_crypto = add_contacts_crypto(None, None) >>> contacts_crypto is None True ''' if contact is None or encryption_software is None: contacts_crypto = None else: if fingerprint is None: formatted_fingerprint = None else: formatted_fingerprint = format_fingerprint(fingerprint) contacts_crypto = ContactsCrypto.objects.create( contact=contact, encryption_software=encryption_software, fingerprint=formatted_fingerprint, source=source) log_message("created contact crypto for {}: {}".format( contact, contacts_crypto is not None)) return contacts_crypto
def save(self, *args, **kwargs): # maintain all addresses in lower case if not self.encryption_software or self.encryption_software is None: self.encryption_software = EnryptionSoftware.objects.all()[0] if self.fingerprint is not None: self.fingerprint = format_fingerprint(self.fingerprint) _log("saving a {} contact's crypto for {}".format(self.encryption_software, self.contact)) super(ContactsCrypto, self).save(*args, **kwargs)
def save(self): ''' Save the fingerprint in the database. Test extreme case. >>> set_fingerprint_class = SetFingerprint(None) >>> set_fingerprint_class.save() False ''' self.result_ok, self.crypto_name, self.email, self.key_plugin = prep_sync(self.contacts_encryption) if self.result_ok: try: # the contact's crypto record must exist or we'll get into an infinite loop # because whenever we add a contact's encryption for an email in our supported domain, # then this class is activated so we can complete the configuration if self.contacts_encryption is None: self.result_ok = False log_message('no contact encryption record for {}'.format(self.email)) else: fingerprint, expiration_date = self.key_plugin.get_fingerprint(self.email) if fingerprint is None: self.result_ok = False log_message('no {} fingerprint found for {}'.format(self.crypto_name, self.email)) else: self.result_ok = True try: fingerprint = format_fingerprint(fingerprint) if (self.contacts_encryption.fingerprint is not None and self.contacts_encryption.fingerprint != fingerprint): log_message('replaced old fingerprint {} with {} for {}'.format( self.contacts_encryption.fingerprint, fingerprint, self.email)) # if we created the key, then be sure it's verified if utils.email_in_domain(self.email): if self.contacts_encryption.source is None and create_private_keys(): self.contacts_encryption.source = AUTO_GENERATED if self.contacts_encryption.source == AUTO_GENERATED: self.contacts_encryption.verified = True self.contacts_encryption.fingerprint = fingerprint self.contacts_encryption.save() log_message('set {} fingerprint for {} in database: {}'.format( self.crypto_name, self.email, fingerprint)) except IntegrityError as ie: self.result_ok = False if 'insert or update on table "mail_contactscrypto" violates foreign key constraint' in str(ie): log_message('{} crypto key no longer exists for {}'.format(self.crypto_name, self.email)) else: raise except Exception as exception: record_exception() log_message('EXCEPTION - see syr.exception.log for details') self.result_ok = False return self.result_ok
def notify_new_key_arrived(to_user, id_fingerprint_pairs): ''' Notify user a new key arrived. >>> notify_new_key_arrived(None, None) ''' if to_user is None or id_fingerprint_pairs is None or len(id_fingerprint_pairs) < 1: pass else: # use the first email address from the imported key try: email, __ = id_fingerprint_pairs[0] except: email = get_admin_email() header = i18n("To be safe, verify their key now by following these instructions:") tip = i18n("https://goodcrypto.com/qna/knowledge-base/user-verify-key") regular_notice = True if require_key_verified(): regular_notice = False if is_metadata_address(email): domain = parse_domain(email) subject = i18n('Mail to {domain} cannot be sent until you verify the metadata key'.format(domain=domain)) body = i18n("You received a public key for the email address(es) below. No one can send mail to users with this domain until you verify the key and update the database if it's okay. Otherwise, any mail sent to {domain} will be returned to the sender.".format(domain)), else: subject = i18n('Mail to {email} cannot be sent until you verify their key'.format(email=email)) body = i18n("You received a public key for the email address(es) below. You cannot send mail until you check with the sender to verify the key and update the database if it's okay. Otherwise, any mail you send to this user will be returned to you."), else: if is_metadata_address(email): domain = parse_domain(email) subject = 'Metadata protection to {domain} is now ready'.format(domain=domain) body = 'Unless you disable metadata protection, all mail to {domain} will now have both metadata and content encrypted.'.format( domain=domain) else: subject = i18n('Mail to {email} is now private'.format(email=email)) body = i18n( "The content of all messages to {email} will be protected. ".format(email=email)) body_text = "{}\n\n{} {}\n".format( body, header, tip) for (user_id, fingerprint) in id_fingerprint_pairs: body_text += " {}: {}".format(user_id, format_fingerprint(fingerprint)) if regular_notice: prefix = TAG_PREFIX else: prefix = TAG_WARNING notify_user(to_user, '{} - {}'.format(prefix, str(subject)), body_text)
def show_fingerprint(request, email, fingerprint, verified, active, page_title): ''' Show the fingerprint. ''' log_message('showing {} fingerprint verified: {}'.format(email, verified)) log_message('require verification {}'.format(options.require_key_verified())) template = 'mail/show_fingerprint.html' data = {'page_title': page_title, 'fingerprint': format_fingerprint(fingerprint), 'verified': verified, 'active': active, 'requires': options.require_key_verified()} return render_to_response(template, data, context_instance=RequestContext(request))
def add_fingerprint(self, from_user): ''' Add the fingerprint for each type of crypto used to the email message header. ''' try: encryption_software_list = contacts.get_encryption_names(from_user) if len(encryption_software_list) <= 0: self.log_message("Not adding fingerprint for {} because no crypto software".format(from_user)) else: for encryption_name in encryption_software_list: fingerprint, __, active = contacts.get_fingerprint(from_user, encryption_name) if active and fingerprint is not None and len(fingerprint.strip()) > 0: self.email_message.add_header(constants.PUBLIC_FINGERPRINT_HEADER.format( encryption_name.upper()), format_fingerprint(fingerprint)) self.log_message('added {} fingerprint'.format(encryption_name)) except: record_exception() self.log_message('EXCEPTION - see syr.exception.log for details')
def add_contacts_crypto(contact, encryption_software, fingerprint=None, source=None): ''' Add a contact's crypto record. >>> contacts_crypto = add_contacts_crypto(None, None) >>> contacts_crypto is None True ''' if contact is None or encryption_software is None: contacts_crypto = None else: if fingerprint is None: formatted_fingerprint = None else: formatted_fingerprint = format_fingerprint(fingerprint) contacts_crypto = ContactsCrypto.objects.create( contact=contact, encryption_software=encryption_software, fingerprint=formatted_fingerprint, source=source) log_message("created contact crypto for {}: {}".format(contact, contacts_crypto is not None)) return contacts_crypto
def notify_new_key_arrived(to_user, id_fingerprint_pairs): ''' Notify user a new key arrived. >>> notify_new_key_arrived(None, None) ''' if to_user is None or id_fingerprint_pairs is None or len( id_fingerprint_pairs) < 1: pass else: # use the first email address from the imported key try: email, __ = id_fingerprint_pairs[0] except: email = get_admin_email() header = i18n( "To be safe, verify their key now by following these instructions:" ) tip = i18n("https://goodcrypto.com/qna/knowledge-base/user-verify-key") regular_notice = True if require_key_verified(): regular_notice = False if is_metadata_address(email): domain = parse_domain(email) subject = i18n( 'Mail to {domain} cannot be sent until you verify the metadata key' .format(domain=domain)) body = i18n( "You received a public key for the email address(es) below. No one can send mail to users with this domain until you verify the key and update the database if it's okay. Otherwise, any mail sent to {domain} will be returned to the sender." .format(domain)), else: subject = i18n( 'Mail to {email} cannot be sent until you verify their key' .format(email=email)) body = i18n( "You received a public key for the email address(es) below. You cannot send mail until you check with the sender to verify the key and update the database if it's okay. Otherwise, any mail you send to this user will be returned to you." ), else: if is_metadata_address(email): domain = parse_domain(email) subject = 'Metadata protection to {domain} is now ready'.format( domain=domain) body = 'Unless you disable metadata protection, all mail to {domain} will now have both metadata and content encrypted.'.format( domain=domain) else: subject = i18n( 'Mail to {email} is now private'.format(email=email)) body = i18n( "The content of all messages to {email} will be protected. " .format(email=email)) body_text = "{}\n\n{} {}\n".format(body, header, tip) for (user_id, fingerprint) in id_fingerprint_pairs: body_text += " {}: {}".format(user_id, format_fingerprint(fingerprint)) if regular_notice: prefix = TAG_PREFIX else: prefix = TAG_WARNING notify_user(to_user, '{} - {}'.format(prefix, str(subject)), body_text)
def add_contact_records(email_or_fingerprint, crypto_name, user_initiated_search, job_id, queue_key): ''' Add contact and associated crypto records in database. This function cannot be part of a class because it's passed to RQ which only accepts standalone functions, not functions in an instance of a class. Also, the function must be defined before the class which calls it or located in a separate file and imported. Test extreme case. >>> add_contact_records(None, None, None, None, None) False ''' result_ok = timed_out = False log_message('entered add_contact_records') try: __, email = parse_address(email_or_fingerprint) if email is None: key_id = email_or_fingerprint else: key_id = None log_message('adding a {} contact for {} if key retrieved by {} job'.format( crypto_name, email_or_fingerprint, job_id)) key_plugin = KeyFactory.get_crypto( crypto_name, crypto_software.get_key_classname(crypto_name)) if queue_key is None or job_id is None: result_ok = False else: MAX_WAIT = 10 * 60 # seconds queue = Queue.from_queue_key(queue_key, connection=key_plugin.get_queue_connection()) job = queue.fetch_job(job_id) # if this function is added to a queue (RQ), then it never starts # so we're going to do this the old fashion way waited = 0 while not job.is_finished and not job.is_failed and waited < MAX_WAIT: sleep(1) if job.is_failed: log_message('retrieving {} key for {} job failed'.format(crypto_name, email_or_fingerprint)) result_ok = False else: # even if the job timed out, see if the key was retrieved result_ok, timed_out, output, error = key_plugin.get_background_job_results( email_or_fingerprint, job) log_message("results from retrieving {} key for {}, result ok: {}; timed out: {}".format( crypto_name, email_or_fingerprint, result_ok, timed_out)) if result_ok: imported_user_ids = key_plugin.parse_keyserver_ids_retrieved(error) log_message("imported user ids: {}".format(imported_user_ids)) if len(imported_user_ids) < 1 and error: log_message('error: {}'.format(error)) if output: log_message('output: {}'.format(output)) if result_ok: id_fingerprint_pairs = [] for user_id, imported_key_id in imported_user_ids: contact = contacts.add(user_id, crypto_name, source=KEYSERVER) result_ok = contact is not None log_message("added contact's crypto for {}: {}".format(user_id, result_ok)) if result_ok: # change the outgoing policy if needed if contact.outbound_encrypt_policy != DEFAULT_OUTBOUND_ENCRYPT_POLICY: contact.outbound_encrypt_policy = DEFAULT_OUTBOUND_ENCRYPT_POLICY contact.save() # activate the contact's crypto "after save signal" to update the fingerprint contacts_crypto = contacts.get_contacts_crypto(user_id, crypto_name) if contacts_crypto is not None: if contacts_crypto.fingerprint is None: contacts_crypto.source = KEYSERVER contacts_crypto.save() if key_id is None: fingerprint = imported_key_id else: fingerprint = key_id else: fingerprint = contacts_crypto.fingerprint elif key_id is None: fingerprint = imported_key_id else: fingerprint = key_id id_fingerprint_pairs.append((contact.email, format_fingerprint(fingerprint))) else: log_message('unable to add {} contact record for {}'.format(crypto_name, user_id)) if result_ok and len(id_fingerprint_pairs) > 0: log_message('notifying {} about new keys: {}'.format(user_initiated_search, id_fingerprint_pairs)) notify_new_key_arrived(user_initiated_search, id_fingerprint_pairs) elif timed_out: log_message('timed out retrieving a {} key for {}.'.format( crypto_name, email_or_fingerprint)) else: log_message('unable to retrieve {} key for {}.'.format( crypto_name, email_or_fingerprint)) except Exception as exception: record_exception() log_message('EXCEPTION - see syr.exception.log for details') result_ok = False log_message('ended add_contact_records: {}'.format(result_ok)) return result_ok
def view_fingerprint(request): '''View the fingerprint for a user.''' if options.login_to_view_fingerprints() and not request.user.is_authenticated(): context = {} context.update(csrf(request)) response = redirect('/login/?next={}'.format(request.path), context) else: response = None form = forms.GetFingerprintForm() if request.method == 'POST': email = None encryption_software = None form = forms.GetFingerprintForm(request.POST) if form.is_valid(): try: email = form.cleaned_data['email'] encryption_software = form.cleaned_data['encryption_software'] page_title = i18n('{encryption_software} fingerprint for {email}'.format( encryption_software=encryption_software, email=email)) fingerprint, verified, active = contacts.get_fingerprint(email, encryption_software.name) if fingerprint is None: fingerprint = i18n('No fingerprint defined') checked = None elif request.user.is_authenticated(): if verified: checked = 'checked' else: checked = None form_template = 'mail/verify_fingerprint.html' response = render_to_response( form_template, {'form': form, 'page_title': page_title, 'email': email, 'encryption_name': encryption_software.name, 'fingerprint': format_fingerprint(fingerprint), 'checked': checked, 'active': active, 'requires': options.require_key_verified()}, context_instance=RequestContext(request)) if response is None: response = show_fingerprint(request, email, fingerprint, verified, active, page_title) except Exception: record_exception() log_message('EXCEPTION - see syr.exception.log for details') if response is None: log_message('view fingerprint post: {}'.format(request.POST)) if response is None: form_template = 'mail/get_fingerprint.html' form = forms.GetFingerprintForm() response = render_to_response( form_template, {'form': form}, context_instance=RequestContext(request)) return response
def add_contact_records(email_or_fingerprint, crypto_name, user_initiated_search, job_id, queue_key): ''' Add contact and associated crypto records in database. This function cannot be part of a class because it's passed to RQ which only accepts standalone functions, not functions in an instance of a class. Also, the function must be defined before the class which calls it or located in a separate file and imported. Test extreme case. >>> add_contact_records(None, None, None, None, None) False ''' result_ok = timed_out = False log_message('entered add_contact_records') try: __, email = parse_address(email_or_fingerprint) if email is None: key_id = email_or_fingerprint else: key_id = None log_message( 'adding a {} contact for {} if key retrieved by {} job'.format( crypto_name, email_or_fingerprint, job_id)) key_plugin = KeyFactory.get_crypto( crypto_name, crypto_software.get_key_classname(crypto_name)) if queue_key is None or job_id is None: result_ok = False else: MAX_WAIT = 10 * 60 # seconds queue = Queue.from_queue_key( queue_key, connection=key_plugin.get_queue_connection()) job = queue.fetch_job(job_id) # if this function is added to a queue (RQ), then it never starts # so we're going to do this the old fashion way waited = 0 while not job.is_finished and not job.is_failed and waited < MAX_WAIT: sleep(1) if job.is_failed: log_message('retrieving {} key for {} job failed'.format( crypto_name, email_or_fingerprint)) result_ok = False else: # even if the job timed out, see if the key was retrieved result_ok, timed_out, output, error = key_plugin.get_background_job_results( email_or_fingerprint, job) log_message( "results from retrieving {} key for {}, result ok: {}; timed out: {}" .format(crypto_name, email_or_fingerprint, result_ok, timed_out)) if result_ok: imported_user_ids = key_plugin.parse_keyserver_ids_retrieved( error) log_message( "imported user ids: {}".format(imported_user_ids)) if len(imported_user_ids) < 1 and error: log_message('error: {}'.format(error)) if output: log_message('output: {}'.format(output)) if result_ok: id_fingerprint_pairs = [] for user_id, imported_key_id in imported_user_ids: contact = contacts.add(user_id, crypto_name, source=KEYSERVER) result_ok = contact is not None log_message("added contact's crypto for {}: {}".format( user_id, result_ok)) if result_ok: # change the outgoing policy if needed if contact.outbound_encrypt_policy != DEFAULT_OUTBOUND_ENCRYPT_POLICY: contact.outbound_encrypt_policy = DEFAULT_OUTBOUND_ENCRYPT_POLICY contact.save() # activate the contact's crypto "after save signal" to update the fingerprint contacts_crypto = contacts.get_contacts_crypto( user_id, crypto_name) if contacts_crypto is not None: if contacts_crypto.fingerprint is None: contacts_crypto.source = KEYSERVER contacts_crypto.save() if key_id is None: fingerprint = imported_key_id else: fingerprint = key_id else: fingerprint = contacts_crypto.fingerprint elif key_id is None: fingerprint = imported_key_id else: fingerprint = key_id id_fingerprint_pairs.append( (contact.email, format_fingerprint(fingerprint))) else: log_message( 'unable to add {} contact record for {}'.format( crypto_name, user_id)) if result_ok and len(id_fingerprint_pairs) > 0: log_message('notifying {} about new keys: {}'.format( user_initiated_search, id_fingerprint_pairs)) notify_new_key_arrived(user_initiated_search, id_fingerprint_pairs) elif timed_out: log_message('timed out retrieving a {} key for {}.'.format( crypto_name, email_or_fingerprint)) else: log_message('unable to retrieve {} key for {}.'.format( crypto_name, email_or_fingerprint)) except Exception as exception: record_exception() log_message('EXCEPTION - see syr.exception.log for details') result_ok = False log_message('ended add_contact_records: {}'.format(result_ok)) return result_ok
def save(self): ''' Save the fingerprint in the database. Test extreme case. >>> set_fingerprint_class = SetFingerprint(None) >>> set_fingerprint_class.save() False ''' self.result_ok, self.crypto_name, self.email, self.key_plugin = prep_sync( self.contacts_encryption) if self.result_ok: try: # the contact's crypto record must exist or we'll get into an infinite loop # because whenever we add a contact's encryption for an email in our supported domain, # then this class is activated so we can complete the configuration if self.contacts_encryption is None: self.result_ok = False log_message('no contact encryption record for {}'.format( self.email)) else: fingerprint, expiration_date = self.key_plugin.get_fingerprint( self.email) if fingerprint is None: self.result_ok = False log_message('no {} fingerprint found for {}'.format( self.crypto_name, self.email)) else: self.result_ok = True try: fingerprint = format_fingerprint(fingerprint) if (self.contacts_encryption.fingerprint is not None and self.contacts_encryption.fingerprint != fingerprint): log_message( 'replaced old fingerprint {} with {} for {}' .format( self.contacts_encryption.fingerprint, fingerprint, self.email)) # if we created the key, then be sure it's verified if utils.email_in_domain(self.email): if self.contacts_encryption.source is None and create_private_keys( ): self.contacts_encryption.source = AUTO_GENERATED if self.contacts_encryption.source == AUTO_GENERATED: self.contacts_encryption.verified = True self.contacts_encryption.fingerprint = fingerprint self.contacts_encryption.save() log_message( 'set {} fingerprint for {} in database: {}'. format(self.crypto_name, self.email, fingerprint)) except IntegrityError as ie: self.result_ok = False if 'insert or update on table "mail_contactscrypto" violates foreign key constraint' in str( ie): log_message( '{} crypto key no longer exists for {}'. format(self.crypto_name, self.email)) else: raise except Exception as exception: record_exception() log_message('EXCEPTION - see syr.exception.log for details') self.result_ok = False return self.result_ok
def add(email, encryption_program, fingerprint=None, passcode=None, source=None): ''' Add a contact and related settings. >>> # In honor of Thomas Drake, a whistleblower about Trailblazer, a NSA mass surveillance project. >>> email = '*****@*****.**' >>> encryption_software = crypto_software.get(KeyFactory.DEFAULT_ENCRYPTION_NAME) >>> contact = add(email, KeyFactory.DEFAULT_ENCRYPTION_NAME) >>> contact.email '*****@*****.**' >>> contact.user_name 'Thomas' >>> address = contact.email >>> address = '*****@*****.**' >>> contacts_crypto = ContactsCrypto.objects.get( ... contact=contact, encryption_software=encryption_software) >>> contacts_crypto is not None True >>> x = contact.delete() >>> contact = add(None, encryption_software) >>> contact is None True >>> contact = add(email, None) >>> contact.email = '*****@*****.**' >>> contact.user_name = 'Thomas' >>> get_contacts_crypto(email) [] >>> x = contact.delete() >>> contact = add(None, None) >>> contact is None True >>> contact = add('*****@*****.**', None) >>> contact.email = '*****@*****.**' >>> contact.user_name = 'test.com domain key (system use only)' >>> x = contact.delete() ''' try: new_contact = True user_name, email_address = parse_address(email) if email_address is None: contact = None else: try: contact = Contact.objects.get(email=email_address) new_contact = False # update the user name if it's been given and it differs from the name in the DB if user_name is not None and contact.user_name != user_name: contact.user_name = user_name contact.save() log_message('updated {} user name to {}'.format(email_address, user_name)) except Contact.DoesNotExist: log_message('creating a contact for {}'.format(email_address)) try: if user_name is None or len(user_name.strip()) <= 0: from goodcrypto.mail.message.metadata import is_metadata_address user_name = email_address i = user_name.find('@') # handle domain keys specially if is_metadata_address(email_address): if i > 0: email_domain = user_name[i+1:] user_name = '{} domain key (system use only)'.format(email_domain) else: if i > 0: user_name = user_name[:i] user_name = user_name.replace('.', ' ').replace('-', ' ').replace('_', ' ') user_name = capwords(user_name) except: pass contact = Contact.objects.create(email=email_address, user_name=user_name) except Exception: record_exception() log_message('EXCEPTION - see syr.exception.log for details') contact = None if encryption_program is None: log_message("no encryption software defined so not creating contact's crytpo record for {}".format(email)) else: # add a corresponding record for the contact's crypto program encryption_software = crypto_software.get(encryption_program) if contact is None or encryption_software is None: log_message('no contact and/or encryption software defined') else: try: contacts_crypto = ContactsCrypto.objects.get( contact=contact, encryption_software=encryption_software) if (fingerprint is not None and strip_fingerprint(contacts_crypto.fingerprint) != strip_fingerprint(fingerprint)): contacts_crypto.fingerprint = format_fingerprint(fingerprint) if email_in_domain(email): if contacts.crypto.source is None: contacts.crypto.source = constants.AUTO_GENERATED if contacts_crypto.source == constants.AUTO_GENERATED: contacts_crypto.verified = True contacts_crypto.save() except ContactsCrypto.DoesNotExist: # if the contact existed without any contact crypto, but was set # to never encrypt and now we have a key, then change the # outbound encrypt policy to the default if (not new_contact and contact.outbound_encrypt_policy == constants.NEVER_ENCRYPT_OUTBOUND): contact.outbound_encrypt_policy = constants.DEFAULT_OUTBOUND_ENCRYPT_POLICY contact.save() contacts_crypto = add_contacts_crypto(contact, encryption_software, fingerprint=fingerprint, source=source) log_message("created {} crypto record for {} with {} fingerprint: {}".format( encryption_software, email, fingerprint, contacts_crypto is not None)) except: record_exception() log_message('EXCEPTION - see syr.exception.log for details') except Exception: contact = None record_exception() log_message('EXCEPTION - see syr.exception.log for details') return contact
def take_api_action(self): result = None ok, error_message = self.is_data_ok() if ok: if self.action == api_constants.CONFIGURE: mail_options = options.get_options() mail_options.domain = self.domain mail_options.mail_server_address = self.mail_server_address options.save_options(mail_options) result = self.format_result(api_constants.CONFIGURE, ok) self.log_message('configure result: {}'.format(result)) elif self.action == api_constants.CREATE_SUPERUSER: user, password, error_message = create_superuser(self.admin) if error_message is None: if password is None: result = self.format_bad_result(error_message) else: result = self.format_message_result( api_constants.CREATE_SUPERUSER, ok, password) else: result = self.format_bad_result(error_message) self.log_message('create user result: {}'.format(result)) elif self.action == api_constants.STATUS: result = self.format_result(api_constants.STATUS, get_mail_status()) self.log_message('status result: {}'.format(result)) elif self.action == api_constants.IMPORT_KEY: from goodcrypto.mail.import_key import import_key_now result_ok, status, fingerprint_ok = import_key_now( self.encryption_name, self.public_key, self.user_name, self.fingerprint, self.password) if result_ok: __, email = status.split(':') result = self.format_message_result( api_constants.IMPORT_KEY, True, email) else: result = self.format_bad_result(status) self.log_message('import key result: {}'.format(result)) elif self.action == api_constants.GET_CONTACT_LIST: email_addresses = contacts.get_contact_list( self.encryption_name) addresses = '\n'.join(email_addresses) result = self.format_message_result( api_constants.GET_CONTACT_LIST, True, addresses) self.log_message('{} {} contacts found'.format( len(email_addresses), self.encryption_name)) elif self.action == api_constants.GET_FINGERPRINT: fingerprint, verified, __ = contacts.get_fingerprint( self.email, self.encryption_name) if fingerprint is None: ok = False error_message = 'No {} fingerprint for {}'.format( self.encryption_name, self.email) result = self.format_bad_result(error_message) self.log_message('bad result: {}'.format(result)) else: message = 'Fingerprint: {} verified: {}'.format( format_fingerprint(fingerprint), verified) result = self.format_message_result( api_constants.GET_FINGERPRINT, True, message) self.log_message(message) else: ok = False error_message = 'Bad action: {}'.format(self.action) result = self.format_bad_result(error_message) self.log_message('bad action result: {}'.format(result)) else: result = self.format_bad_result(error_message) self.log_message('data is bad') return result
def take_api_action(self): result = None ok, error_message = self.is_data_ok() if ok: if self.action == api_constants.CONFIGURE: mail_options = options.get_options() mail_options.domain = self.domain mail_options.mail_server_address = self.mail_server_address options.save_options(mail_options) result = self.format_result(api_constants.CONFIGURE, ok) self.log_message('configure result: {}'.format(result)) elif self.action == api_constants.CREATE_SUPERUSER: user, password, error_message = create_superuser(self.admin) if error_message is None: if password is None: result = self.format_bad_result(error_message) else: result = self.format_message_result(api_constants.CREATE_SUPERUSER, ok, password) else: result = self.format_bad_result(error_message) self.log_message('create user result: {}'.format(result)) elif self.action == api_constants.STATUS: result = self.format_result(api_constants.STATUS, get_mail_status()) self.log_message('status result: {}'.format(result)) elif self.action == api_constants.IMPORT_KEY: from goodcrypto.mail.import_key import import_key_now result_ok, status, fingerprint_ok = import_key_now( self.encryption_name, self.public_key, self.user_name, self.fingerprint, self.password) if result_ok: __, email = status.split(':') result = self.format_message_result(api_constants.IMPORT_KEY, True, email) else: result = self.format_bad_result(status) self.log_message('import key result: {}'.format(result)) elif self.action == api_constants.GET_CONTACT_LIST: email_addresses = contacts.get_contact_list(self.encryption_name) addresses = '\n'.join(email_addresses) result = self.format_message_result(api_constants.GET_CONTACT_LIST, True, addresses) self.log_message('{} {} contacts found'.format(len(email_addresses), self.encryption_name)) elif self.action == api_constants.GET_FINGERPRINT: fingerprint, verified, __ = contacts.get_fingerprint(self.email, self.encryption_name) if fingerprint is None: ok = False error_message = 'No {} fingerprint for {}'.format(self.encryption_name, self.email) result = self.format_bad_result(error_message) self.log_message('bad result: {}'.format(result)) else: message = 'Fingerprint: {} verified: {}'.format(format_fingerprint(fingerprint), verified) result = self.format_message_result(api_constants.GET_FINGERPRINT, True, message) self.log_message(message) else: ok = False error_message = 'Bad action: {}'.format(self.action) result = self.format_bad_result(error_message) self.log_message('bad action result: {}'.format(result)) else: result = self.format_bad_result(error_message) self.log_message('data is bad') return result
def add(email, encryption_program, fingerprint=None, passcode=None, source=None): ''' Add a contact and related settings. >>> # In honor of Thomas Drake, a whistleblower about Trailblazer, a NSA mass surveillance project. >>> email = '*****@*****.**' >>> encryption_software = crypto_software.get(KeyFactory.DEFAULT_ENCRYPTION_NAME) >>> contact = add(email, KeyFactory.DEFAULT_ENCRYPTION_NAME) >>> contact.email '*****@*****.**' >>> contact.user_name 'Thomas' >>> address = contact.email >>> address = '*****@*****.**' >>> contacts_crypto = ContactsCrypto.objects.get( ... contact=contact, encryption_software=encryption_software) >>> contacts_crypto is not None True >>> x = contact.delete() >>> contact = add(None, encryption_software) >>> contact is None True >>> contact = add(email, None) >>> contact.email = '*****@*****.**' >>> contact.user_name = 'Thomas' >>> get_contacts_crypto(email) [] >>> x = contact.delete() >>> contact = add(None, None) >>> contact is None True >>> contact = add('*****@*****.**', None) >>> contact.email = '*****@*****.**' >>> contact.user_name = 'test.com domain key (system use only)' >>> x = contact.delete() ''' try: new_contact = True user_name, email_address = parse_address(email) if email_address is None: contact = None else: try: contact = Contact.objects.get(email=email_address) new_contact = False # update the user name if it's been given and it differs from the name in the DB if user_name is not None and contact.user_name != user_name: contact.user_name = user_name contact.save() log_message('updated {} user name to {}'.format( email_address, user_name)) except Contact.DoesNotExist: log_message('creating a contact for {}'.format(email_address)) try: if user_name is None or len(user_name.strip()) <= 0: from goodcrypto.mail.message.metadata import is_metadata_address user_name = email_address i = user_name.find('@') # handle domain keys specially if is_metadata_address(email_address): if i > 0: email_domain = user_name[i + 1:] user_name = '{} domain key (system use only)'.format( email_domain) else: if i > 0: user_name = user_name[:i] user_name = user_name.replace('.', ' ').replace( '-', ' ').replace('_', ' ') user_name = capwords(user_name) except: pass contact = Contact.objects.create(email=email_address, user_name=user_name) except Exception: record_exception() log_message('EXCEPTION - see syr.exception.log for details') contact = None if encryption_program is None: log_message( "no encryption software defined so not creating contact's crytpo record for {}" .format(email)) else: # add a corresponding record for the contact's crypto program encryption_software = crypto_software.get(encryption_program) if contact is None or encryption_software is None: log_message('no contact and/or encryption software defined') else: try: contacts_crypto = ContactsCrypto.objects.get( contact=contact, encryption_software=encryption_software) if (fingerprint is not None and strip_fingerprint(contacts_crypto.fingerprint) != strip_fingerprint(fingerprint)): contacts_crypto.fingerprint = format_fingerprint( fingerprint) if email_in_domain(email): if contacts.crypto.source is None: contacts.crypto.source = constants.AUTO_GENERATED if contacts_crypto.source == constants.AUTO_GENERATED: contacts_crypto.verified = True contacts_crypto.save() except ContactsCrypto.DoesNotExist: # if the contact existed without any contact crypto, but was set # to never encrypt and now we have a key, then change the # outbound encrypt policy to the default if (not new_contact and contact.outbound_encrypt_policy == constants.NEVER_ENCRYPT_OUTBOUND): contact.outbound_encrypt_policy = constants.DEFAULT_OUTBOUND_ENCRYPT_POLICY contact.save() contacts_crypto = add_contacts_crypto( contact, encryption_software, fingerprint=fingerprint, source=source) log_message( "created {} crypto record for {} with {} fingerprint: {}" .format(encryption_software, email, fingerprint, contacts_crypto is not None)) except: record_exception() log_message( 'EXCEPTION - see syr.exception.log for details') except Exception: contact = None record_exception() log_message('EXCEPTION - see syr.exception.log for details') return contact