marky

Lightweight bookmarking + plaintext archive
Log | Files | Refs | README | LICENSE

commit a40f5b88b37468af2b01bb41187829c49d159730
parent 3ebc107aef28a6f1e402d707647a441d389c263c
Author: David Eisinger <[email protected]>
Date:   Mon,  6 Oct 2025 21:20:45 -0400

user.go

Diffstat:
Ainternal/migrations/0006_users.sql | 12++++++++++++
Ainternal/user.go | 30++++++++++++++++++++++++++++++
2 files changed, 42 insertions(+), 0 deletions(-)

diff --git a/internal/migrations/0006_users.sql b/internal/migrations/0006_users.sql @@ -0,0 +1,12 @@ +-- Users table for authentication +CREATE TABLE IF NOT EXISTS users ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + username TEXT NOT NULL CHECK (username <> '' AND username GLOB '[a-z0-9]*'), + encrypted_password TEXT NOT NULL, + api_token TEXT, + created_at TEXT NOT NULL, + updated_at TEXT NOT NULL +); + +CREATE UNIQUE INDEX IF NOT EXISTS idx_users_username ON users(username); + diff --git a/internal/user.go b/internal/user.go @@ -0,0 +1,30 @@ +package internal + +import ( + "errors" +) + +// User represents an application user. +// The username must be unique and contain only lowercase letters and digits. +type User struct { + ID int64 + Username string + EncryptedPassword string + APIToken *string +} + +// ValidateUsername verifies that the username is non-empty and contains only +// lowercase ASCII letters and digits. +func ValidateUsername(u string) error { + if u == "" { + return errors.New("username is required") + } + for i := 0; i < len(u); i++ { + c := u[i] + if (c < 'a' || c > 'z') && (c < '0' || c > '9') { + return errors.New("username must be lowercase letters and digits only") + } + } + return nil +} +