def is_probably_pgp(self):
        '''
            Returns true if this is probably an OpenPGP message.

            >>> from goodcrypto_tests.mail.message_utils import get_encrypted_message_name
            >>> with open(get_encrypted_message_name('open-pgp-mime.txt')) as input_file:
            ...     mime_message = EmailMessage(input_file)
            ...     mime_message.is_probably_pgp()
            True
        '''

        is_pgp = is_open_pgp_mime(self.get_message())
        if not is_pgp:
            content = self.get_content()
            if is_string(content):
                is_pgp = self.contains_pgp_message_delimters(content)
                self.log_message('message uses in line pgp: {}'.format(is_pgp))
            elif isinstance(content, list):
                for part in content:
                    if isinstance(part, Message):
                        part_content = part.get_payload()
                    else:
                        part_content = part

                    if is_string(part_content):
                        is_pgp = self.contains_pgp_message_delimters(part_content)
                        if is_pgp:
                            self.log_message('part of message uses in line pgp: {}'.format(is_pgp))
                            break
                    else:
                        self.log_message('part of content type is: {}'.format(repr(part_content)))
            else:
                self.log_message('content type is: {}'.format(type(content)))

        return is_pgp
Exemple #2
0
def trim(string, xfix):
    ''' Trim all prefixes or suffixes of xfix from string. '''

    if is_string(string):
        string = string.encode()
    if is_string(xfix):
        xfix = xfix.encode()

    length = len(xfix)
    while string.startswith(xfix):
        string = string[length:]
    while string.endswith(xfix):
        string = string[:-length]
    return string
    def _decrypt(self, from_user, data, charset, crypto, passcode):
        '''
            Decrypt the data from a message (internal use only).
        '''

        decrypted_data = signed_by = None

        if crypto is None or data is None:
            decrypted_data = None
            self.log_message("no crypto defined")
        else:
            if is_string(data):
                encrypted_data = data
            else:
                encrypted_data = data.encode(errors='replace')

            #  ASCII armored plaintext looks just like armored ciphertext,
            #  so check that we actually have encrypted data
            if (OpenPGPAnalyzer().is_encrypted(
                encrypted_data, passphrase=passcode, crypto=crypto)):

                if self.DEBUGGING: self.log_message('encrypted data before decryption:\n{}'.format(encrypted_data))
                decrypted_data, signed_by, result_code = crypto.decrypt(encrypted_data, passcode)

                if (decrypted_data == None or
                    (is_string(decrypted_data) and len(decrypted_data) <= 0)):
                    if self.DEBUGGING: self.log_message('decrypted data:\n{}'.format(decrypted_data))
                    decrypted_data = None
                    self.log_message("unable to decrypt data")
                    if self.DEBUGGING: self.log_message('data bytearray after decryption:\n{}'.format(decrypted_data))
                else:
                    if result_code == 0:
                        tag = tags.get_decrypt_signature_tag(
                           self.crypto_message, from_user, signed_by, crypto.get_name())
                        if tag is not None:
                            self.crypto_message.add_prefix_to_tag_once(tag)
                            self.log_message('decrypt sig tag: {}'.format(tag))
                    elif result_code == 2:
                        self.crypto_message.add_error_tag_once(
                          i18n("Can't verify signature because the message was encrypted using an unknown key. Ask the sender to send their key if they aren't using GoodCrypto."))
                    if is_string(decrypted_data):
                        self.log_message('plaintext length: {}'.format(len(decrypted_data)))
                    if self.DEBUGGING: self.log_message('plaintext:\n{}'.format(decrypted_data))
            else:
                decrypted_data = None
                self.log_message("data appeared encrypted, but wasn't")
                if self.DEBUGGING: self.log_message('data:\n{}'.format(data))

        return decrypted_data
def delete(name_or_software):
    '''
        Delete the encryption software with a matching name.

        >>> updated_software = EncryptionSoftware(name='test', active=True, classname='goodcrypto.oce.test')
        >>> set(updated_software)
        True
        >>> delete('test')
        True
    '''

    result_ok = True
    try:
        if is_string(name_or_software):
            software = get(name_or_software)
        else:
            software = name_or_software

        if software is None:
            log_message('nothing to delete')
        else:
            encryption_software = get(software.name)
            if encryption_software is None:
                log_message('{} does not exist so need to delete'.format(
                    name_or_software))
            else:
                encryption_software.delete()
                log_message("deleted {}".format(software.name))
    except Exception:
        result_ok = False
        record_exception()
        log_message('EXCEPTION - see syr.exception.log for details')

    return result_ok
    def set_message(self, new_message):
        '''
            Set the new message.

            # Get a basic message first so we can avoid recursion
            >>> from goodcrypto_tests.mail.message_utils import get_basic_email_message
            >>> from goodcrypto.oce.test_constants import EDWARD_LOCAL_USER
            >>> basic_email_message = get_basic_email_message().get_message()
            >>> email_message = EmailMessage()
            >>> email_message.get_message().get(mime_constants.FROM_KEYWORD) is None
            True
            >>> email_message.set_message(basic_email_message)
            >>> email_message.get_message().get(mime_constants.FROM_KEYWORD) == EDWARD_LOCAL_USER
            True
        '''

        old_message = self._message

        if is_string(new_message):
            try:
                if isinstance(self.parser, Parser):
                    self._message = self.parser.parsestr(new_message)
                else:
                    self._message = self.parser.parsebytes(new_message.encode())
            except:
                self._message = old_message
                record_exception()
        else:
            self._message = new_message

        # restore the old message if the new one isn't valid.
        if not self.validate_message():
            self._message = old_message
            self.log_message('restored previous message')
Exemple #6
0
def chmod(mode, path, recursive=False):
    ''' Change permissions of path.

        mode is a string or octal integer for the chmod command.
        Examples::
            'o+rw,g+rw'
            0660
    '''

    # arg order used to be chmod(path, mode, ...), so check types
    # delete this assert if no assertion errors 2015-01-01
    # after we remove this assert, mode can be a string
    assert is_string(path)

    if isinstance(mode, int):
        # chmod wants an octal int, not decimal
        # so if it's an int we convert to an octal string
        mode = '0'+oct(mode)

    try:
        if recursive:
            sh.chmod('--recursive', mode, path)
        else:
            sh.chmod(mode, path)
    except sh.ErrorReturnCode as sh_exception:
        log.error('unable to chmod: path={}, mode={}'.format(path, mode))
        log.error(sh_exception)
        raise
def delete(name_or_software):
    '''
        Delete the encryption software with a matching name.

        >>> updated_software = EncryptionSoftware(name='test', active=True, classname='goodcrypto.oce.test')
        >>> set(updated_software)
        True
        >>> delete('test')
        True
    '''

    result_ok = True
    try:
        if is_string(name_or_software):
            software = get(name_or_software)
        else:
            software = name_or_software

        if software is None:
            log_message('nothing to delete')
        else:
            encryption_software = get(software.name)
            if encryption_software is None:
                log_message('{} does not exist so need to delete'.format(name_or_software))
            else:
                encryption_software.delete()
                log_message("deleted {}".format(software.name))
    except Exception:
        result_ok = False
        record_exception()
        log_message('EXCEPTION - see syr.exception.log for details')

    return result_ok
def write(filename, lines, append=False):
    '''Write the lines to a text file.

      Log any io errors and then raise another ioerrr.
    '''

    try:
        if append:
            method = 'at'
        else:
            method = 'wt'

        outputFile = open(filename, method)
        for line in lines:
            if isinstance(line, list):
                # line must be another list
                # let's assume there aren't any more nested lists
                for l in line:
                    if IS_PY2:
                        text = l
                    else:
                        if is_string(l):
                            text = l.decode()
                        else:
                            text = l
                    outputFile.write(text)
            else:
                if IS_PY2:
                    text = line
                else:
                    if is_string(line):
                        text = line
                    else:
                        text = line.decode()
                outputFile.write(text)
        outputFile.close()

    except IOError:
        log('Unable to write %s' % filename)
        log(format_exc())
        raise IOError

    return lines
        def get_addendum_value(addendum, keyword):
            value = addendum[keyword]
            if is_string(value):
                value = value.strip()
            if value == 'True':
                value = True
            elif value == 'False':
                value = False

            return value
Exemple #10
0
def strip_input(data):
    '''Strip the leading and trailing spaces.'''

    try:
        if data is not None:
            if is_string(data) or isinstance(data, CharField):
                data = data.strip()

            elif isinstance(data, EmailField):
                data = '{}'.format(data)
                data = data.strip()
                
            elif isinstance(data, bytes):
                data = data.decode().strip()
    except:
        log(traceback.format_exc())

    return data
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
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
    def set_tag(self, new_tag):
        '''
            Sets the tag to be added to the email_message text.

            >>> crypto_message = CryptoMessage()
            >>> crypto_message.set_tag(None)
            >>> tag = crypto_message.get_tag()
            >>> tag == ''
            True
        '''

        if new_tag is None:
            if self.DEBUGGING: self.log_message("tried to set blank tag")
        elif new_tag == '':
            self.tags = []
            if self.DEBUGGING: self.log_message("reset tags")
        else:
            if is_string(new_tag):
                new_tag = new_tag.strip('\n')
                self.tags = [new_tag]
            else:
                self.tags = new_tag
            if self.DEBUGGING: self.log_message("new tag:\n{}".format(new_tag))
    def set_tag(self, new_tag):
        '''
            Sets the tag to be added to the email_message text.

            >>> crypto_message = CryptoMessage()
            >>> crypto_message.set_tag(None)
            >>> tag = crypto_message.get_tag()
            >>> tag == ''
            True
        '''

        if new_tag is None:
            if self.DEBUGGING: self.log_message("tried to set blank tag")
        elif new_tag == '':
            self.tags = []
            if self.DEBUGGING: self.log_message("reset tags")
        else:
            if is_string(new_tag):
                new_tag = new_tag.strip('\n')
                self.tags = [new_tag]
            else:
                self.tags = new_tag
            if self.DEBUGGING: self.log_message("new tag:\n{}".format(new_tag))
Exemple #15
0
def log(message, filename=None, mode=None):
    ''' Log message that syr.log can't. '''

    if filename is None:
        filename = '/tmp/_log.{}.log'.format(whoami())
    if mode is None:
        mode = '0666'

    # print(message)
    sh.touch(filename)
    try:
        sh.chmod(mode, filename)
    except sh.ErrorReturnCode_1:
        # hopefully the perms are already ok
        pass
    with open(filename, 'a') as logfile:
        try:
            logfile.write('{} {}\n'.format(timestamp(), message))
        except UnicodeDecodeError:
            from syr.python import is_string
            
            logfile.write('unable to write message because it is a type: {}'.format(type(message)))
            if not is_string(message):
                logfile.write('{} {}\n'.format(timestamp(), message.decode(errors='replace')))
    def _decrypt(self, from_user, data, charset, crypto, passcode):
        '''
            Decrypt the data from a message (internal use only).
        '''

        decrypted_data = signed_by = None

        if crypto is None or data is None:
            decrypted_data = None
            self.log_message("no crypto defined")
        else:
            if is_string(data):
                encrypted_data = data
            else:
                encrypted_data = data.encode(errors='replace')

            #  ASCII armored plaintext looks just like armored ciphertext,
            #  so check that we actually have encrypted data
            if (OpenPGPAnalyzer().is_encrypted(encrypted_data,
                                               passphrase=passcode,
                                               crypto=crypto)):

                if self.DEBUGGING:
                    self.log_message(
                        'encrypted data before decryption:\n{}'.format(
                            encrypted_data))
                decrypted_data, signed_by, result_code = crypto.decrypt(
                    encrypted_data, passcode)

                if (decrypted_data == None or
                    (is_string(decrypted_data) and len(decrypted_data) <= 0)):
                    if self.DEBUGGING:
                        self.log_message(
                            'decrypted data:\n{}'.format(decrypted_data))
                    decrypted_data = None
                    self.log_message("unable to decrypt data")
                    if self.DEBUGGING:
                        self.log_message(
                            'data bytearray after decryption:\n{}'.format(
                                decrypted_data))
                else:
                    if result_code == 0:
                        tag = tags.get_decrypt_signature_tag(
                            self.crypto_message, from_user, signed_by,
                            crypto.get_name())
                        if tag is not None:
                            self.crypto_message.add_prefix_to_tag_once(tag)
                            self.log_message('decrypt sig tag: {}'.format(tag))
                    elif result_code == 2:
                        self.crypto_message.add_error_tag_once(
                            i18n(
                                "Can't verify signature because the message was encrypted using an unknown key. Ask the sender to send their key if they aren't using GoodCrypto."
                            ))
                    if is_string(decrypted_data):
                        self.log_message('plaintext length: {}'.format(
                            len(decrypted_data)))
                    if self.DEBUGGING:
                        self.log_message(
                            'plaintext:\n{}'.format(decrypted_data))
            else:
                decrypted_data = None
                self.log_message("data appeared encrypted, but wasn't")
                if self.DEBUGGING: self.log_message('data:\n{}'.format(data))

        return decrypted_data
Exemple #17
0
def edit_file_in_place(filename, replacements, regexp=False, lines=False):
    ''' Replace text in file.

        'replacements' is a dict of {old: new, ...}.
        Every occurence of each old string is replaced with the
        matching new string.

        If regexp=True, the old string is a regular expression.
        If lines=True, each line is matched separately.

        Perserves permissions.

        >>> # note double backslashes because this is a string within a docstring
        >>> text = (
        ...     'browser.search.defaultenginename=Startpage HTTPS\\n' +
        ...     'browser.search.selectedEngine=Startpage HTTPS\\n' +
        ...     'browser.startup.homepage=https://tails.boum.org/news/\\n' +
        ...     'spellchecker.dictionary=en_US')

        >>> f = tempfile.NamedTemporaryFile(mode='w', delete=False)
        >>> f.write(text)
        >>> f.close()

        >>> HOMEPAGE = 'http://127.0.0.1/'
        >>> replacements = {
        ...     'browser.startup.homepage=.*':
        ...         'browser.startup.homepage={}'.format(HOMEPAGE),
        ...     }

        >>> edit_file_in_place(f.name, replacements, regexp=True, lines=True)

        >>> with open(f.name) as textfile:
        ...     newtext = textfile.read()
        >>> assert HOMEPAGE in newtext

        >>> os.remove(f.name)
    '''

    # import delayed to avoid infinite recursion
    import syr.utils

    log.debug('edit file in place: {}, replacements {}'.format(filename, replacements))

    # sometimes replace_strings() gets a type error
    for old, new in replacements.items():
        assert is_string(old), 'replacement old "{}" should be string but is type {}'.format(old, type(old))
        assert is_string(new), 'replacement new "{}" should be string but is type {}'.format(new, type(new))

    # read text
    mode = os.stat(filename).st_mode
    with open(filename) as textfile:
        text = textfile.read()

    if lines:
        newtext = []
        for line in text.split('\n'):
            # sometimes replace_strings() gets a type error
            assert is_string(line), 'line should be string but is {}'.format(type(line))
            newline = syr.utils.replace_strings(line, replacements, regexp)
            newtext.append(newline)
        text = '\n'.join(newtext)
    else:
        text = syr.utils.replace_strings(text, replacements, regexp)

    # write text
    with open(filename, 'w') as textfile:
        textfile.write(text)
    os.chmod(filename, mode)
    assert mode == os.stat(filename).st_mode
Exemple #18
0
    def write(self, message):
        ''' Write message to log.

            write() writes to a log as you would to a file.
            This lets you redirect sys.stdout to the log and log print output
            generated by third party libraries, even if the library uses
            print statements without '>>' or print functions without 'stream='.
        '''

        def notify_webmaster(message):
            ''' Send the message to the webmaster.

                We can't use jean.dmail.send because it imports this module.
            '''

            if alert_from_address is not None and alert_to_address is not None:
                msg = ("From: %s\nTo: %s\nSubject: %s\n\n%s\n"
                   % (alert_from_address, alert_to_address, subject, message))
                server = smtplib.SMTP('localhost')
                server.sendmail(alert_from_address, alert_to_address, msg)

        # we don't use @synchronized here because of import errors

        global _raise_logging_errors

        try:
            from syr.python import is_string

            if is_string(message):
                self._write(message)
            elif isinstance(message, bytes) or isinstance(message, bytearray):
                self._write(message.decode(errors='replace'))
            else:
                self.write('unable to write message because it is a {}'.format(type(message)))

            if self.verbose:
                print(message)
            if _use_master_log and not self.is_master():
                try:
                    _master_logs[self.user]._write('- %s - %s' % (self.filename, message))
                except UnicodeDecodeError:
                    _master_logs[self.user]._write('- %s - !! Unable to log message -- UnicodeDecodeError !!' % (self.filename))

        except UnicodeDecodeError:
            try:
                _debug(message.decode(errors='replace'))
            except UnicodeDecodeError:
                self.write('unable to write message because it is a type: {}'.format(type(message)))
                subject = '!! Unable to log message !!'
                self._write(subject)
                if _raise_logging_errors:
                    _raise_logging_errors = False
                    notify_webmaster(message)

        except:

            raise
            self._write(format_exc())
            subject = '!! Unable to log message !!'
            self._write(subject)
            if _raise_logging_errors:
                _raise_logging_errors = False
                notify_webmaster(message)