Working with packages and allowed IPs.
giredorectl now able to interact with giredored about: * Setting package data. There is no such thing as "create" or "update", just set. * Deleting package data. * Setting allowed IP addresses. This is the only authorization method ATM, more may come in future.
This commit is contained in:
65
internal/httpserver/checkallowedips.go
Normal file
65
internal/httpserver/checkallowedips.go
Normal file
@@ -0,0 +1,65 @@
|
||||
package httpserver
|
||||
|
||||
import (
|
||||
// stdlib
|
||||
"net"
|
||||
"net/http"
|
||||
"strings"
|
||||
|
||||
// local
|
||||
"sources.dev.pztrn.name/pztrn/giredore/internal/configuration"
|
||||
"sources.dev.pztrn.name/pztrn/giredore/internal/structs"
|
||||
|
||||
// other
|
||||
"github.com/labstack/echo"
|
||||
)
|
||||
|
||||
func checkAllowedIPs() echo.MiddlewareFunc {
|
||||
return func(next echo.HandlerFunc) echo.HandlerFunc {
|
||||
return func(ec echo.Context) error {
|
||||
// Do nothing if request came not in "/_api" namespace.
|
||||
if !strings.HasPrefix(ec.Request().RequestURI, "/_api") {
|
||||
_ = next(ec)
|
||||
return nil
|
||||
}
|
||||
|
||||
// Get IPs and subnets from configuration and parse them
|
||||
// into comparable things.
|
||||
// If IP address was specified without network mask - assume /32.
|
||||
var subnets []*net.IPNet
|
||||
allowedIPs := configuration.Cfg.GetAllowedIPs()
|
||||
for _, ip := range allowedIPs {
|
||||
ipToParse := ip
|
||||
if !strings.Contains(ip, "/") {
|
||||
ipToParse = ip + "/32"
|
||||
}
|
||||
|
||||
_, net, err := net.ParseCIDR(ipToParse)
|
||||
if err != nil {
|
||||
log.Error().Err(err).Str("subnet", ipToParse).Msg("Failed to parse CIDR. /_api/ endpoint won't be accessible, this should be fixed manually in configuration file!")
|
||||
return ec.JSON(http.StatusInternalServerError, &structs.Reply{Status: structs.StatusFailure, Errors: []structs.Error{structs.ErrInvalidAllowedIPDefined}})
|
||||
}
|
||||
|
||||
subnets = append(subnets, net)
|
||||
}
|
||||
|
||||
// Check if requester's IP address are within allowed IP
|
||||
// subnets.
|
||||
ipToCheck := net.ParseIP(ec.RealIP())
|
||||
var allowed bool
|
||||
for _, subnet := range subnets {
|
||||
if subnet.Contains(ipToCheck) {
|
||||
allowed = true
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if allowed {
|
||||
_ = next(ec)
|
||||
return nil
|
||||
}
|
||||
|
||||
return ec.JSON(http.StatusBadRequest, &structs.Reply{Status: structs.StatusFailure, Errors: []structs.Error{structs.ErrIPAddressNotAllowed}})
|
||||
}
|
||||
}
|
||||
}
|
@@ -32,9 +32,11 @@ func Initialize() {
|
||||
Srv = echo.New()
|
||||
Srv.Use(middleware.Recover())
|
||||
Srv.Use(requestLogger())
|
||||
Srv.Use(checkAllowedIPs())
|
||||
Srv.DisableHTTP2 = true
|
||||
Srv.HideBanner = true
|
||||
Srv.HidePort = true
|
||||
Srv.Binder = echo.Binder(&StrictJSONBinder{})
|
||||
|
||||
Srv.GET("/_internal/waitForOnline", waitForHTTPServerToBeUpHandler)
|
||||
}
|
||||
|
38
internal/httpserver/strictjson.go
Normal file
38
internal/httpserver/strictjson.go
Normal file
@@ -0,0 +1,38 @@
|
||||
package httpserver
|
||||
|
||||
import (
|
||||
// stdlib
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/http"
|
||||
|
||||
// other
|
||||
"github.com/labstack/echo"
|
||||
)
|
||||
|
||||
// StrictJSONBinder implements Binder interface for Echo. It will parse
|
||||
// JSON in strict mode throwing errors on schema mismatches.
|
||||
type StrictJSONBinder struct{}
|
||||
|
||||
// Bind parses JSON input.
|
||||
func (sjb *StrictJSONBinder) Bind(i interface{}, c echo.Context) error {
|
||||
req := c.Request()
|
||||
if req.ContentLength == 0 {
|
||||
return echo.NewHTTPError(http.StatusBadRequest, "Request body can't be empty")
|
||||
}
|
||||
|
||||
// Decode it.
|
||||
decoder := json.NewDecoder(req.Body)
|
||||
decoder.DisallowUnknownFields()
|
||||
if err := decoder.Decode(i); err != nil {
|
||||
if ute, ok := err.(*json.UnmarshalTypeError); ok {
|
||||
return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Unmarshal type error: expected=%v, got=%v, field=%v, offset=%v", ute.Type, ute.Value, ute.Field, ute.Offset))
|
||||
} else if se, ok := err.(*json.SyntaxError); ok {
|
||||
return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Syntax error: offset=%v, error=%v", se.Offset, se.Error()))
|
||||
} else {
|
||||
return echo.NewHTTPError(http.StatusBadRequest, err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
Reference in New Issue
Block a user