001package com.killcoding.jsplus; 002 003import javax.script.ScriptEngine; 004import javax.script.Invocable; 005import javax.script.Bindings; 006import javax.script.ScriptContext; 007import javax.script.SimpleScriptContext; 008import com.killcoding.tool.CommonTools; 009import java.nio.file.Files; 010import java.util.List; 011import java.nio.file.Paths; 012import com.killcoding.tool.FileTools; 013import java.io.File; 014import com.killcoding.file.DiskFile; 015import com.killcoding.tool.CipherTools; 016import com.killcoding.file.BaseFile; 017import com.killcoding.log.Logger; 018import org.openjdk.nashorn.api.scripting.NashornScriptEngineFactory; 019import org.openjdk.nashorn.api.scripting.ClassFilter; 020import com.killcoding.tool.ConfigProperties; 021 022public class NashornContext extends JsPlusContext { 023 024 private NashornScriptEngineFactory nashornFactory = null; 025 private Invocable invocable = null; 026 private ScriptEngine scriptEngine = null; 027 private ScriptContext context = null; 028 private Bindings bindings = null; 029 private ClassLoader customClassLoader = null; 030 031 private class SecurityClassFilter implements ClassFilter { 032 @Override 033 public boolean exposeToScripts(String className) { 034 if (allowAllAccess) { 035 return true; 036 } 037 return false; 038 } 039 } 040 041 public NashornContext(String engineName){ 042 super(engineName); 043 } 044 045 @Override 046 public Object getBindings(){ 047 return bindings; 048 } 049 050 @Override 051 public Object getEngine(){ 052 return nashornFactory; 053 } 054 055 @Override 056 public ScriptContext getContext(){ 057 return context; 058 } 059 060 @Override 061 public void remove(String name){ 062 if (bindings != null) { 063 bindings.remove(name); 064 } 065 } 066 067 @Override 068 public void put(String name,Object value){ 069 if (bindings != null) { 070 bindings.put(name,value); 071 } 072 } 073 074 @Override 075 public Object get(String name){ 076 return bindings != null ? bindings.get(name) : null; 077 } 078 079 @Override 080 public void initScriptEngineManager() throws Exception { 081 ConfigProperties appenvCp = ScriptConsole.getAppenv(); 082 String[] options = new String[]{}; 083 if(appenvCp != null){ 084 String engineNameMapKey = String.format("%s.options",engineName); 085 List<String> optionsArray = appenvCp.getArray(engineNameMapKey,new String[]{}); 086 options = optionsArray.toArray(new String[]{}); 087 System.out.println("Options: " + optionsArray); 088 } 089 customClassLoader = ClassLoader.getSystemClassLoader(); 090 091 nashornFactory = new NashornScriptEngineFactory(); 092 093 if (allowAllAccess) { 094 if (customClassLoader != null && customClassLoader != ClassLoader.getSystemClassLoader()) { 095 scriptEngine = nashornFactory.getScriptEngine(options,customClassLoader); 096 } else { 097 scriptEngine = nashornFactory.getScriptEngine(options); 098 } 099 } else { 100 ClassFilter filter = new SecurityClassFilter(); 101 scriptEngine = nashornFactory.getScriptEngine(options,customClassLoader,filter); 102 103 } 104 105 if(scriptEngine == null){ 106 throw new Exception(String.format("Unable to create engine '%s'.", engineName)); 107 } 108 109 System.out.println(String.format("Engine Name: %s, Version: %s", 110 scriptEngine.getFactory().getEngineName(), 111 scriptEngine.getFactory().getEngineVersion())); 112 113 context = new SimpleScriptContext(); 114 context.setBindings(scriptEngine.createBindings(), ScriptContext.ENGINE_SCOPE); 115 bindings = context.getBindings(ScriptContext.ENGINE_SCOPE); 116 117 if (customClassLoader != null) { 118 bindings.put("ScriptClassLoader", customClassLoader); 119 } 120 121 invocable = (Invocable) scriptEngine; 122 } 123 124 @Override 125 public void setAllowAllAccess(boolean allowAllAccess){ 126 boolean changed = this.allowAllAccess != allowAllAccess; 127 this.allowAllAccess = allowAllAccess; 128 129 if (changed && scriptEngine != null) { 130 try { 131 recreateEngine(); 132 } catch (Exception e) { 133 log.error("Error resetting access permissions: {}",e.getMessage(),e); 134 } 135 } 136 } 137 138 @Override 139 public Object eval(String scriptPath) throws Exception { 140 return eval(new File(scriptPath)); 141 } 142 143 @Override 144 public Object eval(File scriptPath) throws Exception { 145 String script = null; 146 if(CommonTools.isBlank(scriptCipherAesKey)){ 147 script = FileTools.text(scriptPath); 148 }else{ 149 DiskFile df = new DiskFile(scriptPath); 150 byte[] encryptBytes = df.readAllBytes(); 151 byte[] decryptBytes = CipherTools.AESDecrypt(scriptCipherAesKey,encryptBytes); 152 script = new String(decryptBytes,BaseFile.CHARSET); 153 } 154 Object result = scriptEngine.eval(script, context); 155 scriptEngine.setContext(context); 156 invocable = (Invocable) scriptEngine; 157 return result; 158 } 159 160 @Override 161 public Object evalScript(String script) throws Exception { 162 Object result = scriptEngine.eval(script, context); 163 scriptEngine.setContext(context); 164 invocable = (Invocable) scriptEngine; 165 return result; 166 } 167 168 @Override 169 public void close(){ 170 if (bindings != null) { 171 bindings.clear(); 172 bindings = null; 173 } 174 context = null; 175 scriptEngine = null; 176 invocable = null; 177 nashornFactory = null; 178 customClassLoader = null; 179 } 180 181 @Override 182 public String getEngineName(){ 183 return engineName; 184 } 185 186 public NashornScriptEngineFactory getNashornFactory() { 187 return nashornFactory; 188 } 189 190 public ClassLoader getCustomClassLoader() { 191 return customClassLoader; 192 } 193 194 private void recreateEngine() throws Exception { 195 if (nashornFactory != null) { 196 ConfigProperties appenvCp = ScriptConsole.getAppenv(); 197 String engineNameMapKey = String.format("%s.options",engineName); 198 List<String> optionsArray = appenvCp.getArray(engineNameMapKey,new String[]{}); 199 String[] options = optionsArray.toArray(new String[]{}); 200 System.out.println("Options: " + optionsArray); 201 202 ScriptEngine oldEngine = scriptEngine; 203 Bindings oldBindings = bindings; 204 ScriptContext oldContext = context; 205 206 if (allowAllAccess) { 207 if (customClassLoader != null && customClassLoader != ClassLoader.getSystemClassLoader()) { 208 scriptEngine = nashornFactory.getScriptEngine(options,customClassLoader); 209 } else { 210 scriptEngine = nashornFactory.getScriptEngine(options); 211 } 212 } else { 213 ClassFilter filter = new SecurityClassFilter(); 214 scriptEngine = nashornFactory.getScriptEngine(options, customClassLoader,filter); 215 } 216 217 if (scriptEngine == null) { 218 throw new Exception("Unable to recreate engine."); 219 } 220 221 if (oldContext != null) { 222 context = oldContext; 223 scriptEngine.setContext(context); 224 } 225 226 if (oldBindings != null) { 227 bindings = oldBindings; 228 scriptEngine.setBindings(bindings, ScriptContext.ENGINE_SCOPE); 229 } 230 231 invocable = (Invocable) scriptEngine; 232 } 233 } 234 235}