Improve content negotiation and activity streams

This commit is contained in:
Jan-Lukas Else 2021-03-10 11:29:20 +01:00
parent 13f770dd7f
commit 163e22c49c
5 changed files with 42 additions and 6 deletions

View File

@ -5,20 +5,28 @@ import (
"crypto/x509"
"encoding/json"
"encoding/pem"
"fmt"
"net/http"
"strings"
"github.com/araddon/dateparse"
"github.com/elnormous/contenttype"
)
var asContext = []string{"https://www.w3.org/ns/activitystreams"}
var asCheckMediaTypes = []contenttype.MediaType{
contenttype.NewMediaType(contentTypeHTML),
contenttype.NewMediaType(contentTypeAS),
contenttype.NewMediaType("application/ld+json"),
}
const asRequestKey requestContextKey = "asRequest"
func checkActivityStreamsRequest(next http.Handler) http.Handler {
return http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) {
if ap := appConfig.ActivityPub; ap != nil && ap.Enabled {
if lowerAccept := strings.ToLower(r.Header.Get("Accept")); (strings.Contains(lowerAccept, contentTypeAS) || strings.Contains(lowerAccept, "application/ld+json")) && !strings.Contains(lowerAccept, contentTypeHTML) {
// Check if accepted media type is not HTML
if mt, _, err := contenttype.GetAcceptableMediaType(r, asCheckMediaTypes); err == nil && mt.String() != asCheckMediaTypes[0].String() {
next.ServeHTTP(rw, r.WithContext(context.WithValue(r.Context(), asRequestKey, true)))
return
}
@ -41,6 +49,7 @@ type asNote struct {
ID string `json:"id,omitempty"`
URL string `json:"url,omitempty"`
AttributedTo string `json:"attributedTo,omitempty"`
Tag []*asTag `json:"tag,omitempty"`
}
type asPerson struct {
@ -62,6 +71,12 @@ type asAttachment struct {
URL string `json:"url,omitempty"`
}
type asTag struct {
Type string `json:"type,omitempty"`
Name string `json:"name,omitempty"`
Href string `json:"href,omitempty"`
}
type asPublicKey struct {
ID string `json:"id,omitempty"`
Owner string `json:"owner,omitempty"`
@ -106,6 +121,16 @@ func (p *post) toASNote() *asNote {
})
}
}
// Tags
for _, tagTax := range appConfig.ActivityPub.TagsTaxonomies {
for _, tag := range p.Parameters[tagTax] {
as.Tag = append(as.Tag, &asTag{
Type: "Hashtag",
Name: tag,
Href: appConfig.Server.PublicAddress + appConfig.Blogs[p.Blog].getRelativePath(fmt.Sprintf("/%s/%s", tagTax, urlize(tag))),
})
}
}
// Dates
dateFormat := "2006-01-02T15:04:05-07:00"
if p.Published != "" {

View File

@ -182,8 +182,9 @@ type configRegexRedirect struct {
}
type configActivityPub struct {
Enabled bool `mapstructure:"enabled"`
KeyPath string `mapstructure:"keyPath"`
Enabled bool `mapstructure:"enabled"`
KeyPath string `mapstructure:"keyPath"`
TagsTaxonomies []string `mapstructure:"tagsTaxonomies"`
}
type configNotifications struct {
@ -230,6 +231,7 @@ func initConfig() error {
viper.SetDefault("micropub.photoParam", "images")
viper.SetDefault("micropub.photoDescriptionParam", "imagealts")
viper.SetDefault("activityPub.keyPath", "data/private.pem")
viper.SetDefault("activityPub.tagsTaxonomies", []string{"tags"})
// Unmarshal config
err = viper.Unmarshal(appConfig)
if err != nil {

View File

@ -3,7 +3,8 @@ package main
import (
"fmt"
"net/http"
"strings"
"github.com/elnormous/contenttype"
)
type errorData struct {
@ -15,8 +16,13 @@ func serve404(w http.ResponseWriter, r *http.Request) {
serveError(w, r, fmt.Sprintf("%s was not found", r.RequestURI), http.StatusNotFound)
}
var errorCheckMediaTypes = []contenttype.MediaType{
contenttype.NewMediaType(contentTypeHTML),
}
func serveError(w http.ResponseWriter, r *http.Request, message string, status int) {
if !strings.Contains(strings.ToLower(r.Header.Get("Accept")), contentTypeHTML) {
if mt, _, err := contenttype.GetAcceptableMediaType(r, errorCheckMediaTypes); err != nil || mt.String() != errorCheckMediaTypes[0].String() {
// Request doesn't accept HTML
http.Error(w, message, status)
return
}

1
go.mod
View File

@ -11,6 +11,7 @@ require (
github.com/caddyserver/certmagic v0.12.0
github.com/dchest/captcha v0.0.0-20200903113550-03f5f0333e1f
github.com/dgrijalva/jwt-go v3.2.0+incompatible
github.com/elnormous/contenttype v0.0.0-20210110050721-79150725153f
github.com/go-chi/chi/v5 v5.0.0
github.com/go-fed/httpsig v1.1.0
github.com/go-sql-driver/mysql v1.5.0 // indirect

2
go.sum
View File

@ -62,6 +62,8 @@ github.com/dgrijalva/jwt-go v3.2.0+incompatible h1:7qlOGliEKZXTDg6OTjfoBKDXWrumC
github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no=
github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
github.com/elnormous/contenttype v0.0.0-20210110050721-79150725153f h1:juwLa2Kbp2uwOGMOagrkTYXN/5+7sbINMmIZSluH2Gc=
github.com/elnormous/contenttype v0.0.0-20210110050721-79150725153f/go.mod h1:ngVcyGGU8pnn4QJ5sL4StrNgc/wmXZXy5IQSBuHOFPg=
github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
github.com/felixge/httpsnoop v1.0.1 h1:lvB5Jl89CsZtGIWuTcDM1E/vkVs49/Ml7JJe07l8SPQ=
github.com/felixge/httpsnoop v1.0.1/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U=