Documentation
¶
Overview ¶
Package gap implements the ActivityPub protocol (ActivityStreams 2.0) for Go.
GAP — Go ActivityPub. A lightweight, zero-dependency, framework-agnostic library for building federated social applications in Go.
What gap provides ¶
ActivityPub types that follow the ActivityStreams 2.0 vocabulary:
- Actor (Person, Application, Service, etc.)
- Activity (Create, Follow, Like, Announce, Undo, Delete, Accept, Reject)
- Note (equivalent to a Mastodon status/toot)
- Collection (OrderedCollection with totalItems)
- PublicKey (actor's public key for HTTP Signatures)
Discovery types:
- WebFingerResponse / WebFingerLink (RFC 7033)
- NodeInfo (NodeInfo 2.0 for instance discovery)
HTTP Signatures (draft-cavage-http-signatures-12):
- SignRequest — sign an outbound HTTP request with RSA-SHA256
- VerifyRequest — verify an incoming HTTP Signature
- DeliverActivity — sign and POST an ActivityPub activity to a remote inbox
- AddDateHeader / AddDigestHeader — set required signature headers
- GenerateKeyPair — generate RSA-2048 key pair (returns PEM strings)
Linked Data Signatures:
- SignJSONLD — sign a JSON-LD document with RsaSignature2017
- VerifyJSONLD — verify a Linked Data Signature on a document
Safe HTTP client:
- SafeClient / NewSafeClient — HTTP client with SSRF protection
- ResolveActorURI — extract username and domain from an actor URI
What gap does NOT provide ¶
Gap is intentionally minimal. It does NOT include:
- Database storage
- HTTP routing (use Gin, Echo, Chi, net/http, etc.)
- Queue/worker systems
- Real-time streaming / WebSockets
- OAuth2 / authentication
- Content formatting / HTML rendering
These belong in your application layer. Gap is the protocol foundation.
Quick start ¶
import "github.com/Guaderxx/gap"
// Generate keys
privKey, pubKey, _ := gap.GenerateKeyPair()
// Create an actor
actor := gap.Actor{
ID: "https://example.com/users/alice",
Type: "Person",
Inbox: "https://example.com/users/alice/inbox",
PublicKey: &gap.PublicKey{
ID: "https://example.com/users/alice#main-key",
Owner: "https://example.com/users/alice",
PublicKeyPem: pubKey,
},
}
// Deliver a Follow activity
activity := gap.Activity{
Type: "Follow",
Actor: "https://example.com/users/alice",
Object: "https://mastodon.example/users/bob",
}
body, _ := json.Marshal(activity)
gap.DeliverActivity(inboxURL, body, keyID, privKey)
See example/main.go for a complete working server.
Index ¶
- Constants
- func AddDateHeader(req *http.Request)
- func AddDigestHeader(req *http.Request, body []byte)
- func DeliverActivity(inboxURL string, activityJSON []byte, keyID string, privateKeyPEM string) error
- func GenerateKeyPair() (privatePEM, publicPEM string, err error)
- func ResolveActorURI(uri string) (username, domain string)
- func SignJSONLD(document map[string]interface{}, keyPair LDKeyPair) (string, error)
- func SignRequest(req *http.Request, keyID string, privateKeyPEM string) error
- func VerifyJSONLD(document map[string]interface{}, signature map[string]interface{}, ...) (bool, error)
- func VerifyRequest(req *http.Request, publicKeyPEM string) (bool, error)
- type Activity
- type Actor
- type Collection
- type Image
- type LDKeyPair
- type NodeInfo
- type NodeInfoSoftware
- type NodeInfoUsage
- type NodeInfoUsers
- type Note
- type PublicKey
- type SafeClient
- type WebFingerLink
- type WebFingerResponse
Constants ¶
const ( ContextActivityStreams = "https://www.w3.org/ns/activitystreams" ContextSecurity = "https://w3id.org/security/v1" PublicAddress = "https://www.w3.org/ns/activitystreams#Public" )
ActivityStreams 2.0 context URIs used in all ActivityPub documents.
const ( ActivityAccept = "Accept" ActivityAdd = "Add" ActivityAnnounce = "Announce" // equivalent to a Mastodon boost/reblog ActivityBlock = "Block" ActivityCreate = "Create" ActivityDelete = "Delete" ActivityFlag = "Flag" // report ActivityFollow = "Follow" ActivityLike = "Like" // equivalent to a Mastodon favourite ActivityMove = "Move" // account migration ActivityReject = "Reject" ActivityRemove = "Remove" ActivityUndo = "Undo" ActivityUpdate = "Update" ActivityView = "View" )
Activity types as defined by ActivityStreams 2.0. Use these constants instead of raw strings for type safety.
const ( ActorPerson = "Person" ActorApplication = "Application" ActorService = "Service" ActorGroup = "Group" ActorOrganization = "Organization" )
Actor types as defined by ActivityStreams 2.0.
const ( ObjectNote = "Note" ObjectArticle = "Article" ObjectDocument = "Document" ObjectImage = "Image" ObjectVideo = "Video" ObjectAudio = "Audio" ObjectPage = "Page" ObjectEvent = "Event" ObjectPlace = "Place" ObjectQuestion = "Question" ObjectCollectionType = "OrderedCollection" )
Object types as defined by ActivityStreams 2.0.
Variables ¶
This section is empty.
Functions ¶
func AddDateHeader ¶
AddDateHeader sets the Date header for HTTP Signature purposes.
func AddDigestHeader ¶
AddDigestHeader computes and sets the Digest header for the request body.
func DeliverActivity ¶
func DeliverActivity(inboxURL string, activityJSON []byte, keyID string, privateKeyPEM string) error
DeliverActivity sends an ActivityPub activity JSON to a remote inbox. It sets the proper headers, signs the request, and handles the HTTP delivery.
func GenerateKeyPair ¶
GenerateKeyPair creates a new RSA 2048-bit key pair for HTTP Signatures. Returns the private key PEM and public key PEM.
func ResolveActorURI ¶
ResolveActorURI extracts username and domain from an ActivityPub actor URI. For example, "https://mastodon.example/users/alice" returns ("alice", "mastodon.example").
func SignJSONLD ¶
SignJSONLD signs a JSON-LD document using RSA-SHA256 Linked Data Signatures. This is primarily for backward compatibility with older ActivityPub implementations. Mastodon 4.x primarily uses HTTP Signatures (see signature.go).
func SignRequest ¶
SignRequest signs an HTTP request with an RSA-SHA256 HTTP Signature (draft-cavage-http-signatures). It adds the Signature header to the request. The keyID should be the URL of the actor's public key.
Types ¶
type Activity ¶
type Activity struct {
Context []string `json:"@context"`
ID string `json:"id"`
Type string `json:"type"`
Actor string `json:"actor"`
Object interface{} `json:"object,omitempty"`
To []string `json:"to,omitempty"`
CC []string `json:"cc,omitempty"`
}
Activity represents an ActivityPub activity (Create, Follow, Like, etc.).
type Actor ¶
type Actor struct {
Context []string `json:"@context"`
Type string `json:"type"`
ID string `json:"id"`
Name string `json:"name,omitempty"`
PreferredUsername string `json:"preferredUsername"`
Summary string `json:"summary,omitempty"`
Inbox string `json:"inbox"`
Outbox string `json:"outbox"`
Followers string `json:"followers,omitempty"`
Following string `json:"following,omitempty"`
URL string `json:"url,omitempty"`
PublicKey *PublicKey `json:"publicKey,omitempty"`
Icon *Image `json:"icon,omitempty"`
Image *Image `json:"image,omitempty"`
Endpoints map[string]string `json:"endpoints,omitempty"`
}
Actor represents an ActivityPub actor (Person, Application, Service, etc.).
type Collection ¶
type Collection struct {
Context []string `json:"@context"`
ID string `json:"id"`
Type string `json:"type"`
TotalItems int `json:"totalItems"`
First string `json:"first,omitempty"`
OrderedItems []interface{} `json:"orderedItems,omitempty"`
}
Collection represents an ActivityPub ordered collection (followers, following, outbox).
type Image ¶
type Image struct {
Type string `json:"type"`
MediaType string `json:"mediaType"`
URL string `json:"url"`
}
Image represents an attached image in ActivityPub documents.
type LDKeyPair ¶
type LDKeyPair struct {
ID string `json:"id"`
Owner string `json:"owner"`
PrivateKey string `json:"privateKeyPem"`
PublicKey string `json:"publicKeyPem"`
}
LDKeyPair holds RSA keys for Linked Data Signatures.
type NodeInfo ¶
type NodeInfo struct {
Version string `json:"version"`
Software NodeInfoSoftware `json:"software"`
Protocols []string `json:"protocols"`
Usage NodeInfoUsage `json:"usage"`
OpenRegistrations bool `json:"openRegistrations"`
}
NodeInfo is the standard node information response (NodeInfo 2.0).
type NodeInfoSoftware ¶
NodeInfoSoftware describes the server software.
type NodeInfoUsage ¶
type NodeInfoUsage struct {
Users NodeInfoUsers `json:"users"`
}
NodeInfoUsage contains instance statistics.
type NodeInfoUsers ¶
type NodeInfoUsers struct {
Total int `json:"total"`
}
NodeInfoUsers contains user counts.
type Note ¶
type Note struct {
ID string `json:"id"`
Type string `json:"type"`
AttributedTo string `json:"attributedTo"`
Content string `json:"content"`
Published string `json:"published"`
To []string `json:"to,omitempty"`
CC []string `json:"cc,omitempty"`
InReplyTo string `json:"inReplyTo,omitempty"`
Sensitive bool `json:"sensitive,omitempty"`
Summary string `json:"summary,omitempty"`
URL string `json:"url,omitempty"`
}
Note represents an ActivityPub Note (equivalent to a Mastodon status/toot).
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 SafeClient ¶
type SafeClient struct {
// contains filtered or unexported fields
}
SafeClient is an HTTP client with SSRF protection. It blocks requests to private/internal IP ranges to prevent server-side request forgery.
func NewSafeClient ¶
func NewSafeClient() *SafeClient
NewSafeClient creates an HTTP client with SSRF protection and a 30-second timeout.
type WebFingerLink ¶
type WebFingerLink struct {
Rel string `json:"rel,omitempty"`
Type string `json:"type,omitempty"`
Href string `json:"href,omitempty"`
}
WebFingerLink represents a link in a WebFinger JRD response (RFC 7033).
type WebFingerResponse ¶
type WebFingerResponse struct {
Subject string `json:"subject"`
Aliases []string `json:"aliases,omitempty"`
Links []WebFingerLink `json:"links,omitempty"`
}
WebFingerResponse is the JSON Resource Descriptor for WebFinger.