Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add scopes to API to create token and display them #22989

Merged
merged 9 commits into from Feb 20, 2023
24 changes: 21 additions & 3 deletions models/auth/token_scope.go
Expand Up @@ -168,10 +168,22 @@ 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 {

remainingScopes := string(s)
lunny marked this conversation as resolved.
Show resolved Hide resolved
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:]
}
lunny marked this conversation as resolved.
Show resolved Hide resolved
singleScope := AccessTokenScope(v)
if singleScope == "" {
continue
Expand All @@ -187,9 +199,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()
Expand Down
12 changes: 7 additions & 5 deletions modules/structs/user_app.go
Expand Up @@ -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"`
Scope []string `json:"scope"`
lunny marked this conversation as resolved.
Show resolved Hide resolved
}

// AccessTokenList represents a list of API access token.
Expand All @@ -24,7 +25,8 @@ type AccessTokenList []*AccessToken
// CreateAccessTokenOption options when create access token
// swagger:parameters userCreateToken
type CreateAccessTokenOption struct {
Name string `json:"name" binding:"Required"`
Name string `json:"name" binding:"Required"`
Scope []string
lunny marked this conversation as resolved.
Show resolved Hide resolved
}

// CreateOAuth2ApplicationOptions holds options to create an oauth2 application
Expand Down
1 change: 1 addition & 0 deletions options/locale/locale_en-US.ini
Expand Up @@ -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
Expand Down
9 changes: 9 additions & 0 deletions routers/api/v1/user/app.go
Expand Up @@ -9,6 +9,7 @@ import (
"fmt"
"net/http"
"strconv"
"strings"

auth_model "code.gitea.io/gitea/models/auth"
"code.gitea.io/gitea/modules/context"
Expand Down Expand Up @@ -62,6 +63,7 @@ func ListAccessTokens(ctx *context.APIContext) {
ID: tokens[i].ID,
Name: tokens[i].Name,
TokenLastEight: tokens[i].TokenLastEight,
Scope: tokens[i].Scope.StringSlice(),
}
}

Expand Down Expand Up @@ -111,6 +113,13 @@ func CreateAccessToken(ctx *context.APIContext) {
return
}

scope, err := auth_model.AccessTokenScope(strings.Join(form.Scope, ",")).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
Expand Down
17 changes: 17 additions & 0 deletions templates/swagger/v1_json.tmpl
Expand Up @@ -14091,6 +14091,10 @@
"required": true
},
{
"type": "array",
"items": {
"type": "string"
},
"name": "userCreateToken",
"in": "body",
"schema": {
Expand Down Expand Up @@ -14194,6 +14198,13 @@
"type": "string",
"x-go-name": "Name"
},
"scope": {
"type": "array",
"items": {
"type": "string"
},
"x-go-name": "Scope"
},
"sha1": {
"type": "string",
"x-go-name": "Token"
Expand Down Expand Up @@ -14926,6 +14937,12 @@
"description": "CreateAccessTokenOption options when create access token",
"type": "object",
"properties": {
"Scope": {
lunny marked this conversation as resolved.
Show resolved Hide resolved
"type": "array",
"items": {
"type": "string"
}
},
"name": {
"type": "string",
"x-go-name": "Name"
Expand Down
9 changes: 8 additions & 1 deletion templates/user/settings/applications.tmpl
Expand Up @@ -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>
Expand Down