From b2fc689bdcff28bf75c0128db19ba4730d726b4f Mon Sep 17 00:00:00 2001 From: simponic Date: Thu, 28 Mar 2024 12:57:35 -0400 Subject: dns api (#1) Co-authored-by: Elizabeth Hunt Reviewed-on: https://git.hatecomputers.club/hatecomputers/hatecomputers.club/pulls/1 --- api/dns.go | 114 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 114 insertions(+) (limited to 'api/dns.go') diff --git a/api/dns.go b/api/dns.go index 3105f91..5123acc 100644 --- a/api/dns.go +++ b/api/dns.go @@ -3,10 +3,23 @@ package api import ( "log" "net/http" + "strconv" + "strings" + "git.hatecomputers.club/hatecomputers/hatecomputers.club/adapters/cloudflare" "git.hatecomputers.club/hatecomputers/hatecomputers.club/database" ) +const MAX_USER_RECORDS = 20 + +type FormError struct { + Errors []string +} + +func userCanFuckWithDNSRecord(user *database.User, record *database.DNSRecord) bool { + return user.ID == record.UserID && (record.Name == user.Username || strings.HasSuffix(record.Name, "."+user.Username)) +} + func ListDNSRecordsContinuation(context *RequestContext, req *http.Request, resp http.ResponseWriter) ContinuationChain { return func(success Continuation, failure Continuation) ContinuationChain { dnsRecords, err := database.GetUserDNSRecords(context.DBConn, context.User.ID) @@ -17,7 +30,108 @@ func ListDNSRecordsContinuation(context *RequestContext, req *http.Request, resp } (*context.TemplateData)["DNSRecords"] = dnsRecords + return success(context, req, resp) + } +} + +func CreateDNSRecordContinuation(context *RequestContext, req *http.Request, resp http.ResponseWriter) ContinuationChain { + return func(success Continuation, failure Continuation) ContinuationChain { + formErrors := FormError{ + Errors: []string{}, + } + + name := req.FormValue("name") + recordType := req.FormValue("type") + recordContent := req.FormValue("content") + ttl := req.FormValue("ttl") + ttlNum, err := strconv.Atoi(ttl) + if err != nil { + formErrors.Errors = append(formErrors.Errors, "invalid ttl") + } + + dnsRecord := &database.DNSRecord{ + UserID: context.User.ID, + Name: name, + Type: recordType, + Content: recordContent, + TTL: ttlNum, + } + + dnsRecords, err := database.GetUserDNSRecords(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 { + formErrors.Errors = append(formErrors.Errors, "max records reached") + } + + if !userCanFuckWithDNSRecord(context.User, dnsRecord) { + formErrors.Errors = append(formErrors.Errors, "'name' must end with "+context.User.Username) + } + + if len(formErrors.Errors) == 0 { + cloudflareRecordId, err := cloudflare.CreateDNSRecord(context.Args.CloudflareZone, context.Args.CloudflareToken, dnsRecord) + if err != nil { + log.Println(err) + formErrors.Errors = append(formErrors.Errors, err.Error()) + } + + dnsRecord.ID = cloudflareRecordId + } + + if len(formErrors.Errors) == 0 { + _, err := database.SaveDNSRecord(context.DBConn, dnsRecord) + if err != nil { + log.Println(err) + formErrors.Errors = append(formErrors.Errors, "error saving record") + } + } + + if len(formErrors.Errors) == 0 { + http.Redirect(resp, req, "/dns", http.StatusFound) + return success(context, req, resp) + } + + (*context.TemplateData)["DNSRecords"] = dnsRecords + (*context.TemplateData)["FormError"] = &formErrors + (*context.TemplateData)["RecordForm"] = dnsRecord + + resp.WriteHeader(http.StatusBadRequest) + return failure(context, req, resp) + } +} + +func DeleteDNSRecordContinuation(context *RequestContext, req *http.Request, resp http.ResponseWriter) ContinuationChain { + return func(success Continuation, failure Continuation) ContinuationChain { + recordId := req.FormValue("id") + record, err := database.GetDNSRecord(context.DBConn, recordId) + if err != nil { + log.Println(err) + resp.WriteHeader(http.StatusInternalServerError) + return failure(context, req, resp) + } + + if !userCanFuckWithDNSRecord(context.User, record) { + resp.WriteHeader(http.StatusUnauthorized) + return failure(context, req, resp) + } + + err = cloudflare.DeleteDNSRecord(context.Args.CloudflareZone, context.Args.CloudflareToken, recordId) + if err != nil { + log.Println(err) + resp.WriteHeader(http.StatusInternalServerError) + return failure(context, req, resp) + } + + err = database.DeleteDNSRecord(context.DBConn, recordId) + if err != nil { + resp.WriteHeader(http.StatusInternalServerError) + return failure(context, req, resp) + } + http.Redirect(resp, req, "/dns", http.StatusFound) return success(context, req, resp) } } -- cgit v1.2.3-70-g09d2