From 21812453f65234c90990bd07cc02539b5a1ee249 Mon Sep 17 00:00:00 2001 From: Jonni Liljamo Date: Tue, 17 Oct 2023 02:06:51 +0300 Subject: [PATCH] feat: api endpoint to update a record --- internal/api/update.go | 59 +++++++++++++++++++++++++ internal/db/domains.go | 27 ++++++++++- internal/routers/api.go | 16 +++++-- internal/{api/key.go => util/apikey.go} | 4 +- 4 files changed, 99 insertions(+), 7 deletions(-) create mode 100644 internal/api/update.go rename internal/{api/key.go => util/apikey.go} (91%) diff --git a/internal/api/update.go b/internal/api/update.go new file mode 100644 index 0000000..8d79a5b --- /dev/null +++ b/internal/api/update.go @@ -0,0 +1,59 @@ +/* + * Copyright (C) 2023 Jonni Liljamo + * + * This file is licensed under AGPL-3.0-or-later, see NOTICE and LICENSE for + * more information. + */ +package api + +import ( + "net/http" + + "git.src.quest/~skye/felu-ddns/internal/db" + "github.com/gin-gonic/gin" +) + +func UpdateA() gin.HandlerFunc { + return func(c *gin.Context) { + domain := c.Query("domain") + if domain == "" { + c.JSON(http.StatusBadRequest, gin.H{ + "status": "error", + "error": "no domain was provided", + }) + c.Abort() + return + } + + apiKey := c.Query("api_key") + if apiKey == "" { + c.JSON(http.StatusBadRequest, gin.H{ + "status": "error", + "error": "no api key was provided", + }) + c.Abort() + return + } + + aRecord := c.Query("record") + if aRecord == "" { + aRecord = c.ClientIP() + } + + err := db.UpdateDomainARecord(domain, apiKey, aRecord) + if err != nil { + // FIXME: Handle better, "bad api key" is just the most likely scenario + c.JSON(http.StatusBadRequest, gin.H{ + "status": "error", + "error": "bad api key", + }) + c.Abort() + return + } + + c.JSON(http.StatusOK, gin.H{ + "status": "success", + "a_record": aRecord, + }) + } +} diff --git a/internal/db/domains.go b/internal/db/domains.go index b03d168..b7a278c 100644 --- a/internal/db/domains.go +++ b/internal/db/domains.go @@ -7,7 +7,9 @@ package db import ( - "git.src.quest/~skye/felu-ddns/internal/api" + "errors" + + "git.src.quest/~skye/felu-ddns/internal/util" "github.com/oklog/ulid/v2" ) @@ -45,7 +47,7 @@ func FetchDomainsForUser(userId string) ([]Domain, error) { func CreateDomain(domain string, aRecord string, owner string) error { ulid := ulid.Make().String() - apikey := api.GenKey() + apikey := util.GenApiKey() _, err := DBConn.Exec(`INSERT INTO domains(id, apikey, ddns_domain, a_record, owner) VALUES ($1, $2, $3, $4, $5)`, ulid, apikey, domain, aRecord, owner) if err != nil { @@ -80,3 +82,24 @@ func FetchDomainARecord(ddns_domain string) (string, error) { } return aRecord, nil } + +func UpdateDomainARecord(ddns_domain string, providedApiKey string, aRecord string) error { + var domainApiKey string + err := DBConn.QueryRow(`SELECT apikey FROM domains WHERE ddns_domain = $1`, + ddns_domain).Scan(&domainApiKey) + if err != nil { + return err + } + + if domainApiKey != providedApiKey { + return errors.New("API key doesn't match") + } + + _, err = DBConn.Exec(`UPDATE domains SET a_record = $1 WHERE ddns_domain = $2`, + aRecord, ddns_domain) + if err != nil { + return err + } + + return nil +} diff --git a/internal/routers/api.go b/internal/routers/api.go index acb85c3..a225043 100644 --- a/internal/routers/api.go +++ b/internal/routers/api.go @@ -9,6 +9,7 @@ package routers import ( "net/http" + "git.src.quest/~skye/felu-ddns/internal/api" "git.src.quest/~skye/felu-ddns/internal/log" "github.com/gin-gonic/gin" ) @@ -16,9 +17,16 @@ import ( func SetupAPIRouter(version string) *gin.Engine { r := gin.New() r.Use(gin.Recovery()) - r.Use(gin.LoggerWithFormatter(func(param gin.LogFormatterParams) string { - return log.GinFormat(param, "api") - })) + + var logger = gin.LoggerWithConfig(gin.LoggerConfig{ + Formatter: func(param gin.LogFormatterParams) string { + return log.GinFormat(param, "api") + }, + // NOTE: Don't log paths with query params, also update paths are used _a lot_ + SkipPaths: []string{"/update/a"}, + }) + + r.Use(logger) r.GET("/", func(c *gin.Context) { c.JSON(http.StatusOK, gin.H{ @@ -32,5 +40,7 @@ func SetupAPIRouter(version string) *gin.Engine { }) }) + r.GET("/update/a", api.UpdateA()) + return r } diff --git a/internal/api/key.go b/internal/util/apikey.go similarity index 91% rename from internal/api/key.go rename to internal/util/apikey.go index 1e068be..dec4206 100644 --- a/internal/api/key.go +++ b/internal/util/apikey.go @@ -4,13 +4,13 @@ * This file is licensed under AGPL-3.0-or-later, see NOTICE and LICENSE for * more information. */ -package api +package util import "math/rand" const chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789" -func GenKey() string { +func GenApiKey() string { // NOTE: "Good enough" b := make([]byte, 48) for i := range b { -- 2.44.1