package main import ( "crypto/sha1" "encoding/json" "fmt" "html" "io/ioutil" "log" "net/http" "os" "strings" "time" ) // CreateObject - Used by post web receiver type CreateObject struct { Actor string `json:"actor"` Cc []string `json:"cc"` Content string `json:"content"` To []string `json:"to"` Type string `json:"type"` } // RelayBase - The base object used by web receiver type RelayBase struct { Actor string `json:"actor"` Cc []string `json:"cc"` Object json.RawMessage `json:"Object"` ID string `json:"id"` Published string `json:"published"` To []string `json:"to"` Type string `json:"type"` } func hostmeta(w http.ResponseWriter, r *http.Request) { fmt.Println("PATH --> ", r.URL.Path) host := r.Host xml := "" w.Header().Set("Content-Type", "application/xrd+xml") fmt.Fprintf(w, xml) } func webfinger(w http.ResponseWriter, r *http.Request) { fmt.Println("PATH --> ", r.URL.Path) host := r.Host webfingermap := make(map[string]interface{}) webfingermap["subject"] = "acct:fedilogue@" + host webfingermap["aliases"] = []string{"https://" + host + "/users/fedilogue"} link0 := make(map[string]string) link0["rel"] = "http://webfinger.net/rel/profile-page" link0["type"] = "text/html" link0["href"] = "https://" + host + "/users/fedilogue" link1 := make(map[string]string) link1["rel"] = "self" link1["type"] = "application/activity+json" link1["href"] = "https://" + host + "/users/fedilogue" link2 := make(map[string]string) link2["rel"] = "self" link2["type"] = "application/ld+json; profile=\"https://www.w3.org/ns/activitystreams\"" link2["href"] = "https://" + host + "/users/fedilogue" link3 := make(map[string]string) link3["rel"] = "http://ostatus.org/schema/1.0/subscribe" link3["template"] = "https://" + host + "/ostatus_subscribe?acct={uri}" links := []map[string]string{link0, link1, link2, link3} webfingermap["links"] = links webfingerbin, err := json.Marshal(webfingermap) if err != nil { fmt.Println(err.Error()) return } webfingerstr := string(webfingerbin) query := r.URL.Query() resourceRaw, exists := query["resource"] if exists { resource := resourceRaw[0] if resource != "acct:fedilogue@"+host { fmt.Println("Writes properly but wrong acct") w.Header().Set("Content-Type", "application/json; charset=utf-8") fmt.Fprintf(w, webfingerstr) return } w.Header().Set("Content-Type", "application/json; charset=utf-8") fmt.Fprintf(w, webfingerstr) } else { fmt.Println(query) w.WriteHeader(http.StatusNotFound) return } } func inboxHandler(reportPostChan chan ReportPost) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { fmt.Println("PATH --> ", r.URL.Path) body, err := ioutil.ReadAll(r.Body) if err != nil { fmt.Println(err) return } var findtype RelayBase err = json.Unmarshal(body, &findtype) fmt.Println(string(body)) switch findtype.Type { case "Create": var createobject CreateObject var newpost ReportPost err = json.Unmarshal(findtype.Object, &createobject) if err != nil { return } newpost.Uri = findtype.ID startSlashes := strings.Index(createobject.Actor, "//") + 2 endSlashes := strings.Index(createobject.Actor[startSlashes:], "/") newinstance := createobject.Actor[startSlashes : startSlashes+endSlashes] // For now we are just verifying the user ri_mutex.Lock() o, exist := runninginstances[newinstance] if exist == false { o := RunningInstance{} newClient := http.Client{} o.client = newClient o.Status = KEEPALIVE runninginstances[newinstance] = o } ri_mutex.Unlock() // This only needs to be done if the user does not exist in the database log.Print("Actor object: ", createobject.Actor) realuser, err := fetch_user_info(o.client, createobject.Actor) _, _ = check_user(createobject.Actor) if err != nil { return } posthash := sha1.New() fmt.Fprint(posthash, newpost.Uri) fmt.Fprint(posthash, newpost.normalized) fmt.Fprint(posthash, newpost.Account.Acct) fmt.Fprint(posthash, newpost.Account.Display_name) newpost.posthash = posthash.Sum(nil) newpost.Content = createobject.Content newpost.Created_at = findtype.Published newpost.normalized = html.UnescapeString(strings.ToLower(p.Sanitize(newpost.Content))) newpost.normalized = strings.ReplaceAll(newpost.normalized, "\t", " ") newpost.normalized = spaceReg.ReplaceAllString(newpost.normalized, " ") newpost.Account.Acct = realuser.PreferredUsername + "@" + newinstance newpost.Account.Avatar = realuser.Icon.Url newpost.Account.Bot = false newpost.Account.Created_at = time.Now().Format(time.RFC3339) newpost.Account.Display_name = realuser.Name newpost.Account.Url = createobject.Actor reportPostChan <- newpost case "Like": case "Announcement": case "Delete": case "Undo": default: fmt.Println("Others --> " + findtype.Type) } } } func usersFedilogueFollowers(w http.ResponseWriter, r *http.Request) { fmt.Println("PATH --> ", r.URL.Path) host := r.Host contextlist := map[string]string{"@language": "und"} context := []interface{}{"https://www.w3.org/ns/activitystreams", "https://" + host + "/schemas/litepub-0.1.jsonld", contextlist} followersmap := make(map[string]interface{}) followersmap["@context"] = context staticjson := "{\"@context\":[\"https://www.w3.org/ns/activitystreams\",\"https://" + host + "/schemas/litepub-0.1.jsonld\",{\"@language\":\"und\"}],\"first\":{\"id\":\"https://" + host + "/users/fedilogue/followers?page=1\",\"next\":\"https://" + host + "/users/fedilogue/followers?page=2\",\"orderedItems\":[\"https://mastodon.host/users/federationbot\"],\"partOf\":\"https://" + host + "/users/fedilogue/followers\",\"totalItems\":1,\"type\":\"OrderedCollectionPage\"},\"id\":\"https://" + host + "/users/fedilogue/followers\",\"totalItems\":1,\"type\":\"OrderedCollection\"}" //wtf := "{\"@context\":[\"https://www.w3.org/ns/activitystreams\",\"https://p.farhan.codes/schemas/litepub-0.1.jsonld\",{\"@language\":\"und\"}],\"first\":{\"id\":\"https://p.farhan.codes/users/fedilogue/followers?page=1\",\"next\":\"https://p.farhan.codes/users/fedilogue/followers?page=2\",\"orderedItems\":[\"https://mastodon.host/users/federationbot\"],\"partOf\":\"https://p.farhan.codes/users/fedilogue/followers\",\"totalItems\":1,\"type\":\"OrderedCollectionPage\"},\"id\":\"https://p.farhan.codes/users/fedilogue/followers\",\"totalItems\":1,\"type\":\"OrderedCollection\"}" w.Header().Set("Content-Type", "application/activity+json; charset=utf-8") fmt.Fprintf(w, staticjson) } func usersFedilogueFollowing(w http.ResponseWriter, r *http.Request) { host := r.Host fmt.Println("PATH --> ", r.URL.Path) staticjson := "{\"@context\": [\"https://www.w3.org/ns/activitystreams\", \"https://" + host + "/schemas/litepub-0.1.jsonld\", {\"@language\": \"und\"}], \"first\": {\"id\": \"https://" + host + "/users/fedilogue/following?page=1\", \"orderedItems\": [], \"partOf\": \"https://" + host + "/users/fedilogue/following\", \"totalItems\": 0, \"type\": \"OrderedCollectionPage\"}, \"id\": \"https://" + host + "/users/fedilogue/following\", \"totalItems\": 0, \"type\": \"OrderedCollection\"}" w.Header().Set("Content-Type", "application/activity+json; charset=utf-8") fmt.Fprintf(w, staticjson) } func usersFedilogue(w http.ResponseWriter, r *http.Request) { fmt.Println("PATH --> ", r.URL.Path) host := r.Host fmt.Println(r.Host) fmt.Println(r.Header["Accept"]) publickeybin, err := ioutil.ReadFile("keys/public.pem") if err != nil { fmt.Println(err) os.Exit(1) } publickeypemstr := string(publickeybin) publicKey := map[string]string{"id": "https://" + host + "/users/fedilogue#main-key", "owner": "https://" + host + "/users/fedilogue", "publicKeyPem": publickeypemstr} capabilities := map[string]bool{} tag := []string{} contextlist := map[string]string{"@language": "und"} attachment := []string{} endpoints := map[string]string{"oauthAuthorizationEndpoint": "https://" + host + "/oauth/authorize", "oauthRegistrationEndpoint": "https://" + host + "/api/v1/apps", "oauthTokenEndpoint": "https://" + host + "/oauth/token", "sharedInbox": "https://" + host + "/inbox", "uploadMedia": "https://" + host + "/api/ap/upload_media"} context := []interface{}{"https://www.w3.org/ns/activitystreams", "https://" + host + "/schemas/litepub-0.1.jsonld", contextlist} userjsonmap := make(map[string]interface{}) userjsonmap["@context"] = context userjsonmap["attachment"] = attachment userjsonmap["capabilities"] = capabilities userjsonmap["discoverable"] = false userjsonmap["endpoints"] = endpoints userjsonmap["followers"] = "https://" + host + "/users/fedilogue/followers" userjsonmap["following"] = "https://" + host + "/users/fedilogue/following" userjsonmap["id"] = "https://" + host + "/users/fedilogue" userjsonmap["inbox"] = "https://" + host + "/users/fedilogue/inbox" userjsonmap["manuallyApprovesFollowers"] = false userjsonmap["name"] = "Fedilogue Mass Follower" userjsonmap["outbox"] = "https://" + host + "/users/fedilogue/outbox" userjsonmap["preferredUsername"] = "fedilogue" userjsonmap["publicKey"] = publicKey userjsonmap["summary"] = "" userjsonmap["tag"] = tag userjsonmap["type"] = "Person" userjsonmap["uri"] = "https://" + host + "/users/fedilogue" userjsonbin, err := json.Marshal(userjsonmap) if err != nil { fmt.Println(err.Error()) return } userjsonstr := string(userjsonbin) w.Header().Set("Content-Type", "application/activity+json; charset=utf-8") fmt.Fprintf(w, userjsonstr) } func errorHandler(w http.ResponseWriter, r *http.Request) { fmt.Println("404 --> ", r.URL.Path) } func webmain(reportPostChan chan ReportPost) { http.HandleFunc("/.well-known/webfinger", webfinger) http.HandleFunc("/.well-known/host-meta", hostmeta) http.HandleFunc("/inbox", inboxHandler(reportPostChan)) http.HandleFunc("/users/fedilogue", usersFedilogue) http.HandleFunc("/users/fedilogue/followers", usersFedilogueFollowers) http.HandleFunc("/users/fedilogue/following", usersFedilogueFollowing) http.HandleFunc("/", errorHandler) log.Print("Starting HTTP inbox on port 8080") log.Fatal(http.ListenAndServe(":8080", nil)) }