diff --git a/.golangci.yml b/.golangci.yml index b189b069cfac06a44ad03bf3362f6871aa460233..f4d86fdc5d5a8bf8af3412341fdca18bc491359b 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -69,11 +69,14 @@ linters-settings: exclude-functions: - fmt.Fprintf - os.Remove + - os.RemoveAll - "(io.ReadCloser).Close" - "(*os.File).Close" + - "(net.Listener).Close" - "(*database/sql.Rows).Close" - "(*database/sql.Tx).Rollback" - "(*database/sql.DB).Close" + - "(*google.golang.org/grpc.ClientConn).Close" # Disable error checking, as errorcheck detects more errors and is more configurable. gosec: @@ -123,7 +126,7 @@ linters-settings: suggest-new: true dupl: # tokens count to trigger issue, 150 by default - threshold: 100 + threshold: 150 goconst: # minimal length of string constant, 3 by default min-len: 3 diff --git a/authn/auth.go b/authn/auth.go index 2ab0902c84de3679527386f5dc15693c95fd25bb..67dd20abe990982b44ad115fa28035f28ed8c167 100644 --- a/authn/auth.go +++ b/authn/auth.go @@ -2,12 +2,11 @@ package authn import ( "context" - "net" "time" authpb "git.autistici.org/smol/idp/authn/proto" - "git.autistici.org/smol/idp/userdb" pb "git.autistici.org/smol/idp/proto" + "git.autistici.org/smol/idp/userdb" ) // Custom authpb.Response that includes a private error diagnostic @@ -58,16 +57,6 @@ type shortTermStorage interface { Set(context.Context, []byte, []byte, time.Duration) error } -type rlReservation interface { - Ok() bool - Done(bool) -} - -type rateLimiter interface { - AllowIP(net.IP) rlReservation - Allow(*authpb.Request) rlReservation -} - // Keep track of the authenticator ID that last succeeded (i.e. more // strict), for further handlers to use. type authenticatorIDCtxKeyType int diff --git a/authn/auth_password.go b/authn/auth_password.go index c6c3001542f1152e541908fd096682ca60bf4434..855411a9c16f76aeee5f4e1e37f36dc25937ed05 100644 --- a/authn/auth_password.go +++ b/authn/auth_password.go @@ -5,8 +5,8 @@ import ( "log" authpb "git.autistici.org/smol/idp/authn/proto" - "git.autistici.org/smol/idp/userdb" pb "git.autistici.org/smol/idp/proto" + "git.autistici.org/smol/idp/userdb" ) // Authenticator for the primary (main) password. 2FA is usually diff --git a/authn/auth_recovery.go b/authn/auth_recovery.go index 6396a03833d7a7839a6c435620fbeca21b313102..2de72ebd543e374c6e66e96929f309cd3776e358 100644 --- a/authn/auth_recovery.go +++ b/authn/auth_recovery.go @@ -6,8 +6,8 @@ import ( "time" authpb "git.autistici.org/smol/idp/authn/proto" - "git.autistici.org/smol/idp/userdb" pb "git.autistici.org/smol/idp/proto" + "git.autistici.org/smol/idp/userdb" ) type recoveryAuthHandler struct { diff --git a/cmd/smol-idp/account.go b/cmd/smol-idp/account.go index 99db0be388c1464286bda91b626e5850ebbb15df..97f6199c47fc90d812b86a99cd4206598ddbacd6 100644 --- a/cmd/smol-idp/account.go +++ b/cmd/smol-idp/account.go @@ -12,8 +12,8 @@ import ( apb "git.autistici.org/smol/idp/audit/proto" authpb "git.autistici.org/smol/idp/authn/proto" "git.autistici.org/smol/idp/internal/netutil" - "git.autistici.org/smol/idp/userdb" "git.autistici.org/smol/idp/login" + "git.autistici.org/smol/idp/userdb" "github.com/google/subcommands" ) diff --git a/cmd/smol-idp/bundle.go b/cmd/smol-idp/bundle.go index 80e11fc0d33f4e4bc07ce8ae9c818a5a12a87900..df41efd33eb214a876da21ddf51aaa4089405da2 100644 --- a/cmd/smol-idp/bundle.go +++ b/cmd/smol-idp/bundle.go @@ -16,7 +16,6 @@ import ( "git.autistici.org/smol/idp/authn" authpb "git.autistici.org/smol/idp/authn/proto" "git.autistici.org/smol/idp/internal/netutil" - "git.autistici.org/smol/idp/userdb" "git.autistici.org/smol/idp/internal/web" "git.autistici.org/smol/idp/internal/yamlschema" "git.autistici.org/smol/idp/login" @@ -24,6 +23,7 @@ import ( "git.autistici.org/smol/idp/oidc" "git.autistici.org/smol/idp/oidc/storage" "git.autistici.org/smol/idp/ui" + "git.autistici.org/smol/idp/userdb" "github.com/google/subcommands" "github.com/gorilla/handlers" ) diff --git a/cmd/smol-idp/common.go b/cmd/smol-idp/common.go index 02d54acc36fa799345d3a1022743a91ae5698df0..b397b389f481f19c2639d38f9702408947c89513 100644 --- a/cmd/smol-idp/common.go +++ b/cmd/smol-idp/common.go @@ -27,7 +27,7 @@ const envFlagPrefix = "IDP_" // Read flag defaults from the environment. func defaultsFromEnv(ff *flag.FlagSet) { ff.VisitAll(func(f *flag.Flag) { - envName := envFlagPrefix + strings.ToUpper(strings.Replace(f.Name, "-", "_", -1)) + envName := envFlagPrefix + strings.ToUpper(strings.ReplaceAll(f.Name, "-", "_")) if s := os.Getenv(envName); s != "" { if err := f.Value.Set(s); err != nil { log.Printf("error setting flag %s from env variable %s: %v", f.Name, envName, err) diff --git a/cmd/smol-idp/idp.go b/cmd/smol-idp/idp.go index 459f6a17116b378b010f2b24547cf64e9669ebfb..15fc371fe3b132c4a8c0551fd90ffe4ff439e296 100644 --- a/cmd/smol-idp/idp.go +++ b/cmd/smol-idp/idp.go @@ -14,7 +14,6 @@ import ( apb "git.autistici.org/smol/idp/audit/proto" authpb "git.autistici.org/smol/idp/authn/proto" "git.autistici.org/smol/idp/internal/netutil" - "git.autistici.org/smol/idp/userdb" "git.autistici.org/smol/idp/internal/web" "git.autistici.org/smol/idp/internal/yamlschema" "git.autistici.org/smol/idp/login" @@ -22,6 +21,7 @@ import ( "git.autistici.org/smol/idp/oidc" "git.autistici.org/smol/idp/oidc/storage" "git.autistici.org/smol/idp/ui" + "git.autistici.org/smol/idp/userdb" "github.com/google/subcommands" "github.com/gorilla/handlers" ) diff --git a/cmd/smol-idp/main.go b/cmd/smol-idp/main.go index 0c4d17af6e8db915d860bb1e9581749b919509ac..ff4f7961225b06afb5d1d7c88974879fd57ac068 100644 --- a/cmd/smol-idp/main.go +++ b/cmd/smol-idp/main.go @@ -26,7 +26,6 @@ func explain(w io.Writer, cmd subcommands.Command) { func init() { subcommands.Register(subcommands.HelpCommand(), "help") subcommands.Register(subcommands.CommandsCommand(), "help") - //subcommands.Register(subcommands.FlagsCommand(), "help") subcommands.DefaultCommander.ExplainCommand = explain } diff --git a/internal/memcache/memcache.go b/internal/memcache/memcache.go index c1ae86002ef919d8987c4b7ad2647a21ebb8877c..1a9c24063c4f7f7a7db2af5271d492c5abd59ed4 100644 --- a/internal/memcache/memcache.go +++ b/internal/memcache/memcache.go @@ -139,7 +139,7 @@ func (c *Client) getConn(ctx context.Context) (*conn, bool, error) { func (c *Client) failConn(conn *conn) { c.mx.Lock() if c.cur == conn { - conn.Close() + _ = conn.Close() c.cur = nil } c.mx.Unlock() diff --git a/internal/memcache/replication.go b/internal/memcache/replication.go index 26472a8348ff3827846b0ef742fc9e1816a5b0f5..3d753798c2a3e6cf48bcd5e8d6fc1cf7743ce59a 100644 --- a/internal/memcache/replication.go +++ b/internal/memcache/replication.go @@ -55,7 +55,7 @@ func (c *ReplicatedClient) getServers() []*Client { return c.servers.Load().([]*Client) } -func (c *ReplicatedClient) pickServers(key []byte, n int) []*Client { +func (c *ReplicatedClient) pickServers(_ []byte, n int) []*Client { servers := c.getServers() if len(servers) > n { servers = servers[:n] diff --git a/internal/netutil/grpc_client.go b/internal/netutil/grpc_client.go index a4f2df165135c4d763917c168b28fe86b56bf363..7f5da95434ebb6c5e3fcc75480c2f0c07c93d55b 100644 --- a/internal/netutil/grpc_client.go +++ b/internal/netutil/grpc_client.go @@ -33,7 +33,7 @@ func newConnCache(opts []grpc.DialOption) *grpcConnCache { func (c *grpcConnCache) Close() error { for _, conn := range c.conns { - conn.Close() + _ = conn.Close() } return nil } diff --git a/internal/testutil/fake_auth.go b/internal/testutil/fake_auth.go index 9de132405c858189f857e0b379144ee0c8dfc056..27d0ffa28edecc73a983ce722558b7f71acca2ac 100644 --- a/internal/testutil/fake_auth.go +++ b/internal/testutil/fake_auth.go @@ -13,7 +13,7 @@ import ( var ( fakeWebauthnSession = "webauthn_session" fakeWebauthnEncodedAssertion = "{\"Challenge\":\"webauthn_challenge\"}" - testCredentialOrigin = "https://webauthn.io" + testOrigin = "https://webauthn.io" ) func validWebAuthnRequest(req *authpb.Request) bool { @@ -28,7 +28,7 @@ func validWebAuthnRequest(req *authpb.Request) bool { if err != nil { return false } - if a.Response.CollectedClientData.Origin != testCredentialOrigin { + if a.Response.CollectedClientData.Origin != testOrigin { log.Printf("bad webauthn assertion: '%s'", req.WebauthnEncodedAssertion) return false } @@ -38,7 +38,7 @@ func validWebAuthnRequest(req *authpb.Request) bool { type FakeAuthClient struct{} func (c *FakeAuthClient) Authenticate(ctx context.Context, req *authpb.Request, _ ...grpc.CallOption) (*authpb.Response, error) { - p := string(req.Password) + p := req.Password info := &pb.UserInfo{ Name: "test", Email: "test@example.com", diff --git a/internal/testutil/userdb.go b/internal/testutil/userdb.go index 67c383cfb1559c26ed24eb6f1fe40b718a06180d..74de61e2012703808e839dd3e17c806a1f975f82 100644 --- a/internal/testutil/userdb.go +++ b/internal/testutil/userdb.go @@ -69,7 +69,7 @@ func CreateTestDB(fixtures, dir string) (userdb.Backend, func(), error) { return b, func() { b.Close() if dir == "" { - os.RemoveAll(dbdir) + _ = os.RemoveAll(dbdir) } }, nil } diff --git a/internal/yamlschema/schema.go b/internal/yamlschema/schema.go index 45133baf9c14374f29da0bd1705edd894276994c..0766a56da8f2b4b5dd4bb889e17d9da6dbf40cb8 100644 --- a/internal/yamlschema/schema.go +++ b/internal/yamlschema/schema.go @@ -20,7 +20,7 @@ import ( // documentation. func DumpSchema(w io.Writer, obj any, prefix string) { bufw := bufio.NewWriter(w) - defer bufw.Flush() + defer bufw.Flush() //nolint:errcheck fmt.Fprintf(bufw, "\n") diff --git a/login/login_test.go b/login/login_test.go index 116ee0ff906f64081f0d60f98f28d1f027f6914f..85cf5e9d7d5a7ac52419a9b1cb4db2ae08d87617 100644 --- a/login/login_test.go +++ b/login/login_test.go @@ -80,7 +80,7 @@ func newClient(baseURI string) *httpClient { } func (c *httpClient) withRequestParams(uri string) string { - return uri + "?_rp=" + strings.Replace(c.requestParams, "=", "%3D", -1) + return uri + "?_rp=" + strings.ReplaceAll(c.requestParams, "=", "%3D") } func (c *httpClient) formData(values map[string]string) io.Reader { diff --git a/mgmt/app.go b/mgmt/app.go index 5b22236be88ed9cb5f6a3cbe6b014c0e1855eb02..0fa9f317a29f2ccdcac09ce85e2b90c8b395b986 100644 --- a/mgmt/app.go +++ b/mgmt/app.go @@ -10,10 +10,10 @@ import ( "git.autistici.org/smol/idp" authpb "git.autistici.org/smol/idp/authn/proto" "git.autistici.org/smol/idp/internal/cryptutil" - "git.autistici.org/smol/idp/userdb" "git.autistici.org/smol/idp/internal/web" "git.autistici.org/smol/idp/internal/web/forms" "git.autistici.org/smol/idp/login" + "git.autistici.org/smol/idp/userdb" "google.golang.org/grpc" ) diff --git a/mgmt/app_test.go b/mgmt/app_test.go index af2b367283dfae45b513e5cf876727d165801ec6..b2f190916f43f3972dfd1f1adc0e82bbd4fc7d6e 100644 --- a/mgmt/app_test.go +++ b/mgmt/app_test.go @@ -7,11 +7,11 @@ import ( "git.autistici.org/smol/idp" "git.autistici.org/smol/idp/internal/testutil" - "git.autistici.org/smol/idp/userdb" "git.autistici.org/smol/idp/internal/web" "git.autistici.org/smol/idp/login" lpb "git.autistici.org/smol/idp/login/proto" "git.autistici.org/smol/idp/ui" + "git.autistici.org/smol/idp/userdb" "github.com/gorilla/securecookie" ) diff --git a/mgmt/asp.go b/mgmt/asp.go index 11df36c70e0fd47a78a4f1f43d1fa6b51126c29f..caafb4fd46cc136258dbd628b164d77a4c23e202 100644 --- a/mgmt/asp.go +++ b/mgmt/asp.go @@ -4,9 +4,9 @@ import ( "net/http" "git.autistici.org/smol/idp/internal/random" - "git.autistici.org/smol/idp/userdb" "git.autistici.org/smol/idp/internal/web" "git.autistici.org/smol/idp/internal/web/forms" + "git.autistici.org/smol/idp/userdb" ) type listASPAction struct{} diff --git a/mgmt/change_password.go b/mgmt/change_password.go index 93c81aef57d3586479167b4ffc26efef8a3b1af5..465b0f2956b98af175346b4a0928b622f05b87f7 100644 --- a/mgmt/change_password.go +++ b/mgmt/change_password.go @@ -3,9 +3,9 @@ package mgmt import ( "net/http" - "git.autistici.org/smol/idp/userdb" "git.autistici.org/smol/idp/internal/web" "git.autistici.org/smol/idp/internal/web/forms" + "git.autistici.org/smol/idp/userdb" ) const changePasswordWorkflow = "change-password" diff --git a/mgmt/messages.go b/mgmt/messages.go index a40ac152a6d3cb726c01f4f543a5396e4b468f5f..e6a4fd4d13004e5fe58f34ebb0e014de0ab9a6b3 100644 --- a/mgmt/messages.go +++ b/mgmt/messages.go @@ -6,8 +6,8 @@ import ( "html/template" "net/http" - "git.autistici.org/smol/idp/userdb" "git.autistici.org/smol/idp/internal/web" + "git.autistici.org/smol/idp/userdb" ) type messageAction struct { @@ -31,7 +31,9 @@ func (a *messageAction) ServeAction(req *http.Request, user *userdb.User, tpl *w return newErrorResponse(http.StatusInternalServerError) } return htmlResponse(tpl.WithData(map[string]any{ - "Content": template.HTML(buf.String()), + // Message contents are under our control and we trust + // them to be valid HTML. + "Content": template.HTML(buf.String()), //nolint:gosec }), req, "account_message.html") } diff --git a/mgmt/recovery.go b/mgmt/recovery.go index a644ab6d30443b641248ca485054c24b028acfa9..063795f7fed5ee97980b08b595b990eeb9f0dba2 100644 --- a/mgmt/recovery.go +++ b/mgmt/recovery.go @@ -5,10 +5,10 @@ import ( "time" "git.autistici.org/smol/idp/internal/random" - "git.autistici.org/smol/idp/userdb" "git.autistici.org/smol/idp/internal/web" "git.autistici.org/smol/idp/internal/web/forms" pb "git.autistici.org/smol/idp/proto" + "git.autistici.org/smol/idp/userdb" ) const resetRecoveryWorkflow = "set-recovery" diff --git a/mgmt/util.go b/mgmt/util.go index 8ee2e9007880d843c21fea3dc9678e6b8f678910..c8efbd298ed8025b91b9ebb1a71abc95a524123b 100644 --- a/mgmt/util.go +++ b/mgmt/util.go @@ -4,11 +4,11 @@ import ( "net/http" "git.autistici.org/smol/idp/internal/sessionstore" - "git.autistici.org/smol/idp/userdb" "git.autistici.org/smol/idp/internal/web" "git.autistici.org/smol/idp/internal/web/forms" "git.autistici.org/smol/idp/login" pb "git.autistici.org/smol/idp/proto" + "git.autistici.org/smol/idp/userdb" ) // Minimal web framework, tailored for this specific kind of app. diff --git a/oidc/op.go b/oidc/op.go index eb27bbd602949623f99aa137ef6b2f94dcfd6c54..21f32d19a100d44cbf121d367375bf94a05ff046 100644 --- a/oidc/op.go +++ b/oidc/op.go @@ -135,7 +135,7 @@ func NewOP(storage op.Storage, issuer string, key [32]byte, insecure bool) (op.O } if insecure { - //we must explicitly allow the use of the http issuer + // We must explicitly allow the use of the http issuer. opts = append(opts, op.WithAllowInsecure()) } diff --git a/oidc/storage/oidc.go b/oidc/storage/oidc.go index 3feda7430f4fdd097e21acadfb43b514f0b59242..5f7b72f3ba89d50558ca2f02b0685f15eb2964c3 100644 --- a/oidc/storage/oidc.go +++ b/oidc/storage/oidc.go @@ -11,13 +11,14 @@ import ( const ( // CustomScope is an example for how to use custom scopes in this library - //(in this scenario, when requested, it will return a custom claim) + // (in this scenario, when requested, it will return a custom claim). CustomScope = "custom_scope" - // CustomClaim is an example for how to return custom claims with this library + // CustomClaim is an example for how to return custom claims with this library. CustomClaim = "custom_claim" - // CustomScopeImpersonatePrefix is an example scope prefix for passing user id to impersonate using token exchage + // CustomScopeImpersonatePrefix is an example scope prefix for + // passing user id to impersonate using token exchange. CustomScopeImpersonatePrefix = "custom_scope:impersonate:" GroupsScope = "groups" diff --git a/oidc/storage/op_storage.go b/oidc/storage/op_storage.go index 992b4d897fdd17a6320568536de9920e189f3f36..6c659ca9a49a695ad59d4e05c52222ca3f18432b 100644 --- a/oidc/storage/op_storage.go +++ b/oidc/storage/op_storage.go @@ -60,23 +60,25 @@ func (s *opStorage) SetIntrospectionFromToken(ctx context.Context, introspection if err != nil { return fmt.Errorf("token is invalid or has expired") } - // check if the client is part of the requested audience + + // Check if the client is part of the requested audience. for _, aud := range token.Audience { if aud == clientID { - // the introspection response only has to return a boolean (active) if the token is active - // this will automatically be done by the library if you don't return an error - // you can also return further information about the user / associated token - // e.g. the userinfo (equivalent to userinfo endpoint) - + // The introspection response only has to return a + // boolean (active) if the token is active this will + // automatically be done by the library if you don't + // return an error you can also return further + // information about the user / associated token e.g. + // the userinfo (equivalent to userinfo endpoint). userInfo := new(oidc.UserInfo) err := s.setUserinfo(ctx, userInfo, subject, clientID, token.Scopes) if err != nil { return err } introspection.SetUserInfo(userInfo) - //...and also the requested scopes... + // ...and also the requested scopes... introspection.Scope = token.Scopes - //...and the client the token was issued to + // ...and the client the token was issued to. introspection.ClientID = token.ClientID return nil } @@ -122,7 +124,7 @@ func (s *opStorage) GetPrivateClaimsFromScopes(ctx context.Context, userID, clie return s.getPrivateClaimsFromScopes(ctx, userID, clientID, scopes) } -func (s *opStorage) getPrivateClaimsFromScopes(ctx context.Context, userID, clientID string, scopes []string) (claims map[string]any, err error) { +func (s *opStorage) getPrivateClaimsFromScopes(_ context.Context, userID, clientID string, scopes []string) (claims map[string]any, err error) { for _, scope := range scopes { switch scope { case CustomScope: @@ -210,7 +212,7 @@ func (s *tokenExchangeStorage) SetUserinfoFromTokenExchangeRequest(ctx context.C return nil } -func (s *tokenExchangeStorage) getTokenExchangeClaims(ctx context.Context, request op.TokenExchangeRequest) (claims map[string]any) { +func (s *tokenExchangeStorage) getTokenExchangeClaims(_ context.Context, request op.TokenExchangeRequest) (claims map[string]any) { for _, scope := range request.GetScopes() { switch { case strings.HasPrefix(scope, CustomScopeImpersonatePrefix) && request.GetExchangeActor() == "": diff --git a/userdb/backend/all/all_test.go b/userdb/backend/all/all_test.go index 66d156ffcf9f91b0e36d1c38ab637462e38b596f..a5573c559e9a1fceb56b165645ee120729c71c0c 100644 --- a/userdb/backend/all/all_test.go +++ b/userdb/backend/all/all_test.go @@ -100,10 +100,11 @@ func setPassword(user *userdb.User, pw string) error { return nil } -func runTestNotFound(t *testing.T, db userdb.Backend, username string) { +func runTestNotFound(t *testing.T, db userdb.Backend) { ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second) defer cancel() + username := "nosuchuser" user, err := db.GetUserByName(ctx, username) if !errors.Is(err, userdb.ErrNotFound) { t.Fatalf("GetUserByName(%s): expected ErrNotFound, got err=%v, user=%+v", username, err, user) @@ -151,7 +152,7 @@ func TestBackend_SQL(t *testing.T) { defer cleanup() runTest(t, db, "test", false) - runTestNotFound(t, db, "nosuchuser") + runTestNotFound(t, db) } func TestBackend_Static(t *testing.T) { @@ -162,7 +163,7 @@ func TestBackend_Static(t *testing.T) { defer db.Close() runTest(t, db, "test", true) - runTestNotFound(t, db, "nosuchuser") + runTestNotFound(t, db) } func TestBackend_Chain(t *testing.T) { @@ -174,7 +175,7 @@ func TestBackend_Chain(t *testing.T) { runTest(t, db, "test", true) // static backend comes first runTest(t, db, "test-sqlonly", false) - runTestNotFound(t, db, "nosuchuser") + runTestNotFound(t, db) } func TestBackend_RPC(t *testing.T) { @@ -191,5 +192,5 @@ func TestBackend_RPC(t *testing.T) { defer cleanup2() runTest(t, db, "test", false) - runTestNotFound(t, db, "nosuchuser") + runTestNotFound(t, db) } diff --git a/userdb/backend/rpc/rpc.go b/userdb/backend/rpc/rpc.go index 36ab8617c366f86bce0fd1bc4e4c0ed9bf0fa500..769ddd54be45edb90327e0955a6385dc56aa3112 100644 --- a/userdb/backend/rpc/rpc.go +++ b/userdb/backend/rpc/rpc.go @@ -5,8 +5,8 @@ import ( accpb "git.autistici.org/smol/idp/account/proto" "git.autistici.org/smol/idp/internal/netutil" - "git.autistici.org/smol/idp/userdb" pb "git.autistici.org/smol/idp/proto" + "git.autistici.org/smol/idp/userdb" "google.golang.org/grpc" "google.golang.org/grpc/codes" "google.golang.org/grpc/status" @@ -59,8 +59,7 @@ func (b *rpcBackend) GetUserByName(ctx context.Context, username string) (*userd func (b *rpcBackend) getUser(ctx context.Context, req *accpb.GetUserRequest) (*userdb.User, error) { u, err := b.client.GetUser(ctx, req) if err != nil { - switch status.Code(err) { - case codes.NotFound: + if status.Code(err) == codes.NotFound { err = userdb.ErrNotFound } return nil, err diff --git a/userdb/backend/sql/sql.go b/userdb/backend/sql/sql.go index ec833b31d4e35b957879adad9d86c91196c65682..68deaf2d61427d3bdc54ef95aedebeb3c21cc5ee 100644 --- a/userdb/backend/sql/sql.go +++ b/userdb/backend/sql/sql.go @@ -403,6 +403,8 @@ func newSQLBackendFromParams(sparams *sqlParams) (userdb.Backend, error) { switch sparams.Driver { case "sqlite3": err = setupSQLite(db) + default: + err = errors.New("unsupported sql driver") } if err != nil { return nil, err