Mercurial > hg
annotate tests/httpserverauth.py @ 45161:9abdc0bd2ab9
mergestate: add comments about couple of record types and minor reorder
I am trying to divide the records into certain groups and then have dedicated
objects for them. Taking baby steps in that direction.
Differential Revision: https://phab.mercurial-scm.org/D8717
author | Pulkit Goyal <7895pulkit@gmail.com> |
---|---|
date | Thu, 09 Jul 2020 16:38:24 +0530 |
parents | 2372284d9457 |
children | 6000f5b25c9b |
rev | line source |
---|---|
41585
549af2fa089f
tests: extract the http server authentication extension to a single module
Matt Harbison <matt_harbison@yahoo.com>
parents:
diff
changeset
|
1 from __future__ import absolute_import |
549af2fa089f
tests: extract the http server authentication extension to a single module
Matt Harbison <matt_harbison@yahoo.com>
parents:
diff
changeset
|
2 |
549af2fa089f
tests: extract the http server authentication extension to a single module
Matt Harbison <matt_harbison@yahoo.com>
parents:
diff
changeset
|
3 import base64 |
41587
ccaa52865fac
tests: add code to handle HTTP digests on the server side
Matt Harbison <matt_harbison@yahoo.com>
parents:
41585
diff
changeset
|
4 import hashlib |
41585
549af2fa089f
tests: extract the http server authentication extension to a single module
Matt Harbison <matt_harbison@yahoo.com>
parents:
diff
changeset
|
5 |
549af2fa089f
tests: extract the http server authentication extension to a single module
Matt Harbison <matt_harbison@yahoo.com>
parents:
diff
changeset
|
6 from mercurial.hgweb import common |
43076
2372284d9457
formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents:
41589
diff
changeset
|
7 from mercurial import node |
2372284d9457
formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents:
41589
diff
changeset
|
8 |
41587
ccaa52865fac
tests: add code to handle HTTP digests on the server side
Matt Harbison <matt_harbison@yahoo.com>
parents:
41585
diff
changeset
|
9 |
ccaa52865fac
tests: add code to handle HTTP digests on the server side
Matt Harbison <matt_harbison@yahoo.com>
parents:
41585
diff
changeset
|
10 def parse_keqv_list(req, l): |
ccaa52865fac
tests: add code to handle HTTP digests on the server side
Matt Harbison <matt_harbison@yahoo.com>
parents:
41585
diff
changeset
|
11 """Parse list of key=value strings where keys are not duplicated.""" |
ccaa52865fac
tests: add code to handle HTTP digests on the server side
Matt Harbison <matt_harbison@yahoo.com>
parents:
41585
diff
changeset
|
12 parsed = {} |
ccaa52865fac
tests: add code to handle HTTP digests on the server side
Matt Harbison <matt_harbison@yahoo.com>
parents:
41585
diff
changeset
|
13 for elt in l: |
ccaa52865fac
tests: add code to handle HTTP digests on the server side
Matt Harbison <matt_harbison@yahoo.com>
parents:
41585
diff
changeset
|
14 k, v = elt.split(b'=', 1) |
ccaa52865fac
tests: add code to handle HTTP digests on the server side
Matt Harbison <matt_harbison@yahoo.com>
parents:
41585
diff
changeset
|
15 if v[0:1] == b'"' and v[-1:] == b'"': |
ccaa52865fac
tests: add code to handle HTTP digests on the server side
Matt Harbison <matt_harbison@yahoo.com>
parents:
41585
diff
changeset
|
16 v = v[1:-1] |
ccaa52865fac
tests: add code to handle HTTP digests on the server side
Matt Harbison <matt_harbison@yahoo.com>
parents:
41585
diff
changeset
|
17 parsed[k] = v |
ccaa52865fac
tests: add code to handle HTTP digests on the server side
Matt Harbison <matt_harbison@yahoo.com>
parents:
41585
diff
changeset
|
18 return parsed |
ccaa52865fac
tests: add code to handle HTTP digests on the server side
Matt Harbison <matt_harbison@yahoo.com>
parents:
41585
diff
changeset
|
19 |
43076
2372284d9457
formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents:
41589
diff
changeset
|
20 |
41587
ccaa52865fac
tests: add code to handle HTTP digests on the server side
Matt Harbison <matt_harbison@yahoo.com>
parents:
41585
diff
changeset
|
21 class digestauthserver(object): |
ccaa52865fac
tests: add code to handle HTTP digests on the server side
Matt Harbison <matt_harbison@yahoo.com>
parents:
41585
diff
changeset
|
22 def __init__(self): |
ccaa52865fac
tests: add code to handle HTTP digests on the server side
Matt Harbison <matt_harbison@yahoo.com>
parents:
41585
diff
changeset
|
23 self._user_hashes = {} |
ccaa52865fac
tests: add code to handle HTTP digests on the server side
Matt Harbison <matt_harbison@yahoo.com>
parents:
41585
diff
changeset
|
24 |
ccaa52865fac
tests: add code to handle HTTP digests on the server side
Matt Harbison <matt_harbison@yahoo.com>
parents:
41585
diff
changeset
|
25 def gethashers(self): |
ccaa52865fac
tests: add code to handle HTTP digests on the server side
Matt Harbison <matt_harbison@yahoo.com>
parents:
41585
diff
changeset
|
26 def _md5sum(x): |
ccaa52865fac
tests: add code to handle HTTP digests on the server side
Matt Harbison <matt_harbison@yahoo.com>
parents:
41585
diff
changeset
|
27 m = hashlib.md5() |
ccaa52865fac
tests: add code to handle HTTP digests on the server side
Matt Harbison <matt_harbison@yahoo.com>
parents:
41585
diff
changeset
|
28 m.update(x) |
ccaa52865fac
tests: add code to handle HTTP digests on the server side
Matt Harbison <matt_harbison@yahoo.com>
parents:
41585
diff
changeset
|
29 return node.hex(m.digest()) |
ccaa52865fac
tests: add code to handle HTTP digests on the server side
Matt Harbison <matt_harbison@yahoo.com>
parents:
41585
diff
changeset
|
30 |
ccaa52865fac
tests: add code to handle HTTP digests on the server side
Matt Harbison <matt_harbison@yahoo.com>
parents:
41585
diff
changeset
|
31 h = _md5sum |
ccaa52865fac
tests: add code to handle HTTP digests on the server side
Matt Harbison <matt_harbison@yahoo.com>
parents:
41585
diff
changeset
|
32 |
ccaa52865fac
tests: add code to handle HTTP digests on the server side
Matt Harbison <matt_harbison@yahoo.com>
parents:
41585
diff
changeset
|
33 kd = lambda s, d, h=h: h(b"%s:%s" % (s, d)) |
ccaa52865fac
tests: add code to handle HTTP digests on the server side
Matt Harbison <matt_harbison@yahoo.com>
parents:
41585
diff
changeset
|
34 return h, kd |
ccaa52865fac
tests: add code to handle HTTP digests on the server side
Matt Harbison <matt_harbison@yahoo.com>
parents:
41585
diff
changeset
|
35 |
ccaa52865fac
tests: add code to handle HTTP digests on the server side
Matt Harbison <matt_harbison@yahoo.com>
parents:
41585
diff
changeset
|
36 def adduser(self, user, password, realm): |
ccaa52865fac
tests: add code to handle HTTP digests on the server side
Matt Harbison <matt_harbison@yahoo.com>
parents:
41585
diff
changeset
|
37 h, kd = self.gethashers() |
ccaa52865fac
tests: add code to handle HTTP digests on the server side
Matt Harbison <matt_harbison@yahoo.com>
parents:
41585
diff
changeset
|
38 a1 = h(b'%s:%s:%s' % (user, realm, password)) |
ccaa52865fac
tests: add code to handle HTTP digests on the server side
Matt Harbison <matt_harbison@yahoo.com>
parents:
41585
diff
changeset
|
39 self._user_hashes[(user, realm)] = a1 |
ccaa52865fac
tests: add code to handle HTTP digests on the server side
Matt Harbison <matt_harbison@yahoo.com>
parents:
41585
diff
changeset
|
40 |
ccaa52865fac
tests: add code to handle HTTP digests on the server side
Matt Harbison <matt_harbison@yahoo.com>
parents:
41585
diff
changeset
|
41 def makechallenge(self, realm): |
ccaa52865fac
tests: add code to handle HTTP digests on the server side
Matt Harbison <matt_harbison@yahoo.com>
parents:
41585
diff
changeset
|
42 # We aren't testing the protocol here, just that the bytes make the |
ccaa52865fac
tests: add code to handle HTTP digests on the server side
Matt Harbison <matt_harbison@yahoo.com>
parents:
41585
diff
changeset
|
43 # proper round trip. So hardcoded seems fine. |
ccaa52865fac
tests: add code to handle HTTP digests on the server side
Matt Harbison <matt_harbison@yahoo.com>
parents:
41585
diff
changeset
|
44 nonce = b'064af982c5b571cea6450d8eda91c20d' |
43076
2372284d9457
formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents:
41589
diff
changeset
|
45 return b'realm="%s", nonce="%s", algorithm=MD5, qop="auth"' % ( |
2372284d9457
formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents:
41589
diff
changeset
|
46 realm, |
2372284d9457
formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents:
41589
diff
changeset
|
47 nonce, |
2372284d9457
formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents:
41589
diff
changeset
|
48 ) |
41587
ccaa52865fac
tests: add code to handle HTTP digests on the server side
Matt Harbison <matt_harbison@yahoo.com>
parents:
41585
diff
changeset
|
49 |
ccaa52865fac
tests: add code to handle HTTP digests on the server side
Matt Harbison <matt_harbison@yahoo.com>
parents:
41585
diff
changeset
|
50 def checkauth(self, req, header): |
ccaa52865fac
tests: add code to handle HTTP digests on the server side
Matt Harbison <matt_harbison@yahoo.com>
parents:
41585
diff
changeset
|
51 log = req.rawenv[b'wsgi.errors'] |
ccaa52865fac
tests: add code to handle HTTP digests on the server side
Matt Harbison <matt_harbison@yahoo.com>
parents:
41585
diff
changeset
|
52 |
ccaa52865fac
tests: add code to handle HTTP digests on the server side
Matt Harbison <matt_harbison@yahoo.com>
parents:
41585
diff
changeset
|
53 h, kd = self.gethashers() |
ccaa52865fac
tests: add code to handle HTTP digests on the server side
Matt Harbison <matt_harbison@yahoo.com>
parents:
41585
diff
changeset
|
54 resp = parse_keqv_list(req, header.split(b', ')) |
ccaa52865fac
tests: add code to handle HTTP digests on the server side
Matt Harbison <matt_harbison@yahoo.com>
parents:
41585
diff
changeset
|
55 |
ccaa52865fac
tests: add code to handle HTTP digests on the server side
Matt Harbison <matt_harbison@yahoo.com>
parents:
41585
diff
changeset
|
56 if resp.get(b'algorithm', b'MD5').upper() != b'MD5': |
ccaa52865fac
tests: add code to handle HTTP digests on the server side
Matt Harbison <matt_harbison@yahoo.com>
parents:
41585
diff
changeset
|
57 log.write(b'Unsupported algorithm: %s' % resp.get(b'algorithm')) |
43076
2372284d9457
formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents:
41589
diff
changeset
|
58 raise common.ErrorResponse( |
2372284d9457
formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents:
41589
diff
changeset
|
59 common.HTTP_FORBIDDEN, b"unknown algorithm" |
2372284d9457
formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents:
41589
diff
changeset
|
60 ) |
41587
ccaa52865fac
tests: add code to handle HTTP digests on the server side
Matt Harbison <matt_harbison@yahoo.com>
parents:
41585
diff
changeset
|
61 user = resp[b'username'] |
ccaa52865fac
tests: add code to handle HTTP digests on the server side
Matt Harbison <matt_harbison@yahoo.com>
parents:
41585
diff
changeset
|
62 realm = resp[b'realm'] |
ccaa52865fac
tests: add code to handle HTTP digests on the server side
Matt Harbison <matt_harbison@yahoo.com>
parents:
41585
diff
changeset
|
63 nonce = resp[b'nonce'] |
ccaa52865fac
tests: add code to handle HTTP digests on the server side
Matt Harbison <matt_harbison@yahoo.com>
parents:
41585
diff
changeset
|
64 |
ccaa52865fac
tests: add code to handle HTTP digests on the server side
Matt Harbison <matt_harbison@yahoo.com>
parents:
41585
diff
changeset
|
65 ha1 = self._user_hashes.get((user, realm)) |
ccaa52865fac
tests: add code to handle HTTP digests on the server side
Matt Harbison <matt_harbison@yahoo.com>
parents:
41585
diff
changeset
|
66 if not ha1: |
ccaa52865fac
tests: add code to handle HTTP digests on the server side
Matt Harbison <matt_harbison@yahoo.com>
parents:
41585
diff
changeset
|
67 log.write(b'No hash found for user/realm "%s/%s"' % (user, realm)) |
ccaa52865fac
tests: add code to handle HTTP digests on the server side
Matt Harbison <matt_harbison@yahoo.com>
parents:
41585
diff
changeset
|
68 raise common.ErrorResponse(common.HTTP_FORBIDDEN, b"bad user") |
ccaa52865fac
tests: add code to handle HTTP digests on the server side
Matt Harbison <matt_harbison@yahoo.com>
parents:
41585
diff
changeset
|
69 |
ccaa52865fac
tests: add code to handle HTTP digests on the server side
Matt Harbison <matt_harbison@yahoo.com>
parents:
41585
diff
changeset
|
70 qop = resp.get(b'qop', b'auth') |
ccaa52865fac
tests: add code to handle HTTP digests on the server side
Matt Harbison <matt_harbison@yahoo.com>
parents:
41585
diff
changeset
|
71 if qop != b'auth': |
ccaa52865fac
tests: add code to handle HTTP digests on the server side
Matt Harbison <matt_harbison@yahoo.com>
parents:
41585
diff
changeset
|
72 log.write(b"Unsupported qop: %s" % qop) |
ccaa52865fac
tests: add code to handle HTTP digests on the server side
Matt Harbison <matt_harbison@yahoo.com>
parents:
41585
diff
changeset
|
73 raise common.ErrorResponse(common.HTTP_FORBIDDEN, b"bad qop") |
ccaa52865fac
tests: add code to handle HTTP digests on the server side
Matt Harbison <matt_harbison@yahoo.com>
parents:
41585
diff
changeset
|
74 |
ccaa52865fac
tests: add code to handle HTTP digests on the server side
Matt Harbison <matt_harbison@yahoo.com>
parents:
41585
diff
changeset
|
75 cnonce, ncvalue = resp.get(b'cnonce'), resp.get(b'nc') |
ccaa52865fac
tests: add code to handle HTTP digests on the server side
Matt Harbison <matt_harbison@yahoo.com>
parents:
41585
diff
changeset
|
76 if not cnonce or not ncvalue: |
ccaa52865fac
tests: add code to handle HTTP digests on the server side
Matt Harbison <matt_harbison@yahoo.com>
parents:
41585
diff
changeset
|
77 log.write(b'No cnonce (%s) or ncvalue (%s)' % (cnonce, ncvalue)) |
ccaa52865fac
tests: add code to handle HTTP digests on the server side
Matt Harbison <matt_harbison@yahoo.com>
parents:
41585
diff
changeset
|
78 raise common.ErrorResponse(common.HTTP_FORBIDDEN, b"no cnonce") |
ccaa52865fac
tests: add code to handle HTTP digests on the server side
Matt Harbison <matt_harbison@yahoo.com>
parents:
41585
diff
changeset
|
79 |
ccaa52865fac
tests: add code to handle HTTP digests on the server side
Matt Harbison <matt_harbison@yahoo.com>
parents:
41585
diff
changeset
|
80 a2 = b'%s:%s' % (req.method, resp[b'uri']) |
ccaa52865fac
tests: add code to handle HTTP digests on the server side
Matt Harbison <matt_harbison@yahoo.com>
parents:
41585
diff
changeset
|
81 noncebit = b"%s:%s:%s:%s:%s" % (nonce, ncvalue, cnonce, qop, h(a2)) |
ccaa52865fac
tests: add code to handle HTTP digests on the server side
Matt Harbison <matt_harbison@yahoo.com>
parents:
41585
diff
changeset
|
82 |
ccaa52865fac
tests: add code to handle HTTP digests on the server side
Matt Harbison <matt_harbison@yahoo.com>
parents:
41585
diff
changeset
|
83 respdig = kd(ha1, noncebit) |
ccaa52865fac
tests: add code to handle HTTP digests on the server side
Matt Harbison <matt_harbison@yahoo.com>
parents:
41585
diff
changeset
|
84 if respdig != resp[b'response']: |
43076
2372284d9457
formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents:
41589
diff
changeset
|
85 log.write( |
2372284d9457
formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents:
41589
diff
changeset
|
86 b'User/realm "%s/%s" gave %s, but expected %s' |
2372284d9457
formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents:
41589
diff
changeset
|
87 % (user, realm, resp[b'response'], respdig) |
2372284d9457
formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents:
41589
diff
changeset
|
88 ) |
41587
ccaa52865fac
tests: add code to handle HTTP digests on the server side
Matt Harbison <matt_harbison@yahoo.com>
parents:
41585
diff
changeset
|
89 return False |
ccaa52865fac
tests: add code to handle HTTP digests on the server side
Matt Harbison <matt_harbison@yahoo.com>
parents:
41585
diff
changeset
|
90 |
ccaa52865fac
tests: add code to handle HTTP digests on the server side
Matt Harbison <matt_harbison@yahoo.com>
parents:
41585
diff
changeset
|
91 return True |
41585
549af2fa089f
tests: extract the http server authentication extension to a single module
Matt Harbison <matt_harbison@yahoo.com>
parents:
diff
changeset
|
92 |
43076
2372284d9457
formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents:
41589
diff
changeset
|
93 |
41589
46432c04f010
tests: enable HTTP digest testing
Matt Harbison <matt_harbison@yahoo.com>
parents:
41587
diff
changeset
|
94 digest = digestauthserver() |
46432c04f010
tests: enable HTTP digest testing
Matt Harbison <matt_harbison@yahoo.com>
parents:
41587
diff
changeset
|
95 |
43076
2372284d9457
formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents:
41589
diff
changeset
|
96 |
41585
549af2fa089f
tests: extract the http server authentication extension to a single module
Matt Harbison <matt_harbison@yahoo.com>
parents:
diff
changeset
|
97 def perform_authentication(hgweb, req, op): |
549af2fa089f
tests: extract the http server authentication extension to a single module
Matt Harbison <matt_harbison@yahoo.com>
parents:
diff
changeset
|
98 auth = req.headers.get(b'Authorization') |
41589
46432c04f010
tests: enable HTTP digest testing
Matt Harbison <matt_harbison@yahoo.com>
parents:
41587
diff
changeset
|
99 |
46432c04f010
tests: enable HTTP digest testing
Matt Harbison <matt_harbison@yahoo.com>
parents:
41587
diff
changeset
|
100 if req.headers.get(b'X-HgTest-AuthType') == b'Digest': |
46432c04f010
tests: enable HTTP digest testing
Matt Harbison <matt_harbison@yahoo.com>
parents:
41587
diff
changeset
|
101 if not auth: |
46432c04f010
tests: enable HTTP digest testing
Matt Harbison <matt_harbison@yahoo.com>
parents:
41587
diff
changeset
|
102 challenge = digest.makechallenge(b'mercurial') |
43076
2372284d9457
formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents:
41589
diff
changeset
|
103 raise common.ErrorResponse( |
2372284d9457
formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents:
41589
diff
changeset
|
104 common.HTTP_UNAUTHORIZED, |
2372284d9457
formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents:
41589
diff
changeset
|
105 b'who', |
2372284d9457
formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents:
41589
diff
changeset
|
106 [(b'WWW-Authenticate', b'Digest %s' % challenge)], |
2372284d9457
formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents:
41589
diff
changeset
|
107 ) |
41589
46432c04f010
tests: enable HTTP digest testing
Matt Harbison <matt_harbison@yahoo.com>
parents:
41587
diff
changeset
|
108 |
46432c04f010
tests: enable HTTP digest testing
Matt Harbison <matt_harbison@yahoo.com>
parents:
41587
diff
changeset
|
109 if not digest.checkauth(req, auth[7:]): |
46432c04f010
tests: enable HTTP digest testing
Matt Harbison <matt_harbison@yahoo.com>
parents:
41587
diff
changeset
|
110 raise common.ErrorResponse(common.HTTP_FORBIDDEN, b'no') |
46432c04f010
tests: enable HTTP digest testing
Matt Harbison <matt_harbison@yahoo.com>
parents:
41587
diff
changeset
|
111 |
46432c04f010
tests: enable HTTP digest testing
Matt Harbison <matt_harbison@yahoo.com>
parents:
41587
diff
changeset
|
112 return |
46432c04f010
tests: enable HTTP digest testing
Matt Harbison <matt_harbison@yahoo.com>
parents:
41587
diff
changeset
|
113 |
41585
549af2fa089f
tests: extract the http server authentication extension to a single module
Matt Harbison <matt_harbison@yahoo.com>
parents:
diff
changeset
|
114 if not auth: |
43076
2372284d9457
formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents:
41589
diff
changeset
|
115 raise common.ErrorResponse( |
2372284d9457
formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents:
41589
diff
changeset
|
116 common.HTTP_UNAUTHORIZED, |
2372284d9457
formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents:
41589
diff
changeset
|
117 b'who', |
2372284d9457
formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents:
41589
diff
changeset
|
118 [(b'WWW-Authenticate', b'Basic Realm="mercurial"')], |
2372284d9457
formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents:
41589
diff
changeset
|
119 ) |
41585
549af2fa089f
tests: extract the http server authentication extension to a single module
Matt Harbison <matt_harbison@yahoo.com>
parents:
diff
changeset
|
120 |
549af2fa089f
tests: extract the http server authentication extension to a single module
Matt Harbison <matt_harbison@yahoo.com>
parents:
diff
changeset
|
121 if base64.b64decode(auth.split()[1]).split(b':', 1) != [b'user', b'pass']: |
549af2fa089f
tests: extract the http server authentication extension to a single module
Matt Harbison <matt_harbison@yahoo.com>
parents:
diff
changeset
|
122 raise common.ErrorResponse(common.HTTP_FORBIDDEN, b'no') |
549af2fa089f
tests: extract the http server authentication extension to a single module
Matt Harbison <matt_harbison@yahoo.com>
parents:
diff
changeset
|
123 |
43076
2372284d9457
formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents:
41589
diff
changeset
|
124 |
41585
549af2fa089f
tests: extract the http server authentication extension to a single module
Matt Harbison <matt_harbison@yahoo.com>
parents:
diff
changeset
|
125 def extsetup(ui): |
549af2fa089f
tests: extract the http server authentication extension to a single module
Matt Harbison <matt_harbison@yahoo.com>
parents:
diff
changeset
|
126 common.permhooks.insert(0, perform_authentication) |
41589
46432c04f010
tests: enable HTTP digest testing
Matt Harbison <matt_harbison@yahoo.com>
parents:
41587
diff
changeset
|
127 digest.adduser(b'user', b'pass', b'mercurial') |