diff --git a/Sources/pyOpenRPA/Orchestrator/Server.py b/Sources/pyOpenRPA/Orchestrator/Server.py index 1e616148..00caa157 100755 --- a/Sources/pyOpenRPA/Orchestrator/Server.py +++ b/Sources/pyOpenRPA/Orchestrator/Server.py @@ -7,6 +7,7 @@ # self.OpenRPAResponseDict = lResponseDict #from http.client import HTTPException +from email import header from http.server import BaseHTTPRequestHandler, HTTPServer from socketserver import ThreadingMixIn import threading @@ -48,6 +49,10 @@ from pydantic import BaseModel import uvicorn +import io +from starlette.responses import StreamingResponse + + gCacheDict = {} @@ -111,8 +116,10 @@ def UserAccessCheckBefore(inMethod, inRequest): lAuthToken = inRequest.OpenRPA["AuthToken"] #go next if user is identified lUserDict = None + print(f"lAuthToken: {lAuthToken}") if lAuthToken: lUserDict = gSettingsDict["ServerDict"]["AccessUsers"]["AuthTokensDict"][lAuthToken] + print(f"lUserDict: {lUserDict}") #pdb.set_trace() ######################################## ######################################## @@ -189,6 +196,7 @@ class HTTPRequestOld(): mRequest:Request = None mResponse:Response = None OpenRPA: dict = {} + headers={} def __init__(self,inRequest,inResponse,inAuthDict): self.mRequest = inRequest @@ -200,6 +208,7 @@ class HTTPRequestOld(): self.OpenRPA["Domain"] = None self.OpenRPA["User"] = None else: self.OpenRPA = inAuthDict + self.headers=inRequest.headers # Def to check User Role access grants def UACClientCheck(self, inRoleKeyList): # Alias @@ -387,17 +396,21 @@ class HTTPRequestOld(): def do_GET(self, inBodyStr): try: gSettingsDict = __Orchestrator__.GSettingsGet() - self.OpenRPA["DefUserRoleAccessAsk"]=self.UserRoleAccessAsk # Alias for def - self.OpenRPA["DefUserRoleHierarchyGet"]=self.UserRoleHierarchyGet # Alias for def + try: + self.OpenRPA["DefUserRoleAccessAsk"]=self.UserRoleAccessAsk # Alias for def + self.OpenRPA["DefUserRoleHierarchyGet"]=self.UserRoleHierarchyGet # Alias for def + except Exception as e: + pass # Prepare result dict - lResponseDict = {"Headers": {}, "SetCookies": {}, "Body": b"", "StatusCode": None} + lResponseDict = {"Headers": {}, "SetCookies": {}, "Body": b"", "StatusCode": None, "BodyIsText":True} self.OpenRPAResponseDict = lResponseDict #Check the user access (if flag, UAC) #################################### lFlagUserAccess = True #If need user authentication if gSettingsDict.get("ServerDict", {}).get("AccessUsers", {}).get("FlagCredentialsAsk", False): - lFlagUserAccess = UserAccessCheckBefore("GET", self) + if self.OpenRPA["AuthToken"] != None: + lFlagUserAccess = UserAccessCheckBefore("GET", self) ###################################### if lFlagUserAccess: if CrossOS.IS_WINDOWS_BOOL: lOrchestratorFolder = "\\".join(__file__.split("\\")[:-1]) @@ -431,18 +444,22 @@ class HTTPRequestOld(): try: gSettingsDict = __Orchestrator__.GSettingsGet() lL = gSettingsDict["Logger"] - self.OpenRPA["DefUserRoleAccessAsk"]=self.UserRoleAccessAsk # Alias for def - self.OpenRPA["DefUserRoleHierarchyGet"]=self.UserRoleHierarchyGet # Alias for def + try: + self.OpenRPA["DefUserRoleAccessAsk"]=self.UserRoleAccessAsk # Alias for def + self.OpenRPA["DefUserRoleHierarchyGet"]=self.UserRoleHierarchyGet # Alias for def + except Exception as e: + pass # Prepare result dict #pdb.set_trace() - lResponseDict = {"Headers": {}, "SetCookies":{}, "Body": b"", "StatusCode": None} + lResponseDict = {"Headers": {}, "SetCookies": {}, "Body": b"", "StatusCode": None, "BodyIsText":True} self.OpenRPAResponseDict = lResponseDict #Check the user access (if flag) #################################### lFlagUserAccess = True #If need user authentication if gSettingsDict.get("ServerDict", {}).get("AccessUsers", {}).get("FlagCredentialsAsk", False): - lFlagUserAccess = UserAccessCheckBefore("POST", self) + if self.OpenRPA["AuthToken"] != None: + lFlagUserAccess = UserAccessCheckBefore("POST", self) ###################################### if lFlagUserAccess: lOrchestratorFolder = "\\".join(__file__.split("\\")[:-1]) @@ -496,6 +513,7 @@ def IdentifyAuthorize(inRequest:Request, inResponse:Response, inCookiesStr: Union[str, None] = Header(default=None,alias="Cookie"), inAuthorizationStr: Union[str, None] = Header(default="",alias="Authorization")): lResult={"Domain": "", "User": ""} + print("IdentifyAuthorize") ###################################### #Way 1 - try to find AuthToken lCookies = cookies.SimpleCookie(inCookiesStr) # inRequest.headers.get("Cookie", "") @@ -511,14 +529,14 @@ def IdentifyAuthorize(inRequest:Request, inResponse:Response, lResult["User"] = gSettingsDict["ServerDict"]["AccessUsers"]["AuthTokensDict"][lCookieAuthToken]["User"] #Set auth token mOpenRPA={} - mOpenRPA["AuthToken"] = lAuthToken + mOpenRPA["AuthToken"] = lCookieAuthToken mOpenRPA["Domain"] = lResult["Domain"] mOpenRPA["User"] = lResult["User"] mOpenRPA["IsSuperToken"] = gSettingsDict.get("ServerDict", {}).get("AccessUsers", {}).get("AuthTokensDict", {}).get(mOpenRPA["AuthToken"], {}).get("FlagDoNotExpire", False) return mOpenRPA ###################################### #Way 2 - try to logon - elif len(lHeaderAuthorization) == 2: + if len(lHeaderAuthorization) == 2: llHeaderAuthorizationDecodedUserPasswordList = base64.b64decode(lHeaderAuthorization[1]).decode("utf-8").split( ":") lUser = llHeaderAuthorizationDecodedUserPasswordList[0] @@ -555,46 +573,63 @@ def IdentifyAuthorize(inRequest:Request, inResponse:Response, ###################################### else: raise HTTPException(status_code=401, detail="here is the details", headers={'Content-type':'text/html', 'WWW-Authenticate':'Basic'}) - return True - -def BackwardCompatibityWrapperAuth(inRequest:Request, inResponse:Response, inBodyStr:str = Body(...), - inAuthDict:bool=Depends(IdentifyAuthorize)): # Old from v1.3.1 (updated to FastAPI) +def BackwardCompatibityWrapperAuth(inRequest:Request, inResponse:Response, inBodyStr:str = Body(""), + inAuthDict:dict=Depends(IdentifyAuthorize)): # Old from v1.3.1 (updated to FastAPI) + print(f"{inRequest.url.path}, inAuthDict:{inAuthDict}") lHTTPRequest = HTTPRequestOld(inRequest=inRequest, inResponse=inResponse, inAuthDict=inAuthDict) + lHTTPRequest.path = inRequest.url.path + lHTTPRequest.body = inBodyStr threading.current_thread().request = lHTTPRequest lResult = lHTTPRequest.do_GET(inBodyStr=inBodyStr) if lResult is None: lResult = lHTTPRequest.do_POST(inBodyStr=inBodyStr) - return lResult + #if lHTTPRequest.OpenRPAResponseDict['BodyIsText']==True: return lResult.decode("utf8") + #else: return StreamingResponse(io.BytesIO(lResult), media_type="image/png") + if lHTTPRequest.OpenRPAResponseDict["Headers"]["Content-type"] != None: + return StreamingResponse(io.BytesIO(lResult), media_type=lHTTPRequest.OpenRPAResponseDict["Headers"]["Content-type"]) -def BackwardCompatibityWrapperNoAuth(inRequest:Request, inResponse:Response, inBodyStr:str = Body(...)): # Old from v1.3.1 (updated to FastAPI) +def BackwardCompatibityWrapperNoAuth(inRequest:Request, inResponse:Response, inBodyStr:str = Body("")): # Old from v1.3.1 (updated to FastAPI) + print(f"{inRequest.url.path}, BackwardCompatibityWrapperNoAuth") lHTTPRequest = HTTPRequestOld(inRequest=inRequest, inResponse=inResponse, inAuthDict=None) + lHTTPRequest.path = inRequest.url.path + lHTTPRequest.body = inBodyStr threading.current_thread().request = lHTTPRequest lResult = lHTTPRequest.do_GET(inBodyStr=inBodyStr) + #print(f"RESULT VALUE: {lResult}") if lResult is None: lResult = lHTTPRequest.do_POST(inBodyStr=inBodyStr) - return lResult.decode("utf8") + #if lHTTPRequest.OpenRPAResponseDict['BodyIsText']==True: return lResult.decode("utf8") + #else: return StreamingResponse(io.BytesIO(lResult), media_type="image/png") + if lHTTPRequest.OpenRPAResponseDict["Headers"]["Content-type"] != None: + return StreamingResponse(io.BytesIO(lResult), media_type=lHTTPRequest.OpenRPAResponseDict["Headers"]["Content-type"]) def InitFastAPI(): global gSettingsDict global app + ServerSettings.SettingsUpdate(gSettingsDict) lL = gSettingsDict.get("Logger",None) gSettingsDict["ServerDict"]["ServerThread"] = app for lConnectItemDict in gSettingsDict["ServerDict"]["URLList"]: - if lConnectItemDict.get("UACBool",True): - app.add_api_route( - path=lConnectItemDict["URL"], - endpoint=BackwardCompatibityWrapperAuth, - response_class=PlainTextResponse, - methods=[lConnectItemDict["Method"]] - ) + if "ResponseFolderPath" in lConnectItemDict: + app.mount(lConnectItemDict["URL"], + StaticFiles(directory=CrossOS.PathStr(lConnectItemDict["ResponseFolderPath"])), + name=lConnectItemDict["URL"].replace('/',"_")) else: - app.add_api_route( - path=lConnectItemDict["URL"], - endpoint=BackwardCompatibityWrapperNoAuth, - response_class=PlainTextResponse, - methods=[lConnectItemDict["Method"]] - ) + if lConnectItemDict.get("UACBool",True): + app.add_api_route( + path=lConnectItemDict["URL"], + endpoint=BackwardCompatibityWrapperAuth, + response_class=PlainTextResponse, + methods=[lConnectItemDict["Method"]] + ) + else: + app.add_api_route( + path=lConnectItemDict["URL"], + endpoint=BackwardCompatibityWrapperNoAuth, + response_class=PlainTextResponse, + methods=[lConnectItemDict["Method"]] + ) uvicorn.run('pyOpenRPA.Orchestrator.Server:app', host='0.0.0.0', port=1024) diff --git a/Sources/pyOpenRPA/Orchestrator/ServerSettings.py b/Sources/pyOpenRPA/Orchestrator/ServerSettings.py index cf22e826..97f216b6 100755 --- a/Sources/pyOpenRPA/Orchestrator/ServerSettings.py +++ b/Sources/pyOpenRPA/Orchestrator/ServerSettings.py @@ -118,14 +118,8 @@ def HiddenAgentDictGenerate(inRequest, inGSettings): # Client: mGlobal.pyOpenRPA.ServerDataHashStr # Client: mGlobal.pyOpenRPA.ServerDataDict def pyOpenRPA_ServerData(inRequest,inGSettings): - # Extract the hash value from request - lValueStr = None - if inRequest.headers.get('Content-Length') is not None: - lInputByteArrayLength = int(inRequest.headers.get('Content-Length')) - lInputByteArray = inRequest.rfile.read(lInputByteArrayLength) - # Превращение массива байт в объект - lValueStr = (lInputByteArray.decode('utf8')) + lValueStr = inRequest.body # Generate ServerDataDict lFlagDoGenerateBool = True while lFlagDoGenerateBool: @@ -168,12 +162,7 @@ def pyOpenRPA_ServerJSInit(inRequest,inGSettings): # Client: mGlobal.pyOpenRPA.ServerLogList def pyOpenRPA_ServerLog(inRequest,inGSDict): # Extract the hash value from request - lValueStr = None - if inRequest.headers.get('Content-Length') is not None: - lInputByteArrayLength = int(inRequest.headers.get('Content-Length')) - lInputByteArray = inRequest.rfile.read(lInputByteArrayLength) - # Превращение массива байт в объект - lValueStr = (lInputByteArray.decode('utf8')) + lValueStr = inRequest.body # Generate ServerDataDict lFlagDoGenerateBool = True while lFlagDoGenerateBool: @@ -193,6 +182,7 @@ def pyOpenRPA_ServerLog(inRequest,inGSDict): inResponseDict["Body"] = bytes(message, "utf8") return lResult + def pyOpenRPA_Screenshot(inRequest,inGlobalDict): # Get Screenshot def SaveScreenshot(inFilePath): @@ -209,6 +199,7 @@ def pyOpenRPA_Screenshot(inRequest,inGlobalDict): lFileObject = open("Screenshot.png", "rb") # Write content as utf-8 data inRequest.OpenRPAResponseDict["Body"] = lFileObject.read() + inRequest.OpenRPAResponseDict['BodyIsText']=False # Закрыть файловый объект lFileObject.close() else: @@ -216,6 +207,7 @@ def pyOpenRPA_Screenshot(inRequest,inGlobalDict): lFileObject = open("Screenshot.png", "rb") # Write content as utf-8 data inRequest.OpenRPAResponseDict["Body"] = lFileObject.read() + inRequest.OpenRPAResponseDict['BodyIsText']=False # Закрыть файловый объект lFileObject.close() @@ -224,12 +216,9 @@ def pyOpenRPA_Screenshot(inRequest,inGlobalDict): def pyOpenRPA_Processor(inRequest, inGSettings): lL = inGSettings["Logger"] # Recieve the data - lValueStr = None - if inRequest.headers.get('Content-Length') is not None: - lInputByteArrayLength = int(inRequest.headers.get('Content-Length')) - lInputByteArray = inRequest.rfile.read(lInputByteArrayLength) - # Превращение массива байт в объект - lInput = json.loads(lInputByteArray.decode('utf8')) + lValueStr = inRequest.body + # Превращение массива байт в объект + lInput = json.loads(lValueStr) # If list - operator plus if type(lInput) is list: # Logging info about processor activity if not SuperToken () @@ -279,12 +268,9 @@ def pyOpenRPA_Processor(inRequest, inGSettings): def pyOpenRPA_ActivityListExecute(inRequest, inGSettings): # Recieve the data lL = inGSettings["Logger"] - lValueStr = None - if inRequest.headers.get('Content-Length') is not None: - lInputByteArrayLength = int(inRequest.headers.get('Content-Length')) - lInputByteArray = inRequest.rfile.read(lInputByteArrayLength) - # Превращение массива байт в объект - lInput = json.loads(lInputByteArray.decode('utf8')) + lValueStr = inRequest.body + # Превращение массива байт в объект + lInput = json.loads(lValueStr) # If list - operator plus if type(lInput) is list: # Logging info about processor activity if not SuperToken () @@ -324,12 +310,9 @@ def pyOpenRPA_Agent_O2A(inRequest, inGSettings): lAgentLoopSleepSecFloat = inGSettings["ServerDict"]["AgentLoopSleepSecFloat"] lTimeStartFloat = time.time() # Recieve the data - lValueStr = None - if inRequest.headers.get('Content-Length') is not None: - lInputByteArrayLength = int(inRequest.headers.get('Content-Length')) - lInputByteArray = inRequest.rfile.read(lInputByteArrayLength) - # Превращение массива байт в объект - lInput = json.loads(lInputByteArray.decode('utf8')) + lValueStr = inRequest.body + # Превращение массива байт в объект + lInput = json.loads(lInputByteArray.decode('utf8')) # Check if item is created lAgentDictItemKeyTurple = (lInput["HostNameUpperStr"],lInput["UserUpperStr"]) if lAgentDictItemKeyTurple not in inGSettings["AgentDict"]: @@ -423,13 +406,10 @@ def pyOpenRPA_Debugging_HelperDefAutofill(inRequest, inGSettings): def pyOpenRPA_Agent_A2O(inRequest, inGSettings): lL = inGSettings["Logger"] # Recieve the data - lValueStr = None - if inRequest.headers.get('Content-Length') is not None: - lInputByteArrayLength = int(inRequest.headers.get('Content-Length')) - lInputByteArray = inRequest.rfile.read(lInputByteArrayLength) - # Превращение массива байт в объект - lInput = json.loads(lInputByteArray.decode('utf8')) - lAgentDictItemKeyTurple = (lInput["HostNameUpperStr"], lInput["UserUpperStr"]) + lValueStr = inRequest.body + # Превращение массива байт в объект + lInput = json.loads(lValueStr) + lAgentDictItemKeyTurple = (lInput["HostNameUpperStr"], lInput["UserUpperStr"]) if "LogList" in lInput: for lLogItemStr in lInput["LogList"]: inGSettings["Logger"].info(lLogItemStr) diff --git a/Sources/pyOpenRPA/Orchestrator/__Orchestrator__.py b/Sources/pyOpenRPA/Orchestrator/__Orchestrator__.py index e0abbd15..ca66735f 100755 --- a/Sources/pyOpenRPA/Orchestrator/__Orchestrator__.py +++ b/Sources/pyOpenRPA/Orchestrator/__Orchestrator__.py @@ -2754,14 +2754,6 @@ def Orchestrator(inGSettings=None, inDumpRestoreBool = True, inRunAsAdministrato #Инициализация настроечных параметров gSettingsDict["ServerDict"]["WorkingDirectoryPathStr"] = os.getcwd() # Set working directory in g settings - #Инициализация сервера (инициализация всех интерфейсов) - lListenDict = gSettingsDict.get("ServerDict",{}).get("ListenDict",{}) - for lItemKeyStr in lListenDict: - lItemDict = lListenDict[lItemKeyStr] - Server.InitFastAPI() - - - # Init the RobotScreenActive in another thread lRobotScreenActiveThread = threading.Thread(target= Monitor.CheckScreen) lRobotScreenActiveThread.daemon = True # Run the thread in daemon mode. @@ -2820,9 +2812,17 @@ def Orchestrator(inGSettings=None, inDumpRestoreBool = True, inRunAsAdministrato lThread = threading.Thread(target= lProcess.StatusRestore) lThread.start() + + # Init debug thread (run if "init_dubug" file exists) Debugger.LiveDebugCheckThread(inGSettings=GSettingsGet()) + #Инициализация сервера (инициализация всех интерфейсов) + lListenDict = gSettingsDict.get("ServerDict",{}).get("ListenDict",{}) + for lItemKeyStr in lListenDict: + lItemDict = lListenDict[lItemKeyStr] + Server.InitFastAPI() + def __schedule_loop__(): while True: schedule.run_pending()