...
 
Commits (2)
# This file is autogenerated, do not edit; changes may be undone by the next 'dep ensure'.
[[projects]]
name = "github.com/certifi/gocertifi"
packages = ["."]
revision = "deb3ae2ef2610fde3330947281941c562861188b"
version = "2018.01.18"
[[projects]]
branch = "master"
name = "github.com/dustin/go-humanize"
packages = ["."]
revision = "bb3d318650d48840a39aa21a027c6630e198e626"
[[projects]]
branch = "master"
name = "github.com/getsentry/raven-go"
packages = ["."]
revision = "7562301a6763c9ac631b0a2011b4aa0e064e45d4"
[[projects]]
name = "github.com/go-ini/ini"
packages = ["."]
revision = "32e4c1e6bc4e7d0d8451aa6b75200d19e37a536a"
version = "v1.32.0"
[[projects]]
name = "github.com/google/uuid"
packages = ["."]
......@@ -44,98 +20,15 @@
revision = "da3231b0b66e2e74cdb779f1d46c5e958ba8be27"
version = "v3.1.0"
[[projects]]
name = "github.com/minio/minio-go"
packages = [
".",
"pkg/credentials",
"pkg/encrypt",
"pkg/policy",
"pkg/s3signer",
"pkg/s3utils",
"pkg/set"
]
revision = "706c81d3ee2a18cdd8239faf544de8a066e7e261"
version = "4.0.7"
[[projects]]
branch = "master"
name = "github.com/minio/sio"
packages = ["."]
revision = "59fabbc4e9532bad999ad245b7d90869060b0dc7"
[[projects]]
branch = "master"
name = "github.com/mitchellh/go-homedir"
packages = ["."]
revision = "b8bc1bf767474819792c23f32d8286a45736f1c6"
[[projects]]
name = "github.com/pkg/errors"
packages = ["."]
revision = "645ef00459ed84a119197bfb8d8205042c6df63d"
version = "v0.8.0"
[[projects]]
name = "github.com/sirupsen/logrus"
packages = ["."]
revision = "d682213848ed68c0a260ca37d6dd5ace8423f5ba"
version = "v1.0.4"
[[projects]]
branch = "master"
name = "golang.org/x/crypto"
packages = [
"chacha20poly1305",
"hkdf",
"internal/chacha20",
"poly1305",
"ssh/terminal"
]
revision = "9de5f2eaf759b4c4550b3db39fed2e9e5f86f45c"
[[projects]]
branch = "master"
name = "golang.org/x/net"
packages = [
"idna",
"lex/httplex"
]
revision = "f5dfe339be1d06f81b22525fe34671ee7d2c8904"
[[projects]]
branch = "master"
name = "golang.org/x/sys"
packages = [
"unix",
"windows"
]
revision = "37707fdb30a5b38865cfb95e5aab41707daec7fd"
[[projects]]
branch = "master"
name = "golang.org/x/text"
packages = [
"collate",
"collate/build",
"internal/colltab",
"internal/gen",
"internal/tag",
"internal/triegen",
"internal/ucd",
"language",
"secure/bidirule",
"transform",
"unicode/bidi",
"unicode/cldr",
"unicode/norm",
"unicode/rangetable"
]
revision = "4e4a3210bb54bb31f6ab2cdca2edcc0b50c420c1"
[solve-meta]
analyzer-name = "dep"
analyzer-version = 1
inputs-digest = "650b409269d913b005d0a9ee67b56d646cb2bedc1f318408adfa3ea9548673eb"
inputs-digest = "a7ad5d22cb9589ee9f6f95d2e9f17fc143af1cfa17f6f0774048a9d231369cf0"
solver-name = "gps-cdcl"
solver-version = 1
......@@ -10,7 +10,6 @@ import (
"flag"
"fmt"
"io/ioutil"
"log"
"net"
"os"
"reflect"
......@@ -30,7 +29,7 @@ func init() {
// and populating the config from the config file and from the environment.
// The envinronment are searched for variables prepended with VEE_ and
// uppercased. Thus config.Port can be overwritten with VEE_PORT.
func New() *Obj {
func New() (*Obj, error) {
defaultConfig := stringConfig{
Port: "3000",
......@@ -47,30 +46,31 @@ func New() *Obj {
SQLUser: "postgres",
SQLPassword: "postgres",
SQLDatabase: "postgres",
SQLPort: "5433",
SQLPort: "5432",
SQLMaxConnections: "5",
TTL: "30", //Seconds
IPHeader: "x-forwarded-for",
DownloadRange: "",
UploadRange: "",
Debug: "false",
}
conf := Obj{}
err := defaultConfig.loadLocalConfig(configLocation)
if err != nil {
if strings.Contains(err.Error(), "no such file or directory") == false {
log.Fatal(err)
return nil, err
}
}
err = defaultConfig.loadEnvironment()
if err != nil {
log.Fatal(err)
return nil, err
}
err = defaultConfig.buildConfig(&conf)
if err != nil {
log.Fatal(err)
return nil, err
}
return &conf
return &conf, nil
}
// stringConfig is the type that the defaultConfig is, and it's also the type
......@@ -104,10 +104,13 @@ type stringConfig struct {
// line with IP addresses. Adresses should be in CIDR notation
// except for single host addresses, which can omit the CIDR
// notation. If not set, check is disabled.
DownloadRange string `json:"noauthdownrange"`
DownloadRange string `json:"downrange"`
// UploadRange is identical to DownloadRange except that it
// is applied to uploads instead of downloads.
UploadRange string `json:"noauthuprange"`
UploadRange string `json:"uprange"`
// Debug determines if debugging is enabled or not. Controls, among other things
// if debug statements are logged or not.
Debug string `json:"debug"`
}
// Obj is the type of the object available outside this package.
......@@ -132,8 +135,9 @@ type Obj struct {
SQLMaxConnections int `json:"sqlmaxconnections"`
TTL int `json:"ttl"`
IPHeader string `json:"ipheader"`
DownloadRange map[string]bool `json:"noauthdownrange"`
UploadRange map[string]bool `json:"noauthuprange"`
DownloadRange map[string]bool `json:"downrange"`
UploadRange map[string]bool `json:"uprange"`
Debug bool `json:"debug"`
}
// buildConfig takes a Obj as argument, and tries to copy
......@@ -182,7 +186,7 @@ func (sc *stringConfig) buildConfig(dst *Obj) error {
r := csv.NewReader(strings.NewReader(scValue.Field(i).String()))
result, err := r.ReadAll()
if err != nil {
log.Fatalf("Unable to parse CSV for %v", scValue.Type().Field(i).Name)
return fmt.Errorf("Unable to parse CSV for %v", scValue.Type().Field(i).Name)
}
tempSet := make(map[string]bool)
for _, elem := range result[0] {
......@@ -204,7 +208,7 @@ func (sc *stringConfig) buildConfig(dst *Obj) error {
}
dstField.Set(reflect.ValueOf(tempSet))
default:
log.Printf("Unhandled type: %s\n", dstType)
//log.Printf("Unhandled type: %s\n", dstType)
}
}
......
......@@ -7,12 +7,20 @@ import (
func TestNew(t *testing.T) {
t.Run("New()", func(t *testing.T) {
conf := New()
t.Log(conf.Port)
_, err := New()
if err != nil {
t.Fail()
}
})
t.Run("Returns different objects", func(t *testing.T) {
a := New()
b := New()
a, err := New()
if err != nil {
t.Fail()
}
b, err := New()
if err != nil {
t.Fail()
}
a.Port = "4000"
if a.Port == b.Port {
......
package http
import (
"net/http"
"github.com/google/uuid"
vee "gitlab.com/MadsRC/vee/app"
)
type Handler struct {
FileService vee.FileService
}
func (h *Handler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
name := uuid.New()
_, err := h.FileService.File(name)
if err != nil {
http.Error(w, "Internal Server Error", http.StatusInternalServerError)
return
}
w.Write([]byte("I like cake"))
return
}
package http_test
import (
"errors"
"net/http"
"net/http/httptest"
"testing"
"github.com/google/uuid"
vee "gitlab.com/MadsRC/vee/app"
veeHTTP "gitlab.com/MadsRC/vee/app/http"
"gitlab.com/MadsRC/vee/app/mock"
)
func TestHandler(t *testing.T) {
// Inject our mock
var fs mock.FileService
var h veeHTTP.Handler
h.FileService = &fs
//Mock File() call.
fs.FileFn = func(name uuid.UUID) (*vee.File, error) {
return &vee.File{Name: name}, nil
}
//Invoke the handler
w := httptest.NewRecorder()
r, _ := http.NewRequest("GET", "/files/5c46eccf-cb2f-4c7f-a7cd-2a21eb263b58", nil)
h.ServeHTTP(w, r)
// Validate the mock
if !fs.FileInvoked {
t.Fatal("expected File() to be invoked")
}
if w.Code != http.StatusOK {
t.Fatalf("Expected response code to be %d, was %d\n", http.StatusOK, w.Code)
}
}
func TestHandlerError(t *testing.T) {
// Inject our mock
var fs mock.FileService
var h veeHTTP.Handler
h.FileService = &fs
//Mock File() call.
fs.FileFn = func(name uuid.UUID) (*vee.File, error) {
return nil, errors.New("This is an error")
}
//Invoke the handler
w := httptest.NewRecorder()
r, _ := http.NewRequest("GET", "/files/5c46eccf-cb2f-4c7f-a7cd-2a21eb263b58", nil)
h.ServeHTTP(w, r)
// Validate the mock
if !fs.FileInvoked {
t.Fatal("expected File() to be invoked")
}
if w.Code != http.StatusInternalServerError {
t.Fatalf("Expected response code to be %d, was %d\n", http.StatusInternalServerError, w.Code)
}
}
// Package log implements a simple logging package, that adheres to
// the idea that there's only really 2 log levels. The idea is described well
// in Dave cheney's blog post here
// https://dave.cheney.net/2015/11/05/lets-talk-about-logging
// The log package tries to make logging simple and provides a default logger
// much like Go's standard logger.
//
// By default, logs are send to os.Stdout and debugging is disbled.
package log
import (
"fmt"
"io"
"os"
"sync"
)
var (
defaultLogger *Logger
)
// initialized assigns a new Logger{} to the defaultLogger. This allows us to
// bootstrap the defaultLogger in the init() function. It also allows us to
// reset the defaultLogger during testing.
func initialize() {
defaultLogger = &Logger{
debug: false,
out: os.Stdout,
}
}
func init() {
initialize()
}
// Logger represents a logging instance
type Logger struct {
initialized bool // determines if the Logger has been initialized
out io.Writer // destination for output
debug bool // determines if debugging is enabled
buf []byte // content to be written is accumulated here
mu sync.Mutex // ensures atomic writes
}
// Init creates a new Logger. The debug variable decides if debugging is
// enabled. If the default logger isn't initialized, it will assigned the
// address of Logger created.
func Init(debug bool) *Logger {
l := Logger{debug: debug, initialized: true, out: os.Stdout}
l.mu.Lock()
defer l.mu.Unlock()
if !defaultLogger.initialized {
defaultLogger = &l
}
return &l
}
// Print prints to the logger.
// Arguments are handled in the manner of fmt.Fprint.
func (l *Logger) Print(v ...interface{}) {
fmt.Fprint(l.out, v...)
}
// Printf prints to the logger.
// Arguments are handled in the manner of fmt.Fprintf.
func (l *Logger) Printf(format string, v ...interface{}) {
fmt.Fprint(l.out, fmt.Sprintf(format, v...))
}
// SetOutput set the output for the logger.
func (l *Logger) SetOutput(w io.Writer) {
l.mu.Lock()
defer l.mu.Unlock()
l.out = w
}
// GetDebug determines if debugging is enabled for the logger.
func (l *Logger) GetDebug() bool {
return l.debug
}
// SetDebug determines if debugging is enabled for the logger.
func (l *Logger) SetDebug(state bool) {
l.mu.Lock()
defer l.mu.Unlock()
l.debug = state
}
// Debug prints to the logger only if debugging is enabled.
// Arguments are handled in the manner of fmt.Fprint.
func (l *Logger) Debug(v ...interface{}) {
if l.GetDebug() {
fmt.Fprint(l.out, v...)
}
}
// Debugf prints to the logger only if debugging is enabled.
// Arguments are handled in the manner of fmt.Fprintf.
func (l *Logger) Debugf(format string, v ...interface{}) {
if l.GetDebug() {
fmt.Fprintf(l.out, format, v...)
}
}
// Print prints to the default logger.
// Arguments are handled in the manner of fmt.Fprint.
func Print(v ...interface{}) {
defaultLogger.Print(v...)
}
// Printf prints to the default logger.
// Arguments are handled in the manner of fmt.Fprintf.
func Printf(format string, v ...interface{}) {
defaultLogger.Printf(format, v...)
}
// SetOutput set the output for the default logger.
func SetOutput(w io.Writer) {
defaultLogger.SetOutput(w)
}
// GetDebug determines if debugging is enabled for the default logger.
func GetDebug() bool {
return defaultLogger.GetDebug()
}
// SetDebug determines if debugging is enabled for the default logger.
func SetDebug(state bool) {
defaultLogger.SetDebug(state)
}
// Debug prints to the default logger only if debugging is enabled.
// Arguments are handled in the manner of fmt.Fprint.
func Debug(v ...interface{}) {
defaultLogger.Debug(v...)
}
// Debugf prints to the default logger only if debugging is enabled.
// Arguments are handled in the manner of fmt.Fprintf.
func Debugf(format string, v ...interface{}) {
defaultLogger.Debugf(format, v...)
}
package log
import (
"bufio"
"bytes"
"testing"
)
func TestBeforeInit(t *testing.T) {
var buf bytes.Buffer
w := bufio.NewWriter(&buf)
SetOutput(w)
Print("fisk")
w.Flush()
if buf.String() != "fisk" {
t.Errorf("Output not as expected, was: %v", buf.String())
}
}
func TestInit(t *testing.T) {
Init(false)
t.Run("Test Debug", func(t *testing.T) {
stat := GetDebug()
if stat != false {
t.Errorf("Expected GetDebug to return false, got: %v\n", stat)
}
var buf bytes.Buffer
w := bufio.NewWriter(&buf)
SetOutput(w)
Debug("fisk")
w.Flush()
if buf.String() == "fisk" {
t.Error("Debug wrote with debug being disabled")
}
SetDebug(true)
post := GetDebug()
if post != true {
t.Errorf("SetDebug(true) did not set debug to true, got: %v\n", defaultLogger.debug)
}
Debug("fisk")
w.Flush()
if buf.String() != "fisk" {
t.Error("Debug did not write with debug enabled")
}
})
t.Run("Test Debugf", func(t *testing.T) {
initialize()
var buf bytes.Buffer
w := bufio.NewWriter(&buf)
SetOutput(w)
Debugf("got %s", "fisk")
w.Flush()
if buf.String() != "" {
t.Error("Debug wrote with debug being disabled")
}
SetDebug(true)
Debugf("got %s", "fisk")
w.Flush()
if buf.String() != "got fisk" {
t.Error("Debugf did not write with debug enabled")
}
})
t.Run("Test Print", func(t *testing.T) {
initialize()
var buf bytes.Buffer
w := bufio.NewWriter(&buf)
SetOutput(w)
Print("fisk")
w.Flush()
if buf.String() != "fisk" {
t.Errorf("Output not as expected, was: %v\n", buf.String())
}
})
t.Run("Test Printf", func(t *testing.T) {
initialize()
var buf bytes.Buffer
w := bufio.NewWriter(&buf)
SetOutput(w)
Printf("got %s", "fisk")
w.Flush()
if buf.String() != "got fisk" {
t.Errorf("Output not as expected, was: %v\n", buf.String())
}
})
}
package mock
import (
"github.com/google/uuid"
vee "gitlab.com/MadsRC/vee/app"
)
//FileService represents a mock implementation of vee.FileService
type FileService struct {
FileFn func(name uuid.UUID) (*vee.File, error)
FileInvoked bool
CreateFileFn func(f *vee.File) error
CreateFileInvoked bool
}
// File invokes the mock implementation and marks the function as invoked
func (s *FileService) File(name uuid.UUID) (*vee.File, error) {
s.FileInvoked = true
return s.FileFn(name)
}
// CreateFile invokes the mock implementation aand marks the function as invoked
func (s *FileService) CreateFile(f *vee.File) error {
s.CreateFileInvoked = true
return s.CreateFileFn(f)
}
package postgres
import (
"time"
"github.com/google/uuid"
"github.com/jackc/pgx"
"gitlab.com/MadsRC/vee/app"
)
//FileService represents a PostgreSQL implementation og vee.FileService
type FileService struct {
DB *pgx.ConnPool
}
//File returns a file for a given name.
func (s *FileService) File(name uuid.UUID) (*vee.File, error) {
var f vee.File
var tmpNonce []byte
row := s.DB.QueryRow("SELECT name, nonce, createdat, invalidat FROM file WHERE name = $1", name)
err := row.Scan(&f.Name, &tmpNonce, &f.Createdat, &f.Invalidat)
if err != nil {
return nil, err
}
// As we can't scan directly into f.Nonce, we have to scan into a byte slice
// and copy said byteslice into f.Nonce.
copy(f.Nonce[:], tmpNonce)
return &f, nil
}
//CreateFile returns creates a file with the given values
func (s *FileService) CreateFile(name uuid.UUID, nonce [32]byte, createdat time.Time, invalidat time.Time) error {
_, err := s.DB.Exec("INSERT INTO file (name, nonce, createdat, invalidat) VALUES ($1, $2, $3, $4);", name, nonce[:], createdat, invalidat)
return err
}
package vee
import (
"time"
"github.com/google/uuid"
)
type File struct {
Name uuid.UUID
Nonce [32]byte
Key [32]byte
Createdat time.Time
Invalidat time.Time
}
type FileService interface {
File(name uuid.UUID) (*File, error)
CreateFile(f *File) error
}
CREATE EXTENSION IF NOT EXISTS "uuid-ossp";
CREATE TABLE file (
name uuid PRIMARY KEY,
nonce bytea,
objectname uuid PRIMARY KEY,
createdat timestamp,
invalidat timestamp
);
package app
import (
"github.com/jackc/pgx"
"github.com/minio/minio-go"
"gitlab.com/MadsRC/vee/lib/config"
)
type Context struct {
DB *pgx.ConnPool
Minio *minio.Client
Config *config.ConfigObj
}
package main
import (
"flag"
"fmt"
"log"
"os"
"github.com/jackc/pgx"
"github.com/minio/minio-go"
"gitlab.com/MadsRC/vee"
"gitlab.com/MadsRC/vee/lib/config"
"gitlab.com/MadsRC/vee/lib/housekeep"
"gitlab.com/MadsRC/vee/lib/http"
"gitlab.com/MadsRC/vee/lib/meta"
)
var c = &config.Config
func main() {
log.SetFlags(log.Ldate | log.Ltime | log.LUTC | log.Lshortfile)
housekeepPtr := flag.Bool("housekeep", false, "Enables the housekeeping mode")
versionPtr := flag.Bool("v", false, "Prints version info")
flag.Parse()
var Pool *pgx.ConnPool
var err error
connPoolConfig := pgx.ConnPoolConfig{
ConnConfig: pgx.ConnConfig{
Host: c.SQLHost,
User: c.SQLUser,
Password: c.SQLPassword,
Database: c.SQLDatabase,
Port: uint16(c.SQLPort),
},
MaxConnections: c.SQLMaxConnections,
}
Pool, err = pgx.NewConnPool(connPoolConfig)
if err != nil {
log.Print("Unable to create connection pool", "error", err)
os.Exit(1)
}
minioClient, err := minio.New(c.Endpoint, c.AccessKeyID, c.SecretAccessKey, c.UseSSL)
if err != nil {
log.Print("Unable to create minio client", "error", err)
os.Exit(1)
}
appContext := app.Context{DB: Pool, Minio: minioClient, Config: c}
if *versionPtr == true {
fmt.Printf("Software Version: %s\nGit Commit Hash: %s\nBuild Time: %s\n", meta.Version, meta.GitHash, meta.BuildTime)
os.Exit(0)
}
if *housekeepPtr == true {
log.Println("Housekeeping enabled")
housekeep.Run(Pool, minioClient)
} else {
if len(c.MasterKey) != 32 {
log.Fatal("Invalid master key size")
}
}
log.Fatal(http.Listen(&appContext))
}
</
// Package config provides way to store and access configuration in an application.
// It provides a hardcoded default configuraiton that can be augmented using
// a local json file and/or environment variables.
package config
import (
"encoding/csv"
"encoding/hex"
"encoding/json"
"flag"
"fmt"
"io/ioutil"
"log"
"net"
"os"
"reflect"
"strconv"
"strings"
"gitlab.com/MadsRC/vee/lib/uuid"
)
// init runs on import and takes care of bootstrapping the default config
// and populating the config from the config file and from the environment.
// The envinronment are searched for variables prepended with VEE_ and
// uppercased. Thus config.Port can be overwritten with VEE_PORT.
func init() {
configLocation := flag.String("c", "./config.json", "Location of the JSON config file")
err := defaultConfig.loadLocalConfig(configLocation)
if err != nil {
if strings.Contains(err.Error(), "no such file or directory") {
log.Println("No config file found, skipping")
} else {
log.Fatal(err)
}
}
err = defaultConfig.loadEnvironment()
if err != nil {
log.Fatal(err)
}
err = defaultConfig.buildConfig(&Config)
if err != nil {
log.Fatal(err)
}
}
// Config is the actual configuration object. Preties way to reference is it declaring a variable
// as c := config.Config
var Config = ConfigObj{}
var defaultConfig = stringConfig{
Port: "3000",
Endpoint: "127.0.0.1:9000",
AccessKeyID: "AKIAIOSFODNN7EXAMPLE",
SecretAccessKey: "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY",
UseSSL: "false",
Development: "true",
BucketName: "11bf5b37-e0b8-42e0-8dcf-dc8c4aefc000",
Location: "us-east-1",
MaxUploadSize: "3000",
MasterKey: "000102030405060708090A0B0C0D0E0FF0E0D0C0B0A090807060504030201000",
SQLHost: "127.0.0.1",
SQLUser: "postgres",
SQLPassword: "postgres",
SQLDatabase: "postgres",
SQLPort: "5433",
SQLMaxConnections: "5",
TTL: "30", //Seconds
IPHeader: "x-forwarded-for",
DownloadRange: "",
UploadRange: "",
}
// stringConfig is the type that the defaultConfig is, and it's also the type
// that the environment and JSON file is read into.
type stringConfig struct {
Port string `json: "port"`
Endpoint string `json: "endpoint"`
AccessKeyID string `json: "accesskeyid"`
SecretAccessKey string `json: "secretaccesskey"`
UseSSL string `json: "usessl"`
Development string `json: "developmnet"`
BucketName string `json: "bucketname"`
Location string `json: "location"`
MaxUploadSize string `json: "maxuploadsize"`
MasterKey string `json: "masterkey"`
SQLHost string `json: "sqlhost"`
SQLUser string `json: "sqluser"`
SQLPassword string `json: "sqlpassword"`
SQLDatabase string `json: "sqldatabase"`
SQLPort string `json: "sqlport"`
SQLMaxConnections string `json: "sqlmaxconnections"`
TTL string `json: "ttl"`
// IPHeader is the name of the header that includes the
// endusers IP. Defaults to x-forwarded-for. Leave empty
// to use the IP of sending machine (Which may, or may
// not, be a proxy. Please note that this value is
// case-insensitive.
IPHeader string `json: "ipheader"`
// DownloadRange sets the IP addresses that is allowed
// to do unauthenticated downloads. The list is comma separated
// line with IP addresses. Adresses should be in CIDR notation
// except for single host addresses, which can omit the CIDR
// notation. If not set, check is disabled.
DownloadRange string `json: "noauthdownrange"`
// UploadRange is identical to DownloadRange except that it
// is applied to uploads instead of downloads.
UploadRange string `json: "noauthuprange"`
}
// ConfigObj is the type of the object available outside this package.
// It has the same fields as the stringConfig object, but the types
// differ.
type ConfigObj struct {
Port string `json: "port"`
Endpoint string `json: "endpoint"`
AccessKeyID string `json: "accesskeyid"`
SecretAccessKey string `json: "secretaccesskey"`
UseSSL bool `json: "usessl"`
Development bool `json: "developmnet"`
BucketName uuid.UUID `json: "bucketname"`
Location string `json: "location"`
MaxUploadSize int `json: "maxuploadsize"`
MasterKey []byte `json: "masterkey"`
SQLHost string `json: "sqlhost"`
SQLUser string `json: "sqluser"`
SQLPassword string `json: "sqlpassword"`
SQLDatabase string `json: "sqldatabase"`
SQLPort int `json: "sqlport"`
SQLMaxConnections int `json: "sqlmaxconnections"`
TTL int `json: "ttl"`
IPHeader string `json: "ipheader"`
DownloadRange map[string]bool `json: "noauthdownrange"`
UploadRange map[string]bool `json: "noauthuprange"`
}
// buildConfig takes a ConfigObj as argument, and tries to copy
// and convert each field of stringConfig into the corresponding field in
// ConfigObj.
func (sc *stringConfig) buildConfig(dst *ConfigObj) error {
scValue := reflect.Indirect(reflect.ValueOf(sc))
dstValue := reflect.Indirect(reflect.ValueOf(dst))
for i := 0; i < scValue.Type().NumField(); i++ {
dstField := dstValue.FieldByName(scValue.Type().Field(i).Name)
dstType := dstField.Type()
switch dstType {
case reflect.TypeOf((string)("")):
dstField.SetString(scValue.Field(i).String())
case reflect.TypeOf((bool)(false)):
b, err := strconv.ParseBool(scValue.Field(i).String())
if err != nil {
return err
}
dstField.SetBool(b)
case reflect.TypeOf((int)(1)):
b, err := strconv.ParseInt(scValue.Field(i).String(), 10, 16)
if err != nil {
return err
}
dstField.SetInt(b)
case reflect.TypeOf(([]byte)(nil)):
data, err := hex.DecodeString(scValue.Field(i).String())
if err != nil {
return err
}
dstField.SetBytes(data)
case reflect.TypeOf((uuid.UUID)(uuid.UUID{})):
theUUID, err := uuid.Parse(scValue.Field(i).String())
if err != nil {
return err
}
dstField.Set(reflect.ValueOf(theUUID))
case reflect.TypeOf((map[string]bool)(map[string]bool{})):
if scValue.Field(i).String() == "" {
// If the option isn't set, it will be an empty string.
// continue next iteration, and let the config entry be
// an empty map[string]bool
continue
}
r := csv.NewReader(strings.NewReader(scValue.Field(i).String()))
result, err := r.ReadAll()
if err != nil {
log.Fatalf("Unable to parse CSV for %v", scValue.Type().Field(i).Name)
}
tempSet := make(map[string]bool)
for _, elem := range result[0] {
elem = strings.TrimSpace(elem)
if net.ParseIP(elem).To16() != nil {
// This is a single hos, insert it in the map
tempSet[elem] = true
continue
}
ipv4Addr, ipv4Net, err := net.ParseCIDR(elem)
if err != nil {
return err
}
// Successfully parsed as a CIDR notated IP
for ipv4Addr := ipv4Addr.Mask(ipv4Net.Mask); ipv4Net.Contains(ipv4Addr); inc(ipv4Addr) {