diff --git a/api/announcements.go b/api/announcements.go new file mode 100644 index 0000000..abafc49 --- /dev/null +++ b/api/announcements.go @@ -0,0 +1,111 @@ +package api + +import ( + "errors" + "io" + "log" + "net/http" + "os" + "time" + + "github.com/gorilla/feeds" +) + +var ( + authToken = os.Getenv("SEGFAUTILS_AUTHTOKEN") +) + +func Announcements() { + http.HandleFunc("/api/announcements", getAnnouncements) + http.HandleFunc("/api/announcements/post", handleAnnouncements) + http.HandleFunc("/api/announcements/delete", handleAnnouncementDeleteRequest) +} + +func handleAnnouncements(w http.ResponseWriter, r *http.Request) { + if r.Method != "POST" { + http.Error(w, "Method not allowed", http.StatusMethodNotAllowed) + return + } + if r.FormValue("token") != authToken { + http.Error(w, "You need to provide the authorization token given to you by your system administrator in order to post an announcement.", http.StatusUnauthorized) + return + } else { + if r.FormValue("title") == "" || r.FormValue("link") == "" || r.FormValue("severity") == "" { + http.Error(w, "Your request is not proper. Please add a title, link, and severity.", http.StatusBadRequest) + return + } else { + w.WriteHeader(http.StatusOK) + now := time.Now() + feed := &feeds.Feed{ + Title: r.FormValue("title"), + Link: &feeds.Link{Href: r.FormValue("link")}, + Description: r.FormValue("severity"), + Created: now, + } + + json, err := feed.ToJSON() + if err != nil { + log.Fatal(err) + } + + f, err := os.Create("./static/announcements.json") + + if err != nil { + log.Fatal(err) + } + + defer f.Close() + + _, err2 := f.WriteString(json) + + if err2 != nil { + log.Fatal(err2) + } + + w.Write([]byte("Announcement posted!")) + } + return + } +} + +func handleAnnouncementDeleteRequest(w http.ResponseWriter, r *http.Request) { + if r.Method != "POST" { + http.Error(w, "Method not allowed", http.StatusMethodNotAllowed) + return + } + if r.FormValue("token") != authToken { + http.Error(w, "You need to provide the authorization token given to you by your system administrator in order to delete an announcement.", http.StatusUnauthorized) + return + } else { + w.WriteHeader(http.StatusOK) + if _, err := os.Stat("./static/announcements.json"); errors.Is(err, os.ErrNotExist) { + http.Error(w, "If you're gonna delete the annoucement, there has to be an announcement in the first place.", http.StatusNotFound) + return + } else { + err := os.Remove("./static/announcements.json") + if err != nil { + log.Fatal(err) + } + w.Write([]byte("Announcement deleted!")) + return + } + } +} + +func getAnnouncements(w http.ResponseWriter, r *http.Request) { + if r.Method != "GET" { + http.Error(w, "Method not allowed", http.StatusMethodNotAllowed) + return + } + if _, err := os.Stat("./static/announcements.json"); errors.Is(err, os.ErrNotExist) { + http.Error(w, "There are no announcements.", http.StatusNotFound) + return + } else { + f, err := os.Open("./static/announcements.json") + if err != nil { + log.Fatal(err) + } + defer f.Close() + io.Copy(w, f) + } +} diff --git a/api/form.go b/api/form.go index b96c6ce..9c7d2d9 100644 --- a/api/form.go +++ b/api/form.go @@ -12,7 +12,7 @@ import ( "io" "net/url" - "github.com/ProjectSegfault/segfautils/otherthings" + "github.com/ProjectSegfault/segfautils/utils" ) var ( @@ -34,7 +34,7 @@ func theActualFormCode(w http.ResponseWriter, r *http.Request) { w.WriteHeader(http.StatusUnauthorized) fmt.Fprint(w, "Seems like captcha failed, you didn't complete the captcha or you are a bot. Please try again.\nPlease note that your IP has been logged in our systems for manual review to check if you're an abusive user. If you're seen as abusive, you will be blacklisted.\nYour message has not been sent.") postData := url.Values{ - "content": {"IP " + otherthings.GetUserIP(r) + "failed captcha!\nhttps://abuseipdb.com/check/" + otherthings.GetUserIP(r)}, + "content": {"IP " + utils.GetUserIP(r) + "failed captcha!\nhttps://abuseipdb.com/check/" + utils.GetUserIP(r)}, } req, err := http.PostForm(webhookURL, postData) if err != nil { @@ -45,12 +45,12 @@ func theActualFormCode(w http.ResponseWriter, r *http.Request) { } else { fmt.Fprintf(w, "Thanks for your message, and thanks for doing the captcha!\nPlease ignore how different this page looks to the page you were on earlier. I'll figure it out eventually!\n%#+v", hcaptchaResp) postData := url.Values{ - "content": {"IP " + otherthings.GetUserIP(r) + "\nFrom " + r.FormValue("email") + " with feedback type " + r.FormValue("commentType") + ":\n" + "**" + r.FormValue("message") + "**\n https://abuseipdb.com/check/" + otherthings.GetUserIP(r)}, + "content": {"IP " + utils.GetUserIP(r) + "\nFrom " + r.FormValue("email") + " with feedback type " + r.FormValue("commentType") + ":\n" + "**" + r.FormValue("message") + "**\n https://abuseipdb.com/check/" + utils.GetUserIP(r)}, } if r.FormValue("webhook") != "" { fmt.Fprintf(w, "\nThanks for trying Segfautils Contact Form :)") postData := url.Values{ - "content": {"**Note: you are currently testing our form example. Please check out the actual project at https://github.com/ProjectSegfault/segfautils if you found this neat! It's not hard to self-host :)**\n" + "IP " + otherthings.GetUserIP(r) + "\nFrom " + r.FormValue("email") + " with feedback type " + r.FormValue("commentType") + ":\n" + "**" + r.FormValue("message") + "**\n https://abuseipdb.com/check/" + otherthings.GetUserIP(r)}, + "content": {"**Note: you are currently testing our form example. Please check out the actual project at https://github.com/ProjectSegfault/segfautils if you found this neat! It's not hard to self-host :)**\n" + "IP " + utils.GetUserIP(r) + "\nFrom " + r.FormValue("email") + " with feedback type " + r.FormValue("commentType") + ":\n" + "**" + r.FormValue("message") + "**\n https://abuseipdb.com/check/" + utils.GetUserIP(r)}, } req, err := http.PostForm(r.FormValue("webhook"), postData) if err != nil { @@ -68,5 +68,5 @@ func theActualFormCode(w http.ResponseWriter, r *http.Request) { default: http.Error(w, "Method isn't allowed!\nYou may only POST here, not "+r.Method, http.StatusMethodNotAllowed) } - log.Println("[HTTP] " + otherthings.GetUserIP(r) + " accessed /api/form with method " + r.Method) + log.Println("[HTTP] " + utils.GetUserIP(r) + " accessed /api/form with method " + r.Method) } diff --git a/go.mod b/go.mod index 4e424d0..2a36d81 100644 --- a/go.mod +++ b/go.mod @@ -3,5 +3,6 @@ module github.com/ProjectSegfault/segfautils go 1.18 require ( + github.com/gorilla/feeds v1.1.1 // indirect github.com/kataras/hcaptcha v0.0.0-20200711031247-2927d4faf32f // indirect ) diff --git a/go.sum b/go.sum index 1744370..1eb8b8a 100644 --- a/go.sum +++ b/go.sum @@ -1,2 +1,4 @@ +github.com/gorilla/feeds v1.1.1 h1:HwKXxqzcRNg9to+BbvJog4+f3s/xzvtZXICcQGutYfY= +github.com/gorilla/feeds v1.1.1/go.mod h1:Nk0jZrvPFZX1OBe5NPiddPw7CfwF6Q9eqzaBbaightA= github.com/kataras/hcaptcha v0.0.0-20200711031247-2927d4faf32f h1:ktcW6v946XnYiNU2taSVx79C5eDDQ8MxWepJ8S1Mz5A= github.com/kataras/hcaptcha v0.0.0-20200711031247-2927d4faf32f/go.mod h1:9FC7gVUVZcXkyq6vFY+JVGMrmw1xoe4nD41Whc+gSbo= diff --git a/main.go b/main.go index a44e58f..35e4f4e 100644 --- a/main.go +++ b/main.go @@ -8,7 +8,7 @@ import ( "os" "github.com/ProjectSegfault/segfautils/api" - "github.com/ProjectSegfault/segfautils/otherthings" + "github.com/ProjectSegfault/segfautils/utils" ) type StaticThingy struct { @@ -21,7 +21,7 @@ var shit bool func main() { log.Println("[Segfautils] Starting") - otherthings.CheckEnv() + utils.CheckEnv() log.Println("[HTTP] Starting server") port := os.Getenv("SEGFAUTILS_PORT") hcaptcha_site_key := os.Getenv("HCAPTCHA_SITE_KEY") @@ -44,7 +44,11 @@ func main() { http.HandleFunc("/api/", func(w http.ResponseWriter, r *http.Request) { io.WriteString(w, "welcome to hell") }) + http.HandleFunc("/announcements", func(w http.ResponseWriter, r *http.Request) { + http.ServeFile(w, r, "static/announcements.html") + }) api.Form() + api.Announcements() log.Println("[HTTP] HTTP server is now running at " + port + "!") log.Println(http.ListenAndServe(":"+port, nil)) } diff --git a/otherthings/getip.go b/otherthings/getip.go deleted file mode 100644 index 2200c9c..0000000 --- a/otherthings/getip.go +++ /dev/null @@ -1,15 +0,0 @@ -package otherthings - -import ( - "net/http" -) - -// Thanks random StackOverflow answerer - -func GetUserIP(r *http.Request) string { - IPAddress := r.Header.Get("X-REAL-IP") - if IPAddress == "" { - IPAddress = r.Header.Get("X-FORWARDED-FOR") - } - return IPAddress -} diff --git a/static/announcements.html b/static/announcements.html new file mode 100644 index 0000000..cde6f8f --- /dev/null +++ b/static/announcements.html @@ -0,0 +1,82 @@ + + + + + + + Segfautils form implementation example + + + +

Post Announcement

+
+
+ +
+ +
+ +
+ +
+ +
+

Delete Announcement

+
+
+ +
+
+ +
+ + \ No newline at end of file diff --git a/otherthings/checkenv.go b/utils/checkenv.go similarity index 71% rename from otherthings/checkenv.go rename to utils/checkenv.go index 1d45be9..040f1f3 100644 --- a/otherthings/checkenv.go +++ b/utils/checkenv.go @@ -1,5 +1,5 @@ // Please ignore my terrible code :) It works -package otherthings +package utils import ( "log" @@ -20,7 +20,7 @@ func CheckEnv() { } unused, ok1 = os.LookupEnv("HCAPTCHA_SITE_KEY") if !ok1 || unused == "YOURSITEKEY" { - log.Fatal("[Segfautils] Environment variable HCAPTCHA_SITE_KEY is not set! Please set it to the site key you got from hCaptcha.") + log.Println("[Segfautils] Environment variable HCAPTCHA_SITE_KEY is not not set. It isn't required to be set, but without it, the example form will not work.") } else { log.Println("[Segfautils] Environment variable HCAPTCHA_SITE_KEY is set as " + unused) } @@ -36,5 +36,11 @@ func CheckEnv() { } else { log.Println("[Segfautils] Environment variable SEGFAUTILS_WEBHOOK_URL is set!") } + unused, ok1 = os.LookupEnv("SEGFAUTILS_AUTHTOKEN") + if !ok1 || unused == "YOURAUTHTOKEN" { + log.Fatal("[Segfautils] Environment variable SEGFAUTILS_AUTHTOKEN is not set! Please set it to a token you'd like to use for authorizing actions like announcements.") + } else { + log.Println("[Segfautils] Environment variable SEGFAUTILS_AUTHTOKEN is set!") + } log.Println("[Segfautils] ✅ Passed the Environment Variables check") } diff --git a/utils/getip.go b/utils/getip.go new file mode 100644 index 0000000..ac2ed3a --- /dev/null +++ b/utils/getip.go @@ -0,0 +1,15 @@ +package utils + +import ( + "net/http" +) + +// Thanks random StackOverflow answerer + +func GetUserIP(r *http.Request) string { + IPAddress := r.Header.Get("X-REAL-IP") + if IPAddress == "" { + IPAddress = r.Header.Get("X-FORWARDED-FOR") + } + return IPAddress +}