89 lines
2.7 KiB
Go
89 lines
2.7 KiB
Go
// Package evidence defines the narrow internal screenshot contract shared by HTTP and storage.
|
|
package evidence
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
"io"
|
|
"net/http"
|
|
"time"
|
|
)
|
|
|
|
const (
|
|
KindSKUPanelGate1 = "SKU_PANEL_GATE_1"
|
|
PrivacyInternalRaw = "INTERNAL_RAW"
|
|
PNGContentType = "image/png"
|
|
MaxFileBytes int64 = 10 << 20
|
|
MaxImageSide = 8192
|
|
MaxImagePixels = 16_777_216
|
|
)
|
|
|
|
var (
|
|
ErrInvalid = errors.New("invalid evidence")
|
|
ErrConflict = errors.New("evidence upload key conflict")
|
|
ErrNotFound = errors.New("evidence not found")
|
|
ErrTooLarge = errors.New("evidence file too large")
|
|
)
|
|
|
|
// DevicePrincipal is the already-authenticated device identity used only for audit and idempotency.
|
|
type DevicePrincipal struct {
|
|
ID string
|
|
}
|
|
|
|
// DeviceAuthenticator deliberately has no token implementation in T-204. T-301 will supply one.
|
|
type DeviceAuthenticator interface {
|
|
Authenticate(*http.Request) (DevicePrincipal, bool)
|
|
}
|
|
|
|
// RejectAllDeviceAuthenticator keeps the production upload route fail closed until T-301 wires credentials.
|
|
type RejectAllDeviceAuthenticator struct{}
|
|
|
|
func (RejectAllDeviceAuthenticator) Authenticate(*http.Request) (DevicePrincipal, bool) {
|
|
return DevicePrincipal{}, false
|
|
}
|
|
|
|
type UploadMetadata struct {
|
|
UploadKey string
|
|
TaskID string
|
|
AttemptID string
|
|
Kind string
|
|
PrivacyTier string
|
|
SHA256 string
|
|
CapturedAt time.Time
|
|
}
|
|
|
|
// StagedFile contains only server-generated state. Multipart filenames and client paths never enter this type.
|
|
type StagedFile struct {
|
|
Path string
|
|
SHA256 string
|
|
ByteSize int64
|
|
ContentType string
|
|
Width int
|
|
Height int
|
|
}
|
|
|
|
type Asset struct {
|
|
ID string `json:"asset_id"`
|
|
TaskID string `json:"task_id"`
|
|
AttemptID string `json:"attempt_id"`
|
|
Kind string `json:"kind"`
|
|
PrivacyTier string `json:"privacy_tier"`
|
|
SHA256 string `json:"sha256"`
|
|
ByteSize int64 `json:"byte_size"`
|
|
ContentType string `json:"content_type"`
|
|
Width int `json:"width_px"`
|
|
Height int `json:"height_px"`
|
|
CapturedAt time.Time `json:"captured_at"`
|
|
UploadedByDeviceID string `json:"-"`
|
|
StorageKey string `json:"-"`
|
|
CreatedAt time.Time `json:"-"`
|
|
}
|
|
|
|
// Store separates bounded multipart staging from metadata commit so field order cannot weaken validation.
|
|
type Store interface {
|
|
Stage(io.Reader, string) (StagedFile, error)
|
|
Discard(StagedFile)
|
|
Commit(context.Context, DevicePrincipal, UploadMetadata, StagedFile) (Asset, bool, error)
|
|
Open(context.Context, string) (Asset, io.ReadSeekCloser, error)
|
|
}
|