diff -Nru mercurial-3.8.3~wily1/contrib/docker/ubuntu-precise mercurial-3.8.4~wily1/contrib/docker/ubuntu-precise --- mercurial-3.8.3~wily1/contrib/docker/ubuntu-precise 1970-01-01 00:00:00.000000000 +0000 +++ mercurial-3.8.4~wily1/contrib/docker/ubuntu-precise 2016-07-05 23:12:19.000000000 +0000 @@ -0,0 +1,11 @@ +FROM ubuntu:precise +RUN apt-get update && apt-get install -y \ + build-essential \ + debhelper \ + dh-python \ + devscripts \ + python \ + python-all-dev \ + python-docutils \ + zip \ + unzip diff -Nru mercurial-3.8.3~wily1/debian/changelog mercurial-3.8.4~wily1/debian/changelog --- mercurial-3.8.3~wily1/debian/changelog 2016-07-05 23:12:19.000000000 +0000 +++ mercurial-3.8.4~wily1/debian/changelog 2016-07-05 23:12:19.000000000 +0000 @@ -1,5 +1,5 @@ -mercurial (3.8.3~wily1) wily; urgency=medium +mercurial (3.8.4~wily1) wily; urgency=medium * Automated build performed by upstream. - -- Mercurial Devel Thu, 02 Jun 2016 21:52:05 +0000 + -- Mercurial Devel Tue, 05 Jul 2016 23:10:21 +0000 diff -Nru mercurial-3.8.3~wily1/.hg_archival.txt mercurial-3.8.4~wily1/.hg_archival.txt --- mercurial-3.8.3~wily1/.hg_archival.txt 2016-05-27 22:20:03.000000000 +0000 +++ mercurial-3.8.4~wily1/.hg_archival.txt 2016-06-27 02:34:48.000000000 +0000 @@ -1,4 +1,4 @@ repo: 9117c6561b0bd7792fa13b50d28239d51b78e51f -node: a9764ab80e11bcf6a37255db7dd079011f767c6c +node: 26a5d605b8683a292bb89aea11f37a81b06ac016 branch: stable -tag: 3.8.3 +tag: 3.8.4 diff -Nru mercurial-3.8.3~wily1/hgext/largefiles/lfutil.py mercurial-3.8.4~wily1/hgext/largefiles/lfutil.py --- mercurial-3.8.3~wily1/hgext/largefiles/lfutil.py 2016-05-27 22:20:03.000000000 +0000 +++ mercurial-3.8.4~wily1/hgext/largefiles/lfutil.py 2016-06-27 02:34:48.000000000 +0000 @@ -204,7 +204,7 @@ if instore(repo, hash): return (path, True) elif repo.shared() and instore(repo, hash, True): - return storepath(repo, hash, True) + return storepath(repo, hash, True), True return (path, False) diff -Nru mercurial-3.8.3~wily1/.hgsigs mercurial-3.8.4~wily1/.hgsigs --- mercurial-3.8.3~wily1/.hgsigs 2016-05-27 22:20:03.000000000 +0000 +++ mercurial-3.8.4~wily1/.hgsigs 2016-06-27 02:34:48.000000000 +0000 @@ -127,3 +127,4 @@ f85de28eae32e7d3064b1a1321309071bbaaa069 0 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 diff -Nru mercurial-3.8.3~wily1/.hgtags mercurial-3.8.4~wily1/.hgtags --- mercurial-3.8.3~wily1/.hgtags 2016-05-27 22:20:03.000000000 +0000 +++ mercurial-3.8.4~wily1/.hgtags 2016-06-27 02:34:48.000000000 +0000 @@ -140,3 +140,4 @@ f85de28eae32e7d3064b1a1321309071bbaaa069 3.8 a56296f55a5e1038ea5016dace2076b693c28a56 3.8.1 aaabed77791a75968a12b8c43ad263631a23ee81 3.8.2 +a9764ab80e11bcf6a37255db7dd079011f767c6c 3.8.3 diff -Nru mercurial-3.8.3~wily1/i18n/pt_BR.po mercurial-3.8.4~wily1/i18n/pt_BR.po --- mercurial-3.8.3~wily1/i18n/pt_BR.po 2016-05-27 22:20:03.000000000 +0000 +++ mercurial-3.8.4~wily1/i18n/pt_BR.po 2016-06-27 02:34:48.000000000 +0000 @@ -22714,12 +22714,16 @@ msgid "" "Relative subrepository paths are first made absolute, and the\n" -"rewrite rules are then applied on the full (absolute) path. The rules\n" -"are applied in definition order." +"rewrite rules are then applied on the full (absolute) path. If ``pattern``\n" +"doesn't match the full path, an attempt is made to apply it on the\n" +"relative path alone. The rules are applied in definition order." msgstr "" "Caminhos relativos para sub-repositórios são primeiramente tornados\n" "absolutos, e em seguida as regras de reescrita são aplicadas no\n" -"caminho absoluto completo. As regras são aplicadas na ordem de definição." +"caminho absoluto completo.\n" +"Se ``pattern`` não coincidir com o caminho completo, é feita uma\n" +"tentativa para aplicá-lo no caminho relativo sozinho.\n" +"As regras são aplicadas na ordem de definição." msgid "" "``templatealias``\n" @@ -25625,6 +25629,163 @@ " Veja 'Parent, working directory'.\n" msgid "" +"========\n" +" hg-ssh\n" +"========" +msgstr "" +"========\n" +" hg-ssh\n" +"========" + +msgid "" +"----------------------------------------\n" +"restricted ssh login shell for Mercurial\n" +"----------------------------------------" +msgstr "" +"--------------------------------------------\n" +"shell de login ssh restrito para o Mercurial--------------------------------------------" + +msgid "" +":Author: Thomas Arendsen Hein \n" +":Organization: Mercurial\n" +":Manual section: 8\n" +":Manual group: Mercurial Manual" +msgstr "" +":Author: Thomas Arendsen Hein \n" +":Organization: Mercurial\n" +":Manual section: 8\n" +":Manual group: Mercurial Manual" + +#. do not translate: .. contents:: +msgid "" +".. contents::\n" +" :backlinks: top\n" +" :class: htmlonly\n" +" :depth: 1" +msgstr "" +".. contents::\n" +" :backlinks: top\n" +" :class: htmlonly\n" +" :depth: 1" + +msgid "" +"Synopsis\n" +"\"\"\"\"\"\"\"\"\n" +"**hg-ssh** repositories..." +msgstr "" +"Sinopse\n" +"\"\"\"\"\"\"\"\n" +"**hg-ssh** repositórios..." + +msgid "" +"Description\n" +"\"\"\"\"\"\"\"\"\"\"\"\n" +"**hg-ssh** is a wrapper for ssh access to a limited set of mercurial repos." +msgstr "" +"Descrição\n" +"\"\"\"\"\"\"\"\"\"\n" +"**hg-ssh** é um wrapper para acesso ssh a um conjunto limitado de\n" +"repositórios do Mercurial." + +msgid "" +"To be used in ~/.ssh/authorized_keys with the \"command\" option, see sshd(8):\n" +"command=\"hg-ssh path/to/repo1 /path/to/repo2 ~/repo3 ~user/repo4\" ssh-dss ...\n" +"(probably together with these other useful options:\n" +"no-port-forwarding,no-X11-forwarding,no-agent-forwarding)" +msgstr "" +"Para ser usado em ~/.ssh/authorized_keys com a opção \"command\", veja sshd(8):\n" +"command=\"hg-ssh path/to/repo1 /path/to/repo2 ~/repo3 ~user/repo4\" ssh-dss ...\n" +"(provavelmente incluindo estas outras opções úteis:\n" +"no-port-forwarding,no-X11-forwarding,no-agent-forwarding)" + +msgid "" +"This allows pull/push over ssh from/to the repositories given as arguments." +msgstr "" +"Isto possibilita pull/push através de ssh de/para repositórios passados como\n" +"argumentos." + +msgid "" +"If all your repositories are subdirectories of a common directory, you can\n" +"allow shorter paths with:\n" +"command=\"cd path/to/my/repositories && hg-ssh repo1 subdir/repo2\"" +msgstr "" +"Se os repositórios forem sub-diretórios de um diretírio comum, você pode\n" +"permitir caminhos mais curtos com:\n" +"command=\"cd caminho/para/repositórios && hg-ssh repo1 subdir/repo2\"" + +msgid "" +"You can use pattern matching of your normal shell, e.g.:\n" +"command=\"cd repos && hg-ssh user/thomas/* projects/{mercurial,foo}\"" +msgstr "" +"Você pode usar a correspondência de padrões de seu shell, por exemplo:\n" +"command=\"cd repos && hg-ssh user/thomas/* projetos/{mercurial,foo}\"" + +msgid "" +"You can also add a --read-only flag to allow read-only access to a key, e.g.:\n" +"command=\"hg-ssh --read-only repos/\\*\"" +msgstr "" +"Você também pode adicionar a opção --read-only para permitir acesso somente\n" +"leitura a uma chave, por exemplo:\n" +"command=\"hg-ssh --read-only repos/\\*\"" + +msgid "" +"Bugs\n" +"\"\"\"\"\n" +"Probably lots, please post them to the mailing list (see Resources_\n" +"below) when you find them." +msgstr "" +"Bugs\n" +"\"\"\"\"\n" +"Provavelmente vários, por favor informe-os na lista de discussão\n" +"(veja a seção Recursos_ abaixo)." + +msgid "" +"See Also\n" +"\"\"\"\"\"\"\"\"\n" +"|hg(1)|_" +msgstr "" +"Veja Também\n" +"\"\"\"\"\"\"\"\"\"\"\"\n" +"|hg(1)|_" + +msgid "" +"Author\n" +"\"\"\"\"\"\"\n" +"Written by Matt Mackall " +msgstr "" +"Autor\n" +"\"\"\"\"\"\n" +"Escrito por Matt Mackall " + +msgid "" +"Resources\n" +"\"\"\"\"\"\"\"\"\"\n" +"Main Web Site: https://mercurial-scm.org/" +msgstr "" +"Recursos\n" +"\"\"\"\"\"\"\"\"\n" +"Página Principal: https://mercurial-scm.org/" + +msgid "Source code repository: http://selenic.com/hg" +msgstr "Repositório de código fonte: http://selenic.com/hg" + +msgid "Mailing list: http://selenic.com/mailman/listinfo/mercurial" +msgstr "Lista de discussão: http://selenic.com/mailman/listinfo/mercurial" + +msgid "" +"Copying\n" +"\"\"\"\"\"\"\"\n" +"Copyright (C) 2005-2016 Matt Mackall.\n" +"Free use of this software is granted under the terms of the GNU General\n" +"Public License version 2 or any later version." +msgstr "" +"Cópia\n" +"\"\"\"\"\"\n" +"Copyright (C) 2005-2016 Matt Mackall.\n" +"Garante-se livre uso deste software nos termos da licença\n" +"GNU General Public License, versão 2 ou qualquer versão posterior." + +msgid "" "====\n" " hg\n" "====" @@ -25653,18 +25814,6 @@ ":Manual section: 1\n" ":Manual group: Mercurial Manual" -#. do not translate: .. contents:: -msgid "" -".. contents::\n" -" :backlinks: top\n" -" :class: htmlonly\n" -" :depth: 1" -msgstr "" -".. contents::\n" -" :backlinks: top\n" -" :class: htmlonly\n" -" :depth: 1" - msgid "" "\n" "Synopsis\n" @@ -25829,17 +25978,6 @@ "rastreado pelo Mercurial, ele será sobrescrito." msgid "" -"Bugs\n" -"\"\"\"\"\n" -"Probably lots, please post them to the mailing list (see Resources_\n" -"below) when you find them." -msgstr "" -"Bugs\n" -"\"\"\"\"\n" -"Provavelmente vários, por favor informe-os na lista de discussão\n" -"(veja a seção Recursos_ abaixo)." - -msgid "" "See Also\n" "\"\"\"\"\"\"\"\"\n" "|hgignore(5)|_, |hgrc(5)|_" @@ -25849,43 +25987,6 @@ "|hgignore(5)|_, |hgrc(5)|_" msgid "" -"Author\n" -"\"\"\"\"\"\"\n" -"Written by Matt Mackall " -msgstr "" -"Autor\n" -"\"\"\"\"\"\n" -"Escrito por Matt Mackall " - -msgid "" -"Resources\n" -"\"\"\"\"\"\"\"\"\"\n" -"Main Web Site: https://mercurial-scm.org/" -msgstr "" -"Recursos\n" -"\"\"\"\"\"\"\"\"\n" -"Página Principal: https://mercurial-scm.org/" - -msgid "Source code repository: http://selenic.com/hg" -msgstr "Repositório de código fonte: http://selenic.com/hg" - -msgid "Mailing list: http://selenic.com/mailman/listinfo/mercurial" -msgstr "Lista de discussão: http://selenic.com/mailman/listinfo/mercurial" - -msgid "" -"Copying\n" -"\"\"\"\"\"\"\"\n" -"Copyright (C) 2005-2016 Matt Mackall.\n" -"Free use of this software is granted under the terms of the GNU General\n" -"Public License version 2 or any later version." -msgstr "" -"Cópia\n" -"\"\"\"\"\"\n" -"Copyright (C) 2005-2016 Matt Mackall.\n" -"Garante-se livre uso deste software nos termos da licença\n" -"GNU General Public License, versão 2 ou qualquer versão posterior." - -msgid "" "==========\n" " hgignore\n" "==========" @@ -31696,17 +31797,6 @@ msgid ".hgtags merged successfully\n" msgstr ".hgtags mesclado com successo\n" -#, python-format -msgid "%s, line %s: %s\n" -msgstr "%s, linha %s: %s\n" - -msgid "cannot parse entry" -msgstr "não é possível decodificar entrada" - -#, python-format -msgid "node '%s' is not well formed" -msgstr "nó '%s' não é bem formado" - msgid "" ":addbreaks: Any text. Add an XHTML \"
\" tag before the end of\n" " every line except the last." @@ -33004,6 +33094,15 @@ msgid "number of cpus must be an integer" msgstr "o número de cpus deve ser um inteiro" +#~ msgid "%s, line %s: %s\n" +#~ msgstr "%s, linha %s: %s\n" + +#~ msgid "cannot parse entry" +#~ msgstr "não é possível decodificar entrada" + +#~ msgid "node '%s' is not well formed" +#~ msgstr "nó '%s' não é bem formado" + #~ msgid "" #~ " [blackbox]\n" #~ " track = *" diff -Nru mercurial-3.8.3~wily1/mercurial/bdiff.c mercurial-3.8.4~wily1/mercurial/bdiff.c --- mercurial-3.8.3~wily1/mercurial/bdiff.c 2016-05-27 22:20:03.000000000 +0000 +++ mercurial-3.8.4~wily1/mercurial/bdiff.c 2016-06-27 02:34:48.000000000 +0000 @@ -148,7 +148,7 @@ static int longest_match(struct line *a, struct line *b, struct pos *pos, int a1, int a2, int b1, int b2, int *omi, int *omj) { - int mi = a1, mj = b1, mk = 0, mb = 0, i, j, k, half; + int mi = a1, mj = b1, mk = 0, i, j, k, half; /* window our search on large regions to better bound worst-case performance. by choosing a window at the end, we @@ -166,10 +166,17 @@ /* loop through all lines match a[i] in b */ for (; j >= b1; j = b[j].n) { /* does this extend an earlier match? */ - if (i > a1 && j > b1 && pos[j - 1].pos == i - 1) - k = pos[j - 1].len + 1; - else - k = 1; + for (k = 1; j - k >= b1 && i - k >= a1; k++) { + /* reached an earlier match? */ + if (pos[j - k].pos == i - k) { + k += pos[j - k].len; + break; + } + /* previous line mismatch? */ + if (a[i - k].e != b[j - k].e) + break; + } + pos[j].pos = i; pos[j].len = k; @@ -188,18 +195,15 @@ mj = mj - mk + 1; } - /* expand match to include neighboring popular lines */ - while (mi - mb > a1 && mj - mb > b1 && - a[mi - mb - 1].e == b[mj - mb - 1].e) - mb++; + /* expand match to include subsequent popular lines */ while (mi + mk < a2 && mj + mk < b2 && a[mi + mk].e == b[mj + mk].e) mk++; - *omi = mi - mb; - *omj = mj - mb; + *omi = mi; + *omj = mj; - return mk + mb; + return mk; } static struct hunk *recurse(struct line *a, struct line *b, struct pos *pos, diff -Nru mercurial-3.8.3~wily1/mercurial/bundle2.py mercurial-3.8.4~wily1/mercurial/bundle2.py --- mercurial-3.8.3~wily1/mercurial/bundle2.py 2016-05-27 22:20:03.000000000 +0000 +++ mercurial-3.8.4~wily1/mercurial/bundle2.py 2016-06-27 02:34:48.000000000 +0000 @@ -1453,7 +1453,7 @@ # Trigger a transaction so that we are guaranteed to have the lock now. if op.ui.configbool('experimental', 'bundle2lazylocking'): op.gettransaction() - if heads != op.repo.heads(): + if sorted(heads) != sorted(op.repo.heads()): raise error.PushRaced('repository changed while pushing - ' 'please try again') diff -Nru mercurial-3.8.3~wily1/mercurial/help/config.txt mercurial-3.8.4~wily1/mercurial/help/config.txt --- mercurial-3.8.3~wily1/mercurial/help/config.txt 2016-05-27 22:20:03.000000000 +0000 +++ mercurial-3.8.4~wily1/mercurial/help/config.txt 2016-06-27 02:34:48.000000000 +0000 @@ -1485,8 +1485,9 @@ rewrites ``http://server/foo-hg/`` into ``http://hg.server/foo/``. Relative subrepository paths are first made absolute, and the -rewrite rules are then applied on the full (absolute) path. The rules -are applied in definition order. +rewrite rules are then applied on the full (absolute) path. If ``pattern`` +doesn't match the full path, an attempt is made to apply it on the +relative path alone. The rules are applied in definition order. ``templatealias`` ----------------- diff -Nru mercurial-3.8.3~wily1/mercurial/sslutil.py mercurial-3.8.4~wily1/mercurial/sslutil.py --- mercurial-3.8.3~wily1/mercurial/sslutil.py 2016-05-27 22:20:03.000000000 +0000 +++ mercurial-3.8.4~wily1/mercurial/sslutil.py 2016-06-27 02:34:48.000000000 +0000 @@ -10,6 +10,7 @@ from __future__ import absolute_import import os +import re import ssl import sys @@ -167,6 +168,57 @@ raise error.Abort(_('ssl connection failed')) return sslsocket +class wildcarderror(Exception): + """Represents an error parsing wildcards in DNS name.""" + +def _dnsnamematch(dn, hostname, maxwildcards=1): + """Match DNS names according RFC 6125 section 6.4.3. + + This code is effectively copied from CPython's ssl._dnsname_match. + + Returns a bool indicating whether the expected hostname matches + the value in ``dn``. + """ + pats = [] + if not dn: + return False + + pieces = dn.split(r'.') + leftmost = pieces[0] + remainder = pieces[1:] + wildcards = leftmost.count('*') + if wildcards > maxwildcards: + raise wildcarderror( + _('too many wildcards in certificate DNS name: %s') % dn) + + # speed up common case w/o wildcards + if not wildcards: + return dn.lower() == hostname.lower() + + # RFC 6125, section 6.4.3, subitem 1. + # The client SHOULD NOT attempt to match a presented identifier in which + # the wildcard character comprises a label other than the left-most label. + if leftmost == '*': + # When '*' is a fragment by itself, it matches a non-empty dotless + # fragment. + pats.append('[^.]+') + elif leftmost.startswith('xn--') or hostname.startswith('xn--'): + # RFC 6125, section 6.4.3, subitem 3. + # The client SHOULD NOT attempt to match a presented identifier + # where the wildcard character is embedded within an A-label or + # U-label of an internationalized domain name. + pats.append(re.escape(leftmost)) + else: + # Otherwise, '*' matches any dotless string, e.g. www* + pats.append(re.escape(leftmost).replace(r'\*', '[^.]*')) + + # add the remaining fragments, ignore any wildcards + for frag in remainder: + pats.append(re.escape(frag)) + + pat = re.compile(r'\A' + r'\.'.join(pats) + r'\Z', re.IGNORECASE) + return pat.match(hostname) is not None + def _verifycert(cert, hostname): '''Verify that cert (in socket.getpeercert() format) matches hostname. CRLs is not handled. @@ -175,33 +227,46 @@ ''' if not cert: return _('no certificate received') - dnsname = hostname.lower() - def matchdnsname(certname): - return (certname == dnsname or - '.' in dnsname and certname == '*.' + dnsname.split('.', 1)[1]) + dnsnames = [] san = cert.get('subjectAltName', []) - if san: - certnames = [value.lower() for key, value in san if key == 'DNS'] - for name in certnames: - if matchdnsname(name): - return None - if certnames: - return _('certificate is for %s') % ', '.join(certnames) - - # subject is only checked when subjectAltName is empty - for s in cert.get('subject', []): - key, value = s[0] - if key == 'commonName': + for key, value in san: + if key == 'DNS': try: - # 'subject' entries are unicode - certname = value.lower().encode('ascii') - except UnicodeEncodeError: - return _('IDN in certificate not supported') - if matchdnsname(certname): - return None - return _('certificate is for %s') % certname - return _('no commonName or subjectAltName found in certificate') + if _dnsnamematch(value, hostname): + return + except wildcarderror as e: + return e.message + + dnsnames.append(value) + + if not dnsnames: + # The subject is only checked when there is no DNS in subjectAltName. + for sub in cert.get('subject', []): + for key, value in sub: + # According to RFC 2818 the most specific Common Name must + # be used. + if key == 'commonName': + # 'subject' entries are unicide. + try: + value = value.encode('ascii') + except UnicodeEncodeError: + return _('IDN in certificate not supported') + + try: + if _dnsnamematch(value, hostname): + return + except wildcarderror as e: + return e.message + + dnsnames.append(value) + + if len(dnsnames) > 1: + return _('certificate is for %s') % ', '.join(dnsnames) + elif len(dnsnames) == 1: + return _('certificate is for %s') % dnsnames[0] + else: + return _('no commonName or subjectAltName found in certificate') # CERT_REQUIRED means fetch the cert from the server all the time AND diff -Nru mercurial-3.8.3~wily1/tests/test-largefiles-cache.t mercurial-3.8.4~wily1/tests/test-largefiles-cache.t --- mercurial-3.8.3~wily1/tests/test-largefiles-cache.t 2016-05-27 22:20:03.000000000 +0000 +++ mercurial-3.8.4~wily1/tests/test-largefiles-cache.t 2016-06-27 02:34:48.000000000 +0000 @@ -186,6 +186,10 @@ src/.hg/largefiles/dirstate src/.hg/largefiles/e2fb5f2139d086ded2cb600d5a91a196e76bf020 +Verify that backwards compatibility is maintained for old storage layout + $ mv src/.hg/largefiles/$hash share_dst/.hg/largefiles + $ hg verify --quiet --lfa -R share_dst --config largefiles.usercache= + Inject corruption into the largefiles store and see how update handles that: $ cd src diff -Nru mercurial-3.8.3~wily1/tests/test-subrepo-git.t mercurial-3.8.4~wily1/tests/test-subrepo-git.t --- mercurial-3.8.3~wily1/tests/test-subrepo-git.t 2016-05-27 22:20:03.000000000 +0000 +++ mercurial-3.8.4~wily1/tests/test-subrepo-git.t 2016-06-27 02:34:48.000000000 +0000 @@ -1135,7 +1135,7 @@ test for Git CVE-2016-3068 $ hg init malicious-subrepository $ cd malicious-subrepository - $ echo "s = [git]ext::sh -c echo% \$PWNED_MSG% >pwned.txt" > .hgsub + $ echo "s = [git]ext::sh -c echo% pwned:% \$PWNED_MSG% >pwned.txt" > .hgsub $ git init s Initialized empty Git repository in $TESTTMP/tc/malicious-subrepository/s/.git/ $ cd s @@ -1152,10 +1152,11 @@ Cloning into '$TESTTMP/tc/malicious-subrepository-protected/s'... (glob) fatal: transport 'ext' not allowed updating to branch default - cloning subrepo s from ext::sh -c echo% $PWNED_MSG% >pwned.txt + cloning subrepo s from ext::sh -c echo% pwned:% $PWNED_MSG% >pwned.txt abort: git clone error 128 in s (in subrepo s) [255] - $ test -f pwned.txt && cat pwned.txt || true + $ f -Dq pwned.txt + pwned.txt: file not found whitelisting of ext should be respected (that's the git submodule behaviour) $ rm -f pwned.txt @@ -1167,8 +1168,8 @@ Please make sure you have the correct access rights and the repository exists. updating to branch default - cloning subrepo s from ext::sh -c echo% $PWNED_MSG% >pwned.txt + cloning subrepo s from ext::sh -c echo% pwned:% $PWNED_MSG% >pwned.txt abort: git clone error 128 in s (in subrepo s) [255] - $ cat pwned.txt - you asked for it + $ f -Dq pwned.txt + pwned: you asked for it diff -Nru mercurial-3.8.3~wily1/tests/test-url.py mercurial-3.8.4~wily1/tests/test-url.py --- mercurial-3.8.3~wily1/tests/test-url.py 2016-05-27 22:20:03.000000000 +0000 +++ mercurial-3.8.4~wily1/tests/test-url.py 2016-06-27 02:34:48.000000000 +0000 @@ -1,3 +1,4 @@ +# coding=utf-8 from __future__ import absolute_import, print_function import doctest @@ -50,8 +51,7 @@ # Avoid some pitfalls check(_verifycert(cert('*.foo'), 'foo'), 'certificate is for *.foo') -check(_verifycert(cert('*o'), 'foo'), - 'certificate is for *o') +check(_verifycert(cert('*o'), 'foo'), None) check(_verifycert({'subject': ()}, 'example.com'), @@ -63,6 +63,177 @@ check(_verifycert(cert(u'\u4f8b.jp'), 'example.jp'), 'IDN in certificate not supported') +# The following tests are from CPython's test_ssl.py. +check(_verifycert(cert('example.com'), 'example.com'), None) +check(_verifycert(cert('example.com'), 'ExAmple.cOm'), None) +check(_verifycert(cert('example.com'), 'www.example.com'), + 'certificate is for example.com') +check(_verifycert(cert('example.com'), '.example.com'), + 'certificate is for example.com') +check(_verifycert(cert('example.com'), 'example.org'), + 'certificate is for example.com') +check(_verifycert(cert('example.com'), 'exampleXcom'), + 'certificate is for example.com') +check(_verifycert(cert('*.a.com'), 'foo.a.com'), None) +check(_verifycert(cert('*.a.com'), 'bar.foo.a.com'), + 'certificate is for *.a.com') +check(_verifycert(cert('*.a.com'), 'a.com'), + 'certificate is for *.a.com') +check(_verifycert(cert('*.a.com'), 'Xa.com'), + 'certificate is for *.a.com') +check(_verifycert(cert('*.a.com'), '.a.com'), + 'certificate is for *.a.com') + +# only match one left-most wildcard +check(_verifycert(cert('f*.com'), 'foo.com'), None) +check(_verifycert(cert('f*.com'), 'f.com'), None) +check(_verifycert(cert('f*.com'), 'bar.com'), + 'certificate is for f*.com') +check(_verifycert(cert('f*.com'), 'foo.a.com'), + 'certificate is for f*.com') +check(_verifycert(cert('f*.com'), 'bar.foo.com'), + 'certificate is for f*.com') + +# NULL bytes are bad, CVE-2013-4073 +check(_verifycert(cert('null.python.org\x00example.org'), + 'null.python.org\x00example.org'), None) +check(_verifycert(cert('null.python.org\x00example.org'), + 'example.org'), + 'certificate is for null.python.org\x00example.org') +check(_verifycert(cert('null.python.org\x00example.org'), + 'null.python.org'), + 'certificate is for null.python.org\x00example.org') + +# error cases with wildcards +check(_verifycert(cert('*.*.a.com'), 'bar.foo.a.com'), + 'certificate is for *.*.a.com') +check(_verifycert(cert('*.*.a.com'), 'a.com'), + 'certificate is for *.*.a.com') +check(_verifycert(cert('*.*.a.com'), 'Xa.com'), + 'certificate is for *.*.a.com') +check(_verifycert(cert('*.*.a.com'), '.a.com'), + 'certificate is for *.*.a.com') + +check(_verifycert(cert('a.*.com'), 'a.foo.com'), + 'certificate is for a.*.com') +check(_verifycert(cert('a.*.com'), 'a..com'), + 'certificate is for a.*.com') +check(_verifycert(cert('a.*.com'), 'a.com'), + 'certificate is for a.*.com') + +# wildcard doesn't match IDNA prefix 'xn--' +idna = u'püthon.python.org'.encode('idna').decode('ascii') +check(_verifycert(cert(idna), idna), None) +check(_verifycert(cert('x*.python.org'), idna), + 'certificate is for x*.python.org') +check(_verifycert(cert('xn--p*.python.org'), idna), + 'certificate is for xn--p*.python.org') + +# wildcard in first fragment and IDNA A-labels in sequent fragments +# are supported. +idna = u'www*.pythön.org'.encode('idna').decode('ascii') +check(_verifycert(cert(idna), + u'www.pythön.org'.encode('idna').decode('ascii')), + None) +check(_verifycert(cert(idna), + u'www1.pythön.org'.encode('idna').decode('ascii')), + None) +check(_verifycert(cert(idna), + u'ftp.pythön.org'.encode('idna').decode('ascii')), + 'certificate is for www*.xn--pythn-mua.org') +check(_verifycert(cert(idna), + u'pythön.org'.encode('idna').decode('ascii')), + 'certificate is for www*.xn--pythn-mua.org') + +c = { + 'notAfter': 'Jun 26 21:41:46 2011 GMT', + 'subject': (((u'commonName', u'linuxfrz.org'),),), + 'subjectAltName': ( + ('DNS', 'linuxfr.org'), + ('DNS', 'linuxfr.com'), + ('othername', ''), + ) +} +check(_verifycert(c, 'linuxfr.org'), None) +check(_verifycert(c, 'linuxfr.com'), None) +# Not a "DNS" entry +check(_verifycert(c, ''), + 'certificate is for linuxfr.org, linuxfr.com') +# When there is a subjectAltName, commonName isn't used +check(_verifycert(c, 'linuxfrz.org'), + 'certificate is for linuxfr.org, linuxfr.com') + +# A pristine real-world example +c = { + 'notAfter': 'Dec 18 23:59:59 2011 GMT', + 'subject': ( + ((u'countryName', u'US'),), + ((u'stateOrProvinceName', u'California'),), + ((u'localityName', u'Mountain View'),), + ((u'organizationName', u'Google Inc'),), + ((u'commonName', u'mail.google.com'),), + ), +} +check(_verifycert(c, 'mail.google.com'), None) +check(_verifycert(c, 'gmail.com'), 'certificate is for mail.google.com') + +# Only commonName is considered +check(_verifycert(c, 'California'), 'certificate is for mail.google.com') + +# Neither commonName nor subjectAltName +c = { + 'notAfter': 'Dec 18 23:59:59 2011 GMT', + 'subject': ( + ((u'countryName', u'US'),), + ((u'stateOrProvinceName', u'California'),), + ((u'localityName', u'Mountain View'),), + ((u'organizationName', u'Google Inc'),), + ), +} +check(_verifycert(c, 'mail.google.com'), + 'no commonName or subjectAltName found in certificate') + +# No DNS entry in subjectAltName but a commonName +c = { + 'notAfter': 'Dec 18 23:59:59 2099 GMT', + 'subject': ( + ((u'countryName', u'US'),), + ((u'stateOrProvinceName', u'California'),), + ((u'localityName', u'Mountain View'),), + ((u'commonName', u'mail.google.com'),), + ), + 'subjectAltName': (('othername', 'blabla'),), +} +check(_verifycert(c, 'mail.google.com'), None) + +# No DNS entry subjectAltName and no commonName +c = { + 'notAfter': 'Dec 18 23:59:59 2099 GMT', + 'subject': ( + ((u'countryName', u'US'),), + ((u'stateOrProvinceName', u'California'),), + ((u'localityName', u'Mountain View'),), + ((u'organizationName', u'Google Inc'),), + ), + 'subjectAltName': (('othername', 'blabla'),), +} +check(_verifycert(c, 'google.com'), + 'no commonName or subjectAltName found in certificate') + +# Empty cert / no cert +check(_verifycert(None, 'example.com'), 'no certificate received') +check(_verifycert({}, 'example.com'), 'no certificate received') + +# avoid denials of service by refusing more than one +# wildcard per fragment. +check(_verifycert({'subject': (((u'commonName', u'a*b.com'),),)}, + 'axxb.com'), None) +check(_verifycert({'subject': (((u'commonName', u'a*b.co*'),),)}, + 'axxb.com'), 'certificate is for a*b.co*') +check(_verifycert({'subject': (((u'commonName', u'a*b*.com'),),)}, + 'axxbxxc.com'), + 'too many wildcards in certificate DNS name: a*b*.com') + def test_url(): """ >>> from mercurial.util import url