From ef4a2f3f22a2dcc6d653e7ea404f08568082a37b Mon Sep 17 00:00:00 2001 From: Henry Date: Mon, 8 Feb 2021 17:47:42 +0100 Subject: [PATCH] sqlite and auth setup --- README.md | 28 + admindb/interface.go | 14 +- admindb/mockdb/auth.go | 8 +- admindb/mockdb/auth_fallback.go | 101 ++- admindb/sqlite/aliases.go | 14 + admindb/sqlite/auth_fallback.go | 58 ++ admindb/sqlite/auth_withssb.go | 14 + admindb/sqlite/generate_models.sh | 7 + admindb/sqlite/generated.db | Bin 0 -> 32768 bytes admindb/sqlite/models/aliases.go | 819 ++++++++++++++++++++ admindb/sqlite/models/aliases_test.go | 684 ++++++++++++++++ admindb/sqlite/models/auth_fallback.go | 782 +++++++++++++++++++ admindb/sqlite/models/auth_fallback_test.go | 684 ++++++++++++++++ admindb/sqlite/models/boil_main_test.go | 119 +++ admindb/sqlite/models/boil_queries.go | 33 + admindb/sqlite/models/boil_queries_test.go | 52 ++ admindb/sqlite/models/boil_suites_test.go | 139 ++++ admindb/sqlite/models/boil_table_names.go | 12 + admindb/sqlite/models/boil_types.go | 52 ++ admindb/sqlite/models/sqlite3_main_test.go | 93 +++ admindb/sqlite/new.go | 68 ++ admindb/sqlite/roomcfg.go | 14 + admindb/sqlite/schema-v1.sql | 14 + admindb/sqlite/sqlboiler.toml | 21 + cmd/insert-user/main.go | 50 ++ cmd/server/main.go | 9 +- go.mod | 27 +- go.sum | 192 ++++- web/handlers/auth/handler.go | 4 + web/handlers/http.go | 22 +- web/handlers/http_test.go | 15 +- web/handlers/setup_test.go | 10 +- web/templates/auth/fallback_sign_in.tmpl | 4 +- web/utils.go | 58 ++ 34 files changed, 4165 insertions(+), 56 deletions(-) create mode 100644 admindb/sqlite/aliases.go create mode 100644 admindb/sqlite/auth_fallback.go create mode 100644 admindb/sqlite/auth_withssb.go create mode 100644 admindb/sqlite/generate_models.sh create mode 100644 admindb/sqlite/generated.db create mode 100644 admindb/sqlite/models/aliases.go create mode 100644 admindb/sqlite/models/aliases_test.go create mode 100644 admindb/sqlite/models/auth_fallback.go create mode 100644 admindb/sqlite/models/auth_fallback_test.go create mode 100644 admindb/sqlite/models/boil_main_test.go create mode 100644 admindb/sqlite/models/boil_queries.go create mode 100644 admindb/sqlite/models/boil_queries_test.go create mode 100644 admindb/sqlite/models/boil_suites_test.go create mode 100644 admindb/sqlite/models/boil_table_names.go create mode 100644 admindb/sqlite/models/boil_types.go create mode 100644 admindb/sqlite/models/sqlite3_main_test.go create mode 100644 admindb/sqlite/new.go create mode 100644 admindb/sqlite/roomcfg.go create mode 100644 admindb/sqlite/schema-v1.sql create mode 100644 admindb/sqlite/sqlboiler.toml create mode 100644 cmd/insert-user/main.go diff --git a/README.md b/README.md index f3787fd..5879087 100644 --- a/README.md +++ b/README.md @@ -47,6 +47,34 @@ This way it won't use the assets that are embedded in the binary but read them d Once you are done with your changes run `go generate` in package web to update them. +## Tooling + +### mocks + +[counterfeiter](https://github.com/maxbrunsfeld/counterfeiter) enables generating mocks for defined interfaces. To update them run `go generate` in package admindb. + +TODO: automate setup of tool + +### No ORM + +We use [sqlboiler](github.com/volatiletech/sqlboiler) to generate type-safe Go code code directly from SQL statements and table definitions. This approach suits the programming language much more then classical ORM approaches, which usually rely havily on reflection for (un)packing structs. + +To generate them run the following commands. This will populate `admindb/sqlite/models`: + + +```bash +cd admindb/sqlite +rm generate.db +sqlite3 generate.db < schema-v1.sql +sqlboiler sqlite3 --wipe +``` + +The generated package `admindb/sqlite/models` is then used to implemente the custom logic of the different services in `admindb/sqlite` + +TODO: automate this with `go generate` + +Aside: I would have used `sqlc` since it's a bit more minimal and uses hand written SQL queries instead of generic query builders but it [currently doesn't support sqlite](https://github.com/kyleconroy/sqlc/issues/161). + ## Testing ### Rooms diff --git a/admindb/interface.go b/admindb/interface.go index a000ce8..5cdeb30 100644 --- a/admindb/interface.go +++ b/admindb/interface.go @@ -4,13 +4,15 @@ import ( "go.mindeco.de/http/auth" ) -// FallbackAuth might be helpful for scenarios where one lost access to his ssb device or key -type FallbackAuth interface { +// AuthFallbackService might be helpful for scenarios where one lost access to his ssb device or key +type AuthFallbackService interface { auth.Auther + + Create(user string, password []byte) error } -// AuthService defines functions needed for the challange/response system of sign-in with ssb -type AuthService interface{} +// AuthWithSSBService defines functions needed for the challange/response system of sign-in with ssb +type AuthWithSSBService interface{} // RoomService deals with changing the privacy modes and managing the allow/deny lists of the room type RoomService interface{} @@ -20,9 +22,9 @@ type AliasService interface{} // for tests we use generated mocks from these interfaces created with https://github.com/maxbrunsfeld/counterfeiter -//go:generate counterfeiter -o mockdb/auth.go . AuthService +//go:generate counterfeiter -o mockdb/auth.go . AuthWithSSBService -//go:generate counterfeiter -o mockdb/auth_fallback.go . FallbackAuth +//go:generate counterfeiter -o mockdb/auth_fallback.go . AuthFallbackService //go:generate counterfeiter -o mockdb/room.go . RoomService diff --git a/admindb/mockdb/auth.go b/admindb/mockdb/auth.go index 60ec6c0..4c8d39d 100644 --- a/admindb/mockdb/auth.go +++ b/admindb/mockdb/auth.go @@ -7,12 +7,12 @@ import ( "github.com/ssb-ngi-pointer/gossb-rooms/admindb" ) -type FakeAuthService struct { +type FakeAuthWithSSBService struct { invocations map[string][][]interface{} invocationsMutex sync.RWMutex } -func (fake *FakeAuthService) Invocations() map[string][][]interface{} { +func (fake *FakeAuthWithSSBService) Invocations() map[string][][]interface{} { fake.invocationsMutex.RLock() defer fake.invocationsMutex.RUnlock() copiedInvocations := map[string][][]interface{}{} @@ -22,7 +22,7 @@ func (fake *FakeAuthService) Invocations() map[string][][]interface{} { return copiedInvocations } -func (fake *FakeAuthService) recordInvocation(key string, args []interface{}) { +func (fake *FakeAuthWithSSBService) recordInvocation(key string, args []interface{}) { fake.invocationsMutex.Lock() defer fake.invocationsMutex.Unlock() if fake.invocations == nil { @@ -34,4 +34,4 @@ func (fake *FakeAuthService) recordInvocation(key string, args []interface{}) { fake.invocations[key] = append(fake.invocations[key], args) } -var _ admindb.AuthService = new(FakeAuthService) +var _ admindb.AuthWithSSBService = new(FakeAuthWithSSBService) diff --git a/admindb/mockdb/auth_fallback.go b/admindb/mockdb/auth_fallback.go index 43fbb7c..805d59e 100644 --- a/admindb/mockdb/auth_fallback.go +++ b/admindb/mockdb/auth_fallback.go @@ -7,7 +7,7 @@ import ( "github.com/ssb-ngi-pointer/gossb-rooms/admindb" ) -type FakeFallbackAuth struct { +type FakeAuthFallbackService struct { CheckStub func(string, string) (interface{}, error) checkMutex sync.RWMutex checkArgsForCall []struct { @@ -22,11 +22,23 @@ type FakeFallbackAuth struct { result1 interface{} result2 error } + CreateStub func(string, []byte) error + createMutex sync.RWMutex + createArgsForCall []struct { + arg1 string + arg2 []byte + } + createReturns struct { + result1 error + } + createReturnsOnCall map[int]struct { + result1 error + } invocations map[string][][]interface{} invocationsMutex sync.RWMutex } -func (fake *FakeFallbackAuth) Check(arg1 string, arg2 string) (interface{}, error) { +func (fake *FakeAuthFallbackService) Check(arg1 string, arg2 string) (interface{}, error) { fake.checkMutex.Lock() ret, specificReturn := fake.checkReturnsOnCall[len(fake.checkArgsForCall)] fake.checkArgsForCall = append(fake.checkArgsForCall, struct { @@ -46,26 +58,26 @@ func (fake *FakeFallbackAuth) Check(arg1 string, arg2 string) (interface{}, erro return fakeReturns.result1, fakeReturns.result2 } -func (fake *FakeFallbackAuth) CheckCallCount() int { +func (fake *FakeAuthFallbackService) CheckCallCount() int { fake.checkMutex.RLock() defer fake.checkMutex.RUnlock() return len(fake.checkArgsForCall) } -func (fake *FakeFallbackAuth) CheckCalls(stub func(string, string) (interface{}, error)) { +func (fake *FakeAuthFallbackService) CheckCalls(stub func(string, string) (interface{}, error)) { fake.checkMutex.Lock() defer fake.checkMutex.Unlock() fake.CheckStub = stub } -func (fake *FakeFallbackAuth) CheckArgsForCall(i int) (string, string) { +func (fake *FakeAuthFallbackService) CheckArgsForCall(i int) (string, string) { fake.checkMutex.RLock() defer fake.checkMutex.RUnlock() argsForCall := fake.checkArgsForCall[i] return argsForCall.arg1, argsForCall.arg2 } -func (fake *FakeFallbackAuth) CheckReturns(result1 interface{}, result2 error) { +func (fake *FakeAuthFallbackService) CheckReturns(result1 interface{}, result2 error) { fake.checkMutex.Lock() defer fake.checkMutex.Unlock() fake.CheckStub = nil @@ -75,7 +87,7 @@ func (fake *FakeFallbackAuth) CheckReturns(result1 interface{}, result2 error) { }{result1, result2} } -func (fake *FakeFallbackAuth) CheckReturnsOnCall(i int, result1 interface{}, result2 error) { +func (fake *FakeAuthFallbackService) CheckReturnsOnCall(i int, result1 interface{}, result2 error) { fake.checkMutex.Lock() defer fake.checkMutex.Unlock() fake.CheckStub = nil @@ -91,11 +103,80 @@ func (fake *FakeFallbackAuth) CheckReturnsOnCall(i int, result1 interface{}, res }{result1, result2} } -func (fake *FakeFallbackAuth) Invocations() map[string][][]interface{} { +func (fake *FakeAuthFallbackService) Create(arg1 string, arg2 []byte) error { + var arg2Copy []byte + if arg2 != nil { + arg2Copy = make([]byte, len(arg2)) + copy(arg2Copy, arg2) + } + fake.createMutex.Lock() + ret, specificReturn := fake.createReturnsOnCall[len(fake.createArgsForCall)] + fake.createArgsForCall = append(fake.createArgsForCall, struct { + arg1 string + arg2 []byte + }{arg1, arg2Copy}) + stub := fake.CreateStub + fakeReturns := fake.createReturns + fake.recordInvocation("Create", []interface{}{arg1, arg2Copy}) + fake.createMutex.Unlock() + if stub != nil { + return stub(arg1, arg2) + } + if specificReturn { + return ret.result1 + } + return fakeReturns.result1 +} + +func (fake *FakeAuthFallbackService) CreateCallCount() int { + fake.createMutex.RLock() + defer fake.createMutex.RUnlock() + return len(fake.createArgsForCall) +} + +func (fake *FakeAuthFallbackService) CreateCalls(stub func(string, []byte) error) { + fake.createMutex.Lock() + defer fake.createMutex.Unlock() + fake.CreateStub = stub +} + +func (fake *FakeAuthFallbackService) CreateArgsForCall(i int) (string, []byte) { + fake.createMutex.RLock() + defer fake.createMutex.RUnlock() + argsForCall := fake.createArgsForCall[i] + return argsForCall.arg1, argsForCall.arg2 +} + +func (fake *FakeAuthFallbackService) CreateReturns(result1 error) { + fake.createMutex.Lock() + defer fake.createMutex.Unlock() + fake.CreateStub = nil + fake.createReturns = struct { + result1 error + }{result1} +} + +func (fake *FakeAuthFallbackService) CreateReturnsOnCall(i int, result1 error) { + fake.createMutex.Lock() + defer fake.createMutex.Unlock() + fake.CreateStub = nil + if fake.createReturnsOnCall == nil { + fake.createReturnsOnCall = make(map[int]struct { + result1 error + }) + } + fake.createReturnsOnCall[i] = struct { + result1 error + }{result1} +} + +func (fake *FakeAuthFallbackService) Invocations() map[string][][]interface{} { fake.invocationsMutex.RLock() defer fake.invocationsMutex.RUnlock() fake.checkMutex.RLock() defer fake.checkMutex.RUnlock() + fake.createMutex.RLock() + defer fake.createMutex.RUnlock() copiedInvocations := map[string][][]interface{}{} for key, value := range fake.invocations { copiedInvocations[key] = value @@ -103,7 +184,7 @@ func (fake *FakeFallbackAuth) Invocations() map[string][][]interface{} { return copiedInvocations } -func (fake *FakeFallbackAuth) recordInvocation(key string, args []interface{}) { +func (fake *FakeAuthFallbackService) recordInvocation(key string, args []interface{}) { fake.invocationsMutex.Lock() defer fake.invocationsMutex.Unlock() if fake.invocations == nil { @@ -115,4 +196,4 @@ func (fake *FakeFallbackAuth) recordInvocation(key string, args []interface{}) { fake.invocations[key] = append(fake.invocations[key], args) } -var _ admindb.FallbackAuth = new(FakeFallbackAuth) +var _ admindb.AuthFallbackService = new(FakeAuthFallbackService) diff --git a/admindb/sqlite/aliases.go b/admindb/sqlite/aliases.go new file mode 100644 index 0000000..0f54989 --- /dev/null +++ b/admindb/sqlite/aliases.go @@ -0,0 +1,14 @@ +package sqlite + +import ( + "database/sql" + + "github.com/ssb-ngi-pointer/gossb-rooms/admindb" +) + +// make sure to implement interfaces correctly +var _ admindb.AliasService = (*Aliases)(nil) + +type Aliases struct { + db *sql.DB +} diff --git a/admindb/sqlite/auth_fallback.go b/admindb/sqlite/auth_fallback.go new file mode 100644 index 0000000..4965c08 --- /dev/null +++ b/admindb/sqlite/auth_fallback.go @@ -0,0 +1,58 @@ +package sqlite + +import ( + "context" + "database/sql" + "fmt" + + "github.com/volatiletech/sqlboiler/v4/boil" + + "golang.org/x/crypto/bcrypt" + + "github.com/ssb-ngi-pointer/gossb-rooms/admindb/sqlite/models" + "github.com/volatiletech/sqlboiler/v4/queries/qm" + + "github.com/ssb-ngi-pointer/gossb-rooms/admindb" +) + +// make sure to implement interfaces correctly +var _ admindb.AuthFallbackService = (*AuthFallback)(nil) + +type AuthFallback struct { + db *sql.DB +} + +func (ah AuthFallback) Check(name, password string) (interface{}, error) { + ctx := context.Background() + found, err := models.AuthFallbacks(qm.Where("name = ?", name)).One(ctx, ah.db) + if err != nil { + return nil, err + } + + err = bcrypt.CompareHashAndPassword(found.PasswordHash, []byte(password)) + if err != nil { + return nil, fmt.Errorf("auth/fallback: password missmatch") + } + + return found.ID, nil +} + +func (ah AuthFallback) Create(name string, password []byte) error { + var u models.AuthFallback + u.Name = name + + hashed, err := bcrypt.GenerateFromPassword(password, bcrypt.DefaultCost) + if err != nil { + return fmt.Errorf("auth/fallback: failed to hash password for new user") + } + + u.PasswordHash = hashed + + ctx := context.Background() + err = u.Insert(ctx, ah.db, boil.Infer()) + if err != nil { + return fmt.Errorf("auth/fallback: failed to insert new user: %w", err) + } + + return nil +} diff --git a/admindb/sqlite/auth_withssb.go b/admindb/sqlite/auth_withssb.go new file mode 100644 index 0000000..c40a29e --- /dev/null +++ b/admindb/sqlite/auth_withssb.go @@ -0,0 +1,14 @@ +package sqlite + +import ( + "database/sql" + + "github.com/ssb-ngi-pointer/gossb-rooms/admindb" +) + +// make sure to implement interfaces correctly +var _ admindb.AuthWithSSBService = (*AuthWithSSB)(nil) + +type AuthWithSSB struct { + db *sql.DB +} diff --git a/admindb/sqlite/generate_models.sh b/admindb/sqlite/generate_models.sh new file mode 100644 index 0000000..d4bf82c --- /dev/null +++ b/admindb/sqlite/generate_models.sh @@ -0,0 +1,7 @@ +#!/bin/sh + +dbName=generated.db + +test -f $dbName && rm $dbName +sqlite3 $dbName < schema-v1.sql +sqlboiler sqlite3 --wipe \ No newline at end of file diff --git a/admindb/sqlite/generated.db b/admindb/sqlite/generated.db new file mode 100644 index 0000000000000000000000000000000000000000..349dfddcaa09611adfa4dd14b06d865e4f76c9ea GIT binary patch literal 32768 zcmeI&zi-+=6u|K_Avi+f$Hu_&)P+VWm6A-ET3T6E6hZ@qA(M43jzDqjCN@gCh5Q5g zH@fvN=>OHRN9weo28qu1wPbwfyF>RrPd7Zlr+#;ug>s%;U+PQ_R9!iadMl!oDwuo6 z+)vk{UwrDAr?b>v*DR>lAHG#;Kb2c~P}T3XAGQ0+L-nrOufABfg!c#_fB*srAb8NQu z4sX+|$drq|o@L2n-_Lj9ALNalc4?F8`}uUYy}ilwy?lCUe(Jc5R?E5ffBVd`iGQx6 zDA1oT%%=W!3aeJjL;ovgXysWpou)U*_1K^2bRt2N1QI8i#Iq%ZS2Z_HKR zJ=`iaPFibymv`>(uf$k9ENs4XZ)NG0IZcnXePwa1>Q 0, nil +} + +// Aliases retrieves all the records using an executor. +func Aliases(mods ...qm.QueryMod) aliasQuery { + mods = append(mods, qm.From("\"aliases\"")) + return aliasQuery{NewQuery(mods...)} +} + +// FindAlias retrieves a single record by ID with an executor. +// If selectCols is empty Find will return all columns. +func FindAlias(ctx context.Context, exec boil.ContextExecutor, iD int64, selectCols ...string) (*Alias, error) { + aliasObj := &Alias{} + + sel := "*" + if len(selectCols) > 0 { + sel = strings.Join(strmangle.IdentQuoteSlice(dialect.LQ, dialect.RQ, selectCols), ",") + } + query := fmt.Sprintf( + "select %s from \"aliases\" where \"id\"=?", sel, + ) + + q := queries.Raw(query, iD) + + err := q.Bind(ctx, exec, aliasObj) + if err != nil { + if errors.Cause(err) == sql.ErrNoRows { + return nil, sql.ErrNoRows + } + return nil, errors.Wrap(err, "models: unable to select from aliases") + } + + return aliasObj, nil +} + +// Insert a single record using an executor. +// See boil.Columns.InsertColumnSet documentation to understand column list inference for inserts. +func (o *Alias) Insert(ctx context.Context, exec boil.ContextExecutor, columns boil.Columns) error { + if o == nil { + return errors.New("models: no aliases provided for insertion") + } + + var err error + + if err := o.doBeforeInsertHooks(ctx, exec); err != nil { + return err + } + + nzDefaults := queries.NonZeroDefaultSet(aliasColumnsWithDefault, o) + + key := makeCacheKey(columns, nzDefaults) + aliasInsertCacheMut.RLock() + cache, cached := aliasInsertCache[key] + aliasInsertCacheMut.RUnlock() + + if !cached { + wl, returnColumns := columns.InsertColumnSet( + aliasAllColumns, + aliasColumnsWithDefault, + aliasColumnsWithoutDefault, + nzDefaults, + ) + + cache.valueMapping, err = queries.BindMapping(aliasType, aliasMapping, wl) + if err != nil { + return err + } + cache.retMapping, err = queries.BindMapping(aliasType, aliasMapping, returnColumns) + if err != nil { + return err + } + if len(wl) != 0 { + cache.query = fmt.Sprintf("INSERT INTO \"aliases\" (\"%s\") %%sVALUES (%s)%%s", strings.Join(wl, "\",\""), strmangle.Placeholders(dialect.UseIndexPlaceholders, len(wl), 1, 1)) + } else { + cache.query = "INSERT INTO \"aliases\" %sDEFAULT VALUES%s" + } + + var queryOutput, queryReturning string + + if len(cache.retMapping) != 0 { + cache.retQuery = fmt.Sprintf("SELECT \"%s\" FROM \"aliases\" WHERE %s", strings.Join(returnColumns, "\",\""), strmangle.WhereClause("\"", "\"", 0, aliasPrimaryKeyColumns)) + } + + cache.query = fmt.Sprintf(cache.query, queryOutput, queryReturning) + } + + value := reflect.Indirect(reflect.ValueOf(o)) + vals := queries.ValuesFromMapping(value, cache.valueMapping) + + if boil.IsDebug(ctx) { + writer := boil.DebugWriterFrom(ctx) + fmt.Fprintln(writer, cache.query) + fmt.Fprintln(writer, vals) + } + _, err = exec.ExecContext(ctx, cache.query, vals...) + + if err != nil { + return errors.Wrap(err, "models: unable to insert into aliases") + } + + var identifierCols []interface{} + + if len(cache.retMapping) == 0 { + goto CacheNoHooks + } + + identifierCols = []interface{}{ + o.ID, + } + + if boil.IsDebug(ctx) { + writer := boil.DebugWriterFrom(ctx) + fmt.Fprintln(writer, cache.retQuery) + fmt.Fprintln(writer, identifierCols...) + } + err = exec.QueryRowContext(ctx, cache.retQuery, identifierCols...).Scan(queries.PtrsFromMapping(value, cache.retMapping)...) + if err != nil { + return errors.Wrap(err, "models: unable to populate default values for aliases") + } + +CacheNoHooks: + if !cached { + aliasInsertCacheMut.Lock() + aliasInsertCache[key] = cache + aliasInsertCacheMut.Unlock() + } + + return o.doAfterInsertHooks(ctx, exec) +} + +// Update uses an executor to update the Alias. +// See boil.Columns.UpdateColumnSet documentation to understand column list inference for updates. +// Update does not automatically update the record in case of default values. Use .Reload() to refresh the records. +func (o *Alias) Update(ctx context.Context, exec boil.ContextExecutor, columns boil.Columns) (int64, error) { + var err error + if err = o.doBeforeUpdateHooks(ctx, exec); err != nil { + return 0, err + } + key := makeCacheKey(columns, nil) + aliasUpdateCacheMut.RLock() + cache, cached := aliasUpdateCache[key] + aliasUpdateCacheMut.RUnlock() + + if !cached { + wl := columns.UpdateColumnSet( + aliasAllColumns, + aliasPrimaryKeyColumns, + ) + + if !columns.IsWhitelist() { + wl = strmangle.SetComplement(wl, []string{"created_at"}) + } + if len(wl) == 0 { + return 0, errors.New("models: unable to update aliases, could not build whitelist") + } + + cache.query = fmt.Sprintf("UPDATE \"aliases\" SET %s WHERE %s", + strmangle.SetParamNames("\"", "\"", 0, wl), + strmangle.WhereClause("\"", "\"", 0, aliasPrimaryKeyColumns), + ) + cache.valueMapping, err = queries.BindMapping(aliasType, aliasMapping, append(wl, aliasPrimaryKeyColumns...)) + if err != nil { + return 0, err + } + } + + values := queries.ValuesFromMapping(reflect.Indirect(reflect.ValueOf(o)), cache.valueMapping) + + if boil.IsDebug(ctx) { + writer := boil.DebugWriterFrom(ctx) + fmt.Fprintln(writer, cache.query) + fmt.Fprintln(writer, values) + } + var result sql.Result + result, err = exec.ExecContext(ctx, cache.query, values...) + if err != nil { + return 0, errors.Wrap(err, "models: unable to update aliases row") + } + + rowsAff, err := result.RowsAffected() + if err != nil { + return 0, errors.Wrap(err, "models: failed to get rows affected by update for aliases") + } + + if !cached { + aliasUpdateCacheMut.Lock() + aliasUpdateCache[key] = cache + aliasUpdateCacheMut.Unlock() + } + + return rowsAff, o.doAfterUpdateHooks(ctx, exec) +} + +// UpdateAll updates all rows with the specified column values. +func (q aliasQuery) UpdateAll(ctx context.Context, exec boil.ContextExecutor, cols M) (int64, error) { + queries.SetUpdate(q.Query, cols) + + result, err := q.Query.ExecContext(ctx, exec) + if err != nil { + return 0, errors.Wrap(err, "models: unable to update all for aliases") + } + + rowsAff, err := result.RowsAffected() + if err != nil { + return 0, errors.Wrap(err, "models: unable to retrieve rows affected for aliases") + } + + return rowsAff, nil +} + +// UpdateAll updates all rows with the specified column values, using an executor. +func (o AliasSlice) UpdateAll(ctx context.Context, exec boil.ContextExecutor, cols M) (int64, error) { + ln := int64(len(o)) + if ln == 0 { + return 0, nil + } + + if len(cols) == 0 { + return 0, errors.New("models: update all requires at least one column argument") + } + + colNames := make([]string, len(cols)) + args := make([]interface{}, len(cols)) + + i := 0 + for name, value := range cols { + colNames[i] = name + args[i] = value + i++ + } + + // Append all of the primary key values for each column + for _, obj := range o { + pkeyArgs := queries.ValuesFromMapping(reflect.Indirect(reflect.ValueOf(obj)), aliasPrimaryKeyMapping) + args = append(args, pkeyArgs...) + } + + sql := fmt.Sprintf("UPDATE \"aliases\" SET %s WHERE %s", + strmangle.SetParamNames("\"", "\"", 0, colNames), + strmangle.WhereClauseRepeated(string(dialect.LQ), string(dialect.RQ), 0, aliasPrimaryKeyColumns, len(o))) + + if boil.IsDebug(ctx) { + writer := boil.DebugWriterFrom(ctx) + fmt.Fprintln(writer, sql) + fmt.Fprintln(writer, args...) + } + result, err := exec.ExecContext(ctx, sql, args...) + if err != nil { + return 0, errors.Wrap(err, "models: unable to update all in alias slice") + } + + rowsAff, err := result.RowsAffected() + if err != nil { + return 0, errors.Wrap(err, "models: unable to retrieve rows affected all in update all alias") + } + return rowsAff, nil +} + +// Delete deletes a single Alias record with an executor. +// Delete will match against the primary key column to find the record to delete. +func (o *Alias) Delete(ctx context.Context, exec boil.ContextExecutor) (int64, error) { + if o == nil { + return 0, errors.New("models: no Alias provided for delete") + } + + if err := o.doBeforeDeleteHooks(ctx, exec); err != nil { + return 0, err + } + + args := queries.ValuesFromMapping(reflect.Indirect(reflect.ValueOf(o)), aliasPrimaryKeyMapping) + sql := "DELETE FROM \"aliases\" WHERE \"id\"=?" + + if boil.IsDebug(ctx) { + writer := boil.DebugWriterFrom(ctx) + fmt.Fprintln(writer, sql) + fmt.Fprintln(writer, args...) + } + result, err := exec.ExecContext(ctx, sql, args...) + if err != nil { + return 0, errors.Wrap(err, "models: unable to delete from aliases") + } + + rowsAff, err := result.RowsAffected() + if err != nil { + return 0, errors.Wrap(err, "models: failed to get rows affected by delete for aliases") + } + + if err := o.doAfterDeleteHooks(ctx, exec); err != nil { + return 0, err + } + + return rowsAff, nil +} + +// DeleteAll deletes all matching rows. +func (q aliasQuery) DeleteAll(ctx context.Context, exec boil.ContextExecutor) (int64, error) { + if q.Query == nil { + return 0, errors.New("models: no aliasQuery provided for delete all") + } + + queries.SetDelete(q.Query) + + result, err := q.Query.ExecContext(ctx, exec) + if err != nil { + return 0, errors.Wrap(err, "models: unable to delete all from aliases") + } + + rowsAff, err := result.RowsAffected() + if err != nil { + return 0, errors.Wrap(err, "models: failed to get rows affected by deleteall for aliases") + } + + return rowsAff, nil +} + +// DeleteAll deletes all rows in the slice, using an executor. +func (o AliasSlice) DeleteAll(ctx context.Context, exec boil.ContextExecutor) (int64, error) { + if len(o) == 0 { + return 0, nil + } + + if len(aliasBeforeDeleteHooks) != 0 { + for _, obj := range o { + if err := obj.doBeforeDeleteHooks(ctx, exec); err != nil { + return 0, err + } + } + } + + var args []interface{} + for _, obj := range o { + pkeyArgs := queries.ValuesFromMapping(reflect.Indirect(reflect.ValueOf(obj)), aliasPrimaryKeyMapping) + args = append(args, pkeyArgs...) + } + + sql := "DELETE FROM \"aliases\" WHERE " + + strmangle.WhereClauseRepeated(string(dialect.LQ), string(dialect.RQ), 0, aliasPrimaryKeyColumns, len(o)) + + if boil.IsDebug(ctx) { + writer := boil.DebugWriterFrom(ctx) + fmt.Fprintln(writer, sql) + fmt.Fprintln(writer, args) + } + result, err := exec.ExecContext(ctx, sql, args...) + if err != nil { + return 0, errors.Wrap(err, "models: unable to delete all from alias slice") + } + + rowsAff, err := result.RowsAffected() + if err != nil { + return 0, errors.Wrap(err, "models: failed to get rows affected by deleteall for aliases") + } + + if len(aliasAfterDeleteHooks) != 0 { + for _, obj := range o { + if err := obj.doAfterDeleteHooks(ctx, exec); err != nil { + return 0, err + } + } + } + + return rowsAff, nil +} + +// Reload refetches the object from the database +// using the primary keys with an executor. +func (o *Alias) Reload(ctx context.Context, exec boil.ContextExecutor) error { + ret, err := FindAlias(ctx, exec, o.ID) + if err != nil { + return err + } + + *o = *ret + return nil +} + +// ReloadAll refetches every row with matching primary key column values +// and overwrites the original object slice with the newly updated slice. +func (o *AliasSlice) ReloadAll(ctx context.Context, exec boil.ContextExecutor) error { + if o == nil || len(*o) == 0 { + return nil + } + + slice := AliasSlice{} + var args []interface{} + for _, obj := range *o { + pkeyArgs := queries.ValuesFromMapping(reflect.Indirect(reflect.ValueOf(obj)), aliasPrimaryKeyMapping) + args = append(args, pkeyArgs...) + } + + sql := "SELECT \"aliases\".* FROM \"aliases\" WHERE " + + strmangle.WhereClauseRepeated(string(dialect.LQ), string(dialect.RQ), 0, aliasPrimaryKeyColumns, len(*o)) + + q := queries.Raw(sql, args...) + + err := q.Bind(ctx, exec, &slice) + if err != nil { + return errors.Wrap(err, "models: unable to reload all in AliasSlice") + } + + *o = slice + + return nil +} + +// AliasExists checks if the Alias row exists. +func AliasExists(ctx context.Context, exec boil.ContextExecutor, iD int64) (bool, error) { + var exists bool + sql := "select exists(select 1 from \"aliases\" where \"id\"=? limit 1)" + + if boil.IsDebug(ctx) { + writer := boil.DebugWriterFrom(ctx) + fmt.Fprintln(writer, sql) + fmt.Fprintln(writer, iD) + } + row := exec.QueryRowContext(ctx, sql, iD) + + err := row.Scan(&exists) + if err != nil { + return false, errors.Wrap(err, "models: unable to check if aliases exists") + } + + return exists, nil +} diff --git a/admindb/sqlite/models/aliases_test.go b/admindb/sqlite/models/aliases_test.go new file mode 100644 index 0000000..06344d2 --- /dev/null +++ b/admindb/sqlite/models/aliases_test.go @@ -0,0 +1,684 @@ +// Code generated by SQLBoiler 4.4.0 (https://github.com/volatiletech/sqlboiler). DO NOT EDIT. +// This file is meant to be re-generated in place and/or deleted at any time. + +package models + +import ( + "bytes" + "context" + "reflect" + "testing" + + "github.com/volatiletech/randomize" + "github.com/volatiletech/sqlboiler/v4/boil" + "github.com/volatiletech/sqlboiler/v4/queries" + "github.com/volatiletech/strmangle" +) + +var ( + // Relationships sometimes use the reflection helper queries.Equal/queries.Assign + // so force a package dependency in case they don't. + _ = queries.Equal +) + +func testAliases(t *testing.T) { + t.Parallel() + + query := Aliases() + + if query.Query == nil { + t.Error("expected a query, got nothing") + } +} + +func testAliasesDelete(t *testing.T) { + t.Parallel() + + seed := randomize.NewSeed() + var err error + o := &Alias{} + if err = randomize.Struct(seed, o, aliasDBTypes, true, aliasColumnsWithDefault...); err != nil { + t.Errorf("Unable to randomize Alias struct: %s", err) + } + + ctx := context.Background() + tx := MustTx(boil.BeginTx(ctx, nil)) + defer func() { _ = tx.Rollback() }() + if err = o.Insert(ctx, tx, boil.Infer()); err != nil { + t.Error(err) + } + + if rowsAff, err := o.Delete(ctx, tx); err != nil { + t.Error(err) + } else if rowsAff != 1 { + t.Error("should only have deleted one row, but affected:", rowsAff) + } + + count, err := Aliases().Count(ctx, tx) + if err != nil { + t.Error(err) + } + + if count != 0 { + t.Error("want zero records, got:", count) + } +} + +func testAliasesQueryDeleteAll(t *testing.T) { + t.Parallel() + + seed := randomize.NewSeed() + var err error + o := &Alias{} + if err = randomize.Struct(seed, o, aliasDBTypes, true, aliasColumnsWithDefault...); err != nil { + t.Errorf("Unable to randomize Alias struct: %s", err) + } + + ctx := context.Background() + tx := MustTx(boil.BeginTx(ctx, nil)) + defer func() { _ = tx.Rollback() }() + if err = o.Insert(ctx, tx, boil.Infer()); err != nil { + t.Error(err) + } + + if rowsAff, err := Aliases().DeleteAll(ctx, tx); err != nil { + t.Error(err) + } else if rowsAff != 1 { + t.Error("should only have deleted one row, but affected:", rowsAff) + } + + count, err := Aliases().Count(ctx, tx) + if err != nil { + t.Error(err) + } + + if count != 0 { + t.Error("want zero records, got:", count) + } +} + +func testAliasesSliceDeleteAll(t *testing.T) { + t.Parallel() + + seed := randomize.NewSeed() + var err error + o := &Alias{} + if err = randomize.Struct(seed, o, aliasDBTypes, true, aliasColumnsWithDefault...); err != nil { + t.Errorf("Unable to randomize Alias struct: %s", err) + } + + ctx := context.Background() + tx := MustTx(boil.BeginTx(ctx, nil)) + defer func() { _ = tx.Rollback() }() + if err = o.Insert(ctx, tx, boil.Infer()); err != nil { + t.Error(err) + } + + slice := AliasSlice{o} + + if rowsAff, err := slice.DeleteAll(ctx, tx); err != nil { + t.Error(err) + } else if rowsAff != 1 { + t.Error("should only have deleted one row, but affected:", rowsAff) + } + + count, err := Aliases().Count(ctx, tx) + if err != nil { + t.Error(err) + } + + if count != 0 { + t.Error("want zero records, got:", count) + } +} + +func testAliasesExists(t *testing.T) { + t.Parallel() + + seed := randomize.NewSeed() + var err error + o := &Alias{} + if err = randomize.Struct(seed, o, aliasDBTypes, true, aliasColumnsWithDefault...); err != nil { + t.Errorf("Unable to randomize Alias struct: %s", err) + } + + ctx := context.Background() + tx := MustTx(boil.BeginTx(ctx, nil)) + defer func() { _ = tx.Rollback() }() + if err = o.Insert(ctx, tx, boil.Infer()); err != nil { + t.Error(err) + } + + e, err := AliasExists(ctx, tx, o.ID) + if err != nil { + t.Errorf("Unable to check if Alias exists: %s", err) + } + if !e { + t.Errorf("Expected AliasExists to return true, but got false.") + } +} + +func testAliasesFind(t *testing.T) { + t.Parallel() + + seed := randomize.NewSeed() + var err error + o := &Alias{} + if err = randomize.Struct(seed, o, aliasDBTypes, true, aliasColumnsWithDefault...); err != nil { + t.Errorf("Unable to randomize Alias struct: %s", err) + } + + ctx := context.Background() + tx := MustTx(boil.BeginTx(ctx, nil)) + defer func() { _ = tx.Rollback() }() + if err = o.Insert(ctx, tx, boil.Infer()); err != nil { + t.Error(err) + } + + aliasFound, err := FindAlias(ctx, tx, o.ID) + if err != nil { + t.Error(err) + } + + if aliasFound == nil { + t.Error("want a record, got nil") + } +} + +func testAliasesBind(t *testing.T) { + t.Parallel() + + seed := randomize.NewSeed() + var err error + o := &Alias{} + if err = randomize.Struct(seed, o, aliasDBTypes, true, aliasColumnsWithDefault...); err != nil { + t.Errorf("Unable to randomize Alias struct: %s", err) + } + + ctx := context.Background() + tx := MustTx(boil.BeginTx(ctx, nil)) + defer func() { _ = tx.Rollback() }() + if err = o.Insert(ctx, tx, boil.Infer()); err != nil { + t.Error(err) + } + + if err = Aliases().Bind(ctx, tx, o); err != nil { + t.Error(err) + } +} + +func testAliasesOne(t *testing.T) { + t.Parallel() + + seed := randomize.NewSeed() + var err error + o := &Alias{} + if err = randomize.Struct(seed, o, aliasDBTypes, true, aliasColumnsWithDefault...); err != nil { + t.Errorf("Unable to randomize Alias struct: %s", err) + } + + ctx := context.Background() + tx := MustTx(boil.BeginTx(ctx, nil)) + defer func() { _ = tx.Rollback() }() + if err = o.Insert(ctx, tx, boil.Infer()); err != nil { + t.Error(err) + } + + if x, err := Aliases().One(ctx, tx); err != nil { + t.Error(err) + } else if x == nil { + t.Error("expected to get a non nil record") + } +} + +func testAliasesAll(t *testing.T) { + t.Parallel() + + seed := randomize.NewSeed() + var err error + aliasOne := &Alias{} + aliasTwo := &Alias{} + if err = randomize.Struct(seed, aliasOne, aliasDBTypes, false, aliasColumnsWithDefault...); err != nil { + t.Errorf("Unable to randomize Alias struct: %s", err) + } + if err = randomize.Struct(seed, aliasTwo, aliasDBTypes, false, aliasColumnsWithDefault...); err != nil { + t.Errorf("Unable to randomize Alias struct: %s", err) + } + + ctx := context.Background() + tx := MustTx(boil.BeginTx(ctx, nil)) + defer func() { _ = tx.Rollback() }() + if err = aliasOne.Insert(ctx, tx, boil.Infer()); err != nil { + t.Error(err) + } + if err = aliasTwo.Insert(ctx, tx, boil.Infer()); err != nil { + t.Error(err) + } + + slice, err := Aliases().All(ctx, tx) + if err != nil { + t.Error(err) + } + + if len(slice) != 2 { + t.Error("want 2 records, got:", len(slice)) + } +} + +func testAliasesCount(t *testing.T) { + t.Parallel() + + var err error + seed := randomize.NewSeed() + aliasOne := &Alias{} + aliasTwo := &Alias{} + if err = randomize.Struct(seed, aliasOne, aliasDBTypes, false, aliasColumnsWithDefault...); err != nil { + t.Errorf("Unable to randomize Alias struct: %s", err) + } + if err = randomize.Struct(seed, aliasTwo, aliasDBTypes, false, aliasColumnsWithDefault...); err != nil { + t.Errorf("Unable to randomize Alias struct: %s", err) + } + + ctx := context.Background() + tx := MustTx(boil.BeginTx(ctx, nil)) + defer func() { _ = tx.Rollback() }() + if err = aliasOne.Insert(ctx, tx, boil.Infer()); err != nil { + t.Error(err) + } + if err = aliasTwo.Insert(ctx, tx, boil.Infer()); err != nil { + t.Error(err) + } + + count, err := Aliases().Count(ctx, tx) + if err != nil { + t.Error(err) + } + + if count != 2 { + t.Error("want 2 records, got:", count) + } +} + +func aliasBeforeInsertHook(ctx context.Context, e boil.ContextExecutor, o *Alias) error { + *o = Alias{} + return nil +} + +func aliasAfterInsertHook(ctx context.Context, e boil.ContextExecutor, o *Alias) error { + *o = Alias{} + return nil +} + +func aliasAfterSelectHook(ctx context.Context, e boil.ContextExecutor, o *Alias) error { + *o = Alias{} + return nil +} + +func aliasBeforeUpdateHook(ctx context.Context, e boil.ContextExecutor, o *Alias) error { + *o = Alias{} + return nil +} + +func aliasAfterUpdateHook(ctx context.Context, e boil.ContextExecutor, o *Alias) error { + *o = Alias{} + return nil +} + +func aliasBeforeDeleteHook(ctx context.Context, e boil.ContextExecutor, o *Alias) error { + *o = Alias{} + return nil +} + +func aliasAfterDeleteHook(ctx context.Context, e boil.ContextExecutor, o *Alias) error { + *o = Alias{} + return nil +} + +func aliasBeforeUpsertHook(ctx context.Context, e boil.ContextExecutor, o *Alias) error { + *o = Alias{} + return nil +} + +func aliasAfterUpsertHook(ctx context.Context, e boil.ContextExecutor, o *Alias) error { + *o = Alias{} + return nil +} + +func testAliasesHooks(t *testing.T) { + t.Parallel() + + var err error + + ctx := context.Background() + empty := &Alias{} + o := &Alias{} + + seed := randomize.NewSeed() + if err = randomize.Struct(seed, o, aliasDBTypes, false); err != nil { + t.Errorf("Unable to randomize Alias object: %s", err) + } + + AddAliasHook(boil.BeforeInsertHook, aliasBeforeInsertHook) + if err = o.doBeforeInsertHooks(ctx, nil); err != nil { + t.Errorf("Unable to execute doBeforeInsertHooks: %s", err) + } + if !reflect.DeepEqual(o, empty) { + t.Errorf("Expected BeforeInsertHook function to empty object, but got: %#v", o) + } + aliasBeforeInsertHooks = []AliasHook{} + + AddAliasHook(boil.AfterInsertHook, aliasAfterInsertHook) + if err = o.doAfterInsertHooks(ctx, nil); err != nil { + t.Errorf("Unable to execute doAfterInsertHooks: %s", err) + } + if !reflect.DeepEqual(o, empty) { + t.Errorf("Expected AfterInsertHook function to empty object, but got: %#v", o) + } + aliasAfterInsertHooks = []AliasHook{} + + AddAliasHook(boil.AfterSelectHook, aliasAfterSelectHook) + if err = o.doAfterSelectHooks(ctx, nil); err != nil { + t.Errorf("Unable to execute doAfterSelectHooks: %s", err) + } + if !reflect.DeepEqual(o, empty) { + t.Errorf("Expected AfterSelectHook function to empty object, but got: %#v", o) + } + aliasAfterSelectHooks = []AliasHook{} + + AddAliasHook(boil.BeforeUpdateHook, aliasBeforeUpdateHook) + if err = o.doBeforeUpdateHooks(ctx, nil); err != nil { + t.Errorf("Unable to execute doBeforeUpdateHooks: %s", err) + } + if !reflect.DeepEqual(o, empty) { + t.Errorf("Expected BeforeUpdateHook function to empty object, but got: %#v", o) + } + aliasBeforeUpdateHooks = []AliasHook{} + + AddAliasHook(boil.AfterUpdateHook, aliasAfterUpdateHook) + if err = o.doAfterUpdateHooks(ctx, nil); err != nil { + t.Errorf("Unable to execute doAfterUpdateHooks: %s", err) + } + if !reflect.DeepEqual(o, empty) { + t.Errorf("Expected AfterUpdateHook function to empty object, but got: %#v", o) + } + aliasAfterUpdateHooks = []AliasHook{} + + AddAliasHook(boil.BeforeDeleteHook, aliasBeforeDeleteHook) + if err = o.doBeforeDeleteHooks(ctx, nil); err != nil { + t.Errorf("Unable to execute doBeforeDeleteHooks: %s", err) + } + if !reflect.DeepEqual(o, empty) { + t.Errorf("Expected BeforeDeleteHook function to empty object, but got: %#v", o) + } + aliasBeforeDeleteHooks = []AliasHook{} + + AddAliasHook(boil.AfterDeleteHook, aliasAfterDeleteHook) + if err = o.doAfterDeleteHooks(ctx, nil); err != nil { + t.Errorf("Unable to execute doAfterDeleteHooks: %s", err) + } + if !reflect.DeepEqual(o, empty) { + t.Errorf("Expected AfterDeleteHook function to empty object, but got: %#v", o) + } + aliasAfterDeleteHooks = []AliasHook{} + + AddAliasHook(boil.BeforeUpsertHook, aliasBeforeUpsertHook) + if err = o.doBeforeUpsertHooks(ctx, nil); err != nil { + t.Errorf("Unable to execute doBeforeUpsertHooks: %s", err) + } + if !reflect.DeepEqual(o, empty) { + t.Errorf("Expected BeforeUpsertHook function to empty object, but got: %#v", o) + } + aliasBeforeUpsertHooks = []AliasHook{} + + AddAliasHook(boil.AfterUpsertHook, aliasAfterUpsertHook) + if err = o.doAfterUpsertHooks(ctx, nil); err != nil { + t.Errorf("Unable to execute doAfterUpsertHooks: %s", err) + } + if !reflect.DeepEqual(o, empty) { + t.Errorf("Expected AfterUpsertHook function to empty object, but got: %#v", o) + } + aliasAfterUpsertHooks = []AliasHook{} +} + +func testAliasesInsert(t *testing.T) { + t.Parallel() + + seed := randomize.NewSeed() + var err error + o := &Alias{} + if err = randomize.Struct(seed, o, aliasDBTypes, true, aliasColumnsWithDefault...); err != nil { + t.Errorf("Unable to randomize Alias struct: %s", err) + } + + ctx := context.Background() + tx := MustTx(boil.BeginTx(ctx, nil)) + defer func() { _ = tx.Rollback() }() + if err = o.Insert(ctx, tx, boil.Infer()); err != nil { + t.Error(err) + } + + count, err := Aliases().Count(ctx, tx) + if err != nil { + t.Error(err) + } + + if count != 1 { + t.Error("want one record, got:", count) + } +} + +func testAliasesInsertWhitelist(t *testing.T) { + t.Parallel() + + seed := randomize.NewSeed() + var err error + o := &Alias{} + if err = randomize.Struct(seed, o, aliasDBTypes, true); err != nil { + t.Errorf("Unable to randomize Alias struct: %s", err) + } + + ctx := context.Background() + tx := MustTx(boil.BeginTx(ctx, nil)) + defer func() { _ = tx.Rollback() }() + if err = o.Insert(ctx, tx, boil.Whitelist(aliasColumnsWithoutDefault...)); err != nil { + t.Error(err) + } + + count, err := Aliases().Count(ctx, tx) + if err != nil { + t.Error(err) + } + + if count != 1 { + t.Error("want one record, got:", count) + } +} + +func testAliasesReload(t *testing.T) { + t.Parallel() + + seed := randomize.NewSeed() + var err error + o := &Alias{} + if err = randomize.Struct(seed, o, aliasDBTypes, true, aliasColumnsWithDefault...); err != nil { + t.Errorf("Unable to randomize Alias struct: %s", err) + } + + ctx := context.Background() + tx := MustTx(boil.BeginTx(ctx, nil)) + defer func() { _ = tx.Rollback() }() + if err = o.Insert(ctx, tx, boil.Infer()); err != nil { + t.Error(err) + } + + if err = o.Reload(ctx, tx); err != nil { + t.Error(err) + } +} + +func testAliasesReloadAll(t *testing.T) { + t.Parallel() + + seed := randomize.NewSeed() + var err error + o := &Alias{} + if err = randomize.Struct(seed, o, aliasDBTypes, true, aliasColumnsWithDefault...); err != nil { + t.Errorf("Unable to randomize Alias struct: %s", err) + } + + ctx := context.Background() + tx := MustTx(boil.BeginTx(ctx, nil)) + defer func() { _ = tx.Rollback() }() + if err = o.Insert(ctx, tx, boil.Infer()); err != nil { + t.Error(err) + } + + slice := AliasSlice{o} + + if err = slice.ReloadAll(ctx, tx); err != nil { + t.Error(err) + } +} + +func testAliasesSelect(t *testing.T) { + t.Parallel() + + seed := randomize.NewSeed() + var err error + o := &Alias{} + if err = randomize.Struct(seed, o, aliasDBTypes, true, aliasColumnsWithDefault...); err != nil { + t.Errorf("Unable to randomize Alias struct: %s", err) + } + + ctx := context.Background() + tx := MustTx(boil.BeginTx(ctx, nil)) + defer func() { _ = tx.Rollback() }() + if err = o.Insert(ctx, tx, boil.Infer()); err != nil { + t.Error(err) + } + + slice, err := Aliases().All(ctx, tx) + if err != nil { + t.Error(err) + } + + if len(slice) != 1 { + t.Error("want one record, got:", len(slice)) + } +} + +var ( + aliasDBTypes = map[string]string{`ID`: `INT`, `Name`: `TEXT`, `PubKey`: `TEXT`} + _ = bytes.MinRead +) + +func testAliasesUpdate(t *testing.T) { + t.Parallel() + + if 0 == len(aliasPrimaryKeyColumns) { + t.Skip("Skipping table with no primary key columns") + } + if len(aliasAllColumns) == len(aliasPrimaryKeyColumns) { + t.Skip("Skipping table with only primary key columns") + } + + seed := randomize.NewSeed() + var err error + o := &Alias{} + if err = randomize.Struct(seed, o, aliasDBTypes, true, aliasColumnsWithDefault...); err != nil { + t.Errorf("Unable to randomize Alias struct: %s", err) + } + + ctx := context.Background() + tx := MustTx(boil.BeginTx(ctx, nil)) + defer func() { _ = tx.Rollback() }() + if err = o.Insert(ctx, tx, boil.Infer()); err != nil { + t.Error(err) + } + + count, err := Aliases().Count(ctx, tx) + if err != nil { + t.Error(err) + } + + if count != 1 { + t.Error("want one record, got:", count) + } + + if err = randomize.Struct(seed, o, aliasDBTypes, true, aliasPrimaryKeyColumns...); err != nil { + t.Errorf("Unable to randomize Alias struct: %s", err) + } + + if rowsAff, err := o.Update(ctx, tx, boil.Infer()); err != nil { + t.Error(err) + } else if rowsAff != 1 { + t.Error("should only affect one row but affected", rowsAff) + } +} + +func testAliasesSliceUpdateAll(t *testing.T) { + t.Parallel() + + if len(aliasAllColumns) == len(aliasPrimaryKeyColumns) { + t.Skip("Skipping table with only primary key columns") + } + + seed := randomize.NewSeed() + var err error + o := &Alias{} + if err = randomize.Struct(seed, o, aliasDBTypes, true, aliasColumnsWithDefault...); err != nil { + t.Errorf("Unable to randomize Alias struct: %s", err) + } + + ctx := context.Background() + tx := MustTx(boil.BeginTx(ctx, nil)) + defer func() { _ = tx.Rollback() }() + if err = o.Insert(ctx, tx, boil.Infer()); err != nil { + t.Error(err) + } + + count, err := Aliases().Count(ctx, tx) + if err != nil { + t.Error(err) + } + + if count != 1 { + t.Error("want one record, got:", count) + } + + if err = randomize.Struct(seed, o, aliasDBTypes, true, aliasPrimaryKeyColumns...); err != nil { + t.Errorf("Unable to randomize Alias struct: %s", err) + } + + // Remove Primary keys and unique columns from what we plan to update + var fields []string + if strmangle.StringSliceMatch(aliasAllColumns, aliasPrimaryKeyColumns) { + fields = aliasAllColumns + } else { + fields = strmangle.SetComplement( + aliasAllColumns, + aliasPrimaryKeyColumns, + ) + } + + value := reflect.Indirect(reflect.ValueOf(o)) + typ := reflect.TypeOf(o).Elem() + n := typ.NumField() + + updateMap := M{} + for _, col := range fields { + for i := 0; i < n; i++ { + f := typ.Field(i) + if f.Tag.Get("boil") == col { + updateMap[col] = value.Field(i).Interface() + } + } + } + + slice := AliasSlice{o} + if rowsAff, err := slice.UpdateAll(ctx, tx, updateMap); err != nil { + t.Error(err) + } else if rowsAff != 1 { + t.Error("wanted one record updated but got", rowsAff) + } +} diff --git a/admindb/sqlite/models/auth_fallback.go b/admindb/sqlite/models/auth_fallback.go new file mode 100644 index 0000000..a9db88d --- /dev/null +++ b/admindb/sqlite/models/auth_fallback.go @@ -0,0 +1,782 @@ +// Code generated by SQLBoiler 4.4.0 (https://github.com/volatiletech/sqlboiler). DO NOT EDIT. +// This file is meant to be re-generated in place and/or deleted at any time. + +package models + +import ( + "context" + "database/sql" + "fmt" + "reflect" + "strings" + "sync" + "time" + + "github.com/friendsofgo/errors" + "github.com/volatiletech/sqlboiler/v4/boil" + "github.com/volatiletech/sqlboiler/v4/queries" + "github.com/volatiletech/sqlboiler/v4/queries/qm" + "github.com/volatiletech/sqlboiler/v4/queries/qmhelper" + "github.com/volatiletech/strmangle" +) + +// AuthFallback is an object representing the database table. +type AuthFallback struct { + ID int64 `boil:"id" json:"id" toml:"id" yaml:"id"` + Name string `boil:"name" json:"name" toml:"name" yaml:"name"` + PasswordHash []byte `boil:"password_hash" json:"password_hash" toml:"password_hash" yaml:"password_hash"` + + R *authFallbackR `boil:"-" json:"-" toml:"-" yaml:"-"` + L authFallbackL `boil:"-" json:"-" toml:"-" yaml:"-"` +} + +var AuthFallbackColumns = struct { + ID string + Name string + PasswordHash string +}{ + ID: "id", + Name: "name", + PasswordHash: "password_hash", +} + +// Generated where + +type whereHelper__byte struct{ field string } + +func (w whereHelper__byte) EQ(x []byte) qm.QueryMod { return qmhelper.Where(w.field, qmhelper.EQ, x) } +func (w whereHelper__byte) NEQ(x []byte) qm.QueryMod { return qmhelper.Where(w.field, qmhelper.NEQ, x) } +func (w whereHelper__byte) LT(x []byte) qm.QueryMod { return qmhelper.Where(w.field, qmhelper.LT, x) } +func (w whereHelper__byte) LTE(x []byte) qm.QueryMod { return qmhelper.Where(w.field, qmhelper.LTE, x) } +func (w whereHelper__byte) GT(x []byte) qm.QueryMod { return qmhelper.Where(w.field, qmhelper.GT, x) } +func (w whereHelper__byte) GTE(x []byte) qm.QueryMod { return qmhelper.Where(w.field, qmhelper.GTE, x) } + +var AuthFallbackWhere = struct { + ID whereHelperint64 + Name whereHelperstring + PasswordHash whereHelper__byte +}{ + ID: whereHelperint64{field: "\"auth_fallback\".\"id\""}, + Name: whereHelperstring{field: "\"auth_fallback\".\"name\""}, + PasswordHash: whereHelper__byte{field: "\"auth_fallback\".\"password_hash\""}, +} + +// AuthFallbackRels is where relationship names are stored. +var AuthFallbackRels = struct { +}{} + +// authFallbackR is where relationships are stored. +type authFallbackR struct { +} + +// NewStruct creates a new relationship struct +func (*authFallbackR) NewStruct() *authFallbackR { + return &authFallbackR{} +} + +// authFallbackL is where Load methods for each relationship are stored. +type authFallbackL struct{} + +var ( + authFallbackAllColumns = []string{"id", "name", "password_hash"} + authFallbackColumnsWithoutDefault = []string{"id", "name", "password_hash"} + authFallbackColumnsWithDefault = []string{} + authFallbackPrimaryKeyColumns = []string{"id"} +) + +type ( + // AuthFallbackSlice is an alias for a slice of pointers to AuthFallback. + // This should generally be used opposed to []AuthFallback. + AuthFallbackSlice []*AuthFallback + // AuthFallbackHook is the signature for custom AuthFallback hook methods + AuthFallbackHook func(context.Context, boil.ContextExecutor, *AuthFallback) error + + authFallbackQuery struct { + *queries.Query + } +) + +// Cache for insert, update and upsert +var ( + authFallbackType = reflect.TypeOf(&AuthFallback{}) + authFallbackMapping = queries.MakeStructMapping(authFallbackType) + authFallbackPrimaryKeyMapping, _ = queries.BindMapping(authFallbackType, authFallbackMapping, authFallbackPrimaryKeyColumns) + authFallbackInsertCacheMut sync.RWMutex + authFallbackInsertCache = make(map[string]insertCache) + authFallbackUpdateCacheMut sync.RWMutex + authFallbackUpdateCache = make(map[string]updateCache) + authFallbackUpsertCacheMut sync.RWMutex + authFallbackUpsertCache = make(map[string]insertCache) +) + +var ( + // Force time package dependency for automated UpdatedAt/CreatedAt. + _ = time.Second + // Force qmhelper dependency for where clause generation (which doesn't + // always happen) + _ = qmhelper.Where +) + +var authFallbackBeforeInsertHooks []AuthFallbackHook +var authFallbackBeforeUpdateHooks []AuthFallbackHook +var authFallbackBeforeDeleteHooks []AuthFallbackHook +var authFallbackBeforeUpsertHooks []AuthFallbackHook + +var authFallbackAfterInsertHooks []AuthFallbackHook +var authFallbackAfterSelectHooks []AuthFallbackHook +var authFallbackAfterUpdateHooks []AuthFallbackHook +var authFallbackAfterDeleteHooks []AuthFallbackHook +var authFallbackAfterUpsertHooks []AuthFallbackHook + +// doBeforeInsertHooks executes all "before insert" hooks. +func (o *AuthFallback) doBeforeInsertHooks(ctx context.Context, exec boil.ContextExecutor) (err error) { + if boil.HooksAreSkipped(ctx) { + return nil + } + + for _, hook := range authFallbackBeforeInsertHooks { + if err := hook(ctx, exec, o); err != nil { + return err + } + } + + return nil +} + +// doBeforeUpdateHooks executes all "before Update" hooks. +func (o *AuthFallback) doBeforeUpdateHooks(ctx context.Context, exec boil.ContextExecutor) (err error) { + if boil.HooksAreSkipped(ctx) { + return nil + } + + for _, hook := range authFallbackBeforeUpdateHooks { + if err := hook(ctx, exec, o); err != nil { + return err + } + } + + return nil +} + +// doBeforeDeleteHooks executes all "before Delete" hooks. +func (o *AuthFallback) doBeforeDeleteHooks(ctx context.Context, exec boil.ContextExecutor) (err error) { + if boil.HooksAreSkipped(ctx) { + return nil + } + + for _, hook := range authFallbackBeforeDeleteHooks { + if err := hook(ctx, exec, o); err != nil { + return err + } + } + + return nil +} + +// doBeforeUpsertHooks executes all "before Upsert" hooks. +func (o *AuthFallback) doBeforeUpsertHooks(ctx context.Context, exec boil.ContextExecutor) (err error) { + if boil.HooksAreSkipped(ctx) { + return nil + } + + for _, hook := range authFallbackBeforeUpsertHooks { + if err := hook(ctx, exec, o); err != nil { + return err + } + } + + return nil +} + +// doAfterInsertHooks executes all "after Insert" hooks. +func (o *AuthFallback) doAfterInsertHooks(ctx context.Context, exec boil.ContextExecutor) (err error) { + if boil.HooksAreSkipped(ctx) { + return nil + } + + for _, hook := range authFallbackAfterInsertHooks { + if err := hook(ctx, exec, o); err != nil { + return err + } + } + + return nil +} + +// doAfterSelectHooks executes all "after Select" hooks. +func (o *AuthFallback) doAfterSelectHooks(ctx context.Context, exec boil.ContextExecutor) (err error) { + if boil.HooksAreSkipped(ctx) { + return nil + } + + for _, hook := range authFallbackAfterSelectHooks { + if err := hook(ctx, exec, o); err != nil { + return err + } + } + + return nil +} + +// doAfterUpdateHooks executes all "after Update" hooks. +func (o *AuthFallback) doAfterUpdateHooks(ctx context.Context, exec boil.ContextExecutor) (err error) { + if boil.HooksAreSkipped(ctx) { + return nil + } + + for _, hook := range authFallbackAfterUpdateHooks { + if err := hook(ctx, exec, o); err != nil { + return err + } + } + + return nil +} + +// doAfterDeleteHooks executes all "after Delete" hooks. +func (o *AuthFallback) doAfterDeleteHooks(ctx context.Context, exec boil.ContextExecutor) (err error) { + if boil.HooksAreSkipped(ctx) { + return nil + } + + for _, hook := range authFallbackAfterDeleteHooks { + if err := hook(ctx, exec, o); err != nil { + return err + } + } + + return nil +} + +// doAfterUpsertHooks executes all "after Upsert" hooks. +func (o *AuthFallback) doAfterUpsertHooks(ctx context.Context, exec boil.ContextExecutor) (err error) { + if boil.HooksAreSkipped(ctx) { + return nil + } + + for _, hook := range authFallbackAfterUpsertHooks { + if err := hook(ctx, exec, o); err != nil { + return err + } + } + + return nil +} + +// AddAuthFallbackHook registers your hook function for all future operations. +func AddAuthFallbackHook(hookPoint boil.HookPoint, authFallbackHook AuthFallbackHook) { + switch hookPoint { + case boil.BeforeInsertHook: + authFallbackBeforeInsertHooks = append(authFallbackBeforeInsertHooks, authFallbackHook) + case boil.BeforeUpdateHook: + authFallbackBeforeUpdateHooks = append(authFallbackBeforeUpdateHooks, authFallbackHook) + case boil.BeforeDeleteHook: + authFallbackBeforeDeleteHooks = append(authFallbackBeforeDeleteHooks, authFallbackHook) + case boil.BeforeUpsertHook: + authFallbackBeforeUpsertHooks = append(authFallbackBeforeUpsertHooks, authFallbackHook) + case boil.AfterInsertHook: + authFallbackAfterInsertHooks = append(authFallbackAfterInsertHooks, authFallbackHook) + case boil.AfterSelectHook: + authFallbackAfterSelectHooks = append(authFallbackAfterSelectHooks, authFallbackHook) + case boil.AfterUpdateHook: + authFallbackAfterUpdateHooks = append(authFallbackAfterUpdateHooks, authFallbackHook) + case boil.AfterDeleteHook: + authFallbackAfterDeleteHooks = append(authFallbackAfterDeleteHooks, authFallbackHook) + case boil.AfterUpsertHook: + authFallbackAfterUpsertHooks = append(authFallbackAfterUpsertHooks, authFallbackHook) + } +} + +// One returns a single authFallback record from the query. +func (q authFallbackQuery) One(ctx context.Context, exec boil.ContextExecutor) (*AuthFallback, error) { + o := &AuthFallback{} + + queries.SetLimit(q.Query, 1) + + err := q.Bind(ctx, exec, o) + if err != nil { + if errors.Cause(err) == sql.ErrNoRows { + return nil, sql.ErrNoRows + } + return nil, errors.Wrap(err, "models: failed to execute a one query for auth_fallback") + } + + if err := o.doAfterSelectHooks(ctx, exec); err != nil { + return o, err + } + + return o, nil +} + +// All returns all AuthFallback records from the query. +func (q authFallbackQuery) All(ctx context.Context, exec boil.ContextExecutor) (AuthFallbackSlice, error) { + var o []*AuthFallback + + err := q.Bind(ctx, exec, &o) + if err != nil { + return nil, errors.Wrap(err, "models: failed to assign all query results to AuthFallback slice") + } + + if len(authFallbackAfterSelectHooks) != 0 { + for _, obj := range o { + if err := obj.doAfterSelectHooks(ctx, exec); err != nil { + return o, err + } + } + } + + return o, nil +} + +// Count returns the count of all AuthFallback records in the query. +func (q authFallbackQuery) Count(ctx context.Context, exec boil.ContextExecutor) (int64, error) { + var count int64 + + queries.SetSelect(q.Query, nil) + queries.SetCount(q.Query) + + err := q.Query.QueryRowContext(ctx, exec).Scan(&count) + if err != nil { + return 0, errors.Wrap(err, "models: failed to count auth_fallback rows") + } + + return count, nil +} + +// Exists checks if the row exists in the table. +func (q authFallbackQuery) Exists(ctx context.Context, exec boil.ContextExecutor) (bool, error) { + var count int64 + + queries.SetSelect(q.Query, nil) + queries.SetCount(q.Query) + queries.SetLimit(q.Query, 1) + + err := q.Query.QueryRowContext(ctx, exec).Scan(&count) + if err != nil { + return false, errors.Wrap(err, "models: failed to check if auth_fallback exists") + } + + return count > 0, nil +} + +// AuthFallbacks retrieves all the records using an executor. +func AuthFallbacks(mods ...qm.QueryMod) authFallbackQuery { + mods = append(mods, qm.From("\"auth_fallback\"")) + return authFallbackQuery{NewQuery(mods...)} +} + +// FindAuthFallback retrieves a single record by ID with an executor. +// If selectCols is empty Find will return all columns. +func FindAuthFallback(ctx context.Context, exec boil.ContextExecutor, iD int64, selectCols ...string) (*AuthFallback, error) { + authFallbackObj := &AuthFallback{} + + sel := "*" + if len(selectCols) > 0 { + sel = strings.Join(strmangle.IdentQuoteSlice(dialect.LQ, dialect.RQ, selectCols), ",") + } + query := fmt.Sprintf( + "select %s from \"auth_fallback\" where \"id\"=?", sel, + ) + + q := queries.Raw(query, iD) + + err := q.Bind(ctx, exec, authFallbackObj) + if err != nil { + if errors.Cause(err) == sql.ErrNoRows { + return nil, sql.ErrNoRows + } + return nil, errors.Wrap(err, "models: unable to select from auth_fallback") + } + + return authFallbackObj, nil +} + +// Insert a single record using an executor. +// See boil.Columns.InsertColumnSet documentation to understand column list inference for inserts. +func (o *AuthFallback) Insert(ctx context.Context, exec boil.ContextExecutor, columns boil.Columns) error { + if o == nil { + return errors.New("models: no auth_fallback provided for insertion") + } + + var err error + + if err := o.doBeforeInsertHooks(ctx, exec); err != nil { + return err + } + + nzDefaults := queries.NonZeroDefaultSet(authFallbackColumnsWithDefault, o) + + key := makeCacheKey(columns, nzDefaults) + authFallbackInsertCacheMut.RLock() + cache, cached := authFallbackInsertCache[key] + authFallbackInsertCacheMut.RUnlock() + + if !cached { + wl, returnColumns := columns.InsertColumnSet( + authFallbackAllColumns, + authFallbackColumnsWithDefault, + authFallbackColumnsWithoutDefault, + nzDefaults, + ) + + cache.valueMapping, err = queries.BindMapping(authFallbackType, authFallbackMapping, wl) + if err != nil { + return err + } + cache.retMapping, err = queries.BindMapping(authFallbackType, authFallbackMapping, returnColumns) + if err != nil { + return err + } + if len(wl) != 0 { + cache.query = fmt.Sprintf("INSERT INTO \"auth_fallback\" (\"%s\") %%sVALUES (%s)%%s", strings.Join(wl, "\",\""), strmangle.Placeholders(dialect.UseIndexPlaceholders, len(wl), 1, 1)) + } else { + cache.query = "INSERT INTO \"auth_fallback\" %sDEFAULT VALUES%s" + } + + var queryOutput, queryReturning string + + if len(cache.retMapping) != 0 { + cache.retQuery = fmt.Sprintf("SELECT \"%s\" FROM \"auth_fallback\" WHERE %s", strings.Join(returnColumns, "\",\""), strmangle.WhereClause("\"", "\"", 0, authFallbackPrimaryKeyColumns)) + } + + cache.query = fmt.Sprintf(cache.query, queryOutput, queryReturning) + } + + value := reflect.Indirect(reflect.ValueOf(o)) + vals := queries.ValuesFromMapping(value, cache.valueMapping) + + if boil.IsDebug(ctx) { + writer := boil.DebugWriterFrom(ctx) + fmt.Fprintln(writer, cache.query) + fmt.Fprintln(writer, vals) + } + _, err = exec.ExecContext(ctx, cache.query, vals...) + + if err != nil { + return errors.Wrap(err, "models: unable to insert into auth_fallback") + } + + var identifierCols []interface{} + + if len(cache.retMapping) == 0 { + goto CacheNoHooks + } + + identifierCols = []interface{}{ + o.ID, + } + + if boil.IsDebug(ctx) { + writer := boil.DebugWriterFrom(ctx) + fmt.Fprintln(writer, cache.retQuery) + fmt.Fprintln(writer, identifierCols...) + } + err = exec.QueryRowContext(ctx, cache.retQuery, identifierCols...).Scan(queries.PtrsFromMapping(value, cache.retMapping)...) + if err != nil { + return errors.Wrap(err, "models: unable to populate default values for auth_fallback") + } + +CacheNoHooks: + if !cached { + authFallbackInsertCacheMut.Lock() + authFallbackInsertCache[key] = cache + authFallbackInsertCacheMut.Unlock() + } + + return o.doAfterInsertHooks(ctx, exec) +} + +// Update uses an executor to update the AuthFallback. +// See boil.Columns.UpdateColumnSet documentation to understand column list inference for updates. +// Update does not automatically update the record in case of default values. Use .Reload() to refresh the records. +func (o *AuthFallback) Update(ctx context.Context, exec boil.ContextExecutor, columns boil.Columns) (int64, error) { + var err error + if err = o.doBeforeUpdateHooks(ctx, exec); err != nil { + return 0, err + } + key := makeCacheKey(columns, nil) + authFallbackUpdateCacheMut.RLock() + cache, cached := authFallbackUpdateCache[key] + authFallbackUpdateCacheMut.RUnlock() + + if !cached { + wl := columns.UpdateColumnSet( + authFallbackAllColumns, + authFallbackPrimaryKeyColumns, + ) + + if !columns.IsWhitelist() { + wl = strmangle.SetComplement(wl, []string{"created_at"}) + } + if len(wl) == 0 { + return 0, errors.New("models: unable to update auth_fallback, could not build whitelist") + } + + cache.query = fmt.Sprintf("UPDATE \"auth_fallback\" SET %s WHERE %s", + strmangle.SetParamNames("\"", "\"", 0, wl), + strmangle.WhereClause("\"", "\"", 0, authFallbackPrimaryKeyColumns), + ) + cache.valueMapping, err = queries.BindMapping(authFallbackType, authFallbackMapping, append(wl, authFallbackPrimaryKeyColumns...)) + if err != nil { + return 0, err + } + } + + values := queries.ValuesFromMapping(reflect.Indirect(reflect.ValueOf(o)), cache.valueMapping) + + if boil.IsDebug(ctx) { + writer := boil.DebugWriterFrom(ctx) + fmt.Fprintln(writer, cache.query) + fmt.Fprintln(writer, values) + } + var result sql.Result + result, err = exec.ExecContext(ctx, cache.query, values...) + if err != nil { + return 0, errors.Wrap(err, "models: unable to update auth_fallback row") + } + + rowsAff, err := result.RowsAffected() + if err != nil { + return 0, errors.Wrap(err, "models: failed to get rows affected by update for auth_fallback") + } + + if !cached { + authFallbackUpdateCacheMut.Lock() + authFallbackUpdateCache[key] = cache + authFallbackUpdateCacheMut.Unlock() + } + + return rowsAff, o.doAfterUpdateHooks(ctx, exec) +} + +// UpdateAll updates all rows with the specified column values. +func (q authFallbackQuery) UpdateAll(ctx context.Context, exec boil.ContextExecutor, cols M) (int64, error) { + queries.SetUpdate(q.Query, cols) + + result, err := q.Query.ExecContext(ctx, exec) + if err != nil { + return 0, errors.Wrap(err, "models: unable to update all for auth_fallback") + } + + rowsAff, err := result.RowsAffected() + if err != nil { + return 0, errors.Wrap(err, "models: unable to retrieve rows affected for auth_fallback") + } + + return rowsAff, nil +} + +// UpdateAll updates all rows with the specified column values, using an executor. +func (o AuthFallbackSlice) UpdateAll(ctx context.Context, exec boil.ContextExecutor, cols M) (int64, error) { + ln := int64(len(o)) + if ln == 0 { + return 0, nil + } + + if len(cols) == 0 { + return 0, errors.New("models: update all requires at least one column argument") + } + + colNames := make([]string, len(cols)) + args := make([]interface{}, len(cols)) + + i := 0 + for name, value := range cols { + colNames[i] = name + args[i] = value + i++ + } + + // Append all of the primary key values for each column + for _, obj := range o { + pkeyArgs := queries.ValuesFromMapping(reflect.Indirect(reflect.ValueOf(obj)), authFallbackPrimaryKeyMapping) + args = append(args, pkeyArgs...) + } + + sql := fmt.Sprintf("UPDATE \"auth_fallback\" SET %s WHERE %s", + strmangle.SetParamNames("\"", "\"", 0, colNames), + strmangle.WhereClauseRepeated(string(dialect.LQ), string(dialect.RQ), 0, authFallbackPrimaryKeyColumns, len(o))) + + if boil.IsDebug(ctx) { + writer := boil.DebugWriterFrom(ctx) + fmt.Fprintln(writer, sql) + fmt.Fprintln(writer, args...) + } + result, err := exec.ExecContext(ctx, sql, args...) + if err != nil { + return 0, errors.Wrap(err, "models: unable to update all in authFallback slice") + } + + rowsAff, err := result.RowsAffected() + if err != nil { + return 0, errors.Wrap(err, "models: unable to retrieve rows affected all in update all authFallback") + } + return rowsAff, nil +} + +// Delete deletes a single AuthFallback record with an executor. +// Delete will match against the primary key column to find the record to delete. +func (o *AuthFallback) Delete(ctx context.Context, exec boil.ContextExecutor) (int64, error) { + if o == nil { + return 0, errors.New("models: no AuthFallback provided for delete") + } + + if err := o.doBeforeDeleteHooks(ctx, exec); err != nil { + return 0, err + } + + args := queries.ValuesFromMapping(reflect.Indirect(reflect.ValueOf(o)), authFallbackPrimaryKeyMapping) + sql := "DELETE FROM \"auth_fallback\" WHERE \"id\"=?" + + if boil.IsDebug(ctx) { + writer := boil.DebugWriterFrom(ctx) + fmt.Fprintln(writer, sql) + fmt.Fprintln(writer, args...) + } + result, err := exec.ExecContext(ctx, sql, args...) + if err != nil { + return 0, errors.Wrap(err, "models: unable to delete from auth_fallback") + } + + rowsAff, err := result.RowsAffected() + if err != nil { + return 0, errors.Wrap(err, "models: failed to get rows affected by delete for auth_fallback") + } + + if err := o.doAfterDeleteHooks(ctx, exec); err != nil { + return 0, err + } + + return rowsAff, nil +} + +// DeleteAll deletes all matching rows. +func (q authFallbackQuery) DeleteAll(ctx context.Context, exec boil.ContextExecutor) (int64, error) { + if q.Query == nil { + return 0, errors.New("models: no authFallbackQuery provided for delete all") + } + + queries.SetDelete(q.Query) + + result, err := q.Query.ExecContext(ctx, exec) + if err != nil { + return 0, errors.Wrap(err, "models: unable to delete all from auth_fallback") + } + + rowsAff, err := result.RowsAffected() + if err != nil { + return 0, errors.Wrap(err, "models: failed to get rows affected by deleteall for auth_fallback") + } + + return rowsAff, nil +} + +// DeleteAll deletes all rows in the slice, using an executor. +func (o AuthFallbackSlice) DeleteAll(ctx context.Context, exec boil.ContextExecutor) (int64, error) { + if len(o) == 0 { + return 0, nil + } + + if len(authFallbackBeforeDeleteHooks) != 0 { + for _, obj := range o { + if err := obj.doBeforeDeleteHooks(ctx, exec); err != nil { + return 0, err + } + } + } + + var args []interface{} + for _, obj := range o { + pkeyArgs := queries.ValuesFromMapping(reflect.Indirect(reflect.ValueOf(obj)), authFallbackPrimaryKeyMapping) + args = append(args, pkeyArgs...) + } + + sql := "DELETE FROM \"auth_fallback\" WHERE " + + strmangle.WhereClauseRepeated(string(dialect.LQ), string(dialect.RQ), 0, authFallbackPrimaryKeyColumns, len(o)) + + if boil.IsDebug(ctx) { + writer := boil.DebugWriterFrom(ctx) + fmt.Fprintln(writer, sql) + fmt.Fprintln(writer, args) + } + result, err := exec.ExecContext(ctx, sql, args...) + if err != nil { + return 0, errors.Wrap(err, "models: unable to delete all from authFallback slice") + } + + rowsAff, err := result.RowsAffected() + if err != nil { + return 0, errors.Wrap(err, "models: failed to get rows affected by deleteall for auth_fallback") + } + + if len(authFallbackAfterDeleteHooks) != 0 { + for _, obj := range o { + if err := obj.doAfterDeleteHooks(ctx, exec); err != nil { + return 0, err + } + } + } + + return rowsAff, nil +} + +// Reload refetches the object from the database +// using the primary keys with an executor. +func (o *AuthFallback) Reload(ctx context.Context, exec boil.ContextExecutor) error { + ret, err := FindAuthFallback(ctx, exec, o.ID) + if err != nil { + return err + } + + *o = *ret + return nil +} + +// ReloadAll refetches every row with matching primary key column values +// and overwrites the original object slice with the newly updated slice. +func (o *AuthFallbackSlice) ReloadAll(ctx context.Context, exec boil.ContextExecutor) error { + if o == nil || len(*o) == 0 { + return nil + } + + slice := AuthFallbackSlice{} + var args []interface{} + for _, obj := range *o { + pkeyArgs := queries.ValuesFromMapping(reflect.Indirect(reflect.ValueOf(obj)), authFallbackPrimaryKeyMapping) + args = append(args, pkeyArgs...) + } + + sql := "SELECT \"auth_fallback\".* FROM \"auth_fallback\" WHERE " + + strmangle.WhereClauseRepeated(string(dialect.LQ), string(dialect.RQ), 0, authFallbackPrimaryKeyColumns, len(*o)) + + q := queries.Raw(sql, args...) + + err := q.Bind(ctx, exec, &slice) + if err != nil { + return errors.Wrap(err, "models: unable to reload all in AuthFallbackSlice") + } + + *o = slice + + return nil +} + +// AuthFallbackExists checks if the AuthFallback row exists. +func AuthFallbackExists(ctx context.Context, exec boil.ContextExecutor, iD int64) (bool, error) { + var exists bool + sql := "select exists(select 1 from \"auth_fallback\" where \"id\"=? limit 1)" + + if boil.IsDebug(ctx) { + writer := boil.DebugWriterFrom(ctx) + fmt.Fprintln(writer, sql) + fmt.Fprintln(writer, iD) + } + row := exec.QueryRowContext(ctx, sql, iD) + + err := row.Scan(&exists) + if err != nil { + return false, errors.Wrap(err, "models: unable to check if auth_fallback exists") + } + + return exists, nil +} diff --git a/admindb/sqlite/models/auth_fallback_test.go b/admindb/sqlite/models/auth_fallback_test.go new file mode 100644 index 0000000..22d1cdb --- /dev/null +++ b/admindb/sqlite/models/auth_fallback_test.go @@ -0,0 +1,684 @@ +// Code generated by SQLBoiler 4.4.0 (https://github.com/volatiletech/sqlboiler). DO NOT EDIT. +// This file is meant to be re-generated in place and/or deleted at any time. + +package models + +import ( + "bytes" + "context" + "reflect" + "testing" + + "github.com/volatiletech/randomize" + "github.com/volatiletech/sqlboiler/v4/boil" + "github.com/volatiletech/sqlboiler/v4/queries" + "github.com/volatiletech/strmangle" +) + +var ( + // Relationships sometimes use the reflection helper queries.Equal/queries.Assign + // so force a package dependency in case they don't. + _ = queries.Equal +) + +func testAuthFallbacks(t *testing.T) { + t.Parallel() + + query := AuthFallbacks() + + if query.Query == nil { + t.Error("expected a query, got nothing") + } +} + +func testAuthFallbacksDelete(t *testing.T) { + t.Parallel() + + seed := randomize.NewSeed() + var err error + o := &AuthFallback{} + if err = randomize.Struct(seed, o, authFallbackDBTypes, true, authFallbackColumnsWithDefault...); err != nil { + t.Errorf("Unable to randomize AuthFallback struct: %s", err) + } + + ctx := context.Background() + tx := MustTx(boil.BeginTx(ctx, nil)) + defer func() { _ = tx.Rollback() }() + if err = o.Insert(ctx, tx, boil.Infer()); err != nil { + t.Error(err) + } + + if rowsAff, err := o.Delete(ctx, tx); err != nil { + t.Error(err) + } else if rowsAff != 1 { + t.Error("should only have deleted one row, but affected:", rowsAff) + } + + count, err := AuthFallbacks().Count(ctx, tx) + if err != nil { + t.Error(err) + } + + if count != 0 { + t.Error("want zero records, got:", count) + } +} + +func testAuthFallbacksQueryDeleteAll(t *testing.T) { + t.Parallel() + + seed := randomize.NewSeed() + var err error + o := &AuthFallback{} + if err = randomize.Struct(seed, o, authFallbackDBTypes, true, authFallbackColumnsWithDefault...); err != nil { + t.Errorf("Unable to randomize AuthFallback struct: %s", err) + } + + ctx := context.Background() + tx := MustTx(boil.BeginTx(ctx, nil)) + defer func() { _ = tx.Rollback() }() + if err = o.Insert(ctx, tx, boil.Infer()); err != nil { + t.Error(err) + } + + if rowsAff, err := AuthFallbacks().DeleteAll(ctx, tx); err != nil { + t.Error(err) + } else if rowsAff != 1 { + t.Error("should only have deleted one row, but affected:", rowsAff) + } + + count, err := AuthFallbacks().Count(ctx, tx) + if err != nil { + t.Error(err) + } + + if count != 0 { + t.Error("want zero records, got:", count) + } +} + +func testAuthFallbacksSliceDeleteAll(t *testing.T) { + t.Parallel() + + seed := randomize.NewSeed() + var err error + o := &AuthFallback{} + if err = randomize.Struct(seed, o, authFallbackDBTypes, true, authFallbackColumnsWithDefault...); err != nil { + t.Errorf("Unable to randomize AuthFallback struct: %s", err) + } + + ctx := context.Background() + tx := MustTx(boil.BeginTx(ctx, nil)) + defer func() { _ = tx.Rollback() }() + if err = o.Insert(ctx, tx, boil.Infer()); err != nil { + t.Error(err) + } + + slice := AuthFallbackSlice{o} + + if rowsAff, err := slice.DeleteAll(ctx, tx); err != nil { + t.Error(err) + } else if rowsAff != 1 { + t.Error("should only have deleted one row, but affected:", rowsAff) + } + + count, err := AuthFallbacks().Count(ctx, tx) + if err != nil { + t.Error(err) + } + + if count != 0 { + t.Error("want zero records, got:", count) + } +} + +func testAuthFallbacksExists(t *testing.T) { + t.Parallel() + + seed := randomize.NewSeed() + var err error + o := &AuthFallback{} + if err = randomize.Struct(seed, o, authFallbackDBTypes, true, authFallbackColumnsWithDefault...); err != nil { + t.Errorf("Unable to randomize AuthFallback struct: %s", err) + } + + ctx := context.Background() + tx := MustTx(boil.BeginTx(ctx, nil)) + defer func() { _ = tx.Rollback() }() + if err = o.Insert(ctx, tx, boil.Infer()); err != nil { + t.Error(err) + } + + e, err := AuthFallbackExists(ctx, tx, o.ID) + if err != nil { + t.Errorf("Unable to check if AuthFallback exists: %s", err) + } + if !e { + t.Errorf("Expected AuthFallbackExists to return true, but got false.") + } +} + +func testAuthFallbacksFind(t *testing.T) { + t.Parallel() + + seed := randomize.NewSeed() + var err error + o := &AuthFallback{} + if err = randomize.Struct(seed, o, authFallbackDBTypes, true, authFallbackColumnsWithDefault...); err != nil { + t.Errorf("Unable to randomize AuthFallback struct: %s", err) + } + + ctx := context.Background() + tx := MustTx(boil.BeginTx(ctx, nil)) + defer func() { _ = tx.Rollback() }() + if err = o.Insert(ctx, tx, boil.Infer()); err != nil { + t.Error(err) + } + + authFallbackFound, err := FindAuthFallback(ctx, tx, o.ID) + if err != nil { + t.Error(err) + } + + if authFallbackFound == nil { + t.Error("want a record, got nil") + } +} + +func testAuthFallbacksBind(t *testing.T) { + t.Parallel() + + seed := randomize.NewSeed() + var err error + o := &AuthFallback{} + if err = randomize.Struct(seed, o, authFallbackDBTypes, true, authFallbackColumnsWithDefault...); err != nil { + t.Errorf("Unable to randomize AuthFallback struct: %s", err) + } + + ctx := context.Background() + tx := MustTx(boil.BeginTx(ctx, nil)) + defer func() { _ = tx.Rollback() }() + if err = o.Insert(ctx, tx, boil.Infer()); err != nil { + t.Error(err) + } + + if err = AuthFallbacks().Bind(ctx, tx, o); err != nil { + t.Error(err) + } +} + +func testAuthFallbacksOne(t *testing.T) { + t.Parallel() + + seed := randomize.NewSeed() + var err error + o := &AuthFallback{} + if err = randomize.Struct(seed, o, authFallbackDBTypes, true, authFallbackColumnsWithDefault...); err != nil { + t.Errorf("Unable to randomize AuthFallback struct: %s", err) + } + + ctx := context.Background() + tx := MustTx(boil.BeginTx(ctx, nil)) + defer func() { _ = tx.Rollback() }() + if err = o.Insert(ctx, tx, boil.Infer()); err != nil { + t.Error(err) + } + + if x, err := AuthFallbacks().One(ctx, tx); err != nil { + t.Error(err) + } else if x == nil { + t.Error("expected to get a non nil record") + } +} + +func testAuthFallbacksAll(t *testing.T) { + t.Parallel() + + seed := randomize.NewSeed() + var err error + authFallbackOne := &AuthFallback{} + authFallbackTwo := &AuthFallback{} + if err = randomize.Struct(seed, authFallbackOne, authFallbackDBTypes, false, authFallbackColumnsWithDefault...); err != nil { + t.Errorf("Unable to randomize AuthFallback struct: %s", err) + } + if err = randomize.Struct(seed, authFallbackTwo, authFallbackDBTypes, false, authFallbackColumnsWithDefault...); err != nil { + t.Errorf("Unable to randomize AuthFallback struct: %s", err) + } + + ctx := context.Background() + tx := MustTx(boil.BeginTx(ctx, nil)) + defer func() { _ = tx.Rollback() }() + if err = authFallbackOne.Insert(ctx, tx, boil.Infer()); err != nil { + t.Error(err) + } + if err = authFallbackTwo.Insert(ctx, tx, boil.Infer()); err != nil { + t.Error(err) + } + + slice, err := AuthFallbacks().All(ctx, tx) + if err != nil { + t.Error(err) + } + + if len(slice) != 2 { + t.Error("want 2 records, got:", len(slice)) + } +} + +func testAuthFallbacksCount(t *testing.T) { + t.Parallel() + + var err error + seed := randomize.NewSeed() + authFallbackOne := &AuthFallback{} + authFallbackTwo := &AuthFallback{} + if err = randomize.Struct(seed, authFallbackOne, authFallbackDBTypes, false, authFallbackColumnsWithDefault...); err != nil { + t.Errorf("Unable to randomize AuthFallback struct: %s", err) + } + if err = randomize.Struct(seed, authFallbackTwo, authFallbackDBTypes, false, authFallbackColumnsWithDefault...); err != nil { + t.Errorf("Unable to randomize AuthFallback struct: %s", err) + } + + ctx := context.Background() + tx := MustTx(boil.BeginTx(ctx, nil)) + defer func() { _ = tx.Rollback() }() + if err = authFallbackOne.Insert(ctx, tx, boil.Infer()); err != nil { + t.Error(err) + } + if err = authFallbackTwo.Insert(ctx, tx, boil.Infer()); err != nil { + t.Error(err) + } + + count, err := AuthFallbacks().Count(ctx, tx) + if err != nil { + t.Error(err) + } + + if count != 2 { + t.Error("want 2 records, got:", count) + } +} + +func authFallbackBeforeInsertHook(ctx context.Context, e boil.ContextExecutor, o *AuthFallback) error { + *o = AuthFallback{} + return nil +} + +func authFallbackAfterInsertHook(ctx context.Context, e boil.ContextExecutor, o *AuthFallback) error { + *o = AuthFallback{} + return nil +} + +func authFallbackAfterSelectHook(ctx context.Context, e boil.ContextExecutor, o *AuthFallback) error { + *o = AuthFallback{} + return nil +} + +func authFallbackBeforeUpdateHook(ctx context.Context, e boil.ContextExecutor, o *AuthFallback) error { + *o = AuthFallback{} + return nil +} + +func authFallbackAfterUpdateHook(ctx context.Context, e boil.ContextExecutor, o *AuthFallback) error { + *o = AuthFallback{} + return nil +} + +func authFallbackBeforeDeleteHook(ctx context.Context, e boil.ContextExecutor, o *AuthFallback) error { + *o = AuthFallback{} + return nil +} + +func authFallbackAfterDeleteHook(ctx context.Context, e boil.ContextExecutor, o *AuthFallback) error { + *o = AuthFallback{} + return nil +} + +func authFallbackBeforeUpsertHook(ctx context.Context, e boil.ContextExecutor, o *AuthFallback) error { + *o = AuthFallback{} + return nil +} + +func authFallbackAfterUpsertHook(ctx context.Context, e boil.ContextExecutor, o *AuthFallback) error { + *o = AuthFallback{} + return nil +} + +func testAuthFallbacksHooks(t *testing.T) { + t.Parallel() + + var err error + + ctx := context.Background() + empty := &AuthFallback{} + o := &AuthFallback{} + + seed := randomize.NewSeed() + if err = randomize.Struct(seed, o, authFallbackDBTypes, false); err != nil { + t.Errorf("Unable to randomize AuthFallback object: %s", err) + } + + AddAuthFallbackHook(boil.BeforeInsertHook, authFallbackBeforeInsertHook) + if err = o.doBeforeInsertHooks(ctx, nil); err != nil { + t.Errorf("Unable to execute doBeforeInsertHooks: %s", err) + } + if !reflect.DeepEqual(o, empty) { + t.Errorf("Expected BeforeInsertHook function to empty object, but got: %#v", o) + } + authFallbackBeforeInsertHooks = []AuthFallbackHook{} + + AddAuthFallbackHook(boil.AfterInsertHook, authFallbackAfterInsertHook) + if err = o.doAfterInsertHooks(ctx, nil); err != nil { + t.Errorf("Unable to execute doAfterInsertHooks: %s", err) + } + if !reflect.DeepEqual(o, empty) { + t.Errorf("Expected AfterInsertHook function to empty object, but got: %#v", o) + } + authFallbackAfterInsertHooks = []AuthFallbackHook{} + + AddAuthFallbackHook(boil.AfterSelectHook, authFallbackAfterSelectHook) + if err = o.doAfterSelectHooks(ctx, nil); err != nil { + t.Errorf("Unable to execute doAfterSelectHooks: %s", err) + } + if !reflect.DeepEqual(o, empty) { + t.Errorf("Expected AfterSelectHook function to empty object, but got: %#v", o) + } + authFallbackAfterSelectHooks = []AuthFallbackHook{} + + AddAuthFallbackHook(boil.BeforeUpdateHook, authFallbackBeforeUpdateHook) + if err = o.doBeforeUpdateHooks(ctx, nil); err != nil { + t.Errorf("Unable to execute doBeforeUpdateHooks: %s", err) + } + if !reflect.DeepEqual(o, empty) { + t.Errorf("Expected BeforeUpdateHook function to empty object, but got: %#v", o) + } + authFallbackBeforeUpdateHooks = []AuthFallbackHook{} + + AddAuthFallbackHook(boil.AfterUpdateHook, authFallbackAfterUpdateHook) + if err = o.doAfterUpdateHooks(ctx, nil); err != nil { + t.Errorf("Unable to execute doAfterUpdateHooks: %s", err) + } + if !reflect.DeepEqual(o, empty) { + t.Errorf("Expected AfterUpdateHook function to empty object, but got: %#v", o) + } + authFallbackAfterUpdateHooks = []AuthFallbackHook{} + + AddAuthFallbackHook(boil.BeforeDeleteHook, authFallbackBeforeDeleteHook) + if err = o.doBeforeDeleteHooks(ctx, nil); err != nil { + t.Errorf("Unable to execute doBeforeDeleteHooks: %s", err) + } + if !reflect.DeepEqual(o, empty) { + t.Errorf("Expected BeforeDeleteHook function to empty object, but got: %#v", o) + } + authFallbackBeforeDeleteHooks = []AuthFallbackHook{} + + AddAuthFallbackHook(boil.AfterDeleteHook, authFallbackAfterDeleteHook) + if err = o.doAfterDeleteHooks(ctx, nil); err != nil { + t.Errorf("Unable to execute doAfterDeleteHooks: %s", err) + } + if !reflect.DeepEqual(o, empty) { + t.Errorf("Expected AfterDeleteHook function to empty object, but got: %#v", o) + } + authFallbackAfterDeleteHooks = []AuthFallbackHook{} + + AddAuthFallbackHook(boil.BeforeUpsertHook, authFallbackBeforeUpsertHook) + if err = o.doBeforeUpsertHooks(ctx, nil); err != nil { + t.Errorf("Unable to execute doBeforeUpsertHooks: %s", err) + } + if !reflect.DeepEqual(o, empty) { + t.Errorf("Expected BeforeUpsertHook function to empty object, but got: %#v", o) + } + authFallbackBeforeUpsertHooks = []AuthFallbackHook{} + + AddAuthFallbackHook(boil.AfterUpsertHook, authFallbackAfterUpsertHook) + if err = o.doAfterUpsertHooks(ctx, nil); err != nil { + t.Errorf("Unable to execute doAfterUpsertHooks: %s", err) + } + if !reflect.DeepEqual(o, empty) { + t.Errorf("Expected AfterUpsertHook function to empty object, but got: %#v", o) + } + authFallbackAfterUpsertHooks = []AuthFallbackHook{} +} + +func testAuthFallbacksInsert(t *testing.T) { + t.Parallel() + + seed := randomize.NewSeed() + var err error + o := &AuthFallback{} + if err = randomize.Struct(seed, o, authFallbackDBTypes, true, authFallbackColumnsWithDefault...); err != nil { + t.Errorf("Unable to randomize AuthFallback struct: %s", err) + } + + ctx := context.Background() + tx := MustTx(boil.BeginTx(ctx, nil)) + defer func() { _ = tx.Rollback() }() + if err = o.Insert(ctx, tx, boil.Infer()); err != nil { + t.Error(err) + } + + count, err := AuthFallbacks().Count(ctx, tx) + if err != nil { + t.Error(err) + } + + if count != 1 { + t.Error("want one record, got:", count) + } +} + +func testAuthFallbacksInsertWhitelist(t *testing.T) { + t.Parallel() + + seed := randomize.NewSeed() + var err error + o := &AuthFallback{} + if err = randomize.Struct(seed, o, authFallbackDBTypes, true); err != nil { + t.Errorf("Unable to randomize AuthFallback struct: %s", err) + } + + ctx := context.Background() + tx := MustTx(boil.BeginTx(ctx, nil)) + defer func() { _ = tx.Rollback() }() + if err = o.Insert(ctx, tx, boil.Whitelist(authFallbackColumnsWithoutDefault...)); err != nil { + t.Error(err) + } + + count, err := AuthFallbacks().Count(ctx, tx) + if err != nil { + t.Error(err) + } + + if count != 1 { + t.Error("want one record, got:", count) + } +} + +func testAuthFallbacksReload(t *testing.T) { + t.Parallel() + + seed := randomize.NewSeed() + var err error + o := &AuthFallback{} + if err = randomize.Struct(seed, o, authFallbackDBTypes, true, authFallbackColumnsWithDefault...); err != nil { + t.Errorf("Unable to randomize AuthFallback struct: %s", err) + } + + ctx := context.Background() + tx := MustTx(boil.BeginTx(ctx, nil)) + defer func() { _ = tx.Rollback() }() + if err = o.Insert(ctx, tx, boil.Infer()); err != nil { + t.Error(err) + } + + if err = o.Reload(ctx, tx); err != nil { + t.Error(err) + } +} + +func testAuthFallbacksReloadAll(t *testing.T) { + t.Parallel() + + seed := randomize.NewSeed() + var err error + o := &AuthFallback{} + if err = randomize.Struct(seed, o, authFallbackDBTypes, true, authFallbackColumnsWithDefault...); err != nil { + t.Errorf("Unable to randomize AuthFallback struct: %s", err) + } + + ctx := context.Background() + tx := MustTx(boil.BeginTx(ctx, nil)) + defer func() { _ = tx.Rollback() }() + if err = o.Insert(ctx, tx, boil.Infer()); err != nil { + t.Error(err) + } + + slice := AuthFallbackSlice{o} + + if err = slice.ReloadAll(ctx, tx); err != nil { + t.Error(err) + } +} + +func testAuthFallbacksSelect(t *testing.T) { + t.Parallel() + + seed := randomize.NewSeed() + var err error + o := &AuthFallback{} + if err = randomize.Struct(seed, o, authFallbackDBTypes, true, authFallbackColumnsWithDefault...); err != nil { + t.Errorf("Unable to randomize AuthFallback struct: %s", err) + } + + ctx := context.Background() + tx := MustTx(boil.BeginTx(ctx, nil)) + defer func() { _ = tx.Rollback() }() + if err = o.Insert(ctx, tx, boil.Infer()); err != nil { + t.Error(err) + } + + slice, err := AuthFallbacks().All(ctx, tx) + if err != nil { + t.Error(err) + } + + if len(slice) != 1 { + t.Error("want one record, got:", len(slice)) + } +} + +var ( + authFallbackDBTypes = map[string]string{`ID`: `INT`, `Name`: `TEXT`, `PasswordHash`: `BLOB`} + _ = bytes.MinRead +) + +func testAuthFallbacksUpdate(t *testing.T) { + t.Parallel() + + if 0 == len(authFallbackPrimaryKeyColumns) { + t.Skip("Skipping table with no primary key columns") + } + if len(authFallbackAllColumns) == len(authFallbackPrimaryKeyColumns) { + t.Skip("Skipping table with only primary key columns") + } + + seed := randomize.NewSeed() + var err error + o := &AuthFallback{} + if err = randomize.Struct(seed, o, authFallbackDBTypes, true, authFallbackColumnsWithDefault...); err != nil { + t.Errorf("Unable to randomize AuthFallback struct: %s", err) + } + + ctx := context.Background() + tx := MustTx(boil.BeginTx(ctx, nil)) + defer func() { _ = tx.Rollback() }() + if err = o.Insert(ctx, tx, boil.Infer()); err != nil { + t.Error(err) + } + + count, err := AuthFallbacks().Count(ctx, tx) + if err != nil { + t.Error(err) + } + + if count != 1 { + t.Error("want one record, got:", count) + } + + if err = randomize.Struct(seed, o, authFallbackDBTypes, true, authFallbackPrimaryKeyColumns...); err != nil { + t.Errorf("Unable to randomize AuthFallback struct: %s", err) + } + + if rowsAff, err := o.Update(ctx, tx, boil.Infer()); err != nil { + t.Error(err) + } else if rowsAff != 1 { + t.Error("should only affect one row but affected", rowsAff) + } +} + +func testAuthFallbacksSliceUpdateAll(t *testing.T) { + t.Parallel() + + if len(authFallbackAllColumns) == len(authFallbackPrimaryKeyColumns) { + t.Skip("Skipping table with only primary key columns") + } + + seed := randomize.NewSeed() + var err error + o := &AuthFallback{} + if err = randomize.Struct(seed, o, authFallbackDBTypes, true, authFallbackColumnsWithDefault...); err != nil { + t.Errorf("Unable to randomize AuthFallback struct: %s", err) + } + + ctx := context.Background() + tx := MustTx(boil.BeginTx(ctx, nil)) + defer func() { _ = tx.Rollback() }() + if err = o.Insert(ctx, tx, boil.Infer()); err != nil { + t.Error(err) + } + + count, err := AuthFallbacks().Count(ctx, tx) + if err != nil { + t.Error(err) + } + + if count != 1 { + t.Error("want one record, got:", count) + } + + if err = randomize.Struct(seed, o, authFallbackDBTypes, true, authFallbackPrimaryKeyColumns...); err != nil { + t.Errorf("Unable to randomize AuthFallback struct: %s", err) + } + + // Remove Primary keys and unique columns from what we plan to update + var fields []string + if strmangle.StringSliceMatch(authFallbackAllColumns, authFallbackPrimaryKeyColumns) { + fields = authFallbackAllColumns + } else { + fields = strmangle.SetComplement( + authFallbackAllColumns, + authFallbackPrimaryKeyColumns, + ) + } + + value := reflect.Indirect(reflect.ValueOf(o)) + typ := reflect.TypeOf(o).Elem() + n := typ.NumField() + + updateMap := M{} + for _, col := range fields { + for i := 0; i < n; i++ { + f := typ.Field(i) + if f.Tag.Get("boil") == col { + updateMap[col] = value.Field(i).Interface() + } + } + } + + slice := AuthFallbackSlice{o} + if rowsAff, err := slice.UpdateAll(ctx, tx, updateMap); err != nil { + t.Error(err) + } else if rowsAff != 1 { + t.Error("wanted one record updated but got", rowsAff) + } +} diff --git a/admindb/sqlite/models/boil_main_test.go b/admindb/sqlite/models/boil_main_test.go new file mode 100644 index 0000000..8187902 --- /dev/null +++ b/admindb/sqlite/models/boil_main_test.go @@ -0,0 +1,119 @@ +// Code generated by SQLBoiler 4.4.0 (https://github.com/volatiletech/sqlboiler). DO NOT EDIT. +// This file is meant to be re-generated in place and/or deleted at any time. + +package models + +import ( + "database/sql" + "flag" + "fmt" + "math/rand" + "os" + "path/filepath" + "strings" + "testing" + "time" + + "github.com/spf13/viper" + "github.com/volatiletech/sqlboiler/v4/boil" +) + +var flagDebugMode = flag.Bool("test.sqldebug", false, "Turns on debug mode for SQL statements") +var flagConfigFile = flag.String("test.config", "", "Overrides the default config") + +const outputDirDepth = 1 + +var ( + dbMain tester +) + +type tester interface { + setup() error + conn() (*sql.DB, error) + teardown() error +} + +func TestMain(m *testing.M) { + if dbMain == nil { + fmt.Println("no dbMain tester interface was ready") + os.Exit(-1) + } + + rand.Seed(time.Now().UnixNano()) + + flag.Parse() + + var err error + + // Load configuration + err = initViper() + if err != nil { + fmt.Println("unable to load config file") + os.Exit(-2) + } + + // Set DebugMode so we can see generated sql statements + boil.DebugMode = *flagDebugMode + + if err = dbMain.setup(); err != nil { + fmt.Println("Unable to execute setup:", err) + os.Exit(-4) + } + + conn, err := dbMain.conn() + if err != nil { + fmt.Println("failed to get connection:", err) + } + + var code int + boil.SetDB(conn) + code = m.Run() + + if err = dbMain.teardown(); err != nil { + fmt.Println("Unable to execute teardown:", err) + os.Exit(-5) + } + + os.Exit(code) +} + +func initViper() error { + if flagConfigFile != nil && *flagConfigFile != "" { + viper.SetConfigFile(*flagConfigFile) + if err := viper.ReadInConfig(); err != nil { + return err + } + return nil + } + + var err error + + viper.SetConfigName("sqlboiler") + + configHome := os.Getenv("XDG_CONFIG_HOME") + homePath := os.Getenv("HOME") + wd, err := os.Getwd() + if err != nil { + wd = strings.Repeat("../", outputDirDepth) + } else { + wd = wd + strings.Repeat("/..", outputDirDepth) + } + + configPaths := []string{wd} + if len(configHome) > 0 { + configPaths = append(configPaths, filepath.Join(configHome, "sqlboiler")) + } else { + configPaths = append(configPaths, filepath.Join(homePath, ".config/sqlboiler")) + } + + for _, p := range configPaths { + viper.AddConfigPath(p) + } + + // Ignore errors here, fall back to defaults and validation to provide errs + _ = viper.ReadInConfig() + viper.SetEnvKeyReplacer(strings.NewReplacer(".", "_")) + viper.AutomaticEnv() + + return nil +} diff --git a/admindb/sqlite/models/boil_queries.go b/admindb/sqlite/models/boil_queries.go new file mode 100644 index 0000000..1b4038c --- /dev/null +++ b/admindb/sqlite/models/boil_queries.go @@ -0,0 +1,33 @@ +// Code generated by SQLBoiler 4.4.0 (https://github.com/volatiletech/sqlboiler). DO NOT EDIT. +// This file is meant to be re-generated in place and/or deleted at any time. + +package models + +import ( + "github.com/volatiletech/sqlboiler/v4/drivers" + "github.com/volatiletech/sqlboiler/v4/queries" + "github.com/volatiletech/sqlboiler/v4/queries/qm" +) + +var dialect = drivers.Dialect{ + LQ: 0x22, + RQ: 0x22, + + UseIndexPlaceholders: false, + UseLastInsertID: true, + UseSchema: false, + UseDefaultKeyword: true, + UseAutoColumns: false, + UseTopClause: false, + UseOutputClause: false, + UseCaseWhenExistsClause: false, +} + +// NewQuery initializes a new Query using the passed in QueryMods +func NewQuery(mods ...qm.QueryMod) *queries.Query { + q := &queries.Query{} + queries.SetDialect(q, &dialect) + qm.Apply(q, mods...) + + return q +} diff --git a/admindb/sqlite/models/boil_queries_test.go b/admindb/sqlite/models/boil_queries_test.go new file mode 100644 index 0000000..c56077c --- /dev/null +++ b/admindb/sqlite/models/boil_queries_test.go @@ -0,0 +1,52 @@ +// Code generated by SQLBoiler 4.4.0 (https://github.com/volatiletech/sqlboiler). DO NOT EDIT. +// This file is meant to be re-generated in place and/or deleted at any time. + +package models + +import ( + "bytes" + "fmt" + "io" + "io/ioutil" + "math/rand" + "regexp" + + "github.com/volatiletech/sqlboiler/v4/boil" +) + +var dbNameRand *rand.Rand + +func MustTx(transactor boil.ContextTransactor, err error) boil.ContextTransactor { + if err != nil { + panic(fmt.Sprintf("Cannot create a transactor: %s", err)) + } + return transactor +} + +func newFKeyDestroyer(regex *regexp.Regexp, reader io.Reader) io.Reader { + return &fKeyDestroyer{ + reader: reader, + rgx: regex, + } +} + +type fKeyDestroyer struct { + reader io.Reader + buf *bytes.Buffer + rgx *regexp.Regexp +} + +func (f *fKeyDestroyer) Read(b []byte) (int, error) { + if f.buf == nil { + all, err := ioutil.ReadAll(f.reader) + if err != nil { + return 0, err + } + + all = bytes.Replace(all, []byte{'\r', '\n'}, []byte{'\n'}, -1) + all = f.rgx.ReplaceAll(all, []byte{}) + f.buf = bytes.NewBuffer(all) + } + + return f.buf.Read(b) +} diff --git a/admindb/sqlite/models/boil_suites_test.go b/admindb/sqlite/models/boil_suites_test.go new file mode 100644 index 0000000..086d8cc --- /dev/null +++ b/admindb/sqlite/models/boil_suites_test.go @@ -0,0 +1,139 @@ +// Code generated by SQLBoiler 4.4.0 (https://github.com/volatiletech/sqlboiler). DO NOT EDIT. +// This file is meant to be re-generated in place and/or deleted at any time. + +package models + +import "testing" + +// This test suite runs each operation test in parallel. +// Example, if your database has 3 tables, the suite will run: +// table1, table2 and table3 Delete in parallel +// table1, table2 and table3 Insert in parallel, and so forth. +// It does NOT run each operation group in parallel. +// Separating the tests thusly grants avoidance of Postgres deadlocks. +func TestParent(t *testing.T) { + t.Run("Aliases", testAliases) + t.Run("AuthFallbacks", testAuthFallbacks) +} + +func TestDelete(t *testing.T) { + t.Run("Aliases", testAliasesDelete) + t.Run("AuthFallbacks", testAuthFallbacksDelete) +} + +func TestQueryDeleteAll(t *testing.T) { + t.Run("Aliases", testAliasesQueryDeleteAll) + t.Run("AuthFallbacks", testAuthFallbacksQueryDeleteAll) +} + +func TestSliceDeleteAll(t *testing.T) { + t.Run("Aliases", testAliasesSliceDeleteAll) + t.Run("AuthFallbacks", testAuthFallbacksSliceDeleteAll) +} + +func TestExists(t *testing.T) { + t.Run("Aliases", testAliasesExists) + t.Run("AuthFallbacks", testAuthFallbacksExists) +} + +func TestFind(t *testing.T) { + t.Run("Aliases", testAliasesFind) + t.Run("AuthFallbacks", testAuthFallbacksFind) +} + +func TestBind(t *testing.T) { + t.Run("Aliases", testAliasesBind) + t.Run("AuthFallbacks", testAuthFallbacksBind) +} + +func TestOne(t *testing.T) { + t.Run("Aliases", testAliasesOne) + t.Run("AuthFallbacks", testAuthFallbacksOne) +} + +func TestAll(t *testing.T) { + t.Run("Aliases", testAliasesAll) + t.Run("AuthFallbacks", testAuthFallbacksAll) +} + +func TestCount(t *testing.T) { + t.Run("Aliases", testAliasesCount) + t.Run("AuthFallbacks", testAuthFallbacksCount) +} + +func TestHooks(t *testing.T) { + t.Run("Aliases", testAliasesHooks) + t.Run("AuthFallbacks", testAuthFallbacksHooks) +} + +func TestInsert(t *testing.T) { + t.Run("Aliases", testAliasesInsert) + t.Run("Aliases", testAliasesInsertWhitelist) + t.Run("AuthFallbacks", testAuthFallbacksInsert) + t.Run("AuthFallbacks", testAuthFallbacksInsertWhitelist) +} + +// TestToOne tests cannot be run in parallel +// or deadlocks can occur. +func TestToOne(t *testing.T) {} + +// TestOneToOne tests cannot be run in parallel +// or deadlocks can occur. +func TestOneToOne(t *testing.T) {} + +// TestToMany tests cannot be run in parallel +// or deadlocks can occur. +func TestToMany(t *testing.T) {} + +// TestToOneSet tests cannot be run in parallel +// or deadlocks can occur. +func TestToOneSet(t *testing.T) {} + +// TestToOneRemove tests cannot be run in parallel +// or deadlocks can occur. +func TestToOneRemove(t *testing.T) {} + +// TestOneToOneSet tests cannot be run in parallel +// or deadlocks can occur. +func TestOneToOneSet(t *testing.T) {} + +// TestOneToOneRemove tests cannot be run in parallel +// or deadlocks can occur. +func TestOneToOneRemove(t *testing.T) {} + +// TestToManyAdd tests cannot be run in parallel +// or deadlocks can occur. +func TestToManyAdd(t *testing.T) {} + +// TestToManySet tests cannot be run in parallel +// or deadlocks can occur. +func TestToManySet(t *testing.T) {} + +// TestToManyRemove tests cannot be run in parallel +// or deadlocks can occur. +func TestToManyRemove(t *testing.T) {} + +func TestReload(t *testing.T) { + t.Run("Aliases", testAliasesReload) + t.Run("AuthFallbacks", testAuthFallbacksReload) +} + +func TestReloadAll(t *testing.T) { + t.Run("Aliases", testAliasesReloadAll) + t.Run("AuthFallbacks", testAuthFallbacksReloadAll) +} + +func TestSelect(t *testing.T) { + t.Run("Aliases", testAliasesSelect) + t.Run("AuthFallbacks", testAuthFallbacksSelect) +} + +func TestUpdate(t *testing.T) { + t.Run("Aliases", testAliasesUpdate) + t.Run("AuthFallbacks", testAuthFallbacksUpdate) +} + +func TestSliceUpdateAll(t *testing.T) { + t.Run("Aliases", testAliasesSliceUpdateAll) + t.Run("AuthFallbacks", testAuthFallbacksSliceUpdateAll) +} diff --git a/admindb/sqlite/models/boil_table_names.go b/admindb/sqlite/models/boil_table_names.go new file mode 100644 index 0000000..66b3358 --- /dev/null +++ b/admindb/sqlite/models/boil_table_names.go @@ -0,0 +1,12 @@ +// Code generated by SQLBoiler 4.4.0 (https://github.com/volatiletech/sqlboiler). DO NOT EDIT. +// This file is meant to be re-generated in place and/or deleted at any time. + +package models + +var TableNames = struct { + Aliases string + AuthFallback string +}{ + Aliases: "aliases", + AuthFallback: "auth_fallback", +} diff --git a/admindb/sqlite/models/boil_types.go b/admindb/sqlite/models/boil_types.go new file mode 100644 index 0000000..36523cf --- /dev/null +++ b/admindb/sqlite/models/boil_types.go @@ -0,0 +1,52 @@ +// Code generated by SQLBoiler 4.4.0 (https://github.com/volatiletech/sqlboiler). DO NOT EDIT. +// This file is meant to be re-generated in place and/or deleted at any time. + +package models + +import ( + "strconv" + + "github.com/friendsofgo/errors" + "github.com/volatiletech/sqlboiler/v4/boil" + "github.com/volatiletech/strmangle" +) + +// M type is for providing columns and column values to UpdateAll. +type M map[string]interface{} + +// ErrSyncFail occurs during insert when the record could not be retrieved in +// order to populate default value information. This usually happens when LastInsertId +// fails or there was a primary key configuration that was not resolvable. +var ErrSyncFail = errors.New("models: failed to synchronize data after insert") + +type insertCache struct { + query string + retQuery string + valueMapping []uint64 + retMapping []uint64 +} + +type updateCache struct { + query string + valueMapping []uint64 +} + +func makeCacheKey(cols boil.Columns, nzDefaults []string) string { + buf := strmangle.GetBuffer() + + buf.WriteString(strconv.Itoa(cols.Kind)) + for _, w := range cols.Cols { + buf.WriteString(w) + } + + if len(nzDefaults) != 0 { + buf.WriteByte('.') + } + for _, nz := range nzDefaults { + buf.WriteString(nz) + } + + str := buf.String() + strmangle.PutBuffer(buf) + return str +} diff --git a/admindb/sqlite/models/sqlite3_main_test.go b/admindb/sqlite/models/sqlite3_main_test.go new file mode 100644 index 0000000..6b9da61 --- /dev/null +++ b/admindb/sqlite/models/sqlite3_main_test.go @@ -0,0 +1,93 @@ +// Code generated by SQLBoiler 4.4.0 (https://github.com/volatiletech/sqlboiler). DO NOT EDIT. +// This file is meant to be re-generated in place and/or deleted at any time. + +package models + +import ( + "database/sql" + "fmt" + "io" + "math/rand" + "os" + "os/exec" + "path/filepath" + "regexp" + + _ "github.com/mattn/go-sqlite3" + "github.com/pkg/errors" + "github.com/spf13/viper" +) + +var rgxSQLitekey = regexp.MustCompile(`(?mi)((,\n)?\s+foreign key.*?\n)+`) + +type sqliteTester struct { + dbConn *sql.DB + + dbName string + testDBName string +} + +func init() { + dbMain = &sqliteTester{} +} + +func (s *sqliteTester) setup() error { + var err error + + s.dbName = viper.GetString("sqlite3.dbname") + if len(s.dbName) == 0 { + return errors.New("no dbname specified") + } + + s.testDBName = filepath.Join(os.TempDir(), fmt.Sprintf("boil-sqlite3-%d.sql", rand.Int())) + + dumpCmd := exec.Command("sqlite3", "-cmd", ".dump", s.dbName) + createCmd := exec.Command("sqlite3", s.testDBName) + + r, w := io.Pipe() + dumpCmd.Stdout = w + createCmd.Stdin = newFKeyDestroyer(rgxSQLitekey, r) + + if err = dumpCmd.Start(); err != nil { + return errors.Wrap(err, "failed to start sqlite3 dump command") + } + if err = createCmd.Start(); err != nil { + return errors.Wrap(err, "failed to start sqlite3 create command") + } + + if err = dumpCmd.Wait(); err != nil { + fmt.Println(err) + return errors.Wrap(err, "failed to wait for sqlite3 dump command") + } + + w.Close() // After dumpCmd is done, close the write end of the pipe + + if err = createCmd.Wait(); err != nil { + fmt.Println(err) + return errors.Wrap(err, "failed to wait for sqlite3 create command") + } + + return nil +} + +func (s *sqliteTester) teardown() error { + if s.dbConn != nil { + s.dbConn.Close() + } + + return os.Remove(s.testDBName) +} + +func (s *sqliteTester) conn() (*sql.DB, error) { + if s.dbConn != nil { + return s.dbConn, nil + } + + var err error + s.dbConn, err = sql.Open("sqlite3", fmt.Sprintf("file:%s?_loc=UTC", s.testDBName)) + if err != nil { + return nil, err + } + + return s.dbConn, nil +} diff --git a/admindb/sqlite/new.go b/admindb/sqlite/new.go new file mode 100644 index 0000000..b72dba2 --- /dev/null +++ b/admindb/sqlite/new.go @@ -0,0 +1,68 @@ +package sqlite + +import ( + "database/sql" + "fmt" + + "github.com/ssb-ngi-pointer/gossb-rooms/admindb" +) + +type Database struct { + db *sql.DB + + AuthWithSSB admindb.AuthWithSSBService + AuthFallback admindb.AuthFallbackService + + Rooms admindb.RoomService + Aliases admindb.AliasService +} + +// Open looks for a database file 'fname' +func Open(fname string) (*Database, error) { + db, err := sql.Open("sqlite3", fname) + if err != nil { + return nil, fmt.Errorf("sqlite/open failed: %w", err) + } + + if err := db.Ping(); err != nil { + return nil, fmt.Errorf("sqlite/open: ping failed: %w", err) + } + + admindb := &Database{ + db: db, + AuthWithSSB: AuthWithSSB{db}, + AuthFallback: AuthFallback{db}, + Rooms: Rooms{db}, + Aliases: Aliases{db}, + } + + return admindb, nil +} + +// Close closes the contained sql database object +func (t Database) Close() error { + return t.db.Close() +} + +func transact(db *sql.DB, fn func(tx *sql.Tx) error) error { + var err error + var tx *sql.Tx + tx, err = db.Begin() + if err != nil { + return fmt.Errorf("transact: could not begin transaction: %w", err) + } + if err = fn(tx); err != nil { + if err2 := tx.Rollback(); err2 != nil { + err = fmt.Errorf("rollback failed after %s: %s", err.Error(), err2.Error()) + } else { + err = fmt.Errorf("transaction failed, rolling back: %w", err) + } + return err + } + + if err = tx.Commit(); err != nil { + return fmt.Errorf("transact: could not commit transaction: %w", err) + } + + return nil +} diff --git a/admindb/sqlite/roomcfg.go b/admindb/sqlite/roomcfg.go new file mode 100644 index 0000000..4fc668b --- /dev/null +++ b/admindb/sqlite/roomcfg.go @@ -0,0 +1,14 @@ +package sqlite + +import ( + "database/sql" + + "github.com/ssb-ngi-pointer/gossb-rooms/admindb" +) + +// make sure to implement interfaces correctly +var _ admindb.RoomService = (*Rooms)(nil) + +type Rooms struct { + db *sql.DB +} diff --git a/admindb/sqlite/schema-v1.sql b/admindb/sqlite/schema-v1.sql new file mode 100644 index 0000000..f235ddb --- /dev/null +++ b/admindb/sqlite/schema-v1.sql @@ -0,0 +1,14 @@ +DROP TABLE IF EXISTS auth_fallback; +CREATE TABLE auth_fallback ( + id int PRIMARY KEY NOT NULL, + name text NOT NULL UNIQUE, + password_hash blob not null + -- pub_key text NOT NULL UNIQUE ???? +); + +DROP TABLE IF EXISTS aliases; +CREATE TABLE aliases ( + id int PRIMARY KEY NOT NULL, + name text NOT NULL UNIQUE, + pub_key text NOT NULL UNIQUE +); \ No newline at end of file diff --git a/admindb/sqlite/sqlboiler.toml b/admindb/sqlite/sqlboiler.toml new file mode 100644 index 0000000..672bc51 --- /dev/null +++ b/admindb/sqlite/sqlboiler.toml @@ -0,0 +1,21 @@ +[sqlite3] +dbname = "generated.db" + + +# TODO: fix unsupported type error +# need to add https://pkg.go.dev/database/sql/driver#Valuer +# and https://pkg.go.dev/database/sql#Scanner +# for the full story, see https://husobee.github.io/golang/database/2015/06/12/scanner-valuer.html +#[[types]] +# # marshal pub_key strings ala @asdjjasd as feed references. +# [types.match] +# type = "string" +# #tables = ['fallback_auth'] +# name = "pub_key" +# nullable = false +# +# [types.replace] +# type = "refs.FeedRef" +# +# [types.imports] +# third_party = ['"go.mindeco.de/ssb-refs"'] \ No newline at end of file diff --git a/cmd/insert-user/main.go b/cmd/insert-user/main.go new file mode 100644 index 0000000..b9d7269 --- /dev/null +++ b/cmd/insert-user/main.go @@ -0,0 +1,50 @@ +package main + +import ( + "bytes" + "fmt" + "os" + "syscall" + + _ "github.com/mattn/go-sqlite3" + "golang.org/x/crypto/ssh/terminal" + + "github.com/ssb-ngi-pointer/gossb-rooms/admindb/sqlite" +) + +func main() { + + if len(os.Args) != 3 { + fmt.Fprintf(os.Stderr, "usage: %s \n", os.Args[0]) + os.Exit(1) + return + } + + db, err := sqlite.Open(os.Args[1]) + check(err) + defer db.Close() + + fmt.Fprintln(os.Stderr, "Enter Password: ") + bytePassword, err := terminal.ReadPassword(int(syscall.Stdin)) + check(err) + + fmt.Fprintln(os.Stderr, "Repeat Password: ") + bytePasswordRepeat, err := terminal.ReadPassword(int(syscall.Stdin)) + check(err) + + if !bytes.Equal(bytePassword, bytePasswordRepeat) { + fmt.Fprintln(os.Stderr, "passwords didn't match") + os.Exit(1) + return + } + + err = db.AuthFallback.Create(os.Args[2], bytePassword) + check(err) +} + +func check(err error) { + if err != nil { + fmt.Fprintf(os.Stderr, "error: %s\n", err) + os.Exit(1) + } +} diff --git a/cmd/server/main.go b/cmd/server/main.go index 7e1ae8b..ca4979d 100644 --- a/cmd/server/main.go +++ b/cmd/server/main.go @@ -25,8 +25,10 @@ import ( kitlog "github.com/go-kit/kit/log" "github.com/go-kit/kit/log/level" + _ "github.com/mattn/go-sqlite3" "go.cryptoscope.co/muxrpc/v2/debug" + "github.com/ssb-ngi-pointer/gossb-rooms/admindb/sqlite" "github.com/ssb-ngi-pointer/gossb-rooms/internal/repo" "github.com/ssb-ngi-pointer/gossb-rooms/roomsrv" mksrv "github.com/ssb-ngi-pointer/gossb-rooms/roomsrv" @@ -174,7 +176,10 @@ func runroomsrv() error { r := repo.New(repoDir) - db, err := sqlite.OpenOrCreate(r.GetPath("roomdb")) + db, err := sqlite.Open(r.GetPath("roomdb")) + if err != nil { + return fmt.Errorf("failed to initiate database: %w", err) + } c := make(chan os.Signal) signal.Notify(c, os.Interrupt, syscall.SIGTERM) @@ -198,6 +203,8 @@ func runroomsrv() error { dashboardH, err := handlers.New( nil, repo.New(repoDir), + db.AuthWithSSB, + db.AuthFallback, ) if err != nil { return fmt.Errorf("failed to create HTTPdashboard handler: %w", err) diff --git a/go.mod b/go.mod index d5138cc..40ce862 100644 --- a/go.mod +++ b/go.mod @@ -4,26 +4,43 @@ go 1.15 require ( github.com/BurntSushi/toml v0.3.1 + github.com/friendsofgo/errors v0.9.2 + github.com/fsnotify/fsnotify v1.4.9 // indirect github.com/go-kit/kit v0.10.0 + github.com/gofrs/uuid v4.0.0+incompatible // indirect github.com/gorilla/mux v1.8.0 github.com/gorilla/securecookie v1.1.1 github.com/gorilla/sessions v1.2.1 github.com/gorilla/websocket v1.4.2 github.com/keks/nocomment v0.0.0-20181007001506-30c6dcb4a472 + github.com/magiconair/properties v1.8.4 // indirect + github.com/mattn/go-sqlite3 v2.0.3+incompatible + github.com/mitchellh/mapstructure v1.4.1 // indirect github.com/nicksnyder/go-i18n/v2 v2.1.2 + github.com/pelletier/go-toml v1.8.1 // indirect github.com/pkg/errors v0.9.1 github.com/shurcooL/httpfs v0.0.0-20190707220628-8d4bc4ba7749 // indirect github.com/shurcooL/vfsgen v0.0.0-20200824052919-0d455de96546 // indirect + github.com/spf13/afero v1.5.1 // indirect + github.com/spf13/jwalterweatherman v1.1.0 // indirect + github.com/spf13/pflag v1.0.5 // indirect + github.com/spf13/viper v1.7.1 github.com/stretchr/testify v1.6.1 + github.com/volatiletech/randomize v0.0.1 + github.com/volatiletech/sqlboiler/v4 v4.4.0 + github.com/volatiletech/strmangle v0.0.1 go.cryptoscope.co/muxrpc/v2 v2.0.0-20210202162901-fe642d405dc6 go.cryptoscope.co/netwrap v0.1.1 go.cryptoscope.co/secretstream v1.2.2 go.mindeco.de v1.6.0 go.mindeco.de/ssb-refs v0.1.1-0.20210108133850-cf1f44fea870 - golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad // indirect + golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9 - golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f // indirect - golang.org/x/text v0.3.3 + golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c // indirect + golang.org/x/text v0.3.5 + golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect + gopkg.in/ini.v1 v1.62.0 // indirect + gopkg.in/yaml.v2 v2.4.0 // indirect gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b // indirect ) @@ -37,4 +54,6 @@ exclude go.cryptoscope.co/ssb v0.0.0-20201207161753-31d0f24b7a79 // The branch in use: https://github.com/cryptix/golang_x_crypto/tree/non-internal-edwards replace golang.org/x/crypto => github.com/cryptix/golang_x_crypto v0.0.0-20200924101112-886946aabeb8 -// replace go.mindeco.de => /home/cryptix/go-repos/go-toolbelt +replace go.mindeco.de => /home/cryptix/go-repos/go-toolbelt + +replace github.com/gorilla/mux => /home/cryptix/go/src/github.com/gorilla/mux diff --git a/go.sum b/go.sum index b6549b3..3cf1b86 100644 --- a/go.sum +++ b/go.sum @@ -1,11 +1,26 @@ cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU= +cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU= +cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY= +cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc= +cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0= +cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o= +cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= +cloud.google.com/go/firestore v1.1.0/go.mod h1:ulACoGHTpvq5r8rxGJ4ddJZBZqakUQqClKRT5SZwBmk= +cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I= +cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw= +dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= github.com/AndreasBriese/bbloom v0.0.0-20170702084017-28f7e881ca57/go.mod h1:bOvUY6CB00SOBii9/FifXqc0awNKxLFCL/+pkDPuyl8= github.com/AndreasBriese/bbloom v0.0.0-20180913140656-343706a395b7/go.mod h1:bOvUY6CB00SOBii9/FifXqc0awNKxLFCL/+pkDPuyl8= github.com/AndreasBriese/bbloom v0.0.0-20190306092124-e2d15f34fcf9/go.mod h1:bOvUY6CB00SOBii9/FifXqc0awNKxLFCL/+pkDPuyl8= github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= +github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= +github.com/DATA-DOG/go-sqlmock v1.4.1 h1:ThlnYciV1iM/V0OSF/dtkqWb6xo5qITT1TJBG1MRDJM= +github.com/DATA-DOG/go-sqlmock v1.4.1/go.mod h1:f/Ixk793poVmq4qj/V1dPUg2JEAKC73Q5eFN3EC/SaM= github.com/Knetic/govaluate v3.0.1-0.20171022003610-9aa49832a739+incompatible/go.mod h1:r7JcOSlj0wfOMncg0iLm8Leh48TZaKVeNIfJntJ2wa0= +github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= github.com/PuerkitoBio/goquery v1.5.0 h1:uGvmFXOA73IKluu/F84Xd1tt/z07GYm8X49XKHP7EJk= github.com/PuerkitoBio/goquery v1.5.0/go.mod h1:qD2PgZ9lccMbQlc7eEOjaeRlFQON7xY8kdmcsrnKqMg= github.com/Shopify/sarama v1.19.0/go.mod h1:FVkBWblsNy7DGZRfXLU0O9RCGt5g3g3yEuWXgklEdEo= @@ -20,7 +35,9 @@ github.com/andybalholm/cascadia v1.0.0 h1:hOCXnnZ5A+3eVDX8pvgl4kofXv2ELss0bKcqRy github.com/andybalholm/cascadia v1.0.0/go.mod h1:GsXiBklL0woXo1j/WYWtSYYC4ouU9PqHO0sqidkEA4Y= github.com/apache/thrift v0.12.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ= github.com/apache/thrift v0.13.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ= +github.com/apmckinlay/gsuneido v0.0.0-20180907175622-1f10244968e3/go.mod h1:hJnaqxrCRgMCTWtpNz9XUFkBCREiQdlcyK6YNmOfroM= github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o= +github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8= github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY= github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= github.com/aryann/difflib v0.0.0-20170710044230-e206f873d14a/go.mod h1:DAHtR1m6lCRdSC2Tm3DSWRPvIPr6xNKyeHdqDQSQT+A= @@ -31,19 +48,29 @@ github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24 github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= +github.com/bketelsen/crypt v0.0.3-0.20200106085610-5cbc8cc4026c/go.mod h1:MKsuJmJgSg28kpZDP6UIiPt0e0Oz0kqKNGyRaWEPv84= github.com/casbin/casbin/v2 v2.1.2/go.mod h1:YcPU1XXisHhLzuxH9coDNf2FbKpjGlbCg3n9yuLkIJQ= github.com/cenkalti/backoff v2.2.1+incompatible/go.mod h1:90ReRw6GdpyfrHakVjL/QHaoyV4aDUVVkXQJJJ3NXXM= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= +github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/cheekybits/is v0.0.0-20150225183255-68e9c0620927/go.mod h1:h/aW8ynjgkuj+NQRlZcDbAbM1ORAbXjXX77sX7T289U= github.com/clbanning/x2j v0.0.0-20191024224557-825249438eec/go.mod h1:jMjuTZXRI4dUb/I5gc9Hdhagfvm9+RyrPryS/auMzxE= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= +github.com/cockroachdb/apd v1.1.0/go.mod h1:8Sl8LxpKi29FqWXR16WEFZRNSz3SoPzUzeMeY4+DwBQ= github.com/cockroachdb/datadriven v0.0.0-20190809214429-80d97fb3cbaa/go.mod h1:zn76sxSg3SzpJ0PPJaLDCu+Bu0Lg3sKTORVIj19EIF8= github.com/codahale/hdrhistogram v0.0.0-20161010025455-3a0bb77429bd/go.mod h1:sE/e/2PUdi/liOCUjSTXgM1o87ZssimdTWN964YiIeI= +github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk= +github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= +github.com/coreos/etcd v3.3.13+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= +github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= github.com/coreos/go-systemd v0.0.0-20180511133405-39ca1b05acc7/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= +github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= github.com/coreos/pkg v0.0.0-20160727233714-3ac0863d7acf/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= +github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= +github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY= github.com/cryptix/go v1.3.1/go.mod h1:mFQotm9rTzptzvNjJM+1vSIDa/rVOVqMu0889GIXg70= github.com/cryptix/go v1.3.2/go.mod h1:mFQotm9rTzptzvNjJM+1vSIDa/rVOVqMu0889GIXg70= @@ -55,6 +82,7 @@ github.com/cryptix/golang_x_crypto v0.0.0-20200924101112-886946aabeb8/go.mod h1: 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/denisenkom/go-mssqldb v0.0.0-20200206145737-bbfc9a55622e/go.mod h1:xbL0rPBG9cCiLr28tMa8zpbdarY27NDyej4t/EjAShU= github.com/dgraph-io/badger v1.3.0/go.mod h1:VZxzAIRPHRVNRKRo6AXrX9BJegn6il06VMTZVJYCIjQ= github.com/dgraph-io/badger v1.5.3/go.mod h1:VZxzAIRPHRVNRKRo6AXrX9BJegn6il06VMTZVJYCIjQ= github.com/dgraph-io/badger v1.5.4/go.mod h1:VZxzAIRPHRVNRKRo6AXrX9BJegn6il06VMTZVJYCIjQ= @@ -63,6 +91,7 @@ github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZm github.com/dgryski/go-farm v0.0.0-20180109070241-2de33835d102/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw= github.com/dgryski/go-farm v0.0.0-20190104051053-3adb47b1fb0f/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw= github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw= +github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no= github.com/dustin/go-humanize v0.0.0-20171111073723-bb3d318650d4/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= github.com/eapache/go-resiliency v1.1.0/go.mod h1:kFI+JgMyC7bLPUVY133qvEBtVayf5mFgVsvEsIPBvNs= @@ -72,11 +101,17 @@ github.com/edsrzf/mmap-go v1.0.0/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaB github.com/envoyproxy/go-control-plane v0.6.9/go.mod h1:SBwIajubJHhxtWwsL9s8ss4safvEdbitLhGGK48rN6g= github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= +github.com/ericlagergren/decimal v0.0.0-20181231230500-73749d4874d5/go.mod h1:1yj25TwtUlJ+pfOu9apAVaM1RWfZGg+aFpd4hPQZekQ= github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= github.com/franela/goblin v0.0.0-20200105215937-c9ffbefa60db/go.mod h1:7dvUGVsVBjqR7JHJk0brhHOZYGmfBYOrK0ZhYMEtBr4= github.com/franela/goreq v0.0.0-20171204163338-bcd34c9993f8/go.mod h1:ZhphrRTfi2rbfLwlschooIH4+wKKDR4Pdxhh+TRoA20= +github.com/friendsofgo/errors v0.9.2 h1:X6NYxef4efCBdwI7BgS820zFaN7Cphrmb+Pljdzjtgk= +github.com/friendsofgo/errors v0.9.2/go.mod h1:yCvFW5AkDIL9qn7suHVLiI/gH228n7PC4Pn44IGoTOI= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= +github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4= +github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= +github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= github.com/go-kit/kit v0.6.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= @@ -87,17 +122,25 @@ github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V github.com/go-logfmt/logfmt v0.5.0 h1:TrB8swr/68K7m9CcGut2g3UOihhbcbiMAYiuTXdEih4= github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A= github.com/go-sql-driver/mysql v1.4.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= +github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg= github.com/go-stack/stack v1.7.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= github.com/go-stack/stack v1.8.0 h1:5SgMzNM5HxrEjV0ww2lTmX6E2Izsfxas4+YHWRs3Lsk= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= +github.com/gofrs/uuid v3.2.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= +github.com/gofrs/uuid v4.0.0+incompatible h1:1SD/1F5pU8p29ybwgQSwpQk+mwdRrXCYuPhW6m+TnJw= +github.com/gofrs/uuid v4.0.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= github.com/gogo/googleapis v1.1.0/go.mod h1:gf4bu3Q80BeJ6H1S1vYPm8/ELATdvryBaNFGgqEef3s= github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= github.com/gogo/protobuf v1.2.0/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4= +github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe/go.mod h1:8vg3r2VgvsThLBIFL93Qb5yWzgyZWhEmBwUJWevAkK0= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= github.com/golang/groupcache v0.0.0-20160516000752-02826c3e7903/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= +github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= +github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y= github.com/golang/protobuf v1.0.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= @@ -109,27 +152,33 @@ github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5a github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= +github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= +github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= +github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= +github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 h1:EGx4pi6eqNxGaHF6qqu48+N2wcFQ5qg5FXgOdqsJ5d8= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg= -github.com/gorilla/mux v1.6.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= -github.com/gorilla/mux v1.7.3 h1:gnP5JzjVOuiZD07fKKToCAOjS0yOpj/qPETTXCCS6hw= -github.com/gorilla/mux v1.7.3/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= -github.com/gorilla/mux v1.8.0 h1:i40aqfkR1h2SlN9hojwV5ZA91wcXFOvkdNIeFDP5koI= -github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So= github.com/gorilla/securecookie v1.1.1 h1:miw7JPhV+b/lAHSXz4qd/nN9jRiAFV5FwjeKyCS8BvQ= github.com/gorilla/securecookie v1.1.1/go.mod h1:ra0sb63/xPlUeL+yeDciTfxMRAA+MP+HVt/4epWDjd4= github.com/gorilla/sessions v1.1.3/go.mod h1:8KCfur6+4Mqcc6S0FEfKuN15Vl5MgXW92AE8ovaJD0w= github.com/gorilla/sessions v1.2.1 h1:DHd3rPN5lE3Ts3D8rKkQ8x/0kqfeNmBAaiSi+o7FsgI= github.com/gorilla/sessions v1.2.1/go.mod h1:dk2InVEVJ0sfLlnXv9EAgkf6ecYs/i80K/zI+bUmuGM= github.com/gorilla/websocket v0.0.0-20170926233335-4201258b820c/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= +github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= github.com/gorilla/websocket v1.4.2 h1:+/TMaTYc4QFitKJxsQ7Yye35DkWvkdLcvGKqM+x0Ufc= github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= +github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= github.com/grpc-ecosystem/go-grpc-middleware v1.0.1-0.20190118093823-f849b5445de4/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk= +github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= github.com/grpc-ecosystem/grpc-gateway v1.9.5/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= +github.com/hashicorp/consul/api v1.1.0/go.mod h1:VmuI/Lkw1nC05EYQWNKwWGbkg+FbDBtguAZLlVdkD9Q= github.com/hashicorp/consul/api v1.3.0/go.mod h1:MmDNSzIMUjNpY/mQ398R4bk2FnqQLoPndWW5VkKPlCE= +github.com/hashicorp/consul/sdk v0.1.1/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8= github.com/hashicorp/consul/sdk v0.3.0/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8= github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I= @@ -149,6 +198,8 @@ github.com/hashicorp/go-version v1.2.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09 github.com/hashicorp/go.net v0.0.1/go.mod h1:hjKkEWcCURg++eb33jQU7oqQcI9XDCnUzHA0oac0k90= github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= +github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64= github.com/hashicorp/mdns v1.0.0/go.mod h1:tL+uN++7HEJ6SQLQ2/p+z2pH24WQKWjBPkE0mNTz8vQ= github.com/hashicorp/memberlist v0.1.3/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2pPBoIllUwCN7I= @@ -162,6 +213,9 @@ github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22 github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/json-iterator/go v1.1.8/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= +github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo= github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= github.com/karrick/bufpool v1.2.0 h1:AfhYmVv8A62iOzB31RuJrGLTdHlvBbl0+rh8Gvgvybg= @@ -169,36 +223,50 @@ github.com/karrick/bufpool v1.2.0/go.mod h1:ZRBxSXJi05b7mfd7kcL1M86UL1x8dTValcwC github.com/karrick/gopool v1.1.0/go.mod h1:Llf0mwk3WWtY0AIQoodGWVOU+5xfvUWqJKvck2qNwBU= github.com/karrick/gopool v1.2.2 h1:YcxpjUxiwimrsvxLlIdrMcPPH2mlgLa4XD5z5q90M9U= github.com/karrick/gopool v1.2.2/go.mod h1:5Fng5/Z1F8x09k7QiokCmFB96DKrLra/oub/tKb6mGA= +github.com/kat-co/vala v0.0.0-20170210184112-42e1d8b61f12/go.mod h1:u9MdXq/QageOOSGp7qG4XAQsYUMP+V5zEel/Vrl6OOc= github.com/keks/nocomment v0.0.0-20181007001506-30c6dcb4a472 h1:6nrO82kszcc+rcKPCJGgCj5ACTdmq6aNGav8zE5oYm0= github.com/keks/nocomment v0.0.0-20181007001506-30c6dcb4a472/go.mod h1:oLLUlGld/axGHThR36o8bADQUHG+TKSUdoKqCvnoQB4= github.com/keks/persist v0.0.0-20180731151133-9546f7b3f97e/go.mod h1:KMIOJFEE+0E/mYfYExA9vOpCFDz4TQfzk6mCOtCXR9k= github.com/keks/persist v0.0.0-20181029214439-3af502dad70b/go.mod h1:KMIOJFEE+0E/mYfYExA9vOpCFDz4TQfzk6mCOtCXR9k= +github.com/kevinburke/go-bindata v3.21.0+incompatible/go.mod h1:/pEEZ72flUW2p0yi30bslSp9YqD9pysLxunQDdb2CPM= github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg= github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= +github.com/lib/pq v1.2.1-0.20191011153232-f91d3411e481/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= github.com/lightstep/lightstep-tracer-common/golang/gogo v0.0.0-20190605223551-bc2310a04743/go.mod h1:qklhhLq1aX+mtWk9cPHPzaBjWImj5ULL6C7HFJtXQMM= github.com/lightstep/lightstep-tracer-go v0.18.1/go.mod h1:jlF1pusYV4pidLvZ+XD0UBX0ZE6WURAspgAczcDHrL4= github.com/lyft/protoc-gen-validate v0.0.13/go.mod h1:XbGvPuh87YZc5TdIa2/I4pLk0QoUACkjt2znoq26NVQ= +github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= +github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= +github.com/magiconair/properties v1.8.4 h1:8KGKTcQQGm0Kv7vEbKFErAoAOFyyacLStRtQSeYtvkY= +github.com/magiconair/properties v1.8.4/go.mod h1:y3VJvCyxH9uVvJTWEGAELF3aiYNyPKd5NZ3oSwXrF60= github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= +github.com/mattn/go-sqlite3 v2.0.3+incompatible h1:gXHsfypPkaMZrKbD5209QV9jbUTJKjyR5WD3HYQSd+U= +github.com/mattn/go-sqlite3 v2.0.3+incompatible/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= github.com/miolini/datacounter v0.0.0-20171104152933-fd4e42a1d5e0/go.mod h1:P6fDJzlxN+cWYR09KbE9/ta+Y6JofX9tAUhJpWkWPaM= github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= +github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI= github.com/mitchellh/gox v0.4.0/go.mod h1:Sd9lOJ0+aimLBi73mGofS1ycjY8lL3uZM3JPS42BGNg= github.com/mitchellh/iochan v1.0.0/go.mod h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0QubkSMEySY= github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= +github.com/mitchellh/mapstructure v1.4.1 h1:CpVNEelQCZBooIPDn+AR3NpivK/TIKU8bDxdASFVQag= +github.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= @@ -215,6 +283,7 @@ github.com/nicksnyder/go-i18n/v2 v2.1.2 h1:QHYxcUJnGHBaq7XbvgunmZ2Pn0focXFqTD61C github.com/nicksnyder/go-i18n/v2 v2.1.2/go.mod h1:d++QJC9ZVf7pa48qrsRWhMJ5pSHIPmS3OLqK1niyLxs= github.com/oklog/oklog v0.3.2/go.mod h1:FCV+B7mhrz4o+ueLpx+KqkyXRGMWOYEvfiXtdGtbWGs= github.com/oklog/run v1.0.0/go.mod h1:dlhp/R75TPv97u0XWUtDeV/lRKWPKSdTuV0TZvrmrQA= +github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U= github.com/olekukonko/tablewriter v0.0.0-20170122224234-a0225b3f23b5/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo= github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= @@ -233,6 +302,9 @@ github.com/oxtoacart/bpool v0.0.0-20190524125616-8c0b41497736/go.mod h1:L3UMQOTh github.com/pact-foundation/pact-go v1.0.4/go.mod h1:uExwJY4kCzNPcHRj+hCR/HBbOOIwwtUjcrb0b5/5kLM= github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= github.com/pborman/uuid v1.2.0/go.mod h1:X/NO0urCmaxf9VXbdlT7C2Yzkj2IKimNn4k+gtPdI/k= +github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= +github.com/pelletier/go-toml v1.8.1 h1:1Nf83orprkJyknT6h7zbuEGUEjcyVlCxSUGTENmNCRM= +github.com/pelletier/go-toml v1.8.1/go.mod h1:T2/BmBdy8dvIRq1a/8aqjN41wvWlN4lrapLU/GW4pbc= github.com/performancecopilot/speed v3.0.0+incompatible/go.mod h1:/CLtqpZ5gBg1M9iaPbIdPPGyKcA8hKdoy6hAWba7Yac= github.com/pierrec/lz4 v1.0.2-0.20190131084431-473cd7ce01a1/go.mod h1:3/3N9NVKO0jef7pBehbT1qWhCMrIgbYNnFAZCqQ5LRc= github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= @@ -241,11 +313,13 @@ github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINE github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/profile v1.2.1/go.mod h1:hJw3o1OdXxsrSjjVksARp5W95eeEaEfptyVZyv6JUPA= +github.com/pkg/sftp v1.10.1/go.mod h1:lYOWFsE0bwd1+KfKJaKeuokY15vzFx25BLbzYYoAxZI= 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/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= github.com/prometheus/client_golang v0.9.3-0.20190127221311-3c4408c8b829/go.mod h1:p2iRAGwDERtqlqzRXnrOVns+ignqQo//hLXqYxZYVNs= +github.com/prometheus/client_golang v0.9.3/go.mod h1:/TN21ttK/J9q6uSwhBd54HahCDft0ttaMvbicHlPoso= github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= github.com/prometheus/client_golang v1.3.0/go.mod h1:hJaj2vgQTGQmVCsAACORcieXFeDPbaTKGT+JTgUa3og= github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= @@ -253,13 +327,17 @@ github.com/prometheus/client_model v0.0.0-20190115171406-56726106282f/go.mod h1: github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.1.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/common v0.0.0-20181113130724-41aa239b4cce/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= github.com/prometheus/common v0.2.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= +github.com/prometheus/common v0.4.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= github.com/prometheus/common v0.7.0/go.mod h1:DjGbpBbp5NYNiECxcL/VnbXCCaQpKd3tt26CguLLsqA= github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.0.0-20190117184657-bf6a532e95b1/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= +github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A= +github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU= github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4= github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= @@ -267,6 +345,7 @@ github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQD github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= github.com/samuel/go-zookeeper v0.0.0-20190923202752-2cc03de413da/go.mod h1:gi+0XIa01GRL2eRQVjQkKGqKF3SF9vZR/HnPullcV2E= github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc= +github.com/shopspring/decimal v0.0.0-20180709203117-cd690d0c9e24/go.mod h1:M+9NzErvs504Cn4c5DxATwIqPbtswREoFCre64PpcG4= github.com/shurcooL/go v0.0.0-20180423040247-9e1955d9fb6e/go.mod h1:TDJrrUr11Vxrven61rcy3hJMUqaf/CLWYhHNPmT14Lk= github.com/shurcooL/go v0.0.0-20190121191506-3fef8c783dec/go.mod h1:TDJrrUr11Vxrven61rcy3hJMUqaf/CLWYhHNPmT14Lk= github.com/shurcooL/go v0.0.0-20190330031554-6713ea532688/go.mod h1:TDJrrUr11Vxrven61rcy3hJMUqaf/CLWYhHNPmT14Lk= @@ -279,12 +358,32 @@ github.com/shurcooL/vfsgen v0.0.0-20200824052919-0d455de96546 h1:pXY9qYc/MP5zdvq github.com/shurcooL/vfsgen v0.0.0-20200824052919-0d455de96546/go.mod h1:TrYk7fJVaAttu97ZZKrO9UbRa8izdowaMIZcxYMbVaw= github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= +github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d h1:zE9ykElWQ6/NYmHa3jpm/yHnI4xSofP+UP6SpjHcSeM= github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= +github.com/smartystreets/goconvey v1.6.4 h1:fv0U8FUIMPNf1L9lnHLvLhgicrIVChEkdzIKYqbNC9s= github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM= github.com/sony/gobreaker v0.4.1/go.mod h1:ZKptC7FHNvhBz7dN2LGjPVBz2sZJmc0/PkyDJOjmxWY= +github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= +github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= +github.com/spf13/afero v1.5.1 h1:VHu76Lk0LSP1x254maIu2bplkWpfBWI+B+6fdoZprcg= +github.com/spf13/afero v1.5.1/go.mod h1:Ai8FlHk4v/PARR026UzYexafAt9roJ7LcLMAmO6Z93I= +github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= +github.com/spf13/cast v1.3.1 h1:nFm6S0SMdyzrzcmThSipiEubIDy8WEXKNZ0UOgiRpng= +github.com/spf13/cast v1.3.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= +github.com/spf13/cobra v1.0.0/go.mod h1:/6GTrnGXV9HjY+aR4k0oJ5tcvakLuG6EuKReYlHNrgE= +github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= +github.com/spf13/jwalterweatherman v1.1.0 h1:ue6voC5bR5F8YxI5S67j9i582FU4Qvo2bmqnqMYADFk= +github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo= github.com/spf13/pflag v1.0.1/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= +github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= +github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= +github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= +github.com/spf13/viper v1.4.0/go.mod h1:PTJ7Z/lr49W6bUbkmS1V3by4uWynFiR9p7+dSq/yZzE= +github.com/spf13/viper v1.6.3/go.mod h1:jUMtyi0/lB5yZH/FjyGAoH7IMNrIhlBf6pXZmbMDvzw= +github.com/spf13/viper v1.7.1 h1:pM5oEahlgWv/WnHXpgbKz7iLIxRf65tye2Ci+XFK5sk= +github.com/spf13/viper v1.7.1/go.mod h1:8WkrPz2fc9jxqZNCJI/76HCieCp4Q8HaLFoCha5qpdg= github.com/streadway/amqp v0.0.0-20190404075320-75d898a42a94/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw= github.com/streadway/amqp v0.0.0-20190827072141-edfb9018d271/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw= github.com/streadway/handy v0.0.0-20190108123426-d5acb3125c2a/go.mod h1:qNTQ5P5JnDBl6z3cMAg/SywNDC5ABu5ApDIw6lUbRmI= @@ -295,15 +394,30 @@ github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UV github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0= github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/subosito/gotenv v1.2.0 h1:Slr1R9HxAlEKefgq5jn9U+DnETlIUa6HfgEzj0g5d7s= +github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw= github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= +github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= github.com/ugorji/go v1.1.1/go.mod h1:hnLbHMwcvSihnDhEfx2/BzKp2xb0Y+ErdfYcrs9tkJQ= github.com/ugorji/go v1.1.2/go.mod h1:hnLbHMwcvSihnDhEfx2/BzKp2xb0Y+ErdfYcrs9tkJQ= +github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc= github.com/ugorji/go v1.1.5-pre/go.mod h1:FwP/aQVg39TXzItUBMwnWp9T9gPQnXw4Poh4/oBQZ/0= github.com/ugorji/go/codec v0.0.0-20190126102652-8fd0f8d918c8/go.mod h1:iT03XoTwV7xq/+UGwKO3UbC1nNNlopQiY61beSdrtOA= github.com/ugorji/go/codec v1.1.5-pre/go.mod h1:tULtS6Gy1AE1yCENaw4Vb//HLH5njI2tfCQDUqRd8fI= github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA= github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= +github.com/volatiletech/inflect v0.0.1 h1:2a6FcMQyhmPZcLa+uet3VJ8gLn/9svWhJxJYwvE8KsU= +github.com/volatiletech/inflect v0.0.1/go.mod h1:IBti31tG6phkHitLlr5j7shC5SOo//x0AjDzaJU1PLA= +github.com/volatiletech/null/v8 v8.1.0 h1:eAO3I31A5R04usY5SKMMfDcOCnEGyT/T4wRI0JVGp4U= +github.com/volatiletech/null/v8 v8.1.0/go.mod h1:98DbwNoKEpRrYtGjWFctievIfm4n4MxG0A6EBUcoS5g= +github.com/volatiletech/randomize v0.0.1 h1:eE5yajattWqTB2/eN8df4dw+8jwAzBtbdo5sbWC4nMk= +github.com/volatiletech/randomize v0.0.1/go.mod h1:GN3U0QYqfZ9FOJ67bzax1cqZ5q2xuj2mXrXBjWaRTlY= +github.com/volatiletech/sqlboiler/v4 v4.4.0 h1:aSlvHidRBuxHHQZNX3ZLGgzNVPVPzWqsC3lhcLbV/b0= +github.com/volatiletech/sqlboiler/v4 v4.4.0/go.mod h1:h4RBAO6QbwMP3ezGmtfGljRms7S27cFIgF3rKgPKstE= +github.com/volatiletech/strmangle v0.0.1 h1:UKQoHmY6be/R3tSvD2nQYrH41k43OJkidwEiC74KIzk= +github.com/volatiletech/strmangle v0.0.1/go.mod h1:F6RA6IkB5vq0yTG4GQ0UsbbRcl3ni9P76i+JrTBKFFg= github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= +github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= go.cryptoscope.co/librarian v0.1.0/go.mod h1:dbua5pc7Vq/M0W5CJa/AJYdwlDRlgo2FKrB5tEm2NLc= go.cryptoscope.co/librarian v0.1.1/go.mod h1:cL2xGx4N+lZe6nbBS7vKPyy/rGn0uY2+hP/TwQf6+IM= go.cryptoscope.co/librarian v0.1.2/go.mod h1:U15yqN7eap9RDGqd/wlFUWoGWplXWn3VI3MGStrI3tA= @@ -325,14 +439,18 @@ go.cryptoscope.co/netwrap v0.1.1 h1:JLzzGKEvrUrkKzu3iM0DhpHmt+L/gYqmpcf1lJMUyFs= go.cryptoscope.co/netwrap v0.1.1/go.mod h1:7zcYswCa4CT+ct54e9uH9+IIbYYETEMHKDNpzl8Ukew= go.cryptoscope.co/secretstream v1.2.2 h1:kPxsgWrTDFyS9ZklcD0si1KGljPLz6mmPKnFQjGepMc= go.cryptoscope.co/secretstream v1.2.2/go.mod h1:7nRGZ7fTqSgQAnv2Y4m8xQsS3MFxvB7I0C19reUNlXg= +go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= go.etcd.io/bbolt v1.3.3/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= go.etcd.io/etcd v0.0.0-20191023171146-3cf2f69b5738/go.mod h1:dnLIgRNXwCJa5e+c6mIZCrds/GIG4ncV9HhK5PX7jPg= go.mindeco.de/ssb-refs v0.1.1-0.20210108133850-cf1f44fea870 h1:TCI3AefMAaOYECvppn30+CfEB0Fn8IES1SKvvacc3/c= go.mindeco.de/ssb-refs v0.1.1-0.20210108133850-cf1f44fea870/go.mod h1:OnBnV02ux4lLsZ39LID6yYLqSDp+dqTHb/3miYPkQFs= go.opencensus.io v0.20.1/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk= go.opencensus.io v0.20.2/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk= +go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= +go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= +go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= go.uber.org/atomic v1.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= go.uber.org/multierr v1.3.0/go.mod h1:VgVr7evmIr6uPjLBxg28wmKNXyqE9akIJ5XnfpiKl+4= @@ -340,12 +458,23 @@ go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9E go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= go.uber.org/zap v1.13.0/go.mod h1:zwrFLgMcdUuIBviXEYEH1YKNaOBnKXsx2IPda5bBwHM= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= +golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek= +golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY= +golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= +golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= +golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= +golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY= golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= golang.org/x/net v0.0.0-20180218175443-cbe0f9307d01/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180406214816-61147c48b25b/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -361,7 +490,9 @@ golang.org/x/net v0.0.0-20190125091013-d26f9f9a57f3/go.mod h1:mL1N/T3taQHkDXs73r golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 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-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190522155817-f3200d17e092/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= golang.org/x/net v0.0.0-20190607181551-461777fb6f67/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= @@ -370,6 +501,7 @@ golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7 h1:fHDIZ2oxGnUZRN6WgWFCbYBjH golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -389,22 +521,31 @@ golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5h golang.org/x/sys v0.0.0-20181122145206-62eef0e2fa9b/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190124100055-b90733256f2e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190507053917-2953c62de483/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190610200419-93c9922d18ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191007154456-ef33b2fb2c41/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191220142924-d4481acd189f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f h1:+Nyd8tzPX9R7BWHguqsrbFdRx3WQ/1ib8I44HXV5yTA= -golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c h1:VwygUrnw9jn88c4u8GD3rZQbqrP/tgas88tPUbBxQrk= +golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/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 h1:cokOdA+Jmi5PJGXLlLllQSgYigAEfHXJAERHVMaCc2k= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.5 h1:i6eZZ+zk0SOf0xgBpEpPD18qWcJda6q1sxt3S0kzyUQ= +golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= @@ -412,30 +553,54 @@ golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGm golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191112195655-aa38f8e97acc/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20200103221440-774c71fcf114 h1:DnSr2mCsxyCE6ZgIkmcWUQY2R5cH/6wL7eIxEmQOMSE= golang.org/x/tools v0.0.0-20200103221440-774c71fcf114/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE= +golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= google.golang.org/api v0.3.1/go.mod h1:6wY9I6uQWHQ8EM57III9mq/AjF+i8G65rmVagqKMtkk= +google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= +google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M= +google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= +google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= +google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.2.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= google.golang.org/genproto v0.0.0-20190530194941-fb225487d101/go.mod h1:z3L6/3dTEVtUr6QSP8miRzeRqwQOioJ9I66odjN4I7s= +google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= +google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8= +google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.20.0/go.mod h1:chYK+tFQF0nDUGJgXMSgLCQk3phJEuONr2DCgLDdAQM= google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= google.golang.org/grpc v1.21.0/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= +google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= google.golang.org/grpc v1.22.1/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= google.golang.org/grpc v1.23.1/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= @@ -448,20 +613,29 @@ gopkg.in/cheggaaa/pb.v1 v1.0.25/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qS gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= gopkg.in/gcfg.v1 v1.2.3/go.mod h1:yesOnuUOFQAhST5vPY4nbZsb/huCgGGXlipJsBn0b3o= +gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= +gopkg.in/ini.v1 v1.51.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= +gopkg.in/ini.v1 v1.62.0 h1:duBzk771uxoUuOlyRLkHsygud9+5lrlGjdFBb4mSKDU= +gopkg.in/ini.v1 v1.62.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= gopkg.in/warnings.v0 v0.1.2/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI= gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74= gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.3.0 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU= +gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +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-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo= gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= +rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o= sourcegraph.com/sourcegraph/appdash v0.0.0-20190731080439-ebfcffb1b5c0/go.mod h1:hI742Nqp5OhwiqlzhgfbWU4mW4yO10fP+LoT9WOswdU= diff --git a/web/handlers/auth/handler.go b/web/handlers/auth/handler.go index 63f6b4d..c9a074a 100644 --- a/web/handlers/auth/handler.go +++ b/web/handlers/auth/handler.go @@ -10,6 +10,10 @@ import ( "github.com/ssb-ngi-pointer/gossb-rooms/web/router" ) +var HTMLTemplates = []string{ + "/auth/fallback_sign_in.tmpl", +} + func Handler(m *mux.Router, r *render.Renderer, a *auth.Handler) http.Handler { if m == nil { m = router.Auth(nil) diff --git a/web/handlers/http.go b/web/handlers/http.go index f6723bd..965f944 100644 --- a/web/handlers/http.go +++ b/web/handlers/http.go @@ -1,12 +1,10 @@ package handlers import ( - "bytes" "fmt" "net/http" "github.com/gorilla/mux" - "github.com/gorilla/securecookie" "github.com/gorilla/sessions" "go.mindeco.de/http/auth" "go.mindeco.de/http/render" @@ -25,8 +23,8 @@ import ( func New( m *mux.Router, repo repo.Interface, - as admindb.AuthService, - fs admindb.FallbackAuth, + as admindb.AuthWithSSBService, + fs admindb.AuthFallbackService, ) (http.Handler, error) { if m == nil { m = router.CompleteApp() @@ -46,6 +44,7 @@ func New( "/error.tmpl", }, news.HTMLTemplates, + roomsAuth.HTMLTemplates, admin.HTMLTemplates, )...), render.FuncMap(web.TemplateFuncs(m)), @@ -62,21 +61,20 @@ func New( return nil, fmt.Errorf("web Handler: failed to create renderer: %w", err) } - // TODO: generate & persist me - // repo.GetPath("web-cookie") + cookieCodec, err := web.LoadOrCreateCookieSecrets(repo) + if err != nil { + return nil, err + } + store := &sessions.CookieStore{ - Codecs: securecookie.CodecsFromPairs( - bytes.Repeat([]byte("acab"), 8), - bytes.Repeat([]byte("beef"), 8), - // securecookie.GenerateRandomKey(32), // new key every time we startup - // securecookie.GenerateRandomKey(32), - ), + Codecs: cookieCodec, Options: &sessions.Options{ Path: "/", MaxAge: 30, }, } + // TODO: use r.Error? notAuthorizedH := r.HTML("/error.tmpl", func(rw http.ResponseWriter, req *http.Request) (interface{}, error) { statusCode := http.StatusUnauthorized rw.WriteHeader(statusCode) diff --git a/web/handlers/http_test.go b/web/handlers/http_test.go index 5993f5b..a48fbf3 100644 --- a/web/handlers/http_test.go +++ b/web/handlers/http_test.go @@ -30,7 +30,6 @@ func TestIndex(t *testing.T) { func TestAbout(t *testing.T) { setup(t) t.Cleanup(teardown) - a := assert.New(t) r := require.New(t) @@ -45,7 +44,6 @@ func TestAbout(t *testing.T) { func TestNotFound(t *testing.T) { setup(t) t.Cleanup(teardown) - a := assert.New(t) html, resp := testClient.GetHTML("/some/random/ASDKLANZXC", nil) @@ -57,7 +55,6 @@ func TestNotFound(t *testing.T) { func TestNewsRegisterd(t *testing.T) { setup(t) t.Cleanup(teardown) - a := assert.New(t) html, resp := testClient.GetHTML("/news/", nil) @@ -70,7 +67,6 @@ func TestNewsRegisterd(t *testing.T) { func TestRestricted(t *testing.T) { setup(t) t.Cleanup(teardown) - a := assert.New(t) html, resp := testClient.GetHTML("/admin/", nil) @@ -78,3 +74,14 @@ func TestRestricted(t *testing.T) { found := html.Find("h1").Text() a.Equal("Error #401 - Unauthorized", found) } + +func TestLoginForm(t *testing.T) { + setup(t) + t.Cleanup(teardown) + a := assert.New(t) + + html, resp := testClient.GetHTML(router.AuthFallbackSignInForm, nil) + a.Equal(http.StatusOK, resp.Code, "wrong HTTP status code") + found := html.Find("title").Text() + a.Equal("Login Form", found) +} diff --git a/web/handlers/setup_test.go b/web/handlers/setup_test.go index f694412..a2af4d9 100644 --- a/web/handlers/setup_test.go +++ b/web/handlers/setup_test.go @@ -20,8 +20,8 @@ var ( testRouter = router.CompleteApp() // mocked dbs - testAuthDB *mockdb.FakeAuthService - testAuthFallbackDB *mockdb.FakeFallbackAuth + testAuthDB *mockdb.FakeAuthWithSSBService + testAuthFallbackDB *mockdb.FakeAuthFallbackService ) func setup(t *testing.T) { @@ -30,8 +30,8 @@ func setup(t *testing.T) { os.RemoveAll(testRepoPath) testRepo := repo.New(testRepoPath) - testAuthDB = new(mockdb.FakeAuthService) - testAuthFallbackDB = new(mockdb.FakeFallbackAuth) + testAuthDB = new(mockdb.FakeAuthWithSSBService) + testAuthFallbackDB = new(mockdb.FakeAuthFallbackService) h, err := New( testRouter, testRepo, @@ -52,6 +52,6 @@ func setup(t *testing.T) { func teardown() { testMux = nil testClient = nil - testAuthFallbackDB = nil + testAuthDB = nil testAuthFallbackDB = nil } diff --git a/web/templates/auth/fallback_sign_in.tmpl b/web/templates/auth/fallback_sign_in.tmpl index 0a486f8..a325714 100644 --- a/web/templates/auth/fallback_sign_in.tmpl +++ b/web/templates/auth/fallback_sign_in.tmpl @@ -5,7 +5,9 @@
-
+ + +
diff --git a/web/utils.go b/web/utils.go index 4e2ec69..37d5806 100644 --- a/web/utils.go +++ b/web/utils.go @@ -2,12 +2,19 @@ package web import ( "errors" + "fmt" "html/template" + "io/ioutil" "net/url" + "os" + "path/filepath" "strconv" + "github.com/gorilla/securecookie" + "github.com/go-kit/kit/log/level" "github.com/gorilla/mux" + "github.com/ssb-ngi-pointer/gossb-rooms/internal/repo" "go.mindeco.de/logging" ) @@ -56,3 +63,54 @@ func NewURLTo(appRouter *mux.Router) func(string, ...interface{}) *url.URL { return u } } + +// LoadOrCreateCookieSecrets either parses the bytes from $repo/web/cookie-secret or creates a new file with suitable keys in it +func LoadOrCreateCookieSecrets(repo repo.Interface) ([]securecookie.Codec, error) { + secretPath := repo.GetPath("web", "cookie-secret") + err := os.MkdirAll(filepath.Dir(secretPath), 0700) + if err != nil && !os.IsExist(err) { + return nil, fmt.Errorf("failed to create folder for cookie secret: %w", err) + } + + // load the existing data + secrets, err := ioutil.ReadFile(secretPath) + if err != nil { + if !os.IsNotExist(err) { + return nil, fmt.Errorf("failed to load cookie secrets: %w", err) + } + + // create new keys, save them and return the codec + hashKey := securecookie.GenerateRandomKey(32) + blockKey := securecookie.GenerateRandomKey(32) + + data := append(hashKey, blockKey...) + err = ioutil.WriteFile(secretPath, data, 0600) + if err != nil { + return nil, err + } + sc := securecookie.CodecsFromPairs(hashKey, blockKey) + return sc, nil + } + + // secrets should contain multiple of 64byte (to enable key rotation as supported by gorilla) + if n := len(secrets); n%64 != 0 { + return nil, fmt.Errorf("expected multiple of 64bytes in cookie secret file but got: %d", n) + } + + // range over the secrets []byte in chunks of 64 bytes + // and slice it into 32byte pairs + var pairs [][]byte + + // the increment/next part (which usually is i++) + // is the multiple comma assigment (a,b = b+1,a-1) + // so chunk is the next 64 bytes and then it slices of the first 64 bytes of secrets for the next iteration + for chunk := secrets[:64]; len(secrets) >= 64; chunk, secrets = secrets[:64], secrets[64:] { + pairs = append(pairs, + chunk[0:32], // hash key + chunk[32:64], // block key + ) + } + + sc := securecookie.CodecsFromPairs(pairs...) + return sc, nil +}