Files

305 lines
8.2 KiB
Go
Raw Permalink Normal View History

2015-12-03 00:24:37 -05:00
// Copyright 2015 The Gogs Authors. All rights reserved.
2026-02-06 14:12:05 +01:00
// Copyright 2026 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT
2015-12-03 00:24:37 -05:00
2015-12-04 17:16:42 -05:00
package user
2015-12-03 00:24:37 -05:00
import (
std_ctx "context"
2025-04-01 12:14:01 +02:00
"errors"
2019-12-20 18:07:12 +01:00
"net/http"
2021-12-10 16:14:24 +08:00
asymkey_model "code.gitea.io/gitea/models/asymkey"
"code.gitea.io/gitea/models/db"
2021-11-28 19:58:28 +08:00
"code.gitea.io/gitea/models/perm"
user_model "code.gitea.io/gitea/models/user"
"code.gitea.io/gitea/modules/setting"
2019-08-23 09:40:30 -07:00
api "code.gitea.io/gitea/modules/structs"
2021-01-26 23:36:53 +08:00
"code.gitea.io/gitea/modules/web"
"code.gitea.io/gitea/routers/api/v1/repo"
2020-01-24 19:00:29 +00:00
"code.gitea.io/gitea/routers/api/v1/utils"
2021-12-10 16:14:24 +08:00
asymkey_service "code.gitea.io/gitea/services/asymkey"
"code.gitea.io/gitea/services/context"
2022-12-29 03:57:15 +01:00
"code.gitea.io/gitea/services/convert"
2015-12-03 00:24:37 -05:00
)
2018-11-01 03:40:49 +00:00
// appendPrivateInformation appends the owner and key type information to api.PublicKey
func appendPrivateInformation(ctx std_ctx.Context, apiKey *api.PublicKey, key *asymkey_model.PublicKey, defaultUser *user_model.User) (*api.PublicKey, error) {
2025-03-29 22:32:28 +01:00
switch key.Type {
case asymkey_model.KeyTypeDeploy:
2018-11-01 03:40:49 +00:00
apiKey.KeyType = "deploy"
2025-03-29 22:32:28 +01:00
case asymkey_model.KeyTypeUser:
2018-11-01 03:40:49 +00:00
apiKey.KeyType = "user"
if defaultUser.ID == key.OwnerID {
apiKey.Owner = convert.ToUser(ctx, defaultUser, defaultUser)
2018-11-01 03:40:49 +00:00
} else {
user, err := user_model.GetUserByID(ctx, key.OwnerID)
2018-11-01 03:40:49 +00:00
if err != nil {
return apiKey, err
}
apiKey.Owner = convert.ToUser(ctx, user, user)
2018-11-01 03:40:49 +00:00
}
2025-03-29 22:32:28 +01:00
default:
2018-11-01 03:40:49 +00:00
apiKey.KeyType = "unknown"
}
2021-11-28 19:58:28 +08:00
apiKey.ReadOnly = key.Mode == perm.AccessModeRead
2018-11-01 03:40:49 +00:00
return apiKey, nil
}
2015-12-03 00:24:37 -05:00
func composePublicKeysAPILink() string {
2016-11-27 18:14:25 +08:00
return setting.AppURL + "api/v1/user/keys/"
2015-12-03 00:24:37 -05:00
}
func listPublicKeys(ctx *context.APIContext, user *user_model.User) {
2021-12-10 16:14:24 +08:00
var keys []*asymkey_model.PublicKey
2018-11-01 03:40:49 +00:00
var err error
2026-02-06 14:12:05 +01:00
var count int64
2018-11-01 03:40:49 +00:00
fingerprint := ctx.FormString("fingerprint")
2024-06-19 06:32:45 +08:00
username := ctx.PathParam("username")
2026-02-06 14:12:05 +01:00
listOptions := utils.GetListOptions(ctx)
2018-11-01 03:40:49 +00:00
if fingerprint != "" {
var userID int64 // Unrestricted
2018-11-01 03:40:49 +00:00
// Querying not just listing
if username != "" {
// Restrict to provided uid
userID = user.ID
2018-11-01 03:40:49 +00:00
}
2026-02-06 14:12:05 +01:00
keys, count, err = db.FindAndCount[asymkey_model.PublicKey](ctx, asymkey_model.FindPublicKeyOptions{
ListOptions: listOptions,
OwnerID: userID,
Fingerprint: fingerprint,
})
2018-11-01 03:40:49 +00:00
} else {
// Use ListPublicKeys
2026-02-06 14:12:05 +01:00
keys, count, err = db.FindAndCount[asymkey_model.PublicKey](ctx, asymkey_model.FindPublicKeyOptions{
ListOptions: listOptions,
OwnerID: user.ID,
NotKeytype: asymkey_model.KeyTypePrincipal,
})
2018-11-01 03:40:49 +00:00
}
2015-12-03 00:24:37 -05:00
if err != nil {
2025-02-18 04:41:03 +08:00
ctx.APIErrorInternal(err)
2015-12-03 00:24:37 -05:00
return
}
apiLink := composePublicKeysAPILink()
apiKeys := make([]*api.PublicKey, len(keys))
for i := range keys {
2016-03-13 23:20:22 -04:00
apiKeys[i] = convert.ToPublicKey(apiLink, keys[i])
2022-03-22 08:03:22 +01:00
if ctx.Doer.IsAdmin || ctx.Doer.ID == keys[i].OwnerID {
apiKeys[i], _ = appendPrivateInformation(ctx, apiKeys[i], keys[i], user)
2018-11-01 03:40:49 +00:00
}
2015-12-03 00:24:37 -05:00
}
2026-03-08 15:35:50 +01:00
ctx.SetLinkHeader(count, listOptions.PageSize)
2026-02-06 14:12:05 +01:00
ctx.SetTotalCountHeader(count)
2019-12-20 18:07:12 +01:00
ctx.JSON(http.StatusOK, &apiKeys)
2015-12-03 00:24:37 -05:00
}
2017-11-12 23:02:25 -08:00
// ListMyPublicKeys list all of the authenticated user's public keys
func ListMyPublicKeys(ctx *context.APIContext) {
2017-11-12 23:02:25 -08:00
// swagger:operation GET /user/keys user userCurrentListKeys
// ---
// summary: List the authenticated user's public keys
2018-11-01 03:40:49 +00:00
// parameters:
// - name: fingerprint
// in: query
// description: fingerprint of the key
// type: string
2020-01-24 19:00:29 +00:00
// - name: page
// in: query
// description: page number of results to return (1-based)
// type: integer
// - name: limit
// in: query
// description: page size of results
2020-01-24 19:00:29 +00:00
// type: integer
2017-11-12 23:02:25 -08:00
// produces:
// - application/json
// responses:
// "200":
// "$ref": "#/responses/PublicKeyList"
2019-12-20 18:07:12 +01:00
2022-03-22 08:03:22 +01:00
listPublicKeys(ctx, ctx.Doer)
2015-12-04 17:16:42 -05:00
}
2017-11-12 23:02:25 -08:00
// ListPublicKeys list the given user's public keys
func ListPublicKeys(ctx *context.APIContext) {
2017-11-12 23:02:25 -08:00
// swagger:operation GET /users/{username}/keys user userListKeys
// ---
// summary: List the given user's public keys
// produces:
// - application/json
// parameters:
// - name: username
// in: path
// description: username of the user whose public keys are to be listed
2017-11-12 23:02:25 -08:00
// type: string
// required: true
2018-11-01 03:40:49 +00:00
// - name: fingerprint
// in: query
// description: fingerprint of the key
// type: string
2020-01-24 19:00:29 +00:00
// - name: page
// in: query
// description: page number of results to return (1-based)
// type: integer
// - name: limit
// in: query
// description: page size of results
2020-01-24 19:00:29 +00:00
// type: integer
2017-11-12 23:02:25 -08:00
// responses:
// "200":
// "$ref": "#/responses/PublicKeyList"
// "404":
// "$ref": "#/responses/notFound"
2019-12-20 18:07:12 +01:00
listPublicKeys(ctx, ctx.ContextUser)
2015-12-03 00:24:37 -05:00
}
2017-11-12 23:02:25 -08:00
// GetPublicKey get a public key
func GetPublicKey(ctx *context.APIContext) {
2017-11-12 23:02:25 -08:00
// swagger:operation GET /user/keys/{id} user userCurrentGetKey
// ---
// summary: Get a public key
// produces:
// - application/json
// parameters:
// - name: id
// in: path
// description: id of key to get
// type: integer
// format: int64
2017-11-12 23:02:25 -08:00
// required: true
// responses:
// "200":
// "$ref": "#/responses/PublicKey"
// "404":
// "$ref": "#/responses/notFound"
2019-12-20 18:07:12 +01:00
2024-12-24 21:47:45 +08:00
key, err := asymkey_model.GetPublicKeyByID(ctx, ctx.PathParamInt64("id"))
2015-12-03 00:24:37 -05:00
if err != nil {
2021-12-10 16:14:24 +08:00
if asymkey_model.IsErrKeyNotExist(err) {
2025-02-17 14:13:17 +08:00
ctx.APIErrorNotFound()
2015-12-03 00:24:37 -05:00
} else {
2025-02-18 04:41:03 +08:00
ctx.APIErrorInternal(err)
2015-12-03 00:24:37 -05:00
}
return
}
apiLink := composePublicKeysAPILink()
2018-11-01 03:40:49 +00:00
apiKey := convert.ToPublicKey(apiLink, key)
2022-03-22 08:03:22 +01:00
if ctx.Doer.IsAdmin || ctx.Doer.ID == key.OwnerID {
apiKey, _ = appendPrivateInformation(ctx, apiKey, key, ctx.Doer)
2018-11-01 03:40:49 +00:00
}
2019-12-20 18:07:12 +01:00
ctx.JSON(http.StatusOK, apiKey)
2015-12-03 00:24:37 -05:00
}
2015-12-05 17:13:13 -05:00
// CreateUserPublicKey creates new public key to given user by ID.
func CreateUserPublicKey(ctx *context.APIContext, form api.CreateKeyOption, uid int64) {
if user_model.IsFeatureDisabledWithLoginType(ctx.Doer, setting.UserFeatureManageSSHKeys) {
2025-04-01 12:14:01 +02:00
ctx.APIErrorNotFound("Not Found", errors.New("ssh keys setting is not allowed to be visited"))
return
}
2021-12-10 16:14:24 +08:00
content, err := asymkey_model.CheckPublicKeyString(form.Key)
2015-12-03 00:24:37 -05:00
if err != nil {
2015-12-04 17:16:42 -05:00
repo.HandleCheckKeyStringError(ctx, err)
2015-12-03 00:24:37 -05:00
return
}
key, err := asymkey_model.AddPublicKey(ctx, uid, form.Title, content, 0, false)
2015-12-03 00:24:37 -05:00
if err != nil {
2015-12-04 17:16:42 -05:00
repo.HandleAddKeyError(ctx, err)
2015-12-03 00:24:37 -05:00
return
}
apiLink := composePublicKeysAPILink()
2018-11-01 03:40:49 +00:00
apiKey := convert.ToPublicKey(apiLink, key)
2022-03-22 08:03:22 +01:00
if ctx.Doer.IsAdmin || ctx.Doer.ID == key.OwnerID {
apiKey, _ = appendPrivateInformation(ctx, apiKey, key, ctx.Doer)
2018-11-01 03:40:49 +00:00
}
2019-12-20 18:07:12 +01:00
ctx.JSON(http.StatusCreated, apiKey)
2015-12-04 17:16:42 -05:00
}
2016-11-24 15:04:31 +08:00
// CreatePublicKey create one public key for me
2021-01-26 23:36:53 +08:00
func CreatePublicKey(ctx *context.APIContext) {
2017-11-12 23:02:25 -08:00
// swagger:operation POST /user/keys user userCurrentPostKey
// ---
// summary: Create a public key
// consumes:
// - application/json
// produces:
// - application/json
// parameters:
// - name: body
// in: body
// schema:
// "$ref": "#/definitions/CreateKeyOption"
// responses:
// "201":
// "$ref": "#/responses/PublicKey"
// "422":
// "$ref": "#/responses/validationError"
2019-12-20 18:07:12 +01:00
2021-01-26 23:36:53 +08:00
form := web.GetForm(ctx).(*api.CreateKeyOption)
2022-03-22 08:03:22 +01:00
CreateUserPublicKey(ctx, *form, ctx.Doer.ID)
2015-12-03 00:24:37 -05:00
}
2017-11-12 23:02:25 -08:00
// DeletePublicKey delete one public key
func DeletePublicKey(ctx *context.APIContext) {
2017-11-12 23:02:25 -08:00
// swagger:operation DELETE /user/keys/{id} user userCurrentDeleteKey
// ---
// summary: Delete a public key
// produces:
// - application/json
// parameters:
// - name: id
// in: path
// description: id of key to delete
// type: integer
// format: int64
2017-11-12 23:02:25 -08:00
// required: true
// responses:
// "204":
// "$ref": "#/responses/empty"
// "403":
// "$ref": "#/responses/forbidden"
// "404":
// "$ref": "#/responses/notFound"
2019-12-20 18:07:12 +01:00
if user_model.IsFeatureDisabledWithLoginType(ctx.Doer, setting.UserFeatureManageSSHKeys) {
2025-04-01 12:14:01 +02:00
ctx.APIErrorNotFound("Not Found", errors.New("ssh keys setting is not allowed to be visited"))
return
}
2024-12-24 21:47:45 +08:00
id := ctx.PathParamInt64("id")
externallyManaged, err := asymkey_model.PublicKeyIsExternallyManaged(ctx, id)
if err != nil {
if asymkey_model.IsErrKeyNotExist(err) {
2025-02-17 14:13:17 +08:00
ctx.APIErrorNotFound()
} else {
2025-02-18 04:41:03 +08:00
ctx.APIErrorInternal(err)
}
return
}
if externallyManaged {
2025-02-17 14:13:17 +08:00
ctx.APIError(http.StatusForbidden, "SSH Key is externally managed for this user")
return
}
if err := asymkey_service.DeletePublicKey(ctx, ctx.Doer, id); err != nil {
if asymkey_model.IsErrKeyAccessDenied(err) {
2025-02-17 14:13:17 +08:00
ctx.APIError(http.StatusForbidden, "You do not have access to this key")
2015-12-03 00:24:37 -05:00
} else {
2025-02-18 04:41:03 +08:00
ctx.APIErrorInternal(err)
2015-12-03 00:24:37 -05:00
}
return
}
2019-12-20 18:07:12 +01:00
ctx.Status(http.StatusNoContent)
2015-12-03 00:24:37 -05:00
}