def getHeaders(client, clientMethodConfig, headers): return { **ConverterStatic.getValueOrDefault(client.headers, dict()), **{HttpDomain.HeaderKey.CONTENT_TYPE: clientMethodConfig.consumes}, **ConverterStatic.getValueOrDefault(clientMethodConfig.headers, dict()), **ConverterStatic.getValueOrDefault(headers, dict()) }
def patchAccessToken(newContextList=None, headers=None, data=None, rawJwt=None, apiInstance=None): headers = headers if ObjectHelper.isNone(rawJwt) else { **getJwtHeaders(), **ConverterStatic.getValueOrDefault(headers, dict()) } rawJwt = getJwtBody(rawJwt=rawJwt, apiInstance=apiInstance) deltaMinutes = UtcDateTimeUtil.ofTimestamp( getExpiration(rawJwt=rawJwt)) - UtcDateTimeUtil.now() userClaims = { JwtConstant.KW_CONTEXT: list( set([ *safellyGetContext(getContext(rawJwt=rawJwt)), *safellyGetContext(newContextList) ])), JwtConstant.KW_DATA: { **safellyGetData(getData(rawJwt=rawJwt)), **safellyGetData(data) } } addAccessTokenToBlackList(rawJwt=rawJwt, apiInstance=apiInstance) return create_access_token(identity=getIdentity(rawJwt=rawJwt), user_claims=userClaims, fresh=False, expires_delta=deltaMinutes, headers=ConverterStatic.getValueOrDefault( headers, dict()))
def getJwtMannager(appInstance, jwtSecret, algorithm=None, headerName=None, headerType=None): if not jwtSecret: log.warning( getJwtMannager, f'Not possible to instanciate sessionManager{c.DOT_SPACE_CAUSE}Missing jwt secret at {ConfigurationKeyConstant.API_SESSION_SECRET}' ) else: jwtManager = JwtManager( jwtSecret, ConverterStatic.getValueOrDefault( algorithm, JwtConstant.DEFAULT_JWT_SESSION_ALGORITHM), ConverterStatic.getValueOrDefault( headerName, JwtConstant.DEFAULT_JWT_SESSION_HEADER_NAME), ConverterStatic.getValueOrDefault( headerType, JwtConstant.DEFAULT_JWT_SESSION_HEADER_TYPE)) if SettingHelper.activeEnvironmentIsLocal(): info = { 'secret': jwtManager.secret, 'algorithm': jwtManager.algorithm, 'headerName': jwtManager.headerName, 'headerType': jwtManager.headerType } log.prettyJson(getJwtMannager, f'JWT session', info, logLevel=log.SETTING) return jwtManager
def parseParameters(client, clientMethodConfig, additionalUrl, params, headers, body, timeout, logRequest): url = getUrl(client, clientMethodConfig, additionalUrl) params = ConverterStatic.getValueOrDefault(params, dict()) headers = getHeaders(client, clientMethodConfig, headers) body = ConverterStatic.getValueOrDefault(body, dict()) timeout = getTimeout(client, clientMethodConfig, timeout) logRequest = getLogRequest(client, clientMethodConfig, logRequest) return url, params, headers, body, timeout, logRequest
def doLogRequest(verb, url, body, params, headers, logRequest): log.info(resourceInstanceMethod, f'[CLIENT ] {verb} - {url}') if logRequest: log.prettyJson( resourceInstanceMethod, '[CLIENT ] Request', { 'headers': ConverterStatic.getValueOrDefault(headers, dict()), 'query': ConverterStatic.getValueOrDefault(params, dict()), 'body': ConverterStatic.getValueOrDefault(body, dict()) }, condition = True, logLevel = log.INFO )
def refreshAccessToken(identity, contextList, deltaMinutes=0, headers=None, data=None, apiInstance=None): timeNow = UtcDateTimeUtil.now() return retrieveApiInstance(apiInstance=apiInstance).sessionManager.encode( { JwtConstant.KW_IAT: timeNow, JwtConstant.KW_NFB: timeNow, JwtConstant.KW_JTI: getNewJti(), JwtConstant.KW_EXPIRATION: UtcDateTimeUtil.plusMinutes(timeNow, minutes=deltaMinutes), JwtConstant.KW_IDENTITY: identity, JwtConstant.KW_FRESH: False, JwtConstant.KW_TYPE: JwtConstant.REFRESH_VALUE_TYPE, JwtConstant.KW_CLAIMS: { JwtConstant.KW_CONTEXT: safellyGetContext(contextList), JwtConstant.KW_DATA: safellyGetData(data) } }, headers=ConverterStatic.getValueOrDefault(headers, dict()))
def Client(url=c.BLANK, headers=None, timeout=HttpClientConstant.DEFAULT_TIMEOUT, logRequest=False, logResponse=False): clientUrl = url clientHeaders = ConverterStatic.getValueOrDefault(headers, dict()) clientTimeout = timeout clientLogRequest = logRequest clientLogResponse = logResponse def Wrapper(OuterClass, *args, **kwargs): log.wrapper(Client, f'''wrapping {OuterClass.__name__}''') class InnerClass(OuterClass): url = clientUrl headers = clientHeaders timeout = clientTimeout logRequest = clientLogRequest logResponse = clientLogResponse def __init__(self, *args, **kwargs): log.wrapper( OuterClass, f'in {InnerClass.__name__}.__init__(*{args},**{kwargs})') apiInstance = FlaskManager.getApi() OuterClass.__init__(self, *args, **kwargs) self.globals = apiInstance.globals ReflectionHelper.overrideSignatures(InnerClass, OuterClass) return InnerClass return Wrapper
def HttpClient(url=c.BLANK, headers=None, timeout=HttpClientConstant.DEFAULT_TIMEOUT, logRequest=False, logResponse=False) : clientUrl = url clientHeaders = ConverterStatic.getValueOrDefault(headers, dict()) clientTimeout = timeout clientLogRequest = logRequest clientLogResponse = logResponse def Wrapper(OuterClass, *args, **kwargs): log.wrapper(HttpClient,f'''wrapping {OuterClass.__name__}''') class InnerClass(OuterClass): url = clientUrl headers = clientHeaders timeout = clientTimeout logRequest = clientLogRequest logResponse = clientLogResponse def __init__(self,*args, **kwargs): log.wrapper(OuterClass,f'in {InnerClass.__name__}.__init__(*{args},**{kwargs})') apiInstance = FlaskManager.getApi() OuterClass.__init__(self,*args, **kwargs) self.globals = apiInstance.globals def options(self, *args, **kwargs): raise HttpClientEvent(HttpDomain.Verb.OPTIONS, *args, **kwargs) def get(self, *args, **kwargs): raise HttpClientEvent(HttpDomain.Verb.GET, *args, **kwargs) def post(self, *args, **kwargs): raise HttpClientEvent(HttpDomain.Verb.POST, *args, **kwargs) def put(self, *args, **kwargs): raise HttpClientEvent(HttpDomain.Verb.PUT, *args, **kwargs) def patch(self, *args, **kwargs): raise HttpClientEvent(HttpDomain.Verb.PATCH, *args, **kwargs) def delete(self, *args, **kwargs): raise HttpClientEvent(HttpDomain.Verb.DELETE, *args, **kwargs) ReflectionHelper.overrideSignatures(InnerClass, OuterClass) return InnerClass return Wrapper
def patchAccessToken(newContextList=None, headers=None, data=None, rawJwt=None, apiInstance=None): headers = headers if ObjectHelper.isNone(rawJwt) else { **getJwtHeaders(), **ConverterStatic.getValueOrDefault(headers, dict()) } rawJwt = getJwtBody(rawJwt=rawJwt, apiInstance=apiInstance) userClaims = { JwtConstant.KW_CONTEXT: list( set([ *safellyGetContext(getContext(rawJwt=rawJwt)), *safellyGetContext(newContextList) ])), JwtConstant.KW_DATA: { **safellyGetData(getData(rawJwt=rawJwt)), **safellyGetData(data) } } apiInstance = retrieveApiInstance(apiInstance=apiInstance) addAccessTokenToBlackList(rawJwt=rawJwt, apiInstance=apiInstance) return apiInstance.sessionManager.encode( { JwtConstant.KW_IAT: getIat(rawJwt=rawJwt, apiInstance=apiInstance), JwtConstant.KW_NFB: UtcDateTimeUtil.now(), JwtConstant.KW_JTI: getNewJti(), JwtConstant.KW_EXPIRATION: getExpiration(rawJwt=rawJwt, apiInstance=apiInstance), JwtConstant.KW_IDENTITY: getIdentity(rawJwt=rawJwt, apiInstance=apiInstance), JwtConstant.KW_FRESH: False, JwtConstant.KW_TYPE: JwtConstant.ACCESS_VALUE_TYPE, JwtConstant.KW_CLAIMS: userClaims }, headers=ConverterStatic.getValueOrDefault(headers, dict()))
def getUrl(client, clientMethodConfig, additionalUrl): return StringHelper.join( [ ConverterStatic.getValueOrDefault(u, c.BLANK) for u in [ client.url, clientMethodConfig.url, additionalUrl ] ], character = c.BLANK )
def addInfo(apiInstance): globalsInstance = apiInstance.globals apiInstance.documentation[k.INFO] = { k.TITLE: ConverterStatic.getValueOrDefault( globalsInstance.getSetting(f'{KW_OPEN_API}.{KW_INFO}.{KW_TITLE}'), StringHelper.toTitle(globalsInstance.apiName)), k.DESCRIPTION: ConverterStatic.getValueOrDefault( globalsInstance.getSetting( f'{KW_OPEN_API}.{KW_INFO}.{KW_DESCRIPTION}'), f'This is a {StringHelper.toTitle(globalsInstance.apiName)} service' ), k.VERSION: globalsInstance.getSetting(f'{KW_OPEN_API}.{KW_INFO}.{KW_VERSION}'), k.TERMS_OF_SERVICE: globalsInstance.getSetting( f'{KW_OPEN_API}.{KW_INFO}.{KW_TERMS_OF_SERVICE}') } addContact(globalsInstance, apiInstance.documentation) addLisence(globalsInstance, apiInstance.documentation)
def getDocumentationUrl(apiInstance): # return f'{getApiUrl(apiInstance)}{DOCUMENTATION_ENDPOINT}' globalsInstance = apiInstance.globals sheme = ConverterStatic.getValueOrDefault( ConverterStatic.getValueOrDefault( globalsInstance.getSetting(f'{KW_OPEN_API}.{KW_SCHEMES}'), [apiInstance.scheme]), [apiInstance.scheme])[0] host = ConverterStatic.getValueOrDefault( globalsInstance.getSetting(f'{KW_OPEN_API}.{KW_HOST}'), apiInstance.host).replace(ZERO_DOT_ZERO_DOT_ZERO_DOT_ZERO_HOST, LOCALHOST_HOST) colonPortIfAny = ConverterStatic.getValueOrDefault( f"{c.COLON}{globalsInstance.getSetting(f'{KW_OPEN_API}.{KW_PORT}')}", c.BLANK).replace(f'{c.COLON}None', c.BLANK) documentationUrl = f'{sheme}{SCHEME_HOST_SEPARATOR}{host}{colonPortIfAny}{apiInstance.baseUrl}{DOCUMENTATION_ENDPOINT}' if documentationUrl.endswith(URL_ENDS_WITH_PORT_80): documentationUrl = documentationUrl[:-len(URL_ENDS_WITH_PORT_80)] documentationUrl = documentationUrl.replace(PORT_80_IN_URL, PORT_80_EXCLUDED_FROM_URL) return documentationUrl.replace(ZERO_DOT_ZERO_DOT_ZERO_DOT_ZERO_HOST, LOCALHOST_HOST)
def getJwtMannager(appInstance, jwtSecret, algorithm=None, headerName=None, headerType=None): if ObjectHelper.isNone(jwtSecret): log.warning( getJwtMannager, f'Not possible to instanciate securityManager{c.DOT_SPACE_CAUSE}Missing jwt secret at {ConfigurationKeyConstant.API_SECURITY_SECRET}' ) else: jwtMannager = JWTManager(appInstance) appInstance.config[JwtConstant.KW_JWT_SECRET_KEY] = jwtSecret appInstance.config[JwtConstant.KW_JWT_BLACKLIST_ENABLED] = True appInstance.config[ JwtConstant.KW_JWT_ALGORITHM] = ConverterStatic.getValueOrDefault( algorithm, JwtConstant.DEFAULT_JWT_SECURITY_ALGORITHM) appInstance.config[ JwtConstant. KW_JWT_HEADER_NAME] = ConverterStatic.getValueOrDefault( headerName, JwtConstant.DEFAULT_JWT_SECURITY_HEADER_NAME) appInstance.config[ JwtConstant. KW_JWT_HEADER_TYPE] = ConverterStatic.getValueOrDefault( headerType, JwtConstant.DEFAULT_JWT_SECURITY_HEADER_TYPE) if SettingHelper.activeEnvironmentIsLocal(): info = { 'secret': jwtSecret, 'algorithm': appInstance.config[JwtConstant.KW_JWT_ALGORITHM], 'headerName': appInstance.config[JwtConstant.KW_JWT_HEADER_NAME], 'headerType': appInstance.config[JwtConstant.KW_JWT_HEADER_TYPE] } log.prettyJson(getJwtMannager, f'JWT security', info, logLevel=log.SETTING) return jwtMannager
def refreshAccessToken(identity, contextList, deltaMinutes=0, headers=None, data=None, apiInstance=None): ###- https://flask-jwt-extended.readthedocs.io/en/stable/_modules/flask_jwt_extended/utils/#create_refresh_token return create_refresh_token( identity=identity, user_claims={ JwtConstant.KW_CONTEXT: safellyGetContext(contextList), JwtConstant.KW_DATA: safellyGetData(data) }, expires_delta=DateTimeHelper.timeDelta(minutes=deltaMinutes), headers=ConverterStatic.getValueOrDefault(headers, dict()))
def __init__(self, *args, **kwargs): log.wrapper( OuterClass, f'in {InnerClass.__name__}.__init__(*{args},**{kwargs})') apiInstance = FlaskManager.getApi() OuterClass.__init__(self, *args, **kwargs) self.globals = apiInstance.globals self.service = apiInstance.resource.service self.enabled = self.globals.getApiSetting( ConfigurationKeyConstant.API_SCHEDULER_ENABLE) self.disabled = disable self.muteLogs = muteLogs or ConverterStatic.getValueOrDefault( self.globals.getApiSetting( ConfigurationKeyConstant.API_SCHEDULER_MUTE_LOGS), DEFAUTL_MUTE_LOGS)
def addResource(apiInstance, appInstance) : scheduler = APScheduler() globals = apiInstance.globals scheduler.api_enabled = globals.getApiSetting(ConfigurationKeyConstant.API_SCHEDULER_ENABLE) is True scheduler.timezone = ConverterStatic.getValueOrDefault( globals.getApiSetting(ConfigurationKeyConstant.API_SCHEDULER_TIMEZONE), SchedulerConstant.DEFAULT_TIMEZONE ) ###- guess scheduler.zone = scheduler.timezone ###- guess appInstance.config[SchedulerConstant.KW_SCHEDULER_API_ENABLED] = scheduler.api_enabled appInstance.config[SchedulerConstant.KW_SCHEDULER_TIMEZONE] = scheduler.timezone apiInstance.schedulerManager = scheduler if ObjectHelper.isNotNone(apiInstance.schedulerManager): log.success(addResource, f'APScheduler schedulers created{"" if apiInstance.schedulerManager.api_enabled else ". But are disabled"}') return scheduler
def addSecurity(verb, url, roleRequired, documentation, globalsInstance): if roleRequired: documentation[k.PATHS][url][verb][k.PARAMETERS].append({ k.NAME: ConverterStatic.getValueOrDefault( globalsInstance.getApiSetting( ConfigurationKeyConstant.API_SECURITY_HEADER), JwtConstant.DEFAULT_JWT_SECURITY_HEADER_NAME), k.DESCRIPTION: f'{ConverterStatic.getValueOrDefault(globalsInstance.getApiSetting(ConfigurationKeyConstant.API_SECURITY_TYPE), JwtConstant.DEFAULT_JWT_API_KEY_HEADER_TYPE)}{c.SPACE}{v.TOKEN_DESCRIPTION}', k.IN: v.HEADER, k.REQUIRED: True, k.TYPE: v.STRING })
def override(self, globalException): self.status = HttpStatus.map( ConverterStatic.getValueOrDefault(globalException.status, DEFAULT_STATUS)).enumValue self.verb = str(globalException.verb)[:MAX_VERB_SIZE - 1] self.url = str(globalException.url)[:MAX_URL_SIZE - 1] self.message = str(globalException.message)[:MAX_MESSAGE_SIZE - 1] self.logMessage = str(globalException.logMessage)[:MAX_MESSAGE_SIZE - 1] self.logPayload = str( globalException.logPayload)[:MAX_HTTP_ERROR_LOG_PAYLOAD_SIZE - 1] self.logResource = str( globalException.logResource)[:MAX_RESOURCE_NAME_SIZE - 1] self.logResourceMethod = str( globalException.logResourceMethod)[:MAX_RESOURCE_METHOD_NAME_SIZE - 1] self.timeStamp = globalException.timeStamp
def getCompleteResponse(clientResponse, responseClass, produces, fallbackStatus=HttpStatus.INTERNAL_SERVER_ERROR): responseBody, responseHeaders, responseStatus = dict(), dict(), fallbackStatus responseHeaders = FlaskUtil.safellyGetResponseHeaders(clientResponse) responseBody = FlaskUtil.safellyGetResponseJson(clientResponse) try : responseStatus = HttpStatus.map(HttpStatus.NOT_FOUND if ObjectHelper.isNone(clientResponse.status_code) else clientResponse.status_code) except Exception as exception : responseStatus = HttpStatus.map(fallbackStatus) log.warning(getCompleteResponse, f'Not possible to get client response status. Returning {responseStatus} by default', exception=exception) responseHeaders = { **{HttpDomain.HeaderKey.CONTENT_TYPE: produces}, **responseHeaders } responseStatus = ConverterStatic.getValueOrDefault(responseStatus, HttpStatus.map(fallbackStatus)) if ObjectHelper.isNone(responseClass): return responseBody, responseHeaders, responseStatus return Serializer.convertFromJsonToObject(responseBody, responseClass), responseHeaders, responseStatus
def newApp(filePath, successStatus=True, errorStatus=True, failureStatus=True, warningStatus=True, settingStatus=True, statusStatus=True, infoStatus=True, debugStatus=False, wrapperStatus=False, testStatus=False, logStatus=False): globalsInstance = globals.newGlobalsInstance(filePath, successStatus=successStatus, errorStatus=errorStatus, failureStatus=failureStatus, settingStatus=settingStatus, statusStatus=statusStatus, infoStatus=infoStatus, debugStatus=debugStatus, warningStatus=warningStatus, wrapperStatus=wrapperStatus, testStatus=testStatus, logStatus=logStatus) try: app = globals.importResource( KW_APP, resourceModuleName=ConverterStatic.getValueOrDefault( globalsInstance.apiName, StringHelper.join(EnvironmentHelper.listDirectoryContent( f'{globalsInstance.BASE_API_PATH}')[0].split(c.DOT)[:-1], character=c.DOT)), required=True) except Exception as exception: apiPath = f'{c.DOT}{EnvironmentHelper.OS_SEPARATOR}{globalsInstance.BASE_API_PATH}{globalsInstance.apiName}.py' errorMessage = f"Not possible to load app. Make shure it's name is properlly configured at '{globalsInstance.settingFilePath}' and it's instance is named 'app' at '{apiPath}'" log.error(newApp, errorMessage, exception) raise exception if ObjectHelper.isNone(app): app = globals.importResource( KW_APP, resourceModuleName=globalsInstance.apiName) raise Exception( 'Not possible to load app. Check logs for more details') return app
def __init__(self, id=None, status=None, verb=None, url=None, message=None, logMessage=None, logPayload=None, logResource=None, logResourceMethod=None, timeStamp=None): self.id = id self.status = HttpStatus.map( ConverterStatic.getValueOrDefault(status, DEFAULT_STATUS)).enumValue self.verb = str(verb)[:MAX_VERB_SIZE - 1] self.url = str(url)[:MAX_URL_SIZE - 1] self.message = str(message)[:MAX_MESSAGE_SIZE - 1] self.logMessage = str(logMessage)[:MAX_MESSAGE_SIZE - 1] self.logPayload = str(logPayload)[:MAX_HTTP_ERROR_LOG_PAYLOAD_SIZE - 1] self.logResource = str(logResource)[:MAX_RESOURCE_NAME_SIZE - 1] self.logResourceMethod = str( logResourceMethod)[:MAX_RESOURCE_METHOD_NAME_SIZE - 1] self.timeStamp = timeStamp
def innerMethodWrapper(resourceMethod, *innerMethodArgs, **innerMethodKwargs): log.wrapper(SchedulerMethod, f'''wrapping {resourceMethod.__name__}''') apiInstance = FlaskManager.getApi() methodClassName = ReflectionHelper.getMethodClassName(resourceMethod) methodName = ReflectionHelper.getName(resourceMethod) methodKwargs['id'] = methodKwargs.get( 'id', f'{methodClassName}{c.DOT}{methodName}') instancesUpTo = methodKwargs.pop('instancesUpTo', 1) weekDays = methodKwargs.pop('weekDays', None) resourceMethod.disabled = disable resourceMethod.shedulerId = methodKwargs['id'] resourceMethod.muteLogs = muteLogs or ConverterStatic.getValueOrDefault( apiInstance.globals.getApiSetting( ConfigurationKeyConstant.API_SCHEDULER_MUTE_LOGS), DEFAUTL_MUTE_LOGS) if ObjectHelper.isNotEmpty( methodArgs ) and SchedulerType.CRON == methodArgs[0] and ObjectHelper.isNotNone( weekDays) and StringHelper.isNotBlank(weekDays): methodKwargs['day_of_week'] = weekDays if ObjectHelper.isNotNone(instancesUpTo): methodKwargs['max_instances'] = instancesUpTo shedulerArgs = [*methodArgs] shedulerKwargs = {**methodKwargs} @apiInstance.schedulerManager.task(*shedulerArgs, **shedulerKwargs) def innerResourceInstanceMethod(*args, **kwargs): resourceInstanceName = methodClassName[:-len( FlaskManager.KW_SCHEDULER_RESOURCE)] resourceInstanceName = f'{resourceInstanceName[0].lower()}{resourceInstanceName[1:]}' args = FlaskManager.getArgumentInFrontOfArgs( args, ReflectionHelper.getAttributeOrMethod( apiInstance.resource.scheduler, resourceInstanceName)) resourceInstance = args[0] muteLogs = resourceInstance.muteLogs or resourceMethod.muteLogs if resourceInstance.enabled and not resourceInstance.disabled and not resourceMethod.disabled: if not muteLogs: log.debug( resourceMethod, f'{resourceMethod.shedulerId} scheduler started with args={methodArgs} and kwargs={methodKwargs}' ) methodReturn = None try: FlaskManager.validateArgs(args, requestClass, innerResourceInstanceMethod) methodReturn = resourceMethod(*args, **kwargs) except Exception as exception: if not muteLogs: log.warning( resourceMethod, f'Not possible to run {resourceMethod.shedulerId} properly', exception=exception, muteStackTrace=True) FlaskManager.raiseAndPersistGlobalException( exception, resourceInstance, resourceMethod) if not muteLogs: log.debug( resourceMethod, f'{resourceMethod.shedulerId} scheduler finished') return methodReturn if not muteLogs: log.warning( resourceMethod, f'{resourceMethod.shedulerId} scheduler didn{c.SINGLE_QUOTE}t started. {"Schedulers are disabled" if not resourceInstance.enabled else "This scheduler is disabled" if resourceInstance.disabled else "This scheduler method is disabled"}' ) ReflectionHelper.overrideSignatures(innerResourceInstanceMethod, resourceMethod) resourceMethod.shedulerId = methodKwargs.get('id') innerResourceInstanceMethod.disable = resourceMethodDisable innerResourceInstanceMethod.muteLogs = resourceMethodMuteLogs return innerResourceInstanceMethod
def encode(self, payload, headers=None): return jwt.encode(payload, self.secret, algorithm=self.algorithm, headers=ConverterStatic.getValueOrDefault( headers, dict())).decode()
def getTimeout(client, clientMethodConfig, timeout): return ConverterStatic.getValueOrDefault(timeout, ConverterStatic.getValueOrDefault(clientMethodConfig.timeout, client.timeout))