From 30b7704d74e201483ba110fe911f5977fd41617b Mon Sep 17 00:00:00 2001 From: Jonni Liljamo Date: Wed, 6 Mar 2024 21:12:10 +0200 Subject: [PATCH] chore: implement changes from linters, update copyright years --- cmd/felu/main.go | 18 +++--- internal/api/update.go | 15 +++-- internal/components/adminpartials.templ | 4 +- internal/components/adminpartials_templ.go | 4 +- internal/components/managepartials_templ.go | 22 +++---- internal/config/config.go | 18 +++--- internal/db/db.go | 12 +++- internal/db/domains.go | 67 ++++++++++++--------- internal/db/migrations.go | 12 ++-- internal/db/users.go | 26 +++++--- internal/dns/handle.go | 5 +- internal/dns/query.go | 7 ++- internal/dns/server.go | 9 ++- internal/handlers/admin.go | 6 +- internal/handlers/adminpartials.go | 5 +- internal/handlers/auth.go | 7 ++- internal/handlers/domains.go | 25 +++++--- internal/handlers/index.go | 5 +- internal/handlers/login.go | 4 +- internal/handlers/manage.go | 9 ++- internal/handlers/managepartials.go | 8 ++- internal/handlers/user.go | 20 +++--- internal/handlers/users.go | 4 +- internal/log/ginformat.go | 4 +- internal/log/log.go | 9 ++- internal/middlewares/admin.go | 8 ++- internal/middlewares/auth.go | 10 +-- internal/middlewares/middlewares.go | 9 +++ internal/renderer/renderer.go | 12 +++- internal/routers/api.go | 4 +- internal/routers/frontend.go | 6 +- internal/routers/routers.go | 9 +++ internal/util/apikey.go | 8 ++- internal/util/check.go | 4 +- internal/util/util.go | 9 +++ 35 files changed, 265 insertions(+), 139 deletions(-) create mode 100644 internal/middlewares/middlewares.go create mode 100644 internal/routers/routers.go create mode 100644 internal/util/util.go diff --git a/cmd/felu/main.go b/cmd/felu/main.go index 3dd59da..faa6cf8 100644 --- a/cmd/felu/main.go +++ b/cmd/felu/main.go @@ -1,9 +1,11 @@ /* - * Copyright (C) 2023 Jonni Liljamo + * Copyright (C) 2024 Jonni Liljamo * * This file is licensed under AGPL-3.0-or-later, see NOTICE and LICENSE for * more information. */ + +// nolint package main import ( @@ -25,7 +27,7 @@ import ( var version = "notset-builtin" var ( - g errgroup.Group + g errgroup.Group sessionManager *scs.SessionManager ) @@ -49,16 +51,16 @@ func main() { sessionManager.Lifetime = 6 * time.Hour frontend := &http.Server{ - Addr: config.FeluConfig.FrontendBindAddr, - Handler: sessionManager.LoadAndSave(routers.SetupFrontendRouter(sessionManager)), - ReadTimeout: 5 * time.Second, + Addr: config.FeluConfig.FrontendBindAddr, + Handler: sessionManager.LoadAndSave(routers.SetupFrontendRouter(sessionManager)), + ReadTimeout: 5 * time.Second, WriteTimeout: 10 * time.Second, } api := &http.Server{ - Addr: config.FeluConfig.APIBindAddr, - Handler: routers.SetupAPIRouter(version), - ReadTimeout: 5 * time.Second, + Addr: config.FeluConfig.APIBindAddr, + Handler: routers.SetupAPIRouter(version), + ReadTimeout: 5 * time.Second, WriteTimeout: 10 * time.Second, } diff --git a/internal/api/update.go b/internal/api/update.go index 564edfb..ed436b8 100644 --- a/internal/api/update.go +++ b/internal/api/update.go @@ -1,9 +1,11 @@ /* - * Copyright (C) 2023 Jonni Liljamo + * Copyright (C) 2024 Jonni Liljamo * * This file is licensed under AGPL-3.0-or-later, see NOTICE and LICENSE for * more information. */ + +// Package api implements API route handlers. package api import ( @@ -14,13 +16,14 @@ import ( "github.com/gin-gonic/gin" ) +// UpdateA updates an A record based on query params. 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", + "error": "no domain was provided", }) c.Abort() return @@ -30,7 +33,7 @@ func UpdateA() gin.HandlerFunc { if apiKey == "" { c.JSON(http.StatusBadRequest, gin.H{ "status": "error", - "error": "no api key was provided", + "error": "no api key was provided", }) c.Abort() return @@ -44,7 +47,7 @@ func UpdateA() gin.HandlerFunc { if err := util.CheckARecord(aRecord); err != nil { c.JSON(http.StatusBadRequest, gin.H{ "status": "error", - "error": err.Error(), + "error": err.Error(), }) c.Abort() return @@ -55,14 +58,14 @@ func UpdateA() gin.HandlerFunc { // FIXME: Handle better, "bad api key" is just the most likely scenario c.JSON(http.StatusBadRequest, gin.H{ "status": "error", - "error": "bad api key", + "error": "bad api key", }) c.Abort() return } c.JSON(http.StatusOK, gin.H{ - "status": "success", + "status": "success", "a_record": aRecord, }) } diff --git a/internal/components/adminpartials.templ b/internal/components/adminpartials.templ index 6df8c0e..5ee5d9b 100644 --- a/internal/components/adminpartials.templ +++ b/internal/components/adminpartials.templ @@ -23,7 +23,7 @@ templ AdminPartialUsersList(users []db.User) {
- +
@@ -65,7 +65,7 @@ templ AdminPartialDomainsList(domains []db.Domain) {
- +
diff --git a/internal/components/adminpartials_templ.go b/internal/components/adminpartials_templ.go index a306d5f..89ac092 100644 --- a/internal/components/adminpartials_templ.go +++ b/internal/components/adminpartials_templ.go @@ -35,7 +35,7 @@ func AdminPartialUsersList(users []db.User) templ.Component { if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(user.Id)) + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(user.ID)) if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } @@ -103,7 +103,7 @@ func AdminPartialDomainsList(domains []db.Domain) templ.Component { if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(domain.Id)) + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(domain.ID)) if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } diff --git a/internal/components/managepartials_templ.go b/internal/components/managepartials_templ.go index 876e24a..cfdb4b0 100644 --- a/internal/components/managepartials_templ.go +++ b/internal/components/managepartials_templ.go @@ -81,7 +81,7 @@ func ManagePartialDomains(domains []db.Domain) templ.Component { if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(fmt.Sprintf("/manage/domains/%s", domain.Id))) + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(fmt.Sprintf("/manage/domains/%s", domain.ID))) if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } @@ -89,7 +89,7 @@ func ManagePartialDomains(domains []db.Domain) templ.Component { if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(fmt.Sprintf("#domain_patch_error_%s", domain.Id))) + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(fmt.Sprintf("#domain_patch_error_%s", domain.ID))) if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } @@ -105,7 +105,7 @@ func ManagePartialDomains(domains []db.Domain) templ.Component { if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(fmt.Sprintf("domain_patch_error_%s", domain.Id))) + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(fmt.Sprintf("domain_patch_error_%s", domain.ID))) if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } @@ -113,7 +113,7 @@ func ManagePartialDomains(domains []db.Domain) templ.Component { if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(domain.ApiKey)) + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(domain.APIKey)) if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } @@ -121,7 +121,7 @@ func ManagePartialDomains(domains []db.Domain) templ.Component { if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(fmt.Sprintf("domain_apikey_%s", domain.Id))) + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(fmt.Sprintf("domain_apikey_%s", domain.ID))) if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } @@ -129,7 +129,7 @@ func ManagePartialDomains(domains []db.Domain) templ.Component { if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } - templ_7745c5c3_Err = templ.RenderScriptItems(ctx, templ_7745c5c3_Buffer, toggleApiKeyVisibility(domain.Id)) + templ_7745c5c3_Err = templ.RenderScriptItems(ctx, templ_7745c5c3_Buffer, toggleApiKeyVisibility(domain.ID)) if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } @@ -137,7 +137,7 @@ func ManagePartialDomains(domains []db.Domain) templ.Component { if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } - var templ_7745c5c3_Var4 templ.ComponentScript = toggleApiKeyVisibility(domain.Id) + var templ_7745c5c3_Var4 templ.ComponentScript = toggleApiKeyVisibility(domain.ID) _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var4.Call) if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err @@ -146,7 +146,7 @@ func ManagePartialDomains(domains []db.Domain) templ.Component { if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(fmt.Sprintf("domain_eye_vis_%s", domain.Id))) + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(fmt.Sprintf("domain_eye_vis_%s", domain.ID))) if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } @@ -154,7 +154,7 @@ func ManagePartialDomains(domains []db.Domain) templ.Component { if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(fmt.Sprintf("domain_eye_hid_%s", domain.Id))) + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(fmt.Sprintf("domain_eye_hid_%s", domain.ID))) if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } @@ -162,7 +162,7 @@ func ManagePartialDomains(domains []db.Domain) templ.Component { if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(fmt.Sprintf("/manage/domains/%s/api_key", domain.Id))) + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(fmt.Sprintf("/manage/domains/%s/api_key", domain.ID))) if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } @@ -170,7 +170,7 @@ func ManagePartialDomains(domains []db.Domain) templ.Component { if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(fmt.Sprintf("/manage/domains/%s", domain.Id))) + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(fmt.Sprintf("/manage/domains/%s", domain.ID))) if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } diff --git a/internal/config/config.go b/internal/config/config.go index 2882fc6..6c0d014 100644 --- a/internal/config/config.go +++ b/internal/config/config.go @@ -1,13 +1,16 @@ /* - * Copyright (C) 2023 Jonni Liljamo + * Copyright (C) 2024 Jonni Liljamo * * This file is licensed under AGPL-3.0-or-later, see NOTICE and LICENSE for * more information. */ + +// Package config implements the global program config. package config import "git.src.quest/~skye/erya-go/util" +// FeluConfig is a global for accessing the global config. var FeluConfig *config type config struct { @@ -19,7 +22,7 @@ type config struct { // Initial email for the admin user, only used if no admin account (e.g. first boot) InitialAdminEmail string // Initial password for the admin user, only used if no admin account (e.g. first boot) - InitialAdminPwd string + InitialAdminPwd string LogLevel string @@ -33,17 +36,18 @@ type config struct { DNSBindIP string DNSBindPort int32 // Domain pattern, no leading dot, but with trailing dot - DNSPattern string + DNSPattern string } +// InitConfig initializes the global program config from environment variables. func InitConfig() { - FeluConfig = &config { + FeluConfig = &config{ ServiceName: util.LoadEnvStr("FELU_SERVICE_NAME", "FeluDDNS"), APIUrl: util.LoadEnvStr("FELU_API_URL", "MUST_SET"), InitialAdminEmail: util.LoadEnvStr("FELU_INITIAL_ADMIN_EMAIL", "admin@example.com"), - InitialAdminPwd: util.LoadEnvStr("FELU_INITIAL_ADMIN_PWD", "feluadmin"), + InitialAdminPwd: util.LoadEnvStr("FELU_INITIAL_ADMIN_PWD", "feluadmin"), LogLevel: util.LoadEnvStr("FELU_LOG_LEVEL", "info"), @@ -53,8 +57,8 @@ func InitConfig() { APIBindAddr: util.LoadEnvStr("FELU_API_BIND_ADDR", "0.0.0.0:8081"), - DNSBindIP: util.LoadEnvStr("FELU_DNS_BIND_IP", "0.0.0.0"), + DNSBindIP: util.LoadEnvStr("FELU_DNS_BIND_IP", "0.0.0.0"), DNSBindPort: util.LoadEnvInt32("FELU_DNS_BIND_PORT", 53), - DNSPattern: util.LoadEnvStr("FELU_DNS_PATTERN", "."), + DNSPattern: util.LoadEnvStr("FELU_DNS_PATTERN", "."), } } diff --git a/internal/db/db.go b/internal/db/db.go index 84c9950..91dac5f 100644 --- a/internal/db/db.go +++ b/internal/db/db.go @@ -1,9 +1,11 @@ /* - * Copyright (C) 2023 Jonni Liljamo + * Copyright (C) 2024 Jonni Liljamo * * This file is licensed under AGPL-3.0-or-later, see NOTICE and LICENSE for * more information. */ + +// Package db implements database migrations and manipulation utilities. package db import ( @@ -11,15 +13,18 @@ import ( "log/slog" "git.src.quest/~skye/felu-ddns/internal/config" + // nolint _ "github.com/mattn/go-sqlite3" ) +// DBConn is a global for accessing the database connection. var DBConn *sql.DB +// InitDB initializes the programs database. func InitDB() error { var err error DBConn, err = sql.Open("sqlite3", - config.FeluConfig.DataDir + "felu.db?_foreign_keys=true") + config.FeluConfig.DataDir+"felu.db?_foreign_keys=true") if err != nil { return err } @@ -29,6 +34,9 @@ func InitDB() error { return nil } +// InitAdminUser initializes the programs admin user. +// +// Errors out if at least one admin user already exists. func InitAdminUser() error { rows, err := DBConn.Query(`SELECT id FROM users WHERE is_admin = TRUE`) if err != nil { diff --git a/internal/db/domains.go b/internal/db/domains.go index 6777d4a..41202e4 100644 --- a/internal/db/domains.go +++ b/internal/db/domains.go @@ -1,9 +1,10 @@ /* - * Copyright (C) 2023 Jonni Liljamo + * Copyright (C) 2024 Jonni Liljamo * * This file is licensed under AGPL-3.0-or-later, see NOTICE and LICENSE for * more information. */ + package db import ( @@ -13,23 +14,26 @@ import ( "github.com/oklog/ulid/v2" ) +// DomainOwner contains a domains owners information. type DomainOwner struct { ID string Email string } +// Domain contains a domains information. type Domain struct { - Id string - ApiKey string - Domain string - A string + ID string + APIKey string + Domain string + A string Owner DomainOwner } -func FetchDomainsForUser(userId string) ([]Domain, error) { +// FetchDomainsForUser fetches all domains for a specific user. +func FetchDomainsForUser(userID string) ([]Domain, error) { rows, err := DBConn.Query(`SELECT id, apikey, ddns_domain, a_record - FROM domains WHERE owner = $1`, userId) + FROM domains WHERE owner = $1`, userID) if err != nil { return nil, err } @@ -38,7 +42,7 @@ func FetchDomainsForUser(userId string) ([]Domain, error) { var domains []Domain for rows.Next() { var domain Domain - err = rows.Scan(&domain.Id, &domain.ApiKey, &domain.Domain, &domain.A) + err = rows.Scan(&domain.ID, &domain.APIKey, &domain.Domain, &domain.A) if err != nil { return nil, err } @@ -52,6 +56,7 @@ func FetchDomainsForUser(userId string) ([]Domain, error) { return domains, nil } +// FetchAllDomains fetches all domains. func FetchAllDomains() ([]Domain, error) { rows, err := DBConn.Query(`SELECT id, ddns_domain, a_record, owner FROM domains`) @@ -63,7 +68,7 @@ func FetchAllDomains() ([]Domain, error) { var domains []Domain for rows.Next() { var domain Domain - err = rows.Scan(&domain.Id, &domain.Domain, &domain.A, &domain.Owner.ID) + err = rows.Scan(&domain.ID, &domain.Domain, &domain.A, &domain.Owner.ID) if err != nil { return nil, err } @@ -84,9 +89,10 @@ func FetchAllDomains() ([]Domain, error) { return domains, nil } +// CreateDomain creates a domains. func CreateDomain(domain string, aRecord string, owner string) error { ulid := ulid.Make().String() - apikey := util.GenApiKey() + 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 { @@ -96,56 +102,61 @@ func CreateDomain(domain string, aRecord string, owner string) error { return nil } -func DeleteDomain(id string, user_id string) error { - _, err := DBConn.Exec(`DELETE FROM domains WHERE id = $1 AND owner = $2`, id, user_id) +// DeleteDomain deletes a domain. +func DeleteDomain(id string, userID string) error { + _, err := DBConn.Exec(`DELETE FROM domains WHERE id = $1 AND owner = $2`, id, userID) if err != nil { return err } return nil } -func DeleteDomainsForUser(userId string) error { - _, err := DBConn.Exec(`DELETE FROM domains WHERE owner = $1`, userId) +// DeleteDomainsForUser deletes all domains for a user. +func DeleteDomainsForUser(userID string) error { + _, err := DBConn.Exec(`DELETE FROM domains WHERE owner = $1`, userID) if err != nil { return err } return nil } -func FetchDomainARecord(ddns_domain string) (string, error) { +// FetchDomainARecord fetches the A record of a domain. +func FetchDomainARecord(ddnsDomain string) (string, error) { var aRecord string err := DBConn.QueryRow(`SELECT a_record FROM domains WHERE ddns_domain = $1`, - ddns_domain).Scan(&aRecord) + ddnsDomain).Scan(&aRecord) if err != nil { return "", err } return aRecord, nil } -func UpdateDomainARecord(ddns_domain string, providedApiKey string, aRecord string) error { - var domainApiKey string +// UpdateDomainARecord updates the A record of a domain. +func UpdateDomainARecord(ddnsDomain string, providedAPIKey string, aRecord string) error { + var domainAPIKey string err := DBConn.QueryRow(`SELECT apikey FROM domains WHERE ddns_domain = $1`, - ddns_domain).Scan(&domainApiKey) + ddnsDomain).Scan(&domainAPIKey) if err != nil { return err } - if domainApiKey != providedApiKey { + 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) + aRecord, ddnsDomain) if err != nil { return err } - + return nil } -func UpdateDomainARecordManual(id string, userId string, aRecord string) error { +// UpdateDomainARecordManual updates the A record of a domain. +func UpdateDomainARecordManual(id string, userID string, aRecord string) error { _, err := DBConn.Exec(`UPDATE domains SET a_record = $1 WHERE id = $2 AND owner = $3`, - aRecord, id, userId) + aRecord, id, userID) if err != nil { return err } @@ -153,10 +164,10 @@ func UpdateDomainARecordManual(id string, userId string, aRecord string) error { return nil } - -func RefreshDomainApiKey(id string, user_id string) error { - apiKey := util.GenApiKey() - _, err := DBConn.Exec(`UPDATE domains SET apikey = $1 WHERE id = $2 AND owner = $3`, apiKey, id, user_id) +// RefreshDomainAPIKey refreshes the API key of a domain. +func RefreshDomainAPIKey(id string, userID string) error { + apiKey := util.GenAPIKey() + _, err := DBConn.Exec(`UPDATE domains SET apikey = $1 WHERE id = $2 AND owner = $3`, apiKey, id, userID) if err != nil { return err } diff --git a/internal/db/migrations.go b/internal/db/migrations.go index 3535fb9..b3aaf5a 100644 --- a/internal/db/migrations.go +++ b/internal/db/migrations.go @@ -1,9 +1,10 @@ /* - * Copyright (C) 2023 Jonni Liljamo + * Copyright (C) 2024 Jonni Liljamo * * This file is licensed under AGPL-3.0-or-later, see NOTICE and LICENSE for * more information. */ + package db import ( @@ -12,12 +13,12 @@ import ( "os" ) -var migrationsTable string = "schema_migrations" +var migrationsTable = "schema_migrations" func runMigrations() { slog.Info("Running migrations") - var schemaVersion int = 0 + var schemaVersion int schemaVersionQuery := fmt.Sprintf( `SELECT schema_version @@ -36,7 +37,7 @@ func runMigrations() { if schemaVersion != len(migrations) { for i := 0; i < len(migrations); i++ { if i >= schemaVersion { - slog.Info("Running migration", slog.Int("version", i + 1)) // + 1 is just a visual thing + slog.Info("Running migration", slog.Int("version", i+1)) // + 1 is just a visual thing _, err := DBConn.Exec(migrations[i]) if err != nil { slog.Error("Migration failed to run!", slog.Int("version", i)) @@ -55,9 +56,8 @@ func runMigrations() { if err != nil { slog.Error("Migrations ran, but was not able to create migration entry") os.Exit(1) - } else { - slog.Info("Migrations ran successfully") } + slog.Info("Migrations ran successfully") } else { slog.Info("No migrations to run") } diff --git a/internal/db/users.go b/internal/db/users.go index c385c7a..a8cc4b0 100644 --- a/internal/db/users.go +++ b/internal/db/users.go @@ -1,9 +1,10 @@ /* - * Copyright (C) 2023 Jonni Liljamo + * Copyright (C) 2024 Jonni Liljamo * * This file is licensed under AGPL-3.0-or-later, see NOTICE and LICENSE for * more information. */ + package db import ( @@ -14,6 +15,7 @@ import ( "github.com/oklog/ulid/v2" ) +// CreateUser creates a user. func CreateUser(email string, pwd string) error { argon := argon2.DefaultConfig() encoded, err := argon.HashEncoded([]byte(pwd)) @@ -32,6 +34,7 @@ func CreateUser(email string, pwd string) error { return nil } +// CreateAdmin creates an admin user. func CreateAdmin(email string, pwd string) error { argon := argon2.DefaultConfig() encoded, err := argon.HashEncoded([]byte(pwd)) @@ -50,17 +53,19 @@ func CreateAdmin(email string, pwd string) error { return nil } +// User contains a users relevant information. type User struct { - Id string + ID string Email string IsAdmin bool } +// FetchUserWithCreds fetches a users information based on given credentials. func FetchUserWithCreds(email string, pwd string) (*User, error) { - user := User{ Email: email } + user := User{Email: email} var encodedPwd string err := DBConn.QueryRow(`SELECT id, pwd FROM users WHERE email = $1`, - email).Scan(&user.Id, &encodedPwd) + email).Scan(&user.ID, &encodedPwd) if err == sql.ErrNoRows { return nil, errors.New("User not found") } @@ -79,8 +84,9 @@ func FetchUserWithCreds(email string, pwd string) (*User, error) { return &user, nil } -func FetchUserWithId(id string) (*User, error) { - user := User{ Id: id } +// FetchUserWithID fetches a users information. +func FetchUserWithID(id string) (*User, error) { + user := User{ID: id} err := DBConn.QueryRow(`SELECT email, is_admin FROM users WHERE id = $1`, id).Scan(&user.Email, &user.IsAdmin) if err == sql.ErrNoRows { @@ -93,6 +99,7 @@ func FetchUserWithId(id string) (*User, error) { return &user, nil } +// FetchAllUsers fetches all users. func FetchAllUsers() ([]User, error) { rows, err := DBConn.Query(`SELECT id, email, is_admin FROM users`) if err != nil { @@ -103,7 +110,7 @@ func FetchAllUsers() ([]User, error) { var users []User for rows.Next() { var user User - err = rows.Scan(&user.Id, &user.Email, &user.IsAdmin) + err = rows.Scan(&user.ID, &user.Email, &user.IsAdmin) if err != nil { return nil, err } @@ -117,6 +124,7 @@ func FetchAllUsers() ([]User, error) { return users, nil } +// FetchUserEmail fetches a users email address. func FetchUserEmail(id string) (string, error) { var email string err := DBConn.QueryRow(`SELECT email FROM users WHERE id = $1`, @@ -128,6 +136,7 @@ func FetchUserEmail(id string) (string, error) { return email, nil } +// DeleteUser deletes a user. func DeleteUser(id string) error { err := DeleteDomainsForUser(id) if err != nil { @@ -140,6 +149,7 @@ func DeleteUser(id string) error { return nil } +// UpdateUserEmail updates a users email address. func UpdateUserEmail(id string, email string) error { _, err := DBConn.Exec(`UPDATE users SET email = $1 WHERE id = $2`, email, id) @@ -149,6 +159,7 @@ func UpdateUserEmail(id string, email string) error { return nil } +// UpdateUserPassword updates a users password. func UpdateUserPassword(id string, pwd string) error { argon := argon2.DefaultConfig() encoded, err := argon.HashEncoded([]byte(pwd)) @@ -165,6 +176,7 @@ func UpdateUserPassword(id string, pwd string) error { return nil } +// VerifyUserPassword verifies a users password. func VerifyUserPassword(id string, pwd string) bool { // FIXME: Currently doesn't return any errors, and just return false in error cases // I mean... Shouldn't really error, but who knows diff --git a/internal/dns/handle.go b/internal/dns/handle.go index d107e01..29a040d 100644 --- a/internal/dns/handle.go +++ b/internal/dns/handle.go @@ -1,14 +1,15 @@ /* - * Copyright (C) 2023 Jonni Liljamo + * Copyright (C) 2024 Jonni Liljamo * * This file is licensed under AGPL-3.0-or-later, see NOTICE and LICENSE for * more information. */ + package dns import "github.com/miekg/dns" -func handleDnsRequest(w dns.ResponseWriter, r *dns.Msg) { +func handleDNSRequest(w dns.ResponseWriter, r *dns.Msg) { m := new(dns.Msg) m.SetReply(r) m.Compress = false diff --git a/internal/dns/query.go b/internal/dns/query.go index 4e13535..6b394f6 100644 --- a/internal/dns/query.go +++ b/internal/dns/query.go @@ -1,9 +1,10 @@ /* - * Copyright (C) 2023 Jonni Liljamo + * Copyright (C) 2024 Jonni Liljamo * * This file is licensed under AGPL-3.0-or-later, see NOTICE and LICENSE for * more information. */ + package dns import ( @@ -33,8 +34,8 @@ func handleARecord(q *dns.Question, m *dns.Msg, r *dns.Msg) { m.SetRcode(r, dns.RcodeNameError) } else { m.Answer = append(m.Answer, &dns.A{ - Hdr: dns.RR_Header{ Name: q.Name, Rrtype: dns.TypeA, Class: dns.ClassINET, Ttl: 60 }, - A: net.ParseIP(aRecord), + Hdr: dns.RR_Header{Name: q.Name, Rrtype: dns.TypeA, Class: dns.ClassINET, Ttl: 60}, + A: net.ParseIP(aRecord), }) } } else { diff --git a/internal/dns/server.go b/internal/dns/server.go index 6927d9b..705b53a 100644 --- a/internal/dns/server.go +++ b/internal/dns/server.go @@ -1,9 +1,11 @@ /* - * Copyright (C) 2023 Jonni Liljamo + * Copyright (C) 2024 Jonni Liljamo * * This file is licensed under AGPL-3.0-or-later, see NOTICE and LICENSE for * more information. */ + +// Package dns implements all required DNS functionality for the program. package dns import ( @@ -11,12 +13,13 @@ import ( "github.com/miekg/dns" ) +// Run starts the DNS server. func Run(addr string) error { - dns.HandleFunc(config.FeluConfig.DNSPattern, handleDnsRequest) + dns.HandleFunc(config.FeluConfig.DNSPattern, handleDNSRequest) server := &dns.Server{ Addr: addr, - Net: "udp", + Net: "udp", } return server.ListenAndServe() diff --git a/internal/handlers/admin.go b/internal/handlers/admin.go index 3d3d939..eb20214 100644 --- a/internal/handlers/admin.go +++ b/internal/handlers/admin.go @@ -1,9 +1,10 @@ /* - * Copyright (C) 2023 Jonni Liljamo + * Copyright (C) 2024 Jonni Liljamo * * This file is licensed under AGPL-3.0-or-later, see NOTICE and LICENSE for * more information. */ + package handlers import ( @@ -13,18 +14,21 @@ import ( "github.com/gin-gonic/gin" ) +// ManageAdmin returns a gin handler func ManageAdmin() gin.HandlerFunc { return func(c *gin.Context) { c.HTML(http.StatusOK, "", components.ManageAdmin()) } } +// ManageAdminUsers returns a gin handler func ManageAdminUsers() gin.HandlerFunc { return func(c *gin.Context) { c.HTML(http.StatusOK, "", components.ManageAdminUsers()) } } +// ManageAdminDomains returns a gin handler func ManageAdminDomains() gin.HandlerFunc { return func(c *gin.Context) { c.HTML(http.StatusOK, "", components.ManageAdminDomains()) diff --git a/internal/handlers/adminpartials.go b/internal/handlers/adminpartials.go index 76e7829..fc7457c 100644 --- a/internal/handlers/adminpartials.go +++ b/internal/handlers/adminpartials.go @@ -1,9 +1,10 @@ /* - * Copyright (C) 2023 Jonni Liljamo + * Copyright (C) 2024 Jonni Liljamo * * This file is licensed under AGPL-3.0-or-later, see NOTICE and LICENSE for * more information. */ + package handlers import ( @@ -14,6 +15,7 @@ import ( "github.com/gin-gonic/gin" ) +// AdminPartialUsersList returns a gin handler func AdminPartialUsersList() gin.HandlerFunc { return func(c *gin.Context) { users, err := db.FetchAllUsers() @@ -27,6 +29,7 @@ func AdminPartialUsersList() gin.HandlerFunc { } } +// AdminPartialDomainsList returns a gin handler func AdminPartialDomainsList() gin.HandlerFunc { return func(c *gin.Context) { users, err := db.FetchAllDomains() diff --git a/internal/handlers/auth.go b/internal/handlers/auth.go index 2245420..db987ca 100644 --- a/internal/handlers/auth.go +++ b/internal/handlers/auth.go @@ -1,9 +1,10 @@ /* - * Copyright (C) 2023 Jonni Liljamo + * Copyright (C) 2024 Jonni Liljamo * * This file is licensed under AGPL-3.0-or-later, see NOTICE and LICENSE for * more information. */ + package handlers import ( @@ -19,6 +20,7 @@ type postAuthLoginData struct { Password string `form:"password"` } +// AuthLogin returns a gin handler func AuthLogin(sm *scs.SessionManager) gin.HandlerFunc { return func(c *gin.Context) { data := &postAuthLoginData{} @@ -34,12 +36,13 @@ func AuthLogin(sm *scs.SessionManager) gin.HandlerFunc { return } - sm.Put(c.Request.Context(), "user_id", user.Id) + sm.Put(c.Request.Context(), "user_id", user.ID) c.Header("HX-Redirect", "/manage") } } +// AuthLogout returns a gin handler func AuthLogout(sm *scs.SessionManager) gin.HandlerFunc { return func(c *gin.Context) { sm.Destroy(c.Request.Context()) diff --git a/internal/handlers/domains.go b/internal/handlers/domains.go index 5af8479..7244eb4 100644 --- a/internal/handlers/domains.go +++ b/internal/handlers/domains.go @@ -1,9 +1,10 @@ /* - * Copyright (C) 2023 Jonni Liljamo + * Copyright (C) 2024 Jonni Liljamo * * This file is licensed under AGPL-3.0-or-later, see NOTICE and LICENSE for * more information. */ + package handlers import ( @@ -21,6 +22,7 @@ type postDomainData struct { ARecord string `form:"a_record"` } +// PostDomain returns a gin handler func PostDomain() gin.HandlerFunc { return func(c *gin.Context) { data := &postDomainData{} @@ -52,14 +54,14 @@ func PostDomain() gin.HandlerFunc { return } - userId, exists := c.Get("user_id") + userID, exists := c.Get("user_id") if !exists { c.String(http.StatusInternalServerError, "This should not be possible, but don't quote me on that") c.Abort() return } - err := db.CreateDomain(data.Domain, data.ARecord, userId.(string)) + err := db.CreateDomain(data.Domain, data.ARecord, userID.(string)) if err != nil { // FIXME: Handle better c.String(http.StatusInternalServerError, "Something went wrong while creating a new domain") @@ -71,9 +73,10 @@ func PostDomain() gin.HandlerFunc { } } +// PatchDomain returns a gin handler func PatchDomain() gin.HandlerFunc { return func(c *gin.Context) { - userId, exists := c.Get("user_id") + userID, exists := c.Get("user_id") if !exists { c.String(http.StatusInternalServerError, "This should not be possible, but don't quote me on that") c.Abort() @@ -89,7 +92,7 @@ func PatchDomain() gin.HandlerFunc { c.Abort() return } - err := db.UpdateDomainARecordManual(id, userId.(string), aRecord) + err := db.UpdateDomainARecordManual(id, userID.(string), aRecord) if err != nil { // FIXME: Handle better c.String(http.StatusInternalServerError, "Something went wrong while updating the a record") @@ -102,18 +105,19 @@ func PatchDomain() gin.HandlerFunc { } } +// DeleteDomain returns a gin handler func DeleteDomain() gin.HandlerFunc { return func(c *gin.Context) { id := c.Param("id") - userId, exists := c.Get("user_id") + userID, exists := c.Get("user_id") if !exists { c.String(http.StatusInternalServerError, "This should not be possible, but don't quote me on that") c.Abort() return } - err := db.DeleteDomain(id, userId.(string)) + err := db.DeleteDomain(id, userID.(string)) if err != nil { // FIXME: Handle better c.String(http.StatusInternalServerError, "Something went wrong while deleting the domain") @@ -125,18 +129,19 @@ func DeleteDomain() gin.HandlerFunc { } } -func RefreshDomainApiKey() gin.HandlerFunc { +// RefreshDomainAPIKey returns a gin handler +func RefreshDomainAPIKey() gin.HandlerFunc { return func(c *gin.Context) { id := c.Param("id") - userId, exists := c.Get("user_id") + userID, exists := c.Get("user_id") if !exists { c.String(http.StatusInternalServerError, "This should not be possible, but don't quote me on that") c.Abort() return } - err := db.RefreshDomainApiKey(id, userId.(string)) + err := db.RefreshDomainAPIKey(id, userID.(string)) if err != nil { // FIXME: Handle better c.String(http.StatusInternalServerError, "Something went wrong while updating the api key") diff --git a/internal/handlers/index.go b/internal/handlers/index.go index 490d8d1..b3d3ca9 100644 --- a/internal/handlers/index.go +++ b/internal/handlers/index.go @@ -1,9 +1,11 @@ /* - * Copyright (C) 2023 Jonni Liljamo + * Copyright (C) 2024 Jonni Liljamo * * This file is licensed under AGPL-3.0-or-later, see NOTICE and LICENSE for * more information. */ + +// Package handlers implements all request handlers. package handlers import ( @@ -13,6 +15,7 @@ import ( "github.com/gin-gonic/gin" ) +// Index returns a gin handler func Index() gin.HandlerFunc { return func(c *gin.Context) { c.HTML(http.StatusOK, "", components.Index()) diff --git a/internal/handlers/login.go b/internal/handlers/login.go index 952d807..afb177f 100644 --- a/internal/handlers/login.go +++ b/internal/handlers/login.go @@ -1,9 +1,10 @@ /* - * Copyright (C) 2023 Jonni Liljamo + * Copyright (C) 2024 Jonni Liljamo * * This file is licensed under AGPL-3.0-or-later, see NOTICE and LICENSE for * more information. */ + package handlers import ( @@ -13,6 +14,7 @@ import ( "github.com/gin-gonic/gin" ) +// Login returns a gin handler func Login() gin.HandlerFunc { return func(c *gin.Context) { c.HTML(http.StatusOK, "", components.Login()) diff --git a/internal/handlers/manage.go b/internal/handlers/manage.go index 4c49185..6b1f3a9 100644 --- a/internal/handlers/manage.go +++ b/internal/handlers/manage.go @@ -1,9 +1,10 @@ /* - * Copyright (C) 2023 Jonni Liljamo + * Copyright (C) 2024 Jonni Liljamo * * This file is licensed under AGPL-3.0-or-later, see NOTICE and LICENSE for * more information. */ + package handlers import ( @@ -14,22 +15,24 @@ import ( "github.com/gin-gonic/gin" ) +// Manage returns a gin handler func Manage() gin.HandlerFunc { return func(c *gin.Context) { c.HTML(http.StatusOK, "", components.Manage()) } } +// ManageUser returns a gin handler func ManageUser() gin.HandlerFunc { return func(c *gin.Context) { - user_id, exists := c.Get("user_id") + userID, exists := c.Get("user_id") if !exists { c.String(http.StatusInternalServerError, "This should not be possible, but don't quote me on that, S01E01") c.Abort() return } - user, err := db.FetchUserWithId(user_id.(string)) + user, err := db.FetchUserWithID(userID.(string)) if err != nil { c.String(http.StatusInternalServerError, "This should not be possible, but don't quote me on that, S01E02") c.Abort() diff --git a/internal/handlers/managepartials.go b/internal/handlers/managepartials.go index 90b54cf..8010870 100644 --- a/internal/handlers/managepartials.go +++ b/internal/handlers/managepartials.go @@ -1,9 +1,10 @@ /* - * Copyright (C) 2023 Jonni Liljamo + * Copyright (C) 2024 Jonni Liljamo * * This file is licensed under AGPL-3.0-or-later, see NOTICE and LICENSE for * more information. */ + package handlers import ( @@ -14,16 +15,17 @@ import ( "github.com/gin-gonic/gin" ) +// ManagePartialDomains returns a gin handler func ManagePartialDomains() gin.HandlerFunc { return func(c *gin.Context) { - user_id, exists := c.Get("user_id") + userID, exists := c.Get("user_id") if !exists { c.String(http.StatusInternalServerError, "This should not be possible, but don't quote me on that") c.Abort() return } - domains, err := db.FetchDomainsForUser(user_id.(string)) + domains, err := db.FetchDomainsForUser(userID.(string)) if err != nil { c.String(http.StatusInternalServerError, "Failed to fetch domains for user") c.Abort() diff --git a/internal/handlers/user.go b/internal/handlers/user.go index b6ec89b..fd53d05 100644 --- a/internal/handlers/user.go +++ b/internal/handlers/user.go @@ -1,9 +1,10 @@ /* - * Copyright (C) 2023 Jonni Liljamo + * Copyright (C) 2024 Jonni Liljamo * * This file is licensed under AGPL-3.0-or-later, see NOTICE and LICENSE for * more information. */ + package handlers import ( @@ -20,6 +21,7 @@ type postUserPasswordData struct { ConfirmNewPassword string `form:"confirm_new_password"` } +// PostUserPassword returns a gin handler func PostUserPassword() gin.HandlerFunc { return func(c *gin.Context) { data := &postUserPasswordData{} @@ -40,20 +42,20 @@ func PostUserPassword() gin.HandlerFunc { return } - userId, exists := c.Get("user_id") + userID, exists := c.Get("user_id") if !exists { c.String(http.StatusInternalServerError, "This should not be possible, but don't quote me on that") c.Abort() return } - if !db.VerifyUserPassword(userId.(string), data.CurrentPassword) { + if !db.VerifyUserPassword(userID.(string), data.CurrentPassword) { c.String(http.StatusBadRequest, "Current password is not correct") c.Abort() return } - err := db.UpdateUserPassword(userId.(string), data.NewPassword) + err := db.UpdateUserPassword(userID.(string), data.NewPassword) if err != nil { // FIXME: Handle better c.String(http.StatusInternalServerError, "Something went wrong while deleting the user") @@ -69,6 +71,7 @@ type postUserEmailData struct { Email string `form:"email"` } +// PostUserEmail returns a gin handler func PostUserEmail() gin.HandlerFunc { return func(c *gin.Context) { data := &postUserEmailData{} @@ -84,14 +87,14 @@ func PostUserEmail() gin.HandlerFunc { return } - userId, exists := c.Get("user_id") + userID, exists := c.Get("user_id") if !exists { c.String(http.StatusInternalServerError, "This should not be possible, but don't quote me on that") c.Abort() return } - err := db.UpdateUserEmail(userId.(string), data.Email) + err := db.UpdateUserEmail(userID.(string), data.Email) if err != nil { // FIXME: Handle better c.String(http.StatusInternalServerError, "Something went wrong while deleting the user") @@ -103,16 +106,17 @@ func PostUserEmail() gin.HandlerFunc { } } +// DeleteUser returns a gin handler func DeleteUser(sm *scs.SessionManager) gin.HandlerFunc { return func(c *gin.Context) { - userId, exists := c.Get("user_id") + userID, exists := c.Get("user_id") if !exists { c.String(http.StatusInternalServerError, "This should not be possible, but don't quote me on that") c.Abort() return } - err := db.DeleteUser(userId.(string)) + err := db.DeleteUser(userID.(string)) if err != nil { // FIXME: Handle better c.String(http.StatusInternalServerError, "Something went wrong while deleting the user") diff --git a/internal/handlers/users.go b/internal/handlers/users.go index 86f15fc..541ab00 100644 --- a/internal/handlers/users.go +++ b/internal/handlers/users.go @@ -1,9 +1,10 @@ /* - * Copyright (C) 2023 Jonni Liljamo + * Copyright (C) 2024 Jonni Liljamo * * This file is licensed under AGPL-3.0-or-later, see NOTICE and LICENSE for * more information. */ + package handlers import ( @@ -18,6 +19,7 @@ type postUserData struct { InitialPwd string `form:"initial_pwd"` } +// PostUser returns a gin handler func PostUser() gin.HandlerFunc { return func(c *gin.Context) { data := &postUserData{} diff --git a/internal/log/ginformat.go b/internal/log/ginformat.go index 9af6688..e9e26e0 100644 --- a/internal/log/ginformat.go +++ b/internal/log/ginformat.go @@ -1,9 +1,10 @@ /* - * Copyright (C) 2023 Jonni Liljamo + * Copyright (C) 2024 Jonni Liljamo * * This file is licensed under AGPL-3.0-or-later, see NOTICE and LICENSE for * more information. */ + package log import ( @@ -13,6 +14,7 @@ import ( "github.com/gin-gonic/gin" ) +// GinFormat is a custom gin log formatting function. func GinFormat(param gin.LogFormatterParams, router string) string { var statusColor, methodColor, resetColor string if param.IsOutputColor() { diff --git a/internal/log/log.go b/internal/log/log.go index 5204869..3ff4dd4 100644 --- a/internal/log/log.go +++ b/internal/log/log.go @@ -1,9 +1,11 @@ /* - * Copyright (C) 2023 Jonni Liljamo + * Copyright (C) 2024 Jonni Liljamo * * This file is licensed under AGPL-3.0-or-later, see NOTICE and LICENSE for * more information. */ + +// Package log implements logging utilities. package log import ( @@ -12,6 +14,7 @@ import ( "path/filepath" ) +// InitDefaultLogger initializes the default logger. func InitDefaultLogger(logLevel string) { var feluLogLevel = new(slog.LevelVar) switch logLevel { @@ -35,8 +38,8 @@ func InitDefaultLogger(logLevel string) { } logger := slog.New(slog.NewTextHandler(os.Stdout, &slog.HandlerOptions{ - Level: feluLogLevel, - AddSource: true, + Level: feluLogLevel, + AddSource: true, ReplaceAttr: replace, })) diff --git a/internal/middlewares/admin.go b/internal/middlewares/admin.go index 7c51ed1..385b1bb 100644 --- a/internal/middlewares/admin.go +++ b/internal/middlewares/admin.go @@ -1,9 +1,10 @@ /* - * Copyright (C) 2023 Jonni Liljamo + * Copyright (C) 2024 Jonni Liljamo * * This file is licensed under AGPL-3.0-or-later, see NOTICE and LICENSE for * more information. */ + package middlewares import ( @@ -13,11 +14,12 @@ import ( "github.com/gin-gonic/gin" ) +// AdminOnly returns a gin middleware for checking if a user is an admin. func AdminOnly() gin.HandlerFunc { return func(c *gin.Context) { - user_id, exists := c.Get("user_id") + userID, exists := c.Get("user_id") if exists { - user, err := db.FetchUserWithId(user_id.(string)) + user, err := db.FetchUserWithID(userID.(string)) if err == nil { if user.IsAdmin { c.Next() diff --git a/internal/middlewares/auth.go b/internal/middlewares/auth.go index 4b24433..26e6dfa 100644 --- a/internal/middlewares/auth.go +++ b/internal/middlewares/auth.go @@ -1,9 +1,10 @@ /* - * Copyright (C) 2023 Jonni Liljamo + * Copyright (C) 2024 Jonni Liljamo * * This file is licensed under AGPL-3.0-or-later, see NOTICE and LICENSE for * more information. */ + package middlewares import ( @@ -13,16 +14,17 @@ import ( "github.com/gin-gonic/gin" ) +// SessionExists returns a gin middleware for checking if a session exists. func SessionExists(sm *scs.SessionManager) gin.HandlerFunc { return func(c *gin.Context) { - user_id := sm.Get(c.Request.Context(), "user_id") - if user_id != nil { + userID := sm.Get(c.Request.Context(), "user_id") + if userID != nil { if c.Request.URL.Path == "/login" { c.Redirect(http.StatusTemporaryRedirect, "/manage") c.Abort() } else { // Set user_id in context, if needed later (e.g. AdminOnly middleware) - c.Set("user_id", user_id) + c.Set("user_id", userID) // TODO: Validate in db? c.Next() } diff --git a/internal/middlewares/middlewares.go b/internal/middlewares/middlewares.go new file mode 100644 index 0000000..753eea1 --- /dev/null +++ b/internal/middlewares/middlewares.go @@ -0,0 +1,9 @@ +/* + * Copyright (C) 2024 Jonni Liljamo + * + * This file is licensed under AGPL-3.0-or-later, see NOTICE and LICENSE for + * more information. + */ + +// Package middlewares implements gin middlewares. +package middlewares diff --git a/internal/renderer/renderer.go b/internal/renderer/renderer.go index 76ba605..a89b68f 100644 --- a/internal/renderer/renderer.go +++ b/internal/renderer/renderer.go @@ -1,9 +1,11 @@ /* - * Copyright (C) 2023 Jonni Liljamo + * Copyright (C) 2024 Jonni Liljamo * * This file is licensed under AGPL-3.0-or-later, see NOTICE and LICENSE for * more information. */ + +// Package renderer implements templ rendering. package renderer import ( @@ -14,12 +16,14 @@ import ( "github.com/gin-gonic/gin/render" ) +// TemplRender holds the required info for rendering templ components. type TemplRender struct { Code int Data templ.Component } -func (t TemplRender) Render (w http.ResponseWriter) error { +// Render renders templ templates to HTML (and friends). +func (t TemplRender) Render(w http.ResponseWriter) error { w.WriteHeader(t.Code) if t.Data != nil { return t.Data.Render(context.Background(), w) @@ -28,11 +32,13 @@ func (t TemplRender) Render (w http.ResponseWriter) error { return nil } +// WriteContentType sets the Content-Type header. func (t TemplRender) WriteContentType(w http.ResponseWriter) { w.Header().Set("Content-Type", "text/html; charset=utf-8") } -func (t *TemplRender) Instance(name string, data interface{}) render.Render { +// Instance returns an instance of the templ renderer. +func (t *TemplRender) Instance( /* name */ _ string, data interface{}) render.Render { if templData, ok := data.(templ.Component); ok { return &TemplRender{ Code: http.StatusOK, diff --git a/internal/routers/api.go b/internal/routers/api.go index a225043..b2a6ecd 100644 --- a/internal/routers/api.go +++ b/internal/routers/api.go @@ -1,9 +1,10 @@ /* - * Copyright (C) 2023 Jonni Liljamo + * Copyright (C) 2024 Jonni Liljamo * * This file is licensed under AGPL-3.0-or-later, see NOTICE and LICENSE for * more information. */ + package routers import ( @@ -14,6 +15,7 @@ import ( "github.com/gin-gonic/gin" ) +// SetupAPIRouter returns the API router. func SetupAPIRouter(version string) *gin.Engine { r := gin.New() r.Use(gin.Recovery()) diff --git a/internal/routers/frontend.go b/internal/routers/frontend.go index e1122f6..0517641 100644 --- a/internal/routers/frontend.go +++ b/internal/routers/frontend.go @@ -1,9 +1,10 @@ /* - * Copyright (C) 2023 Jonni Liljamo + * Copyright (C) 2024 Jonni Liljamo * * This file is licensed under AGPL-3.0-or-later, see NOTICE and LICENSE for * more information. */ + package routers import ( @@ -15,6 +16,7 @@ import ( "github.com/gin-gonic/gin" ) +// SetupFrontendRouter returns the frontend router. func SetupFrontendRouter(sm *scs.SessionManager) *gin.Engine { r := gin.New() r.Use(gin.Recovery()) @@ -46,7 +48,7 @@ func SetupFrontendRouter(sm *scs.SessionManager) *gin.Engine { manage.POST("/domains", handlers.PostDomain()) manage.PATCH("/domains/:id", handlers.PatchDomain()) manage.DELETE("/domains/:id", handlers.DeleteDomain()) - manage.POST("/domains/:id/api_key", handlers.RefreshDomainApiKey()) + manage.POST("/domains/:id/api_key", handlers.RefreshDomainAPIKey()) manage.GET("/partials/domains", handlers.ManagePartialDomains()) } diff --git a/internal/routers/routers.go b/internal/routers/routers.go new file mode 100644 index 0000000..05ac1f7 --- /dev/null +++ b/internal/routers/routers.go @@ -0,0 +1,9 @@ +/* + * Copyright (C) 2024 Jonni Liljamo + * + * This file is licensed under AGPL-3.0-or-later, see NOTICE and LICENSE for + * more information. + */ + +// Package routers implements both the frontend and API routers. +package routers diff --git a/internal/util/apikey.go b/internal/util/apikey.go index dec4206..e5cdb8c 100644 --- a/internal/util/apikey.go +++ b/internal/util/apikey.go @@ -1,20 +1,22 @@ /* - * Copyright (C) 2023 Jonni Liljamo + * Copyright (C) 2024 Jonni Liljamo * * This file is licensed under AGPL-3.0-or-later, see NOTICE and LICENSE for * more information. */ + package util import "math/rand" const chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789" -func GenApiKey() string { +// GenAPIKey returns a 48 char string. +func GenAPIKey() string { // NOTE: "Good enough" b := make([]byte, 48) for i := range b { - b[i] = chars[rand.Int63() % int64(len(chars))] + b[i] = chars[rand.Int63()%int64(len(chars))] } return string(b) } diff --git a/internal/util/check.go b/internal/util/check.go index de46633..2c91335 100644 --- a/internal/util/check.go +++ b/internal/util/check.go @@ -1,9 +1,10 @@ /* - * Copyright (C) 2023 Jonni Liljamo + * Copyright (C) 2024 Jonni Liljamo * * This file is licensed under AGPL-3.0-or-later, see NOTICE and LICENSE for * more information. */ + package util import ( @@ -11,6 +12,7 @@ import ( "net" ) +// CheckARecord verifies the validity of an A record. func CheckARecord(aRecord string) error { if net.ParseIP(aRecord).To4() == nil { return errors.New("Invalid A record") diff --git a/internal/util/util.go b/internal/util/util.go new file mode 100644 index 0000000..757124f --- /dev/null +++ b/internal/util/util.go @@ -0,0 +1,9 @@ +/* + * Copyright (C) 2024 Jonni Liljamo + * + * This file is licensed under AGPL-3.0-or-later, see NOTICE and LICENSE for + * more information. + */ + +// Package util implements a variety of small utility functions. +package util -- 2.44.1