Merge dkimpy-milter:dkg/python3 into dkimpy-milter:1_0
- Git
- lp:dkimpy-milter
- dkg/python3
- Merge into 1_0
Proposed by
dkg
| Status: | Merged |
|---|---|
| Merge reported by: | Scott Kitterman |
| Merged at revision: | ea09bab1a8fb9eeed3429e9a8411ee42f9c423f3 |
| Proposed branch: | dkimpy-milter:dkg/python3 |
| Merge into: | dkimpy-milter:1_0 |
| Prerequisite: | dkimpy-milter:dkg/test-suite |
| Diff against target: |
327 lines (+55/-56) 6 files modified
dkimpy_milter/__init__.py (+31/-32) dkimpy_milter/__main__.py (+1/-1) dkimpy_milter/config.py (+10/-10) dkimpy_milter/dnsplug.py (+8/-8) setup.py (+4/-4) tests/dkimpy-milter (+1/-1) |
| Related bugs: |
| Reviewer | Review Type | Date Requested | Status |
|---|---|---|---|
| Scott Kitterman | Pending | ||
|
Review via email:
|
|||
Commit message
This brief series converts dkimpy-milter to python3. It depends on the test-suite branch to verify that the major functionality remains functional.
Description of the change
To post a comment you must log in.
Preview Diff
[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
| 1 | diff --git a/dkimpy_milter/__init__.py b/dkimpy_milter/__init__.py |
| 2 | index 5345fc7..bcdf2a7 100644 |
| 3 | --- a/dkimpy_milter/__init__.py |
| 4 | +++ b/dkimpy_milter/__init__.py |
| 5 | @@ -1,4 +1,4 @@ |
| 6 | -#! /usr/bin/python2 |
| 7 | +#! /usr/bin/python3 |
| 8 | # Original dkim-milter.py code: |
| 9 | # Author: Stuart D. Gathman <stuart@bmsi.com> |
| 10 | # Copyright 2007 Business Management Systems, Inc. |
| 11 | @@ -28,8 +28,9 @@ import dkim |
| 12 | import authres |
| 13 | import os |
| 14 | import tempfile |
| 15 | -import StringIO |
| 16 | +import io |
| 17 | import re |
| 18 | +import codecs |
| 19 | from Milter.utils import parse_addr, parseaddr |
| 20 | import dkimpy_milter.config as config |
| 21 | from dkimpy_milter.util import drop_privileges |
| 22 | @@ -110,7 +111,7 @@ class dkimMilter(Milter.Base): |
| 23 | def envfrom(self, f, *str): |
| 24 | if milterconfig.get('Syslog') and milterconfig.get('debugLevel') >= 2: |
| 25 | syslog.syslog("mail from: {0} {1}".format(f, str)) |
| 26 | - self.fp = StringIO.StringIO() |
| 27 | + self.fp = io.BytesIO() |
| 28 | self.mailfrom = f |
| 29 | t = parse_addr(f) |
| 30 | if len(t) == 2: |
| 31 | @@ -142,13 +143,13 @@ class dkimMilter(Milter.Base): |
| 32 | elif lname == 'authentication-results': |
| 33 | self.arheaders.append(val) |
| 34 | if self.fp: |
| 35 | - self.fp.write("%s: %s\n" % (name, val)) |
| 36 | + self.fp.write(b"%s: %s\n" % (codecs.encode(name, 'ascii'), codecs.encode(val, 'ascii'))) |
| 37 | return Milter.CONTINUE |
| 38 | |
| 39 | @Milter.noreply |
| 40 | def eoh(self): |
| 41 | if self.fp: |
| 42 | - self.fp.write("\n") # terminate headers |
| 43 | + self.fp.write(b"\n") # terminate headers |
| 44 | self.bodysize = 0 |
| 45 | return Milter.CONTINUE |
| 46 | |
| 47 | @@ -195,20 +196,20 @@ class dkimMilter(Milter.Base): |
| 48 | h = authres.AuthenticationResultsHeader(authserv_id= |
| 49 | self.AuthservID, |
| 50 | results=self.arresults) |
| 51 | - h = fold(str(h)) |
| 52 | + h = fold(codecs.encode(str(h), 'ascii')) |
| 53 | if (milterconfig.get('Syslog') and |
| 54 | milterconfig.get('debugLevel') >= 2): |
| 55 | - syslog.syslog(str(h)) |
| 56 | - name, val = str(h).split(': ', 1) |
| 57 | + syslog.syslog(codecs.decode(h, 'ascii')) |
| 58 | + name, val = codecs.decode(h, 'ascii').split(': ', 1) |
| 59 | self.addheader(name, val, 0) |
| 60 | return Milter.CONTINUE |
| 61 | |
| 62 | def sign_dkim(self, txt): |
| 63 | - canon = milterconfig.get('Canonicalization') |
| 64 | + canon = codecs.encode(milterconfig.get('Canonicalization'), 'ascii') |
| 65 | canonicalize = [] |
| 66 | - if len(canon.split('/')) == 2: |
| 67 | - canonicalize.append(canon.split('/')[0]) |
| 68 | - canonicalize.append(canon.split('/')[1]) |
| 69 | + if len(canon.split(b'/')) == 2: |
| 70 | + canonicalize.append(canon.split(b'/')[0]) |
| 71 | + canonicalize.append(canon.split(b'/')[1]) |
| 72 | else: |
| 73 | canonicalize.append(canon) |
| 74 | canonicalize.append(canon) |
| 75 | @@ -218,11 +219,12 @@ class dkimMilter(Milter.Base): |
| 76 | try: |
| 77 | if privateRSA: |
| 78 | d = dkim.DKIM(txt) |
| 79 | - h = d.sign(milterconfig.get('Selector'), self.fdomain, |
| 80 | - privateRSA, canonicalize=(canonicalize[0], |
| 81 | - canonicalize[1])) |
| 82 | - name, val = h.split(': ', 1) |
| 83 | - self.addheader(name, val.strip().replace('\r\n', '\n'), 0) |
| 84 | + h = d.sign(codecs.encode(milterconfig.get('Selector'), 'ascii'), codecs.encode(self.fdomain, 'ascii'), |
| 85 | + codecs.encode(privateRSA, 'ascii'), |
| 86 | + canonicalize=(canonicalize[0], |
| 87 | + canonicalize[1])) |
| 88 | + name, val = h.split(b': ', 1) |
| 89 | + self.addheader(codecs.decode(name, 'ascii'), codecs.decode(val, 'ascii').strip().replace('\r\n', '\n'), 0) |
| 90 | if (milterconfig.get('Syslog') and |
| 91 | (milterconfig.get('SyslogSuccess') |
| 92 | or milterconfig.get('debugLevel') >= 1)): |
| 93 | @@ -233,12 +235,12 @@ class dkimMilter(Milter.Base): |
| 94 | d.domain.lower())) |
| 95 | if privateEd25519: |
| 96 | d = dkim.DKIM(txt) |
| 97 | - h = d.sign(milterconfig.get('SelectorEd25519'), self.fdomain, |
| 98 | + h = d.sign(codecs.encode(milterconfig.get('SelectorEd25519'), 'ascii'), codecs.encode(self.fdomain, 'ascii'), |
| 99 | privateEd25519, canonicalize=(canonicalize[0], |
| 100 | canonicalize[1]), |
| 101 | - signature_algorithm='ed25519-sha256') |
| 102 | - name, val = h.split(': ', 1) |
| 103 | - self.addheader(name, val.strip().replace('\r\n', '\n'), 0) |
| 104 | + signature_algorithm=b'ed25519-sha256') |
| 105 | + name, val = h.split(b': ', 1) |
| 106 | + self.addheader(codecs.decode(name, 'ascii'), codecs.decode(val, 'ascii').strip().replace('\r\n', '\n'), 0) |
| 107 | if (milterconfig.get('Syslog') and |
| 108 | (milterconfig.get('SyslogSuccess') |
| 109 | or milterconfig.get('debugLevel') >= 1)): |
| 110 | @@ -266,20 +268,17 @@ class dkimMilter(Milter.Base): |
| 111 | res = d.verify(idx=y, dnsfunc=lambda _x: dnsoverride) |
| 112 | else: |
| 113 | res = d.verify(idx=y) |
| 114 | + algo = codecs.decode(d.signature_fields.get(b'a'), 'ascii') |
| 115 | if res: |
| 116 | - if d.signature_fields.get(b'a') == 'ed25519-sha256': |
| 117 | + if algo == 'ed25519-sha256': |
| 118 | self.dkim_comment = ('Good {0} signature' |
| 119 | - .format(d.signature_fields |
| 120 | - .get(b'a'))) |
| 121 | + .format(algo)) |
| 122 | else: |
| 123 | self.dkim_comment = ('Good {0} bit {1} signature' |
| 124 | - .format(d.keysize, |
| 125 | - d.signature_fields |
| 126 | - .get(b'a'))) |
| 127 | + .format(d.keysize, algo)) |
| 128 | else: |
| 129 | self.dkim_comment = ('Bad {0} bit {1} signature.' |
| 130 | - .format(d.keysize, |
| 131 | - d.signature_fields.get(b'a'))) |
| 132 | + .format(d.keysize, algo)) |
| 133 | except dkim.DKIMException as x: |
| 134 | self.dkim_comment = str(x) |
| 135 | if milterconfig.get('Syslog'): |
| 136 | @@ -288,9 +287,9 @@ class dkimMilter(Milter.Base): |
| 137 | self.dkim_comment = str(x) |
| 138 | if milterconfig.get('Syslog'): |
| 139 | syslog.syslog("check_dkim: {0}".format(x)) |
| 140 | - self.header_i = d.signature_fields.get(b'i') |
| 141 | - self.header_d = d.signature_fields.get(b'd') |
| 142 | - self.header_a = d.signature_fields.get(b'a') |
| 143 | + self.header_i = codecs.decode(d.signature_fields.get(b'i'), 'ascii') |
| 144 | + self.header_d = codecs.decode(d.signature_fields.get(b'd'), 'ascii') |
| 145 | + self.header_a = codecs.decode(d.signature_fields.get(b'a'), 'ascii') |
| 146 | if res: |
| 147 | if (milterconfig.get('Syslog') and |
| 148 | (milterconfig.get('SyslogSuccess') or |
| 149 | diff --git a/dkimpy_milter/__main__.py b/dkimpy_milter/__main__.py |
| 150 | index 8c5cf9c..f95075f 100644 |
| 151 | --- a/dkimpy_milter/__main__.py |
| 152 | +++ b/dkimpy_milter/__main__.py |
| 153 | @@ -1,4 +1,4 @@ |
| 154 | -#!/usr/bin/python2 |
| 155 | +#!/usr/bin/python3 |
| 156 | |
| 157 | from dkimpy_milter import main |
| 158 | |
| 159 | diff --git a/dkimpy_milter/config.py b/dkimpy_milter/config.py |
| 160 | index d562e97..bf6551a 100644 |
| 161 | --- a/dkimpy_milter/config.py |
| 162 | +++ b/dkimpy_milter/config.py |
| 163 | @@ -31,13 +31,13 @@ import stat |
| 164 | import dkim |
| 165 | import socket |
| 166 | import ipaddress |
| 167 | -from dnsplug import Session |
| 168 | +from .dnsplug import Session |
| 169 | |
| 170 | # default values |
| 171 | defaultConfigData = { |
| 172 | 'Syslog': 'yes', |
| 173 | 'SyslogFacility': 'mail', |
| 174 | - 'UMask': 007, |
| 175 | + 'UMask': 0o07, |
| 176 | 'Mode': 'sv', |
| 177 | 'Socket': 'local:/var/run/dkimpy-milter/dkimpy-milter.sock', |
| 178 | 'PidFile': '/var/run/dkimpy-milter/dkimpy-milter.pid', |
| 179 | @@ -85,14 +85,14 @@ class HostsDataset(object): |
| 180 | self.item = item[1:] |
| 181 | self.negative = True |
| 182 | try: |
| 183 | - self.item = ipaddress.ip_address(unicode(self.item, "utf-8")) |
| 184 | + self.item = ipaddress.ip_address(str(self.item, "utf-8")) |
| 185 | if isinstance(self.item, ipaddress.IPv4Address): |
| 186 | self.isipv4 = True |
| 187 | elif isinstance(self.item, ipaddress.IPv6Address): |
| 188 | self.isipv6 = True |
| 189 | except ValueError as e: |
| 190 | try: |
| 191 | - self.item = ipaddress.ip_network(unicode |
| 192 | + self.item = ipaddress.ip_network(str |
| 193 | (self.item, "utf-8"), |
| 194 | strict=False) |
| 195 | if isinstance(self.item, ipaddress.IPv4Network): |
| 196 | @@ -110,7 +110,7 @@ class HostsDataset(object): |
| 197 | |
| 198 | def match(self, connectip): |
| 199 | '''Check if the connect IP is part of the dataset''' |
| 200 | - source = ipaddress.ip_address(unicode(connectip, "utf-8")) |
| 201 | + source = ipaddress.ip_address(str(connectip, "utf-8")) |
| 202 | for item in self.dataset: |
| 203 | if item.isdomain or item.ishostname: |
| 204 | result = self.matchname(source) # Match host/domains first |
| 205 | @@ -160,13 +160,13 @@ class HostsDataset(object): |
| 206 | if isinstance(source, ipaddress.IPv4Address): |
| 207 | ips = s.dns(name, 'A') |
| 208 | for ip in ips: |
| 209 | - ip = ipaddress.IPv4Address(unicode(ip, 'UTF-8')) |
| 210 | + ip = ipaddress.IPv4Address(str(ip, 'UTF-8')) |
| 211 | if ip == source: |
| 212 | results.append(name) |
| 213 | if isinstance(source, ipaddress.IPv6Address): |
| 214 | ips = s.dns(name, 'AAAA') |
| 215 | for ip in ips: |
| 216 | - ip = ipaddress.IPv6Address(unicode(ip, 'UTF-8')) |
| 217 | + ip = ipaddress.IPv6Address(str(ip, 'UTF-8')) |
| 218 | if ip == source: |
| 219 | results.append(name) |
| 220 | return results |
| 221 | @@ -225,13 +225,13 @@ def _processConfigFile(filename=None, configdata=None, useSyslog=1, |
| 222 | '''Load the specified config file, exit and log errors if it fails, |
| 223 | otherwise return a config dictionary.''' |
| 224 | |
| 225 | - import config |
| 226 | + from . import config |
| 227 | if configdata is None: |
| 228 | configdata = config.defaultConfigData |
| 229 | if filename is not None: |
| 230 | try: |
| 231 | _readConfigFile(filename, configdata) |
| 232 | - except Exception, e: |
| 233 | + except Exception as e: |
| 234 | raise |
| 235 | if useSyslog: |
| 236 | syslog.syslog(e.args[0]) |
| 237 | @@ -342,7 +342,7 @@ def _readConfigFile(path, configData=None, configGlobal={}): |
| 238 | # check to see if it's a file |
| 239 | try: |
| 240 | mode = os.stat(path)[0] |
| 241 | - except OSError, e: |
| 242 | + except OSError as e: |
| 243 | syslog.syslog(syslog.LOG_ERR, 'ERROR stating "%s": %s' |
| 244 | % (path, e.strerror)) |
| 245 | return(configData) |
| 246 | diff --git a/dkimpy_milter/dnsplug.py b/dkimpy_milter/dnsplug.py |
| 247 | index aa357ec..33067e9 100644 |
| 248 | --- a/dkimpy_milter/dnsplug.py |
| 249 | +++ b/dkimpy_milter/dnsplug.py |
| 250 | @@ -84,7 +84,7 @@ class Session(object): |
| 251 | raise DNSError('Length of CNAME chain exceeds %d' % MAX_CNAME) |
| 252 | cnames[name] = cname |
| 253 | if cname in cnames: |
| 254 | - raise DNSError, 'CNAME loop' |
| 255 | + raise DNSError('CNAME loop') |
| 256 | result = self.dns(cname, qtype, cnames=cnames) |
| 257 | return result |
| 258 | |
| 259 | @@ -103,16 +103,16 @@ def DNSLookup_pydns(name, qtype, tcpfallback=True, timeout=30): |
| 260 | # |
| 261 | if resp.header['tc'] == True: |
| 262 | if not tcpfallback: |
| 263 | - raise DNS.DNSError, 'DNS: Truncated UDP Reply, SPF records should fit in a UDP packet' |
| 264 | + raise DNS.DNSError('DNS: Truncated UDP Reply, SPF records should fit in a UDP packet') |
| 265 | try: |
| 266 | req = DNS.DnsRequest(name, qtype=qtype, protocol='tcp', |
| 267 | timeout=timeout) |
| 268 | resp = req.req() |
| 269 | - except DNS.DNSError, x: |
| 270 | - raise DNS.DNSError, 'TCP Fallback error: ' + str(x) |
| 271 | + except DNS.DNSError as x: |
| 272 | + raise DNS.DNSError('TCP Fallback error: ' + str(x)) |
| 273 | return [((a['name'], a['typename']), a['data']) for a in resp.answers] |
| 274 | - except IOError, x: |
| 275 | - raise DNS.DNSError, 'DNS: ' + str(x) |
| 276 | + except IOError as x: |
| 277 | + raise DNS.DNSError('DNS: ' + str(x)) |
| 278 | |
| 279 | def DNSLookup_dnspython(name,qtype,tcpfallback=True,timeout=30): |
| 280 | retVal = [] |
| 281 | @@ -164,5 +164,5 @@ if __name__ == '__main__': |
| 282 | import sys |
| 283 | s = Session() |
| 284 | for n,t in zip(*[iter(sys.argv[1:])]*2): |
| 285 | - print n,t |
| 286 | - print s.dns(n,t) |
| 287 | + print(n,t) |
| 288 | + print(s.dns(n,t)) |
| 289 | diff --git a/setup.py b/setup.py |
| 290 | index 18c2ec9..c7990d7 100644 |
| 291 | --- a/setup.py |
| 292 | +++ b/setup.py |
| 293 | @@ -1,4 +1,4 @@ |
| 294 | -#! /usr/bin/python |
| 295 | +#! /usr/bin/python3 |
| 296 | # dkimpy-milter: A DKIM signing/verification Milter application |
| 297 | # Author: Scott Kitterman <scott@kitterman.com> |
| 298 | # Copyright 2018 Scott Kitterman |
| 299 | @@ -24,9 +24,9 @@ description = "Domain Keys Identified Mail (DKIM) signing/verifying milter for P |
| 300 | kw = {} # Work-around for lack of 'or' requires in setuptools. |
| 301 | try: |
| 302 | import dns |
| 303 | - kw['install_requires'] = ['dkimpy>=0.7', 'pymilter', 'authres>=1.1.0', 'PyNaCl', 'ipaddress', 'dnspython'] |
| 304 | + kw['install_requires'] = ['dkimpy>=0.7', 'pymilter', 'authres>=1.1.0', 'PyNaCl', 'dnspython'] |
| 305 | except ImportError: # If PyDNS is not installed, prefer dnspython |
| 306 | - kw['install_requires'] = ['dkimpy>=0.7', 'pymilter', 'authres>=1.1.0', 'PyNaCl', 'ipaddress', 'PyDNS'] |
| 307 | + kw['install_requires'] = ['dkimpy>=0.7', 'pymilter', 'authres>=1.1.0', 'PyNaCl', 'PyDNS'] |
| 308 | |
| 309 | setup( |
| 310 | name='dkimpy-milter', |
| 311 | @@ -43,7 +43,7 @@ setup( |
| 312 | 'License :: OSI Approved :: GNU General Public License (GPL)', |
| 313 | 'Natural Language :: English', |
| 314 | 'Operating System :: POSIX', |
| 315 | - 'Programming Language :: Python :: 2 :: Only', |
| 316 | + 'Programming Language :: Python :: 3 :: Only', |
| 317 | 'Topic :: Communications :: Email :: Mail Transport Agents', |
| 318 | 'Topic :: Communications :: Email :: Filters', |
| 319 | 'Topic :: Security', |
| 320 | diff --git a/tests/dkimpy-milter b/tests/dkimpy-milter |
| 321 | index 39b64d5..9ee02e9 100755 |
| 322 | --- a/tests/dkimpy-milter |
| 323 | +++ b/tests/dkimpy-milter |
| 324 | @@ -1,2 +1,2 @@ |
| 325 | #!/bin/sh |
| 326 | -python2 -m dkimpy_milter "$@" |
| 327 | +python3 -m dkimpy_milter "$@" |