Activity Pub Implementation #58
|
@ -53,14 +53,20 @@ func (cfg *ActivityPubConfig) PrivateKey() *rsa.PrivateKey {
|
|||
}
|
||||
|
||||
type ActivityPubService struct {
|
||||
followersRepo repository.FollowerRepository
|
||||
configRepo repository.ConfigRepository
|
||||
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,
|
||||
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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
|
||||
|
|
Loading…
Reference in New Issue