mirror of https://github.com/jlelse/GoBlog
Improve content negotiation and activity streams
This commit is contained in:
parent
13f770dd7f
commit
163e22c49c
|
@ -5,20 +5,28 @@ import (
|
||||||
"crypto/x509"
|
"crypto/x509"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"encoding/pem"
|
"encoding/pem"
|
||||||
|
"fmt"
|
||||||
"net/http"
|
"net/http"
|
||||||
"strings"
|
|
||||||
|
|
||||||
"github.com/araddon/dateparse"
|
"github.com/araddon/dateparse"
|
||||||
|
"github.com/elnormous/contenttype"
|
||||||
)
|
)
|
||||||
|
|
||||||
var asContext = []string{"https://www.w3.org/ns/activitystreams"}
|
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"
|
const asRequestKey requestContextKey = "asRequest"
|
||||||
|
|
||||||
func checkActivityStreamsRequest(next http.Handler) http.Handler {
|
func checkActivityStreamsRequest(next http.Handler) http.Handler {
|
||||||
return http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) {
|
return http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) {
|
||||||
if ap := appConfig.ActivityPub; ap != nil && ap.Enabled {
|
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)))
|
next.ServeHTTP(rw, r.WithContext(context.WithValue(r.Context(), asRequestKey, true)))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -41,6 +49,7 @@ type asNote struct {
|
||||||
ID string `json:"id,omitempty"`
|
ID string `json:"id,omitempty"`
|
||||||
URL string `json:"url,omitempty"`
|
URL string `json:"url,omitempty"`
|
||||||
AttributedTo string `json:"attributedTo,omitempty"`
|
AttributedTo string `json:"attributedTo,omitempty"`
|
||||||
|
Tag []*asTag `json:"tag,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type asPerson struct {
|
type asPerson struct {
|
||||||
|
@ -62,6 +71,12 @@ type asAttachment struct {
|
||||||
URL string `json:"url,omitempty"`
|
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 {
|
type asPublicKey struct {
|
||||||
ID string `json:"id,omitempty"`
|
ID string `json:"id,omitempty"`
|
||||||
Owner string `json:"owner,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
|
// Dates
|
||||||
dateFormat := "2006-01-02T15:04:05-07:00"
|
dateFormat := "2006-01-02T15:04:05-07:00"
|
||||||
if p.Published != "" {
|
if p.Published != "" {
|
||||||
|
|
|
@ -184,6 +184,7 @@ type configRegexRedirect struct {
|
||||||
type configActivityPub struct {
|
type configActivityPub struct {
|
||||||
Enabled bool `mapstructure:"enabled"`
|
Enabled bool `mapstructure:"enabled"`
|
||||||
KeyPath string `mapstructure:"keyPath"`
|
KeyPath string `mapstructure:"keyPath"`
|
||||||
|
TagsTaxonomies []string `mapstructure:"tagsTaxonomies"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type configNotifications struct {
|
type configNotifications struct {
|
||||||
|
@ -230,6 +231,7 @@ func initConfig() error {
|
||||||
viper.SetDefault("micropub.photoParam", "images")
|
viper.SetDefault("micropub.photoParam", "images")
|
||||||
viper.SetDefault("micropub.photoDescriptionParam", "imagealts")
|
viper.SetDefault("micropub.photoDescriptionParam", "imagealts")
|
||||||
viper.SetDefault("activityPub.keyPath", "data/private.pem")
|
viper.SetDefault("activityPub.keyPath", "data/private.pem")
|
||||||
|
viper.SetDefault("activityPub.tagsTaxonomies", []string{"tags"})
|
||||||
// Unmarshal config
|
// Unmarshal config
|
||||||
err = viper.Unmarshal(appConfig)
|
err = viper.Unmarshal(appConfig)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
10
errors.go
10
errors.go
|
@ -3,7 +3,8 @@ package main
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"net/http"
|
"net/http"
|
||||||
"strings"
|
|
||||||
|
"github.com/elnormous/contenttype"
|
||||||
)
|
)
|
||||||
|
|
||||||
type errorData struct {
|
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)
|
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) {
|
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)
|
http.Error(w, message, status)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
1
go.mod
1
go.mod
|
@ -11,6 +11,7 @@ require (
|
||||||
github.com/caddyserver/certmagic v0.12.0
|
github.com/caddyserver/certmagic v0.12.0
|
||||||
github.com/dchest/captcha v0.0.0-20200903113550-03f5f0333e1f
|
github.com/dchest/captcha v0.0.0-20200903113550-03f5f0333e1f
|
||||||
github.com/dgrijalva/jwt-go v3.2.0+incompatible
|
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-chi/chi/v5 v5.0.0
|
||||||
github.com/go-fed/httpsig v1.1.0
|
github.com/go-fed/httpsig v1.1.0
|
||||||
github.com/go-sql-driver/mysql v1.5.0 // indirect
|
github.com/go-sql-driver/mysql v1.5.0 // indirect
|
||||||
|
|
2
go.sum
2
go.sum
|
@ -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/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/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/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/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 h1:lvB5Jl89CsZtGIWuTcDM1E/vkVs49/Ml7JJe07l8SPQ=
|
||||||
github.com/felixge/httpsnoop v1.0.1/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U=
|
github.com/felixge/httpsnoop v1.0.1/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U=
|
||||||
|
|
Loading…
Reference in New Issue