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 {
followersRepo repository.FollowerRepository
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{
followersRepo: followersRepo,
configRepo: configRepo,
siteConfigServcie: siteConfigServcie,
}
}
@ -104,6 +110,27 @@ func (svc *ActivityPubService) GetApConfig() (ActivityPubConfig, error) {
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 {
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("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 {
slog.Error("Signing error", "err", 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.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 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("Date", time.Now().Format(http.TimeFormat))
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 {
slog.Error("Signing error", "err", err)
return err

View File

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

View File

@ -6,6 +6,7 @@ import (
"net/http"
"net/url"
"owl-blogs/app"
"strings"
vocab "github.com/go-ap/activitypub"
"github.com/go-ap/jsonld"
@ -63,7 +64,7 @@ func (s *ActivityPubServer) HandleWebfinger(ctx *fiber.Ctx) error {
{
Rel: "self",
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) {
router.Get("/actor", s.HandleActor)
// router.Get("/actor", s.HandleActor)
router.Get("/outbox", s.HandleOutbox)
router.Post("/inbox", s.HandleInbox)
router.Get("/followers", s.HandleFollowers)
}
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()
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.Inbox = vocab.IRI(siteConfig.FullUrl + "/activitypub/inbox")
actor.Outbox = vocab.IRI(siteConfig.FullUrl + "/activitypub/outbox")
actor.Followers = vocab.IRI(siteConfig.FullUrl + "/activitypub/followers")
actor.Inbox = vocab.IRI(s.apService.InboxUrl())
actor.Outbox = vocab.IRI(s.apService.OutboxUrl())
actor.Followers = vocab.IRI(s.apService.FollowersUrl())
actor.PublicKey = vocab.PublicKey{
ID: vocab.ID(siteConfig.FullUrl + "/activitypub/actor#main-key"),
Owner: vocab.IRI(siteConfig.FullUrl + "/activitypub/actor"),
ID: vocab.IRI(s.apService.MainKeyUri()),
Owner: vocab.IRI(s.apService.ActorUrl()),
PublicKeyPem: apConfig.PublicKeyPem,
}
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.OrderedItems = items
@ -205,9 +210,6 @@ func (s *ActivityPubServer) HandleInbox(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()
if err != nil {
return err
@ -218,7 +220,7 @@ func (s *ActivityPubServer) HandleFollowers(ctx *fiber.Ctx) error {
followers.Append(vocab.IRI(f))
}
followers.TotalItems = uint(len(fs))
followers.ID = vocab.IRI(siteConfig.FullUrl + "/activitypub/followers")
followers.ID = vocab.IRI(s.apService.FollowersUrl())
data, err := jsonld.WithContext(
jsonld.IRI(vocab.ActivityBaseURI),
).Marshal(followers)

View File

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