diff --git a/api/admin.go b/api/admin.go index 44843d7..4d41164 100644 --- a/api/admin.go +++ b/api/admin.go @@ -31,23 +31,6 @@ func HandleCreateIdentityFlow(c *gin.Context) { return } - var mappedJsonIdentity map[string]interface{} - - data, err := json.Marshal(t) - - if err != nil { - log.ErrorLogger("Unable to convert map to json", err) - - errCode, _ := strconv.Atoi(strings.Split(err.Error(), " ")[0]) - c.JSON(errCode, gin.H{ - "error": err.Error(), - "message": "Unable to convert map to json", - }) - return - } - - err = json.Unmarshal(data, &mappedJsonIdentity) - if err != nil { log.ErrorLogger("Unable to convert JSON to map", err) @@ -59,7 +42,7 @@ func HandleCreateIdentityFlow(c *gin.Context) { return } - createdIdentity, r, err := admin.CreateIdentityFlowWrapper(mappedJsonIdentity) + createdIdentity, r, err := admin.CreateIdentityFlowWrapper(t) if err != nil { log.ErrorLogger("Error while calling `AdminCreateIdentity`", err) @@ -209,3 +192,85 @@ func HandleBanIdentity(c *gin.Context) { "identity": id, }) } + +func HandleRemoveBanIdentity(c *gin.Context) { + var t IdentityBody + 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 + } + + identityResult, r, err := admin.GetIdentityFlowWrapper(t.Identity) + + if err != nil { + log.ErrorLogger("Error while fetching Identity details", err) + fmt.Fprintf(os.Stderr, "Full HTTP response: %v\n", r) + c.JSON(http.StatusInternalServerError, gin.H{ + "error": "Internal server error", + }) + return + } + + id, r, err := admin.RemoveBanIdentityFlowWrapper(identityResult) + + if err != nil { + log.ErrorLogger("Error while calling `AdminPatchIdentities`", err) + fmt.Fprintf(os.Stderr, "Full HTTP response: %v\n", r) + c.JSON(http.StatusInternalServerError, gin.H{ + "error": err.Error(), + }) + return + } + c.JSON(http.StatusOK, gin.H{ + "identity": id, + }) +} + +func HandleRoleSwitch(c *gin.Context) { + var t IdentityBody + 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 + } + + identityResult, r, err := admin.GetIdentityFlowWrapper(t.Identity) + + if err != nil { + log.ErrorLogger("Error while fetching Identity details", err) + fmt.Fprintf(os.Stderr, "Full HTTP response: %v\n", r) + c.JSON(http.StatusInternalServerError, gin.H{ + "error": "Internal server error", + }) + return + } + + id, r, err := admin.RoleSwitchFlowWrapper(identityResult) + + if err != nil { + log.ErrorLogger("Error while calling `AdminPatchIdentities`", err) + fmt.Fprintf(os.Stderr, "Full HTTP response: %v\n", r) + c.JSON(http.StatusInternalServerError, gin.H{ + "error": err.Error(), + }) + return + } + c.JSON(http.StatusOK, gin.H{ + "identity": id, + }) +} diff --git a/api/logout.go b/api/logout.go index bd24dcc..be24203 100644 --- a/api/logout.go +++ b/api/logout.go @@ -7,6 +7,7 @@ import ( "github.com/gin-gonic/gin" + "github.com/sdslabs/nymeria/config" "github.com/sdslabs/nymeria/log" "github.com/sdslabs/nymeria/pkg/wrapper/kratos/logout" ) @@ -79,6 +80,7 @@ func HandlePostLogoutFlow(c *gin.Context) { return } + c.SetCookie("sdslabs_session", "", 1, "/", config.NymeriaConfig.URL.Domain, true, true) c.JSON(http.StatusOK, gin.H{ "status": "user logged out", }) diff --git a/api/main.go b/api/main.go index 8ce13cc..8b3d3c2 100644 --- a/api/main.go +++ b/api/main.go @@ -36,11 +36,13 @@ func Start() { r.GET("/mfa", HandleGetMFAFlow) r.POST("/mfa", HandlePostMFAFlow) - r.POST("/create-identity", HandleCreateIdentityFlow) - r.GET("/get-identity", HandleGetIdentityFlow) - r.POST("/delete-identity", HandleDeleteIdentityFlow) - r.GET("/list-identity", HandleListIdentity) - r.PUT("/update-identity/ban", HandleBanIdentity) + r.POST("/create-identity", middleware.OnlyAdmin, HandleCreateIdentityFlow) + r.GET("/get-identity", middleware.OnlyAdmin, HandleGetIdentityFlow) + r.POST("/delete-identity", middleware.OnlyAdmin, HandleDeleteIdentityFlow) + r.GET("/list-identity", middleware.OnlyAdmin, HandleListIdentity) + r.PUT("/update-identity/ban", middleware.OnlyAdmin, HandleBanIdentity) + r.PUT("/update-identity/remove-ban", middleware.OnlyAdmin, HandleRemoveBanIdentity) + r.PUT("/update-identity/switch-roles", middleware.OnlyAdmin, HandleRoleSwitch) r.GET("/register", HandleGetRegistrationFlow) r.POST("/register", HandlePostRegistrationFlow) @@ -61,7 +63,7 @@ func Start() { r.GET("/verification", HandleGetVerificationFlow) r.POST("/verification", HandlePostVerificationFlow) - r.POST("/get_profile", middleware.HandleAppAuthorization, HandlePostProfile) + r.POST("/get_profile", HandlePostProfile) r.POST("/verify_app", middleware.HandleAppAuthorization, func(c *gin.Context) { c.JSON(http.StatusOK, gin.H{ "message": "Authorized", diff --git a/api/profile.go b/api/profile.go index 3251bf3..4f1d20e 100644 --- a/api/profile.go +++ b/api/profile.go @@ -11,12 +11,6 @@ import ( "github.com/sdslabs/nymeria/pkg/middleware" ) -type Profile struct { - Email string `json:"email"` - Name string `json:"name"` - PhoneNumber string `json:"phone_number"` -} - func HandlePostProfile(c *gin.Context) { session, err := middleware.GetSession(c) if err != nil { @@ -31,10 +25,6 @@ func HandlePostProfile(c *gin.Context) { identity := session.GetIdentity() traits := identity.GetTraits() profile := traits.(map[string]interface{}) - response := Profile{ - Email: profile["email"].(string), - Name: profile["name"].(string), - PhoneNumber: profile["phone_number"].(string), - } - c.JSON(http.StatusOK, response) + + c.JSON(http.StatusOK, profile) } diff --git a/api/recovery.go b/api/recovery.go index 85e833f..1515a19 100644 --- a/api/recovery.go +++ b/api/recovery.go @@ -61,7 +61,7 @@ func HandlePostRecoveryFlow(c *gin.Context) { return } - session, err := recovery.SubmitRecoveryFlowWrapper(cookie, t.FlowID, t.CsrfToken, t.Code, t.Method) + _, err = recovery.SubmitRecoveryFlowWrapper(cookie, t.FlowID, t.CsrfToken, t.Email) if err != nil { log.ErrorLogger("POST Recovery flow failed", err) @@ -73,8 +73,7 @@ func HandlePostRecoveryFlow(c *gin.Context) { return } - c.SetCookie("sdslabs_session", session, 3600, "/", config.NymeriaConfig.URL.Domain, true, true) c.JSON(http.StatusOK, gin.H{ - "message": "Mail sent with recovery code", + "message": "Mail sent with recovery link", }) } diff --git a/api/settings.go b/api/settings.go index 3bc5141..2fecfe1 100644 --- a/api/settings.go +++ b/api/settings.go @@ -9,14 +9,22 @@ import ( "github.com/sdslabs/nymeria/config" "github.com/sdslabs/nymeria/log" + "github.com/sdslabs/nymeria/pkg/middleware" "github.com/sdslabs/nymeria/pkg/wrapper/kratos/settings" ) func HandleGetSettingsFlow(c *gin.Context) { log.Logger.Debug("Get Settings") - session_cookie, err := c.Cookie("sdslabs_session") - - if err != nil { + 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 + } log.ErrorLogger("Initialize Settings Failed", err) errCode, _ := strconv.Atoi(strings.Split(err.Error(), " ")[0]) c.JSON(errCode, gin.H{ @@ -26,11 +34,7 @@ func HandleGetSettingsFlow(c *gin.Context) { return } - flow, flow_cookie, err := settings.InitializeSettingsFlowWrapper(session_cookie) - - c.SetCookie("settings_flow", flow_cookie, 3600, "/", config.NymeriaConfig.URL.Domain, true, true) - - flowID := flow.GetId() + flow, flow_cookie, err := settings.InitializeSettingsFlowWrapper(session_cookie, recovery_cookie) if err != nil { log.ErrorLogger("Initialize Settings flow Failed", err) @@ -40,6 +44,15 @@ func HandleGetSettingsFlow(c *gin.Context) { return } + 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 for _, node := range flow.Ui.Nodes { @@ -67,6 +80,36 @@ func HandleGetSettingsFlow(c *gin.Context) { break } } + + session, err := middleware.GetSession(c) + if err != nil { + log.ErrorLogger("Unable to get session", err) + errCode, _ := strconv.Atoi(strings.Split(err.Error(), " ")[0]) + c.JSON(errCode, gin.H{ + "error": err.Error(), + "message": "Unable to get session", + }) + return + } + identity := session.GetIdentity() + traits := identity.GetTraits().(map[string]interface{}) + + if identity.VerifiableAddresses[0].Verified && traits["verified"] == false { + traits["verified"] = true + + _, err = settings.SubmitSettingsFlowProfileMethod(flow_cookie, session_cookie, flowID, csrf_token, traits) + if err != nil { + log.ErrorLogger("Kratos post settings update profile flow failed", err) + + errCode, _ := strconv.Atoi((strings.Split(err.Error(), " "))[0]) + c.JSON(errCode, gin.H{ + "error": err.Error(), + "message": "Kratos post settings update profile flow failed", + }) + return + } + } + c.JSON(http.StatusOK, gin.H{ "flowID": flowID, "csrf_token": csrf_token, @@ -80,14 +123,16 @@ func HandleUpdateProfile(c *gin.Context) { err := c.BindJSON(&req_body) traitsinterface := map[string]interface{}{ - "name": req_body.Traits.Name, - "phone_number": req_body.Traits.PhoneNumber, - "img_url": req_body.Traits.ImgURL, - "email": req_body.Traits.Email, - "totp_enabled": req_body.Traits.TOTP_Enabled, - "created_at": req_body.Traits.Created_At, - "role": req_body.Traits.Role, - "active": req_body.Traits.Active, + "email": req_body.Traits.Email, + "name": req_body.Traits.Name, + "password": req_body.Traits.Password, + "img_url": req_body.Traits.ImgURL, + "phone_number": req_body.Traits.PhoneNumber, + "invite_status": req_body.Traits.InviteStatus, + "verified": req_body.Traits.Verified, + "role": req_body.Traits.Role, + "created_at": req_body.Traits.Created_At, + "totp_enabled": req_body.Traits.TOTP_Enabled, } if err != nil { @@ -125,15 +170,34 @@ func HandleUpdateProfile(c *gin.Context) { return } - msg, err := settings.SubmitSettingsFlowProfileMethod(flow_cookie, session_cookie, req_body.FlowID, req_body.CsrfToken, req_body.Method, traitsinterface) + //Checking if email is changed then verified will be false + session, err := middleware.GetSession(c) + if err != nil { + log.ErrorLogger("Unable to get session", err) + errCode, _ := strconv.Atoi(strings.Split(err.Error(), " ")[0]) + c.JSON(errCode, gin.H{ + "error": err.Error(), + "message": "Unable to get session", + }) + return + } + identity := session.GetIdentity() + traits := identity.GetTraits() + profile := traits.(map[string]interface{}) + + if profile["email"] != traitsinterface["email"] { + traitsinterface["verified"] = false + } + + msg, err := settings.SubmitSettingsFlowProfileMethod(flow_cookie, session_cookie, req_body.FlowID, req_body.CsrfToken, traitsinterface) if err != nil { - log.ErrorLogger("Kratos post settings flow failed", err) + log.ErrorLogger("Kratos post settings update profile flow failed", err) errCode, _ := strconv.Atoi((strings.Split(err.Error(), " "))[0]) c.JSON(errCode, gin.H{ "error": err.Error(), - "message": "Kratos post settings flow failed", + "message": "Kratos post settings update profile flow failed", }) return } @@ -182,19 +246,57 @@ func HandleChangePassword(c *gin.Context) { return } - msg, err := settings.SubmitSettingsFlowPasswordMethod(flow_cookie, session_cookie, req_body.FlowID, req_body.CsrfToken, req_body.Method, req_body.Password) + msg, err := settings.SubmitSettingsFlowPasswordMethod(flow_cookie, session_cookie, req_body.FlowID, req_body.CsrfToken, req_body.Password) if err != nil { - log.ErrorLogger("Kratos post settings flow failed", err) + log.ErrorLogger("Kratos post settings change password flow failed", err) errCode, _ := strconv.Atoi((strings.Split(err.Error(), " "))[0]) c.JSON(errCode, gin.H{ "error": err.Error(), - "message": "Kratos post settings flow failed", + "message": "Kratos post settings change password flow failed", + }) + return + } + + recovery_cookie, _ := c.Cookie("ory_kratos_session") + + session, err := middleware.GetSession(c) + if err != nil { + log.ErrorLogger("Unable to get session", err) + errCode, _ := strconv.Atoi(strings.Split(err.Error(), " ")[0]) + c.JSON(errCode, gin.H{ + "error": err.Error(), + "message": "Unable to get session", }) return } + identity := session.GetIdentity() + traits := identity.GetTraits() + profile := traits.(map[string]interface{}) + + profile["password"] = req_body.Password + if recovery_cookie != "" { + if profile["verified"] == false { + profile["verified"] = true + } + if profile["invite_status"] == "pending" { + profile["invite_status"] = "accepted" + } + } + + _, err = settings.SubmitSettingsFlowProfileMethod(flow_cookie, session_cookie, req_body.FlowID, req_body.CsrfToken, profile) + if err != nil { + log.ErrorLogger("Kratos post settings update profile flow failed", err) + + errCode, _ := strconv.Atoi((strings.Split(err.Error(), " "))[0]) + c.JSON(errCode, gin.H{ + "error": err.Error(), + "message": "Kratos post settings update profile flow failed", + }) + return + } c.JSON(http.StatusOK, gin.H{ "status": msg, }) @@ -239,15 +341,47 @@ func HandleToggleTOTP(c *gin.Context) { return } - msg, err := settings.SubmitSettingsFlowTOTPMethod(flow_cookie, session_cookie, req_body.FlowID, req_body.CsrfToken, req_body.Method, req_body.TOTPCode, req_body.TOTPUnlink) + msg, err := settings.SubmitSettingsFlowTOTPMethod(flow_cookie, session_cookie, req_body.FlowID, req_body.CsrfToken, req_body.TOTPCode, req_body.TOTPUnlink) + + if err != nil { + log.ErrorLogger("Kratos post settings toggle totp flow failed", err) + + errCode, _ := strconv.Atoi((strings.Split(err.Error(), " "))[0]) + c.JSON(errCode, gin.H{ + "error": err.Error(), + "message": "Kratos post settings toggle totp flow failed", + }) + return + } + + // Updates traits in identity + session, err := middleware.GetSession(c) + if err != nil { + log.ErrorLogger("Unable to get session", err) + errCode, _ := strconv.Atoi(strings.Split(err.Error(), " ")[0]) + c.JSON(errCode, gin.H{ + "error": err.Error(), + "message": "Unable to get session", + }) + return + } + identity := session.GetIdentity() + profile := identity.GetTraits().(map[string]interface{}) + + if !req_body.TOTPUnlink { + profile["totp_enabled"] = true + } else { + profile["totp_enabled"] = false + } + _, err = settings.SubmitSettingsFlowProfileMethod(flow_cookie, session_cookie, req_body.FlowID, req_body.CsrfToken, profile) if err != nil { - log.ErrorLogger("Kratos post settings flow failed", err) + log.ErrorLogger("Kratos post settings update profile flow failed", err) errCode, _ := strconv.Atoi((strings.Split(err.Error(), " "))[0]) c.JSON(errCode, gin.H{ "error": err.Error(), - "message": "Kratos post settings flow failed", + "message": "Kratos post settings update profile flow failed", }) return } diff --git a/api/verification.go b/api/verification.go index ac77c12..ddc01a9 100644 --- a/api/verification.go +++ b/api/verification.go @@ -74,6 +74,7 @@ func HandlePostVerificationFlow(c *gin.Context) { } c.JSON(http.StatusOK, gin.H{ - "message": "Account Verification Successful", + "message": "Account Verification Mail Sent", }) + } diff --git a/go.mod b/go.mod index d2219d9..2ee5374 100644 --- a/go.mod +++ b/go.mod @@ -5,7 +5,6 @@ go 1.18 require ( github.com/gin-contrib/cors v1.4.0 github.com/gin-gonic/gin v1.8.1 - github.com/goccy/go-json v0.9.7 github.com/lib/pq v1.10.7 github.com/ory/client-go v0.2.0-alpha.60 github.com/sirupsen/logrus v1.9.0 @@ -23,6 +22,7 @@ require ( github.com/go-playground/locales v0.14.0 // indirect github.com/go-playground/universal-translator v0.18.0 // indirect github.com/go-playground/validator/v10 v10.11.0 // indirect + github.com/goccy/go-json v0.9.7 // indirect github.com/golang/protobuf v1.5.2 // indirect github.com/json-iterator/go v1.1.12 // indirect github.com/leodido/go-urn v1.2.1 // indirect diff --git a/pkg/controller/admin/identity.go b/pkg/controller/admin/identity.go deleted file mode 100644 index 0966bd8..0000000 --- a/pkg/controller/admin/identity.go +++ /dev/null @@ -1,173 +0,0 @@ -package controller - -import ( - "context" - "encoding/json" - "fmt" - "net/http" - "os" - "strconv" - - "github.com/gin-gonic/gin" - client "github.com/ory/client-go" - - "github.com/sdslabs/nymeria/log" -) - -func CreateIdentity(c *gin.Context) { - configuration := client.NewConfiguration() - configuration.Servers = []client.ServerConfiguration{ - { - URL: "http://127.0.0.1:4434", // Kratos Admin API - }, - } - apiClient := client.NewAPIClient(configuration) - - id, _ := strconv.Atoi(c.PostForm("id")) - verified, _ := strconv.Atoi(c.PostForm("verified")) - active, _ := strconv.ParseBool(c.PostForm("active")) - totp_enabled, _ := strconv.ParseBool(c.PostForm("totp_enabled")) - adminCreateIdentityBody := *client.NewAdminCreateIdentityBody( - "default", - map[string]interface{}{ - "id": id, - "name": c.PostForm("name"), - "email": c.PostForm("email"), - "phone_number": c.PostForm("phone_number"), - "password": c.PostForm("password"), - "img_url": c.PostForm("img_url"), - "active": active, - "verified": verified, - "role": c.PostForm("role"), - "created_at": c.PostForm("created_at"), - "totp_enabled": totp_enabled, - }, - ) // AdminCreateIdentityBody | (optional) - - createdIdentity, r, err := apiClient.V0alpha2Api.AdminCreateIdentity(context.Background()).AdminCreateIdentityBody(adminCreateIdentityBody).Execute() - if err != nil { - log.ErrorLogger("Error while calling `AdminCreateIdentity`", err) - fmt.Fprintf(os.Stderr, "Full HTTP response: %v\n", r) - c.JSON(http.StatusInternalServerError, gin.H{ - "error": "INternal server error", - }) - } - c.JSON(http.StatusOK, gin.H{ - "identity": createdIdentity.Id, - }) - -} - -func GetIdentity(c *gin.Context) { - configuration := client.NewConfiguration() - configuration.Servers = []client.ServerConfiguration{ - { - URL: "http://127.0.0.1:4434", // Kratos Admin API - }, - } - apiClient := client.NewAPIClient(configuration) - - createdIdentity := c.Query("identity") - fmt.Println(createdIdentity) - getIdentity, r, err := apiClient.V0alpha2Api.AdminGetIdentity(context.Background(), createdIdentity).Execute() - - if err != nil { - log.ErrorLogger("Error while calling `AdminGetIdentity`", err) - fmt.Fprintf(os.Stderr, "Full HTTP response: %v\n", r) - c.JSON(http.StatusInternalServerError, gin.H{ - "error": "INternal server error", - }) - } - - jsonString, _ := json.Marshal(getIdentity.Traits) - - var identity Identity - if err := json.Unmarshal(jsonString, &identity); err != nil { - fmt.Println(err) - } - fmt.Fprintf(os.Stdout, "Identity details for id %v. Traits: %v\n", createdIdentity, identity) - c.JSON(http.StatusOK, gin.H{ - "Identity": createdIdentity, - "Traits": identity, - }) -} - -func DeleteIdentity(c *gin.Context) { - configuration := client.NewConfiguration() - configuration.Servers = []client.ServerConfiguration{ - { - URL: "http://127.0.0.1:4434", // Kratos Admin API - }, - } - apiClient := client.NewAPIClient(configuration) - - identity := c.PostForm("identity") - - r, err := apiClient.V0alpha2Api.AdminDeleteIdentity(context.Background(), identity).Execute() - if err != nil { - log.ErrorLogger("Error while calling `AdminDeleteIdentity`", err) - fmt.Fprintf(os.Stderr, "Full HTTP response: %v\n", r) - c.JSON(http.StatusInternalServerError, gin.H{ - "error": "INternal server error", - }) - } - c.JSON(http.StatusOK, gin.H{ - "message": "removed identity", - }) -} - -func ListIdentity(c *gin.Context) { - configuration := client.NewConfiguration() - configuration.Servers = []client.ServerConfiguration{ - { - URL: "http://127.0.0.1:4434", // Kratos Admin API - }, - } - apiClient := client.NewAPIClient(configuration) - - identities, r, err := apiClient.V0alpha2Api.AdminListIdentities(context.Background()).Execute() - - if err != nil { - log.ErrorLogger("Error while calling `AdminListIdentities`", err) - fmt.Fprintf(os.Stderr, "Full HTTP response: %v\n", r) - c.JSON(http.StatusInternalServerError, gin.H{ - "error": "Internal server error", - }) - } - c.JSON(http.StatusOK, gin.H{ - "identities": identities, - }) -} - -func UpdateBanIdentity(c *gin.Context) { - configuration := client.NewConfiguration() - configuration.Servers = []client.ServerConfiguration{ - { - URL: "http://127.0.0.1:4434", // Kratos Admin API - }, - } - apiClient := client.NewAPIClient(configuration) - - identity := c.PostForm("identity") - - jsonPatch := []client.JsonPatch{ - { - From: nil, - Op: "replace", - Path: "/active", - Value: false, - }, - } - id, r, err := apiClient.V0alpha2Api.AdminPatchIdentity(context.Background(), identity).JsonPatch(jsonPatch).Execute() - - if err != nil { - log.ErrorLogger("Error while calling `AdminPatchIdentities`", err) - fmt.Fprintf(os.Stderr, "Full HTTP response: %v\n", r) - c.JSON(http.StatusInternalServerError, gin.H{ - "error": err.Error(), - }) - } - c.JSON(http.StatusOK, gin.H{ - "identities": id, - }) -} diff --git a/pkg/controller/admin/types.go b/pkg/controller/admin/types.go deleted file mode 100644 index 7018a6b..0000000 --- a/pkg/controller/admin/types.go +++ /dev/null @@ -1,16 +0,0 @@ -package controller - -type Identity struct { - Id int - Name string - Username string - Email string - Phone_number uint64 - Password string - Image_url string - Active bool - Verified int - Created_at string - Github_id string - Dribble_id string -} diff --git a/pkg/middleware/rolecheck.go b/pkg/middleware/rolecheck.go index a63ab66..a9a3cb4 100644 --- a/pkg/middleware/rolecheck.go +++ b/pkg/middleware/rolecheck.go @@ -36,6 +36,7 @@ func GetSession(c *gin.Context) (*client.Session, error) { func OnlyAdmin(c *gin.Context) { session, err := GetSession(c) if err != nil { + c.JSON(http.StatusUnauthorized, gin.H{"error": "Unauthorized"}) c.Abort() return } diff --git a/pkg/wrapper/kratos/admin/admin.go b/pkg/wrapper/kratos/admin/admin.go index e24da94..8150855 100644 --- a/pkg/wrapper/kratos/admin/admin.go +++ b/pkg/wrapper/kratos/admin/admin.go @@ -7,16 +7,28 @@ import ( client "github.com/ory/client-go" "github.com/sdslabs/nymeria/config" + "github.com/sdslabs/nymeria/pkg/middleware" ) -func CreateIdentityFlowWrapper(identityMap map[string]interface{}) (*client.Identity, *http.Response, error) { - apiClient := client.NewAPIClient(config.KratosClientConfigAdmin) +func CreateIdentityFlowWrapper(data Identity) (*client.Identity, *http.Response, error) { + timeStamp := middleware.CurrentTimeStamp() + + trait := map[string]interface{}{ + "email": data.Email, + "name": data.Name, + "password": data.Password, + "phone_number": data.PhoneNumber, + "img_url": data.ImgURL, + "invite_status": "pending", + "verified": false, + "role": data.Role, + "created_at": timeStamp, + "totp_enabled": false, + } - adminCreateIdentityBody := *client.NewAdminCreateIdentityBody( - "default", - identityMap, - ) // AdminCreateIdentityBody | (optional) + adminCreateIdentityBody := *client.NewAdminCreateIdentityBody("default", trait) // AdminCreateIdentityBody | (optional) + apiClient := client.NewAPIClient(config.KratosClientConfigAdmin) createdIdentity, r, err := apiClient.V0alpha2Api.AdminCreateIdentity(context.Background()).AdminCreateIdentityBody(adminCreateIdentityBody).Execute() return createdIdentity, r, err @@ -53,7 +65,19 @@ func BanIdentityFlowWrapper(identity *client.Identity) (*client.Identity, *http. return nil, nil, err } - identity.Traits.(map[string]interface{})["active"] = false + submitDataBody := *client.NewAdminUpdateIdentityBody(identity.SchemaId, *newState, identity.Traits.(map[string]interface{})) + + apiClient := client.NewAPIClient(config.KratosClientConfigAdmin) + id, r, err := apiClient.V0alpha2Api.AdminUpdateIdentity(context.Background(), identity.Id).AdminUpdateIdentityBody(submitDataBody).Execute() + + return id, r, err +} + +func RemoveBanIdentityFlowWrapper(identity *client.Identity) (*client.Identity, *http.Response, error) { + newState, err := client.NewIdentityStateFromValue("active") + if err != nil { + return nil, nil, err + } submitDataBody := *client.NewAdminUpdateIdentityBody(identity.SchemaId, *newState, identity.Traits.(map[string]interface{})) @@ -62,3 +86,20 @@ func BanIdentityFlowWrapper(identity *client.Identity) (*client.Identity, *http. return id, r, err } + +func RoleSwitchFlowWrapper(identity *client.Identity) (*client.Identity, *http.Response, error) { + traits := identity.GetTraits().(map[string]interface{}) + + if traits["role"] == "user" { + traits["role"] = "admin" + } else if traits["role"] == "admin" { + traits["role"] = "user" + } + + submitDataBody := *client.NewAdminUpdateIdentityBody(identity.SchemaId, *identity.State, traits) + + apiClient := client.NewAPIClient(config.KratosClientConfigAdmin) + id, r, err := apiClient.V0alpha2Api.AdminUpdateIdentity(context.Background(), identity.Id).AdminUpdateIdentityBody(submitDataBody).Execute() + + return id, r, err +} diff --git a/pkg/wrapper/kratos/admin/types.go b/pkg/wrapper/kratos/admin/types.go index 0be4721..7f6d549 100644 --- a/pkg/wrapper/kratos/admin/types.go +++ b/pkg/wrapper/kratos/admin/types.go @@ -1,14 +1,10 @@ package admin type Identity struct { - Name string `json:"name"` - Email string `json:"email"` - Phone_number string `json:"phone_number"` - Password string `json:"password"` - Image_url string `json:"img_url"` - Active bool `json:"active"` - Verified bool `json:"verified"` - Role string `json:"role"` - Created_at string `json:"created_at"` - Totp_enabled bool `json:"totp_enabled"` + Name string `json:"name"` + Email string `json:"email"` + PhoneNumber string `json:"phone_number"` + Password string `json:"password"` + Role string `json:"role"` + ImgURL string `json:"img_url,omitempty"` } diff --git a/pkg/wrapper/kratos/login/login.go b/pkg/wrapper/kratos/login/login.go index 0cf9baf..bc2fa5c 100644 --- a/pkg/wrapper/kratos/login/login.go +++ b/pkg/wrapper/kratos/login/login.go @@ -10,7 +10,7 @@ import ( func InitializeLoginFlowWrapper(aal string, cookie string) (string, string, string, error) { refresh := false // bool | Refresh a login session If set to true, this will refresh an existing login session by asking the user to sign in again. This will reset the authenticated_at time of the session. (optional) - returnTo := "http://127.0.0.1:4455/ping" // string | The URL to return the browser to after the flow was completed. (optional) + returnTo := "http://localhost:4455/ping" // string | The URL to return the browser to after the flow was completed. (optional) apiClient := client.NewAPIClient(config.KratosClientConfig) diff --git a/pkg/wrapper/kratos/recovery/recovery.go b/pkg/wrapper/kratos/recovery/recovery.go index db2fc85..b8c3476 100644 --- a/pkg/wrapper/kratos/recovery/recovery.go +++ b/pkg/wrapper/kratos/recovery/recovery.go @@ -12,7 +12,7 @@ import ( func InitializeRecoveryFlowWrapper() (string, string, string, error) { - returnTo := "http://127.0.0.1:4455/ping" // string | The URL to return the browser to after the flow was completed. (optional) + returnTo := "http://localhost:4455/ping" // string | The URL to return the browser to after the flow was completed. (optional) apiClient := client.NewAPIClient(config.KratosClientConfig) @@ -24,7 +24,6 @@ func InitializeRecoveryFlowWrapper() (string, string, string, error) { var csrf_token string for _, node := range resp.Ui.Nodes { - fmt.Println(node.Attributes.UiNodeInputAttributes) if node.Attributes.UiNodeInputAttributes.Name == "csrf_token" { csrf_token_interface := node.Attributes.UiNodeInputAttributes.Value csrf_token, _ = csrf_token_interface.(string) @@ -36,13 +35,12 @@ func InitializeRecoveryFlowWrapper() (string, string, string, error) { return setCookie, resp.Id, csrf_token, nil } -func SubmitRecoveryFlowWrapper(cookie string, flowID string, csrfToken string, code string, method string) (string, error) { +func SubmitRecoveryFlowWrapper(cookie string, flowID string, csrfToken string, email string) (string, error) { submitFlowBody := client.SubmitSelfServiceRecoveryFlowBody{ - SubmitSelfServiceRecoveryFlowWithCodeMethodBody: client.NewSubmitSelfServiceRecoveryFlowWithCodeMethodBody(method), + SubmitSelfServiceRecoveryFlowWithLinkMethodBody: client.NewSubmitSelfServiceRecoveryFlowWithLinkMethodBody(email, "link"), } - submitFlowBody.SubmitSelfServiceRecoveryFlowWithCodeMethodBody.SetCode(code) - submitFlowBody.SubmitSelfServiceRecoveryFlowWithCodeMethodBody.SetCsrfToken(csrfToken) + submitFlowBody.SubmitSelfServiceRecoveryFlowWithLinkMethodBody.SetCsrfToken(csrfToken) apiClient := client.NewAPIClient(config.KratosClientConfig) _, r, err := apiClient.V0alpha2Api.SubmitSelfServiceRecoveryFlow(context.Background()).Flow(flowID).SubmitSelfServiceRecoveryFlowBody(submitFlowBody).Cookie(cookie).Execute() diff --git a/pkg/wrapper/kratos/recovery/types.go b/pkg/wrapper/kratos/recovery/types.go index 4777017..6cfee10 100644 --- a/pkg/wrapper/kratos/recovery/types.go +++ b/pkg/wrapper/kratos/recovery/types.go @@ -3,6 +3,5 @@ package recovery type SubmitRecoveryAPIBody struct { CsrfToken string `json:"csrf_token"` FlowID string `json:"flowID"` - Code string `json:"code"` - Method string `json:"method"` + Email string `json:"email"` } diff --git a/pkg/wrapper/kratos/registration/registration.go b/pkg/wrapper/kratos/registration/registration.go index c88bfc4..943e13c 100644 --- a/pkg/wrapper/kratos/registration/registration.go +++ b/pkg/wrapper/kratos/registration/registration.go @@ -12,7 +12,7 @@ import ( ) func InitializeRegistrationFlowWrapper() (string, string, string, error) { - returnTo := "http://127.0.0.1:4455/ping" + returnTo := "http://localhost:4455/ping" apiClient := client.NewAPIClient(config.KratosClientConfig) resp, r, err := apiClient.V0alpha2Api.InitializeSelfServiceRegistrationFlowForBrowsers(context.Background()).ReturnTo(returnTo).Execute() @@ -38,15 +38,16 @@ func InitializeRegistrationFlowWrapper() (string, string, string, error) { func SubmitRegistrationFlowWrapper(cookie string, flowID string, csrfToken string, password string, data Traits) (string, error) { timeStamp := middleware.CurrentTimeStamp() trait := map[string]interface{}{ - "email": data.Email, - "name": data.Name, - "password": password, - "phone_number": data.PhoneNumber, - "active": true, - "verified": false, - "role": "user", - "created_at": timeStamp, - "totp_enabled": false, + "email": data.Email, + "name": data.Name, + "password": password, + "img_url": data.ImgURL, + "phone_number": data.PhoneNumber, + "invite_status": "self_created", + "verified": false, + "role": "user", + "created_at": timeStamp, + "totp_enabled": false, } submitDataBody := client.SubmitSelfServiceRegistrationFlowBody{ diff --git a/pkg/wrapper/kratos/registration/types.go b/pkg/wrapper/kratos/registration/types.go index c4208ca..666da16 100644 --- a/pkg/wrapper/kratos/registration/types.go +++ b/pkg/wrapper/kratos/registration/types.go @@ -11,4 +11,5 @@ type Traits struct { Email string `json:"email"` Name string `json:"name"` PhoneNumber string `json:"phone_number"` + ImgURL string `json:"img_url,omitempty"` } diff --git a/pkg/wrapper/kratos/settings/settings.go b/pkg/wrapper/kratos/settings/settings.go index 03c1412..d861671 100644 --- a/pkg/wrapper/kratos/settings/settings.go +++ b/pkg/wrapper/kratos/settings/settings.go @@ -1,136 +1,98 @@ package settings import ( - "bytes" "context" - "errors" - "net/http" + "fmt" + "os" "strings" - "github.com/goccy/go-json" client "github.com/ory/client-go" "github.com/sdslabs/nymeria/config" ) -func InitializeSettingsFlowWrapper(req_cookie string) (client.SelfServiceSettingsFlow, string, error) { +func InitializeSettingsFlowWrapper(session_cookie string, recovery_cookie string) (client.SelfServiceSettingsFlow, string, error) { - returnTo := "http://127.0.0.1:4455/ping" // string | The URL to return the browser to after the flow was completed. (optional) + returnTo := "http://localhost:4455/ping" // 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] + } apiClient := client.NewAPIClient(config.KratosClientConfig) - resp, httpRes, err := apiClient.V0alpha2Api.InitializeSelfServiceSettingsFlowForBrowsers(context.Background()).ReturnTo(returnTo).Cookie(req_cookie).Execute() + resp, httpRes, err := apiClient.V0alpha2Api.InitializeSelfServiceSettingsFlowForBrowsers(context.Background()).ReturnTo(returnTo).Cookie(cookie).Execute() if err != nil { return *client.NewSelfServiceSettingsFlowWithDefaults(), "", err } - cookie := httpRes.Header.Get("Set-Cookie") + cookie = httpRes.Header.Get("Set-Cookie") return *resp, cookie, nil } -func SubmitSettingsFlowPasswordMethod(flow_cookie string, session_cookie string, flowID string, csrfToken string, method string, password string) (string, error) { - client := &http.Client{} - - var req_body SubmitSettingsWithPasswordBody - req_body.Method = method - req_body.Password = password - req_body.CsrfToken = csrfToken - - body, err := json.Marshal(req_body) - if err != nil { - return "", err - } - req, err := http.NewRequest(http.MethodPost, "http://127.0.0.1:4433/self-service/settings", bytes.NewBuffer(body)) - - q := req.URL.Query() - q.Add("flow", flowID) - - if err != nil { - return "", err +func SubmitSettingsFlowPasswordMethod(flow_cookie string, session_cookie string, flowID string, csrfToken string, password string) (string, error) { + submitFlowBody := client.SubmitSelfServiceSettingsFlowBody{ + SubmitSelfServiceSettingsFlowWithPasswordMethodBody: client.NewSubmitSelfServiceSettingsFlowWithPasswordMethodBody("password", password), } + submitFlowBody.SubmitSelfServiceSettingsFlowWithPasswordMethodBody.SetCsrfToken(csrfToken) cookie := strings.Split(flow_cookie, ";")[0] + "; " + strings.Split(session_cookie, ";")[0] + "; x-csrf-token=" + csrfToken - req.URL.RawQuery = q.Encode() - req.Header.Set("Cookie", cookie) - req.Header.Set("Content-Type", "application/json") - resp, err := client.Do(req) + apiClient := client.NewAPIClient(config.KratosClientConfig) + _, r, err := apiClient.V0alpha2Api.SubmitSelfServiceSettingsFlow(context.Background()).Flow(flowID).Cookie(cookie).SubmitSelfServiceSettingsFlowBody(submitFlowBody).Execute() - if err != nil || resp.StatusCode != 200 { - error := errors.New(resp.Status) - return "", error + if err != nil { + fmt.Fprintf(os.Stderr, "Error when calling `V0alpha2Api.SubmitSelfServiceVerificationFlow``: %v\n", err) + fmt.Fprintf(os.Stderr, "Full HTTP response: %v\n", r) + return "", err } return "Password Changed", nil } -func SubmitSettingsFlowProfileMethod(flow_cookie string, session_cookie string, flowID string, csrfToken string, method string, traits map[string]interface{}) (string, error) { - client := &http.Client{} - - var req_body SubmitSettingsProfileRequest - req_body.Method = method - req_body.CsrfToken = csrfToken - req_body.Traits = traits - - body, err := json.Marshal(req_body) - if err != nil { - return "", err +func SubmitSettingsFlowProfileMethod(flow_cookie string, session_cookie string, flowID string, csrfToken string, traits map[string]interface{}) (string, error) { + submitFlowBody := client.SubmitSelfServiceSettingsFlowBody{ + SubmitSelfServiceSettingsFlowWithProfileMethodBody: client.NewSubmitSelfServiceSettingsFlowWithProfileMethodBody("profile", traits), } - req, err := http.NewRequest(http.MethodPost, "http://127.0.0.1:4433/self-service/settings", bytes.NewBuffer(body)) - q := req.URL.Query() - q.Add("flow", flowID) + submitFlowBody.SubmitSelfServiceSettingsFlowWithProfileMethodBody.SetCsrfToken(csrfToken) - if err != nil { - return "", err - } cookie := strings.Split(flow_cookie, ";")[0] + "; " + strings.Split(session_cookie, ";")[0] + "; x-csrf-token=" + csrfToken - req.URL.RawQuery = q.Encode() - req.Header.Set("Cookie", cookie) - req.Header.Set("Content-Type", "application/json") - resp, err := client.Do(req) + apiClient := client.NewAPIClient(config.KratosClientConfig) + _, r, err := apiClient.V0alpha2Api.SubmitSelfServiceSettingsFlow(context.Background()).Flow(flowID).Cookie(cookie).SubmitSelfServiceSettingsFlowBody(submitFlowBody).Execute() - if err != nil || resp.StatusCode != 200 { - error := errors.New(resp.Status) - return "", error + if err != nil { + fmt.Fprintf(os.Stderr, "Error when calling `V0alpha2Api.SubmitSelfServiceVerificationFlow``: %v\n", err) + fmt.Fprintf(os.Stderr, "Full HTTP response: %v\n", r) + return "", err } return "Profile Updated", nil } -func SubmitSettingsFlowTOTPMethod(flow_cookie string, session_cookie string, flowID string, csrfToken string, method string, TOTPcode string, TOTPUnlink bool) (string, error) { - client := &http.Client{} - - var req_body SubmitSettingsWithTOTPBody - req_body.Method = method - req_body.TotpCode = TOTPcode - req_body.TotpUnlink = TOTPUnlink - req_body.CsrfToken = csrfToken - - body, err := json.Marshal(req_body) - if err != nil { - return "", err +func SubmitSettingsFlowTOTPMethod(flow_cookie string, session_cookie string, flowID string, csrfToken string, TOTPcode string, TOTPUnlink bool) (string, error) { + submitFlowBody := client.SubmitSelfServiceSettingsFlowBody{ + SubmitSelfServiceSettingsFlowWithTotpMethodBody: client.NewSubmitSelfServiceSettingsFlowWithTotpMethodBody("totp"), } - req, err := http.NewRequest(http.MethodPost, "http://127.0.0.1:4433/self-service/settings", bytes.NewBuffer(body)) - q := req.URL.Query() - q.Add("flow", flowID) - - if err != nil { - return "", err - } + submitFlowBody.SubmitSelfServiceSettingsFlowWithTotpMethodBody.SetCsrfToken(csrfToken) + submitFlowBody.SubmitSelfServiceSettingsFlowWithTotpMethodBody.SetTotpCode(TOTPcode) + submitFlowBody.SubmitSelfServiceSettingsFlowWithTotpMethodBody.SetTotpUnlink(TOTPUnlink) cookie := strings.Split(flow_cookie, ";")[0] + "; " + strings.Split(session_cookie, ";")[0] + "; x-csrf-token=" + csrfToken - req.URL.RawQuery = q.Encode() - req.Header.Set("Cookie", cookie) - req.Header.Set("Content-Type", "application/json") - resp, err := client.Do(req) + apiClient := client.NewAPIClient(config.KratosClientConfig) + _, r, err := apiClient.V0alpha2Api.SubmitSelfServiceSettingsFlow(context.Background()).Flow(flowID).Cookie(cookie).SubmitSelfServiceSettingsFlowBody(submitFlowBody).Execute() - if err != nil || resp.StatusCode != 200 { - error := errors.New(resp.Status) - return "", error + if err != nil { + fmt.Fprintf(os.Stderr, "Error when calling `V0alpha2Api.SubmitSelfServiceVerificationFlow``: %v\n", err) + fmt.Fprintf(os.Stderr, "Full HTTP response: %v\n", r) + return "", err } return "Totp Toggled", nil diff --git a/pkg/wrapper/kratos/settings/types.go b/pkg/wrapper/kratos/settings/types.go index be555ca..387a107 100644 --- a/pkg/wrapper/kratos/settings/types.go +++ b/pkg/wrapper/kratos/settings/types.go @@ -1,21 +1,18 @@ package settings type UpdateProfileAPIBody struct { - Method string `json:"method"` FlowID string `json:"flowID"` CsrfToken string `json:"csrf_token"` - Traits Traits `json:"Traits"` + Traits Traits `json:"traits"` } type ChangePasswordAPIBody struct { - Method string `json:"method"` FlowID string `json:"flowID"` CsrfToken string `json:"csrf_token"` Password string `json:"password"` } type ToggleTOTPAPIBody struct { - Method string `json:"method"` FlowID string `json:"flowID"` CsrfToken string `json:"csrf_token"` TOTPCode string `json:"totp_code"` @@ -42,12 +39,14 @@ type SubmitSettingsWithPasswordBody struct { } type Traits struct { + Email string `json:"email"` Name string `json:"name"` - PhoneNumber string `json:"phone_number"` + Password string `json:"password"` ImgURL string `json:"img_url,omitempty"` - Email string `json:"email"` + PhoneNumber string `json:"phone_number"` + InviteStatus string `json:"invite_status"` + Verified bool `json:"verified"` Role string `json:"role"` - Active bool `json:"active"` Created_At string `json:"created_at"` TOTP_Enabled bool `json:"totp_enabled"` } diff --git a/pkg/wrapper/kratos/verification/verification.go b/pkg/wrapper/kratos/verification/verification.go index 31edb84..6f87672 100644 --- a/pkg/wrapper/kratos/verification/verification.go +++ b/pkg/wrapper/kratos/verification/verification.go @@ -22,7 +22,6 @@ func InitializeVerificationFlowWrapper() (string, string, string, error) { var csrf_token string for _, node := range resp.Ui.Nodes { - fmt.Println(node.Attributes.UiNodeInputAttributes) if node.Attributes.UiNodeInputAttributes.Name == "csrf_token" { csrf_token_interface := node.Attributes.UiNodeInputAttributes.Value csrf_token, _ = csrf_token_interface.(string)