summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorzeripath <art27@cantab.net>2023-02-20 21:28:44 +0000
committerGitHub <noreply@github.com>2023-02-20 15:28:44 -0600
commitd2128b44f714fcaacdc88865e62f6f9dd8216577 (patch)
treef6697bf42a61acc7f31b378882124e764281106b
parent330b16642305458339d12222eea2ee9a1bbb3b64 (diff)
downloadgitea-d2128b44f714fcaacdc88865e62f6f9dd8216577.tar.gz
gitea-d2128b44f714fcaacdc88865e62f6f9dd8216577.zip
Add scopes to API to create token and display them (#22989)
The API to create tokens is missing the ability to set the required scopes for tokens, and to show them on the API and on the UI. This PR adds this functionality. Signed-off-by: Andrew Thornton <art27@cantab.net>
-rw-r--r--models/auth/token_scope.go25
-rw-r--r--modules/structs/user_app.go14
-rw-r--r--options/locale/locale_en-US.ini1
-rw-r--r--routers/api/v1/user/app.go13
-rw-r--r--templates/swagger/v1_json.tmpl20
-rw-r--r--templates/user/settings/applications.tmpl9
6 files changed, 68 insertions, 14 deletions
diff --git a/models/auth/token_scope.go b/models/auth/token_scope.go
index c61c306496..38733a1c8f 100644
--- a/models/auth/token_scope.go
+++ b/models/auth/token_scope.go
@@ -168,10 +168,23 @@ var allAccessTokenScopeBits = map[AccessTokenScope]AccessTokenScopeBitmap{
// Parse parses the scope string into a bitmap, thus removing possible duplicates.
func (s AccessTokenScope) Parse() (AccessTokenScopeBitmap, error) {
- list := strings.Split(string(s), ",")
-
var bitmap AccessTokenScopeBitmap
- for _, v := range list {
+
+ // The following is the more performant equivalent of 'for _, v := range strings.Split(remainingScope, ",")' as this is hot code
+ remainingScopes := string(s)
+ for len(remainingScopes) > 0 {
+ i := strings.IndexByte(remainingScopes, ',')
+ var v string
+ if i < 0 {
+ v = remainingScopes
+ remainingScopes = ""
+ } else if i+1 >= len(remainingScopes) {
+ v = remainingScopes[:i]
+ remainingScopes = ""
+ } else {
+ v = remainingScopes[:i]
+ remainingScopes = remainingScopes[i+1:]
+ }
singleScope := AccessTokenScope(v)
if singleScope == "" {
continue
@@ -187,9 +200,15 @@ func (s AccessTokenScope) Parse() (AccessTokenScopeBitmap, error) {
}
bitmap |= bits
}
+
return bitmap, nil
}
+// StringSlice returns the AccessTokenScope as a []string
+func (s AccessTokenScope) StringSlice() []string {
+ return strings.Split(string(s), ",")
+}
+
// Normalize returns a normalized scope string without any duplicates.
func (s AccessTokenScope) Normalize() (AccessTokenScope, error) {
bitmap, err := s.Parse()
diff --git a/modules/structs/user_app.go b/modules/structs/user_app.go
index 3a5ae34df1..7f78fbd495 100644
--- a/modules/structs/user_app.go
+++ b/modules/structs/user_app.go
@@ -11,10 +11,11 @@ import (
// AccessToken represents an API access token.
// swagger:response AccessToken
type AccessToken struct {
- ID int64 `json:"id"`
- Name string `json:"name"`
- Token string `json:"sha1"`
- TokenLastEight string `json:"token_last_eight"`
+ ID int64 `json:"id"`
+ Name string `json:"name"`
+ Token string `json:"sha1"`
+ TokenLastEight string `json:"token_last_eight"`
+ Scopes []string `json:"scopes"`
}
// AccessTokenList represents a list of API access token.
@@ -22,9 +23,10 @@ type AccessToken struct {
type AccessTokenList []*AccessToken
// CreateAccessTokenOption options when create access token
-// swagger:parameters userCreateToken
type CreateAccessTokenOption struct {
- Name string `json:"name" binding:"Required"`
+ // required: true
+ Name string `json:"name" binding:"Required"`
+ Scopes []string `json:"scopes"`
}
// CreateOAuth2ApplicationOptions holds options to create an oauth2 application
diff --git a/options/locale/locale_en-US.ini b/options/locale/locale_en-US.ini
index 92ca5be8d3..df66ce2339 100644
--- a/options/locale/locale_en-US.ini
+++ b/options/locale/locale_en-US.ini
@@ -757,6 +757,7 @@ access_token_deletion_confirm_action = Delete
access_token_deletion_desc = Deleting a token will revoke access to your account for applications using it. This cannot be undone. Continue?
delete_token_success = The token has been deleted. Applications using it no longer have access to your account.
select_scopes = Select scopes
+scopes_list = Scopes:
manage_oauth2_applications = Manage OAuth2 Applications
edit_oauth2_application = Edit OAuth2 Application
diff --git a/routers/api/v1/user/app.go b/routers/api/v1/user/app.go
index 7b2f0d8c30..f89d53945f 100644
--- a/routers/api/v1/user/app.go
+++ b/routers/api/v1/user/app.go
@@ -9,6 +9,7 @@ import (
"fmt"
"net/http"
"strconv"
+ "strings"
auth_model "code.gitea.io/gitea/models/auth"
"code.gitea.io/gitea/modules/context"
@@ -62,6 +63,7 @@ func ListAccessTokens(ctx *context.APIContext) {
ID: tokens[i].ID,
Name: tokens[i].Name,
TokenLastEight: tokens[i].TokenLastEight,
+ Scopes: tokens[i].Scope.StringSlice(),
}
}
@@ -82,9 +84,9 @@ func CreateAccessToken(ctx *context.APIContext) {
// - name: username
// in: path
// description: username of user
- // type: string
// required: true
- // - name: userCreateToken
+ // type: string
+ // - name: body
// in: body
// schema:
// "$ref": "#/definitions/CreateAccessTokenOption"
@@ -111,6 +113,13 @@ func CreateAccessToken(ctx *context.APIContext) {
return
}
+ scope, err := auth_model.AccessTokenScope(strings.Join(form.Scopes, ",")).Normalize()
+ if err != nil {
+ ctx.Error(http.StatusBadRequest, "AccessTokenScope.Normalize", fmt.Errorf("invalid access token scope provided: %w", err))
+ return
+ }
+ t.Scope = scope
+
if err := auth_model.NewAccessToken(t); err != nil {
ctx.Error(http.StatusInternalServerError, "NewAccessToken", err)
return
diff --git a/templates/swagger/v1_json.tmpl b/templates/swagger/v1_json.tmpl
index 2a675766ab..de774deaed 100644
--- a/templates/swagger/v1_json.tmpl
+++ b/templates/swagger/v1_json.tmpl
@@ -14084,14 +14084,13 @@
"parameters": [
{
"type": "string",
- "x-go-name": "Name",
"description": "username of user",
"name": "username",
"in": "path",
"required": true
},
{
- "name": "userCreateToken",
+ "name": "body",
"in": "body",
"schema": {
"$ref": "#/definitions/CreateAccessTokenOption"
@@ -14194,6 +14193,13 @@
"type": "string",
"x-go-name": "Name"
},
+ "scopes": {
+ "type": "array",
+ "items": {
+ "type": "string"
+ },
+ "x-go-name": "Scopes"
+ },
"sha1": {
"type": "string",
"x-go-name": "Token"
@@ -14925,10 +14931,20 @@
"CreateAccessTokenOption": {
"description": "CreateAccessTokenOption options when create access token",
"type": "object",
+ "required": [
+ "name"
+ ],
"properties": {
"name": {
"type": "string",
"x-go-name": "Name"
+ },
+ "scopes": {
+ "type": "array",
+ "items": {
+ "type": "string"
+ },
+ "x-go-name": "Scopes"
}
},
"x-go-package": "code.gitea.io/gitea/modules/structs"
diff --git a/templates/user/settings/applications.tmpl b/templates/user/settings/applications.tmpl
index 439ed5e148..ef9ac9a977 100644
--- a/templates/user/settings/applications.tmpl
+++ b/templates/user/settings/applications.tmpl
@@ -21,7 +21,14 @@
</div>
<i class="icon tooltip{{if .HasRecentActivity}} green{{end}}" {{if .HasRecentActivity}}data-content="{{$.locale.Tr "settings.token_state_desc"}}"{{end}}>{{svg "fontawesome-send" 36}}</i>
<div class="content">
- <strong>{{.Name}}</strong>
+ <details><summary><strong>{{.Name}}</strong></summary>
+ <p class="gt-my-2">{{$.locale.Tr "settings.scopes_list"}}</p>
+ <ul class="gt-my-2">
+ {{range .Scope.StringSlice}}
+ <li>{{.}}</li>
+ {{end}}
+ </ul>
+ </details>
<div class="activity meta">
<i>{{$.locale.Tr "settings.add_on"}} <span><time data-format="short-date" datetime="{{.CreatedUnix.FormatLong}}">{{.CreatedUnix.FormatShort}}</time></span> — {{svg "octicon-info"}} {{if .HasUsed}}{{$.locale.Tr "settings.last_used"}} <span {{if .HasRecentActivity}}class="green"{{end}}><time data-format="short-date" datetime="{{.UpdatedUnix.FormatLong}}">{{.UpdatedUnix.FormatShort}}</time></span>{{else}}{{$.locale.Tr "settings.no_activity"}}{{end}}</i>
</div>