mirror of
https://codeberg.org/forgejo/forgejo.git
synced 2026-02-19 03:17:49 -05:00
fix(ui): document token validity in key verification view (#9002)
Some checks are pending
/ release (push) Waiting to run
testing-integration / test-unit (push) Waiting to run
testing-integration / test-sqlite (push) Waiting to run
testing-integration / test-mariadb (v10.6) (push) Waiting to run
testing-integration / test-mariadb (v11.8) (push) Waiting to run
testing / backend-checks (push) Waiting to run
testing / frontend-checks (push) Waiting to run
testing / test-unit (push) Blocked by required conditions
testing / test-e2e (push) Blocked by required conditions
testing / test-remote-cacher (redis) (push) Blocked by required conditions
testing / test-remote-cacher (valkey) (push) Blocked by required conditions
testing / test-remote-cacher (garnet) (push) Blocked by required conditions
testing / test-remote-cacher (redict) (push) Blocked by required conditions
testing / test-mysql (push) Blocked by required conditions
testing / test-pgsql (push) Blocked by required conditions
testing / test-sqlite (push) Blocked by required conditions
testing / security-check (push) Blocked by required conditions
Some checks are pending
/ release (push) Waiting to run
testing-integration / test-unit (push) Waiting to run
testing-integration / test-sqlite (push) Waiting to run
testing-integration / test-mariadb (v10.6) (push) Waiting to run
testing-integration / test-mariadb (v11.8) (push) Waiting to run
testing / backend-checks (push) Waiting to run
testing / frontend-checks (push) Waiting to run
testing / test-unit (push) Blocked by required conditions
testing / test-e2e (push) Blocked by required conditions
testing / test-remote-cacher (redis) (push) Blocked by required conditions
testing / test-remote-cacher (valkey) (push) Blocked by required conditions
testing / test-remote-cacher (garnet) (push) Blocked by required conditions
testing / test-remote-cacher (redict) (push) Blocked by required conditions
testing / test-mysql (push) Blocked by required conditions
testing / test-pgsql (push) Blocked by required conditions
testing / test-sqlite (push) Blocked by required conditions
testing / security-check (push) Blocked by required conditions
Document that the token is only valid for a minute. Add a link to get a new token. Resolves #8048 Co-authored-by: 0ko <0ko@noreply.codeberg.org> Co-authored-by: Gusted <postmaster@gusted.xyz> Reviewed-on: https://codeberg.org/forgejo/forgejo/pulls/9002 Reviewed-by: Gusted <gusted@noreply.codeberg.org> Co-authored-by: dawe <dawedawe@posteo.de> Co-committed-by: dawe <dawedawe@posteo.de>
This commit is contained in:
parent
bcd03d0e0d
commit
efd4d2d8f5
5 changed files with 61 additions and 0 deletions
|
|
@ -52,3 +52,9 @@ func MockProtect[T any](p *T) (reset func()) {
|
|||
func SleepTillNextSecond() {
|
||||
time.Sleep(time.Second - time.Since(time.Now().Truncate(time.Second)))
|
||||
}
|
||||
|
||||
// When this is called, sleep until the truncated unix time to a minute was
|
||||
// increased by one.
|
||||
func SleepTillNextMinute() {
|
||||
time.Sleep(time.Minute - time.Since(time.Now().Truncate(time.Minute)))
|
||||
}
|
||||
|
|
|
|||
|
|
@ -109,6 +109,7 @@
|
|||
"feed.atom.link": "Atom feed",
|
||||
"keys.ssh.link": "SSH keys",
|
||||
"keys.gpg.link": "GPG keys",
|
||||
"keys.verify.token.hint": "The token is only valid for 1 minute. <a href=\"%[1]s\">Get a new one if it expired</a>.",
|
||||
"admin.config.moderation_config": "Moderation configuration",
|
||||
"admin.moderation.moderation_reports": "Moderation reports",
|
||||
"admin.moderation.reports": "Reports",
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@
|
|||
<div class="field">
|
||||
<label for="token">{{ctx.Locale.Tr "settings.gpg_token"}}</label>
|
||||
<input readonly="" value="{{.TokenToSign}}">
|
||||
<span class="help">{{ctx.Locale.Tr "keys.verify.token.hint" (printf "?verify_gpg=%s" .KeyID)}}</span>
|
||||
<div class="help">
|
||||
<p>{{ctx.Locale.Tr "settings.gpg_token_help"}}</p>
|
||||
<p><code>{{printf `echo "%s" | gpg -a --default-key %s --detach-sig` .TokenToSign .PaddedKeyID}}</code></p>
|
||||
|
|
@ -88,6 +89,7 @@
|
|||
<div class="field">
|
||||
<label for="token">{{ctx.Locale.Tr "settings.gpg_token"}}</label>
|
||||
<input readonly="" value="{{$.TokenToSign}}">
|
||||
<span class="help">{{ctx.Locale.Tr "keys.verify.token.hint" (printf "?verify_gpg=%s" .KeyID)}}</span>
|
||||
<div class="help">
|
||||
<p>{{ctx.Locale.Tr "settings.gpg_token_help"}}</p>
|
||||
<p><code>{{printf `echo "%s" | gpg -a --default-key %s --detach-sig` $.TokenToSign .PaddedKeyID}}</code></p>
|
||||
|
|
|
|||
|
|
@ -74,6 +74,7 @@
|
|||
<div class="field">
|
||||
<label for="token">{{ctx.Locale.Tr "settings.ssh_token"}}</label>
|
||||
<input readonly="" value="{{$.TokenToSign}}">
|
||||
<span class="help">{{ctx.Locale.Tr "keys.verify.token.hint" (printf "?verify_ssh=%s" .Fingerprint)}}</span>
|
||||
<div class="help">
|
||||
<br>
|
||||
<p>{{ctx.Locale.Tr "settings.ssh_token_help"}}</p>
|
||||
|
|
|
|||
51
tests/integration/user_keys_test.go
Normal file
51
tests/integration/user_keys_test.go
Normal file
|
|
@ -0,0 +1,51 @@
|
|||
// Copyright 2025 The Forgejo Authors. All rights reserved.
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
package integration
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"forgejo.org/modules/test"
|
||||
"forgejo.org/tests"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestVerifySSHkeyPage(t *testing.T) {
|
||||
defer tests.PrepareTestEnv(t)()
|
||||
|
||||
// user2 has an SSH key in fixtures to test this on
|
||||
session := loginUser(t, "user2")
|
||||
|
||||
page := NewHTMLParser(t, session.MakeRequest(t, NewRequest(t, "GET", "/user/settings/keys"), http.StatusOK).Body)
|
||||
link, exists := page.Find("#keys-ssh a.button[href^='?verify_ssh=']").Attr("href")
|
||||
assert.True(t, exists)
|
||||
|
||||
page = NewHTMLParser(t, session.MakeRequest(t, NewRequest(t, "GET", fmt.Sprintf("/user/settings/keys%s", link)), http.StatusOK).Body)
|
||||
|
||||
// QueryUnescape the link for selector matching
|
||||
link, err := url.QueryUnescape(link)
|
||||
require.NoError(t, err)
|
||||
|
||||
// The hint contains a link to the same page the user is at now to get it reloaded if followed
|
||||
page.AssertElement(t, fmt.Sprintf("#keys-ssh form[action='/user/settings/keys'] .help a[href='%s']", link), true)
|
||||
|
||||
// The token changes every minute, we can avoid this sleep via timeutil and mocking.
|
||||
test.SleepTillNextMinute()
|
||||
|
||||
// Verify that if you refresh it via the link another token is shown.
|
||||
token, exists := page.Find("#keys-ssh form input[readonly]").Attr("value")
|
||||
assert.True(t, exists)
|
||||
|
||||
link = url.QueryEscape(strings.TrimPrefix(link, "?verify_ssh="))
|
||||
page = NewHTMLParser(t, session.MakeRequest(t, NewRequestf(t, "GET", "/user/settings/keys?verify_ssh=%s", link), http.StatusOK).Body)
|
||||
otherToken, exists := page.Find("#keys-ssh form .field input[readonly]").Attr("value")
|
||||
assert.True(t, exists)
|
||||
assert.NotEqual(t, token, otherToken)
|
||||
}
|
||||
Loading…
Reference in a new issue