{ "info": { "author": "Yaroslav Polyakov", "author_email": "xenon@sysattack.com", "bugtrack_url": null, "classifiers": [], "description": "\ufeffEvalidate\n===\nEvalidate is simple python module for safe eval()'uating user-supplied (possible malicious) logical expressions in python syntax.\n\nPurpose\n---\nOriginally it's developed for filtering (performing boolean expressions) complex data structures e.g. raise salary if \n\n```python\nperson.age>30 and person.salary>5000 or \"Jack\" in person.children\n```\nor, like simple firewall, allow inbound traffic if:\n\n```python\n(packet.tcp.dstport==22 or packet.tcp.dstport==80) and packet.tcp.srcip in WhiteListIP\n```\nBut also, it can be used for other expressions, e.g. arithmetical, like\n```python\na+b-100\n```\n\nInstall\n---\n```shell\npip install evalidate\n```\n \nSecurity\n---\nBuilt-in python features such as compile() or eval() is quite powerful to run any kind of user-supplied code, but could be insecure if used code is malicious like os.system(\"rm -rf /\"). Evalidate works on whitelist principle, allowing code only if it consist only of safe operations (based on authors views about what is safe and what is not, your mileage may vary - but you can supply your list of safe operations)\n\nVery basic example\n---\n```python\nimport evalidate\n\nsrc=\"a+b\" # source code\nc={'a': 1, 'b': 2} # context, variables which will be available for code\n\nsuccess,result = evalidate.safeeval(src,c)\nif success:\n print result\nelse:\n print \"ERROR:\",result\n```\n\nGives output:\n\n 3\n\nIn case of dangerous code:\n```python\nsrc=\"__import__('os').system('clear')\"\n``` \n \noutput will be:\n\n ERROR: Validation error: Operaton type Call is not allowed\n \n# Extending evalidate, safenodes and addnodes #\nEvalidate has built-in set of python operations, which are considered 'safe' (from author point of view). Code is considered valid only if all of it's operations are in this lisst. You can override this list by adding argument *safenodes* like:\n```python\nsuccess,result = evalidate.safeeval(src,c, safenodes=['Expression','BinOp','Num','Add'])\n```\nthis will be enough for '1+1' expression (in src argument), but not for '1-1'. If you will try '1-1', it will report error:\n\n ERROR: Validation error: Operaton type Sub is not allowed\n\n\nThis way you can start from scratch and allow only required operations. As an alternative, you can use built-in list of allowed operations and extend it if needed, using *addnodes* argument.\n\nFor example, \"1*1\" will give error:\n\n ERROR: Validation error: Operaton type Mult is not allowed\n\n\nBut it will work with addnodes:\n```python\nsuccess,result = evalidate.safeeval(src,c, addnodes=['Mult'])\n``` \nPlease note, using 'Mult' operation isn't very secure, because for strings it can lead to Out-of-memory:\n```python\nsrc='\"a\"==\"a\"*100*100*100*100*100'\n``` \n ERROR: Runtime error (OverflowError): repeated string is too long\n\n# Allowing function calls\nEvalidate does not allows any function calls by default:\n```\n>>> import evalidate\n>>> evalidate.safeeval('1+int(2)')\n(False, 'Validation error: Operaton type Call is not allowed')\n```\nTo enable int() function, need to allow 'Call' node and add this function to list of allowed function:\n```\n>>> evalidate.safeeval('1+int(2)', addnodes=['Call'], funcs=['int'])\n(True, 3)\n```\nAttempt to call other functions will fail (because it's not in funcs list):\n```\n>>> evalidate.safeeval('1+round(2)', addnodes=['Call'], funcs=['int'])\n(False, 'Validation error: Call to function round() is not allowed')\n```\n\nFunctions\n---\n\n### safeeval()\n\n```python\nsuccess,result = safeeval(src,context={}, safenodes=None, addnodes=None, funcs=None, attrs=None)\n```\n\n*safeeval* is C-style higher-level wrapper of evalidate(), which validates code and runs it (if validation is successful)\n\n*src* - source expression like \"person['Age']>30 and salary==10000\"\n\n*context* - dictionary of variables, available for evaluated code.\n\n*safenodes*, *addnodes*, *funcs* and *attrs* are same as in evalidate()\n\nreturn values:\n\n*success* - binary, True if validation is successul and evaluation didn't thrown any exceptions. (False in this case) \n\n*result* - if success==True, result is result of expression. If success==False, result is string with error message, like \"ERROR: Runtime error (NameError): name 'aaa' is not defined\"\n \nsafeeval doesn't throws any exceptions\n\n### evalidate() \n```python\nnode = evalidate(expression, safenodes=None, addnodes=None, funcs=None, attrs=None)\n```\nevalidate() is main (and recommended to use) method, performs parsing of python expession, validates it, and returns python AST (Abstract Syntax Tree) structure, which can be later compiled and executed\n```python \n\n>>> import evalidate\n>>> node = evalidate.evalidate('1+2')\n>>> code = compile(node,'','eval')\n>>> eval(code)\n3\n``` \n \n- *expression* - string with python expressions like '1+2' or 'a+b' or 'a if a>0 else b' or 'p.salary * 1.2'\n- *safenodes* - list of allowed nodes. This will *override* built-in list of allowed nodes. e.g. `safenodes=['Expression','BinOp','Num','Add'])`\n- *addnodes* - list of allowed nodes. This will *extend* built-in lsit of allowed nodes. e.g. `addnodes=['Mult']`\n- *funcs* - list of allowed function calls. You need to add 'Call' to safe nodes. e.g. `funcs=['int']`\n- *attrs* - list of allowed attributes. You need to add 'Attribute' to attrs. e.g. `attrs=['salary']`.\n\n \nevalidate() throws ValueError if it doesn't like source code (if code has unsafe operations).\n \nEven if evalidate is successful, this doesn't guarantees that code will run well, For example, code still can have NameError (if tries to access undefined variable) or ZeroDivisionError.\n\nExamples\n---\n\n### Filtering by user-supplied condition ###\n```python\nimport evalidate\n \ndepot = [\n {\n 'book': 'Sirens of Titan',\n 'price': 12,\n 'stock': 4\n },\n {\n 'book': 'Gone Girl',\n 'price': 9.8,\n 'stock': 0\n },\n {\n 'book': 'Choke',\n 'price': 14,\n 'stock': 2\n },\n {\n 'book': 'Pulp',\n 'price': 7.45,\n 'stock': 4\n }\n]\n \n#src='stock==0' # books out of stock\nsrc='stock>0 and price>8' # expensive book available for sale\n \nfor book in depot:\n success, result = evalidate.safeeval(src,book)\n \n if success:\n if result:\n print book\n else:\n print \"ERR:\", result\n``` \n \nWith first src line ('stock==0') it gives:\n\n {'price': 9.8, 'book': 'Gone Girl', 'stock': 0}\n\nWith second src line ('stock>0 and price>8') it gives:\n\n {'price': 12, 'book': 'Sirens of Titan', 'stock': 4}\n {'price': 14, 'book': 'Choke', 'stock': 2}\n \n\n\n### Data as objects ###\nData represented as object with attributes (not as dictionary) (we have to add 'Attribute' to safe nodes). Increase salary for person for 200, and additionaly 25 for each year (s)he works in company.\n```python\nimport evalidate\n \nclass Person:\n pass\n \np = Person()\np.salary=1000\np.age=5\n \ndata = {'p':p}\nsrc = 'p.salary+200+p.age*25'\n \nsuccess, result = evalidate.safeeval(src,data,addnodes=['Attribute','Mult'], attrs=['salary', 'age'])\n \nif success:\n print \"result\", result\nelse:\n print \"ERR:\", result\n```\n \n### Validate, compile and evaluate code ###\n```python\nimport evalidate\nimport os\n \ndata={'one':1,'two':2}\nsrc='one+two+3'\n#src='one+two+3+os.system(\"clear\")'\n \ntry:\n node = evalidate.evalidate(src)\n code = compile(node,'','eval')\n result = eval(code,{},data)\n print \"result:\",result\nexcept ValueError:\n print \"Bad source code:\", src\n``` \n \nMore info\n---\nWant more info? Check source code of module, it's very short and simple, easy to modify\n\nContact\n---\nWrite me: yaroslaff@gmail.com", "description_content_type": "text/markdown", "docs_url": null, "download_url": "", "downloads": { "last_day": -1, "last_month": -1, "last_week": -1 }, "home_page": "http://bitbucket.org/yaroslaff/evalidate", "keywords": "", "license": "MIT", "maintainer": "", "maintainer_email": "", "name": "evalidate", "package_url": "https://pypi.org/project/evalidate/", "platform": "", "project_url": "https://pypi.org/project/evalidate/", "project_urls": { "Homepage": "http://bitbucket.org/yaroslaff/evalidate" }, "release_url": "https://pypi.org/project/evalidate/0.7.7/", "requires_dist": null, "requires_python": "", "summary": "Validation and secure evaluation untrusted python expressions", "version": "0.7.7" }, "last_serial": 5427044, "releases": { "0.1": [ { "comment_text": "", "digests": { "md5": "5be24e69c9cec4d3942180b30fb0a957", "sha256": "c939d6b300502c07750386108d938cfb47ae2b11bd00143bfbd1bef740989399" }, "downloads": -1, "filename": "evalidate-0.1.tar.gz", "has_sig": false, "md5_digest": "5be24e69c9cec4d3942180b30fb0a957", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 1793, "upload_time": "2014-10-04T15:35:15", "url": "https://files.pythonhosted.org/packages/5d/e3/cf0dc8919585a6d152d56605fbe260fb789b846da497904cf22186469f32/evalidate-0.1.tar.gz" } ], "0.2": [ { "comment_text": "", "digests": { "md5": "04bb2a464b87ac3c474c5ff8e893a37f", "sha256": "b9fc1f1d6864f33348be53ae893f8720a6988e104f921ac99e7d83b96e20c628" }, "downloads": -1, "filename": "evalidate-0.2.tar.gz", "has_sig": false, "md5_digest": "04bb2a464b87ac3c474c5ff8e893a37f", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 1787, "upload_time": "2014-10-04T18:05:04", "url": "https://files.pythonhosted.org/packages/4c/2a/5579ead8502e8b3bdc1530ea3554375d074bddedff35772b938e46c634b5/evalidate-0.2.tar.gz" } ], "0.3": [ { "comment_text": "", "digests": { "md5": "bdfbbf424447f24caab99e4be575ef48", "sha256": "4a1672f85fa85997dd244ce29d4fe4321fe6997d41152fba38124363ef1cee90" }, "downloads": -1, "filename": "evalidate-0.3.tar.gz", "has_sig": false, "md5_digest": "bdfbbf424447f24caab99e4be575ef48", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 1790, "upload_time": "2014-10-04T18:06:41", "url": "https://files.pythonhosted.org/packages/60/c3/0be3b2c7f503484802c7c3eb3a2130ce52a9ef04f38de9425d31e236bcdc/evalidate-0.3.tar.gz" } ], "0.4": [ { "comment_text": "", "digests": { "md5": "dad1ee596ab1171d992a9a32e59c8cc9", "sha256": "f6541fc2ab686747b7813a9f5d0a768f7cca7ad0096997bba49c95f89ff07347" }, "downloads": -1, "filename": "evalidate-0.4.tar.gz", "has_sig": false, "md5_digest": "dad1ee596ab1171d992a9a32e59c8cc9", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 1853, "upload_time": "2015-01-17T04:33:25", "url": "https://files.pythonhosted.org/packages/f5/22/e60bb2f6d4da1c81d3ba0797cc2d0830120f72d763f00839918e01e81bd3/evalidate-0.4.tar.gz" } ], "0.5": [ { "comment_text": "", "digests": { "md5": "17589bdb86fb26ae168ed535e3d899b9", "sha256": "8caa52f4ecfcc2de050e9a59cdf19d708d8d6ffd417ee4ed95a6d3701f6edba5" }, "downloads": -1, "filename": "evalidate-0.5.tar.gz", "has_sig": false, "md5_digest": "17589bdb86fb26ae168ed535e3d899b9", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 1854, "upload_time": "2015-01-20T17:00:09", "url": "https://files.pythonhosted.org/packages/af/5a/8d1772cda097c762945358e8c84727446d2faff602841d77eff9f2389fbd/evalidate-0.5.tar.gz" } ], "0.6": [ { "comment_text": "", "digests": { "md5": "b9dd3b82de7d31c3628cae7e065bf43a", "sha256": "5ee01f17353ff63f818c7ee228b0e0a4e4f24833eae9fc48467799be08061e57" }, "downloads": -1, "filename": "evalidate-0.6.tar.gz", "has_sig": false, "md5_digest": "b9dd3b82de7d31c3628cae7e065bf43a", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 1992, "upload_time": "2015-01-21T11:57:32", "url": "https://files.pythonhosted.org/packages/6d/d1/ebc154f2f88f90be612b515fd284504fa4ca9de77854afa5a1e5db6cf8a6/evalidate-0.6.tar.gz" } ], "0.7": [ { "comment_text": "", "digests": { "md5": "f29f3981cd8ceed7402ffa236a7f7c76", "sha256": "f69bd0f88defecc3425a4d6055900000c7137d84826a3d03613ea3938bbd0943" }, "downloads": -1, "filename": "evalidate-0.7.tar.gz", "has_sig": false, "md5_digest": "f29f3981cd8ceed7402ffa236a7f7c76", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 2083, "upload_time": "2015-05-28T19:33:21", "url": "https://files.pythonhosted.org/packages/56/3c/3b474e4fd74312fae2b11ffe63bf00805ffe0c8cf92cdfd2daf4cc7fe693/evalidate-0.7.tar.gz" } ], "0.7.1": [ { "comment_text": "", "digests": { "md5": "da6145a9fcbbdcdeef1fe3714f633a98", "sha256": "a04361b85ca0c4908d9d152cb87f97ca66bdf559639e6172e518528cd49c30e3" }, "downloads": -1, "filename": "evalidate-0.7.1.tar.gz", "has_sig": false, "md5_digest": "da6145a9fcbbdcdeef1fe3714f633a98", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 2083, "upload_time": "2015-05-28T19:39:15", "url": "https://files.pythonhosted.org/packages/f5/87/3f22ba6aefadf364d0d6cca9654b6cb0f506da83dbec53e97ee44cb79cf1/evalidate-0.7.1.tar.gz" } ], "0.7.2": [ { "comment_text": "", "digests": { "md5": "38769e0d181007b1eeb03f7d27919692", "sha256": "429c4f0a2cf01a4c2e94c3c1680ecaf41d76d2fcc6fe76b9d71d41200c1716e2" }, "downloads": -1, "filename": "evalidate-0.7.2.tar.gz", "has_sig": false, "md5_digest": "38769e0d181007b1eeb03f7d27919692", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 4804, "upload_time": "2018-10-01T20:53:35", "url": "https://files.pythonhosted.org/packages/11/23/85884a724411dbdf2e9dfaf2dab5bfbf0acacecbc848b2e9d3662a8bd911/evalidate-0.7.2.tar.gz" } ], "0.7.3": [ { "comment_text": "", "digests": { "md5": "b6c9da2b83d897752363a8b9c9bf9e14", "sha256": "4729fc42c09836c8bf28ec731dc32086ccfd665340938d897531105d1ab97a1d" }, "downloads": -1, "filename": "evalidate-0.7.3.tar.gz", "has_sig": false, "md5_digest": "b6c9da2b83d897752363a8b9c9bf9e14", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 5740, "upload_time": "2018-10-01T21:02:53", "url": "https://files.pythonhosted.org/packages/36/12/f4ba5cb5802f09bb9121dfb575e0fede01aa82994526feed6152d227f6ef/evalidate-0.7.3.tar.gz" } ], "0.7.4": [ { "comment_text": "", "digests": { "md5": "f01ce64af252b9d905e2f5c122af9863", "sha256": "be6e5b5d58aa037d948db677925d72297ca4b503ddc0141d96f2ee5487a8a034" }, "downloads": -1, "filename": "evalidate-0.7.4.tar.gz", "has_sig": false, "md5_digest": "f01ce64af252b9d905e2f5c122af9863", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 5779, "upload_time": "2018-10-01T21:16:27", "url": "https://files.pythonhosted.org/packages/5c/82/49a1bd923366cca11dff92e67d1b0c6cc4bfb4aec7cf288e65376010773e/evalidate-0.7.4.tar.gz" } ], "0.7.5": [ { "comment_text": "", "digests": { "md5": "9991ebf88eb5f3097a1bdb7e77e4f9dd", "sha256": "f0c4b12b72d2aed05ad55dd7a3998b47646d94b52fc8c864ae6a8c8640c6054b" }, "downloads": -1, "filename": "evalidate-0.7.5.tar.gz", "has_sig": false, "md5_digest": "9991ebf88eb5f3097a1bdb7e77e4f9dd", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 5788, "upload_time": "2018-10-02T15:21:21", "url": "https://files.pythonhosted.org/packages/d9/35/412b40cac393554a435472ee05c536f31b461f5e1f0e6bc28862e26d8f58/evalidate-0.7.5.tar.gz" } ], "0.7.6": [ { "comment_text": "", "digests": { "md5": "2b28de2e7ea310c9357c0dd8eb61a7fd", "sha256": "cf4a93cede189553fc2dffe1880ae67197bdeca7d1cf3bba012c91aefe211852" }, "downloads": -1, "filename": "evalidate-0.7.6.tar.gz", "has_sig": false, "md5_digest": "2b28de2e7ea310c9357c0dd8eb61a7fd", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 6210, "upload_time": "2018-10-04T18:04:04", "url": "https://files.pythonhosted.org/packages/a5/c4/37fee204e378755c8aea64a1e62684a710d482c0b6140923cc52e9cff862/evalidate-0.7.6.tar.gz" } ], "0.7.7": [ { "comment_text": "", "digests": { "md5": "d44609a4db7ac928676262ba46dfd0fe", "sha256": "637f97bd3fad19f60a077924aa26a5818065316efe8333bda33e11da6b4afd32" }, "downloads": -1, "filename": "evalidate-0.7.7.tar.gz", "has_sig": false, "md5_digest": "d44609a4db7ac928676262ba46dfd0fe", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 6299, "upload_time": "2019-06-20T18:09:30", "url": "https://files.pythonhosted.org/packages/65/a8/28fd618da4e6d0eeacb523687c313acc320f5f85e4878f8d14e56cfb7cec/evalidate-0.7.7.tar.gz" } ] }, "urls": [ { "comment_text": "", "digests": { "md5": "d44609a4db7ac928676262ba46dfd0fe", "sha256": "637f97bd3fad19f60a077924aa26a5818065316efe8333bda33e11da6b4afd32" }, "downloads": -1, "filename": "evalidate-0.7.7.tar.gz", "has_sig": false, "md5_digest": "d44609a4db7ac928676262ba46dfd0fe", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 6299, "upload_time": "2019-06-20T18:09:30", "url": "https://files.pythonhosted.org/packages/65/a8/28fd618da4e6d0eeacb523687c313acc320f5f85e4878f8d14e56cfb7cec/evalidate-0.7.7.tar.gz" } ] }