[PATCH] hgweb: make raw file download configurable and disabled (BC) (issue2923)

Mads Kiilerich mads at kiilerich.com
Sat Jul 30 19:02:09 CDT 2011


# HG changeset patch
# User Mads Kiilerich <mads at kiilerich.com>
# Date 1312069612 -7200
# Branch stable
# Node ID cfa2db1db62e2602c97dff06829000dab1a0d8d8
# Parent  192e02680d094dc22cf856e70f07348bd6de18d1
hgweb: make raw file download configurable and disabled (BC) (issue2923)

Before: hgweb made it possible to download file content with a content type
detected from the file extension. It would serve .html files as text/html and
could thus cause XSS vulnerabilities if the web site had any kind of session
authorization and the repository content wasn't fully trusted.

Now: Serving of raw file content is now made configurable with the web.allowraw
config setting.

Note: Raw file download is now disabled by default. Sites that need this
feature and know what they are doing must enable it in the site configuration.

The hgweb menu entries for raw is not removed.

diff --git a/mercurial/help/config.txt b/mercurial/help/config.txt
--- a/mercurial/help/config.txt
+++ b/mercurial/help/config.txt
@@ -1154,6 +1154,17 @@
     be present in this list. The contents of the allow_push list are
     examined after the deny_push list.
 
+``allowraw``
+    Control raw download of file revision content.
+    Set to ``guess`` to let hgweb guess the content type from the file
+    extension. Note: This will serve html as ``text/html`` and might thus
+    be vulnerable to XSS attacks.
+    Set to ``plain`` to serve text files as ``text/plain`` and binary
+    files as ``application/octet-stream``. Note: Some browsers might
+    ignore the content type and might thus be vulnerable to XSS attacks anyway.
+    Set to empty to disable raw download.
+    Default is empty.
+   
 ``allow_read``
     If the user has not already been denied repository access due to
     the contents of deny_read, this list determines whether to grant
diff --git a/mercurial/hgweb/webcommands.py b/mercurial/hgweb/webcommands.py
--- a/mercurial/hgweb/webcommands.py
+++ b/mercurial/hgweb/webcommands.py
@@ -32,6 +32,10 @@
         return changelog(web, req, tmpl)
 
 def rawfile(web, req, tmpl):
+    allowraw = web.config('web', 'allowraw', '')
+    if allowraw not in ['guess', 'plain']:
+        raise ErrorResponse(HTTP_FORBIDDEN, 'raw file download not allowed')
+
     path = webutil.cleanpath(web.repo, req.form.get('file', [''])[0])
     if not path:
         content = manifest(web, req, tmpl)
@@ -50,7 +54,9 @@
 
     path = fctx.path()
     text = fctx.data()
-    mt = mimetypes.guess_type(path)[0]
+    mt = None
+    if allowraw == 'guess':
+        mt = mimetypes.guess_type(path)[0]
     if mt is None:
         mt = binary(text) and 'application/octet-stream' or 'text/plain'
     if mt.startswith('text/'):
diff --git a/tests/test-hgweb-commands.t b/tests/test-hgweb-commands.t
--- a/tests/test-hgweb-commands.t
+++ b/tests/test-hgweb-commands.t
@@ -21,7 +21,8 @@
   $ hg branch stable
   marked working directory as branch stable
   $ hg ci -Ambranch
-  $ hg serve --config server.uncompressed=False -n test -p $HGPORT -d --pid-file=hg.pid -E errors.log
+  $ hg serve --config server.uncompressed=False --config web.allowraw=plain \
+  >   -n test -p $HGPORT -d --pid-file=hg.pid -E errors.log
   $ cat hg.pid >> $DAEMON_PIDS
 
 Logs and changes
@@ -500,6 +501,15 @@
 
 File-related
 
+  $ hg serve -p $HGPORT1 -d --pid-file=hg.pid
+  $ cat hg.pid >> $DAEMON_PIDS
+  $ "$TESTDIR/get-with-headers.py" 127.0.0.1:$HGPORT1 '/file/1/foo/?style=raw'
+  403 raw file download not allowed
+  
+  
+  error: raw file download not allowed
+  [1]
+
   $ "$TESTDIR/get-with-headers.py" 127.0.0.1:$HGPORT '/file/1/foo/?style=raw'
   200 Script output follows
   
diff --git a/tests/test-hgweb-no-request-uri.t b/tests/test-hgweb-no-request-uri.t
--- a/tests/test-hgweb-no-request-uri.t
+++ b/tests/test-hgweb-no-request-uri.t
@@ -2,6 +2,9 @@
 no longer passed with the request. Instead, SCRIPT_NAME and PATH_INFO
 should be used from d74fc8dec2b4 onward to route the request.
 
+  $ echo '[web]' >> $HGRCPATH
+  $ echo 'allowraw=plain' >> $HGRCPATH
+
   $ hg init repo
   $ cd repo
   $ echo foo > bar
diff --git a/tests/test-hgweb-raw.t b/tests/test-hgweb-raw.t
--- a/tests/test-hgweb-raw.t
+++ b/tests/test-hgweb-raw.t
@@ -13,7 +13,8 @@
   warning: filename contains '"', which is reserved on Windows: 'sub/some "text".txt'
   $ hg commit -d "1 0" -m "Just some text"
 
-  $ hg serve -p $HGPORT -A access.log -E error.log -d --pid-file=hg.pid
+  $ hg serve -p $HGPORT -A access.log -E error.log -d --pid-file=hg.pid \
+  >   --config web.allowraw=plain
 
   $ cat hg.pid >> $DAEMON_PIDS
   $ ("$TESTDIR/get-with-headers.py" localhost:$HGPORT '/?f=a23bf1310f6e;file=sub/some%20%22text%22.txt;style=raw' content-type content-length content-disposition) >getoutput.txt &
diff --git a/tests/test-hgweb.t b/tests/test-hgweb.t
--- a/tests/test-hgweb.t
+++ b/tests/test-hgweb.t
@@ -8,7 +8,8 @@
   $ hg ci -Ambase
   adding da/foo
   adding foo
-  $ hg serve -n test -p $HGPORT -d --pid-file=hg.pid -A access.log -E errors.log
+  $ hg serve --config web.allowraw=plain -n test -p $HGPORT -d \
+  >   --pid-file=hg.pid -A access.log -E errors.log
   $ cat hg.pid >> $DAEMON_PIDS
 
 manifest
diff --git a/tests/test-hgwebdir.t b/tests/test-hgwebdir.t
--- a/tests/test-hgwebdir.t
+++ b/tests/test-hgwebdir.t
@@ -39,6 +39,8 @@
   > [paths]
   > a=$root/a
   > b=$root/b
+  > [web]
+  > allowraw=plain
   > EOF
   $ hg serve -p $HGPORT -d --pid-file=hg.pid --webdir-conf paths.conf \
   >     -A access-paths.log -E error-paths-1.log
@@ -100,6 +102,8 @@
   > star=*
   > starstar=**
   > astar=webdir/a/*
+  > [web]
+  > allowraw=plain
   > EOF
   $ hg serve -p $HGPORT1 -d --pid-file=hg.pid --webdir-conf paths.conf \
   >     -A access-paths.log -E error-paths-2.log
@@ -599,6 +603,8 @@
   $ cat > collections.conf <<EOF
   > [collections]
   > $root=$root
+  > [web]
+  > allowraw=plain
   > EOF
   $ hg serve --config web.baseurl=http://hg.example.com:8080/ -p $HGPORT2 -d \
   >     --pid-file=hg.pid --webdir-conf collections.conf \
diff --git a/tests/test-hgwebdirsym.t b/tests/test-hgwebdirsym.t
--- a/tests/test-hgwebdirsym.t
+++ b/tests/test-hgwebdirsym.t
@@ -22,6 +22,8 @@
   $ cat > collections.conf <<EOF
   > [collections]
   > $root=$root
+  > [web]
+  > allowraw=plain
   > EOF
   $ hg serve -p $HGPORT -d --pid-file=hg.pid --webdir-conf collections.conf \
   >     -A access-collections.log -E error-collections.log
diff --git a/tests/test-highlight.t b/tests/test-highlight.t
--- a/tests/test-highlight.t
+++ b/tests/test-highlight.t
@@ -5,6 +5,7 @@
   > highlight =
   > [web]
   > pygments_style = friendly
+  > allowraw=plain
   > EOF
   $ hg init test
   $ cd test
diff --git a/tests/test-keyword.t b/tests/test-keyword.t
--- a/tests/test-keyword.t
+++ b/tests/test-keyword.t
@@ -7,6 +7,8 @@
   > transplant =
   > [ui]
   > interactive = true
+  > [web]
+  > allowraw=plain
   > EOF
 
 Run kwdemo before [keyword] files are set up
diff --git a/tests/test-share.t b/tests/test-share.t
--- a/tests/test-share.t
+++ b/tests/test-share.t
@@ -1,6 +1,8 @@
 
   $ echo "[extensions]"      >> $HGRCPATH
   $ echo "share = "          >> $HGRCPATH
+  $ echo "[web]"             >> $HGRCPATH
+  $ echo "allowraw=plain"    >> $HGRCPATH
 
 prepare repo1
 


More information about the Mercurial-devel mailing list