Skip to content

Commit

Permalink
In JavaScript engine settings was added one new property - `AllowRefl…
Browse files Browse the repository at this point in the history
…ection` (default `false`)
  • Loading branch information
Taritsyn committed Feb 26, 2023
1 parent a61ba63 commit 0deec16
Show file tree
Hide file tree
Showing 38 changed files with 696 additions and 148 deletions.
34 changes: 34 additions & 0 deletions build-js.cmd
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
@echo off
setlocal

cd ./src/MsieJavaScriptEngine/

::--------------------------------------------------------------------------------
:: Build
::--------------------------------------------------------------------------------

echo Installing Node.js packages ...
echo.
call npm install
if errorlevel 1 goto error
echo.

echo Minifying JS files ...
echo.
call npm run -s minify-js
if errorlevel 1 goto error
echo.

::--------------------------------------------------------------------------------
:: Exit
::--------------------------------------------------------------------------------

echo Succeeded!
goto exit

:error
echo *** Error: The previous step failed!

:exit
cd ../../
endlocal
2 changes: 1 addition & 1 deletion global.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"sdk": {
"version": "7.0.102"
"version": "7.0.200"
}
}
11 changes: 11 additions & 0 deletions src/MsieJavaScriptEngine/.uglifyjsrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"compress": {
"hoist_funs": true,
"hoist_vars": true,
"passes": 2
},
"mangle": {},
"output": {
"comments": "/^!/"
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -571,7 +571,7 @@ private void InnerCollectGarbage(ScriptGCType type)
/// <returns>The mapped value</returns>
private object MapToScriptType(object value)
{
return TypeMappingHelpers.MapToScriptType(value, _settings.EngineMode);
return TypeMappingHelpers.MapToScriptType(value, _settings.EngineMode, _settings.AllowReflection);
}

/// <summary>
Expand All @@ -581,7 +581,7 @@ private object MapToScriptType(object value)
/// <returns>The mapped array</returns>
private object[] MapToScriptType(object[] args)
{
return TypeMappingHelpers.MapToScriptType(args, _settings.EngineMode);
return TypeMappingHelpers.MapToScriptType(args, _settings.EngineMode, _settings.AllowReflection);
}

/// <summary>
Expand Down Expand Up @@ -900,7 +900,7 @@ public override void EmbedHostObject(string itemName, object value)

public override void EmbedHostType(string itemName, Type type)
{
var typeValue = new HostType(type, _settings.EngineMode);
var typeValue = new HostType(type, _settings.EngineMode, _settings.AllowReflection);

_dispatcher.Invoke(() =>
{
Expand Down
60 changes: 57 additions & 3 deletions src/MsieJavaScriptEngine/ActiveScript/HostItemBase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,11 @@ internal abstract class HostItemBase : IReflect
/// </summary>
protected readonly JsEngineMode _engineMode;

/// <summary>
/// Flag for whether to allow the usage of reflection API in the script code
/// </summary>
protected readonly bool _allowReflection;

/// <summary>
/// List of fields
/// </summary>
Expand Down Expand Up @@ -57,20 +62,26 @@ public object Target
/// <param name="type">Target type</param>
/// <param name="target">Target object</param>
/// <param name="engineMode">JS engine mode</param>
/// <param name="allowReflection">Flag for whether to allow the usage of reflection API in the script code</param>
/// <param name="instance">Flag for whether to allow access to members of the instance</param>
protected HostItemBase(Type type, object target, JsEngineMode engineMode, bool instance)
protected HostItemBase(Type type, object target, JsEngineMode engineMode, bool allowReflection, bool instance)
{
_type = type;
_target = target;
_allowReflection = allowReflection;
_engineMode = engineMode;

BindingFlags defaultBindingFlags = ReflectionHelpers.GetDefaultBindingFlags(instance);
FieldInfo[] fields = _type.GetFields(defaultBindingFlags);
PropertyInfo[] properties = _type.GetProperties(defaultBindingFlags);
if (properties.Length > 0 && !allowReflection)
{
properties = GetAvailableProperties(properties);
}
MethodInfo[] methods = _type.GetMethods(defaultBindingFlags);
if (methods.Length > 0 && properties.Length > 0)
if (methods.Length > 0 && (properties.Length > 0 || !allowReflection))
{
methods = ReflectionHelpers.GetFullyFledgedMethods(methods);
methods = GetAvailableMethods(methods, allowReflection);
}

_fields = fields;
Expand All @@ -79,6 +90,49 @@ protected HostItemBase(Type type, object target, JsEngineMode engineMode, bool i
}


private static PropertyInfo[] GetAvailableProperties(PropertyInfo[] properties)
{
int propertyCount = properties.Length;
var availableProperties = new PropertyInfo[propertyCount];
int availablePropertyIndex = 0;

for (int propertyIndex = 0; propertyIndex < propertyCount; propertyIndex++)
{
PropertyInfo property = properties[propertyIndex];
if (ReflectionHelpers.IsAllowedProperty(property))
{
availableProperties[availablePropertyIndex] = property;
availablePropertyIndex++;
}
}

Array.Resize(ref availableProperties, availablePropertyIndex);

return availableProperties;
}

private static MethodInfo[] GetAvailableMethods(MethodInfo[] methods, bool allowReflection)
{
int methodCount = methods.Length;
var availableMethods = new MethodInfo[methodCount];
int availableMethodIndex = 0;

for (int methodIndex = 0; methodIndex < methodCount; methodIndex++)
{
MethodInfo method = methods[methodIndex];
if (ReflectionHelpers.IsFullyFledgedMethod(method)
&& (allowReflection || ReflectionHelpers.IsAllowedMethod(method)))
{
availableMethods[availableMethodIndex] = method;
availableMethodIndex++;
}
}

Array.Resize(ref availableMethods, availableMethodIndex);

return availableMethods;
}

private bool IsField(string name)
{
bool isField = false;
Expand Down
7 changes: 4 additions & 3 deletions src/MsieJavaScriptEngine/ActiveScript/HostObject.cs
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,9 @@ internal sealed class HostObject : HostItemBase
/// </summary>
/// <param name="target">Target object</param>
/// <param name="engineMode">JS engine mode</param>
public HostObject(object target, JsEngineMode engineMode)
: base(target.GetType(), target, engineMode, true)
/// <param name="allowReflection">Flag for whether to allow the usage of reflection API in the script code</param>
public HostObject(object target, JsEngineMode engineMode, bool allowReflection)
: base(target.GetType(), target, engineMode, allowReflection, true)
{
var del = _target as Delegate;
if (del != null)
Expand Down Expand Up @@ -88,7 +89,7 @@ protected override object InnerInvokeMember(string name, BindingFlags invokeAttr
processedArgs, modifiers, culture, namedParameters);
}

return TypeMappingHelpers.MapToScriptType(result, _engineMode);
return TypeMappingHelpers.MapToScriptType(result, _engineMode, _allowReflection);
}

#endregion
Expand Down
7 changes: 4 additions & 3 deletions src/MsieJavaScriptEngine/ActiveScript/HostType.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,9 @@ internal sealed class HostType : HostItemBase
/// </summary>
/// <param name="type">Target type</param>
/// <param name="engineMode">JS engine mode</param>
public HostType(Type type, JsEngineMode engineMode)
: base(type, null, engineMode, false)
/// <param name="allowReflection">Flag for whether to allow the usage of reflection API in the script code</param>
public HostType(Type type, JsEngineMode engineMode, bool allowReflection)
: base(type, null, engineMode, allowReflection, false)
{ }


Expand Down Expand Up @@ -51,7 +52,7 @@ protected override object InnerInvokeMember(string name, BindingFlags invokeAttr
processedArgs, modifiers, culture, namedParameters);
}

return TypeMappingHelpers.MapToScriptType(result, _engineMode);
return TypeMappingHelpers.MapToScriptType(result, _engineMode, _allowReflection);
}

#endregion
Expand Down
82 changes: 59 additions & 23 deletions src/MsieJavaScriptEngine/Helpers/ReflectionHelpers.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,19 @@ namespace MsieJavaScriptEngine.Helpers
/// </summary>
internal static class ReflectionHelpers
{
private static readonly PropertyInfo[] _disallowedProperties =
{
typeof(Delegate).GetProperty("Method"),
typeof(Exception).GetProperty("TargetSite")
};

private static readonly MethodInfo[] _disallowedMethods =
{
typeof(object).GetMethod("GetType"),
typeof(Exception).GetMethod("GetType")
};


public static BindingFlags GetDefaultBindingFlags(bool instance)
{
BindingFlags bindingFlags = BindingFlags.Public;
Expand All @@ -27,6 +40,20 @@ public static BindingFlags GetDefaultBindingFlags(bool instance)
return bindingFlags;
}

public static bool IsAllowedProperty(PropertyInfo property)
{
bool isAllowed = !_disallowedProperties.Contains(property, MemberComparer<PropertyInfo>.Instance);

return isAllowed;
}

public static bool IsAllowedMethod(MethodInfo method)
{
bool isAllowed = !_disallowedMethods.Contains(method, MemberComparer<MethodInfo>.Instance);

return isAllowed;
}

public static bool IsFullyFledgedMethod(MethodInfo method)
{
if (!method.Attributes.HasFlag(MethodAttributes.SpecialName))
Expand All @@ -40,29 +67,6 @@ public static bool IsFullyFledgedMethod(MethodInfo method)

return isFullyFledged;
}
#if NETFRAMEWORK

public static MethodInfo[] GetFullyFledgedMethods(MethodInfo[] methods)
{
int methodCount = methods.Length;
var fullyFledgedMethods = new MethodInfo[methodCount];
int fullyFledgedMethodIndex = 0;

for (int methodIndex = 0; methodIndex < methodCount; methodIndex++)
{
MethodInfo method = methods[methodIndex];
if (IsFullyFledgedMethod(method))
{
fullyFledgedMethods[fullyFledgedMethodIndex] = method;
fullyFledgedMethodIndex++;
}
}

Array.Resize(ref fullyFledgedMethods, fullyFledgedMethodIndex);

return fullyFledgedMethods;
}
#endif

public static void FixFieldValueType(ref object value, FieldInfo field)
{
Expand Down Expand Up @@ -244,6 +248,38 @@ private static bool CompareParameterTypes(object[] argValues, Type[] argTypes, T
}


private sealed class MemberComparer<T> : EqualityComparer<T>
where T : MemberInfo
{
public static MemberComparer<T> Instance { get; } = new MemberComparer<T>();


private MemberComparer()
{ }


#region MemberComparer overrides

public override bool Equals(T x, T y)
{
return x.Module == y.Module
#if !NETSTANDARD1_3
&& x.MetadataToken == y.MetadataToken
#else
&& x.DeclaringType == y.DeclaringType
&& x.Name == y.Name
#endif
;
}

public override int GetHashCode(T obj)
{
return obj != null ? obj.GetHashCode() : 0;
}

#endregion
}

private sealed class MethodWithMetadata
{
public MethodBase Method
Expand Down
10 changes: 6 additions & 4 deletions src/MsieJavaScriptEngine/Helpers/TypeMappingHelpers.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,9 @@ internal static class TypeMappingHelpers
/// </summary>
/// <param name="value">The source value</param>
/// <param name="engineMode">JavaScript engine mode</param>
/// <param name="allowReflection">Flag for whether to allow the usage of reflection API in the script code</param>
/// <returns>The mapped value</returns>
public static object MapToScriptType(object value, JsEngineMode engineMode)
public static object MapToScriptType(object value, JsEngineMode engineMode, bool allowReflection)
{
if (value == null)
{
Expand All @@ -36,7 +37,7 @@ public static object MapToScriptType(object value, JsEngineMode engineMode)
return value;
}

var result = new HostObject(value, engineMode);
var result = new HostObject(value, engineMode, allowReflection);

return result;
}
Expand All @@ -46,10 +47,11 @@ public static object MapToScriptType(object value, JsEngineMode engineMode)
/// </summary>
/// <param name="args">The source array</param>
/// <param name="engineMode">JavaScript engine mode</param>
/// <param name="allowReflection">Flag for whether to allow the usage of reflection API in the script code</param>
/// <returns>The mapped array</returns>
public static object[] MapToScriptType(object[] args, JsEngineMode engineMode)
public static object[] MapToScriptType(object[] args, JsEngineMode engineMode, bool allowReflection)
{
return args.Select(arg => MapToScriptType(arg, engineMode)).ToArray();
return args.Select(arg => MapToScriptType(arg, engineMode, allowReflection)).ToArray();
}

/// <summary>
Expand Down
14 changes: 14 additions & 0 deletions src/MsieJavaScriptEngine/JsEngineSettings.cs
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,19 @@ public sealed class JsEngineSettings
private int _maxStackSize;

#endif
/// <summary>
/// Gets or sets a flag for whether to allow the usage of reflection API in the script code
/// </summary>
/// <remarks>
/// This affects <see cref="Object.GetType"/>, <c>Exception.GetType</c>,
/// <c>Exception.TargetSite</c> and <c>Delegate.Method</c>.
/// </remarks>
public bool AllowReflection
{
get;
set;
}

/// <summary>
/// Gets or sets a flag for whether to enable script debugging features
/// </summary>
Expand Down Expand Up @@ -95,6 +108,7 @@ public bool UseJson2Library
/// </summary>
public JsEngineSettings()
{
AllowReflection = false;
EnableDebugging = false;
EngineMode = JsEngineMode.Auto;
#if !NETSTANDARD1_3
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ internal sealed class ChakraEdgeJsRtJsEngine : ChakraJsRtJsEngineBase
public ChakraEdgeJsRtJsEngine(JsEngineSettings settings)
: base(settings)
{
_typeMapper = new EdgeTypeMapper();
_typeMapper = new EdgeTypeMapper(settings.AllowReflection);

try
{
Expand Down
Loading

0 comments on commit 0deec16

Please sign in to comment.