##// END OF EJS Templates
tests: show test-patchbomb-tls.t smtp server log...
Mads Kiilerich -
r51622:5644f628 stable
parent child Browse files
Show More
@@ -1,120 +1,122 b''
1 #!/usr/bin/env python
1 #!/usr/bin/env python
2
2
3 """dummy SMTP server for use in tests"""
3 """dummy SMTP server for use in tests"""
4
4
5
5
6 import asyncore
6 import asyncore
7 import optparse
7 import optparse
8 import smtpd
8 import smtpd
9 import ssl
9 import ssl
10 import sys
10 import sys
11 import traceback
11 import traceback
12
12
13 from mercurial import (
13 from mercurial import (
14 pycompat,
14 pycompat,
15 server,
15 server,
16 sslutil,
16 sslutil,
17 ui as uimod,
17 ui as uimod,
18 )
18 )
19
19
20
20
21 def log(msg):
21 def log(msg):
22 sys.stdout.write(msg)
22 sys.stdout.write(msg)
23 sys.stdout.flush()
23 sys.stdout.flush()
24
24
25
25
26 class dummysmtpserver(smtpd.SMTPServer):
26 class dummysmtpserver(smtpd.SMTPServer):
27 def __init__(self, localaddr):
27 def __init__(self, localaddr):
28 smtpd.SMTPServer.__init__(self, localaddr, remoteaddr=None)
28 smtpd.SMTPServer.__init__(self, localaddr, remoteaddr=None)
29
29
30 def process_message(self, peer, mailfrom, rcpttos, data, **kwargs):
30 def process_message(self, peer, mailfrom, rcpttos, data, **kwargs):
31 log('%s from=%s to=%s\n' % (peer[0], mailfrom, ', '.join(rcpttos)))
31 log('%s from=%s to=%s\n' % (peer[0], mailfrom, ', '.join(rcpttos)))
32
32
33 def handle_error(self):
33 def handle_error(self):
34 # On Windows, a bad SSL connection sometimes generates a WSAECONNRESET.
34 # On Windows, a bad SSL connection sometimes generates a WSAECONNRESET.
35 # The default handler will shutdown this server, and then both the
35 # The default handler will shutdown this server, and then both the
36 # current connection and subsequent ones fail on the client side with
36 # current connection and subsequent ones fail on the client side with
37 # "No connection could be made because the target machine actively
37 # "No connection could be made because the target machine actively
38 # refused it". If we eat the error, then the client properly aborts in
38 # refused it". If we eat the error, then the client properly aborts in
39 # the expected way, and the server is available for subsequent requests.
39 # the expected way, and the server is available for subsequent requests.
40 traceback.print_exc()
40 traceback.print_exc()
41
41
42
42
43 class dummysmtpsecureserver(dummysmtpserver):
43 class dummysmtpsecureserver(dummysmtpserver):
44 def __init__(self, localaddr, certfile):
44 def __init__(self, localaddr, certfile):
45 dummysmtpserver.__init__(self, localaddr)
45 dummysmtpserver.__init__(self, localaddr)
46 self._certfile = certfile
46 self._certfile = certfile
47
47
48 def handle_accept(self):
48 def handle_accept(self):
49 pair = self.accept()
49 pair = self.accept()
50 if not pair:
50 if not pair:
51 return
51 return
52 conn, addr = pair
52 conn, addr = pair
53 ui = uimod.ui.load()
53 ui = uimod.ui.load()
54 try:
54 try:
55 # wrap_socket() would block, but we don't care
55 # wrap_socket() would block, but we don't care
56 conn = sslutil.wrapserversocket(conn, ui, certfile=self._certfile)
56 conn = sslutil.wrapserversocket(conn, ui, certfile=self._certfile)
57 except ssl.SSLError:
57 except ssl.SSLError:
58 log('%s ssl error\n' % addr[0])
58 log('%s ssl error\n' % addr[0])
59 conn.close()
59 conn.close()
60 return
60 return
61 smtpd.SMTPChannel(self, conn, addr)
61 smtpd.SMTPChannel(self, conn, addr)
62
62
63
63
64 def run():
64 def run():
65 try:
65 try:
66 asyncore.loop()
66 asyncore.loop()
67 except KeyboardInterrupt:
67 except KeyboardInterrupt:
68 pass
68 pass
69
69
70
70
71 def _encodestrsonly(v):
71 def _encodestrsonly(v):
72 if isinstance(v, type(u'')):
72 if isinstance(v, type(u'')):
73 return v.encode('ascii')
73 return v.encode('ascii')
74 return v
74 return v
75
75
76
76
77 def bytesvars(obj):
77 def bytesvars(obj):
78 unidict = vars(obj)
78 unidict = vars(obj)
79 bd = {k.encode('ascii'): _encodestrsonly(v) for k, v in unidict.items()}
79 bd = {k.encode('ascii'): _encodestrsonly(v) for k, v in unidict.items()}
80 if bd[b'daemon_postexec'] is not None:
80 if bd[b'daemon_postexec'] is not None:
81 bd[b'daemon_postexec'] = [
81 bd[b'daemon_postexec'] = [
82 _encodestrsonly(v) for v in bd[b'daemon_postexec']
82 _encodestrsonly(v) for v in bd[b'daemon_postexec']
83 ]
83 ]
84 return bd
84 return bd
85
85
86
86
87 def main():
87 def main():
88 op = optparse.OptionParser()
88 op = optparse.OptionParser()
89 op.add_option('-d', '--daemon', action='store_true')
89 op.add_option('-d', '--daemon', action='store_true')
90 op.add_option('--daemon-postexec', action='append')
90 op.add_option('--daemon-postexec', action='append')
91 op.add_option('-p', '--port', type=int, default=8025)
91 op.add_option('-p', '--port', type=int, default=8025)
92 op.add_option('-a', '--address', default='localhost')
92 op.add_option('-a', '--address', default='localhost')
93 op.add_option('--pid-file', metavar='FILE')
93 op.add_option('--pid-file', metavar='FILE')
94 op.add_option('--tls', choices=['none', 'smtps'], default='none')
94 op.add_option('--tls', choices=['none', 'smtps'], default='none')
95 op.add_option('--certificate', metavar='FILE')
95 op.add_option('--certificate', metavar='FILE')
96 op.add_option('--logfile', metavar='FILE')
96
97
97 opts, args = op.parse_args()
98 opts, args = op.parse_args()
98 if opts.tls == 'smtps' and not opts.certificate:
99 if opts.tls == 'smtps' and not opts.certificate:
99 op.error('--certificate must be specified')
100 op.error('--certificate must be specified')
100
101
101 addr = (opts.address, opts.port)
102 addr = (opts.address, opts.port)
102
103
103 def init():
104 def init():
104 if opts.tls == 'none':
105 if opts.tls == 'none':
105 dummysmtpserver(addr)
106 dummysmtpserver(addr)
106 else:
107 else:
107 dummysmtpsecureserver(addr, opts.certificate)
108 dummysmtpsecureserver(addr, opts.certificate)
108 log('listening at %s:%d\n' % addr)
109 log('listening at %s:%d\n' % addr)
109
110
110 server.runservice(
111 server.runservice(
111 bytesvars(opts),
112 bytesvars(opts),
112 initfn=init,
113 initfn=init,
113 runfn=run,
114 runfn=run,
114 runargs=[pycompat.sysexecutable, pycompat.fsencode(__file__)]
115 runargs=[pycompat.sysexecutable, pycompat.fsencode(__file__)]
115 + pycompat.sysargv[1:],
116 + pycompat.sysargv[1:],
117 logfile=opts.logfile,
116 )
118 )
117
119
118
120
119 if __name__ == '__main__':
121 if __name__ == '__main__':
120 main()
122 main()
@@ -1,99 +1,111 b''
1 #require serve ssl
1 #require serve ssl
2
2
3 Set up SMTP server:
3 Set up SMTP server:
4
4
5 $ CERTSDIR="$TESTDIR/sslcerts"
5 $ CERTSDIR="$TESTDIR/sslcerts"
6 $ cat "$CERTSDIR/priv.pem" "$CERTSDIR/pub.pem" >> server.pem
6 $ cat "$CERTSDIR/priv.pem" "$CERTSDIR/pub.pem" >> server.pem
7
7
8 $ "$PYTHON" "$TESTDIR/dummysmtpd.py" -p $HGPORT --pid-file a.pid -d \
8 $ "$PYTHON" "$TESTDIR/dummysmtpd.py" -p $HGPORT --pid-file a.pid --logfile log -d \
9 > --tls smtps --certificate `pwd`/server.pem
9 > --tls smtps --certificate `pwd`/server.pem
10 listening at localhost:$HGPORT (?)
10 listening at localhost:$HGPORT (?)
11 $ cat a.pid >> $DAEMON_PIDS
11 $ cat a.pid >> $DAEMON_PIDS
12
12
13 Set up repository:
13 Set up repository:
14
14
15 $ hg init t
15 $ hg init t
16 $ cd t
16 $ cd t
17 $ cat <<EOF >> .hg/hgrc
17 $ cat <<EOF >> .hg/hgrc
18 > [extensions]
18 > [extensions]
19 > patchbomb =
19 > patchbomb =
20 > [email]
20 > [email]
21 > method = smtp
21 > method = smtp
22 > [smtp]
22 > [smtp]
23 > host = localhost
23 > host = localhost
24 > port = $HGPORT
24 > port = $HGPORT
25 > tls = smtps
25 > tls = smtps
26 > EOF
26 > EOF
27
27
28 $ echo a > a
28 $ echo a > a
29 $ hg commit -Ama -d '1 0'
29 $ hg commit -Ama -d '1 0'
30 adding a
30 adding a
31
31
32 Utility functions:
32 Utility functions:
33
33
34 $ DISABLECACERTS=
34 $ DISABLECACERTS=
35 $ try () {
35 $ try () {
36 > hg email $DISABLECACERTS -f quux -t foo -c bar -r tip "$@"
36 > hg email $DISABLECACERTS -f quux -t foo -c bar -r tip "$@"
37 > }
37 > }
38
38
39 Our test cert is not signed by a trusted CA. It should fail to verify if
39 Our test cert is not signed by a trusted CA. It should fail to verify if
40 we are able to load CA certs:
40 we are able to load CA certs:
41
41
42 #if no-defaultcacertsloaded
42 #if no-defaultcacertsloaded
43 $ try
43 $ try
44 this patch series consists of 1 patches.
44 this patch series consists of 1 patches.
45
45
46
46
47 (an attempt was made to load CA certificates but none were loaded; see https://mercurial-scm.org/wiki/SecureConnections for how to configure Mercurial to avoid this error)
47 (an attempt was made to load CA certificates but none were loaded; see https://mercurial-scm.org/wiki/SecureConnections for how to configure Mercurial to avoid this error)
48 (?i)abort: .*?certificate.verify.failed.* (re)
48 (?i)abort: .*?certificate.verify.failed.* (re)
49 [255]
49 [255]
50 #endif
50 #endif
51
51
52 #if defaultcacertsloaded
52 #if defaultcacertsloaded
53 $ try
53 $ try
54 this patch series consists of 1 patches.
54 this patch series consists of 1 patches.
55
55
56
56
57 (the full certificate chain may not be available locally; see "hg help debugssl") (windows !)
57 (the full certificate chain may not be available locally; see "hg help debugssl") (windows !)
58 (?i)abort: .*?certificate.verify.failed.* (re)
58 (?i)abort: .*?certificate.verify.failed.* (re)
59 [255]
59 [255]
60
60
61 #endif
61 #endif
62
62
63 $ DISABLECACERTS="--config devel.disableloaddefaultcerts=true"
63 $ DISABLECACERTS="--config devel.disableloaddefaultcerts=true"
64
64
65 Without certificates:
65 Without certificates:
66
66
67 $ try --debug
67 $ try --debug
68 this patch series consists of 1 patches.
68 this patch series consists of 1 patches.
69
69
70
70
71 (using smtps)
71 (using smtps)
72 sending mail: smtp host localhost, port * (glob)
72 sending mail: smtp host localhost, port * (glob)
73 (verifying remote certificate)
73 (verifying remote certificate)
74 abort: unable to verify security of localhost (no loaded CA certificates); refusing to connect
74 abort: unable to verify security of localhost (no loaded CA certificates); refusing to connect
75 (see https://mercurial-scm.org/wiki/SecureConnections for how to configure Mercurial to avoid this error or set hostsecurity.localhost:fingerprints=sha256:20:de:b3:ad:b4:cd:a5:42:f0:74:41:1c:a2:70:1e:da:6e:c0:5c:16:9e:e7:22:0f:f1:b7:e5:6e:e4:92:af:7e to trust this server)
75 (see https://mercurial-scm.org/wiki/SecureConnections for how to configure Mercurial to avoid this error or set hostsecurity.localhost:fingerprints=sha256:20:de:b3:ad:b4:cd:a5:42:f0:74:41:1c:a2:70:1e:da:6e:c0:5c:16:9e:e7:22:0f:f1:b7:e5:6e:e4:92:af:7e to trust this server)
76 [150]
76 [150]
77
77
78 $ cat ../log
79 * ssl error (glob)
80 $ : > ../log
81
78 With global certificates:
82 With global certificates:
79
83
80 $ try --debug --config web.cacerts="$CERTSDIR/pub.pem"
84 $ try --debug --config web.cacerts="$CERTSDIR/pub.pem"
81 this patch series consists of 1 patches.
85 this patch series consists of 1 patches.
82
86
83
87
84 (using smtps)
88 (using smtps)
85 sending mail: smtp host localhost, port * (glob)
89 sending mail: smtp host localhost, port * (glob)
86 (verifying remote certificate)
90 (verifying remote certificate)
87 sending [PATCH] a ...
91 sending [PATCH] a ...
88
92
93 $ cat ../log
94 * from=quux to=foo, bar (glob)
95 $ : > ../log
96
89 With invalid certificates:
97 With invalid certificates:
90
98
91 $ try --config web.cacerts="$CERTSDIR/pub-other.pem"
99 $ try --config web.cacerts="$CERTSDIR/pub-other.pem"
92 this patch series consists of 1 patches.
100 this patch series consists of 1 patches.
93
101
94
102
95 (the full certificate chain may not be available locally; see "hg help debugssl") (windows !)
103 (the full certificate chain may not be available locally; see "hg help debugssl") (windows !)
96 (?i)abort: .*?certificate.verify.failed.* (re)
104 (?i)abort: .*?certificate.verify.failed.* (re)
97 [255]
105 [255]
98
106
107 $ cat ../log
108 * ssl error (glob)
109 $ : > ../log
110
99 $ cd ..
111 $ cd ..
General Comments 0
You need to be logged in to leave comments. Login now