Haxe / hscript - предотвращение предоставления определенных методов сценариям

Итак, я создал "интерфейсный класс" со всеми статическими методами, которые я хочу показать hscript скрипты. Это выглядит так:

package com.application.interfaces.Terrain;

import com.application.TerrainCore

class Terrain {

    private static var terrain:TerrainCore;

    public static function _init(inTerrain:TerrainCore):Void {
        terrain = inTerrain;
    }

    public static function test(s:Int):Void {
        terrain.test(s);
    }
}

Проблема в том, что мне нужно установить terrain как-то возражать, но я не хочу, чтобы он подвергался воздействию скриптов. Я выставляю целые классы с

var interp = new Interp();
var module = Type.resolveClass("com.application.interfaces.Terrain");
interp.variables.set("Terrain", module)

Идея была переопределить метод call в hscript.Interp поэтому он не выполняет какой-либо метод с именем _init, но я не знаю, как это сделать. оригинал call Метод выглядит так:

function call( o : Dynamic, f : Dynamic, args : Array<Dynamic> ) : Dynamic {
    return Reflect.callMethod(o,f,args);
}

2 ответа

Решение

Можете ли вы использовать экземпляр класса Terrain вместо статических членов? Например:

interp.variables.set("Terrain", new Terrain(new TerrainCore()));

Пользователи сценариев не будут знать, используют ли они статические методы или методы экземпляра, так как к нему все равно будет доступ через:

Terrain.test(123);

в сценарии.

Другой вариант (основанный на clemos) - использовать rtti для определения того, что разрешено (вместо того, чтобы поддерживать его список), например:

Terrain._init(new TerrainCore());

_init сейчас является частной функцией, поэтому вам нужно @:allow это из вашего вызывающего класса (см. ниже), также вы должны аннотировать с @:rtti так что вы можете получить информацию о функциях во время выполнения, поэтому Terrain теперь выглядит так:

@:rtti
class Terrain {

    private static var terrain:TerrainCore;

    @:allow(test.hscript.demo.Main)
    private static function _init(inTerrain:TerrainCore):Void {
        terrain = inTerrain;
    }

    public static function test(s:Int):Void {
        terrain.test(s);
    }
}

Наконец, сценарий взаимодействия fcall Теперь учитывается, является ли поле публичным или частным, то есть:

public override function fcall(o:Dynamic, f:String, args:Array<Dynamic>):Dynamic 
    var rtti = haxe.rtti.Rtti.getRtti(o);
    for (field in rtti.statics) {
        if (field.name == f && field.isPublic == false) {
            error(EInvalidAccess(f));
        }
    }
    return super.fcall(o, f, args);
}

Стоит отметить, что я использовал statics скорее, чем fields по понятным причинам. Я также не уверен, какие издержки это может вызвать с циклом и RTI.

Я верю что это fcall вы должны переопределить, как call используется только для вызовов верхнего уровня:

https://github.com/HaxeFoundation/hscript/blob/master/hscript/Interp.hx#L328-L331

Это должно быть легко фильтровать f аргумент как:

if ( FORBIDDEN_FIELDS.indexOf( f ) > -1 ) throw EInvalidAccess( f );

или же

if ( f.indexOf('_') == 0 ) throw EInvalidAccess( f );
Другие вопросы по тегам