mirror of
https://github.com/openfaas/faasd.git
synced 2025-06-22 14:53:30 +00:00
**What** - Use the compose-go library to read the service definitions from an external compose file instead of building them in Go - Add default compose file and copy during `faasd install` - Add test for load and parse of compose file - Make testing easier by sorting the env keys - Allow append to instantiate the slices so that we can more easily test for proper parsing (e.g. nil is still nil etc) - Add the arch suffix to the compose file and set this as part of the env when we parse the compose file. This allows faasd to dynamically set the arch suffix used for the basic auth and the gateway images. Signed-off-by: Lucas Roesler <roesler.lucas@gmail.com>
369 lines
9.7 KiB
Go
Generated
369 lines
9.7 KiB
Go
Generated
package gojsonschema
|
|
|
|
import (
|
|
"net"
|
|
"net/mail"
|
|
"net/url"
|
|
"regexp"
|
|
"strings"
|
|
"sync"
|
|
"time"
|
|
)
|
|
|
|
type (
|
|
// FormatChecker is the interface all formatters added to FormatCheckerChain must implement
|
|
FormatChecker interface {
|
|
// IsFormat checks if input has the correct format and type
|
|
IsFormat(input interface{}) bool
|
|
}
|
|
|
|
// FormatCheckerChain holds the formatters
|
|
FormatCheckerChain struct {
|
|
formatters map[string]FormatChecker
|
|
}
|
|
|
|
// EmailFormatChecker verifies email address formats
|
|
EmailFormatChecker struct{}
|
|
|
|
// IPV4FormatChecker verifies IP addresses in the IPv4 format
|
|
IPV4FormatChecker struct{}
|
|
|
|
// IPV6FormatChecker verifies IP addresses in the IPv6 format
|
|
IPV6FormatChecker struct{}
|
|
|
|
// DateTimeFormatChecker verifies date/time formats per RFC3339 5.6
|
|
//
|
|
// Valid formats:
|
|
// Partial Time: HH:MM:SS
|
|
// Full Date: YYYY-MM-DD
|
|
// Full Time: HH:MM:SSZ-07:00
|
|
// Date Time: YYYY-MM-DDTHH:MM:SSZ-0700
|
|
//
|
|
// Where
|
|
// YYYY = 4DIGIT year
|
|
// MM = 2DIGIT month ; 01-12
|
|
// DD = 2DIGIT day-month ; 01-28, 01-29, 01-30, 01-31 based on month/year
|
|
// HH = 2DIGIT hour ; 00-23
|
|
// MM = 2DIGIT ; 00-59
|
|
// SS = 2DIGIT ; 00-58, 00-60 based on leap second rules
|
|
// T = Literal
|
|
// Z = Literal
|
|
//
|
|
// Note: Nanoseconds are also suported in all formats
|
|
//
|
|
// http://tools.ietf.org/html/rfc3339#section-5.6
|
|
DateTimeFormatChecker struct{}
|
|
|
|
// DateFormatChecker verifies date formats
|
|
//
|
|
// Valid format:
|
|
// Full Date: YYYY-MM-DD
|
|
//
|
|
// Where
|
|
// YYYY = 4DIGIT year
|
|
// MM = 2DIGIT month ; 01-12
|
|
// DD = 2DIGIT day-month ; 01-28, 01-29, 01-30, 01-31 based on month/year
|
|
DateFormatChecker struct{}
|
|
|
|
// TimeFormatChecker verifies time formats
|
|
//
|
|
// Valid formats:
|
|
// Partial Time: HH:MM:SS
|
|
// Full Time: HH:MM:SSZ-07:00
|
|
//
|
|
// Where
|
|
// HH = 2DIGIT hour ; 00-23
|
|
// MM = 2DIGIT ; 00-59
|
|
// SS = 2DIGIT ; 00-58, 00-60 based on leap second rules
|
|
// T = Literal
|
|
// Z = Literal
|
|
TimeFormatChecker struct{}
|
|
|
|
// URIFormatChecker validates a URI with a valid Scheme per RFC3986
|
|
URIFormatChecker struct{}
|
|
|
|
// URIReferenceFormatChecker validates a URI or relative-reference per RFC3986
|
|
URIReferenceFormatChecker struct{}
|
|
|
|
// URITemplateFormatChecker validates a URI template per RFC6570
|
|
URITemplateFormatChecker struct{}
|
|
|
|
// HostnameFormatChecker validates a hostname is in the correct format
|
|
HostnameFormatChecker struct{}
|
|
|
|
// UUIDFormatChecker validates a UUID is in the correct format
|
|
UUIDFormatChecker struct{}
|
|
|
|
// RegexFormatChecker validates a regex is in the correct format
|
|
RegexFormatChecker struct{}
|
|
|
|
// JSONPointerFormatChecker validates a JSON Pointer per RFC6901
|
|
JSONPointerFormatChecker struct{}
|
|
|
|
// RelativeJSONPointerFormatChecker validates a relative JSON Pointer is in the correct format
|
|
RelativeJSONPointerFormatChecker struct{}
|
|
)
|
|
|
|
var (
|
|
// FormatCheckers holds the valid formatters, and is a public variable
|
|
// so library users can add custom formatters
|
|
FormatCheckers = FormatCheckerChain{
|
|
formatters: map[string]FormatChecker{
|
|
"date": DateFormatChecker{},
|
|
"time": TimeFormatChecker{},
|
|
"date-time": DateTimeFormatChecker{},
|
|
"hostname": HostnameFormatChecker{},
|
|
"email": EmailFormatChecker{},
|
|
"idn-email": EmailFormatChecker{},
|
|
"ipv4": IPV4FormatChecker{},
|
|
"ipv6": IPV6FormatChecker{},
|
|
"uri": URIFormatChecker{},
|
|
"uri-reference": URIReferenceFormatChecker{},
|
|
"iri": URIFormatChecker{},
|
|
"iri-reference": URIReferenceFormatChecker{},
|
|
"uri-template": URITemplateFormatChecker{},
|
|
"uuid": UUIDFormatChecker{},
|
|
"regex": RegexFormatChecker{},
|
|
"json-pointer": JSONPointerFormatChecker{},
|
|
"relative-json-pointer": RelativeJSONPointerFormatChecker{},
|
|
},
|
|
}
|
|
|
|
// Regex credit: https://www.socketloop.com/tutorials/golang-validate-hostname
|
|
rxHostname = regexp.MustCompile(`^([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\-]{0,61}[a-zA-Z0-9])(\.([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\-]{0,61}[a-zA-Z0-9]))*$`)
|
|
|
|
// Use a regex to make sure curly brackets are balanced properly after validating it as a AURI
|
|
rxURITemplate = regexp.MustCompile("^([^{]*({[^}]*})?)*$")
|
|
|
|
rxUUID = regexp.MustCompile("^[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}$")
|
|
|
|
rxJSONPointer = regexp.MustCompile("^(?:/(?:[^~/]|~0|~1)*)*$")
|
|
|
|
rxRelJSONPointer = regexp.MustCompile("^(?:0|[1-9][0-9]*)(?:#|(?:/(?:[^~/]|~0|~1)*)*)$")
|
|
|
|
lock = new(sync.RWMutex)
|
|
)
|
|
|
|
// Add adds a FormatChecker to the FormatCheckerChain
|
|
// The name used will be the value used for the format key in your json schema
|
|
func (c *FormatCheckerChain) Add(name string, f FormatChecker) *FormatCheckerChain {
|
|
lock.Lock()
|
|
c.formatters[name] = f
|
|
lock.Unlock()
|
|
|
|
return c
|
|
}
|
|
|
|
// Remove deletes a FormatChecker from the FormatCheckerChain (if it exists)
|
|
func (c *FormatCheckerChain) Remove(name string) *FormatCheckerChain {
|
|
lock.Lock()
|
|
delete(c.formatters, name)
|
|
lock.Unlock()
|
|
|
|
return c
|
|
}
|
|
|
|
// Has checks to see if the FormatCheckerChain holds a FormatChecker with the given name
|
|
func (c *FormatCheckerChain) Has(name string) bool {
|
|
lock.RLock()
|
|
_, ok := c.formatters[name]
|
|
lock.RUnlock()
|
|
|
|
return ok
|
|
}
|
|
|
|
// IsFormat will check an input against a FormatChecker with the given name
|
|
// to see if it is the correct format
|
|
func (c *FormatCheckerChain) IsFormat(name string, input interface{}) bool {
|
|
lock.RLock()
|
|
f, ok := c.formatters[name]
|
|
lock.RUnlock()
|
|
|
|
// If a format is unrecognized it should always pass validation
|
|
if !ok {
|
|
return true
|
|
}
|
|
|
|
return f.IsFormat(input)
|
|
}
|
|
|
|
// IsFormat checks if input is a correctly formatted e-mail address
|
|
func (f EmailFormatChecker) IsFormat(input interface{}) bool {
|
|
asString, ok := input.(string)
|
|
if !ok {
|
|
return false
|
|
}
|
|
|
|
_, err := mail.ParseAddress(asString)
|
|
return err == nil
|
|
}
|
|
|
|
// IsFormat checks if input is a correctly formatted IPv4-address
|
|
func (f IPV4FormatChecker) IsFormat(input interface{}) bool {
|
|
asString, ok := input.(string)
|
|
if !ok {
|
|
return false
|
|
}
|
|
|
|
// Credit: https://github.com/asaskevich/govalidator
|
|
ip := net.ParseIP(asString)
|
|
return ip != nil && strings.Contains(asString, ".")
|
|
}
|
|
|
|
// IsFormat checks if input is a correctly formatted IPv6=address
|
|
func (f IPV6FormatChecker) IsFormat(input interface{}) bool {
|
|
asString, ok := input.(string)
|
|
if !ok {
|
|
return false
|
|
}
|
|
|
|
// Credit: https://github.com/asaskevich/govalidator
|
|
ip := net.ParseIP(asString)
|
|
return ip != nil && strings.Contains(asString, ":")
|
|
}
|
|
|
|
// IsFormat checks if input is a correctly formatted date/time per RFC3339 5.6
|
|
func (f DateTimeFormatChecker) IsFormat(input interface{}) bool {
|
|
asString, ok := input.(string)
|
|
if !ok {
|
|
return false
|
|
}
|
|
|
|
formats := []string{
|
|
"15:04:05",
|
|
"15:04:05Z07:00",
|
|
"2006-01-02",
|
|
time.RFC3339,
|
|
time.RFC3339Nano,
|
|
}
|
|
|
|
for _, format := range formats {
|
|
if _, err := time.Parse(format, asString); err == nil {
|
|
return true
|
|
}
|
|
}
|
|
|
|
return false
|
|
}
|
|
|
|
// IsFormat checks if input is a correctly formatted date (YYYY-MM-DD)
|
|
func (f DateFormatChecker) IsFormat(input interface{}) bool {
|
|
asString, ok := input.(string)
|
|
if !ok {
|
|
return false
|
|
}
|
|
_, err := time.Parse("2006-01-02", asString)
|
|
return err == nil
|
|
}
|
|
|
|
// IsFormat checks if input correctly formatted time (HH:MM:SS or HH:MM:SSZ-07:00)
|
|
func (f TimeFormatChecker) IsFormat(input interface{}) bool {
|
|
asString, ok := input.(string)
|
|
if !ok {
|
|
return false
|
|
}
|
|
|
|
if _, err := time.Parse("15:04:05Z07:00", asString); err == nil {
|
|
return true
|
|
}
|
|
|
|
_, err := time.Parse("15:04:05", asString)
|
|
return err == nil
|
|
}
|
|
|
|
// IsFormat checks if input is correctly formatted URI with a valid Scheme per RFC3986
|
|
func (f URIFormatChecker) IsFormat(input interface{}) bool {
|
|
asString, ok := input.(string)
|
|
if !ok {
|
|
return false
|
|
}
|
|
|
|
u, err := url.Parse(asString)
|
|
|
|
if err != nil || u.Scheme == "" {
|
|
return false
|
|
}
|
|
|
|
return !strings.Contains(asString, `\`)
|
|
}
|
|
|
|
// IsFormat checks if input is a correctly formatted URI or relative-reference per RFC3986
|
|
func (f URIReferenceFormatChecker) IsFormat(input interface{}) bool {
|
|
asString, ok := input.(string)
|
|
if !ok {
|
|
return false
|
|
}
|
|
|
|
_, err := url.Parse(asString)
|
|
return err == nil && !strings.Contains(asString, `\`)
|
|
}
|
|
|
|
// IsFormat checks if input is a correctly formatted URI template per RFC6570
|
|
func (f URITemplateFormatChecker) IsFormat(input interface{}) bool {
|
|
asString, ok := input.(string)
|
|
if !ok {
|
|
return false
|
|
}
|
|
|
|
u, err := url.Parse(asString)
|
|
if err != nil || strings.Contains(asString, `\`) {
|
|
return false
|
|
}
|
|
|
|
return rxURITemplate.MatchString(u.Path)
|
|
}
|
|
|
|
// IsFormat checks if input is a correctly formatted hostname
|
|
func (f HostnameFormatChecker) IsFormat(input interface{}) bool {
|
|
asString, ok := input.(string)
|
|
if !ok {
|
|
return false
|
|
}
|
|
|
|
return rxHostname.MatchString(asString) && len(asString) < 256
|
|
}
|
|
|
|
// IsFormat checks if input is a correctly formatted UUID
|
|
func (f UUIDFormatChecker) IsFormat(input interface{}) bool {
|
|
asString, ok := input.(string)
|
|
if !ok {
|
|
return false
|
|
}
|
|
|
|
return rxUUID.MatchString(asString)
|
|
}
|
|
|
|
// IsFormat checks if input is a correctly formatted regular expression
|
|
func (f RegexFormatChecker) IsFormat(input interface{}) bool {
|
|
asString, ok := input.(string)
|
|
if !ok {
|
|
return false
|
|
}
|
|
|
|
if asString == "" {
|
|
return true
|
|
}
|
|
_, err := regexp.Compile(asString)
|
|
return err == nil
|
|
}
|
|
|
|
// IsFormat checks if input is a correctly formatted JSON Pointer per RFC6901
|
|
func (f JSONPointerFormatChecker) IsFormat(input interface{}) bool {
|
|
asString, ok := input.(string)
|
|
if !ok {
|
|
return false
|
|
}
|
|
|
|
return rxJSONPointer.MatchString(asString)
|
|
}
|
|
|
|
// IsFormat checks if input is a correctly formatted relative JSON Pointer
|
|
func (f RelativeJSONPointerFormatChecker) IsFormat(input interface{}) bool {
|
|
asString, ok := input.(string)
|
|
if !ok {
|
|
return false
|
|
}
|
|
|
|
return rxRelJSONPointer.MatchString(asString)
|
|
}
|