feat(user): allow renaming security keys (webauthn/passkey) (#39413)

Closes https://github.com/go-gitea/gitea/issues/39287

Security key nicknames could only be set at registration, so a skipped
nickname left an auto-generated hex name until the key was
re-registered. Each key now has a Rename button opening a dialog with
the current nickname. A nickname used by another of the user's keys
(case-insensitive) or a blank nickname is rejected. Renames are recorded
as `user:webauth:rename` audit events.

Co-authored-by: silverwind <me@silverwind.io>
Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
This commit is contained in:
authored and GitHub committed 2026-10-05 19:12:22 +02:00
1 parent 66546045b5
commit d16b20b972
17 files changed
+142 -21

No files matched your search

+1 -1
View File
@@ -33,7 +33,7 @@
</button>
{{end}}
<button type="button" class="ui red tiny button link-action" data-modal-confirm="#repo-deploy-key-delete-modal" data-url="{{ctx.RootData.Link}}/delete?id={{$key.ID}}">
{{ctx.Locale.Tr "settings.delete_key"}}
{{ctx.Locale.Tr "remove"}}
</button>
</div>
</div>
@@ -27,7 +27,7 @@
<button type="button" class="ui red tiny button link-action" data-modal-confirm="#remove-gitea-oauth2-application"
data-url="{{$.Link}}/oauth2/{{.ID}}/delete">
{{svg "octicon-trash"}}
{{ctx.Locale.Tr "settings.delete_key"}}
{{ctx.Locale.Tr "remove"}}
</button>
{{end}}
</div>
+1 -1
View File
@@ -77,7 +77,7 @@
</div>
<div class="item-trailing">
<button type="button" class="ui red tiny button link-action" data-modal-confirm="#delete-gpg" data-url="{{$.Link}}/delete?type=gpg&id={{.ID}}">
{{ctx.Locale.Tr "settings.delete_key"}}
{{ctx.Locale.Tr "remove"}}
</button>
{{if and (not .Verified) (ne $.VerifyingID .KeyID)}}
<a class="ui primary tiny button" href="?verify_gpg={{.KeyID}}">{{ctx.Locale.Tr "settings.gpg_key_verify"}}</a>
+1 -1
View File
@@ -27,7 +27,7 @@
</div>
<div class="item-trailing">
<button type="button" class="ui red tiny button link-action" data-modal-confirm="#delete-principal" data-url="{{$.Link}}/delete?type=principal&id={{.ID}}">
{{ctx.Locale.Tr "settings.delete_key"}}
{{ctx.Locale.Tr "remove"}}
</button>
</div>
</div>
+1 -1
View File
@@ -57,7 +57,7 @@
</div>
<div class="item-trailing">
<button type="button" class="ui red tiny button link-action{{if index $.ExternalKeys $index}} disabled{{end}}" data-modal-confirm="#delete-ssh" data-url="{{$.Link}}/delete?type=ssh&id={{.ID}}"{{if index $.ExternalKeys $index}} title="{{ctx.Locale.Tr "settings.ssh_externally_managed"}}"{{end}}>
{{ctx.Locale.Tr "settings.delete_key"}}
{{ctx.Locale.Tr "remove"}}
</button>
{{if and (not .Verified) (ne $.VerifyingFingerprint .Fingerprint)}}
<a class="ui primary tiny button" href="?verify_ssh={{.Fingerprint}}">{{ctx.Locale.Tr "settings.ssh_key_verify"}}</a>
@@ -41,7 +41,7 @@
</div>
<div class="item-trailing">
<button type="button" class="ui red tiny button link-action" data-modal-confirm="#delete-account-link" data-url="{{AppSubUrl}}/user/settings/security/account_link?id={{$loginSource.ID}}">
{{ctx.Locale.Tr "settings.delete_key"}}
{{ctx.Locale.Tr "remove"}}
</button>
</div>
</div>
+1 -1
View File
@@ -30,7 +30,7 @@
{{end}}
</form>
<button type="button" class="ui red tiny button link-action" data-modal-confirm="#delete-openid" data-url="{{AppSubUrl}}/user/settings/security/openid/delete?id={{.ID}}">
{{ctx.Locale.Tr "settings.delete_key"}}
{{ctx.Locale.Tr "remove"}}
</button>
</div>
</div>
+20 -1
View File
@@ -16,13 +16,18 @@
</div>
</div>
<div class="item-trailing">
<button type="button" class="ui tiny button show-modal" data-modal="#rename-webauthn-nickname" data-modal-id="{{.ID}}" data-modal-name="{{.Name}}">
{{ctx.Locale.Tr "rename"}}
</button>
<button type="button" class="ui red tiny button link-action" data-modal-confirm="#delete-registration" data-url="{{$.Link}}/webauthn/delete?id={{.ID}}">
{{ctx.Locale.Tr "settings.delete_key"}}
{{ctx.Locale.Tr "remove"}}
</button>
</div>
</div>
{{end}}
</div>
</div>
<div class="ui attached segment">
<div class="ui form">
<div class="required field">
<label for="nickname">{{ctx.Locale.Tr "settings.webauthn_nickname"}}</label>
@@ -30,6 +35,20 @@
</div>
<button type="button" id="register-webauthn" class="ui primary button">{{svg "octicon-key"}} {{ctx.Locale.Tr "settings.webauthn_register_key"}}</button>
</div>
<div class="ui small modal" id="rename-webauthn-nickname">
<div class="header">
{{svg "octicon-pencil"}}
{{ctx.Locale.Tr "rename"}}
</div>
<form class="content ui form form-fetch-action" action="{{$.Link}}/webauthn/rename" method="post">
<input type="hidden" name="id">
<div class="required field">
<label>{{ctx.Locale.Tr "settings.webauthn_nickname"}}</label>
<input name="name" type="text" maxlength="255" required>
</div>
{{template "base/modal_actions_confirm" (dict "ModalButtonTypes" "confirm")}}
</form>
</div>
<div class="ui small modal" id="delete-registration">
<div class="header">
{{svg "octicon-trash"}}