/** * Access control rules for objects * * Rules: * - Only the author (pubkey) who published the original note can modify or delete it * - All users have read access to public content (previews, metadata) * - For paid content, users must have paid (via zap receipt) to access the full content * - Payment verification follows the transaction rules (zap receipt validation) */ import type { Event } from 'nostr-tools' import { extractTagsFromEvent } from './nostrTagSystem' import { canModifyObject } from './versionManager' import { t } from './i18n' /** * Check if a user can modify an object * Only the author (pubkey) who published the original note can modify it */ export function canUserModify(event: Event, userPubkey: string): boolean { return canModifyObject(event, userPubkey) } /** * Check if a user can delete an object * Only the author (pubkey) who published the original note can delete it */ export function canUserDelete(event: Event, userPubkey: string): boolean { return canModifyObject(event, userPubkey) } /** * Check if a user can read an object * All users can read public content (previews, metadata) * For paid content, users must have paid (via zap receipt) to access full content */ export function canUserRead(event: Event, _userPubkey: string | null, hasPaid: boolean = false): { canReadPreview: boolean canReadFullContent: boolean } { const tags = extractTagsFromEvent(event) // Preview is always readable (public) const canReadPreview = true // Full content access depends on paywall status if (tags.paywall) { // Paid content: user must have paid const canReadFullContent = hasPaid return { canReadPreview, canReadFullContent } } // Free content: everyone can read return { canReadPreview, canReadFullContent: true } } /** * Check if content is paid (has paywall tag) */ export function isPaidContent(event: Event): boolean { const tags = extractTagsFromEvent(event) return tags.paywall === true } /** * Access control result */ export interface AccessControlResult { canModify: boolean canDelete: boolean canReadPreview: boolean canReadFullContent: boolean isPaid: boolean reason?: string } /** * Get complete access control information for an object */ export function getAccessControl( event: Event, userPubkey: string | null, hasPaid: boolean = false ): AccessControlResult { const canModify = userPubkey ? canUserModify(event, userPubkey) : false const canDelete = userPubkey ? canUserDelete(event, userPubkey) : false const { canReadPreview, canReadFullContent } = canUserRead(event, userPubkey, hasPaid) const isPaid = isPaidContent(event) const reason = getAccessControlReason({ isPaid, canReadFullContent, userPubkey, canModify, canDelete }) return { canModify, canDelete, canReadPreview, canReadFullContent, isPaid, ...(reason ? { reason } : {}), } } function getAccessControlReason(params: { isPaid: boolean canReadFullContent: boolean userPubkey: string | null canModify: boolean canDelete: boolean }): string | undefined { if (params.isPaid && !params.canReadFullContent) { return t('access.paymentRequired') } if (!params.userPubkey) { return undefined } if (!params.canModify) { return t('access.onlyAuthorModify') } if (!params.canDelete) { return t('access.onlyAuthorDelete') } return undefined }