mirror of
https://github.com/go-gitea/gitea.git
synced 2026-09-21 20:23:41 +09:00
feat: manage bot accounts from the admin UI, API and CLI (#38966)
Adds first-class bot accounts (`UserTypeBot`): local, password-less
users for automation that authenticate only with access tokens.
1. Admin UI: create bots, filter users by type, manage a bot's access
tokens, convert between user and bot
2. API: `POST /admin/users/{username}/convert-type`, and user objects
gain a GitHub-compatible `type` (`User`, `Organization`, `Bot`)
3. CLI: `gitea admin user change-type`, `--user-type` accepts `User` or
`Bot` case-insensitively
4. Converting keeps the password, 2FA, OAuth2 grants and access tokens,
and since sign-in rejects bots, converting back restores the account.
Only local, non-admin accounts can be converted, and conversions are
audited
5. Session, reverse proxy, SSPI, external source and password reset
sign-in reject non-individual users, so a bot never gets an interactive
session
6. Bots receive no notifications or emails
Co-authored-by: Nicolas <bircni@icloud.com>
Co-authored-by: joestump <joe@joestump.net>
Co-authored-by: Joe Stump <joe@stu.mp>
Co-authored-by: silverwind <me@silverwind.io>
Co-authored-by: Lunny Xiao <xiaolunwen@gmail.com>
This commit is contained in:
co-authored by
Nicolas
joestump
Joe Stump
silverwind
Lunny Xiao
parent
db7dbd5a6b
commit
3bec08f998
@@ -1,94 +1,6 @@
|
||||
{{template "user/settings/layout_head" (dict "pageClass" "user settings applications")}}
|
||||
<div class="user-setting-content">
|
||||
<h4 class="ui top attached header">
|
||||
{{ctx.Locale.Tr "settings.manage_access_token"}}
|
||||
</h4>
|
||||
<div class="ui attached segment">
|
||||
<div class="flex-divided-list items-with-main">
|
||||
<div class="item">
|
||||
{{ctx.Locale.Tr "settings.tokens_desc"}}
|
||||
</div>
|
||||
{{range .Tokens}}
|
||||
<div class="item">
|
||||
<div class="item-leading">
|
||||
<span class="{{if .HasRecentActivity}}tw-text-green{{end}}" {{if .HasRecentActivity}}data-tooltip-content="{{ctx.Locale.Tr "settings.token_state_desc"}}"{{end}}>
|
||||
{{svg "fontawesome-send" 32}}
|
||||
</span>
|
||||
</div>
|
||||
<div class="item-main">
|
||||
<details>
|
||||
<summary><span class="item-title">{{.Name}}</span></summary>
|
||||
<p class="tw-my-1">
|
||||
{{ctx.Locale.Tr "settings.repo_and_org_access"}}:
|
||||
{{if .DisplayPublicOnly}}
|
||||
{{ctx.Locale.Tr "settings.permissions_public_only"}}
|
||||
{{else}}
|
||||
{{ctx.Locale.Tr "settings.permissions_access_all"}}
|
||||
{{end}}
|
||||
</p>
|
||||
<p class="tw-my-1">{{ctx.Locale.Tr "settings.permissions_list"}}</p>
|
||||
<ul class="tw-my-1">
|
||||
{{range .Scope.StringSlice}}
|
||||
{{if (ne . $.AccessTokenScopePublicOnly)}}
|
||||
<li>{{.}}</li>
|
||||
{{end}}
|
||||
{{end}}
|
||||
</ul>
|
||||
</details>
|
||||
<div class="item-body">
|
||||
<i>{{ctx.Locale.Tr "settings.added_on" (DateUtils.AbsoluteShort .CreatedUnix)}} — {{svg "octicon-info"}} {{if .HasUsed}}{{ctx.Locale.Tr "settings.last_used"}} <span {{if .HasRecentActivity}}class="tw-text-green"{{end}}>{{DateUtils.AbsoluteShort .UpdatedUnix}}</span>{{else}}{{ctx.Locale.Tr "settings.no_activity"}}{{end}}</i>
|
||||
</div>
|
||||
</div>
|
||||
<div class="item-trailing">
|
||||
<button type="button" class="ui tiny button link-action" data-modal-confirm="#regenerate-token" data-url="{{$.Link}}/regenerate?id={{.ID}}">
|
||||
{{svg "octicon-sync"}}
|
||||
{{ctx.Locale.Tr "settings.regenerate_token"}}
|
||||
</button>
|
||||
<button type="button" class="ui red tiny button link-action" data-modal-confirm="#delete-token" data-url="{{$.Link}}/delete?id={{.ID}}">
|
||||
{{svg "octicon-trash"}}
|
||||
{{ctx.Locale.Tr "settings.delete_token"}}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
{{end}}
|
||||
</div>
|
||||
</div>
|
||||
<div class="ui bottom attached segment">
|
||||
<details {{if or .name (not .Tokens)}}open{{end}}>
|
||||
<summary><h4 class="ui header tw-inline-block tw-my-2">{{ctx.Locale.Tr "settings.generate_new_token"}}</h4></summary>
|
||||
<form class="ui form ignore-dirty" action="{{.Link}}" method="post">
|
||||
<div class="field {{if .Err_Name}}error{{end}}">
|
||||
<label for="name">{{ctx.Locale.Tr "settings.token_name"}}</label>
|
||||
<input id="name" name="name" value="{{.name}}" required maxlength="255">
|
||||
</div>
|
||||
<div class="field">
|
||||
<div class="tw-my-2">{{ctx.Locale.Tr "settings.repo_and_org_access"}}</div>
|
||||
<label class="gt-checkbox">
|
||||
<input type="radio" name="scope-public-only" value="{{$.AccessTokenScopePublicOnly}}"> {{ctx.Locale.Tr "settings.permissions_public_only"}}
|
||||
</label>
|
||||
<label class="gt-checkbox">
|
||||
<input type="radio" name="scope-public-only" value="" checked> {{ctx.Locale.Tr "settings.permissions_access_all"}}
|
||||
</label>
|
||||
</div>
|
||||
<div>
|
||||
<div class="tw-my-2">{{ctx.Locale.Tr "settings.access_token_desc" (HTMLFormat `href="%s/api/swagger" target="_blank"` AppSubUrl) (HTMLFormat `href="%s" target="_blank"` "https://docs.gitea.com/development/oauth2-provider#scopes")}}</div>
|
||||
<table class="ui table unstackable tw-my-2">
|
||||
{{range $category := .TokenCategories}}
|
||||
<tr>
|
||||
<td>{{$category}}</td>
|
||||
<td><label class="gt-checkbox"><input type="radio" name="scope-{{$category}}" value="" checked> {{ctx.Locale.Tr "settings.permission_no_access"}}</label></td>
|
||||
<td><label class="gt-checkbox"><input type="radio" name="scope-{{$category}}" value="read:{{$category}}"> {{ctx.Locale.Tr "settings.permission_read"}}</label></td>
|
||||
<td><label class="gt-checkbox"><input type="radio" name="scope-{{$category}}" value="write:{{$category}}"> {{ctx.Locale.Tr "settings.permission_write"}}</label></td>
|
||||
</tr>
|
||||
{{end}}
|
||||
</table>
|
||||
</div>
|
||||
<button type="submit" class="ui primary button">
|
||||
{{ctx.Locale.Tr "settings.generate_token"}}
|
||||
</button>
|
||||
</form>
|
||||
</details>
|
||||
</div>
|
||||
{{template "shared/user/access_tokens" .AccessTokens}}
|
||||
|
||||
{{if .EnableOAuth2}}
|
||||
{{template "user/settings/grants_oauth2" .}}
|
||||
@@ -96,25 +8,4 @@
|
||||
{{end}}
|
||||
</div>
|
||||
|
||||
<div class="ui small modal" id="delete-token">
|
||||
<div class="header">
|
||||
{{svg "octicon-trash"}}
|
||||
{{ctx.Locale.Tr "settings.access_token_deletion"}}
|
||||
</div>
|
||||
<div class="content">
|
||||
<p>{{ctx.Locale.Tr "settings.access_token_deletion_desc"}}</p>
|
||||
</div>
|
||||
{{template "base/modal_actions_confirm"}}
|
||||
</div>
|
||||
|
||||
<div class="ui small modal" id="regenerate-token">
|
||||
<div class="header">
|
||||
{{ctx.Locale.Tr "settings.access_token_regeneration"}}
|
||||
</div>
|
||||
<div class="content">
|
||||
<p>{{ctx.Locale.Tr "settings.access_token_regeneration_desc"}}</p>
|
||||
</div>
|
||||
{{template "base/modal_actions_confirm"}}
|
||||
</div>
|
||||
|
||||
{{template "user/settings/layout_footer" .}}
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
{{ctx.AvatarUtils.Avatar . 28 "mini"}}
|
||||
</div>
|
||||
<div class="item-main">
|
||||
<div class="item-title">{{template "shared/user/name" .}}</div>
|
||||
<div class="item-title">{{template "shared/user/name" .AsUser}}</div>
|
||||
<div class="flex-text-body">
|
||||
{{.Description}}
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user