mirror of
https://github.com/acme-dns/acme-dns.git
synced 2026-02-22 09:35:35 -07:00
* Refactor core * Re-added tests * Small fixes * Add tests for acmetxt cidrslice and util funcs * Remove the last dangling reference to old logging package * Refactoring (#327) * chore: enable more linters and fix linter issues * ci: enable linter checks on all branches and disable recurring checks recurring linter checks don't make that much sense. The code & linter checks should not change on their own over night ;) * chore: update packages * Revert "chore: update packages" This reverts commit 30250bf28c4b39e9e5b3af012a4e28ab036bf9af. * chore: manually upgrade some packages * Updated dependencies, wrote changelog entry and fixed namespace for release * Refactoring - improving coverage (#371) * Increase code coverage in acmedns * More testing of ReadConfig() and its fallback mechanism * Found that if someone put a '"' double quote into the filename that we configure zap to log to, it would cause the the JSON created to be invalid. I have replaced the JSON string with proper config * Better handling of config options for api.TLS - we now error on an invalid value instead of silently failing. added a basic test for api.setupTLS() (to increase test coverage) * testing nameserver isOwnChallenge and isAuthoritative methods * add a unit test for nameserver answerOwnChallenge * fix linting errors * bump go and golangci-lint versions in github actions * Update golangci-lint.yml Bumping github-actions workflow versions to accommodate some changes in upstream golanci-lint * Bump Golang version to 1.23 (currently the oldest supported version) Bump golanglint-ci to 2.0.2 and migrate the config file. This should resolve the math/rand/v2 issue * bump golanglint-ci action version * Fixing up new golanglint-ci warnings and errors --------- Co-authored-by: Joona Hoikkala <5235109+joohoi@users.noreply.github.com> * Minor refactoring, error returns and e2e testing suite * Add a few tests * Fix linter and umask setting * Update github actions * Refine concurrency configuration for GitHub actions * HTTP timeouts to API, and self-validation mutex to nameserver ops --------- Co-authored-by: Florian Ritterhoff <32478819+fritterhoff@users.noreply.github.com> Co-authored-by: Jason Playne <jason@jasonplayne.com>
104 lines
3.0 KiB
Go
104 lines
3.0 KiB
Go
package api
|
|
|
|
import (
|
|
"context"
|
|
"encoding/json"
|
|
"fmt"
|
|
"net"
|
|
"net/http"
|
|
|
|
"github.com/julienschmidt/httprouter"
|
|
|
|
"github.com/joohoi/acme-dns/pkg/acmedns"
|
|
)
|
|
|
|
type key int
|
|
|
|
// ACMETxtKey is a context key for ACMETxt struct
|
|
const ACMETxtKey key = 0
|
|
|
|
// Auth middleware for update request
|
|
func (a *AcmednsAPI) Auth(update httprouter.Handle) httprouter.Handle {
|
|
return func(w http.ResponseWriter, r *http.Request, p httprouter.Params) {
|
|
postData := acmedns.ACMETxt{}
|
|
userOK := false
|
|
user, err := a.getUserFromRequest(r)
|
|
if err == nil {
|
|
if a.updateAllowedFromIP(r, user) {
|
|
dec := json.NewDecoder(r.Body)
|
|
err = dec.Decode(&postData)
|
|
if err != nil {
|
|
a.Logger.Errorw("Decoding error",
|
|
"error", "json_error")
|
|
}
|
|
if user.Subdomain == postData.Subdomain {
|
|
userOK = true
|
|
} else {
|
|
a.Logger.Errorw("Subdomain mismatch",
|
|
"error", "subdomain_mismatch",
|
|
"name", postData.Subdomain,
|
|
"expected", user.Subdomain)
|
|
}
|
|
} else {
|
|
a.Logger.Errorw("Update not allowed from IP",
|
|
"error", "ip_unauthorized")
|
|
}
|
|
} else {
|
|
a.Logger.Errorw("Error while trying to get user",
|
|
"error", err.Error())
|
|
}
|
|
if userOK {
|
|
// Set user info to the decoded ACMETxt object
|
|
postData.Username = user.Username
|
|
postData.Password = user.Password
|
|
// Set the ACMETxt struct to context to pull in from update function
|
|
ctx := context.WithValue(r.Context(), ACMETxtKey, postData)
|
|
update(w, r.WithContext(ctx), p)
|
|
} else {
|
|
w.Header().Set("Content-Type", "application/json")
|
|
w.WriteHeader(http.StatusUnauthorized)
|
|
_, _ = w.Write(jsonError("forbidden"))
|
|
}
|
|
}
|
|
}
|
|
|
|
func (a *AcmednsAPI) getUserFromRequest(r *http.Request) (acmedns.ACMETxt, error) {
|
|
uname := r.Header.Get("X-Api-User")
|
|
passwd := r.Header.Get("X-Api-Key")
|
|
username, err := getValidUsername(uname)
|
|
if err != nil {
|
|
return acmedns.ACMETxt{}, fmt.Errorf("invalid username: %s: %w", uname, err)
|
|
}
|
|
if validKey(passwd) {
|
|
dbuser, err := a.DB.GetByUsername(username)
|
|
if err != nil {
|
|
a.Logger.Errorw("Error while trying to get user",
|
|
"error", err.Error())
|
|
// To protect against timed side channel (never gonna give you up)
|
|
acmedns.CorrectPassword(passwd, "$2a$10$8JEFVNYYhLoBysjAxe2yBuXrkDojBQBkVpXEQgyQyjn43SvJ4vL36")
|
|
|
|
return acmedns.ACMETxt{}, fmt.Errorf("invalid username: %s", uname)
|
|
}
|
|
if acmedns.CorrectPassword(passwd, dbuser.Password) {
|
|
return dbuser, nil
|
|
}
|
|
return acmedns.ACMETxt{}, fmt.Errorf("invalid password for user %s", uname)
|
|
}
|
|
return acmedns.ACMETxt{}, fmt.Errorf("invalid key for user %s", uname)
|
|
}
|
|
|
|
func (a *AcmednsAPI) updateAllowedFromIP(r *http.Request, user acmedns.ACMETxt) bool {
|
|
if a.Config.API.UseHeader {
|
|
ips := getIPListFromHeader(r.Header.Get(a.Config.API.HeaderName))
|
|
return user.AllowedFromList(ips)
|
|
}
|
|
host, _, err := net.SplitHostPort(r.RemoteAddr)
|
|
if err != nil {
|
|
a.Logger.Errorw("Error while parsing remote address",
|
|
"error", err.Error(),
|
|
"remoteaddr", r.RemoteAddr)
|
|
host = ""
|
|
}
|
|
return user.AllowedFrom(host)
|
|
}
|