Esempio n. 1
0
    def import_key(email, encryption_name, public_key, id_fingerprint_pairs,
                   plugin):
        ''' Import the key and return the fingerprint. '''

        status = fingerprint = None
        result_ok = False

        # make sure the email address is in the key
        for (user_id, fingerprint) in id_fingerprint_pairs:
            user_name, email_address = parse_address(email)
            key_address = get_email(user_id)
            if email_address.lower() == key_address.lower():
                result_ok = True
                break

        if result_ok:
            status = ''
            for (user_id, fingerprint) in id_fingerprint_pairs:
                result_ok = plugin.import_public(public_key,
                                                 id_fingerprint_pairs)
                if result_ok:
                    status += '{}\n'.format(
                        i18n(
                            'Imported key successfully. Fingerprint: {fingerprint}'
                            .format(fingerprint=fingerprint)))
                else:
                    status += '{}\n'.format(i18n('Unable to import key'))
        else:
            status = i18n(
                "Cannot import the key because it isn't for {email}".format(
                    email=email))

        return result_ok, status
Esempio n. 2
0
    def clean(self):
        '''Verify there is only 1 general info record.'''

        error_message = None
        cleaned_data = super(ImportKeyFromKeyserverForm, self).clean()

        email_or_fingerprint = cleaned_data.get('email_or_fingerprint')
        __, email = parse_address(email_or_fingerprint)
        if email is None:
            fingerprint = strip_fingerprint(email_or_fingerprint)
            m = re.match('^[0-9A-Fa-f]+$', fingerprint)
            if m:
                if len(fingerprint) < 16:
                    error_message = i18n(
                        'Either enter a valid email address or a fingerprint that is least 16 characters'
                    )
            else:
                error_message = i18n(
                    'Either enter a valid email address or a fingerprint which must contain only numbers and the letters A through F.'
                )

            if error_message is not None:
                _log.write(error_message)
                raise forms.ValidationError(error_message, code='invalid')

        return cleaned_data
Esempio n. 3
0
    def import_key(email, encryption_name, public_key, id_fingerprint_pairs, plugin):
        ''' Import the key and return the fingerprint. '''

        status = fingerprint = None
        result_ok = False

        # make sure the email address is in the key
        for (user_id, fingerprint) in id_fingerprint_pairs:
            user_name, email_address = parse_address(email)
            key_address = get_email(user_id)
            if email_address.lower() == key_address.lower():
                result_ok = True
                break

        if result_ok:
            status = ''
            for (user_id, fingerprint) in id_fingerprint_pairs:
                result_ok = plugin.import_public(public_key, id_fingerprint_pairs)
                if result_ok:
                    status += '{}\n'.format(i18n('Imported key successfully. Fingerprint: {fingerprint}'.format(
                        fingerprint=fingerprint)))
                else:
                    status += '{}\n'.format(i18n('Unable to import key'))
        else:
            status = i18n("Cannot import the key because it isn't for {email}".format(email=email))

        return result_ok, status
Esempio n. 4
0
    def manage_keys_in_header(self, crypto_message):
        '''
            Manage all the public keys in the message's header.
        '''
        header_contains_key_info = False
        try:
            from_user = crypto_message.smtp_sender()
            self.recipient_to_notify = crypto_message.smtp_recipient()
            # all notices about a metadata address goes to the admin
            if is_metadata_address(self.recipient_to_notify):
                self.recipient_to_notify = get_admin_email()

            name, address = parse_address(from_user)
            if address is None or crypto_message is None or crypto_message.get_email_message() is None:
                self.log_message('missing data so cannot import key')
                self.log_message('   from user: {}'.format(from_user))
                self.log_message('   address: {}'.format(address))
                self.log_message('   crypto message: {}'.format(crypto_message))
                if crypto_message is not None: self.log_message('   email message: {}'.format(crypto_message.get_email_message()))
            else:
                accepted_crypto_packages = crypto_message.get_accepted_crypto_software()
                if accepted_crypto_packages is None or len(accepted_crypto_packages) <= 0:
                    self.log_message("checking for default key for {} <{}>".format(name, address))
                    tag = self._manage_key_header(address, crypto_message,
                       KeyFactory.get_default_encryption_name(), PUBLIC_KEY_HEADER)
                else:
                    self.log_message("checking for {} keys".format(accepted_crypto_packages))
                    for encryption_name in accepted_crypto_packages:
                        # see if there's a the key block for this encryption program
                        header_name = get_public_key_header_name(encryption_name)
                        key_block = get_multientry_header(
                          crypto_message.get_email_message().get_message(), header_name)
                        # see if there's a plain key block
                        if ((key_block is None or len(key_block) <= 0) and
                            len(accepted_crypto_packages) == 1):
                            self.log_message("no {} public key in header so trying generic header".format(encryption_name))
                            key_block = get_multientry_header(
                              crypto_message.get_email_message().get_message(), PUBLIC_KEY_HEADER)

                        tag = self._manage_key_header(
                          address, crypto_message, encryption_name, key_block)
                    header_contains_key_info = True
                    self.update_accepted_crypto(from_user, accepted_crypto_packages)

        except MessageException as message_exception:
            self.log_message(message_exception.value)
            raise MessageException(value=message_exception.value)

        except:
            record_exception()
            self.log_message('EXCEPTION - see syr.exception.log for details')
            if crypto_message is not None:
                crypto_message.add_error_tag_once(self.UNEXPECTED_ERROR)

        self.log_message('header_contains_key_info: {}'.format(header_contains_key_info))

        return header_contains_key_info
Esempio n. 5
0
def import_key_from_keyserver(request, form):
    ''' Import a key from a keyserver, if found. '''

    MISSING_USER_EMAIL_ERROR = i18n(
      'Unable to search for keys. Searches can take a long time so when the search finds a key, you would receive an email message.<p>Your User account does not have an email address defined so searches cannot be performed. Contact your mail administrator and request they enter your email address in your User account.')
    UNEXPECTED_START_SEARCH_ERROR = i18n('An unexpected error was detected when starting search for the key. Contact your mail administrator.')
    NO_ACTIVE_KEYSERVERS_ERROR = i18n('Unable to search for key because there are no active keyservers. Contact your mail administrator.')
    UNEXPECTED_SEARCH_ERROR = i18n('Unexpected error while starting search for key. Contact your mail administrator.')

    response = status = None
    try:
        log_message('searching for key on keyservers and importing if found')

        email_or_fingerprint = form.cleaned_data['email_or_fingerprint']
        encryption_software = form.cleaned_data['encryption_software']

        user_requesting_search = request.user.email
        if user_requesting_search is None or len(user_requesting_search) <= 0:
            status = MISSING_USER_EMAIL_ERROR
        else:
            max_wait_time = len(get_active_keyservers(KeyFactory.DEFAULT_ENCRYPTION_NAME)) * 5 * 60
            if max_wait_time > 0:
                __, email = parse_address(email_or_fingerprint)
                if email is None:
                    fingerprint = email_or_fingerprint
                    result_ok = queue_keyserver_retrieval(
                      fingerprint, encryption_software.name, user_requesting_search)
                    log_message('started retrieving key using {} key id'.format(fingerprint))
                else:
                    result_ok = queue_keyserver_search(
                      email, user_requesting_search, interactive=True)
                    log_message('started searching for key for {}'.format(email))

                if result_ok:
                    page_title = i18n("Starting search for Key")
                    data = {'page_title': page_title,
                            'status': 'Searches can take a long time. You will receive email with the results.'}
                    template = 'mail/import_from_keyserver_results.html'
                else:
                    status = UNEXPECTED_START_SEARCH_ERROR
            else:
                status = NO_ACTIVE_KEYSERVERS_ERROR
    except:
        status = UNEXPECTED_SEARCH_ERROR
        record_exception()

    if status is not None:
        page_title = i18n("Import Key From Keyserver Error")
        data = {'page_title': page_title,
                'result': status}
        template = 'mail/key_error_results.html'
        log_message(status)

    response = render_to_response(template, data, context_instance=RequestContext(request))

    return response
def make_key(line, domain, crypto_name):
    ''' Make a private key if its in the domain.'''

    user_name, email = parse_address(line)
    if email is None:
        print('{} is not a valid email address'.format(line))
    elif email_in_domain(email):
        if user_name is None or len(user_name.strip()) <= 0:
            full_address = email
        else:
            full_address = '{} <{}>'.format(user_name, email)
        contacts.add(full_address, crypto_name, source=AUTO_GENERATED)
    else:
        print('{} not in the domain: {}'.format(line, domain))
Esempio n. 7
0
def make_key(line, domain, crypto_name):
    ''' Make a private key if its in the domain.'''

    user_name, email = parse_address(line)
    if email is None:
        print('{} is not a valid email address'.format(line))
    elif email_in_domain(email):
        if user_name is None or len(user_name.strip()) <= 0:
            full_address = email
        else:
            full_address = '{} <{}>'.format(user_name, email)
        contacts.add(full_address, crypto_name, source=AUTO_GENERATED)
    else:
        print('{} not in the domain: {}'.format(line, domain))
Esempio n. 8
0
def delete(email_or_address):
    '''
        Delete the contact with a matching email address.

        >>> # In honor of Amy Goodman, who hosts Democracy Now!
        # returns true because the address doesn't exist, even though it wasn't necessary to delete it.
        >>> delete('*****@*****.**')
        True

        # test the extreme cases
        >>> delete(None)
        False
    '''

    result_ok = True
    try:
        if is_string(email_or_address):
            name, address = parse_address(email_or_address)
            contact = get(address)
            if contact is None:
                log_message('no {} <{}> contact to delete'.format(
                    name, address))
            else:
                contact.delete()
                log_message("deleted {}".format(contact.email))
        elif email_or_address is None:
            result_ok = False
        elif isinstance(email_or_address, Contact):
            contact = email_or_address
            contact.delete()
            log_message("deleted {}".format(contact.email))
        else:
            result_ok = False
            log_message(
                "unable to delete contact because wront type: {}".format(
                    type(email_or_address)))

    except Exception:
        result_ok = False
        record_exception()
        log_message('EXCEPTION - see syr.exception.log for details')

    return result_ok
Esempio n. 9
0
def exists(email):
    '''
        Determine if the contact exists already.

        Test an unknown email address so we're sure of the result.
        See the unittest to understand how to really use this function.

        >>> # In honor of Thomas Tamm, who was a whistleblower to the NY Times about senior
        >>> # Justice officials fight against the widening scope of warrantless NSA surveillance.
        >>> exists('*****@*****.**')
        False
    '''

    name, address = parse_address(email)
    contact = get(address)
    found = contact is not None and contact.email == address
    log_message("{} <{}> contact exists: {}".format(name, address, found))

    return found
Esempio n. 10
0
def exists(email):
    '''
        Determine if the contact exists already.

        Test an unknown email address so we're sure of the result.
        See the unittest to understand how to really use this function.

        >>> # In honor of Thomas Tamm, who was a whistleblower to the NY Times about senior
        >>> # Justice officials fight against the widening scope of warrantless NSA surveillance.
        >>> exists('*****@*****.**')
        False
    '''

    name, address = parse_address(email)
    contact = get(address)
    found = contact is not None and contact.email == address
    log_message("{} <{}> contact exists: {}".format(name, address, found))

    return found
Esempio n. 11
0
def delete(email_or_address):
    '''
        Delete the contact with a matching email address.

        >>> # In honor of Amy Goodman, who hosts Democracy Now!
        # returns true because the address doesn't exist, even though it wasn't necessary to delete it.
        >>> delete('*****@*****.**')
        True

        # test the extreme cases
        >>> delete(None)
        False
    '''

    result_ok = True
    try:
        if is_string(email_or_address):
            name, address = parse_address(email_or_address)
            contact = get(address)
            if contact is None:
                log_message('no {} <{}> contact to delete'.format(name, address))
            else:
                contact.delete()
                log_message("deleted {}".format(contact.email))
        elif email_or_address is None:
            result_ok = False
        elif isinstance(email_or_address, Contact):
            contact = email_or_address
            contact.delete()
            log_message("deleted {}".format(contact.email))
        else:
            result_ok = False
            log_message("unable to delete contact because wront type: {}".format(type(email_or_address)))

    except Exception:
        result_ok = False
        record_exception()
        log_message('EXCEPTION - see syr.exception.log for details')

    return result_ok
Esempio n. 12
0
    def manage_keys_in_header(self, crypto_message):
        '''
            Manage all the public keys in the message's header.
        '''
        header_contains_key_info = False
        try:
            from_user = crypto_message.smtp_sender()
            self.recipient_to_notify = crypto_message.smtp_recipient()
            # all notices about a metadata address goes to the admin
            if is_metadata_address(self.recipient_to_notify):
                self.recipient_to_notify = get_admin_email()

            name, address = parse_address(from_user)
            if address is None or crypto_message is None or crypto_message.get_email_message(
            ) is None:
                self.log_message('missing data so cannot import key')
                self.log_message('   from user: {}'.format(from_user))
                self.log_message('   address: {}'.format(address))
                self.log_message(
                    '   crypto message: {}'.format(crypto_message))
                if crypto_message is not None:
                    self.log_message('   email message: {}'.format(
                        crypto_message.get_email_message()))
            else:
                accepted_crypto_packages = crypto_message.get_accepted_crypto_software(
                )
                if accepted_crypto_packages is None or len(
                        accepted_crypto_packages) <= 0:
                    self.log_message(
                        "checking for default key for {} <{}>".format(
                            name, address))
                    tag = self._manage_key_header(
                        address, crypto_message,
                        KeyFactory.get_default_encryption_name(),
                        PUBLIC_KEY_HEADER)
                else:
                    self.log_message("checking for {} keys".format(
                        accepted_crypto_packages))
                    for encryption_name in accepted_crypto_packages:
                        # see if there's a the key block for this encryption program
                        header_name = get_public_key_header_name(
                            encryption_name)
                        key_block = get_multientry_header(
                            crypto_message.get_email_message().get_message(),
                            header_name)
                        # see if there's a plain key block
                        if ((key_block is None or len(key_block) <= 0)
                                and len(accepted_crypto_packages) == 1):
                            self.log_message(
                                "no {} public key in header so trying generic header"
                                .format(encryption_name))
                            key_block = get_multientry_header(
                                crypto_message.get_email_message().get_message(
                                ), PUBLIC_KEY_HEADER)

                        tag = self._manage_key_header(address, crypto_message,
                                                      encryption_name,
                                                      key_block)
                    header_contains_key_info = True
                    self.update_accepted_crypto(from_user,
                                                accepted_crypto_packages)

        except MessageException as message_exception:
            self.log_message(message_exception.value)
            raise MessageException(value=message_exception.value)

        except:
            record_exception()
            self.log_message('EXCEPTION - see syr.exception.log for details')
            if crypto_message is not None:
                crypto_message.add_error_tag_once(self.UNEXPECTED_ERROR)

        self.log_message(
            'header_contains_key_info: {}'.format(header_contains_key_info))

        return header_contains_key_info
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
Esempio n. 14
0
def import_key_from_keyserver(request, form):
    ''' Import a key from a keyserver, if found. '''

    MISSING_USER_EMAIL_ERROR = i18n(
        'Unable to search for keys. Searches can take a long time so when the search finds a key, you would receive an email message.<p>Your User account does not have an email address defined so searches cannot be performed. Contact your mail administrator and request they enter your email address in your User account.'
    )
    UNEXPECTED_START_SEARCH_ERROR = i18n(
        'An unexpected error was detected when starting search for the key. Contact your mail administrator.'
    )
    NO_ACTIVE_KEYSERVERS_ERROR = i18n(
        'Unable to search for key because there are no active keyservers. Contact your mail administrator.'
    )
    UNEXPECTED_SEARCH_ERROR = i18n(
        'Unexpected error while starting search for key. Contact your mail administrator.'
    )

    response = status = None
    try:
        log_message('searching for key on keyservers and importing if found')

        email_or_fingerprint = form.cleaned_data['email_or_fingerprint']
        encryption_software = form.cleaned_data['encryption_software']

        user_requesting_search = request.user.email
        if user_requesting_search is None or len(user_requesting_search) <= 0:
            status = MISSING_USER_EMAIL_ERROR
        else:
            max_wait_time = len(
                get_active_keyservers(
                    KeyFactory.DEFAULT_ENCRYPTION_NAME)) * 5 * 60
            if max_wait_time > 0:
                __, email = parse_address(email_or_fingerprint)
                if email is None:
                    fingerprint = email_or_fingerprint
                    result_ok = queue_keyserver_retrieval(
                        fingerprint, encryption_software.name,
                        user_requesting_search)
                    log_message(
                        'started retrieving key using {} key id'.format(
                            fingerprint))
                else:
                    result_ok = queue_keyserver_search(email,
                                                       user_requesting_search,
                                                       interactive=True)
                    log_message(
                        'started searching for key for {}'.format(email))

                if result_ok:
                    page_title = i18n("Starting search for Key")
                    data = {
                        'page_title':
                        page_title,
                        'status':
                        'Searches can take a long time. You will receive email with the results.'
                    }
                    template = 'mail/import_from_keyserver_results.html'
                else:
                    status = UNEXPECTED_START_SEARCH_ERROR
            else:
                status = NO_ACTIVE_KEYSERVERS_ERROR
    except:
        status = UNEXPECTED_SEARCH_ERROR
        record_exception()

    if status is not None:
        page_title = i18n("Import Key From Keyserver Error")
        data = {'page_title': page_title, 'result': status}
        template = 'mail/key_error_results.html'
        log_message(status)

    response = render_to_response(template,
                                  data,
                                  context_instance=RequestContext(request))

    return response
Esempio n. 15
0
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
Esempio n. 16
0
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
Esempio n. 17
0
    def create(self, user_id, passcode, expiration=None, wait_for_results=False):
        '''
            Create a new key. If wait_for_results is False, then start the process, but
            don't wait for the results.

            If the key already exists and hasn't expired, then return True without creating a new key.
            If key generated while waiting or key generation started successfully when not waiting,
            then return True; otherwise, False.

            >>> # In honor of Moritz Bartl, advocate for the Tor project.
            >>> from goodcrypto.oce.key.key_factory import KeyFactory
            >>> plugin = KeyFactory.get_crypto(gpg_key_constants.NAME)
            >>> plugin.create('*****@*****.**', 'a secret code')
            (True, False, None, False)

            >>> # In honor of Roger Dingledine, one of the original developers of the Tor project.
            >>> from goodcrypto.oce.key.constants import EXPIRES_IN, EXPIRATION_UNIT
            >>> from goodcrypto.oce.key.key_factory import KeyFactory
            >>> email = '*****@*****.**'
            >>> plugin = KeyFactory.get_crypto(gpg_key_constants.NAME)
            >>> plugin.create(email, 'a secret code', wait_for_results=True)
            (True, False, None, False)
            >>> while not plugin.private_key_exists(email):
            ...     sleep(10)
            >>> plugin.private_key_exists(email)
            True
            >>> encrypted_data, __ = plugin.encrypt_and_armor('Test data', email)
            >>> unencrypted_data, signed_by, result_code = plugin.decrypt(encrypted_data, 'a secret code')
            >>> result_code == gpg_constants.GOOD_RESULT
            True
            >>> unencrypted_data, signed_by, result_code = plugin.decrypt(encrypted_data, 'another code')
            >>> result_code == gpg_constants.ERROR_RESULT
            True
            >>> plugin.create(email, 'another code', wait_for_results=True)
            (True, False, None, True)
            >>> plugin.delete(email)
            True
        '''

        result_code = gpg_constants.ERROR_RESULT
        result_ok = timed_out = key_already_exists = False
        fingerprint = None
        try:
            self.log_message('gen key for {} that expires within {}'.format(user_id, expiration))

            name, email = parse_address(user_id)
            # gpg requires "real names" be at least 5 characters long
            if name == None or len(name) <= 4:
                index = email.find('@')
                if index > 0:
                    name = email[:index].capitalize()
                else:
                    name = email
                if len(name) <= 4:
                    name = email

            expires_in, expiration_unit = gpg_utils.get_standardized_expiration(expiration)

            data = ''
            data += '{}{}{}'.format(gpg_constants.KEY_TYPE, self.DefaultKeyType, gpg_constants.EOL)
            data += '{}{}{}'.format(gpg_constants.KEY_LENGTH, self.DefaultKeyLength, gpg_constants.EOL)
            data += '{}{}{}'.format(gpg_constants.SUBKEY_TYPE, self.DefaultSubkeyType, gpg_constants.EOL)
            data += '{}{}{}'.format(gpg_constants.SUBKEY_LENGTH, self.DefaultKeyLength, gpg_constants.EOL)
            data += '{}{}{}{}'.format(gpg_constants.EXPIRE_DATE, expires_in, expiration_unit, gpg_constants.EOL)
            data += '{}{}{}'.format(gpg_constants.KEY_PASSPHRASE, passcode, gpg_constants.EOL)
            data += '{}{}{}'.format(gpg_constants.NAME_REAL, name, gpg_constants.EOL)
            data += '{}{}{}'.format(gpg_constants.NAME_EMAIL, email, gpg_constants.EOL)
            data += '{}{}'.format(gpg_constants.COMMIT_KEY, gpg_constants.EOL)

            if GPGPlugin.DEBUGGING:
                self.log_message('Name-Real: {}'.format(name))
                self.log_message('Name-Email: {}'.format(email))
                self.log_message('Expire-Date: {}{}'.format(expires_in, expiration_unit))

            result_code, gpg_output, gpg_error = self.gpg_command(
                [gpg_constants.GEN_KEY], data=data, wait_for_results=wait_for_results)

            if result_code == gpg_constants.GOOD_RESULT:
                fingerprint = gpg_utils.parse_gen_key_results(gpg_error)
                if fingerprint is None:
                    if gpg_output: self.log_message(gpg_output)
                    if gpg_error: self.log_message(gpg_error)

                if gpg_output == gpg_constants.KEY_EXISTS:
                    key_already_exists = True
                    self.log_message('key already exists for {}'.format(email))
            else:
                self.log_message('created key for {} <{}>: {} result code'.format(name, email, result_code))
                if gpg_output: self.log_message(gpg_output)
                if gpg_error: self.log_message(gpg_error)

            result_ok = result_code == gpg_constants.GOOD_RESULT
            self.log_message('result ok: {}'.format(result_ok))
            timed_out = result_code == gpg_constants.TIMED_OUT_RESULT
            self.log_message('timedout: {}'.format(timed_out))

        except Exception as exception:
            self.handle_unexpected_exception(exception)
        finally:
            self.log_message('finished starting to gen key for {}'.format(user_id))

        return result_ok, timed_out, fingerprint, key_already_exists
Esempio n. 18
0
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