v0.6.0 d5cc8fe

token.go RawHistoryFolder

1// SPDX-License-Identifier: AGPL-3.0-or-later
2
3package domain
4
5import (
6	"crypto/sha256"
7	"encoding/hex"
8	"fmt"
9	"slices"
10	"time"
11)
12
13// TokenSecretPrefix starts every token secret.
14const TokenSecretPrefix = "ermite_"
15
16// Scope is one permission of a stored token.
17type Scope string
18
19// The scopes of ADR 0006. The last three only matter after v1 and are defined
20// now so that the token format never changes.
21const (
22	// ScopeRepoRead reads private repositories.
23	ScopeRepoRead Scope = "repo:read"
24	// ScopeRepoWrite pushes and creates a repository on first push.
25	ScopeRepoWrite Scope = "repo:write"
26	// ScopeRepoAdmin deletes a repository and changes its visibility or description.
27	ScopeRepoAdmin Scope = "repo:admin"
28	// ScopeMRWrite creates, comments on and closes merge requests.
29	ScopeMRWrite Scope = "mr:write"
30	// ScopeMRMerge merges, and deletes the merged source branch on request.
31	ScopeMRMerge Scope = "mr:merge"
32	// ScopeCIWrite re-runs or cancels CI runs.
33	ScopeCIWrite Scope = "ci:write"
34	// ScopeSecretsWrite sets and deletes secrets and variables.
35	ScopeSecretsWrite Scope = "secrets:write"
36	// ScopeRunnerRegister registers a CI runner.
37	ScopeRunnerRegister Scope = "runner:register"
38	// ScopeTokenAdmin creates, lists and revokes stored tokens.
39	ScopeTokenAdmin Scope = "token:admin"
40)
41
42// AllScopes returns the nine scopes in a stable order.
43func AllScopes() []Scope {
44	return []Scope{
45		ScopeRepoRead, ScopeRepoWrite, ScopeRepoAdmin,
46		ScopeMRWrite, ScopeMRMerge,
47		ScopeCIWrite, ScopeSecretsWrite, ScopeRunnerRegister,
48		ScopeTokenAdmin,
49	}
50}
51
52// ParseScope parses the text form of a scope, such as "repo:read".
53func ParseScope(s string) (Scope, error) {
54	sc := Scope(s)
55	if slices.Contains(AllScopes(), sc) {
56		return sc, nil
57	}
58	return "", fmt.Errorf("%w: %q", ErrInvalidScope, s)
59}
60
61// String returns the scope as text.
62func (s Scope) String() string { return string(s) }
63
64// TokenHash is the SHA-256 of a token secret. Secrets are never stored.
65type TokenHash [sha256.Size]byte
66
67// HashTokenSecret returns the hash of a token secret.
68func HashTokenSecret(secret string) TokenHash { return sha256.Sum256([]byte(secret)) }
69
70// String returns the hash as lowercase hex.
71func (h TokenHash) String() string { return hex.EncodeToString(h[:]) }
72
73// Token is a stored credential: what it may do, where, and until when.
74type Token struct {
75	// ID identifies the token; it is not secret.
76	ID    string
77	Label string
78	Hash  TokenHash
79	// Scopes is never empty.
80	Scopes []Scope
81	// Repos limits the token to these repositories; empty means every one.
82	Repos []RepoName
83	// ExpiresAt is the zero time for a token that never expires.
84	ExpiresAt  time.Time
85	CreatedAt  time.Time
86	LastUsedAt time.Time // zero until first used
87}
88
89// Expired reports whether the token is no longer valid at now.
90func (t Token) Expired(now time.Time) bool {
91	return !t.ExpiresAt.IsZero() && !now.Before(t.ExpiresAt)
92}

Keyboard shortcuts

Single-key shortcuts are on. ctrl k and esc work whatever this says.

ctrl k :
go to a section, branch, tag, file or repository
?
this list
j k
move the row cursor down / up
enter
open the row under the cursor; on Files, a directory opens or closes in place
↑ ↓ ← → home end
in the file tree (focus on a row): previous / next row, close / open a directory or go to its parent / first entry, first / last row. They never open a file
l h
on Files: open a directory or a file / close a directory or go up to its parent, then to the parent page. Elsewhere: into the side panel (on a merge request, its files) / back to the content; there j k move between its controls
g g G
first / last row
/
filter the list; on Files, find a file anywhere in the repository (esc clears, enter opens the best match)
b
switch branch or tag
g s g f g c g b g m g i g r g a
tabs: summary, files, commits, branches & tags, merge requests, issues, releases, actions (when available)
g h
home
w
wide mode: use the whole width of the screen, or not (remembered)
y
copy a permalink pinned to the commit
d u x
diff: split / unified / collapse or expand all
e E
diff: the whole file in view / every file, with the lines the hunks hide
n
merge request: next note in the diff
esc
close a dialog, leave a field

Branches 3

Tags 43

↑↓ moveenter openesc close