mirror of
https://github.com/MeshCore-Beacon/beacon-server.git
synced 2026-10-16 22:30:43 +00:00
61 lines
1.7 KiB
Go
61 lines
1.7 KiB
Go
// Copyright 2026 Beacon Contributors
|
|
// SPDX-License-Identifier: AGPL-3.0-or-later
|
|
|
|
package api
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
"strings"
|
|
"time"
|
|
"unicode"
|
|
"unicode/utf8"
|
|
|
|
"github.com/google/uuid"
|
|
)
|
|
|
|
var (
|
|
ErrAccountNotFound = errors.New("account not found")
|
|
ErrAccountInactive = errors.New("account is already inactive")
|
|
ErrAccountNameConflict = errors.New("an active account already uses this name")
|
|
ErrAccountNameInvalid = errors.New("account name must be 1-128 characters without control characters")
|
|
)
|
|
|
|
// Account is an operator-defined record, not a login or authentication principal.
|
|
type Account struct {
|
|
ID uuid.UUID `json:"id"`
|
|
Name string `json:"name"`
|
|
CreatedAt time.Time `json:"created_at"`
|
|
DeactivatedAt *time.Time `json:"deactivated_at,omitempty"`
|
|
Active bool `json:"active"`
|
|
}
|
|
|
|
type AccountList struct {
|
|
Items []Account `json:"items"`
|
|
}
|
|
|
|
// AccountStore is separate from public Reader/cache and ingest write interfaces.
|
|
type AccountStore interface {
|
|
CreateAccount(context.Context, string) (Account, error)
|
|
ListAccounts(context.Context) ([]Account, error)
|
|
GetAccount(context.Context, uuid.UUID) (Account, error)
|
|
DeactivateAccount(context.Context, uuid.UUID) error
|
|
}
|
|
|
|
// NormalizeAccountName applies the same validation to every account writer.
|
|
func NormalizeAccountName(name string) (string, error) {
|
|
if !utf8.ValidString(name) {
|
|
return "", ErrAccountNameInvalid
|
|
}
|
|
name = strings.TrimSpace(name)
|
|
if length := utf8.RuneCountInString(name); length < 1 || length > 128 {
|
|
return "", ErrAccountNameInvalid
|
|
}
|
|
for _, r := range name {
|
|
if unicode.IsControl(r) {
|
|
return "", ErrAccountNameInvalid
|
|
}
|
|
}
|
|
return name, nil
|
|
}
|