Skip to content

Commit 4e27a3a

Browse files
committed
Blacklisted class macro
Macro that automatically generates fields for use in sandboxed classes.
1 parent 5b5d76a commit 4e27a3a

File tree

2 files changed

+360
-126
lines changed

2 files changed

+360
-126
lines changed

source/funkin/util/ReflectUtil.hx

Lines changed: 88 additions & 126 deletions
Original file line numberDiff line numberDiff line change
@@ -1,41 +1,64 @@
11
package funkin.util;
22

3-
import Type.ValueType;
4-
53
/**
64
* Provides sanitized and blacklisted access to haxe's Reflection functions.
75
* Used for sandboxing in scripts.
86
*/
97
@:nullSafety
108
@SuppressWarnings("checkstyle:VarTypeHint")
9+
@:build(funkin.util.macro.BlacklistClassMacro.build(
10+
{
11+
classes: ["Reflect", "Type"],
12+
aliases:
13+
{
14+
"setAnonymousField": ["setField"],
15+
"getAnonymousField": ["field", "getField"],
16+
"getAnonymousFieldsOf": ["fields", "getFieldsOf"],
17+
"copyAnonymousFieldsOf": ["copy"],
18+
"hasAnonymousField": ["hasField"],
19+
"deleteAnonymousField": ["delete", "deleteField"],
20+
"compareValues": ["compare"]
21+
},
22+
whitelist: [
23+
"isEnumValue",
24+
"compareMethods",
25+
"isFunction",
26+
"isObject",
27+
"getClassFields",
28+
"getInstanceFields",
29+
"getClassName",
30+
"getEnumName",
31+
"setProperty"
32+
]
33+
}))
1134
class ReflectUtil
1235
{
1336
/**
1437
* A list of field names which cannot be retrieved with `getAnonymousField()`
38+
*
39+
* This should always be a property so that scripts won't be able to change it.
1540
*/
16-
static final FIELD_NAME_BLACKLIST:Array<String> = ['_interp'];
41+
static var FIELD_NAME_BLACKLIST(get, never):Array<String>;
42+
43+
static function get_FIELD_NAME_BLACKLIST():Array<String>
44+
{
45+
return ['_interp'];
46+
}
1747

1848
/**
1949
* This function is not allowed to be used by scripts.
2050
* @throws error When called by a script.
2151
*/
22-
@SuppressWarnings("checkstyle:FieldDocComment")
23-
public static function callMethod(obj:Any, name:String, args:Array<Any>):Any
24-
{
25-
throw "Function Reflect.callMethod is blacklisted.";
26-
}
27-
52+
// public static function callMethod(obj:Any, name:String, args:Array<Any>):Any
2853
/**
2954
* Compares two objects by value.
3055
*
56+
* The actual function exists and is generated at build time.
3157
* @param valueA First value to compare
3258
* @param valueB Second value to compare
3359
* @return Int indicating relative order of values
3460
*/
35-
public static function compare(valueA:Any, valueB:Any):Int
36-
{
37-
return compareValues(valueA, valueB);
38-
}
61+
// public static function compare(valueA:Any, valueB:Any):Int
3962

4063
/**
4164
* Compares two values and returns an integer indicating their relative order.
@@ -59,21 +82,16 @@ class ReflectUtil
5982
* @param functionB A method closure to compare.
6083
* @return Whether functionA and functionB are equal.
6184
*/
62-
public static function compareMethods(functionA:Any, functionB:Any):Bool
63-
{
64-
return Reflect.compareMethods(functionA, functionB);
65-
}
66-
85+
// public static function compareMethods(functionA:Any, functionB:Any):Bool
6786
/**
6887
* Copies the given object.
6988
* Only guaranteed to work on anonymous structures.
89+
*
90+
* The actual function exists and is generated at build time.
7091
* @param obj The object to copy.
7192
* @return An independent clone of that object.
7293
*/
73-
public static function copy(obj:Any):Null<Any>
74-
{
75-
return copyAnonymousFieldsOf(obj);
76-
}
94+
// public static function copy(obj:Any):Null<Any>
7795

7896
/**
7997
* Copies the anonymous structure to a new object.
@@ -88,14 +106,13 @@ class ReflectUtil
88106
/**
89107
* Delete the field of a given name from an object.
90108
* Only guaranteed to work on anonymous structures.
109+
*
110+
* The actual function exists and is generated at build time.
91111
* @param obj The object to delete the field from.
92112
* @param name The name of the field to delete.
93113
* @return Whether the operation was successful.
94114
*/
95-
public static function delete(obj:Any, name:String):Bool
96-
{
97-
return deleteAnonymousField(obj, name);
98-
}
115+
// public static function delete(obj:Any, name:String):Bool
99116

100117
/**
101118
* Delete the field of a given name from an anonymous structure.
@@ -112,26 +129,23 @@ class ReflectUtil
112129
/**
113130
* Retrive the value of a given field (by name) from an object.
114131
* Only guaranteed to work on anonymous structures.
132+
*
133+
* The actual function exists and is generated at build time.
115134
* @param obj The object to delete the field from.
116135
* @param name The name of the field to delete.
117136
* @return Whether the operation was successful.
118137
*/
119-
public static function field(obj:Any, name:String):Any
120-
{
121-
return getAnonymousField(obj, name);
122-
}
123-
138+
// public static function field(obj:Any, name:String):Any
124139
/**
125140
* Retrive the value of a given field (by name) from an object.
126141
* Only guaranteed to work on anonymous structures.
142+
*
143+
* The actual function exists and is generated at build time.
127144
* @param obj The object to delete the field from.
128145
* @param name The name of the field to delete.
129146
* @return Whether the operation was successful.
130147
*/
131-
public static function getField(obj:Any, name:String):Any
132-
{
133-
return getAnonymousField(obj, name);
134-
}
148+
// public static function getField(obj:Any, name:String):Any
135149

136150
/**
137151
* Retrieve the value of the field of the given name from an anonymous structure.
@@ -153,24 +167,21 @@ class ReflectUtil
153167
/**
154168
* Get a list of fields available on the given object.
155169
* Only guaranteed to work on anonymous structures.
170+
*
171+
* The actual function exists and is generated at build time.
156172
* @param obj The object to query.
157173
* @return A list of fields on that object.
158174
*/
159-
public static function fields(obj:Any):Array<String>
160-
{
161-
return getAnonymousFieldsOf(obj);
162-
}
163-
175+
// public static function fields(obj:Any):Array<String>
164176
/**
165177
* Get a list of fields available on the given object.
166178
* Only guaranteed to work on anonymous structures.
179+
*
180+
* The actual function exists and is generated at build time.
167181
* @param obj The object to query.
168182
* @return A list of fields on that object.
169183
*/
170-
public static function getFieldsOf(obj:Any):Array<String>
171-
{
172-
return getAnonymousFieldsOf(obj);
173-
}
184+
// public static function getFieldsOf(obj:Any):Array<String>
174185

175186
/**
176187
* Get a list of fields available on the given anonymous structure.
@@ -191,6 +202,7 @@ class ReflectUtil
191202
* @return The value of the field.
192203
* @throws error If the field is blacklisted.
193204
*/
205+
@:blacklistOverride
194206
public static function getProperty(obj:Any, name:String):Any
195207
{
196208
if (FIELD_NAME_BLACKLIST.contains(name))
@@ -201,18 +213,6 @@ class ReflectUtil
201213
return Reflect.getProperty(obj, name);
202214
}
203215

204-
/**
205-
* Determine whether the given object has the given field.
206-
* Only guaranteed to work for anonymous structures.
207-
* @param obj The object to query.
208-
* @param name The field name to query.
209-
* @return Whether the field exists.
210-
*/
211-
public static function hasField(obj:Any, name:String):Bool
212-
{
213-
return hasAnonymousField(obj, name);
214-
}
215-
216216
/**
217217
* Determine whether the given anonymous structure has the given field.
218218
* @param obj The structure to query.
@@ -231,45 +231,38 @@ class ReflectUtil
231231

232232
/**
233233
* Determine whether the given input is an enum value.
234+
*
235+
* The actual function exists and is generated at build time.
234236
* @param value The input to evaluate.
235237
* @return Whether `value` is an enum value.
236238
*/
237-
public static function isEnumValue(value:Any):Bool
238-
{
239-
return Reflect.isEnumValue(value);
240-
}
241-
239+
// public static function isEnumValue(value:Any):Bool
242240
/**
243241
* Determine whether the given input is a callable function.
242+
*
243+
* The actual function exists and is generated at build time.
244244
* @param value The input to evaluate.
245245
* @return Whether `value` is a function.
246246
*/
247-
public static function isFunction(value:Any):Bool
248-
{
249-
return Reflect.isFunction(value);
250-
}
251-
247+
// public static function isFunction(value:Any):Bool
252248
/**
253249
* Determine whether the given input is an object.
250+
*
251+
* The actual function exists and is generated at build time.
254252
* @param value The input to evaluate.
255253
* @return Whether `value` is an object.
256254
*/
257-
public static function isObject(value:Any):Bool
258-
{
259-
return Reflect.isObject(value);
260-
}
261-
255+
// public static function isObject(value:Any):Bool
262256
/**
263257
* Set the value of a specific field on an object.
264258
* Only guaranteed to work for anonymous structures.
259+
*
260+
* The actual function exists and is generated at build time.
265261
* @param obj The object to modify.
266262
* @param name The field to modify.
267263
* @param value The new value to apply.
268264
*/
269-
public static function setField(obj:Any, name:String, value:Any):Void
270-
{
271-
return setAnonymousField(obj, name, value);
272-
}
265+
// public static function setField(obj:Any, name:String, value:Any):Void
273266

274267
/**
275268
* Set the value of a specific field on an anonymous structure.
@@ -285,74 +278,45 @@ class ReflectUtil
285278
/**
286279
* Set the value of a specific field on an object.
287280
* Accounts for property fields with getters and setters.
281+
*
282+
* The actual function exists and is generated at build time.
288283
* @param obj The object to modify.
289284
* @param name The field to modify.
290285
* @param value The new value to apply.
291286
*/
292-
public static function setProperty(obj:Any, name:String, value:Any):Void
293-
{
294-
return Reflect.setProperty(obj, name, value);
295-
}
296-
287+
// public static function setProperty(obj:Any, name:String, value:Any):Void
297288
/**
298289
* This function is not allowed to be used by scripts.
290+
*
291+
* The actual function exists and is generated at build time.
299292
* @throws error When called by a script.
300293
*/
301-
@SuppressWarnings("checkstyle:FieldDocComment")
302-
public static function createEmptyInstance(cls:Class<Any>):Any
303-
{
304-
throw "Function Type.createEmptyInstance is blacklisted.";
305-
}
306-
307-
/**
308-
* This function is not allowed to be used by scripts.
309-
* @throws error When called by a script.
310-
*/
311-
@SuppressWarnings("checkstyle:FieldDocComment")
312-
public static function createInstance(cls:Class<Any>, args:Array<Any>):Any
313-
{
314-
throw "Function Type.createInstance is blacklisted.";
315-
}
316-
294+
// public static function createEmptyInstance(cls:Class<Any>):Any
317295
/**
318296
* This function is not allowed to be used by scripts.
297+
*
298+
* The actual function exists and is generated at build time.
319299
* @throws error When called by a script.
320300
*/
321-
@SuppressWarnings("checkstyle:FieldDocComment")
322-
public static function resolveClass(name:String):Class<Any>
323-
{
324-
throw "Function Type.resolveClass is blacklisted.";
325-
}
326-
301+
// public static function createInstance(cls:Class<Any>, args:Array<Any>):Any
327302
/**
328303
* This function is not allowed to be used by scripts.
329304
* @throws error When called by a script.
330305
*/
331-
@SuppressWarnings("checkstyle:FieldDocComment")
332-
public static function resolveEnum(name:String):Enum<Any>
333-
{
334-
throw "Function Type.resolveEnum is blacklisted.";
335-
}
336-
306+
// public static function resolveEnum(name:String):Enum<Any>
337307
/**
338308
* This function is not allowed to be used by scripts.
339309
* @throws error When called by a script.
340310
*/
341-
@SuppressWarnings("checkstyle:FieldDocComment")
342-
public static function typeof(value:Any):ValueType
343-
{
344-
throw "Function Type.typeof is blacklisted.";
345-
}
346-
311+
// public static function typeof(value:Any):ValueType
347312
/**
348313
* Get a list of the static class fields on the given class.
314+
*
315+
* The actual function exists and is generated at build time.
349316
* @param cls The class object to query.
350317
* @return A list of class field names.
351318
*/
352-
public static function getClassFields(cls:Class<Any>):Array<String>
353-
{
354-
return Type.getClassFields(cls);
355-
}
319+
// public static function getClassFields(cls:Class<Any>):Array<String>
356320

357321
/**
358322
* Get a list of the static class fields on the class of the given object.
@@ -370,13 +334,12 @@ class ReflectUtil
370334

371335
/**
372336
* Get a list of all the fields on instances of the given class.
337+
*
338+
* The actual function exists and is generated at build time.
373339
* @param cls The class object to query.
374340
* @return A list of object field names.
375341
*/
376-
public static function getInstanceFields(cls:Class<Any>):Array<String>
377-
{
378-
return Type.getInstanceFields(cls);
379-
}
342+
// public static function getInstanceFields(cls:Class<Any>):Array<String>
380343

381344
/**
382345
* Get a list of all the fields on instances of the class of the given object.
@@ -394,13 +357,12 @@ class ReflectUtil
394357

395358
/**
396359
* Get the string name of the given class.
360+
*
361+
* The actual function exists and is generated at build time.
397362
* @param cls The class to query.
398363
* @return The name of the given class.
399364
*/
400-
public static function getClassName(cls:Class<Any>):String
401-
{
402-
return Type.getClassName(cls);
403-
}
365+
// public static function getClassName(cls:Class<Any>):String
404366

405367
/**
406368
* Get the string name of the class of the given object.

0 commit comments

Comments
 (0)