From 7b2bbfa89749b775cbacafed147eb2ce102c3589 Mon Sep 17 00:00:00 2001 From: Ryan Oberlander <46940735+roberlander2@users.noreply.github.com> Date: Wed, 28 Jun 2023 13:42:48 -0500 Subject: [PATCH] [#632] Enable CORS (#634) * update logging library to v2 * revert testing changes [#624] * upgrade core-auth-library-go to v2.1.0, add empty enc APIs policy [#624] * remove individual web auth entities, use claimsCheck functions * upgrade auth-lib and logging-lib versions [#624] * clean up unnecessary schema files, upgrade dependencies, trouble with openapi3 example validation [#624] * downgrade openapi to 0.110.0, remove more unnecessary schemas [#624] * update error messages with new logutils strings [#624] * update swagger docs to only use yaml syntax [#624] * update changelog * fix typo * logging adjustments, fix comment * bug fixes * do not store access tokens in DB, encrypt oidc tokens in login session params * return raw oidc tokens in login, refresh responses, only store encrypted refresh token, add decryption function * remove whitespace from decrypted refresh tokens * store hashed refresh tokens, prefix refresh tokens with session ID, remove some refresh token logging * first implementation of session ID rate limit * delete login session on rate limit hit * add allow legacy refresh flag to env vars, don't send oidc refresh tokens to client * update login and refresh response docs * limit block size in pkcs7 padding * limit ciphertext size * don't allow negative ciphertext size * fix padded ciphertext length * use AES encryption in GCM mode instead of CBC, store nonce in session params [#628] * update usage of global configs, will probably update to be used more like bb template configs [#628] * start refactoring GlobalConfig into Config [#628] * add new files * finish global_configs -> configs refactor, bug fixes [#628] * handle backward compatibility * use Log.SendHTTPResponse * setup CORS handler in web adapter * update go mod * fix go mod * update changelog * update config data type [#632] * gen mocks * fix configs, docs * fix admin update config API [#632] * fix changelog, merge changes from develop * update configs APIs [#632] * bug fixes * do not setup cors if there are no allowed origins [#632] * move storage out of web package, upgrade dependencies --------- Co-authored-by: Stephen Hurwit --- .secrets.baseline | 77 ++-- CHANGELOG.md | 4 + core/apis.go | 33 +- core/apis_test.go | 31 +- core/app_administration.go | 111 ++++- core/app_system.go | 54 --- core/auth/apis.go | 2 +- core/auth/auth.go | 47 +-- core/interfaces.go | 20 +- core/mocks/Storage.go | 168 +++++--- core/model/config.go | 46 ++- driven/storage/adapter.go | 205 +++++++-- driven/storage/database.go | 26 +- driver/web/adapter.go | 26 +- driver/web/apis_admin.go | 127 +++++- driver/web/apis_services.go | 1 - driver/web/apis_system.go | 63 --- driver/web/authorization_admin_policy.csv | 9 + driver/web/authorization_system_policy.csv | 4 - driver/web/conversions_config.go | 89 ++++ driver/web/docs/gen/def.yaml | 389 ++++++++++++++---- driver/web/docs/gen/gen_types.go | 182 ++++++-- driver/web/docs/index.yaml | 8 +- driver/web/docs/resources/admin/configs.yaml | 97 +++++ .../web/docs/resources/admin/configsId.yaml | 139 +++++++ .../docs/resources/system/global-config.yaml | 83 ---- .../apis/admin/configs/request/Request.yaml | 19 + .../shared/responses/refresh/Response.yaml | 8 +- driver/web/docs/schemas/config/Config.yaml | 34 ++ .../docs/schemas/config/EnvConfigData.yaml | 12 + .../web/docs/schemas/global/GlobalConfig.yaml | 6 - driver/web/docs/schemas/index.yaml | 12 +- .../docs/schemas/user/AccountAuthType.yaml | 2 +- go.mod | 77 ++-- go.sum | 203 +++++---- main.go | 25 +- utils/utils.go | 35 ++ 37 files changed, 1796 insertions(+), 678 deletions(-) create mode 100644 driver/web/conversions_config.go create mode 100644 driver/web/docs/resources/admin/configs.yaml create mode 100644 driver/web/docs/resources/admin/configsId.yaml delete mode 100644 driver/web/docs/resources/system/global-config.yaml create mode 100644 driver/web/docs/schemas/apis/admin/configs/request/Request.yaml create mode 100644 driver/web/docs/schemas/config/Config.yaml create mode 100644 driver/web/docs/schemas/config/EnvConfigData.yaml delete mode 100644 driver/web/docs/schemas/global/GlobalConfig.yaml diff --git a/.secrets.baseline b/.secrets.baseline index 7a17d3968..a2437bbdc 100644 --- a/.secrets.baseline +++ b/.secrets.baseline @@ -109,12 +109,6 @@ }, { "path": "detect_secrets.filters.heuristic.is_templated_secret" - }, - { - "path": "detect_secrets.filters.regex.should_exclude_file", - "pattern": [ - "go.sum" - ] } ], "results": { @@ -124,8 +118,7 @@ "filename": "README.md", "hashed_secret": "112bb791304791ddcf692e29fd5cf149b35fea37", "is_verified": false, - "line_number": 37, - "is_secret": false + "line_number": 37 } ], "core/app_shared.go": [ @@ -134,8 +127,7 @@ "filename": "core/app_shared.go", "hashed_secret": "44e17306b837162269a410204daaa5ecee4ec22c", "is_verified": false, - "line_number": 41, - "is_secret": false + "line_number": 41 } ], "core/auth/apis.go": [ @@ -154,15 +146,15 @@ "filename": "core/auth/auth.go", "hashed_secret": "417355fe2b66baa6826739a6d8006ab2ddcf5186", "is_verified": false, - "line_number": 151, + "line_number": 154, "is_secret": false }, { "type": "Secret Keyword", "filename": "core/auth/auth.go", - "hashed_secret": "700f93e97a8aaf0664601a8f298ac5ad0ff13c37", + "hashed_secret": "bbdb97274c94b9605a766e317fca26186c34c510", "is_verified": false, - "line_number": 153, + "line_number": 156, "is_secret": false }, { @@ -170,7 +162,7 @@ "filename": "core/auth/auth.go", "hashed_secret": "58f3388441fbce0e48aef2bf74413a6f43f6dc70", "is_verified": false, - "line_number": 933, + "line_number": 936, "is_secret": false }, { @@ -178,7 +170,7 @@ "filename": "core/auth/auth.go", "hashed_secret": "94a7f0195bbbd2260c4e4d02b6348fbcd90b2b30", "is_verified": false, - "line_number": 2440, + "line_number": 2442, "is_secret": false } ], @@ -188,56 +180,49 @@ "filename": "core/auth/auth_type_email.go", "hashed_secret": "f3f2fb17a3bf9f307cb6e79b61b9d4baf07dd681", "is_verified": false, - "line_number": 75, - "is_secret": false + "line_number": 75 }, { "type": "Secret Keyword", "filename": "core/auth/auth_type_email.go", "hashed_secret": "fe70d8c51780596c0b3399573122bba943a461da", "is_verified": false, - "line_number": 76, - "is_secret": false + "line_number": 76 }, { "type": "Secret Keyword", "filename": "core/auth/auth_type_email.go", "hashed_secret": "06354d205ab5a3b6c7ad2333c58f1ddc810c97ba", "is_verified": false, - "line_number": 87, - "is_secret": false + "line_number": 87 }, { "type": "Secret Keyword", "filename": "core/auth/auth_type_email.go", "hashed_secret": "7cbe6dcf7274355d223e3174e4d8a7ffb55a9227", "is_verified": false, - "line_number": 156, - "is_secret": false + "line_number": 156 }, { "type": "Secret Keyword", "filename": "core/auth/auth_type_email.go", "hashed_secret": "69411040443be576ce64fc793269d7c26dd0866a", "is_verified": false, - "line_number": 253, - "is_secret": false + "line_number": 253 }, { "type": "Secret Keyword", "filename": "core/auth/auth_type_email.go", "hashed_secret": "cba104f0870345d3ec99d55c06441bdce9fcf584", "is_verified": false, - "line_number": 390, - "is_secret": false + "line_number": 390 }, { "type": "Secret Keyword", "filename": "core/auth/auth_type_email.go", "hashed_secret": "c74f3640d83fd19d941a4f44b28fbd9e57f59eef", "is_verified": false, - "line_number": 391, - "is_secret": false + "line_number": 391 } ], "core/auth/auth_type_oidc.go": [ @@ -246,8 +231,7 @@ "filename": "core/auth/auth_type_oidc.go", "hashed_secret": "0ade4f3edccc8888bef404fe6b3c92c13cdfad6b", "is_verified": false, - "line_number": 376, - "is_secret": false + "line_number": 376 } ], "core/auth/auth_type_username.go": [ @@ -306,8 +290,7 @@ "filename": "core/auth/service_static_token.go", "hashed_secret": "44e17306b837162269a410204daaa5ecee4ec22c", "is_verified": false, - "line_number": 78, - "is_secret": false + "line_number": 78 } ], "driven/emailer/adapter.go": [ @@ -316,8 +299,7 @@ "filename": "driven/emailer/adapter.go", "hashed_secret": "9df4524d2441f00999342c4541a39932198d4bb4", "is_verified": false, - "line_number": 70, - "is_secret": false + "line_number": 70 } ], "driven/profilebb/adapter.go": [ @@ -326,8 +308,7 @@ "filename": "driven/profilebb/adapter.go", "hashed_secret": "36c48d6ac9d10902792fa78b9c2d7d535971c2cc", "is_verified": false, - "line_number": 224, - "is_secret": false + "line_number": 224 } ], "driven/storage/database.go": [ @@ -336,8 +317,7 @@ "filename": "driven/storage/database.go", "hashed_secret": "6547f385c6d867e20f8217018a4d468a7d67d638", "is_verified": false, - "line_number": 209, - "is_secret": false + "line_number": 209 } ], "driver/web/apis_system.go": [ @@ -346,8 +326,7 @@ "filename": "driver/web/apis_system.go", "hashed_secret": "44e17306b837162269a410204daaa5ecee4ec22c", "is_verified": false, - "line_number": 700, - "is_secret": false + "line_number": 637 } ], "driver/web/docs/gen/def.yaml": [ @@ -356,8 +335,7 @@ "filename": "driver/web/docs/gen/def.yaml", "hashed_secret": "448ed7416fce2cb66c285d182b1ba3df1e90016d", "is_verified": false, - "line_number": 55, - "is_secret": false + "line_number": 55 } ], "driver/web/docs/gen/gen_types.go": [ @@ -366,7 +344,7 @@ "filename": "driver/web/docs/gen/gen_types.go", "hashed_secret": "c9739eab2dfa093cc0e450bf0ea81a43ae67b581", "is_verified": false, - "line_number": 1673, + "line_number": 1717, "is_secret": false } ], @@ -376,8 +354,7 @@ "filename": "driver/web/docs/resources/admin/auth/login.yaml", "hashed_secret": "448ed7416fce2cb66c285d182b1ba3df1e90016d", "is_verified": false, - "line_number": 26, - "is_secret": false + "line_number": 26 } ], "driver/web/docs/resources/services/auth/account/auth-type/link.yaml": [ @@ -386,8 +363,7 @@ "filename": "driver/web/docs/resources/services/auth/account/auth-type/link.yaml", "hashed_secret": "448ed7416fce2cb66c285d182b1ba3df1e90016d", "is_verified": false, - "line_number": 26, - "is_secret": false + "line_number": 26 } ], "driver/web/docs/resources/services/auth/login.yaml": [ @@ -396,10 +372,9 @@ "filename": "driver/web/docs/resources/services/auth/login.yaml", "hashed_secret": "448ed7416fce2cb66c285d182b1ba3df1e90016d", "is_verified": false, - "line_number": 24, - "is_secret": false + "line_number": 24 } ] }, - "generated_at": "2023-05-02T15:15:38Z" + "generated_at": "2023-06-07T20:22:07Z" } diff --git a/CHANGELOG.md b/CHANGELOG.md index 0709588ba..a2f1215a4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,7 +6,11 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). ## Unreleased +### Added +- Enable CORS [#632](https://github.com/rokwire/core-building-block/issues/632) + ## [1.33.0] - 2023-05-02 +### Added - Username and password authentication [#658](https://github.com/rokwire/core-building-block/issues/658) ## [1.32.2] - 2023-04-20 diff --git a/core/apis.go b/core/apis.go index cc254bc35..4a7957d67 100644 --- a/core/apis.go +++ b/core/apis.go @@ -22,6 +22,7 @@ import ( "time" "github.com/google/uuid" + "github.com/rokwire/core-auth-library-go/v3/tokenauth" "github.com/rokwire/logging-library-go/v2/errors" "github.com/rokwire/logging-library-go/v2/logs" "github.com/rokwire/logging-library-go/v2/logutils" @@ -336,6 +337,26 @@ type administrationImpl struct { app *application } +func (s *administrationImpl) AdmGetConfig(id string, claims *tokenauth.Claims) (*model.Config, error) { + return s.app.admGetConfig(id, claims) +} + +func (s *administrationImpl) AdmGetConfigs(configType *string, claims *tokenauth.Claims) ([]model.Config, error) { + return s.app.admGetConfigs(configType, claims) +} + +func (s *administrationImpl) AdmCreateConfig(config model.Config, claims *tokenauth.Claims) (*model.Config, error) { + return s.app.admCreateConfig(config, claims) +} + +func (s *administrationImpl) AdmUpdateConfig(config model.Config, claims *tokenauth.Claims) error { + return s.app.admUpdateConfig(config, claims) +} + +func (s *administrationImpl) AdmDeleteConfig(id string, claims *tokenauth.Claims) error { + return s.app.admDeleteConfig(id, claims) +} + func (s *administrationImpl) AdmGetTest() string { return s.app.admGetTest() } @@ -514,18 +535,6 @@ type systemImpl struct { app *application } -func (s *systemImpl) SysCreateGlobalConfig(setting string) (*model.GlobalConfig, error) { - return s.app.sysCreateGlobalConfig(setting) -} - -func (s *systemImpl) SysGetGlobalConfig() (*model.GlobalConfig, error) { - return s.app.sysGetGlobalConfig() -} - -func (s *systemImpl) SysUpdateGlobalConfig(setting string) error { - return s.app.sysUpdateGlobalConfig(setting) -} - func (s *systemImpl) SysGetApplicationOrganizations(appID *string, orgID *string) ([]model.ApplicationOrganization, error) { return s.app.sysGetApplicationOrganizations(appID, orgID) } diff --git a/core/apis_test.go b/core/apis_test.go index 52b1f603e..d2ec310fc 100644 --- a/core/apis_test.go +++ b/core/apis_test.go @@ -22,7 +22,9 @@ import ( genmocks "core-building-block/core/mocks" "core-building-block/core/model" + "github.com/rokwire/core-auth-library-go/v3/tokenauth" "github.com/rokwire/logging-library-go/v2/logs" + "github.com/stretchr/testify/mock" "gotest.tools/assert" ) @@ -78,40 +80,39 @@ func TestAdmGetTest(t *testing.T) { } } -/// - -//System - -func TestSysCreateGlobalConfig(t *testing.T) { +func TestAdmCreateConfig(t *testing.T) { + anyConfig := mock.AnythingOfType("model.Config") storage := genmocks.Storage{} - storage.On("GetGlobalConfig").Return(nil, nil) - storage.On("CreateGlobalConfig", nil, &model.GlobalConfig{Setting: "setting"}).Return(nil) + storage.On("InsertConfig", anyConfig).Return(nil) coreAPIs := buildTestCoreAPIs(&storage) - gc, _ := coreAPIs.System.SysCreateGlobalConfig("setting") - if gc == nil { - t.Error("gc is nil") + config := model.Config{Type: model.ConfigTypeEnv, AppID: "app", OrgID: "org", System: false, Data: model.EnvConfigData{}} + _, err := coreAPIs.Administration.AdmCreateConfig(config, &tokenauth.Claims{AppID: "app", OrgID: "org"}) + if err != nil { + t.Error("we are not expecting error") return } - assert.Equal(t, gc.Setting, "setting", "setting is different") //second case - error storage2 := genmocks.Storage{} - storage2.On("GetGlobalConfig").Return(nil, nil) - storage2.On("CreateGlobalConfig", nil, &model.GlobalConfig{Setting: "setting"}).Return(errors.New("error occured")) + storage2.On("InsertConfig", anyConfig).Return(errors.New("error occured")) coreAPIs = buildTestCoreAPIs(&storage2) - _, err := coreAPIs.System.SysCreateGlobalConfig("setting") + _, err = coreAPIs.Administration.AdmCreateConfig(config, &tokenauth.Claims{AppID: "app", OrgID: "org"}) if err == nil { t.Error("we are expecting error") return } errText := err.Error() - assert.Equal(t, errText, "core-building-block/core.(*application).sysCreateGlobalConfig() error inserting global config: error occured", "error is different: "+err.Error()) + assert.Equal(t, errText, "core-building-block/core.(*application).admCreateConfig() error inserting config: error occured", "error is different: "+err.Error()) } +/// + +//System + func TestSysGetOrganization(t *testing.T) { storage := genmocks.Storage{} storage.On("FindOrganization", "_id").Return(&model.Organization{ID: "_id"}, nil) diff --git a/core/app_administration.go b/core/app_administration.go index 0b92394c5..e1adf7eed 100644 --- a/core/app_administration.go +++ b/core/app_administration.go @@ -22,6 +22,8 @@ import ( "time" "github.com/rokwire/core-auth-library-go/v3/authorization" + "github.com/rokwire/core-auth-library-go/v3/authutils" + "github.com/rokwire/core-auth-library-go/v3/tokenauth" "github.com/google/uuid" "github.com/rokwire/logging-library-go/v2/errors" @@ -184,6 +186,113 @@ func (app *application) admGetTestModel() string { return "" } +func (app *application) admGetConfig(id string, claims *tokenauth.Claims) (*model.Config, error) { + config, err := app.storage.FindConfigByID(id) + if err != nil { + return nil, errors.WrapErrorAction(logutils.ActionFind, model.TypeConfig, nil, err) + } + if config == nil { + return nil, errors.ErrorData(logutils.StatusMissing, model.TypeConfig, &logutils.FieldArgs{"id": id}) + } + + err = claims.CanAccess(config.AppID, config.OrgID, config.System) + if err != nil { + return nil, errors.WrapErrorAction(logutils.ActionValidate, "config access", nil, err) + } + + return config, nil +} + +func (app *application) admGetConfigs(configType *string, claims *tokenauth.Claims) ([]model.Config, error) { + configs, err := app.storage.FindConfigs(configType) + if err != nil { + return nil, errors.WrapErrorAction(logutils.ActionFind, model.TypeConfig, nil, err) + } + + allowedConfigs := make([]model.Config, 0) + for _, config := range configs { + if err := claims.CanAccess(config.AppID, config.OrgID, config.System); err == nil { + allowedConfigs = append(allowedConfigs, config) + } + } + return allowedConfigs, nil +} + +func (app *application) admCreateConfig(config model.Config, claims *tokenauth.Claims) (*model.Config, error) { + // must be a system config if applying to all orgs + if config.OrgID == authutils.AllOrgs && !config.System { + return nil, errors.ErrorData(logutils.StatusInvalid, "config system status", &logutils.FieldArgs{"config.org_id": authutils.AllOrgs}) + } + + err := claims.CanAccess(config.AppID, config.OrgID, config.System) + if err != nil { + return nil, errors.WrapErrorAction(logutils.ActionValidate, "config access", nil, err) + } + + config.ID = uuid.NewString() + config.DateCreated = time.Now().UTC() + err = app.storage.InsertConfig(config) + if err != nil { + return nil, errors.WrapErrorAction(logutils.ActionInsert, model.TypeConfig, nil, err) + } + return &config, nil +} + +func (app *application) admUpdateConfig(config model.Config, claims *tokenauth.Claims) error { + // must be a system config if applying to all orgs + if config.OrgID == authutils.AllOrgs && !config.System { + return errors.ErrorData(logutils.StatusInvalid, "config system status", &logutils.FieldArgs{"config.org_id": authutils.AllOrgs}) + } + + oldConfig, err := app.storage.FindConfig(config.Type, config.AppID, config.OrgID) + if err != nil { + return errors.WrapErrorAction(logutils.ActionFind, model.TypeConfig, nil, err) + } + if oldConfig == nil { + return errors.ErrorData(logutils.StatusMissing, model.TypeConfig, &logutils.FieldArgs{"type": config.Type, "app_id": config.AppID, "org_id": config.OrgID}) + } + + // cannot update a system config if not a system admin + if !claims.System && oldConfig.System { + return errors.ErrorData(logutils.StatusInvalid, "system claim", nil) + } + err = claims.CanAccess(config.AppID, config.OrgID, config.System) + if err != nil { + return errors.WrapErrorAction(logutils.ActionValidate, "config access", nil, err) + } + + now := time.Now().UTC() + config.ID = oldConfig.ID + config.DateUpdated = &now + + err = app.storage.UpdateConfig(config) + if err != nil { + return errors.WrapErrorAction(logutils.ActionUpdate, model.TypeConfig, nil, err) + } + return nil +} + +func (app *application) admDeleteConfig(id string, claims *tokenauth.Claims) error { + config, err := app.storage.FindConfigByID(id) + if err != nil { + return errors.WrapErrorAction(logutils.ActionFind, model.TypeConfig, nil, err) + } + if config == nil { + return errors.ErrorData(logutils.StatusMissing, model.TypeConfig, &logutils.FieldArgs{"id": id}) + } + + err = claims.CanAccess(config.AppID, config.OrgID, config.System) + if err != nil { + return errors.WrapErrorAction(logutils.ActionValidate, "config access", nil, err) + } + + err = app.storage.DeleteConfig(id) + if err != nil { + return errors.WrapErrorAction(logutils.ActionDelete, model.TypeConfig, nil, err) + } + return nil +} + func (app *application) adminGetAppConfig(appTypeIdentifier string, orgID *string, versionNumbers model.VersionNumbers, apiKey *string) (*model.ApplicationConfig, error) { return app.sharedGetAppConfig(appTypeIdentifier, orgID, versionNumbers, apiKey, true) } @@ -443,7 +552,7 @@ func (app *application) admGetAppOrgGroups(appID string, orgID string) ([]model. //find application organization groups getAppOrgGroups, err := app.storage.FindAppOrgGroups(appOrg.ID) if err != nil { - return nil, errors.WrapErrorAction(logutils.ActionGet, model.TypeAppOrgGroup, nil, err) + return nil, errors.WrapErrorAction(logutils.ActionFind, model.TypeAppOrgGroup, nil, err) } return getAppOrgGroups, nil diff --git a/core/app_system.go b/core/app_system.go index b37204f1f..0d57328e7 100644 --- a/core/app_system.go +++ b/core/app_system.go @@ -24,60 +24,6 @@ import ( "github.com/rokwire/logging-library-go/v2/logutils" ) -func (app *application) sysCreateGlobalConfig(setting string) (*model.GlobalConfig, error) { - gc, err := app.storage.GetGlobalConfig() - if err != nil { - return nil, errors.WrapErrorAction(logutils.ActionFind, model.TypeGlobalConfig, nil, err) - } - if gc != nil { - return nil, errors.ErrorData("existing", model.TypeGlobalConfig, nil) - } - - gc = &model.GlobalConfig{Setting: setting} - err = app.storage.CreateGlobalConfig(nil, gc) - if err != nil { - return nil, errors.WrapErrorAction(logutils.ActionInsert, model.TypeGlobalConfig, nil, err) - } - return gc, nil -} - -func (app *application) sysGetGlobalConfig() (*model.GlobalConfig, error) { - gc, err := app.storage.GetGlobalConfig() - if err != nil { - return nil, errors.WrapErrorAction(logutils.ActionFind, model.TypeGlobalConfig, nil, err) - } - return gc, nil -} - -func (app *application) sysUpdateGlobalConfig(setting string) error { - gc, err := app.storage.GetGlobalConfig() - if err != nil { - return errors.WrapErrorAction(logutils.ActionFind, model.TypeGlobalConfig, nil, err) - } - if gc == nil { - return errors.WrapErrorData(logutils.StatusMissing, model.TypeGlobalConfig, nil, err) - } - - gc.Setting = setting - transaction := func(context storage.TransactionContext) error { - //1. clear the global config - we always keep only one global config - err := app.storage.DeleteGlobalConfig(context) - if err != nil { - return errors.WrapErrorAction(logutils.ActionDelete, model.TypeGlobalConfig, nil, err) - } - - //2. add the new one - err = app.storage.CreateGlobalConfig(context, gc) - if err != nil { - return errors.WrapErrorAction(logutils.ActionInsert, model.TypeGlobalConfig, nil, err) - } - - return nil - } - - return app.storage.PerformTransaction(transaction) -} - func (app *application) sysGetApplicationOrganizations(appID *string, orgID *string) ([]model.ApplicationOrganization, error) { return app.storage.FindApplicationOrganizations(appID, orgID) } diff --git a/core/auth/apis.go b/core/auth/apis.go index e135c8076..5d5261bae 100644 --- a/core/auth/apis.go +++ b/core/auth/apis.go @@ -39,7 +39,7 @@ func (a *Auth) Start() { storageListener := StorageListener{auth: a} a.storage.RegisterStorageListener(&storageListener) - go a.setupDeleteSessionsTimer() + go utils.StartTimer(a.deleteSessionsTimer, a.deleteSessionsTimerDone, time.Hour*time.Duration(sessionDeletePeriod), a.deleteSessions, "delete sessions", a.logger) } // GetHost returns the host/issuer of the auth service diff --git a/core/auth/auth.go b/core/auth/auth.go index 5a96424b7..77746ffa4 100644 --- a/core/auth/auth.go +++ b/core/auth/auth.go @@ -67,14 +67,17 @@ const ( refreshTokenLength int = 256 - sessionDeletePeriod int = 24 + sessionDeletePeriod int = 24 // hours maxSessionsDelete int = 250 + sessionIDRateLimit int = 5 + sessionIDRatePeriod int = 5 // minutes + loginStateLength int = 128 - loginStateDuration int = 5 + loginStateDuration int = 5 // minutes maxMfaAttempts int = 5 - mfaCodeExpiration int = 5 + mfaCodeExpiration int = 5 // minutes mfaCodeMax int = 1000000 ) @@ -113,9 +116,9 @@ type Auth struct { apiKeys *syncmap.Map //cache api keys / api_key (string) -> APIKey apiKeysLock *sync.RWMutex - //delete refresh tokens timer - deleteSessionsTimer *time.Timer - timerDone chan bool + //delete sessions timer + deleteSessionsTimer *time.Timer + deleteSessionsTimerDone chan bool } // NewAuth creates a new auth instance @@ -145,12 +148,12 @@ func NewAuth(serviceID string, host string, authPrivKey *keys.PrivKey, authServi apiKeys := &syncmap.Map{} apiKeysLock := &sync.RWMutex{} - timerDone := make(chan bool) + deleteSessionsTimerDone := make(chan bool) auth := &Auth{storage: storage, emailer: emailer, logger: logger, authTypes: authTypes, externalAuthTypes: externalAuthTypes, anonymousAuthTypes: anonymousAuthTypes, serviceAuthTypes: serviceAuthTypes, mfaTypes: mfaTypes, authPrivKey: authPrivKey, ServiceRegManager: nil, serviceID: serviceID, host: host, minTokenExp: *minTokenExp, maxTokenExp: *maxTokenExp, profileBB: profileBB, cachedIdentityProviders: cachedIdentityProviders, identityProvidersLock: identityProvidersLock, - timerDone: timerDone, emailDialer: emailDialer, emailFrom: smtpFrom, apiKeys: apiKeys, apiKeysLock: apiKeysLock} + apiKeys: apiKeys, apiKeysLock: apiKeysLock, deleteSessionsTimerDone: deleteSessionsTimerDone, emailDialer: emailDialer, emailFrom: smtpFrom} err := auth.storeCoreRegs() if err != nil { @@ -1107,7 +1110,6 @@ func (a *Auth) applyLogin(anonymous bool, sub string, authType model.AuthType, a var err error var loginSession *model.LoginSession - transaction := func(context storage.TransactionContext) error { ///1. assign device to session and account var device *model.Device @@ -2488,21 +2490,7 @@ func (a *Auth) getCachedAPIKeys() ([]model.APIKey, error) { return apiKeyList, err } -func (a *Auth) setupDeleteSessionsTimer() { - a.logger.Info("setupDeleteSessionsTimer") - - //cancel if active - if a.deleteSessionsTimer != nil { - a.timerDone <- true - a.deleteSessionsTimer.Stop() - } - - a.deleteSessions() -} - func (a *Auth) deleteSessions() { - a.logger.Info("deleteSessions") - // to delete: // - not completed MFA // - expired sessions @@ -2512,19 +2500,6 @@ func (a *Auth) deleteSessions() { //2. expired sessions a.deleteExpiredSessions() - - duration := time.Hour * time.Duration(sessionDeletePeriod) - a.deleteSessionsTimer = time.NewTimer(duration) - select { - case <-a.deleteSessionsTimer.C: - // timer expired - a.deleteSessionsTimer = nil - - a.deleteSessions() - case <-a.timerDone: - // timer aborted - a.deleteSessionsTimer = nil - } } func (a *Auth) deleteNotCompletedMFASessions() { diff --git a/core/interfaces.go b/core/interfaces.go index 5053e9dd7..71bfd5b2a 100644 --- a/core/interfaces.go +++ b/core/interfaces.go @@ -18,6 +18,7 @@ import ( "core-building-block/core/model" "core-building-block/driven/storage" + "github.com/rokwire/core-auth-library-go/v3/tokenauth" "github.com/rokwire/logging-library-go/v2/logs" ) @@ -46,6 +47,12 @@ type Administration interface { AdmGetTest() string AdmGetTestModel() string + AdmGetConfig(id string, claims *tokenauth.Claims) (*model.Config, error) + AdmGetConfigs(configType *string, claims *tokenauth.Claims) ([]model.Config, error) + AdmCreateConfig(config model.Config, claims *tokenauth.Claims) (*model.Config, error) + AdmUpdateConfig(config model.Config, claims *tokenauth.Claims) error + AdmDeleteConfig(id string, claims *tokenauth.Claims) error + AdmGetApplications(orgID string) ([]model.Application, error) AdmCreateAppOrgGroup(name string, description string, system bool, permissionNames []string, rolesIDs []string, accountIDs []string, appID string, orgID string, assignerPermissions []string, systemClaim bool, l *logs.Log) (*model.AppOrgGroup, error) @@ -111,10 +118,6 @@ type TPS interface { // System exposes system APIs for the driver adapters type System interface { - SysCreateGlobalConfig(setting string) (*model.GlobalConfig, error) - SysGetGlobalConfig() (*model.GlobalConfig, error) - SysUpdateGlobalConfig(setting string) error - SysGetApplicationOrganization(ID string) (*model.ApplicationOrganization, error) SysGetApplicationOrganizations(appID *string, orgID *string) ([]model.ApplicationOrganization, error) SysCreateApplicationOrganization(appID string, orgID string, appOrg model.ApplicationOrganization) (*model.ApplicationOrganization, error) @@ -182,9 +185,12 @@ type Storage interface { SaveDevice(context storage.TransactionContext, device *model.Device) error DeleteDevice(context storage.TransactionContext, id string) error - CreateGlobalConfig(context storage.TransactionContext, globalConfig *model.GlobalConfig) error - GetGlobalConfig() (*model.GlobalConfig, error) - DeleteGlobalConfig(context storage.TransactionContext) error + FindConfig(configType string, appID string, orgID string) (*model.Config, error) + FindConfigByID(id string) (*model.Config, error) + FindConfigs(configType *string) ([]model.Config, error) + InsertConfig(config model.Config) error + UpdateConfig(config model.Config) error + DeleteConfig(id string) error FindPermissionsByName(context storage.TransactionContext, names []string) ([]model.Permission, error) FindPermissionsByServiceIDs(serviceIDs []string) ([]model.Permission, error) diff --git a/core/mocks/Storage.go b/core/mocks/Storage.go index 682fbc7f9..ca39676b8 100644 --- a/core/mocks/Storage.go +++ b/core/mocks/Storage.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.21.4. DO NOT EDIT. +// Code generated by mockery v2.28.2. DO NOT EDIT. package mocks @@ -117,20 +117,6 @@ func (_m *Storage) CountGroupsByRoleID(roleID string) (*int64, error) { return r0, r1 } -// CreateGlobalConfig provides a mock function with given fields: context, globalConfig -func (_m *Storage) CreateGlobalConfig(context storage.TransactionContext, globalConfig *model.GlobalConfig) error { - ret := _m.Called(context, globalConfig) - - var r0 error - if rf, ok := ret.Get(0).(func(storage.TransactionContext, *model.GlobalConfig) error); ok { - r0 = rf(context, globalConfig) - } else { - r0 = ret.Error(0) - } - - return r0 -} - // DeleteAccountPermissions provides a mock function with given fields: context, accountID, permissionNames func (_m *Storage) DeleteAccountPermissions(context storage.TransactionContext, accountID string, permissionNames []string) error { ret := _m.Called(context, accountID, permissionNames) @@ -201,13 +187,13 @@ func (_m *Storage) DeleteAppOrgRole(id string) error { return r0 } -// DeleteDevice provides a mock function with given fields: context, id -func (_m *Storage) DeleteDevice(context storage.TransactionContext, id string) error { - ret := _m.Called(context, id) +// DeleteConfig provides a mock function with given fields: id +func (_m *Storage) DeleteConfig(id string) error { + ret := _m.Called(id) var r0 error - if rf, ok := ret.Get(0).(func(storage.TransactionContext, string) error); ok { - r0 = rf(context, id) + if rf, ok := ret.Get(0).(func(string) error); ok { + r0 = rf(id) } else { r0 = ret.Error(0) } @@ -215,13 +201,13 @@ func (_m *Storage) DeleteDevice(context storage.TransactionContext, id string) e return r0 } -// DeleteGlobalConfig provides a mock function with given fields: context -func (_m *Storage) DeleteGlobalConfig(context storage.TransactionContext) error { - ret := _m.Called(context) +// DeleteDevice provides a mock function with given fields: context, id +func (_m *Storage) DeleteDevice(context storage.TransactionContext, id string) error { + ret := _m.Called(context, id) var r0 error - if rf, ok := ret.Get(0).(func(storage.TransactionContext) error); ok { - r0 = rf(context) + if rf, ok := ret.Get(0).(func(storage.TransactionContext, string) error); ok { + r0 = rf(context, id) } else { r0 = ret.Error(0) } @@ -869,6 +855,84 @@ func (_m *Storage) FindAuthTypes() ([]model.AuthType, error) { return r0, r1 } +// FindConfig provides a mock function with given fields: configType, appID, orgID +func (_m *Storage) FindConfig(configType string, appID string, orgID string) (*model.Config, error) { + ret := _m.Called(configType, appID, orgID) + + var r0 *model.Config + var r1 error + if rf, ok := ret.Get(0).(func(string, string, string) (*model.Config, error)); ok { + return rf(configType, appID, orgID) + } + if rf, ok := ret.Get(0).(func(string, string, string) *model.Config); ok { + r0 = rf(configType, appID, orgID) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*model.Config) + } + } + + if rf, ok := ret.Get(1).(func(string, string, string) error); ok { + r1 = rf(configType, appID, orgID) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// FindConfigByID provides a mock function with given fields: id +func (_m *Storage) FindConfigByID(id string) (*model.Config, error) { + ret := _m.Called(id) + + var r0 *model.Config + var r1 error + if rf, ok := ret.Get(0).(func(string) (*model.Config, error)); ok { + return rf(id) + } + if rf, ok := ret.Get(0).(func(string) *model.Config); ok { + r0 = rf(id) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*model.Config) + } + } + + if rf, ok := ret.Get(1).(func(string) error); ok { + r1 = rf(id) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// FindConfigs provides a mock function with given fields: configType +func (_m *Storage) FindConfigs(configType *string) ([]model.Config, error) { + ret := _m.Called(configType) + + var r0 []model.Config + var r1 error + if rf, ok := ret.Get(0).(func(*string) ([]model.Config, error)); ok { + return rf(configType) + } + if rf, ok := ret.Get(0).(func(*string) []model.Config); ok { + r0 = rf(configType) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).([]model.Config) + } + } + + if rf, ok := ret.Get(1).(func(*string) error); ok { + r1 = rf(configType) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + // FindLoginSessionsByParams provides a mock function with given fields: appID, orgID, sessionID, identifier, accountAuthTypeIdentifier, appTypeID, appTypeIdentifier, anonymous, deviceID, ipAddress func (_m *Storage) FindLoginSessionsByParams(appID string, orgID string, sessionID *string, identifier *string, accountAuthTypeIdentifier *string, appTypeID *string, appTypeIdentifier *string, anonymous *bool, deviceID *string, ipAddress *string) ([]model.LoginSession, error) { ret := _m.Called(appID, orgID, sessionID, identifier, accountAuthTypeIdentifier, appTypeID, appTypeIdentifier, anonymous, deviceID, ipAddress) @@ -1025,32 +1089,6 @@ func (_m *Storage) FindSystemOrganization() (*model.Organization, error) { return r0, r1 } -// GetGlobalConfig provides a mock function with given fields: -func (_m *Storage) GetGlobalConfig() (*model.GlobalConfig, error) { - ret := _m.Called() - - var r0 *model.GlobalConfig - var r1 error - if rf, ok := ret.Get(0).(func() (*model.GlobalConfig, error)); ok { - return rf() - } - if rf, ok := ret.Get(0).(func() *model.GlobalConfig); ok { - r0 = rf() - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(*model.GlobalConfig) - } - } - - if rf, ok := ret.Get(1).(func() error); ok { - r1 = rf() - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - // InsertAPIKey provides a mock function with given fields: context, apiKey func (_m *Storage) InsertAPIKey(context storage.TransactionContext, apiKey model.APIKey) (*model.APIKey, error) { ret := _m.Called(context, apiKey) @@ -1265,6 +1303,20 @@ func (_m *Storage) InsertAuthType(context storage.TransactionContext, authType m return r0, r1 } +// InsertConfig provides a mock function with given fields: config +func (_m *Storage) InsertConfig(config model.Config) error { + ret := _m.Called(config) + + var r0 error + if rf, ok := ret.Get(0).(func(model.Config) error); ok { + r0 = rf(config) + } else { + r0 = ret.Error(0) + } + + return r0 +} + // InsertOrganization provides a mock function with given fields: context, organization func (_m *Storage) InsertOrganization(context storage.TransactionContext, organization model.Organization) (*model.Organization, error) { ret := _m.Called(context, organization) @@ -1492,6 +1544,20 @@ func (_m *Storage) UpdateAuthTypes(ID string, code string, description string, i return r0 } +// UpdateConfig provides a mock function with given fields: config +func (_m *Storage) UpdateConfig(config model.Config) error { + ret := _m.Called(config) + + var r0 error + if rf, ok := ret.Get(0).(func(model.Config) error); ok { + r0 = rf(config) + } else { + r0 = ret.Error(0) + } + + return r0 +} + // UpdateOrganization provides a mock function with given fields: ID, name, requestType, organizationDomains func (_m *Storage) UpdateOrganization(ID string, name string, requestType string, organizationDomains []string) error { ret := _m.Called(ID, name, requestType, organizationDomains) diff --git a/core/model/config.go b/core/model/config.go index 2db9f2a35..b6041236b 100644 --- a/core/model/config.go +++ b/core/model/config.go @@ -18,23 +18,53 @@ import ( "fmt" "time" + "github.com/rokwire/logging-library-go/v2/errors" "github.com/rokwire/logging-library-go/v2/logutils" ) const ( - //TypeGlobalConfig ... - TypeGlobalConfig logutils.MessageDataType = "global config" + // TypeConfig configs type + TypeConfig logutils.MessageDataType = "config" + // TypeConfigData config data type + TypeConfigData logutils.MessageDataType = "config data" + // TypeEnvConfigData env configs type + TypeEnvConfigData logutils.MessageDataType = "env config data" //TypeOrganizationConfig ... TypeOrganizationConfig logutils.MessageDataType = "org config" + + // ConfigTypeEnv is the Config type for EnvConfigData + ConfigTypeEnv string = "env" ) -// GlobalConfig represents global config for the system -type GlobalConfig struct { - Setting string +// Config contains generic configs +type Config struct { + ID string `bson:"_id"` + Type string `bson:"type"` + AppID string `bson:"app_id"` + OrgID string `bson:"org_id"` + System bool `bson:"system"` + Data interface{} `bson:"data"` + DateCreated time.Time `bson:"date_created"` + DateUpdated *time.Time `bson:"date_updated"` +} + +// EnvConfigData contains environment configs for this service +type EnvConfigData struct { + CORSAllowedOrigins []string `json:"cors_allowed_origins" bson:"cors_allowed_origins"` + CORSAllowedHeaders []string `json:"cors_allowed_headers" bson:"cors_allowed_headers"` +} + +// GetConfigData returns a pointer to the given config's Data as the given type T +func GetConfigData[T ConfigData](c Config) (*T, error) { + if data, ok := c.Data.(T); ok { + return &data, nil + } + return nil, errors.ErrorData(logutils.StatusInvalid, TypeConfigData, &logutils.FieldArgs{"type": c.Type}) } -func (gc GlobalConfig) String() string { - return fmt.Sprintf("[setting:%s]", gc.Setting) +// ConfigData represents any set of data that may be stored in a config +type ConfigData interface { + EnvConfigData | map[string]interface{} } // OrganizationConfig represents configuration for an organization @@ -51,5 +81,5 @@ type OrganizationConfig struct { } func (cc OrganizationConfig) String() string { - return fmt.Sprintf("[ID:%s\tSetting:%s\tDomains:%s\tCustom:%s]", cc.ID, cc.Setting, cc.Domains, cc.Custom) + return fmt.Sprintf("[ID:%s\tSetting:%s\tDomains:%s\tCustom:%v]", cc.ID, cc.Setting, cc.Domains, cc.Custom) } diff --git a/driven/storage/adapter.go b/driven/storage/adapter.go index 52f7c784f..c498d8015 100644 --- a/driven/storage/adapter.go +++ b/driven/storage/adapter.go @@ -21,6 +21,7 @@ import ( "fmt" "reflect" "strconv" + "strings" "sync" "time" @@ -61,6 +62,9 @@ type Adapter struct { cachedApplicationConfigs *syncmap.Map applicationConfigsLock *sync.RWMutex + + cachedConfigs *syncmap.Map + configsLock *sync.RWMutex } // Start starts the storage @@ -111,6 +115,12 @@ func (sa *Adapter) Start() error { return errors.WrapErrorAction(logutils.ActionCache, model.TypeApplicationConfig, nil, err) } + // cache configs + err = sa.cacheConfigs() + if err != nil { + return errors.WrapErrorAction(logutils.ActionCache, model.TypeConfig, nil, err) + } + return err } @@ -697,6 +707,113 @@ func (sa *Adapter) getCachedApplicationConfigByID(id string) (*model.Application return nil, errors.ErrorData(logutils.StatusMissing, model.TypeApplicationConfig, errArgs) } +// cacheConfigs caches the configs from the DB +func (sa *Adapter) cacheConfigs() error { + sa.db.logger.Info("cacheConfigs...") + + configs, err := sa.loadConfigs() + if err != nil { + return errors.WrapErrorAction(logutils.ActionLoad, model.TypeConfig, nil, err) + } + + sa.setCachedConfigs(configs) + + return nil +} + +func (sa *Adapter) setCachedConfigs(configs []model.Config) { + sa.configsLock.Lock() + defer sa.configsLock.Unlock() + + sa.cachedConfigs = &syncmap.Map{} + + for _, config := range configs { + var err error + switch config.Type { + case model.ConfigTypeEnv: + err = parseConfigsData[model.EnvConfigData](&config) + default: + err = parseConfigsData[map[string]interface{}](&config) + } + if err != nil { + sa.db.logger.Warn(err.Error()) + } + sa.cachedConfigs.Store(config.ID, config) + sa.cachedConfigs.Store(fmt.Sprintf("%s_%s_%s", config.Type, config.AppID, config.OrgID), config) + } +} + +func parseConfigsData[T model.ConfigData](config *model.Config) error { + bsonBytes, err := bson.Marshal(config.Data) + if err != nil { + return errors.WrapErrorAction(logutils.ActionUnmarshal, model.TypeConfig, nil, err) + } + + var data T + err = bson.Unmarshal(bsonBytes, &data) + if err != nil { + return errors.WrapErrorAction(logutils.ActionUnmarshal, model.TypeConfigData, &logutils.FieldArgs{"type": config.Type}, err) + } + + config.Data = data + return nil +} + +func (sa *Adapter) getCachedConfig(id string, configType string, appID string, orgID string) (*model.Config, error) { + sa.configsLock.RLock() + defer sa.configsLock.RUnlock() + + var item any + var errArgs logutils.FieldArgs + if id != "" { + errArgs = logutils.FieldArgs{"id": id} + item, _ = sa.cachedConfigs.Load(id) + } else { + errArgs = logutils.FieldArgs{"type": configType, "app_id": appID, "org_id": orgID} + item, _ = sa.cachedConfigs.Load(fmt.Sprintf("%s_%s_%s", configType, appID, orgID)) + } + + if item != nil { + config, ok := item.(model.Config) + if !ok { + return nil, errors.ErrorAction(logutils.ActionCast, model.TypeConfig, &errArgs) + } + return &config, nil + } + return nil, nil +} + +func (sa *Adapter) getCachedConfigs(configType *string) ([]model.Config, error) { + sa.configsLock.RLock() + defer sa.configsLock.RUnlock() + + var err error + configList := make([]model.Config, 0) + sa.cachedConfigs.Range(func(key, item interface{}) bool { + keyStr, ok := key.(string) + if !ok || item == nil { + return false + } + if !strings.Contains(keyStr, "_") { + return true + } + + config, ok := item.(model.Config) + if !ok { + err = errors.ErrorAction(logutils.ActionCast, model.TypeConfig, &logutils.FieldArgs{"key": key}) + return false + } + + if configType == nil || strings.HasPrefix(keyStr, fmt.Sprintf("%s_", *configType)) { + configList = append(configList, config) + } + + return true + }) + + return configList, err +} + // loadAuthTypes loads all auth types func (sa *Adapter) loadAuthTypes() ([]model.AuthType, error) { filter := bson.D{} @@ -2943,42 +3060,71 @@ func (sa *Adapter) FindProfiles(appID string, authTypeID string, accountAuthType return result, nil } -// CreateGlobalConfig creates global config -func (sa *Adapter) CreateGlobalConfig(context TransactionContext, globalConfig *model.GlobalConfig) error { - if globalConfig == nil { - return errors.ErrorData(logutils.StatusInvalid, logutils.TypeArg, logutils.StringArgs("global_config")) +// loadConfigs loads configs +func (sa *Adapter) loadConfigs() ([]model.Config, error) { + filter := bson.M{} + + var configs []model.Config + err := sa.db.configs.Find(filter, &configs, nil) + if err != nil { + return nil, errors.WrapErrorAction(logutils.ActionFind, model.TypeConfig, nil, err) } - _, err := sa.db.globalConfig.InsertOneWithContext(context, globalConfig) + return configs, nil +} + +// FindConfig finds the config for the specified type, appID, and orgID +func (sa *Adapter) FindConfig(configType string, appID string, orgID string) (*model.Config, error) { + return sa.getCachedConfig("", configType, appID, orgID) +} + +// FindConfigByID finds the config for the specified ID +func (sa *Adapter) FindConfigByID(id string) (*model.Config, error) { + return sa.getCachedConfig(id, "", "", "") +} + +// FindConfigs finds all configs for the specified type +func (sa *Adapter) FindConfigs(configType *string) ([]model.Config, error) { + return sa.getCachedConfigs(configType) +} + +// InsertConfig inserts a new config +func (sa *Adapter) InsertConfig(config model.Config) error { + _, err := sa.db.configs.InsertOne(config) if err != nil { - return errors.WrapErrorAction(logutils.ActionInsert, model.TypeGlobalConfig, &logutils.FieldArgs{"setting": globalConfig.Setting}, err) + return errors.WrapErrorAction(logutils.ActionInsert, model.TypeConfig, nil, err) } return nil } -// GetGlobalConfig give config -func (sa *Adapter) GetGlobalConfig() (*model.GlobalConfig, error) { - filter := bson.D{} - var result []model.GlobalConfig - err := sa.db.globalConfig.Find(filter, &result, nil) - if err != nil { - return nil, errors.WrapErrorAction(logutils.ActionFind, model.TypeGlobalConfig, nil, err) +// UpdateConfig updates an existing config +func (sa *Adapter) UpdateConfig(config model.Config) error { + filter := bson.M{"_id": config.ID} + update := bson.D{ + primitive.E{Key: "$set", Value: bson.D{ + primitive.E{Key: "type", Value: config.Type}, + primitive.E{Key: "app_id", Value: config.AppID}, + primitive.E{Key: "org_id", Value: config.OrgID}, + primitive.E{Key: "system", Value: config.System}, + primitive.E{Key: "data", Value: config.Data}, + primitive.E{Key: "date_updated", Value: config.DateUpdated}, + }}, } - if len(result) == 0 { - //no record - return nil, nil + _, err := sa.db.configs.UpdateOne(filter, update, nil) + if err != nil { + return errors.WrapErrorAction(logutils.ActionUpdate, model.TypeConfig, &logutils.FieldArgs{"id": config.ID}, err) } - return &result[0], nil + return nil } -// DeleteGlobalConfig deletes the global configuration from storage -func (sa *Adapter) DeleteGlobalConfig(context TransactionContext) error { - delFilter := bson.D{} - _, err := sa.db.globalConfig.DeleteManyWithContext(context, delFilter, nil) +// DeleteConfig deletes a configuration from storage +func (sa *Adapter) DeleteConfig(id string) error { + delFilter := bson.M{"_id": id} + _, err := sa.db.configs.DeleteMany(delFilter, nil) if err != nil { - return errors.WrapErrorAction(logutils.ActionDelete, model.TypeGlobalConfig, nil, err) + return errors.WrapErrorAction(logutils.ActionDelete, model.TypeConfig, &logutils.FieldArgs{"id": id}, err) } return nil @@ -3799,12 +3945,17 @@ func NewStorageAdapter(host string, mongoDBAuth string, mongoDBName string, mong cachedApplicationConfigs := &syncmap.Map{} applicationConfigsLock := &sync.RWMutex{} + cachedConfigs := &syncmap.Map{} + configsLock := &sync.RWMutex{} + db := &database{mongoDBAuth: mongoDBAuth, mongoDBName: mongoDBName, mongoTimeout: timeout, logger: logger} return &Adapter{db: db, logger: logger, host: host, cachedServiceRegs: cachedServiceRegs, serviceRegsLock: serviceRegsLock, cachedOrganizations: cachedOrganizations, organizationsLock: organizationsLock, cachedApplications: cachedApplications, applicationsLock: applicationsLock, cachedAuthTypes: cachedAuthTypes, authTypesLock: authTypesLock, - cachedApplicationsOrganizations: cachedApplicationsOrganizations, applicationsOrganizationsLock: applicationsOrganizationsLock, cachedApplicationConfigs: cachedApplicationConfigs, applicationConfigsLock: applicationConfigsLock} + cachedApplicationsOrganizations: cachedApplicationsOrganizations, applicationsOrganizationsLock: applicationsOrganizationsLock, + cachedApplicationConfigs: cachedApplicationConfigs, applicationConfigsLock: applicationConfigsLock, + cachedConfigs: cachedConfigs, configsLock: configsLock} } type storageListener struct { @@ -3839,6 +3990,10 @@ func (sl *storageListener) OnApplicationConfigsUpdated() { sl.adapter.cacheApplicationConfigs() } +func (sl *storageListener) OnConfigsUpdated() { + sl.adapter.cacheConfigs() +} + // Listener represents storage listener type Listener interface { OnAPIKeysUpdated() @@ -3849,6 +4004,7 @@ type Listener interface { OnApplicationsUpdated() OnApplicationsOrganizationsUpdated() OnApplicationConfigsUpdated() + OnConfigsUpdated() } // DefaultListenerImpl default listener implementation @@ -3878,6 +4034,9 @@ func (d *DefaultListenerImpl) OnApplicationsOrganizationsUpdated() {} // OnApplicationConfigsUpdated notifies application configs have been updated func (d *DefaultListenerImpl) OnApplicationConfigsUpdated() {} +// OnConfigsUpdated notifies configs have been updated +func (d *DefaultListenerImpl) OnConfigsUpdated() {} + // TransactionContext wraps mongo.SessionContext for use by external packages type TransactionContext interface { mongo.SessionContext diff --git a/driven/storage/database.go b/driven/storage/database.go index 447f1a571..caa241637 100644 --- a/driven/storage/database.go +++ b/driven/storage/database.go @@ -42,7 +42,7 @@ type database struct { devices *collectionWrapper credentials *collectionWrapper loginsSessions *collectionWrapper - globalConfig *collectionWrapper + configs *collectionWrapper serviceRegs *collectionWrapper serviceRegistrations *collectionWrapper serviceAccounts *collectionWrapper @@ -141,8 +141,8 @@ func (m *database) start() error { return err } - globalConfig := &collectionWrapper{database: m, coll: db.Collection("global_config")} - err = m.applyGlobalConfigChecks(globalConfig) + configs := &collectionWrapper{database: m, coll: db.Collection("configs")} + err = m.applyConfigsChecks(configs) if err != nil { return err } @@ -205,7 +205,7 @@ func (m *database) start() error { m.devices = devices m.credentials = credentials m.loginsSessions = loginsSessions - m.globalConfig = globalConfig + m.configs = configs m.apiKeys = apiKeys m.serviceRegs = serviceRegs m.serviceRegistrations = serviceRegistrations @@ -227,6 +227,7 @@ func (m *database) start() error { go m.applications.Watch(nil, m.logger) go m.applicationsOrganizations.Watch(nil, m.logger) go m.applicationConfigs.Watch(nil, m.logger) + go m.configs.Watch(nil, m.logger) m.listeners = []Listener{} @@ -341,10 +342,15 @@ func (m *database) applyAPIKeysChecks(apiKeys *collectionWrapper) error { return nil } -func (m *database) applyGlobalConfigChecks(configs *collectionWrapper) error { - m.logger.Info("apply global config checks.....") +func (m *database) applyConfigsChecks(configs *collectionWrapper) error { + m.logger.Info("apply configs checks.....") - m.logger.Info("global config checks passed") + err := configs.AddIndex(bson.D{primitive.E{Key: "type", Value: 1}, primitive.E{Key: "app_id", Value: 1}, primitive.E{Key: "org_id", Value: 1}}, true) + if err != nil { + return err + } + + m.logger.Info("configs checks passed") return nil } @@ -609,5 +615,11 @@ func (m *database) onDataChanged(changeDoc map[string]interface{}) { for _, listener := range m.listeners { go listener.OnApplicationConfigsUpdated() } + case "configs": + m.logger.Info("configs collection changed") + + for _, listener := range m.listeners { + go listener.OnConfigsUpdated() + } } } diff --git a/driver/web/adapter.go b/driver/web/adapter.go index df273b210..86c3f5b8c 100644 --- a/driver/web/adapter.go +++ b/driver/web/adapter.go @@ -37,6 +37,7 @@ import ( "github.com/rokwire/core-auth-library-go/v3/authservice" "github.com/rokwire/core-auth-library-go/v3/tokenauth" + "github.com/rokwire/core-auth-library-go/v3/webauth" httpSwagger "github.com/swaggo/http-swagger" ) @@ -67,6 +68,9 @@ type Adapter struct { systemApisHandler SystemApisHandler coreAPIs *core.APIs + + corsAllowedOrigins []string + corsAllowedHeaders []string } type handlerFunc = func(*logs.Log, *http.Request, *tokenauth.Claims) logs.HTTPResponse @@ -153,6 +157,12 @@ func (we Adapter) Start() { adminSubrouter.HandleFunc("/auth/verify-mfa", we.wrapFunc(we.adminApisHandler.verifyMFA, we.auth.admin.User)).Methods("POST") adminSubrouter.HandleFunc("/auth/app-token", we.wrapFunc(we.adminApisHandler.getAppToken, we.auth.admin.User)).Methods("GET") + adminSubrouter.HandleFunc("/configs/{id}", we.wrapFunc(we.adminApisHandler.getConfig, we.auth.admin.Permissions)).Methods("GET") + adminSubrouter.HandleFunc("/configs", we.wrapFunc(we.adminApisHandler.getConfigs, we.auth.admin.Permissions)).Methods("GET") + adminSubrouter.HandleFunc("/configs", we.wrapFunc(we.adminApisHandler.createConfig, we.auth.admin.Permissions)).Methods("POST") + adminSubrouter.HandleFunc("/configs/{id}", we.wrapFunc(we.adminApisHandler.updateConfig, we.auth.admin.Permissions)).Methods("PUT") + adminSubrouter.HandleFunc("/configs/{id}", we.wrapFunc(we.adminApisHandler.deleteConfig, we.auth.admin.Permissions)).Methods("DELETE") + adminSubrouter.HandleFunc("/account", we.wrapFunc(we.adminApisHandler.getAccount, we.auth.admin.User)).Methods("GET") adminSubrouter.HandleFunc("/account/mfa", we.wrapFunc(we.adminApisHandler.getMFATypes, we.auth.admin.User)).Methods("GET") adminSubrouter.HandleFunc("/account/mfa", we.wrapFunc(we.adminApisHandler.addMFAType, we.auth.admin.Authenticated)).Methods("POST") @@ -235,10 +245,6 @@ func (we Adapter) Start() { systemSubrouter.HandleFunc("/auth/app-org-token", we.wrapFunc(we.systemApisHandler.getAppOrgToken, we.auth.system.User)).Methods("GET") - systemSubrouter.HandleFunc("/global-config", we.wrapFunc(we.systemApisHandler.createGlobalConfig, we.auth.system.Permissions)).Methods("POST") - systemSubrouter.HandleFunc("/global-config", we.wrapFunc(we.systemApisHandler.getGlobalConfig, we.auth.system.Permissions)).Methods("GET") - systemSubrouter.HandleFunc("/global-config", we.wrapFunc(we.systemApisHandler.updateGlobalConfig, we.auth.system.Permissions)).Methods("PUT") - systemSubrouter.HandleFunc("/organizations", we.wrapFunc(we.systemApisHandler.createOrganization, we.auth.system.Permissions)).Methods("POST") systemSubrouter.HandleFunc("/organizations/{id}", we.wrapFunc(we.systemApisHandler.updateOrganization, we.auth.system.Permissions)).Methods("PUT") systemSubrouter.HandleFunc("/organizations/{id}", we.wrapFunc(we.systemApisHandler.getOrganization, we.auth.system.Permissions)).Methods("GET") @@ -287,7 +293,11 @@ func (we Adapter) Start() { systemSubrouter.HandleFunc("/auth-types/{id}", we.wrapFunc(we.systemApisHandler.updateAuthTypes, we.auth.system.Permissions)).Methods("PUT") /// - err := http.ListenAndServe(":"+we.port, router) + var handler http.Handler = router + if len(we.corsAllowedOrigins) > 0 { + handler = webauth.SetupCORS(we.corsAllowedOrigins, we.corsAllowedHeaders, router) + } + err := http.ListenAndServe(":"+we.port, handler) if err != nil { we.logger.Fatalf("error on listen and server - %s", err.Error()) } @@ -521,7 +531,8 @@ func (we Adapter) completeResponse(w http.ResponseWriter, response logs.HTTPResp } // NewWebAdapter creates new WebAdapter instance -func NewWebAdapter(env string, serviceRegManager *authservice.ServiceRegManager, port string, coreAPIs *core.APIs, host string, baseServerURL string, prodServerURL string, testServerURL string, devServerURL string, logger *logs.Logger) Adapter { +func NewWebAdapter(env string, serviceRegManager *authservice.ServiceRegManager, port string, coreAPIs *core.APIs, host string, corsAllowedOrigins []string, + corsAllowedHeaders []string, baseServerURL string, prodServerURL string, testServerURL string, devServerURL string, logger *logs.Logger) Adapter { //openAPI doc loader := &openapi3.Loader{Context: context.Background(), IsExternalRefsAllowed: true} // doc, err := loader.LoadFromFile("driver/web/docs/gen/def.yaml") @@ -571,7 +582,8 @@ func NewWebAdapter(env string, serviceRegManager *authservice.ServiceRegManager, systemApisHandler := NewSystemApisHandler(coreAPIs) return Adapter{env: env, port: port, productionServerURL: prodServerURL, testServerURL: testServerURL, developmentServerURL: devServerURL, cachedYamlDoc: yamlDoc, openAPIRouter: openAPIRouter, host: host, auth: auth, logger: logger, defaultApisHandler: defaultApisHandler, servicesApisHandler: servicesApisHandler, adminApisHandler: adminApisHandler, - encApisHandler: encApisHandler, bbsApisHandler: bbsApisHandler, tpsApisHandler: tpsApisHandler, systemApisHandler: systemApisHandler, coreAPIs: coreAPIs} + encApisHandler: encApisHandler, bbsApisHandler: bbsApisHandler, tpsApisHandler: tpsApisHandler, systemApisHandler: systemApisHandler, coreAPIs: coreAPIs, + corsAllowedOrigins: corsAllowedOrigins, corsAllowedHeaders: corsAllowedHeaders} } // AppListener implements core.ApplicationListener interface diff --git a/driver/web/apis_admin.go b/driver/web/apis_admin.go index 946e92ad6..950d5a48e 100644 --- a/driver/web/apis_admin.go +++ b/driver/web/apis_admin.go @@ -217,7 +217,6 @@ func (h AdminApisHandler) refresh(l *logs.Log, r *http.Request, claims *tokenaut } if loginSession == nil { //if login session is null then unauthorized - l.Infof("trying to refresh - %s", requestData.RefreshToken) return l.HTTPResponseError(http.StatusText(http.StatusUnauthorized), nil, http.StatusUnauthorized, true) } @@ -240,6 +239,132 @@ func (h AdminApisHandler) refresh(l *logs.Log, r *http.Request, claims *tokenaut return l.HTTPResponseSuccessJSON(respData) } +// getConfig gets config by id +func (h AdminApisHandler) getConfig(l *logs.Log, r *http.Request, claims *tokenauth.Claims) logs.HTTPResponse { + params := mux.Vars(r) + id := params["id"] + if len(id) <= 0 { + return l.HTTPResponseErrorData(logutils.StatusMissing, logutils.TypePathParam, logutils.StringArgs("id"), nil, http.StatusBadRequest, false) + } + + config, err := h.coreAPIs.Administration.AdmGetConfig(id, claims) + if err != nil { + return l.HTTPResponseErrorAction(logutils.ActionGet, model.TypeConfig, nil, err, http.StatusInternalServerError, true) + } + if config == nil { + return l.HTTPResponseErrorData(logutils.StatusMissing, model.TypeConfig, &logutils.FieldArgs{"id": id}, nil, http.StatusNotFound, true) + } + + configRes, err := configToDef(*config) + if err != nil { + return l.HTTPResponseErrorAction(logutils.ActionCast, "config response", nil, err, http.StatusInternalServerError, false) + } + data, err := json.Marshal(configRes) + if err != nil { + return l.HTTPResponseErrorAction(logutils.ActionMarshal, model.TypeConfig, nil, err, http.StatusInternalServerError, false) + } + + return l.HTTPResponseSuccessJSON(data) +} + +// getConfig gets configs by type +func (h AdminApisHandler) getConfigs(l *logs.Log, r *http.Request, claims *tokenauth.Claims) logs.HTTPResponse { + var configType *string + typeParam := r.URL.Query().Get("type") + if len(typeParam) > 0 { + configType = &typeParam + } + + configs, err := h.coreAPIs.Administration.AdmGetConfigs(configType, claims) + if err != nil { + return l.HTTPResponseErrorAction(logutils.ActionGet, model.TypeConfig, nil, err, http.StatusInternalServerError, true) + } + + configRes, err := configsToDef(configs) + if err != nil { + return l.HTTPResponseErrorAction(logutils.ActionCast, "configs response", nil, err, http.StatusInternalServerError, false) + } + data, err := json.Marshal(configRes) + if err != nil { + return l.HTTPResponseErrorAction(logutils.ActionMarshal, model.TypeConfig, nil, err, http.StatusInternalServerError, false) + } + + return l.HTTPResponseSuccessJSON(data) +} + +// createConfig creates a config by id +func (h AdminApisHandler) createConfig(l *logs.Log, r *http.Request, claims *tokenauth.Claims) logs.HTTPResponse { + var requestData Def.AdminReqCreateUpdateConfig + err := json.NewDecoder(r.Body).Decode(&requestData) + if err != nil { + return l.HTTPResponseErrorAction(logutils.ActionUnmarshal, logutils.TypeRequestBody, nil, err, http.StatusBadRequest, true) + } + + config, err := configFromDef(requestData, claims) + if err != nil { + return l.HTTPResponseErrorAction(logutils.ActionCast, model.TypeConfig, nil, err, http.StatusInternalServerError, false) + } + + newConfig, err := h.coreAPIs.Administration.AdmCreateConfig(*config, claims) + if err != nil { + return l.HTTPResponseErrorAction(logutils.ActionCreate, model.TypeConfig, nil, err, http.StatusInternalServerError, true) + } + + configRes, err := configToDef(*newConfig) + if err != nil { + return l.HTTPResponseErrorAction(logutils.ActionCast, "config response", nil, err, http.StatusInternalServerError, false) + } + data, err := json.Marshal(configRes) + if err != nil { + return l.HTTPResponseErrorAction(logutils.ActionMarshal, model.TypeConfig, nil, err, http.StatusInternalServerError, false) + } + + return l.HTTPResponseSuccessJSON(data) +} + +// updateConfig updates a config by id +func (h AdminApisHandler) updateConfig(l *logs.Log, r *http.Request, claims *tokenauth.Claims) logs.HTTPResponse { + params := mux.Vars(r) + id := params["id"] + if len(id) <= 0 { + return l.HTTPResponseErrorData(logutils.StatusMissing, logutils.TypePathParam, logutils.StringArgs("id"), nil, http.StatusBadRequest, false) + } + + var requestData Def.AdminReqCreateUpdateConfig + err := json.NewDecoder(r.Body).Decode(&requestData) + if err != nil { + return l.HTTPResponseErrorAction(logutils.ActionUnmarshal, logutils.TypeRequestBody, nil, err, http.StatusBadRequest, true) + } + + config, err := configFromDef(requestData, claims) + if err != nil { + return l.HTTPResponseErrorAction(logutils.ActionCast, model.TypeConfig, nil, err, http.StatusInternalServerError, false) + } + + err = h.coreAPIs.Administration.AdmUpdateConfig(*config, claims) + if err != nil { + return l.HTTPResponseErrorAction(logutils.ActionUpdate, model.TypeConfig, nil, err, http.StatusInternalServerError, true) + } + + return l.HTTPResponseSuccess() +} + +// deleteConfig deletes a config by id +func (h AdminApisHandler) deleteConfig(l *logs.Log, r *http.Request, claims *tokenauth.Claims) logs.HTTPResponse { + params := mux.Vars(r) + id := params["id"] + if len(id) <= 0 { + return l.HTTPResponseErrorData(logutils.StatusMissing, logutils.TypePathParam, logutils.StringArgs("id"), nil, http.StatusBadRequest, false) + } + + err := h.coreAPIs.Administration.AdmDeleteConfig(id, claims) + if err != nil { + return l.HTTPResponseErrorAction(logutils.ActionDelete, model.TypeConfig, nil, err, http.StatusInternalServerError, true) + } + + return l.HTTPResponseSuccess() +} + func (h AdminApisHandler) getAppConfigs(l *logs.Log, r *http.Request, claims *tokenauth.Claims) logs.HTTPResponse { data, err := ioutil.ReadAll(r.Body) if err != nil { diff --git a/driver/web/apis_services.go b/driver/web/apis_services.go index 668fb8dc6..d7b4eae54 100644 --- a/driver/web/apis_services.go +++ b/driver/web/apis_services.go @@ -170,7 +170,6 @@ func (h ServicesApisHandler) refresh(l *logs.Log, r *http.Request, claims *token } if loginSession == nil { //if login session is null then unauthorized - l.Infof("trying to refresh - %s", requestData.RefreshToken) return l.HTTPResponseError(http.StatusText(http.StatusUnauthorized), nil, http.StatusUnauthorized, true) } diff --git a/driver/web/apis_system.go b/driver/web/apis_system.go index 597be02ce..67e06e24d 100644 --- a/driver/web/apis_system.go +++ b/driver/web/apis_system.go @@ -60,69 +60,6 @@ func (h SystemApisHandler) getAppOrgToken(l *logs.Log, r *http.Request, claims * return l.HTTPResponseSuccessJSON(responseJSON) } -// createGlobalConfig creates a global config -func (h SystemApisHandler) createGlobalConfig(l *logs.Log, r *http.Request, claims *tokenauth.Claims) logs.HTTPResponse { - data, err := ioutil.ReadAll(r.Body) - if err != nil { - return l.HTTPResponseErrorAction(logutils.ActionRead, logutils.TypeRequestBody, nil, err, http.StatusBadRequest, false) - } - - var requestData Def.GlobalConfig - err = json.Unmarshal(data, &requestData) - if err != nil { - return l.HTTPResponseErrorAction(logutils.ActionUnmarshal, model.TypeGlobalConfig, nil, err, http.StatusBadRequest, true) - } - - _, err = h.coreAPIs.System.SysCreateGlobalConfig(requestData.Setting) - if err != nil { - return l.HTTPResponseErrorAction(logutils.ActionCreate, model.TypeGlobalConfig, nil, err, http.StatusInternalServerError, true) - } - - return l.HTTPResponseSuccess() -} - -// getGlobalConfig gets config -func (h SystemApisHandler) getGlobalConfig(l *logs.Log, r *http.Request, claims *tokenauth.Claims) logs.HTTPResponse { - config, err := h.coreAPIs.System.SysGetGlobalConfig() - if err != nil { - return l.HTTPResponseErrorAction(logutils.ActionGet, model.TypeGlobalConfig, nil, err, http.StatusInternalServerError, true) - } - - var responseData *Def.GlobalConfig - if config != nil { - responseData = &Def.GlobalConfig{Setting: config.Setting} - } - data, err := json.Marshal(responseData) - if err != nil { - return l.HTTPResponseErrorAction(logutils.ActionMarshal, model.TypeGlobalConfig, nil, err, http.StatusInternalServerError, false) - } - - return l.HTTPResponseSuccessJSON(data) -} - -// updateGlobalConfig updates global config -func (h SystemApisHandler) updateGlobalConfig(l *logs.Log, r *http.Request, claims *tokenauth.Claims) logs.HTTPResponse { - data, err := ioutil.ReadAll(r.Body) - if err != nil { - return l.HTTPResponseErrorAction(logutils.ActionRead, logutils.TypeRequestBody, nil, err, http.StatusBadRequest, false) - } - - var updateConfig Def.GlobalConfig - err = json.Unmarshal(data, &updateConfig) - if err != nil { - return l.HTTPResponseErrorAction(logutils.ActionUnmarshal, model.TypeGlobalConfig, nil, err, http.StatusBadRequest, true) - } - - setting := updateConfig.Setting - - err = h.coreAPIs.System.SysUpdateGlobalConfig(setting) - if err != nil { - return l.HTTPResponseErrorAction(logutils.ActionUpdate, model.TypeGlobalConfig, nil, err, http.StatusInternalServerError, true) - } - - return l.HTTPResponseSuccess() -} - // getApplicationOrganization retrieves app-org for specified id func (h SystemApisHandler) getApplicationOrganization(l *logs.Log, r *http.Request, claims *tokenauth.Claims) logs.HTTPResponse { params := mux.Vars(r) diff --git a/driver/web/authorization_admin_policy.csv b/driver/web/authorization_admin_policy.csv index 42d8cecaa..0758e73d0 100644 --- a/driver/web/authorization_admin_policy.csv +++ b/driver/web/authorization_admin_policy.csv @@ -6,6 +6,15 @@ p, get_test, /core/admin/test, (GET), Get test data p, get_test-model, /core/admin/test-model, (GET), Get test models +p, all_configs_core, /core/admin/configs/*, (GET)|(PUT)|(DELETE), All core config admin actions +p, all_configs_core, /core/admin/configs, (GET)|(POST), +p, get_configs_core, /core/admin/configs/*, (GET), Get core configs +p, get_configs_core, /core/admin/configs, (GET), +p, update_configs_core, /core/admin/configs/*, (GET)|(PUT), Update core configs +p, update_configs_core, /core/admin/configs, (GET)|(POST), +p, delete_configs_core, /core/admin/configs/*, (GET)|(DELETE), Delete core configs +p, delete_configs_core, /core/admin/configs, (GET), + p, all_login-sessions, /core/admin/application/login-sessions, (GET), All login session actions p, all_login-sessions, /core/admin/application/account/*/login-sessions/*, (DELETE), p, get_login-sessions, /core/admin/application/login-sessions, (GET), Get login sessions diff --git a/driver/web/authorization_system_policy.csv b/driver/web/authorization_system_policy.csv index e9ffb190f..083e97e69 100644 --- a/driver/web/authorization_system_policy.csv +++ b/driver/web/authorization_system_policy.csv @@ -1,9 +1,5 @@ p, all_system_core, /core/system/*, (GET)|(POST)|(DELETE)|(PUT), Access all Core BB system and admin endpoints -p, all_global-config, /core/system/global-config, (GET)|(POST)|(DELETE)|(PUT), All global config actions -p, get_global-config, /core/system/global-config, (GET), Get global configs -p, update_global-config, /core/system/global-config, (GET)|(PUT)|(POST), Update and create global configs - p, all_organizations, /core/system/organizations, (GET)|(POST)|(DELETE)|(PUT), All organization actions p, all_organizations, /core/system/organizations/*, (GET)|(POST)|(DELETE)|(PUT), p, get_organizations, /core/system/organizations, (GET), Get organizations diff --git a/driver/web/conversions_config.go b/driver/web/conversions_config.go new file mode 100644 index 000000000..d4476a9d0 --- /dev/null +++ b/driver/web/conversions_config.go @@ -0,0 +1,89 @@ +// Copyright 2022 Board of Trustees of the University of Illinois. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package web + +import ( + "core-building-block/core/model" + Def "core-building-block/driver/web/docs/gen" + "core-building-block/utils" + "encoding/json" + + "github.com/rokwire/core-auth-library-go/v3/authutils" + "github.com/rokwire/core-auth-library-go/v3/tokenauth" + "github.com/rokwire/logging-library-go/v2/errors" + "github.com/rokwire/logging-library-go/v2/logutils" +) + +func configToDef(item model.Config) (*Def.Config, error) { + var dateUpdated *string + dateCreated := utils.FormatTime(&item.DateCreated) + if item.DateUpdated != nil { + formatted := utils.FormatTime(item.DateUpdated) + dateUpdated = &formatted + } + + var configData Def.Config_Data + if item.Data != nil { + configBytes, err := json.Marshal(item.Data) + if err != nil { + return nil, errors.WrapErrorAction(logutils.ActionMarshal, model.TypeConfig, nil, err) + } + + err = json.Unmarshal(configBytes, &configData) + if err != nil { + return nil, errors.WrapErrorAction(logutils.ActionUnmarshal, model.TypeConfig, nil, err) + } + } + + appID := item.AppID + orgID := item.OrgID + return &Def.Config{Id: &item.ID, Type: item.Type, AppId: &appID, OrgId: &orgID, System: item.System, Data: configData, + DateCreated: &dateCreated, DateUpdated: dateUpdated}, nil +} + +func configsToDef(items []model.Config) ([]Def.Config, error) { + result := make([]Def.Config, 0) + for _, item := range items { + defItem, err := configToDef(item) + if err != nil { + return nil, err + } + result = append(result, *defItem) + } + return result, nil +} + +func configFromDef(item Def.AdminReqCreateUpdateConfig, claims *tokenauth.Claims) (*model.Config, error) { + appID := claims.AppID + if item.AllApps != nil && *item.AllApps { + appID = authutils.AllApps + } + orgID := claims.OrgID + if item.AllOrgs != nil && *item.AllOrgs { + orgID = authutils.AllOrgs + } + + var configData interface{} + configBytes, err := json.Marshal(item.Data) + if err != nil { + return nil, errors.WrapErrorAction(logutils.ActionMarshal, model.TypeConfig, nil, err) + } + + err = json.Unmarshal(configBytes, &configData) + if err != nil { + return nil, errors.WrapErrorAction(logutils.ActionUnmarshal, model.TypeConfig, nil, err) + } + return &model.Config{Type: item.Type, AppID: appID, OrgID: orgID, System: item.System, Data: configData}, nil +} diff --git a/driver/web/docs/gen/def.yaml b/driver/web/docs/gen/def.yaml index 5a3c9e0e7..8b9f7c563 100644 --- a/driver/web/docs/gen/def.yaml +++ b/driver/web/docs/gen/def.yaml @@ -3086,6 +3086,244 @@ paths: description: Unauthorized '500': description: Internal error + /admin/configs: + get: + tags: + - Admin + summary: Get configs + description: | + Get existing configs by search parameters + + **Auth:** Requires admin access token with `get_configs_core`, `update_configs_core`, `delete_configs_core`, or `all_configs_core` permission: + security: + - bearerAuth: [] + parameters: + - name: type + in: query + description: config type + required: false + style: form + explode: false + schema: + type: string + responses: + '200': + description: Success + content: + application/json: + schema: + type: array + items: + $ref: '#/components/schemas/Config' + '400': + description: Bad request + '401': + description: Unauthorized + '500': + description: Internal error + post: + tags: + - Admin + summary: Create config + description: | + Creates a new config + + **Auth:** Requires admin access token with `update_configs_core` or `all_configs_core` permission + security: + - bearerAuth: [] + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/_admin_req_create-update-config' + examples: + system: + summary: System-wide config + value: + type: config_type + all_apps: true + all_orgs: true + system: true + data: + cors_allowed_origins: + - origin1 + - origin2 + org_admin: + summary: Organization-wide config + value: + type: config_type + all_apps: true + all_orgs: false + system: false + data: + cors_allowed_origins: + - origin1 + - origin2 + app_org_specific: + summary: Application organization specific config + value: + type: config_type + all_apps: false + all_orgs: false + system: false + data: + cors_allowed_origins: + - origin1 + - origin2 + required: true + responses: + '200': + description: Success + content: + application/json: + schema: + $ref: '#/components/schemas/Config' + '400': + description: Bad request + '401': + description: Unauthorized + '500': + description: Internal error + '/admin/configs/{id}': + get: + tags: + - Admin + summary: Get config + description: | + Get an existing config + + **Auth:** Requires admin access token with `get_configs_core`, `update_configs_core`, `delete_configs_core`, or `all_configs_core` permission + security: + - bearerAuth: [] + parameters: + - name: id + in: path + description: ID of config to retrieve + required: true + style: simple + explode: false + schema: + type: string + responses: + '200': + description: Success + content: + application/json: + schema: + $ref: '#/components/schemas/Config' + '400': + description: Bad request + '401': + description: Unauthorized + '500': + description: Internal error + put: + tags: + - Admin + summary: Update config + description: | + Updates an existing config + + **Auth:** Requires admin access token with `update_configs_core` or `all_configs_core` permission + security: + - bearerAuth: [] + parameters: + - name: id + in: path + description: ID of config to update + required: true + style: simple + explode: false + schema: + type: string + requestBody: + description: New config content + content: + application/json: + schema: + $ref: '#/components/schemas/_admin_req_create-update-config' + examples: + system: + summary: System-wide config + value: + type: config_type + all_apps: true + all_orgs: true + system: true + data: + cors_allowed_origins: + - origin1 + - origin2 + org_admin: + summary: Organization-wide config + value: + type: config_type + all_apps: true + all_orgs: false + system: false + data: + cors_allowed_origins: + - origin1 + - origin2 + app_org_specific: + summary: Application organization specific config + value: + type: config_type + all_apps: false + all_orgs: false + system: false + data: + cors_allowed_origins: + - origin1 + - origin2 + required: true + responses: + '200': + description: Success + content: + text/plain: + schema: + type: string + example: Success + '400': + description: Bad request + '401': + description: Unauthorized + '500': + description: Internal error + delete: + tags: + - Admin + summary: Delete config + description: | + Deletes a config + + **Auth:** Requires admin access token with `delete_configs_core` or `all_configs_core` permission + security: + - bearerAuth: [] + parameters: + - name: id + in: path + description: ID of config to delete + required: true + style: simple + explode: false + schema: + type: string + responses: + '200': + description: Success + content: + text/plain: + schema: + type: string + example: Success + '400': + description: Bad request + '401': + description: Unauthorized + '500': + description: Internal error /enc/test: get: tags: @@ -3815,90 +4053,6 @@ paths: description: Unauthorized '500': description: Internal error - /system/global-config: - get: - tags: - - System - summary: Get global config - description: | - Gives the system global config - - **Auth:** Requires system access token with `get_global-config`, `update_global-config`, or `all_global-config` permission - security: - - bearerAuth: [] - responses: - '200': - description: Success - content: - application/json: - schema: - $ref: '#/components/schemas/GlobalConfig' - '400': - description: Bad request - '401': - description: Unauthorized - '500': - description: Internal error - post: - tags: - - System - summary: Create global config - description: | - Creates the system global config - - **Auth:** Requires system access token with `update_global-config` or `all_global-config` permission - security: - - bearerAuth: [] - requestBody: - content: - application/json: - schema: - $ref: '#/components/schemas/GlobalConfig' - required: true - responses: - '200': - description: Success - content: - text/plain: - schema: - type: string - example: Success - '400': - description: Bad request - '401': - description: Unauthorized - '500': - description: Internal error - put: - tags: - - System - summary: Update global config - description: | - Updates the system global config - - **Auth:** Requires system access token with `update_global-config` or `all_global-config` permission - security: - - bearerAuth: [] - requestBody: - content: - application/json: - schema: - $ref: '#/components/schemas/GlobalConfig' - required: true - responses: - '200': - description: Success - content: - text/plain: - schema: - type: string - example: Success - '400': - description: Bad request - '401': - description: Unauthorized - '500': - description: Internal error '/system/organizations/{id}': get: tags: @@ -5480,13 +5634,54 @@ components: scheme: bearer bearerFormat: JWT schemas: - GlobalConfig: + Config: required: - - setting + - id + - type + - app_id + - org_id + - system + - data + - date_created + - date_updated type: object properties: - setting: + id: + readOnly: true + type: string + type: + type: string + app_id: + readOnly: true + type: string + org_id: + readOnly: true + type: string + system: + type: boolean + data: + anyOf: + - $ref: '#/components/schemas/EnvConfigData' + date_created: + readOnly: true type: string + date_updated: + readOnly: true + type: string + nullable: true + EnvConfigData: + type: object + properties: + cors_allowed_origins: + type: array + items: + type: string + nullable: true + cors_allowed_headers: + type: array + items: + type: string + nullable: true Application: required: - id @@ -7147,6 +7342,26 @@ components: type: array items: type: string + _admin_req_create-update-config: + required: + - type + - system + - data + type: object + properties: + type: + type: string + all_apps: + type: boolean + nullable: true + all_orgs: + type: boolean + nullable: true + system: + type: boolean + data: + anyOf: + - $ref: '#/components/schemas/EnvConfigData' _system_req_update_service-account: type: object properties: diff --git a/driver/web/docs/gen/gen_types.go b/driver/web/docs/gen/gen_types.go index f7b5a130b..9f59e9b57 100644 --- a/driver/web/docs/gen/gen_types.go +++ b/driver/web/docs/gen/gen_types.go @@ -1,6 +1,6 @@ // Package Def provides primitives to interact with the openapi HTTP API. // -// Code generated by github.com/deepmap/oapi-codegen version v1.12.4 DO NOT EDIT. +// Code generated by github.com/deepmap/oapi-codegen version v1.13.0 DO NOT EDIT. package Def import ( @@ -311,6 +311,23 @@ type AuthType struct { UseCredentials bool `json:"use_credentials"` } +// Config defines model for Config. +type Config struct { + AppId *string `json:"app_id,omitempty"` + Data Config_Data `json:"data"` + DateCreated *string `json:"date_created,omitempty"` + DateUpdated *string `json:"date_updated"` + Id *string `json:"id,omitempty"` + OrgId *string `json:"org_id,omitempty"` + System bool `json:"system"` + Type string `json:"type"` +} + +// Config_Data defines model for Config.Data. +type Config_Data struct { + union json.RawMessage +} + // Device defines model for Device. type Device struct { DeviceId *string `json:"device_id,omitempty"` @@ -322,9 +339,10 @@ type Device struct { // DeviceType defines model for Device.Type. type DeviceType string -// GlobalConfig defines model for GlobalConfig. -type GlobalConfig struct { - Setting string `json:"setting"` +// EnvConfigData defines model for EnvConfigData. +type EnvConfigData struct { + CorsAllowedHeaders *[]string `json:"cors_allowed_headers"` + CorsAllowedOrigins *[]string `json:"cors_allowed_origins"` } // IdentityProviderSettings defines model for IdentityProviderSettings. @@ -653,6 +671,20 @@ type AdminReqApplicationRole struct { System *bool `json:"system,omitempty"` } +// AdminReqCreateUpdateConfig defines model for _admin_req_create-update-config. +type AdminReqCreateUpdateConfig struct { + AllApps *bool `json:"all_apps"` + AllOrgs *bool `json:"all_orgs"` + Data AdminReqCreateUpdateConfig_Data `json:"data"` + System bool `json:"system"` + Type string `json:"type"` +} + +// AdminReqCreateUpdateConfig_Data defines model for AdminReqCreateUpdateConfig.Data. +type AdminReqCreateUpdateConfig_Data struct { + union json.RawMessage +} + // AdminReqGrantPermissions defines model for _admin_req_grant-permissions. type AdminReqGrantPermissions struct { Permissions []string `json:"permissions"` @@ -1225,6 +1257,12 @@ type PostAdminAuthMfaParams struct { State *string `form:"state,omitempty" json:"state,omitempty"` } +// GetAdminConfigsParams defines parameters for GetAdminConfigs. +type GetAdminConfigsParams struct { + // Type config type + Type *string `form:"type,omitempty" json:"type,omitempty"` +} + // PostBbsAccountsJSONBody defines parameters for PostBbsAccounts. type PostBbsAccountsJSONBody = map[string]interface{} @@ -1573,6 +1611,12 @@ type PostAdminAuthRefreshJSONRequestBody = SharedReqRefresh // PostAdminAuthVerifyMfaJSONRequestBody defines body for PostAdminAuthVerifyMfa for application/json ContentType. type PostAdminAuthVerifyMfaJSONRequestBody = SharedReqMfa +// PostAdminConfigsJSONRequestBody defines body for PostAdminConfigs for application/json ContentType. +type PostAdminConfigsJSONRequestBody = AdminReqCreateUpdateConfig + +// PutAdminConfigsIdJSONRequestBody defines body for PutAdminConfigsId for application/json ContentType. +type PutAdminConfigsIdJSONRequestBody = AdminReqCreateUpdateConfig + // PostBbsAccessTokenJSONRequestBody defines body for PostBbsAccessToken for application/json ContentType. type PostBbsAccessTokenJSONRequestBody = ServicesReqServiceAccountsAccessToken @@ -1699,12 +1743,6 @@ type PostSystemAuthTypesJSONRequestBody = AuthType // PutSystemAuthTypesIdJSONRequestBody defines body for PutSystemAuthTypesId for application/json ContentType. type PutSystemAuthTypesIdJSONRequestBody = AuthType -// PostSystemGlobalConfigJSONRequestBody defines body for PostSystemGlobalConfig for application/json ContentType. -type PostSystemGlobalConfigJSONRequestBody = GlobalConfig - -// PutSystemGlobalConfigJSONRequestBody defines body for PutSystemGlobalConfig for application/json ContentType. -type PutSystemGlobalConfigJSONRequestBody = GlobalConfig - // PostSystemOrganizationsJSONRequestBody defines body for PostSystemOrganizations for application/json ContentType. type PostSystemOrganizationsJSONRequestBody = Organization @@ -1747,6 +1785,78 @@ type PostTpsAccountsCountJSONRequestBody = PostTpsAccountsCountJSONBody // PostTpsServiceAccountIdJSONRequestBody defines body for PostTpsServiceAccountId for application/json ContentType. type PostTpsServiceAccountIdJSONRequestBody = ServicesReqServiceAccountsParams +// AsEnvConfigData returns the union data inside the Config_Data as a EnvConfigData +func (t Config_Data) AsEnvConfigData() (EnvConfigData, error) { + var body EnvConfigData + err := json.Unmarshal(t.union, &body) + return body, err +} + +// FromEnvConfigData overwrites any union data inside the Config_Data as the provided EnvConfigData +func (t *Config_Data) FromEnvConfigData(v EnvConfigData) error { + b, err := json.Marshal(v) + t.union = b + return err +} + +// MergeEnvConfigData performs a merge with any union data inside the Config_Data, using the provided EnvConfigData +func (t *Config_Data) MergeEnvConfigData(v EnvConfigData) error { + b, err := json.Marshal(v) + if err != nil { + return err + } + + merged, err := runtime.JsonMerge(t.union, b) + t.union = merged + return err +} + +func (t Config_Data) MarshalJSON() ([]byte, error) { + b, err := t.union.MarshalJSON() + return b, err +} + +func (t *Config_Data) UnmarshalJSON(b []byte) error { + err := t.union.UnmarshalJSON(b) + return err +} + +// AsEnvConfigData returns the union data inside the AdminReqCreateUpdateConfig_Data as a EnvConfigData +func (t AdminReqCreateUpdateConfig_Data) AsEnvConfigData() (EnvConfigData, error) { + var body EnvConfigData + err := json.Unmarshal(t.union, &body) + return body, err +} + +// FromEnvConfigData overwrites any union data inside the AdminReqCreateUpdateConfig_Data as the provided EnvConfigData +func (t *AdminReqCreateUpdateConfig_Data) FromEnvConfigData(v EnvConfigData) error { + b, err := json.Marshal(v) + t.union = b + return err +} + +// MergeEnvConfigData performs a merge with any union data inside the AdminReqCreateUpdateConfig_Data, using the provided EnvConfigData +func (t *AdminReqCreateUpdateConfig_Data) MergeEnvConfigData(v EnvConfigData) error { + b, err := json.Marshal(v) + if err != nil { + return err + } + + merged, err := runtime.JsonMerge(t.union, b) + t.union = merged + return err +} + +func (t AdminReqCreateUpdateConfig_Data) MarshalJSON() ([]byte, error) { + b, err := t.union.MarshalJSON() + return b, err +} + +func (t *AdminReqCreateUpdateConfig_Data) UnmarshalJSON(b []byte) error { + err := t.union.UnmarshalJSON(b) + return err +} + // AsSharedReqCredsEmail returns the union data inside the ServicesReqAccountAuthTypeLink_Creds as a SharedReqCredsEmail func (t ServicesReqAccountAuthTypeLink_Creds) AsSharedReqCredsEmail() (SharedReqCredsEmail, error) { var body SharedReqCredsEmail @@ -1768,7 +1878,7 @@ func (t *ServicesReqAccountAuthTypeLink_Creds) MergeSharedReqCredsEmail(v Shared return err } - merged, err := runtime.JsonMerge(b, t.union) + merged, err := runtime.JsonMerge(t.union, b) t.union = merged return err } @@ -1794,7 +1904,7 @@ func (t *ServicesReqAccountAuthTypeLink_Creds) MergeSharedReqCredsTwilioPhone(v return err } - merged, err := runtime.JsonMerge(b, t.union) + merged, err := runtime.JsonMerge(t.union, b) t.union = merged return err } @@ -1820,7 +1930,7 @@ func (t *ServicesReqAccountAuthTypeLink_Creds) MergeSharedReqCredsOIDC(v SharedR return err } - merged, err := runtime.JsonMerge(b, t.union) + merged, err := runtime.JsonMerge(t.union, b) t.union = merged return err } @@ -1856,7 +1966,7 @@ func (t *ServicesReqAccountAuthTypeLink_Params) MergeSharedReqParamsEmail(v Shar return err } - merged, err := runtime.JsonMerge(b, t.union) + merged, err := runtime.JsonMerge(t.union, b) t.union = merged return err } @@ -1882,7 +1992,7 @@ func (t *ServicesReqAccountAuthTypeLink_Params) MergeSharedReqParamsOIDC(v Share return err } - merged, err := runtime.JsonMerge(b, t.union) + merged, err := runtime.JsonMerge(t.union, b) t.union = merged return err } @@ -1908,7 +2018,7 @@ func (t *ServicesReqAccountAuthTypeLink_Params) MergeSharedReqParamsNone(v Share return err } - merged, err := runtime.JsonMerge(b, t.union) + merged, err := runtime.JsonMerge(t.union, b) t.union = merged return err } @@ -1944,7 +2054,7 @@ func (t *ServicesReqCredentialForgotComplete_Params) MergeSharedReqParamsSetEmai return err } - merged, err := runtime.JsonMerge(b, t.union) + merged, err := runtime.JsonMerge(t.union, b) t.union = merged return err } @@ -1980,7 +2090,7 @@ func (t *ServicesReqCredentialUpdate_Params) MergeSharedReqParamsSetEmailCredent return err } - merged, err := runtime.JsonMerge(b, t.union) + merged, err := runtime.JsonMerge(t.union, b) t.union = merged return err } @@ -2016,7 +2126,7 @@ func (t *SharedReqLogin_Creds) MergeSharedReqCredsEmail(v SharedReqCredsEmail) e return err } - merged, err := runtime.JsonMerge(b, t.union) + merged, err := runtime.JsonMerge(t.union, b) t.union = merged return err } @@ -2042,7 +2152,7 @@ func (t *SharedReqLogin_Creds) MergeSharedReqCredsTwilioPhone(v SharedReqCredsTw return err } - merged, err := runtime.JsonMerge(b, t.union) + merged, err := runtime.JsonMerge(t.union, b) t.union = merged return err } @@ -2068,7 +2178,7 @@ func (t *SharedReqLogin_Creds) MergeSharedReqCredsOIDC(v SharedReqCredsOIDC) err return err } - merged, err := runtime.JsonMerge(b, t.union) + merged, err := runtime.JsonMerge(t.union, b) t.union = merged return err } @@ -2094,7 +2204,7 @@ func (t *SharedReqLogin_Creds) MergeSharedReqCredsAPIKey(v SharedReqCredsAPIKey) return err } - merged, err := runtime.JsonMerge(b, t.union) + merged, err := runtime.JsonMerge(t.union, b) t.union = merged return err } @@ -2120,7 +2230,7 @@ func (t *SharedReqLogin_Creds) MergeSharedReqLoginCreds4(v SharedReqLoginCreds4) return err } - merged, err := runtime.JsonMerge(b, t.union) + merged, err := runtime.JsonMerge(t.union, b) t.union = merged return err } @@ -2156,7 +2266,7 @@ func (t *SharedReqLogin_Params) MergeSharedReqParamsEmail(v SharedReqParamsEmail return err } - merged, err := runtime.JsonMerge(b, t.union) + merged, err := runtime.JsonMerge(t.union, b) t.union = merged return err } @@ -2182,7 +2292,7 @@ func (t *SharedReqLogin_Params) MergeSharedReqParamsOIDC(v SharedReqParamsOIDC) return err } - merged, err := runtime.JsonMerge(b, t.union) + merged, err := runtime.JsonMerge(t.union, b) t.union = merged return err } @@ -2208,7 +2318,7 @@ func (t *SharedReqLogin_Params) MergeSharedReqParamsNone(v SharedReqParamsNone) return err } - merged, err := runtime.JsonMerge(b, t.union) + merged, err := runtime.JsonMerge(t.union, b) t.union = merged return err } @@ -2234,7 +2344,7 @@ func (t *SharedReqLogin_Params) MergeSharedReqLoginParams3(v SharedReqLoginParam return err } - merged, err := runtime.JsonMerge(b, t.union) + merged, err := runtime.JsonMerge(t.union, b) t.union = merged return err } @@ -2270,7 +2380,7 @@ func (t *SharedResLogin_Params) MergeSharedResParamsOIDC(v SharedResParamsOIDC) return err } - merged, err := runtime.JsonMerge(b, t.union) + merged, err := runtime.JsonMerge(t.union, b) t.union = merged return err } @@ -2296,7 +2406,7 @@ func (t *SharedResLogin_Params) MergeSharedResParamsAPIKey(v SharedResParamsAPIK return err } - merged, err := runtime.JsonMerge(b, t.union) + merged, err := runtime.JsonMerge(t.union, b) t.union = merged return err } @@ -2322,7 +2432,7 @@ func (t *SharedResLogin_Params) MergeSharedResParamsNone(v SharedResParamsNone) return err } - merged, err := runtime.JsonMerge(b, t.union) + merged, err := runtime.JsonMerge(t.union, b) t.union = merged return err } @@ -2358,7 +2468,7 @@ func (t *SharedResLoginMfa_Params) MergeSharedResParamsOIDC(v SharedResParamsOID return err } - merged, err := runtime.JsonMerge(b, t.union) + merged, err := runtime.JsonMerge(t.union, b) t.union = merged return err } @@ -2384,7 +2494,7 @@ func (t *SharedResLoginMfa_Params) MergeSharedResParamsAPIKey(v SharedResParamsA return err } - merged, err := runtime.JsonMerge(b, t.union) + merged, err := runtime.JsonMerge(t.union, b) t.union = merged return err } @@ -2410,7 +2520,7 @@ func (t *SharedResLoginMfa_Params) MergeSharedResParamsNone(v SharedResParamsNon return err } - merged, err := runtime.JsonMerge(b, t.union) + merged, err := runtime.JsonMerge(t.union, b) t.union = merged return err } @@ -2446,7 +2556,7 @@ func (t *SharedResRefresh_Params) MergeSharedResParamsOIDC(v SharedResParamsOIDC return err } - merged, err := runtime.JsonMerge(b, t.union) + merged, err := runtime.JsonMerge(t.union, b) t.union = merged return err } @@ -2472,7 +2582,7 @@ func (t *SharedResRefresh_Params) MergeSharedResParamsAPIKey(v SharedResParamsAP return err } - merged, err := runtime.JsonMerge(b, t.union) + merged, err := runtime.JsonMerge(t.union, b) t.union = merged return err } @@ -2498,7 +2608,7 @@ func (t *SharedResRefresh_Params) MergeSharedResParamsNone(v SharedResParamsNone return err } - merged, err := runtime.JsonMerge(b, t.union) + merged, err := runtime.JsonMerge(t.union, b) t.union = merged return err } diff --git a/driver/web/docs/index.yaml b/driver/web/docs/index.yaml index 08b34489a..42acf2019 100644 --- a/driver/web/docs/index.yaml +++ b/driver/web/docs/index.yaml @@ -145,7 +145,11 @@ paths: $ref: "./resources/admin/application/roles/permissions.yaml" /admin/organization/applications: $ref: "./resources/admin/organization/applications.yaml" - + /admin/configs: + $ref: "./resources/admin/configs.yaml" + /admin/configs/{id}: + $ref: "./resources/admin/configsId.yaml" + #enc /enc/test: $ref: "./resources/enc/test.yaml" @@ -185,8 +189,6 @@ paths: #system /system/auth/app-org-token: $ref: "./resources/system/auth/app-org-token.yaml" - /system/global-config: - $ref: "./resources/system/global-config.yaml" /system/organizations/{id}: $ref: "./resources/system/organizationsId.yaml" /system/organizations: diff --git a/driver/web/docs/resources/admin/configs.yaml b/driver/web/docs/resources/admin/configs.yaml new file mode 100644 index 000000000..1e1ccc0fe --- /dev/null +++ b/driver/web/docs/resources/admin/configs.yaml @@ -0,0 +1,97 @@ +get: + tags: + - Admin + summary: Get configs + description: | + Get existing configs by search parameters + + **Auth:** Requires admin access token with `get_configs_core`, `update_configs_core`, `delete_configs_core`, or `all_configs_core` permission: + security: + - bearerAuth: [] + parameters: + - name: type + in: query + description: config type + required: false + style: form + explode: false + schema: + type: string + responses: + 200: + description: Success + content: + application/json: + schema: + type: array + items: + $ref: "../../schemas/config/Config.yaml" + 400: + description: Bad request + 401: + description: Unauthorized + 500: + description: Internal error +post: + tags: + - Admin + summary: Create config + description: | + Creates a new config + + **Auth:** Requires admin access token with `update_configs_core` or `all_configs_core` permission + security: + - bearerAuth: [] + requestBody: + content: + application/json: + schema: + $ref: "../../schemas/apis/admin/configs/request/Request.yaml" + examples: + system: + summary: System-wide config + value: + type: "config_type" + all_apps: true + all_orgs: true + system: true + data: + cors_allowed_origins: + - origin1 + - origin2 + org_admin: + summary: Organization-wide config + value: + type: "config_type" + all_apps: true + all_orgs: false + system: false + data: + cors_allowed_origins: + - origin1 + - origin2 + app_org_specific: + summary: Application organization specific config + value: + type: "config_type" + all_apps: false + all_orgs: false + system: false + data: + cors_allowed_origins: + - origin1 + - origin2 + required: true + responses: + 200: + description: Success + content: + application/json: + schema: + $ref: "../../schemas/config/Config.yaml" + 400: + description: Bad request + 401: + description: Unauthorized + 500: + description: Internal error \ No newline at end of file diff --git a/driver/web/docs/resources/admin/configsId.yaml b/driver/web/docs/resources/admin/configsId.yaml new file mode 100644 index 000000000..176cd2107 --- /dev/null +++ b/driver/web/docs/resources/admin/configsId.yaml @@ -0,0 +1,139 @@ +get: + tags: + - Admin + summary: Get config + description: | + Get an existing config + + **Auth:** Requires admin access token with `get_configs_core`, `update_configs_core`, `delete_configs_core`, or `all_configs_core` permission + security: + - bearerAuth: [] + parameters: + - name: id + in: path + description: ID of config to retrieve + required: true + style: simple + explode: false + schema: + type: string + responses: + 200: + description: Success + content: + application/json: + schema: + $ref: "../../schemas/config/Config.yaml" + 400: + description: Bad request + 401: + description: Unauthorized + 500: + description: Internal error +put: + tags: + - Admin + summary: Update config + description: | + Updates an existing config + + **Auth:** Requires admin access token with `update_configs_core` or `all_configs_core` permission + security: + - bearerAuth: [] + parameters: + - name: id + in: path + description: ID of config to update + required: true + style: simple + explode: false + schema: + type: string + requestBody: + description: New config content + content: + application/json: + schema: + $ref: "../../schemas/apis/admin/configs/request/Request.yaml" + examples: + system: + summary: System-wide config + value: + type: "config_type" + all_apps: true + all_orgs: true + system: true + data: + cors_allowed_origins: + - origin1 + - origin2 + org_admin: + summary: Organization-wide config + value: + type: "config_type" + all_apps: true + all_orgs: false + system: false + data: + cors_allowed_origins: + - origin1 + - origin2 + app_org_specific: + summary: Application organization specific config + value: + type: "config_type" + all_apps: false + all_orgs: false + system: false + data: + cors_allowed_origins: + - origin1 + - origin2 + required: true + responses: + 200: + description: Success + content: + text/plain: + schema: + type: string + example: Success + 400: + description: Bad request + 401: + description: Unauthorized + 500: + description: Internal error +delete: + tags: + - Admin + summary: Delete config + description: | + Deletes a config + + **Auth:** Requires admin access token with `delete_configs_core` or `all_configs_core` permission + security: + - bearerAuth: [] + parameters: + - name: id + in: path + description: ID of config to delete + required: true + style: simple + explode: false + schema: + type: string + responses: + 200: + description: Success + content: + text/plain: + schema: + type: string + example: Success + 400: + description: Bad request + 401: + description: Unauthorized + 500: + description: Internal error \ No newline at end of file diff --git a/driver/web/docs/resources/system/global-config.yaml b/driver/web/docs/resources/system/global-config.yaml deleted file mode 100644 index b5e2724cd..000000000 --- a/driver/web/docs/resources/system/global-config.yaml +++ /dev/null @@ -1,83 +0,0 @@ -get: - tags: - - System - summary: Get global config - description: | - Gives the system global config - - **Auth:** Requires system access token with `get_global-config`, `update_global-config`, or `all_global-config` permission - security: - - bearerAuth: [] - responses: - 200: - description: Success - content: - application/json: - schema: - $ref: "../../schemas/global/GlobalConfig.yaml" - 400: - description: Bad request - 401: - description: Unauthorized - 500: - description: Internal error -post: - tags: - - System - summary: Create global config - description: | - Creates the system global config - - **Auth:** Requires system access token with `update_global-config` or `all_global-config` permission - security: - - bearerAuth: [] - requestBody: - content: - application/json: - schema: - $ref: "../../schemas/global/GlobalConfig.yaml" - required: true - responses: - 200: - description: Success - content: - text/plain: - schema: - type: string - example: Success - 400: - description: Bad request - 401: - description: Unauthorized - 500: - description: Internal error -put: - tags: - - System - summary: Update global config - description: | - Updates the system global config - - **Auth:** Requires system access token with `update_global-config` or `all_global-config` permission - security: - - bearerAuth: [] - requestBody: - content: - application/json: - schema: - $ref: "../../schemas/global/GlobalConfig.yaml" - required: true - responses: - 200: - description: Success - content: - text/plain: - schema: - type: string - example: Success - 400: - description: Bad request - 401: - description: Unauthorized - 500: - description: Internal error \ No newline at end of file diff --git a/driver/web/docs/schemas/apis/admin/configs/request/Request.yaml b/driver/web/docs/schemas/apis/admin/configs/request/Request.yaml new file mode 100644 index 000000000..b356a62f5 --- /dev/null +++ b/driver/web/docs/schemas/apis/admin/configs/request/Request.yaml @@ -0,0 +1,19 @@ +required: + - type + - system + - data +type: object +properties: + type: + type: string + all_apps: + type: boolean + nullable: true + all_orgs: + type: boolean + nullable: true + system: + type: boolean + data: + anyOf: + - $ref: "../../../../config/EnvConfigData.yaml" \ No newline at end of file diff --git a/driver/web/docs/schemas/apis/shared/responses/refresh/Response.yaml b/driver/web/docs/schemas/apis/shared/responses/refresh/Response.yaml index b1c21d66c..ce27aaf49 100644 --- a/driver/web/docs/schemas/apis/shared/responses/refresh/Response.yaml +++ b/driver/web/docs/schemas/apis/shared/responses/refresh/Response.yaml @@ -1,11 +1,11 @@ type: object properties: token: - $ref: "../../responses/RokwireToken.yaml" + $ref: "../RokwireToken.yaml" params: type: object nullable: true anyOf: - - $ref: "../../responses/ParamsOIDC.yaml" - - $ref: "../../responses/ParamsAPIKey.yaml" - - $ref: "../../responses/ParamsNone.yaml" + - $ref: "../ParamsOIDC.yaml" + - $ref: "../ParamsAPIKey.yaml" + - $ref: "../ParamsNone.yaml" diff --git a/driver/web/docs/schemas/config/Config.yaml b/driver/web/docs/schemas/config/Config.yaml new file mode 100644 index 000000000..e69bb7109 --- /dev/null +++ b/driver/web/docs/schemas/config/Config.yaml @@ -0,0 +1,34 @@ +required: + - id + - type + - app_id + - org_id + - system + - data + - date_created + - date_updated +type: object +properties: + id: + readOnly: true + type: string + type: + type: string + app_id: + readOnly: true + type: string + org_id: + readOnly: true + type: string + system: + type: boolean + data: + anyOf: + - $ref: "./EnvConfigData.yaml" + date_created: + readOnly: true + type: string + date_updated: + readOnly: true + type: string + nullable: true \ No newline at end of file diff --git a/driver/web/docs/schemas/config/EnvConfigData.yaml b/driver/web/docs/schemas/config/EnvConfigData.yaml new file mode 100644 index 000000000..61162e24f --- /dev/null +++ b/driver/web/docs/schemas/config/EnvConfigData.yaml @@ -0,0 +1,12 @@ +type: object +properties: + cors_allowed_origins: + type: array + items: + type: string + nullable: true + cors_allowed_headers: + type: array + items: + type: string + nullable: true \ No newline at end of file diff --git a/driver/web/docs/schemas/global/GlobalConfig.yaml b/driver/web/docs/schemas/global/GlobalConfig.yaml deleted file mode 100644 index 9b104a44d..000000000 --- a/driver/web/docs/schemas/global/GlobalConfig.yaml +++ /dev/null @@ -1,6 +0,0 @@ -required: - - setting -type: object -properties: - setting: - type: string \ No newline at end of file diff --git a/driver/web/docs/schemas/index.yaml b/driver/web/docs/schemas/index.yaml index b0f3e5225..23795c1e9 100644 --- a/driver/web/docs/schemas/index.yaml +++ b/driver/web/docs/schemas/index.yaml @@ -1,6 +1,8 @@ -# global -GlobalConfig: - $ref: "./global/GlobalConfig.yaml" +# config +Config: + $ref: "./config/Config.yaml" +EnvConfigData: + $ref: "./config/EnvConfigData.yaml" # application Application: @@ -237,6 +239,10 @@ _admin_req_revoke-permissions: ### grant permissions to role API _admin_req_grant-permissions-to-role: $ref: "./apis/admin/application/roles/permissions/grant/request/Request.yaml" + +### create config API and update config API +_admin_req_create-update-config: + $ref: "./apis/admin/configs/request/Request.yaml" ## end ADMIN section ## SYSTEM section diff --git a/driver/web/docs/schemas/user/AccountAuthType.yaml b/driver/web/docs/schemas/user/AccountAuthType.yaml index 119e92685..410ed119b 100644 --- a/driver/web/docs/schemas/user/AccountAuthType.yaml +++ b/driver/web/docs/schemas/user/AccountAuthType.yaml @@ -17,4 +17,4 @@ properties: active: type: boolean unverified: - type: boolean \ No newline at end of file + type: boolean diff --git a/go.mod b/go.mod index 393d4a151..46df0c669 100644 --- a/go.mod +++ b/go.mod @@ -4,51 +4,70 @@ go 1.20 require ( github.com/coreos/go-oidc v2.2.1+incompatible - github.com/deepmap/oapi-codegen v1.12.4 - github.com/getkin/kin-openapi v0.115.0 + github.com/deepmap/oapi-codegen v1.13.0 + github.com/getkin/kin-openapi v0.118.0 github.com/golang-jwt/jwt v3.2.2+incompatible github.com/google/uuid v1.3.0 github.com/gorilla/mux v1.8.0 - github.com/lestrrat-go/jwx v1.2.25 + github.com/lestrrat-go/jwx v1.2.26 github.com/pquerna/otp v1.4.0 github.com/rokwire/core-auth-library-go/v3 v3.0.1 github.com/rokwire/logging-library-go/v2 v2.2.0 - github.com/stretchr/testify v1.8.2 + github.com/stretchr/testify v1.8.4 github.com/swaggo/http-swagger v1.3.4 - go.mongodb.org/mongo-driver v1.11.4 - golang.org/x/crypto v0.8.0 - golang.org/x/sync v0.1.0 + go.mongodb.org/mongo-driver v1.12.0 + golang.org/x/crypto v0.10.0 + golang.org/x/sync v0.3.0 gopkg.in/go-playground/validator.v9 v9.31.0 gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df + gopkg.in/yaml.v2 v2.4.0 gotest.tools v2.2.0+incompatible ) require ( github.com/apapsch/go-jsonmerge/v2 v2.0.0 // indirect - github.com/decred/dcrd/dcrec/secp256k1/v4 v4.1.0 // indirect + github.com/bytedance/sonic v1.9.2 // indirect + github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 // indirect + github.com/decred/dcrd/dcrec/secp256k1/v4 v4.2.0 // indirect + github.com/gabriel-vasile/mimetype v1.4.2 // indirect + github.com/gin-contrib/sse v0.1.0 // indirect + github.com/gin-gonic/gin v1.9.1 // indirect + github.com/go-playground/validator/v10 v10.14.1 // indirect github.com/goccy/go-json v0.10.2 // indirect + github.com/json-iterator/go v1.1.12 // indirect + github.com/klauspost/cpuid/v2 v2.2.5 // indirect + github.com/labstack/echo/v4 v4.10.2 // indirect + github.com/labstack/gommon v0.4.0 // indirect github.com/lestrrat-go/backoff/v2 v2.0.8 // indirect github.com/lestrrat-go/blackmagic v1.0.1 // indirect github.com/lestrrat-go/httpcc v1.0.1 // indirect github.com/lestrrat-go/iter v1.0.2 // indirect github.com/lestrrat-go/option v1.0.1 // indirect - github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 // indirect - github.com/perimeterx/marshmallow v1.1.4 // indirect + github.com/mattn/go-colorable v0.1.13 // indirect + github.com/mattn/go-isatty v0.0.19 // 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/pkg/errors v0.9.1 // indirect - github.com/rogpeppe/go-internal v1.9.0 // indirect + github.com/rogpeppe/go-internal v1.10.0 // indirect + github.com/twitchyliquid64/golang-asm v0.15.1 // indirect + github.com/ugorji/go/codec v1.2.11 // indirect + github.com/valyala/bytebufferpool v1.0.0 // indirect + github.com/valyala/fasttemplate v1.2.2 // indirect + golang.org/x/arch v0.3.0 // indirect ) require ( github.com/Knetic/govaluate v3.0.1-0.20171022003610-9aa49832a739+incompatible // indirect github.com/KyleBanks/depth v1.2.1 // indirect - github.com/aws/aws-sdk-go v1.44.239 // indirect + github.com/aws/aws-sdk-go v1.44.291 // indirect github.com/boombuler/barcode v1.0.1 // indirect - github.com/casbin/casbin/v2 v2.66.3 // indirect + github.com/casbin/casbin/v2 v2.71.1 // indirect github.com/davecgh/go-spew v1.1.1 // indirect github.com/go-openapi/jsonpointer v0.19.6 // indirect github.com/go-openapi/jsonreference v0.20.2 // indirect - github.com/go-openapi/spec v0.20.8 // indirect - github.com/go-openapi/swag v0.22.3 // indirect + github.com/go-openapi/spec v0.20.9 // indirect + github.com/go-openapi/swag v0.22.4 // indirect github.com/go-playground/locales v0.14.1 // indirect github.com/go-playground/universal-translator v0.18.1 // indirect github.com/golang/protobuf v1.5.3 // indirect @@ -57,29 +76,31 @@ require ( github.com/invopop/yaml v0.2.0 // indirect github.com/jmespath/go-jmespath v0.4.0 // indirect github.com/josharian/intern v1.0.0 // indirect - github.com/klauspost/compress v1.16.4 // indirect - github.com/leodido/go-urn v1.2.3 // indirect + github.com/klauspost/compress v1.16.6 // indirect + github.com/leodido/go-urn v1.2.4 // indirect github.com/mailru/easyjson v0.7.7 // indirect - github.com/montanaflynn/stats v0.7.0 // indirect + github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 // indirect + github.com/montanaflynn/stats v0.7.1 // indirect + github.com/perimeterx/marshmallow v1.1.4 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect - github.com/pquerna/cachecontrol v0.1.0 // indirect - github.com/sirupsen/logrus v1.9.0 // indirect + github.com/pquerna/cachecontrol v0.2.0 // indirect + github.com/rs/cors v1.9.0 // indirect + github.com/sirupsen/logrus v1.9.3 // indirect github.com/stretchr/objx v0.5.0 // indirect github.com/swaggo/files v1.0.1 // indirect - github.com/swaggo/swag v1.8.12 // indirect + github.com/swaggo/swag v1.16.1 // indirect github.com/xdg-go/pbkdf2 v1.0.0 // indirect github.com/xdg-go/scram v1.1.2 // indirect github.com/xdg-go/stringprep v1.0.4 // indirect github.com/youmark/pkcs8 v0.0.0-20201027041543-1326539a0a0a // indirect - golang.org/x/net v0.9.0 // indirect - golang.org/x/oauth2 v0.7.0 // indirect - golang.org/x/sys v0.7.0 // indirect - golang.org/x/text v0.9.0 // indirect - golang.org/x/tools v0.8.0 // indirect + golang.org/x/net v0.11.0 // indirect + golang.org/x/oauth2 v0.9.0 // indirect + golang.org/x/sys v0.9.0 // indirect + golang.org/x/text v0.10.0 // indirect + golang.org/x/tools v0.10.0 // indirect google.golang.org/appengine v1.6.7 // indirect - google.golang.org/protobuf v1.30.0 // indirect + google.golang.org/protobuf v1.31.0 // indirect gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc // indirect gopkg.in/square/go-jose.v2 v2.6.0 // indirect - gopkg.in/yaml.v2 v2.4.0 gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/go.sum b/go.sum index 2af54eb3b..fb3fb3430 100644 --- a/go.sum +++ b/go.sum @@ -5,32 +5,39 @@ github.com/KyleBanks/depth v1.2.1/go.mod h1:jzSb9d0L43HxTQfT+oSA1EEp2q+ne2uh6Xge github.com/RaveNoX/go-jsoncommentstrip v1.0.0/go.mod h1:78ihd09MekBnJnxpICcwzCMzGrKSKYe4AqU6PDYYpjk= github.com/apapsch/go-jsonmerge/v2 v2.0.0 h1:axGnT1gRIfimI7gJifB699GoE/oq+F2MU7Dml6nw9rQ= github.com/apapsch/go-jsonmerge/v2 v2.0.0/go.mod h1:lvDnEdqiQrp0O42VQGgmlKpxL1AP2+08jFMw88y4klk= -github.com/aws/aws-sdk-go v1.44.235 h1:5MS1ZW1Pr27mmHFqqjuXYwGMlNTW/g6DqU5ekamPMeU= -github.com/aws/aws-sdk-go v1.44.235/go.mod h1:aVsgQcEevwlmQ7qHE9I3h+dtQgpqhFB+i8Phjh7fkwI= -github.com/aws/aws-sdk-go v1.44.239 h1:AenB6byCYGSBb30q99CGYqFbqpLpWrTidzm7MzxtuPo= -github.com/aws/aws-sdk-go v1.44.239/go.mod h1:aVsgQcEevwlmQ7qHE9I3h+dtQgpqhFB+i8Phjh7fkwI= +github.com/aws/aws-sdk-go v1.44.291 h1:JVgIyvdYm/A6iCHD0UIS/Hvu/GVHjpW7bN3mwG6sHlU= +github.com/aws/aws-sdk-go v1.44.291/go.mod h1:aVsgQcEevwlmQ7qHE9I3h+dtQgpqhFB+i8Phjh7fkwI= github.com/bmatcuk/doublestar v1.1.1/go.mod h1:UD6OnuiIn0yFxxA2le/rnRU1G4RaI4UvFv1sNto9p6w= github.com/boombuler/barcode v1.0.1-0.20190219062509-6c824513bacc/go.mod h1:paBWMcWSl3LHKBqUq+rly7CNSldXjb2rDl3JlRe0mD8= github.com/boombuler/barcode v1.0.1 h1:NDBbPmhS+EqABEs5Kg3n/5ZNjy73Pz7SIV+KCeqyXcs= github.com/boombuler/barcode v1.0.1/go.mod h1:paBWMcWSl3LHKBqUq+rly7CNSldXjb2rDl3JlRe0mD8= -github.com/casbin/casbin/v2 v2.66.1 h1:HOFlZYTUYx8ktgv5fLNFo6hr4K18ogGFq/lnYXv1OfA= -github.com/casbin/casbin/v2 v2.66.1/go.mod h1:vByNa/Fchek0KZUgG5wEsl7iFsiviAYKRtgrQfcJqHg= -github.com/casbin/casbin/v2 v2.66.3 h1:m0/mO4Xpu4YzTMqm0U1bm9JqEMSdIx6IRmnMCORnVDs= -github.com/casbin/casbin/v2 v2.66.3/go.mod h1:vByNa/Fchek0KZUgG5wEsl7iFsiviAYKRtgrQfcJqHg= +github.com/bytedance/sonic v1.5.0/go.mod h1:ED5hyg4y6t3/9Ku1R6dU/4KyJ48DZ4jPhfY1O2AihPM= +github.com/bytedance/sonic v1.9.2 h1:GDaNjuWSGu09guE9Oql0MSTNhNCLlWwO8y/xM5BzcbM= +github.com/bytedance/sonic v1.9.2/go.mod h1:i736AoUSYt75HyZLoJW9ERYxcy6eaN6h4BZXU064P/U= +github.com/casbin/casbin/v2 v2.71.1 h1:LRHyqM0S1LzM/K59PmfUIN0ZJfLgcOjL4OhOQI/FNXU= +github.com/casbin/casbin/v2 v2.71.1/go.mod h1:vByNa/Fchek0KZUgG5wEsl7iFsiviAYKRtgrQfcJqHg= +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/coreos/go-oidc v2.2.1+incompatible h1:mh48q/BqXqgjVHpy2ZY7WnWAbenxRjsz9N1i1YxjHAk= github.com/coreos/go-oidc v2.2.1+incompatible/go.mod h1:CgnwVTmzoESiwO9qyAFEMiHoZ1nMCKZlZ9V6mm3/LKc= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/decred/dcrd/crypto/blake256 v1.0.0/go.mod h1:sQl2p6Y26YV+ZOcSTP6thNdn47hh8kt6rqSlvmrXFAc= -github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.0-20210816181553-5444fa50b93d/go.mod h1:tmAIfUFEirG/Y8jhZ9M+h36obRZAk/1fcSpXwAVlfqE= -github.com/decred/dcrd/dcrec/secp256k1/v4 v4.1.0 h1:HbphB4TFFXpv7MNrT52FGrrgVXF1owhMVTHFZIlnvd4= -github.com/decred/dcrd/dcrec/secp256k1/v4 v4.1.0/go.mod h1:DZGJHZMqrU4JJqFAWUS2UO1+lbSKsdiOoYi9Zzey7Fc= -github.com/deepmap/oapi-codegen v1.12.4 h1:pPmn6qI9MuOtCz82WY2Xaw46EQjgvxednXXrP7g5Q2s= -github.com/deepmap/oapi-codegen v1.12.4/go.mod h1:3lgHGMu6myQ2vqbbTXH2H1o4eXFTGnFiDaOaKKl5yas= -github.com/getkin/kin-openapi v0.115.0 h1:c8WHRLVY3G8m9jQTy0/DnIuljgRwTCB5twZytQS4JyU= -github.com/getkin/kin-openapi v0.115.0/go.mod h1:l5e9PaFUo9fyLJCPGQeXI2ML8c3P8BHOEV2VaAVf/pc= +github.com/decred/dcrd/crypto/blake256 v1.0.1/go.mod h1:2OfgNZ5wDpcsFmHmCK5gZTPcCXqlm2ArzUIkw9czNJo= +github.com/decred/dcrd/dcrec/secp256k1/v4 v4.2.0 h1:8UrgZ3GkP4i/CLijOJx79Yu+etlyjdBU4sfcs2WYQMs= +github.com/decred/dcrd/dcrec/secp256k1/v4 v4.2.0/go.mod h1:v57UDF4pDQJcEfFUCRop3lJL149eHGSe9Jvczhzjo/0= +github.com/deepmap/oapi-codegen v1.13.0 h1:cnFHelhsRQbYvanCUAbRSn/ZpkUb1HPRlQcu8YqSORQ= +github.com/deepmap/oapi-codegen v1.13.0/go.mod h1:Amy7tbubKY9qkZOXqymI3Z6xSbndmu+atMJheLdyg44= +github.com/gabriel-vasile/mimetype v1.4.2 h1:w5qFW6JKBz9Y393Y4q372O9A7cUSequkh1Q7OhCmWKU= +github.com/gabriel-vasile/mimetype v1.4.2/go.mod h1:zApsH/mKG4w07erKIaJPFiX0Tsq9BFQgN3qGY5GnNgA= +github.com/getkin/kin-openapi v0.118.0 h1:z43njxPmJ7TaPpMSCQb7PN0dEYno4tyBPQcrFdHoLuM= +github.com/getkin/kin-openapi v0.118.0/go.mod h1:l5e9PaFUo9fyLJCPGQeXI2ML8c3P8BHOEV2VaAVf/pc= +github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE= +github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI= +github.com/gin-gonic/gin v1.9.1 h1:4idEAncQnU5cB7BeOkPtxjfCSye0AAm1R0RVIqJ+Jmg= +github.com/gin-gonic/gin v1.9.1/go.mod h1:hPrL7YrpYKXt5YId3A/Tnip5kqbEAP+KLuI3SUcPTeU= github.com/go-openapi/jsonpointer v0.19.3/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= github.com/go-openapi/jsonpointer v0.19.5/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= github.com/go-openapi/jsonpointer v0.19.6 h1:eCs3fxoIi3Wh6vtgmLTOjdhSpiqphQ+DaPn38N2ZdrE= @@ -38,19 +45,22 @@ github.com/go-openapi/jsonpointer v0.19.6/go.mod h1:osyAmYz/mB/C3I+WsTTSgw1ONzaL github.com/go-openapi/jsonreference v0.20.0/go.mod h1:Ag74Ico3lPc+zR+qjn4XBUmXymS4zJbYVCZmcgkasdo= github.com/go-openapi/jsonreference v0.20.2 h1:3sVjiK66+uXK/6oQ8xgcRKcFgQ5KXa2KvnJRumpMGbE= github.com/go-openapi/jsonreference v0.20.2/go.mod h1:Bl1zwGIM8/wsvqjsOQLJ/SH+En5Ap4rVB5KVcIDZG2k= -github.com/go-openapi/spec v0.20.8 h1:ubHmXNY3FCIOinT8RNrrPfGc9t7I1qhPtdOGoG2AxRU= -github.com/go-openapi/spec v0.20.8/go.mod h1:2OpW+JddWPrpXSCIX8eOx7lZ5iyuWj3RYR6VaaBKcWA= +github.com/go-openapi/spec v0.20.9 h1:xnlYNQAwKd2VQRRfwTEI0DcK+2cbuvI/0c7jx3gA8/8= +github.com/go-openapi/spec v0.20.9/go.mod h1:2OpW+JddWPrpXSCIX8eOx7lZ5iyuWj3RYR6VaaBKcWA= github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= github.com/go-openapi/swag v0.19.15/go.mod h1:QYRuS/SOXUCsnplDa677K7+DxSOj6IPNl/eQntq43wQ= -github.com/go-openapi/swag v0.22.3 h1:yMBqmnQ0gyZvEb/+KzuWZOXgllrXT4SADYbvDaXHv/g= github.com/go-openapi/swag v0.22.3/go.mod h1:UzaqsxGiab7freDnrUUra0MwWfN/q7tE4j+VcZ0yl14= +github.com/go-openapi/swag v0.22.4 h1:QLMzNJnMGPRNDCbySlcj1x01tzU8/9LTTL9hZZZogBU= +github.com/go-openapi/swag v0.22.4/go.mod h1:UzaqsxGiab7freDnrUUra0MwWfN/q7tE4j+VcZ0yl14= +github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s= github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA= 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.1 h1:9c50NUPC30zyuKprjL3vNZ0m5oG+jU0zvx4AqHGnv4k= +github.com/go-playground/validator/v10 v10.14.1/go.mod h1:9iXMNT7sEkjXb0I+enO7QXmzG6QCsPWY4zveKFVRSyU= github.com/go-test/deep v1.0.8 h1:TDsG77qcSprGbC6vTN8OuXp5g+J+b5Pcguhf7Zt61VM= github.com/go-test/deep v1.0.8/go.mod h1:5C2ZWiW0ErCdrYzpqxLbTX7MG14M9iiw8DgHncVwcsE= -github.com/goccy/go-json v0.9.7/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I= 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-jwt/jwt v3.2.2+incompatible h1:IfV12K8xAKAnZqdXVzCZ+TOjboZ2keLg81eXfW3O+oY= @@ -68,6 +78,7 @@ github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/ github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I= github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/gorilla/mux v1.8.0 h1:i40aqfkR1h2SlN9hojwV5ZA91wcXFOvkdNIeFDP5koI= @@ -81,12 +92,15 @@ github.com/jmespath/go-jmespath/internal/testify v1.5.1 h1:shLQSRRSCCPj3f2gpwzGw github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U= github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY= github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= +github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= +github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= github.com/juju/gnuflag v0.0.0-20171113085948-2ce1bb71843d/go.mod h1:2PavIy+JPciBPrBUjwbNvtwB6RQlve+hkpll6QSNmOE= github.com/klauspost/compress v1.13.6/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk= -github.com/klauspost/compress v1.16.3 h1:XuJt9zzcnaz6a16/OU53ZjWp/v7/42WcR5t2a0PcNQY= -github.com/klauspost/compress v1.16.3/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE= -github.com/klauspost/compress v1.16.4 h1:91KN02FnsOYhuunwU4ssRe8lc2JosWmizWa91B5v1PU= -github.com/klauspost/compress v1.16.4/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE= +github.com/klauspost/compress v1.16.6 h1:91SKEy4K37vkp255cJ8QesJhjyRO0hn9i9G0GoUwLsk= +github.com/klauspost/compress v1.16.6/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE= +github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= +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/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= @@ -94,22 +108,22 @@ github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= -github.com/leodido/go-urn v1.2.2 h1:7z68G0FCGvDk646jz1AelTYNYWrTNm0bEcFAo147wt4= -github.com/leodido/go-urn v1.2.2/go.mod h1:kUaIbLZWttglzwNuG0pgsh5vuV6u2YcGBYz1hIPjtOQ= -github.com/leodido/go-urn v1.2.3 h1:6BE2vPT0lqoz3fmOesHZiaiFh7889ssCo2GMvLCfiuA= -github.com/leodido/go-urn v1.2.3/go.mod h1:7ZrI8mTSeBSHl/UaRyKQW1qZeMgak41ANeCNaVckg+4= +github.com/labstack/echo/v4 v4.10.2 h1:n1jAhnq/elIFTHr1EYpiYtyKgx4RW9ccVgkqByZaN2M= +github.com/labstack/echo/v4 v4.10.2/go.mod h1:OEyqf2//K1DFdE57vw2DRgWY0M7s65IVQO2FzvI4J5k= +github.com/labstack/gommon v0.4.0 h1:y7cvthEAEbU0yHOf4axH8ZG2NH8knB9iNSoTO8dyIk8= +github.com/labstack/gommon v0.4.0/go.mod h1:uW6kP17uPlLJsD3ijUYn3/M5bAxtlZhMI6m3MFxTMTM= +github.com/leodido/go-urn v1.2.4 h1:XlAE/cm/ms7TE/VMVoduSpNBoyc2dOxHs5MZSwAN63Q= +github.com/leodido/go-urn v1.2.4/go.mod h1:7ZrI8mTSeBSHl/UaRyKQW1qZeMgak41ANeCNaVckg+4= github.com/lestrrat-go/backoff/v2 v2.0.8 h1:oNb5E5isby2kiro9AgdHLv5N5tint1AnDVVf2E2un5A= github.com/lestrrat-go/backoff/v2 v2.0.8/go.mod h1:rHP/q/r9aT27n24JQLa7JhSQZCKBBOiM/uP402WwN8Y= -github.com/lestrrat-go/blackmagic v1.0.0/go.mod h1:TNgH//0vYSs8VXDCfkZLgIrVTTXQELZffUV0tz3MtdQ= github.com/lestrrat-go/blackmagic v1.0.1 h1:lS5Zts+5HIC/8og6cGHb0uCcNCa3OUt1ygh3Qz2Fe80= github.com/lestrrat-go/blackmagic v1.0.1/go.mod h1:UrEqBzIR2U6CnzVyUtfM6oZNMt/7O7Vohk2J0OGSAtU= github.com/lestrrat-go/httpcc v1.0.1 h1:ydWCStUeJLkpYyjLDHihupbn2tYmZ7m22BGkcvZZrIE= github.com/lestrrat-go/httpcc v1.0.1/go.mod h1:qiltp3Mt56+55GPVCbTdM9MlqhvzyuL6W/NMDA8vA5E= -github.com/lestrrat-go/iter v1.0.1/go.mod h1:zIdgO1mRKhn8l9vrZJZz9TUMMFbQbLeTsbqPDrJ/OJc= github.com/lestrrat-go/iter v1.0.2 h1:gMXo1q4c2pHmC3dn8LzRhJfP1ceCbgSiT9lUydIzltI= github.com/lestrrat-go/iter v1.0.2/go.mod h1:Momfcq3AnRlRjI5b5O8/G5/BvpzrhoFTZcn06fEOPt4= -github.com/lestrrat-go/jwx v1.2.25 h1:tAx93jN2SdPvFn08fHNAhqFJazn5mBBOB8Zli0g0otA= -github.com/lestrrat-go/jwx v1.2.25/go.mod h1:zoNuZymNl5lgdcu6P7K6ie2QRll5HVfF4xwxBBK1NxY= +github.com/lestrrat-go/jwx v1.2.26 h1:4iFo8FPRZGDYe1t19mQP0zTRqA7n8HnJ5lkIiDvJcB0= +github.com/lestrrat-go/jwx v1.2.26/go.mod h1:MaiCdGbn3/cckbOFSCluJlJMmp9dmZm5hDuIkx8ftpQ= github.com/lestrrat-go/option v1.0.0/go.mod h1:5ZHFbivi4xwXxhxY9XHDe2FHo6/Z7WWmtT7T5nBBp3I= github.com/lestrrat-go/option v1.0.1 h1:oAzP2fvZGQKWkvHa1/SAcFolBEca1oN+mQ7eooNBEYU= github.com/lestrrat-go/option v1.0.1/go.mod h1:5ZHFbivi4xwXxhxY9XHDe2FHo6/Z7WWmtT7T5nBBp3I= @@ -118,85 +132,103 @@ github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN github.com/mailru/easyjson v0.7.6/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0= github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= +github.com/mattn/go-colorable v0.1.11/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4= +github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= +github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= +github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= +github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/mattn/go-isatty v0.0.19 h1:JITubQf0MOLdlGRuRq+jtsDlekdYPia9ZFsB8h/APPA= +github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= +github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= +github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 h1:RWengNIwukTxcDr9M+97sNutRR1RKhG96O6jWumTTnw= github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826/go.mod h1:TaXosZuwdSHYgviHp1DAtfrULt5eUgsSMsZf+YrPgl8= github.com/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe/go.mod h1:wL8QJuTMNUDYhXwkmfOly8iTdp5TEcJFWZD2D7SIkUc= -github.com/montanaflynn/stats v0.7.0 h1:r3y12KyNxj/Sb/iOE46ws+3mS1+MZca1wlHQFPsY/JU= -github.com/montanaflynn/stats v0.7.0/go.mod h1:etXPPgVO6n31NxCd9KQUMvCM+ve0ruNzt6R8Bnaayow= +github.com/montanaflynn/stats v0.7.1 h1:etflOAAHORrCC44V+aR6Ftzort912ZU+YLiSTuV8eaE= +github.com/montanaflynn/stats v0.7.1/go.mod h1:etXPPgVO6n31NxCd9KQUMvCM+ve0ruNzt6R8Bnaayow= github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= +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/perimeterx/marshmallow v1.1.4 h1:pZLDH9RjlLGGorbXhcaQLhfuV0pFMNfPO55FuFkxqLw= github.com/perimeterx/marshmallow v1.1.4/go.mod h1:dsXbUu8CRzfYP5a87xpp0xq9S3u0Vchtcl8we9tYaXw= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/pquerna/cachecontrol v0.1.0 h1:yJMy84ti9h/+OEWa752kBTKv4XC30OtVVHYv/8cTqKc= -github.com/pquerna/cachecontrol v0.1.0/go.mod h1:NrUG3Z7Rdu85UNR3vm7SOsl1nFIeSiQnrHV5K9mBcUI= +github.com/pquerna/cachecontrol v0.2.0 h1:vBXSNuE5MYP9IJ5kjsdo8uq+w41jSPgvba2DEnkRx9k= +github.com/pquerna/cachecontrol v0.2.0/go.mod h1:NrUG3Z7Rdu85UNR3vm7SOsl1nFIeSiQnrHV5K9mBcUI= github.com/pquerna/otp v1.4.0 h1:wZvl1TIVxKRThZIBiwOOHOGP/1+nZyWBil9Y2XNEDzg= github.com/pquerna/otp v1.4.0/go.mod h1:dkJfzwRKNiegxyNb54X/3fLwhCynbMspSyWKnvi1AEg= -github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8= -github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs= +github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ= +github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog= github.com/rokwire/core-auth-library-go/v3 v3.0.1 h1:7kZqnXq3lsb8sU+YxXEtHXjmxvFd5X/VpqQKiy/RnqA= github.com/rokwire/core-auth-library-go/v3 v3.0.1/go.mod h1:VtpVajbA8JPjOzvEFQpxOm4pfok4z/8a2WshErTZd7s= github.com/rokwire/logging-library-go/v2 v2.2.0 h1:SKFq+rrl+li1RhEhB7CV+pVcptu/nurX9/DWj/oRaw4= github.com/rokwire/logging-library-go/v2 v2.2.0/go.mod h1:6QSqTlk5nNQcZweqg0sLCCoIwpRpTu3AmOi7EJy38Tg= -github.com/rwtodd/Go.Sed v0.0.0-20210816025313-55464686f9ef/go.mod h1:8AEUvGVi2uQ5b24BIhcr0GCcpd/RNAFWaN2CJFrWIIQ= -github.com/sirupsen/logrus v1.9.0 h1:trlNQbNUG3OdDrDil03MCb1H2o9nJ1x4/5LYw7byDE0= -github.com/sirupsen/logrus v1.9.0/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= +github.com/rs/cors v1.9.0 h1:l9HGsTsHJcvW14Nk7J9KFz8bzeAWXn3CG6bgt7LsrAE= +github.com/rs/cors v1.9.0/go.mod h1:XyqrcTp5zjWr1wsJ8PIRZssZ8b/WMcMf71DJnit4EMU= +github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ= +github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= github.com/spkg/bom v0.0.0-20160624110644-59b7046e48ad/go.mod h1:qLr4V1qq6nMqFKkMo8ZTx3f+BZEkzsRUY10Xsm2mwU0= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= github.com/stretchr/objx v0.5.0 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c= github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= -github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= 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 h1:+h33VjcLVPDHtOdpUCuF+7gSuG3yGIftsP1YvFihtJ8= 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/swaggo/files v1.0.1 h1:J1bVJ4XHZNq0I46UU90611i9/YzdrF7x92oX1ig5IdE= github.com/swaggo/files v1.0.1/go.mod h1:0qXmMNH6sXNf+73t65aKeB+ApmgxdnkQzVTAj2uaMUg= github.com/swaggo/http-swagger v1.3.4 h1:q7t/XLx0n15H1Q9/tk3Y9L4n210XzJF5WtnDX64a5ww= github.com/swaggo/http-swagger v1.3.4/go.mod h1:9dAh0unqMBAlbp1uE2Uc2mQTxNMU/ha4UbucIg1MFkQ= -github.com/swaggo/swag v1.8.12 h1:pctzkNPu0AlQP2royqX3apjKCQonAnf7KGoxeO4y64w= -github.com/swaggo/swag v1.8.12/go.mod h1:lNfm6Gg+oAq3zRJQNEMBE66LIJKM44mxFqhEEgy2its= -github.com/tidwall/pretty v1.0.0 h1:HsD+QiTn7sK6flMKIvNmpqz1qrpP3Ps6jOKIKMooyg4= -github.com/tidwall/pretty v1.0.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk= -github.com/ugorji/go v1.2.7 h1:qYhyWUUd6WbiM+C6JZAUkIJt/1WrjzNHY9+KCIjVqTo= +github.com/swaggo/swag v1.16.1 h1:fTNRhKstPKxcnoKsytm4sahr8FaYzUcT7i1/3nd/fBg= +github.com/swaggo/swag v1.16.1/go.mod h1:9/LMvHycG3NFHfR6LwvikHv5iFvmPADQ359cKikGxto= +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 v1.2.7/go.mod h1:nF9osbDWLy6bDVv/Rtoh6QgnvNDpmCalQV5urGCCS6M= -github.com/ugorji/go/codec v1.2.7 h1:YPXUKf7fYbp/y8xloBqZOw2qaVggbfwMlI8WM3wZUJ0= github.com/ugorji/go/codec v1.2.7/go.mod h1:WGN1fab3R1fzQlVQTkfxVtIBhWDRqOviHU95kRgeqEY= +github.com/ugorji/go/codec v1.2.11 h1:BMaWp1Bb6fHwEtbplGBGJ498wD+LKlNSl25MjdZY4dU= +github.com/ugorji/go/codec v1.2.11/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg= +github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw= +github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= +github.com/valyala/fasttemplate v1.2.1/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+qRAEEKiv+SiQ= +github.com/valyala/fasttemplate v1.2.2 h1:lxLXG0uE3Qnshl9QyaK6XJxMXlQZELvChBOCmQD0Loo= +github.com/valyala/fasttemplate v1.2.2/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+qRAEEKiv+SiQ= github.com/xdg-go/pbkdf2 v1.0.0 h1:Su7DPu48wXMwC3bs7MCNG+z4FhcyEuz5dlvchbq0B0c= github.com/xdg-go/pbkdf2 v1.0.0/go.mod h1:jrpuAogTd400dnrH08LKmI/xc1MbPOebTwRqcT5RDeI= -github.com/xdg-go/scram v1.1.1/go.mod h1:RaEWvsqvNKKvBPvcKeFjrG2cJqOkHTiyTpzz23ni57g= github.com/xdg-go/scram v1.1.2 h1:FHX5I5B4i4hKRVRBCFRxq1iQRej7WO3hhBuJf+UUySY= github.com/xdg-go/scram v1.1.2/go.mod h1:RT/sEzTbU5y00aCK8UOx6R7YryM0iF1N2MOmC3kKLN4= -github.com/xdg-go/stringprep v1.0.3/go.mod h1:W3f5j4i+9rC0kuIEJL0ky1VpHXQU3ocBgklLGvcBnW8= github.com/xdg-go/stringprep v1.0.4 h1:XLI/Ng3O1Atzq0oBs3TWm+5ZVgkq2aqdlvP9JtoZ6c8= github.com/xdg-go/stringprep v1.0.4/go.mod h1:mPGuuIYwz7CmR2bT9j4GbQqutWS1zV24gijq1dTyGkM= github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d/go.mod h1:rHwXgn7JulP+udvsHwJoVG1YGAP6VLg4y9I5dyZdqmA= github.com/youmark/pkcs8 v0.0.0-20201027041543-1326539a0a0a h1:fZHgsYlfvtyqToslyjUt3VOPF4J7aK/3MPcK7xp3PDk= github.com/youmark/pkcs8 v0.0.0-20201027041543-1326539a0a0a/go.mod h1:ul22v+Nro/R083muKhosV54bj5niojjWZvU8xrevuH4= github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= -go.mongodb.org/mongo-driver v1.11.3 h1:Ql6K6qYHEzB6xvu4+AU0BoRoqf9vFPcc4o7MUIdPW8Y= -go.mongodb.org/mongo-driver v1.11.3/go.mod h1:PTSz5yu21bkT/wXpkS7WR5f0ddqw5quethTUn9WM+2g= -go.mongodb.org/mongo-driver v1.11.4 h1:4ayjakA013OdpGyL2K3ZqylTac/rMjrJOMZ1EHizXas= -go.mongodb.org/mongo-driver v1.11.4/go.mod h1:PTSz5yu21bkT/wXpkS7WR5f0ddqw5quethTUn9WM+2g= +go.mongodb.org/mongo-driver v1.12.0 h1:aPx33jmn/rQuJXPQLZQ8NtfPQG8CaqgLThFtqRb0PiE= +go.mongodb.org/mongo-driver v1.12.0/go.mod h1:AZkxhPnFJUoH7kZlFkVKucV20K387miPfm7oimrSmK0= +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/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20200302210943-78000ba7a073/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= -golang.org/x/crypto v0.0.0-20220427172511-eb4f295cb31f/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= -golang.org/x/crypto v0.7.0 h1:AvwMYaRytfdeVt3u6mLaxYtErKYjxA2OXjJ1HHq6t3A= -golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU= -golang.org/x/crypto v0.8.0 h1:pd9TJtTueMTVQXzk8E2XESSMQDj/U7OUu0PqJqPXQjQ= -golang.org/x/crypto v0.8.0/go.mod h1:mRqEX+O9/h5TFCrQhkgjo2yKi0yYA+9ecGkdQoHrywE= +golang.org/x/crypto v0.9.0/go.mod h1:yrmDGqONDYtNj3tH8X9dzUun2m2lzPa9ngI6/RUPGR0= +golang.org/x/crypto v0.10.0 h1:LKqV2xt9+kDzSTfOhx4FrkEBcMrAgHSYgzywV9zcGmM= +golang.org/x/crypto v0.10.0/go.mod h1:o4eNf7Ede1fv+hwOwZsTHl9EsPFO6q6ZvYR8vYfY45I= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= -golang.org/x/mod v0.9.0 h1:KENHtAZL2y3NLMYZeHY9DW8HW8V+kQyJsY/V9JlKvCs= -golang.org/x/mod v0.10.0 h1:lFO9qtOdlre5W1jxS3r/4szv2/6iXxScdzjoBMXNhYk= +golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= +golang.org/x/mod v0.11.0 h1:bUO06HqtnRcc/7l71XBe4WcqTZ+3AH1J59zWDDwLKgU= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= @@ -205,38 +237,41 @@ golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= 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.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= -golang.org/x/net v0.8.0 h1:Zrh2ngAOFYneWTAIAPethzeaQLuHwhuBkuV6ZiRnUaQ= -golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc= -golang.org/x/net v0.9.0 h1:aWJ/m6xSmxWBx+V0XRHTlrYrPG56jKsLdTFmsSsCzOM= -golang.org/x/net v0.9.0/go.mod h1:d48xBJpPfHeWQsugry2m+kC02ZBRGRgulfHnEXEuWns= -golang.org/x/oauth2 v0.6.0 h1:Lh8GPgSKBfWSwFvtuWOfeI3aAAnbXTSutYxJiOJFgIw= -golang.org/x/oauth2 v0.6.0/go.mod h1:ycmewcwgD4Rpr3eZJLSB4Kyyljb3qDh40vJ8STE5HKw= -golang.org/x/oauth2 v0.7.0 h1:qe6s0zUXlPX80/dITx3440hWZ7GwMwgDDyrSGTPJG/g= -golang.org/x/oauth2 v0.7.0/go.mod h1:hPLQkd9LyjfXTiRohC/41GhcFqxisoUQ99sCUOHO9x4= +golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= +golang.org/x/net v0.11.0 h1:Gi2tvZIJyBtO9SDr1q9h5hEQCp/4L2RQ+ar0qjx2oNU= +golang.org/x/net v0.11.0/go.mod h1:2L/ixqYpgIVXmeoSA/4Lu7BzTG4KIyPIryS4IsOd1oQ= +golang.org/x/oauth2 v0.9.0 h1:BPpt2kU7oMRq3kCHAA1tbSEshXRw1LpG2ztgDwrzuAs= +golang.org/x/oauth2 v0.9.0/go.mod h1:qYgFZaFiu6Wg24azG8bdV52QJXJGbZzIIsRCdVKzbLw= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.1.0 h1:wsuoTGHzEhffawBOhz5CYhcrV4IdKZbEyZjBMuTp12o= golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.3.0 h1:ftCYgMx6zT/asHUrPw8BLLscYtGznsLAnjq5RH9P66E= +golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423082822-04245dca01da/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-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211103235746-7861aae1554b/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-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-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.6.0 h1:MVltZSvRTcU2ljQOhs94SXPftV6DCNnZViHeQps87pQ= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.7.0 h1:3jlCCIQZPdOYu1h8BkNvLz8Kgwtae2cagcG/VamtZRU= -golang.org/x/sys v0.7.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.9.0 h1:KS/R3tvhPqvJvwcKfnBHJwwthS11LRhmM5D59eEXa0s= +golang.org/x/sys v0.9.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.1.0/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= +golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= @@ -245,26 +280,24 @@ golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ= golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= -golang.org/x/text v0.8.0 h1:57P1ETyNKtuIjB4SRd15iJxuhj8Gc416Y78H3qgMh68= -golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= -golang.org/x/text v0.9.0 h1:2sjJmO8cDvYveuX97RDLsxlyUxLl+GHoLxBiRdHllBE= golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= +golang.org/x/text v0.10.0 h1:UpjohKhiEgNc0CSauXmwYftY1+LlaC75SJwh0SgCX58= +golang.org/x/text v0.10.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= -golang.org/x/tools v0.7.0 h1:W4OVu8VVOaIO0yzWMNdepAulS7YfoS3Zabrm8DOXXU4= -golang.org/x/tools v0.7.0/go.mod h1:4pg6aUX35JBAogB10C9AtvVL+qowtN4pT3CGSQex14s= -golang.org/x/tools v0.8.0 h1:vSDcovVPld282ceKgDimkRSC8kpaH1dgyc9UMzlt84Y= -golang.org/x/tools v0.8.0/go.mod h1:JxBZ99ISMI5ViVkT1tr6tdNmXeTrcpVSD3vZ1RsRdN4= +golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= +golang.org/x/tools v0.10.0 h1:tvDr/iQoUqNdohiYm0LmmKcBk+q86lb9EprIUFhHHGg= +golang.org/x/tools v0.10.0/go.mod h1:UJwyiVBsOA2uwvK/e5OY3GTpDUJriEd+/YlqAwLPmyM= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= google.golang.org/appengine v1.6.7 h1:FZR1q0exgwxzPzp/aF+VccGrSfxfPpkBqjIIEq3ru6c= google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= -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/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc h1:2gGKlE2+asNV9m7xrywl36YYNnBG5ZQ0r/BOOxqPpmk= gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc/go.mod h1:m7x9LTH6d71AHyAX77c9yqWCCa3UKHcVEj9y7hAtKDk= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= @@ -285,8 +318,10 @@ gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.0/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gotest.tools v2.2.0+incompatible h1:VsBPFP1AI068pPrMxtb/S8Zkgf9xEmTLJjfM+P5UIEo= gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw= +rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4= diff --git a/main.go b/main.go index f749c8bd7..54e0b753b 100644 --- a/main.go +++ b/main.go @@ -17,6 +17,7 @@ package main import ( "core-building-block/core" "core-building-block/core/auth" + "core-building-block/core/model" "core-building-block/driven/emailer" "core-building-block/driven/identitybb" "core-building-block/driven/profilebb" @@ -28,10 +29,13 @@ import ( "strings" "github.com/rokwire/core-auth-library-go/v3/authservice" + "github.com/rokwire/core-auth-library-go/v3/authutils" "github.com/rokwire/core-auth-library-go/v3/envloader" "github.com/rokwire/core-auth-library-go/v3/keys" + "github.com/rokwire/logging-library-go/v2/errors" "github.com/rokwire/logging-library-go/v2/logs" + "github.com/rokwire/logging-library-go/v2/logutils" ) var ( @@ -194,7 +198,26 @@ func main() { coreAPIs := core.NewCoreAPIs(env, Version, Build, serviceID, storageAdapter, authImpl, systemInitSettings, logger) coreAPIs.Start() + // read CORS parameters from stored env config + var envData *model.EnvConfigData + var corsAllowedHeaders []string + var corsAllowedOrigins []string + config, err := storageAdapter.FindConfig(model.ConfigTypeEnv, authutils.AllApps, authutils.AllOrgs) + if err != nil { + logger.Fatal(errors.WrapErrorAction(logutils.ActionFind, model.TypeConfig, nil, err).Error()) + } + if config != nil { + envData, err = model.GetConfigData[model.EnvConfigData](*config) + if err != nil { + logger.Fatal(errors.WrapErrorAction(logutils.ActionCast, model.TypeEnvConfigData, nil, err).Error()) + } + + corsAllowedHeaders = envData.CORSAllowedHeaders + corsAllowedOrigins = envData.CORSAllowedOrigins + } + //web adapter - webAdapter := web.NewWebAdapter(env, authImpl.ServiceRegManager, port, coreAPIs, host, baseServerURL, prodServerURL, testServerURL, devServerURL, logger) + webAdapter := web.NewWebAdapter(env, authImpl.ServiceRegManager, port, coreAPIs, host, corsAllowedOrigins, + corsAllowedHeaders, baseServerURL, prodServerURL, testServerURL, devServerURL, logger) webAdapter.Start() } diff --git a/utils/utils.go b/utils/utils.go index 5d6fcbe3e..87d05ee91 100644 --- a/utils/utils.go +++ b/utils/utils.go @@ -223,3 +223,38 @@ func GetPrintableString(v *string, defaultVal string) string { } return defaultVal } + +// StartTimer starts a timer with the given name, period, and function to call when the timer goes off +func StartTimer(timer *time.Timer, timerDone chan bool, period time.Duration, periodicFunc func(), name string, logger *logs.Logger) { + if logger != nil { + logger.Info("start timer for " + name) + } + + //cancel if active + if timer != nil { + timerDone <- true + timer.Stop() + } + + onTimer(timer, timerDone, period, periodicFunc, name, logger) +} + +func onTimer(timer *time.Timer, timerDone chan bool, period time.Duration, periodicFunc func(), name string, logger *logs.Logger) { + if logger != nil { + logger.Info(name) + } + + periodicFunc() + + timer = time.NewTimer(period) + select { + case <-timer.C: + // timer expired + timer = nil + + onTimer(timer, timerDone, period, periodicFunc, name, logger) + case <-timerDone: + // timer aborted + timer = nil + } +}