diff --git a/README.md b/README.md index 1166491..c315198 100644 --- a/README.md +++ b/README.md @@ -17,7 +17,7 @@ For adding a library only: com.instancify.scriptify core - 1.3.3-SNAPSHOT + 1.3.4-SNAPSHOT ``` @@ -26,12 +26,12 @@ For adding a library with JS for Rhino or GraalVM: com.instancify.scriptify script-js-rhino - 1.3.3-SNAPSHOT + 1.3.4-SNAPSHOT com.instancify.scriptify script-js-graalvm - 1.3.3-SNAPSHOT + 1.3.4-SNAPSHOT ``` ## Gradle @@ -45,11 +45,11 @@ maven { For adding a library only: ```groovy -implementation "com.instancify.scriptify:core:1.3.3-SNAPSHOT" +implementation "com.instancify.scriptify:core:1.3.4-SNAPSHOT" ``` For adding a library with JS for Rhino or GraalVM: ```groovy -implementation "com.instancify.scriptify:script-js-rhino:1.3.3-SNAPSHOT" -implementation "com.instancify.scriptify:script-js-graalvm:1.3.3-SNAPSHOT" +implementation "com.instancify.scriptify:script-js-rhino:1.3.4-SNAPSHOT" +implementation "com.instancify.scriptify:script-js-graalvm:1.3.4-SNAPSHOT" ``` \ No newline at end of file diff --git a/api/src/main/java/com/instancify/scriptify/api/script/security/SecurityClassAccessor.java b/api/src/main/java/com/instancify/scriptify/api/script/security/SecurityClassAccessor.java index a8f4a26..ac06de5 100644 --- a/api/src/main/java/com/instancify/scriptify/api/script/security/SecurityClassAccessor.java +++ b/api/src/main/java/com/instancify/scriptify/api/script/security/SecurityClassAccessor.java @@ -1,5 +1,7 @@ package com.instancify.scriptify.api.script.security; +import com.instancify.scriptify.api.script.security.exclude.SecurityExclude; + import java.util.Set; /** @@ -12,12 +14,5 @@ public interface SecurityClassAccessor { * * @return A set of strings representing the names of allowed classes */ - Set getAllowedClasses(); - - /** - * Adds a class to the list of allowed classes, which can then be used or accessed. - * - * @param allowedClass The name of the class to be added to the allowed list - */ - void addAllowedClass(String allowedClass); + Set getExcludes(); } \ No newline at end of file diff --git a/api/src/main/java/com/instancify/scriptify/api/script/security/exclude/ClassSecurityExclude.java b/api/src/main/java/com/instancify/scriptify/api/script/security/exclude/ClassSecurityExclude.java index 118c770..5718879 100644 --- a/api/src/main/java/com/instancify/scriptify/api/script/security/exclude/ClassSecurityExclude.java +++ b/api/src/main/java/com/instancify/scriptify/api/script/security/exclude/ClassSecurityExclude.java @@ -1,9 +1,17 @@ package com.instancify.scriptify.api.script.security.exclude; +/** + * Excludes a specific class for security purposes. + */ public class ClassSecurityExclude implements SecurityExclude { private final Class value; + /** + * Creates a class exclusion rule. + * + * @param value Class to exclude + */ public ClassSecurityExclude(Class value) { this.value = value; } diff --git a/api/src/main/java/com/instancify/scriptify/api/script/security/exclude/PackageSecurityExclude.java b/api/src/main/java/com/instancify/scriptify/api/script/security/exclude/PackageSecurityExclude.java new file mode 100644 index 0000000..b1d8c24 --- /dev/null +++ b/api/src/main/java/com/instancify/scriptify/api/script/security/exclude/PackageSecurityExclude.java @@ -0,0 +1,23 @@ +package com.instancify.scriptify.api.script.security.exclude; + +/** + * Excludes an entire package for security purposes. + */ +public class PackageSecurityExclude implements SecurityExclude { + + private final String value; + + /** + * Creates a package exclusion rule. + * + * @param value Package name to exclude + */ + public PackageSecurityExclude(String value) { + this.value = value; + } + + @Override + public String getValue() { + return value; + } +} diff --git a/api/src/main/java/com/instancify/scriptify/api/script/security/exclude/PathSecurityExclude.java b/api/src/main/java/com/instancify/scriptify/api/script/security/exclude/PathSecurityExclude.java index 0c5e516..949286f 100644 --- a/api/src/main/java/com/instancify/scriptify/api/script/security/exclude/PathSecurityExclude.java +++ b/api/src/main/java/com/instancify/scriptify/api/script/security/exclude/PathSecurityExclude.java @@ -1,9 +1,17 @@ package com.instancify.scriptify.api.script.security.exclude; +/** + * Excludes a specific path for security purposes. + */ public class PathSecurityExclude implements SecurityExclude { private final String value; + /** + * Creates a path exclusion rule. + * + * @param value Path to exclude + */ public PathSecurityExclude(String value) { this.value = value; } diff --git a/api/src/main/java/com/instancify/scriptify/api/script/security/exclude/SecurityExclude.java b/api/src/main/java/com/instancify/scriptify/api/script/security/exclude/SecurityExclude.java index 1b14e79..d767fad 100644 --- a/api/src/main/java/com/instancify/scriptify/api/script/security/exclude/SecurityExclude.java +++ b/api/src/main/java/com/instancify/scriptify/api/script/security/exclude/SecurityExclude.java @@ -1,5 +1,9 @@ package com.instancify.scriptify.api.script.security.exclude; +/** + * Defines exclusions for security purposes, specifically for paths, packages, or classes. + * This interface acts as a base for creating exclusion rules in a security context. + */ public interface SecurityExclude { /** @@ -20,6 +24,16 @@ default boolean isExcluded(String value) { return value.startsWith(this.getValue()); } + /** + * Creates a new exclusion instance for the package. + * + * @param value A package that will be excluded + * @return A new exclusion instance for the package + */ + static PackageSecurityExclude ofPackage(String value) { + return new PackageSecurityExclude(value); + } + /** * Creates a new exclusion instance for the class. * diff --git a/build.gradle.kts b/build.gradle.kts index 5e222ec..05aa678 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -12,7 +12,7 @@ java { allprojects { group = "com.instancify.scriptify" - version = "1.3.3-SNAPSHOT" + version = "1.3.4-SNAPSHOT" } subprojects { diff --git a/script-js-graalvm/src/main/java/com/instancify/scriptify/script/JsScript.java b/script-js-graalvm/src/main/java/com/instancify/scriptify/script/JsScript.java index 5c53326..6db4ca4 100644 --- a/script-js-graalvm/src/main/java/com/instancify/scriptify/script/JsScript.java +++ b/script-js-graalvm/src/main/java/com/instancify/scriptify/script/JsScript.java @@ -7,10 +7,10 @@ import com.instancify.scriptify.api.script.function.ScriptFunction; import com.instancify.scriptify.api.script.function.ScriptFunctionManager; import com.instancify.scriptify.api.script.security.ScriptSecurityManager; -import com.instancify.scriptify.api.script.security.exclude.ClassSecurityExclude; -import com.instancify.scriptify.api.script.security.exclude.SecurityExclude; import com.instancify.scriptify.core.script.security.StandardSecurityManager; -import org.graalvm.polyglot.*; +import org.graalvm.polyglot.Context; +import org.graalvm.polyglot.HostAccess; +import org.graalvm.polyglot.Value; public class JsScript implements Script { @@ -51,13 +51,7 @@ public Value eval(String script) throws ScriptException { // If security mode is enabled, search all exclusions // and add the classes that were excluded to JsSecurityClassAccessor if (securityManager.getSecurityMode()) { - JsSecurityClassAccessor classAccessor = new JsSecurityClassAccessor(); - for (SecurityExclude exclude : securityManager.getExcludes()) { - if (exclude instanceof ClassSecurityExclude classExclude) { - classAccessor.addAllowedClass(classExclude.getValue()); - } - } - builder.allowHostClassLookup(classAccessor); + builder.allowHostClassLookup(new JsSecurityClassAccessor(securityManager.getExcludes())); } else { builder.allowHostClassLookup(className -> true); } diff --git a/script-js-graalvm/src/main/java/com/instancify/scriptify/script/JsSecurityClassAccessor.java b/script-js-graalvm/src/main/java/com/instancify/scriptify/script/JsSecurityClassAccessor.java index 23b4427..3b37f57 100644 --- a/script-js-graalvm/src/main/java/com/instancify/scriptify/script/JsSecurityClassAccessor.java +++ b/script-js-graalvm/src/main/java/com/instancify/scriptify/script/JsSecurityClassAccessor.java @@ -1,6 +1,9 @@ package com.instancify.scriptify.script; import com.instancify.scriptify.api.script.security.SecurityClassAccessor; +import com.instancify.scriptify.api.script.security.exclude.ClassSecurityExclude; +import com.instancify.scriptify.api.script.security.exclude.PackageSecurityExclude; +import com.instancify.scriptify.api.script.security.exclude.SecurityExclude; import org.graalvm.polyglot.PolyglotException; import java.util.HashSet; @@ -9,24 +12,41 @@ public class JsSecurityClassAccessor implements Predicate, SecurityClassAccessor { - private final Set allowedClasses = new HashSet<>(); + private final Set excludes; + private final Set allowedClasses; + private final Set allowedPackages; - public JsSecurityClassAccessor() { - this.allowedClasses.add(PolyglotException.class.getName()); - } + public JsSecurityClassAccessor(Set excludes) { + this.excludes = excludes; + this.allowedClasses = new HashSet<>(); + this.allowedPackages = new HashSet<>(); - @Override - public Set getAllowedClasses() { - return allowedClasses; + for (SecurityExclude exclude : excludes) { + if (exclude instanceof ClassSecurityExclude classExclude) { + allowedClasses.add(classExclude.getValue()); + } else if (exclude instanceof PackageSecurityExclude packageExclude) { + allowedPackages.add(packageExclude.getValue()); + } + } + + this.allowedClasses.add(PolyglotException.class.getName()); } @Override - public void addAllowedClass(String allowedClass) { - this.allowedClasses.add(allowedClass); + public Set getExcludes() { + return excludes; } @Override public boolean test(String className) { - return this.allowedClasses.contains(className); + if (this.allowedClasses.contains(className)) { + return true; + } + for (String exclude : this.allowedPackages) { + if (className.startsWith(exclude)) { + return true; + } + } + return false; } } diff --git a/script-js-rhino/src/main/java/com/instancify/scriptify/script/JsScript.java b/script-js-rhino/src/main/java/com/instancify/scriptify/script/JsScript.java index c984146..3e618a6 100644 --- a/script-js-rhino/src/main/java/com/instancify/scriptify/script/JsScript.java +++ b/script-js-rhino/src/main/java/com/instancify/scriptify/script/JsScript.java @@ -52,13 +52,7 @@ public Object eval(String script) throws ScriptException { // If security mode is enabled, search all exclusions // and add the classes that were excluded to JsSecurityClassAccessor if (securityManager.getSecurityMode()) { - JsSecurityClassAccessor classAccessor = new JsSecurityClassAccessor(); - for (SecurityExclude exclude : securityManager.getExcludes()) { - if (exclude instanceof ClassSecurityExclude classExclude) { - classAccessor.addAllowedClass(classExclude.getValue()); - } - } - context.setClassShutter(classAccessor); + context.setClassShutter(new JsSecurityClassAccessor(securityManager.getExcludes())); } if (functionManager != null) { diff --git a/script-js-rhino/src/main/java/com/instancify/scriptify/script/JsSecurityClassAccessor.java b/script-js-rhino/src/main/java/com/instancify/scriptify/script/JsSecurityClassAccessor.java index f94ed7f..a6f1092 100644 --- a/script-js-rhino/src/main/java/com/instancify/scriptify/script/JsSecurityClassAccessor.java +++ b/script-js-rhino/src/main/java/com/instancify/scriptify/script/JsSecurityClassAccessor.java @@ -1,6 +1,9 @@ package com.instancify.scriptify.script; import com.instancify.scriptify.api.script.security.SecurityClassAccessor; +import com.instancify.scriptify.api.script.security.exclude.ClassSecurityExclude; +import com.instancify.scriptify.api.script.security.exclude.PackageSecurityExclude; +import com.instancify.scriptify.api.script.security.exclude.SecurityExclude; import org.mozilla.javascript.ClassShutter; import org.mozilla.javascript.EcmaError; @@ -9,24 +12,41 @@ public class JsSecurityClassAccessor implements ClassShutter, SecurityClassAccessor { - private final Set allowedClasses = new HashSet<>(); + private final Set excludes; + private final Set allowedClasses; + private final Set allowedPackages; - public JsSecurityClassAccessor() { - this.allowedClasses.add(EcmaError.class.getName()); - } + public JsSecurityClassAccessor(Set excludes) { + this.excludes = excludes; + this.allowedClasses = new HashSet<>(); + this.allowedPackages = new HashSet<>(); - @Override - public Set getAllowedClasses() { - return allowedClasses; + for (SecurityExclude exclude : excludes) { + if (exclude instanceof ClassSecurityExclude classExclude) { + allowedClasses.add(classExclude.getValue()); + } else if (exclude instanceof PackageSecurityExclude packageExclude) { + allowedPackages.add(packageExclude.getValue()); + } + } + + this.allowedClasses.add(EcmaError.class.getName()); } @Override - public void addAllowedClass(String allowedClass) { - this.allowedClasses.add(allowedClass); + public Set getExcludes() { + return excludes; } @Override - public boolean visibleToScripts(String fullClassName) { - return this.allowedClasses.contains(fullClassName); + public boolean visibleToScripts(String className) { + if (this.allowedClasses.contains(className)) { + return true; + } + for (String exclude : this.allowedPackages) { + if (className.startsWith(exclude)) { + return true; + } + } + return false; } }