remove preact and create setup wizard

This commit is contained in:
2026-06-01 10:10:36 -04:00
parent b3364447a1
commit ebe0920f89
53 changed files with 818 additions and 4226 deletions

View File

@@ -55,7 +55,34 @@ func NewService(repo *Repository, publicOrigin string) (*Service, error) {
return &Service{repo: repo, webauthn: web, publicOrigin: publicOrigin}, nil
}
func (s *Service) GetInstanceSettings(ctx context.Context) (InstanceSettings, error) {
return s.repo.GetInstanceSettings(ctx)
}
func (s *Service) CompleteInitialSetup(ctx context.Context, email, displayName, password string, signupsEnabled bool) (User, error) {
email = normalizeEmail(email)
if email == "" {
return User{}, fmt.Errorf("email is required")
}
if len(password) < 12 {
return User{}, fmt.Errorf("password must be at least 12 characters")
}
passwordHash, err := hashPassword(password)
if err != nil {
return User{}, err
}
return s.repo.CompleteInitialSetup(ctx, User{
Email: email,
DisplayName: strings.TrimSpace(displayName),
PasswordHash: passwordHash,
Role: RoleAdmin,
}, signupsEnabled)
}
func (s *Service) RegisterPasswordUser(ctx context.Context, email, displayName, password, role string) (User, error) {
if err := s.requirePublicSignups(ctx); err != nil {
return User{}, err
}
email = normalizeEmail(email)
if email == "" {
return User{}, fmt.Errorf("email is required")
@@ -72,21 +99,11 @@ func (s *Service) RegisterPasswordUser(ctx context.Context, email, displayName,
if err != nil {
return User{}, err
}
userCount, err := s.repo.CountUsers(ctx)
if err != nil {
return User{}, err
}
normalizedRole := RoleViewer
if userCount == 0 {
normalizedRole = RoleAdmin
} else if strings.EqualFold(role, string(RoleViewer)) {
normalizedRole = RoleViewer
}
return s.repo.UpsertUser(ctx, User{
Email: email,
DisplayName: strings.TrimSpace(displayName),
PasswordHash: passwordHash,
Role: normalizedRole,
Role: RoleViewer,
})
}
@@ -113,23 +130,18 @@ func (s *Service) LoginPassword(ctx context.Context, email, password, ip, userAg
}
func (s *Service) BeginPasskeyRegistration(ctx context.Context, email, displayName, role string) (any, string, error) {
if err := s.requirePublicSignups(ctx); err != nil {
return nil, "", err
}
user, err := s.repo.GetUserByEmail(ctx, normalizeEmail(email))
if err != nil {
if !isNoRows(err) {
return nil, "", err
}
userCount, err := s.repo.CountUsers(ctx)
if err != nil {
return nil, "", err
}
normalizedRole := RoleViewer
if userCount == 0 {
normalizedRole = RoleAdmin
}
user, err = s.repo.UpsertUser(ctx, User{
Email: normalizeEmail(email),
DisplayName: strings.TrimSpace(displayName),
Role: normalizedRole,
Role: RoleViewer,
})
if err != nil {
return nil, "", err
@@ -278,6 +290,43 @@ func (s *Service) ListUsers(ctx context.Context) ([]User, error) {
return s.repo.ListUsers(ctx)
}
func (s *Service) UpdateSignupsEnabled(ctx context.Context, actor Principal, enabled bool) (InstanceSettings, error) {
if !Allows(actor, ScopeAdmin) {
return InstanceSettings{}, fmt.Errorf("admin role required")
}
if err := s.repo.UpdateSignupsEnabled(ctx, enabled); err != nil {
return InstanceSettings{}, err
}
return s.repo.GetInstanceSettings(ctx)
}
func (s *Service) EnsureDevUser(ctx context.Context) (User, error) {
const email = "dev@localhost"
settings, err := s.repo.GetInstanceSettings(ctx)
if err != nil {
return User{}, err
}
if !settings.SetupComplete {
return s.CompleteInitialSetup(ctx, email, "Development Admin", "development-only-password", true)
}
user, err := s.repo.GetUserByEmail(ctx, email)
if err == nil {
return user, nil
}
if !isNoRows(err) {
return User{}, err
}
return s.repo.UpsertUser(ctx, User{Email: email, DisplayName: "Development Admin", Role: RoleAdmin})
}
func (s *Service) PrincipalForUser(ctx context.Context, userID string) (Principal, error) {
user, err := s.repo.GetUserByID(ctx, userID)
if err != nil {
return Principal{}, err
}
return principalFromUser(user, "dev", "", "", nil, time.Time{}), nil
}
func (s *Service) UpdateUserRole(ctx context.Context, actor Principal, userID, role string) (User, error) {
if !Allows(actor, ScopeAdmin) {
return User{}, fmt.Errorf("admin role required")
@@ -453,6 +502,20 @@ func (s *Service) createSession(ctx context.Context, user User, ip, userAgent st
return principalFromUser(user, "session", session.ID, "", nil, session.ExpiresAt), token, nil
}
func (s *Service) requirePublicSignups(ctx context.Context) error {
settings, err := s.repo.GetInstanceSettings(ctx)
if err != nil {
return err
}
if !settings.SetupComplete {
return fmt.Errorf("initial setup is required")
}
if !settings.SignupsEnabled {
return fmt.Errorf("signups are disabled")
}
return nil
}
func principalFromUser(user User, method, sessionID, apiKeyID string, scopes []Scope, expiresAt time.Time) Principal {
return Principal{
UserID: user.ID,