Activity Pub Implementation #58

Merged
h4kor merged 13 commits from activity_pub into main 2024-05-18 14:31:11 +00:00
4 changed files with 56 additions and 26 deletions
Showing only changes of commit ced3907880 - Show all commits

View File

@ -55,12 +55,18 @@ func (cfg *ActivityPubConfig) PrivateKey() *rsa.PrivateKey {
type ActivityPubService struct { type ActivityPubService struct {
followersRepo repository.FollowerRepository followersRepo repository.FollowerRepository
configRepo repository.ConfigRepository configRepo repository.ConfigRepository
siteConfigServcie *SiteConfigService
} }
func NewActivityPubService(followersRepo repository.FollowerRepository, configRepo repository.ConfigRepository) *ActivityPubService { func NewActivityPubService(
followersRepo repository.FollowerRepository,
configRepo repository.ConfigRepository,
siteConfigServcie *SiteConfigService,
) *ActivityPubService {
return &ActivityPubService{ return &ActivityPubService{
followersRepo: followersRepo, followersRepo: followersRepo,
configRepo: configRepo, configRepo: configRepo,
siteConfigServcie: siteConfigServcie,
} }
} }
@ -104,6 +110,27 @@ func (svc *ActivityPubService) GetApConfig() (ActivityPubConfig, error) {
return apConfig, nil return apConfig, nil
} }
func (svc *ActivityPubService) ActorUrl() string {
cfg, _ := svc.siteConfigServcie.GetSiteConfig()
return cfg.FullUrl
}
func (svc *ActivityPubService) MainKeyUri() string {
cfg, _ := svc.siteConfigServcie.GetSiteConfig()
return cfg.FullUrl + "#main-key"
}
func (svc *ActivityPubService) InboxUrl() string {
cfg, _ := svc.siteConfigServcie.GetSiteConfig()
return cfg.FullUrl + "/activitypub/inbox"
}
func (svc *ActivityPubService) OutboxUrl() string {
cfg, _ := svc.siteConfigServcie.GetSiteConfig()
return cfg.FullUrl + "/activitypub/outbox"
}
func (svc *ActivityPubService) FollowersUrl() string {
cfg, _ := svc.siteConfigServcie.GetSiteConfig()
return cfg.FullUrl + "/activitypub/followers"
}
func (s *ActivityPubService) AddFollower(follower string) error { func (s *ActivityPubService) AddFollower(follower string) error {
return s.followersRepo.Add(follower) return s.followersRepo.Add(follower)
} }
@ -157,7 +184,7 @@ func (s *ActivityPubService) GetActor(reqUrl string) (vocab.Actor, error) {
req.Header.Set("Date", time.Now().Format(http.TimeFormat)) req.Header.Set("Date", time.Now().Format(http.TimeFormat))
req.Header.Set("Host", parsedUrl.Host) req.Header.Set("Host", parsedUrl.Host)
err = s.sign(apConfig.PrivateKey(), siteConfig.FullUrl+"/activitypub/actor#main-key", nil, req) err = s.sign(apConfig.PrivateKey(), s.MainKeyUri(), nil, req)
if err != nil { if err != nil {
slog.Error("Signing error", "err", err) slog.Error("Signing error", "err", err)
return vocab.Actor{}, err return vocab.Actor{}, err
@ -195,7 +222,7 @@ func (s *ActivityPubService) VerifySignature(r *http.Request, sender string) err
s.configRepo.Get(config.ACT_PUB_CONF_NAME, &apConfig) s.configRepo.Get(config.ACT_PUB_CONF_NAME, &apConfig)
s.configRepo.Get(config.SITE_CONFIG, &siteConfig) s.configRepo.Get(config.SITE_CONFIG, &siteConfig)
slog.Info("verifying for", "sender", sender, "retriever", siteConfig.FullUrl+"/activitypub/actor") slog.Info("verifying for", "sender", sender, "retriever", s.ActorUrl())
actor, err := s.GetActor(sender) actor, err := s.GetActor(sender)
// actor does not have a pub key -> don't verify // actor does not have a pub key -> don't verify
@ -264,7 +291,7 @@ func (s *ActivityPubService) sendObject(to vocab.Actor, data []byte) error {
req.Header.Set("Accept", "application/ld+json") req.Header.Set("Accept", "application/ld+json")
req.Header.Set("Date", time.Now().Format(http.TimeFormat)) req.Header.Set("Date", time.Now().Format(http.TimeFormat))
req.Header.Set("Host", actorUrl.Host) req.Header.Set("Host", actorUrl.Host)
err = s.sign(apConfig.PrivateKey(), siteConfig.FullUrl+"/activitypub/actor#main-key", data, req) err = s.sign(apConfig.PrivateKey(), s.MainKeyUri(), data, req)
if err != nil { if err != nil {
slog.Error("Signing error", "err", err) slog.Error("Signing error", "err", err)
return err return err

View File

@ -66,7 +66,7 @@ func App(db infra.Database) *web.WebApp {
webmentionService := app.NewWebmentionService( webmentionService := app.NewWebmentionService(
siteConfigService, interactionRepo, entryRepo, httpClient, eventBus, siteConfigService, interactionRepo, entryRepo, httpClient, eventBus,
) )
apService := app.NewActivityPubService(followersRepo, configRepo) apService := app.NewActivityPubService(followersRepo, configRepo, siteConfigService)
// setup render functions // setup render functions
render.SiteConfigService = siteConfigService render.SiteConfigService = siteConfigService

View File

@ -6,6 +6,7 @@ import (
"net/http" "net/http"
"net/url" "net/url"
"owl-blogs/app" "owl-blogs/app"
"strings"
vocab "github.com/go-ap/activitypub" vocab "github.com/go-ap/activitypub"
"github.com/go-ap/jsonld" "github.com/go-ap/jsonld"
@ -63,7 +64,7 @@ func (s *ActivityPubServer) HandleWebfinger(ctx *fiber.Ctx) error {
{ {
Rel: "self", Rel: "self",
Type: "application/activity+json", Type: "application/activity+json",
Href: siteConfig.FullUrl + "/activitypub/actor", Href: s.apService.ActorUrl(),
}, },
}, },
} }
@ -73,24 +74,28 @@ func (s *ActivityPubServer) HandleWebfinger(ctx *fiber.Ctx) error {
} }
func (s *ActivityPubServer) Router(router fiber.Router) { func (s *ActivityPubServer) Router(router fiber.Router) {
router.Get("/actor", s.HandleActor) // router.Get("/actor", s.HandleActor)
router.Get("/outbox", s.HandleOutbox) router.Get("/outbox", s.HandleOutbox)
router.Post("/inbox", s.HandleInbox) router.Post("/inbox", s.HandleInbox)
router.Get("/followers", s.HandleFollowers) router.Get("/followers", s.HandleFollowers)
} }
func (s *ActivityPubServer) HandleActor(ctx *fiber.Ctx) error { func (s *ActivityPubServer) HandleActor(ctx *fiber.Ctx) error {
siteConfig, _ := s.siteConfigService.GetSiteConfig() accepts := strings.Contains(string(ctx.Request().Header.Peek("Accept")), "application/activity+json")
req_content := strings.Contains(string(ctx.Request().Header.Peek("Content-Type")), "application/activity+json")
if !accepts && !req_content {
return ctx.Next()
}
apConfig, _ := s.apService.GetApConfig() apConfig, _ := s.apService.GetApConfig()
actor := vocab.PersonNew(vocab.IRI(siteConfig.FullUrl + "/activitypub/actor")) actor := vocab.PersonNew(vocab.IRI(s.apService.ActorUrl()))
actor.PreferredUsername = vocab.NaturalLanguageValues{{Value: vocab.Content(apConfig.PreferredUsername)}} actor.PreferredUsername = vocab.NaturalLanguageValues{{Value: vocab.Content(apConfig.PreferredUsername)}}
actor.Inbox = vocab.IRI(siteConfig.FullUrl + "/activitypub/inbox") actor.Inbox = vocab.IRI(s.apService.InboxUrl())
actor.Outbox = vocab.IRI(siteConfig.FullUrl + "/activitypub/outbox") actor.Outbox = vocab.IRI(s.apService.OutboxUrl())
actor.Followers = vocab.IRI(siteConfig.FullUrl + "/activitypub/followers") actor.Followers = vocab.IRI(s.apService.FollowersUrl())
actor.PublicKey = vocab.PublicKey{ actor.PublicKey = vocab.PublicKey{
ID: vocab.ID(siteConfig.FullUrl + "/activitypub/actor#main-key"), ID: vocab.IRI(s.apService.MainKeyUri()),
Owner: vocab.IRI(siteConfig.FullUrl + "/activitypub/actor"), Owner: vocab.IRI(s.apService.ActorUrl()),
PublicKeyPem: apConfig.PublicKeyPem, PublicKeyPem: apConfig.PublicKeyPem,
} }
data, err := jsonld.WithContext( data, err := jsonld.WithContext(
@ -125,7 +130,7 @@ func (s *ActivityPubServer) HandleOutbox(ctx *fiber.Ctx) error {
}) })
} }
outbox := vocab.OrderedCollectionNew(vocab.IRI(siteConfig.FullUrl + "/activitypub/outbox")) outbox := vocab.OrderedCollectionNew(vocab.IRI(s.apService.OutboxUrl()))
outbox.TotalItems = uint(len(items)) outbox.TotalItems = uint(len(items))
outbox.OrderedItems = items outbox.OrderedItems = items
@ -205,9 +210,6 @@ func (s *ActivityPubServer) HandleInbox(ctx *fiber.Ctx) error {
} }
func (s *ActivityPubServer) HandleFollowers(ctx *fiber.Ctx) error { func (s *ActivityPubServer) HandleFollowers(ctx *fiber.Ctx) error {
siteConfig, _ := s.siteConfigService.GetSiteConfig()
// apConfig, _ := s.apService.GetApConfig()
fs, err := s.apService.AllFollowers() fs, err := s.apService.AllFollowers()
if err != nil { if err != nil {
return err return err
@ -218,7 +220,7 @@ func (s *ActivityPubServer) HandleFollowers(ctx *fiber.Ctx) error {
followers.Append(vocab.IRI(f)) followers.Append(vocab.IRI(f))
} }
followers.TotalItems = uint(len(fs)) followers.TotalItems = uint(len(fs))
followers.ID = vocab.IRI(siteConfig.FullUrl + "/activitypub/followers") followers.ID = vocab.IRI(s.apService.FollowersUrl())
data, err := jsonld.WithContext( data, err := jsonld.WithContext(
jsonld.IRI(vocab.ActivityBaseURI), jsonld.IRI(vocab.ActivityBaseURI),
).Marshal(followers) ).Marshal(followers)

View File

@ -109,12 +109,15 @@ func NewWebApp(
siteConfig.Post("/menus/create/", siteConfigMenusHandler.HandleCreate) siteConfig.Post("/menus/create/", siteConfigMenusHandler.HandleCreate)
siteConfig.Post("/menus/delete/", siteConfigMenusHandler.HandleDelete) siteConfig.Post("/menus/delete/", siteConfigMenusHandler.HandleDelete)
activityPubServer := NewActivityPubServer(siteConfigService, entryService, apService)
configRegister.Register(config.ACT_PUB_CONF_NAME, &app.ActivityPubConfig{})
fiberApp.Use("/static", filesystem.New(filesystem.Config{ fiberApp.Use("/static", filesystem.New(filesystem.Config{
Root: http.FS(embedDirStatic), Root: http.FS(embedDirStatic),
PathPrefix: "static", PathPrefix: "static",
Browse: false, Browse: false,
})) }))
fiberApp.Get("/", indexHandler.Handle) fiberApp.Get("/", activityPubServer.HandleActor, indexHandler.Handle)
fiberApp.Get("/lists/:list/", listHandler.Handle) fiberApp.Get("/lists/:list/", listHandler.Handle)
// Media // Media
fiberApp.Get("/media/+", mediaHandler.Handle) fiberApp.Get("/media/+", mediaHandler.Handle)
@ -135,8 +138,6 @@ func NewWebApp(
fiberApp.Get("/sitemap.xml", NewSiteMapHandler(entryService, siteConfigService).Handle) fiberApp.Get("/sitemap.xml", NewSiteMapHandler(entryService, siteConfigService).Handle)
// ActivityPub // ActivityPub
activityPubServer := NewActivityPubServer(siteConfigService, entryService, apService)
configRegister.Register(config.ACT_PUB_CONF_NAME, &app.ActivityPubConfig{})
fiberApp.Get("/.well-known/webfinger", activityPubServer.HandleWebfinger) fiberApp.Get("/.well-known/webfinger", activityPubServer.HandleWebfinger)
fiberApp.Route("/activitypub", activityPubServer.Router) fiberApp.Route("/activitypub", activityPubServer.Router)