v0.3.0 0a8834d

config.go RawHistoryFolder

1package ports
2
3import (
4	"fmt"
5	"strings"
6	"time"
7	"unicode"
8	"unicode/utf8"
9)
10
11const MaxDuration = 24 * time.Hour
12
13// Zero After disables only that action. No deadline implies another action.
14type Config struct {
15	LockAfter, FadeAfter, OffAfter, SleepAfter time.Duration
16	FadeDuration                               time.Duration
17	Auth                                       AuthConfig
18}
19type AuthMode string
20
21const (
22	AuthModePassword AuthMode = "password"
23	AuthModePIN      AuthMode = "pin"
24)
25
26type PINSource string
27
28const (
29	PINSourceEnv  PINSource = "env"
30	PINSourcePass PINSource = "pass"
31)
32
33// Only metadata: values resolved by the visual/auth worker never reach policy.
34// PIN mode always falls back to PAM when its selected source is unavailable or
35// invalid. A wrong PIN is authentication failure, never a fallback trigger.
36type AuthConfig struct {
37	Mode             AuthMode
38	PINSource        PINSource
39	PINEnv, PINEntry string
40}
41
42func Defaults() Config {
43	return Config{LockAfter: 5 * time.Minute, FadeAfter: 6 * time.Minute, FadeDuration: 2 * time.Second, OffAfter: 7 * time.Minute, SleepAfter: 20 * time.Minute, Auth: AuthConfig{Mode: AuthModePassword}}
44}
45func (c Config) Validate() error {
46	for _, d := range []time.Duration{c.LockAfter, c.FadeAfter, c.OffAfter, c.SleepAfter, c.FadeDuration} {
47		if d < 0 || d > MaxDuration {
48			return fmt.Errorf("duration outside 0..24h")
49		}
50	}
51	a := c.Auth
52	for _, r := range []string{string(a.Mode), string(a.PINSource), a.PINEnv, a.PINEntry} {
53		if !utf8.ValidString(r) {
54			return fmt.Errorf("auth metadata is not valid UTF-8")
55		}
56	}
57	if a.Mode != AuthModePassword && a.Mode != AuthModePIN {
58		return fmt.Errorf("unknown auth mode")
59	}
60	for _, r := range []string{a.PINEnv, a.PINEntry} {
61		if len(r) > 4096 {
62			return fmt.Errorf("auth metadata too large")
63		}
64		for _, c := range r {
65			if unicode.IsControl(c) {
66				return fmt.Errorf("control character in auth metadata")
67			}
68		}
69	}
70	if a.PINEnv != "" {
71		for i, r := range a.PINEnv {
72			if !(r == '_' || r >= 'A' && r <= 'Z' || r >= 'a' && r <= 'z' || i > 0 && r >= '0' && r <= '9') {
73				return fmt.Errorf("invalid environment reference")
74			}
75		}
76	}
77	if a.PINEntry != "" {
78		if strings.HasPrefix(a.PINEntry, "-") || strings.HasPrefix(a.PINEntry, "/") || strings.Contains(a.PINEntry, "\\") {
79			return fmt.Errorf("invalid pass entry")
80		}
81		for _, part := range strings.Split(a.PINEntry, "/") {
82			if part == "" || part == "." || part == ".." {
83				return fmt.Errorf("invalid pass entry")
84			}
85		}
86	}
87	switch a.PINSource {
88	case "":
89		if a.Mode == AuthModePIN || a.PINEnv != "" || a.PINEntry != "" {
90			return fmt.Errorf("PIN metadata requires source")
91		}
92	case PINSourceEnv:
93		if a.PINEnv == "" || a.PINEntry != "" {
94			return fmt.Errorf("env source requires only pin-env")
95		}
96	case PINSourcePass:
97		if a.PINEntry == "" || a.PINEnv != "" {
98			return fmt.Errorf("pass source requires only pin-entry")
99		}
100	default:
101		return fmt.Errorf("unknown PIN source")
102	}
103	return nil
104}
105
106type ConfigChanged struct{ Config Config }

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 2

Tags 9

↑↓ moveenter openesc close