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