package auth import ( "context" "fmt" "atcr.io/pkg/atproto" ) // HoldAuthorizer checks if a DID has read/write access to a hold // Implementations can query local PDS (hold service) or remote XRPC (appview) type HoldAuthorizer interface { // CheckReadAccess checks if userDID can read from holdDID // Returns: (allowed bool, error) CheckReadAccess(ctx context.Context, holdDID, userDID string) (bool, error) // CheckWriteAccess checks if userDID can write to holdDID // Returns: (allowed bool, error) CheckWriteAccess(ctx context.Context, holdDID, userDID string) (bool, error) // GetCaptainRecord retrieves the captain record for a hold // Used to check public flag and allowAllCrew settings GetCaptainRecord(ctx context.Context, holdDID string) (*atproto.CaptainRecord, error) // IsCrewMember checks if userDID is a crew member of holdDID IsCrewMember(ctx context.Context, holdDID, userDID string) (bool, error) } // CheckReadAccessWithCaptain implements the standard read authorization logic // This is shared across all HoldAuthorizer implementations // Read access rules: // - Public hold: allow anyone (even anonymous) // - Private hold: require authentication (any authenticated user) func CheckReadAccessWithCaptain(captain *atproto.CaptainRecord, userDID string) bool { if captain.Public { // Public hold - allow anyone (even anonymous) return true } // Private hold - require authentication // Any authenticated user with a DID can read if userDID == "" { // Anonymous user trying to access private hold return false } // For MVP: assume DID presence means they have sailor.profile // Future: could query PDS to verify sailor.profile exists return true } // CheckWriteAccessWithCaptain implements the standard write authorization logic // This is shared across all HoldAuthorizer implementations // Write access rules: // - Must be authenticated // - Must be hold owner OR crew member func CheckWriteAccessWithCaptain(captain *atproto.CaptainRecord, userDID string, isCrew bool) bool { if userDID == "" { // Anonymous writes not allowed return false } // Check if DID is the hold owner if userDID == captain.Owner { // Owner always has write access return true } // Check if DID is a crew member return isCrew } // ErrHoldNotFound is returned when a hold's captain record cannot be found var ErrHoldNotFound = fmt.Errorf("hold not found") // ErrUnauthorized is returned when access is denied var ErrUnauthorized = fmt.Errorf("unauthorized")