userstore

package
v0.6.6 Latest Latest
Warning

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

Go to latest
Published: Jul 31, 2026 License: MIT Imports: 11 Imported by: 0

Documentation

Overview

Package userstore is a SQLite-backed store for users, personal access tokens, per-repo memberships, and invite keys. The git-backed repo content itself lives in gitstore — userstore only owns access metadata.

Index

Constants

View Source
const (
	RoleOwner  = "owner"
	RoleMember = "member"
)

RoleOwner has full control of a repo (mint invite keys, delete repo). RoleMember can read and write pages.

View Source
const InviteKeyPrefix = "ctxi_"

InviteKeyPrefix marks raw repo invite keys (separates them from PATs at a glance).

View Source
const PATPrefix = "ctxp_"

PATPrefix is prepended to every personal access token's raw value so they are visually distinct from session JWTs / invite keys when leaked.

Variables

View Source
var ErrExpired = errors.New("userstore: invite key expired")

ErrExpired is returned when an invite key exists but has passed its expiry.

View Source
var ErrLastOwner = errors.New("userstore: cannot remove the last owner")

ErrLastOwner is returned when removing a member would leave a repo with no owner.

View Source
var ErrNotFound = errors.New("userstore: not found")

ErrNotFound is returned when a lookup misses.

Functions

This section is empty.

Types

type Activity

type Activity struct {
	UserID    string
	Email     string
	Action    string
	Detail    string
	CreatedAt time.Time
}

Activity is one recorded member action (push/pull) on a repo. Email is joined in from the users table by ListActivity. Detail is an opaque JSON blob (pushed paths for "push", client/agent for "pull"); "" when absent.

type InviteKey

type InviteKey struct {
	ID        string
	RepoID    string
	Label     string
	CreatedBy string
	CreatedAt time.Time
	ExpiresAt time.Time
}

InviteKey is a stored row (no raw secret).

type Membership

type Membership struct {
	RepoID  string
	UserID  string
	Role    string
	AddedAt time.Time
	// Email is populated by ListRepoMembers (joined from the users table).
	// Queries that do not join users leave it empty.
	Email string
}

Membership describes one (repo_id, user_id) row.

type PAT

type PAT struct {
	ID         string
	UserID     string
	Label      string
	CreatedAt  time.Time
	LastUsedAt *time.Time
}

PAT describes a personal access token without the raw secret.

type Store

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

Store wraps the SQLite database holding access metadata.

func Open

func Open(path string) (*Store, error)

Open opens (or creates) a SQLite database at path and runs migrations.

func (*Store) AddMember

func (s *Store) AddMember(repoID, userID, role string) error

AddMember adds userID to repoID with the given role (idempotent). If a row already exists, the role is preserved (call with RoleOwner first when claiming a brand-new repo).

func (*Store) Close

func (s *Store) Close() error

Close closes the underlying database.

func (*Store) CountActivity

func (s *Store) CountActivity(repoID string) (int, error)

CountActivity returns the total number of events stored for repoID (bounded by activityRetentionPerRepo). Used to drive pagination.

func (*Store) CountOwnedRepos added in v0.5.0

func (s *Store) CountOwnedRepos(userID string) (int, error)

CountOwnedRepos returns how many distinct repos the user owns (role=owner). The hosted quota policy compares this against the free-tier repo cap.

func (*Store) CountRepoMembers added in v0.5.0

func (s *Store) CountRepoMembers(repoID string) (int, error)

CountRepoMembers returns the number of people with any role in repo. The owner counts as a member, matching the free-tier "N members per repo" cap.

func (*Store) CountUsers

func (s *Store) CountUsers() (int, error)

CountUsers returns the total number of users.

func (*Store) DB

func (s *Store) DB() *sql.DB

DB exposes the underlying *sql.DB (mainly for tests).

func (*Store) DeleteInviteKey

func (s *Store) DeleteInviteKey(repoID, keyID string) error

DeleteInviteKey revokes an invite key. Caller MUST verify the user is an owner of the repo.

func (*Store) DeletePAT

func (s *Store) DeletePAT(userID, patID string) error

DeletePAT revokes a PAT. Caller MUST verify the PAT belongs to the user.

func (*Store) GetRole

func (s *Store) GetRole(repoID, userID string) (string, error)

GetRole returns the role of user in repo, or ErrNotFound.

func (*Store) GetUserByEmail

func (s *Store) GetUserByEmail(email string) (*User, error)

GetUserByEmail returns a user by email (case-insensitive) or ErrNotFound.

func (*Store) GetUserByID

func (s *Store) GetUserByID(id string) (*User, error)

GetUserByID returns a user by id or ErrNotFound.

func (*Store) IsMember

func (s *Store) IsMember(repoID, userID string) (bool, error)

IsMember reports whether user has any role in repo.

func (*Store) ListActivity

func (s *Store) ListActivity(repoID string, limit, offset int) ([]Activity, error)

ListActivity returns a page of events for repoID (reverse-chronological), each with the actor's email joined from the users table. limit <= 0 defaults to 50; offset < 0 is treated as 0.

func (*Store) ListInviteKeys

func (s *Store) ListInviteKeys(repoID string) ([]InviteKey, error)

ListInviteKeys returns every invite key for a repo (no raw values).

func (*Store) ListPATs

func (s *Store) ListPATs(userID string) ([]PAT, error)

ListPATs returns PAT records (no raw values) for a user, newest first.

func (*Store) ListRepoMembers

func (s *Store) ListRepoMembers(repoID string) ([]Membership, error)

ListRepoMembers returns every member of a repo, with each member's email joined in from the users table.

func (*Store) ListUserRepos

func (s *Store) ListUserRepos(userID string) ([]Membership, error)

ListUserRepos returns every repo_id the user belongs to, with their role.

func (*Store) MintInviteKey

func (s *Store) MintInviteKey(repoID, createdBy, label string) (*InviteKey, string, error)

MintInviteKey creates a new invite key for repo, returning the row and the raw key (only returned once).

func (*Store) MintPAT

func (s *Store) MintPAT(userID, label string) (*PAT, string, error)

MintPAT creates a new PAT for user_id with the given label and returns both the database record and the raw token (only returned once).

func (*Store) RecordActivity

func (s *Store) RecordActivity(repoID, userID, action, detail string) error

RecordActivity appends one event to a repo's feed, then prunes the feed back to activityRetentionPerRepo newest events. Best-effort: callers log-and-ignore.

func (*Store) RemoveMember

func (s *Store) RemoveMember(repoID, userID string) error

RemoveMember removes userID from repoID. It returns ErrNotFound if the user is not a member, or ErrLastOwner if removing them would leave the repo with no owner.

func (*Store) RepoHasOwner

func (s *Store) RepoHasOwner(repoID string) (bool, error)

RepoHasOwner reports whether at least one row exists for repo with role=owner.

func (*Store) RepoOwners added in v0.5.0

func (s *Store) RepoOwners(repoID string) ([]string, error)

RepoOwners returns the user IDs of every owner of repo (possibly empty). The hosted quota policy treats a repo as uncapped if any owner is subscribed.

func (*Store) ResolveInviteKey

func (s *Store) ResolveInviteKey(raw string) (string, error)

ResolveInviteKey returns the repo_id for a raw invite key. It returns ErrNotFound if the key is unknown, or ErrExpired if it has passed its TTL.

func (*Store) ResolvePAT

func (s *Store) ResolvePAT(raw string) (string, error)

ResolvePAT returns the user_id for a raw PAT, or ErrNotFound. Also bumps last_used_at.

func (*Store) UpsertGoogleUser

func (s *Store) UpsertGoogleUser(email, name, googleSub string) (*User, bool, error)

UpsertGoogleUser creates a user keyed by Google sub/email or updates the existing row's name and last_login_at. Returns the resulting User and whether this was a fresh insert (the very first sign-in for this email).

type User

type User struct {
	ID          string
	Email       string
	Name        string
	GoogleSub   string
	CreatedAt   time.Time
	LastLoginAt *time.Time
}

User represents a row in the users table.

Jump to

Keyboard shortcuts

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