session

package
v1.3.0 Latest Latest
Warning

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

Go to latest
Published: Aug 15, 2026 License: MIT Imports: 9 Imported by: 0

Documentation

Index

Constants

This section is empty.

Variables

View Source
var ErrOutsideHome = errors.New("path is outside home directory")

ErrOutsideHome is returned by Register when a file resolves to a path outside the user's home directory. Callers use it to surface a clear user-facing error.

Functions

func ContainWithinHome

func ContainWithinHome(home, child string) (string, bool)

ContainWithinHome reports whether child is strictly inside home. When it is, it returns child rebuilt with home's exact casing on the prefix, so derived relative paths and map keys stay stable no matter how child was cased (e.g. a lowercase Windows drive letter, or macOS symlink resolution that preserves input casing). The containment test folds case on case-insensitive platforms and is exact on case-sensitive ones (Linux).

func EqualOrUnder added in v1.2.0

func EqualOrUnder(child, parent string) bool

EqualOrUnder reports whether child is parent or sits below it, folding case on the platforms whose filesystem ignores it.

It exists so forbidden-root guards cannot disagree with ContainWithinHome about whether two spellings name the same directory. A plain byte-wise strings.HasPrefix is wrong here: filepath.EvalSymlinks preserves the caller's spelling of non-symlink components, so on macOS the same directory reaches a guard as both "Library/Application Support" and "library/application support" and a case-sensitive test waves the second one through.

func HasHiddenComponent added in v1.2.0

func HasHiddenComponent(home, path string) bool

HasHiddenComponent reports whether any component of path below home starts with a dot. It keeps grants and asset reads away from ~/.ssh, ~/.git, ~/.config, and the like.

func SamePathComponent added in v1.2.0

func SamePathComponent(a, b string) bool

SamePathComponent reports whether two single path components name the same thing, folding case on case-insensitive platforms. It exists so the broker's LCA computation agrees with the rest of the authorization code about casing: a byte-wise comparison split one real directory into two on macOS and could grant a broader ancestor than the assets needed.

Types

type File

type File struct {
	Token   string
	AbsPath string
	RelPath string
	Name    string
	// contains filtered or unexported fields
}

func (*File) HistoryKey added in v1.2.0

func (f *File) HistoryKey() string

HistoryKey returns this file's resolved backup identity, or "" if it has not been resolved yet. Caller must hold Lock().

func (*File) LastServerWrite added in v1.2.0

func (f *File) LastServerWrite() string

LastServerWrite returns the hash of the bytes this server last wrote. Caller must hold Lock().

func (*File) LastStableObservation added in v1.2.0

func (f *File) LastStableObservation() string

LastStableObservation returns the hash of the content last confirmed stable on disk. Caller must hold Lock().

func (*File) Lock

func (f *File) Lock()

Lock and Unlock serialize read-modify-write operations on this file (saves, restores, and on-serve htmlclayid injection) so concurrent handlers cannot clobber each other. They also guard the two per-file records.

func (*File) NoteFirstObservation added in v1.2.0

func (f *File) NoteFirstObservation(hash string) bool

NoteFirstObservation seeds both records the first time a file is read, so the first save of a file the server has never written does not false-positive as a stale write. It reports whether this was the first observation. Caller must hold Lock().

func (*File) Observed added in v1.2.0

func (f *File) Observed() bool

Observed reports whether this server has ever written or first-observed this file, which is what makes the very first save comparable.

It is derived from lastServerWrite rather than stored, deliberately. As a stored flag it was a third per-file record, and a load-bearing one: it gates clone resolution and the first-open snapshot. The watcher could set it for a file that had never been served (an origin-trusted SSE subscription may name any registered path), and that file's first real GET then skipped both. Since the normative table says lastServerWrite is never set by the watcher and never set by serving a page, deriving from it makes the watcher structurally unable to mark a file observed. Caller must hold Lock().

func (*File) RecordServerWrite added in v1.2.0

func (f *File) RecordServerWrite(hash string)

RecordServerWrite advances both records. Caller must hold Lock().

func (*File) RecordStableObservation added in v1.2.0

func (f *File) RecordStableObservation(hash string)

RecordStableObservation advances only the stable-observation record, which is what the watcher does after confirming a stable external read. Caller must hold Lock().

func (*File) SetHistoryKey added in v1.2.0

func (f *File) SetHistoryKey(key string)

SetHistoryKey records the backup identity the first time it is resolved and then refuses to move it. Every list, read, restore and save path reads the stored key rather than recomputing one from whatever is on disk right now. Caller must hold Lock().

func (*File) Unlock

func (f *File) Unlock()

type Manager

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

func NewManager

func NewManager() (*Manager, error)

func NewManagerWithHome

func NewManagerWithHome(homeDir string) *Manager

func (*Manager) AssetRoot added in v1.1.1

func (m *Manager) AssetRoot(absPath string) (root, rel string, ok bool)

AssetRoot returns the read root that authorizes absPath and absPath's path relative to that root, in the root's canonical casing. A read root is either the folder of an opened file or a folder the user granted. When roots nest, the MOST SPECIFIC (longest) containing root wins, so the result is deterministic regardless of map order.

func (*Manager) AssetRootOpened added in v1.2.0

func (m *Manager) AssetRootOpened(absPath string) (root, rel string, opened, ok bool)

AssetRootOpened is AssetRoot plus whether the winning root exists because the user explicitly opened a file in it, rather than only because of a grant. Site routing prefers an opened root so a read-only grant never pulls a later explicit open into the granting origin, where an already-running page could lift the new file's save token.

func (*Manager) CanGrant added in v1.2.0

func (m *Manager) CanGrant(dir string) bool

CanGrant reports whether dir could be granted as a read root: strictly inside home, no hidden component, and not vetoed by the guard (config/versions tree). The broker calls this before prompting so it never raises a dialog for a folder that GrantReadRoot would then refuse (e.g. macOS ~/Library, which swallows the config dir). It does not resolve symlinks, and the broker deliberately calls it with the LEXICAL least-common-ancestor: resolving before this gate would let a folder that fails to resolve answer differently from one that succeeds, which is the existence oracle. Resolution happens afterwards, in decide, where it can only change which folder is named and granted, never whether the user is asked.

func (*Manager) GrantCanonicalRoot added in v1.2.0

func (m *Manager) GrantCanonicalRoot(canonical string) error

GrantCanonicalRoot installs an already symlink-resolved directory as a granted read root, keyed by exactly the path given. The broker resolves the folder once and passes the result here, so the dialog it showed, the log line, the tray entry, and the installed capability all name the same directory. Resolving again here would let a swap between the prompt and the install bind the capability to a directory the user never saw.

func (*Manager) GrantReadRoot added in v1.2.0

func (m *Manager) GrantReadRoot(dir string) error

GrantReadRoot widens a session's reads to dir (read-only), the operation a granted permission performs.

func (*Manager) HomeDir

func (m *Manager) HomeDir() string

func (*Manager) InstallTrustedRoot added in v1.2.0

func (m *Manager) InstallTrustedRoot(canonical string) error

InstallTrustedRoot installs an ALREADY-canonical trusted folder (resolved, home-validated and identity-checked by the caller at trust time) as a silent capability over its whole tree, with its own provenance so untrusting never disturbs a root an open or a grant also created. Unlike every other root kind this one is write-granting: files under it auto-register and mint save tokens.

It deliberately does NOT re-resolve symlinks. The caller's stored path is the folder's identity; re-running EvalSymlinks on it could, if a component were swapped for a symlink in between, open a different tree under a key that no longer matches the stored path and so could never be revoked. The path is still re-validated (inside home, no hidden component, not guard-vetoed) so a stale or tampered config entry can never install a forbidden root.

func (*Manager) Lookup

func (m *Manager) Lookup(token string) (*File, bool)

func (*Manager) LookupByPath

func (m *Manager) LookupByPath(absPath string) (*File, bool)

func (*Manager) OpenAsset added in v1.2.0

func (m *Manager) OpenAsset(absPath string) (file *os.File, authorized bool, err error)

OpenAsset opens absPath for reading through the held capability of the most specific read root that authorizes it, and reports whether any root authorized it at all. The returned *os.File is an independent descriptor the caller closes; the root handle stays owned by the manager. The open happens under the read lock, so RevokeReadRoot / RevokeAll (write lock) cannot close the handle mid-open, and reading through the handle keeps a directory component swapped for a symlink after authorization from escaping the root.

func (*Manager) Register

func (m *Manager) Register(absPath string, via Provenance) (*File, error)

func (*Manager) Registrations added in v1.3.0

func (m *Manager) Registrations() []RegistrationInfo

Registrations returns a snapshot of every registration and its provenance.

func (*Manager) RevokeAll

func (m *Manager) RevokeAll()

func (*Manager) RevokeReadRoot added in v1.2.0

func (m *Manager) RevokeReadRoot(dir string)

RevokeReadRoot withdraws a grant (used by the tray's per-root revoke). A root that also exists because the user explicitly opened a file in it, or because it was seeded from a trusted folder, survives with that provenance intact: revoking a grant must never take away the capability an open or trust created.

func (*Manager) RevokeTrustedRoot added in v1.2.0

func (m *Manager) RevokeTrustedRoot(dir string)

RevokeTrustedRoot withdraws a trusted root when the user untrusts its folder. dir must be the canonical trusted-folder path (the same value InstallTrustedRoot keyed on). A root the open or a grant also created survives with that provenance intact.

func (*Manager) SetGuard added in v1.2.0

func (m *Manager) SetGuard(guard func(dir string) bool)

SetGuard installs the predicate that vetoes granted read roots. Call it once, at construction, before the manager serves any request.

func (*Manager) TrustedCovers added in v1.3.0

func (m *Manager) TrustedCovers(absPath string) bool

TrustedCovers reports whether an installed trusted root covers absPath. Saves re-check this at write time for trusted-provenance registrations, so untrusting a folder genuinely ends its write capability even for a session that was already minted and looked up.

func (*Manager) Unregister added in v1.3.0

func (m *Manager) Unregister(absPath string) bool

Unregister withdraws absPath's registration: the token dies immediately, and the opened root the registration installed is dropped when no other registered file in that directory needs it and no other provenance (grant, trust) holds the root. It reports whether a registration was removed. Live-sync subscribers for the path are the caller's to tear down; the session manager does not know the hub.

func (*Manager) Via added in v1.3.0

func (m *Manager) Via(absPath string) Provenance

Via reports the accumulated provenance of the registration at absPath, or 0 when absPath is not registered.

type Provenance added in v1.3.0

type Provenance uint8

Provenance records how a file's registration came to exist, as independent accumulating flags rather than one value. A file can be more than one thing at once — OS-opened AND covered by a trusted folder — and collapsing that into a single enum repeats the bug root provenance already fixed (see readRoot): revoking one origin of the capability silently destroyed the other's.

const (
	// ViaOsOpen: the user opened the file itself (double-click, drag, CLI, or
	// the open-file event). The most deliberate act, and the only provenance
	// that may request trust for its own folder without the request saying it
	// was reached by a link.
	ViaOsOpen Provenance = 1 << iota
	// ViaTrusted: the file auto-registered because it sits under a declared
	// trusted folder. Grants no opened read root of its own; reads and the save
	// capability ride the trusted root and end with it.
	ViaTrusted
)

func (Provenance) Has added in v1.3.0

func (p Provenance) Has(flag Provenance) bool

type RegistrationInfo added in v1.3.0

type RegistrationInfo struct {
	Path string
	Via  Provenance
}

RegistrationInfo is a snapshot of one registration, for the tray and for provenance-aware revocation sweeps.

Jump to

Keyboard shortcuts

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