Skip to content

Commit

Permalink
Vendor pretty_bad_protocol
Browse files Browse the repository at this point in the history
pretty_bad_protocol is unmaintained upstream, not seeing any commits
since the 3.1.1 release in August 2018. As part of our shift to Sequoia,
we will just need a small part of this library during the migration, so
let's fork/vendor it and remove the parts we don't need. This will also
let us get rid of the monkey-patching that's accumulated over the years.

This is a direct copy of the 3.1.1 source tree:
 $ wget https://files.pythonhosted.org/packages/84/0d/814c6c96f64f9cfc235fe102024b00ee77d107977e32996c59aed8f27ec0/pretty-bad-protocol-3.1.1.tar.gz
 $ tar xvf pretty-bad-protocol-3.1.1.tar.gz
 $ cp -Rv pretty-bad-protocol-3.1.1/pretty_bad_protocol freedomofpress/securedrop/securedrop/

Follow-up commits will reformat it per our coding standards and other
necessary fixes.

Refs #6807.
  • Loading branch information
legoktm committed Jun 12, 2023
1 parent f724466 commit a67420b
Show file tree
Hide file tree
Showing 12 changed files with 6,106 additions and 7 deletions.
54 changes: 54 additions & 0 deletions securedrop/pretty_bad_protocol/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
# -*- coding: utf-8 -*-
#
# This file is part of python-gnupg, a Python interface to GnuPG.
# Copyright © 2013 Isis Lovecruft, <[email protected]> 0xA3ADB67A2CDB8B35
# © 2013 Andrej B.
# © 2013 LEAP Encryption Access Project
# © 2008-2012 Vinay Sajip
# © 2005 Steve Traugott
# © 2004 A.M. Kuchling
#
# This program is free software: you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by the Free
# Software Foundation, either version 3 of the License, or (at your option)
# any later version.
#
# This program is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
# FITNESS FOR A PARTICULAR PURPOSE. See the included LICENSE file for details.

from __future__ import absolute_import

from . import gnupg
from . import copyleft
from . import _ansistrm
from . import _logger
from . import _meta
from . import _parsers
from . import _util
from .gnupg import GPG
from ._version import get_versions

__version__ = get_versions()['version']
__authors__ = copyleft.authors
__license__ = copyleft.full_text
__copyleft__ = copyleft.copyright

gnupg.__version__ = __version__
gnupg.__authors__ = __authors__
gnupg.__licence__ = __license__
gnupg.__copyleft__ = __copyleft__

gnupg._logger = _logger
gnupg._meta = _meta
gnupg._parsers = _parsers
gnupg._util = _util

## do not set __package__ = "gnupg", else we will end up with
## gnupg.<*allofthethings*>
__all__ = ["GPG", "_util", "_parsers", "_meta", "_logger"]

del absolute_import
del copyleft
del get_versions
del _version
172 changes: 172 additions & 0 deletions securedrop/pretty_bad_protocol/_ansistrm.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,172 @@
# -*- coding: utf-8 -*-
#
# This file is part of python-gnupg, a Python wrapper aroung GnuPG, and it was
# taken from https://gist.github.com/vsajip/758430 on the 14th of May, 2013. It
# has also been included in the 'logutils' Python module, see
# https://code.google.com/p/logutils/ .
#
# The original copyright and license text are as follows:
# |
# | Copyright (C) 2010-2012 Vinay Sajip. All rights reserved.
# | Licensed under the new BSD license.
# |
#
# This file is part of python-gnupg, a Python interface to GnuPG.
# Copyright © 2013 Isis Lovecruft, <[email protected]> 0xA3ADB67A2CDB8B35
# © 2013 Andrej B.
# © 2013 LEAP Encryption Access Project
# © 2008-2012 Vinay Sajip
# © 2005 Steve Traugott
# © 2004 A.M. Kuchling
#
# This program is free software: you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by the Free
# Software Foundation, either version 3 of the License, or (at your option)
# any later version.
#
# This program is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
# FITNESS FOR A PARTICULAR PURPOSE. See the included LICENSE file for details.

import ctypes
import logging
import os

class ColorizingStreamHandler(logging.StreamHandler):
# color names to indices
color_map = {
'black': 0,
'red': 1,
'green': 2,
'yellow': 3,
'blue': 4,
'magenta': 5,
'cyan': 6,
'white': 7,
}

#levels to (background, foreground, bold/intense)
if os.name == 'nt':
level_map = {
logging.DEBUG: (None, 'blue', True),
logging.INFO: (None, 'green', False),
logging.WARNING: (None, 'yellow', True),
logging.ERROR: (None, 'red', True),
logging.CRITICAL: ('red', 'white', True),
}
else:
level_map = {
logging.DEBUG: (None, 'blue', False),
logging.INFO: (None, 'green', False),
logging.WARNING: (None, 'yellow', False),
logging.ERROR: (None, 'red', False),
logging.CRITICAL: ('red', 'white', True),
}
csi = '\x1b['
reset = '\x1b[0m'

@property
def is_tty(self):
isatty = getattr(self.stream, 'isatty', None)
return isatty and isatty()

def emit(self, record):
try:
message = self.format(record)
stream = self.stream
if not self.is_tty:
stream.write(message)
else:
self.output_colorized(message)
stream.write(getattr(self, 'terminator', '\n'))
self.flush()
except (KeyboardInterrupt, SystemExit):
raise
except:
self.handleError(record)

if os.name != 'nt':
def output_colorized(self, message):
self.stream.write(message)
else:
import re
ansi_esc = re.compile(r'\x1b\[((?:\d+)(?:;(?:\d+))*)m')

nt_color_map = {
0: 0x00, # black
1: 0x04, # red
2: 0x02, # green
3: 0x06, # yellow
4: 0x01, # blue
5: 0x05, # magenta
6: 0x03, # cyan
7: 0x07, # white
}

def output_colorized(self, message):
parts = self.ansi_esc.split(message)
write = self.stream.write
h = None
fd = getattr(self.stream, 'fileno', None)
if fd is not None:
fd = fd()
if fd in (1, 2): # stdout or stderr
h = ctypes.windll.kernel32.GetStdHandle(-10 - fd)
while parts:
text = parts.pop(0)
if text:
write(text)
if parts:
params = parts.pop(0)
if h is not None:
params = [int(p) for p in params.split(';')]
color = 0
for p in params:
if 40 <= p <= 47:
color |= self.nt_color_map[p - 40] << 4
elif 30 <= p <= 37:
color |= self.nt_color_map[p - 30]
elif p == 1:
color |= 0x08 # foreground intensity on
elif p == 0: # reset to default color
color = 0x07
else:
pass # error condition ignored
ctypes.windll.kernel32.SetConsoleTextAttribute(h, color)

def colorize(self, message, record):
if record.levelno in self.level_map:
bg, fg, bold = self.level_map[record.levelno]
params = []
if bg in self.color_map:
params.append(str(self.color_map[bg] + 40))
if fg in self.color_map:
params.append(str(self.color_map[fg] + 30))
if bold:
params.append('1')
if params:
message = ''.join((self.csi, ';'.join(params),
'm', message, self.reset))
return message

def format(self, record):
message = logging.StreamHandler.format(self, record)
if self.is_tty:
# Don't colorize any traceback
parts = message.split('\n', 1)
parts[0] = self.colorize(parts[0], record)
message = '\n'.join(parts)
return message

def main():
root = logging.getLogger()
root.setLevel(logging.DEBUG)
root.addHandler(ColorizingStreamHandler())
logging.debug('DEBUG')
logging.info('INFO')
logging.warning('WARNING')
logging.error('ERROR')
logging.critical('CRITICAL')

if __name__ == '__main__':
main()
99 changes: 99 additions & 0 deletions securedrop/pretty_bad_protocol/_logger.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
# -*- coding: utf-8 -*-
#
# This file is part of python-gnupg, a Python interface to GnuPG.
# Copyright © 2013 Isis Lovecruft, <[email protected]> 0xA3ADB67A2CDB8B35
# © 2013 Andrej B.
# © 2013 LEAP Encryption Access Project
# © 2008-2012 Vinay Sajip
# © 2005 Steve Traugott
# © 2004 A.M. Kuchling
#
# This program is free software: you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by the Free
# Software Foundation, either version 3 of the License, or (at your option)
# any later version.
#
# This program is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
# FITNESS FOR A PARTICULAR PURPOSE. See the included LICENSE file for details.

'''Logging module for python-gnupg.'''

from __future__ import absolute_import
from __future__ import print_function
from datetime import datetime
from functools import wraps

import logging
import sys
import os

try:
from logging import NullHandler
except:
class NullHandler(logging.Handler):
def handle(self, record):
pass

from . import _ansistrm

GNUPG_STATUS_LEVEL = 9

def status(self, message, *args, **kwargs):
"""LogRecord for GnuPG internal status messages."""
if self.isEnabledFor(GNUPG_STATUS_LEVEL):
self._log(GNUPG_STATUS_LEVEL, message, args, **kwargs)

@wraps(logging.Logger)
def create_logger(level=logging.NOTSET):
"""Create a logger for python-gnupg at a specific message level.
:type level: :obj:`int` or :obj:`str`
:param level: A string or an integer for the lowest level to include in
logs.
**Available levels:**
==== ======== ========================================
int str description
==== ======== ========================================
0 NOTSET Disable all logging.
9 GNUPG Log GnuPG's internal status messages.
10 DEBUG Log module level debuging messages.
20 INFO Normal user-level messages.
30 WARN Warning messages.
40 ERROR Error messages and tracebacks.
50 CRITICAL Unhandled exceptions and tracebacks.
==== ======== ========================================
"""
_test = os.path.join(os.path.join(os.getcwd(), 'pretty_bad_protocol'), 'test')
_now = datetime.now().strftime("%Y-%m-%d_%H%M%S")
_fn = os.path.join(_test, "%s_test_gnupg.log" % _now)
_fmt = "%(relativeCreated)-4d L%(lineno)-4d:%(funcName)-18.18s %(levelname)-7.7s %(message)s"

## Add the GNUPG_STATUS_LEVEL LogRecord to all Loggers in the module:
logging.addLevelName(GNUPG_STATUS_LEVEL, "GNUPG")
logging.Logger.status = status

if level > logging.NOTSET:
logging.basicConfig(level=level, filename=_fn,
filemode="a", format=_fmt)
logging.logThreads = True
if hasattr(logging,'captureWarnings'):
logging.captureWarnings(True)
colouriser = _ansistrm.ColorizingStreamHandler
colouriser.level_map[9] = (None, 'blue', False)
colouriser.level_map[10] = (None, 'cyan', False)
handler = colouriser(sys.stderr)
handler.setLevel(level)

formatr = logging.Formatter(_fmt)
handler.setFormatter(formatr)
else:
handler = NullHandler()

log = logging.getLogger('gnupg')
log.addHandler(handler)
log.setLevel(level)
log.info("Log opened: %s UTC" % datetime.ctime(datetime.utcnow()))
return log
Loading

0 comments on commit a67420b

Please sign in to comment.