Remove webmentions
parent
9aebddd251
commit
7cbaf6ad31
1
main.go
1
main.go
|
@ -16,6 +16,5 @@ func main() {
|
||||||
log.Println("Blog URL: " + BlogUrl)
|
log.Println("Blog URL: " + BlogUrl)
|
||||||
http.HandleFunc("/micropub", HandleMicroPub)
|
http.HandleFunc("/micropub", HandleMicroPub)
|
||||||
http.HandleFunc("/media", HandleMedia)
|
http.HandleFunc("/media", HandleMedia)
|
||||||
http.HandleFunc("/webmention", HandleWebmention)
|
|
||||||
log.Fatal(http.ListenAndServe(":5555", nil))
|
log.Fatal(http.ListenAndServe(":5555", nil))
|
||||||
}
|
}
|
||||||
|
|
161
webmention.go
161
webmention.go
|
@ -1,161 +0,0 @@
|
||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"crypto/md5"
|
|
||||||
"encoding/json"
|
|
||||||
"errors"
|
|
||||||
"fmt"
|
|
||||||
"net/http"
|
|
||||||
"net/url"
|
|
||||||
"strings"
|
|
||||||
"time"
|
|
||||||
"willnorris.com/go/webmention"
|
|
||||||
)
|
|
||||||
|
|
||||||
type Mention struct {
|
|
||||||
Source string `json:"source"`
|
|
||||||
Target string `json:"target"`
|
|
||||||
Date string `json:"date"`
|
|
||||||
}
|
|
||||||
|
|
||||||
func HandleWebmention(w http.ResponseWriter, r *http.Request) {
|
|
||||||
if r.Method != "POST" {
|
|
||||||
w.WriteHeader(http.StatusMethodNotAllowed)
|
|
||||||
_, _ = w.Write([]byte("The HTTP method is not allowed, make a POST request"))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
sourceUrl, err := url.Parse(r.FormValue("source"))
|
|
||||||
if err != nil || !(sourceUrl.Scheme == "http" || sourceUrl.Scheme == "https") {
|
|
||||||
err = errors.New("failed to parse webmention source URL")
|
|
||||||
w.WriteHeader(http.StatusBadRequest)
|
|
||||||
_, _ = w.Write([]byte(err.Error()))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
targetUrl, err := url.Parse(r.FormValue("target"))
|
|
||||||
if err != nil || !(sourceUrl.Scheme == "http" || sourceUrl.Scheme == "https") {
|
|
||||||
err = errors.New("failed to parse webmention target URL")
|
|
||||||
w.WriteHeader(http.StatusBadRequest)
|
|
||||||
_, _ = w.Write([]byte(err.Error()))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
// Check if urls don't equal
|
|
||||||
if sourceUrl.String() == targetUrl.String() {
|
|
||||||
err = errors.New("source and target equal")
|
|
||||||
w.WriteHeader(http.StatusBadRequest)
|
|
||||||
_, _ = w.Write([]byte(err.Error()))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
// Check if target is blog
|
|
||||||
if !strings.HasPrefix(targetUrl.String(), strings.TrimSuffix(BlogUrl, "/")) {
|
|
||||||
err = errors.New("wrong webmention target")
|
|
||||||
w.WriteHeader(http.StatusBadRequest)
|
|
||||||
_, _ = w.Write([]byte(err.Error()))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
// Check response code for source
|
|
||||||
respCode, err := responseCodeForSource(sourceUrl.String())
|
|
||||||
if err != nil {
|
|
||||||
w.WriteHeader(http.StatusInternalServerError)
|
|
||||||
_, _ = w.Write([]byte(err.Error()))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if respCode < 200 || respCode >= 300 {
|
|
||||||
if respCode == 410 || respCode == 404 {
|
|
||||||
// Delete mention, because source is gone
|
|
||||||
go func() {
|
|
||||||
e := deleteWebmention(sourceUrl.String(), targetUrl.String())
|
|
||||||
if e != nil {
|
|
||||||
fmt.Print("Tried to delete webmention", sourceUrl.String(), "but failed:", e.Error())
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
returnSuccess(targetUrl.String(), w, r)
|
|
||||||
return
|
|
||||||
} else {
|
|
||||||
err = errors.New("source returned error")
|
|
||||||
w.WriteHeader(http.StatusBadRequest)
|
|
||||||
_, _ = w.Write([]byte(err.Error()))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Check if source mentions target
|
|
||||||
if !sourceMentionsTarget(sourceUrl.String(), targetUrl.String()) {
|
|
||||||
err = errors.New("source doesn't mention target")
|
|
||||||
go func() {
|
|
||||||
// Try to delete webmention nevertheless
|
|
||||||
e := deleteWebmention(sourceUrl.String(), targetUrl.String())
|
|
||||||
if e != nil {
|
|
||||||
fmt.Print("Tried to delete webmention (source doesn't mention target) ", sourceUrl.String(), "but failed:", e.Error())
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
w.WriteHeader(http.StatusBadRequest)
|
|
||||||
_, _ = w.Write([]byte(err.Error()))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
go func() {
|
|
||||||
e := saveWebmention(&Mention{
|
|
||||||
Source: sourceUrl.String(),
|
|
||||||
Target: targetUrl.String(),
|
|
||||||
Date: time.Now().Format("2006-01-02"),
|
|
||||||
})
|
|
||||||
if e != nil {
|
|
||||||
fmt.Println("Failed to save webmention:", e.Error())
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
returnSuccess(targetUrl.String(), w, r)
|
|
||||||
go func() {
|
|
||||||
if SelectedNotificationServices != nil {
|
|
||||||
SelectedNotificationServices.Post("New webmention: " + sourceUrl.String())
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func responseCodeForSource(source string) (int, error) {
|
|
||||||
client := http.DefaultClient
|
|
||||||
resp, err := client.Get(source)
|
|
||||||
if err != nil || resp == nil {
|
|
||||||
return 0, err
|
|
||||||
}
|
|
||||||
return resp.StatusCode, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func sourceMentionsTarget(source string, target string) bool {
|
|
||||||
client := webmention.New(nil)
|
|
||||||
dl, err := client.DiscoverLinks(source, "")
|
|
||||||
if err != nil {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
for _, link := range dl {
|
|
||||||
if link == target {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
func saveWebmention(mention *Mention) (err error) {
|
|
||||||
bytesRepresentation, err := json.Marshal(mention)
|
|
||||||
if err != nil {
|
|
||||||
return errors.New("failed to marshal json before committing")
|
|
||||||
}
|
|
||||||
filePath := fmt.Sprintf("data/mentions/%x/%x.json", md5.Sum([]byte(strings.ReplaceAll(mention.Target, "/", ""))), md5.Sum([]byte(mention.Source)))
|
|
||||||
err = SelectedStorage.UpdateFile(filePath, string(bytesRepresentation), "New webmention from "+mention.Source)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func deleteWebmention(source string, target string) (err error) {
|
|
||||||
filePath := fmt.Sprintf("data/mentions/%x/%x.json", md5.Sum([]byte(strings.ReplaceAll(target, "/", ""))), md5.Sum([]byte(source)))
|
|
||||||
err = SelectedStorage.DeleteFile(filePath, "Delete webmention from "+source)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func returnSuccess(target string, w http.ResponseWriter, r *http.Request) {
|
|
||||||
w.Header().Add("Location", target)
|
|
||||||
if strings.Contains(r.Header.Get("Accept"), "text/html") {
|
|
||||||
// Redirect browser
|
|
||||||
w.WriteHeader(http.StatusSeeOther)
|
|
||||||
} else {
|
|
||||||
w.WriteHeader(http.StatusCreated)
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
|
@ -1,34 +0,0 @@
|
||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"net/http"
|
|
||||||
"net/http/httptest"
|
|
||||||
"strconv"
|
|
||||||
"testing"
|
|
||||||
)
|
|
||||||
|
|
||||||
func Test_responseCodeForSource(t *testing.T) {
|
|
||||||
for _, code := range []int{200, 404} {
|
|
||||||
t.Run(strconv.Itoa(code), func(t *testing.T) {
|
|
||||||
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
||||||
w.WriteHeader(code)
|
|
||||||
}))
|
|
||||||
defer ts.Close()
|
|
||||||
got, err := responseCodeForSource(ts.URL)
|
|
||||||
if err != nil || got != code {
|
|
||||||
t.Errorf("Wrong response code: Got %d, but expected %d", got, code)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
t.Run("Error", func(t *testing.T) {
|
|
||||||
ts := httptest.NewUnstartedServer(nil)
|
|
||||||
defer ts.Close()
|
|
||||||
got, err := responseCodeForSource(ts.URL)
|
|
||||||
if err == nil {
|
|
||||||
t.Errorf("Error is nil")
|
|
||||||
}
|
|
||||||
if got != 0 {
|
|
||||||
t.Errorf("Wrong response code: Got %d, but expected %d", got, 0)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
Loading…
Reference in New Issue