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 "$@" |