allura-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From brond...@apache.org
Subject [1/5] allura git commit: [#8082] apply rate limiting to ForgeBlog
Date Mon, 09 May 2016 19:13:09 GMT
Repository: allura
Updated Branches:
  refs/heads/master 68437f901 -> 78007dba6


[#8082] apply rate limiting to ForgeBlog


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

Branch: refs/heads/master
Commit: 85064754e3ed39bfc658395fc4ae50f9326f0b32
Parents: dd0e7f9
Author: Dave Brondsema <dave@brondsema.net>
Authored: Mon May 2 14:16:15 2016 -0400
Committer: Dave Brondsema <dave@brondsema.net>
Committed: Mon May 2 14:23:57 2016 -0400

----------------------------------------------------------------------
 Allura/development.ini                          |  2 ++
 ForgeBlog/forgeblog/main.py                     | 19 +++++++++++
 .../forgeblog/tests/functional/test_rest.py     | 33 ++++++++++++++++++++
 .../forgeblog/tests/functional/test_root.py     | 19 +++++++++--
 4 files changed, 71 insertions(+), 2 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/allura/blob/85064754/Allura/development.ini
----------------------------------------------------------------------
diff --git a/Allura/development.ini b/Allura/development.ini
index 6f98435..89566a7 100644
--- a/Allura/development.ini
+++ b/Allura/development.ini
@@ -462,12 +462,14 @@ forgemail.domain = .in.localhost
 ; Keys are number of seconds, values are max number allowed until that time period is reached
 ;forgewiki.rate_limits = {"3600": 100, "172800": 10000}
 ;forgetracker.rate_limits = {"3600": 100, "172800": 10000}
+;forgeblog.rate_limits = {"3600": 100, "172800": 10000}
 
 ; Number of different wiki pages, tickets, etc that a user can create or edit, per time period,
across all projects
 ; Keys are number of seconds, values are max number allowed until that time period is reached
 ; NOTE: wiki pages include the default "Home" page created for the user-project and any other
projects created by the user
 ;forgewiki.rate_limits_per_user =    {"60": 3, "120": 3, "900": 5, "1800": 7, "3600": 10,
"7200": 15, "86400": 20, "604800": 50, "2592000": 200}
 ;forgetracker.rate_limits_per_user = {"60": 1, "120": 3, "900": 5, "1800": 7, "3600": 10,
"7200": 15, "86400": 20, "604800": 50, "2592000": 200}
+;forgeblog.rate_limits_per_user =    {"60": 1, "120": 3, "900": 5, "1800": 7, "3600": 10,
"7200": 15, "86400": 20, "604800": 50, "2592000": 200}
 
 ; set this to "false" if you are deploying to production and want performance improvements
 auto_reload_templates = true

http://git-wip-us.apache.org/repos/asf/allura/blob/85064754/ForgeBlog/forgeblog/main.py
----------------------------------------------------------------------
diff --git a/ForgeBlog/forgeblog/main.py b/ForgeBlog/forgeblog/main.py
index ca23336..f093df0 100644
--- a/ForgeBlog/forgeblog/main.py
+++ b/ForgeBlog/forgeblog/main.py
@@ -44,6 +44,7 @@ from allura.lib.search import search_app
 from allura.lib.decorators import require_post
 from allura.lib.security import has_access, require_access
 from allura.lib import widgets as w
+from allura.lib import exceptions as forge_exc
 from allura.lib.widgets.subscriptions import SubscribeForm
 from allura.lib.widgets import form_fields as ffw
 from allura.lib.widgets.search import SearchResults, SearchHelp
@@ -233,6 +234,14 @@ class ForgeBlogApp(Application):
                 self.save_attachments(post_path, post.attachments)
 
 
+def rate_limit():
+    if BM.BlogPost.is_limit_exceeded(c.app.config, user=c.user):
+        msg = 'Create/edit rate limit exceeded. '
+        log.warn(msg + c.app.config.url())
+        flash(msg + 'Please try again later.', 'error')
+        redirect(c.app.config.url())
+
+
 class RootController(BaseController, FeedController):
 
     def __init__(self):
@@ -285,6 +294,7 @@ class RootController(BaseController, FeedController):
     @without_trailing_slash
     def new(self, **kw):
         require_access(c.app, 'write')
+        rate_limit()
         post = dict(
             state='published')
         c.form = W.new_post_form
@@ -296,6 +306,7 @@ class RootController(BaseController, FeedController):
     @without_trailing_slash
     def save(self, **kw):
         require_access(c.app, 'write')
+        rate_limit()
         post = BM.BlogPost.new(**kw)
         redirect(h.really_unicode(post.url()).encode('utf-8'))
 
@@ -350,6 +361,7 @@ class PostController(BaseController, FeedController):
     @without_trailing_slash
     def edit(self, **kw):
         require_access(self.post, 'write')
+        rate_limit()
         c.form = W.edit_post_form
         c.attachment_add = W.attachment_add
         c.attachment_list = W.attachment_list
@@ -376,6 +388,7 @@ class PostController(BaseController, FeedController):
     @without_trailing_slash
     def save(self, delete=None, **kw):
         require_access(self.post, 'write')
+        rate_limit()
         if delete:
             # Remove from the Rss Feed.
             M.Feed.update(self.post, delete=True)
@@ -509,6 +522,9 @@ class RootRestController(BaseController, AppRestControllerMixin):
     def index(self, title='', text='', state='draft', labels='', limit=10, page=0, **kw):
         if request.method == 'POST':
             require_access(c.app, 'write')
+            if BM.BlogPost.is_limit_exceeded(c.app.config, user=c.user):
+                log.warn('Create/edit rate limit exceeded. %s', c.app.config.url())
+                raise forge_exc.HTTPTooManyRequests()
             post = BM.BlogPost.new(
                 title=title,
                 state=state,
@@ -559,6 +575,9 @@ class PostRestController(BaseController):
 
     def _update_post(self, **post_data):
         require_access(self.post, 'write')
+        if BM.BlogPost.is_limit_exceeded(c.app.config, user=c.user):
+            log.warn('Create/edit rate limit exceeded. %s', c.app.config.url())
+            raise forge_exc.HTTPTooManyRequests()
         if 'delete' in post_data:
             self.post.delete()
             return {}

http://git-wip-us.apache.org/repos/asf/allura/blob/85064754/ForgeBlog/forgeblog/tests/functional/test_rest.py
----------------------------------------------------------------------
diff --git a/ForgeBlog/forgeblog/tests/functional/test_rest.py b/ForgeBlog/forgeblog/tests/functional/test_rest.py
index ed3e9fc..8acdd87 100644
--- a/ForgeBlog/forgeblog/tests/functional/test_rest.py
+++ b/ForgeBlog/forgeblog/tests/functional/test_rest.py
@@ -18,11 +18,14 @@
 #       under the License.
 from datetime import date
 
+import tg
 from nose.tools import assert_equal, assert_in
+
 from allura.lib import helpers as h
 from allura.tests import decorators as td
 from allura import model as M
 from alluratest.controller import TestRestApiBase
+
 from forgeblog import model as BM
 
 
@@ -252,3 +255,33 @@ class TestBlogApi(TestRestApiBase):
             user='root')
         assert_equal(r.status_int, 200)
         assert_equal(r.json['result'], False)
+
+    def test_create_post_limit_by_project(self):
+        data = {
+            'title': 'test against limit',
+            'text': 'test text',
+            'state': 'published',
+            'labels': 'label1, label2'
+        }
+        # Set rate limit to 0 in first hour of project
+        with h.push_config(tg.config, **{'forgeblog.rate_limits': '{"3600": 0}'}):
+            self.api_post('/rest/p/test/blog/', status=429, **data)
+
+    def test_edit_post_limit_by_user(self):
+        data = {
+            'title': 'test abc',
+            'text': 'test text',
+            'state': 'published',
+            'labels': 'label1, label2'
+        }
+        self.api_post('/rest/p/test/blog/', status=201, **data)
+
+        url = '/rest' + BM.BlogPost.query.find().first().url()
+        data = {
+            'text': 'test xyz',
+            'state': 'published',
+            'labels': 'label3'
+        }
+        # Set rate limit to 1 in first hour of user
+        with h.push_config(tg.config, **{'forgeblog.rate_limits_per_user': '{"3600": 1}'}):
+            self.api_post(url, status=429, **data)

http://git-wip-us.apache.org/repos/asf/allura/blob/85064754/ForgeBlog/forgeblog/tests/functional/test_root.py
----------------------------------------------------------------------
diff --git a/ForgeBlog/forgeblog/tests/functional/test_root.py b/ForgeBlog/forgeblog/tests/functional/test_root.py
index 4ca87ac..500b835 100644
--- a/ForgeBlog/forgeblog/tests/functional/test_root.py
+++ b/ForgeBlog/forgeblog/tests/functional/test_root.py
@@ -16,13 +16,14 @@
 #       under the License.
 
 import datetime
+import json
 
+import tg
 from nose.tools import assert_equal, assert_in
-from ming.orm.ormsession import ThreadLocalORMSession
 from mock import patch
 
+from allura.lib import helpers as h
 from alluratest.controller import TestController
-from allura import model as M
 
 #---------x---------x---------x---------x---------x---------x---------x
 # RootController methods exposed:
@@ -201,3 +202,17 @@ class Test(TestController):
         self._post()
         d = self._blog_date()
         self.app.get('/blog/%s/my-post/?limit=blah&page=2x' % d, status=200)
+
+    def test_rate_limit_submit(self):
+        with h.push_config(tg.config, **{'forgeblog.rate_limits': '{"3600": 0}'}):
+            r = self._post()
+            wf = json.loads(self.webflash(r))
+            assert_equal(wf['status'], 'error')
+            assert_equal(wf['message'], 'Create/edit rate limit exceeded. Please try again
later.')
+
+    def test_rate_limit_form(self):
+        with h.push_config(tg.config, **{'forgeblog.rate_limits': '{"3600": 0}'}):
+            r = self.app.get('/blog/new')
+            wf = json.loads(self.webflash(r))
+            assert_equal(wf['status'], 'error')
+            assert_equal(wf['message'], 'Create/edit rate limit exceeded. Please try again
later.')


Mime
View raw message