Files
story/internal/devicebinding/guard.go
T
Codex Local bf1233d5df
ci / verify (push) Canceled after 0s
feat: expand companion platform, device controls, and memoir workflows
Add customer and operator login, BLE provisioning, device fleet controls, call memory, memoir generation, and refreshed family and maintenance portals. Include API contracts, migrations, firmware sources, tests, assets, and deployment documentation.
2026-10-08 10:06:44 +08:00

40 lines
1.3 KiB
Go

// Package devicebinding owns compatibility gates shared by all ownership writers.
// Generation advancement and claim fencing are enforced by the database trigger
// so background deletion and operator mutations cannot omit invalidation.
package devicebinding
import (
"context"
"errors"
"github.com/jackc/pgx/v5"
)
var ErrConfirmationRequired = errors.New("device physical confirmation workflow required")
type Queryer interface {
QueryRow(context.Context, string, ...any) pgx.Row
}
func RequireLegacy(ctx context.Context, q Queryer, deviceID string) error {
var mode string
err := q.QueryRow(ctx, `SELECT enrollment_mode FROM device WHERE id=$1::uuid`, deviceID).Scan(&mode)
if err != nil {
return err
}
if mode != "legacy" {
return ErrConfirmationRequired
}
return nil
}
func RequireUnboundForReset(ctx context.Context, q Queryer, deviceID string) error {
var allowed bool
err := q.QueryRow(ctx, `SELECT enrollment_mode='legacy' OR (NOT EXISTS(SELECT 1 FROM device_binding WHERE device_id=d.id AND unbound_at IS NULL) AND NOT EXISTS(SELECT 1 FROM device_account_binding WHERE device_id=d.id AND released_at IS NULL)) FROM device d WHERE id=$1::uuid`, deviceID).Scan(&allowed)
if err != nil {
return err
}
if !allowed {
return ErrConfirmationRequired
}
return nil
}