You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@allura.apache.org by he...@apache.org on 2015/04/01 23:10:35 UTC

[18/45] allura git commit: [#7820] ticket:747 Validate URLs when configuring external link tool

[#7820] ticket:747 Validate URLs when configuring external link tool


Project: http://git-wip-us.apache.org/repos/asf/allura/repo
Commit: http://git-wip-us.apache.org/repos/asf/allura/commit/53b5577a
Tree: http://git-wip-us.apache.org/repos/asf/allura/tree/53b5577a
Diff: http://git-wip-us.apache.org/repos/asf/allura/diff/53b5577a

Branch: refs/heads/hss/7072
Commit: 53b5577a36005cbd938bc16fa38cb0795eab4dd1
Parents: e146bbe
Author: Igor Bondarenko <je...@gmail.com>
Authored: Thu Mar 19 14:12:03 2015 +0000
Committer: Dave Brondsema <db...@slashdotmedia.com>
Committed: Mon Mar 23 19:43:48 2015 +0000

----------------------------------------------------------------------
 ForgeLink/forgelink/link_main.py                | 19 ++++-
 .../forgelink/templates/app_admin_options.html  | 77 ++++++++++++++++++++
 .../forgelink/tests/functional/test_root.py     | 47 ++++++++++++
 3 files changed, 142 insertions(+), 1 deletion(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/allura/blob/53b5577a/ForgeLink/forgelink/link_main.py
----------------------------------------------------------------------
diff --git a/ForgeLink/forgelink/link_main.py b/ForgeLink/forgelink/link_main.py
index bb55a3e..bfcf9f9 100644
--- a/ForgeLink/forgelink/link_main.py
+++ b/ForgeLink/forgelink/link_main.py
@@ -23,11 +23,12 @@ import json
 from tg import expose, redirect, flash, jsonify
 from pylons import tmpl_context as c
 from pylons import request
+from formencode import validators as fev
 
 # Pyforge-specific imports
 from allura.app import Application, ConfigOption, SitemapEntry, DefaultAdminController
 from allura.lib import helpers as h
-from allura.lib.security import require_access
+from allura.lib.security import require_access, has_access
 from allura.lib.utils import permanent_redirect
 from allura import model as M
 from allura.controllers import BaseController
@@ -128,6 +129,22 @@ class LinkAdminController(DefaultAdminController):
         flash('External link URL updated.')
         redirect(c.project.url() + 'admin/tools')
 
+    @expose('jinja:forgelink:templates/app_admin_options.html')
+    def options(self):
+        return dict(
+            app=self.app,
+            allow_config=has_access(self.app, 'configure')())
+
+    @expose('json:')
+    def set_url(self, **kw):
+        validator = fev.URL(not_empty=True, add_http=True)
+        try:
+            url = validator.to_python(kw.get('url'))
+        except fev.Invalid as e:
+            return {'status': 'error', 'errors': {'url': e.msg}}
+        self.app.config.options['url'] = url
+        return {'status': 'ok'}
+
 
 class RootRestController(BaseController):
 

http://git-wip-us.apache.org/repos/asf/allura/blob/53b5577a/ForgeLink/forgelink/templates/app_admin_options.html
----------------------------------------------------------------------
diff --git a/ForgeLink/forgelink/templates/app_admin_options.html b/ForgeLink/forgelink/templates/app_admin_options.html
new file mode 100644
index 0000000..a62dfa7
--- /dev/null
+++ b/ForgeLink/forgelink/templates/app_admin_options.html
@@ -0,0 +1,77 @@
+{#-
+       Licensed to the Apache Software Foundation (ASF) under one
+       or more contributor license agreements.  See the NOTICE file
+       distributed with this work for additional information
+       regarding copyright ownership.  The ASF licenses this file
+       to you under the Apache License, Version 2.0 (the
+       "License"); you may not use this file except in compliance
+       with the License.  You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+       Unless required by applicable law or agreed to in writing,
+       software distributed under the License is distributed on an
+       "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+       KIND, either express or implied.  See the License for the
+       specific language governing permissions and limitations
+       under the License.
+-#}
+<!DOCTYPE html>
+{% import 'allura:templates/jinja_master/lib.html' as lib with context %}
+<form id="set-url-form" method="post" action="{{c.project.url()}}admin/{{app.config.options.mount_point}}/set_url">
+  <label for="url" class="grid-4">url</label>
+  <div class="grid-9">
+    {% if not allow_config %}
+      {{app.config.options.get('url', '')}}
+    {% else %}
+      <input id="url" name="url" value="{{app.config.options.get('url', '')}}">
+    {% endif %}
+  </div>
+  <div class="grid-4">&nbsp;</div><div id='url-error' class='grid-9'></div>
+  {% if allow_config %}
+    <div class="grid-13">&nbsp;</div>
+    <hr>
+    <div class="grid-13">&nbsp;</div>
+    <div class="grid-13">
+      <input type="submit" value="Save" id="save" />
+      <a href="#" class="close">Cancel</a>
+    </div>
+  {% endif %}
+  {{lib.csrf_token()}}
+</form>
+
+<script type="text/javascript">
+$(function() {
+  $('#save').on('click', function(e) {
+    e.preventDefault();
+    var form = $('#set-url-form');
+    var button = $(this);
+    var input = form.find('input[name="url"]')
+    var url_error = $('#url-error');
+    var url = input.val();
+    var csrf = $.cookie('_session_id');
+    button.prop('disabled', true);
+    input.prop('disabled', true);
+    url_error.text('');
+    $.post(
+      form.attr('action'),
+      {'_session_id': csrf, 'url': url},
+      function(data) {
+        if (data['status'] == 'ok') {
+          location.reload();
+        } else {
+          url_error.text(data['errors']['url']);
+        }
+        button.prop('disabled', false);
+        input.prop('disabled', false);
+      });
+  });
+});
+</script>
+
+<style type="text/css">
+#url-error {
+  margin-left: 15px;
+  color: #f33;
+}
+</style>

http://git-wip-us.apache.org/repos/asf/allura/blob/53b5577a/ForgeLink/forgelink/tests/functional/test_root.py
----------------------------------------------------------------------
diff --git a/ForgeLink/forgelink/tests/functional/test_root.py b/ForgeLink/forgelink/tests/functional/test_root.py
index ca57244..e4fc656 100644
--- a/ForgeLink/forgelink/tests/functional/test_root.py
+++ b/ForgeLink/forgelink/tests/functional/test_root.py
@@ -15,6 +15,9 @@
 #       specific language governing permissions and limitations
 #       under the License.
 
+from nose.tools import assert_equal
+
+from allura import model as M
 from allura.tests import decorators as td
 from alluratest.controller import TestController
 
@@ -58,3 +61,47 @@ class TestRootController(TestController):
         response = self.app.get('/link/help')
         # HACK: support for remote redirects is limited in follow()
         assert 'http://www.google.de/search?q=help' in response
+
+    @td.with_link
+    def test_set_url_validation(self):
+        r = self.app.post('/p/test/admin/link/set_url', {})
+        expected = {'status': 'error',
+                    'errors': {'url': u'Please enter a value'}}
+        assert_equal(r.json, expected)
+
+        r = self.app.post('/p/test/admin/link/set_url', {'url': ''})
+        expected = {'status': 'error',
+                    'errors': {'url': u'Please enter a value'}}
+        assert_equal(r.json, expected)
+
+        r = self.app.post('/p/test/admin/link/set_url', {'url': 'bad url'})
+        expected = {'status': 'error',
+                    'errors': {'url': u'That is not a valid URL'}}
+        assert_equal(r.json, expected)
+
+        p = M.Project.query.get(shortname='test')
+        link = p.app_instance('link')
+        assert_equal(link.config.options.get('url'), None)
+
+    @td.with_link
+    def test_set_url(self):
+        data = {'url': 'http://example.com'}  # http
+        r = self.app.post('/p/test/admin/link/set_url', data)
+        assert_equal(r.json, {'status': 'ok'})
+        p = M.Project.query.get(shortname='test')
+        link = p.app_instance('link')
+        assert_equal(link.config.options.get('url'), 'http://example.com')
+
+        data = {'url': 'https://google.com'}  # https
+        r = self.app.post('/p/test/admin/link/set_url', data)
+        assert_equal(r.json, {'status': 'ok'})
+        p = M.Project.query.get(shortname='test')
+        link = p.app_instance('link')
+        assert_equal(link.config.options.get('url'), 'https://google.com')
+
+        data = {'url': 'lmgtfy.com'}  # http is added if not provided
+        r = self.app.post('/p/test/admin/link/set_url', data)
+        assert_equal(r.json, {'status': 'ok'})
+        p = M.Project.query.get(shortname='test')
+        link = p.app_instance('link')
+        assert_equal(link.config.options.get('url'), 'http://lmgtfy.com')