From 0115128ee72dc4bc8d3c977996937ac766dfe8de Mon Sep 17 00:00:00 2001 From: Lakhan Samani Date: Sun, 9 Oct 2022 19:48:13 +0530 Subject: [PATCH 01/66] fix(server): authorizer as oauth provider --- server/constants/oauth2.go | 17 +++ server/handlers/authorize.go | 185 +++++------------------ server/memorystore/memory_store.go | 2 +- server/memorystore/required_env_store.go | 4 +- 4 files changed, 61 insertions(+), 147 deletions(-) create mode 100644 server/constants/oauth2.go diff --git a/server/constants/oauth2.go b/server/constants/oauth2.go new file mode 100644 index 0000000..d3ff253 --- /dev/null +++ b/server/constants/oauth2.go @@ -0,0 +1,17 @@ +package constants + +const ( + // - query: for Authorization Code grant. 302 Found triggers redirect. + ResponseModeQuery = "query" + // - fragment: for Implicit grant. 302 Found triggers redirect. + ResponseModeFragment = "fragment" + // - form_post: 200 OK with response parameters embedded in an HTML form as hidden parameters. + ResponseModeFormPost = "form_post" + // - web_message: For Silent Authentication. Uses HTML5 web messaging. + ResponseModeWebMessage = "web_message" + + // For the Authorization Code grant, use response_type=code to include the authorization code. + ResponseTypeCode = "code" + // For the Implicit grant, use response_type=token to include an access token. + ResponseTypeToken = "token" +) diff --git a/server/handlers/authorize.go b/server/handlers/authorize.go index fd2372c..b3db022 100644 --- a/server/handlers/authorize.go +++ b/server/handlers/authorize.go @@ -1,6 +1,7 @@ package handlers import ( + "fmt" "net/http" "strconv" "strings" @@ -45,176 +46,42 @@ func AuthorizeHandler() gin.HandlerFunc { } if responseMode == "" { - responseMode = "query" - } - - if responseMode != "query" && responseMode != "web_message" { - log.Debug("Invalid response_mode: ", responseMode) - gc.JSON(400, gin.H{"error": "invalid response mode"}) + responseMode = constants.ResponseModeQuery } if redirectURI == "" { redirectURI = "/app" } - isQuery := responseMode == "query" - - loginURL := "/app?state=" + state + "&scope=" + strings.Join(scope, " ") + "&redirect_uri=" + redirectURI - - if clientID == "" { - if isQuery { - gc.Redirect(http.StatusFound, loginURL) - } else { - log.Debug("Failed to get client_id: ", clientID) - gc.HTML(http.StatusOK, template, gin.H{ - "target_origin": redirectURI, - "authorization_response": map[string]interface{}{ - "type": "authorization_response", - "response": map[string]string{ - "error": "client_id is required", - }, - }, - }) - } - return - } - - if client, err := memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeyClientID); client != clientID || err != nil { - if isQuery { - gc.Redirect(http.StatusFound, loginURL) - } else { - log.Debug("Invalid client_id: ", clientID) - gc.HTML(http.StatusOK, template, gin.H{ - "target_origin": redirectURI, - "authorization_response": map[string]interface{}{ - "type": "authorization_response", - "response": map[string]string{ - "error": "invalid_client_id", - }, - }, - }) - } - return - } - - if state == "" { - if isQuery { - gc.Redirect(http.StatusFound, loginURL) - } else { - log.Debug("Failed to get state: ", state) - gc.HTML(http.StatusOK, template, gin.H{ - "target_origin": redirectURI, - "authorization_response": map[string]interface{}{ - "type": "authorization_response", - "response": map[string]string{ - "error": "state is required", - }, - }, - }) - } - return - } - if responseType == "" { responseType = "token" } - isResponseTypeCode := responseType == "code" - isResponseTypeToken := responseType == "token" - - if !isResponseTypeCode && !isResponseTypeToken { - if isQuery { - gc.Redirect(http.StatusFound, loginURL) - } else { - log.Debug("Invalid response_type: ", responseType) - gc.HTML(http.StatusOK, template, gin.H{ - "target_origin": redirectURI, - "authorization_response": map[string]interface{}{ - "type": "authorization_response", - "response": map[string]string{ - "error": "response_type is invalid", - }, - }, - }) - } + if err := validateAuthorizeRequest(responseType, responseMode, clientID, state, codeChallenge); err != nil { + log.Debug("invalid authorization request: ", err) + gc.JSON(http.StatusBadRequest, gin.H{"error": err}) return } - if isResponseTypeCode { - if codeChallenge == "" { - if isQuery { - gc.Redirect(http.StatusFound, loginURL) - } else { - log.Debug("Failed to get code_challenge: ", codeChallenge) - gc.HTML(http.StatusBadRequest, template, gin.H{ - "target_origin": redirectURI, - "authorization_response": map[string]interface{}{ - "type": "authorization_response", - "response": map[string]string{ - "error": "code_challenge is required", - }, - }, - }) - } - return - } - } - sessionToken, err := cookie.GetSession(gc) if err != nil { - if isQuery { - gc.Redirect(http.StatusFound, loginURL) - } else { - gc.HTML(http.StatusOK, template, gin.H{ - "target_origin": redirectURI, - "authorization_response": map[string]interface{}{ - "type": "authorization_response", - "response": map[string]string{ - "error": "login_required", - "error_description": "Login is required", - }, - }, - }) - } + log.Debug("GetSession failed: ", err) + gc.JSON(http.StatusBadRequest, gin.H{"error": fmt.Sprintf("login required. %v", err)}) return } // get session from cookie claims, err := token.ValidateBrowserSession(gc, sessionToken) if err != nil { - if isQuery { - gc.Redirect(http.StatusFound, loginURL) - } else { - gc.HTML(http.StatusOK, template, gin.H{ - "target_origin": redirectURI, - "authorization_response": map[string]interface{}{ - "type": "authorization_response", - "response": map[string]string{ - "error": "login_required", - "error_description": "Login is required", - }, - }, - }) - } + log.Debug("ValidateBrowserSession failed: ", err) + gc.JSON(http.StatusBadRequest, gin.H{"error": fmt.Sprintf("login required. %v", err)}) return } userID := claims.Subject user, err := db.Provider.GetUserByID(gc, userID) if err != nil { - if isQuery { - gc.Redirect(http.StatusFound, loginURL) - } else { - gc.HTML(http.StatusOK, template, gin.H{ - "target_origin": redirectURI, - "authorization_response": map[string]interface{}{ - "type": "authorization_response", - "response": map[string]string{ - "error": "signup_required", - "error_description": "Sign up required", - }, - }, - }) - } + log.Debug("GetUserByID failed: ", err) + gc.JSON(http.StatusBadRequest, gin.H{"error": fmt.Sprintf("sign up required. %v", err)}) return } @@ -223,6 +90,12 @@ func AuthorizeHandler() gin.HandlerFunc { sessionKey = claims.LoginMethod + ":" + user.ID } + loginState := "state=" + state + "&scope=" + strings.Join(scope, " ") + "&redirect_uri=" + redirectURI + loginURL := "/app?" + loginState + if responseMode == constants.ResponseModeFragment { + loginURL = "/app#" + loginState + } + // if user is logged in // based on the response type code, generate the response if isResponseTypeCode { @@ -349,3 +222,27 @@ func AuthorizeHandler() gin.HandlerFunc { } } } + +func validateAuthorizeRequest(responseType, responseMode, clientID, state, codeChallenge string) error { + if responseType != constants.ResponseTypeCode && responseType != constants.ResponseTypeToken { + return fmt.Errorf("invalid response type %s. 'code' & 'token' are valid response_type", responseMode) + } + + if responseMode != constants.ResponseModeQuery && responseMode != constants.ResponseModeWebMessage && responseMode != constants.ResponseModeFragment && responseMode != constants.ResponseModeFormPost { + return fmt.Errorf("invalid response mode %s. 'query', 'fragment', 'form_post' and 'web_message' are valid response_mode") + } + + if responseType == constants.ResponseTypeCode && strings.TrimSpace(codeChallenge) == "" { + return fmt.Errorf("code_challenge is required for %s '%s'", responseType, constants.ResponseTypeCode) + } + + if client, err := memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeyClientID); client != clientID || err != nil { + return fmt.Errorf("invalid client_id %s", clientID) + } + + if strings.TrimSpace(state) == "" { + return fmt.Errorf("state is required") + } + + return nil +} diff --git a/server/memorystore/memory_store.go b/server/memorystore/memory_store.go index c112c01..15b7248 100644 --- a/server/memorystore/memory_store.go +++ b/server/memorystore/memory_store.go @@ -57,7 +57,7 @@ func InitMemStore() error { } redisURL := requiredEnvs.RedisURL - if redisURL != "" && !requiredEnvs.disableRedisForEnv { + if redisURL != "" && !requiredEnvs.DisableRedisForEnv { log.Info("Initializing Redis memory store") Provider, err = redis.NewRedisProvider(redisURL) if err != nil { diff --git a/server/memorystore/required_env_store.go b/server/memorystore/required_env_store.go index a5f3a81..b81cf56 100644 --- a/server/memorystore/required_env_store.go +++ b/server/memorystore/required_env_store.go @@ -27,7 +27,7 @@ type RequiredEnv struct { DatabaseCertKey string `json:"DATABASE_CERT_KEY"` DatabaseCACert string `json:"DATABASE_CA_CERT"` RedisURL string `json:"REDIS_URL"` - disableRedisForEnv bool `json:"DISABLE_REDIS_FOR_ENV"` + DisableRedisForEnv bool `json:"DISABLE_REDIS_FOR_ENV"` } // RequiredEnvObj is a simple in-memory store for sessions. @@ -138,7 +138,7 @@ func InitRequiredEnv() error { DatabaseCertKey: dbCertKey, DatabaseCACert: dbCACert, RedisURL: redisURL, - disableRedisForEnv: disableRedisForEnv, + DisableRedisForEnv: disableRedisForEnv, } RequiredEnvStoreObj = &RequiredEnvStore{ From ff805e3ef2720f1b659572fa16fdd2949efdbeb6 Mon Sep 17 00:00:00 2001 From: Lakhan Samani Date: Wed, 12 Oct 2022 13:10:24 +0530 Subject: [PATCH 02/66] fix: add comments --- server/handlers/authorize.go | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/server/handlers/authorize.go b/server/handlers/authorize.go index b3db022..4f1df0c 100644 --- a/server/handlers/authorize.go +++ b/server/handlers/authorize.go @@ -90,17 +90,19 @@ func AuthorizeHandler() gin.HandlerFunc { sessionKey = claims.LoginMethod + ":" + user.ID } + // used for response mode query or fragment loginState := "state=" + state + "&scope=" + strings.Join(scope, " ") + "&redirect_uri=" + redirectURI loginURL := "/app?" + loginState if responseMode == constants.ResponseModeFragment { loginURL = "/app#" + loginState } + // rollover the session for security + go memorystore.Provider.DeleteUserSession(sessionKey, claims.Nonce) + // if user is logged in // based on the response type code, generate the response if isResponseTypeCode { - // rollover the session for security - go memorystore.Provider.DeleteUserSession(sessionKey, claims.Nonce) nonce := uuid.New().String() newSessionTokenData, newSessionToken, err := token.CreateSessionToken(user, nonce, claims.Roles, scope, claims.LoginMethod) if err != nil { @@ -159,7 +161,6 @@ func AuthorizeHandler() gin.HandlerFunc { return } - go memorystore.Provider.DeleteUserSession(sessionKey, claims.Nonce) memorystore.Provider.SetUserSession(sessionKey, constants.TokenTypeSessionToken+"_"+authToken.FingerPrint, authToken.FingerPrintHash) memorystore.Provider.SetUserSession(sessionKey, constants.TokenTypeAccessToken+"_"+authToken.FingerPrint, authToken.AccessToken.Token) cookie.SetSession(gc, authToken.FingerPrintHash) From 2bd92d60286d2fe811dd101fe07455fb794efa09 Mon Sep 17 00:00:00 2001 From: Lakhan Samani Date: Sun, 16 Oct 2022 20:46:54 +0530 Subject: [PATCH 03/66] feat: add form_post method --- server/handlers/authorize.go | 180 ++++++++++-------- server/resolvers/forgot_password.go | 2 +- templates/authorize_form_post.tmpl | 13 ++ ...horize.tmpl => authorize_web_message.tmpl} | 0 4 files changed, 118 insertions(+), 77 deletions(-) create mode 100644 templates/authorize_form_post.tmpl rename templates/{authorize.tmpl => authorize_web_message.tmpl} (100%) diff --git a/server/handlers/authorize.go b/server/handlers/authorize.go index 4f1df0c..9337ce9 100644 --- a/server/handlers/authorize.go +++ b/server/handlers/authorize.go @@ -27,6 +27,12 @@ import ( // code_challenge_method = to prevent CSRF attack [only sh256 is supported] // check the flow for generating and verifying codes: https://developer.okta.com/blog/2019/08/22/okta-authjs-pkce#:~:text=PKCE%20works%20by%20having%20the,is%20called%20the%20Code%20Challenge. + +const ( + authorizeWebMessageTemplate = "authorize_web_message.tmpl" + authorizeFormPostTemplate = "authorize_form_post.tmpl" +) + func AuthorizeHandler() gin.HandlerFunc { return func(gc *gin.Context) { redirectURI := strings.TrimSpace(gc.Query("redirect_uri")) @@ -35,7 +41,6 @@ func AuthorizeHandler() gin.HandlerFunc { codeChallenge := strings.TrimSpace(gc.Query("code_challenge")) scopeString := strings.TrimSpace(gc.Query("scope")) clientID := strings.TrimSpace(gc.Query("client_id")) - template := "authorize.tmpl" responseMode := strings.TrimSpace(gc.Query("response_mode")) var scope []string @@ -63,10 +68,22 @@ func AuthorizeHandler() gin.HandlerFunc { return } + // used for response mode query or fragment + loginState := "state=" + state + "&scope=" + strings.Join(scope, " ") + "&redirect_uri=" + redirectURI + loginURL := "/app?" + loginState + if responseMode == constants.ResponseModeFragment { + loginURL = "/app#" + loginState + } + + loginError := map[string]interface{}{ + "error": "login_required", + "error_description": "Login is required", + } + sessionToken, err := cookie.GetSession(gc) if err != nil { log.Debug("GetSession failed: ", err) - gc.JSON(http.StatusBadRequest, gin.H{"error": fmt.Sprintf("login required. %v", err)}) + handleResponse(gc, responseMode, loginURL, redirectURI, loginError, http.StatusOK) return } @@ -74,14 +91,17 @@ func AuthorizeHandler() gin.HandlerFunc { claims, err := token.ValidateBrowserSession(gc, sessionToken) if err != nil { log.Debug("ValidateBrowserSession failed: ", err) - gc.JSON(http.StatusBadRequest, gin.H{"error": fmt.Sprintf("login required. %v", err)}) + handleResponse(gc, responseMode, loginURL, redirectURI, loginError, http.StatusOK) return } userID := claims.Subject user, err := db.Provider.GetUserByID(gc, userID) if err != nil { log.Debug("GetUserByID failed: ", err) - gc.JSON(http.StatusBadRequest, gin.H{"error": fmt.Sprintf("sign up required. %v", err)}) + handleResponse(gc, responseMode, loginURL, redirectURI, map[string]interface{}{ + "error": "signup_required", + "error_description": "Sign up required", + }, http.StatusOK) return } @@ -90,44 +110,34 @@ func AuthorizeHandler() gin.HandlerFunc { sessionKey = claims.LoginMethod + ":" + user.ID } - // used for response mode query or fragment - loginState := "state=" + state + "&scope=" + strings.Join(scope, " ") + "&redirect_uri=" + redirectURI - loginURL := "/app?" + loginState - if responseMode == constants.ResponseModeFragment { - loginURL = "/app#" + loginState - } - // rollover the session for security go memorystore.Provider.DeleteUserSession(sessionKey, claims.Nonce) - - // if user is logged in - // based on the response type code, generate the response - if isResponseTypeCode { + if responseType == constants.ResponseTypeCode { nonce := uuid.New().String() newSessionTokenData, newSessionToken, err := token.CreateSessionToken(user, nonce, claims.Roles, scope, claims.LoginMethod) if err != nil { - if isQuery { - gc.Redirect(http.StatusFound, loginURL) - } else { - gc.HTML(http.StatusOK, template, gin.H{ - "target_origin": redirectURI, - "authorization_response": map[string]interface{}{ - "type": "authorization_response", - "response": map[string]string{ - "error": "login_required", - "error_description": "Login is required", - }, - }, - }) - } + log.Debug("CreateSessionToken failed: ", err) + handleResponse(gc, responseMode, loginURL, redirectURI, loginError, http.StatusOK) + return + } + + if err := memorystore.Provider.SetUserSession(sessionKey, constants.TokenTypeSessionToken+"_"+newSessionTokenData.Nonce, newSessionToken); err != nil { + log.Debug("SetUserSession failed: ", err) + handleResponse(gc, responseMode, loginURL, redirectURI, loginError, http.StatusOK) return } - memorystore.Provider.SetUserSession(sessionKey, constants.TokenTypeSessionToken+"_"+newSessionTokenData.Nonce, newSessionToken) cookie.SetSession(gc, newSessionToken) code := uuid.New().String() - memorystore.Provider.SetState(codeChallenge, code+"@"+newSessionToken) - gc.HTML(http.StatusOK, template, gin.H{ + if err := memorystore.Provider.SetState(codeChallenge, code+"@"+newSessionToken); err != nil { + log.Debug("SetState failed: ", err) + handleResponse(gc, responseMode, loginURL, redirectURI, loginError, http.StatusOK) + return + } + + // in case, response type is code and user is already logged in send the code and state + // and cookie session will already be rolled over and set + gc.HTML(http.StatusOK, authorizeWebMessageTemplate, gin.H{ "target_origin": redirectURI, "authorization_response": map[string]interface{}{ "type": "authorization_response", @@ -140,29 +150,27 @@ func AuthorizeHandler() gin.HandlerFunc { return } - if isResponseTypeToken { + if responseType == constants.ResponseTypeToken { // rollover the session for security authToken, err := token.CreateAuthToken(gc, user, claims.Roles, scope, claims.LoginMethod) if err != nil { - if isQuery { - gc.Redirect(http.StatusFound, loginURL) - } else { - gc.HTML(http.StatusOK, template, gin.H{ - "target_origin": redirectURI, - "authorization_response": map[string]interface{}{ - "type": "authorization_response", - "response": map[string]string{ - "error": "login_required", - "error_description": "Login is required", - }, - }, - }) - } + log.Debug("CreateAuthToken failed: ", err) + handleResponse(gc, responseMode, loginURL, redirectURI, loginError, http.StatusOK) + return + } + + if err := memorystore.Provider.SetUserSession(sessionKey, constants.TokenTypeSessionToken+"_"+authToken.FingerPrint, authToken.FingerPrintHash); err != nil { + log.Debug("SetUserSession failed: ", err) + handleResponse(gc, responseMode, loginURL, redirectURI, loginError, http.StatusOK) + return + } + + if err := memorystore.Provider.SetUserSession(sessionKey, constants.TokenTypeAccessToken+"_"+authToken.FingerPrint, authToken.AccessToken.Token); err != nil { + log.Debug("SetUserSession failed: ", err) + handleResponse(gc, responseMode, loginURL, redirectURI, loginError, http.StatusOK) return } - memorystore.Provider.SetUserSession(sessionKey, constants.TokenTypeSessionToken+"_"+authToken.FingerPrint, authToken.FingerPrintHash) - memorystore.Provider.SetUserSession(sessionKey, constants.TokenTypeAccessToken+"_"+authToken.FingerPrint, authToken.AccessToken.Token) cookie.SetSession(gc, authToken.FingerPrintHash) expiresIn := authToken.AccessToken.ExpiresAt - time.Now().Unix() @@ -188,39 +196,28 @@ func AuthorizeHandler() gin.HandlerFunc { memorystore.Provider.SetUserSession(sessionKey, constants.TokenTypeRefreshToken+"_"+authToken.FingerPrint, authToken.RefreshToken.Token) } - if isQuery { + if responseMode == constants.ResponseModeQuery { if strings.Contains(redirectURI, "?") { - gc.Redirect(http.StatusFound, redirectURI+"&"+params) + redirectURI = redirectURI + "&" + params } else { - gc.Redirect(http.StatusFound, redirectURI+"?"+params) + redirectURI = redirectURI + "?" + params + } + } else if responseMode == constants.ResponseModeFragment { + if strings.Contains(redirectURI, "#") { + redirectURI = redirectURI + "&" + params + } else { + redirectURI = redirectURI + "#" + params } - } else { - gc.HTML(http.StatusOK, template, gin.H{ - "target_origin": redirectURI, - "authorization_response": map[string]interface{}{ - "type": "authorization_response", - "response": res, - }, - }) } + + handleResponse(gc, responseMode, loginURL, redirectURI, map[string]interface{}{ + "type": "authorization_response", + "response": res, + }, http.StatusOK) return } - if isQuery { - gc.Redirect(http.StatusFound, loginURL) - } else { - // by default return with error - gc.HTML(http.StatusOK, template, gin.H{ - "target_origin": redirectURI, - "authorization_response": map[string]interface{}{ - "type": "authorization_response", - "response": map[string]string{ - "error": "login_required", - "error_description": "Login is required", - }, - }, - }) - } + handleResponse(gc, responseMode, loginURL, redirectURI, loginError, http.StatusOK) } } @@ -230,7 +227,7 @@ func validateAuthorizeRequest(responseType, responseMode, clientID, state, codeC } if responseMode != constants.ResponseModeQuery && responseMode != constants.ResponseModeWebMessage && responseMode != constants.ResponseModeFragment && responseMode != constants.ResponseModeFormPost { - return fmt.Errorf("invalid response mode %s. 'query', 'fragment', 'form_post' and 'web_message' are valid response_mode") + return fmt.Errorf("invalid response mode %s. 'query', 'fragment', 'form_post' and 'web_message' are valid response_mode", responseMode) } if responseType == constants.ResponseTypeCode && strings.TrimSpace(codeChallenge) == "" { @@ -247,3 +244,34 @@ func validateAuthorizeRequest(responseType, responseMode, clientID, state, codeC return nil } + +func handleResponse(gc *gin.Context, responseMode, loginURI, redirectURI string, data map[string]interface{}, httpStatusCode int) { + isAuthenticationRequired := false + if val, ok := data["error"]; ok { + if val == "login_required" || val == "signup_required" { + isAuthenticationRequired = true + } + } + + switch responseMode { + case constants.ResponseModeQuery, constants.ResponseModeFragment: + if isAuthenticationRequired { + gc.Redirect(http.StatusFound, loginURI) + } else { + gc.Redirect(http.StatusFound, redirectURI) + } + return + case constants.ResponseModeWebMessage: + gc.HTML(httpStatusCode, authorizeWebMessageTemplate, gin.H{ + "target_origin": redirectURI, + "authorization_response": data, + }) + return + case constants.ResponseModeFormPost: + gc.HTML(httpStatusCode, authorizeFormPostTemplate, gin.H{ + "target_origin": redirectURI, + "authorization_response": data, + }) + return + } +} diff --git a/server/resolvers/forgot_password.go b/server/resolvers/forgot_password.go index c04bf1c..5f58ef3 100644 --- a/server/resolvers/forgot_password.go +++ b/server/resolvers/forgot_password.go @@ -85,7 +85,7 @@ func ForgotPasswordResolver(ctx context.Context, params model.ForgotPasswordInpu return res, err } - // exec it as go routine so that we can reduce the api latency + // execute it as go routine so that we can reduce the api latency go email.SendEmail([]string{params.Email}, constants.VerificationTypeForgotPassword, map[string]interface{}{ "user": user.ToMap(), "organization": utils.GetOrganization(), diff --git a/templates/authorize_form_post.tmpl b/templates/authorize_form_post.tmpl new file mode 100644 index 0000000..b3c94bf --- /dev/null +++ b/templates/authorize_form_post.tmpl @@ -0,0 +1,13 @@ + + + + Authorization Response + + +
+ {{ range $key, $val := .authorization_response }} + + {{ end }} +
+ + diff --git a/templates/authorize.tmpl b/templates/authorize_web_message.tmpl similarity index 100% rename from templates/authorize.tmpl rename to templates/authorize_web_message.tmpl From 3cd99fe5f62b58e66b3bbcbd2be7236c37b10b18 Mon Sep 17 00:00:00 2001 From: Lakhan Samani Date: Sun, 16 Oct 2022 21:03:37 +0530 Subject: [PATCH 04/66] fix: open id config --- server/constants/oauth2.go | 2 ++ server/handlers/authorize.go | 36 ++++++++++++++++++++++---------- server/handlers/openid_config.go | 2 +- 3 files changed, 28 insertions(+), 12 deletions(-) diff --git a/server/constants/oauth2.go b/server/constants/oauth2.go index d3ff253..f3e0a67 100644 --- a/server/constants/oauth2.go +++ b/server/constants/oauth2.go @@ -14,4 +14,6 @@ const ( ResponseTypeCode = "code" // For the Implicit grant, use response_type=token to include an access token. ResponseTypeToken = "token" + // For the Implicit grant of id_token, use response_type=id_token to include an identifier token. + ResponseTypeIDToken = "id_token" ) diff --git a/server/handlers/authorize.go b/server/handlers/authorize.go index 9337ce9..ad26576 100644 --- a/server/handlers/authorize.go +++ b/server/handlers/authorize.go @@ -137,20 +137,34 @@ func AuthorizeHandler() gin.HandlerFunc { // in case, response type is code and user is already logged in send the code and state // and cookie session will already be rolled over and set - gc.HTML(http.StatusOK, authorizeWebMessageTemplate, gin.H{ - "target_origin": redirectURI, - "authorization_response": map[string]interface{}{ - "type": "authorization_response", - "response": map[string]string{ - "code": code, - "state": state, + if responseMode == constants.ResponseModeFormPost { + gc.HTML(http.StatusOK, authorizeFormPostTemplate, gin.H{ + "target_origin": redirectURI, + "authorization_response": map[string]interface{}{ + "type": "authorization_response", + "response": map[string]string{ + "code": code, + "state": state, + }, }, - }, - }) + }) + } else { + gc.HTML(http.StatusOK, authorizeWebMessageTemplate, gin.H{ + "target_origin": redirectURI, + "authorization_response": map[string]interface{}{ + "type": "authorization_response", + "response": map[string]string{ + "code": code, + "state": state, + }, + }, + }) + } + return } - if responseType == constants.ResponseTypeToken { + if responseType == constants.ResponseTypeToken || responseType == constants.ResponseTypeIDToken { // rollover the session for security authToken, err := token.CreateAuthToken(gc, user, claims.Roles, scope, claims.LoginMethod) if err != nil { @@ -222,7 +236,7 @@ func AuthorizeHandler() gin.HandlerFunc { } func validateAuthorizeRequest(responseType, responseMode, clientID, state, codeChallenge string) error { - if responseType != constants.ResponseTypeCode && responseType != constants.ResponseTypeToken { + if responseType != constants.ResponseTypeCode && responseType != constants.ResponseTypeToken && responseType != constants.ResponseTypeIDToken { return fmt.Errorf("invalid response type %s. 'code' & 'token' are valid response_type", responseMode) } diff --git a/server/handlers/openid_config.go b/server/handlers/openid_config.go index 781caf1..db3a52f 100644 --- a/server/handlers/openid_config.go +++ b/server/handlers/openid_config.go @@ -22,7 +22,7 @@ func OpenIDConfigurationHandler() gin.HandlerFunc { "jwks_uri": issuer + "/.well-known/jwks.json", "response_types_supported": []string{"code", "token", "id_token", "code token", "code id_token", "token id_token", "code token id_token"}, "scopes_supported": []string{"openid", "email", "profile", "email_verified", "given_name", "family_name", "nick_name", "picture"}, - "response_modes_supported": []string{"query", "fragment", "form_post"}, + "response_modes_supported": []string{"query", "fragment", "form_post", "web_message"}, "id_token_signing_alg_values_supported": []string{jwtType}, "claims_supported": []string{"aud", "exp", "iss", "iat", "sub", "given_name", "family_name", "middle_name", "nickname", "preferred_username", "picture", "email", "email_verified", "roles", "gender", "birthdate", "phone_number", "phone_number_verified"}, }) From 346c8e5a479eec9aae6d09bad7ca8ab2fec85058 Mon Sep 17 00:00:00 2001 From: Lakhan Samani Date: Sun, 16 Oct 2022 22:16:37 +0530 Subject: [PATCH 05/66] fix: handle response --- server/handlers/authorize.go | 65 +++++++++++++++++++++----------- server/handlers/openid_config.go | 2 +- 2 files changed, 44 insertions(+), 23 deletions(-) diff --git a/server/handlers/authorize.go b/server/handlers/authorize.go index ad26576..19f5101 100644 --- a/server/handlers/authorize.go +++ b/server/handlers/authorize.go @@ -137,30 +137,51 @@ func AuthorizeHandler() gin.HandlerFunc { // in case, response type is code and user is already logged in send the code and state // and cookie session will already be rolled over and set - if responseMode == constants.ResponseModeFormPost { - gc.HTML(http.StatusOK, authorizeFormPostTemplate, gin.H{ - "target_origin": redirectURI, - "authorization_response": map[string]interface{}{ - "type": "authorization_response", - "response": map[string]string{ - "code": code, - "state": state, - }, - }, - }) - } else { - gc.HTML(http.StatusOK, authorizeWebMessageTemplate, gin.H{ - "target_origin": redirectURI, - "authorization_response": map[string]interface{}{ - "type": "authorization_response", - "response": map[string]string{ - "code": code, - "state": state, - }, - }, - }) + // if responseMode == constants.ResponseModeFormPost { + // gc.HTML(http.StatusOK, authorizeFormPostTemplate, gin.H{ + // "target_origin": redirectURI, + // "authorization_response": map[string]interface{}{ + // "type": "authorization_response", + // "response": map[string]string{ + // "code": code, + // "state": state, + // }, + // }, + // }) + // } else { + // gc.HTML(http.StatusOK, authorizeWebMessageTemplate, gin.H{ + // "target_origin": redirectURI, + // "authorization_response": map[string]interface{}{ + // "type": "authorization_response", + // "response": map[string]string{ + // "code": code, + // "state": state, + // }, + // }, + // }) + // } + + params := "code=" + code + "&state=" + state + + if responseMode == constants.ResponseModeQuery { + if strings.Contains(redirectURI, "?") { + redirectURI = redirectURI + "&" + params + } else { + redirectURI = redirectURI + "?" + params + } + } else if responseMode == constants.ResponseModeFragment { + if strings.Contains(redirectURI, "#") { + redirectURI = redirectURI + "&" + params + } else { + redirectURI = redirectURI + "#" + params + } } + handleResponse(gc, responseMode, loginURL, redirectURI, map[string]interface{}{ + "code": code, + "state": state, + }, http.StatusOK) + return } diff --git a/server/handlers/openid_config.go b/server/handlers/openid_config.go index db3a52f..c2a95c4 100644 --- a/server/handlers/openid_config.go +++ b/server/handlers/openid_config.go @@ -20,7 +20,7 @@ func OpenIDConfigurationHandler() gin.HandlerFunc { "token_endpoint": issuer + "/token", "userinfo_endpoint": issuer + "/userinfo", "jwks_uri": issuer + "/.well-known/jwks.json", - "response_types_supported": []string{"code", "token", "id_token", "code token", "code id_token", "token id_token", "code token id_token"}, + "response_types_supported": []string{"code", "token", "id_token"}, "scopes_supported": []string{"openid", "email", "profile", "email_verified", "given_name", "family_name", "nick_name", "picture"}, "response_modes_supported": []string{"query", "fragment", "form_post", "web_message"}, "id_token_signing_alg_values_supported": []string{jwtType}, From 9a411e673c2a9be931b66040c96ef165a6352cbe Mon Sep 17 00:00:00 2001 From: Lakhan Samani Date: Tue, 18 Oct 2022 21:08:53 +0530 Subject: [PATCH 06/66] fix: reponse --- server/handlers/authorize.go | 100 +++++++++++++++++------------------ 1 file changed, 50 insertions(+), 50 deletions(-) diff --git a/server/handlers/authorize.go b/server/handlers/authorize.go index 19f5101..d93847d 100644 --- a/server/handlers/authorize.go +++ b/server/handlers/authorize.go @@ -68,6 +68,15 @@ func AuthorizeHandler() gin.HandlerFunc { return } + log := log.WithFields(log.Fields{ + "response_mode": responseMode, + "response_type": responseType, + "state": state, + "code_challenge": codeChallenge, + "scope": scope, + "redirect_uri": redirectURI, + }) + // used for response mode query or fragment loginState := "state=" + state + "&scope=" + strings.Join(scope, " ") + "&redirect_uri=" + redirectURI loginURL := "/app?" + loginState @@ -76,8 +85,11 @@ func AuthorizeHandler() gin.HandlerFunc { } loginError := map[string]interface{}{ - "error": "login_required", - "error_description": "Login is required", + "type": "authorization_response", + "response": map[string]string{ + "error": "login_required", + "error_description": "Login is required", + }, } sessionToken, err := cookie.GetSession(gc) @@ -99,8 +111,11 @@ func AuthorizeHandler() gin.HandlerFunc { if err != nil { log.Debug("GetUserByID failed: ", err) handleResponse(gc, responseMode, loginURL, redirectURI, map[string]interface{}{ - "error": "signup_required", - "error_description": "Sign up required", + "type": "authorization_response", + "response": map[string]string{ + "error": "signup_required", + "error_description": "Sign up required", + }, }, http.StatusOK) return } @@ -137,50 +152,37 @@ func AuthorizeHandler() gin.HandlerFunc { // in case, response type is code and user is already logged in send the code and state // and cookie session will already be rolled over and set - // if responseMode == constants.ResponseModeFormPost { - // gc.HTML(http.StatusOK, authorizeFormPostTemplate, gin.H{ - // "target_origin": redirectURI, - // "authorization_response": map[string]interface{}{ - // "type": "authorization_response", - // "response": map[string]string{ - // "code": code, - // "state": state, - // }, - // }, - // }) - // } else { - // gc.HTML(http.StatusOK, authorizeWebMessageTemplate, gin.H{ - // "target_origin": redirectURI, - // "authorization_response": map[string]interface{}{ - // "type": "authorization_response", - // "response": map[string]string{ - // "code": code, - // "state": state, - // }, - // }, - // }) + gc.HTML(http.StatusOK, authorizeWebMessageTemplate, gin.H{ + "target_origin": redirectURI, + "authorization_response": map[string]interface{}{ + "type": "authorization_response", + "response": map[string]string{ + "code": code, + "state": state, + }, + }, + }) + + // params := "code=" + code + "&state=" + state + + // if responseMode == constants.ResponseModeQuery { + // if strings.Contains(redirectURI, "?") { + // redirectURI = redirectURI + "&" + params + // } else { + // redirectURI = redirectURI + "?" + params + // } + // } else if responseMode == constants.ResponseModeFragment { + // if strings.Contains(redirectURI, "#") { + // redirectURI = redirectURI + "&" + params + // } else { + // redirectURI = redirectURI + "#" + params + // } // } - params := "code=" + code + "&state=" + state - - if responseMode == constants.ResponseModeQuery { - if strings.Contains(redirectURI, "?") { - redirectURI = redirectURI + "&" + params - } else { - redirectURI = redirectURI + "?" + params - } - } else if responseMode == constants.ResponseModeFragment { - if strings.Contains(redirectURI, "#") { - redirectURI = redirectURI + "&" + params - } else { - redirectURI = redirectURI + "#" + params - } - } - - handleResponse(gc, responseMode, loginURL, redirectURI, map[string]interface{}{ - "code": code, - "state": state, - }, http.StatusOK) + // handleResponse(gc, responseMode, loginURL, redirectURI, map[string]interface{}{ + // "code": code, + // "state": state, + // }, http.StatusOK) return } @@ -282,10 +284,8 @@ func validateAuthorizeRequest(responseType, responseMode, clientID, state, codeC func handleResponse(gc *gin.Context, responseMode, loginURI, redirectURI string, data map[string]interface{}, httpStatusCode int) { isAuthenticationRequired := false - if val, ok := data["error"]; ok { - if val == "login_required" || val == "signup_required" { - isAuthenticationRequired = true - } + if _, ok := data["error"]; ok { + isAuthenticationRequired = true } switch responseMode { From 8e655bcb5bc9cfb017076d83717599d2b9975390 Mon Sep 17 00:00:00 2001 From: Lakhan Samani Date: Tue, 18 Oct 2022 21:29:09 +0530 Subject: [PATCH 07/66] fix: authorize response --- server/handlers/authorize.go | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/server/handlers/authorize.go b/server/handlers/authorize.go index d93847d..e2e74ab 100644 --- a/server/handlers/authorize.go +++ b/server/handlers/authorize.go @@ -152,16 +152,16 @@ func AuthorizeHandler() gin.HandlerFunc { // in case, response type is code and user is already logged in send the code and state // and cookie session will already be rolled over and set - gc.HTML(http.StatusOK, authorizeWebMessageTemplate, gin.H{ - "target_origin": redirectURI, - "authorization_response": map[string]interface{}{ - "type": "authorization_response", - "response": map[string]string{ - "code": code, - "state": state, - }, - }, - }) + // gc.HTML(http.StatusOK, authorizeWebMessageTemplate, gin.H{ + // "target_origin": redirectURI, + // "authorization_response": map[string]interface{}{ + // "type": "authorization_response", + // "response": map[string]string{ + // "code": code, + // "state": state, + // }, + // }, + // }) // params := "code=" + code + "&state=" + state @@ -179,10 +179,10 @@ func AuthorizeHandler() gin.HandlerFunc { // } // } - // handleResponse(gc, responseMode, loginURL, redirectURI, map[string]interface{}{ - // "code": code, - // "state": state, - // }, http.StatusOK) + handleResponse(gc, responseMode, loginURL, redirectURI, map[string]interface{}{ + "code": code, + "state": state, + }, http.StatusOK) return } From cddfe1e0887566c7a8323f1f6ce573d267f9a00c Mon Sep 17 00:00:00 2001 From: Lakhan Samani Date: Tue, 18 Oct 2022 21:46:37 +0530 Subject: [PATCH 08/66] fix: response --- server/handlers/authorize.go | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/server/handlers/authorize.go b/server/handlers/authorize.go index e2e74ab..2d95458 100644 --- a/server/handlers/authorize.go +++ b/server/handlers/authorize.go @@ -180,8 +180,11 @@ func AuthorizeHandler() gin.HandlerFunc { // } handleResponse(gc, responseMode, loginURL, redirectURI, map[string]interface{}{ - "code": code, - "state": state, + "type": "authorization_response", + "response": map[string]string{ + "code": code, + "state": state, + }, }, http.StatusOK) return From 253128ca0c130ac74c2d51ec0c0772069fc11371 Mon Sep 17 00:00:00 2001 From: Lakhan Samani Date: Tue, 18 Oct 2022 22:00:54 +0530 Subject: [PATCH 09/66] fix: query params for code response --- server/handlers/authorize.go | 29 ++++++++++++++--------------- 1 file changed, 14 insertions(+), 15 deletions(-) diff --git a/server/handlers/authorize.go b/server/handlers/authorize.go index 2d95458..805912d 100644 --- a/server/handlers/authorize.go +++ b/server/handlers/authorize.go @@ -163,21 +163,20 @@ func AuthorizeHandler() gin.HandlerFunc { // }, // }) - // params := "code=" + code + "&state=" + state - - // if responseMode == constants.ResponseModeQuery { - // if strings.Contains(redirectURI, "?") { - // redirectURI = redirectURI + "&" + params - // } else { - // redirectURI = redirectURI + "?" + params - // } - // } else if responseMode == constants.ResponseModeFragment { - // if strings.Contains(redirectURI, "#") { - // redirectURI = redirectURI + "&" + params - // } else { - // redirectURI = redirectURI + "#" + params - // } - // } + params := "code=" + code + "&state=" + state + if responseMode == constants.ResponseModeQuery { + if strings.Contains(redirectURI, "?") { + redirectURI = redirectURI + "&" + params + } else { + redirectURI = redirectURI + "?" + params + } + } else if responseMode == constants.ResponseModeFragment { + if strings.Contains(redirectURI, "#") { + redirectURI = redirectURI + "&" + params + } else { + redirectURI = redirectURI + "#" + params + } + } handleResponse(gc, responseMode, loginURL, redirectURI, map[string]interface{}{ "type": "authorization_response", From eaa10ec5bc0b6d071fcdd16c09fc313b334b8a23 Mon Sep 17 00:00:00 2001 From: Lakhan Samani Date: Tue, 18 Oct 2022 22:34:57 +0530 Subject: [PATCH 10/66] fix: error detection --- server/handlers/authorize.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/server/handlers/authorize.go b/server/handlers/authorize.go index 805912d..a550a06 100644 --- a/server/handlers/authorize.go +++ b/server/handlers/authorize.go @@ -106,6 +106,7 @@ func AuthorizeHandler() gin.HandlerFunc { handleResponse(gc, responseMode, loginURL, redirectURI, loginError, http.StatusOK) return } + userID := claims.Subject user, err := db.Provider.GetUserByID(gc, userID) if err != nil { @@ -286,7 +287,7 @@ func validateAuthorizeRequest(responseType, responseMode, clientID, state, codeC func handleResponse(gc *gin.Context, responseMode, loginURI, redirectURI string, data map[string]interface{}, httpStatusCode int) { isAuthenticationRequired := false - if _, ok := data["error"]; ok { + if _, ok := data["response"].(map[string]string)["error"]; ok { isAuthenticationRequired = true } From 7c2693b086f79fab7ef61249e07dcb88abf94471 Mon Sep 17 00:00:00 2001 From: Lakhan Samani Date: Tue, 18 Oct 2022 23:03:52 +0530 Subject: [PATCH 11/66] fix: form post template --- server/handlers/authorize.go | 10 +++++----- templates/authorize_form_post.tmpl | 4 ++-- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/server/handlers/authorize.go b/server/handlers/authorize.go index a550a06..0a8ee75 100644 --- a/server/handlers/authorize.go +++ b/server/handlers/authorize.go @@ -86,7 +86,7 @@ func AuthorizeHandler() gin.HandlerFunc { loginError := map[string]interface{}{ "type": "authorization_response", - "response": map[string]string{ + "response": map[string]interface{}{ "error": "login_required", "error_description": "Login is required", }, @@ -113,7 +113,7 @@ func AuthorizeHandler() gin.HandlerFunc { log.Debug("GetUserByID failed: ", err) handleResponse(gc, responseMode, loginURL, redirectURI, map[string]interface{}{ "type": "authorization_response", - "response": map[string]string{ + "response": map[string]interface{}{ "error": "signup_required", "error_description": "Sign up required", }, @@ -181,7 +181,7 @@ func AuthorizeHandler() gin.HandlerFunc { handleResponse(gc, responseMode, loginURL, redirectURI, map[string]interface{}{ "type": "authorization_response", - "response": map[string]string{ + "response": map[string]interface{}{ "code": code, "state": state, }, @@ -287,7 +287,7 @@ func validateAuthorizeRequest(responseType, responseMode, clientID, state, codeC func handleResponse(gc *gin.Context, responseMode, loginURI, redirectURI string, data map[string]interface{}, httpStatusCode int) { isAuthenticationRequired := false - if _, ok := data["response"].(map[string]string)["error"]; ok { + if _, ok := data["response"].(map[string]interface{})["error"]; ok { isAuthenticationRequired = true } @@ -308,7 +308,7 @@ func handleResponse(gc *gin.Context, responseMode, loginURI, redirectURI string, case constants.ResponseModeFormPost: gc.HTML(httpStatusCode, authorizeFormPostTemplate, gin.H{ "target_origin": redirectURI, - "authorization_response": data, + "authorization_response": data["response"], }) return } diff --git a/templates/authorize_form_post.tmpl b/templates/authorize_form_post.tmpl index b3c94bf..3098636 100644 --- a/templates/authorize_form_post.tmpl +++ b/templates/authorize_form_post.tmpl @@ -4,9 +4,9 @@ Authorization Response -
+ {{ range $key, $val := .authorization_response }} - + {{ end }}
From 252cd1fa2d25cf5b50907582dddb54afdacd1dcb Mon Sep 17 00:00:00 2001 From: Lakhan Samani Date: Tue, 18 Oct 2022 23:14:24 +0530 Subject: [PATCH 12/66] fix: make code_challenge optional --- server/handlers/authorize.go | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/server/handlers/authorize.go b/server/handlers/authorize.go index 0a8ee75..5ececd2 100644 --- a/server/handlers/authorize.go +++ b/server/handlers/authorize.go @@ -64,7 +64,7 @@ func AuthorizeHandler() gin.HandlerFunc { if err := validateAuthorizeRequest(responseType, responseMode, clientID, state, codeChallenge); err != nil { log.Debug("invalid authorization request: ", err) - gc.JSON(http.StatusBadRequest, gin.H{"error": err}) + gc.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) return } @@ -270,10 +270,6 @@ func validateAuthorizeRequest(responseType, responseMode, clientID, state, codeC return fmt.Errorf("invalid response mode %s. 'query', 'fragment', 'form_post' and 'web_message' are valid response_mode", responseMode) } - if responseType == constants.ResponseTypeCode && strings.TrimSpace(codeChallenge) == "" { - return fmt.Errorf("code_challenge is required for %s '%s'", responseType, constants.ResponseTypeCode) - } - if client, err := memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeyClientID); client != clientID || err != nil { return fmt.Errorf("invalid client_id %s", clientID) } From c716638725118ed0a3fa0a3d61855b44ea6caf5f Mon Sep 17 00:00:00 2001 From: Lakhan Samani Date: Tue, 18 Oct 2022 23:24:19 +0530 Subject: [PATCH 13/66] fix(server): revert the state & code_challenge validation --- server/handlers/authorize.go | 27 ++++++++++++++++++++++----- 1 file changed, 22 insertions(+), 5 deletions(-) diff --git a/server/handlers/authorize.go b/server/handlers/authorize.go index 5ececd2..ba745f5 100644 --- a/server/handlers/authorize.go +++ b/server/handlers/authorize.go @@ -80,10 +80,32 @@ func AuthorizeHandler() gin.HandlerFunc { // used for response mode query or fragment loginState := "state=" + state + "&scope=" + strings.Join(scope, " ") + "&redirect_uri=" + redirectURI loginURL := "/app?" + loginState + if responseMode == constants.ResponseModeFragment { loginURL = "/app#" + loginState } + if state == "" { + handleResponse(gc, responseMode, loginURL, redirectURI, map[string]interface{}{ + "type": "authorization_response", + "response": map[string]interface{}{ + "error": "state_required", + "error_description": "state is required", + }, + }, http.StatusOK) + return + } + + if responseType == constants.ResponseTypeCode && codeChallenge == "" { + handleResponse(gc, responseMode, loginURL, redirectURI, map[string]interface{}{ + "type": "authorization_response", + "response": map[string]interface{}{ + "error": "code_challenge_required", + "error_description": "code challenge is required", + }, + }, http.StatusOK) + } + loginError := map[string]interface{}{ "type": "authorization_response", "response": map[string]interface{}{ @@ -91,7 +113,6 @@ func AuthorizeHandler() gin.HandlerFunc { "error_description": "Login is required", }, } - sessionToken, err := cookie.GetSession(gc) if err != nil { log.Debug("GetSession failed: ", err) @@ -274,10 +295,6 @@ func validateAuthorizeRequest(responseType, responseMode, clientID, state, codeC return fmt.Errorf("invalid client_id %s", clientID) } - if strings.TrimSpace(state) == "" { - return fmt.Errorf("state is required") - } - return nil } From 2b52932e986ce5f57a077609797eb63eba4b1699 Mon Sep 17 00:00:00 2001 From: Lakhan Samani Date: Wed, 19 Oct 2022 09:03:00 +0530 Subject: [PATCH 14/66] fix: add code to other response methods --- server/handlers/authorize.go | 30 ++++++++++++++++-------------- 1 file changed, 16 insertions(+), 14 deletions(-) diff --git a/server/handlers/authorize.go b/server/handlers/authorize.go index ba745f5..1b3d51c 100644 --- a/server/handlers/authorize.go +++ b/server/handlers/authorize.go @@ -147,17 +147,24 @@ func AuthorizeHandler() gin.HandlerFunc { sessionKey = claims.LoginMethod + ":" + user.ID } + nonce := uuid.New().String() + newSessionTokenData, newSessionToken, err := token.CreateSessionToken(user, nonce, claims.Roles, scope, claims.LoginMethod) + if err != nil { + log.Debug("CreateSessionToken failed: ", err) + handleResponse(gc, responseMode, loginURL, redirectURI, loginError, http.StatusOK) + return + } + + code := uuid.New().String() + if err := memorystore.Provider.SetState(codeChallenge, code+"@"+newSessionToken); err != nil { + log.Debug("SetState failed: ", err) + handleResponse(gc, responseMode, loginURL, redirectURI, loginError, http.StatusOK) + return + } + // rollover the session for security go memorystore.Provider.DeleteUserSession(sessionKey, claims.Nonce) if responseType == constants.ResponseTypeCode { - nonce := uuid.New().String() - newSessionTokenData, newSessionToken, err := token.CreateSessionToken(user, nonce, claims.Roles, scope, claims.LoginMethod) - if err != nil { - log.Debug("CreateSessionToken failed: ", err) - handleResponse(gc, responseMode, loginURL, redirectURI, loginError, http.StatusOK) - return - } - if err := memorystore.Provider.SetUserSession(sessionKey, constants.TokenTypeSessionToken+"_"+newSessionTokenData.Nonce, newSessionToken); err != nil { log.Debug("SetUserSession failed: ", err) handleResponse(gc, responseMode, loginURL, redirectURI, loginError, http.StatusOK) @@ -165,12 +172,6 @@ func AuthorizeHandler() gin.HandlerFunc { } cookie.SetSession(gc, newSessionToken) - code := uuid.New().String() - if err := memorystore.Provider.SetState(codeChallenge, code+"@"+newSessionToken); err != nil { - log.Debug("SetState failed: ", err) - handleResponse(gc, responseMode, loginURL, redirectURI, loginError, http.StatusOK) - return - } // in case, response type is code and user is already logged in send the code and state // and cookie session will already be rolled over and set @@ -249,6 +250,7 @@ func AuthorizeHandler() gin.HandlerFunc { "scope": scope, "token_type": "Bearer", "expires_in": expiresIn, + "code": code, } if authToken.RefreshToken != nil { From 7ff3b3018ac4d041142469ba5c7d5b1bd63eaa59 Mon Sep 17 00:00:00 2001 From: Lakhan Samani Date: Wed, 19 Oct 2022 11:29:49 +0530 Subject: [PATCH 15/66] fix: add code to query params --- server/handlers/authorize.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server/handlers/authorize.go b/server/handlers/authorize.go index 1b3d51c..53c357f 100644 --- a/server/handlers/authorize.go +++ b/server/handlers/authorize.go @@ -241,7 +241,7 @@ func AuthorizeHandler() gin.HandlerFunc { } // used of query mode - params := "access_token=" + authToken.AccessToken.Token + "&token_type=bearer&expires_in=" + strconv.FormatInt(expiresIn, 10) + "&state=" + state + "&id_token=" + authToken.IDToken.Token + params := "access_token=" + authToken.AccessToken.Token + "&token_type=bearer&expires_in=" + strconv.FormatInt(expiresIn, 10) + "&state=" + state + "&id_token=" + authToken.IDToken.Token + "&code=" + code res := map[string]interface{}{ "access_token": authToken.AccessToken.Token, From cc23784df884790fc4b8c8ceefbb8f2593030afa Mon Sep 17 00:00:00 2001 From: Lakhan Samani Date: Wed, 19 Oct 2022 12:01:34 +0530 Subject: [PATCH 16/66] fix: add code to login query params --- server/handlers/authorize.go | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/server/handlers/authorize.go b/server/handlers/authorize.go index 53c357f..d9cc5a5 100644 --- a/server/handlers/authorize.go +++ b/server/handlers/authorize.go @@ -77,8 +77,11 @@ func AuthorizeHandler() gin.HandlerFunc { "redirect_uri": redirectURI, }) + code := uuid.New().String() + memorystore.Provider.SetState(codeChallenge, code) + // used for response mode query or fragment - loginState := "state=" + state + "&scope=" + strings.Join(scope, " ") + "&redirect_uri=" + redirectURI + loginState := "state=" + state + "&scope=" + strings.Join(scope, " ") + "&redirect_uri=" + redirectURI + "&code=" + code loginURL := "/app?" + loginState if responseMode == constants.ResponseModeFragment { @@ -155,7 +158,6 @@ func AuthorizeHandler() gin.HandlerFunc { return } - code := uuid.New().String() if err := memorystore.Provider.SetState(codeChallenge, code+"@"+newSessionToken); err != nil { log.Debug("SetState failed: ", err) handleResponse(gc, responseMode, loginURL, redirectURI, loginError, http.StatusOK) From 89f08b6d317b6284d6b49cbd96c619bb6adeb628 Mon Sep 17 00:00:00 2001 From: Lakhan Samani Date: Wed, 19 Oct 2022 12:20:22 +0530 Subject: [PATCH 17/66] fix: redirect from app --- app/src/Root.tsx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/app/src/Root.tsx b/app/src/Root.tsx index 88cec21..189f261 100644 --- a/app/src/Root.tsx +++ b/app/src/Root.tsx @@ -38,6 +38,7 @@ export default function Root({ const scope = searchParams.get('scope') ? searchParams.get('scope')?.toString().split(' ') : ['openid', 'profile', 'email']; + const code = searchParams.get('code') || createRandomString() const urlProps: Record = { state, @@ -57,7 +58,7 @@ export default function Root({ useEffect(() => { if (token) { let redirectURL = config.redirectURL || '/app'; - let params = `access_token=${token.access_token}&id_token=${token.id_token}&expires_in=${token.expires_in}&state=${globalState.state}`; + let params = `access_token=${token.access_token}&id_token=${token.id_token}&expires_in=${token.expires_in}&state=${globalState.state}&code=`+code; if (token.refresh_token) { params += `&refresh_token=${token.refresh_token}`; } From a916b8c32cbd3185decb68785b0eb58e7beddc12 Mon Sep 17 00:00:00 2001 From: Lakhan Samani Date: Wed, 19 Oct 2022 19:04:15 +0530 Subject: [PATCH 18/66] fix: add nonce --- app/src/Root.tsx | 11 ++++++++++- server/handlers/authorize.go | 9 +++++---- 2 files changed, 15 insertions(+), 5 deletions(-) diff --git a/app/src/Root.tsx b/app/src/Root.tsx index 189f261..b3fee57 100644 --- a/app/src/Root.tsx +++ b/app/src/Root.tsx @@ -38,7 +38,8 @@ export default function Root({ const scope = searchParams.get('scope') ? searchParams.get('scope')?.toString().split(' ') : ['openid', 'profile', 'email']; - const code = searchParams.get('code') || createRandomString() + const code = searchParams.get('code') || '' + const nonce = searchParams.get('nonce') || '' const urlProps: Record = { state, @@ -59,9 +60,17 @@ export default function Root({ if (token) { let redirectURL = config.redirectURL || '/app'; let params = `access_token=${token.access_token}&id_token=${token.id_token}&expires_in=${token.expires_in}&state=${globalState.state}&code=`+code; + + if (code !== '') { + params += `&code=${code}` + } + if (nonce !== '') { + params += `&nonce=${nonce}` + } if (token.refresh_token) { params += `&refresh_token=${token.refresh_token}`; } + const url = new URL(redirectURL); if (redirectURL.includes('?')) { redirectURL = `${redirectURL}&${params}`; diff --git a/server/handlers/authorize.go b/server/handlers/authorize.go index d9cc5a5..1ffcabf 100644 --- a/server/handlers/authorize.go +++ b/server/handlers/authorize.go @@ -78,10 +78,11 @@ func AuthorizeHandler() gin.HandlerFunc { }) code := uuid.New().String() + nonce := uuid.New().String() memorystore.Provider.SetState(codeChallenge, code) // used for response mode query or fragment - loginState := "state=" + state + "&scope=" + strings.Join(scope, " ") + "&redirect_uri=" + redirectURI + "&code=" + code + loginState := "state=" + state + "&scope=" + strings.Join(scope, " ") + "&redirect_uri=" + redirectURI + "&code=" + code + "&nonce=" + nonce loginURL := "/app?" + loginState if responseMode == constants.ResponseModeFragment { @@ -150,7 +151,6 @@ func AuthorizeHandler() gin.HandlerFunc { sessionKey = claims.LoginMethod + ":" + user.ID } - nonce := uuid.New().String() newSessionTokenData, newSessionToken, err := token.CreateSessionToken(user, nonce, claims.Roles, scope, claims.LoginMethod) if err != nil { log.Debug("CreateSessionToken failed: ", err) @@ -188,7 +188,7 @@ func AuthorizeHandler() gin.HandlerFunc { // }, // }) - params := "code=" + code + "&state=" + state + params := "code=" + code + "&state=" + state + "&nonce=" + nonce if responseMode == constants.ResponseModeQuery { if strings.Contains(redirectURI, "?") { redirectURI = redirectURI + "&" + params @@ -243,7 +243,7 @@ func AuthorizeHandler() gin.HandlerFunc { } // used of query mode - params := "access_token=" + authToken.AccessToken.Token + "&token_type=bearer&expires_in=" + strconv.FormatInt(expiresIn, 10) + "&state=" + state + "&id_token=" + authToken.IDToken.Token + "&code=" + code + params := "access_token=" + authToken.AccessToken.Token + "&token_type=bearer&expires_in=" + strconv.FormatInt(expiresIn, 10) + "&state=" + state + "&id_token=" + authToken.IDToken.Token + "&code=" + code + "&nonce=" + nonce res := map[string]interface{}{ "access_token": authToken.AccessToken.Token, @@ -253,6 +253,7 @@ func AuthorizeHandler() gin.HandlerFunc { "token_type": "Bearer", "expires_in": expiresIn, "code": code, + "nonce": nonce, } if authToken.RefreshToken != nil { From de4381261e7b00eba7b437df1a914cdcc68b834a Mon Sep 17 00:00:00 2001 From: Lakhan Samani Date: Wed, 19 Oct 2022 23:17:13 +0530 Subject: [PATCH 19/66] fix: add nonce to supported claims --- app/src/Root.tsx | 7 ++----- server/handlers/authorize.go | 5 ++--- server/handlers/openid_config.go | 2 +- server/handlers/token.go | 2 +- 4 files changed, 6 insertions(+), 10 deletions(-) diff --git a/app/src/Root.tsx b/app/src/Root.tsx index b3fee57..cf1041e 100644 --- a/app/src/Root.tsx +++ b/app/src/Root.tsx @@ -39,7 +39,6 @@ export default function Root({ ? searchParams.get('scope')?.toString().split(' ') : ['openid', 'profile', 'email']; const code = searchParams.get('code') || '' - const nonce = searchParams.get('nonce') || '' const urlProps: Record = { state, @@ -59,14 +58,12 @@ export default function Root({ useEffect(() => { if (token) { let redirectURL = config.redirectURL || '/app'; - let params = `access_token=${token.access_token}&id_token=${token.id_token}&expires_in=${token.expires_in}&state=${globalState.state}&code=`+code; + let params = `access_token=${token.access_token}&id_token=${token.id_token}&expires_in=${token.expires_in}&state=${globalState.state}`; if (code !== '') { params += `&code=${code}` } - if (nonce !== '') { - params += `&nonce=${nonce}` - } + if (token.refresh_token) { params += `&refresh_token=${token.refresh_token}`; } diff --git a/server/handlers/authorize.go b/server/handlers/authorize.go index 1ffcabf..397aac6 100644 --- a/server/handlers/authorize.go +++ b/server/handlers/authorize.go @@ -188,7 +188,7 @@ func AuthorizeHandler() gin.HandlerFunc { // }, // }) - params := "code=" + code + "&state=" + state + "&nonce=" + nonce + params := "code=" + code + "&state=" + state if responseMode == constants.ResponseModeQuery { if strings.Contains(redirectURI, "?") { redirectURI = redirectURI + "&" + params @@ -243,7 +243,7 @@ func AuthorizeHandler() gin.HandlerFunc { } // used of query mode - params := "access_token=" + authToken.AccessToken.Token + "&token_type=bearer&expires_in=" + strconv.FormatInt(expiresIn, 10) + "&state=" + state + "&id_token=" + authToken.IDToken.Token + "&code=" + code + "&nonce=" + nonce + params := "access_token=" + authToken.AccessToken.Token + "&token_type=bearer&expires_in=" + strconv.FormatInt(expiresIn, 10) + "&state=" + state + "&id_token=" + authToken.IDToken.Token + "&code=" + code res := map[string]interface{}{ "access_token": authToken.AccessToken.Token, @@ -253,7 +253,6 @@ func AuthorizeHandler() gin.HandlerFunc { "token_type": "Bearer", "expires_in": expiresIn, "code": code, - "nonce": nonce, } if authToken.RefreshToken != nil { diff --git a/server/handlers/openid_config.go b/server/handlers/openid_config.go index c2a95c4..8138d42 100644 --- a/server/handlers/openid_config.go +++ b/server/handlers/openid_config.go @@ -24,7 +24,7 @@ func OpenIDConfigurationHandler() gin.HandlerFunc { "scopes_supported": []string{"openid", "email", "profile", "email_verified", "given_name", "family_name", "nick_name", "picture"}, "response_modes_supported": []string{"query", "fragment", "form_post", "web_message"}, "id_token_signing_alg_values_supported": []string{jwtType}, - "claims_supported": []string{"aud", "exp", "iss", "iat", "sub", "given_name", "family_name", "middle_name", "nickname", "preferred_username", "picture", "email", "email_verified", "roles", "gender", "birthdate", "phone_number", "phone_number_verified"}, + "claims_supported": []string{"aud", "exp", "iss", "iat", "sub", "given_name", "family_name", "middle_name", "nickname", "preferred_username", "picture", "email", "email_verified", "roles", "gender", "birthdate", "phone_number", "phone_number_verified", "nonce"}, }) } } diff --git a/server/handlers/token.go b/server/handlers/token.go index da72969..97bce00 100644 --- a/server/handlers/token.go +++ b/server/handlers/token.go @@ -22,7 +22,7 @@ import ( func TokenHandler() gin.HandlerFunc { return func(gc *gin.Context) { var reqBody map[string]string - if err := gc.BindJSON(&reqBody); err != nil { + if err := gc.Bind(&reqBody); err != nil { log.Debug("Error binding JSON: ", err) gc.JSON(http.StatusBadRequest, gin.H{ "error": "error_binding_json", From fedc3173fefa98344ab3d5c1ce70a75a39cfed3f Mon Sep 17 00:00:00 2001 From: Lakhan Samani Date: Wed, 19 Oct 2022 23:36:33 +0530 Subject: [PATCH 20/66] fix: get nonce from query request if possible --- server/handlers/authorize.go | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/server/handlers/authorize.go b/server/handlers/authorize.go index 397aac6..8dfcbc9 100644 --- a/server/handlers/authorize.go +++ b/server/handlers/authorize.go @@ -42,6 +42,7 @@ func AuthorizeHandler() gin.HandlerFunc { scopeString := strings.TrimSpace(gc.Query("scope")) clientID := strings.TrimSpace(gc.Query("client_id")) responseMode := strings.TrimSpace(gc.Query("response_mode")) + nonce := strings.TrimSpace(gc.Query("nonce")) var scope []string if scopeString == "" { @@ -78,11 +79,13 @@ func AuthorizeHandler() gin.HandlerFunc { }) code := uuid.New().String() - nonce := uuid.New().String() + if nonce == "" { + nonce = uuid.New().String() + } memorystore.Provider.SetState(codeChallenge, code) // used for response mode query or fragment - loginState := "state=" + state + "&scope=" + strings.Join(scope, " ") + "&redirect_uri=" + redirectURI + "&code=" + code + "&nonce=" + nonce + loginState := "state=" + state + "&scope=" + strings.Join(scope, " ") + "&redirect_uri=" + redirectURI + "&code=" + code loginURL := "/app?" + loginState if responseMode == constants.ResponseModeFragment { From 74b858ac24afc63400e879dfc865bc6b299cd757 Mon Sep 17 00:00:00 2001 From: Lakhan Samani Date: Wed, 19 Oct 2022 23:39:48 +0530 Subject: [PATCH 21/66] fix: binding --- server/handlers/token.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server/handlers/token.go b/server/handlers/token.go index 97bce00..da72969 100644 --- a/server/handlers/token.go +++ b/server/handlers/token.go @@ -22,7 +22,7 @@ import ( func TokenHandler() gin.HandlerFunc { return func(gc *gin.Context) { var reqBody map[string]string - if err := gc.Bind(&reqBody); err != nil { + if err := gc.BindJSON(&reqBody); err != nil { log.Debug("Error binding JSON: ", err) gc.JSON(http.StatusBadRequest, gin.H{ "error": "error_binding_json", From 2c867b0314929e573afca9224789e2cd7b1fc454 Mon Sep 17 00:00:00 2001 From: Lakhan Samani Date: Wed, 19 Oct 2022 23:41:08 +0530 Subject: [PATCH 22/66] fix: issuer token endpoint --- server/handlers/openid_config.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server/handlers/openid_config.go b/server/handlers/openid_config.go index 8138d42..8785437 100644 --- a/server/handlers/openid_config.go +++ b/server/handlers/openid_config.go @@ -17,7 +17,7 @@ func OpenIDConfigurationHandler() gin.HandlerFunc { c.JSON(200, gin.H{ "issuer": issuer, "authorization_endpoint": issuer + "/authorize", - "token_endpoint": issuer + "/token", + "token_endpoint": issuer + "/oauth/token", "userinfo_endpoint": issuer + "/userinfo", "jwks_uri": issuer + "/.well-known/jwks.json", "response_types_supported": []string{"code", "token", "id_token"}, From a68876a6f43edb86d47355aa1245aa005af62f97 Mon Sep 17 00:00:00 2001 From: Lakhan Samani Date: Wed, 19 Oct 2022 23:55:47 +0530 Subject: [PATCH 23/66] fix: comment --- server/parsers/url.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server/parsers/url.go b/server/parsers/url.go index c98ad54..48c2c79 100644 --- a/server/parsers/url.go +++ b/server/parsers/url.go @@ -91,7 +91,7 @@ func GetDomainName(uri string) string { return host } -// GetAppURL to get /app/ url if not configured by user +// GetAppURL to get /app url if not configured by user func GetAppURL(gc *gin.Context) string { envAppURL, err := memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeyAppURL) if envAppURL == "" || err != nil { From b2e0a3371f97d3677703ab1773e4daa9f3fe38d4 Mon Sep 17 00:00:00 2001 From: Lakhan Samani Date: Thu, 20 Oct 2022 00:14:06 +0530 Subject: [PATCH 24/66] fix: revert nonce --- .github/workflows/release.yaml | 10 +++++----- app/src/Root.tsx | 5 +++++ server/handlers/authorize.go | 7 ++++--- 3 files changed, 14 insertions(+), 8 deletions(-) diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml index e30808b..2fd77a8 100644 --- a/.github/workflows/release.yaml +++ b/.github/workflows/release.yaml @@ -2,17 +2,17 @@ on: workflow_dispatch: inputs: logLevel: - description: 'Log level' + description: 'Log level' required: true - default: 'warning' + default: 'warning' type: choice options: - info - warning - - debug + - debug tags: description: 'Tags' - required: false + required: false type: boolean release: types: [created] @@ -28,7 +28,7 @@ jobs: node-version: '16' - uses: actions/setup-go@v2 with: - go-version: '^1.17.3' + go-version: '^1.19.1' - name: Install dependencies run: | sudo apt-get install build-essential wget zip gcc-mingw-w64 && \ diff --git a/app/src/Root.tsx b/app/src/Root.tsx index cf1041e..522e4ca 100644 --- a/app/src/Root.tsx +++ b/app/src/Root.tsx @@ -39,6 +39,7 @@ export default function Root({ ? searchParams.get('scope')?.toString().split(' ') : ['openid', 'profile', 'email']; const code = searchParams.get('code') || '' + const nonce = searchParams.get('nonce') || '' const urlProps: Record = { state, @@ -64,6 +65,10 @@ export default function Root({ params += `&code=${code}` } + if (nonce !== '') { + params += `&nonce=${nonce}` + } + if (token.refresh_token) { params += `&refresh_token=${token.refresh_token}`; } diff --git a/server/handlers/authorize.go b/server/handlers/authorize.go index 8dfcbc9..c99cba8 100644 --- a/server/handlers/authorize.go +++ b/server/handlers/authorize.go @@ -85,7 +85,7 @@ func AuthorizeHandler() gin.HandlerFunc { memorystore.Provider.SetState(codeChallenge, code) // used for response mode query or fragment - loginState := "state=" + state + "&scope=" + strings.Join(scope, " ") + "&redirect_uri=" + redirectURI + "&code=" + code + loginState := "state=" + state + "&scope=" + strings.Join(scope, " ") + "&redirect_uri=" + redirectURI + "&code=" + code + "&nonce=" + nonce loginURL := "/app?" + loginState if responseMode == constants.ResponseModeFragment { @@ -191,7 +191,7 @@ func AuthorizeHandler() gin.HandlerFunc { // }, // }) - params := "code=" + code + "&state=" + state + params := "code=" + code + "&state=" + state + "&nonce=" + nonce if responseMode == constants.ResponseModeQuery { if strings.Contains(redirectURI, "?") { redirectURI = redirectURI + "&" + params @@ -246,7 +246,7 @@ func AuthorizeHandler() gin.HandlerFunc { } // used of query mode - params := "access_token=" + authToken.AccessToken.Token + "&token_type=bearer&expires_in=" + strconv.FormatInt(expiresIn, 10) + "&state=" + state + "&id_token=" + authToken.IDToken.Token + "&code=" + code + params := "access_token=" + authToken.AccessToken.Token + "&token_type=bearer&expires_in=" + strconv.FormatInt(expiresIn, 10) + "&state=" + state + "&id_token=" + authToken.IDToken.Token + "&code=" + code + "&nonce=" + nonce res := map[string]interface{}{ "access_token": authToken.AccessToken.Token, @@ -256,6 +256,7 @@ func AuthorizeHandler() gin.HandlerFunc { "token_type": "Bearer", "expires_in": expiresIn, "code": code, + "nonce": nonce, } if authToken.RefreshToken != nil { From c6019e650b8e5f0c0fbb90d73c55d854338fbba7 Mon Sep 17 00:00:00 2001 From: Lakhan Samani Date: Thu, 20 Oct 2022 15:35:26 +0530 Subject: [PATCH 25/66] fix: add manual code generation --- server/handlers/authorize.go | 94 +++++++++++++++++++++----------- server/handlers/openid_config.go | 2 +- 2 files changed, 64 insertions(+), 32 deletions(-) diff --git a/server/handlers/authorize.go b/server/handlers/authorize.go index c99cba8..373e1ba 100644 --- a/server/handlers/authorize.go +++ b/server/handlers/authorize.go @@ -15,7 +15,9 @@ import ( "github.com/authorizerdev/authorizer/server/cookie" "github.com/authorizerdev/authorizer/server/db" "github.com/authorizerdev/authorizer/server/memorystore" + "github.com/authorizerdev/authorizer/server/parsers" "github.com/authorizerdev/authorizer/server/token" + "github.com/authorizerdev/authorizer/server/utils" ) // AuthorizeHandler is the handler for the /authorize route @@ -69,6 +71,11 @@ func AuthorizeHandler() gin.HandlerFunc { return } + code := uuid.New().String() + if nonce == "" { + nonce = uuid.New().String() + } + log := log.WithFields(log.Fields{ "response_mode": responseMode, "response_type": responseType, @@ -76,12 +83,10 @@ func AuthorizeHandler() gin.HandlerFunc { "code_challenge": codeChallenge, "scope": scope, "redirect_uri": redirectURI, + "nonce": nonce, + "code": code, }) - code := uuid.New().String() - if nonce == "" { - nonce = uuid.New().String() - } memorystore.Provider.SetState(codeChallenge, code) // used for response mode query or fragment @@ -154,22 +159,22 @@ func AuthorizeHandler() gin.HandlerFunc { sessionKey = claims.LoginMethod + ":" + user.ID } - newSessionTokenData, newSessionToken, err := token.CreateSessionToken(user, nonce, claims.Roles, scope, claims.LoginMethod) - if err != nil { - log.Debug("CreateSessionToken failed: ", err) - handleResponse(gc, responseMode, loginURL, redirectURI, loginError, http.StatusOK) - return - } - - if err := memorystore.Provider.SetState(codeChallenge, code+"@"+newSessionToken); err != nil { - log.Debug("SetState failed: ", err) - handleResponse(gc, responseMode, loginURL, redirectURI, loginError, http.StatusOK) - return - } - // rollover the session for security go memorystore.Provider.DeleteUserSession(sessionKey, claims.Nonce) if responseType == constants.ResponseTypeCode { + newSessionTokenData, newSessionToken, err := token.CreateSessionToken(user, nonce, claims.Roles, scope, claims.LoginMethod) + if err != nil { + log.Debug("CreateSessionToken failed: ", err) + handleResponse(gc, responseMode, loginURL, redirectURI, loginError, http.StatusOK) + return + } + + if err := memorystore.Provider.SetState(codeChallenge, code+"@"+newSessionToken); err != nil { + log.Debug("SetState failed: ", err) + handleResponse(gc, responseMode, loginURL, redirectURI, loginError, http.StatusOK) + return + } + if err := memorystore.Provider.SetUserSession(sessionKey, constants.TokenTypeSessionToken+"_"+newSessionTokenData.Nonce, newSessionToken); err != nil { log.Debug("SetUserSession failed: ", err) handleResponse(gc, responseMode, loginURL, redirectURI, loginError, http.StatusOK) @@ -218,39 +223,60 @@ func AuthorizeHandler() gin.HandlerFunc { } if responseType == constants.ResponseTypeToken || responseType == constants.ResponseTypeIDToken { - // rollover the session for security - authToken, err := token.CreateAuthToken(gc, user, claims.Roles, scope, claims.LoginMethod) + hostname := parsers.GetHost(gc) + nonce := uuid.New().String() + _, fingerPrintHash, err := token.CreateSessionToken(user, nonce, claims.Roles, scope, claims.LoginMethod) if err != nil { - log.Debug("CreateAuthToken failed: ", err) + log.Debug("CreateSessionToken failed: ", err) + handleResponse(gc, responseMode, loginURL, redirectURI, loginError, http.StatusOK) + return + } + accessToken, accessTokenExpiresAt, err := token.CreateAccessToken(user, claims.Roles, scope, hostname, nonce, claims.LoginMethod) + if err != nil { + log.Debug("CreateAccessToken failed: ", err) handleResponse(gc, responseMode, loginURL, redirectURI, loginError, http.StatusOK) return } - if err := memorystore.Provider.SetUserSession(sessionKey, constants.TokenTypeSessionToken+"_"+authToken.FingerPrint, authToken.FingerPrintHash); err != nil { + idToken, _, err := token.CreateIDToken(user, claims.Roles, hostname, nonce, claims.LoginMethod) + if err != nil { + log.Debug("CreateIDToken failed: ", err) + handleResponse(gc, responseMode, loginURL, redirectURI, loginError, http.StatusOK) + return + } + // rollover the session for security + // authToken, err := token.CreateAuthToken(gc, user, claims.Roles, scope, claims.LoginMethod) + // if err != nil { + // log.Debug("CreateAuthToken failed: ", err) + // handleResponse(gc, responseMode, loginURL, redirectURI, loginError, http.StatusOK) + // return + // } + + if err := memorystore.Provider.SetUserSession(sessionKey, constants.TokenTypeSessionToken+"_"+nonce, fingerPrintHash); err != nil { log.Debug("SetUserSession failed: ", err) handleResponse(gc, responseMode, loginURL, redirectURI, loginError, http.StatusOK) return } - if err := memorystore.Provider.SetUserSession(sessionKey, constants.TokenTypeAccessToken+"_"+authToken.FingerPrint, authToken.AccessToken.Token); err != nil { + if err := memorystore.Provider.SetUserSession(sessionKey, constants.TokenTypeAccessToken+"_"+nonce, accessToken); err != nil { log.Debug("SetUserSession failed: ", err) handleResponse(gc, responseMode, loginURL, redirectURI, loginError, http.StatusOK) return } - cookie.SetSession(gc, authToken.FingerPrintHash) + cookie.SetSession(gc, fingerPrintHash) - expiresIn := authToken.AccessToken.ExpiresAt - time.Now().Unix() + expiresIn := accessTokenExpiresAt - time.Now().Unix() if expiresIn <= 0 { expiresIn = 1 } // used of query mode - params := "access_token=" + authToken.AccessToken.Token + "&token_type=bearer&expires_in=" + strconv.FormatInt(expiresIn, 10) + "&state=" + state + "&id_token=" + authToken.IDToken.Token + "&code=" + code + "&nonce=" + nonce + params := "access_token=" + accessToken + "&token_type=bearer&expires_in=" + strconv.FormatInt(expiresIn, 10) + "&state=" + state + "&id_token=" + idToken + "&code=" + code + "&nonce=" + nonce res := map[string]interface{}{ - "access_token": authToken.AccessToken.Token, - "id_token": authToken.IDToken.Token, + "access_token": accessToken, + "id_token": idToken, "state": state, "scope": scope, "token_type": "Bearer", @@ -259,10 +285,16 @@ func AuthorizeHandler() gin.HandlerFunc { "nonce": nonce, } - if authToken.RefreshToken != nil { - res["refresh_token"] = authToken.RefreshToken.Token - params += "&refresh_token=" + authToken.RefreshToken.Token - memorystore.Provider.SetUserSession(sessionKey, constants.TokenTypeRefreshToken+"_"+authToken.FingerPrint, authToken.RefreshToken.Token) + if utils.StringSliceContains(scope, "offline_access") { + refreshToken, _, err := token.CreateRefreshToken(user, claims.Roles, scope, hostname, nonce, claims.LoginMethod) + if err != nil { + log.Debug("SetUserSession failed: ", err) + handleResponse(gc, responseMode, loginURL, redirectURI, loginError, http.StatusOK) + return + } + res["refresh_token"] = refreshToken + params += "&refresh_token=" + refreshToken + memorystore.Provider.SetUserSession(sessionKey, constants.TokenTypeRefreshToken+"_"+nonce, refreshToken) } if responseMode == constants.ResponseModeQuery { diff --git a/server/handlers/openid_config.go b/server/handlers/openid_config.go index 8785437..33ad090 100644 --- a/server/handlers/openid_config.go +++ b/server/handlers/openid_config.go @@ -24,7 +24,7 @@ func OpenIDConfigurationHandler() gin.HandlerFunc { "scopes_supported": []string{"openid", "email", "profile", "email_verified", "given_name", "family_name", "nick_name", "picture"}, "response_modes_supported": []string{"query", "fragment", "form_post", "web_message"}, "id_token_signing_alg_values_supported": []string{jwtType}, - "claims_supported": []string{"aud", "exp", "iss", "iat", "sub", "given_name", "family_name", "middle_name", "nickname", "preferred_username", "picture", "email", "email_verified", "roles", "gender", "birthdate", "phone_number", "phone_number_verified", "nonce"}, + "claims_supported": []string{"aud", "exp", "iss", "iat", "sub", "given_name", "family_name", "middle_name", "nickname", "preferred_username", "picture", "email", "email_verified", "roles", "role", "gender", "birthdate", "phone_number", "phone_number_verified", "nonce", "updated_at", "created_at", "revoked_timestamp", "login_method", "signup_methods", "token_type"}, }) } } From 274909b7c992c71ec4bd7789ae6c2319f5551a77 Mon Sep 17 00:00:00 2001 From: Lakhan Samani Date: Sun, 23 Oct 2022 21:08:08 +0530 Subject: [PATCH 26/66] feat: add nonce variable to create auth token --- server/handlers/authorize.go | 53 +++++++------------------- server/handlers/oauth_callback.go | 4 +- server/handlers/token.go | 4 +- server/handlers/verify_email.go | 5 ++- server/resolvers/login.go | 4 +- server/resolvers/session.go | 4 +- server/resolvers/signup.go | 4 +- server/resolvers/verify_email.go | 4 +- server/resolvers/verify_otp.go | 4 +- server/test/validate_jwt_token_test.go | 3 +- server/token/auth_token.go | 12 +++--- 11 files changed, 46 insertions(+), 55 deletions(-) diff --git a/server/handlers/authorize.go b/server/handlers/authorize.go index 373e1ba..f57c98d 100644 --- a/server/handlers/authorize.go +++ b/server/handlers/authorize.go @@ -5,7 +5,6 @@ import ( "net/http" "strconv" "strings" - "time" "github.com/gin-gonic/gin" "github.com/google/uuid" @@ -224,65 +223,39 @@ func AuthorizeHandler() gin.HandlerFunc { if responseType == constants.ResponseTypeToken || responseType == constants.ResponseTypeIDToken { hostname := parsers.GetHost(gc) - nonce := uuid.New().String() - _, fingerPrintHash, err := token.CreateSessionToken(user, nonce, claims.Roles, scope, claims.LoginMethod) - if err != nil { - log.Debug("CreateSessionToken failed: ", err) - handleResponse(gc, responseMode, loginURL, redirectURI, loginError, http.StatusOK) - return - } - accessToken, accessTokenExpiresAt, err := token.CreateAccessToken(user, claims.Roles, scope, hostname, nonce, claims.LoginMethod) - if err != nil { - log.Debug("CreateAccessToken failed: ", err) - handleResponse(gc, responseMode, loginURL, redirectURI, loginError, http.StatusOK) - return - } - - idToken, _, err := token.CreateIDToken(user, claims.Roles, hostname, nonce, claims.LoginMethod) - if err != nil { - log.Debug("CreateIDToken failed: ", err) - handleResponse(gc, responseMode, loginURL, redirectURI, loginError, http.StatusOK) - return - } // rollover the session for security - // authToken, err := token.CreateAuthToken(gc, user, claims.Roles, scope, claims.LoginMethod) - // if err != nil { - // log.Debug("CreateAuthToken failed: ", err) - // handleResponse(gc, responseMode, loginURL, redirectURI, loginError, http.StatusOK) - // return - // } + authToken, err := token.CreateAuthToken(gc, user, claims.Roles, scope, claims.LoginMethod, nonce) + if err != nil { + log.Debug("CreateAuthToken failed: ", err) + handleResponse(gc, responseMode, loginURL, redirectURI, loginError, http.StatusOK) + return + } - if err := memorystore.Provider.SetUserSession(sessionKey, constants.TokenTypeSessionToken+"_"+nonce, fingerPrintHash); err != nil { + if err := memorystore.Provider.SetUserSession(sessionKey, constants.TokenTypeSessionToken+"_"+nonce, authToken.FingerPrintHash); err != nil { log.Debug("SetUserSession failed: ", err) handleResponse(gc, responseMode, loginURL, redirectURI, loginError, http.StatusOK) return } - if err := memorystore.Provider.SetUserSession(sessionKey, constants.TokenTypeAccessToken+"_"+nonce, accessToken); err != nil { + if err := memorystore.Provider.SetUserSession(sessionKey, constants.TokenTypeAccessToken+"_"+nonce, authToken.FingerPrintHash); err != nil { log.Debug("SetUserSession failed: ", err) handleResponse(gc, responseMode, loginURL, redirectURI, loginError, http.StatusOK) return } - cookie.SetSession(gc, fingerPrintHash) - - expiresIn := accessTokenExpiresAt - time.Now().Unix() - if expiresIn <= 0 { - expiresIn = 1 - } + cookie.SetSession(gc, authToken.FingerPrintHash) // used of query mode - params := "access_token=" + accessToken + "&token_type=bearer&expires_in=" + strconv.FormatInt(expiresIn, 10) + "&state=" + state + "&id_token=" + idToken + "&code=" + code + "&nonce=" + nonce + params := "access_token=" + authToken.AccessToken.Token + "&token_type=bearer&expires_in=" + strconv.FormatInt(authToken.IDToken.ExpiresAt, 10) + "&state=" + state + "&id_token=" + authToken.IDToken.Token + "&code=" + code res := map[string]interface{}{ - "access_token": accessToken, - "id_token": idToken, + "access_token": authToken.AccessToken.Token, + "id_token": authToken.IDToken.Token, "state": state, "scope": scope, "token_type": "Bearer", - "expires_in": expiresIn, + "expires_in": authToken.AccessToken.ExpiresAt, "code": code, - "nonce": nonce, } if utils.StringSliceContains(scope, "offline_access") { diff --git a/server/handlers/oauth_callback.go b/server/handlers/oauth_callback.go index 02c284c..20e256f 100644 --- a/server/handlers/oauth_callback.go +++ b/server/handlers/oauth_callback.go @@ -13,6 +13,7 @@ import ( "github.com/coreos/go-oidc/v3/oidc" "github.com/gin-gonic/gin" + "github.com/google/uuid" log "github.com/sirupsen/logrus" "golang.org/x/oauth2" @@ -196,7 +197,8 @@ func OAuthCallbackHandler() gin.HandlerFunc { } } - authToken, err := token.CreateAuthToken(ctx, user, inputRoles, scopes, provider) + nonce := uuid.New().String() + authToken, err := token.CreateAuthToken(ctx, user, inputRoles, scopes, provider, nonce) if err != nil { log.Debug("Failed to create auth token: ", err) ctx.JSON(500, gin.H{"error": err.Error()}) diff --git a/server/handlers/token.go b/server/handlers/token.go index da72969..5240b30 100644 --- a/server/handlers/token.go +++ b/server/handlers/token.go @@ -8,6 +8,7 @@ import ( "time" "github.com/gin-gonic/gin" + "github.com/google/uuid" log "github.com/sirupsen/logrus" "github.com/authorizerdev/authorizer/server/constants" @@ -202,7 +203,8 @@ func TokenHandler() gin.HandlerFunc { return } - authToken, err := token.CreateAuthToken(gc, user, roles, scope, loginMethod) + nonce := uuid.New().String() + authToken, err := token.CreateAuthToken(gc, user, roles, scope, loginMethod, nonce) if err != nil { log.Debug("Error creating auth token: ", err) gc.JSON(http.StatusUnauthorized, gin.H{ diff --git a/server/handlers/verify_email.go b/server/handlers/verify_email.go index 10d4fad..c0f0283 100644 --- a/server/handlers/verify_email.go +++ b/server/handlers/verify_email.go @@ -7,6 +7,7 @@ import ( "time" "github.com/gin-gonic/gin" + "github.com/google/uuid" log "github.com/sirupsen/logrus" "github.com/authorizerdev/authorizer/server/constants" @@ -98,7 +99,9 @@ func VerifyEmailHandler() gin.HandlerFunc { if verificationRequest.Identifier == constants.VerificationTypeMagicLinkLogin { loginMethod = constants.AuthRecipeMethodMagicLinkLogin } - authToken, err := token.CreateAuthToken(c, user, roles, scope, loginMethod) + + nonce := uuid.New().String() + authToken, err := token.CreateAuthToken(c, user, roles, scope, loginMethod, nonce) if err != nil { log.Debug("Error creating auth token: ", err) errorRes["error_description"] = err.Error() diff --git a/server/resolvers/login.go b/server/resolvers/login.go index b597ada..7683932 100644 --- a/server/resolvers/login.go +++ b/server/resolvers/login.go @@ -6,6 +6,7 @@ import ( "strings" "time" + "github.com/google/uuid" log "github.com/sirupsen/logrus" "golang.org/x/crypto/bcrypt" @@ -140,7 +141,8 @@ func LoginResolver(ctx context.Context, params model.LoginInput) (*model.AuthRes }, nil } - authToken, err := token.CreateAuthToken(gc, user, roles, scope, constants.AuthRecipeMethodBasicAuth) + nonce := uuid.New().String() + authToken, err := token.CreateAuthToken(gc, user, roles, scope, constants.AuthRecipeMethodBasicAuth, nonce) if err != nil { log.Debug("Failed to create auth token", err) return res, err diff --git a/server/resolvers/session.go b/server/resolvers/session.go index dfa4e3d..7bc0e72 100644 --- a/server/resolvers/session.go +++ b/server/resolvers/session.go @@ -6,6 +6,7 @@ import ( "fmt" "time" + "github.com/google/uuid" log "github.com/sirupsen/logrus" "github.com/authorizerdev/authorizer/server/constants" @@ -70,7 +71,8 @@ func SessionResolver(ctx context.Context, params *model.SessionQueryInput) (*mod scope = params.Scope } - authToken, err := token.CreateAuthToken(gc, user, claimRoles, scope, claims.LoginMethod) + nonce := uuid.New().String() + authToken, err := token.CreateAuthToken(gc, user, claimRoles, scope, claims.LoginMethod, nonce) if err != nil { log.Debug("Failed to create auth token: ", err) return res, err diff --git a/server/resolvers/signup.go b/server/resolvers/signup.go index d5cd071..3365cd6 100644 --- a/server/resolvers/signup.go +++ b/server/resolvers/signup.go @@ -6,6 +6,7 @@ import ( "strings" "time" + "github.com/google/uuid" log "github.com/sirupsen/logrus" "github.com/authorizerdev/authorizer/server/constants" @@ -242,7 +243,8 @@ func SignupResolver(ctx context.Context, params model.SignUpInput) (*model.AuthR scope = params.Scope } - authToken, err := token.CreateAuthToken(gc, user, roles, scope, constants.AuthRecipeMethodBasicAuth) + nonce := uuid.New().String() + authToken, err := token.CreateAuthToken(gc, user, roles, scope, constants.AuthRecipeMethodBasicAuth, nonce) if err != nil { log.Debug("Failed to create auth token: ", err) return res, err diff --git a/server/resolvers/verify_email.go b/server/resolvers/verify_email.go index 624d08a..37cd7b2 100644 --- a/server/resolvers/verify_email.go +++ b/server/resolvers/verify_email.go @@ -6,6 +6,7 @@ import ( "strings" "time" + "github.com/google/uuid" log "github.com/sirupsen/logrus" "github.com/authorizerdev/authorizer/server/constants" @@ -84,7 +85,8 @@ func VerifyEmailResolver(ctx context.Context, params model.VerifyEmailInput) (*m roles := strings.Split(user.Roles, ",") scope := []string{"openid", "email", "profile"} - authToken, err := token.CreateAuthToken(gc, user, roles, scope, loginMethod) + nonce := uuid.New().String() + authToken, err := token.CreateAuthToken(gc, user, roles, scope, loginMethod, nonce) if err != nil { log.Debug("Failed to create auth token: ", err) return res, err diff --git a/server/resolvers/verify_otp.go b/server/resolvers/verify_otp.go index b792adb..6aeea5f 100644 --- a/server/resolvers/verify_otp.go +++ b/server/resolvers/verify_otp.go @@ -14,6 +14,7 @@ import ( "github.com/authorizerdev/authorizer/server/memorystore" "github.com/authorizerdev/authorizer/server/token" "github.com/authorizerdev/authorizer/server/utils" + "github.com/google/uuid" log "github.com/sirupsen/logrus" ) @@ -57,7 +58,8 @@ func VerifyOtpResolver(ctx context.Context, params model.VerifyOTPRequest) (*mod roles := strings.Split(user.Roles, ",") scope := []string{"openid", "email", "profile"} - authToken, err := token.CreateAuthToken(gc, user, roles, scope, loginMethod) + nonce := uuid.New().String() + authToken, err := token.CreateAuthToken(gc, user, roles, scope, loginMethod, nonce) if err != nil { log.Debug("Failed to create auth token: ", err) return res, err diff --git a/server/test/validate_jwt_token_test.go b/server/test/validate_jwt_token_test.go index 0d5358a..db46fab 100644 --- a/server/test/validate_jwt_token_test.go +++ b/server/test/validate_jwt_token_test.go @@ -51,7 +51,8 @@ func validateJwtTokenTest(t *testing.T, s TestSetup) { gc, err := utils.GinContextFromContext(ctx) assert.NoError(t, err) sessionKey := constants.AuthRecipeMethodBasicAuth + ":" + user.ID - authToken, err := token.CreateAuthToken(gc, user, roles, scope, constants.AuthRecipeMethodBasicAuth) + nonce := uuid.New().String() + authToken, err := token.CreateAuthToken(gc, user, roles, scope, constants.AuthRecipeMethodBasicAuth, nonce) memorystore.Provider.SetUserSession(sessionKey, constants.TokenTypeSessionToken+"_"+authToken.FingerPrint, authToken.FingerPrintHash) memorystore.Provider.SetUserSession(sessionKey, constants.TokenTypeAccessToken+"_"+authToken.FingerPrint, authToken.AccessToken.Token) diff --git a/server/token/auth_token.go b/server/token/auth_token.go index 4572b6b..152f5b4 100644 --- a/server/token/auth_token.go +++ b/server/token/auth_token.go @@ -10,7 +10,6 @@ import ( "github.com/gin-gonic/gin" "github.com/golang-jwt/jwt" - "github.com/google/uuid" "github.com/robertkrimen/otto" "github.com/authorizerdev/authorizer/server/constants" @@ -68,9 +67,8 @@ func CreateSessionToken(user models.User, nonce string, roles, scope []string, l } // CreateAuthToken creates a new auth token when userlogs in -func CreateAuthToken(gc *gin.Context, user models.User, roles, scope []string, loginMethod string) (*Token, error) { +func CreateAuthToken(gc *gin.Context, user models.User, roles, scope []string, loginMethod, nonce string) (*Token, error) { hostname := parsers.GetHost(gc) - nonce := uuid.New().String() _, fingerPrintHash, err := CreateSessionToken(user, nonce, roles, scope, loginMethod) if err != nil { return nil, err @@ -317,6 +315,8 @@ func ValidateBrowserSession(gc *gin.Context, encryptedSession string) (*SessionD // CreateIDToken util to create JWT token, based on // user information, roles config and CUSTOM_ACCESS_TOKEN_SCRIPT +// For response_type (code) / authorization_code grant nonce should be empty +// for implicit flow it should be present to verify with actual state func CreateIDToken(user models.User, roles []string, hostname, nonce, loginMethod string) (string, int64, error) { expireTime, err := memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeyAccessTokenExpiryTime) if err != nil { @@ -344,9 +344,9 @@ func CreateIDToken(user models.User, roles []string, hostname, nonce, loginMetho return "", 0, err } customClaims := jwt.MapClaims{ - "iss": hostname, - "aud": clientID, - "nonce": nonce, + "iss": hostname, + "aud": clientID, + // "nonce": nonce, "sub": user.ID, "exp": expiresAt, "iat": time.Now().Unix(), From b224892a39f87b1e26abb7a4e1275fe3c1552b44 Mon Sep 17 00:00:00 2001 From: Lakhan Samani Date: Wed, 2 Nov 2022 08:48:56 +0530 Subject: [PATCH 27/66] fix: minor space --- server/db/providers/dynamodb/provider.go | 1 - 1 file changed, 1 deletion(-) diff --git a/server/db/providers/dynamodb/provider.go b/server/db/providers/dynamodb/provider.go index 81aa8ce..4bf3345 100644 --- a/server/db/providers/dynamodb/provider.go +++ b/server/db/providers/dynamodb/provider.go @@ -26,7 +26,6 @@ func NewProvider() (*provider, error) { config := aws.Config{ MaxRetries: aws.Int(3), CredentialsChainVerboseErrors: aws.Bool(true), // for full error logs - } if awsRegion != "" { From 63c8e2e55fe0bb2435026e75aa861821da1f6ef7 Mon Sep 17 00:00:00 2001 From: Pjort Kat Date: Thu, 3 Nov 2022 11:51:59 +0100 Subject: [PATCH 28/66] fixed validation of refresh token --- server/handlers/token.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/server/handlers/token.go b/server/handlers/token.go index da72969..20be2ac 100644 --- a/server/handlers/token.go +++ b/server/handlers/token.go @@ -154,6 +154,7 @@ func TokenHandler() gin.HandlerFunc { "error": "invalid_refresh_token", "error_description": "The refresh token is invalid", }) + return } claims, err := token.ValidateRefreshToken(gc, refreshToken) @@ -163,6 +164,7 @@ func TokenHandler() gin.HandlerFunc { "error": "unauthorized", "error_description": err.Error(), }) + return } userID = claims["sub"].(string) loginMethod := claims["login_method"] From 307c6f7d15d9e324a3b1c41f84fe1b3d95ac1a15 Mon Sep 17 00:00:00 2001 From: Lakhan Samani Date: Fri, 4 Nov 2022 01:40:18 +0530 Subject: [PATCH 29/66] fix: refresh token login method claim --- server/handlers/token.go | 9 ++++++--- server/token/auth_token.go | 1 - 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/server/handlers/token.go b/server/handlers/token.go index 20be2ac..4d0064d 100644 --- a/server/handlers/token.go +++ b/server/handlers/token.go @@ -167,7 +167,7 @@ func TokenHandler() gin.HandlerFunc { return } userID = claims["sub"].(string) - loginMethod := claims["login_method"] + claimLoginMethod := claims["login_method"] rolesInterface := claims["roles"].([]interface{}) scopeInterface := claims["scope"].([]interface{}) for _, v := range rolesInterface { @@ -178,9 +178,11 @@ func TokenHandler() gin.HandlerFunc { } sessionKey = userID - if loginMethod != nil && loginMethod != "" { - sessionKey = loginMethod.(string) + ":" + sessionKey + if claimLoginMethod != nil && claimLoginMethod != "" { + sessionKey = claimLoginMethod.(string) + ":" + sessionKey + loginMethod = claimLoginMethod.(string) } + // remove older refresh token and rotate it for security go memorystore.Provider.DeleteUserSession(sessionKey, claims["nonce"].(string)) } @@ -213,6 +215,7 @@ func TokenHandler() gin.HandlerFunc { }) return } + memorystore.Provider.SetUserSession(sessionKey, constants.TokenTypeSessionToken+"_"+authToken.FingerPrint, authToken.FingerPrintHash) memorystore.Provider.SetUserSession(sessionKey, constants.TokenTypeAccessToken+"_"+authToken.FingerPrint, authToken.AccessToken.Token) cookie.SetSession(gc, authToken.FingerPrintHash) diff --git a/server/token/auth_token.go b/server/token/auth_token.go index 4572b6b..4e947e2 100644 --- a/server/token/auth_token.go +++ b/server/token/auth_token.go @@ -256,7 +256,6 @@ func ValidateRefreshToken(gc *gin.Context, refreshToken string) (map[string]inte if loginMethod != nil && loginMethod != "" { sessionKey = loginMethod.(string) + ":" + userID } - token, err := memorystore.Provider.GetUserSession(sessionKey, constants.TokenTypeRefreshToken+"_"+nonce) if nonce == "" || err != nil { return res, fmt.Errorf(`unauthorized`) From 4afd544c413d38fbe4b5535dfac940a90dd380e2 Mon Sep 17 00:00:00 2001 From: Lakhan Samani Date: Mon, 7 Nov 2022 07:11:23 +0530 Subject: [PATCH 30/66] feat(server): add allowed_roles in access_token + refresh_token --- server/token/auth_token.go | 42 ++++++++++++++++++++------------------ 1 file changed, 22 insertions(+), 20 deletions(-) diff --git a/server/token/auth_token.go b/server/token/auth_token.go index 4e947e2..87d164f 100644 --- a/server/token/auth_token.go +++ b/server/token/auth_token.go @@ -114,16 +114,17 @@ func CreateRefreshToken(user models.User, roles, scopes []string, hostname, nonc return "", 0, err } customClaims := jwt.MapClaims{ - "iss": hostname, - "aud": clientID, - "sub": user.ID, - "exp": expiresAt, - "iat": time.Now().Unix(), - "token_type": constants.TokenTypeRefreshToken, - "roles": roles, - "scope": scopes, - "nonce": nonce, - "login_method": loginMethod, + "iss": hostname, + "aud": clientID, + "sub": user.ID, + "exp": expiresAt, + "iat": time.Now().Unix(), + "token_type": constants.TokenTypeRefreshToken, + "roles": roles, + "scope": scopes, + "nonce": nonce, + "login_method": loginMethod, + "allowed_roles": strings.Split(user.Roles, ","), } token, err := SignJWTToken(customClaims) @@ -153,16 +154,17 @@ func CreateAccessToken(user models.User, roles, scopes []string, hostName, nonce return "", 0, err } customClaims := jwt.MapClaims{ - "iss": hostName, - "aud": clientID, - "nonce": nonce, - "sub": user.ID, - "exp": expiresAt, - "iat": time.Now().Unix(), - "token_type": constants.TokenTypeAccessToken, - "scope": scopes, - "roles": roles, - "login_method": loginMethod, + "iss": hostName, + "aud": clientID, + "nonce": nonce, + "sub": user.ID, + "exp": expiresAt, + "iat": time.Now().Unix(), + "token_type": constants.TokenTypeAccessToken, + "scope": scopes, + "roles": roles, + "login_method": loginMethod, + "allowed_roles": strings.Split(user.Roles, ","), } token, err := SignJWTToken(customClaims) From 19f9caf4783624fc8ab1292436adc9a0a9cbbb28 Mon Sep 17 00:00:00 2001 From: Lakhan Samani Date: Wed, 9 Nov 2022 03:47:28 +0530 Subject: [PATCH 31/66] chore: test gox + buildx --- .github/workflows/release.yaml | 36 +++++++++++++++++++++++++--------- Makefile | 6 ++++++ server/go.mod | 1 + server/go.sum | 6 ++++++ 4 files changed, 40 insertions(+), 9 deletions(-) diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml index e30808b..880473f 100644 --- a/.github/workflows/release.yaml +++ b/.github/workflows/release.yaml @@ -2,17 +2,17 @@ on: workflow_dispatch: inputs: logLevel: - description: 'Log level' + description: "Log level" required: true - default: 'warning' + default: "warning" type: choice options: - - info - - warning - - debug + - info + - warning + - debug tags: - description: 'Tags' - required: false + description: "Tags" + required: false type: boolean release: types: [created] @@ -25,10 +25,19 @@ jobs: - uses: actions/checkout@v2 - uses: actions/setup-node@v2 with: - node-version: '16' + node-version: "16" + - # Add support for more platforms with QEMU (optional) + # https://github.com/docker/setup-qemu-action + name: Set up QEMU + uses: docker/setup-qemu-action@v2 + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v2 + with: + platforms: linux/amd64,linux/arm64 + buildkitd-flags: --debug - uses: actions/setup-go@v2 with: - go-version: '^1.17.3' + go-version: "^1.17.3" - name: Install dependencies run: | sudo apt-get install build-essential wget zip gcc-mingw-w64 && \ @@ -59,10 +68,16 @@ jobs: make clean && \ CGO_ENABLED=1 make && \ tar cvfz authorizer-${VERSION}-linux-amd64.tar.gz .env app/build build templates dashboard/build + - name: Build package + run: | + make clean && \ + make build && \ + mkdir -p authorizer-${VERSION}-darwin-amd64/build authorizer-${VERSION}-darwin-amd64/app authorizer-${VERSION}-darwin-amd64/templates authorizer-${VERSION}-darwin-amd64/dashboard && cp build/darwin/amd64/server authorizer-${VERSION}-darwin-amd64/build/ && cp .env authorizer-${VERSION}-darwin-amd64/.env && cp -rf app/build authorizer-${VERSION}-darwin-amd64/app/build && cp -rf templates authorizer-${VERSION}-darwin-amd64/templates && cp -rf dashboard/build authorizer-${VERSION}-darwin-amd64/dashboard/build && tar cvfz authorizer-${VERSION}-darwin-amd64.tar.gz authorizer-${VERSION}-darwin-amd64 - name: Upload assets run: | github-assets-uploader -f authorizer-${VERSION}-windows-amd64.zip -mediatype application/zip -repo authorizerdev/authorizer -token ${{secrets.RELEASE_TOKEN}} -tag ${VERSION} && \ github-assets-uploader -f authorizer-${VERSION}-linux-amd64.tar.gz -mediatype application/gzip -repo authorizerdev/authorizer -token ${{secrets.RELEASE_TOKEN}} -tag ${VERSION} + github-assets-uploader -f authorizer-${VERSION}-darwin-amd64.tar.gz -mediatype application/gzip -repo authorizerdev/authorizer -token ${{secrets.RELEASE_TOKEN}} -tag ${VERSION} - name: Log in to Docker Hub uses: docker/login-action@v1 with: @@ -74,6 +89,9 @@ jobs: uses: docker/metadata-action@v3 with: images: lakhansamani/authorizer + tags: | + # set latest tag for default branch + type=raw,value=latest,enable={{is_default_branch}} - name: Build and push Docker image uses: docker/build-push-action@v2 diff --git a/Makefile b/Makefile index ac0a427..38e819f 100644 --- a/Makefile +++ b/Makefile @@ -3,6 +3,12 @@ VERSION := $(or $(VERSION),$(DEFAULT_VERSION)) cmd: cd server && go build -ldflags "-w -X main.VERSION=$(VERSION)" -o '../build/server' +build: + cd server && gox \ + -osarch="linux/amd64 linux/arm64 darwin/amd64 windows/386 windows/amd64" \ + -ldflags "-w -X main.VERSION=$(VERSION)" \ + -output="../build/{{.OS}}/{{.Arch}}/server" \ + ./... build-app: cd app && npm i && npm run build build-dashboard: diff --git a/server/go.mod b/server/go.mod index 19cf4a7..852165e 100644 --- a/server/go.mod +++ b/server/go.mod @@ -17,6 +17,7 @@ require ( github.com/google/uuid v1.3.0 github.com/guregu/dynamo v1.16.0 github.com/joho/godotenv v1.3.0 + github.com/mitchellh/gox v1.0.1 // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/pelletier/go-toml/v2 v2.0.5 // indirect github.com/robertkrimen/otto v0.0.0-20211024170158-b87d35c0b86f diff --git a/server/go.sum b/server/go.sum index ece2bd3..20da382 100644 --- a/server/go.sum +++ b/server/go.sum @@ -195,6 +195,8 @@ github.com/guregu/dynamo v1.16.0 h1:gmI8oi1VHwYQtq7+RPBeOiSssVLgxH/Az2t+NtDtL2c= github.com/guregu/dynamo v1.16.0/go.mod h1:W2Gqcf3MtkrS+Q6fHPGAmRtT0Dyq+TGrqfqrUC9+R/c= github.com/hailocab/go-hostpool v0.0.0-20160125115350-e80d13ce29ed h1:5upAirOpQc1Q53c0bnx2ufif5kANL7bfZWcc6VJWJd8= github.com/hailocab/go-hostpool v0.0.0-20160125115350-e80d13ce29ed/go.mod h1:tMWxXQ9wFIaZeTI9F+hmhFiGpFmhOHzyShyFUhRm0H4= +github.com/hashicorp/go-version v1.0.0 h1:21MVWPKDphxa7ineQQTrCU5brh7OuVVAzGOCnnCPtE8= +github.com/hashicorp/go-version v1.0.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/golang-lru v0.5.4 h1:YDjusn29QI/Das2iO9M0BHnIbxPeyuCHsjMW+lJfyTc= @@ -300,6 +302,10 @@ github.com/mattn/go-isatty v0.0.16 h1:bq3VjFmv/sOjHtdEhmkEV4x1AJtvUvOJ2PFAZ5+peK github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= github.com/mattn/go-sqlite3 v1.14.9 h1:10HX2Td0ocZpYEjhilsuo6WWtUqttj2Kb0KtD86/KYA= github.com/mattn/go-sqlite3 v1.14.9/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU= +github.com/mitchellh/gox v1.0.1 h1:x0jD3dcHk9a9xPSDN6YEL4xL6Qz0dvNYm8yZqui5chI= +github.com/mitchellh/gox v1.0.1/go.mod h1:ED6BioOGXMswlXa2zxfh/xdd5QhwYliBFn9V18Ap4z4= +github.com/mitchellh/iochan v1.0.0 h1:C+X3KsSTLFVBr/tK1eYN/vs4rJcvsiLU338UhYPJWeY= +github.com/mitchellh/iochan v1.0.0/go.mod h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0QubkSMEySY= github.com/mitchellh/mapstructure v1.3.1 h1:cCBH2gTD2K0OtLlv/Y5H01VQCqmlDxz30kS5Y5bqfLA= github.com/mitchellh/mapstructure v1.3.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= From e1718206147c25909fd723f80cdadcd754b88908 Mon Sep 17 00:00:00 2001 From: Lakhan Samani Date: Wed, 9 Nov 2022 03:51:08 +0530 Subject: [PATCH 32/66] chore: use checkout@v3 --- .github/workflows/release.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml index 880473f..cde9178 100644 --- a/.github/workflows/release.yaml +++ b/.github/workflows/release.yaml @@ -22,7 +22,7 @@ jobs: name: Release Authorizer Binary runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - uses: actions/setup-node@v2 with: node-version: "16" From 024ffd85f3248f5c3bc7bb2fbf50c30e48f2f157 Mon Sep 17 00:00:00 2001 From: Lakhan Samani Date: Wed, 9 Nov 2022 03:52:47 +0530 Subject: [PATCH 33/66] chore: fix yaml indentation --- .github/workflows/release.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml index cde9178..63f68fd 100644 --- a/.github/workflows/release.yaml +++ b/.github/workflows/release.yaml @@ -68,7 +68,7 @@ jobs: make clean && \ CGO_ENABLED=1 make && \ tar cvfz authorizer-${VERSION}-linux-amd64.tar.gz .env app/build build templates dashboard/build - - name: Build package + - name: Build package run: | make clean && \ make build && \ From 1bff6720fccb3dc9aa54c513c1606891ce35227b Mon Sep 17 00:00:00 2001 From: Lakhan Samani Date: Wed, 9 Nov 2022 03:59:20 +0530 Subject: [PATCH 34/66] chore: install gox --- .github/workflows/release.yaml | 15 ++------------- 1 file changed, 2 insertions(+), 13 deletions(-) diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml index 63f68fd..73203de 100644 --- a/.github/workflows/release.yaml +++ b/.github/workflows/release.yaml @@ -53,21 +53,12 @@ jobs: run: whereis go - name: Print Go Version run: go version + - name: Install gox + run: go install github.com/mitchellh/gox@latest - name: Set VERSION env run: echo VERSION=$(basename ${GITHUB_REF}) >> ${GITHUB_ENV} - name: Copy .env file run: mv .env.sample .env - - name: Package files for windows - run: | - make clean && \ - CGO_ENABLED=1 GOOS=windows CC=/usr/bin/x86_64-w64-mingw32-gcc make && \ - mv build/server build/server.exe && \ - zip -vr authorizer-${VERSION}-windows-amd64.zip .env app/build build templates dashboard/build - - name: Package files for linux - run: | - make clean && \ - CGO_ENABLED=1 make && \ - tar cvfz authorizer-${VERSION}-linux-amd64.tar.gz .env app/build build templates dashboard/build - name: Build package run: | make clean && \ @@ -75,8 +66,6 @@ jobs: mkdir -p authorizer-${VERSION}-darwin-amd64/build authorizer-${VERSION}-darwin-amd64/app authorizer-${VERSION}-darwin-amd64/templates authorizer-${VERSION}-darwin-amd64/dashboard && cp build/darwin/amd64/server authorizer-${VERSION}-darwin-amd64/build/ && cp .env authorizer-${VERSION}-darwin-amd64/.env && cp -rf app/build authorizer-${VERSION}-darwin-amd64/app/build && cp -rf templates authorizer-${VERSION}-darwin-amd64/templates && cp -rf dashboard/build authorizer-${VERSION}-darwin-amd64/dashboard/build && tar cvfz authorizer-${VERSION}-darwin-amd64.tar.gz authorizer-${VERSION}-darwin-amd64 - name: Upload assets run: | - github-assets-uploader -f authorizer-${VERSION}-windows-amd64.zip -mediatype application/zip -repo authorizerdev/authorizer -token ${{secrets.RELEASE_TOKEN}} -tag ${VERSION} && \ - github-assets-uploader -f authorizer-${VERSION}-linux-amd64.tar.gz -mediatype application/gzip -repo authorizerdev/authorizer -token ${{secrets.RELEASE_TOKEN}} -tag ${VERSION} github-assets-uploader -f authorizer-${VERSION}-darwin-amd64.tar.gz -mediatype application/gzip -repo authorizerdev/authorizer -token ${{secrets.RELEASE_TOKEN}} -tag ${VERSION} - name: Log in to Docker Hub uses: docker/login-action@v1 From a18046748b3fbffeec9cdc17f6072761a05543b4 Mon Sep 17 00:00:00 2001 From: Lakhan Samani Date: Wed, 9 Nov 2022 04:09:55 +0530 Subject: [PATCH 35/66] chore: add cgo param to gox --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 38e819f..37fa7ee 100644 --- a/Makefile +++ b/Makefile @@ -4,7 +4,7 @@ VERSION := $(or $(VERSION),$(DEFAULT_VERSION)) cmd: cd server && go build -ldflags "-w -X main.VERSION=$(VERSION)" -o '../build/server' build: - cd server && gox \ + cd server && gox -cgo \ -osarch="linux/amd64 linux/arm64 darwin/amd64 windows/386 windows/amd64" \ -ldflags "-w -X main.VERSION=$(VERSION)" \ -output="../build/{{.OS}}/{{.Arch}}/server" \ From e54b7f18f0df6c4600e7244304f5f07256b4466f Mon Sep 17 00:00:00 2001 From: Lakhan Samani Date: Wed, 9 Nov 2022 04:25:09 +0530 Subject: [PATCH 36/66] chore: add dependencies for cross compile --- .github/workflows/release.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml index 73203de..7a51f6a 100644 --- a/.github/workflows/release.yaml +++ b/.github/workflows/release.yaml @@ -40,7 +40,7 @@ jobs: go-version: "^1.17.3" - name: Install dependencies run: | - sudo apt-get install build-essential wget zip gcc-mingw-w64 && \ + sudo apt-get install build-essential wget zip gcc-multilib gcc-mingw-w64 gcc-aarch64-linux-gnu libc6-dev-arm64-cross && \ echo "/usr/bin/x86_64-w64-mingw32-gcc" >> GITHUB_PATH && \ wget --no-check-certificate --progress=dot:mega https://github.com/wangyoucao577/assets-uploader/releases/download/v0.3.0/github-assets-uploader-v0.3.0-linux-amd64.tar.gz -O github-assets-uploader.tar.gz && \ tar -zxf github-assets-uploader.tar.gz && \ From c6c3af1114d1f8f73a3e346f1c7bbcdcd44eeda0 Mon Sep 17 00:00:00 2001 From: Lakhan Samani Date: Wed, 9 Nov 2022 04:31:04 +0530 Subject: [PATCH 37/66] chore: update dependencies for cross compile --- .github/workflows/release.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml index 7a51f6a..7a9548a 100644 --- a/.github/workflows/release.yaml +++ b/.github/workflows/release.yaml @@ -19,7 +19,7 @@ on: jobs: releases: - name: Release Authorizer Binary + name: Release Authorizer runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 @@ -40,7 +40,7 @@ jobs: go-version: "^1.17.3" - name: Install dependencies run: | - sudo apt-get install build-essential wget zip gcc-multilib gcc-mingw-w64 gcc-aarch64-linux-gnu libc6-dev-arm64-cross && \ + sudo apt-get install build-essential wget zip gcc-multilib gcc-mingw-w64 gcc-9-aarch64-linux-gnu gcc-aarch64-linux-gnu libc6-dev-arm64-cross && \ echo "/usr/bin/x86_64-w64-mingw32-gcc" >> GITHUB_PATH && \ wget --no-check-certificate --progress=dot:mega https://github.com/wangyoucao577/assets-uploader/releases/download/v0.3.0/github-assets-uploader-v0.3.0-linux-amd64.tar.gz -O github-assets-uploader.tar.gz && \ tar -zxf github-assets-uploader.tar.gz && \ From 27160ecbd5b396de17f1c720b7d7a0536a7ab784 Mon Sep 17 00:00:00 2001 From: Lakhan Samani Date: Wed, 9 Nov 2022 09:46:27 +0530 Subject: [PATCH 38/66] chore: fix arm dependencies --- .github/workflows/release.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml index 7a9548a..56f5448 100644 --- a/.github/workflows/release.yaml +++ b/.github/workflows/release.yaml @@ -40,7 +40,7 @@ jobs: go-version: "^1.17.3" - name: Install dependencies run: | - sudo apt-get install build-essential wget zip gcc-multilib gcc-mingw-w64 gcc-9-aarch64-linux-gnu gcc-aarch64-linux-gnu libc6-dev-arm64-cross && \ + sudo apt-get install build-essential wget zip gcc-mingw-w64 gcc-9-aarch64-linux-gnu gcc-aarch64-linux-gnu libc6-dev-arm64-cross && \ echo "/usr/bin/x86_64-w64-mingw32-gcc" >> GITHUB_PATH && \ wget --no-check-certificate --progress=dot:mega https://github.com/wangyoucao577/assets-uploader/releases/download/v0.3.0/github-assets-uploader-v0.3.0-linux-amd64.tar.gz -O github-assets-uploader.tar.gz && \ tar -zxf github-assets-uploader.tar.gz && \ From cb5af1e679afdb64901ad091a3e9e4f910f7dd7f Mon Sep 17 00:00:00 2001 From: Lakhan Samani Date: Wed, 9 Nov 2022 13:07:20 +0530 Subject: [PATCH 39/66] use non c binding for sqlite --- .github/workflows/release.yaml | 2 +- .gitignore | 4 +- Makefile | 8 +-- server/db/providers/sql/provider.go | 4 +- server/go.mod | 13 ++-- server/go.sum | 98 +++++++++++++++++++++++++++++ 6 files changed, 115 insertions(+), 14 deletions(-) diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml index 56f5448..0d77c88 100644 --- a/.github/workflows/release.yaml +++ b/.github/workflows/release.yaml @@ -40,7 +40,7 @@ jobs: go-version: "^1.17.3" - name: Install dependencies run: | - sudo apt-get install build-essential wget zip gcc-mingw-w64 gcc-9-aarch64-linux-gnu gcc-aarch64-linux-gnu libc6-dev-arm64-cross && \ + sudo apt-get install build-essential wget zip libc6-dev-arm64-cross && \ echo "/usr/bin/x86_64-w64-mingw32-gcc" >> GITHUB_PATH && \ wget --no-check-certificate --progress=dot:mega https://github.com/wangyoucao577/assets-uploader/releases/download/v0.3.0/github-assets-uploader-v0.3.0-linux-amd64.tar.gz -O github-assets-uploader.tar.gz && \ tar -zxf github-assets-uploader.tar.gz && \ diff --git a/.gitignore b/.gitignore index 7fdb338..fe8d948 100644 --- a/.gitignore +++ b/.gitignore @@ -15,4 +15,6 @@ test.db .vscode/ .yalc yalc.lock -certs/ \ No newline at end of file +certs/ +*-shm +*-wal \ No newline at end of file diff --git a/Makefile b/Makefile index 37fa7ee..1326318 100644 --- a/Makefile +++ b/Makefile @@ -4,8 +4,8 @@ VERSION := $(or $(VERSION),$(DEFAULT_VERSION)) cmd: cd server && go build -ldflags "-w -X main.VERSION=$(VERSION)" -o '../build/server' build: - cd server && gox -cgo \ - -osarch="linux/amd64 linux/arm64 darwin/amd64 windows/386 windows/amd64" \ + cd server && gox \ + -osarch="linux/amd64 linux/arm64 darwin/amd64 windows/amd64" \ -ldflags "-w -X main.VERSION=$(VERSION)" \ -output="../build/{{.OS}}/{{.Arch}}/server" \ ./... @@ -16,7 +16,7 @@ build-dashboard: clean: rm -rf build test: - rm -rf server/test/test.db && rm -rf test.db && cd server && go clean --testcache && TEST_DBS="sqlite" go test -p 1 -v ./test + rm -rf server/test/test.db server/test/test.db-shm server/test/test.db-wal && rm -rf test.db test.db-shm test.db-wal && cd server && go clean --testcache && TEST_DBS="sqlite" go test -p 1 -v ./test test-mongodb: docker run -d --name authorizer_mongodb_db -p 27017:27017 mongo:4.4.15 cd server && go clean --testcache && TEST_DBS="mongodb" go test -p 1 -v ./test @@ -34,7 +34,7 @@ test-dynamodb: cd server && go clean --testcache && TEST_DBS="dynamodb" go test -p 1 -v ./test docker rm -vf dynamodb-local-test test-all-db: - rm -rf server/test/test.db && rm -rf test.db + rm -rf server/test/test.db server/test/test.db-shm server/test/test.db-wal && rm -rf test.db test.db-shm test.db-wal docker run -d --name authorizer_scylla_db -p 9042:9042 scylladb/scylla docker run -d --name authorizer_mongodb_db -p 27017:27017 mongo:4.4.15 docker run -d --name authorizer_arangodb -p 8529:8529 -e ARANGO_NO_AUTH=1 arangodb/arangodb:3.8.4 diff --git a/server/db/providers/sql/provider.go b/server/db/providers/sql/provider.go index cfe83eb..b077b6b 100644 --- a/server/db/providers/sql/provider.go +++ b/server/db/providers/sql/provider.go @@ -9,9 +9,9 @@ import ( "github.com/authorizerdev/authorizer/server/constants" "github.com/authorizerdev/authorizer/server/db/models" "github.com/authorizerdev/authorizer/server/memorystore" + "github.com/glebarez/sqlite" "gorm.io/driver/mysql" "gorm.io/driver/postgres" - "gorm.io/driver/sqlite" "gorm.io/driver/sqlserver" "gorm.io/gorm" "gorm.io/gorm/logger" @@ -61,7 +61,7 @@ func NewProvider() (*provider, error) { case constants.DbTypePostgres, constants.DbTypeYugabyte, constants.DbTypeCockroachDB: sqlDB, err = gorm.Open(postgres.Open(dbURL), ormConfig) case constants.DbTypeSqlite: - sqlDB, err = gorm.Open(sqlite.Open(dbURL), ormConfig) + sqlDB, err = gorm.Open(sqlite.Open(dbURL+"?_pragma=busy_timeout(5000)&_pragma=journal_mode(WAL)"), ormConfig) case constants.DbTypeMysql, constants.DbTypeMariaDB, constants.DbTypePlanetScaleDB: sqlDB, err = gorm.Open(mysql.Open(dbURL), ormConfig) case constants.DbTypeSqlserver: diff --git a/server/go.mod b/server/go.mod index 852165e..ca7f949 100644 --- a/server/go.mod +++ b/server/go.mod @@ -7,7 +7,9 @@ require ( github.com/arangodb/go-driver v1.2.1 github.com/aws/aws-sdk-go v1.44.109 github.com/coreos/go-oidc/v3 v3.1.0 + github.com/denisenkom/go-mssqldb v0.11.0 // indirect github.com/gin-gonic/gin v1.8.1 + github.com/glebarez/sqlite v1.5.0 // indirect github.com/go-playground/validator/v10 v10.11.1 // indirect github.com/go-redis/redis/v8 v8.11.0 github.com/goccy/go-json v0.9.11 // indirect @@ -25,7 +27,7 @@ require ( github.com/stretchr/testify v1.8.0 github.com/vektah/gqlparser/v2 v2.5.1 go.mongodb.org/mongo-driver v1.8.1 - golang.org/x/crypto v0.0.0-20220926161630-eccd6366d1be + golang.org/x/crypto v0.0.0-20221005025214-4161e89ecf1b golang.org/x/net v0.0.0-20220930213112-107f3e3c3b0b // indirect golang.org/x/oauth2 v0.0.0-20210628180205-a41e5a781914 golang.org/x/sys v0.0.0-20220928140112-f11e5e49a4ec // indirect @@ -34,9 +36,8 @@ require ( gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc // indirect gopkg.in/mail.v2 v2.3.1 gopkg.in/square/go-jose.v2 v2.6.0 - gorm.io/driver/mysql v1.2.1 - gorm.io/driver/postgres v1.2.3 - gorm.io/driver/sqlite v1.2.6 - gorm.io/driver/sqlserver v1.2.1 - gorm.io/gorm v1.22.4 + gorm.io/driver/mysql v1.4.3 + gorm.io/driver/postgres v1.4.5 + gorm.io/driver/sqlserver v1.4.1 + gorm.io/gorm v1.24.1 ) diff --git a/server/go.sum b/server/go.sum index 20da382..3a9f6d3 100644 --- a/server/go.sum +++ b/server/go.sum @@ -33,6 +33,10 @@ cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9 dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= github.com/99designs/gqlgen v0.17.20 h1:O7WzccIhKB1dm+7g6dhQcULINftfiLSBg2l/mwbpJMw= github.com/99designs/gqlgen v0.17.20/go.mod h1:Mja2HI23kWT1VRH09hvWshFgOzKswpO20o4ScpJIES4= +github.com/Azure/azure-sdk-for-go/sdk/azcore v1.0.0/go.mod h1:uGG2W01BaETf0Ozp+QxxKJdMBNRWPdstHG0Fmdwn1/U= +github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.0.0/go.mod h1:+6sju8gk8FRmSajX3Oz4G5Gm7P+mbqE9FVaXXFYTkCM= +github.com/Azure/azure-sdk-for-go/sdk/internal v1.0.0/go.mod h1:eWRD7oawr1Mu1sLCawqVc0CUiF43ia3qQMxLscsKQ9w= +github.com/AzureAD/microsoft-authentication-library-for-go v0.4.0/go.mod h1:Vt9sXTKwMyGcOxSmLDMnGPgqsUg7m8pe215qMLrDXw4= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/BurntSushi/toml v1.1.0/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ= github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= @@ -87,6 +91,9 @@ github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/r github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc= github.com/dgryski/trifles v0.0.0-20200323201526-dd97f9abfb48 h1:fRzb/w+pyskVMQ+UbP35JkH8yB7MYb4q/qhBarqZE6g= github.com/dgryski/trifles v0.0.0-20200323201526-dd97f9abfb48/go.mod h1:if7Fbed8SFyPtHLHbg49SI7NAdJiC5WIA09pe59rfAA= +github.com/dnaeon/go-vcr v1.1.0/go.mod h1:M7tiix8f0r6mKKJ3Yq/kqU1OYf3MnfmBWVbPx/yU9ko= +github.com/dnaeon/go-vcr v1.2.0/go.mod h1:R4UdLID7HZT3taECzJs4YgbbH6PIGXB6W/sc5OLb6RQ= +github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= @@ -98,6 +105,10 @@ github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI= github.com/gin-gonic/gin v1.8.1 h1:4+fr/el88TOO3ewCmQr8cx/CtZ/umlIRIs5M4NTNjf8= github.com/gin-gonic/gin v1.8.1/go.mod h1:ji8BvRH1azfM+SYow9zQ6SZMvR8qOMZHmsCuWR9tTTk= +github.com/glebarez/go-sqlite v1.19.1 h1:o2XhjyR8CQ2m84+bVz10G0cabmG0tY4sIMiCbrcUTrY= +github.com/glebarez/go-sqlite v1.19.1/go.mod h1:9AykawGIyIcxoSfpYWiX1SgTNHTNsa/FVc75cDkbp4M= +github.com/glebarez/sqlite v1.5.0 h1:+8LAEpmywqresSoGlqjjT+I9m4PseIM3NcerIJ/V7mk= +github.com/glebarez/sqlite v1.5.0/go.mod h1:0wzXzTvfVJIN2GqRhCdMbnYd+m+aH5/QV7B30rM6NgY= github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= @@ -126,10 +137,16 @@ github.com/gocql/gocql v1.2.0/go.mod h1:3gM2c4D3AnkISwBxGnMMsS8Oy4y2lhbPRsH4xnJr github.com/gofrs/uuid v4.0.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= github.com/gofrs/uuid v4.2.0+incompatible h1:yyYWMnhkhrKwwr8gAOcOCYxOOscHgDS9yZgBrnJfGa0= github.com/gofrs/uuid v4.2.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= +github.com/golang-jwt/jwt v3.2.1+incompatible/go.mod h1:8pz2t5EyA70fFQQSrl6XZXzqecmYZeUEB8OUGHkxJ+I= github.com/golang-jwt/jwt v3.2.2+incompatible h1:IfV12K8xAKAnZqdXVzCZ+TOjboZ2keLg81eXfW3O+oY= github.com/golang-jwt/jwt v3.2.2+incompatible/go.mod h1:8pz2t5EyA70fFQQSrl6XZXzqecmYZeUEB8OUGHkxJ+I= +github.com/golang-jwt/jwt/v4 v4.2.0/go.mod h1:/xlHOz8bRuivTWchD4jCa+NbatV+wEUSzwAxVc6locg= github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe h1:lXe2qZdvpiX5WZkZR4hgp4KJVfY3nMkvmwbVkpv1rVY= github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe/go.mod h1:8vg3r2VgvsThLBIFL93Qb5yWzgyZWhEmBwUJWevAkK0= +github.com/golang-sql/civil v0.0.0-20220223132316-b832511892a9 h1:au07oEsX2xN0ktxqI+Sida1w446QrXBRJ0nee3SNZlA= +github.com/golang-sql/civil v0.0.0-20220223132316-b832511892a9/go.mod h1:8vg3r2VgvsThLBIFL93Qb5yWzgyZWhEmBwUJWevAkK0= +github.com/golang-sql/sqlexp v0.1.0 h1:ZCD6MBpcuOVfGVqsEmY5/4FtYiKz6tSyUv9LPEDei6A= +github.com/golang-sql/sqlexp v0.1.0/go.mod h1:J4ad9Vo8ZCWQ2GMrC4UCQy1JpCbwU9m3EOqtpKwwwHI= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= @@ -170,6 +187,7 @@ github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/ github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.6 h1:BKbKCqvP6I+rmFHt06ZmyQtvB8xAkWdhFyr0ZUNZcxQ= github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= @@ -216,6 +234,8 @@ github.com/jackc/pgconn v1.9.0/go.mod h1:YctiPyvzfU11JFxoXokUOOKQXQmDMoJL9vJzHH8 github.com/jackc/pgconn v1.9.1-0.20210724152538-d89c8390a530/go.mod h1:4z2w8XhRbP1hYxkpTuBjTS3ne3J48K83+u0zoyvg2pI= github.com/jackc/pgconn v1.10.1 h1:DzdIHIjG1AxGwoEEqS+mGsURyjt4enSmqzACXvVzOT8= github.com/jackc/pgconn v1.10.1/go.mod h1:4z2w8XhRbP1hYxkpTuBjTS3ne3J48K83+u0zoyvg2pI= +github.com/jackc/pgconn v1.13.0 h1:3L1XMNV2Zvca/8BYhzcRFS70Lr0WlDg16Di6SFGAbys= +github.com/jackc/pgconn v1.13.0/go.mod h1:AnowpAqO4CMIIJNZl2VJp+KrkAZciAkhEl0W0JIobpI= github.com/jackc/pgio v1.0.0 h1:g12B9UwVnzGhueNavwioyEEpAmqMe1E/BN9ES+8ovkE= github.com/jackc/pgio v1.0.0/go.mod h1:oP+2QK2wFfUWgr+gxjoBH9KGBb31Eio69xUb0w5bYf8= github.com/jackc/pgmock v0.0.0-20190831213851-13a1b77aafa2/go.mod h1:fGZlG77KXmcq05nJLRkk0+p82V8B8Dw8KN2/V9c/OAE= @@ -234,6 +254,8 @@ github.com/jackc/pgproto3/v2 v2.0.6/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwX github.com/jackc/pgproto3/v2 v2.1.1/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA= github.com/jackc/pgproto3/v2 v2.2.0 h1:r7JypeP2D3onoQTCxWdTpCtJ4D+qpKr0TxvoyMhZ5ns= github.com/jackc/pgproto3/v2 v2.2.0/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA= +github.com/jackc/pgproto3/v2 v2.3.1 h1:nwj7qwf0S+Q7ISFfBndqeLwSwxs+4DPsbRFjECT1Y4Y= +github.com/jackc/pgproto3/v2 v2.3.1/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA= github.com/jackc/pgservicefile v0.0.0-20200714003250-2b9c44734f2b h1:C8S2+VttkHFdOOCXJe+YGfa4vHYwlt4Zx+IVXQ97jYg= github.com/jackc/pgservicefile v0.0.0-20200714003250-2b9c44734f2b/go.mod h1:vsD4gTJCa9TptPL8sPkXrLZ+hDuNrZCnj29CQpr4X1E= github.com/jackc/pgtype v0.0.0-20190421001408-4ed0de4755e0/go.mod h1:hdSHsc1V01CGwFsrv11mJRHWJ6aifDLfdV3aVjFF0zg= @@ -242,21 +264,29 @@ github.com/jackc/pgtype v0.0.0-20190828014616-a8802b16cc59/go.mod h1:MWlu30kVJrU github.com/jackc/pgtype v1.8.1-0.20210724151600-32e20a603178/go.mod h1:C516IlIV9NKqfsMCXTdChteoXmwgUceqaLfjg2e3NlM= github.com/jackc/pgtype v1.9.0 h1:/SH1RxEtltvJgsDqp3TbiTFApD3mey3iygpuEGeuBXk= github.com/jackc/pgtype v1.9.0/go.mod h1:LUMuVrfsFfdKGLw+AFFVv6KtHOFMwRgDDzBt76IqCA4= +github.com/jackc/pgtype v1.12.0 h1:Dlq8Qvcch7kiehm8wPGIW0W3KsCCHJnRacKW0UM8n5w= +github.com/jackc/pgtype v1.12.0/go.mod h1:LUMuVrfsFfdKGLw+AFFVv6KtHOFMwRgDDzBt76IqCA4= github.com/jackc/pgx/v4 v4.0.0-20190420224344-cc3461e65d96/go.mod h1:mdxmSJJuR08CZQyj1PVQBHy9XOp5p8/SHH6a0psbY9Y= github.com/jackc/pgx/v4 v4.0.0-20190421002000-1b8f0016e912/go.mod h1:no/Y67Jkk/9WuGR0JG/JseM9irFbnEPbuWV2EELPNuM= github.com/jackc/pgx/v4 v4.0.0-pre1.0.20190824185557-6972a5742186/go.mod h1:X+GQnOEnf1dqHGpw7JmHqHc1NxDoalibchSk9/RWuDc= github.com/jackc/pgx/v4 v4.12.1-0.20210724153913-640aa07df17c/go.mod h1:1QD0+tgSXP7iUjYm9C1NxKhny7lq6ee99u/z+IHFcgs= github.com/jackc/pgx/v4 v4.14.0 h1:TgdrmgnM7VY72EuSQzBbBd4JA1RLqJolrw9nQVZABVc= github.com/jackc/pgx/v4 v4.14.0/go.mod h1:jT3ibf/A0ZVCp89rtCIN0zCJxcE74ypROmHEZYsG/j8= +github.com/jackc/pgx/v4 v4.17.2 h1:0Ut0rpeKwvIVbMQ1KbMBU4h6wxehBI535LK6Flheh8E= +github.com/jackc/pgx/v4 v4.17.2/go.mod h1:lcxIZN44yMIrWI78a5CpucdD14hX0SBDbNRvjDBItsw= github.com/jackc/puddle v0.0.0-20190413234325-e4ced69a3a2b/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= github.com/jackc/puddle v0.0.0-20190608224051-11cab39313c9/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= github.com/jackc/puddle v1.1.3/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= github.com/jackc/puddle v1.2.0/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= +github.com/jackc/puddle v1.3.0/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E= github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc= github.com/jinzhu/now v1.1.2/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8= github.com/jinzhu/now v1.1.3 h1:PlHq1bSCSZL9K0wUhbm2pGLoTWs2GwVhsP6emvGV/ZI= github.com/jinzhu/now v1.1.3/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8= +github.com/jinzhu/now v1.1.4/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8= +github.com/jinzhu/now v1.1.5 h1:/o9tlHleP7gOFmsnYNz3RGnqzefHA47wQpKrrdTIwXQ= +github.com/jinzhu/now v1.1.5/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8= github.com/jmespath/go-jmespath v0.4.0 h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9YPoQUg= github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo= github.com/jmespath/go-jmespath/internal/testify v1.5.1 h1:shLQSRRSCCPj3f2gpwzGwWFoC7ycTf1rcQZHOlsJ6N8= @@ -267,6 +297,7 @@ github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnr github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= +github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51/go.mod h1:CzGEWj7cYgsdH8dAjBGEr58BoE7ScuLd+fwFZ44+/x8= github.com/kevinmbeaulieu/eq-go v1.0.0/go.mod h1:G3S8ajA56gKBZm4UB9AOyoOS37JO3roToPzKNM8dtdM= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/klauspost/compress v1.13.6 h1:P76CopJELS0TiO2mebmnzgWaajssP/EszplttgQxcgc= @@ -282,6 +313,7 @@ github.com/kr/pty v1.1.8/go.mod h1:O1sed60cT9XZ5uDucP5qwvh+TE3NnUj51EiZO/lmSfw= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= +github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw= github.com/leodido/go-urn v1.2.1 h1:BqpAaACuzVSgi/VLzGZIobT2z4v53pjosyNd9Yv6n/w= github.com/leodido/go-urn v1.2.1/go.mod h1:zt4jvISO2HfUBqxjfIshjdMTYS56ZS/qv49ictyFfxY= github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= @@ -302,6 +334,10 @@ github.com/mattn/go-isatty v0.0.16 h1:bq3VjFmv/sOjHtdEhmkEV4x1AJtvUvOJ2PFAZ5+peK github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= github.com/mattn/go-sqlite3 v1.14.9 h1:10HX2Td0ocZpYEjhilsuo6WWtUqttj2Kb0KtD86/KYA= github.com/mattn/go-sqlite3 v1.14.9/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU= +github.com/mattn/go-sqlite3 v1.14.15 h1:vfoHhTN1af61xCRSWzFIWzx2YskyMTwHLrExkBOjvxI= +github.com/mattn/go-sqlite3 v1.14.15/go.mod h1:2eHXhiwb8IkHr+BDWZGa96P6+rkvnG63S2DGjv9HUNg= +github.com/microsoft/go-mssqldb v0.17.0 h1:Fto83dMZPnYv1Zwx5vHHxpNraeEaUlQ/hhHLgZiaenE= +github.com/microsoft/go-mssqldb v0.17.0/go.mod h1:OkoNGhGEs8EZqchVTtochlXruEhEOaO4S0d2sB5aeGQ= github.com/mitchellh/gox v1.0.1 h1:x0jD3dcHk9a9xPSDN6YEL4xL6Qz0dvNYm8yZqui5chI= github.com/mitchellh/gox v1.0.1/go.mod h1:ED6BioOGXMswlXa2zxfh/xdd5QhwYliBFn9V18Ap4z4= github.com/mitchellh/iochan v1.0.0 h1:C+X3KsSTLFVBr/tK1eYN/vs4rJcvsiLU338UhYPJWeY= @@ -313,7 +349,9 @@ github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= +github.com/modocache/gover v0.0.0-20171022184752-b58185e213c5/go.mod h1:caMODM3PzxT8aQXRPkAt8xlV/e7d7w8GM5g0fa5F0D8= github.com/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe/go.mod h1:wL8QJuTMNUDYhXwkmfOly8iTdp5TEcJFWZD2D7SIkUc= +github.com/montanaflynn/stats v0.6.6/go.mod h1:etXPPgVO6n31NxCd9KQUMvCM+ve0ruNzt6R8Bnaayow= github.com/nxadm/tail v1.4.4 h1:DQuhQpB1tVlglWS2hLQ5OV6B5r8aGxSrPc5Qo6uTN78= github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= @@ -327,6 +365,8 @@ github.com/onsi/gomega v1.10.5/go.mod h1:gza4q3jKQJijlu05nKWRCW/GavJumGt8aNRxWg7 github.com/pelletier/go-toml/v2 v2.0.1/go.mod h1:r9LEWfGN8R5k0VXJ+0BkIe7MYkRdwZOjgMj2KwnJFUo= github.com/pelletier/go-toml/v2 v2.0.5 h1:ipoSadvV8oGUjnUbMub59IDPPwfxF694nG/jwbMiyQg= github.com/pelletier/go-toml/v2 v2.0.5/go.mod h1:OMHamSCAODeSsVrwwvcJOaoN0LIUIaFVNZzmWyNfXas= +github.com/pkg/browser v0.0.0-20210115035449-ce105d075bb4/go.mod h1:N6UoU20jOqggOuDwUaBQpluzLNDqif3kq9z2wpdYEfQ= +github.com/pkg/browser v0.0.0-20210911075715-681adbf594b8/go.mod h1:HKlIX3XHQyzLZPlr7++PzdhaXEj94dEiJgZDTsxEqUI= github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= @@ -334,6 +374,8 @@ github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINE github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0 h1:OdAsTTz6OkFY5QxjkYwrChwuRruF69c169dPK26NUlk= +github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo= github.com/robertkrimen/otto v0.0.0-20211024170158-b87d35c0b86f h1:a7clxaGmmqtdNTXyvrp/lVO/Gnkzlhc/+dLs5v965GM= github.com/robertkrimen/otto v0.0.0-20211024170158-b87d35c0b86f/go.mod h1:/mK7FZ3mFYEn9zvNPhpngTyatyehSwte5bJZ4ehL5Xw= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= @@ -428,8 +470,12 @@ golang.org/x/crypto v0.0.0-20210616213533-5ff15b29337e/go.mod h1:GvvjBRRGRdwPK5y golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20211215153901-e495a2d5b3d3/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= +golang.org/x/crypto v0.0.0-20220511200225-c6db032c6c88/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= +golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.0.0-20220926161630-eccd6366d1be h1:fmw3UbQh+nxngCAHrDCCztao/kbYFnWjoqop8dHx05A= golang.org/x/crypto v0.0.0-20220926161630-eccd6366d1be/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= +golang.org/x/crypto v0.0.0-20221005025214-4161e89ecf1b h1:huxqepDufQpLLIRXiVkTvnxrzJlpwmIWAObmcCcUFr0= +golang.org/x/crypto v0.0.0-20221005025214-4161e89ecf1b/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= @@ -493,6 +539,7 @@ golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/ golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/net v0.0.0-20201010224723-4f7140c49acb/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20201202161906-c7110b5ffcbb/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= @@ -500,6 +547,7 @@ golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qx golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20211216030914-fe4d6282115f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= +golang.org/x/net v0.0.0-20220425223048-2871e0cb64e4/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/net v0.0.0-20220930213112-107f3e3c3b0b h1:uKO3Js8lXGjpjdc4J3rqs0/Ex5yDKUGfk43tTYWVLas= golang.org/x/net v0.0.0-20220930213112-107f3e3c3b0b/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk= @@ -561,12 +609,16 @@ golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210616045830-e2b7044e8c71/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210806184541-e5e7981a1069/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211007075335-d3039528d8ac/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211019181941-9d821ace8654/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220224120231-95c6836cb0e7/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= @@ -637,6 +689,7 @@ golang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/go.mod h1:EkVYQZoAsY45+roY golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= +golang.org/x/tools v0.0.0-20201124115921-2c860bdd6e78/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.1.10/go.mod h1:Uh6Zz+xoGYZom868N8YTex3t7RhtHDBrE8Gzo9bV56E= golang.org/x/tools v0.1.12 h1:VveCTK38A2rkS8ZqFY25HIDFscX5X9OoEhJd3quQmXU= @@ -750,6 +803,7 @@ gopkg.in/square/go-jose.v2 v2.6.0 h1:NGk74WTnPKBNUhNzQX7PYcTLUjoq7mzKk2OKbvwk2iI gopkg.in/square/go-jose.v2 v2.6.0/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= +gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= @@ -762,16 +816,28 @@ gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gorm.io/driver/mysql v1.2.1 h1:h+3f1l9Ng2C072Y2tIiLgPpWN78r1KXL7bHJ0nTjlhU= gorm.io/driver/mysql v1.2.1/go.mod h1:qsiz+XcAyMrS6QY+X3M9R6b/lKM1imKmcuK9kac5LTo= +gorm.io/driver/mysql v1.4.3 h1:/JhWJhO2v17d8hjApTltKNADm7K7YI2ogkR7avJUL3k= +gorm.io/driver/mysql v1.4.3/go.mod h1:sSIebwZAVPiT+27jK9HIwvsqOGKx3YMPmrA3mBJR10c= gorm.io/driver/postgres v1.2.3 h1:f4t0TmNMy9gh3TU2PX+EppoA6YsgFnyq8Ojtddb42To= gorm.io/driver/postgres v1.2.3/go.mod h1:pJV6RgYQPG47aM1f0QeOzFH9HxQc8JcmAgjRCgS0wjs= +gorm.io/driver/postgres v1.4.5 h1:mTeXTTtHAgnS9PgmhN2YeUbazYpLhUI1doLnw42XUZc= +gorm.io/driver/postgres v1.4.5/go.mod h1:GKNQYSJ14qvWkvPwXljMGehpKrhlDNsqYRr5HnYGncg= gorm.io/driver/sqlite v1.2.6 h1:SStaH/b+280M7C8vXeZLz/zo9cLQmIGwwj3cSj7p6l4= gorm.io/driver/sqlite v1.2.6/go.mod h1:gyoX0vHiiwi0g49tv+x2E7l8ksauLK0U/gShcdUsjWY= gorm.io/driver/sqlserver v1.2.1 h1:KhGOjvPX7JZ5hPyQICTJfMuTz88zgJ2lk9bWiHVNHd8= gorm.io/driver/sqlserver v1.2.1/go.mod h1:nixq0OB3iLXZDiPv6JSOjWuPgpyaRpOIIevYtA4Ulb4= +gorm.io/driver/sqlserver v1.4.1 h1:t4r4r6Jam5E6ejqP7N82qAJIJAht27EGT41HyPfXRw0= +gorm.io/driver/sqlserver v1.4.1/go.mod h1:DJ4P+MeZbc5rvY58PnmN1Lnyvb5gw5NPzGshHDnJLig= gorm.io/gorm v1.22.2/go.mod h1:F+OptMscr0P2F2qU97WT1WimdH9GaQPoDW7AYd5i2Y0= gorm.io/gorm v1.22.3/go.mod h1:F+OptMscr0P2F2qU97WT1WimdH9GaQPoDW7AYd5i2Y0= gorm.io/gorm v1.22.4 h1:8aPcyEJhY0MAt8aY6Dc524Pn+pO29K+ydu+e/cXSpQM= gorm.io/gorm v1.22.4/go.mod h1:1aeVC+pe9ZmvKZban/gW4QPra7PRoTEssyc922qCAkk= +gorm.io/gorm v1.23.8/go.mod h1:l2lP/RyAtc1ynaTjFksBde/O8v9oOGIApu2/xRitmZk= +gorm.io/gorm v1.24.0 h1:j/CoiSm6xpRpmzbFJsQHYj+I8bGYWLXVHeYEyyKlF74= +gorm.io/gorm v1.24.0/go.mod h1:DVrVomtaYTbqs7gB/x2uVvqnXzv0nqjB396B8cG4dBA= +gorm.io/gorm v1.24.1-0.20221019064659-5dd2bb482755/go.mod h1:DVrVomtaYTbqs7gB/x2uVvqnXzv0nqjB396B8cG4dBA= +gorm.io/gorm v1.24.1 h1:CgvzRniUdG67hBAzsxDGOAuq4Te1osVMYsa1eQbd4fs= +gorm.io/gorm v1.24.1/go.mod h1:DVrVomtaYTbqs7gB/x2uVvqnXzv0nqjB396B8cG4dBA= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= @@ -779,6 +845,38 @@ honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWh honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= +lukechampine.com/uint128 v1.1.1/go.mod h1:c4eWIwlEGaxC/+H1VguhU4PHXNWDCDMUlWdIWl2j1gk= +modernc.org/cc/v3 v3.36.2/go.mod h1:NFUHyPn4ekoC/JHeZFfZurN6ixxawE1BnVonP/oahEI= +modernc.org/cc/v3 v3.37.0/go.mod h1:vtL+3mdHx/wcj3iEGz84rQa8vEqR6XM84v5Lcvfph20= +modernc.org/cc/v3 v3.38.1/go.mod h1:vtL+3mdHx/wcj3iEGz84rQa8vEqR6XM84v5Lcvfph20= +modernc.org/ccgo/v3 v3.0.0-20220904174949-82d86e1b6d56/go.mod h1:YSXjPL62P2AMSxBphRHPn7IkzhVHqkvOnRKAKh+W6ZI= +modernc.org/ccgo/v3 v3.0.0-20220910160915-348f15de615a/go.mod h1:8p47QxPkdugex9J4n9P2tLZ9bK01yngIVp00g4nomW0= +modernc.org/ccgo/v3 v3.16.9/go.mod h1:zNMzC9A9xeNUepy6KuZBbugn3c0Mc9TeiJO4lgvkJDo= +modernc.org/ccorpus v1.11.6/go.mod h1:2gEUTrWqdpH2pXsmTM1ZkjeSrUWDpjMu2T6m29L/ErQ= +modernc.org/httpfs v1.0.6/go.mod h1:7dosgurJGp0sPaRanU53W4xZYKh14wfzX420oZADeHM= +modernc.org/libc v1.17.0/go.mod h1:XsgLldpP4aWlPlsjqKRdHPqCxCjISdHfM/yeWC5GyW0= +modernc.org/libc v1.17.4/go.mod h1:WNg2ZH56rDEwdropAJeZPQkXmDwh+JCA1s/htl6r2fA= +modernc.org/libc v1.18.0/go.mod h1:vj6zehR5bfc98ipowQOM2nIDUZnVew/wNC/2tOGS+q0= +modernc.org/libc v1.19.0 h1:bXyVhGQg6KIClTr8FMVIDPl7jtbcs7aS5WP7vLDaxPs= +modernc.org/libc v1.19.0/go.mod h1:ZRfIaEkgrYgZDl6pa4W39HgN5G/yDW+NRmNKZBDFrk0= +modernc.org/mathutil v1.2.2/go.mod h1:mZW8CKdRPY1v87qxC/wUdX5O1qDzXMP5TH3wjfpga6E= +modernc.org/mathutil v1.4.1/go.mod h1:mZW8CKdRPY1v87qxC/wUdX5O1qDzXMP5TH3wjfpga6E= +modernc.org/mathutil v1.5.0 h1:rV0Ko/6SfM+8G+yKiyI830l3Wuz1zRutdslNoQ0kfiQ= +modernc.org/mathutil v1.5.0/go.mod h1:mZW8CKdRPY1v87qxC/wUdX5O1qDzXMP5TH3wjfpga6E= +modernc.org/memory v1.2.0/go.mod h1:/0wo5ibyrQiaoUoH7f9D8dnglAmILJ5/cxZlRECf+Nw= +modernc.org/memory v1.3.0/go.mod h1:PkUhL0Mugw21sHPeskwZW4D6VscE/GQJOnIpCnW6pSU= +modernc.org/memory v1.4.0 h1:crykUfNSnMAXaOJnnxcSzbUGMqkLWjklJKkBK2nwZwk= +modernc.org/memory v1.4.0/go.mod h1:PkUhL0Mugw21sHPeskwZW4D6VscE/GQJOnIpCnW6pSU= +modernc.org/opt v0.1.1/go.mod h1:WdSiB5evDcignE70guQKxYUl14mgWtbClRi5wmkkTX0= +modernc.org/opt v0.1.3/go.mod h1:WdSiB5evDcignE70guQKxYUl14mgWtbClRi5wmkkTX0= +modernc.org/sqlite v1.19.1 h1:8xmS5oLnZtAK//vnd4aTVj8VOeTAccEFOtUnIzfSw+4= +modernc.org/sqlite v1.19.1/go.mod h1:UfQ83woKMaPW/ZBruK0T7YaFCrI+IE0LeWVY6pmnVms= +modernc.org/strutil v1.1.1/go.mod h1:DE+MQQ/hjKBZS2zNInV5hhcipt5rLPWkmpbGeW5mmdw= +modernc.org/strutil v1.1.3/go.mod h1:MEHNA7PdEnEwLvspRMtWTNnp2nnyvMfkimT1NKNAGbw= +modernc.org/tcl v1.14.0/go.mod h1:gQ7c1YPMvryCHCcmf8acB6VPabE59QBeuRQLL7cTUlM= +modernc.org/token v1.0.0/go.mod h1:UGzOrNV1mAFSEB63lOFHIpNRUVMvYTc6yu1SMY/XTDM= +modernc.org/token v1.0.1/go.mod h1:UGzOrNV1mAFSEB63lOFHIpNRUVMvYTc6yu1SMY/XTDM= +modernc.org/z v1.6.0/go.mod h1:hVdgNMh8ggTuRG1rGU8x+xGRFfiQUIAw0ZqlPy8+HyQ= rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= From 1f2ded421954470c152e7f7b2ddc7b2d3e67bec5 Mon Sep 17 00:00:00 2001 From: Lakhan Samani Date: Wed, 9 Nov 2022 14:15:09 +0530 Subject: [PATCH 40/66] chore: fix tags --- .github/workflows/release.yaml | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml index 0d77c88..0aa5950 100644 --- a/.github/workflows/release.yaml +++ b/.github/workflows/release.yaml @@ -63,7 +63,7 @@ jobs: run: | make clean && \ make build && \ - mkdir -p authorizer-${VERSION}-darwin-amd64/build authorizer-${VERSION}-darwin-amd64/app authorizer-${VERSION}-darwin-amd64/templates authorizer-${VERSION}-darwin-amd64/dashboard && cp build/darwin/amd64/server authorizer-${VERSION}-darwin-amd64/build/ && cp .env authorizer-${VERSION}-darwin-amd64/.env && cp -rf app/build authorizer-${VERSION}-darwin-amd64/app/build && cp -rf templates authorizer-${VERSION}-darwin-amd64/templates && cp -rf dashboard/build authorizer-${VERSION}-darwin-amd64/dashboard/build && tar cvfz authorizer-${VERSION}-darwin-amd64.tar.gz authorizer-${VERSION}-darwin-amd64 + mkdir -p authorizer-${VERSION}-darwin-amd64/build authorizer-${VERSION}-darwin-amd64/app authorizer-${VERSION}-darwin-amd64/dashboard && cp build/darwin/amd64/server authorizer-${VERSION}-darwin-amd64/build/ && cp .env authorizer-${VERSION}-darwin-amd64/.env && cp -rf app/build authorizer-${VERSION}-darwin-amd64/app/build && cp -rf templates authorizer-${VERSION}-darwin-amd64/ && cp -rf dashboard/build authorizer-${VERSION}-darwin-amd64/dashboard/build && tar cvfz authorizer-${VERSION}-darwin-amd64.tar.gz authorizer-${VERSION}-darwin-amd64 - name: Upload assets run: | github-assets-uploader -f authorizer-${VERSION}-darwin-amd64.tar.gz -mediatype application/gzip -repo authorizerdev/authorizer -token ${{secrets.RELEASE_TOKEN}} -tag ${VERSION} @@ -79,7 +79,10 @@ jobs: with: images: lakhansamani/authorizer tags: | - # set latest tag for default branch + type=schedule + type=ref,event=branch + type=ref,event=tag + type=ref,event=pr type=raw,value=latest,enable={{is_default_branch}} - name: Build and push Docker image From 48deae1d11bdf24b7c4e0b02209dfabffce01370 Mon Sep 17 00:00:00 2001 From: Lakhan Samani Date: Wed, 9 Nov 2022 15:02:37 +0530 Subject: [PATCH 41/66] chore: fix multi arch build --- .github/workflows/release.yaml | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml index 0aa5950..46ed7b1 100644 --- a/.github/workflows/release.yaml +++ b/.github/workflows/release.yaml @@ -30,11 +30,6 @@ jobs: # https://github.com/docker/setup-qemu-action name: Set up QEMU uses: docker/setup-qemu-action@v2 - - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v2 - with: - platforms: linux/amd64,linux/arm64 - buildkitd-flags: --debug - uses: actions/setup-go@v2 with: go-version: "^1.17.3" @@ -63,10 +58,16 @@ jobs: run: | make clean && \ make build && \ - mkdir -p authorizer-${VERSION}-darwin-amd64/build authorizer-${VERSION}-darwin-amd64/app authorizer-${VERSION}-darwin-amd64/dashboard && cp build/darwin/amd64/server authorizer-${VERSION}-darwin-amd64/build/ && cp .env authorizer-${VERSION}-darwin-amd64/.env && cp -rf app/build authorizer-${VERSION}-darwin-amd64/app/build && cp -rf templates authorizer-${VERSION}-darwin-amd64/ && cp -rf dashboard/build authorizer-${VERSION}-darwin-amd64/dashboard/build && tar cvfz authorizer-${VERSION}-darwin-amd64.tar.gz authorizer-${VERSION}-darwin-amd64 + mkdir -p authorizer-${VERSION}-darwin-amd64/build authorizer-${VERSION}-darwin-amd64/app authorizer-${VERSION}-darwin-amd64/dashboard && cp build/darwin/amd64/server authorizer-${VERSION}-darwin-amd64/build/ && cp .env authorizer-${VERSION}-darwin-amd64/.env && cp -rf app/build authorizer-${VERSION}-darwin-amd64/app/build && cp -rf templates authorizer-${VERSION}-darwin-amd64/ && cp -rf dashboard/build authorizer-${VERSION}-darwin-amd64/dashboard/build && tar cvfz authorizer-${VERSION}-darwin-amd64.tar.gz authorizer-${VERSION}-darwin-amd64 && \ + mkdir -p authorizer-${VERSION}-linux-amd64/build authorizer-${VERSION}-linux-amd64/app authorizer-${VERSION}-linux-amd64/dashboard && cp build/linux/amd64/server authorizer-${VERSION}-linux-amd64/build/ && cp .env authorizer-${VERSION}-linux-amd64/.env && cp -rf app/build authorizer-${VERSION}-linux-amd64/app/build && cp -rf templates authorizer-${VERSION}-linux-amd64/ && cp -rf dashboard/build authorizer-${VERSION}-linux-amd64/dashboard/build && tar cvfz authorizer-${VERSION}-linux-amd64.tar.gz authorizer-${VERSION}-linux-amd64 && \ + mkdir -p authorizer-${VERSION}-linux-arm64/build authorizer-${VERSION}-linux-arm64/app authorizer-${VERSION}-linux-arm64/dashboard && cp build/linux/arm64/server authorizer-${VERSION}-linux-arm64/build/ && cp .env authorizer-${VERSION}-linux-arm64/.env && cp -rf app/build authorizer-${VERSION}-linux-arm64/app/build && cp -rf templates authorizer-${VERSION}-linux-arm64/ && cp -rf dashboard/build authorizer-${VERSION}-linux-arm64/dashboard/build && tar cvfz authorizer-${VERSION}-linux-arm64.tar.gz authorizer-${VERSION}-linux-arm64 && \ + mkdir -p authorizer-${VERSION}-windows-amd64/build authorizer-${VERSION}-windows-amd64/app authorizer-${VERSION}-windows-amd64/dashboard && cp build/windows/amd64/server.exe authorizer-${VERSION}-windows-amd64/build/ && cp .env authorizer-${VERSION}-windows-amd64/.env && cp -rf app/build authorizer-${VERSION}-windows-amd64/app/build && cp -rf templates authorizer-${VERSION}-windows-amd64/ && cp -rf dashboard/build authorizer-${VERSION}-windows-amd64/dashboard/build && tar cvfz authorizer-${VERSION}-windows-amd64.tar.gz authorizer-${VERSION}-windows-amd64 - name: Upload assets run: | github-assets-uploader -f authorizer-${VERSION}-darwin-amd64.tar.gz -mediatype application/gzip -repo authorizerdev/authorizer -token ${{secrets.RELEASE_TOKEN}} -tag ${VERSION} + github-assets-uploader -f authorizer-${VERSION}-linux-amd64.tar.gz -mediatype application/gzip -repo authorizerdev/authorizer -token ${{secrets.RELEASE_TOKEN}} -tag ${VERSION} + github-assets-uploader -f authorizer-${VERSION}-linux-arm64.tar.gz -mediatype application/gzip -repo authorizerdev/authorizer -token ${{secrets.RELEASE_TOKEN}} -tag ${VERSION} + github-assets-uploader -f authorizer-${VERSION}-windows-amd64.zip -mediatype application/zip -repo authorizerdev/authorizer -token ${{secrets.RELEASE_TOKEN}} -tag ${VERSION} - name: Log in to Docker Hub uses: docker/login-action@v1 with: @@ -78,6 +79,8 @@ jobs: uses: docker/metadata-action@v3 with: images: lakhansamani/authorizer + flavor: | + latest=false tags: | type=schedule type=ref,event=branch @@ -92,5 +95,6 @@ jobs: push: true tags: ${{ steps.meta.outputs.tags }} labels: ${{ steps.meta.outputs.labels }} + platforms: linux/amd64,linux/arm64 build-args: | VERSION=${{ fromJSON(steps.meta.outputs.json).labels['org.opencontainers.image.version'] }} From 67da4a49e4e382117e01fb531cb7f8bfea1f4078 Mon Sep 17 00:00:00 2001 From: Lakhan Samani Date: Wed, 9 Nov 2022 16:07:27 +0530 Subject: [PATCH 42/66] chore: use zip for windows assets --- .github/workflows/release.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml index 46ed7b1..082dc6b 100644 --- a/.github/workflows/release.yaml +++ b/.github/workflows/release.yaml @@ -61,7 +61,7 @@ jobs: mkdir -p authorizer-${VERSION}-darwin-amd64/build authorizer-${VERSION}-darwin-amd64/app authorizer-${VERSION}-darwin-amd64/dashboard && cp build/darwin/amd64/server authorizer-${VERSION}-darwin-amd64/build/ && cp .env authorizer-${VERSION}-darwin-amd64/.env && cp -rf app/build authorizer-${VERSION}-darwin-amd64/app/build && cp -rf templates authorizer-${VERSION}-darwin-amd64/ && cp -rf dashboard/build authorizer-${VERSION}-darwin-amd64/dashboard/build && tar cvfz authorizer-${VERSION}-darwin-amd64.tar.gz authorizer-${VERSION}-darwin-amd64 && \ mkdir -p authorizer-${VERSION}-linux-amd64/build authorizer-${VERSION}-linux-amd64/app authorizer-${VERSION}-linux-amd64/dashboard && cp build/linux/amd64/server authorizer-${VERSION}-linux-amd64/build/ && cp .env authorizer-${VERSION}-linux-amd64/.env && cp -rf app/build authorizer-${VERSION}-linux-amd64/app/build && cp -rf templates authorizer-${VERSION}-linux-amd64/ && cp -rf dashboard/build authorizer-${VERSION}-linux-amd64/dashboard/build && tar cvfz authorizer-${VERSION}-linux-amd64.tar.gz authorizer-${VERSION}-linux-amd64 && \ mkdir -p authorizer-${VERSION}-linux-arm64/build authorizer-${VERSION}-linux-arm64/app authorizer-${VERSION}-linux-arm64/dashboard && cp build/linux/arm64/server authorizer-${VERSION}-linux-arm64/build/ && cp .env authorizer-${VERSION}-linux-arm64/.env && cp -rf app/build authorizer-${VERSION}-linux-arm64/app/build && cp -rf templates authorizer-${VERSION}-linux-arm64/ && cp -rf dashboard/build authorizer-${VERSION}-linux-arm64/dashboard/build && tar cvfz authorizer-${VERSION}-linux-arm64.tar.gz authorizer-${VERSION}-linux-arm64 && \ - mkdir -p authorizer-${VERSION}-windows-amd64/build authorizer-${VERSION}-windows-amd64/app authorizer-${VERSION}-windows-amd64/dashboard && cp build/windows/amd64/server.exe authorizer-${VERSION}-windows-amd64/build/ && cp .env authorizer-${VERSION}-windows-amd64/.env && cp -rf app/build authorizer-${VERSION}-windows-amd64/app/build && cp -rf templates authorizer-${VERSION}-windows-amd64/ && cp -rf dashboard/build authorizer-${VERSION}-windows-amd64/dashboard/build && tar cvfz authorizer-${VERSION}-windows-amd64.tar.gz authorizer-${VERSION}-windows-amd64 + mkdir -p authorizer-${VERSION}-windows-amd64/build authorizer-${VERSION}-windows-amd64/app authorizer-${VERSION}-windows-amd64/dashboard && cp build/windows/amd64/server.exe authorizer-${VERSION}-windows-amd64/build/ && cp .env authorizer-${VERSION}-windows-amd64/.env && cp -rf app/build authorizer-${VERSION}-windows-amd64/app/build && cp -rf templates authorizer-${VERSION}-windows-amd64/ && cp -rf dashboard/build authorizer-${VERSION}-windows-amd64/dashboard/build && zip -vr authorizer-${VERSION}-windows-amd64.zip authorizer-${VERSION}-windows-amd64 - name: Upload assets run: | github-assets-uploader -f authorizer-${VERSION}-darwin-amd64.tar.gz -mediatype application/gzip -repo authorizerdev/authorizer -token ${{secrets.RELEASE_TOKEN}} -tag ${VERSION} From 512fd4f1f7e91e82faac1d89e2be18b94b6ed881 Mon Sep 17 00:00:00 2001 From: Lakhan Samani Date: Wed, 9 Nov 2022 17:36:53 +0530 Subject: [PATCH 43/66] chore: add multi arch setup --- .github/workflows/release.yaml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml index 082dc6b..a1529e0 100644 --- a/.github/workflows/release.yaml +++ b/.github/workflows/release.yaml @@ -30,6 +30,10 @@ jobs: # https://github.com/docker/setup-qemu-action name: Set up QEMU uses: docker/setup-qemu-action@v2 + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v2 + with: + platforms: linux/amd64,linux/arm64 - uses: actions/setup-go@v2 with: go-version: "^1.17.3" From b467e7002df38ddaaa7f211506f4cf45f91eb273 Mon Sep 17 00:00:00 2001 From: anik-ghosh-au7 Date: Wed, 9 Nov 2022 22:17:41 +0530 Subject: [PATCH 44/66] feat: add plain html email template editor --- dashboard/package-lock.json | 1079 +---------------- .../components/UpdateEmailTemplateModal.tsx | 938 +++++++------- dashboard/src/constants.ts | 491 ++++---- 3 files changed, 778 insertions(+), 1730 deletions(-) diff --git a/dashboard/package-lock.json b/dashboard/package-lock.json index ea2eba5..569c165 100644 --- a/dashboard/package-lock.json +++ b/dashboard/package-lock.json @@ -37,19 +37,6 @@ "prettier": "2.7.1" } }, - "node_modules/@ampproject/remapping": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.2.0.tgz", - "integrity": "sha512-qRmjj8nj9qmLTQXXmaR1cck3UXSRMPrbsLJAasZpF+t3riI71BXed5ebIOYwQntykeZuhjsdweEc9BxH5Jc26w==", - "peer": true, - "dependencies": { - "@jridgewell/gen-mapping": "^0.1.0", - "@jridgewell/trace-mapping": "^0.3.9" - }, - "engines": { - "node": ">=6.0.0" - } - }, "node_modules/@babel/code-frame": { "version": "7.18.6", "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.18.6.tgz", @@ -61,125 +48,6 @@ "node": ">=6.9.0" } }, - "node_modules/@babel/compat-data": { - "version": "7.19.3", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.19.3.tgz", - "integrity": "sha512-prBHMK4JYYK+wDjJF1q99KK4JLL+egWS4nmNqdlMUgCExMZ+iZW0hGhyC3VEbsPjvaN0TBhW//VIFwBrk8sEiw==", - "peer": true, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/core": { - "version": "7.19.3", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.19.3.tgz", - "integrity": "sha512-WneDJxdsjEvyKtXKsaBGbDeiyOjR5vYq4HcShxnIbG0qixpoHjI3MqeZM9NDvsojNCEBItQE4juOo/bU6e72gQ==", - "peer": true, - "dependencies": { - "@ampproject/remapping": "^2.1.0", - "@babel/code-frame": "^7.18.6", - "@babel/generator": "^7.19.3", - "@babel/helper-compilation-targets": "^7.19.3", - "@babel/helper-module-transforms": "^7.19.0", - "@babel/helpers": "^7.19.0", - "@babel/parser": "^7.19.3", - "@babel/template": "^7.18.10", - "@babel/traverse": "^7.19.3", - "@babel/types": "^7.19.3", - "convert-source-map": "^1.7.0", - "debug": "^4.1.0", - "gensync": "^1.0.0-beta.2", - "json5": "^2.2.1", - "semver": "^6.3.0" - }, - "engines": { - "node": ">=6.9.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/babel" - } - }, - "node_modules/@babel/generator": { - "version": "7.19.3", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.19.3.tgz", - "integrity": "sha512-fqVZnmp1ncvZU757UzDheKZpfPgatqY59XtW2/j/18H7u76akb8xqvjw82f+i2UKd/ksYsSick/BCLQUUtJ/qQ==", - "peer": true, - "dependencies": { - "@babel/types": "^7.19.3", - "@jridgewell/gen-mapping": "^0.3.2", - "jsesc": "^2.5.1" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/generator/node_modules/@jridgewell/gen-mapping": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.2.tgz", - "integrity": "sha512-mh65xKQAzI6iBcFzwv28KVWSmCkdRBWoOh+bYQGW3+6OZvbbN3TqMGo5hqYxQniRcH9F2VZIoJCm4pa3BPDK/A==", - "peer": true, - "dependencies": { - "@jridgewell/set-array": "^1.0.1", - "@jridgewell/sourcemap-codec": "^1.4.10", - "@jridgewell/trace-mapping": "^0.3.9" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@babel/helper-compilation-targets": { - "version": "7.19.3", - "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.19.3.tgz", - "integrity": "sha512-65ESqLGyGmLvgR0mst5AdW1FkNlj9rQsCKduzEoEPhBCDFGXvz2jW6bXFG6i0/MrV2s7hhXjjb2yAzcPuQlLwg==", - "peer": true, - "dependencies": { - "@babel/compat-data": "^7.19.3", - "@babel/helper-validator-option": "^7.18.6", - "browserslist": "^4.21.3", - "semver": "^6.3.0" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, - "node_modules/@babel/helper-environment-visitor": { - "version": "7.18.9", - "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.18.9.tgz", - "integrity": "sha512-3r/aACDJ3fhQ/EVgFy0hpj8oHyHpQc+LPtJoY9SzTThAsStm4Ptegq92vqKoE3vD706ZVFWITnMnxucw+S9Ipg==", - "peer": true, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-function-name": { - "version": "7.19.0", - "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.19.0.tgz", - "integrity": "sha512-WAwHBINyrpqywkUH0nTnNgI5ina5TFn85HKS0pbPDfxFfhyR/aNQEn4hGi1P1JyT//I0t4OgXUlofzWILRvS5w==", - "peer": true, - "dependencies": { - "@babel/template": "^7.18.10", - "@babel/types": "^7.19.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-hoist-variables": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.18.6.tgz", - "integrity": "sha512-UlJQPkFqFULIcyW5sbzgbkxn2FKRgwWiRexcuaR8RNJRy8+LLveqPjwZV/bwrLZCN0eUHD/x8D0heK1ozuoo6Q==", - "peer": true, - "dependencies": { - "@babel/types": "^7.18.6" - }, - "engines": { - "node": ">=6.9.0" - } - }, "node_modules/@babel/helper-module-imports": { "version": "7.18.6", "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.18.6.tgz", @@ -191,25 +59,6 @@ "node": ">=6.9.0" } }, - "node_modules/@babel/helper-module-transforms": { - "version": "7.19.0", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.19.0.tgz", - "integrity": "sha512-3HBZ377Fe14RbLIA+ac3sY4PTgpxHVkFrESaWhoI5PuyXPBBX8+C34qblV9G89ZtycGJCmCI/Ut+VUDK4bltNQ==", - "peer": true, - "dependencies": { - "@babel/helper-environment-visitor": "^7.18.9", - "@babel/helper-module-imports": "^7.18.6", - "@babel/helper-simple-access": "^7.18.6", - "@babel/helper-split-export-declaration": "^7.18.6", - "@babel/helper-validator-identifier": "^7.18.6", - "@babel/template": "^7.18.10", - "@babel/traverse": "^7.19.0", - "@babel/types": "^7.19.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, "node_modules/@babel/helper-plugin-utils": { "version": "7.16.5", "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.16.5.tgz", @@ -218,30 +67,6 @@ "node": ">=6.9.0" } }, - "node_modules/@babel/helper-simple-access": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.18.6.tgz", - "integrity": "sha512-iNpIgTgyAvDQpDj76POqg+YEt8fPxx3yaNBg3S30dxNKm2SWfYhD0TGrK/Eu9wHpUW63VQU894TsTg+GLbUa1g==", - "peer": true, - "dependencies": { - "@babel/types": "^7.18.6" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-split-export-declaration": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.18.6.tgz", - "integrity": "sha512-bde1etTx6ZyTmobl9LLMMQsaizFVZrquTEHOqKeQESMKo4PlObf+8+JA25ZsIpZhT/WEd39+vOdLXAFG/nELpA==", - "peer": true, - "dependencies": { - "@babel/types": "^7.18.6" - }, - "engines": { - "node": ">=6.9.0" - } - }, "node_modules/@babel/helper-string-parser": { "version": "7.18.10", "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.18.10.tgz", @@ -258,29 +83,6 @@ "node": ">=6.9.0" } }, - "node_modules/@babel/helper-validator-option": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.18.6.tgz", - "integrity": "sha512-XO7gESt5ouv/LRJdrVjkShckw6STTaB7l9BrpBaAHDeF5YZT+01PCwmR0SJHnkW6i8OwW/EVWRShfi4j2x+KQw==", - "peer": true, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helpers": { - "version": "7.19.0", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.19.0.tgz", - "integrity": "sha512-DRBCKGwIEdqY3+rPJgG/dKfQy9+08rHIAJx8q2p+HSWP87s2HCrQmaAMMyMll2kIXKCW0cO1RdQskx15Xakftg==", - "peer": true, - "dependencies": { - "@babel/template": "^7.18.10", - "@babel/traverse": "^7.19.0", - "@babel/types": "^7.19.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, "node_modules/@babel/highlight": { "version": "7.18.6", "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.18.6.tgz", @@ -294,18 +96,6 @@ "node": ">=6.9.0" } }, - "node_modules/@babel/parser": { - "version": "7.19.3", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.19.3.tgz", - "integrity": "sha512-pJ9xOlNWHiy9+FuFP09DEAFbAn4JskgRsVcc169w2xRBC3FRGuQEwjeIMMND9L2zc0iEhO/tGv4Zq+km+hxNpQ==", - "peer": true, - "bin": { - "parser": "bin/babel-parser.js" - }, - "engines": { - "node": ">=6.0.0" - } - }, "node_modules/@babel/plugin-syntax-jsx": { "version": "7.16.5", "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.16.5.tgz", @@ -331,41 +121,6 @@ "node": ">=6.9.0" } }, - "node_modules/@babel/template": { - "version": "7.18.10", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.18.10.tgz", - "integrity": "sha512-TI+rCtooWHr3QJ27kJxfjutghu44DLnasDMwpDqCXVTal9RLp3RSYNh4NdBrRP2cQAoG9A8juOQl6P6oZG4JxA==", - "peer": true, - "dependencies": { - "@babel/code-frame": "^7.18.6", - "@babel/parser": "^7.18.10", - "@babel/types": "^7.18.10" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/traverse": { - "version": "7.19.3", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.19.3.tgz", - "integrity": "sha512-qh5yf6149zhq2sgIXmwjnsvmnNQC2iw70UFjp4olxucKrWd/dvlUsBI88VSLUsnMNF7/vnOiA+nk1+yLoCqROQ==", - "peer": true, - "dependencies": { - "@babel/code-frame": "^7.18.6", - "@babel/generator": "^7.19.3", - "@babel/helper-environment-visitor": "^7.18.9", - "@babel/helper-function-name": "^7.19.0", - "@babel/helper-hoist-variables": "^7.18.6", - "@babel/helper-split-export-declaration": "^7.18.6", - "@babel/parser": "^7.19.3", - "@babel/types": "^7.19.3", - "debug": "^4.1.0", - "globals": "^11.1.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, "node_modules/@babel/types": { "version": "7.19.3", "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.19.3.tgz", @@ -1354,53 +1109,6 @@ "graphql": "^0.8.0 || ^0.9.0 || ^0.10.0 || ^0.11.0 || ^0.12.0 || ^0.13.0 || ^14.0.0 || ^15.0.0 || ^16.0.0" } }, - "node_modules/@jridgewell/gen-mapping": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.1.1.tgz", - "integrity": "sha512-sQXCasFk+U8lWYEe66WxRDOE9PjVz4vSM51fTu3Hw+ClTpUSQb718772vH3pyS5pShp6lvQM7SxgIDXXXmOX7w==", - "peer": true, - "dependencies": { - "@jridgewell/set-array": "^1.0.0", - "@jridgewell/sourcemap-codec": "^1.4.10" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@jridgewell/resolve-uri": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz", - "integrity": "sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==", - "peer": true, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@jridgewell/set-array": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz", - "integrity": "sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==", - "peer": true, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@jridgewell/sourcemap-codec": { - "version": "1.4.14", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz", - "integrity": "sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==", - "peer": true - }, - "node_modules/@jridgewell/trace-mapping": { - "version": "0.3.15", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.15.tgz", - "integrity": "sha512-oWZNOULl+UbhsgB51uuZzglikfIKSUBO/M9W2OfEjn7cmqoAiCgmv9lyACTUacZwBz0ITnJ2NqjU8Tx0DHL88g==", - "peer": true, - "dependencies": { - "@jridgewell/resolve-uri": "^3.0.3", - "@jridgewell/sourcemap-codec": "^1.4.10" - } - }, "node_modules/@popperjs/core": { "version": "2.11.0", "resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.11.0.tgz", @@ -1575,12 +1283,6 @@ "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==" }, - "node_modules/asap": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz", - "integrity": "sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA==", - "peer": true - }, "node_modules/attr-accept": { "version": "2.2.2", "resolved": "https://registry.npmjs.org/attr-accept/-/attr-accept-2.2.2.tgz", @@ -1599,34 +1301,6 @@ "resolve": "^1.12.0" } }, - "node_modules/browserslist": { - "version": "4.21.4", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.21.4.tgz", - "integrity": "sha512-CBHJJdDmgjl3daYjN5Cp5kbTf1mUhZoS+beLklHIvkOWscs83YAhLlF3Wsh/lciQYAcbBJgTOD44VtG31ZM4Hw==", - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/browserslist" - } - ], - "peer": true, - "dependencies": { - "caniuse-lite": "^1.0.30001400", - "electron-to-chromium": "^1.4.251", - "node-releases": "^2.0.6", - "update-browserslist-db": "^1.0.9" - }, - "bin": { - "browserslist": "cli.js" - }, - "engines": { - "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" - } - }, "node_modules/callsites": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", @@ -1635,22 +1309,6 @@ "node": ">=6" } }, - "node_modules/caniuse-lite": { - "version": "1.0.30001414", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001414.tgz", - "integrity": "sha512-t55jfSaWjCdocnFdKQoO+d2ct9C59UZg4dY3OnUlSZ447r8pUtIKdp0hpAzrGFultmTC+Us+KpKi4GZl/LXlFg==", - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/caniuse-lite" - } - ], - "peer": true - }, "node_modules/chalk": { "version": "2.4.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", @@ -1711,17 +1369,6 @@ "toggle-selection": "^1.0.6" } }, - "node_modules/core-js": { - "version": "3.25.3", - "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.25.3.tgz", - "integrity": "sha512-y1hvKXmPHvm5B7w4ln1S4uc9eV/O5+iFExSRUimnvIph11uaizFR8LFMdONN8hG3P2pipUfX4Y/fR8rAEtcHcQ==", - "hasInstallScript": true, - "peer": true, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/core-js" - } - }, "node_modules/cosmiconfig": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-6.0.0.tgz", @@ -1737,15 +1384,6 @@ "node": ">=8" } }, - "node_modules/cross-fetch": { - "version": "3.1.5", - "resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-3.1.5.tgz", - "integrity": "sha512-lvb1SBsI0Z7GDwmuid+mU3kWVBwTVUbe7S0H52yaaAdQOXq2YktTCZdlAcNKFzE6QtRz0snpw9bNiPeOIkkQvw==", - "peer": true, - "dependencies": { - "node-fetch": "2.6.7" - } - }, "node_modules/css-box-model": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/css-box-model/-/css-box-model-1.2.1.tgz", @@ -1769,52 +1407,11 @@ "resolved": "https://registry.npmjs.org/debounce/-/debounce-1.2.1.tgz", "integrity": "sha512-XRRe6Glud4rd/ZGQfiV1ruXSfbvfJedlV9Y6zOlP+2K04vBYiJEte6stfFkCP03aMnY5tsipamumUjL14fofug==" }, - "node_modules/debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", - "peer": true, - "dependencies": { - "ms": "2.1.2" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, "node_modules/detect-node-es": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/detect-node-es/-/detect-node-es-1.1.0.tgz", "integrity": "sha512-ypdmJU/TbBby2Dxibuv7ZLW3Bs1QEmM7nHjEANfohJLvE0XVujisn1qPJcZxg+qDucsr+bP6fLD1rPS3AhJ7EQ==" }, - "node_modules/draft-js": { - "version": "0.11.7", - "resolved": "https://registry.npmjs.org/draft-js/-/draft-js-0.11.7.tgz", - "integrity": "sha512-ne7yFfN4sEL82QPQEn80xnADR8/Q6ALVworbC5UOSzOvjffmYfFsr3xSZtxbIirti14R7Y33EZC5rivpLgIbsg==", - "peer": true, - "dependencies": { - "fbjs": "^2.0.0", - "immutable": "~3.7.4", - "object-assign": "^4.1.1" - }, - "peerDependencies": { - "react": ">=0.14.0", - "react-dom": ">=0.14.0" - } - }, - "node_modules/draft-js/node_modules/immutable": { - "version": "3.7.6", - "resolved": "https://registry.npmjs.org/immutable/-/immutable-3.7.6.tgz", - "integrity": "sha512-AizQPcaofEtO11RZhPPHBOJRdo/20MKQF9mBLnVkBoyHi1/zXK8fzVdnEpSV9gxqtnh6Qomfp3F0xT5qP/vThw==", - "peer": true, - "engines": { - "node": ">=0.8.0" - } - }, "node_modules/draftjs-utils": { "version": "0.10.2", "resolved": "https://registry.npmjs.org/draftjs-utils/-/draftjs-utils-0.10.2.tgz", @@ -1824,12 +1421,6 @@ "immutable": "3.x.x || 4.x.x" } }, - "node_modules/electron-to-chromium": { - "version": "1.4.270", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.270.tgz", - "integrity": "sha512-KNhIzgLiJmDDC444dj9vEOpZEgsV96ult9Iff98Vanumn+ShJHd5se8aX6KeVxdc0YQeqdrezBZv89rleDbvSg==", - "peer": true - }, "node_modules/error-ex": { "version": "1.3.2", "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", @@ -2083,15 +1674,6 @@ "win32" ] }, - "node_modules/escalade": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", - "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", - "peer": true, - "engines": { - "node": ">=6" - } - }, "node_modules/escape-string-regexp": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", @@ -2103,28 +1685,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/fbjs": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/fbjs/-/fbjs-2.0.0.tgz", - "integrity": "sha512-8XA8ny9ifxrAWlyhAbexXcs3rRMtxWcs3M0lctLfB49jRDHiaxj+Mo0XxbwE7nKZYzgCFoq64FS+WFd4IycPPQ==", - "peer": true, - "dependencies": { - "core-js": "^3.6.4", - "cross-fetch": "^3.0.4", - "fbjs-css-vars": "^1.0.0", - "loose-envify": "^1.0.0", - "object-assign": "^4.1.0", - "promise": "^7.1.1", - "setimmediate": "^1.0.5", - "ua-parser-js": "^0.7.18" - } - }, - "node_modules/fbjs-css-vars": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/fbjs-css-vars/-/fbjs-css-vars-1.0.2.tgz", - "integrity": "sha512-b2XGFAFdWZWg0phtAWLHCk836A1Xann+I+Dgd3Gk64MHKZO44FfoD1KxyvbSh0qZsIoXQGGlVztIY+oitJPpRQ==", - "peer": true - }, "node_modules/file-selector": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/file-selector/-/file-selector-0.4.0.tgz", @@ -2224,15 +1784,6 @@ "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" }, - "node_modules/gensync": { - "version": "1.0.0-beta.2", - "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", - "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", - "peer": true, - "engines": { - "node": ">=6.9.0" - } - }, "node_modules/get-nonce": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/get-nonce/-/get-nonce-1.0.1.tgz", @@ -2241,15 +1792,6 @@ "node": ">=6" } }, - "node_modules/globals": { - "version": "11.12.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", - "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", - "peer": true, - "engines": { - "node": ">=4" - } - }, "node_modules/graphql": { "version": "16.2.0", "resolved": "https://registry.npmjs.org/graphql/-/graphql-16.2.0.tgz", @@ -2307,12 +1849,6 @@ "immutable": "3.x.x || 4.x.x" } }, - "node_modules/immutable": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/immutable/-/immutable-4.1.0.tgz", - "integrity": "sha512-oNkuqVTA8jqG1Q6c+UglTOD1xhC1BtjKI7XkCXRkZHrN5m18/XsnUp8Q89GkQO/z+0WjonSvl0FLhDYftp46nQ==", - "peer": true - }, "node_modules/import-fresh": { "version": "3.3.0", "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", @@ -2357,35 +1893,11 @@ "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==" }, - "node_modules/jsesc": { - "version": "2.5.2", - "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", - "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", - "peer": true, - "bin": { - "jsesc": "bin/jsesc" - }, - "engines": { - "node": ">=4" - } - }, "node_modules/json-parse-even-better-errors": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==" }, - "node_modules/json5": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.1.tgz", - "integrity": "sha512-1hqLFMSrGHRHxav9q9gNjJ5EXznIxGVO09xQRrwplcS8qs28pZ8s8hupZAmqDwZUmVZ2Qb2jnyPOWcDH8m8dlA==", - "peer": true, - "bin": { - "json5": "lib/cli.js" - }, - "engines": { - "node": ">=6" - } - }, "node_modules/lines-and-columns": { "version": "1.2.4", "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", @@ -2420,38 +1932,6 @@ "loose-envify": "cli.js" } }, - "node_modules/ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "peer": true - }, - "node_modules/node-fetch": { - "version": "2.6.7", - "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.7.tgz", - "integrity": "sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==", - "peer": true, - "dependencies": { - "whatwg-url": "^5.0.0" - }, - "engines": { - "node": "4.x || >=6.0.0" - }, - "peerDependencies": { - "encoding": "^0.1.0" - }, - "peerDependenciesMeta": { - "encoding": { - "optional": true - } - } - }, - "node_modules/node-releases": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.6.tgz", - "integrity": "sha512-PiVXnNuFm5+iYkLBNeq5211hvO38y63T0i2KKh2KnUs3RpzJ+JtODFjkD8yjLwnDkTYF1eKXheUwdssR+NRZdg==", - "peer": true - }, "node_modules/object-assign": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", @@ -2501,12 +1981,6 @@ "node": ">=8" } }, - "node_modules/picocolors": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", - "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==", - "peer": true - }, "node_modules/popmotion": { "version": "11.0.3", "resolved": "https://registry.npmjs.org/popmotion/-/popmotion-11.0.3.tgz", @@ -2541,15 +2015,6 @@ "url": "https://github.com/prettier/prettier?sponsor=1" } }, - "node_modules/promise": { - "version": "7.3.1", - "resolved": "https://registry.npmjs.org/promise/-/promise-7.3.1.tgz", - "integrity": "sha512-nolQXZ/4L+bP/UGlkfaIujX9BKxGwmQ9OT4mOt5yvy8iK1h3wqTEJCijzGANTCCl9nWjY41juyAn2K3Q1hLLTg==", - "peer": true, - "dependencies": { - "asap": "~2.0.3" - } - }, "node_modules/prop-types": { "version": "15.8.1", "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz", @@ -2838,21 +2303,6 @@ "object-assign": "^4.1.1" } }, - "node_modules/semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", - "peer": true, - "bin": { - "semver": "bin/semver.js" - } - }, - "node_modules/setimmediate": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz", - "integrity": "sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA==", - "peer": true - }, "node_modules/source-map": { "version": "0.5.7", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", @@ -2904,12 +2354,6 @@ "resolved": "https://registry.npmjs.org/toggle-selection/-/toggle-selection-1.0.6.tgz", "integrity": "sha1-bkWxJj8gF/oKzH2J14sVuL932jI=" }, - "node_modules/tr46": { - "version": "0.0.3", - "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", - "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==", - "peer": true - }, "node_modules/tslib": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.3.1.tgz", @@ -2927,56 +2371,11 @@ "node": ">=4.2.0" } }, - "node_modules/ua-parser-js": { - "version": "0.7.31", - "resolved": "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-0.7.31.tgz", - "integrity": "sha512-qLK/Xe9E2uzmYI3qLeOmI0tEOt+TBBQyUIAh4aAgU05FVYzeZrKUdkAZfBNVGRaHVgV0TDkdEngJSw/SyQchkQ==", - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/ua-parser-js" - }, - { - "type": "paypal", - "url": "https://paypal.me/faisalman" - } - ], - "peer": true, - "engines": { - "node": "*" - } - }, "node_modules/uc.micro": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/uc.micro/-/uc.micro-1.0.6.tgz", "integrity": "sha512-8Y75pvTYkLJW2hWQHXxoqRgV7qb9B+9vFEtidML+7koHUFapnVJAZ6cKs+Qjz5Aw3aZWHMC6u0wJE3At+nSGwA==" }, - "node_modules/update-browserslist-db": { - "version": "1.0.9", - "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.9.tgz", - "integrity": "sha512-/xsqn21EGVdXI3EXSum1Yckj3ZVZugqyOZQ/CxYPBD/R+ko9NSUScf8tFF4dOKY+2pvSSJA/S+5B8s4Zr4kyvg==", - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/browserslist" - } - ], - "peer": true, - "dependencies": { - "escalade": "^3.1.1", - "picocolors": "^1.0.0" - }, - "bin": { - "browserslist-lint": "cli.js" - }, - "peerDependencies": { - "browserslist": ">= 4.21.0" - } - }, "node_modules/urql": { "version": "2.0.6", "resolved": "https://registry.npmjs.org/urql/-/urql-2.0.6.tgz", @@ -3035,22 +2434,6 @@ "loose-envify": "^1.0.0" } }, - "node_modules/webidl-conversions": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", - "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==", - "peer": true - }, - "node_modules/whatwg-url": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", - "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", - "peer": true, - "dependencies": { - "tr46": "~0.0.3", - "webidl-conversions": "^3.0.0" - } - }, "node_modules/wonka": { "version": "4.0.15", "resolved": "https://registry.npmjs.org/wonka/-/wonka-4.0.15.tgz", @@ -3066,16 +2449,6 @@ } }, "dependencies": { - "@ampproject/remapping": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.2.0.tgz", - "integrity": "sha512-qRmjj8nj9qmLTQXXmaR1cck3UXSRMPrbsLJAasZpF+t3riI71BXed5ebIOYwQntykeZuhjsdweEc9BxH5Jc26w==", - "peer": true, - "requires": { - "@jridgewell/gen-mapping": "^0.1.0", - "@jridgewell/trace-mapping": "^0.3.9" - } - }, "@babel/code-frame": { "version": "7.18.6", "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.18.6.tgz", @@ -3084,96 +2457,6 @@ "@babel/highlight": "^7.18.6" } }, - "@babel/compat-data": { - "version": "7.19.3", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.19.3.tgz", - "integrity": "sha512-prBHMK4JYYK+wDjJF1q99KK4JLL+egWS4nmNqdlMUgCExMZ+iZW0hGhyC3VEbsPjvaN0TBhW//VIFwBrk8sEiw==", - "peer": true - }, - "@babel/core": { - "version": "7.19.3", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.19.3.tgz", - "integrity": "sha512-WneDJxdsjEvyKtXKsaBGbDeiyOjR5vYq4HcShxnIbG0qixpoHjI3MqeZM9NDvsojNCEBItQE4juOo/bU6e72gQ==", - "peer": true, - "requires": { - "@ampproject/remapping": "^2.1.0", - "@babel/code-frame": "^7.18.6", - "@babel/generator": "^7.19.3", - "@babel/helper-compilation-targets": "^7.19.3", - "@babel/helper-module-transforms": "^7.19.0", - "@babel/helpers": "^7.19.0", - "@babel/parser": "^7.19.3", - "@babel/template": "^7.18.10", - "@babel/traverse": "^7.19.3", - "@babel/types": "^7.19.3", - "convert-source-map": "^1.7.0", - "debug": "^4.1.0", - "gensync": "^1.0.0-beta.2", - "json5": "^2.2.1", - "semver": "^6.3.0" - } - }, - "@babel/generator": { - "version": "7.19.3", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.19.3.tgz", - "integrity": "sha512-fqVZnmp1ncvZU757UzDheKZpfPgatqY59XtW2/j/18H7u76akb8xqvjw82f+i2UKd/ksYsSick/BCLQUUtJ/qQ==", - "peer": true, - "requires": { - "@babel/types": "^7.19.3", - "@jridgewell/gen-mapping": "^0.3.2", - "jsesc": "^2.5.1" - }, - "dependencies": { - "@jridgewell/gen-mapping": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.2.tgz", - "integrity": "sha512-mh65xKQAzI6iBcFzwv28KVWSmCkdRBWoOh+bYQGW3+6OZvbbN3TqMGo5hqYxQniRcH9F2VZIoJCm4pa3BPDK/A==", - "peer": true, - "requires": { - "@jridgewell/set-array": "^1.0.1", - "@jridgewell/sourcemap-codec": "^1.4.10", - "@jridgewell/trace-mapping": "^0.3.9" - } - } - } - }, - "@babel/helper-compilation-targets": { - "version": "7.19.3", - "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.19.3.tgz", - "integrity": "sha512-65ESqLGyGmLvgR0mst5AdW1FkNlj9rQsCKduzEoEPhBCDFGXvz2jW6bXFG6i0/MrV2s7hhXjjb2yAzcPuQlLwg==", - "peer": true, - "requires": { - "@babel/compat-data": "^7.19.3", - "@babel/helper-validator-option": "^7.18.6", - "browserslist": "^4.21.3", - "semver": "^6.3.0" - } - }, - "@babel/helper-environment-visitor": { - "version": "7.18.9", - "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.18.9.tgz", - "integrity": "sha512-3r/aACDJ3fhQ/EVgFy0hpj8oHyHpQc+LPtJoY9SzTThAsStm4Ptegq92vqKoE3vD706ZVFWITnMnxucw+S9Ipg==", - "peer": true - }, - "@babel/helper-function-name": { - "version": "7.19.0", - "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.19.0.tgz", - "integrity": "sha512-WAwHBINyrpqywkUH0nTnNgI5ina5TFn85HKS0pbPDfxFfhyR/aNQEn4hGi1P1JyT//I0t4OgXUlofzWILRvS5w==", - "peer": true, - "requires": { - "@babel/template": "^7.18.10", - "@babel/types": "^7.19.0" - } - }, - "@babel/helper-hoist-variables": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.18.6.tgz", - "integrity": "sha512-UlJQPkFqFULIcyW5sbzgbkxn2FKRgwWiRexcuaR8RNJRy8+LLveqPjwZV/bwrLZCN0eUHD/x8D0heK1ozuoo6Q==", - "peer": true, - "requires": { - "@babel/types": "^7.18.6" - } - }, "@babel/helper-module-imports": { "version": "7.18.6", "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.18.6.tgz", @@ -3182,45 +2465,11 @@ "@babel/types": "^7.18.6" } }, - "@babel/helper-module-transforms": { - "version": "7.19.0", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.19.0.tgz", - "integrity": "sha512-3HBZ377Fe14RbLIA+ac3sY4PTgpxHVkFrESaWhoI5PuyXPBBX8+C34qblV9G89ZtycGJCmCI/Ut+VUDK4bltNQ==", - "peer": true, - "requires": { - "@babel/helper-environment-visitor": "^7.18.9", - "@babel/helper-module-imports": "^7.18.6", - "@babel/helper-simple-access": "^7.18.6", - "@babel/helper-split-export-declaration": "^7.18.6", - "@babel/helper-validator-identifier": "^7.18.6", - "@babel/template": "^7.18.10", - "@babel/traverse": "^7.19.0", - "@babel/types": "^7.19.0" - } - }, "@babel/helper-plugin-utils": { "version": "7.16.5", "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.16.5.tgz", "integrity": "sha512-59KHWHXxVA9K4HNF4sbHCf+eJeFe0Te/ZFGqBT4OjXhrwvA04sGfaEGsVTdsjoszq0YTP49RC9UKe5g8uN2RwQ==" }, - "@babel/helper-simple-access": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.18.6.tgz", - "integrity": "sha512-iNpIgTgyAvDQpDj76POqg+YEt8fPxx3yaNBg3S30dxNKm2SWfYhD0TGrK/Eu9wHpUW63VQU894TsTg+GLbUa1g==", - "peer": true, - "requires": { - "@babel/types": "^7.18.6" - } - }, - "@babel/helper-split-export-declaration": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.18.6.tgz", - "integrity": "sha512-bde1etTx6ZyTmobl9LLMMQsaizFVZrquTEHOqKeQESMKo4PlObf+8+JA25ZsIpZhT/WEd39+vOdLXAFG/nELpA==", - "peer": true, - "requires": { - "@babel/types": "^7.18.6" - } - }, "@babel/helper-string-parser": { "version": "7.18.10", "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.18.10.tgz", @@ -3231,23 +2480,6 @@ "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.19.1.tgz", "integrity": "sha512-awrNfaMtnHUr653GgGEs++LlAvW6w+DcPrOliSMXWCKo597CwL5Acf/wWdNkf/tfEQE3mjkeD1YOVZOUV/od1w==" }, - "@babel/helper-validator-option": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.18.6.tgz", - "integrity": "sha512-XO7gESt5ouv/LRJdrVjkShckw6STTaB7l9BrpBaAHDeF5YZT+01PCwmR0SJHnkW6i8OwW/EVWRShfi4j2x+KQw==", - "peer": true - }, - "@babel/helpers": { - "version": "7.19.0", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.19.0.tgz", - "integrity": "sha512-DRBCKGwIEdqY3+rPJgG/dKfQy9+08rHIAJx8q2p+HSWP87s2HCrQmaAMMyMll2kIXKCW0cO1RdQskx15Xakftg==", - "peer": true, - "requires": { - "@babel/template": "^7.18.10", - "@babel/traverse": "^7.19.0", - "@babel/types": "^7.19.0" - } - }, "@babel/highlight": { "version": "7.18.6", "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.18.6.tgz", @@ -3258,12 +2490,6 @@ "js-tokens": "^4.0.0" } }, - "@babel/parser": { - "version": "7.19.3", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.19.3.tgz", - "integrity": "sha512-pJ9xOlNWHiy9+FuFP09DEAFbAn4JskgRsVcc169w2xRBC3FRGuQEwjeIMMND9L2zc0iEhO/tGv4Zq+km+hxNpQ==", - "peer": true - }, "@babel/plugin-syntax-jsx": { "version": "7.16.5", "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.16.5.tgz", @@ -3280,35 +2506,6 @@ "regenerator-runtime": "^0.13.4" } }, - "@babel/template": { - "version": "7.18.10", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.18.10.tgz", - "integrity": "sha512-TI+rCtooWHr3QJ27kJxfjutghu44DLnasDMwpDqCXVTal9RLp3RSYNh4NdBrRP2cQAoG9A8juOQl6P6oZG4JxA==", - "peer": true, - "requires": { - "@babel/code-frame": "^7.18.6", - "@babel/parser": "^7.18.10", - "@babel/types": "^7.18.10" - } - }, - "@babel/traverse": { - "version": "7.19.3", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.19.3.tgz", - "integrity": "sha512-qh5yf6149zhq2sgIXmwjnsvmnNQC2iw70UFjp4olxucKrWd/dvlUsBI88VSLUsnMNF7/vnOiA+nk1+yLoCqROQ==", - "peer": true, - "requires": { - "@babel/code-frame": "^7.18.6", - "@babel/generator": "^7.19.3", - "@babel/helper-environment-visitor": "^7.18.9", - "@babel/helper-function-name": "^7.19.0", - "@babel/helper-hoist-variables": "^7.18.6", - "@babel/helper-split-export-declaration": "^7.18.6", - "@babel/parser": "^7.19.3", - "@babel/types": "^7.19.3", - "debug": "^4.1.0", - "globals": "^11.1.0" - } - }, "@babel/types": { "version": "7.19.3", "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.19.3.tgz", @@ -3439,8 +2636,7 @@ "@chakra-ui/css-reset": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/@chakra-ui/css-reset/-/css-reset-1.1.1.tgz", - "integrity": "sha512-+KNNHL4OWqeKia5SL858K3Qbd8WxMij9mWIilBzLD4j2KFrl/+aWFw8syMKth3NmgIibrjsljo+PU3fy2o50dg==", - "requires": {} + "integrity": "sha512-+KNNHL4OWqeKia5SL858K3Qbd8WxMij9mWIilBzLD4j2KFrl/+aWFw8syMKth3NmgIibrjsljo+PU3fy2o50dg==" }, "@chakra-ui/descendant": { "version": "2.1.1", @@ -4044,46 +3240,7 @@ "@graphql-typed-document-node/core": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/@graphql-typed-document-node/core/-/core-3.1.1.tgz", - "integrity": "sha512-NQ17ii0rK1b34VZonlmT2QMJFI70m0TRwbknO/ihlbatXyaktDhN/98vBiUU6kNBPljqGqyIrl2T4nY2RpFANg==", - "requires": {} - }, - "@jridgewell/gen-mapping": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.1.1.tgz", - "integrity": "sha512-sQXCasFk+U8lWYEe66WxRDOE9PjVz4vSM51fTu3Hw+ClTpUSQb718772vH3pyS5pShp6lvQM7SxgIDXXXmOX7w==", - "peer": true, - "requires": { - "@jridgewell/set-array": "^1.0.0", - "@jridgewell/sourcemap-codec": "^1.4.10" - } - }, - "@jridgewell/resolve-uri": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz", - "integrity": "sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==", - "peer": true - }, - "@jridgewell/set-array": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz", - "integrity": "sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==", - "peer": true - }, - "@jridgewell/sourcemap-codec": { - "version": "1.4.14", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz", - "integrity": "sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==", - "peer": true - }, - "@jridgewell/trace-mapping": { - "version": "0.3.15", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.15.tgz", - "integrity": "sha512-oWZNOULl+UbhsgB51uuZzglikfIKSUBO/M9W2OfEjn7cmqoAiCgmv9lyACTUacZwBz0ITnJ2NqjU8Tx0DHL88g==", - "peer": true, - "requires": { - "@jridgewell/resolve-uri": "^3.0.3", - "@jridgewell/sourcemap-codec": "^1.4.10" - } + "integrity": "sha512-NQ17ii0rK1b34VZonlmT2QMJFI70m0TRwbknO/ihlbatXyaktDhN/98vBiUU6kNBPljqGqyIrl2T4nY2RpFANg==" }, "@popperjs/core": { "version": "2.11.0", @@ -4236,12 +3393,6 @@ } } }, - "asap": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz", - "integrity": "sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA==", - "peer": true - }, "attr-accept": { "version": "2.2.2", "resolved": "https://registry.npmjs.org/attr-accept/-/attr-accept-2.2.2.tgz", @@ -4257,29 +3408,11 @@ "resolve": "^1.12.0" } }, - "browserslist": { - "version": "4.21.4", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.21.4.tgz", - "integrity": "sha512-CBHJJdDmgjl3daYjN5Cp5kbTf1mUhZoS+beLklHIvkOWscs83YAhLlF3Wsh/lciQYAcbBJgTOD44VtG31ZM4Hw==", - "peer": true, - "requires": { - "caniuse-lite": "^1.0.30001400", - "electron-to-chromium": "^1.4.251", - "node-releases": "^2.0.6", - "update-browserslist-db": "^1.0.9" - } - }, "callsites": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==" }, - "caniuse-lite": { - "version": "1.0.30001414", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001414.tgz", - "integrity": "sha512-t55jfSaWjCdocnFdKQoO+d2ct9C59UZg4dY3OnUlSZ447r8pUtIKdp0hpAzrGFultmTC+Us+KpKi4GZl/LXlFg==", - "peer": true - }, "chalk": { "version": "2.4.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", @@ -4336,12 +3469,6 @@ "toggle-selection": "^1.0.6" } }, - "core-js": { - "version": "3.25.3", - "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.25.3.tgz", - "integrity": "sha512-y1hvKXmPHvm5B7w4ln1S4uc9eV/O5+iFExSRUimnvIph11uaizFR8LFMdONN8hG3P2pipUfX4Y/fR8rAEtcHcQ==", - "peer": true - }, "cosmiconfig": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-6.0.0.tgz", @@ -4354,15 +3481,6 @@ "yaml": "^1.7.2" } }, - "cross-fetch": { - "version": "3.1.5", - "resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-3.1.5.tgz", - "integrity": "sha512-lvb1SBsI0Z7GDwmuid+mU3kWVBwTVUbe7S0H52yaaAdQOXq2YktTCZdlAcNKFzE6QtRz0snpw9bNiPeOIkkQvw==", - "peer": true, - "requires": { - "node-fetch": "2.6.7" - } - }, "css-box-model": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/css-box-model/-/css-box-model-1.2.1.tgz", @@ -4386,50 +3504,15 @@ "resolved": "https://registry.npmjs.org/debounce/-/debounce-1.2.1.tgz", "integrity": "sha512-XRRe6Glud4rd/ZGQfiV1ruXSfbvfJedlV9Y6zOlP+2K04vBYiJEte6stfFkCP03aMnY5tsipamumUjL14fofug==" }, - "debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", - "peer": true, - "requires": { - "ms": "2.1.2" - } - }, "detect-node-es": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/detect-node-es/-/detect-node-es-1.1.0.tgz", "integrity": "sha512-ypdmJU/TbBby2Dxibuv7ZLW3Bs1QEmM7nHjEANfohJLvE0XVujisn1qPJcZxg+qDucsr+bP6fLD1rPS3AhJ7EQ==" }, - "draft-js": { - "version": "0.11.7", - "resolved": "https://registry.npmjs.org/draft-js/-/draft-js-0.11.7.tgz", - "integrity": "sha512-ne7yFfN4sEL82QPQEn80xnADR8/Q6ALVworbC5UOSzOvjffmYfFsr3xSZtxbIirti14R7Y33EZC5rivpLgIbsg==", - "peer": true, - "requires": { - "fbjs": "^2.0.0", - "immutable": "~3.7.4", - "object-assign": "^4.1.1" - }, - "dependencies": { - "immutable": { - "version": "3.7.6", - "resolved": "https://registry.npmjs.org/immutable/-/immutable-3.7.6.tgz", - "integrity": "sha512-AizQPcaofEtO11RZhPPHBOJRdo/20MKQF9mBLnVkBoyHi1/zXK8fzVdnEpSV9gxqtnh6Qomfp3F0xT5qP/vThw==", - "peer": true - } - } - }, "draftjs-utils": { "version": "0.10.2", "resolved": "https://registry.npmjs.org/draftjs-utils/-/draftjs-utils-0.10.2.tgz", - "integrity": "sha512-EstHqr3R3JVcilJrBaO/A+01GvwwKmC7e4TCjC7S94ZeMh4IVmf60OuQXtHHpwItK8C2JCi3iljgN5KHkJboUg==", - "requires": {} - }, - "electron-to-chromium": { - "version": "1.4.270", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.270.tgz", - "integrity": "sha512-KNhIzgLiJmDDC444dj9vEOpZEgsV96ult9Iff98Vanumn+ShJHd5se8aX6KeVxdc0YQeqdrezBZv89rleDbvSg==", - "peer": true + "integrity": "sha512-EstHqr3R3JVcilJrBaO/A+01GvwwKmC7e4TCjC7S94ZeMh4IVmf60OuQXtHHpwItK8C2JCi3iljgN5KHkJboUg==" }, "error-ex": { "version": "1.3.2", @@ -4572,39 +3655,11 @@ "integrity": "sha512-NKPPsYVlHqdF0yMuMJrjuAzqS/BHrMXZ8TN1Du+Pgi8KkmxzNXRPDHQV0NPPJ+Z7Lp09joEHSz1zrvQRs1j6jw==", "optional": true }, - "escalade": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", - "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", - "peer": true - }, "escape-string-regexp": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==" }, - "fbjs": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/fbjs/-/fbjs-2.0.0.tgz", - "integrity": "sha512-8XA8ny9ifxrAWlyhAbexXcs3rRMtxWcs3M0lctLfB49jRDHiaxj+Mo0XxbwE7nKZYzgCFoq64FS+WFd4IycPPQ==", - "peer": true, - "requires": { - "core-js": "^3.6.4", - "cross-fetch": "^3.0.4", - "fbjs-css-vars": "^1.0.0", - "loose-envify": "^1.0.0", - "object-assign": "^4.1.0", - "promise": "^7.1.1", - "setimmediate": "^1.0.5", - "ua-parser-js": "^0.7.18" - } - }, - "fbjs-css-vars": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/fbjs-css-vars/-/fbjs-css-vars-1.0.2.tgz", - "integrity": "sha512-b2XGFAFdWZWg0phtAWLHCk836A1Xann+I+Dgd3Gk64MHKZO44FfoD1KxyvbSh0qZsIoXQGGlVztIY+oitJPpRQ==", - "peer": true - }, "file-selector": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/file-selector/-/file-selector-0.4.0.tgz", @@ -4684,23 +3739,11 @@ "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" }, - "gensync": { - "version": "1.0.0-beta.2", - "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", - "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", - "peer": true - }, "get-nonce": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/get-nonce/-/get-nonce-1.0.1.tgz", "integrity": "sha512-FJhYRoDaiatfEkUK8HKlicmu/3SGFD51q3itKDGoSTysQJBnfOcxU5GxnhE1E6soB76MbT0MBtnKJuXyAx+96Q==" }, - "globals": { - "version": "11.12.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", - "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", - "peer": true - }, "graphql": { "version": "16.2.0", "resolved": "https://registry.npmjs.org/graphql/-/graphql-16.2.0.tgz", @@ -4743,14 +3786,7 @@ "html-to-draftjs": { "version": "1.5.0", "resolved": "https://registry.npmjs.org/html-to-draftjs/-/html-to-draftjs-1.5.0.tgz", - "integrity": "sha512-kggLXBNciKDwKf+KYsuE+V5gw4dZ7nHyGMX9m0wy7urzWjKGWyNFetmArRLvRV0VrxKN70WylFsJvMTJx02OBQ==", - "requires": {} - }, - "immutable": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/immutable/-/immutable-4.1.0.tgz", - "integrity": "sha512-oNkuqVTA8jqG1Q6c+UglTOD1xhC1BtjKI7XkCXRkZHrN5m18/XsnUp8Q89GkQO/z+0WjonSvl0FLhDYftp46nQ==", - "peer": true + "integrity": "sha512-kggLXBNciKDwKf+KYsuE+V5gw4dZ7nHyGMX9m0wy7urzWjKGWyNFetmArRLvRV0VrxKN70WylFsJvMTJx02OBQ==" }, "import-fresh": { "version": "3.3.0", @@ -4787,23 +3823,11 @@ "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==" }, - "jsesc": { - "version": "2.5.2", - "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", - "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", - "peer": true - }, "json-parse-even-better-errors": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==" }, - "json5": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.1.tgz", - "integrity": "sha512-1hqLFMSrGHRHxav9q9gNjJ5EXznIxGVO09xQRrwplcS8qs28pZ8s8hupZAmqDwZUmVZ2Qb2jnyPOWcDH8m8dlA==", - "peer": true - }, "lines-and-columns": { "version": "1.2.4", "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", @@ -4835,27 +3859,6 @@ "js-tokens": "^3.0.0 || ^4.0.0" } }, - "ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "peer": true - }, - "node-fetch": { - "version": "2.6.7", - "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.7.tgz", - "integrity": "sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==", - "peer": true, - "requires": { - "whatwg-url": "^5.0.0" - } - }, - "node-releases": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.6.tgz", - "integrity": "sha512-PiVXnNuFm5+iYkLBNeq5211hvO38y63T0i2KKh2KnUs3RpzJ+JtODFjkD8yjLwnDkTYF1eKXheUwdssR+NRZdg==", - "peer": true - }, "object-assign": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", @@ -4890,12 +3893,6 @@ "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==" }, - "picocolors": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", - "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==", - "peer": true - }, "popmotion": { "version": "11.0.3", "resolved": "https://registry.npmjs.org/popmotion/-/popmotion-11.0.3.tgz", @@ -4923,15 +3920,6 @@ "integrity": "sha512-ujppO+MkdPqoVINuDFDRLClm7D78qbDt0/NR+wp5FqEZOoTNAjPHWj17QRhu7geIHJfcNhRk1XVQmF8Bp3ye+g==", "dev": true }, - "promise": { - "version": "7.3.1", - "resolved": "https://registry.npmjs.org/promise/-/promise-7.3.1.tgz", - "integrity": "sha512-nolQXZ/4L+bP/UGlkfaIujX9BKxGwmQ9OT4mOt5yvy8iK1h3wqTEJCijzGANTCCl9nWjY41juyAn2K3Q1hLLTg==", - "peer": true, - "requires": { - "asap": "~2.0.3" - } - }, "prop-types": { "version": "15.8.1", "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz", @@ -4994,8 +3982,7 @@ "react-email-editor": { "version": "1.6.1", "resolved": "https://registry.npmjs.org/react-email-editor/-/react-email-editor-1.6.1.tgz", - "integrity": "sha512-pEWpRmTY0ok03cwTGqEOoEldnzThhuRGTrcMnv8W3/jc5MTfcr9USU/IQ9HrVvFStLKoxYBIQnSKY+iCYWOtSQ==", - "requires": {} + "integrity": "sha512-pEWpRmTY0ok03cwTGqEOoEldnzThhuRGTrcMnv8W3/jc5MTfcr9USU/IQ9HrVvFStLKoxYBIQnSKY+iCYWOtSQ==" }, "react-fast-compare": { "version": "3.2.0", @@ -5018,8 +4005,7 @@ "react-icons": { "version": "4.3.1", "resolved": "https://registry.npmjs.org/react-icons/-/react-icons-4.3.1.tgz", - "integrity": "sha512-cB10MXLTs3gVuXimblAdI71jrJx8njrJZmNMEMC+sQu5B/BIOmlsAjskdqpn81y8UBVEGuHODd7/ci5DvoSzTQ==", - "requires": {} + "integrity": "sha512-cB10MXLTs3gVuXimblAdI71jrJx8njrJZmNMEMC+sQu5B/BIOmlsAjskdqpn81y8UBVEGuHODd7/ci5DvoSzTQ==" }, "react-is": { "version": "16.13.1", @@ -5141,18 +4127,6 @@ "object-assign": "^4.1.1" } }, - "semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", - "peer": true - }, - "setimmediate": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz", - "integrity": "sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA==", - "peer": true - }, "source-map": { "version": "0.5.7", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", @@ -5195,12 +4169,6 @@ "resolved": "https://registry.npmjs.org/toggle-selection/-/toggle-selection-1.0.6.tgz", "integrity": "sha1-bkWxJj8gF/oKzH2J14sVuL932jI=" }, - "tr46": { - "version": "0.0.3", - "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", - "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==", - "peer": true - }, "tslib": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.3.1.tgz", @@ -5211,27 +4179,11 @@ "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.5.4.tgz", "integrity": "sha512-VgYs2A2QIRuGphtzFV7aQJduJ2gyfTljngLzjpfW9FoYZF6xuw1W0vW9ghCKLfcWrCFxK81CSGRAvS1pn4fIUg==" }, - "ua-parser-js": { - "version": "0.7.31", - "resolved": "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-0.7.31.tgz", - "integrity": "sha512-qLK/Xe9E2uzmYI3qLeOmI0tEOt+TBBQyUIAh4aAgU05FVYzeZrKUdkAZfBNVGRaHVgV0TDkdEngJSw/SyQchkQ==", - "peer": true - }, "uc.micro": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/uc.micro/-/uc.micro-1.0.6.tgz", "integrity": "sha512-8Y75pvTYkLJW2hWQHXxoqRgV7qb9B+9vFEtidML+7koHUFapnVJAZ6cKs+Qjz5Aw3aZWHMC6u0wJE3At+nSGwA==" }, - "update-browserslist-db": { - "version": "1.0.9", - "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.9.tgz", - "integrity": "sha512-/xsqn21EGVdXI3EXSum1Yckj3ZVZugqyOZQ/CxYPBD/R+ko9NSUScf8tFF4dOKY+2pvSSJA/S+5B8s4Zr4kyvg==", - "peer": true, - "requires": { - "escalade": "^3.1.1", - "picocolors": "^1.0.0" - } - }, "urql": { "version": "2.0.6", "resolved": "https://registry.npmjs.org/urql/-/urql-2.0.6.tgz", @@ -5244,8 +4196,7 @@ "use-callback-ref": { "version": "1.2.5", "resolved": "https://registry.npmjs.org/use-callback-ref/-/use-callback-ref-1.2.5.tgz", - "integrity": "sha512-gN3vgMISAgacF7sqsLPByqoePooY3n2emTH59Ur5d/M8eg4WTWu1xp8i8DHjohftIyEx0S08RiYxbffr4j8Peg==", - "requires": {} + "integrity": "sha512-gN3vgMISAgacF7sqsLPByqoePooY3n2emTH59Ur5d/M8eg4WTWu1xp8i8DHjohftIyEx0S08RiYxbffr4j8Peg==" }, "use-sidecar": { "version": "1.0.5", @@ -5271,22 +4222,6 @@ "loose-envify": "^1.0.0" } }, - "webidl-conversions": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", - "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==", - "peer": true - }, - "whatwg-url": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", - "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", - "peer": true, - "requires": { - "tr46": "~0.0.3", - "webidl-conversions": "^3.0.0" - } - }, "wonka": { "version": "4.0.15", "resolved": "https://registry.npmjs.org/wonka/-/wonka-4.0.15.tgz", diff --git a/dashboard/src/components/UpdateEmailTemplateModal.tsx b/dashboard/src/components/UpdateEmailTemplateModal.tsx index 620ee3b..92d0098 100644 --- a/dashboard/src/components/UpdateEmailTemplateModal.tsx +++ b/dashboard/src/components/UpdateEmailTemplateModal.tsx @@ -1,457 +1,565 @@ import React, { useEffect, useRef, useState } from 'react'; import { - Button, - Center, - Flex, - Input, - InputGroup, - MenuItem, - Modal, - ModalBody, - ModalCloseButton, - ModalContent, - ModalFooter, - ModalHeader, - ModalOverlay, - Select, - Text, - useDisclosure, - useToast, - Alert, - AlertIcon, - Collapse, - Box, - TableContainer, - Table, - Thead, - Tr, - Th, - Tbody, - Td, - Code, + Button, + Center, + Flex, + Input, + InputGroup, + MenuItem, + Modal, + ModalBody, + ModalCloseButton, + ModalContent, + ModalFooter, + ModalHeader, + ModalOverlay, + Select, + Text, + useDisclosure, + useToast, + Alert, + AlertIcon, + Collapse, + Box, + TableContainer, + Table, + Thead, + Tr, + Th, + Tbody, + Td, + Code, + Radio, + RadioGroup, + Stack, + Textarea, } from '@chakra-ui/react'; import { FaPlus, FaAngleDown, FaAngleUp } from 'react-icons/fa'; import { useClient } from 'urql'; import EmailEditor from 'react-email-editor'; import { - UpdateModalViews, - EmailTemplateInputDataFields, - emailTemplateEventNames, - emailTemplateVariables, + UpdateModalViews, + EmailTemplateInputDataFields, + emailTemplateEventNames, + emailTemplateVariables, + EmailTemplateEditors, } from '../constants'; import { capitalizeFirstLetter } from '../utils'; import { AddEmailTemplate, EditEmailTemplate } from '../graphql/mutation'; interface selectedEmailTemplateDataTypes { - [EmailTemplateInputDataFields.ID]: string; - [EmailTemplateInputDataFields.EVENT_NAME]: string; - [EmailTemplateInputDataFields.SUBJECT]: string; - [EmailTemplateInputDataFields.CREATED_AT]: number; - [EmailTemplateInputDataFields.TEMPLATE]: string; - [EmailTemplateInputDataFields.DESIGN]: string; + [EmailTemplateInputDataFields.ID]: string; + [EmailTemplateInputDataFields.EVENT_NAME]: string; + [EmailTemplateInputDataFields.SUBJECT]: string; + [EmailTemplateInputDataFields.CREATED_AT]: number; + [EmailTemplateInputDataFields.TEMPLATE]: string; + [EmailTemplateInputDataFields.DESIGN]: string; } interface UpdateEmailTemplateInputPropTypes { - view: UpdateModalViews; - selectedTemplate?: selectedEmailTemplateDataTypes; - fetchEmailTemplatesData: Function; + view: UpdateModalViews; + selectedTemplate?: selectedEmailTemplateDataTypes; + fetchEmailTemplatesData: Function; } interface templateVariableDataTypes { - text: string; - value: string; - description: string; + text: string; + value: string; + description: string; } interface emailTemplateDataType { - [EmailTemplateInputDataFields.EVENT_NAME]: string; - [EmailTemplateInputDataFields.SUBJECT]: string; + [EmailTemplateInputDataFields.EVENT_NAME]: string; + [EmailTemplateInputDataFields.SUBJECT]: string; + [EmailTemplateInputDataFields.TEMPLATE]: string; + [EmailTemplateInputDataFields.DESIGN]: string; } interface validatorDataType { - [EmailTemplateInputDataFields.SUBJECT]: boolean; + [EmailTemplateInputDataFields.SUBJECT]: boolean; } const initTemplateData: emailTemplateDataType = { - [EmailTemplateInputDataFields.EVENT_NAME]: emailTemplateEventNames.Signup, - [EmailTemplateInputDataFields.SUBJECT]: '', + [EmailTemplateInputDataFields.EVENT_NAME]: emailTemplateEventNames.Signup, + [EmailTemplateInputDataFields.SUBJECT]: '', + [EmailTemplateInputDataFields.TEMPLATE]: '', + [EmailTemplateInputDataFields.DESIGN]: '', }; const initTemplateValidatorData: validatorDataType = { - [EmailTemplateInputDataFields.SUBJECT]: true, + [EmailTemplateInputDataFields.SUBJECT]: true, }; const UpdateEmailTemplate = ({ - view, - selectedTemplate, - fetchEmailTemplatesData, + view, + selectedTemplate, + fetchEmailTemplatesData, }: UpdateEmailTemplateInputPropTypes) => { - const client = useClient(); - const toast = useToast(); - const emailEditorRef = useRef(null); - const { isOpen, onOpen, onClose } = useDisclosure(); - const [loading, setLoading] = useState(false); - const [templateVariables, setTemplateVariables] = useState< - templateVariableDataTypes[] - >([]); - const [templateData, setTemplateData] = useState({ - ...initTemplateData, - }); - const [validator, setValidator] = useState({ - ...initTemplateValidatorData, - }); - const [isDynamicVariableInfoOpen, setIsDynamicVariableInfoOpen] = - useState(false); + const client = useClient(); + const toast = useToast(); + const emailEditorRef = useRef(null); + const { isOpen, onOpen, onClose } = useDisclosure(); + const [loading, setLoading] = useState(false); + const [editor, setEditor] = useState( + EmailTemplateEditors.PLAIN_HTML_EDITOR, + ); + const [templateVariables, setTemplateVariables] = useState< + templateVariableDataTypes[] + >([]); + const [templateData, setTemplateData] = useState({ + ...initTemplateData, + }); + const [validator, setValidator] = useState({ + ...initTemplateValidatorData, + }); + const [isDynamicVariableInfoOpen, setIsDynamicVariableInfoOpen] = + useState(false); - const onReady = () => { - if (selectedTemplate) { - const { design } = selectedTemplate; - try { - const designData = JSON.parse(design); - // @ts-ignore - emailEditorRef.current.editor.loadDesign(designData); - } catch (error) { - console.error(error); - onClose(); - } - } - }; + const onReady = () => { + if (selectedTemplate) { + const { design } = selectedTemplate; + try { + if (design) { + const designData = JSON.parse(design); + // @ts-ignore + emailEditorRef.current.editor.loadDesign(designData); + } + } catch (error) { + console.error(error); + onClose(); + } + } + }; - const inputChangehandler = (inputType: string, value: any) => { - if (inputType !== EmailTemplateInputDataFields.EVENT_NAME) { - setValidator({ - ...validator, - [inputType]: value?.trim().length, - }); - } - setTemplateData({ ...templateData, [inputType]: value }); - }; + const inputChangehandler = (inputType: string, value: any) => { + if (inputType !== EmailTemplateInputDataFields.EVENT_NAME) { + setValidator({ + ...validator, + [inputType]: value?.trim().length, + }); + } + setTemplateData({ ...templateData, [inputType]: value }); + }; - const validateData = () => { - return ( - !loading && - templateData[EmailTemplateInputDataFields.EVENT_NAME].length > 0 && - templateData[EmailTemplateInputDataFields.SUBJECT].length > 0 && - validator[EmailTemplateInputDataFields.SUBJECT] - ); - }; + const validateData = () => { + return ( + !loading && + templateData[EmailTemplateInputDataFields.EVENT_NAME].length > 0 && + templateData[EmailTemplateInputDataFields.SUBJECT].length > 0 && + validator[EmailTemplateInputDataFields.SUBJECT] + ); + }; - const saveData = async () => { - if (!validateData()) return; - setLoading(true); - // @ts-ignore - return await emailEditorRef.current.editor.exportHtml(async (data) => { - const { design, html } = data; - if (!html || !design) { - setLoading(false); - return; - } - const params = { - [EmailTemplateInputDataFields.EVENT_NAME]: - templateData[EmailTemplateInputDataFields.EVENT_NAME], - [EmailTemplateInputDataFields.SUBJECT]: - templateData[EmailTemplateInputDataFields.SUBJECT], - [EmailTemplateInputDataFields.TEMPLATE]: html.trim(), - [EmailTemplateInputDataFields.DESIGN]: JSON.stringify(design), - }; - let res: any = {}; - if ( - view === UpdateModalViews.Edit && - selectedTemplate?.[EmailTemplateInputDataFields.ID] - ) { - res = await client - .mutation(EditEmailTemplate, { - params: { - ...params, - id: selectedTemplate[EmailTemplateInputDataFields.ID], - }, - }) - .toPromise(); - } else { - res = await client.mutation(AddEmailTemplate, { params }).toPromise(); - } - setLoading(false); - if (res.error) { - toast({ - title: capitalizeFirstLetter(res.error.message), - isClosable: true, - status: 'error', - position: 'bottom-right', - }); - } else if ( - res.data?._add_email_template || - res.data?._update_email_template - ) { - toast({ - title: capitalizeFirstLetter( - res.data?._add_email_template?.message || - res.data?._update_email_template?.message, - ), - isClosable: true, - status: 'success', - position: 'bottom-right', - }); - setTemplateData({ - ...initTemplateData, - }); - setValidator({ ...initTemplateValidatorData }); - fetchEmailTemplatesData(); - } - view === UpdateModalViews.ADD && onClose(); - }); - }; - const resetData = () => { - if (selectedTemplate) { - setTemplateData(selectedTemplate); - } else { - setTemplateData({ ...initTemplateData }); - } - }; - useEffect(() => { - if ( - isOpen && - view === UpdateModalViews.Edit && - selectedTemplate && - Object.keys(selectedTemplate || {}).length - ) { - const { id, created_at, template, design, ...rest } = selectedTemplate; - setTemplateData(rest); - } - }, [isOpen]); - useEffect(() => { - const updatedTemplateVariables = Object.entries( - emailTemplateVariables, - ).reduce((acc, [key, val]): any => { - if ( - (templateData[EmailTemplateInputDataFields.EVENT_NAME] !== - emailTemplateEventNames['Verify Otp'] && - val === emailTemplateVariables.otp) || - (templateData[EmailTemplateInputDataFields.EVENT_NAME] === - emailTemplateEventNames['Verify Otp'] && - val === emailTemplateVariables.verification_url) - ) { - return acc; - } - return [ - ...acc, - { - text: key, - value: val.value, - description: val.description, - }, - ]; - }, []); - setTemplateVariables(updatedTemplateVariables); - }, [templateData[EmailTemplateInputDataFields.EVENT_NAME]]); + const updateTemplate = async (params: emailTemplateDataType) => { + let res: any = {}; + if ( + view === UpdateModalViews.Edit && + selectedTemplate?.[EmailTemplateInputDataFields.ID] + ) { + res = await client + .mutation(EditEmailTemplate, { + params: { + ...params, + id: selectedTemplate[EmailTemplateInputDataFields.ID], + }, + }) + .toPromise(); + } else { + res = await client.mutation(AddEmailTemplate, { params }).toPromise(); + } + setLoading(false); + if (res.error) { + toast({ + title: capitalizeFirstLetter(res.error.message), + isClosable: true, + status: 'error', + position: 'bottom-right', + }); + } else if ( + res.data?._add_email_template || + res.data?._update_email_template + ) { + toast({ + title: capitalizeFirstLetter( + res.data?._add_email_template?.message || + res.data?._update_email_template?.message, + ), + isClosable: true, + status: 'success', + position: 'bottom-right', + }); + setTemplateData({ + ...initTemplateData, + }); + setValidator({ ...initTemplateValidatorData }); + fetchEmailTemplatesData(); + } + }; - return ( - <> - {view === UpdateModalViews.ADD ? ( - - ) : ( - Edit - )} - { - resetData(); - onClose(); - }} - size="6xl" - > - - - - {view === UpdateModalViews.ADD - ? 'Add New Email Template' - : 'Edit Email Template'} - - - - - - setIsDynamicVariableInfoOpen(!isDynamicVariableInfoOpen) - } - borderRadius="5" - marginBottom={5} - cursor="pointer" - fontSize="sm" - > - - - - Note: You can add set of dynamic variables to subject - and email body. Click here to see the set of dynamic - variables. - - {isDynamicVariableInfoOpen ? : } - - - - - - - - - - - - - {templateVariables.map((i) => ( - - - - - ))} - -
VariableDescription
- {`{{.${i.text}}}`} - - - {i.description} - -
-
-
- - Event Name - - - - - - Subject - - - - inputChangehandler( - EmailTemplateInputDataFields.SUBJECT, - e.currentTarget.value, - ) - } - /> - - - - - Template Body - - - - -
-
- - - - -
-
- - ); + const saveData = async () => { + if (!validateData()) return; + setLoading(true); + let params: emailTemplateDataType = { + [EmailTemplateInputDataFields.EVENT_NAME]: + templateData[EmailTemplateInputDataFields.EVENT_NAME], + [EmailTemplateInputDataFields.SUBJECT]: + templateData[EmailTemplateInputDataFields.SUBJECT], + [EmailTemplateInputDataFields.TEMPLATE]: + templateData[EmailTemplateInputDataFields.TEMPLATE], + [EmailTemplateInputDataFields.DESIGN]: '', + }; + if (editor === EmailTemplateEditors.UNLAYER_EDITOR) { + // @ts-ignore + await emailEditorRef.current.editor.exportHtml(async (data) => { + const { design, html } = data; + if (!html || !design) { + setLoading(false); + return; + } + params = { + ...params, + [EmailTemplateInputDataFields.TEMPLATE]: html.trim(), + [EmailTemplateInputDataFields.DESIGN]: JSON.stringify(design), + }; + await updateTemplate(params); + }); + } else { + await updateTemplate(params); + } + view === UpdateModalViews.ADD && onClose(); + }; + + const resetData = () => { + if (selectedTemplate) { + setTemplateData(selectedTemplate); + } else { + setTemplateData({ ...initTemplateData }); + } + }; + + // set template data if edit modal is open + useEffect(() => { + if ( + isOpen && + view === UpdateModalViews.Edit && + selectedTemplate && + Object.keys(selectedTemplate || {}).length + ) { + const { id, created_at, ...rest } = selectedTemplate; + setTemplateData(rest); + } + }, [isOpen]); + + // set template variables + useEffect(() => { + const updatedTemplateVariables = Object.entries( + emailTemplateVariables, + ).reduce((acc, [key, val]): any => { + if ( + (templateData[EmailTemplateInputDataFields.EVENT_NAME] !== + emailTemplateEventNames['Verify Otp'] && + val === emailTemplateVariables.otp) || + (templateData[EmailTemplateInputDataFields.EVENT_NAME] === + emailTemplateEventNames['Verify Otp'] && + val === emailTemplateVariables.verification_url) + ) { + return acc; + } + return [ + ...acc, + { + text: key, + value: val.value, + description: val.description, + }, + ]; + }, []); + setTemplateVariables(updatedTemplateVariables); + }, [templateData[EmailTemplateInputDataFields.EVENT_NAME]]); + + // change editor + useEffect(() => { + if (isOpen && selectedTemplate) { + const { design } = selectedTemplate; + if (design) { + setEditor(EmailTemplateEditors.UNLAYER_EDITOR); + } else { + setEditor(EmailTemplateEditors.PLAIN_HTML_EDITOR); + } + } + }, [isOpen, selectedTemplate]); + + // reset fields when editor is changed + useEffect(() => { + if (selectedTemplate?.design) { + if (editor === EmailTemplateEditors.UNLAYER_EDITOR) { + setTemplateData({ + ...templateData, + [EmailTemplateInputDataFields.TEMPLATE]: selectedTemplate.template, + [EmailTemplateInputDataFields.DESIGN]: selectedTemplate.design, + }); + } else { + setTemplateData({ + ...templateData, + [EmailTemplateInputDataFields.TEMPLATE]: '', + [EmailTemplateInputDataFields.DESIGN]: '', + }); + } + } else if (selectedTemplate?.template) { + if (editor === EmailTemplateEditors.UNLAYER_EDITOR) { + setTemplateData({ + ...templateData, + [EmailTemplateInputDataFields.TEMPLATE]: '', + [EmailTemplateInputDataFields.DESIGN]: '', + }); + } else { + setTemplateData({ + ...templateData, + [EmailTemplateInputDataFields.TEMPLATE]: selectedTemplate?.template, + [EmailTemplateInputDataFields.DESIGN]: '', + }); + } + } + }, [editor]); + + return ( + <> + {view === UpdateModalViews.ADD ? ( + + ) : ( + Edit + )} + { + resetData(); + onClose(); + }} + size="6xl" + > + + + + {view === UpdateModalViews.ADD + ? 'Add New Email Template' + : 'Edit Email Template'} + + + + + + setIsDynamicVariableInfoOpen(!isDynamicVariableInfoOpen) + } + borderRadius="5" + marginBottom={5} + cursor="pointer" + fontSize="sm" + > + + + + Note: You can add set of dynamic variables to subject + and email body. Click here to see the set of dynamic + variables. + + {isDynamicVariableInfoOpen ? : } + + + + + + + + + + + + + {templateVariables.map((i) => ( + + + + + ))} + +
VariableDescription
+ {`{{.${i.text}}}`} + + + {i.description} + +
+
+
+ + Event Name + + + + + + Subject + + + + inputChangehandler( + EmailTemplateInputDataFields.SUBJECT, + e.currentTarget.value, + ) + } + /> + + + + + Template Body + + setEditor(value)} + value={editor} + > + + + Plain HTML + + + Unlayer Editor + + + + + + + {editor === EmailTemplateEditors.UNLAYER_EDITOR ? ( + + ) : ( +