Documentation
¶
Overview ¶
Package activitypub provides parsing and validation utilities for ActivityPub protocol messages.
Index ¶
- Constants
- Variables
- func SanitizeHTML(content string) string
- func SanitizeHTMLRelaxed(content string) string
- func ValidateActivity(activity *Activity) error
- func ValidateActor(actor *Actor) error
- func ValidateActorID(actorID string) error
- func ValidateAddressing(addresses []string, fieldName string) error
- func ValidateDomain(domain string) error
- func ValidateNote(note *Note) error
- func ValidateURL(urlStr string, fieldName string) error
- func ValidateUsername(username string) error
- func ValidateWebfinger(resource string) error
- type Accept
- type Activity
- type Actor
- type Add
- type AddressingValidator
- func (v *AddressingValidator) DetermineDeliveryRecipients(activity *Activity) *DeliveryTargets
- func (v *AddressingValidator) GetDeliveryRecipientsForPrivacy(activity *Activity, requestingActor string) []string
- func (v *AddressingValidator) GetVisibilityLevel(activity *Activity) string
- func (v *AddressingValidator) IsDirectMessage(activity *Activity) bool
- func (v *AddressingValidator) IsFollowersOnlyMessage(activity *Activity) bool
- func (v *AddressingValidator) IsPrivateMessage(activity *Activity) bool
- func (v *AddressingValidator) IsPublicMessage(activity *Activity) bool
- func (v *AddressingValidator) IsUnlistedMessage(activity *Activity) bool
- func (v *AddressingValidator) SanitizeForDelivery(activity *Activity, excludeBTo bool) *Activity
- func (v *AddressingValidator) ValidateAddressing(activity *Activity) error
- func (v *AddressingValidator) ValidatePrivacyCompliance(activity *Activity) error
- type AgentCapabilities
- type AgentManifest
- type AgentPostAttribution
- type Announce
- type Article
- type Attachment
- type BaseObject
- type Collection
- type CollectionPage
- type ContextValue
- type Create
- type Delete
- type DeliveryTargets
- type Endpoints
- type Flag
- type Follow
- type Image
- type Like
- type Move
- type Note
- type OrderedCollection
- type OrderedCollectionPage
- type PublicKey
- type QuoteContext
- type QuoteNote
- type Reject
- type Remove
- type Tag
- type Tombstone
- type Undo
- type Update
- type WebFingerLink
- type WebFingerResource
Constants ¶
const ( // Actor types PersonType = "Person" ServiceType = "Service" GroupType = "Group" OrganizationType = "Organization" ApplicationType = "Application" // Activity types CreateType = "Create" UpdateType = "Update" DeleteType = "Delete" FollowType = "Follow" AcceptType = "Accept" RejectType = "Reject" LikeType = "Like" AnnounceType = "Announce" UndoType = "Undo" BlockType = "Block" FlagType = "Flag" MoveType = "Move" AddType = "Add" RemoveType = "Remove" // Object types NoteType = "Note" ArticleType = "Article" ImageType = "Image" VideoType = "Video" DocumentType = "Document" CollectionType = "Collection" OrderedCollectionType = "OrderedCollection" OrderedCollectionPageType = "OrderedCollectionPage" TombstoneType = "Tombstone" // Collection types InboxCollection = "inbox" OutboxCollection = "outbox" FollowersCollection = "followers" FollowingCollection = "following" LikedCollection = "liked" // Public addressing PublicAddress = "https://www.w3.org/ns/activitystreams#Public" )
Constants for common ActivityPub types
const ( // HTTPScheme represents the HTTP URL scheme HTTPScheme = "http" // HTTPSScheme represents the HTTPS URL scheme HTTPSScheme = "https" )
Variables ¶
var ( // ErrInvalidJSON is returned when JSON validation fails before parsing ErrInvalidJSON = apperrors.JSONFormatInvalid("invalid ActivityPub JSON") // ErrParseActivity is returned when activity parsing fails ErrParseActivity = apperrors.ActivityParsingFailed("activity", errors.New("activity parsing failed")) // ErrParseActor is returned when actor parsing fails ErrParseActor = apperrors.ActivityParsingFailed("actor", errors.New("actor parsing failed")) // ErrParseNote is returned when note parsing fails ErrParseNote = apperrors.ActivityParsingFailed("note", errors.New("note parsing failed")) // ErrInvalidActivity is returned when activity validation fails ErrInvalidActivity = apperrors.InvalidActivityObject() // ErrInvalidActor is returned when actor validation fails ErrInvalidActor = apperrors.NewValidationError("actor", "Invalid actor") // ErrInvalidNote is returned when note validation fails ErrInvalidNote = apperrors.NewValidationError("note", "Invalid note") // ErrEmptyRecipient is returned when a recipient field is empty ErrEmptyRecipient = apperrors.RequiredFieldMissing("recipient") // ErrInvalidRecipientURL is returned when a recipient URL is malformed ErrInvalidRecipientURL = apperrors.InvalidFormat("recipient_url", "valid URL format") // ErrInvalidURLScheme is returned when a recipient URL doesn't use HTTP(S) ErrInvalidURLScheme = apperrors.URLSchemeNotAllowed("", "") // ErrInvalidRecipientFormat is returned when a recipient URL format is invalid ErrInvalidRecipientFormat = apperrors.InvalidFormat("recipient_url", "valid URL format") // ErrDirectMessagePublicAddressing is returned when direct messages have public addressing ErrDirectMessagePublicAddressing = apperrors.BusinessRuleViolated("direct message addressing", map[string]interface{}{"rule": "no public addressing"}) // ErrBCCInVisibleFields is returned when BCC recipients appear in visible addressing fields ErrBCCInVisibleFields = apperrors.BusinessRuleViolated("BCC privacy", map[string]interface{}{"rule": "BCC not in visible fields"}) // Validation errors // ErrEmptyDomain is returned when domain is empty ErrEmptyDomain = apperrors.RequiredFieldMissing("domain") // ErrIPAddressAsDomain is returned when an IP address is used as a domain ErrIPAddressAsDomain = apperrors.NewValidationError("domain", "IP addresses cannot be used as domains") // ErrInvalidDomainFormat is returned when domain format is invalid ErrInvalidDomainFormat = apperrors.InvalidFormat("domain", "valid domain format") // ErrConsecutiveDots is returned when domain contains consecutive dots ErrConsecutiveDots = apperrors.NewValidationError("domain", "Domain cannot contain consecutive dots") // ErrInvalidActorIDURL is returned when actor ID URL is malformed ErrInvalidActorIDURL = apperrors.InvalidFormat("actor_id_url", "valid actor ID URL") // ErrActorIDScheme is returned when actor ID doesn't use HTTP(S) ErrActorIDScheme = apperrors.URLSchemeNotAllowed("", "") // ErrActorIDMissingPath is returned when actor ID has no path ErrActorIDMissingPath = apperrors.NewValidationError("actor_id", "Actor ID must have a path") // ErrInvalidWebfingerFormat is returned when webfinger format is invalid ErrInvalidWebfingerFormat = apperrors.InvalidFormat("webfinger", "acct:user@domain") // ErrInvalidDomainInActorID is returned when actor ID contains invalid domain ErrInvalidDomainInActorID = apperrors.NewValidationError("actor_id", "Invalid domain in actor ID") // ErrInvalidUsernameInWebfinger is returned when webfinger contains invalid username ErrInvalidUsernameInWebfinger = apperrors.NewValidationError("webfinger", "Invalid username") // ErrInvalidDomainInWebfinger is returned when webfinger contains invalid domain ErrInvalidDomainInWebfinger = apperrors.NewValidationError("webfinger", "Invalid domain") // ErrInvalidActivityType is returned when activity type is not recognized ErrInvalidActivityType = apperrors.NewValidationError("activity_type", "Invalid activity type") )
Legacy error variables for backwards compatibility These are now wrappers around the centralized error system
var Context = ContextValue{ "https://www.w3.org/ns/activitystreams", map[string]any{ "manuallyApprovesFollowers": "as:manuallyApprovesFollowers", "sensitive": "as:sensitive", "Hashtag": "as:Hashtag", "quoteUrl": "as:quoteUrl", "toot": "http://joinmastodon.org/ns#", "Emoji": "toot:Emoji", "featured": "toot:featured", "discoverable": "toot:discoverable", "schema": "http://schema.org#", "PropertyValue": "schema:PropertyValue", "value": "schema:value", "agentManifest": "https://lesser.social/ns/agentManifest", }, }
Context represents the richer JSON-LD context for ActivityStreams with Mastodon extensions.
var DefaultContext = ContextValue{"https://www.w3.org/ns/activitystreams"}
DefaultContext represents the bare ActivityStreams context.
Functions ¶
func SanitizeHTML ¶
SanitizeHTML removes potentially dangerous HTML from content Uses bluemonday for robust XSS prevention
func SanitizeHTMLRelaxed ¶
SanitizeHTMLRelaxed applies a more relaxed sanitization policy Only use this for content from trusted sources
func ValidateActivity ¶
ValidateActivity validates an Activity object
func ValidateActorID ¶
ValidateActorID validates an ActivityPub actor ID URL
func ValidateAddressing ¶
ValidateAddressing validates addressing fields (to, cc, etc.)
func ValidateDomain ¶
ValidateDomain validates a domain name format
func ValidateURL ¶
ValidateURL validates that a string is a valid URL
func ValidateUsername ¶
ValidateUsername validates an ActivityPub username format
func ValidateWebfinger ¶
ValidateWebfinger validates a WebFinger resource identifier
Types ¶
type Activity ¶
type Activity struct {
BaseObject
Actor string `json:"actor"`
Object any `json:"object"`
Target string `json:"target,omitempty"` // For Add/Remove activities
Origin string `json:"origin,omitempty"` // For Move activities
Instrument string `json:"instrument,omitempty"` // For various activities
}
Activity represents an ActivityPub activity
func NewActivity ¶
NewActivity creates a new activity
func ParseActivity ¶
ParseActivity parses a JSON byte array into an Activity struct
type Actor ¶
type Actor struct {
BaseObject
PreferredUsername string `json:"preferredUsername"`
Name string `json:"name,omitempty"`
Summary string `json:"summary,omitempty"`
URL string `json:"url,omitempty"`
Icon *Image `json:"icon,omitempty"`
Image *Image `json:"image,omitempty"`
Inbox string `json:"inbox"`
Outbox string `json:"outbox"`
Following string `json:"following,omitempty"`
Followers string `json:"followers,omitempty"`
Liked string `json:"liked,omitempty"`
PublicKey *PublicKey `json:"publicKey,omitempty"`
Endpoints *Endpoints `json:"endpoints,omitempty"`
// Account migration support
AlsoKnownAs []string `json:"alsoKnownAs,omitempty"`
MovedTo string `json:"movedTo,omitempty"`
// Mastodon-specific fields
ManuallyApprovesFollowers bool `json:"manuallyApprovesFollowers,omitempty"`
Discoverable bool `json:"discoverable,omitempty"`
Featured string `json:"featured,omitempty"`
LastStatusAt *time.Time `json:"lastStatusAt,omitempty"`
CreatedAt *time.Time `json:"createdAt,omitempty"`
Attachment []Attachment `json:"attachment,omitempty"`
// Lesser extension: optional agent metadata for Service actors.
AgentManifest *AgentManifest `json:"agentManifest,omitempty"`
}
Actor represents an ActivityPub actor (Person, Service, etc.)
func ParseActor ¶
ParseActor parses a JSON byte array into an Actor struct
func (*Actor) MarshalJSON ¶
MarshalJSON provides custom JSON marshaling to handle the context
type AddressingValidator ¶
type AddressingValidator struct{}
AddressingValidator provides validation for ActivityPub addressing fields
func NewAddressingValidator ¶
func NewAddressingValidator() *AddressingValidator
NewAddressingValidator creates a new addressing validator
func (*AddressingValidator) DetermineDeliveryRecipients ¶
func (v *AddressingValidator) DetermineDeliveryRecipients(activity *Activity) *DeliveryTargets
DetermineDeliveryRecipients determines who should receive the activity with shared inbox optimization
func (*AddressingValidator) GetDeliveryRecipientsForPrivacy ¶
func (v *AddressingValidator) GetDeliveryRecipientsForPrivacy(activity *Activity, requestingActor string) []string
GetDeliveryRecipientsForPrivacy returns recipients based on privacy level
func (*AddressingValidator) GetVisibilityLevel ¶
func (v *AddressingValidator) GetVisibilityLevel(activity *Activity) string
GetVisibilityLevel determines the privacy level of an activity
func (*AddressingValidator) IsDirectMessage ¶
func (v *AddressingValidator) IsDirectMessage(activity *Activity) bool
IsDirectMessage checks if an activity represents a direct message
func (*AddressingValidator) IsFollowersOnlyMessage ¶
func (v *AddressingValidator) IsFollowersOnlyMessage(activity *Activity) bool
IsFollowersOnlyMessage checks if the activity is addressed only to followers
func (*AddressingValidator) IsPrivateMessage ¶
func (v *AddressingValidator) IsPrivateMessage(activity *Activity) bool
IsPrivateMessage checks if an activity is private/followers-only
func (*AddressingValidator) IsPublicMessage ¶
func (v *AddressingValidator) IsPublicMessage(activity *Activity) bool
IsPublicMessage checks if an activity is public
func (*AddressingValidator) IsUnlistedMessage ¶
func (v *AddressingValidator) IsUnlistedMessage(activity *Activity) bool
IsUnlistedMessage checks if an activity is unlisted
func (*AddressingValidator) SanitizeForDelivery ¶
func (v *AddressingValidator) SanitizeForDelivery(activity *Activity, excludeBTo bool) *Activity
SanitizeForDelivery removes BCC recipients from activity before delivery
func (*AddressingValidator) ValidateAddressing ¶
func (v *AddressingValidator) ValidateAddressing(activity *Activity) error
ValidateAddressing validates the addressing fields of an activity
func (*AddressingValidator) ValidatePrivacyCompliance ¶
func (v *AddressingValidator) ValidatePrivacyCompliance(activity *Activity) error
ValidatePrivacyCompliance ensures activity respects privacy settings
type AgentCapabilities ¶
type AgentCapabilities struct {
CanPost bool `json:"canPost"`
CanReply bool `json:"canReply"`
CanBoost bool `json:"canBoost"`
CanFollow bool `json:"canFollow"`
CanDM bool `json:"canDM"`
RestrictedDomains []string `json:"restrictedDomains,omitempty"`
MaxPostsPerHour int `json:"maxPostsPerHour,omitempty"`
RequiresApproval bool `json:"requiresApproval,omitempty"`
}
AgentCapabilities describe what an agent claims to be able to do. These are informational and should not be treated as authorization.
type AgentManifest ¶
type AgentManifest struct {
Type string `json:"type"`
Version string `json:"version,omitempty"`
Capabilities *AgentCapabilities `json:"capabilities,omitempty"`
Purpose string `json:"purpose,omitempty"`
OperatedBy string `json:"operatedBy,omitempty"`
Source string `json:"source,omitempty"`
}
AgentManifest is a Lesser-specific ActivityPub extension describing an LLM agent account.
It is intentionally optional and designed to degrade gracefully on remote servers that ignore unknown fields.
type AgentPostAttribution ¶
type AgentPostAttribution struct {
TriggerType string `json:"trigger_type,omitempty"`
TriggerDetails string `json:"trigger_details,omitempty"`
MemoryCitations []string `json:"memory_citations,omitempty"`
DelegatedBy string `json:"delegated_by,omitempty"`
Scopes []string `json:"scopes,omitempty"`
Constraints []string `json:"constraints,omitempty"`
ModelVersion string `json:"model_version,omitempty"`
}
AgentPostAttribution captures transparency metadata for an agent-authored post.
This is a Lesser extension. It is stored on the underlying Note and exposed via the REST API as `agent_attribution`.
type Announce ¶
type Announce struct {
Activity
}
Announce represents an announce (boost/share) activity
type Attachment ¶
type Attachment struct {
Type string `json:"type"`
MediaType string `json:"mediaType"`
URL string `json:"url"`
Name string `json:"name,omitempty"`
Value string `json:"value,omitempty"` // For profile metadata
Width int `json:"width,omitempty"`
Height int `json:"height,omitempty"`
}
Attachment represents media attachments
type BaseObject ¶
type BaseObject struct {
Context ContextValue `json:"@context,omitempty"`
ID string `json:"id"`
Type string `json:"type"`
Published *time.Time `json:"published,omitempty"`
Updated *time.Time `json:"updated,omitempty"`
To []string `json:"to,omitempty"`
CC []string `json:"cc,omitempty"`
BTo []string `json:"bto,omitempty"`
BCC []string `json:"bcc,omitempty"`
InReplyTo string `json:"inReplyTo,omitempty"`
Summary string `json:"summary,omitempty"`
Sensitive bool `json:"sensitive,omitempty"`
}
BaseObject represents the base ActivityStreams object
type Collection ¶
type Collection struct {
BaseObject
TotalItems int `json:"totalItems"`
Current string `json:"current,omitempty"`
First string `json:"first,omitempty"`
Last string `json:"last,omitempty"`
Items any `json:"items,omitempty"`
OrderedItems any `json:"orderedItems,omitempty"`
}
Collection represents an ActivityStreams collection
type CollectionPage ¶
type CollectionPage struct {
Collection
PartOf string `json:"partOf"`
Next string `json:"next,omitempty"`
Prev string `json:"prev,omitempty"`
}
CollectionPage represents a page of a collection
type ContextValue ¶
type ContextValue []any
ContextValue wraps the ActivityPub @context field to support both legacy string and modern array representations.
func (ContextValue) Clone ¶
func (c ContextValue) Clone() ContextValue
Clone returns a shallow copy of the context slice so callers can safely append without mutating the shared base context.
func (ContextValue) MarshalJSON ¶
func (c ContextValue) MarshalJSON() ([]byte, error)
MarshalJSON persists the context as a string when a single string value is present, otherwise it writes an array to match ActivityPub expectations.
func (*ContextValue) UnmarshalJSON ¶
func (c *ContextValue) UnmarshalJSON(data []byte) error
UnmarshalJSON accepts either a single string or an array of values.
func (ContextValue) With ¶
func (c ContextValue) With(values ...any) ContextValue
With returns a new context that includes the receiver's entries plus the provided ones.
type DeliveryTargets ¶
type DeliveryTargets struct {
DirectRecipients map[string]bool // Individual actor inboxes
DomainGroups map[string][]string // Recipients grouped by domain for shared inbox optimization
}
DeliveryTargets represents the recipients for federation delivery
func (*DeliveryTargets) GetAllRecipients ¶
func (dt *DeliveryTargets) GetAllRecipients() []string
GetAllRecipients returns all unique recipients
type Image ¶
type Image struct {
BaseObject
URL string `json:"url"`
MediaType string `json:"mediaType,omitempty"`
Width int `json:"width,omitempty"`
Height int `json:"height,omitempty"`
}
Image represents an image object
type Note ¶
type Note struct {
BaseObject
Content string `json:"content"`
AttributedTo string `json:"attributedTo"`
Attachment []Attachment `json:"attachment,omitempty"`
Tag []Tag `json:"tag,omitempty"`
ConversationID string `json:"conversationId,omitempty"` // For tracking conversation threads
Visibility string `json:"_:visibility,omitempty"` // Lesser extension for preserving visibility
QuoteURL string `json:"quoteUrl,omitempty"`
Quoteable bool `json:"_:quoteable,omitempty"`
QuoteNotifications bool `json:"_:quoteNotifications,omitempty"`
QuoteContext *QuoteContext `json:"_:quoteContext,omitempty"`
// Lesser extension: per-status attribution for agent-authored content.
AgentAttribution *AgentPostAttribution `json:"_:agentAttribution,omitempty"`
}
Note represents a basic text post
type OrderedCollection ¶
type OrderedCollection struct {
Collection
}
OrderedCollection represents an ordered ActivityStreams collection
type OrderedCollectionPage ¶
type OrderedCollectionPage struct {
CollectionPage
}
OrderedCollectionPage represents a page of an ordered collection
type PublicKey ¶
type PublicKey struct {
ID string `json:"id"`
Owner string `json:"owner"`
PublicKeyPem string `json:"publicKeyPem"`
}
PublicKey represents an actor's public key for HTTP signatures
type QuoteContext ¶
type QuoteContext struct {
OriginalNoteID string `json:"originalNoteId,omitempty"`
OriginalAuthor string `json:"originalAuthor"`
OriginalAuthorUsername string `json:"originalAuthorUsername,omitempty"`
QuoteCount int `json:"quoteCount"`
AllowWithdrawal bool `json:"allowWithdrawal"`
QuoteAllowed bool `json:"quoteAllowed"`
Withdrawn bool `json:"withdrawn"`
OriginalStatus any `json:"-"`
}
QuoteContext provides metadata about a quoted note
type QuoteNote ¶
type QuoteNote struct {
Note
}
QuoteNote is retained for backwards compatibility; it now simply aliases Note.
type Tag ¶
type Tag struct {
Type string `json:"type"`
Href string `json:"href,omitempty"`
Name string `json:"name"`
}
Tag represents hashtags or mentions
type Tombstone ¶
type Tombstone struct {
BaseObject
FormerType string `json:"formerType,omitempty"` // The original object type
Deleted string `json:"deleted,omitempty"` // ISO 8601 timestamp of deletion
}
Tombstone represents a deleted object placeholder per ActivityPub spec
type WebFingerLink ¶
type WebFingerLink struct {
Rel string `json:"rel"`
Type string `json:"type,omitempty"`
Href string `json:"href,omitempty"`
Template string `json:"template,omitempty"`
}
WebFingerLink represents a link in a WebFinger response
type WebFingerResource ¶
type WebFingerResource struct {
Subject string `json:"subject"`
Aliases []string `json:"aliases,omitempty"`
Links []WebFingerLink `json:"links"`
}
WebFingerResource represents a WebFinger response