View Javadoc

1   package delight.rhinosandox.internal;
2   
3   import com.google.common.base.Objects;
4   import delight.rhinosandox.RhinoSandbox;
5   import delight.rhinosandox.internal.RhinoEval;
6   import delight.rhinosandox.internal.RhinoEvalDummy;
7   import delight.rhinosandox.internal.SafeClassShutter;
8   import delight.rhinosandox.internal.SafeContext;
9   import delight.rhinosandox.internal.SafeWrapFactory;
10  import java.lang.reflect.Method;
11  import java.util.HashMap;
12  import java.util.Map;
13  import java.util.Set;
14  import org.eclipse.xtext.xbase.lib.Exceptions;
15  import org.mozilla.javascript.Context;
16  import org.mozilla.javascript.ContextFactory;
17  import org.mozilla.javascript.Scriptable;
18  import org.mozilla.javascript.ScriptableObject;
19  
20  @SuppressWarnings("all")
21  public class RhinoSandboxImpl implements RhinoSandbox {
22    private SafeContext contextFactory;
23    
24    private ScriptableObject globalScope;
25    
26    private ScriptableObject safeScope;
27    
28    private int instructionLimit;
29    
30    private long maxDuration;
31    
32    private boolean useSafeStandardObjects;
33    
34    private boolean sealScope;
35    
36    private final Map<String, Object> inScope;
37    
38    private SafeClassShutter classShutter;
39    
40    /**
41     * see https://developer.mozilla.org/en-US/docs/Mozilla/Projects/Rhino/Scopes_and_Contexts
42     */
43    public void assertContextFactory() {
44      try {
45        boolean _notEquals = (!Objects.equal(this.contextFactory, null));
46        if (_notEquals) {
47          return;
48        }
49        SafeContext _safeContext = new SafeContext();
50        this.contextFactory = _safeContext;
51        boolean _hasExplicitGlobal = ContextFactory.hasExplicitGlobal();
52        boolean _not = (!_hasExplicitGlobal);
53        if (_not) {
54          ContextFactory.initGlobal(this.contextFactory);
55        }
56        this.contextFactory.maxInstructions = this.instructionLimit;
57        this.contextFactory.maxRuntimeInMs = this.maxDuration;
58        try {
59          final Context context = this.contextFactory.enterContext();
60          ScriptableObject _initStandardObjects = context.initStandardObjects(null, false);
61          this.globalScope = _initStandardObjects;
62          Set<Map.Entry<String, Object>> _entrySet = this.inScope.entrySet();
63          for (final Map.Entry<String, Object> entry : _entrySet) {
64            String _key = entry.getKey();
65            Object _value = entry.getValue();
66            Scriptable _object = Context.toObject(_value, this.globalScope);
67            this.globalScope.put(_key, this.globalScope, _object);
68          }
69          final Class[] parameters = { String.class };
70          final Method dealMethod = RhinoEvalDummy.class.getMethod("eval", parameters);
71          RhinoEval _rhinoEval = new RhinoEval("eval", dealMethod, this.globalScope);
72          this.globalScope.defineProperty("eval", _rhinoEval, ScriptableObject.DONTENUM);
73        } finally {
74          Context.exit();
75        }
76      } catch (Throwable _e) {
77        throw Exceptions.sneakyThrow(_e);
78      }
79    }
80    
81    public void assertSafeScope(final Context context) {
82      boolean _notEquals = (!Objects.equal(this.safeScope, null));
83      if (_notEquals) {
84        return;
85      }
86      if (this.useSafeStandardObjects) {
87        ScriptableObject _initSafeStandardObjects = context.initSafeStandardObjects(this.globalScope, true);
88        this.safeScope = _initSafeStandardObjects;
89        return;
90      }
91      context.setClassShutter(this.classShutter);
92      SafeWrapFactory _safeWrapFactory = new SafeWrapFactory();
93      context.setWrapFactory(_safeWrapFactory);
94      this.safeScope = this.globalScope;
95    }
96    
97    @Override
98    public Object evalWithGlobalScope(final String sourceName, final String js) {
99      this.assertContextFactory();
100     try {
101       final Context context = this.contextFactory.enterContext();
102       return context.evaluateString(this.globalScope, js, sourceName, 1, null);
103     } finally {
104       Context.exit();
105     }
106   }
107   
108   @Override
109   public Object eval(final String sourceName, final String js, final Map<String, Object> variables) {
110     this.assertContextFactory();
111     try {
112       final Context context = this.contextFactory.enterContext();
113       this.assertSafeScope(context);
114       if (this.sealScope) {
115         this.globalScope.sealObject();
116       }
117       final Scriptable instanceScope = context.newObject(this.safeScope);
118       instanceScope.setPrototype(this.safeScope);
119       instanceScope.setParentScope(null);
120       Set<Map.Entry<String, Object>> _entrySet = variables.entrySet();
121       for (final Map.Entry<String, Object> entry : _entrySet) {
122         {
123           Object _value = entry.getValue();
124           Class<?> _class = _value.getClass();
125           this.allow(_class);
126           String _key = entry.getKey();
127           Object _value_1 = entry.getValue();
128           Scriptable _object = Context.toObject(_value_1, instanceScope);
129           instanceScope.put(_key, instanceScope, _object);
130         }
131       }
132       return context.evaluateString(instanceScope, js, sourceName, 1, null);
133     } finally {
134       Context.exit();
135     }
136   }
137   
138   @Override
139   public Object eval(final String sourceName, final String js) {
140     HashMap<String, Object> _hashMap = new HashMap<String, Object>();
141     return this.eval(sourceName, js, _hashMap);
142   }
143   
144   @Override
145   public RhinoSandbox setInstructionLimit(final int limit) {
146     RhinoSandboxImpl _xblockexpression = null;
147     {
148       this.instructionLimit = limit;
149       boolean _notEquals = (!Objects.equal(this.contextFactory, null));
150       if (_notEquals) {
151         this.contextFactory.maxInstructions = this.instructionLimit;
152       }
153       _xblockexpression = this;
154     }
155     return _xblockexpression;
156   }
157   
158   /**
159    * Sets the maximum allowed duration for scripts.
160    */
161   @Override
162   public RhinoSandbox setMaxDuration(final int limitInMs) {
163     RhinoSandboxImpl _xblockexpression = null;
164     {
165       this.maxDuration = limitInMs;
166       boolean _notEquals = (!Objects.equal(this.contextFactory, null));
167       if (_notEquals) {
168         this.contextFactory.maxRuntimeInMs = this.maxDuration;
169       }
170       _xblockexpression = this;
171     }
172     return _xblockexpression;
173   }
174   
175   @Override
176   public RhinoSandbox setUseSafeStandardObjects(final boolean useSafeStandardObjects) {
177     RhinoSandboxImpl _xblockexpression = null;
178     {
179       this.useSafeStandardObjects = useSafeStandardObjects;
180       _xblockexpression = this;
181     }
182     return _xblockexpression;
183   }
184   
185   @Override
186   public RhinoSandbox allow(final Class<?> clazz) {
187     RhinoSandboxImpl _xblockexpression = null;
188     {
189       String _name = clazz.getName();
190       this.classShutter.allowedClasses.add(_name);
191       _xblockexpression = this;
192     }
193     return _xblockexpression;
194   }
195   
196   @Override
197   public RhinoSandbox inject(final Class<ScriptableObject> clazz) {
198     try {
199       RhinoSandboxImpl _xblockexpression = null;
200       {
201         ScriptableObject.<ScriptableObject>defineClass(this.globalScope, clazz);
202         this.allow(clazz);
203         _xblockexpression = this;
204       }
205       return _xblockexpression;
206     } catch (Throwable _e) {
207       throw Exceptions.sneakyThrow(_e);
208     }
209   }
210   
211   @Override
212   public RhinoSandbox inject(final String variableName, final Object object) {
213     RhinoSandboxImpl _xblockexpression = null;
214     {
215       this.injectInt(variableName, object);
216       Class<?> _class = object.getClass();
217       this.allow(_class);
218       _xblockexpression = this;
219     }
220     return _xblockexpression;
221   }
222   
223   private void injectInt(final String variableName, final Object object) {
224     boolean _containsKey = this.inScope.containsKey(variableName);
225     if (_containsKey) {
226       throw new IllegalArgumentException(
227         (("A variable with the name [" + variableName) + "] has already been defined."));
228     }
229     boolean _equals = Objects.equal(this.contextFactory, null);
230     if (_equals) {
231       this.inScope.put(variableName, object);
232     } else {
233       try {
234         this.contextFactory.enterContext();
235         Scriptable _object = Context.toObject(object, this.globalScope);
236         this.globalScope.put(variableName, this.globalScope, _object);
237       } finally {
238         Context.exit();
239       }
240     }
241   }
242   
243   public RhinoSandboxImpl() {
244     HashMap<String, Object> _hashMap = new HashMap<String, Object>();
245     this.inScope = _hashMap;
246     this.useSafeStandardObjects = false;
247     this.sealScope = true;
248     SafeClassShutter _safeClassShutter = new SafeClassShutter();
249     this.classShutter = _safeClassShutter;
250   }
251   
252   @Override
253   public RhinoSandbox setUseSealedScope(final boolean value) {
254     this.sealScope = value;
255     return this;
256   }
257 }