/// <summary> /// Calls the function as the owner of the object /// </summary> /// <param name="function"></param> /// <returns></returns> public static object callAsOwner(SubProcess.Callback callback) { FunctionCallContext functionCallContext = FunctionCallContext.GetCurrentContext(); ID<IUserOrGroup, Guid>? ownerId = functionCallContext.ScopeWrapper.FileContainer.OwnerId; IUser owner; if (null != ownerId) owner = functionCallContext.ScopeWrapper.FileHandlerFactoryLocator.UserManagerHandler.GetUser(ownerId.Value); else owner = functionCallContext.WebConnection.WebServer.FileHandlerFactoryLocator.UserFactory.AnonymousUser; // When calling as the owner, a shell web connection is pushed that impersonates the owner IWebConnection shellConnection = functionCallContext.WebConnection.CreateShellConnection(owner); FunctionCaller.WebConnectionStack.Push(shellConnection); try { return callback.Call(new object[0]); } finally { FunctionCaller.WebConnectionStack.Pop(); } }
/// <summary> /// Creates a Javascript execution environment /// </summary> /// <param name="fileContainer">The object that will be accessed through Javascript</param> /// <param name="javascriptContainer">The text file that contains the javascript</param> public ExecutionEnvironment( FileHandlerFactoryLocator fileHandlerFactoryLocator, IFileContainer javascriptContainer, IFileContainer fileContainer, SubProcess subProcess, ParentScope parentScope) { _FileHandlerFactoryLocator = fileHandlerFactoryLocator; _JavascriptContainer = javascriptContainer; _JavascriptLastModified = javascriptContainer.LastModified; parentScope.WebHandlersWithThisAsParent.Enqueue(fileContainer.WebHandler); object toDiscard; ISession ownerSession = FileHandlerFactoryLocator.SessionManagerHandler.CreateSession(); try { if (null != fileContainer.Owner) ownerSession.Login(fileContainer.Owner); IWebConnection ownerWebConnection = new BlockingShellWebConnection( FileHandlerFactoryLocator.WebServer, ownerSession, fileContainer.FullPath, null, null, new CookiesFromBrowser(), CallingFrom.Web, WebMethod.GET); ScopeWrapper = new ScopeWrapper( fileHandlerFactoryLocator, subProcess, fileContainer, parentScope, ownerWebConnection, out toDiscard); } catch (Exception e) { // If the Javascript has an error in it, it must be ignored. If an error were returned, then malformed Javascript could hose the system! this._ExecutionEnvironmentErrors = e.ToString(); log.Error("Error creating scope", e); } finally { FileHandlerFactoryLocator.SessionManagerHandler.EndSession(ownerSession.SessionId); } }
/// <summary> /// Disables server-side JavaScript while calling the passed-in function /// </summary> /// <param name="function"></param> /// <param name="callingFrom"></param> /// <returns></returns> public static object bypassJavascript(SubProcess.Callback callback) { bool oldBypassJavascript = FunctionCaller.BypassJavascript; FunctionCaller.BypassJavascript = true; try { return callback.Call(new object[0]); } finally { FunctionCaller.BypassJavascript = oldBypassJavascript; } }
/// <summary> /// Creates a scope wrapper /// </summary> /// <param name="fileHandlerFactoryLocator"></param> /// <param name="webConnection"></param> /// <param name="javascript"></param> /// <param name="fileContainer"></param> /// <param name="constructScopeResults"></param> public ScopeWrapper( FileHandlerFactoryLocator fileHandlerFactoryLocator, SubProcess subProcess, IFileContainer fileContainer, ParentScope parentScope, IWebConnection constructWebConnection, out object constructScopeResults) { _FileContainer = fileContainer; _SubProcess = subProcess; _ParentScope = parentScope; _ScopeId = GetScopeID(); _FileHandlerFactoryLocator = fileHandlerFactoryLocator; constructScopeResults = ConstructScope(constructWebConnection); }
/// <summary> /// Returns all of the script IDs for the class /// </summary> /// <param name="javascriptClass">The text handler that has the class's javascript</param> /// <param name="subProcess">The process that must have the given script loaded</param> /// <returns></returns> public ScopeInfo GetScopeInfoForClass(ITextHandler javascriptClass, SubProcess subProcess) { DateTime javascriptLastModified = javascriptClass.FileContainer.LastModified; ScopeInfo toReturn = null; using (TimedLock.Lock(ScopeInfoCache)) ScopeInfoCache.TryGetValue(javascriptClass.FileContainer.FileId, out toReturn); if (null != toReturn) if (toReturn.JavascriptLastModified == javascriptLastModified) { using (TimedLock.Lock(PrecompiledScriptDataByID)) foreach (int scriptID in toReturn.ScriptsAndIDsToBuildScope) subProcess.LoadCompiled( Thread.CurrentThread.ManagedThreadId, PrecompiledScriptDataByID[scriptID], scriptID); return toReturn; } string javascript = javascriptClass.ReadAll(); string fileType = null; List<int> scriptIDsToBuildScope = new List<int>(); ISession ownerSession = FileHandlerFactoryLocator.SessionManagerHandler.CreateSession(); try { ownerSession.Login(javascriptClass.FileContainer.Owner); IWebConnection ownerWebConnection = new BlockingShellWebConnection( FileHandlerFactoryLocator.WebServer, ownerSession, javascriptClass.FileContainer.FullPath, null, null, new CookiesFromBrowser(), CallingFrom.Web, WebMethod.GET); IEnumerable<ScriptAndMD5> dependantScriptsAndMD5s = FileHandlerFactoryLocator.WebServer.WebComponentResolver.DetermineDependantScripts( GetRequiredScriptURLs(javascriptClass, out fileType), ownerWebConnection); // Load static methods that are passed into the Javascript environment as-is Dictionary<string, MethodInfo> functionsInScope = SubProcessFactory.GetFunctionsForFileType(fileType); // Load all dependant scripts foreach (ScriptAndMD5 dependantScript in dependantScriptsAndMD5s) { int scriptID = GetScriptID( dependantScript.ScriptName + "___" + ownerSession.User.Identity, dependantScript.MD5, dependantScript.Script, subProcess); scriptIDsToBuildScope.Add(scriptID); } // Construct Javascript to shell to the "base" webHandler Set<Type> webHandlerTypes = new Set<Type>(FileHandlerFactoryLocator.WebHandlerPlugins); if (null != fileType) webHandlerTypes.Add(FileHandlerFactoryLocator.WebHandlerClasses[fileType]); string baseWrapper = GetJavascriptWrapperForBase("base", webHandlerTypes); scriptIDsToBuildScope.Add( GetScriptID( javascriptClass.FileContainer.FullPath + "___" + "serversideBaseWrapper", StringParser.GenerateMD5String(baseWrapper), baseWrapper, subProcess)); // Get the ID for the actual javascript scriptIDsToBuildScope.Add( GetScriptID( javascriptClass.FileContainer.FullPath, StringParser.GenerateMD5String(javascript), javascript, subProcess)); // Add a little shunt to return information about the options scriptIDsToBuildScope.Add( GetScriptID( "____scopeshunt", "xxx", "\nif (this.options) options; else null;", subProcess)); toReturn = new ScopeInfo( javascriptLastModified, functionsInScope, scriptIDsToBuildScope); using (TimedLock.Lock(ScopeInfoCache)) ScopeInfoCache[javascriptClass.FileContainer.FileId] = toReturn; return toReturn; } finally { FileHandlerFactoryLocator.SessionManagerHandler.EndSession(ownerSession.SessionId); } }
public ParentScopeFactory(FileHandlerFactoryLocator fileHandlerFactoryLocator, SubProcess subProcess) { FileHandlerFactoryLocator = fileHandlerFactoryLocator; _SubProcess = subProcess; }
/// <summary> /// Returns the corresponding sub process for the given class. Creates it if it isn't running, restarts if the class was modified /// </summary> /// <param name="javascriptContainer"></param> /// <returns></returns> public SubProcess GetOrCreateSubProcess(IFileContainer javascriptContainer) { SubProcess toReturn = null; using (TimedLock.Lock(javascriptContainer)) { using (TimedLock.Lock(SubProcessesByClass)) { if (SubProcessesByClass.TryGetValue(javascriptContainer.FullPath, out toReturn)) { DateTime classLastModified; if (ClassLastModified.TryGetValue(javascriptContainer.FullPath, out classLastModified)) if (javascriptContainer.LastModified == classLastModified) if (toReturn.Alive) return toReturn; } if (null != toReturn) toReturn.Dispose(); ClassLastModified[javascriptContainer.FullPath] = javascriptContainer.LastModified; } toReturn = new SubProcess(javascriptContainer, FileHandlerFactoryLocator); using (TimedLock.Lock(SubProcessesByClass)) SubProcessesByClass[javascriptContainer.FullPath] = toReturn; return toReturn; } }
/// <summary> /// Calls the given function in an de-elevated cecurity context /// </summary> /// <param name="function"></param> /// <returns></returns> public static object deElevate(SubProcess.Callback callback) { return SetTempCallingFrom(callback, CallingFrom.Web); }
/// <summary> /// Calls a function within the context of a CallingFrom /// </summary> /// <param name="function"></param> /// <param name="callingFrom"></param> /// <returns></returns> private static object SetTempCallingFrom(SubProcess.Callback callback, CallingFrom callingFrom) { CallingFrom priorCallingFrom = FunctionCaller.CallingFrom; FunctionCaller.CallingFrom = callingFrom; try { return callback.Call(new object[0]); } finally { FunctionCaller.CallingFrom = priorCallingFrom; } }
/// <summary> /// Ugly hack that hacks around permission issues by changing the current user to root /// </summary> /// <param name="function"></param> /// <returns></returns> public static object sudo(SubProcess.Callback callback) { FunctionCallContext functionCallContext = FunctionCallContext.GetCurrentContext(); // When calling as the owner, a shell web connection is pushed that impersonates the owner IWebConnection shellConnection = functionCallContext.WebConnection.CreateShellConnection( functionCallContext.WebConnection.WebServer.FileHandlerFactoryLocator.UserFactory.RootUser); FunctionCaller.WebConnectionStack.Push(shellConnection); try { return callback.Call(new object[0]); } finally { FunctionCaller.WebConnectionStack.Pop(); } }
/// <summary> /// Locks the owning object so that the passed in function has exclusive access to it /// </summary> /// <param name="function"></param> /// <returns></returns> public static object lockMe(SubProcess.Callback callback) { FunctionCallContext functionCallContext = FunctionCallContext.GetCurrentContext(); using (TimedLock.Lock(functionCallContext.ScopeWrapper.FileContainer.FileHandler)) { return callback.Call(new object[0]); } }
/// <summary> /// Calls the given function in an elevated cecurity context /// </summary> /// <param name="function"></param> /// <returns></returns> public static object elevate(SubProcess.Callback callback) { return SetTempCallingFrom(callback, CallingFrom.Local); }
public Callback(SubProcess subProcess, int scopeId, object threadId, object callbackId) { _SubProcess = subProcess; _ScopeId = scopeId; _ThreadId = threadId; _CallbackId = callbackId; }