diff --git a/ihatemoney/forms.py b/ihatemoney/forms.py index b16d131f..5374fd9f 100644 --- a/ihatemoney/forms.py +++ b/ihatemoney/forms.py @@ -53,11 +53,16 @@ class CalculatorStringField(StringField): def process_formdata(self, valuelist): if valuelist: - error_msg = "Not a valid amount or expression" + message = _( + "Not a valid amount or expression." + "Only numbers and + - * / operators" + "are accepted." + ) value = str(valuelist[0]).replace(",", ".") - if not match(r'^[ 0-9\.\+\-\*/\(\)]{0,50}$', value) or "**" in value: - raise ValueError(error_msg) + # avoid exponents to prevent expensive calculations i.e 2**9999999999**9999999 + if not match(r'^[ 0-9\.\+\-\*/\(\)]{0,200}$', value) or "**" in value: + raise ValueError(Markup(message)) valuelist[0] = str(eval_arithmetic_expression(value)) diff --git a/ihatemoney/tests/tests.py b/ihatemoney/tests/tests.py index 980f4d13..26d7af6c 100644 --- a/ihatemoney/tests/tests.py +++ b/ihatemoney/tests/tests.py @@ -1357,49 +1357,66 @@ class APITestCase(IhatemoneyTestCase): self.api_add_member("raclette", "alexis") self.api_add_member("raclette", "fred") - # add a bill - req = self.client.post("/api/projects/raclette/bills", data={ - 'date': '2011-08-10', - 'what': 'fromage', - 'payer': "1", - 'payed_for': ["1", "2"], - 'amount': '((100 + 200.25) * 2 - 100) / 2', - }, headers=self.get_auth("raclette")) + # valid amounts + input_expected = [ + ("((100 + 200.25) * 2 - 100) / 2", 250.25), + ("3/2", 1.5), + ] - # should return the id - self.assertStatus(201, req) - self.assertEqual(req.data.decode('utf-8'), "1\n") + for i, pair in enumerate(input_expected): + input_amount, expected_amount = pair + id = i + 1 - # get this bill details - req = self.client.get("/api/projects/raclette/bills/1", - headers=self.get_auth("raclette")) + req = self.client.post( + "/api/projects/raclette/bills", + data={ + 'date': '2011-08-10', + 'what': 'fromage', + 'payer': "1", + 'payed_for': ["1", "2"], + 'amount': input_amount, + }, + headers=self.get_auth("raclette") + ) - # compare with the added info - self.assertStatus(200, req) - expected = { - "what": "fromage", - "payer_id": 1, - "owers": [ - {"activated": True, "id": 1, "name": "alexis", "weight": 1}, - {"activated": True, "id": 2, "name": "fred", "weight": 1}], - "amount": 250.25, - "date": "2011-08-10", - "id": 1} + # should return the id + self.assertStatus(201, req) + self.assertEqual(req.data.decode('utf-8'), "{}\n".format(id)) - got = json.loads(req.data.decode('utf-8')) - self.assertEqual( - datetime.date.today(), - datetime.datetime.strptime(got["creation_date"], '%Y-%m-%d').date() - ) - del got["creation_date"] - self.assertDictEqual(expected, got) + # get this bill's details + req = self.client.get( + "/api/projects/raclette/bills/{}".format(id), + headers=self.get_auth("raclette") + ) + # compare with the added info + self.assertStatus(200, req) + expected = { + "what": "fromage", + "payer_id": 1, + "owers": [ + {"activated": True, "id": 1, "name": "alexis", "weight": 1}, + {"activated": True, "id": 2, "name": "fred", "weight": 1}], + "amount": expected_amount, + "date": "2011-08-10", + "id": id, + } + + got = json.loads(req.data.decode('utf-8')) + self.assertEqual( + datetime.date.today(), + datetime.datetime.strptime(got["creation_date"], '%Y-%m-%d').date() + ) + del got["creation_date"] + self.assertDictEqual(expected, got) + + # should raise errors erroneous_amounts = [ "lambda ", # letters "(20 + 2", # invalid expression "20/0", # invalid calc "9999**99999999999999999", # exponents - "2*2*2*2*2*2*2*2*2*2*2*2*2*2*2*2*2*2*2*2*2*2*2*2*2*2", # greater than 50 chars, + "2" * 201, # greater than 200 chars, ] for amount in erroneous_amounts: diff --git a/ihatemoney/utils.py b/ihatemoney/utils.py index f75219e2..2fac4efb 100644 --- a/ihatemoney/utils.py +++ b/ihatemoney/utils.py @@ -1,3 +1,4 @@ +from __future__ import division import base64 import re import ast