diff --git a/scnserver/TODO.md b/scnserver/TODO.md index 4f2dfbf..e6ed3ec 100644 --- a/scnserver/TODO.md +++ b/scnserver/TODO.md @@ -44,7 +44,7 @@ * [X] CRUD routes for keys * [X] KeyToken.messagecounter * [x] update old-data migration to create token-keys - * [ ] unit tests + * [x] unit tests - We no longer have a route to reshuffle all keys (previously in updateUser), add a /user/:uid/keys/reset ? Would delete all existing keys and create 3 new ones? diff --git a/scnserver/api/apierr/enums.go b/scnserver/api/apierr/enums.go index 283c9d6..9d1d448 100644 --- a/scnserver/api/apierr/enums.go +++ b/scnserver/api/apierr/enums.go @@ -44,6 +44,7 @@ const ( CHANNEL_ALREADY_EXISTS APIError = 1501 CANNOT_SELFDELETE_KEY APIError = 1511 + CANNOT_SELFUPDATE_KEY APIError = 1512 QUOTA_REACHED APIError = 2101 diff --git a/scnserver/api/handler/api.go b/scnserver/api/handler/api.go index 5986a6a..9c3bbc3 100644 --- a/scnserver/api/handler/api.go +++ b/scnserver/api/handler/api.go @@ -201,10 +201,7 @@ func (h APIHandler) GetUser(g *gin.Context) ginresp.HTTPResponse { // @Param uid path int true "UserID" // // @Param username body string false "Change the username (send an empty string to clear it)" -// @Param pro_token body string false "Send a verification of permium purchase" -// @Param read_key body string false "Send `true` to create a new read_key" -// @Param send_key body string false "Send `true` to create a new send_key" -// @Param admin_key body string false "Send `true` to create a new admin_key" +// @Param pro_token body string false "Send a verification of premium purchase" // // @Success 200 {object} models.UserJSON // @Failure 400 {object} ginresp.apiError "supplied values/parameters cannot be parsed / are invalid" @@ -1619,7 +1616,7 @@ func (h APIHandler) GetUserKey(g *gin.Context) ginresp.HTTPResponse { return *permResp } - client, err := h.database.GetKeyToken(ctx, u.UserID, u.KeyID) + keytoken, err := h.database.GetKeyToken(ctx, u.UserID, u.KeyID) if err == sql.ErrNoRows { return ginresp.APIError(g, 404, apierr.KEY_NOT_FOUND, "Key not found", err) } @@ -1627,7 +1624,7 @@ func (h APIHandler) GetUserKey(g *gin.Context) ginresp.HTTPResponse { return ginresp.APIError(g, 500, apierr.DATABASE_ERROR, "Failed to query client", err) } - return ctx.FinishSuccess(ginresp.JSON(http.StatusOK, client.JSON())) + return ctx.FinishSuccess(ginresp.JSON(http.StatusOK, keytoken.JSON())) } // UpdateUserKey swaggerdoc @@ -1639,6 +1636,8 @@ func (h APIHandler) GetUserKey(g *gin.Context) ginresp.HTTPResponse { // @Param uid path int true "UserID" // @Param kid path int true "TokenKeyID" // +// @Param post_body body handler.UpdateUserKey.body false " " +// // @Success 200 {object} models.KeyTokenJSON // @Failure 400 {object} ginresp.apiError "supplied values/parameters cannot be parsed / are invalid" // @Failure 401 {object} ginresp.apiError "user is not authorized / has missing permissions" @@ -1670,7 +1669,7 @@ func (h APIHandler) UpdateUserKey(g *gin.Context) ginresp.HTTPResponse { return *permResp } - client, err := h.database.GetKeyToken(ctx, u.UserID, u.KeyID) + keytoken, err := h.database.GetKeyToken(ctx, u.UserID, u.KeyID) if err == sql.ErrNoRows { return ginresp.APIError(g, 404, apierr.KEY_NOT_FOUND, "Key not found", err) } @@ -1683,30 +1682,47 @@ func (h APIHandler) UpdateUserKey(g *gin.Context) ginresp.HTTPResponse { if err != nil { return ginresp.APIError(g, 500, apierr.DATABASE_ERROR, "Failed to update name", err) } + keytoken.Name = *b.Name } if b.Permissions != nil { - err := h.database.UpdateKeyTokenPermissions(ctx, u.KeyID, models.ParseTokenPermissionList(*b.Permissions)) + if keytoken.KeyTokenID == *ctx.GetPermissionKeyTokenID() { + return ginresp.APIError(g, 400, apierr.CANNOT_SELFUPDATE_KEY, "Cannot update the currently used key", err) + } + + permlist := models.ParseTokenPermissionList(*b.Permissions) + err := h.database.UpdateKeyTokenPermissions(ctx, u.KeyID, permlist) if err != nil { return ginresp.APIError(g, 500, apierr.DATABASE_ERROR, "Failed to update permissions", err) } + keytoken.Permissions = permlist } if b.AllChannels != nil { + if keytoken.KeyTokenID == *ctx.GetPermissionKeyTokenID() { + return ginresp.APIError(g, 400, apierr.CANNOT_SELFUPDATE_KEY, "Cannot update the currently used key", err) + } + err := h.database.UpdateKeyTokenAllChannels(ctx, u.KeyID, *b.AllChannels) if err != nil { return ginresp.APIError(g, 500, apierr.DATABASE_ERROR, "Failed to update all_channels", err) } + keytoken.AllChannels = *b.AllChannels } if b.Channels != nil { + if keytoken.KeyTokenID == *ctx.GetPermissionKeyTokenID() { + return ginresp.APIError(g, 400, apierr.CANNOT_SELFUPDATE_KEY, "Cannot update the currently used key", err) + } + err := h.database.UpdateKeyTokenChannels(ctx, u.KeyID, *b.Channels) if err != nil { return ginresp.APIError(g, 500, apierr.DATABASE_ERROR, "Failed to update channels", err) } + keytoken.Channels = *b.Channels } - return ctx.FinishSuccess(ginresp.JSON(http.StatusOK, client.JSON())) + return ctx.FinishSuccess(ginresp.JSON(http.StatusOK, keytoken.JSON())) } // CreateUserKey swaggerdoc @@ -1810,7 +1826,7 @@ func (h APIHandler) DeleteUserKey(g *gin.Context) ginresp.HTTPResponse { } if u.KeyID == *ctx.GetPermissionKeyTokenID() { - return ginresp.APIError(g, 404, apierr.CANNOT_SELFDELETE_KEY, "Cannot delete the currently used key", err) + return ginresp.APIError(g, 400, apierr.CANNOT_SELFDELETE_KEY, "Cannot delete the currently used key", err) } err = h.database.DeleteKeyToken(ctx, u.KeyID) diff --git a/scnserver/test/keytoken_test.go b/scnserver/test/keytoken_test.go index 92d138c..759b5c7 100644 --- a/scnserver/test/keytoken_test.go +++ b/scnserver/test/keytoken_test.go @@ -1,56 +1,493 @@ package test import ( + "blackforestbytes.com/simplecloudnotifier/api/apierr" tt "blackforestbytes.com/simplecloudnotifier/test/util" "fmt" + "github.com/gin-gonic/gin" "testing" ) -func TestListUserKeys(t *testing.T) { +func TestTokenKeys(t *testing.T) { ws, baseUrl, stop := tt.StartSimpleWebserver(t) defer stop() data := tt.InitSingleData(t, ws) + type keyobj struct { + AllChannels bool `json:"all_channels"` + Channels []string `json:"channels"` + KeytokenId string `json:"keytoken_id"` + MessagesSent int `json:"messages_sent"` + Name string `json:"name"` + OwnerUserId string `json:"owner_user_id"` + Permissions string `json:"permissions"` + Token string `json:"token"` // only in create + } type keylist struct { - Tokens []struct { - AllChannels bool `json:"all_channels"` - Channels []string `json:"channels"` - KeytokenId string `json:"keytoken_id"` - MessagesSent int `json:"messages_sent"` - Name string `json:"name"` - OwnerUserId string `json:"owner_user_id"` - Permissions string `json:"permissions"` - } `json:"tokens"` + Keys []keyobj `json:"keys"` + } + + { + klist := tt.RequestAuthGet[keylist](t, data.AdminKey, baseUrl, fmt.Sprintf("/api/v2/users/%s/keys", data.UserID)) + tt.AssertEqual(t, "len(keys)", 3, len(klist.Keys)) + + tt.AssertArrAny(t, "keys->any[Admin]", klist.Keys, func(s keyobj) bool { + return s.AllChannels == true && s.Name == "AdminKey (default)" && s.Permissions == "A" + }) + tt.AssertArrAny(t, "keys->any[Send]", klist.Keys, func(s keyobj) bool { + return s.AllChannels == true && s.Name == "SendKey (default)" && s.Permissions == "CS" + }) + tt.AssertArrAny(t, "keys->any[Read]", klist.Keys, func(s keyobj) bool { + return s.AllChannels == true && s.Name == "ReadKey (default)" && s.Permissions == "UR;CR" + }) + } + + key2 := tt.RequestAuthPost[keyobj](t, data.AdminKey, baseUrl, fmt.Sprintf("/api/v2/users/%s/keys", data.UserID), gin.H{ + "all_channels": true, + "channels": []string{}, + "name": "Admin2", + "permissions": "A", + }) + + tt.AssertEqual(t, "Name", "Admin2", key2.Name) + tt.AssertEqual(t, "Permissions", "A", key2.Permissions) + tt.AssertEqual(t, "AllChannels", true, key2.AllChannels) + + { + klist := tt.RequestAuthGet[keylist](t, data.AdminKey, baseUrl, fmt.Sprintf("/api/v2/users/%s/keys", data.UserID)) + tt.AssertEqual(t, "len(keys)", 4, len(klist.Keys)) + } + + key3 := tt.RequestAuthGet[keyobj](t, data.AdminKey, baseUrl, fmt.Sprintf("/api/v2/users/%s/keys/%s", data.UserID, key2.KeytokenId)) + + tt.AssertEqual(t, "KeytokenId", key2.KeytokenId, key3.KeytokenId) + tt.AssertEqual(t, "UserID", data.UserID, key3.OwnerUserId) + tt.AssertEqual(t, "Name", "Admin2", key3.Name) + tt.AssertEqual(t, "Permissions", "A", key3.Permissions) + tt.AssertEqual(t, "AllChannels", true, key3.AllChannels) + + tt.RequestAuthDelete[tt.Void](t, data.AdminKey, baseUrl, fmt.Sprintf("/api/v2/users/%s/keys/%s", data.UserID, key2.KeytokenId), gin.H{}) + + tt.RequestAuthGetShouldFail(t, data.AdminKey, baseUrl, fmt.Sprintf("/api/v2/users/%s/keys/%s", data.UserID, key2.KeytokenId), 404, apierr.KEY_NOT_FOUND) + + { + klist := tt.RequestAuthGet[keylist](t, data.AdminKey, baseUrl, fmt.Sprintf("/api/v2/users/%s/keys", data.UserID)) + tt.AssertEqual(t, "len(keys)", 3, len(klist.Keys)) + } + + chan0 := tt.RequestAuthPost[gin.H](t, data.AdminKey, baseUrl, fmt.Sprintf("/api/v2/users/%s/channels", data.UserID), gin.H{ + "name": "testchan1", + }) + chanid := fmt.Sprintf("%v", chan0["channel_id"]) + + key4 := tt.RequestAuthPost[keyobj](t, data.AdminKey, baseUrl, fmt.Sprintf("/api/v2/users/%s/keys", data.UserID), gin.H{ + "all_channels": false, + "channels": []string{chanid}, + "name": "TKey1", + "permissions": "CS", + }) + tt.AssertEqual(t, "Name", "TKey1", key4.Name) + tt.AssertEqual(t, "Permissions", "CS", key4.Permissions) + tt.AssertEqual(t, "AllChannels", false, key4.AllChannels) + tt.AssertStrRepEqual(t, "Channels", []string{chanid}, key4.Channels) + + key5 := tt.RequestAuthPatch[keyobj](t, data.AdminKey, baseUrl, fmt.Sprintf("/api/v2/users/%s/keys/%s", data.UserID, key4.KeytokenId), gin.H{ + "all_channels": true, + "channels": []string{}, + "name": "TKey2-A", + "permissions": "A", + }) + tt.AssertEqual(t, "Name", "TKey2-A", key5.Name) + tt.AssertEqual(t, "Permissions", "A", key5.Permissions) + tt.AssertEqual(t, "AllChannels", true, key5.AllChannels) + tt.AssertStrRepEqual(t, "Channels", []string{}, key5.Channels) + + key6 := tt.RequestAuthGet[keyobj](t, data.AdminKey, baseUrl, fmt.Sprintf("/api/v2/users/%s/keys/%s", data.UserID, key5.KeytokenId)) + tt.AssertEqual(t, "Name", "TKey2-A", key6.Name) + tt.AssertEqual(t, "Permissions", "A", key6.Permissions) + tt.AssertEqual(t, "AllChannels", true, key6.AllChannels) + tt.AssertStrRepEqual(t, "Channels", []string{}, key6.Channels) + + key7 := tt.RequestAuthPost[keyobj](t, data.AdminKey, baseUrl, fmt.Sprintf("/api/v2/users/%s/keys", data.UserID), gin.H{ + "all_channels": false, + "channels": []string{chanid}, + "name": "TKey7", + "permissions": "CS", + }) + + { + klist := tt.RequestAuthGet[keylist](t, data.AdminKey, baseUrl, fmt.Sprintf("/api/v2/users/%s/keys", data.UserID)) + tt.AssertEqual(t, "len(keys)", 5, len(klist.Keys)) + } + + msg1s := tt.RequestPost[gin.H](t, baseUrl, "/", gin.H{ + "key": key7.Token, + "user_id": data.UserID, + "channel": "testchan1", + "title": "HelloWorld_001", + }) + + msg1 := tt.RequestAuthGet[gin.H](t, data.AdminKey, baseUrl, fmt.Sprintf("/api/v2/messages/%s", msg1s["scn_msg_id"])) + + tt.AssertEqual(t, "AllChannels", key7.KeytokenId, msg1["used_key_id"]) + + tt.RequestPostShouldFail(t, baseUrl, "/", gin.H{ + "key": key7.Token, + "user_id": data.UserID, + "channel": "testchan2", + "title": "HelloWorld_001", + }, 401, apierr.USER_AUTH_FAILED) // wrong channel + + tt.RequestPostShouldFail(t, baseUrl, "/", gin.H{ + "key": key7.Token, + "user_id": data.UserID, + "title": "HelloWorld_001", + }, 401, apierr.USER_AUTH_FAILED) // no channel (=main) + + tt.RequestAuthGetShouldFail(t, key7.Token, baseUrl, fmt.Sprintf("/api/v2/users/%s", data.UserID), 401, apierr.USER_AUTH_FAILED) // no user read perm + + tt.RequestAuthPatchShouldFail(t, key7.Token, baseUrl, "/api/v2/users/"+data.UserID, gin.H{"username": "my_user_001"}, 401, apierr.USER_AUTH_FAILED) // no user update perm + + key8 := tt.RequestAuthPost[keyobj](t, data.AdminKey, baseUrl, fmt.Sprintf("/api/v2/users/%s/keys", data.UserID), gin.H{ + "all_channels": true, + "channels": []string{}, + "name": "TKey7", + "permissions": "CR", + }) + + tt.RequestPostShouldFail(t, baseUrl, "/", gin.H{ + "key": key8.Token, + "user_id": data.UserID, + "title": "HelloWorld_001", + }, 401, apierr.USER_AUTH_FAILED) // no send perm + +} + +func TestTokenKeysInitial(t *testing.T) { + ws, baseUrl, stop := tt.StartSimpleWebserver(t) + defer stop() + + data := tt.InitSingleData(t, ws) + + type keyobj struct { + AllChannels bool `json:"all_channels"` + Channels []string `json:"channels"` + KeytokenId string `json:"keytoken_id"` + MessagesSent int `json:"messages_sent"` + Name string `json:"name"` + OwnerUserId string `json:"owner_user_id"` + Permissions string `json:"permissions"` + Token string `json:"token"` // only in create + } + type keylist struct { + Keys []keyobj `json:"keys"` + } + + klist := tt.RequestAuthGet[keylist](t, data.AdminKey, baseUrl, fmt.Sprintf("/api/v2/users/%s/keys", data.UserID)) + tt.AssertEqual(t, "len(keys)", 3, len(klist.Keys)) + + tt.AssertArrAny(t, "keys->any[Admin]", klist.Keys, func(s keyobj) bool { + return s.AllChannels == true && s.Name == "AdminKey (default)" && s.Permissions == "A" + }) + tt.AssertArrAny(t, "keys->any[Send]", klist.Keys, func(s keyobj) bool { + return s.AllChannels == true && s.Name == "SendKey (default)" && s.Permissions == "CS" + }) + tt.AssertArrAny(t, "keys->any[Read]", klist.Keys, func(s keyobj) bool { + return s.AllChannels == true && s.Name == "ReadKey (default)" && s.Permissions == "UR;CR" + }) +} + +func TestTokenKeysCreate(t *testing.T) { + ws, baseUrl, stop := tt.StartSimpleWebserver(t) + defer stop() + + data := tt.InitSingleData(t, ws) + + type keyobj struct { + AllChannels bool `json:"all_channels"` + Channels []string `json:"channels"` + KeytokenId string `json:"keytoken_id"` + MessagesSent int `json:"messages_sent"` + Name string `json:"name"` + OwnerUserId string `json:"owner_user_id"` + Permissions string `json:"permissions"` + Token string `json:"token"` // only in create + } + type keylist struct { + Keys []keyobj `json:"keys"` + } + + key2 := tt.RequestAuthPost[keyobj](t, data.AdminKey, baseUrl, fmt.Sprintf("/api/v2/users/%s/keys", data.UserID), gin.H{ + "all_channels": true, + "channels": []string{}, + "name": "Admin2", + "permissions": "A", + }) + + tt.AssertEqual(t, "Name", "Admin2", key2.Name) + tt.AssertEqual(t, "Permissions", "A", key2.Permissions) + tt.AssertEqual(t, "AllChannels", true, key2.AllChannels) + + { + klist := tt.RequestAuthGet[keylist](t, data.AdminKey, baseUrl, fmt.Sprintf("/api/v2/users/%s/keys", data.UserID)) + tt.AssertEqual(t, "len(keys)", 4, len(klist.Keys)) + } + + key3 := tt.RequestAuthGet[keyobj](t, data.AdminKey, baseUrl, fmt.Sprintf("/api/v2/users/%s/keys/%s", data.UserID, key2.KeytokenId)) + + tt.AssertEqual(t, "KeytokenId", key2.KeytokenId, key3.KeytokenId) + tt.AssertEqual(t, "UserID", data.UserID, key3.OwnerUserId) + tt.AssertEqual(t, "Name", "Admin2", key3.Name) + tt.AssertEqual(t, "Permissions", "A", key3.Permissions) + tt.AssertEqual(t, "AllChannels", true, key3.AllChannels) + +} + +func TestTokenKeysUpdate(t *testing.T) { + ws, baseUrl, stop := tt.StartSimpleWebserver(t) + defer stop() + + data := tt.InitSingleData(t, ws) + + type keyobj struct { + AllChannels bool `json:"all_channels"` + Channels []string `json:"channels"` + KeytokenId string `json:"keytoken_id"` + MessagesSent int `json:"messages_sent"` + Name string `json:"name"` + OwnerUserId string `json:"owner_user_id"` + Permissions string `json:"permissions"` + Token string `json:"token"` // only in create + } + type keylist struct { + Keys []keyobj `json:"keys"` + } + + key2 := tt.RequestAuthPost[keyobj](t, data.AdminKey, baseUrl, fmt.Sprintf("/api/v2/users/%s/keys", data.UserID), gin.H{ + "all_channels": true, + "channels": []string{}, + "name": "Admin2", + "permissions": "A", + }) + + tt.AssertEqual(t, "Name", "Admin2", key2.Name) + tt.AssertEqual(t, "Permissions", "A", key2.Permissions) + tt.AssertEqual(t, "AllChannels", true, key2.AllChannels) + + key3 := tt.RequestAuthGet[keyobj](t, data.AdminKey, baseUrl, fmt.Sprintf("/api/v2/users/%s/keys/%s", data.UserID, key2.KeytokenId)) + + tt.AssertEqual(t, "KeytokenId", key2.KeytokenId, key3.KeytokenId) + tt.AssertEqual(t, "UserID", data.UserID, key3.OwnerUserId) + tt.AssertEqual(t, "Name", "Admin2", key3.Name) + tt.AssertEqual(t, "Permissions", "A", key3.Permissions) + tt.AssertEqual(t, "AllChannels", true, key3.AllChannels) + + key5 := tt.RequestAuthPatch[keyobj](t, data.AdminKey, baseUrl, fmt.Sprintf("/api/v2/users/%s/keys/%s", data.UserID, key3.KeytokenId), gin.H{ + "name": "Hello", + }) + tt.AssertEqual(t, "Name", "Hello", key5.Name) + tt.AssertEqual(t, "Permissions", "A", key5.Permissions) + tt.AssertEqual(t, "AllChannels", true, key5.AllChannels) + tt.AssertStrRepEqual(t, "Channels", []string{}, key5.Channels) + + key6 := tt.RequestAuthGet[keyobj](t, data.AdminKey, baseUrl, fmt.Sprintf("/api/v2/users/%s/keys/%s", data.UserID, key5.KeytokenId)) + tt.AssertEqual(t, "Name", "Hello", key6.Name) + tt.AssertEqual(t, "Permissions", "A", key6.Permissions) + tt.AssertEqual(t, "AllChannels", true, key6.AllChannels) + tt.AssertStrRepEqual(t, "Channels", []string{}, key6.Channels) + +} + +func TestTokenKeysDelete(t *testing.T) { + ws, baseUrl, stop := tt.StartSimpleWebserver(t) + defer stop() + + data := tt.InitSingleData(t, ws) + + type keyobj struct { + AllChannels bool `json:"all_channels"` + Channels []string `json:"channels"` + KeytokenId string `json:"keytoken_id"` + MessagesSent int `json:"messages_sent"` + Name string `json:"name"` + OwnerUserId string `json:"owner_user_id"` + Permissions string `json:"permissions"` + Token string `json:"token"` // only in create + } + type keylist struct { + Keys []keyobj `json:"keys"` + } + + key2 := tt.RequestAuthPost[keyobj](t, data.AdminKey, baseUrl, fmt.Sprintf("/api/v2/users/%s/keys", data.UserID), gin.H{ + "all_channels": true, + "channels": []string{}, + "name": "Admin2", + "permissions": "A", + }) + + tt.AssertEqual(t, "Name", "Admin2", key2.Name) + tt.AssertEqual(t, "Permissions", "A", key2.Permissions) + tt.AssertEqual(t, "AllChannels", true, key2.AllChannels) + + { + klist := tt.RequestAuthGet[keylist](t, data.AdminKey, baseUrl, fmt.Sprintf("/api/v2/users/%s/keys", data.UserID)) + tt.AssertEqual(t, "len(keys)", 4, len(klist.Keys)) + } + + tt.RequestAuthDelete[tt.Void](t, data.AdminKey, baseUrl, fmt.Sprintf("/api/v2/users/%s/keys/%s", data.UserID, key2.KeytokenId), gin.H{}) + + { + klist := tt.RequestAuthGet[keylist](t, data.AdminKey, baseUrl, fmt.Sprintf("/api/v2/users/%s/keys", data.UserID)) + tt.AssertEqual(t, "len(keys)", 3, len(klist.Keys)) + } + +} + +func TestTokenKeysDeleteSelf(t *testing.T) { + ws, baseUrl, stop := tt.StartSimpleWebserver(t) + defer stop() + + data := tt.InitSingleData(t, ws) + + type keyobj struct { + AllChannels bool `json:"all_channels"` + Channels []string `json:"channels"` + KeytokenId string `json:"keytoken_id"` + MessagesSent int `json:"messages_sent"` + Name string `json:"name"` + OwnerUserId string `json:"owner_user_id"` + Permissions string `json:"permissions"` + Token string `json:"token"` // only in create + } + type keylist struct { + Keys []keyobj `json:"keys"` } klist := tt.RequestAuthGet[keylist](t, data.AdminKey, baseUrl, fmt.Sprintf("/api/v2/users/%s/keys", data.UserID)) - tt.AssertEqual(t, "len(keys)", 1, len(klist.Tokens)) + ak := "" + for _, v := range klist.Keys { + if v.Permissions == "A" { + ak = v.KeytokenId + } + } - t.SkipNow() //TODO + tt.RequestAuthDeleteShouldFail(t, data.AdminKey, baseUrl, fmt.Sprintf("/api/v2/users/%s/keys/%s", data.UserID, ak), gin.H{}, 400, apierr.CANNOT_SELFDELETE_KEY) } -func TestCreateUserKey(t *testing.T) { - t.SkipNow() //TODO +func TestTokenKeysDowngradeSelf(t *testing.T) { + ws, baseUrl, stop := tt.StartSimpleWebserver(t) + defer stop() + + data := tt.InitSingleData(t, ws) + + type keyobj struct { + AllChannels bool `json:"all_channels"` + Channels []string `json:"channels"` + KeytokenId string `json:"keytoken_id"` + MessagesSent int `json:"messages_sent"` + Name string `json:"name"` + OwnerUserId string `json:"owner_user_id"` + Permissions string `json:"permissions"` + Token string `json:"token"` // only in create + } + type keylist struct { + Keys []keyobj `json:"keys"` + } + + klist := tt.RequestAuthGet[keylist](t, data.AdminKey, baseUrl, fmt.Sprintf("/api/v2/users/%s/keys", data.UserID)) + + ak := "" + for _, v := range klist.Keys { + if v.Permissions == "A" { + ak = v.KeytokenId + } + } + + tt.RequestAuthPatchShouldFail(t, data.AdminKey, baseUrl, fmt.Sprintf("/api/v2/users/%s/keys/%s", data.UserID, ak), gin.H{ + "permissions": "CR", + }, 400, apierr.CANNOT_SELFUPDATE_KEY) + + tt.RequestAuthPatchShouldFail(t, data.AdminKey, baseUrl, fmt.Sprintf("/api/v2/users/%s/keys/%s", data.UserID, ak), gin.H{ + "all_channels": false, + }, 400, apierr.CANNOT_SELFUPDATE_KEY) + + tt.RequestAuthPatchShouldFail(t, data.AdminKey, baseUrl, fmt.Sprintf("/api/v2/users/%s/keys/%s", data.UserID, ak), gin.H{ + "channels": []string{"main"}, + }, 400, apierr.CANNOT_SELFUPDATE_KEY) + + tt.RequestAuthPatch[tt.Void](t, data.AdminKey, baseUrl, fmt.Sprintf("/api/v2/users/%s/keys/%s", data.UserID, ak), gin.H{ + "name": "This-is-allowed", + }) + + keyOut := tt.RequestAuthGet[keyobj](t, data.AdminKey, baseUrl, fmt.Sprintf("/api/v2/users/%s/keys/%s", data.UserID, ak)) + + tt.AssertEqual(t, "UserID", data.UserID, keyOut.OwnerUserId) + tt.AssertEqual(t, "Name", "This-is-allowed", keyOut.Name) + tt.AssertEqual(t, "Permissions", "A", keyOut.Permissions) + tt.AssertEqual(t, "AllChannels", true, keyOut.AllChannels) + tt.AssertStrRepEqual(t, "Channels", []string{}, keyOut.Channels) + } -func TestDeleteUserKey(t *testing.T) { - t.SkipNow() //TODO -} +func TestTokenKeysPermissions(t *testing.T) { + ws, baseUrl, stop := tt.StartSimpleWebserver(t) + defer stop() -func TestGetUserKey(t *testing.T) { - t.SkipNow() //TODO -} + data := tt.InitSingleData(t, ws) -func TestUpdateUserKey(t *testing.T) { - t.SkipNow() //TODO -} + type keyobj struct { + AllChannels bool `json:"all_channels"` + Channels []string `json:"channels"` + KeytokenId string `json:"keytoken_id"` + MessagesSent int `json:"messages_sent"` + Name string `json:"name"` + OwnerUserId string `json:"owner_user_id"` + Permissions string `json:"permissions"` + Token string `json:"token"` // only in create + } -func TestUserKeyPermissions(t *testing.T) { - t.SkipNow() //TODO -} + chan0 := tt.RequestAuthPost[gin.H](t, data.AdminKey, baseUrl, fmt.Sprintf("/api/v2/users/%s/channels", data.UserID), gin.H{ + "name": "testchan1", + }) + chanid := fmt.Sprintf("%v", chan0["channel_id"]) + + key7 := tt.RequestAuthPost[keyobj](t, data.AdminKey, baseUrl, fmt.Sprintf("/api/v2/users/%s/keys", data.UserID), gin.H{ + "all_channels": false, + "channels": []string{chanid}, + "name": "TKey7", + "permissions": "CS", + }) + + tt.RequestPostShouldFail(t, baseUrl, "/", gin.H{ + "key": key7.Token, + "user_id": data.UserID, + "channel": "testchan2", + "title": "HelloWorld_001", + }, 401, apierr.USER_AUTH_FAILED) // wrong channel + + tt.RequestPostShouldFail(t, baseUrl, "/", gin.H{ + "key": key7.Token, + "user_id": data.UserID, + "title": "HelloWorld_001", + }, 401, apierr.USER_AUTH_FAILED) // no channel (=main) + + tt.RequestAuthGetShouldFail(t, key7.Token, baseUrl, fmt.Sprintf("/api/v2/users/%s", data.UserID), 401, apierr.USER_AUTH_FAILED) // no user read perm + + tt.RequestAuthPatchShouldFail(t, key7.Token, baseUrl, "/api/v2/users/"+data.UserID, gin.H{"username": "my_user_001"}, 401, apierr.USER_AUTH_FAILED) // no user update perm + + key8 := tt.RequestAuthPost[keyobj](t, data.AdminKey, baseUrl, fmt.Sprintf("/api/v2/users/%s/keys", data.UserID), gin.H{ + "all_channels": true, + "channels": []string{}, + "name": "TKey7", + "permissions": "CR", + }) + + tt.RequestPostShouldFail(t, baseUrl, "/", gin.H{ + "key": key8.Token, + "user_id": data.UserID, + "title": "HelloWorld_001", + }, 401, apierr.USER_AUTH_FAILED) // no send perm -func TestUsedKeyInMessage(t *testing.T) { - t.SkipNow() //TODO }