changeset 29621:d3df009ab117 stable

merge with i18n
author Matt Mackall <mpm@selenic.com>
date Wed, 20 Jul 2016 14:12:45 -0500
parents 53e80179bd6a (diff) fe0eeef0986a (current diff)
children 9c2cc107547f
files
diffstat 8 files changed, 169 insertions(+), 25 deletions(-) [+]
line wrap: on
line diff
--- a/hgext/convert/bzr.py	Tue Jul 19 19:01:11 2016 -0300
+++ b/hgext/convert/bzr.py	Wed Jul 20 14:12:45 2016 -0500
@@ -228,9 +228,10 @@
                     renaming = paths[0] != paths[1]
                     # neither an add nor an delete - a move
                     # rename all directory contents manually
-                    subdir = origin.inventory.path2id(paths[0])
+                    subdir = origin.root_inventory.path2id(paths[0])
                     # get all child-entries of the directory
-                    for name, entry in origin.inventory.iter_entries(subdir):
+                    for name, entry in origin.root_inventory.iter_entries(
+                            subdir):
                         # hg does not track directory renames
                         if entry.kind == 'directory':
                             continue
--- a/mercurial/branchmap.py	Tue Jul 19 19:01:11 2016 -0300
+++ b/mercurial/branchmap.py	Wed Jul 20 14:12:45 2016 -0500
@@ -358,7 +358,7 @@
         self._repo = repo
         self._names = [] # branch names in local encoding with static index
         self._rbcrevs = array('c') # structs of type _rbcrecfmt
-        self._rbcsnameslen = 0
+        self._rbcsnameslen = 0 # length of names read at _rbcsnameslen
         try:
             bndata = repo.vfs.read(_rbcnames)
             self._rbcsnameslen = len(bndata) # for verification before writing
@@ -380,7 +380,8 @@
                                len(repo.changelog))
         if self._rbcrevslen == 0:
             self._names = []
-        self._rbcnamescount = len(self._names) # number of good names on disk
+        self._rbcnamescount = len(self._names) # number of names read at
+                                               # _rbcsnameslen
         self._namesreverse = dict((b, r) for r, b in enumerate(self._names))
 
     def _clear(self):
@@ -416,13 +417,17 @@
         if cachenode == '\0\0\0\0':
             pass
         elif cachenode == reponode:
-            if branchidx < self._rbcnamescount:
+            try:
                 return self._names[branchidx], close
-            # referenced branch doesn't exist - rebuild is expensive but needed
-            self._repo.ui.debug("rebuilding corrupted revision branch cache\n")
-            self._clear()
+            except IndexError:
+                # recover from invalid reference to unknown branch
+                self._repo.ui.debug("referenced branch names not found"
+                    " - rebuilding revision branch cache from scratch\n")
+                self._clear()
         else:
             # rev/node map has changed, invalidate the cache from here up
+            self._repo.ui.debug("history modification detected - truncating "
+                "revision branch cache to revision %s\n" % rev)
             truncate = rbcrevidx + _rbcrecsize
             del self._rbcrevs[truncate:]
             self._rbcrevslen = min(self._rbcrevslen, truncate)
--- a/mercurial/hg.py	Tue Jul 19 19:01:11 2016 -0300
+++ b/mercurial/hg.py	Wed Jul 20 14:12:45 2016 -0500
@@ -923,7 +923,7 @@
         dst.setconfig('bundle', 'mainreporoot', r, 'copied')
 
     # copy selected local settings to the remote ui
-    for sect in ('auth', 'hostfingerprints', 'http_proxy'):
+    for sect in ('auth', 'hostfingerprints', 'hostsecurity', 'http_proxy'):
         for key, val in src.configitems(sect):
             dst.setconfig(sect, key, val, 'copied')
     v = src.config('web', 'cacerts')
--- a/mercurial/sslutil.py	Tue Jul 19 19:01:11 2016 -0300
+++ b/mercurial/sslutil.py	Wed Jul 20 14:12:45 2016 -0500
@@ -139,6 +139,9 @@
         'legacyfingerprint': False,
         # PROTOCOL_* constant to use for SSLContext.__init__.
         'protocol': None,
+        # String representation of minimum protocol to be used for UI
+        # presentation.
+        'protocolui': None,
         # ssl.CERT_* constant used by SSLContext.verify_mode.
         'verifymode': None,
         # Defines extra ssl.OP* bitwise options to set.
@@ -181,7 +184,13 @@
     protocol = ui.config('hostsecurity', key, protocol)
     validateprotocol(protocol, key)
 
-    s['protocol'], s['ctxoptions'] = protocolsettings(protocol)
+    # If --insecure is used, we allow the use of TLS 1.0 despite config options.
+    # We always print a "connection security to %s is disabled..." message when
+    # --insecure is used. So no need to print anything more here.
+    if ui.insecureconnections:
+        protocol = 'tls1.0'
+
+    s['protocol'], s['ctxoptions'], s['protocolui'] = protocolsettings(protocol)
 
     ciphers = ui.config('hostsecurity', 'ciphers')
     ciphers = ui.config('hostsecurity', '%s:ciphers' % hostname, ciphers)
@@ -279,7 +288,12 @@
     return s
 
 def protocolsettings(protocol):
-    """Resolve the protocol and context options for a config value."""
+    """Resolve the protocol for a config value.
+
+    Returns a 3-tuple of (protocol, options, ui value) where the first
+    2 items are values used by SSLContext and the last is a string value
+    of the ``minimumprotocol`` config option equivalent.
+    """
     if protocol not in configprotocols:
         raise ValueError('protocol value not supported: %s' % protocol)
 
@@ -301,7 +315,7 @@
                               hint=_('upgrade Python or disable setting since '
                                      'only TLS 1.0 is supported'))
 
-        return ssl.PROTOCOL_TLSv1, 0
+        return ssl.PROTOCOL_TLSv1, 0, 'tls1.0'
 
     # WARNING: returned options don't work unless the modern ssl module
     # is available. Be careful when adding options here.
@@ -323,7 +337,7 @@
     # There is no guarantee this attribute is defined on the module.
     options |= getattr(ssl, 'OP_NO_COMPRESSION', 0)
 
-    return ssl.PROTOCOL_SSLv23, options
+    return ssl.PROTOCOL_SSLv23, options, protocol
 
 def wrapsocket(sock, keyfile, certfile, ui, serverhostname=None):
     """Add SSL/TLS to a socket.
@@ -403,11 +417,57 @@
                       'how to configure Mercurial to avoid this error)\n'))
         # Try to print more helpful error messages for known failures.
         if util.safehasattr(e, 'reason'):
+            # This error occurs when the client and server don't share a
+            # common/supported SSL/TLS protocol. We've disabled SSLv2 and SSLv3
+            # outright. Hopefully the reason for this error is that we require
+            # TLS 1.1+ and the server only supports TLS 1.0. Whatever the
+            # reason, try to emit an actionable warning.
             if e.reason == 'UNSUPPORTED_PROTOCOL':
-                ui.warn(_('(could not negotiate a common protocol; see '
-                          'https://mercurial-scm.org/wiki/SecureConnections '
-                          'for how to configure Mercurial to avoid this '
-                          'error)\n'))
+                # We attempted TLS 1.0+.
+                if settings['protocolui'] == 'tls1.0':
+                    # We support more than just TLS 1.0+. If this happens,
+                    # the likely scenario is either the client or the server
+                    # is really old. (e.g. server doesn't support TLS 1.0+ or
+                    # client doesn't support modern TLS versions introduced
+                    # several years from when this comment was written).
+                    if supportedprotocols != set(['tls1.0']):
+                        ui.warn(_(
+                            '(could not communicate with %s using security '
+                            'protocols %s; if you are using a modern Mercurial '
+                            'version, consider contacting the operator of this '
+                            'server; see '
+                            'https://mercurial-scm.org/wiki/SecureConnections '
+                            'for more info)\n') % (
+                                serverhostname,
+                                ', '.join(sorted(supportedprotocols))))
+                    else:
+                        ui.warn(_(
+                            '(could not communicate with %s using TLS 1.0; the '
+                            'likely cause of this is the server no longer '
+                            'supports TLS 1.0 because it has known security '
+                            'vulnerabilities; see '
+                            'https://mercurial-scm.org/wiki/SecureConnections '
+                            'for more info)\n') % serverhostname)
+                else:
+                    # We attempted TLS 1.1+. We can only get here if the client
+                    # supports the configured protocol. So the likely reason is
+                    # the client wants better security than the server can
+                    # offer.
+                    ui.warn(_(
+                        '(could not negotiate a common security protocol (%s+) '
+                        'with %s; the likely cause is Mercurial is configured '
+                        'to be more secure than the server can support)\n') % (
+                        settings['protocolui'], serverhostname))
+                    ui.warn(_('(consider contacting the operator of this '
+                              'server and ask them to support modern TLS '
+                              'protocol versions; or, set '
+                              'hostsecurity.%s:minimumprotocol=tls1.0 to allow '
+                              'use of legacy, less secure protocols when '
+                              'communicating with this server)\n') %
+                            serverhostname)
+                    ui.warn(_(
+                        '(see https://mercurial-scm.org/wiki/SecureConnections '
+                        'for more info)\n'))
         raise
 
     # check if wrap_socket failed silently because socket had been
@@ -439,7 +499,7 @@
 
     Typically ``cafile`` is only defined if ``requireclientcert`` is true.
     """
-    protocol, options = protocolsettings('tls1.0')
+    protocol, options, _protocolui = protocolsettings('tls1.0')
 
     # This config option is intended for use in tests only. It is a giant
     # footgun to kill security. Don't define it.
--- a/mercurial/util.py	Tue Jul 19 19:01:11 2016 -0300
+++ b/mercurial/util.py	Wed Jul 20 14:12:45 2016 -0500
@@ -396,10 +396,26 @@
     (3, 6, None)
     >>> versiontuple(v, 4)
     (3, 6, None, None)
+
+    >>> v = '3.9-rc'
+    >>> versiontuple(v, 2)
+    (3, 9)
+    >>> versiontuple(v, 3)
+    (3, 9, None)
+    >>> versiontuple(v, 4)
+    (3, 9, None, 'rc')
+
+    >>> v = '3.9-rc+2-02a8fea4289b'
+    >>> versiontuple(v, 2)
+    (3, 9)
+    >>> versiontuple(v, 3)
+    (3, 9, None)
+    >>> versiontuple(v, 4)
+    (3, 9, None, 'rc+2-02a8fea4289b')
     """
     if not v:
         v = version()
-    parts = v.split('+', 1)
+    parts = remod.split('[\+-]', v, 1)
     if len(parts) == 1:
         vparts, extra = parts[0], None
     else:
--- a/tests/test-branches.t	Tue Jul 19 19:01:11 2016 -0300
+++ b/tests/test-branches.t	Wed Jul 20 14:12:45 2016 -0500
@@ -587,6 +587,8 @@
   $ f --size .hg/cache/rbc-revs*
   .hg/cache/rbc-revs-v1: size=120
   $ hg log -r 'branch(.)' -T '{rev} ' --debug
+  history modification detected - truncating revision branch cache to revision 13
+  history modification detected - truncating revision branch cache to revision 1
   3 4 8 9 10 11 12 13 truncating cache/rbc-revs-v1 to 8
   $ rm -f .hg/cache/branch* && hg head a -T '{rev}\n' --debug
   5
@@ -632,7 +634,7 @@
 cache is rebuilt when corruption is detected
   $ echo > .hg/cache/rbc-names-v1
   $ hg log -r '5:&branch(.)' -T '{rev} ' --debug
-  rebuilding corrupted revision branch cache
+  referenced branch names not found - rebuilding revision branch cache from scratch
   8 9 10 11 12 13 truncating cache/rbc-revs-v1 to 40
   $ f --size --hexdump .hg/cache/rbc-*
   .hg/cache/rbc-names-v1: size=79
@@ -668,3 +670,33 @@
   0060: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
 
   $ cd ..
+
+Test for multiple incorrect branch cache entries:
+
+  $ hg init b
+  $ cd b
+  $ touch f
+  $ hg ci -Aqmf
+  $ echo >> f
+  $ hg ci -Amf
+  $ hg branch -q branch
+  $ hg ci -Amf
+
+  $ f --size --hexdump .hg/cache/rbc-*
+  .hg/cache/rbc-names-v1: size=14
+  0000: 64 65 66 61 75 6c 74 00 62 72 61 6e 63 68       |default.branch|
+  .hg/cache/rbc-revs-v1: size=24
+  0000: 66 e5 f5 aa 00 00 00 00 fa 4c 04 e5 00 00 00 00 |f........L......|
+  0010: 56 46 78 69 00 00 00 01                         |VFxi....|
+  $ : > .hg/cache/rbc-revs-v1
+
+No superfluous rebuilding of cache:
+  $ hg log -r "branch(null)&branch(branch)" --debug
+  $ f --size --hexdump .hg/cache/rbc-*
+  .hg/cache/rbc-names-v1: size=14
+  0000: 64 65 66 61 75 6c 74 00 62 72 61 6e 63 68       |default.branch|
+  .hg/cache/rbc-revs-v1: size=24
+  0000: 66 e5 f5 aa 00 00 00 00 fa 4c 04 e5 00 00 00 00 |f........L......|
+  0010: 56 46 78 69 00 00 00 01                         |VFxi....|
+
+  $ cd ..
--- a/tests/test-https.t	Tue Jul 19 19:01:11 2016 -0300
+++ b/tests/test-https.t	Wed Jul 20 14:12:45 2016 -0500
@@ -469,23 +469,37 @@
 Clients requiring newer TLS version than what server supports fail
 
   $ P="$CERTSDIR" hg id https://localhost:$HGPORT/
-  (could not negotiate a common protocol; see https://mercurial-scm.org/wiki/SecureConnections for how to configure Mercurial to avoid this error)
+  (could not negotiate a common security protocol (tls1.1+) with localhost; the likely cause is Mercurial is configured to be more secure than the server can support)
+  (consider contacting the operator of this server and ask them to support modern TLS protocol versions; or, set hostsecurity.localhost:minimumprotocol=tls1.0 to allow use of legacy, less secure protocols when communicating with this server)
+  (see https://mercurial-scm.org/wiki/SecureConnections for more info)
   abort: error: *unsupported protocol* (glob)
   [255]
 
   $ P="$CERTSDIR" hg --config hostsecurity.minimumprotocol=tls1.1 id https://localhost:$HGPORT/
-  (could not negotiate a common protocol; see https://mercurial-scm.org/wiki/SecureConnections for how to configure Mercurial to avoid this error)
+  (could not negotiate a common security protocol (tls1.1+) with localhost; the likely cause is Mercurial is configured to be more secure than the server can support)
+  (consider contacting the operator of this server and ask them to support modern TLS protocol versions; or, set hostsecurity.localhost:minimumprotocol=tls1.0 to allow use of legacy, less secure protocols when communicating with this server)
+  (see https://mercurial-scm.org/wiki/SecureConnections for more info)
   abort: error: *unsupported protocol* (glob)
   [255]
   $ P="$CERTSDIR" hg --config hostsecurity.minimumprotocol=tls1.2 id https://localhost:$HGPORT/
-  (could not negotiate a common protocol; see https://mercurial-scm.org/wiki/SecureConnections for how to configure Mercurial to avoid this error)
+  (could not negotiate a common security protocol (tls1.2+) with localhost; the likely cause is Mercurial is configured to be more secure than the server can support)
+  (consider contacting the operator of this server and ask them to support modern TLS protocol versions; or, set hostsecurity.localhost:minimumprotocol=tls1.0 to allow use of legacy, less secure protocols when communicating with this server)
+  (see https://mercurial-scm.org/wiki/SecureConnections for more info)
   abort: error: *unsupported protocol* (glob)
   [255]
   $ P="$CERTSDIR" hg --config hostsecurity.minimumprotocol=tls1.2 id https://localhost:$HGPORT1/
-  (could not negotiate a common protocol; see https://mercurial-scm.org/wiki/SecureConnections for how to configure Mercurial to avoid this error)
+  (could not negotiate a common security protocol (tls1.2+) with localhost; the likely cause is Mercurial is configured to be more secure than the server can support)
+  (consider contacting the operator of this server and ask them to support modern TLS protocol versions; or, set hostsecurity.localhost:minimumprotocol=tls1.0 to allow use of legacy, less secure protocols when communicating with this server)
+  (see https://mercurial-scm.org/wiki/SecureConnections for more info)
   abort: error: *unsupported protocol* (glob)
   [255]
 
+--insecure will allow TLS 1.0 connections and override configs
+
+  $ hg --config hostsecurity.minimumprotocol=tls1.2 id --insecure https://localhost:$HGPORT1/
+  warning: connection security to localhost is disabled per current settings; communication is susceptible to eavesdropping and tampering
+  5fed3813f7f5
+
 The per-host config option overrides the default
 
   $ P="$CERTSDIR" hg id https://localhost:$HGPORT/ \
@@ -497,10 +511,25 @@
 
   $ P="$CERTSDIR" hg id https://localhost:$HGPORT/ \
   > --config hostsecurity.localhost:minimumprotocol=tls1.2
-  (could not negotiate a common protocol; see https://mercurial-scm.org/wiki/SecureConnections for how to configure Mercurial to avoid this error)
+  (could not negotiate a common security protocol (tls1.2+) with localhost; the likely cause is Mercurial is configured to be more secure than the server can support)
+  (consider contacting the operator of this server and ask them to support modern TLS protocol versions; or, set hostsecurity.localhost:minimumprotocol=tls1.0 to allow use of legacy, less secure protocols when communicating with this server)
+  (see https://mercurial-scm.org/wiki/SecureConnections for more info)
   abort: error: *unsupported protocol* (glob)
   [255]
 
+.hg/hgrc file [hostsecurity] settings are applied to remote ui instances (issue5305)
+
+  $ cat >> copy-pull/.hg/hgrc << EOF
+  > [hostsecurity]
+  > localhost:minimumprotocol=tls1.2
+  > EOF
+  $ P="$CERTSDIR" hg -R copy-pull id https://localhost:$HGPORT/
+  (could not negotiate a common security protocol (tls1.2+) with localhost; the likely cause is Mercurial is configured to be more secure than the server can support)
+  (consider contacting the operator of this server and ask them to support modern TLS protocol versions; or, set hostsecurity.localhost:minimumprotocol=tls1.0 to allow use of legacy, less secure protocols when communicating with this server)
+  (see https://mercurial-scm.org/wiki/SecureConnections for more info)
+  abort: error: [SSL: UNSUPPORTED_PROTOCOL] unsupported protocol (_ssl.c:590)
+  [255]
+
   $ killdaemons.py hg0.pid
   $ killdaemons.py hg1.pid
   $ killdaemons.py hg2.pid
--- a/tests/test-rebase-conflicts.t	Tue Jul 19 19:01:11 2016 -0300
+++ b/tests/test-rebase-conflicts.t	Wed Jul 20 14:12:45 2016 -0500
@@ -302,6 +302,7 @@
   bundle2-input-part: total payload size 1713
   bundle2-input-bundle: 0 parts total
   invalid branchheads cache (served): tip differs
+  history modification detected - truncating revision branch cache to revision 9
   rebase completed
   updating the branch cache
   truncating cache/rbc-revs-v1 to 72