Show More
@@ -381,6 +381,14 b' web::' | |||||
381 | Default is false. |
|
381 | Default is false. | |
382 | allowpull;; |
|
382 | allowpull;; | |
383 | Whether to allow pulling from the repository. Default is true. |
|
383 | Whether to allow pulling from the repository. Default is true. | |
|
384 | allow_push;; | |||
|
385 | Whether to allow pushing to the repository. If empty or not set, | |||
|
386 | push is not allowed. If the special value "*", any remote user | |||
|
387 | can push, including unauthenticated users. Otherwise, the remote | |||
|
388 | user must have been authenticated, and the authenticated user name | |||
|
389 | must be present in this list (separated by whitespace or ","). | |||
|
390 | The contents of the allow_push list are examined after the | |||
|
391 | deny_push list. | |||
384 | allowzip;; |
|
392 | allowzip;; | |
385 | (DEPRECATED) Whether to allow .zip downloading of repo revisions. |
|
393 | (DEPRECATED) Whether to allow .zip downloading of repo revisions. | |
386 | Default is false. This feature creates temporary files. |
|
394 | Default is false. This feature creates temporary files. | |
@@ -391,6 +399,13 b' web::' | |||||
391 | contact;; |
|
399 | contact;; | |
392 | Name or email address of the person in charge of the repository. |
|
400 | Name or email address of the person in charge of the repository. | |
393 | Default is "unknown". |
|
401 | Default is "unknown". | |
|
402 | deny_push;; | |||
|
403 | Whether to deny pushing to the repository. If empty or not set, | |||
|
404 | push is not denied. If the special value "*", all remote users | |||
|
405 | are denied push. Otherwise, unauthenticated users are all denied, | |||
|
406 | and any authenticated user name present in this list (separated by | |||
|
407 | whitespace or ",") is also denied. The contents of the deny_push | |||
|
408 | list are examined before the allow_push list. | |||
394 | description;; |
|
409 | description;; | |
395 | Textual description of the repository's purpose or contents. |
|
410 | Textual description of the repository's purpose or contents. | |
396 | Default is "unknown". |
|
411 | Default is "unknown". | |
@@ -407,6 +422,9 b' web::' | |||||
407 | Maximum number of files to list per changeset. Default is 10. |
|
422 | Maximum number of files to list per changeset. Default is 10. | |
408 | port;; |
|
423 | port;; | |
409 | Port to listen on. Default is 8000. |
|
424 | Port to listen on. Default is 8000. | |
|
425 | push_ssl;; | |||
|
426 | Whether to require that inbound pushes be transported over SSL to | |||
|
427 | prevent password sniffing. Default is true. | |||
410 | style;; |
|
428 | style;; | |
411 | Which template map style to use. |
|
429 | Which template map style to use. | |
412 | templates;; |
|
430 | templates;; |
@@ -839,19 +839,59 b' class hgweb(object):' | |||||
839 | req.httphdr("application/mercurial-0.1", length=len(resp)) |
|
839 | req.httphdr("application/mercurial-0.1", length=len(resp)) | |
840 | req.write(resp) |
|
840 | req.write(resp) | |
841 |
|
841 | |||
|
842 | def check_perm(self, req, op, default): | |||
|
843 | '''check permission for operation based on user auth. | |||
|
844 | return true if op allowed, else false. | |||
|
845 | default is policy to use if no config given.''' | |||
|
846 | ||||
|
847 | user = req.env.get('REMOTE_USER') | |||
|
848 | ||||
|
849 | deny = self.repo.ui.config('web', 'deny_' + op, '') | |||
|
850 | deny = deny.replace(',', ' ').split() | |||
|
851 | ||||
|
852 | if deny and (not user or deny == ['*'] or user in deny): | |||
|
853 | return False | |||
|
854 | ||||
|
855 | allow = self.repo.ui.config('web', 'allow_' + op, '') | |||
|
856 | allow = allow.replace(',', ' ').split() | |||
|
857 | ||||
|
858 | return (allow and (allow == ['*'] or user in allow)) or default | |||
|
859 | ||||
842 | def do_unbundle(self, req): |
|
860 | def do_unbundle(self, req): | |
|
861 | def bail(response, headers={}): | |||
|
862 | length = int(req.env['CONTENT_LENGTH']) | |||
|
863 | for s in util.filechunkiter(req, limit=length): | |||
|
864 | # drain incoming bundle, else client will not see | |||
|
865 | # response when run outside cgi script | |||
|
866 | pass | |||
|
867 | req.httphdr("application/mercurial-0.1", headers=headers) | |||
|
868 | req.write('0\n') | |||
|
869 | req.write(response) | |||
|
870 | ||||
|
871 | # require ssl by default, auth info cannot be sniffed and | |||
|
872 | # replayed | |||
|
873 | ssl_req = self.repo.ui.configbool('web', 'push_ssl', True) | |||
|
874 | if ssl_req and not req.env.get('HTTPS'): | |||
|
875 | bail(_('ssl required\n')) | |||
|
876 | return | |||
|
877 | ||||
|
878 | # do not allow push unless explicitly allowed | |||
|
879 | if not self.check_perm(req, 'push', False): | |||
|
880 | bail(_('push not authorized\n'), | |||
|
881 | headers={'status': '401 Unauthorized'}) | |||
|
882 | return | |||
|
883 | ||||
|
884 | req.httphdr("application/mercurial-0.1") | |||
|
885 | ||||
843 | their_heads = req.form['heads'][0].split(' ') |
|
886 | their_heads = req.form['heads'][0].split(' ') | |
844 |
|
887 | |||
845 | def check_heads(): |
|
888 | def check_heads(): | |
846 | heads = map(hex, self.repo.heads()) |
|
889 | heads = map(hex, self.repo.heads()) | |
847 | return their_heads == [hex('force')] or their_heads == heads |
|
890 | return their_heads == [hex('force')] or their_heads == heads | |
848 |
|
891 | |||
849 | req.httphdr("application/mercurial-0.1") |
|
|||
850 |
|
||||
851 | # fail early if possible |
|
892 | # fail early if possible | |
852 | if not check_heads(): |
|
893 | if not check_heads(): | |
853 | req.write('0\n') |
|
894 | bail(_('unsynced changes\n')) | |
854 | req.write(_('unsynced changes\n')) |
|
|||
855 | return |
|
895 | return | |
856 |
|
896 | |||
857 | # do not lock repo until all changegroup data is |
|
897 | # do not lock repo until all changegroup data is |
@@ -45,9 +45,9 b' class hgrequest(object):' | |||||
45 | self.out.write("%s: %s\r\n" % header) |
|
45 | self.out.write("%s: %s\r\n" % header) | |
46 | self.out.write("\r\n") |
|
46 | self.out.write("\r\n") | |
47 |
|
47 | |||
48 | def httphdr(self, type, filename=None, length=0): |
|
48 | def httphdr(self, type, filename=None, length=0, headers={}): | |
49 |
|
49 | headers = headers.items() | ||
50 |
headers |
|
50 | headers.append(('Content-type', type)) | |
51 | if filename: |
|
51 | if filename: | |
52 | headers.append(('Content-disposition', 'attachment; filename=%s' % |
|
52 | headers.append(('Content-disposition', 'attachment; filename=%s' % | |
53 | filename)) |
|
53 | filename)) |
General Comments 0
You need to be logged in to leave comments.
Login now