diff --git a/main.go b/main.go index 8e39de7..45c0e13 100644 --- a/main.go +++ b/main.go @@ -16,6 +16,5 @@ func main() { log.Println("Blog URL: " + BlogUrl) http.HandleFunc("/micropub", HandleMicroPub) http.HandleFunc("/media", HandleMedia) - http.HandleFunc("/webmention", HandleWebmention) log.Fatal(http.ListenAndServe(":5555", nil)) } diff --git a/webmention.go b/webmention.go deleted file mode 100644 index 1947c10..0000000 --- a/webmention.go +++ /dev/null @@ -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 -} diff --git a/webmention_test.go b/webmention_test.go deleted file mode 100644 index 495225b..0000000 --- a/webmention_test.go +++ /dev/null @@ -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) - } - }) -}