access

package
v0.0.0-...-b43479a Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Aug 3, 2026 License: MIT Imports: 17 Imported by: 0

Documentation

Overview

Package access is Eta's optional browser-session login. It is off by default: an Eta instance with no password configured behaves exactly as before, matching the LAN/Tailscale trust boundary the rest of the product assumes. Setting a password gates the desktop UI and this machine's API behind a login, for the case where the LAN itself is not fully trusted (a shared network, a guest VLAN, a NAS closet someone else can plug into).

The password never reaches the server. The browser derives a PBKDF2 verifier client-side and the server only ever sees that verifier, so a disk read or a request log can't leak the password itself. See web/app.ts's auth section for the client half, and Manager.Login for the challenge/response the two sides share.

Index

Constants

View Source
const (
	PasswordHashVersion    = "v1"
	PasswordHashAlgorithm  = "pbkdf2-sha256"
	PasswordHashIterations = 600_000

	SessionTTL    = 365 * 24 * time.Hour
	SessionCookie = "eta_access_session"
)

Variables

View Source
var (
	ErrUnauthorized = errors.New("access authentication required")
	ErrRateLimited  = errors.New("too many failed password attempts; try again shortly")
)

Functions

func DefaultPath

func DefaultPath() (string, error)

DefaultPath returns the per-user config path, alongside identity.json and state.json.

func DeriveVerifier

func DeriveVerifier(password string, salt []byte) []byte

DeriveVerifier runs the same PBKDF2-HMAC-SHA256 the browser runs. No production code path calls it: a peer's password is derived in the browser too (see web/app.ts's derivePeerVerifier, and handlePeerAuthStatus in main.go, which exists so the browser can fetch a peer's salt without contacting that peer directly). A password does not pass through this server in plaintext for its own login or for a peer's. Kept as an exported function because tests need a Go-side way to construct a valid verifier without a browser to derive one.

func ParsePasswordHash

func ParsePasswordHash(encoded string) (*passwordRecord, error)

ParsePasswordHash accepts the only verifier format this package writes. The browser derives the verifier; the server stores it without ever receiving the raw password. The salt and iteration count are public KDF parameters; the verifier is the secret and is never returned by an API.

func Save

func Save(path string, cfg Config) error

Save writes atomically: a partial write from a killed process must never leave access.json holding half a JSON document, which would lock the owner out on the next start with no way back in except deleting the file by hand.

Types

type Config

type Config struct {
	PasswordHash string `json:"password_hash,omitempty"`
}

Config is the on-disk shape. PasswordHash is the encoded verifier record (see ParsePasswordHash), never the raw password.

func Load

func Load(path string) (Config, error)

type Manager

type Manager struct {
	// contains filtered or unexported fields
}

Manager holds one instance's access password state: the configured verifier, in-flight login challenges, live sessions, and a per-client failed-attempt backoff. All in memory — a restart resets sessions and backoff state, matching the no-account, no-database design; only the password verifier itself persists, via Config.

func NewManager

func NewManager() *Manager

func (*Manager) Authenticated

func (m *Manager) Authenticated(r *http.Request) bool

func (*Manager) Configure

func (m *Manager) Configure(encoded string) error

func (*Manager) Enabled

func (m *Manager) Enabled() bool

func (*Manager) EncodedVerifier

func (m *Manager) EncodedVerifier() string

EncodedVerifier returns the on-disk form of the configured password verifier (the format ParsePasswordHash accepts), or "" when no password is configured. Used by the SSH setup path to forward the same access control to a freshly installed remote eta.

func (*Manager) Login

func (m *Manager) Login(challenge, proof, remoteAddr string) (string, error)

func (*Manager) StatusAndChallenge

func (m *Manager) StatusAndChallenge() (enabled bool, salt, challenge string, err error)

StatusAndChallenge returns public KDF parameters and a single-use login challenge from one locked snapshot, so a concurrent password change cannot pair an old salt with a challenge for the new verifier.

func (*Manager) UpdatePassword

func (m *Manager) UpdatePassword(encoded string, authorized bool) (token string, revokeLiveConnections bool, err error)

UpdatePassword atomically prevents an unauthenticated caller from replacing a password that became enabled between middleware evaluation and this handler running. A new verifier invalidates all prior sessions.

func (*Manager) ValidSession

func (m *Manager) ValidSession(token string) bool

ValidSession checks a bare session token, for callers that carry it somewhere other than this server's own cookie jar — a peer's proxied request forwards the token it was issued, not a browser cookie read from this request.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL