Пример #1
0
    def update_accepted_crypto(self, email, encryption_software_list):
        ''' Update the list of encryption software accepted by user.
        '''

        if email is None:
            self.log_message("email not defined so no need to update accepted crypto")
        elif encryption_software_list is None or len(encryption_software_list) <= 0:
            self.log_message('no encryption programs defined for {}'.format(email))
        else:
            contact = contacts.get(email)
            if contact is None:
                # if the contact doesn't exist, then add them with the first encryption program
                encryption_program = encryption_software_list[0]
                contact = contacts.add(email, encryption_program, source=MESSAGE_HEADER)
                self.log_message("added {} to contacts".format(email))

            # associate each encryption program in the list with this contact
            for encryption_program in encryption_software_list:
                try:
                    contacts_crypto = contacts.get_contacts_crypto(email, encryption_program)
                    if contacts_crypto is None:
                        encryption_software = crypto_software.get(encryption_program)
                        if encryption_software is None:
                            self.log_message('{} encryption software unknown'.format(encryption_program))
                            self.log_message(
                              'unable to add contacts crypt for {} using {} encryption software unknown'.format(email, encryption_program))
                        else:
                            contacts_crypto = contacts.add_contacts_crypto(
                               contact=contact, encryption_software=encryption_software, source=MESSAGE_HEADER)
                except Exception:
                    record_exception()
                    self.log_message('EXCEPTION - see syr.exception.log for details')
Пример #2
0
def import_all_keys(parent_dir, extension, crypto_name):

    crypto = crypto_software.get(crypto_name)
    filenames = os.listdir(parent_dir)
    for filename in filenames:
        if filename.endswith(extension):
            email = filename[:len(filename) - len(extension)]
            with open(os.path.join(parent_dir, filename), 'rt') as f:
                public_key = f.read()
                result_ok, status = import_crypto_key(email, crypto,
                                                      public_key)
                if not result_ok:
                    print(status)
def prep_sync(contacts_crypto):
    '''
        Prepare to sync database and crypto keys.

        Test extreme case.
        >>> prep_sync(None)
        (False, None, None, None)
    '''

    result_ok = True
    crypto_name = email = key_plugin = None
    try:
        if contacts_crypto is None:
            result_ok = False
            log_message('contacts crypto not defined')
        else:
            crypto_name = contacts_crypto.encryption_software.name
            email = contacts_crypto.contact.email

            log_message('preparing to sync db and {} keyring for {}'.format(
                crypto_name, email))
            crypto_record = crypto_software.get(
                contacts_crypto.encryption_software)
            if crypto_record is None:
                result_ok = False
                log_message('{} encryption not defined in database'.format(
                    crypto_name))
            elif not crypto_record.active:
                result_ok = False
                log_message('{} encryption is not active'.format(crypto_name))
            else:
                key_plugin = KeyFactory.get_crypto(
                    crypto_name,
                    crypto_software.get_key_classname(crypto_name))
                result_ok = key_plugin is not None
                if not result_ok:
                    log_message('key plugin not defined'.format(crypto_name))
    except:
        log_message('{} had an unexpected error'.format(contacts_crypto))
        record_exception()
        log_message('EXCEPTION - see syr.exception.log for details')
        result_ok = False

    log_message(
        'finished preparing to sync db and keyring for {}'.format(email))

    return result_ok, crypto_name, email, key_plugin
Пример #4
0
    def update_accepted_crypto(self, email, encryption_software_list):
        ''' Update the list of encryption software accepted by user.
        '''

        if email is None:
            self.log_message(
                "email not defined so no need to update accepted crypto")
        elif encryption_software_list is None or len(
                encryption_software_list) <= 0:
            self.log_message(
                'no encryption programs defined for {}'.format(email))
        else:
            contact = contacts.get(email)
            if contact is None:
                # if the contact doesn't exist, then add them with the first encryption program
                encryption_program = encryption_software_list[0]
                contact = contacts.add(email,
                                       encryption_program,
                                       source=MESSAGE_HEADER)
                self.log_message("added {} to contacts".format(email))

            # associate each encryption program in the list with this contact
            for encryption_program in encryption_software_list:
                try:
                    contacts_crypto = contacts.get_contacts_crypto(
                        email, encryption_program)
                    if contacts_crypto is None:
                        encryption_software = crypto_software.get(
                            encryption_program)
                        if encryption_software is None:
                            self.log_message(
                                '{} encryption software unknown'.format(
                                    encryption_program))
                            self.log_message(
                                'unable to add contacts crypt for {} using {} encryption software unknown'
                                .format(email, encryption_program))
                        else:
                            contacts_crypto = contacts.add_contacts_crypto(
                                contact=contact,
                                encryption_software=encryption_software,
                                source=MESSAGE_HEADER)
                except Exception:
                    record_exception()
                    self.log_message(
                        'EXCEPTION - see syr.exception.log for details')
def prep_sync(contacts_crypto):
    '''
        Prepare to sync database and crypto keys.

        Test extreme case.
        >>> prep_sync(None)
        (False, None, None, None)
    '''

    result_ok = True
    crypto_name = email = key_plugin = None
    try:
        if contacts_crypto is None:
            result_ok = False
            log_message('contacts crypto not defined')
        else:
            crypto_name = contacts_crypto.encryption_software.name
            email = contacts_crypto.contact.email

            log_message('preparing to sync db and {} keyring for {}'.format(crypto_name, email))
            crypto_record = crypto_software.get(contacts_crypto.encryption_software)
            if crypto_record is None:
                result_ok = False
                log_message('{} encryption not defined in database'.format(crypto_name))
            elif not crypto_record.active:
                result_ok = False
                log_message('{} encryption is not active'.format(crypto_name))
            else:
                key_plugin = KeyFactory.get_crypto(
                    crypto_name, crypto_software.get_key_classname(crypto_name))
                result_ok = key_plugin is not None
                if not result_ok:
                    log_message('key plugin not defined'.format(crypto_name))
    except:
        log_message('{} had an unexpected error'.format(contacts_crypto))
        record_exception()
        log_message('EXCEPTION - see syr.exception.log for details')
        result_ok = False

    log_message('finished preparing to sync db and keyring for {}'.format(email))

    return result_ok, crypto_name, email, key_plugin
def main(argv):
    # set the defaults
    crypto_name = CryptoFactory.DEFAULT_ENCRYPTION_NAME

    # use the args passed on the command line
    if argv and len(argv) >= 1:
        pathname = argv[0]
        if len(argv) >= 2:
            crypto_name = argv[1]

        crypto = crypto_software.get(crypto_name)
        if crypto is None:
            print('{} encryption not defined in database'.format(crypto_name))
        else:
            domain = get_domain()
            with open(pathname, 'rt') as f:
                lines = f.readlines()
                for line in lines:
                    if len(line.strip()) > 0 and not line.startswith('#'):
                        make_key(line, domain, crypto_name)
    else:
        print_usage()
Пример #7
0
def main(argv):
    # set the defaults
    crypto_name = CryptoFactory.DEFAULT_ENCRYPTION_NAME

    # use the args passed on the command line
    if argv and len(argv) >= 1:
        pathname = argv[0]
        if len(argv) >= 2:
            crypto_name = argv[1]

        crypto = crypto_software.get(crypto_name)
        if crypto is None:
            print('{} encryption not defined in database'.format(crypto_name))
        else:
            domain = get_domain()
            with open(pathname, 'rt') as f:
                lines = f.readlines()
                for line in lines:
                    if len(line.strip()) > 0 and not line.startswith('#'):
                        make_key(line, domain, crypto_name)
    else:
        print_usage()
Пример #8
0
def main(argv):
    # set the defaults
    crypto_name = CryptoFactory.DEFAULT_ENCRYPTION_NAME
    parent_dir = '/var/local/projects/goodcrypto/server/data/oce/pubkeys'

    # use the args passed on the command line
    if argv and len(argv) >= 1:
        parent_dir = argv[0]
        if len(argv) >= 2:
            crypto_name = argv[1]

    if not os.path.exists(parent_dir):
        os.makedirs(parent_dir)

    domain = get_domain()

    gpg_crypto = crypto_software.get(crypto_name)
    contacts = Contact.objects.filter(email__iendswith=domain)
    for contact in contacts:
        email = contact.email
        public_key = get_public_key(email, gpg_crypto)
        filename = os.path.join(parent_dir, email + '.asc')
        with open(filename, 'wt') as f:
            f.write(public_key)
def main(argv):
    # set the defaults
    crypto_name = CryptoFactory.DEFAULT_ENCRYPTION_NAME
    parent_dir = '/var/local/projects/goodcrypto/server/data/oce/pubkeys'

    # use the args passed on the command line
    if argv and len(argv) >= 1:
        parent_dir = argv[0]
        if len(argv) >= 2:
            crypto_name = argv[1]

    if not os.path.exists(parent_dir):
        os.makedirs(parent_dir)

    domain = get_domain()

    gpg_crypto = crypto_software.get(crypto_name)
    contacts = Contact.objects.filter(email__iendswith=domain)
    for contact in contacts:
        email = contact.email
        public_key = get_public_key(email, gpg_crypto)
        filename = os.path.join(parent_dir, email + '.asc')
        with open(filename, 'wt') as f:
            f.write(public_key)
Пример #10
0
def import_key_now(encryption_name, keyblock, user_name, possible_fingerprint, passcode):
    ''' Import if key is ok and doesn't exist. '''

    fingerprint_ok = True
    id_fingerprint_pairs = []

    if encryption_name is None or keyblock is None:
        result_ok = False
        fingerprint_ok = False
        status = MISSING_DATA_STATUS
        log_message('crypto: {} / keyblock is None: {}'.format(
           encryption_name, keyblock is None))
    else:
        encryption_software = crypto_software.get(encryption_name)
        plugin = KeyFactory.get_crypto(encryption_software.name, encryption_software.classname)
        if plugin is None:
            result_ok = False
            status = ('GoodCrypto does not currently support {encryption}').format(
                encryption=encryption_software.name)
            log_message('no plugin for {} with classname: {}'.format(
                encryption_software.name, encryption_software.classname))
        else:
            id_fingerprint_pairs = plugin.get_id_fingerprint_pairs(keyblock)
            if id_fingerprint_pairs is None or len(id_fingerprint_pairs) <= 0:
                result_ok = False
                status = KEYBLOCK_INVALID
            else:
                result_ok = True
                for (user_id, fingerprint) in id_fingerprint_pairs:
                    if email_in_domain(user_id):
                        if passcode is None or len(passcode.strip()) <= 0:
                            result_ok = False
                            status = ('You must include the passcode when importing a key for {email}').format(email=user_id)
                            break

                    if result_ok:
                        # make sure we don't already have crypto defined for this user
                        contacts_crypto = contacts.get_contacts_crypto(user_id, encryption_name)
                        if contacts_crypto is None or contacts_crypto.fingerprint is None:
                            fingerprint, expiration = plugin.get_fingerprint(user_id)
                            if fingerprint is not None:
                                log_message('{} key exists for {}: {}'.format(
                                    encryption_name, user_id, fingerprint))
                                result_ok = False
                        else:
                            result_ok = False

                        if not result_ok:
                            status = ('A {encryption_name} key already exists for {email}. If you have a new key, then delete the Contact and then try importing the key again.').format(
                                encryption_name=encryption_name, email=user_id)
                            break

                # import the key if this is a new contact
                if result_ok:
                    log_message('importing keys for {}'.format(id_fingerprint_pairs))
                    result_ok, status, fingerprint_ok = _import_key_add_contact(
                        keyblock, user_name, possible_fingerprint, passcode, id_fingerprint_pairs, plugin)
                else:
                    log_message('unable to import keys for {}'.format(id_fingerprint_pairs))

    log_message("Imported public {} key ok: {}".format(encryption_name, result_ok))
    log_message("    Status: {}".format(status))

    return result_ok, status, fingerprint_ok, id_fingerprint_pairs
Пример #11
0
def import_key_now(encryption_name, keyblock, user_name, possible_fingerprint,
                   passcode):
    ''' Import if key is ok and doesn't exist. '''

    fingerprint_ok = True
    id_fingerprint_pairs = []

    if encryption_name is None or keyblock is None:
        result_ok = False
        fingerprint_ok = False
        status = MISSING_DATA_STATUS
        log_message('crypto: {} / keyblock is None: {}'.format(
            encryption_name, keyblock is None))
    else:
        encryption_software = crypto_software.get(encryption_name)
        plugin = KeyFactory.get_crypto(encryption_software.name,
                                       encryption_software.classname)
        if plugin is None:
            result_ok = False
            status = (
                'GoodCrypto does not currently support {encryption}').format(
                    encryption=encryption_software.name)
            log_message('no plugin for {} with classname: {}'.format(
                encryption_software.name, encryption_software.classname))
        else:
            id_fingerprint_pairs = plugin.get_id_fingerprint_pairs(keyblock)
            if id_fingerprint_pairs is None or len(id_fingerprint_pairs) <= 0:
                result_ok = False
                status = KEYBLOCK_INVALID
            else:
                result_ok = True
                for (user_id, fingerprint) in id_fingerprint_pairs:
                    if email_in_domain(user_id):
                        if passcode is None or len(passcode.strip()) <= 0:
                            result_ok = False
                            status = (
                                'You must include the passcode when importing a key for {email}'
                            ).format(email=user_id)
                            break

                    if result_ok:
                        # make sure we don't already have crypto defined for this user
                        contacts_crypto = contacts.get_contacts_crypto(
                            user_id, encryption_name)
                        if contacts_crypto is None or contacts_crypto.fingerprint is None:
                            fingerprint, expiration = plugin.get_fingerprint(
                                user_id)
                            if fingerprint is not None:
                                log_message('{} key exists for {}: {}'.format(
                                    encryption_name, user_id, fingerprint))
                                result_ok = False
                        else:
                            result_ok = False

                        if not result_ok:
                            status = (
                                'A {encryption_name} key already exists for {email}. If you have a new key, then delete the Contact and then try importing the key again.'
                            ).format(encryption_name=encryption_name,
                                     email=user_id)
                            break

                # import the key if this is a new contact
                if result_ok:
                    log_message(
                        'importing keys for {}'.format(id_fingerprint_pairs))
                    result_ok, status, fingerprint_ok = _import_key_add_contact(
                        keyblock, user_name, possible_fingerprint, passcode,
                        id_fingerprint_pairs, plugin)
                else:
                    log_message('unable to import keys for {}'.format(
                        id_fingerprint_pairs))

    log_message("Imported public {} key ok: {}".format(encryption_name,
                                                       result_ok))
    log_message("    Status: {}".format(status))

    return result_ok, status, fingerprint_ok, id_fingerprint_pairs
Пример #12
0
def is_key_ok(email, encryption_name):
    '''
        Throws a CryptoException if the email address does not have a crypto key, or
        the key has expired, or the key's fingerprint does not match the fingerprint in the database.

        >>> from goodcrypto.oce.test_constants import EDWARD_LOCAL_USER_ADDR
        >>> ok, __, active = is_key_ok(EDWARD_LOCAL_USER_ADDR, KeyFactory.DEFAULT_ENCRYPTION_NAME)
        >>> ok
        True
        >>> active
        True

        # In honor of Georg Koppen, works on Tor Browser, Torbutton, and our build automation.
        >>> email = 'Georg <*****@*****.**>'
        >>> try:
        ...     is_key_ok(email, KeyFactory.DEFAULT_ENCRYPTION_NAME)
        ...     fail()
        ... except CryptoException as crypto_exception:
        ...     crypto_exception.__str__() == 'There is no key for Georg <*****@*****.**>.'
        True
    '''

    # we use NO_FINGERPRINT_IN_DB a few times because we don't want to get too technical

    key_ok = verified = active = False
    encryption_software = crypto_software.get(encryption_name)
    if encryption_software is None:
        # this should never happen, but better be prepared
        log_message('no database entry for {}'.format(email))
        raise CryptoException(i18n(NO_FINGERPRINT_IN_DB.format(encryption=encryption_name, email=email)))
    else:
        key_crypto = KeyFactory.get_crypto(encryption_name, encryption_software.classname)
        if key_crypto is None:
            # this should never happen, but better to be prepared
            log_message('no plugin for {} with classname: {}'.format(
                encryption_name, encryption_software.classname))
            raise CryptoException(i18n(NO_FINGERPRINT_IN_DB.format(encryption=encryption_name, email=email)))
        else:
            # see if the crypto key exists
            crypto_fingerprint, expiration = key_crypto.get_fingerprint(email)
            if crypto_fingerprint is None:
                message = i18n('There is no key for {email}.'.format(email=email))
                log_message(message)
                raise CryptoException(message)

            # if the key has expired, then raise an error
            if expiration is not None and key_crypto.fingerprint_expired(expiration):
                message = i18n('The key for {email} expired on {date}.'.format(email=email, date=expiration))
                log_message(message)
                raise CryptoException(message)

            database_fingerprint, verified, active = get_fingerprint(email, encryption_name)
            # if there isn't a fingerprint, then try to save the crypto fingerprint
            if database_fingerprint is None or len(database_fingerprint.strip()) <= 0:
                contacts_encryption = get_contacts_crypto(email, encryption_name=encryption_name)
                if contacts_encryption is not None and contacts_encryption.fingerprint is None:
                    database_fingerprint = crypto_fingerprint
                    contacts_encryption.fingerprint = database_fingerprint
                    if email_in_domain(email) and contacts.crypto.source is None:
                        contacts.crypto.source = constants.AUTO_GENERATED
                    contacts_encryption.save()
                    log_message('updated {} fingerprint for {}'.format(encryption_name, email))

            if database_fingerprint is None or len(database_fingerprint.strip()) <= 0:
                error_message = i18n(NO_FINGERPRINT_IN_DB.format(encryption=encryption_name, email=email))
                log_message(error_message)
                raise CryptoException(error_message)
            else:
                # finally verify the fingerprints agree
                if (strip_fingerprint(database_fingerprint).lower() ==
                    strip_fingerprint(crypto_fingerprint).lower()):
                    key_ok = True
                else:
                    message = i18n('The fingerprint for {email} does not match the saved fingerprint.'.format(
                        email=email))
                    log_message('email address: {}'.format(email))
                    log_message('  database fingerprint: {}'.format(database_fingerprint.lower()))
                    log_message('  crypto fingerprint: {}'.format(crypto_fingerprint.lower()))
                    log_message(message)
                    raise CryptoException(message)

            log_message('{} fingerprints agree and key has not expired for {}'.format(
              encryption_name, email))

    return key_ok, verified, active
Пример #13
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
Пример #14
0
def is_key_ok(email, encryption_name):
    '''
        Throws a CryptoException if the email address does not have a crypto key, or
        the key has expired, or the key's fingerprint does not match the fingerprint in the database.

        >>> from goodcrypto.oce.test_constants import EDWARD_LOCAL_USER_ADDR
        >>> ok, __, active = is_key_ok(EDWARD_LOCAL_USER_ADDR, KeyFactory.DEFAULT_ENCRYPTION_NAME)
        >>> ok
        True
        >>> active
        True

        # In honor of Georg Koppen, works on Tor Browser, Torbutton, and our build automation.
        >>> email = 'Georg <*****@*****.**>'
        >>> try:
        ...     is_key_ok(email, KeyFactory.DEFAULT_ENCRYPTION_NAME)
        ...     fail()
        ... except CryptoException as crypto_exception:
        ...     crypto_exception.__str__() == 'There is no key for Georg <*****@*****.**>.'
        True
    '''

    # we use NO_FINGERPRINT_IN_DB a few times because we don't want to get too technical

    key_ok = verified = active = False
    encryption_software = crypto_software.get(encryption_name)
    if encryption_software is None:
        # this should never happen, but better be prepared
        log_message('no database entry for {}'.format(email))
        raise CryptoException(
            i18n(
                NO_FINGERPRINT_IN_DB.format(encryption=encryption_name,
                                            email=email)))
    else:
        key_crypto = KeyFactory.get_crypto(encryption_name,
                                           encryption_software.classname)
        if key_crypto is None:
            # this should never happen, but better to be prepared
            log_message('no plugin for {} with classname: {}'.format(
                encryption_name, encryption_software.classname))
            raise CryptoException(
                i18n(
                    NO_FINGERPRINT_IN_DB.format(encryption=encryption_name,
                                                email=email)))
        else:
            # see if the crypto key exists
            crypto_fingerprint, expiration = key_crypto.get_fingerprint(email)
            if crypto_fingerprint is None:
                message = i18n(
                    'There is no key for {email}.'.format(email=email))
                log_message(message)
                raise CryptoException(message)

            # if the key has expired, then raise an error
            if expiration is not None and key_crypto.fingerprint_expired(
                    expiration):
                message = i18n('The key for {email} expired on {date}.'.format(
                    email=email, date=expiration))
                log_message(message)
                raise CryptoException(message)

            database_fingerprint, verified, active = get_fingerprint(
                email, encryption_name)
            # if there isn't a fingerprint, then try to save the crypto fingerprint
            if database_fingerprint is None or len(
                    database_fingerprint.strip()) <= 0:
                contacts_encryption = get_contacts_crypto(
                    email, encryption_name=encryption_name)
                if contacts_encryption is not None and contacts_encryption.fingerprint is None:
                    database_fingerprint = crypto_fingerprint
                    contacts_encryption.fingerprint = database_fingerprint
                    if email_in_domain(
                            email) and contacts.crypto.source is None:
                        contacts.crypto.source = constants.AUTO_GENERATED
                    contacts_encryption.save()
                    log_message('updated {} fingerprint for {}'.format(
                        encryption_name, email))

            if database_fingerprint is None or len(
                    database_fingerprint.strip()) <= 0:
                error_message = i18n(
                    NO_FINGERPRINT_IN_DB.format(encryption=encryption_name,
                                                email=email))
                log_message(error_message)
                raise CryptoException(error_message)
            else:
                # finally verify the fingerprints agree
                if (strip_fingerprint(database_fingerprint).lower() ==
                        strip_fingerprint(crypto_fingerprint).lower()):
                    key_ok = True
                else:
                    message = i18n(
                        'The fingerprint for {email} does not match the saved fingerprint.'
                        .format(email=email))
                    log_message('email address: {}'.format(email))
                    log_message('  database fingerprint: {}'.format(
                        database_fingerprint.lower()))
                    log_message('  crypto fingerprint: {}'.format(
                        crypto_fingerprint.lower()))
                    log_message(message)
                    raise CryptoException(message)

            log_message(
                '{} fingerprints agree and key has not expired for {}'.format(
                    encryption_name, email))

    return key_ok, verified, active
Пример #15
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