2023-05-28 13:39:20 +02:00
|
|
|
package handler
|
|
|
|
|
|
|
|
import (
|
|
|
|
"blackforestbytes.com/simplecloudnotifier/api/apierr"
|
|
|
|
"blackforestbytes.com/simplecloudnotifier/api/ginresp"
|
2024-07-16 17:19:55 +02:00
|
|
|
"blackforestbytes.com/simplecloudnotifier/logic"
|
2023-05-28 13:39:20 +02:00
|
|
|
"blackforestbytes.com/simplecloudnotifier/models"
|
|
|
|
"database/sql"
|
2023-07-30 15:58:37 +02:00
|
|
|
"errors"
|
2024-07-15 17:26:55 +02:00
|
|
|
"gogs.mikescher.com/BlackForestBytes/goext/ginext"
|
2023-05-28 13:39:20 +02:00
|
|
|
"gogs.mikescher.com/BlackForestBytes/goext/langext"
|
|
|
|
"net/http"
|
|
|
|
)
|
|
|
|
|
|
|
|
// ListUserKeys swaggerdoc
|
|
|
|
//
|
|
|
|
// @Summary List keys of the user
|
|
|
|
// @Description The request must be done with an ADMIN key, the returned keys are without their token.
|
|
|
|
// @ID api-tokenkeys-list
|
|
|
|
// @Tags API-v2
|
|
|
|
//
|
2023-05-28 17:04:44 +02:00
|
|
|
// @Param uid path string true "UserID"
|
2023-05-28 13:39:20 +02:00
|
|
|
//
|
|
|
|
// @Success 200 {object} handler.ListUserKeys.response
|
|
|
|
// @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"
|
|
|
|
// @Failure 404 {object} ginresp.apiError "message not found"
|
|
|
|
// @Failure 500 {object} ginresp.apiError "internal server error"
|
|
|
|
//
|
2023-05-28 17:04:44 +02:00
|
|
|
// @Router /api/v2/users/{uid}/keys [GET]
|
2024-07-15 17:26:55 +02:00
|
|
|
func (h APIHandler) ListUserKeys(pctx ginext.PreContext) ginext.HTTPResponse {
|
2023-05-28 13:39:20 +02:00
|
|
|
type uri struct {
|
|
|
|
UserID models.UserID `uri:"uid" binding:"entityid"`
|
|
|
|
}
|
|
|
|
type response struct {
|
2024-09-15 21:07:46 +02:00
|
|
|
Keys []models.KeyToken `json:"keys"`
|
2023-05-28 13:39:20 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
var u uri
|
2024-07-16 17:19:55 +02:00
|
|
|
ctx, g, errResp := pctx.URI(&u).Start()
|
2023-05-28 13:39:20 +02:00
|
|
|
if errResp != nil {
|
|
|
|
return *errResp
|
|
|
|
}
|
|
|
|
defer ctx.Cancel()
|
|
|
|
|
2024-09-16 15:17:20 +02:00
|
|
|
return h.app.DoRequest(ctx, g, models.TLockRead, func(ctx *logic.AppContext, finishSuccess func(r ginext.HTTPResponse) ginext.HTTPResponse) ginext.HTTPResponse {
|
2023-05-28 13:39:20 +02:00
|
|
|
|
2024-07-16 17:19:55 +02:00
|
|
|
if permResp := ctx.CheckPermissionUserAdmin(u.UserID); permResp != nil {
|
|
|
|
return *permResp
|
|
|
|
}
|
2023-05-28 13:39:20 +02:00
|
|
|
|
2024-07-16 17:19:55 +02:00
|
|
|
toks, err := h.database.ListKeyTokens(ctx, u.UserID)
|
|
|
|
if err != nil {
|
|
|
|
return ginresp.APIError(g, 500, apierr.DATABASE_ERROR, "Failed to query keys", err)
|
|
|
|
}
|
2023-05-28 13:39:20 +02:00
|
|
|
|
2024-09-15 21:07:46 +02:00
|
|
|
return finishSuccess(ginext.JSON(http.StatusOK, response{Keys: toks}))
|
2024-07-16 17:19:55 +02:00
|
|
|
|
|
|
|
})
|
2023-05-28 13:39:20 +02:00
|
|
|
}
|
|
|
|
|
2024-06-01 13:22:56 +02:00
|
|
|
// GetCurrentUserKey swaggerdoc
|
|
|
|
//
|
|
|
|
// @Summary Get the key currently used by this request
|
|
|
|
// @Description Can be done with keys of any permission - the returned key does not include its token.
|
|
|
|
// @ID api-tokenkeys-get-current
|
|
|
|
// @Tags API-v2
|
|
|
|
//
|
|
|
|
// @Param uid path string true "UserID"
|
|
|
|
// @Param kid path string true "TokenKeyID"
|
|
|
|
//
|
2024-09-15 21:07:46 +02:00
|
|
|
// @Success 200 {object} models.KeyToken
|
2024-06-01 13:22:56 +02:00
|
|
|
// @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"
|
|
|
|
// @Failure 404 {object} ginresp.apiError "message not found"
|
|
|
|
// @Failure 500 {object} ginresp.apiError "internal server error"
|
|
|
|
//
|
|
|
|
// @Router /api/v2/users/{uid}/keys/current [GET]
|
2024-07-15 17:26:55 +02:00
|
|
|
func (h APIHandler) GetCurrentUserKey(pctx ginext.PreContext) ginext.HTTPResponse {
|
2024-06-01 13:22:56 +02:00
|
|
|
type uri struct {
|
|
|
|
UserID models.UserID `uri:"uid" binding:"entityid"`
|
|
|
|
}
|
|
|
|
|
|
|
|
var u uri
|
2024-07-16 17:19:55 +02:00
|
|
|
ctx, g, errResp := pctx.URI(&u).Start()
|
2024-06-01 13:22:56 +02:00
|
|
|
if errResp != nil {
|
|
|
|
return *errResp
|
|
|
|
}
|
|
|
|
defer ctx.Cancel()
|
|
|
|
|
2024-09-16 15:17:20 +02:00
|
|
|
return h.app.DoRequest(ctx, g, models.TLockRead, func(ctx *logic.AppContext, finishSuccess func(r ginext.HTTPResponse) ginext.HTTPResponse) ginext.HTTPResponse {
|
2024-06-01 13:22:56 +02:00
|
|
|
|
2024-07-16 17:19:55 +02:00
|
|
|
if permResp := ctx.CheckPermissionAny(); permResp != nil {
|
|
|
|
return *permResp
|
|
|
|
}
|
2024-06-01 13:22:56 +02:00
|
|
|
|
2024-07-16 17:19:55 +02:00
|
|
|
tokid := ctx.GetPermissionKeyTokenID()
|
|
|
|
if tokid == nil {
|
|
|
|
return ginresp.APIError(g, 400, apierr.USER_AUTH_FAILED, "Missing KeyTokenID in context", nil)
|
|
|
|
}
|
|
|
|
|
|
|
|
keytoken, err := h.database.GetKeyToken(ctx, u.UserID, *tokid)
|
|
|
|
if errors.Is(err, sql.ErrNoRows) {
|
|
|
|
return ginresp.APIError(g, 404, apierr.KEY_NOT_FOUND, "Key not found", err)
|
|
|
|
}
|
|
|
|
if err != nil {
|
|
|
|
return ginresp.APIError(g, 500, apierr.DATABASE_ERROR, "Failed to query client", err)
|
|
|
|
}
|
2024-06-01 13:22:56 +02:00
|
|
|
|
2024-09-15 21:07:46 +02:00
|
|
|
return finishSuccess(ginext.JSONWithFilter(http.StatusOK, keytoken, "INCLUDE_TOKEN"))
|
2024-07-16 17:19:55 +02:00
|
|
|
|
|
|
|
})
|
2024-06-01 13:22:56 +02:00
|
|
|
}
|
|
|
|
|
2023-05-28 13:39:20 +02:00
|
|
|
// GetUserKey swaggerdoc
|
|
|
|
//
|
|
|
|
// @Summary Get a single key
|
|
|
|
// @Description The request must be done with an ADMIN key, the returned key does not include its token.
|
|
|
|
// @ID api-tokenkeys-get
|
|
|
|
// @Tags API-v2
|
|
|
|
//
|
2023-05-28 17:04:44 +02:00
|
|
|
// @Param uid path string true "UserID"
|
|
|
|
// @Param kid path string true "TokenKeyID"
|
2023-05-28 13:39:20 +02:00
|
|
|
//
|
2024-09-15 21:07:46 +02:00
|
|
|
// @Success 200 {object} models.KeyToken
|
2023-05-28 13:39:20 +02:00
|
|
|
// @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"
|
|
|
|
// @Failure 404 {object} ginresp.apiError "message not found"
|
|
|
|
// @Failure 500 {object} ginresp.apiError "internal server error"
|
|
|
|
//
|
2023-05-28 17:04:44 +02:00
|
|
|
// @Router /api/v2/users/{uid}/keys/{kid} [GET]
|
2024-07-15 17:26:55 +02:00
|
|
|
func (h APIHandler) GetUserKey(pctx ginext.PreContext) ginext.HTTPResponse {
|
2023-05-28 13:39:20 +02:00
|
|
|
type uri struct {
|
|
|
|
UserID models.UserID `uri:"uid" binding:"entityid"`
|
|
|
|
KeyID models.KeyTokenID `uri:"kid" binding:"entityid"`
|
|
|
|
}
|
|
|
|
|
|
|
|
var u uri
|
2024-07-16 17:19:55 +02:00
|
|
|
ctx, g, errResp := pctx.URI(&u).Start()
|
2023-05-28 13:39:20 +02:00
|
|
|
if errResp != nil {
|
|
|
|
return *errResp
|
|
|
|
}
|
|
|
|
defer ctx.Cancel()
|
|
|
|
|
2024-09-16 15:17:20 +02:00
|
|
|
return h.app.DoRequest(ctx, g, models.TLockRead, func(ctx *logic.AppContext, finishSuccess func(r ginext.HTTPResponse) ginext.HTTPResponse) ginext.HTTPResponse {
|
2023-05-28 13:39:20 +02:00
|
|
|
|
2024-07-16 17:19:55 +02:00
|
|
|
if permResp := ctx.CheckPermissionUserAdmin(u.UserID); permResp != nil {
|
|
|
|
return *permResp
|
|
|
|
}
|
|
|
|
|
|
|
|
keytoken, err := h.database.GetKeyToken(ctx, u.UserID, u.KeyID)
|
|
|
|
if errors.Is(err, sql.ErrNoRows) {
|
|
|
|
return ginresp.APIError(g, 404, apierr.KEY_NOT_FOUND, "Key not found", err)
|
|
|
|
}
|
|
|
|
if err != nil {
|
|
|
|
return ginresp.APIError(g, 500, apierr.DATABASE_ERROR, "Failed to query client", err)
|
|
|
|
}
|
|
|
|
|
2024-09-15 21:07:46 +02:00
|
|
|
return finishSuccess(ginext.JSON(http.StatusOK, keytoken))
|
2023-05-28 13:39:20 +02:00
|
|
|
|
2024-07-16 17:19:55 +02:00
|
|
|
})
|
2023-05-28 13:39:20 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
// UpdateUserKey swaggerdoc
|
|
|
|
//
|
|
|
|
// @Summary Update a key
|
|
|
|
// @ID api-tokenkeys-update
|
|
|
|
// @Tags API-v2
|
|
|
|
//
|
2023-06-10 00:15:42 +02:00
|
|
|
// @Param uid path string true "UserID"
|
|
|
|
// @Param kid path string true "TokenKeyID"
|
2023-05-28 13:39:20 +02:00
|
|
|
//
|
|
|
|
// @Param post_body body handler.UpdateUserKey.body false " "
|
|
|
|
//
|
2024-09-15 21:07:46 +02:00
|
|
|
// @Success 200 {object} models.KeyToken
|
2023-05-28 13:39:20 +02:00
|
|
|
// @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"
|
|
|
|
// @Failure 404 {object} ginresp.apiError "message not found"
|
|
|
|
// @Failure 500 {object} ginresp.apiError "internal server error"
|
|
|
|
//
|
2023-05-28 17:04:44 +02:00
|
|
|
// @Router /api/v2/users/{uid}/keys/{kid} [PATCH]
|
2024-07-15 17:26:55 +02:00
|
|
|
func (h APIHandler) UpdateUserKey(pctx ginext.PreContext) ginext.HTTPResponse {
|
2023-05-28 13:39:20 +02:00
|
|
|
type uri struct {
|
|
|
|
UserID models.UserID `uri:"uid" binding:"entityid"`
|
|
|
|
KeyID models.KeyTokenID `uri:"kid" binding:"entityid"`
|
|
|
|
}
|
|
|
|
type body struct {
|
|
|
|
Name *string `json:"name"`
|
|
|
|
AllChannels *bool `json:"all_channels"`
|
|
|
|
Channels *[]models.ChannelID `json:"channels"`
|
|
|
|
Permissions *string `json:"permissions"`
|
|
|
|
}
|
|
|
|
|
|
|
|
var u uri
|
|
|
|
var b body
|
2024-07-16 17:19:55 +02:00
|
|
|
ctx, g, errResp := pctx.URI(&u).Body(&b).Start()
|
2023-05-28 13:39:20 +02:00
|
|
|
if errResp != nil {
|
|
|
|
return *errResp
|
|
|
|
}
|
|
|
|
defer ctx.Cancel()
|
|
|
|
|
2024-09-16 15:17:20 +02:00
|
|
|
return h.app.DoRequest(ctx, g, models.TLockReadWrite, func(ctx *logic.AppContext, finishSuccess func(r ginext.HTTPResponse) ginext.HTTPResponse) ginext.HTTPResponse {
|
2023-05-28 13:39:20 +02:00
|
|
|
|
2024-07-16 17:19:55 +02:00
|
|
|
if permResp := ctx.CheckPermissionUserAdmin(u.UserID); permResp != nil {
|
|
|
|
return *permResp
|
2023-05-28 13:39:20 +02:00
|
|
|
}
|
|
|
|
|
2024-07-16 17:19:55 +02:00
|
|
|
keytoken, err := h.database.GetKeyToken(ctx, u.UserID, u.KeyID)
|
|
|
|
if errors.Is(err, sql.ErrNoRows) {
|
|
|
|
return ginresp.APIError(g, 404, apierr.KEY_NOT_FOUND, "Key not found", err)
|
2023-05-28 13:39:20 +02:00
|
|
|
}
|
|
|
|
if err != nil {
|
2024-07-16 17:19:55 +02:00
|
|
|
return ginresp.APIError(g, 500, apierr.DATABASE_ERROR, "Failed to query client", err)
|
2023-05-28 13:39:20 +02:00
|
|
|
}
|
|
|
|
|
2024-07-16 17:19:55 +02:00
|
|
|
if b.Name != nil {
|
|
|
|
err := h.database.UpdateKeyTokenName(ctx, u.KeyID, *b.Name)
|
|
|
|
if err != nil {
|
|
|
|
return ginresp.APIError(g, 500, apierr.DATABASE_ERROR, "Failed to update name", err)
|
|
|
|
}
|
|
|
|
keytoken.Name = *b.Name
|
2023-05-28 13:39:20 +02:00
|
|
|
}
|
|
|
|
|
2024-07-16 17:19:55 +02:00
|
|
|
if b.Permissions != nil {
|
|
|
|
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
|
2023-05-28 13:39:20 +02:00
|
|
|
}
|
|
|
|
|
2024-07-16 17:19:55 +02:00
|
|
|
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
|
2023-05-28 13:39:20 +02:00
|
|
|
}
|
|
|
|
|
2024-07-16 17:19:55 +02:00
|
|
|
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
|
2023-05-28 13:39:20 +02:00
|
|
|
}
|
|
|
|
|
2024-09-15 21:07:46 +02:00
|
|
|
return finishSuccess(ginext.JSON(http.StatusOK, keytoken))
|
2024-07-16 17:19:55 +02:00
|
|
|
|
|
|
|
})
|
2023-05-28 13:39:20 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
// CreateUserKey swaggerdoc
|
|
|
|
//
|
|
|
|
// @Summary Create a new key
|
|
|
|
// @ID api-tokenkeys-create
|
|
|
|
// @Tags API-v2
|
|
|
|
//
|
2023-06-10 00:15:42 +02:00
|
|
|
// @Param uid path string true "UserID"
|
2023-05-28 13:39:20 +02:00
|
|
|
//
|
|
|
|
// @Param post_body body handler.CreateUserKey.body false " "
|
|
|
|
//
|
2024-09-15 21:07:46 +02:00
|
|
|
// @Success 200 {object} models.KeyToken
|
2023-05-28 13:39:20 +02:00
|
|
|
// @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"
|
|
|
|
// @Failure 404 {object} ginresp.apiError "message not found"
|
|
|
|
// @Failure 500 {object} ginresp.apiError "internal server error"
|
|
|
|
//
|
2023-05-28 17:04:44 +02:00
|
|
|
// @Router /api/v2/users/{uid}/keys [POST]
|
2024-07-15 17:26:55 +02:00
|
|
|
func (h APIHandler) CreateUserKey(pctx ginext.PreContext) ginext.HTTPResponse {
|
2023-05-28 13:39:20 +02:00
|
|
|
type uri struct {
|
|
|
|
UserID models.UserID `uri:"uid" binding:"entityid"`
|
|
|
|
}
|
|
|
|
type body struct {
|
|
|
|
Name string `json:"name" binding:"required"`
|
2023-06-18 02:54:41 +02:00
|
|
|
Permissions string `json:"permissions" binding:"required"`
|
|
|
|
AllChannels *bool `json:"all_channels"`
|
|
|
|
Channels *[]models.ChannelID `json:"channels"`
|
2023-05-28 13:39:20 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
var u uri
|
|
|
|
var b body
|
2024-07-16 17:19:55 +02:00
|
|
|
ctx, g, errResp := pctx.URI(&u).Body(&b).Start()
|
2023-05-28 13:39:20 +02:00
|
|
|
if errResp != nil {
|
|
|
|
return *errResp
|
|
|
|
}
|
|
|
|
defer ctx.Cancel()
|
|
|
|
|
2024-09-16 15:17:20 +02:00
|
|
|
return h.app.DoRequest(ctx, g, models.TLockReadWrite, func(ctx *logic.AppContext, finishSuccess func(r ginext.HTTPResponse) ginext.HTTPResponse) ginext.HTTPResponse {
|
2023-06-18 02:54:41 +02:00
|
|
|
|
2024-07-16 17:19:55 +02:00
|
|
|
channels := langext.Coalesce(b.Channels, make([]models.ChannelID, 0))
|
2023-06-18 02:54:41 +02:00
|
|
|
|
2024-07-16 17:19:55 +02:00
|
|
|
var allChan bool
|
|
|
|
if b.AllChannels == nil && b.Channels != nil {
|
|
|
|
allChan = false
|
|
|
|
} else if b.AllChannels == nil && b.Channels == nil {
|
|
|
|
allChan = true
|
|
|
|
} else {
|
|
|
|
allChan = *b.AllChannels
|
2023-05-28 13:39:20 +02:00
|
|
|
}
|
|
|
|
|
2024-07-16 17:19:55 +02:00
|
|
|
for _, c := range channels {
|
|
|
|
if err := c.Valid(); err != nil {
|
|
|
|
return ginresp.APIError(g, 400, apierr.INVALID_BODY_PARAM, "Invalid ChannelID", err)
|
|
|
|
}
|
|
|
|
}
|
2023-05-28 13:39:20 +02:00
|
|
|
|
2024-07-16 17:19:55 +02:00
|
|
|
if permResp := ctx.CheckPermissionUserAdmin(u.UserID); permResp != nil {
|
|
|
|
return *permResp
|
|
|
|
}
|
2023-05-28 13:39:20 +02:00
|
|
|
|
2024-07-16 17:19:55 +02:00
|
|
|
token := h.app.GenerateRandomAuthKey()
|
2023-05-28 13:39:20 +02:00
|
|
|
|
2024-07-16 17:19:55 +02:00
|
|
|
perms := models.ParseTokenPermissionList(b.Permissions)
|
2023-05-28 13:39:20 +02:00
|
|
|
|
2024-07-16 17:19:55 +02:00
|
|
|
keytok, err := h.database.CreateKeyToken(ctx, b.Name, *ctx.GetPermissionUserID(), allChan, channels, perms, token)
|
|
|
|
if err != nil {
|
|
|
|
return ginresp.APIError(g, 500, apierr.DATABASE_ERROR, "Failed to create keytoken in db", err)
|
|
|
|
}
|
|
|
|
|
2024-09-15 21:07:46 +02:00
|
|
|
return finishSuccess(ginext.JSONWithFilter(http.StatusOK, keytok, "INCLUDE_TOKEN"))
|
2024-07-16 17:19:55 +02:00
|
|
|
|
|
|
|
})
|
2023-05-28 13:39:20 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
// DeleteUserKey swaggerdoc
|
|
|
|
//
|
|
|
|
// @Summary Delete a key
|
|
|
|
// @Description Cannot be used to delete the key used in the request itself
|
|
|
|
// @ID api-tokenkeys-delete
|
|
|
|
// @Tags API-v2
|
|
|
|
//
|
2023-05-28 17:04:44 +02:00
|
|
|
// @Param uid path string true "UserID"
|
|
|
|
// @Param kid path string true "TokenKeyID"
|
2023-05-28 13:39:20 +02:00
|
|
|
//
|
2024-09-15 21:07:46 +02:00
|
|
|
// @Success 200 {object} models.KeyToken
|
2023-05-28 13:39:20 +02:00
|
|
|
// @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"
|
|
|
|
// @Failure 404 {object} ginresp.apiError "message not found"
|
|
|
|
// @Failure 500 {object} ginresp.apiError "internal server error"
|
|
|
|
//
|
2023-05-28 17:04:44 +02:00
|
|
|
// @Router /api/v2/users/{uid}/keys/{kid} [DELETE]
|
2024-07-15 17:26:55 +02:00
|
|
|
func (h APIHandler) DeleteUserKey(pctx ginext.PreContext) ginext.HTTPResponse {
|
2023-05-28 13:39:20 +02:00
|
|
|
type uri struct {
|
|
|
|
UserID models.UserID `uri:"uid" binding:"entityid"`
|
|
|
|
KeyID models.KeyTokenID `uri:"kid" binding:"entityid"`
|
|
|
|
}
|
|
|
|
|
|
|
|
var u uri
|
2024-07-16 17:19:55 +02:00
|
|
|
ctx, g, errResp := pctx.URI(&u).Start()
|
2023-05-28 13:39:20 +02:00
|
|
|
if errResp != nil {
|
|
|
|
return *errResp
|
|
|
|
}
|
|
|
|
defer ctx.Cancel()
|
|
|
|
|
2024-09-16 15:17:20 +02:00
|
|
|
return h.app.DoRequest(ctx, g, models.TLockReadWrite, func(ctx *logic.AppContext, finishSuccess func(r ginext.HTTPResponse) ginext.HTTPResponse) ginext.HTTPResponse {
|
2023-05-28 13:39:20 +02:00
|
|
|
|
2024-07-16 17:19:55 +02:00
|
|
|
if permResp := ctx.CheckPermissionUserAdmin(u.UserID); permResp != nil {
|
|
|
|
return *permResp
|
|
|
|
}
|
2023-05-28 13:39:20 +02:00
|
|
|
|
2024-07-16 17:19:55 +02:00
|
|
|
client, err := h.database.GetKeyToken(ctx, u.UserID, u.KeyID)
|
|
|
|
if errors.Is(err, sql.ErrNoRows) {
|
|
|
|
return ginresp.APIError(g, 404, apierr.KEY_NOT_FOUND, "Key not found", err)
|
|
|
|
}
|
|
|
|
if err != nil {
|
|
|
|
return ginresp.APIError(g, 500, apierr.DATABASE_ERROR, "Failed to query client", err)
|
|
|
|
}
|
2023-05-28 13:39:20 +02:00
|
|
|
|
2024-07-16 17:19:55 +02:00
|
|
|
if u.KeyID == *ctx.GetPermissionKeyTokenID() {
|
|
|
|
return ginresp.APIError(g, 400, apierr.CANNOT_SELFDELETE_KEY, "Cannot delete the currently used key", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
err = h.database.DeleteKeyToken(ctx, u.KeyID)
|
|
|
|
if err != nil {
|
|
|
|
return ginresp.APIError(g, 500, apierr.DATABASE_ERROR, "Failed to delete client", err)
|
|
|
|
}
|
|
|
|
|
2024-09-15 21:07:46 +02:00
|
|
|
return finishSuccess(ginext.JSON(http.StatusOK, client))
|
2023-05-28 13:39:20 +02:00
|
|
|
|
2024-07-16 17:19:55 +02:00
|
|
|
})
|
2023-05-28 13:39:20 +02:00
|
|
|
}
|