summaryrefslogtreecommitdiff
path: root/api
diff options
context:
space:
mode:
authorLizzy Hunt <lizzy.hunt@usu.edu>2024-03-29 16:35:04 -0600
committerLizzy Hunt <lizzy.hunt@usu.edu>2024-03-29 16:35:04 -0600
commit5080c566ac31ec622986c04f1812a1e88c88210e (patch)
treed8dbaa766ef21b098c5740880facc2989c750295 /api
parent7cc13887eae7dd2a61900751e038d273313d077f (diff)
downloadhatecomputers.club-5080c566ac31ec622986c04f1812a1e88c88210e.tar.gz
hatecomputers.club-5080c566ac31ec622986c04f1812a1e88c88210e.zip
guestbook!
Diffstat (limited to 'api')
-rw-r--r--api/api_keys.go11
-rw-r--r--api/dns.go22
-rw-r--r--api/guestbook.go143
-rw-r--r--api/serve.go14
4 files changed, 172 insertions, 18 deletions
diff --git a/api/api_keys.go b/api/api_keys.go
index 17ed6c9..d636044 100644
--- a/api/api_keys.go
+++ b/api/api_keys.go
@@ -30,17 +30,22 @@ func CreateAPIKeyContinuation(context *RequestContext, req *http.Request, resp h
Errors: []string{},
}
- apiKeys, err := database.ListUserAPIKeys(context.DBConn, context.User.ID)
+ numKeys, err := database.CountUserAPIKeys(context.DBConn, context.User.ID)
if err != nil {
log.Println(err)
resp.WriteHeader(http.StatusInternalServerError)
return failure(context, req, resp)
}
- if len(apiKeys) >= MAX_USER_API_KEYS {
+ if numKeys >= MAX_USER_API_KEYS {
formErrors.Errors = append(formErrors.Errors, "max api keys reached")
}
+ if len(formErrors.Errors) > 0 {
+ (*context.TemplateData)["FormError"] = formErrors
+ return failure(context, req, resp)
+ }
+
_, err = database.SaveAPIKey(context.DBConn, &database.UserApiKey{
UserID: context.User.ID,
Key: utils.RandomId(),
@@ -50,8 +55,6 @@ func CreateAPIKeyContinuation(context *RequestContext, req *http.Request, resp h
resp.WriteHeader(http.StatusInternalServerError)
return failure(context, req, resp)
}
-
- http.Redirect(resp, req, "/keys", http.StatusFound)
return success(context, req, resp)
}
}
diff --git a/api/dns.go b/api/dns.go
index 0205f5d..a1739d3 100644
--- a/api/dns.go
+++ b/api/dns.go
@@ -72,25 +72,24 @@ func CreateDNSRecordContinuation(context *RequestContext, req *http.Request, res
formErrors.Errors = append(formErrors.Errors, "invalid ttl")
}
- dnsRecord := &database.DNSRecord{
- UserID: context.User.ID,
- Name: name,
- Type: recordType,
- Content: recordContent,
- TTL: ttlNum,
- Internal: internal,
- }
-
- dnsRecords, err := database.GetUserDNSRecords(context.DBConn, context.User.ID)
+ dnsRecordCount, err := database.CountUserDNSRecords(context.DBConn, context.User.ID)
if err != nil {
log.Println(err)
resp.WriteHeader(http.StatusInternalServerError)
return failure(context, req, resp)
}
- if len(dnsRecords) >= MAX_USER_RECORDS {
+ if dnsRecordCount >= MAX_USER_RECORDS {
formErrors.Errors = append(formErrors.Errors, "max records reached")
}
+ dnsRecord := &database.DNSRecord{
+ UserID: context.User.ID,
+ Name: name,
+ Type: recordType,
+ Content: recordContent,
+ TTL: ttlNum,
+ Internal: internal,
+ }
if !userCanFuckWithDNSRecord(context.DBConn, context.User, dnsRecord) {
formErrors.Errors = append(formErrors.Errors, "'name' must end with "+context.User.Username+" or you must be a domain owner for internal domains")
}
@@ -122,7 +121,6 @@ func CreateDNSRecordContinuation(context *RequestContext, req *http.Request, res
return success(context, req, resp)
}
- (*context.TemplateData)["DNSRecords"] = dnsRecords
(*context.TemplateData)["FormError"] = &formErrors
(*context.TemplateData)["RecordForm"] = dnsRecord
diff --git a/api/guestbook.go b/api/guestbook.go
new file mode 100644
index 0000000..2037e7e
--- /dev/null
+++ b/api/guestbook.go
@@ -0,0 +1,143 @@
+package api
+
+import (
+ "encoding/json"
+ "fmt"
+ "log"
+ "net/http"
+ "strings"
+
+ "git.hatecomputers.club/hatecomputers/hatecomputers.club/database"
+ "git.hatecomputers.club/hatecomputers/hatecomputers.club/utils"
+)
+
+type HcaptchaArgs struct {
+ SiteKey string
+}
+
+func validateGuestbookEntry(entry *database.GuestbookEntry) []string {
+ errors := []string{}
+
+ if entry.Name == "" {
+ errors = append(errors, "name is required")
+ }
+
+ if entry.Message == "" {
+ errors = append(errors, "message is required")
+ }
+
+ messageLength := len(entry.Message)
+ if messageLength < 10 || messageLength > 500 {
+ errors = append(errors, "message must be between 10 and 500 characters")
+ }
+
+ newLines := strings.Count(entry.Message, "\n")
+ if newLines > 10 {
+ errors = append(errors, "message cannot contain more than 10 new lines")
+ }
+
+ return errors
+}
+
+func SignGuestbookContinuation(context *RequestContext, req *http.Request, resp http.ResponseWriter) ContinuationChain {
+ return func(success Continuation, failure Continuation) ContinuationChain {
+ name := req.FormValue("name")
+ message := req.FormValue("message")
+ hCaptchaResponse := req.FormValue("h-captcha-response")
+
+ formErrors := FormError{
+ Errors: []string{},
+ }
+
+ if hCaptchaResponse == "" {
+ formErrors.Errors = append(formErrors.Errors, "hCaptcha is required")
+ }
+
+ entry := &database.GuestbookEntry{
+ ID: utils.RandomId(),
+ Name: name,
+ Message: message,
+ }
+
+ formErrors.Errors = append(formErrors.Errors, validateGuestbookEntry(entry)...)
+
+ if len(formErrors.Errors) > 0 {
+ (*context.TemplateData)["FormError"] = formErrors
+ return failure(context, req, resp)
+ }
+
+ err := verifyHCaptcha(context.Args.HcaptchaSecret, hCaptchaResponse)
+ if err != nil {
+ log.Println(err)
+
+ resp.WriteHeader(http.StatusBadRequest)
+ return failure(context, req, resp)
+ }
+
+ _, err = database.SaveGuestbookEntry(context.DBConn, entry)
+ if err != nil {
+ log.Println(err)
+ resp.WriteHeader(http.StatusInternalServerError)
+ return failure(context, req, resp)
+ }
+
+ return success(context, req, resp)
+ }
+}
+
+func ListGuestbookContinuation(context *RequestContext, req *http.Request, resp http.ResponseWriter) ContinuationChain {
+ return func(success Continuation, failure Continuation) ContinuationChain {
+ entries, err := database.GetGuestbookEntries(context.DBConn)
+ if err != nil {
+ log.Println(err)
+ resp.WriteHeader(http.StatusInternalServerError)
+ return failure(context, req, resp)
+ }
+
+ (*context.TemplateData)["GuestbookEntries"] = entries
+ return success(context, req, resp)
+ }
+}
+
+func HcaptchaArgsContinuation(context *RequestContext, req *http.Request, resp http.ResponseWriter) ContinuationChain {
+ return func(success Continuation, failure Continuation) ContinuationChain {
+ (*context.TemplateData)["HcaptchaArgs"] = HcaptchaArgs{
+ SiteKey: context.Args.HcaptchaSiteKey,
+ }
+ log.Println(context.Args.HcaptchaSiteKey)
+ return success(context, req, resp)
+ }
+}
+
+func verifyHCaptcha(secret, response string) error {
+ verifyURL := "https://hcaptcha.com/siteverify"
+ body := strings.NewReader("secret=" + secret + "&response=" + response)
+
+ req, err := http.NewRequest("POST", verifyURL, body)
+ if err != nil {
+ return err
+ }
+
+ req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
+
+ client := &http.Client{}
+ resp, err := client.Do(req)
+ if err != nil {
+ return err
+ }
+
+ jsonResponse := struct {
+ Success bool `json:"success"`
+ }{}
+ err = json.NewDecoder(resp.Body).Decode(&jsonResponse)
+ if err != nil {
+ return err
+ }
+
+ if !jsonResponse.Success {
+ return fmt.Errorf("hcaptcha verification failed")
+ }
+
+ defer resp.Body.Close()
+ return nil
+}
diff --git a/api/serve.go b/api/serve.go
index d16ea99..7cef1c9 100644
--- a/api/serve.go
+++ b/api/serve.go
@@ -118,7 +118,7 @@ func MakeServer(argv *args.Arguments, dbConn *sql.DB) *http.Server {
mux.HandleFunc("POST /dns", func(w http.ResponseWriter, r *http.Request) {
requestContext := makeRequestContext()
- LogRequestContinuation(requestContext, r, w)(VerifySessionContinuation, FailurePassingContinuation)(CreateDNSRecordContinuation, GoLoginContinuation)(IdContinuation, TemplateContinuation("dns.html", true))(LogExecutionTimeContinuation, LogExecutionTimeContinuation)(IdContinuation, IdContinuation)
+ LogRequestContinuation(requestContext, r, w)(VerifySessionContinuation, FailurePassingContinuation)(ListDNSRecordsContinuation, GoLoginContinuation)(CreateDNSRecordContinuation, FailurePassingContinuation)(TemplateContinuation("dns.html", true), TemplateContinuation("dns.html", true))(LogExecutionTimeContinuation, LogExecutionTimeContinuation)(IdContinuation, IdContinuation)
})
mux.HandleFunc("POST /dns/delete", func(w http.ResponseWriter, r *http.Request) {
@@ -133,7 +133,7 @@ func MakeServer(argv *args.Arguments, dbConn *sql.DB) *http.Server {
mux.HandleFunc("POST /keys", func(w http.ResponseWriter, r *http.Request) {
requestContext := makeRequestContext()
- LogRequestContinuation(requestContext, r, w)(VerifySessionContinuation, FailurePassingContinuation)(CreateAPIKeyContinuation, GoLoginContinuation)(IdContinuation, TemplateContinuation("api_keys.html", true))(LogExecutionTimeContinuation, LogExecutionTimeContinuation)(IdContinuation, IdContinuation)
+ LogRequestContinuation(requestContext, r, w)(VerifySessionContinuation, FailurePassingContinuation)(CreateAPIKeyContinuation, GoLoginContinuation)(ListAPIKeysContinuation, ListAPIKeysContinuation)(TemplateContinuation("api_keys.html", true), TemplateContinuation("api_keys.html", true))(LogExecutionTimeContinuation, LogExecutionTimeContinuation)(IdContinuation, IdContinuation)
})
mux.HandleFunc("POST /keys/delete", func(w http.ResponseWriter, r *http.Request) {
@@ -141,6 +141,16 @@ func MakeServer(argv *args.Arguments, dbConn *sql.DB) *http.Server {
LogRequestContinuation(requestContext, r, w)(VerifySessionContinuation, FailurePassingContinuation)(DeleteAPIKeyContinuation, GoLoginContinuation)(LogExecutionTimeContinuation, LogExecutionTimeContinuation)(IdContinuation, IdContinuation)
})
+ mux.HandleFunc("GET /guestbook", func(w http.ResponseWriter, r *http.Request) {
+ requestContext := makeRequestContext()
+ LogRequestContinuation(requestContext, r, w)(VerifySessionContinuation, FailurePassingContinuation)(HcaptchaArgsContinuation, HcaptchaArgsContinuation)(ListGuestbookContinuation, ListGuestbookContinuation)(TemplateContinuation("guestbook.html", true), FailurePassingContinuation)(LogExecutionTimeContinuation, LogExecutionTimeContinuation)(IdContinuation, IdContinuation)
+ })
+
+ mux.HandleFunc("POST /guestbook", func(w http.ResponseWriter, r *http.Request) {
+ requestContext := makeRequestContext()
+ LogRequestContinuation(requestContext, r, w)(VerifySessionContinuation, FailurePassingContinuation)(HcaptchaArgsContinuation, HcaptchaArgsContinuation)(SignGuestbookContinuation, FailurePassingContinuation)(ListGuestbookContinuation, ListGuestbookContinuation)(TemplateContinuation("guestbook.html", true), TemplateContinuation("guestbook.html", true))(LogExecutionTimeContinuation, LogExecutionTimeContinuation)(IdContinuation, IdContinuation)
+ })
+
mux.HandleFunc("GET /{name}", func(w http.ResponseWriter, r *http.Request) {
requestContext := makeRequestContext()
name := r.PathValue("name")