40 lines
1.2 KiB
Go
40 lines
1.2 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) FROM device d WHERE id=$1::uuid`, deviceID).Scan(&allowed)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if !allowed {
|
|
return ErrConfirmationRequired
|
|
}
|
|
return nil
|
|
}
|