Skins & capes:
- Fix uploadSkin auth: Bearer token instead of user_id form hack
- Add POST /api/web/profile/cape (upload cape)
- Add DELETE /api/web/profile/skin and DELETE /api/web/profile/cape
- Validate skin PNG dimensions (64x32, 64x64, 128x128, 128x64)
- Add size limits: 1 MB for skins, 2 MB for capes
- Add basic email validation on register
Profile & session server:
- Add GET /api/web/profile/{uuid} — public profile with skin/cape hashes
- Add GET /sessionserver/session/minecraft/profile/{uuid} — Mojang-compatible
texture response for game client
- Add POST /authserver/invalidate and POST /authserver/signout
- Export VerifyPassword and ExtractBearer from auth package
- Remove duplicate verifyPassword from api.go
- Add PlayerTextures model to database.go
96 lines
2.6 KiB
Go
96 lines
2.6 KiB
Go
// package database manages PostgreSQL connections and data models.
|
|
package database
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
|
|
"github.com/jackc/pgx/v5/pgxpool"
|
|
)
|
|
|
|
// DB wraps pgxpool.Pool with application-specific helpers.
|
|
type DB struct {
|
|
pool *pgxpool.Pool
|
|
}
|
|
|
|
// Open creates a new database connection pool.
|
|
func Open(ctx context.Context, databaseURL string) (*DB, error) {
|
|
pool, err := pgxpool.New(ctx, databaseURL)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("connecting to database: %w", err)
|
|
}
|
|
if err := pool.Ping(ctx); err != nil {
|
|
pool.Close()
|
|
return nil, fmt.Errorf("pinging database: %w", err)
|
|
}
|
|
return &DB{pool: pool}, nil
|
|
}
|
|
|
|
// Close shuts down the connection pool.
|
|
func (db *DB) Close() {
|
|
db.pool.Close()
|
|
}
|
|
|
|
// Pool returns the underlying pool for direct queries.
|
|
func (db *DB) Pool() *pgxpool.Pool {
|
|
return db.pool
|
|
}
|
|
|
|
// ── Models ─────────────────────────────────────────────────────
|
|
|
|
// User represents a registered player.
|
|
type User struct {
|
|
ID int `db:"id"`
|
|
Username string `db:"username"`
|
|
Email string `db:"email"`
|
|
PasswordHash string `db:"password_hash"`
|
|
UUID string `db:"uuid"`
|
|
Role string `db:"role"`
|
|
}
|
|
|
|
// YggdrasilSession represents an active authentication session.
|
|
type YggdrasilSession struct {
|
|
ClientToken string `db:"client_token"`
|
|
AccessToken string `db:"access_token"`
|
|
UserID int `db:"user_id"`
|
|
ExpiresAt string `db:"expires_at"`
|
|
}
|
|
|
|
// Modpack represents a game server / modpack configuration.
|
|
type Modpack struct {
|
|
ID int `db:"id"`
|
|
Slug string `db:"slug"`
|
|
Name string `db:"name"`
|
|
MinecraftVersion string `db:"minecraft_version"`
|
|
JavaVersion int `db:"java_version"`
|
|
ServerIP string `db:"server_ip"`
|
|
IsActive bool `db:"is_active"`
|
|
}
|
|
|
|
// GlobalFile is a CAS entry.
|
|
type GlobalFile struct {
|
|
SHA1 string `db:"sha1"`
|
|
Size int64 `db:"size_bytes"`
|
|
FileName string `db:"file_name"`
|
|
}
|
|
|
|
// PlayerTextures holds skin/cape references for a user.
|
|
type PlayerTextures struct {
|
|
UserID int `db:"user_id"`
|
|
SkinHash string `db:"skin_hash"`
|
|
CapeHash string `db:"cape_hash"`
|
|
IsSlim bool `db:"is_slim"`
|
|
}
|
|
|
|
// LauncherRelease tracks published launcher binaries.
|
|
type LauncherRelease struct {
|
|
ID int `db:"id"`
|
|
Version string `db:"version"`
|
|
OS string `db:"os"`
|
|
Arch string `db:"arch"`
|
|
SHA256 string `db:"sha256"`
|
|
FilePath string `db:"file_path"`
|
|
IsActive bool `db:"is_active"`
|
|
IsMandatory bool `db:"is_mandatory"`
|
|
}
|