// +build fasthttp package routebuildermdl import ( "strings" "github.com/pquerna/ffjson/ffjson" routing "github.com/qiangxue/fasthttp-routing" "corelab.mkcl.org/MKCLOS/coredevelopmentplatform/corepkgv2/statemdl" "corelab.mkcl.org/MKCLOS/coredevelopmentplatform/corepkgv2/authmdl/jwtmdl" "corelab.mkcl.org/MKCLOS/coredevelopmentplatform/corepkgv2/authmdl/roleenforcemdl" "corelab.mkcl.org/MKCLOS/coredevelopmentplatform/corepkgv2/errormdl" "corelab.mkcl.org/MKCLOS/coredevelopmentplatform/corepkgv2/loggermdl" "corelab.mkcl.org/MKCLOS/coredevelopmentplatform/corepkgv2/servicebuildermdl" version "github.com/hashicorp/go-version" "github.com/tidwall/gjson" ) // Init routing init func Init(o, r, c *routing.RouteGroup, JWTKey string) { o.Post("/mql/state", statemdl.StateHandler) o.Post("/mql", OpenHandler) r.Post("/mql", RestrictedHandler) c.Post("/mql", RoleBasedHandler) o.Post("/heavymql", HeavyOpenHandler) r.Post("/heavymql", HeavyRestrictedHandler) c.Post("/heavymql", HeavyRoleBasedHandler) jwtmdl.GlobalJWTKey = JWTKey } func commonHandler(c *routing.Context, isRestricted, isRoleBased, heavyDataActivity bool, principalObj servicebuildermdl.Principal) error { serviceHeader := string(c.Request.Header.Peek("Service-Header")) services := strings.Split(serviceHeader, ",") versionError := appVersioning(c) if versionError != nil { _, err := c.WriteString(versionError.Error()) c.SetStatusCode(417) return err } responseMap := make(map[string]responseData) var reqBody []byte reqBody = c.Request.Body() requestBody := gjson.ParseBytes(reqBody) for i := 0; i < len(services); i++ { responseDataObj := responseData{} service := services[i] result, ab, isCompressed, errorCode, err := executeService(service, []byte(requestBody.Get(service).String()), isRestricted, isRoleBased, heavyDataActivity, principalObj) if errormdl.CheckErr1(err) != nil { if ab == nil { responseDataObj.ErrorCode = errorCode responseDataObj.Error = err.Error() } else { responseDataObj.Error = ab.GetErrorData() if responseDataObj.Error == nil { responseDataObj.Error = err.Error() } errorCode := ab.GetErrorCode() if errorCode == 0 { errorCode = errormdl.EXPECTATIONFAILED } responseDataObj.ErrorCode = errorCode if ab.TransactionEnable { if ab.TXN != nil { loggermdl.LogError("Transaction Rollbacked") err := ab.TXN.Rollback() if err != nil { responseDataObj.Error = err.Error() responseDataObj.ErrorCode = errormdl.MYSQLERROR } } } } } else { if ab != nil { if ab.TransactionEnable { if ab.TXN != nil { loggermdl.LogError("Transaction Commit") err := ab.TXN.Commit() if err != nil { responseDataObj.Error = err.Error() responseDataObj.ErrorCode = errormdl.MYSQLERROR } else { responseDataObj.Result = result responseDataObj.ErrorCode = errormdl.NOERROR } } else { responseDataObj.Result = result responseDataObj.ErrorCode = errormdl.NOERROR } } else { responseDataObj.Result = result responseDataObj.ErrorCode = errormdl.NOERROR } } else { responseDataObj.Result = result responseDataObj.ErrorCode = errormdl.NOERROR } } responseDataObj.IsCompressed = isCompressed responseDataObj = formatResponse(ab, responseDataObj) responseMap[service] = responseDataObj // Token extraction // if ab != nil { // token, ok := ab.GetDataString("MQLToken") // if !ok { // token = string(c.Request.Header.Peek("Authorization")) // token = strings.TrimPrefix(token, "Bearer") // token = strings.TrimSpace(token) // c.Response.Header.Set("Authorization", token) // } // c.Response.Header.Set("Authorization", token) // } else { // token := string(c.Request.Header.Peek("Authorization")) // token = strings.TrimPrefix(token, "Bearer") // token = strings.TrimSpace(token) // c.Response.Header.Set("Authorization", token) // } if ab != nil { token, ok := ab.GetDataString("MQLToken") if ok { c.Response.Header.Set("Authorization", token) } } } ba, _ := ffjson.Marshal(responseMap) _, err := c.Write(ba) c.SetStatusCode(200) return err } // OpenHandler for /o func OpenHandler(c *routing.Context) error { c.Response.Header.Set("content-type", "application/json") principal := servicebuildermdl.Principal{} principal.ClientIP = c.RemoteIP().String() commonHandler(c, false, false, false, principal) return nil } // RestrictedHandler for /r func RestrictedHandler(c *routing.Context) error { c.Response.Header.Set("content-type", "application/json") pricipalObj, extractError := extractPricipalObject(c) if extractError != nil { loggermdl.LogError(extractError) _, err := c.WriteString(extractError.Error()) c.SetStatusCode(412) return err } pricipalObj.ClientIP = c.RemoteIP().String() commonHandler(c, true, false, false, pricipalObj) return nil } // RoleBasedHandler for /r/c func RoleBasedHandler(c *routing.Context) error { c.Response.Header.Set("content-type", "application/json") pricipalObj, extractError := extractPricipalObject(c) if extractError != nil { loggermdl.LogError(extractError) _, err := c.WriteString(extractError.Error()) c.SetStatusCode(412) return err } pricipalObj.ClientIP = c.RemoteIP().String() commonHandler(c, true, true, false, pricipalObj) return nil } // HeavyOpenHandler for /o func HeavyOpenHandler(c *routing.Context) error { c.Response.Header.Set("content-type", "application/json") principal := servicebuildermdl.Principal{} principal.ClientIP = c.RemoteIP().String() commonHandler(c, false, false, true, principal) return nil } // HeavyRestrictedHandler for /r func HeavyRestrictedHandler(c *routing.Context) error { c.Response.Header.Set("content-type", "application/json") pricipalObj, extractError := extractPricipalObject(c) if extractError != nil { loggermdl.LogError(extractError) _, err := c.WriteString(extractError.Error()) c.SetStatusCode(412) return err } pricipalObj.ClientIP = c.RemoteIP().String() commonHandler(c, true, false, true, pricipalObj) return nil } // HeavyRoleBasedHandler for /r/c func HeavyRoleBasedHandler(c *routing.Context) error { c.Response.Header.Set("content-type", "application/json") pricipalObj, extractError := extractPricipalObject(c) if extractError != nil { loggermdl.LogError(extractError) _, err := c.WriteString(extractError.Error()) c.SetStatusCode(412) return err } pricipalObj.ClientIP = c.RemoteIP().String() commonHandler(c, true, true, true, pricipalObj) return nil } func appVersioning(c *routing.Context) error { if isAppVersionEnabled { appVersion := string(c.Request.Header.Peek("app-version")) if appVersion == "" { return errormdl.Wrap("No App version Found in request header") } ver, err := version.NewVersion(appVersion) if errormdl.CheckErr(err) != nil { return errormdl.CheckErr(err) } if isStrictMode { if !ver.Equal(applicationVersion) { return errormdl.Wrap("Application version mismatched") } } else { if ver.GreaterThan(applicationVersion) { return errormdl.Wrap("Server Version is outdated") } if ver.LessThan(minimumSupportedVersion) { return errormdl.Wrap("Client Version is outdated") } } } return nil } func extractPricipalObject(c *routing.Context) (servicebuildermdl.Principal, error) { principal := servicebuildermdl.Principal{} if jwtmdl.GlobalJWTKey == "" { return principal, errormdl.Wrap("No Global JWT key found") } claim, decodeError := jwtmdl.DecodeToken(&c.Request) if errormdl.CheckErr(decodeError) != nil { loggermdl.LogError(decodeError) return principal, errormdl.CheckErr(decodeError) } groups, grperr := roleenforcemdl.GetGroupNames(claim, "groups") if errormdl.CheckErr(grperr) != nil { loggermdl.LogError(grperr) return principal, errormdl.CheckErr(grperr) } userID, ok := claim["userId"].(string) if !ok { loggermdl.LogError("Unable to parse UserID from JWT Token") return principal, errormdl.Wrap("Unable to parse UserID from JWT Token") } if len(userID) < 2 { loggermdl.LogError("UserID length is less than 2") return principal, errormdl.Wrap("UserID length is less than 2") } rawMetadata, ok := claim["metadata"] if ok { metadata, ok := rawMetadata.(string) if !ok { loggermdl.LogError("Unable to parse metadata from JWT Token") return principal, errormdl.Wrap("Unable to parse metadata from JWT Token") } principal.Metadata = metadata } principal.Groups = groups principal.UserID = userID principal.Token = string(c.Request.Header.Peek("Authorization")) return principal, nil }