From 24b20d7668eb105d678259596e2d3a03a9b344aa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michael=20P=C3=B6hn?= Date: Tue, 22 May 2018 13:08:14 +0200 Subject: [PATCH 1/2] use simple ast+operator based calculator for evaluating Vercode Operation --- fdroidserver/checkupdates.py | 2 +- fdroidserver/common.py | 24 ++++++++++++++++++++++++ 2 files changed, 25 insertions(+), 1 deletion(-) diff --git a/fdroidserver/checkupdates.py b/fdroidserver/checkupdates.py index 59e2ddd1..60314160 100644 --- a/fdroidserver/checkupdates.py +++ b/fdroidserver/checkupdates.py @@ -434,7 +434,7 @@ def checkupdates_app(app): .format(field=app.VercodeOperation)) oldvercode = str(int(vercode)) op = app.VercodeOperation.replace("%c", oldvercode) - vercode = str(eval(op)) + vercode = str(common.calculate_math_string(op)) logging.debug("Applied vercode operation: %s -> %s" % (oldvercode, vercode)) if version and any(version.startswith(s) for s in [ diff --git a/fdroidserver/common.py b/fdroidserver/common.py index dcda699a..c1a70003 100644 --- a/fdroidserver/common.py +++ b/fdroidserver/common.py @@ -24,6 +24,7 @@ import io import os import sys import re +import ast import shutil import glob import stat @@ -3205,3 +3206,26 @@ def get_git_describe_link(): else: logging.error(_("'{path}' failed to execute!").format(path='git describe')) return '' + + +def calculate_math_string(expr): + ops = {ast.Add: operator.add, ast.Sub: operator.sub, + ast.Mult: operator.mul} + + def execute_ast(node): + if isinstance(node, ast.Num): # + return node.n + elif isinstance(node, ast.BinOp): # + return ops[type(node.op)](execute_ast(node.left), + execute_ast(node.right)) + elif isinstance(node, ast.UnaryOp): # e.g., -1 + return ops[type(node.op)](eval(node.operand)) + else: + raise SyntaxError(node) + + try: + return execute_ast(ast.parse(expr, mode='eval').body) + except SyntaxError as e: + raise SyntaxError("could not parse expression '{expr}', " + "only basic math operations are allowed (+, -, *)" + .format(expr=expr)) From 6b1f242d251d88c906bc98d32b4ae5d1593620e3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michael=20P=C3=B6hn?= Date: Tue, 22 May 2018 13:24:37 +0200 Subject: [PATCH 2/2] added tests for common.calculate_math_string --- fdroidserver/common.py | 2 ++ tests/common.TestCase | 13 +++++++++++++ 2 files changed, 15 insertions(+) diff --git a/fdroidserver/common.py b/fdroidserver/common.py index c1a70003..2cde1dc1 100644 --- a/fdroidserver/common.py +++ b/fdroidserver/common.py @@ -3224,6 +3224,8 @@ def calculate_math_string(expr): raise SyntaxError(node) try: + if '#' in expr: + raise SyntaxError('no comments allowed') return execute_ast(ast.parse(expr, mode='eval').body) except SyntaxError as e: raise SyntaxError("could not parse expression '{expr}', " diff --git a/tests/common.TestCase b/tests/common.TestCase index f95a0820..e9dcafa7 100755 --- a/tests/common.TestCase +++ b/tests/common.TestCase @@ -779,6 +779,19 @@ class CommonTest(unittest.TestCase): self.assertEqual(('1.0-free', '1', 'com.kunzisoft.fdroidtest.applicationidsuffix'), fdroidserver.common.parse_androidmanifests(paths, app)) + def test_calculate_math_string(self): + self.assertEqual(1234, fdroidserver.common.calculate_math_string('1234')) + self.assertEqual(4, fdroidserver.common.calculate_math_string('(1+1)*2')) + self.assertEqual(2, fdroidserver.common.calculate_math_string('(1-1)*2+3*1-1')) + with self.assertRaises(SyntaxError): + fdroidserver.common.calculate_math_string('__import__("urllib")') + with self.assertRaises(SyntaxError): + fdroidserver.common.calculate_math_string('self') + with self.assertRaises(SyntaxError): + fdroidserver.common.calculate_math_string('1+1; print(1)') + with self.assertRaises(SyntaxError): + fdroidserver.common.calculate_math_string('1-1 # no comment') + if __name__ == "__main__": parser = optparse.OptionParser()