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:
2019-10-07 18:21:26 +05:00
parent 83a8694061
commit 6ce7747dd5
24 changed files with 725 additions and 47 deletions

View 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}})
}
}
}

View File

@@ -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)
}

View 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
}