WIP minimal AP

This commit is contained in:
Niko Abeler 2023-07-26 21:28:57 +02:00
parent 5f49754b71
commit 5e77fdd33b
4 changed files with 84 additions and 58 deletions

5
go.mod
View File

@ -15,8 +15,12 @@ require (
) )
require ( require (
git.sr.ht/~mariusor/go-xsd-duration v0.0.0-20220703122237-02e73435a078 // indirect
github.com/andybalholm/brotli v1.0.5 // indirect github.com/andybalholm/brotli v1.0.5 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect github.com/davecgh/go-spew v1.1.1 // indirect
github.com/go-ap/activitypub v0.0.0-20230719093539-2b6a6f3a25ee // indirect
github.com/go-ap/errors v0.0.0-20221205040414-01c1adfc98ea // indirect
github.com/go-ap/jsonld v0.0.0-20221030091449-f2a191312c73 // indirect
github.com/inconshreveable/mousetrap v1.1.0 // indirect github.com/inconshreveable/mousetrap v1.1.0 // indirect
github.com/klauspost/compress v1.16.3 // indirect github.com/klauspost/compress v1.16.3 // indirect
github.com/mattn/go-colorable v0.1.13 // indirect github.com/mattn/go-colorable v0.1.13 // indirect
@ -31,6 +35,7 @@ require (
github.com/tinylib/msgp v1.1.8 // indirect github.com/tinylib/msgp v1.1.8 // indirect
github.com/valyala/bytebufferpool v1.0.0 // indirect github.com/valyala/bytebufferpool v1.0.0 // indirect
github.com/valyala/fasthttp v1.47.0 // indirect github.com/valyala/fasthttp v1.47.0 // indirect
github.com/valyala/fastjson v1.6.4 // indirect
github.com/valyala/tcplisten v1.0.0 // indirect github.com/valyala/tcplisten v1.0.0 // indirect
golang.org/x/sys v0.10.0 // indirect golang.org/x/sys v0.10.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect

11
go.sum
View File

@ -1,8 +1,16 @@
git.sr.ht/~mariusor/go-xsd-duration v0.0.0-20220703122237-02e73435a078 h1:cliQ4HHsCo6xi2oWZYKWW4bly/Ory9FuTpFPRxj/mAg=
git.sr.ht/~mariusor/go-xsd-duration v0.0.0-20220703122237-02e73435a078/go.mod h1:g/V2Hjas6Z1UHUp4yIx6bATpNzJ7DYtD0FG3+xARWxs=
github.com/andybalholm/brotli v1.0.5 h1:8uQZIdzKmjc/iuPu7O2ioW48L81FgatrcpfFmiq/cCs= github.com/andybalholm/brotli v1.0.5 h1:8uQZIdzKmjc/iuPu7O2ioW48L81FgatrcpfFmiq/cCs=
github.com/andybalholm/brotli v1.0.5/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig= github.com/andybalholm/brotli v1.0.5/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig=
github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/go-ap/activitypub v0.0.0-20230719093539-2b6a6f3a25ee h1:1OMBlmSzLXftIj5z/D1s1Xr3FanVKtLFZPtdIFslh1A=
github.com/go-ap/activitypub v0.0.0-20230719093539-2b6a6f3a25ee/go.mod h1:qw0WNf+PTG69Xu6mVqUluDuKl1VwVYdgntOZQFBZQ48=
github.com/go-ap/errors v0.0.0-20221205040414-01c1adfc98ea h1:ywGtLGVjJjMrq4mu35Qmu+NtlhlTk/gTayE6Bb4tQZk=
github.com/go-ap/errors v0.0.0-20221205040414-01c1adfc98ea/go.mod h1:SaTNjEEkp0q+w3pUS1ccyEL/lUrHteORlDq/e21mCc8=
github.com/go-ap/jsonld v0.0.0-20221030091449-f2a191312c73 h1:GMKIYXyXPGIp+hYiWOhfqK4A023HdgisDT4YGgf99mw=
github.com/go-ap/jsonld v0.0.0-20221030091449-f2a191312c73/go.mod h1:jyveZeGw5LaADntW+UEsMjl3IlIwk+DxlYNsbofQkGA=
github.com/go-sql-driver/mysql v1.6.0 h1:BCTh4TKNUYmOmMUcQ3IipzF5prigylS7XXjEkfCHuOE= github.com/go-sql-driver/mysql v1.6.0 h1:BCTh4TKNUYmOmMUcQ3IipzF5prigylS7XXjEkfCHuOE=
github.com/go-sql-driver/mysql v1.6.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg= github.com/go-sql-driver/mysql v1.6.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
github.com/gofiber/fiber/v2 v2.47.0 h1:EN5lHVCc+Pyqh5OEsk8fzRiifgwpbrP0rulQ4iNf3fs= github.com/gofiber/fiber/v2 v2.47.0 h1:EN5lHVCc+Pyqh5OEsk8fzRiifgwpbrP0rulQ4iNf3fs=
@ -53,6 +61,9 @@ github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6Kllzaw
github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc=
github.com/valyala/fasthttp v1.47.0 h1:y7moDoxYzMooFpT5aHgNgVOQDrS3qlkfiP9mDtGGK9c= github.com/valyala/fasthttp v1.47.0 h1:y7moDoxYzMooFpT5aHgNgVOQDrS3qlkfiP9mDtGGK9c=
github.com/valyala/fasthttp v1.47.0/go.mod h1:k2zXd82h/7UZc3VOdJ2WaUqt1uZ/XpXAfE9i+HBC3lA= github.com/valyala/fasthttp v1.47.0/go.mod h1:k2zXd82h/7UZc3VOdJ2WaUqt1uZ/XpXAfE9i+HBC3lA=
github.com/valyala/fastjson v1.6.3/go.mod h1:CLCAqky6SMuOcxStkYQvblddUtoRxhYMGLrsQns1aXY=
github.com/valyala/fastjson v1.6.4 h1:uAUNq9Z6ymTgGhcm0UynUAB6tlbakBrz6CQFax3BXVQ=
github.com/valyala/fastjson v1.6.4/go.mod h1:CLCAqky6SMuOcxStkYQvblddUtoRxhYMGLrsQns1aXY=
github.com/valyala/tcplisten v1.0.0 h1:rBHj/Xf+E1tRGZyWIWwJDiRY0zc1Js+CV5DqwacVSA8= github.com/valyala/tcplisten v1.0.0 h1:rBHj/Xf+E1tRGZyWIWwJDiRY0zc1Js+CV5DqwacVSA8=
github.com/valyala/tcplisten v1.0.0/go.mod h1:T0xQ8SeCZGxckz9qRXTfG43PvQ/mcWh7FwZEA7Ioqkc= github.com/valyala/tcplisten v1.0.0/go.mod h1:T0xQ8SeCZGxckz9qRXTfG43PvQ/mcWh7FwZEA7Ioqkc=
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=

View File

@ -1,17 +1,22 @@
package web package web
import ( import (
"net/url"
"owl-blogs/app"
"owl-blogs/app/repository" "owl-blogs/app/repository"
"owl-blogs/config" "owl-blogs/config"
"owl-blogs/domain/model" "owl-blogs/domain/model"
vocab "github.com/go-ap/activitypub"
"github.com/gofiber/fiber/v2" "github.com/gofiber/fiber/v2"
) )
const ACT_PUB_CONF_NAME = "activity_pub" const ACT_PUB_CONF_NAME = "activity_pub"
type ActivityPubServer struct { type ActivityPubServer struct {
configRepo repository.ConfigRepository configRepo repository.ConfigRepository
entryService *app.EntryService
} }
type ActivityPubConfig struct { type ActivityPubConfig struct {
@ -21,48 +26,20 @@ type ActivityPubConfig struct {
} }
type WebfingerResponse struct { type WebfingerResponse struct {
Subject string `json:"subject"` Subject string `json:"subject"`
Links []ActivityPubLink `json:"links"` Links []WebfingerLink `json:"links"`
} }
type ActivityPubLink struct { type WebfingerLink struct {
Rel string `json:"rel"` Rel string `json:"rel"`
Type string `json:"type"` Type string `json:"type"`
Href string `json:"href"` Href string `json:"href"`
} }
type ActivityPubActor struct { func NewActivityPubServer(configRepo repository.ConfigRepository, entryService *app.EntryService) *ActivityPubServer {
Context []string `json:"@context"`
ID string `json:"id"`
Type string `json:"type"`
PreferredUsername string `json:"preferredUsername"`
Inbox string `json:"inbox"`
Oubox string `json:"outbox"`
Followers string `json:"followers"`
PublicKey ActivityPubPublicKey `json:"publicKey"`
}
type ActivityPubPublicKey struct {
ID string `json:"id"`
Owner string `json:"owner"`
PublicKeyPem string `json:"publicKeyPem"`
}
type ActivityPubOrderedCollection struct {
Context []string `json:"@context"`
ID string `json:"id"`
Type string `json:"type"`
TotalItems int `json:"totalItems"`
First string `json:"first"`
Last string `json:"last"`
}
func NewActivityPubServer(configRepo repository.ConfigRepository) *ActivityPubServer {
return &ActivityPubServer{ return &ActivityPubServer{
configRepo: configRepo, configRepo: configRepo,
entryService: entryService,
} }
} }
@ -75,7 +52,7 @@ func (s *ActivityPubServer) HandleWebfinger(ctx *fiber.Ctx) error {
webfinger := WebfingerResponse{ webfinger := WebfingerResponse{
Subject: ctx.Query("resource"), Subject: ctx.Query("resource"),
Links: []ActivityPubLink{ Links: []WebfingerLink{
{ {
Rel: "self", Rel: "self",
Type: "application/activity+json", Type: "application/activity+json",
@ -90,6 +67,7 @@ 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)
} }
func (s *ActivityPubServer) HandleActor(ctx *fiber.Ctx) error { func (s *ActivityPubServer) HandleActor(ctx *fiber.Ctx) error {
@ -98,25 +76,57 @@ func (s *ActivityPubServer) HandleActor(ctx *fiber.Ctx) error {
s.configRepo.Get(ACT_PUB_CONF_NAME, &apConfig) s.configRepo.Get(ACT_PUB_CONF_NAME, &apConfig)
s.configRepo.Get(config.SITE_CONFIG, &siteConfig) s.configRepo.Get(config.SITE_CONFIG, &siteConfig)
actor := ActivityPubActor{ actor := vocab.PersonNew(vocab.IRI(siteConfig.FullUrl + "/activitypub/actor"))
Context: []string{ actor.PreferredUsername = vocab.NaturalLanguageValues{{Value: vocab.Content(apConfig.PreferredUsername)}}
"https://www.w3.org/ns/activitystreams", actor.Inbox = vocab.IRI(siteConfig.FullUrl + "/activitypub/inbox")
"https://w3id.org/security/v1", actor.Outbox = vocab.IRI(siteConfig.FullUrl + "/activitypub/outbox")
}, actor.Followers = vocab.IRI(siteConfig.FullUrl + "/activitypub/followers")
actor.PublicKey = vocab.PublicKey{
ID: siteConfig.FullUrl + "/activitypub/actor", ID: vocab.ID(siteConfig.FullUrl + "/activitypub/actor#main-key"),
Type: "Person", Owner: vocab.IRI(siteConfig.FullUrl + "/activitypub/actor"),
PreferredUsername: apConfig.PreferredUsername, PublicKeyPem: apConfig.PublicKeyPem,
Inbox: siteConfig.FullUrl + "/activitypub/inbox",
Oubox: siteConfig.FullUrl + "/activitypub/outbox",
Followers: siteConfig.FullUrl + "/activitypub/followers",
PublicKey: ActivityPubPublicKey{
ID: siteConfig.FullUrl + "/activitypub/actor#main-key",
Owner: siteConfig.FullUrl + "/activitypub/actor",
PublicKeyPem: apConfig.PublicKeyPem,
},
} }
return ctx.JSON(actor) data, err := actor.MarshalJSON()
if err != nil {
return err
}
ctx.Set("Content-Type", "application/activity+json")
return ctx.Send(data)
}
func (s *ActivityPubServer) HandleOutbox(ctx *fiber.Ctx) error {
siteConfig := model.SiteConfig{}
apConfig := ActivityPubConfig{}
s.configRepo.Get(ACT_PUB_CONF_NAME, &apConfig)
s.configRepo.Get(config.SITE_CONFIG, &siteConfig)
entries, err := s.entryService.FindAllByType(nil, true, false)
if err != nil {
return err
}
items := make([]vocab.Item, len(entries))
for i, entry := range entries {
url, _ := url.JoinPath(siteConfig.FullUrl, "/posts/"+entry.ID()+"/")
items[i] = *vocab.ActivityNew(vocab.IRI(url), vocab.CreateType, vocab.Object{
ID: vocab.ID(url),
Type: vocab.ArticleType,
Content: vocab.NaturalLanguageValues{
{Value: vocab.Content(entry.Content())},
},
})
}
outbox := vocab.OrderedCollectionNew(vocab.IRI(siteConfig.FullUrl + "/activitypub/outbox"))
outbox.TotalItems = uint(len(items))
outbox.OrderedItems = items
data, err := outbox.MarshalJSON()
if err != nil {
return err
}
ctx.Set("Content-Type", "application/activity+json")
return ctx.Send(data)
} }

View File

@ -118,10 +118,10 @@ func NewWebApp(
app.Get("/sitemap.xml", NewSiteMapHandler(entryService, configRepo).Handle) app.Get("/sitemap.xml", NewSiteMapHandler(entryService, configRepo).Handle)
// ActivityPub // ActivityPub
// activityPubServer := NewActivityPubServer(configRepo) activityPubServer := NewActivityPubServer(configRepo, entryService)
configRegister.Register(ACT_PUB_CONF_NAME, &ActivityPubConfig{}) configRegister.Register(ACT_PUB_CONF_NAME, &ActivityPubConfig{})
// app.Get("/.well-known/webfinger", activityPubServer.HandleWebfinger) app.Get("/.well-known/webfinger", activityPubServer.HandleWebfinger)
// app.Route("/activitypub", activityPubServer.Router) app.Route("/activitypub", activityPubServer.Router)
// Webmention // Webmention
// app.Post("/webmention/", userWebmentionHandler(repo)) // app.Post("/webmention/", userWebmentionHandler(repo))