code.gitea.io/gitea@v1.22.3/routers/api/v1/user/key.go (about) 1 // Copyright 2015 The Gogs Authors. All rights reserved. 2 // SPDX-License-Identifier: MIT 3 4 package user 5 6 import ( 7 std_ctx "context" 8 "fmt" 9 "net/http" 10 11 asymkey_model "code.gitea.io/gitea/models/asymkey" 12 "code.gitea.io/gitea/models/db" 13 "code.gitea.io/gitea/models/perm" 14 user_model "code.gitea.io/gitea/models/user" 15 "code.gitea.io/gitea/modules/setting" 16 api "code.gitea.io/gitea/modules/structs" 17 "code.gitea.io/gitea/modules/web" 18 "code.gitea.io/gitea/routers/api/v1/repo" 19 "code.gitea.io/gitea/routers/api/v1/utils" 20 asymkey_service "code.gitea.io/gitea/services/asymkey" 21 "code.gitea.io/gitea/services/context" 22 "code.gitea.io/gitea/services/convert" 23 ) 24 25 // appendPrivateInformation appends the owner and key type information to api.PublicKey 26 func appendPrivateInformation(ctx std_ctx.Context, apiKey *api.PublicKey, key *asymkey_model.PublicKey, defaultUser *user_model.User) (*api.PublicKey, error) { 27 if key.Type == asymkey_model.KeyTypeDeploy { 28 apiKey.KeyType = "deploy" 29 } else if key.Type == asymkey_model.KeyTypeUser { 30 apiKey.KeyType = "user" 31 32 if defaultUser.ID == key.OwnerID { 33 apiKey.Owner = convert.ToUser(ctx, defaultUser, defaultUser) 34 } else { 35 user, err := user_model.GetUserByID(ctx, key.OwnerID) 36 if err != nil { 37 return apiKey, err 38 } 39 apiKey.Owner = convert.ToUser(ctx, user, user) 40 } 41 } else { 42 apiKey.KeyType = "unknown" 43 } 44 apiKey.ReadOnly = key.Mode == perm.AccessModeRead 45 return apiKey, nil 46 } 47 48 func composePublicKeysAPILink() string { 49 return setting.AppURL + "api/v1/user/keys/" 50 } 51 52 func listPublicKeys(ctx *context.APIContext, user *user_model.User) { 53 var keys []*asymkey_model.PublicKey 54 var err error 55 var count int 56 57 fingerprint := ctx.FormString("fingerprint") 58 username := ctx.Params("username") 59 60 if fingerprint != "" { 61 var userID int64 // Unrestricted 62 // Querying not just listing 63 if username != "" { 64 // Restrict to provided uid 65 userID = user.ID 66 } 67 keys, err = db.Find[asymkey_model.PublicKey](ctx, asymkey_model.FindPublicKeyOptions{ 68 OwnerID: userID, 69 Fingerprint: fingerprint, 70 }) 71 count = len(keys) 72 } else { 73 var total int64 74 // Use ListPublicKeys 75 keys, total, err = db.FindAndCount[asymkey_model.PublicKey](ctx, asymkey_model.FindPublicKeyOptions{ 76 ListOptions: utils.GetListOptions(ctx), 77 OwnerID: user.ID, 78 NotKeytype: asymkey_model.KeyTypePrincipal, 79 }) 80 count = int(total) 81 } 82 83 if err != nil { 84 ctx.Error(http.StatusInternalServerError, "ListPublicKeys", err) 85 return 86 } 87 88 apiLink := composePublicKeysAPILink() 89 apiKeys := make([]*api.PublicKey, len(keys)) 90 for i := range keys { 91 apiKeys[i] = convert.ToPublicKey(apiLink, keys[i]) 92 if ctx.Doer.IsAdmin || ctx.Doer.ID == keys[i].OwnerID { 93 apiKeys[i], _ = appendPrivateInformation(ctx, apiKeys[i], keys[i], user) 94 } 95 } 96 97 ctx.SetTotalCountHeader(int64(count)) 98 ctx.JSON(http.StatusOK, &apiKeys) 99 } 100 101 // ListMyPublicKeys list all of the authenticated user's public keys 102 func ListMyPublicKeys(ctx *context.APIContext) { 103 // swagger:operation GET /user/keys user userCurrentListKeys 104 // --- 105 // summary: List the authenticated user's public keys 106 // parameters: 107 // - name: fingerprint 108 // in: query 109 // description: fingerprint of the key 110 // type: string 111 // - name: page 112 // in: query 113 // description: page number of results to return (1-based) 114 // type: integer 115 // - name: limit 116 // in: query 117 // description: page size of results 118 // type: integer 119 // produces: 120 // - application/json 121 // responses: 122 // "200": 123 // "$ref": "#/responses/PublicKeyList" 124 125 listPublicKeys(ctx, ctx.Doer) 126 } 127 128 // ListPublicKeys list the given user's public keys 129 func ListPublicKeys(ctx *context.APIContext) { 130 // swagger:operation GET /users/{username}/keys user userListKeys 131 // --- 132 // summary: List the given user's public keys 133 // produces: 134 // - application/json 135 // parameters: 136 // - name: username 137 // in: path 138 // description: username of user 139 // type: string 140 // required: true 141 // - name: fingerprint 142 // in: query 143 // description: fingerprint of the key 144 // type: string 145 // - name: page 146 // in: query 147 // description: page number of results to return (1-based) 148 // type: integer 149 // - name: limit 150 // in: query 151 // description: page size of results 152 // type: integer 153 // responses: 154 // "200": 155 // "$ref": "#/responses/PublicKeyList" 156 // "404": 157 // "$ref": "#/responses/notFound" 158 159 listPublicKeys(ctx, ctx.ContextUser) 160 } 161 162 // GetPublicKey get a public key 163 func GetPublicKey(ctx *context.APIContext) { 164 // swagger:operation GET /user/keys/{id} user userCurrentGetKey 165 // --- 166 // summary: Get a public key 167 // produces: 168 // - application/json 169 // parameters: 170 // - name: id 171 // in: path 172 // description: id of key to get 173 // type: integer 174 // format: int64 175 // required: true 176 // responses: 177 // "200": 178 // "$ref": "#/responses/PublicKey" 179 // "404": 180 // "$ref": "#/responses/notFound" 181 182 key, err := asymkey_model.GetPublicKeyByID(ctx, ctx.ParamsInt64(":id")) 183 if err != nil { 184 if asymkey_model.IsErrKeyNotExist(err) { 185 ctx.NotFound() 186 } else { 187 ctx.Error(http.StatusInternalServerError, "GetPublicKeyByID", err) 188 } 189 return 190 } 191 192 apiLink := composePublicKeysAPILink() 193 apiKey := convert.ToPublicKey(apiLink, key) 194 if ctx.Doer.IsAdmin || ctx.Doer.ID == key.OwnerID { 195 apiKey, _ = appendPrivateInformation(ctx, apiKey, key, ctx.Doer) 196 } 197 ctx.JSON(http.StatusOK, apiKey) 198 } 199 200 // CreateUserPublicKey creates new public key to given user by ID. 201 func CreateUserPublicKey(ctx *context.APIContext, form api.CreateKeyOption, uid int64) { 202 if user_model.IsFeatureDisabledWithLoginType(ctx.Doer, setting.UserFeatureManageSSHKeys) { 203 ctx.NotFound("Not Found", fmt.Errorf("ssh keys setting is not allowed to be visited")) 204 return 205 } 206 207 content, err := asymkey_model.CheckPublicKeyString(form.Key) 208 if err != nil { 209 repo.HandleCheckKeyStringError(ctx, err) 210 return 211 } 212 213 key, err := asymkey_model.AddPublicKey(ctx, uid, form.Title, content, 0) 214 if err != nil { 215 repo.HandleAddKeyError(ctx, err) 216 return 217 } 218 apiLink := composePublicKeysAPILink() 219 apiKey := convert.ToPublicKey(apiLink, key) 220 if ctx.Doer.IsAdmin || ctx.Doer.ID == key.OwnerID { 221 apiKey, _ = appendPrivateInformation(ctx, apiKey, key, ctx.Doer) 222 } 223 ctx.JSON(http.StatusCreated, apiKey) 224 } 225 226 // CreatePublicKey create one public key for me 227 func CreatePublicKey(ctx *context.APIContext) { 228 // swagger:operation POST /user/keys user userCurrentPostKey 229 // --- 230 // summary: Create a public key 231 // consumes: 232 // - application/json 233 // produces: 234 // - application/json 235 // parameters: 236 // - name: body 237 // in: body 238 // schema: 239 // "$ref": "#/definitions/CreateKeyOption" 240 // responses: 241 // "201": 242 // "$ref": "#/responses/PublicKey" 243 // "422": 244 // "$ref": "#/responses/validationError" 245 246 form := web.GetForm(ctx).(*api.CreateKeyOption) 247 CreateUserPublicKey(ctx, *form, ctx.Doer.ID) 248 } 249 250 // DeletePublicKey delete one public key 251 func DeletePublicKey(ctx *context.APIContext) { 252 // swagger:operation DELETE /user/keys/{id} user userCurrentDeleteKey 253 // --- 254 // summary: Delete a public key 255 // produces: 256 // - application/json 257 // parameters: 258 // - name: id 259 // in: path 260 // description: id of key to delete 261 // type: integer 262 // format: int64 263 // required: true 264 // responses: 265 // "204": 266 // "$ref": "#/responses/empty" 267 // "403": 268 // "$ref": "#/responses/forbidden" 269 // "404": 270 // "$ref": "#/responses/notFound" 271 272 if user_model.IsFeatureDisabledWithLoginType(ctx.Doer, setting.UserFeatureManageSSHKeys) { 273 ctx.NotFound("Not Found", fmt.Errorf("ssh keys setting is not allowed to be visited")) 274 return 275 } 276 277 id := ctx.ParamsInt64(":id") 278 externallyManaged, err := asymkey_model.PublicKeyIsExternallyManaged(ctx, id) 279 if err != nil { 280 if asymkey_model.IsErrKeyNotExist(err) { 281 ctx.NotFound() 282 } else { 283 ctx.Error(http.StatusInternalServerError, "PublicKeyIsExternallyManaged", err) 284 } 285 return 286 } 287 288 if externallyManaged { 289 ctx.Error(http.StatusForbidden, "", "SSH Key is externally managed for this user") 290 return 291 } 292 293 if err := asymkey_service.DeletePublicKey(ctx, ctx.Doer, id); err != nil { 294 if asymkey_model.IsErrKeyAccessDenied(err) { 295 ctx.Error(http.StatusForbidden, "", "You do not have access to this key") 296 } else { 297 ctx.Error(http.StatusInternalServerError, "DeletePublicKey", err) 298 } 299 return 300 } 301 302 ctx.Status(http.StatusNoContent) 303 }