From 5f02223ec7d8bf7fb631b8128e5befafe1f34fae Mon Sep 17 00:00:00 2001 From: "Piotr F. Mieszkowski" Date: Sat, 8 Jan 2022 14:06:18 +0100 Subject: [PATCH 01/12] Perform automatic migration to Python 3.x Use lib2to3 automatic migration tool provided by Python 2.x to convert codebase to new idioms. Command line: find . -type f -name '*.py' \ -exec python2.7 -m lib2to3 \ -f all -f idioms -f buffer -f set_literal -f ws_comma -w \ '{}' '+' --- GnuPG/__init__.py | 6 +++--- gpg-mailgate-web/cron.py | 12 ++++++------ gpg-mailgate.py | 38 +++++++++++++++++++------------------- register-handler.py | 12 ++++++------ test/e2e_test.py | 10 +++++----- test/relay.py | 8 ++++---- 6 files changed, 43 insertions(+), 43 deletions(-) diff --git a/GnuPG/__init__.py b/GnuPG/__init__.py index 540622e..6404720 100644 --- a/GnuPG/__init__.py +++ b/GnuPG/__init__.py @@ -101,7 +101,7 @@ def confirm_key( content, email ): # adds a key and ensures it has the given email address def add_key( keyhome, content ): - p = subprocess.Popen( build_command(keyhome, '--import', '--batch'), stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE ) + p = subprocess.Popen( ['/usr/bin/gpg', '--homedir', keyhome, '--import', '--batch'], stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE ) p.communicate(input=content) p.wait() @@ -130,7 +130,7 @@ class GPGEncryptor: self._message += message def encrypt(self): - p = subprocess.Popen( self._command(), stdin=subprocess.PIPE, stdout=subprocess.PIPE,stderr=subprocess.PIPE ) + p = subprocess.Popen( self._command(), stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE ) encdata = p.communicate(input=self._message)[0] return (encdata, p.returncode) @@ -158,7 +158,7 @@ class GPGDecryptor: self._message += message def decrypt(self): - p = subprocess.Popen( self._command(), stdin=subprocess.PIPE, stdout=subprocess.PIPE,stderr=subprocess.PIPE ) + p = subprocess.Popen( self._command(), stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE ) decdata = p.communicate(input=self._message)[0] return (decdata, p.returncode) diff --git a/gpg-mailgate-web/cron.py b/gpg-mailgate-web/cron.py index 3f305ba..98cd8d1 100644 --- a/gpg-mailgate-web/cron.py +++ b/gpg-mailgate-web/cron.py @@ -19,7 +19,7 @@ # along with gpg-mailgate source code. If not, see . # -from ConfigParser import RawConfigParser +from configparser import RawConfigParser import GnuPG import MySQLdb import smtplib @@ -64,7 +64,7 @@ for sect in _cfg.sections(): for (name, value) in _cfg.items(sect): cfg[sect][name] = value -if cfg.has_key('database') and cfg['database'].has_key('enabled') and cfg['database']['enabled'] == 'yes' and cfg['database'].has_key('name') and cfg['database'].has_key('host') and cfg['database'].has_key('username') and cfg['database'].has_key('password'): +if 'database' in cfg and 'enabled' in cfg['database'] and cfg['database']['enabled'] == 'yes' and 'name' in cfg['database'] and 'host' in cfg['database'] and 'username' in cfg['database'] and 'password' in cfg['database']: connection = MySQLdb.connect(host = cfg['database']['host'], user = cfg['database']['username'], passwd = cfg['database']['password'], db = cfg['database']['name'], port = 3306) cursor = connection.cursor() @@ -83,17 +83,17 @@ if cfg.has_key('database') and cfg['database'].has_key('enabled') and cfg['datab GnuPG.add_key(cfg['gpg']['keyhome'], row[0]) # import the key to gpg cursor.execute("UPDATE gpgmw_keys SET status = 1 WHERE id = %s", (row[1],)) # mark key as accepted appendLog('Imported key from <' + row[2] + '>') - if cfg['cron'].has_key('send_email') and cfg['cron']['send_email'] == 'yes': + if 'send_email' in cfg['cron'] and cfg['cron']['send_email'] == 'yes': send_msg( "PGP key registration successful", "registrationSuccess.md", row[2] ) else: cursor.execute("DELETE FROM gpgmw_keys WHERE id = %s", (row[1],)) # delete key appendLog('Import confirmation failed for <' + row[2] + '>') - if cfg['cron'].has_key('send_email') and cfg['cron']['send_email'] == 'yes': + if 'send_email' in cfg['cron'] and cfg['cron']['send_email'] == 'yes': send_msg( "PGP key registration failed", "registrationError.md", row[2] ) else: # delete key so we don't continue processing it cursor.execute("DELETE FROM gpgmw_keys WHERE id = %s", (row[1],)) - if cfg['cron'].has_key('send_email') and cfg['cron']['send_email'] == 'yes': + if 'send_email' in cfg['cron'] and cfg['cron']['send_email'] == 'yes': send_msg( "PGP key deleted", "keyDeleted.md", row[2]) connection.commit() @@ -108,4 +108,4 @@ if cfg.has_key('database') and cfg['database'].has_key('enabled') and cfg['datab appendLog('Deleted key for <' + row[0] + '>') connection.commit() else: - print "Warning: doing nothing since database settings are not configured!" + print("Warning: doing nothing since database settings are not configured!") diff --git a/gpg-mailgate.py b/gpg-mailgate.py index b39c786..e520aa5 100755 --- a/gpg-mailgate.py +++ b/gpg-mailgate.py @@ -19,7 +19,7 @@ # along with gpg-mailgate source code. If not, see . # -from ConfigParser import RawConfigParser +from configparser import RawConfigParser from email.mime.base import MIMEBase from email.mime.multipart import MIMEMultipart import copy @@ -94,7 +94,7 @@ def gpg_decrypt( raw_message, recipients ): keys[fingerprint] = sanitize_case_sense(keys[fingerprint]) for to in recipients: - if to in keys.values() and not get_bool_from_cfg('default', 'dec_keymap_only', 'yes'): + if to in list(keys.values()) and not get_bool_from_cfg('default', 'dec_keymap_only', 'yes'): gpg_to.append(to) # Is this recipient defined in regex for default decryption? elif not (dec_regex is None) and not (re.match(dec_regex, to) is None): @@ -106,7 +106,7 @@ def gpg_decrypt( raw_message, recipients ): if not cfg['dec_keymap'][to] in keys: log("Key '%s' in decryption keymap not found in keyring for email address '%s'. Won't decrypt." % (cfg['dec_keymap'][to], to)) # Avoid unwanted encryption if set - if to in keys.values() and get_bool_from_cfg('default', 'failsave_dec', 'yes'): + if to in list(keys.values()) and get_bool_from_cfg('default', 'failsave_dec', 'yes'): noenc_to.append(to) else: ungpg_to.append(to) @@ -116,7 +116,7 @@ def gpg_decrypt( raw_message, recipients ): if verbose: log("Recipient (%s) not in PGP domain list for decrypting." % to) # Avoid unwanted encryption if set - if to in keys.values() and get_bool_from_cfg('default', 'failsave_dec', 'yes'): + if to in list(keys.values()) and get_bool_from_cfg('default', 'failsave_dec', 'yes'): noenc_to.append(to) else: ungpg_to.append(to) @@ -206,7 +206,7 @@ def decrypt_inline_with_attachments( payloads, success, message = None ): message = email.mime.multipart.MIMEMultipart(payloads.get_content_subtype()) for payload in payloads.get_payload(): - if( type( payload.get_payload() ) == list ): + if( isinstance(payload.get_payload(), list) ): # Take care of cascaded MIME messages submessage, subsuccess = decrypt_inline_with_attachments( payload, success ) message.attach(submessage) @@ -317,7 +317,7 @@ def gpg_encrypt( raw_message, recipients ): log("Key '%s' in encrypt keymap not found in keyring for email address '%s'." % (cfg['enc_keymap'][to], to)) # Check if key in keychain is present - if to in keys.values() and not get_bool_from_cfg('default', 'enc_keymap_only', 'yes'): + if to in list(keys.values()) and not get_bool_from_cfg('default', 'enc_keymap_only', 'yes'): gpg_to.append( (to, to) ) continue @@ -341,7 +341,7 @@ def gpg_encrypt( raw_message, recipients ): ungpg_to.append(to) if gpg_to != list(): - log("Encrypting email to: %s" % ' '.join( map(lambda x: x[0], gpg_to) )) + log("Encrypting email to: %s" % ' '.join( [x[0] for x in gpg_to] )) # Getting PGP style for recipient gpg_to_smtp_mime = list() @@ -378,8 +378,8 @@ def gpg_encrypt( raw_message, recipients ): if get_bool_from_cfg('default', 'add_header', 'yes'): raw_message_mime['X-GPG-Mailgate'] = 'Encrypted by GPG Mailgate' - if raw_message_mime.has_key('Content-Transfer-Encoding'): - raw_message_mime.replace_header('Content-Transfer-Encoding','8BIT') + if 'Content-Transfer-Encoding' in raw_message_mime: + raw_message_mime.replace_header('Content-Transfer-Encoding', '8BIT') else: raw_message_mime['Content-Transfer-Encoding'] = '8BIT' @@ -395,8 +395,8 @@ def gpg_encrypt( raw_message, recipients ): if get_bool_from_cfg('default', 'add_header', 'yes'): raw_message_inline['X-GPG-Mailgate'] = 'Encrypted by GPG Mailgate' - if raw_message_inline.has_key('Content-Transfer-Encoding'): - raw_message_inline.replace_header('Content-Transfer-Encoding','8BIT') + if 'Content-Transfer-Encoding' in raw_message_inline: + raw_message_inline.replace_header('Content-Transfer-Encoding', '8BIT') else: raw_message_inline['Content-Transfer-Encoding'] = '8BIT' @@ -411,11 +411,11 @@ def encrypt_all_payloads_inline( message, gpg_to_cmdline ): # This breaks cascaded MIME messages. Blame PGP/INLINE. encrypted_payloads = list() - if type( message.get_payload() ) == str: + if isinstance(message.get_payload(), str): return encrypt_payload( message, gpg_to_cmdline ).get_payload() for payload in message.get_payload(): - if( type( payload.get_payload() ) == list ): + if( isinstance(payload.get_payload(), list) ): encrypted_payloads.extend( encrypt_all_payloads_inline( payload, gpg_to_cmdline ) ) else: encrypted_payloads.append( encrypt_payload( payload, gpg_to_cmdline ) ) @@ -437,13 +437,13 @@ def encrypt_all_payloads_mime( message, gpg_to_cmdline ): submsg2.set_param('inline', "", 'Content-Disposition' ) submsg2.set_param('filename', "encrypted.asc", 'Content-Disposition' ) - if type ( message.get_payload() ) == str: + if isinstance(message.get_payload(), str): # WTF! It seems to swallow the first line. Not sure why. Perhaps # it's skipping an imaginary blank line someplace. (ie skipping a header) # Workaround it here by prepending a blank line. # This happens only on text only messages. additionalSubHeader="" - if message.has_key('Content-Type') and not message['Content-Type'].startswith('multipart'): + if 'Content-Type' in message and not message['Content-Type'].startswith('multipart'): additionalSubHeader="Content-Type: "+message['Content-Type']+"\n" submsg2.set_payload(additionalSubHeader+"\n" +message.get_payload(decode=True)) check_nested = True @@ -460,7 +460,7 @@ def encrypt_all_payloads_mime( message, gpg_to_cmdline ): boundary = junk_msg.get_boundary() # This also modifies the boundary in the body of the message, ie it gets parsed. - if message.has_key('Content-Type'): + if 'Content-Type' in message: message.replace_header('Content-Type', "multipart/encrypted; protocol=\"application/pgp-encrypted\";\nboundary=\"%s\"\n" % boundary) else: message['Content-Type'] = "multipart/encrypted; protocol=\"application/pgp-encrypted\";\nboundary=\"%s\"\n" % boundary @@ -608,7 +608,7 @@ def generate_message_from_payloads( payloads, message = None ): message = email.mime.multipart.MIMEMultipart(payloads.get_content_subtype()) for payload in payloads.get_payload(): - if( type( payload.get_payload() ) == list ): + if( isinstance(payload.get_payload(), list) ): message.attach(generate_message_from_payloads(payload)) else: message.attach(payload) @@ -624,7 +624,7 @@ def get_first_payload( payloads ): def send_msg( message, recipients ): - recipients = filter(None, recipients) + recipients = [_f for _f in recipients if _f] if recipients: if not (get_bool_from_cfg('relay', 'host') and get_bool_from_cfg('relay', 'port')): log("Missing settings for relay. Sending email aborted.") @@ -632,7 +632,7 @@ def send_msg( message, recipients ): log("Sending email to: <%s>" % '> <'.join( recipients )) relay = (cfg['relay']['host'], int(cfg['relay']['port'])) smtp = smtplib.SMTP(relay[0], relay[1]) - if cfg.has_key('relay') and cfg['relay'].has_key('starttls') and cfg['relay']['starttls'] == 'yes': + if 'relay' in cfg and 'starttls' in cfg['relay'] and cfg['relay']['starttls'] == 'yes': smtp.starttls() smtp.sendmail( from_addr, recipients, message ) else: diff --git a/register-handler.py b/register-handler.py index 5b1cf9a..f4c1e57 100644 --- a/register-handler.py +++ b/register-handler.py @@ -1,6 +1,6 @@ #!/usr/bin/python -from ConfigParser import RawConfigParser +from configparser import RawConfigParser import email, os, smtplib, sys, traceback, markdown, syslog, requests from M2Crypto import BIO, Rand, SMIME, X509 @@ -17,7 +17,7 @@ for sect in _cfg.sections(): cfg[sect][name] = value def log(msg): - if cfg.has_key('logging') and cfg['logging'].has_key('file'): + if 'logging' in cfg and 'file' in cfg['logging']: if cfg['logging']['file'] == "syslog": syslog.syslog(syslog.LOG_INFO | syslog.LOG_MAIL, msg) else: @@ -78,9 +78,9 @@ if __name__ == "__main__": sys.exit(0) if sign_type == 'smime': - raw_sig = sign_part.get_payload().replace("\n","") + raw_sig = sign_part.get_payload().replace("\n", "") # re-wrap signature so that it fits base64 standards - cooked_sig = '\n'.join(raw_sig[pos:pos+76] for pos in xrange(0, len(raw_sig), 76)) + cooked_sig = '\n'.join(raw_sig[pos:pos+76] for pos in range(0, len(raw_sig), 76)) # now, wrap the signature in a PKCS7 block sig = """ @@ -106,7 +106,7 @@ if __name__ == "__main__": # format in user-specific data # sending success mail only for S/MIME as GPGMW handles this on its own success_msg = file(cfg['mailregister']['mail_templates']+"/registrationSuccess.md").read() - success_msg = success_msg.replace("[:FROMADDRESS:]",from_addr) + success_msg = success_msg.replace("[:FROMADDRESS:]", from_addr) msg = MIMEMultipart("alternative") msg["From"] = cfg['mailregister']['register_email'] @@ -128,7 +128,7 @@ if __name__ == "__main__": if r.status_code != 200: log("Could not hand registration over to GPGMW. Error: %s" % r.status_code) error_msg = file(cfg['mailregister']['mail_templates']+"/gpgmwFailed.md").read() - error_msg = error_msg.replace("[:FROMADDRESS:]",from_addr) + error_msg = error_msg.replace("[:FROMADDRESS:]", from_addr) msg = MIMEMultipart("alternative") msg["From"] = cfg['mailregister']['register_email'] diff --git a/test/e2e_test.py b/test/e2e_test.py index d53d6d9..0f7705f 100644 --- a/test/e2e_test.py +++ b/test/e2e_test.py @@ -24,7 +24,7 @@ import sys import difflib -import ConfigParser +import configparser import logging from time import sleep @@ -35,7 +35,7 @@ CONFIG_FILE = "test/gpg-mailgate.conf" PYTHON_BIN = "python2.7" def build_config(config): - cp = ConfigParser.ConfigParser() + cp = configparser.ConfigParser() cp.add_section("logging") cp.set("logging", "file", config["log_file"]) @@ -83,7 +83,7 @@ def report_result(message_file, expected, test_output): else: status = "Failure" - print message_file.ljust(30), status + print(message_file.ljust(30), status) def execute_e2e_test(case_name, config, config_path): """Read test case configuration from config and run that test case. @@ -116,7 +116,7 @@ def execute_e2e_test(case_name, config, config_path): report_result(config.get(case_name, "in"), config.get(case_name, "out"), testout) def load_test_config(): - cp = ConfigParser.ConfigParser() + cp = configparser.ConfigParser() cp.read("test/e2e.ini") return cp @@ -146,4 +146,4 @@ for case_no in range(1, config.getint("tests", "cases")+1): execute_e2e_test(case_name, config, config_path) -print "See diagnostic output for details. Tests: '%s', Lacre: '%s'" % (config.get("tests", "e2e_log"), config.get("tests", "lacre_log")) +print("See diagnostic output for details. Tests: '%s', Lacre: '%s'" % (config.get("tests", "e2e_log"), config.get("tests", "lacre_log"))) diff --git a/test/relay.py b/test/relay.py index 01b93d4..bc6969c 100644 --- a/test/relay.py +++ b/test/relay.py @@ -40,8 +40,8 @@ def serve(port): try: s.bind(('', port)) s.listen(1) - except socket.error, e: - print "Cannot connect", e + except socket.error as e: + print("Cannot connect", e) sys.exit(EXIT_UNAVAILABLE) (conn, addr) = s.accept() @@ -69,7 +69,7 @@ def serve(port): return message[:-len(EOM)] def error(msg): - print "ERROR: %s" % (msg) + print("ERROR: %s" % (msg)) sys.exit(1) @@ -79,4 +79,4 @@ if len(sys.argv) < 2: port = int(sys.argv[1]) body = serve(port) -print body +print(body) From b2a01c15b075fded0fb2e46bcafc179dc91de751 Mon Sep 17 00:00:00 2001 From: "Piotr F. Mieszkowski" Date: Sun, 9 Jan 2022 15:01:38 +0100 Subject: [PATCH 02/12] Fix auto-migrated code - Use b'' (byte strings) where appropriate. - Fix indentation. - Replace python2.x references with python3.x. --- Makefile | 2 +- gpg-mailgate.py | 20 ++++++++++---------- test/e2e_test.py | 12 ++++++------ test/relay.py | 29 +++++++++++++++++------------ 4 files changed, 34 insertions(+), 29 deletions(-) diff --git a/Makefile b/Makefile index a14332a..7184529 100644 --- a/Makefile +++ b/Makefile @@ -1,4 +1,4 @@ -PYTHON = python2.7 +PYTHON = python3.8 .PHONY: test pre-clean clean diff --git a/gpg-mailgate.py b/gpg-mailgate.py index e520aa5..39fcc61 100755 --- a/gpg-mailgate.py +++ b/gpg-mailgate.py @@ -255,7 +255,7 @@ def decrypt_inline_with_attachments( payloads, success, message = None ): # There was no encrypted payload found, so the original payload is attached message.attach(payload) - return message, success + return message, success def decrypt_inline_without_attachments( decrypted_message ): @@ -379,9 +379,9 @@ def gpg_encrypt( raw_message, recipients ): raw_message_mime['X-GPG-Mailgate'] = 'Encrypted by GPG Mailgate' if 'Content-Transfer-Encoding' in raw_message_mime: - raw_message_mime.replace_header('Content-Transfer-Encoding', '8BIT') - else: - raw_message_mime['Content-Transfer-Encoding'] = '8BIT' + raw_message_mime.replace_header('Content-Transfer-Encoding', '8BIT') + else: + raw_message_mime['Content-Transfer-Encoding'] = '8BIT' encrypted_payloads = encrypt_all_payloads_mime( raw_message_mime, gpg_to_cmdline_mime ) raw_message_mime.set_payload( encrypted_payloads ) @@ -396,9 +396,9 @@ def gpg_encrypt( raw_message, recipients ): raw_message_inline['X-GPG-Mailgate'] = 'Encrypted by GPG Mailgate' if 'Content-Transfer-Encoding' in raw_message_inline: - raw_message_inline.replace_header('Content-Transfer-Encoding', '8BIT') - else: - raw_message_inline['Content-Transfer-Encoding'] = '8BIT' + raw_message_inline.replace_header('Content-Transfer-Encoding', '8BIT') + else: + raw_message_inline['Content-Transfer-Encoding'] = '8BIT' encrypted_payloads = encrypt_all_payloads_inline( raw_message_inline, gpg_to_cmdline_inline ) raw_message_inline.set_payload( encrypted_payloads ) @@ -632,8 +632,8 @@ def send_msg( message, recipients ): log("Sending email to: <%s>" % '> <'.join( recipients )) relay = (cfg['relay']['host'], int(cfg['relay']['port'])) smtp = smtplib.SMTP(relay[0], relay[1]) - if 'relay' in cfg and 'starttls' in cfg['relay'] and cfg['relay']['starttls'] == 'yes': - smtp.starttls() + if 'relay' in cfg and 'starttls' in cfg['relay'] and cfg['relay']['starttls'] == 'yes': + smtp.starttls() smtp.sendmail( from_addr, recipients, message ) else: log("No recipient found") @@ -658,7 +658,7 @@ def sort_recipients( raw_message, from_addr, to_addrs ): return first_payload = first_payload.get_payload(decode=True) - if "-----BEGIN PGP MESSAGE-----" in first_payload and "-----END PGP MESSAGE-----" in first_payload: + if b"-----BEGIN PGP MESSAGE-----" in first_payload and b"-----END PGP MESSAGE-----" in first_payload: if verbose: log("Message is already encrypted as PGP/INLINE. Encryption aborted.") send_msg(raw_message.as_string(), recipients_left) diff --git a/test/e2e_test.py b/test/e2e_test.py index 0f7705f..619ce75 100644 --- a/test/e2e_test.py +++ b/test/e2e_test.py @@ -1,4 +1,4 @@ -#!/usr/local/bin/python2 +#!/usr/local/bin/python3.8 # # gpg-mailgate @@ -32,7 +32,7 @@ from time import sleep RELAY_SCRIPT = "test/relay.py" CONFIG_FILE = "test/gpg-mailgate.conf" -PYTHON_BIN = "python2.7" +PYTHON_BIN = "python3.8" def build_config(config): cp = configparser.ConfigParser() @@ -55,7 +55,7 @@ def build_config(config): cp.set("enc_keymap", "alice@disposlab", "1CD245308F0963D038E88357973CF4D9387C44D7") cp.set("enc_keymap", "bob@disposlab", "19CF4B47ECC9C47AFA84D4BD96F39FDA0E31BB67") - logging.debug("Created config with keyhome=%s, cert_path=%s and relay at port %d" % + logging.debug("Created config with keyhome=%s, cert_path=%s and relay at port %s" % (config["gpg_keyhome"], config["smime_certpath"], config["port"])) return cp @@ -128,14 +128,14 @@ logging.basicConfig(filename = config.get("tests", "e2e_log"), # Get raw values of log and date formats because they # contain %-sequences and we don't want them to be expanded # by the ConfigParser. - format = config.get("tests", "e2e_log_format", True), - datefmt = config.get("tests", "e2e_log_datefmt", True), + format = config.get("tests", "e2e_log_format", raw=True), + datefmt = config.get("tests", "e2e_log_datefmt", raw=True), level = logging.DEBUG) config_path = os.getcwd() + "/" + CONFIG_FILE write_test_config(config_path, - port = config.getint("relay", "port"), + port = config.get("relay", "port"), gpg_keyhome = config.get("dirs", "keys"), smime_certpath = config.get("dirs", "certs"), log_file = config.get("tests", "lacre_log")) diff --git a/test/relay.py b/test/relay.py index bc6969c..a8e3db7 100644 --- a/test/relay.py +++ b/test/relay.py @@ -14,38 +14,43 @@ import socket EXIT_UNAVAILABLE = 1 +ENCODING = 'utf-8' + BUFFER_SIZE = 4096 EOM = "\r\n.\r\n" LAST_LINE = -3 def welcome(msg): - return "220 %s\r\n" % (msg) + return b"220 %b\r\n" % (msg) -def ok(msg = "OK"): - return "250 %s\r\n" % (msg) +def ok(msg = b"OK"): + return b"250 %b\r\n" % (msg) def bye(): - return "251 Bye" + return b"251 Bye" def provide_message(): - return "354 Enter a message, ending it with a '.' on a line by itself\r\n" + return b"354 Enter a message, ending it with a '.' on a line by itself\r\n" def receive_and_confirm(session): session.recv(BUFFER_SIZE) session.sendall(ok()) +def localhost_at(port): + return ('127.0.0.1', port) + def serve(port): s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) try: - s.bind(('', port)) + s.bind(localhost_at(port)) s.listen(1) except socket.error as e: print("Cannot connect", e) sys.exit(EXIT_UNAVAILABLE) (conn, addr) = s.accept() - conn.sendall(welcome("TEST SERVER")) + conn.sendall(welcome(b"TEST SERVER")) receive_and_confirm(conn) # Ignore HELO/EHLO receive_and_confirm(conn) # Ignore sender address @@ -57,8 +62,8 @@ def serve(port): # Consume until we get ., the end-of-message marker. message = '' while not message.endswith(EOM): - message += conn.recv(BUFFER_SIZE) - conn.sendall(ok("OK, id=test")) + message += conn.recv(BUFFER_SIZE).decode(ENCODING) + conn.sendall(ok(b"OK, id=test")) conn.recv(BUFFER_SIZE) conn.sendall(bye()) @@ -68,13 +73,13 @@ def serve(port): # Trim EOM marker as we're only interested in the message body. return message[:-len(EOM)] -def error(msg): +def error(msg, exit_code): print("ERROR: %s" % (msg)) - sys.exit(1) + sys.exit(exit_code) if len(sys.argv) < 2: - error("Usage: relay.py PORT_NUMBER") + error("Usage: relay.py PORT_NUMBER", EXIT_UNAVAILABLE) port = int(sys.argv[1]) body = serve(port) From 1e7d33c1df9c7810568bfab67d65edc1bd2c62fa Mon Sep 17 00:00:00 2001 From: "Piotr F. Mieszkowski" Date: Sun, 9 Jan 2022 17:56:09 +0100 Subject: [PATCH 03/12] Handle bytes properly Fix bytes sequences handling after auto-migration. --- GnuPG/__init__.py | 3 ++- gpg-mailgate.py | 10 +++++++--- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/GnuPG/__init__.py b/GnuPG/__init__.py index 6404720..b20c3d8 100644 --- a/GnuPG/__init__.py +++ b/GnuPG/__init__.py @@ -58,6 +58,7 @@ def public_keys( keyhome ): fingerprint = None email = None for line in p.stdout.readlines(): + line = line.decode('utf-8') if line[0:3] == LINE_FINGERPRINT: fingerprint = line.split(':')[POS_FINGERPRINT] if line[0:3] == LINE_USER_ID: @@ -120,7 +121,7 @@ def delete_key( keyhome, email ): class GPGEncryptor: def __init__(self, keyhome, recipients = None, charset = None): self._keyhome = keyhome - self._message = '' + self._message = b'' self._recipients = list() self._charset = charset if recipients != None: diff --git a/gpg-mailgate.py b/gpg-mailgate.py index 39fcc61..d360255 100755 --- a/gpg-mailgate.py +++ b/gpg-mailgate.py @@ -470,7 +470,7 @@ def encrypt_all_payloads_mime( message, gpg_to_cmdline ): def encrypt_payload( payload, gpg_to_cmdline, check_nested = True ): raw_payload = payload.get_payload(decode=True) - if check_nested and "-----BEGIN PGP MESSAGE-----" in raw_payload and "-----END PGP MESSAGE-----" in raw_payload: + if check_nested and b"-----BEGIN PGP MESSAGE-----" in raw_payload and b"-----END PGP MESSAGE-----" in raw_payload: if verbose: log("Message is already pgp encrypted. No nested encryption needed.") return payload @@ -596,9 +596,13 @@ def sanitize_case_sense( address ): if get_bool_from_cfg('default', 'mail_case_insensitive', 'yes'): address = address.lower() else: - splitted_address = address.split('@') + if isinstance(address, str): + sep = '@' + else: + sep = b'@' + splitted_address = address.split(sep) if len(splitted_address) > 1: - address = splitted_address[0] + '@' + splitted_address[1].lower() + address = splitted_address[0] + sep + splitted_address[1].lower() return address From 24f0c86d4f480feafed6a42206a10b95587a1ee0 Mon Sep 17 00:00:00 2001 From: "Piotr F. Mieszkowski" Date: Mon, 10 Jan 2022 18:30:19 +0100 Subject: [PATCH 04/12] Tidy up tests - Makefile: add 'unittest' to .PHONY targets. - Remove unnecessary #! line from e2e_test.py. - Extract Python path to test/e2e.ini file. --- Makefile | 2 +- test/e2e.ini | 1 + test/e2e_test.py | 8 ++------ 3 files changed, 4 insertions(+), 7 deletions(-) diff --git a/Makefile b/Makefile index 7184529..4b31a51 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,6 @@ PYTHON = python3.8 -.PHONY: test pre-clean clean +.PHONY: test unittest pre-clean clean # # Run a set of end-to-end tests. diff --git a/test/e2e.ini b/test/e2e.ini index 2d6fb0b..c964ebf 100644 --- a/test/e2e.ini +++ b/test/e2e.ini @@ -31,6 +31,7 @@ certs: test/certs [tests] # Number of "test-*" sections in this file, describing test cases. cases: 3 +python_path: /usr/local/bin/python3.8 e2e_log: test/logs/e2e.log e2e_log_format: %(asctime)s %(pathname)s:%(lineno)d %(levelname)s [%(funcName)s] %(message)s e2e_log_datefmt: %Y-%m-%d %H:%M:%S diff --git a/test/e2e_test.py b/test/e2e_test.py index 619ce75..d04216a 100644 --- a/test/e2e_test.py +++ b/test/e2e_test.py @@ -1,5 +1,3 @@ -#!/usr/local/bin/python3.8 - # # gpg-mailgate # @@ -32,8 +30,6 @@ from time import sleep RELAY_SCRIPT = "test/relay.py" CONFIG_FILE = "test/gpg-mailgate.conf" -PYTHON_BIN = "python3.8" - def build_config(config): cp = configparser.ConfigParser() @@ -95,10 +91,10 @@ def execute_e2e_test(case_name, config, config_path): test_command = "GPG_MAILGATE_CONFIG=%s %s gpg-mailgate.py %s < %s" % ( config_path, - PYTHON_BIN, + config.get("tests", "python_path"), config.get(case_name, "to"), config.get(case_name, "in")) - result_command = "%s %s %d" % (PYTHON_BIN, config.get("relay", "script"), config.getint("relay", "port")) + result_command = "%s %s %d" % (config.get("tests", "python_path"), config.get("relay", "script"), config.getint("relay", "port")) logging.debug("Spawning relay: '%s'" % (result_command)) pipe = os.popen(result_command, 'r') From 435528de433b410caccbd9d4662d63f65b74db8f Mon Sep 17 00:00:00 2001 From: "Piotr F. Mieszkowski" Date: Mon, 10 Jan 2022 19:32:46 +0100 Subject: [PATCH 05/12] Add an E2E test case with an already encrypted message --- test/e2e.ini | 8 +++++++- test/msgin/ed2ed.msg | 13 +++++++++++++ 2 files changed, 20 insertions(+), 1 deletion(-) create mode 100644 test/msgin/ed2ed.msg diff --git a/test/e2e.ini b/test/e2e.ini index c964ebf..feac655 100644 --- a/test/e2e.ini +++ b/test/e2e.ini @@ -30,7 +30,7 @@ certs: test/certs [tests] # Number of "test-*" sections in this file, describing test cases. -cases: 3 +cases: 4 python_path: /usr/local/bin/python3.8 e2e_log: test/logs/e2e.log e2e_log_format: %(asctime)s %(pathname)s:%(lineno)d %(levelname)s [%(funcName)s] %(message)s @@ -54,3 +54,9 @@ descr: Clear text message to a user with an Ed25519 key to: bob@disposlab in: test/msgin/clear2ed.msg out: -----BEGIN PGP MESSAGE----- + +[case-4] +descr: Encrypted message to a user with an Ed25519 key +to: bob@disposlab +in: test/msgin/ed2ed.msg +out: -----BEGIN PGP MESSAGE----- diff --git a/test/msgin/ed2ed.msg b/test/msgin/ed2ed.msg new file mode 100644 index 0000000..90b73a8 --- /dev/null +++ b/test/msgin/ed2ed.msg @@ -0,0 +1,13 @@ +From: Dave +To: Bob +Subject: Test +Content-Transfer-Encoding: 7bit + +-----BEGIN PGP MESSAGE----- + +hF4DujWCoRS24dYSAQdAyGDF9Us11JDr8+XPmvlJHsMS7A4UBIcCiresJyZpSxYw +Cqcugy5AX5fgSAiL1Cd2b1zpQ/rYdTWkFYMVbH4jBEoPC3z/aSd+hTnneJFDUdXl +0koBDIw7NQylu6SrW+Y/DmXgalIHtwACuKivJTq/z9jdwFScV7adRR/VO53Inah3 +L1+Ho7Zta95AYW3UPu71Gw3rrkfjY4uGDiFAFg== +=yTzD +-----END PGP MESSAGE----- From 5a8d2c0108c0c9c3cb5f8e91fa115087c4d6bfe8 Mon Sep 17 00:00:00 2001 From: "Piotr F. Mieszkowski" Date: Mon, 10 Jan 2022 19:48:44 +0100 Subject: [PATCH 06/12] Add E2E cases: signed cleartext and multipart/encrypted --- test/e2e.ini | 14 +++++++++++- test/msgin/multipart2rsa.msg | 43 ++++++++++++++++++++++++++++++++++++ test/msgin/signed.msg | 39 ++++++++++++++++++++++++++++++++ 3 files changed, 95 insertions(+), 1 deletion(-) create mode 100644 test/msgin/multipart2rsa.msg create mode 100644 test/msgin/signed.msg diff --git a/test/e2e.ini b/test/e2e.ini index feac655..8ad8577 100644 --- a/test/e2e.ini +++ b/test/e2e.ini @@ -30,7 +30,7 @@ certs: test/certs [tests] # Number of "test-*" sections in this file, describing test cases. -cases: 4 +cases: 6 python_path: /usr/local/bin/python3.8 e2e_log: test/logs/e2e.log e2e_log_format: %(asctime)s %(pathname)s:%(lineno)d %(levelname)s [%(funcName)s] %(message)s @@ -60,3 +60,15 @@ descr: Encrypted message to a user with an Ed25519 key to: bob@disposlab in: test/msgin/ed2ed.msg out: -----BEGIN PGP MESSAGE----- + +[case-5] +descr: Signed message to a user with an Ed25519 key +to: bob@disposlab +in: test/msgin/signed.msg +out: -----BEGIN PGP MESSAGE----- + +[case-6] +descr: Multipart encrypted message to a user with an Ed25519 key. +to: bob@disposlab +in: test/msgin/multipart2rsa.msg +out: -----BEGIN PGP MESSAGE----- diff --git a/test/msgin/multipart2rsa.msg b/test/msgin/multipart2rsa.msg new file mode 100644 index 0000000..3b8f623 --- /dev/null +++ b/test/msgin/multipart2rsa.msg @@ -0,0 +1,43 @@ +Date: Sun, 18 Jul 2021 16:53:45 +0200 +From: User Alice +To: User Bob +Subject: encrypted +Message-ID: +MIME-Version: 1.0 +Content-Type: multipart/encrypted; protocol="application/pgp-encrypted"; + boundary="95hZs/zeBetwhuEy" +Content-Disposition: inline +Status: RO +Content-Length: 1140 +Lines: 30 + + +--95hZs/zeBetwhuEy +Content-Type: application/pgp-encrypted +Content-Disposition: attachment + +Version: 1 + +--95hZs/zeBetwhuEy +Content-Type: application/octet-stream +Content-Disposition: attachment; filename="msg.asc" + +-----BEGIN PGP MESSAGE----- + +hQGMA/vsqjpkmZurAQwAnb+2kDPgVFWVLkafuzVJGqFWKNtdVsvk7I1zhzFw5Hsr +h4irSHcH0X0QjaHprNiMBDfIZaCx5VVsvGYLiu/iQkdVPXItugTpln8aAvDt8/Bp +Hse69tgG5S9o4fPK4K2bMjNdomclDdz51cu9NXYjk/6OtzVwcSypyEmxgw24Oo1+ +Q8KfZN9n6VTXGNlrV9KnAZYs/5aaSABTeC+cDvOcjDbPAmwDHYS3qsbITYoGHnEz +QfPIakYWPtPWkajhm4Z/iyEUSTeqew1/gAJ8sZnJpV0eg1Cr/44XgklZKFr8aJgk +SG8PkQxsyzAZklpwMSWdbb+t9a5nEKvky3zMpdmS1GE7ubTO7nQ1geUdBiv1UUNh +BY9d4nlGirqxX1MZUTGZidJgCy0365xbJSKkU0yFFW2uWtCKzJTEQBk3YZkNmnGH +h8BiVvMhQ8SxKBRPeH6Zb6HHlbcgkPvJAAI4VLqkZPCBvp9irmcdFGmrgCWLxzgk +sIjYGLA+ZuSXOKuAssXE0sAbASPAkUJRTIjzXFrCnr/MB3ZonESH01fsbsX+E/Qi ++2oLrgjjPHcPq76fvdO6fJP6c1pM8TlOoZKn/RkPm1llULtOn4n5JZJjeUA0F2ID +Te/U9i4YtcFZbuvw2bjeu8sAf77U6O3iTTBWkPWQT3H4YMskQc7lS1Mug6A9HL/n +TQvAwh2MIveYyEy/y/dKeFUbpSKxyOInhTg1XtYFiT8bzEF7OEJLU9GyF5oMs67d +o12uYlEnPhWz9oZp11aSdnyeADpVu6BQsPbwfTifcpajQSarH5sG8+rDSPju +=7CnH +-----END PGP MESSAGE----- + +--95hZs/zeBetwhuEy-- diff --git a/test/msgin/signed.msg b/test/msgin/signed.msg new file mode 100644 index 0000000..917291e --- /dev/null +++ b/test/msgin/signed.msg @@ -0,0 +1,39 @@ +Date: Sun, 18 Jul 2021 12:08:41 +0200 +From: User Alice +To: User Bob +Subject: signed +Message-ID: +MIME-Version: 1.0 +Content-Type: multipart/signed; micalg=pgp-sha256; + protocol="application/pgp-signature"; boundary="U/XjR71RAixRcb28" +Content-Disposition: inline +Status: RO +Content-Length: 870 +Lines: 26 + + +--U/XjR71RAixRcb28 +Content-Type: text/plain; charset=us-ascii +Content-Disposition: inline + +A signed msg. + +--U/XjR71RAixRcb28 +Content-Type: application/pgp-signature; name="signature.asc" + +-----BEGIN PGP SIGNATURE----- + +iQGzBAEBCAAdFiEEHNJFMI8JY9A46INXlzz02Th8RNcFAmDz/aUACgkQlzz02Th8 +RNdtOQv/ca8c51KoVq7CyPJUr54n4DEk/LlYniR0W51tL2a4rQxyF2AxqjdI8T4u +bT1+bqPNYgegesyCLokeZKqhLVtCH+UVOTdtUq5bB1J7ALuuVTOIdR5woMBBsazV +ETYEMzL6y2sGPW92ynriEw6B9pPnFKFPhOOZLrnMzM8CpkTfNmGoej+EdV74s0z4 +RayKu/WaZ1Dtx2Vy2YDtG36p/Y3n62bnzQJCRyPYfrmCxH5X5i5oibQwxLROCFNE +4X3iVZLPHFg/DS9m4L7mBe0MJewGa1oPFr7t3ZfJ+24aJ/AvUv5uQIO+s6a7AcjD +Pgw/IjeM/uZdPrzniZI2zsWEgsjRCL1fj49XWVNkTHrWCqLvkBg+suucNO2SR0/d +ps+RP5mkJJHaSZyPpxwo9/PHKX67Mkpn/uEXlE8nV6IqKoXRzr1N0qwyhvbZQZLD +FMumxx/eOSiOpaiRhGhoZiUpf+VdnV/1ClpAcdbthy/psx/CMYVblAM8xg74NR9+ +Q/WlFbRl +=uMdE +-----END PGP SIGNATURE----- + +--U/XjR71RAixRcb28-- From c81c6e6e0d991219b4d0729b3377d1cedef85ad1 Mon Sep 17 00:00:00 2001 From: "Piotr F. Mieszkowski" Date: Mon, 10 Jan 2022 20:22:17 +0100 Subject: [PATCH 07/12] Remove hardcoded python3.8 path - Let the user overwrite Python binary name while calling make. - Use environment variable set by make to instruct e2e_test.py which binary it should call to execute Python code. --- Makefile | 14 ++++++++++++-- test/e2e.ini | 1 - test/e2e_test.py | 6 ++++-- 3 files changed, 16 insertions(+), 5 deletions(-) diff --git a/Makefile b/Makefile index 4b31a51..9c4ce7b 100644 --- a/Makefile +++ b/Makefile @@ -1,7 +1,17 @@ -PYTHON = python3.8 - +.POSIX: .PHONY: test unittest pre-clean clean +# +# On systems where Python 3.x binary has a different name, just +# overwrite the name/path on the command line, like: +# +# make test PYTHON=/usr/local/bin/python3.8 +# +# This marco is passed via environment to test/e2e_test.py, where it's +# used to compute further commands. +# +PYTHON = python3 + # # Run a set of end-to-end tests. # diff --git a/test/e2e.ini b/test/e2e.ini index 8ad8577..134a005 100644 --- a/test/e2e.ini +++ b/test/e2e.ini @@ -31,7 +31,6 @@ certs: test/certs [tests] # Number of "test-*" sections in this file, describing test cases. cases: 6 -python_path: /usr/local/bin/python3.8 e2e_log: test/logs/e2e.log e2e_log_format: %(asctime)s %(pathname)s:%(lineno)d %(levelname)s [%(funcName)s] %(message)s e2e_log_datefmt: %Y-%m-%d %H:%M:%S diff --git a/test/e2e_test.py b/test/e2e_test.py index d04216a..a3617d6 100644 --- a/test/e2e_test.py +++ b/test/e2e_test.py @@ -88,13 +88,15 @@ def execute_e2e_test(case_name, config, config_path): config file. Each of these sections should contain following properties: 'descr', 'to', 'in' and 'out'. """ + # This environment variable is set in Makefile. + python_path = os.getenv('PYTHON', 'python3') test_command = "GPG_MAILGATE_CONFIG=%s %s gpg-mailgate.py %s < %s" % ( config_path, - config.get("tests", "python_path"), + python_path, config.get(case_name, "to"), config.get(case_name, "in")) - result_command = "%s %s %d" % (config.get("tests", "python_path"), config.get("relay", "script"), config.getint("relay", "port")) + result_command = "%s %s %d" % (python_path, config.get("relay", "script"), config.getint("relay", "port")) logging.debug("Spawning relay: '%s'" % (result_command)) pipe = os.popen(result_command, 'r') From a201265f871c45eb5ee44b90fea1cf4d2ce81e39 Mon Sep 17 00:00:00 2001 From: "Piotr F. Mieszkowski" Date: Wed, 19 Jan 2022 21:57:46 +0100 Subject: [PATCH 08/12] Rework how E2E tests are executed Tests kept breaking (not failing) randomly with "Broken pipe" errors. Rework how processes are spawned to make sure that it doesn't break them again. --- test/e2e_test.py | 44 +++++++++++++++++++++++++++++--------------- 1 file changed, 29 insertions(+), 15 deletions(-) diff --git a/test/e2e_test.py b/test/e2e_test.py index a3617d6..efc9e3c 100644 --- a/test/e2e_test.py +++ b/test/e2e_test.py @@ -20,6 +20,8 @@ import os import sys +import subprocess + import difflib import configparser @@ -70,7 +72,7 @@ def load_file(name): contents = f.read() f.close() - return contents + return bytes(contents, 'utf-8') def report_result(message_file, expected, test_output): status = None @@ -91,23 +93,35 @@ def execute_e2e_test(case_name, config, config_path): # This environment variable is set in Makefile. python_path = os.getenv('PYTHON', 'python3') - test_command = "GPG_MAILGATE_CONFIG=%s %s gpg-mailgate.py %s < %s" % ( - config_path, - python_path, - config.get(case_name, "to"), - config.get(case_name, "in")) - result_command = "%s %s %d" % (python_path, config.get("relay", "script"), config.getint("relay", "port")) + gpglacre_cmd = [python_path, + "gpg-mailgate.py", + config.get(case_name, "to")] - logging.debug("Spawning relay: '%s'" % (result_command)) - pipe = os.popen(result_command, 'r') + relay_cmd = [python_path, + config.get("relay", "script"), + config.get("relay", "port")] - logging.debug("Spawning GPG-Lacre: '%s'" % (test_command)) - msgin = os.popen(test_command, 'w') - msgin.write(load_file(config.get(case_name, "in"))) - msgin.close() + logging.debug("Spawning relay: '%s'" % (relay_cmd)) + relay_proc = subprocess.Popen(relay_cmd, + stdin = None, + stdout = subprocess.PIPE) - testout = pipe.read() - pipe.close() + logging.debug("Spawning GPG-Lacre: '%s', stdin = %s" + % (gpglacre_cmd, + config.get(case_name, "in"))) + + # pass PATH because otherwise it would be dropped + gpglacre_proc = subprocess.run(gpglacre_cmd, + input = load_file(config.get(case_name, "in")), + capture_output = True, + env = {"GPG_MAILGATE_CONFIG": config_path, + "PATH": os.getenv("PATH")}) + + # Let the relay process the data. + relay_proc.wait() + + (testout, _) = relay_proc.communicate() + testout = testout.decode('utf-8') logging.debug("Read %d characters of test output: '%s'" % (len(testout), testout)) From 03fc3d138e277b432ecc1488a5bec80a54f20aa2 Mon Sep 17 00:00:00 2001 From: "Piotr F. Mieszkowski" Date: Wed, 19 Jan 2022 22:16:27 +0100 Subject: [PATCH 09/12] Update testing documentation - Explain how to specify Python binary path used during tests. - Mention test logs. --- doc/testing.md | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/doc/testing.md b/doc/testing.md index a462b0f..d018770 100644 --- a/doc/testing.md +++ b/doc/testing.md @@ -11,6 +11,10 @@ To run tests, use command `make test` or `make unittest`. Tests produce some helpful logs, so inspect contents of `test/logs` directory if something goes wrong. +If your system's Python binary isn't found in your `$PATH` or you want to use +a specific binary, use make's macro overriding: `make test +PYTHON=/path/to/python`. + ## Key building blocks - *Test Script* (`test/e2e_test.py`) that orchestrates the other components. @@ -29,3 +33,8 @@ Currently tests only check if the message has been encrypted, without verifying that the correct key has been used. That's because we don't know (yet) how to have a reproducible encrypted message. Option `--faked-system-time` wasn't enough to produce identical output. + +## Troubleshooting + +When things go wrong, be sure to study `test/logs/e2e.log` and +`test/logs/gpg-mailgate.log` files -- they contain some useful information. From 67a938c049dd15215031f02d2075640a3e4971e7 Mon Sep 17 00:00:00 2001 From: "Piotr F. Mieszkowski" Date: Tue, 25 Jan 2022 20:32:17 +0100 Subject: [PATCH 10/12] GnuPG.add_key: Use build_command --- GnuPG/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/GnuPG/__init__.py b/GnuPG/__init__.py index b20c3d8..8bcfebd 100644 --- a/GnuPG/__init__.py +++ b/GnuPG/__init__.py @@ -102,7 +102,7 @@ def confirm_key( content, email ): # adds a key and ensures it has the given email address def add_key( keyhome, content ): - p = subprocess.Popen( ['/usr/bin/gpg', '--homedir', keyhome, '--import', '--batch'], stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE ) + p = subprocess.Popen( build_command(keyhome, '--import', '--batch'), stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE ) p.communicate(input=content) p.wait() From 9e17726e39f0407f32926b866bbaaaee021bb8cb Mon Sep 17 00:00:00 2001 From: "Piotr F. Mieszkowski" Date: Sun, 6 Feb 2022 00:13:15 +0100 Subject: [PATCH 11/12] Use f-strings for formatting --- test/e2e_test.py | 19 ++++++++----------- 1 file changed, 8 insertions(+), 11 deletions(-) diff --git a/test/e2e_test.py b/test/e2e_test.py index efc9e3c..f937fa9 100644 --- a/test/e2e_test.py +++ b/test/e2e_test.py @@ -53,19 +53,18 @@ def build_config(config): cp.set("enc_keymap", "alice@disposlab", "1CD245308F0963D038E88357973CF4D9387C44D7") cp.set("enc_keymap", "bob@disposlab", "19CF4B47ECC9C47AFA84D4BD96F39FDA0E31BB67") - logging.debug("Created config with keyhome=%s, cert_path=%s and relay at port %s" % - (config["gpg_keyhome"], config["smime_certpath"], config["port"])) + logging.debug(f"Created config with keyhome={config['gpg_keyhome']}, cert_path={config['smime_certpath']} and relay at port {config['port']}") return cp def write_test_config(outfile, **config): - logging.debug("Generating configuration with %s" % repr(config)) + logging.debug(f"Generating configuration with {config!r}") out = open(outfile, "w+") cp = build_config(config) cp.write(out) out.close() - logging.debug("Wrote configuration to %s" % outfile) + logging.debug(f"Wrote configuration to {outfile}") def load_file(name): f = open(name, 'r') @@ -101,14 +100,12 @@ def execute_e2e_test(case_name, config, config_path): config.get("relay", "script"), config.get("relay", "port")] - logging.debug("Spawning relay: '%s'" % (relay_cmd)) + logging.debug(f"Spawning relay: {relay_cmd}") relay_proc = subprocess.Popen(relay_cmd, stdin = None, stdout = subprocess.PIPE) - logging.debug("Spawning GPG-Lacre: '%s', stdin = %s" - % (gpglacre_cmd, - config.get(case_name, "in"))) + logging.debug(f"Spawning GPG-Lacre: {gpglacre_cmd}, stdin = {config.get(case_name, 'in')}") # pass PATH because otherwise it would be dropped gpglacre_proc = subprocess.run(gpglacre_cmd, @@ -123,7 +120,7 @@ def execute_e2e_test(case_name, config, config_path): (testout, _) = relay_proc.communicate() testout = testout.decode('utf-8') - logging.debug("Read %d characters of test output: '%s'" % (len(testout), testout)) + logging.debug(f"Read {len(testout)} characters of test output: '{testout}'") report_result(config.get(case_name, "in"), config.get(case_name, "out"), testout) @@ -153,8 +150,8 @@ write_test_config(config_path, log_file = config.get("tests", "lacre_log")) for case_no in range(1, config.getint("tests", "cases")+1): - case_name = "case-%d" % (case_no) - logging.info("Executing %s: %s", case_name, config.get(case_name, "descr")) + case_name = f"case-{case_no}" + logging.info(f"Executing {case_name}: {config.get(case_name, 'descr')}") execute_e2e_test(case_name, config, config_path) From c4927d2722580e6c329ec755abcd31d3ecdd77aa Mon Sep 17 00:00:00 2001 From: "Piotr F. Mieszkowski" Date: Sun, 6 Feb 2022 00:27:38 +0100 Subject: [PATCH 12/12] Avoid unnecessary list creation --- gpg-mailgate.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/gpg-mailgate.py b/gpg-mailgate.py index d360255..5c8090a 100755 --- a/gpg-mailgate.py +++ b/gpg-mailgate.py @@ -94,7 +94,7 @@ def gpg_decrypt( raw_message, recipients ): keys[fingerprint] = sanitize_case_sense(keys[fingerprint]) for to in recipients: - if to in list(keys.values()) and not get_bool_from_cfg('default', 'dec_keymap_only', 'yes'): + if to in keys.values() and not get_bool_from_cfg('default', 'dec_keymap_only', 'yes'): gpg_to.append(to) # Is this recipient defined in regex for default decryption? elif not (dec_regex is None) and not (re.match(dec_regex, to) is None): @@ -106,7 +106,7 @@ def gpg_decrypt( raw_message, recipients ): if not cfg['dec_keymap'][to] in keys: log("Key '%s' in decryption keymap not found in keyring for email address '%s'. Won't decrypt." % (cfg['dec_keymap'][to], to)) # Avoid unwanted encryption if set - if to in list(keys.values()) and get_bool_from_cfg('default', 'failsave_dec', 'yes'): + if to in keys.values() and get_bool_from_cfg('default', 'failsave_dec', 'yes'): noenc_to.append(to) else: ungpg_to.append(to) @@ -116,7 +116,7 @@ def gpg_decrypt( raw_message, recipients ): if verbose: log("Recipient (%s) not in PGP domain list for decrypting." % to) # Avoid unwanted encryption if set - if to in list(keys.values()) and get_bool_from_cfg('default', 'failsave_dec', 'yes'): + if to in keys.values() and get_bool_from_cfg('default', 'failsave_dec', 'yes'): noenc_to.append(to) else: ungpg_to.append(to) @@ -317,7 +317,7 @@ def gpg_encrypt( raw_message, recipients ): log("Key '%s' in encrypt keymap not found in keyring for email address '%s'." % (cfg['enc_keymap'][to], to)) # Check if key in keychain is present - if to in list(keys.values()) and not get_bool_from_cfg('default', 'enc_keymap_only', 'yes'): + if to in keys.values() and not get_bool_from_cfg('default', 'enc_keymap_only', 'yes'): gpg_to.append( (to, to) ) continue @@ -341,7 +341,7 @@ def gpg_encrypt( raw_message, recipients ): ungpg_to.append(to) if gpg_to != list(): - log("Encrypting email to: %s" % ' '.join( [x[0] for x in gpg_to] )) + log("Encrypting email to: %s" % ' '.join( x[0] for x in gpg_to )) # Getting PGP style for recipient gpg_to_smtp_mime = list()