diff --git a/api/main.go b/api/main.go index efc3ae6..675e29d 100644 --- a/api/main.go +++ b/api/main.go @@ -54,6 +54,7 @@ func Start() { r.GET("/recovery", HandleGetRecoveryFlow) r.POST("/recovery", HandlePostRecoveryFlow) + r.POST("/recovery-code", HandlePostRecoveryCodeFlow) r.GET("/settings", HandleGetSettingsFlow) r.POST("/updateprofile", HandleUpdateProfile) diff --git a/api/recovery.go b/api/recovery.go index 1515a19..3bd6b03 100644 --- a/api/recovery.go +++ b/api/recovery.go @@ -60,8 +60,8 @@ func HandlePostRecoveryFlow(c *gin.Context) { }) return } - - _, err = recovery.SubmitRecoveryFlowWrapper(cookie, t.FlowID, t.CsrfToken, t.Email) + var csrf_token string + csrf_token, err = recovery.SubmitRecoveryFlowWrapper(cookie, t.FlowID, t.CsrfToken, t.Email) if err != nil { log.ErrorLogger("POST Recovery flow failed", err) @@ -74,6 +74,52 @@ func HandlePostRecoveryFlow(c *gin.Context) { } c.JSON(http.StatusOK, gin.H{ - "message": "Mail sent with recovery link", + "message": "Mail sent with recovery code", + "csrf_token": csrf_token, + }) +} + +func HandlePostRecoveryCodeFlow(c *gin.Context) { + var t recovery.SubmitRecoveryAPIBody + err := c.BindJSON(&t) + + if err != nil { + log.ErrorLogger("Unable to process json body", err) + errCode, _ := strconv.Atoi(strings.Split(err.Error(), " ")[0]) + c.JSON(errCode, gin.H{ + "error": err.Error(), + "message": "Unable to process json body", + }) + return + } + + cookie, err := c.Cookie("recovery_flow") + + if err != nil { + log.ErrorLogger("Recovery Flow Cookie not found", err) + errCode, _ := strconv.Atoi(strings.Split(err.Error(), " ")[0]) + c.JSON(errCode, gin.H{ + "error": err.Error(), + "message": "Recovery Flow Cookie not found", + }) + return + } + + session, err := recovery.SubmitRecoveryCodeFlowWrapper(cookie, t.FlowID, t.CsrfToken, t.RecoveryCode) + + if err != nil { + log.ErrorLogger("POST Recovery flow failed", err) + errCode, _ := strconv.Atoi(strings.Split(err.Error(), " ")[0]) + c.JSON(errCode, gin.H{ + "error": err.Error(), + "message": "POST Recovery Code flow failed", + }) + return + } + + c.SetCookie("sdslabs_session", session, 3600, "/", config.NymeriaConfig.URL.Domain, true, true) + + c.JSON(http.StatusOK, gin.H{ + "message": "Session cookie set for password change", }) } diff --git a/api/settings.go b/api/settings.go index 27771fc..79be25c 100644 --- a/api/settings.go +++ b/api/settings.go @@ -15,16 +15,9 @@ import ( func HandleGetSettingsFlow(c *gin.Context) { log.Logger.Debug("Get Settings") - session_cookie, err1 := c.Cookie("sdslabs_session") - recovery_cookie, err2 := c.Cookie("ory_kratos_session") - - if err1 != nil && err2 != nil { - var err error - if err1 != nil { - err = err1 - } else { - err = err2 - } + session_cookie, err := c.Cookie("sdslabs_session") + + if err != nil { log.ErrorLogger("Initialize Settings Failed", err) errCode, _ := strconv.Atoi(strings.Split(err.Error(), " ")[0]) c.JSON(errCode, gin.H{ @@ -34,7 +27,7 @@ func HandleGetSettingsFlow(c *gin.Context) { return } - flow, flow_cookie, err := settings.InitializeSettingsFlowWrapper(session_cookie, recovery_cookie) + flow, flow_cookie, err := settings.InitializeSettingsFlowWrapper(session_cookie) if err != nil { log.ErrorLogger("Initialize Settings flow Failed", err) @@ -46,11 +39,6 @@ func HandleGetSettingsFlow(c *gin.Context) { c.SetCookie("settings_flow", flow_cookie, 3600, "/", config.NymeriaConfig.URL.Domain, true, true) - if recovery_cookie != "" { - recovery_cookie = "ory_kratos_session=" + recovery_cookie - c.SetCookie("sdslabs_session", recovery_cookie, 900, "/", config.NymeriaConfig.URL.Domain, false, true) - } - flowID := flow.GetId() var csrf_token string diff --git a/pkg/wrapper/kratos/recovery/recovery.go b/pkg/wrapper/kratos/recovery/recovery.go index a5cedf1..0046d8b 100644 --- a/pkg/wrapper/kratos/recovery/recovery.go +++ b/pkg/wrapper/kratos/recovery/recovery.go @@ -38,9 +38,39 @@ func InitializeRecoveryFlowWrapper() (string, string, string, error) { func SubmitRecoveryFlowWrapper(cookie string, flowID string, csrfToken string, email string) (string, error) { submitFlowBody := client.UpdateRecoveryFlowBody{ - UpdateRecoveryFlowWithLinkMethod: client.NewUpdateRecoveryFlowWithLinkMethod(email, "link"), + UpdateRecoveryFlowWithCodeMethod: client.NewUpdateRecoveryFlowWithCodeMethod("code"), } - submitFlowBody.UpdateRecoveryFlowWithLinkMethod.SetCsrfToken(csrfToken) + submitFlowBody.UpdateRecoveryFlowWithCodeMethod.SetCsrfToken(csrfToken) + submitFlowBody.UpdateRecoveryFlowWithCodeMethod.SetEmail(email) + + apiClient := client.NewAPIClient(config.KratosClientConfig) + resp, r, err := apiClient.FrontendAPI.UpdateRecoveryFlow(context.Background()).Flow(flowID).UpdateRecoveryFlowBody(submitFlowBody).Cookie(cookie).Execute() + + var csrf_token string + + for _, node := range resp.Ui.Nodes { + if node.Attributes.UiNodeInputAttributes.Name == "csrf_token" { + csrf_token_interface := node.Attributes.UiNodeInputAttributes.Value + csrf_token, _ = csrf_token_interface.(string) + break + } + } + + if err != nil { + fmt.Fprintf(os.Stderr, "Error when calling `V0alpha2Api.SubmitSelfServiceRecoveryFlow``: %v\n", err) + fmt.Fprintf(os.Stderr, "Full HTTP response: %v\n", r) + return "", err + } + + return csrf_token, nil +} + +func SubmitRecoveryCodeFlowWrapper(cookie string, flowID string, csrfToken string, recoveryCode string) (string, error) { + submitFlowBody := client.UpdateRecoveryFlowBody{ + UpdateRecoveryFlowWithCodeMethod: client.NewUpdateRecoveryFlowWithCodeMethod("code"), + } + submitFlowBody.UpdateRecoveryFlowWithCodeMethod.SetCsrfToken(csrfToken) + submitFlowBody.UpdateRecoveryFlowWithCodeMethod.SetCode(recoveryCode) apiClient := client.NewAPIClient(config.KratosClientConfig) _, r, err := apiClient.FrontendAPI.UpdateRecoveryFlow(context.Background()).Flow(flowID).UpdateRecoveryFlowBody(submitFlowBody).Cookie(cookie).Execute() @@ -51,5 +81,7 @@ func SubmitRecoveryFlowWrapper(cookie string, flowID string, csrfToken string, e return "", err } - return "", nil + responseCookies := r.Header["Set-Cookie"] + + return responseCookies[1], nil } diff --git a/pkg/wrapper/kratos/recovery/types.go b/pkg/wrapper/kratos/recovery/types.go index 6cfee10..f6a3300 100644 --- a/pkg/wrapper/kratos/recovery/types.go +++ b/pkg/wrapper/kratos/recovery/types.go @@ -1,7 +1,8 @@ package recovery type SubmitRecoveryAPIBody struct { - CsrfToken string `json:"csrf_token"` - FlowID string `json:"flowID"` - Email string `json:"email"` + CsrfToken string `json:"csrf_token"` + FlowID string `json:"flowID"` + Email string `json:"email"` + RecoveryCode string `json:"recovery_code"` } diff --git a/pkg/wrapper/kratos/settings/settings.go b/pkg/wrapper/kratos/settings/settings.go index 8ad78a2..b4f686d 100644 --- a/pkg/wrapper/kratos/settings/settings.go +++ b/pkg/wrapper/kratos/settings/settings.go @@ -11,20 +11,15 @@ import ( "github.com/sdslabs/nymeria/config" ) -func InitializeSettingsFlowWrapper(session_cookie string, recovery_cookie string) (client.SettingsFlow, string, error) { +func InitializeSettingsFlowWrapper(session_cookie string) (client.SettingsFlow, string, error) { returnTo := "" // string | The URL to return the browser to after the flow was completed. (optional) - var cookie string - - if recovery_cookie != "" { - cookie = "ory_kratos_session=" + recovery_cookie - } else { - cookie = strings.Split(session_cookie, ";")[0] - } + cookie := strings.Split(session_cookie, ";")[0] apiClient := client.NewAPIClient(config.KratosClientConfig) resp, httpRes, err := apiClient.FrontendAPI.CreateBrowserSettingsFlow(context.Background()).ReturnTo(returnTo).Cookie(cookie).Execute() + if err != nil { return *client.NewSettingsFlowWithDefaults(), "", err }