Чуваку в списке рассылки ещё более креативные способы предлагали. Своё облачное хранилище, например :) Но загрузчик мне и так пригодился бы, вот и решил совместить приятное с полезным.
Да, но идея была в том, чтобы от eval не отказываться. Про парсинг вручную есть у меня материал, этакий crash course, но он, сырой и, скорее, для детей. Не вижу смысла его тут публиковать.
Если посмотреть дерево для sin.__name__, то наблюдаем Attribute
AST Expression
body
AST Attribute
value
AST Name
id
'sin'
ctx
AST Load
attr
'__name__'
ctx
AST Load
Я аж протёр глаза, и подумал что Attribute каким-то образом унаследован от Name, поэтому isinstance его пропускает и даже полез смотреть Python-ast.c как они это делают, но всё оказалось гораздо проще. Вот правильная (надеюсь) версия валидатора:
def validate_ast(node):
for child in ast.iter_child_nodes(node):
if isinstance(child, list):
for grandchild in child:
validate_ast(grandchild)
else:
if not isinstance(child, _allowed_nodes):
raise Exception('Неправильное выражение')
if isinstance(child, ast.Constant) and not isinstance(child.value, (int, float, complex)):
raise Exception('Неправильное выражение')
validate_ast(child)
А всё потому, что скопипастил из аналогичного проекта, но там у меня разрешались только Call и Constant.
Была также мысль запретить Name везде, кроме вызовов функций, но это усложнило бы валидатор, и нельзя было бы добавить в контекст математические константы pi, e, tau
Понял, спасибо! Javascript у меня очень эпизодический, но я стараюсь не отставать.
Я что-то упускаю? Какая строчка попахивает мамонтом?
Всё это требует интернета. Самое штатное из всех средств должно быть USB, как наикратчайший путь.
А не пофиг ли? Мы же не собираемся загруженный файл выполнять.
Чуваку в списке рассылки ещё более креативные способы предлагали. Своё облачное хранилище, например :) Но загрузчик мне и так пригодился бы, вот и решил совместить приятное с полезным.
Да, но идея была в том, чтобы от eval не отказываться. Про парсинг вручную есть у меня материал, этакий crash course, но он, сырой и, скорее, для детей. Не вижу смысла его тут публиковать.
bad saturday ¯_(ツ)_/¯
Да, забыл сказать, что
ast.Expression
тогда надо добавить в_allowed_nodes
. Хотя, минимально достаточный патч для исправления этой баги будет таким:Поправил в статье, хотя вредительство уже успело расползтись.
Спасибо за +2 к миллиону глаз ?
'exec':None
бесполезен, в__builtins__
много всякого, напримерeval("__builtins__.import('os').removedirs('test-test-test')")
— сейчас всё исправим, насяльника ?
Если посмотреть дерево для sin.__name__, то наблюдаем Attribute
Я аж протёр глаза, и подумал что Attribute каким-то образом унаследован от Name, поэтому isinstance его пропускает и даже полез смотреть Python-ast.c как они это делают, но всё оказалось гораздо проще. Вот правильная (надеюсь) версия валидатора:
А всё потому, что скопипастил из аналогичного проекта, но там у меня разрешались только Call и Constant.
Была также мысль запретить Name везде, кроме вызовов функций, но это усложнило бы валидатор, и нельзя было бы добавить в контекст математические константы pi, e, tau
Ага, со строками недоработка. Можно добавить в валидатор
или попытаться преобразовать их в число как, это бывает в известных языках ?