auth

package
v1.0.1 Latest Latest
Warning

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

Go to latest
Published: Aug 23, 2026 License: AGPL-3.0 Imports: 11 Imported by: 0

Documentation

Overview

Package auth password-protects the dashboard and API.

The model follows LAN Orangutan's, so that the two siblings behave the same way: a fresh install has no password; when the server is reachable from the network, the first visitor must create one before anything is shown; after that a password is exchanged for a session cookie.

Bound to loopback only, no password is required, a dashboard nothing else can reach is already private, and demanding a password would be friction with no benefit. That default is what keeps the zero-configuration promise intact.

This differs from Orangutan in one respect: LAN Sheriff's front end is a single-page app, so setup and login are JSON endpoints the app calls rather than server-rendered form pages with redirects.

Index

Constants

View Source
const (
	// SessionCookie holds the session token.
	SessionCookie = "sheriff_session"

	// MinPasswordLength is the shortest password setup accepts.
	MinPasswordLength = 8

	// MaxPasswordBytes is bcrypt's own limit. It is checked here so the failure
	// can be explained in plain terms rather than surfacing the library's
	// "password length exceeds 72 bytes".
	MaxPasswordBytes = 72

	// DefaultSessionTTL is how long a login lasts.
	DefaultSessionTTL = 7 * 24 * time.Hour
)

Variables

View Source
var ErrPasswordAlreadySet = errors.New("a password has already been set")

ErrPasswordAlreadySet reports that a password existed by the time a first-run setup got as far as storing one.

Functions

func IsHash

func IsHash(s string) bool

IsHash reports whether s looks like a bcrypt hash rather than a plaintext password.

func LoadHash

func LoadHash(path string) string

LoadHash reads a stored password hash. A missing file is not an error: it means no password has been set.

func SaveHash

func SaveHash(path, hash string) error

SaveHash writes a password hash to disk, readable only by its owner.

func ValidatePassword

func ValidatePassword(password string) error

ValidatePassword reports whether a proposed password is acceptable.

Types

type Authenticator

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

Authenticator guards the API with a password.

func New

func New(password string, sessionTTL time.Duration) (*Authenticator, error)

New creates an Authenticator. password may be a plaintext password or an existing bcrypt hash, so a stored hash can be passed straight through.

func (*Authenticator) Authenticated

func (a *Authenticator) Authenticated(token string) bool

Authenticated reports whether a request carries a valid, unexpired session.

func (*Authenticator) Enabled

func (a *Authenticator) Enabled() bool

Enabled reports whether a password is currently set.

func (*Authenticator) LockedOut

func (a *Authenticator) LockedOut(remoteAddr string) bool

LockedOut reports whether an address has failed too many logins recently.

func (*Authenticator) Login

func (a *Authenticator) Login(remoteAddr, password string) (string, bool)

Login verifies a password and, on success, returns a new session token.

func (*Authenticator) Logout

func (a *Authenticator) Logout(token string)

Logout invalidates a session token.

func (*Authenticator) NeedsSetup

func (a *Authenticator) NeedsSetup() bool

NeedsSetup reports whether a password still has to be created.

func (*Authenticator) SessionTTL

func (a *Authenticator) SessionTTL() time.Duration

SessionTTL is how long a login lasts.

func (*Authenticator) SetInitialPassword

func (a *Authenticator) SetInitialPassword(plaintext string) (string, error)

SetInitialPassword establishes the *first* password, and only if there is not one already. This is what first-run setup must call.

The check and the assignment happen under a single lock, which is the entire point of the method. Setup used to be a NeedsSetup call in the HTTP handler followed by a separate SetPassword, and those are two acquisitions with a gap between them. Twelve simultaneous setup requests all passed the check before any of them assigned: every one of the twelve was answered with success, the last to finish owned the password, and whoever arrived first was handed a session cookie that quietly stopped working some minutes later.

On a bind reachable from the network that gap is the difference between two very different models. "Whoever gets there first wins" is the documented one, and it is defensible: the dashboard is unreachable until someone claims it. "Whoever is still in flight last wins" is what the code actually did, and it lets a stranger who merely holds requests open take an install away from the person sitting in front of the machine, while telling that person setup succeeded.

bcrypt runs before the lock is taken rather than inside it. It costs roughly a tenth of a second, and holding the mutex across it would park every session check in the server behind an unauthenticated stranger's request, which is a denial of service offered up for free. The cost is that a loser has burned a hash for nothing, and that is exactly the right thing to waste.

func (*Authenticator) SetPassword

func (a *Authenticator) SetPassword(plaintext string) (string, error)

SetPassword replaces the password unconditionally, and returns its hash so the caller can persist it.

For *changing* a password that already exists. First-run setup must use SetInitialPassword instead: this one overwrites whatever is there, so on the setup path it is the race described above. Any caller added here has to establish that the person asking already holds the current password.

func (*Authenticator) SetSetupRequired

func (a *Authenticator) SetSetupRequired(required bool)

SetSetupRequired controls what happens when no password is set: either the user must create one, or access is open.

func (*Authenticator) StartSession

func (a *Authenticator) StartSession() (string, bool)

StartSession issues a session without checking a password, so that completing setup signs the user in rather than bouncing them to a login form for the password they just chose.

Jump to

Keyboard shortcuts

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