diff --git a/api/api.go b/api/api.go index c0c7ec1..caadb6d 100644 --- a/api/api.go +++ b/api/api.go @@ -7,13 +7,20 @@ import ( "time" "github.com/gin-gonic/gin" - "github.com/neicnordic/sda-download/api/middleware" "github.com/neicnordic/sda-download/api/s3" "github.com/neicnordic/sda-download/api/sda" "github.com/neicnordic/sda-download/internal/config" log "github.com/sirupsen/logrus" ) +// SelectedMiddleware is used to control authentication and authorization +// behaviour with config app.middleware +// available middlewares: +// "default" for TokenMiddleware +var SelectedMiddleware = func() gin.HandlerFunc { + return nil +} + // healthResponse func healthResponse(c *gin.Context) { // ok response to health @@ -29,11 +36,11 @@ func Setup() *http.Server { router.HandleMethodNotAllowed = true - router.GET("/metadata/datasets", middleware.TokenMiddleware(), sda.Datasets) - router.GET("/metadata/datasets/*dataset", middleware.TokenMiddleware(), sda.Files) - router.GET("/files/:fileid", middleware.TokenMiddleware(), sda.Download) - router.GET("/s3/*path", middleware.TokenMiddleware(), s3.Download) - router.HEAD("/s3/*path", middleware.TokenMiddleware(), s3.Download) + router.GET("/metadata/datasets", SelectedMiddleware(), sda.Datasets) + router.GET("/metadata/datasets/*dataset", SelectedMiddleware(), sda.Files) + router.GET("/files/:fileid", SelectedMiddleware(), sda.Download) + router.GET("/s3/*path", SelectedMiddleware(), s3.Download) + router.HEAD("/s3/*path", SelectedMiddleware(), s3.Download) router.GET("/health", healthResponse) // Configure TLS settings diff --git a/api/middleware/README.md b/api/middleware/README.md new file mode 100644 index 0000000..bcf4240 --- /dev/null +++ b/api/middleware/README.md @@ -0,0 +1,5 @@ +# Middlewares +- The default middleware is `TokenMiddleware`, which expects an access token, that can be sent to AAI in return for GA4GH visas. +- One may create custom middlewares in this `middleware` package, and register them to the `availableMiddlewares` in [config.go](../../internal/config/config.go), and adding a case for them in [main.go](../../cmd/main.go). +- A middleware for runtime can then be selected with the `app.middleware` config. +- For custom middlewares, it is important, that they use the `storeDatasets` function available in [middleware.go](middleware.go) to set the permissions for accessing data. diff --git a/api/middleware/middleware.go b/api/middleware/middleware.go index 91eb244..e2e4bda 100644 --- a/api/middleware/middleware.go +++ b/api/middleware/middleware.go @@ -23,11 +23,11 @@ func TokenMiddleware() gin.HandlerFunc { if err != nil { log.Debugf("no session cookie received") } - var datasets []string + var datasetCache session.DatasetCache var exists bool if sessionCookie != "" { log.Debug("session cookie received") - datasets, exists = session.Get(sessionCookie) + datasetCache, exists = session.Get(sessionCookie) } if !exists { @@ -57,11 +57,14 @@ func TokenMiddleware() gin.HandlerFunc { // 200 OK with [] empty dataset list, when listing datasets (use case for sda-filesystem download tool) // 404 dataset not found, when listing files from a dataset // 401 unauthorised, when downloading a file - datasets = auth.GetPermissions(*visas) + datasets := auth.GetPermissions(*visas) + datasetCache = session.DatasetCache{ + Datasets: datasets, + } // Start a new session and store datasets under the session key key := session.NewSessionKey() - session.Set(key, datasets) + session.Set(key, datasetCache) c.SetCookie(config.Config.Session.Name, // name key, // value int(config.Config.Session.Expiration)/1e9, // max age @@ -74,7 +77,7 @@ func TokenMiddleware() gin.HandlerFunc { } // Store dataset list to request context, for use in the endpoint handlers - c = storeDatasets(c, datasets) + c = storeDatasets(c, datasetCache) // Forward request to the next endpoint handler c.Next() @@ -83,7 +86,7 @@ func TokenMiddleware() gin.HandlerFunc { } // storeDatasets stores the dataset list to the request context -func storeDatasets(c *gin.Context, datasets []string) *gin.Context { +func storeDatasets(c *gin.Context, datasets session.DatasetCache) *gin.Context { log.Debugf("storing %v datasets to request context", datasets) c.Set(datasetsKey, datasets) @@ -92,10 +95,13 @@ func storeDatasets(c *gin.Context, datasets []string) *gin.Context { } // GetDatasets extracts the dataset list from the request context -var GetDatasets = func(c *gin.Context) []string { - datasets := c.GetStringSlice(datasetsKey) - - log.Debugf("returning %v from request context", datasets) +var GetDatasets = func(c *gin.Context) session.DatasetCache { + var datasetCache session.DatasetCache + cached, exists := c.Get(datasetsKey) + if exists { + datasetCache = cached.(session.DatasetCache) + } + log.Debugf("returning %v from request context", cached) - return datasets + return datasetCache } diff --git a/api/middleware/middleware_test.go b/api/middleware/middleware_test.go index cb8e95a..edfb872 100644 --- a/api/middleware/middleware_test.go +++ b/api/middleware/middleware_test.go @@ -182,8 +182,8 @@ func TestTokenMiddleware_Success_NoCache(t *testing.T) { // Now that we are modifying the request context, we need to place the context test inside the handler expectedDatasets := []string{"dataset1", "dataset2"} testEndpointWithContextData := func(c *gin.Context) { - datasets := c.GetStringSlice(datasetsKey) - if !reflect.DeepEqual(datasets, expectedDatasets) { + datasets, _ := c.Get(datasetsKey) + if !reflect.DeepEqual(datasets.(session.DatasetCache).Datasets, expectedDatasets) { t.Errorf("TestTokenMiddleware_Success_NoCache failed, got %s expected %s", datasets, expectedDatasets) } } @@ -224,10 +224,13 @@ func TestTokenMiddleware_Success_FromCache(t *testing.T) { originalGetCache := session.Get // Substitute mock functions - session.Get = func(key string) ([]string, bool) { + session.Get = func(key string) (session.DatasetCache, bool) { log.Warningf("session.Get %v", key) + cached := session.DatasetCache{ + Datasets: []string{"dataset1", "dataset2"}, + } - return []string{"dataset1", "dataset2"}, true + return cached, true } config.Config.Session.Name = "sda_session_key" @@ -245,8 +248,8 @@ func TestTokenMiddleware_Success_FromCache(t *testing.T) { // Now that we are modifying the request context, we need to place the context test inside the handler expectedDatasets := []string{"dataset1", "dataset2"} testEndpointWithContextData := func(c *gin.Context) { - datasets := c.GetStringSlice(datasetsKey) - if !reflect.DeepEqual(datasets, expectedDatasets) { + datasets, _ := c.Get(datasetsKey) + if !reflect.DeepEqual(datasets.(session.DatasetCache).Datasets, expectedDatasets) { t.Errorf("TestTokenMiddleware_Success_FromCache failed, got %s expected %s", datasets, expectedDatasets) } } @@ -281,11 +284,13 @@ func TestStoreDatasets(t *testing.T) { c, _ := gin.CreateTestContext(w) // Store data to request context - datasets := []string{"dataset1", "dataset2"} + datasets := session.DatasetCache{ + Datasets: []string{"dataset1", "dataset2"}, + } modifiedContext := storeDatasets(c, datasets) // Verify that context has new data - storedDatasets := modifiedContext.Value(datasetsKey).([]string) + storedDatasets := modifiedContext.Value(datasetsKey).(session.DatasetCache) if !reflect.DeepEqual(datasets, storedDatasets) { t.Errorf("TestStoreDatasets failed, got %s, expected %s", storedDatasets, datasets) } @@ -299,7 +304,9 @@ func TestGetDatasets(t *testing.T) { c, _ := gin.CreateTestContext(w) // Store data to request context - datasets := []string{"dataset1", "dataset2"} + datasets := session.DatasetCache{ + Datasets: []string{"dataset1", "dataset2"}, + } modifiedContext := storeDatasets(c, datasets) // Verify that context has new data diff --git a/api/s3/s3.go b/api/s3/s3.go index 4419b0d..83af590 100644 --- a/api/s3/s3.go +++ b/api/s3/s3.go @@ -94,7 +94,8 @@ func ListBuckets(c *gin.Context) { } buckets := []Bucket{} - for _, dataset := range middleware.GetDatasets(c) { + datasetCache := middleware.GetDatasets(c) + for _, dataset := range datasetCache.Datasets { datasetInfo, err := database.GetDatasetInfo(dataset) if err != nil { log.Errorf("Failed to get dataset information: %v", err) @@ -122,7 +123,8 @@ func ListObjects(c *gin.Context) { dataset := c.Param("dataset") allowed := false - for _, known := range middleware.GetDatasets(c) { + datasetCache := middleware.GetDatasets(c) + for _, known := range datasetCache.Datasets { if dataset == known { allowed = true @@ -242,7 +244,8 @@ func parseParams(c *gin.Context) *gin.Context { path = string(protocolPattern.ReplaceAll([]byte(path), []byte("$1/$2"))) } - for _, dataset := range middleware.GetDatasets(c) { + datasetCache := middleware.GetDatasets(c) + for _, dataset := range datasetCache.Datasets { // check that the path starts with the dataset name, but also that the // path is only the dataset, or that the following character is a slash. // This prevents wrong matches in cases like when one dataset name is a diff --git a/api/sda/sda.go b/api/sda/sda.go index f10be1d..9f63653 100644 --- a/api/sda/sda.go +++ b/api/sda/sda.go @@ -35,10 +35,10 @@ func Datasets(c *gin.Context) { // Retrieve dataset list from request context // generated by the authentication middleware - datasets := middleware.GetDatasets(c) + datasetCache := middleware.GetDatasets(c) // Return response - c.JSON(http.StatusOK, datasets) + c.JSON(http.StatusOK, datasetCache.Datasets) } // find looks for a dataset name in a list of datasets @@ -60,11 +60,11 @@ var getFiles = func(datasetID string, ctx *gin.Context) ([]*database.FileInfo, i // Retrieve dataset list from request context // generated by the authentication middleware - datasets := middleware.GetDatasets(ctx) + datasetCache := middleware.GetDatasets(ctx) log.Debugf("request to process files for dataset %s", sanitizeString(datasetID)) - if find(datasetID, datasets) { + if find(datasetID, datasetCache.Datasets) { // Get file metadata files, err := database.GetFiles(datasetID) if err != nil { @@ -133,12 +133,12 @@ func Download(c *gin.Context) { } // Get datasets from request context, parsed previously by token middleware - datasets := middleware.GetDatasets(c) + datasetCache := middleware.GetDatasets(c) // Verify user has permission to datafile permission := false - for d := range datasets { - if datasets[d] == dataset { + for d := range datasetCache.Datasets { + if datasetCache.Datasets[d] == dataset { permission = true break diff --git a/api/sda/sda_test.go b/api/sda/sda_test.go index 3636590..ebd842d 100644 --- a/api/sda/sda_test.go +++ b/api/sda/sda_test.go @@ -15,6 +15,7 @@ import ( "github.com/neicnordic/sda-download/api/middleware" "github.com/neicnordic/sda-download/internal/config" "github.com/neicnordic/sda-download/internal/database" + "github.com/neicnordic/sda-download/internal/session" "github.com/neicnordic/sda-download/internal/storage" ) @@ -24,14 +25,16 @@ func TestDatasets(t *testing.T) { originalGetDatasets := middleware.GetDatasets // Substitute mock functions - middleware.GetDatasets = func(c *gin.Context) []string { - return []string{"dataset1", "dataset2"} + middleware.GetDatasets = func(c *gin.Context) session.DatasetCache { + return session.DatasetCache{ + Datasets: []string{"dataset1", "dataset2"}, + } } // Mock request and response holders w := httptest.NewRecorder() c, _ := gin.CreateTestContext(w) - c.Set("datasets", []string{"dataset1", "dataset2"}) + c.Set("datasets", session.DatasetCache{Datasets: []string{"dataset1", "dataset2"}}) // Test the outcomes of the handler Datasets(c) @@ -97,8 +100,10 @@ func TestGetFiles_Fail_Database(t *testing.T) { originalGetFilesDB := database.GetFiles // Substitute mock functions - middleware.GetDatasets = func(ctx *gin.Context) []string { - return []string{"dataset1", "dataset2"} + middleware.GetDatasets = func(ctx *gin.Context) session.DatasetCache { + return session.DatasetCache{ + Datasets: []string{"dataset1", "dataset2"}, + } } database.GetFiles = func(datasetID string) ([]*database.FileInfo, error) { return nil, errors.New("something went wrong") @@ -135,8 +140,10 @@ func TestGetFiles_Fail_NotFound(t *testing.T) { originalGetDatasets := middleware.GetDatasets // Substitute mock functions - middleware.GetDatasets = func(ctx *gin.Context) []string { - return []string{"dataset1", "dataset2"} + middleware.GetDatasets = func(ctx *gin.Context) session.DatasetCache { + return session.DatasetCache{ + Datasets: []string{"dataset1", "dataset2"}, + } } // Run test target @@ -169,8 +176,10 @@ func TestGetFiles_Success(t *testing.T) { originalGetFilesDB := database.GetFiles // Substitute mock functions - middleware.GetDatasets = func(ctx *gin.Context) []string { - return []string{"dataset1", "dataset2"} + middleware.GetDatasets = func(ctx *gin.Context) session.DatasetCache { + return session.DatasetCache{ + Datasets: []string{"dataset1", "dataset2"}, + } } database.GetFiles = func(datasetID string) ([]*database.FileInfo, error) { fileInfo := database.FileInfo{ @@ -447,8 +456,8 @@ func TestDownload_Fail_NoPermissions(t *testing.T) { // nolint:goconst return "dataset1", nil } - middleware.GetDatasets = func(ctx *gin.Context) []string { - return []string{} + middleware.GetDatasets = func(ctx *gin.Context) session.DatasetCache { + return session.DatasetCache{} } // Mock request and response holders @@ -490,8 +499,10 @@ func TestDownload_Fail_GetFile(t *testing.T) { database.CheckFilePermission = func(fileID string) (string, error) { return "dataset1", nil } - middleware.GetDatasets = func(ctx *gin.Context) []string { - return []string{"dataset1"} + middleware.GetDatasets = func(ctx *gin.Context) session.DatasetCache { + return session.DatasetCache{ + Datasets: []string{"dataset1"}, + } } database.GetFile = func(fileID string) (*database.FileDownload, error) { return nil, errors.New("database error") @@ -538,8 +549,10 @@ func TestDownload_Fail_OpenFile(t *testing.T) { database.CheckFilePermission = func(fileID string) (string, error) { return "dataset1", nil } - middleware.GetDatasets = func(ctx *gin.Context) []string { - return []string{"dataset1"} + middleware.GetDatasets = func(ctx *gin.Context) session.DatasetCache { + return session.DatasetCache{ + Datasets: []string{"dataset1"}, + } } database.GetFile = func(fileID string) (*database.FileDownload, error) { fileDetails := &database.FileDownload{ @@ -594,8 +607,10 @@ func TestDownload_Fail_ParseCoordinates(t *testing.T) { database.CheckFilePermission = func(fileID string) (string, error) { return "dataset1", nil } - middleware.GetDatasets = func(ctx *gin.Context) []string { - return []string{"dataset1"} + middleware.GetDatasets = func(ctx *gin.Context) session.DatasetCache { + return session.DatasetCache{ + Datasets: []string{"dataset1"}, + } } database.GetFile = func(fileID string) (*database.FileDownload, error) { fileDetails := &database.FileDownload{ @@ -655,8 +670,10 @@ func TestDownload_Fail_StreamFile(t *testing.T) { database.CheckFilePermission = func(fileID string) (string, error) { return "dataset1", nil } - middleware.GetDatasets = func(ctx *gin.Context) []string { - return []string{"dataset1"} + middleware.GetDatasets = func(ctx *gin.Context) session.DatasetCache { + return session.DatasetCache{ + Datasets: []string{"dataset1"}, + } } database.GetFile = func(fileID string) (*database.FileDownload, error) { fileDetails := &database.FileDownload{ @@ -723,8 +740,10 @@ func TestDownload_Success(t *testing.T) { database.CheckFilePermission = func(fileID string) (string, error) { return "dataset1", nil } - middleware.GetDatasets = func(ctx *gin.Context) []string { - return []string{"dataset1"} + middleware.GetDatasets = func(ctx *gin.Context) session.DatasetCache { + return session.DatasetCache{ + Datasets: []string{"dataset1"}, + } } database.GetFile = func(fileID string) (*database.FileDownload, error) { fileDetails := &database.FileDownload{ diff --git a/cmd/main.go b/cmd/main.go index bc122d6..46c21aa 100644 --- a/cmd/main.go +++ b/cmd/main.go @@ -2,6 +2,7 @@ package main import ( "github.com/neicnordic/sda-download/api" + "github.com/neicnordic/sda-download/api/middleware" "github.com/neicnordic/sda-download/api/sda" "github.com/neicnordic/sda-download/internal/config" "github.com/neicnordic/sda-download/internal/database" @@ -23,6 +24,14 @@ func init() { } config.Config = *conf + // Set middleware + // nolint:gocritic // this nolint can be removed, if you have more than one middlewares available + switch conf.App.Middleware { + default: + api.SelectedMiddleware = middleware.TokenMiddleware + } + log.Infof("%s middleware selected", conf.App.Middleware) + // Connect to database db, err := database.NewDB(conf.DB) if err != nil { diff --git a/dev_utils/config.yaml b/dev_utils/config.yaml index 55136cd..1556a85 100644 --- a/dev_utils/config.yaml +++ b/dev_utils/config.yaml @@ -3,6 +3,7 @@ app: servercert: "./dev_utils/certs/download.pem" serverkey: "./dev_utils/certs/download-key.pem" port: "8443" + middleware: "default" log: level: "debug" diff --git a/go.mod b/go.mod index adc479d..27a98e9 100644 --- a/go.mod +++ b/go.mod @@ -15,29 +15,31 @@ require ( github.com/sirupsen/logrus v1.9.3 github.com/spf13/viper v1.16.0 github.com/stretchr/testify v1.8.4 + golang.org/x/exp v0.0.0-20230817173708-d852ddb80c63 ) require ( filippo.io/edwards25519 v1.0.0 // indirect - github.com/bytedance/sonic v1.9.1 // indirect - github.com/cespare/xxhash/v2 v2.1.2 // indirect - github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 // indirect + github.com/bytedance/sonic v1.10.0 // indirect + github.com/cespare/xxhash/v2 v2.2.0 // indirect + github.com/chenzhuoyu/base64x v0.0.0-20230717121745-296ad89f973d // indirect + github.com/chenzhuoyu/iasm v0.9.0 // indirect github.com/davecgh/go-spew v1.1.1 // indirect github.com/dchest/bcrypt_pbkdf v0.0.0-20150205184540-83f37f9c154a // indirect github.com/decred/dcrd/dcrec/secp256k1/v4 v4.2.0 // indirect - github.com/dustin/go-humanize v1.0.0 // indirect + github.com/dustin/go-humanize v1.0.1 // indirect github.com/fsnotify/fsnotify v1.6.0 // indirect github.com/gabriel-vasile/mimetype v1.4.2 // indirect github.com/gin-contrib/sse v0.1.0 // indirect github.com/go-playground/locales v0.14.1 // indirect github.com/go-playground/universal-translator v0.18.1 // indirect - github.com/go-playground/validator/v10 v10.14.0 // indirect + github.com/go-playground/validator/v10 v10.15.2 // indirect github.com/goccy/go-json v0.10.2 // indirect - github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b // indirect + github.com/golang/glog v1.1.2 // indirect github.com/hashicorp/hcl v1.0.0 // indirect github.com/jmespath/go-jmespath v0.4.0 // indirect github.com/json-iterator/go v1.1.12 // indirect - github.com/klauspost/cpuid/v2 v2.2.4 // indirect + github.com/klauspost/cpuid/v2 v2.2.5 // indirect github.com/leodido/go-urn v1.2.4 // indirect github.com/lestrrat-go/backoff/v2 v2.0.8 // indirect github.com/lestrrat-go/blackmagic v1.0.1 // indirect @@ -49,7 +51,7 @@ require ( github.com/mitchellh/mapstructure v1.5.0 // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/reflect2 v1.0.2 // indirect - github.com/pelletier/go-toml/v2 v2.0.8 // indirect + github.com/pelletier/go-toml/v2 v2.0.9 // indirect github.com/pkg/errors v0.9.1 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect github.com/ryszard/goskiplist v0.0.0-20150312221310-2dfbae5fcf46 // indirect @@ -58,16 +60,16 @@ require ( github.com/spf13/cast v1.5.1 // indirect github.com/spf13/jwalterweatherman v1.1.0 // indirect github.com/spf13/pflag v1.0.5 // indirect - github.com/subosito/gotenv v1.4.2 // indirect + github.com/subosito/gotenv v1.6.0 // indirect github.com/twitchyliquid64/golang-asm v0.15.1 // indirect github.com/ugorji/go/codec v1.2.11 // indirect - golang.org/x/arch v0.3.0 // indirect + golang.org/x/arch v0.4.0 // indirect golang.org/x/crypto v0.12.0 // indirect - golang.org/x/net v0.10.0 // indirect + golang.org/x/net v0.14.0 // indirect golang.org/x/sys v0.11.0 // indirect golang.org/x/text v0.12.0 // indirect - golang.org/x/tools v0.6.0 // indirect - google.golang.org/protobuf v1.30.0 // indirect + golang.org/x/tools v0.12.1-0.20230815132531-74c255bcf846 // indirect + google.golang.org/protobuf v1.31.0 // indirect gopkg.in/ini.v1 v1.67.0 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect diff --git a/go.sum b/go.sum index c67a653..4b94a76 100644 --- a/go.sum +++ b/go.sum @@ -46,15 +46,19 @@ github.com/aws/aws-sdk-go v1.33.0/go.mod h1:5zCpMtNQVjRREroY7sYe8lOMRSxkhG6MZveU github.com/aws/aws-sdk-go v1.44.333 h1:X0j5TGXtHLZzDB/uRcGKLG77ERFtxYQtXefs+Apf2PU= github.com/aws/aws-sdk-go v1.44.333/go.mod h1:aVsgQcEevwlmQ7qHE9I3h+dtQgpqhFB+i8Phjh7fkwI= github.com/bytedance/sonic v1.5.0/go.mod h1:ED5hyg4y6t3/9Ku1R6dU/4KyJ48DZ4jPhfY1O2AihPM= -github.com/bytedance/sonic v1.9.1 h1:6iJ6NqdoxCDr6mbY8h18oSO+cShGSMRGCEo7F2h0x8s= -github.com/bytedance/sonic v1.9.1/go.mod h1:i736AoUSYt75HyZLoJW9ERYxcy6eaN6h4BZXU064P/U= +github.com/bytedance/sonic v1.10.0-rc/go.mod h1:ElCzW+ufi8qKqNW0FY314xriJhyJhuoJ3gFZdAHF7NM= +github.com/bytedance/sonic v1.10.0 h1:qtNZduETEIWJVIyDl01BeNxur2rW9OwTQ/yBqFRkKEk= +github.com/bytedance/sonic v1.10.0/go.mod h1:iZcSUejdk5aukTND/Eu/ivjQuEL0Cu9/rf50Hi0u/g4= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= -github.com/cespare/xxhash/v2 v2.1.2 h1:YRXhKfTDauu4ajMg1TPgFO5jnlC2HCbmLXMcTG5cbYE= -github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44= +github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/chenzhuoyu/base64x v0.0.0-20211019084208-fb5309c8db06/go.mod h1:DH46F32mSOjUmXrMHnKwZdA8wcEefY7UVqBKYGjpdQY= -github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 h1:qSGYFH7+jGhDF8vLC+iwCD4WpbV1EBDSzWkJODFLams= github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311/go.mod h1:b583jCggY9gE99b6G5LEC39OIiVsWj+R97kbl5odCEk= +github.com/chenzhuoyu/base64x v0.0.0-20230717121745-296ad89f973d h1:77cEq6EriyTZ0g/qfRdp61a3Uu/AWrgIq2s0ClJV1g0= +github.com/chenzhuoyu/base64x v0.0.0-20230717121745-296ad89f973d/go.mod h1:8EPpVsBuRksnlj1mLy4AWzRNQYxauNi62uWcE3to6eA= +github.com/chenzhuoyu/iasm v0.9.0 h1:9fhXjVzq5hUy2gkhhgHl95zG2cEAhw9OSGs8toWWAwo= +github.com/chenzhuoyu/iasm v0.9.0/go.mod h1:Xjy2NpN3h7aUqeqM+woSuuvxmIe6+DDsiNLIrkAmYog= github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= @@ -74,8 +78,9 @@ github.com/dgraph-io/ristretto v0.1.1 h1:6CWw5tJNgpegArSHpNHJKldNeq03FQCwYvfMVWa github.com/dgraph-io/ristretto v0.1.1/go.mod h1:S1GPSBCYCIhmVNfcth17y2zZtQT6wzkzgwUve0VDWWA= github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2 h1:tdlZCpZ/P9DhczCTSixgIKmwPv6+wP5DGjqLYw5SUiA= github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw= -github.com/dustin/go-humanize v1.0.0 h1:VSnTsYCnlFHaM2/igO1h6X3HA71jcobQuxemgkq4zYo= github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= +github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY= +github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto= github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= @@ -99,13 +104,14 @@ github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/o github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY= github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY= github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY= -github.com/go-playground/validator/v10 v10.14.0 h1:vgvQWe3XCz3gIeFDm/HnTIbj6UGmg/+t63MyGU2n5js= -github.com/go-playground/validator/v10 v10.14.0/go.mod h1:9iXMNT7sEkjXb0I+enO7QXmzG6QCsPWY4zveKFVRSyU= +github.com/go-playground/validator/v10 v10.15.2 h1:Ra5cll2/eF8X0Ff2+8SMD7euo2nenQ8WEpgqfy4NhHU= +github.com/go-playground/validator/v10 v10.15.2/go.mod h1:9iXMNT7sEkjXb0I+enO7QXmzG6QCsPWY4zveKFVRSyU= github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg= github.com/goccy/go-json v0.10.2 h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU= github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I= -github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b h1:VKtxabqXZkF25pY9ekfRL6a582T4P37/31XEstQ5p58= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= +github.com/golang/glog v1.1.2 h1:DVjP2PbBOzHyzA+dn3WhHIq4NdVu3Q+pvivFICf/7fo= +github.com/golang/glog v1.1.2/go.mod h1:zR+okUeTbrL6EL3xHUDxZuEtGv04p5shwip1+mL/rLQ= github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= @@ -184,8 +190,9 @@ github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1 github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= -github.com/klauspost/cpuid/v2 v2.2.4 h1:acbojRNwl3o09bUq+yDCtZFc1aiwaAAxtcn8YkZXnvk= -github.com/klauspost/cpuid/v2 v2.2.4/go.mod h1:RVVoqg1df56z8g3pUjL/3lE5UfnlrJX8tyFgg4nqhuY= +github.com/klauspost/cpuid/v2 v2.2.5 h1:0E5MSMDEoAulmXNFquVs//DdoomxaoTY1kUhbc/qbZg= +github.com/klauspost/cpuid/v2 v2.2.5/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws= +github.com/knz/go-libedit v1.10.1/go.mod h1:MZTVkCWyz0oBc7JOWP3wNAzd002ZbM/5hgShxwh4x8M= github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= @@ -222,8 +229,8 @@ github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9G github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= github.com/neicnordic/crypt4gh v1.8.2 h1:KNqYBBDU0qW296I6yLoA7l0GoNA/lfzhpy9RDkzNrRM= github.com/neicnordic/crypt4gh v1.8.2/go.mod h1:VftsV+iUntv40/EB9TbnBnQ3/IDH40zEAqcMajrFVVg= -github.com/pelletier/go-toml/v2 v2.0.8 h1:0ctb6s9mE31h0/lhu+J6OPmVeDxJn+kYnJc2jZR9tGQ= -github.com/pelletier/go-toml/v2 v2.0.8/go.mod h1:vuYfssBdrU2XDZ9bYydBu6t+6a6PYNcZljzZR9VXg+4= +github.com/pelletier/go-toml/v2 v2.0.9 h1:uH2qQXheeefCCkuBBSLi7jCiSmj3VRh2+Goq2N7Xxu0= +github.com/pelletier/go-toml/v2 v2.0.9/go.mod h1:tJU2Z3ZkXwnxa4DPO899bsyIoywizdUvyaeZurnPPDc= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/sftp v1.13.1/go.mod h1:3HaPG6Dq1ILlpPZRO0HVMrsydcdLt6HRDccSgb87qRg= @@ -262,11 +269,10 @@ github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/ github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= -github.com/stretchr/testify v1.8.3/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= -github.com/subosito/gotenv v1.4.2 h1:X1TuBLAMDFbaTAChgCBLu3DU3UPyELpnF2jjJ2cz/S8= -github.com/subosito/gotenv v1.4.2/go.mod h1:ayKnFf/c6rvx/2iiLrJUk1e6plDbT3edrFNGqEflhK0= +github.com/subosito/gotenv v1.6.0 h1:9NlTDc1FTs4qu0DDq7AEtTPNw6SVm7uBMsUCUjABIf8= +github.com/subosito/gotenv v1.6.0/go.mod h1:Dk4QP5c2W3ibzajGcXpNraDfq2IrhjMIvMSWPKKo0FU= github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS4MhqMhdFk5YI= github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08= github.com/ugorji/go/codec v1.2.11 h1:BMaWp1Bb6fHwEtbplGBGJ498wD+LKlNSl25MjdZY4dU= @@ -284,8 +290,8 @@ go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk= golang.org/x/arch v0.0.0-20210923205945-b76863e36670/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8= -golang.org/x/arch v0.3.0 h1:02VY4/ZcO/gBOH6PUaoiptASxtXU10jazRCP865E97k= -golang.org/x/arch v0.3.0/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8= +golang.org/x/arch v0.4.0 h1:A8WCeEWhLwPBKNbFi5Wv5UTCBx5zzubnXDlMOFAzFMc= +golang.org/x/arch v0.4.0/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= @@ -307,6 +313,8 @@ golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u0 golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM= golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU= +golang.org/x/exp v0.0.0-20230817173708-d852ddb80c63 h1:m64FZMko/V45gv0bNmrNYoDEq8U5YUhetc9cBWKS1TQ= +golang.org/x/exp v0.0.0-20230817173708-d852ddb80c63/go.mod h1:0v4NqG35kSWCMzLaMeX+IQrlSnVE/bqGSyC2cz/9Le8= golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= @@ -367,8 +375,9 @@ golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qx golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/net v0.1.0/go.mod h1:Cx3nUiGt4eDBEyega/BKRp+/AlGL8hYe7U9odMt2Cco= golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= -golang.org/x/net v0.10.0 h1:X2//UzNDwYmtCLn7To6G58Wr6f5ahEAQgKNzv9Y951M= golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= +golang.org/x/net v0.14.0 h1:BONx9s002vGdD9umnlX1Po8vOZmrgH34qlHcD1MfK14= +golang.org/x/net v0.14.0/go.mod h1:PpSgVXXLK0OxS0F31C1/tv6XNguvCrnXIDrFMspZIUI= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -426,7 +435,6 @@ golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20210423185535-09eb48e85fd7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220704084225-05e143d24a9e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= @@ -508,8 +516,9 @@ golang.org/x/tools v0.0.0-20210105154028-b0ab187a4818/go.mod h1:emZCQorbCU4vsT4f golang.org/x/tools v0.0.0-20210108195828-e2f9c7f1fc8e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= -golang.org/x/tools v0.6.0 h1:BOw41kyTf3PuCW1pVQf8+Cyg8pMlkYB1oo9iJ6D/lKM= golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= +golang.org/x/tools v0.12.1-0.20230815132531-74c255bcf846 h1:Vve/L0v7CXXuxUmaMGIEK/dEeq7uiqb5qBgQrZzIE7E= +golang.org/x/tools v0.12.1-0.20230815132531-74c255bcf846/go.mod h1:Sc0INKfu04TlqNoRA1hgpFZbhYXHPr4V5DzpSBTPqQM= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= @@ -603,8 +612,8 @@ google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpAD google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4= google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= -google.golang.org/protobuf v1.30.0 h1:kPPoIgf3TsEvrm0PFe15JQ+570QVxYzEvvHqChK+cng= -google.golang.org/protobuf v1.30.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +google.golang.org/protobuf v1.31.0 h1:g0LDEJHgrBl9N9r17Ru3sqWhkIx2NB67okBHPwC7hs8= +google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= @@ -626,6 +635,7 @@ honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWh honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= +nullprogram.com/x/optparse v1.0.0/go.mod h1:KdyPE+Igbe0jQUrVfMqDMeJQIJZEuyV7pjYmp6pbG50= rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4= rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= diff --git a/internal/config/config.go b/internal/config/config.go index 14c1c79..fb716a2 100644 --- a/internal/config/config.go +++ b/internal/config/config.go @@ -14,11 +14,15 @@ import ( "github.com/neicnordic/sda-download/internal/storage" log "github.com/sirupsen/logrus" "github.com/spf13/viper" + "golang.org/x/exp/slices" ) const POSIX = "posix" const S3 = "s3" +// availableMiddlewares list the options for middlewares +var availableMiddlewares = []string{"", "default"} + // Config is a global configuration value store var Config Map @@ -51,6 +55,10 @@ type AppConfig struct { // Stores the Crypt4GH private key if the two configs above are set // Unconfigurable. Depends on Crypt4GHKeyFile and Crypt4GHPassFile Crypt4GHKey *[32]byte + + // Selected middleware for authentication and authorizaton + // Optional. Default value is "default" for TokenMiddleware + Middleware string } type SessionConfig struct { @@ -213,6 +221,7 @@ func NewConfig() (*Map, error) { func (c *Map) applyDefaults() { viper.SetDefault("app.host", "0.0.0.0") viper.SetDefault("app.port", 8080) + viper.SetDefault("app.middleware", "default") viper.SetDefault("session.expiration", -1) viper.SetDefault("session.secure", true) viper.SetDefault("session.httponly", true) @@ -292,6 +301,7 @@ func (c *Map) appConfig() error { c.App.Port = viper.GetInt("app.port") c.App.ServerCert = viper.GetString("app.servercert") c.App.ServerKey = viper.GetString("app.serverkey") + c.App.Middleware = viper.GetString("app.middleware") if c.App.Port != 443 && c.App.Port != 8080 { c.App.Port = viper.GetInt("app.port") @@ -305,6 +315,12 @@ func (c *Map) appConfig() error { return err } + if !slices.Contains(availableMiddlewares, c.App.Middleware) { + err := fmt.Errorf("app.middleware value=%v is not one of allowed values=%v", c.App.Middleware, availableMiddlewares) + + return err + } + return nil } diff --git a/internal/session/session.go b/internal/session/session.go index ea5073d..4f95d91 100644 --- a/internal/session/session.go +++ b/internal/session/session.go @@ -50,25 +50,20 @@ func InitialiseSessionCache() (*ristretto.Cache, error) { } // Get returns a value from cache at key -var Get = func(key string) ([]string, bool) { +var Get = func(key string) (DatasetCache, bool) { log.Debug("get value from cache") - header, exists := SessionCache.Get(key) - var cachedDatasets []string - if header != nil { - cachedDatasets = header.(DatasetCache).Datasets - } else { - cachedDatasets = nil + cached, exists := SessionCache.Get(key) + var cachedDatasets DatasetCache // default nil + if cached != nil { + cachedDatasets = cached.(DatasetCache) } - log.Debugf("cache response, exists=%t, datasets=%s", exists, cachedDatasets) + log.Debugf("cache response, exists=%t, cached=%v", exists, cachedDatasets) return cachedDatasets, exists } -func Set(key string, datasets []string) { +func Set(key string, datasetCache DatasetCache) { log.Debug("store to cache") - datasetCache := DatasetCache{ - Datasets: datasets, - } // Each item has a cost of 1, with max size of cache being 100,000 items SessionCache.SetWithTTL(key, datasetCache, 1, config.Config.Session.Expiration) log.Debug("stored to cache") diff --git a/internal/session/session_test.go b/internal/session/session_test.go index 2ec6a1e..22a0fa5 100644 --- a/internal/session/session_test.go +++ b/internal/session/session_test.go @@ -36,7 +36,7 @@ func TestGetSetCache_Found(t *testing.T) { cache, _ := InitialiseSessionCache() SessionCache = cache - Set("key1", []string{"dataset1", "dataset2"}) + Set("key1", DatasetCache{Datasets: []string{"dataset1", "dataset2"}}) time.Sleep(time.Duration(100 * time.Millisecond)) // need to give cache time to get ready datasets, exists := Get("key1") @@ -44,7 +44,7 @@ func TestGetSetCache_Found(t *testing.T) { expectedDatasets := []string{"dataset1", "dataset2"} expectedExists := true - if strings.Join(datasets, "") != strings.Join(expectedDatasets, "") { + if strings.Join(datasets.Datasets, "") != strings.Join(expectedDatasets, "") { t.Errorf("TestGetSetCache_Found failed, expected %s but received %s", expectedDatasets, datasets) } if expectedExists != exists { @@ -62,7 +62,7 @@ func TestGetSetCache_NotFound(t *testing.T) { cache, _ := InitialiseSessionCache() SessionCache = cache - Set("key1", []string{"dataset1", "dataset2"}) + Set("key1", DatasetCache{Datasets: []string{"dataset1", "dataset2"}}) time.Sleep(time.Duration(100 * time.Millisecond)) // need to give cache time to get ready datasets, exists := Get("key2") @@ -70,7 +70,7 @@ func TestGetSetCache_NotFound(t *testing.T) { expectedDatasets := []string{} expectedExists := false - if strings.Join(datasets, "") != strings.Join(expectedDatasets, "") { + if strings.Join(datasets.Datasets, "") != strings.Join(expectedDatasets, "") { t.Errorf("TestGetSetCache_NotFound failed, expected %s but received %s", expectedDatasets, datasets) } if expectedExists != exists {