diff --git a/.github/workflows/go.yaml b/.github/workflows/go.yaml
index 95600c65..93c5d631 100644
--- a/.github/workflows/go.yaml
+++ b/.github/workflows/go.yaml
@@ -19,7 +19,7 @@ jobs:
strategy:
matrix:
os: [ubuntu-latest, macos-latest]
- go: ['1.22', '1.23']
+ go: ['1.23', '1.24']
fail-fast: false
env:
OS: ${{ matrix.os }}
@@ -46,8 +46,11 @@ jobs:
- name: 'Tags: libsqlite3'
run: go test -race -v -tags "libsqlite3"
+ - name: 'Tags: userauth deprecated'
+ run: make test_userauth_fails test_userauth_fails_libsqlite3
+
- name: 'Tags: full'
- run: go test -race -v -tags "sqlite_allow_uri_authority sqlite_app_armor sqlite_column_metadata sqlite_foreign_keys sqlite_fts5 sqlite_icu sqlite_introspect sqlite_json sqlite_math_functions sqlite_os_trace sqlite_preupdate_hook sqlite_secure_delete sqlite_see sqlite_stat4 sqlite_trace sqlite_unlock_notify sqlite_userauth sqlite_vacuum_incr sqlite_vtable"
+ run: go test -race -v -tags "sqlite_allow_uri_authority sqlite_app_armor sqlite_column_metadata sqlite_foreign_keys sqlite_fts5 sqlite_icu sqlite_introspect sqlite_json sqlite_math_functions sqlite_os_trace sqlite_preupdate_hook sqlite_secure_delete sqlite_see sqlite_stat4 sqlite_trace sqlite_unlock_notify sqlite_vacuum_incr sqlite_vtable"
- name: 'Tags: vacuum'
run: go test -v -tags "sqlite_vacuum_full"
diff --git a/Makefile b/Makefile
new file mode 100644
index 00000000..34e74761
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,111 @@
+# Benchmark options
+NO_TESTS = ^$
+# BENCHMARKS = ^BenchmarkIndex('\$'|Hard|Torture|Periodic(Unicode)?)
+BENCH_SUITE = BenchmarkSuite
+BENCH_QUERY = BenchmarkSuite/.*BenchmarkQuery$
+BENCH_EXEC_STEP = BenchmarkSuite/.*BenchmarkExecStep$
+
+# TODO: join these into a single list
+ALL_TEST_TAGS := sqlite_allow_uri_authority
+ALL_TEST_TAGS += sqlite_app_armor
+ALL_TEST_TAGS += sqlite_column_metadata
+ALL_TEST_TAGS += sqlite_foreign_keys
+ALL_TEST_TAGS += sqlite_fts5
+ALL_TEST_TAGS += sqlite_icu
+ALL_TEST_TAGS += sqlite_introspect
+ALL_TEST_TAGS += sqlite_json
+ALL_TEST_TAGS += sqlite_math_functions
+ALL_TEST_TAGS += sqlite_preupdate_hook
+ALL_TEST_TAGS += sqlite_secure_delete
+ALL_TEST_TAGS += sqlite_see
+ALL_TEST_TAGS += sqlite_stat4
+ALL_TEST_TAGS += sqlite_trace
+ALL_TEST_TAGS += sqlite_unlock_notify
+ALL_TEST_TAGS += sqlite_vacuum_incr
+ALL_TEST_TAGS += sqlite_vtable
+
+space := $(subst ,, )
+comma := ,
+
+ALL_TEST_TAGS_JOINED = $(subst $(space),$(comma),$(ALL_TEST_TAGS))
+
+# GO_VERSION = $(shell go version | grep -oE 'go[1-9]\.[0-9]+(\.[0-9]+)?')
+# ifeq (,$(shell echo $(GO_VERSION_NUMBER) | grep -E 'go1\.2[2-9]'))
+# export GOEXPERIMENT=cgocheck2
+# endif
+
+.PHONY: all
+all: build
+
+.PHONY: build
+build:
+ @go build -tags "libsqlite3"
+
+.PHONY: test
+test:
+ @GOEXPERIMENT=cgocheck2 go test -tags "libsqlite3" -v
+
+.PHONY: test_all
+test_all:
+ @GOEXPERIMENT=cgocheck2 go test -tags "$(ALL_TEST_TAGS_JOINED)" -v
+
+# TODO: merge with the above target
+.PHONY: test_all_libsqlite3
+test_all_libsqlite3:
+ GOEXPERIMENT=cgocheck2 go test -tags "$(ALL_TEST_TAGS_JOINED),libsqlite3" -v
+
+.PHONY: qtest
+qtest:
+ @GOEXPERIMENT=cgocheck2 go test -tags "libsqlite3"
+
+.PHONY: short
+short:
+ @go test -tags "libsqlite3" -short
+
+.PHONY: testrace
+testrace:
+ @GOEXPERIMENT=cgocheck2 go test -tags "libsqlite3" -race
+
+.PHONY: test_userauth_fails
+test_userauth_fails:
+ @./scripts/test-userauth-fails.bash
+
+.PHONY: test_userauth_fails_libsqlite3
+test_userauth_fails_libsqlite3:
+ @./scripts/test-userauth-fails.bash -libsqlite3
+
+.PHONY: testfull
+testfull:
+ @./scripts/test-full.bash -v
+
+.PHONY: testfull_race
+testfull_race:
+ @./scripts/test-full.bash -v -race
+
+.PHONY: bench
+bench:
+ @go test -tags "libsqlite3 darwin" -run $(NO_TESTS) -bench $(BENCH_SUITE) -benchmem
+
+.PHONY: bench_stmt_rows
+bench_stmt_rows:
+ @go test -tags "libsqlite3 darwin" -run $(NO_TESTS) -bench $(BENCH_QUERY) -benchmem
+
+.PHONY: bench_exec_step
+bench_exec_step:
+ @go test -tags "libsqlite3 darwin" -run $(NO_TESTS) -bench $(BENCH_EXEC_STEP) -benchmem
+
+.PHONY: bench_mem
+bench_mem:
+ @go test -tags "libsqlite3 darwin" -run $(NO_TESTS) \
+ -bench $(BENCH_SUITE) \
+ -benchmem -memprofilerate 1 -memprofile mem.out -benchtime 5s
+
+.PHONY: bench_cpu
+bench_cpu:
+ @go test -tags "libsqlite3 darwin" -run $(NO_TESTS) \
+ -bench $(BENCH_SUITE) \
+ -cpuprofile cpu.out -benchtime 5s
+
+.PHONY: tags
+tags:
+ @\grep -ohP '(?<=//go:build )\w+(\s+\w+)?' *.go | sort -u
diff --git a/README.md b/README.md
index 847dc7d5..f8edf5d7 100644
--- a/README.md
+++ b/README.md
@@ -468,10 +468,21 @@ For example the TDM-GCC Toolchain can be found [here](https://jmeubank.github.io
# User Authentication
-This package supports the SQLite User Authentication module.
+### ***This is deprecated***
+
+~~This package supports the SQLite User Authentication module.~~
+
+User authentication deprecated as of [#28](https://github.com/charlievieth/go-sqlite3/pull/28)
+and building with the `sqlite_userauth` tag will cause [`Open()`](https://pkg.go.dev/github.com/charlievieth/go-sqlite3#SQLiteDriver.Open)
+to fail.
+
+
+Deprecated User Authentication
## Compile
+### WARN: THIS IS DEPRECATED
+
To use the User authentication module, the package has to be compiled with the tag `sqlite_userauth`. See [Features](#features).
## Usage
@@ -577,6 +588,8 @@ The following functions are available for User authentication from the `*SQLiteC
When using attached databases, SQLite will use the authentication from the `main` database for the attached database(s).
+
+
# Extensions
If you want your own extension to be listed here, or you want to add a reference to an extension; please submit an Issue for this.
diff --git a/error_test.go b/error_test.go
index 618810a7..80cabe94 100644
--- a/error_test.go
+++ b/error_test.go
@@ -43,7 +43,10 @@ func TestCorruptDbErrors(t *testing.T) {
_, err = db.Exec("drop table foo")
}
- sqliteErr := err.(Error)
+ sqliteErr, ok := err.(Error)
+ if !ok {
+ t.Fatalf("Not a sqlite3.Error: %#v", err)
+ }
if sqliteErr.Code != ErrNotADB {
t.Error("wrong error code for corrupted DB")
}
@@ -113,7 +116,10 @@ func TestExtendedErrorCodes_ForeignKey(t *testing.T) {
if err == nil {
t.Error("No error!")
} else {
- sqliteErr := err.(Error)
+ sqliteErr, ok := err.(Error)
+ if !ok {
+ t.Fatalf("Not a sqlite3.Error: %#v", err)
+ }
if sqliteErr.Code != ErrConstraint {
t.Errorf("Wrong basic error code: %d != %d",
sqliteErr.Code, ErrConstraint)
diff --git a/scripts/test-userauth-fails.bash b/scripts/test-userauth-fails.bash
new file mode 100755
index 00000000..d4dd5d78
--- /dev/null
+++ b/scripts/test-userauth-fails.bash
@@ -0,0 +1,47 @@
+#!/usr/bin/env bash
+
+# Test that the userauth tests fail, but don't panic.
+# Pass "-libsqlite3" as an argument to the script to
+# run the tests with the "libsqlite3" build tag.
+
+set -euo pipefail
+
+OUT="$(mktemp -t 'go-sqlite3.XXXXXX')"
+trap 'rm "${OUT}"' EXIT
+
+function test_sqlite_userauth() {
+ local tags='sqlite_userauth'
+ while (( $# > 0 )); do
+ if [[ -n $1 ]]; then
+ tags+=",$1"
+ fi
+ shift
+ done
+
+ echo "Running: \`go test -tags=${tags}\`"
+ if go test -tags="${tags}" &> "${OUT}"; then
+ cat "${OUT}"
+ echo >&2 ''
+ echo >&2 'FAIL: tests passed: expected them to fail'
+ return 2
+ fi
+
+ if \grep -qF 'panic:' "${OUT}"; then
+ cat "${OUT}"
+ echo >&2 ''
+ echo >&2 'FAIL: test panicked'
+ return 2
+ fi
+
+ echo "PASS"
+}
+
+function main() {
+ local tags=''
+ if [[ ${1:-} == '-libsqlite3' ]]; then
+ tags='libsqlite3'
+ fi
+ test_sqlite_userauth "${tags}"
+}
+
+main "$@"
diff --git a/sqlite3.go b/sqlite3.go
index 65ac01a6..d24eba0c 100644
--- a/sqlite3.go
+++ b/sqlite3.go
@@ -1906,64 +1906,10 @@ func (d *SQLiteDriver) Open(dsn string) (driver.Conn, error) {
}
// Preform Authentication
- if err := conn.Authenticate(authUser, authPass); err != nil {
- return err
- }
-
- // Register: authenticate
- // Authenticate will perform an authentication of the provided username
- // and password against the database.
- //
- // If a database contains the SQLITE_USER table, then the
- // call to Authenticate must be invoked with an
- // appropriate username and password prior to enable read and write
- //access to the database.
- //
- // Return SQLITE_OK on success or SQLITE_ERROR if the username/password
- // combination is incorrect or unknown.
- //
- // If the SQLITE_USER table is not present in the database file, then
- // this interface is a harmless no-op returnning SQLITE_OK.
- if err := conn.registerAuthFunc("authenticate", conn.authenticate, true); err != nil {
- return err
- }
- //
- // Register: auth_user_add
- // auth_user_add can be used (by an admin user only)
- // to create a new user. When called on a no-authentication-required
- // database, this routine converts the database into an authentication-
- // required database, automatically makes the added user an
- // administrator, and logs in the current connection as that user.
- // The AuthUserAdd only works for the "main" database, not
- // for any ATTACH-ed databases. Any call to AuthUserAdd by a
- // non-admin user results in an error.
- if err := conn.registerAuthFunc("auth_user_add", conn.authUserAdd, true); err != nil {
- return err
- }
- //
- // Register: auth_user_change
- // auth_user_change can be used to change a users
- // login credentials or admin privilege. Any user can change their own
- // login credentials. Only an admin user can change another users login
- // credentials or admin privilege setting. No user may change their own
- // admin privilege setting.
- if err := conn.registerAuthFunc("auth_user_change", conn.authUserChange, true); err != nil {
- return err
- }
//
- // Register: auth_user_delete
- // auth_user_delete can be used (by an admin user only)
- // to delete a user. The currently logged-in user cannot be deleted,
- // which guarantees that there is always an admin user and hence that
- // the database cannot be converted into a no-authentication-required
- // database.
- if err := conn.registerAuthFunc("auth_user_delete", conn.authUserDelete, true); err != nil {
- return err
- }
-
- // Register: auth_enabled
- // auth_enabled can be used to check if user authentication is enabled
- if err := conn.registerAuthFunc("auth_enabled", conn.authEnabled, true); err != nil {
+ // NB: This will always fail if built with the "sqlite_userauth"
+ // build tag since user authentication is now deprecated.
+ if err := conn.Authenticate(authUser, authPass); err != nil {
return err
}
@@ -1980,6 +1926,9 @@ func (d *SQLiteDriver) Open(dsn string) (driver.Conn, error) {
}
// Check if user wants to activate User Authentication
+ //
+ // NB: This will always fail if built with the "sqlite_userauth"
+ // build tag since user authentication is now deprecated.
if authCreate {
// Before going any further, we need to check that the user
// has provided an username and password within the DSN.
@@ -1992,8 +1941,7 @@ func (d *SQLiteDriver) Open(dsn string) (driver.Conn, error) {
}
// Check if User Authentication is Enabled
- authExists := conn.AuthEnabled()
- if !authExists {
+ if !conn.AuthEnabled() {
if err := conn.AuthUserAdd(authUser, authPass, true); err != nil {
return err
}
diff --git a/sqlite3_go124_test.go b/sqlite3_go124_test.go
index 3dc4f7d6..36cd0aed 100644
--- a/sqlite3_go124_test.go
+++ b/sqlite3_go124_test.go
@@ -6,73 +6,5 @@ package sqlite3
import "testing"
func TestGGO(t *testing.T) {
- const msg = `
-#cgo noescape _sqlite3_bind_blob
-#cgo noescape _sqlite3_bind_text
-#cgo noescape _sqlite3_column_blob
-#cgo noescape _sqlite3_column_decltypes
-#cgo noescape _sqlite3_column_text
-#cgo noescape _sqlite3_column_types
-#cgo noescape _sqlite3_create_function
-#cgo noescape _sqlite3_exec_no_args
-#cgo noescape _sqlite3_limit
-#cgo noescape _sqlite3_open_v2
-#cgo noescape _sqlite3_prepare_query
-#cgo noescape _sqlite3_prepare_v2
-#cgo noescape _sqlite3_prepare_v2_internal
-#cgo noescape _sqlite3_step_internal
-#cgo noescape _sqlite3_step_row_internal
-#cgo noescape sqlite3_aggregate_context
-#cgo noescape sqlite3_bind_double
-#cgo noescape sqlite3_bind_int
-#cgo noescape sqlite3_bind_int64
-#cgo noescape sqlite3_bind_null
-#cgo noescape sqlite3_bind_parameter_count
-#cgo noescape sqlite3_bind_parameter_index
-
-#cgo nocallback sqlite3_bind_double
-#cgo nocallback sqlite3_bind_int
-#cgo nocallback sqlite3_bind_int64
-#cgo nocallback sqlite3_bind_null
-#cgo nocallback sqlite3_bind_parameter_count
-#cgo nocallback sqlite3_bind_parameter_index
-
-#cgo noescape sqlite3_clear_bindings
-#cgo noescape sqlite3_close_v2
-#cgo noescape sqlite3_column_count
-#cgo noescape sqlite3_column_decltype
-#cgo noescape sqlite3_column_double
-#cgo noescape sqlite3_column_int64
-#cgo noescape sqlite3_column_name
-
-#cgo nocallback sqlite3_column_count
-#cgo nocallback sqlite3_column_decltype
-#cgo nocallback sqlite3_column_double
-#cgo nocallback sqlite3_column_int64
-#cgo nocallback sqlite3_column_name
-
-#cgo noescape sqlite3_commit_hook
-#cgo noescape sqlite3_create_collation
-#cgo noescape sqlite3_db_filename
-#cgo noescape sqlite3_errcode
-#cgo noescape sqlite3_errmsg
-#cgo noescape sqlite3_exec
-#cgo noescape sqlite3_extended_errcode
-#cgo noescape sqlite3_file_control
-#cgo noescape sqlite3_finalize
-#cgo noescape sqlite3_get_autocommit
-#cgo noescape sqlite3_interrupt
-#cgo noescape sqlite3_libversion
-#cgo noescape sqlite3_libversion_number
-#cgo noescape sqlite3_reset
-#cgo noescape sqlite3_rollback_hook
-#cgo noescape sqlite3_set_authorizer
-#cgo noescape sqlite3_sourceid
-#cgo noescape sqlite3_stmt_readonly
-#cgo noescape sqlite3_system_errno
-#cgo noescape sqlite3_threadsafe
-#cgo noescape sqlite3_update_hook
-`
- // https://pkg.go.dev/cmd/cgo@master#hdr-Optimizing_calls_of_C_code
- t.Fatal("TODO: see if adding go1.24 optimization hint helps")
+ t.Skip("TODO: see if adding go1.24 optimization hint helps")
}
diff --git a/sqlite3_opt_userauth.go b/sqlite3_opt_userauth.go
index 4fda59da..c35a4e1c 100644
--- a/sqlite3_opt_userauth.go
+++ b/sqlite3_opt_userauth.go
@@ -8,68 +8,19 @@
package sqlite3
-/*
-#cgo CFLAGS: -DSQLITE_USER_AUTHENTICATION
-#cgo LDFLAGS: -lm
-#ifndef USE_LIBSQLITE3
-#include "sqlite3-binding.h"
-#else
-#include
-#endif
-#include
-
-static int
-_sqlite3_user_authenticate(sqlite3* db, const char* zUsername, const char* aPW, int nPW)
-{
- return sqlite3_user_authenticate(db, zUsername, aPW, nPW);
-}
-
-static int
-_sqlite3_user_add(sqlite3* db, const char* zUsername, const char* aPW, int nPW, int isAdmin)
-{
- return sqlite3_user_add(db, zUsername, aPW, nPW, isAdmin);
-}
-
-static int
-_sqlite3_user_change(sqlite3* db, const char* zUsername, const char* aPW, int nPW, int isAdmin)
-{
- return sqlite3_user_change(db, zUsername, aPW, nPW, isAdmin);
-}
-
-static int
-_sqlite3_user_delete(sqlite3* db, const char* zUsername)
-{
- return sqlite3_user_delete(db, zUsername);
-}
-
-static int
-_sqlite3_auth_enabled(sqlite3* db)
-{
- int exists = -1;
-
- sqlite3_stmt *stmt;
- sqlite3_prepare_v2(db, "select count(type) from sqlite_master WHERE type='table' and name='sqlite_user';", -1, &stmt, NULL);
-
- while ( sqlite3_step(stmt) == SQLITE_ROW) {
- exists = sqlite3_column_int(stmt, 0);
- }
-
- sqlite3_finalize(stmt);
-
- return exists;
-}
-*/
-import "C"
-import (
- "errors"
- "unsafe"
-)
+import "errors"
var (
- ErrUnauthorized = errors.New("SQLITE_AUTH: Unauthorized")
- ErrAdminRequired = errors.New("SQLITE_AUTH: Unauthorized; Admin Privileges Required")
+ ErrUnauthorized = errors.New("SQLITE_AUTH: Unauthorized")
+ ErrAdminRequired = errors.New("SQLITE_AUTH: Unauthorized; Admin Privileges Required")
+ errUserAuthNoLongerSupported = errors.New("sqlite3: the sqlite_userauth tag is no longer supported " +
+ "as the userauth extension is no longer supported by the SQLite authors, " +
+ "see https://github.com/mattn/go-sqlite3/issues/1341")
)
+// NB: Even though userauth is no longer supported, we preserve
+// these methods to maintain backwards compatibility.
+
// Authenticate will perform an authentication of the provided username
// and password against the database.
//
@@ -82,214 +33,62 @@ var (
// combination is incorrect or unknown.
//
// If the SQLITE_USER table is not present in the database file, then
-// this interface is a harmless no-op returning SQLITE_OK.
-func (c *SQLiteConn) Authenticate(username, password string) error {
- rv := c.authenticate(username, password)
- switch rv {
- case C.SQLITE_ERROR, C.SQLITE_AUTH:
- return ErrUnauthorized
- case C.SQLITE_OK:
- return nil
- default:
- return c.lastError(int(rv))
- }
-}
-
-// authenticate provides the actual authentication to SQLite.
-// This is not exported for usage in Go.
-// It is however exported for usage within SQL by the user.
+// this interface is a harmless no-op returnning SQLITE_OK.
//
-// Returns:
+// Deprecated: The sqlite3 ext/userauth module is [deprecated].
//
-// C.SQLITE_OK (0)
-// C.SQLITE_ERROR (1)
-// C.SQLITE_AUTH (23)
-func (c *SQLiteConn) authenticate(username, password string) int {
- // Allocate C Variables
- cuser := C.CString(username)
- cpass := C.CString(password)
-
- // Free C Variables
- defer func() {
- C.free(unsafe.Pointer(cuser))
- C.free(unsafe.Pointer(cpass))
- }()
-
- return int(C._sqlite3_user_authenticate(c.db, cuser, cpass, C.int(len(password))))
+// [deprecated]: https://www.sqlite.org/src/artifact/ca7e9ee82ca4e1c
+func (c *SQLiteConn) Authenticate(username, password string) error {
+ return errUserAuthNoLongerSupported
}
// AuthUserAdd can be used (by an admin user only)
-// to create a new user. When called on a no-authentication-required
+// to create a new user. When called on a no-authentication-required
// database, this routine converts the database into an authentication-
// required database, automatically makes the added user an
// administrator, and logs in the current connection as that user.
// The AuthUserAdd only works for the "main" database, not
// for any ATTACH-ed databases. Any call to AuthUserAdd by a
// non-admin user results in an error.
-func (c *SQLiteConn) AuthUserAdd(username, password string, admin bool) error {
- isAdmin := 0
- if admin {
- isAdmin = 1
- }
-
- rv := c.authUserAdd(username, password, isAdmin)
- switch rv {
- case C.SQLITE_ERROR, C.SQLITE_AUTH:
- return ErrAdminRequired
- case C.SQLITE_OK:
- return nil
- default:
- return c.lastError(int(rv))
- }
-}
-
-// authUserAdd enables the User Authentication if not enabled.
-// Otherwise it will add a user.
//
-// When user authentication is already enabled then this function
-// can only be called by an admin.
+// Deprecated: The sqlite3 ext/userauth module is [deprecated].
//
-// This is not exported for usage in Go.
-// It is however exported for usage within SQL by the user.
-//
-// Returns:
-//
-// C.SQLITE_OK (0)
-// C.SQLITE_ERROR (1)
-// C.SQLITE_AUTH (23)
-func (c *SQLiteConn) authUserAdd(username, password string, admin int) int {
- // Allocate C Variables
- cuser := C.CString(username)
- cpass := C.CString(password)
-
- // Free C Variables
- defer func() {
- C.free(unsafe.Pointer(cuser))
- C.free(unsafe.Pointer(cpass))
- }()
-
- return int(C._sqlite3_user_add(c.db, cuser, cpass, C.int(len(password)), C.int(admin)))
+// [deprecated]: https://www.sqlite.org/src/artifact/ca7e9ee82ca4e1c
+func (c *SQLiteConn) AuthUserAdd(username, password string, admin bool) error {
+ return errUserAuthNoLongerSupported
}
// AuthUserChange can be used to change a users
// login credentials or admin privilege. Any user can change their own
-// login credentials. Only an admin user can change another users login
-// credentials or admin privilege setting. No user may change their own
+// login credentials. Only an admin user can change another users login
+// credentials or admin privilege setting. No user may change their own
// admin privilege setting.
-func (c *SQLiteConn) AuthUserChange(username, password string, admin bool) error {
- isAdmin := 0
- if admin {
- isAdmin = 1
- }
-
- rv := c.authUserChange(username, password, isAdmin)
- switch rv {
- case C.SQLITE_ERROR, C.SQLITE_AUTH:
- return ErrAdminRequired
- case C.SQLITE_OK:
- return nil
- default:
- return c.lastError(int(rv))
- }
-}
-
-// authUserChange allows to modify a user.
-// Users can change their own password.
-//
-// Only admins can change passwords for other users
-// and modify the admin flag.
-//
-// The admin flag of the current logged in user cannot be changed.
-// THis ensures that their is always an admin.
//
-// This is not exported for usage in Go.
-// It is however exported for usage within SQL by the user.
+// Deprecated: The sqlite3 ext/userauth module is [deprecated].
//
-// Returns:
-//
-// C.SQLITE_OK (0)
-// C.SQLITE_ERROR (1)
-// C.SQLITE_AUTH (23)
-func (c *SQLiteConn) authUserChange(username, password string, admin int) int {
- // Allocate C Variables
- cuser := C.CString(username)
- cpass := C.CString(password)
-
- // Free C Variables
- defer func() {
- C.free(unsafe.Pointer(cuser))
- C.free(unsafe.Pointer(cpass))
- }()
-
- return int(C._sqlite3_user_change(c.db, cuser, cpass, C.int(len(password)), C.int(admin)))
+// [deprecated]: https://www.sqlite.org/src/artifact/ca7e9ee82ca4e1c
+func (c *SQLiteConn) AuthUserChange(username, password string, admin bool) error {
+ return errUserAuthNoLongerSupported
}
// AuthUserDelete can be used (by an admin user only)
-// to delete a user. The currently logged-in user cannot be deleted,
+// to delete a user. The currently logged-in user cannot be deleted,
// which guarantees that there is always an admin user and hence that
// the database cannot be converted into a no-authentication-required
// database.
-func (c *SQLiteConn) AuthUserDelete(username string) error {
- rv := c.authUserDelete(username)
- switch rv {
- case C.SQLITE_ERROR, C.SQLITE_AUTH:
- return ErrAdminRequired
- case C.SQLITE_OK:
- return nil
- default:
- return c.lastError(int(rv))
- }
-}
-
-// authUserDelete can be used to delete a user.
//
-// This function can only be executed by an admin.
+// Deprecated: The sqlite3 ext/userauth module is [deprecated].
//
-// This is not exported for usage in Go.
-// It is however exported for usage within SQL by the user.
-//
-// Returns:
-//
-// C.SQLITE_OK (0)
-// C.SQLITE_ERROR (1)
-// C.SQLITE_AUTH (23)
-func (c *SQLiteConn) authUserDelete(username string) int {
- // Allocate C Variables
- cuser := C.CString(username)
-
- // Free C Variables
- defer func() {
- C.free(unsafe.Pointer(cuser))
- }()
-
- return int(C._sqlite3_user_delete(c.db, cuser))
+// [deprecated]: https://www.sqlite.org/src/artifact/ca7e9ee82ca4e1c
+func (c *SQLiteConn) AuthUserDelete(username string) error {
+ return errUserAuthNoLongerSupported
}
// AuthEnabled checks if the database is protected by user authentication
-func (c *SQLiteConn) AuthEnabled() (exists bool) {
- rv := c.authEnabled()
- if rv == 1 {
- exists = true
- }
-
- return
-}
-
-// authEnabled perform the actual check for user authentication.
//
-// This is not exported for usage in Go.
-// It is however exported for usage within SQL by the user.
+// Deprecated: The sqlite3 ext/userauth module is [deprecated].
//
-// Returns:
-//
-// 0 - Disabled
-// 1 - Enabled
-func (c *SQLiteConn) authEnabled() int {
- return int(C._sqlite3_auth_enabled(c.db))
-}
-
-func (c *SQLiteConn) registerAuthFunc(name string, impl any, pure bool) error {
- return c.RegisterFunc(name, impl, pure)
+// [deprecated]: https://www.sqlite.org/src/artifact/ca7e9ee82ca4e1c
+func (c *SQLiteConn) AuthEnabled() (exists bool) {
+ return false
}
-
-// EOF
diff --git a/sqlite3_opt_userauth_omit.go b/sqlite3_opt_userauth_omit.go
index 56b6140b..7a2e08ad 100644
--- a/sqlite3_opt_userauth_omit.go
+++ b/sqlite3_opt_userauth_omit.go
@@ -15,6 +15,9 @@ var (
ErrAdminRequired = errors.New("SQLITE_AUTH: Unauthorized; Admin Privileges Required")
)
+// NB: Even though userauth is no longer supported, we preserve
+// these methods to maintain backwards compatibility.
+
// Authenticate will perform an authentication of the provided username
// and password against the database.
//
@@ -28,23 +31,12 @@ var (
//
// If the SQLITE_USER table is not present in the database file, then
// this interface is a harmless no-op returnning SQLITE_OK.
-func (c *SQLiteConn) Authenticate(username, password string) error {
- // NOOP
- return nil
-}
-
-// authenticate provides the actual authentication to SQLite.
-// This is not exported for usage in Go.
-// It is however exported for usage within SQL by the user.
//
-// Returns:
+// Deprecated: The sqlite3 ext/userauth module is [deprecated].
//
-// C.SQLITE_OK (0)
-// C.SQLITE_ERROR (1)
-// C.SQLITE_AUTH (23)
-func (c *SQLiteConn) authenticate(username, password string) int {
- // NOOP
- return 0
+// [deprecated]: https://www.sqlite.org/src/artifact/ca7e9ee82ca4e1c
+func (c *SQLiteConn) Authenticate(username, password string) error {
+ return nil
}
// AuthUserAdd can be used (by an admin user only)
@@ -55,28 +47,12 @@ func (c *SQLiteConn) authenticate(username, password string) int {
// The AuthUserAdd only works for the "main" database, not
// for any ATTACH-ed databases. Any call to AuthUserAdd by a
// non-admin user results in an error.
-func (c *SQLiteConn) AuthUserAdd(username, password string, admin bool) error {
- // NOOP
- return nil
-}
-
-// authUserAdd enables the User Authentication if not enabled.
-// Otherwise it will add a user.
//
-// When user authentication is already enabled then this function
-// can only be called by an admin.
+// Deprecated: The sqlite3 ext/userauth module is [deprecated].
//
-// This is not exported for usage in Go.
-// It is however exported for usage within SQL by the user.
-//
-// Returns:
-//
-// C.SQLITE_OK (0)
-// C.SQLITE_ERROR (1)
-// C.SQLITE_AUTH (23)
-func (c *SQLiteConn) authUserAdd(username, password string, admin int) int {
- // NOOP
- return 0
+// [deprecated]: https://www.sqlite.org/src/artifact/ca7e9ee82ca4e1c
+func (c *SQLiteConn) AuthUserAdd(username, password string, admin bool) error {
+ return nil
}
// AuthUserChange can be used to change a users
@@ -84,31 +60,12 @@ func (c *SQLiteConn) authUserAdd(username, password string, admin int) int {
// login credentials. Only an admin user can change another users login
// credentials or admin privilege setting. No user may change their own
// admin privilege setting.
-func (c *SQLiteConn) AuthUserChange(username, password string, admin bool) error {
- // NOOP
- return nil
-}
-
-// authUserChange allows to modify a user.
-// Users can change their own password.
-//
-// Only admins can change passwords for other users
-// and modify the admin flag.
-//
-// The admin flag of the current logged in user cannot be changed.
-// THis ensures that their is always an admin.
//
-// This is not exported for usage in Go.
-// It is however exported for usage within SQL by the user.
+// Deprecated: The sqlite3 ext/userauth module is [deprecated].
//
-// Returns:
-//
-// C.SQLITE_OK (0)
-// C.SQLITE_ERROR (1)
-// C.SQLITE_AUTH (23)
-func (c *SQLiteConn) authUserChange(username, password string, admin int) int {
- // NOOP
- return 0
+// [deprecated]: https://www.sqlite.org/src/artifact/ca7e9ee82ca4e1c
+func (c *SQLiteConn) AuthUserChange(username, password string, admin bool) error {
+ return nil
}
// AuthUserDelete can be used (by an admin user only)
@@ -116,51 +73,19 @@ func (c *SQLiteConn) authUserChange(username, password string, admin int) int {
// which guarantees that there is always an admin user and hence that
// the database cannot be converted into a no-authentication-required
// database.
+//
+// Deprecated: The sqlite3 ext/userauth module is [deprecated].
+//
+// [deprecated]: https://www.sqlite.org/src/artifact/ca7e9ee82ca4e1c
func (c *SQLiteConn) AuthUserDelete(username string) error {
- // NOOP
return nil
}
-// authUserDelete can be used to delete a user.
-//
-// This function can only be executed by an admin.
-//
-// This is not exported for usage in Go.
-// It is however exported for usage within SQL by the user.
+// AuthEnabled checks if the database is protected by user authentication
//
-// Returns:
+// Deprecated: The sqlite3 ext/userauth module is [deprecated].
//
-// C.SQLITE_OK (0)
-// C.SQLITE_ERROR (1)
-// C.SQLITE_AUTH (23)
-func (c *SQLiteConn) authUserDelete(username string) int {
- // NOOP
- return 0
-}
-
-// AuthEnabled checks if the database is protected by user authentication
+// [deprecated]: https://www.sqlite.org/src/artifact/ca7e9ee82ca4e1c
func (c *SQLiteConn) AuthEnabled() (exists bool) {
- // NOOP
return false
}
-
-// authEnabled perform the actual check for user authentication.
-//
-// This is not exported for usage in Go.
-// It is however exported for usage within SQL by the user.
-//
-// Returns:
-//
-// 0 - Disabled
-// 1 - Enabled
-func (c *SQLiteConn) authEnabled() int {
- // NOOP
- return 0
-}
-
-func (c *SQLiteConn) registerAuthFunc(_ string, _ any, _ bool) error {
- // NOOP
- return nil
-}
-
-// EOF
diff --git a/sqlite3_opt_userauth_test.go b/sqlite3_opt_userauth_test.go
index 12e11510..48945f7f 100644
--- a/sqlite3_opt_userauth_test.go
+++ b/sqlite3_opt_userauth_test.go
@@ -10,27 +10,15 @@ package sqlite3
import (
"database/sql"
+ "errors"
"fmt"
"os"
"testing"
)
-var (
- conn *SQLiteConn
- create func(t *testing.T, username, password string) (file string, err error)
- createWithCrypt func(t *testing.T, username, password, crypt, salt string) (file string, err error)
- connect func(t *testing.T, f string, username, password string) (file string, db *sql.DB, c *SQLiteConn, err error)
- connectWithCrypt func(t *testing.T, f string, username, password string, crypt string, salt string) (file string, db *sql.DB, c *SQLiteConn, err error)
- authEnabled func(db *sql.DB) (exists bool, err error)
- addUser func(db *sql.DB, username, password string, admin int) (rv int, err error)
- userExists func(db *sql.DB, username string) (rv int, err error)
- isAdmin func(db *sql.DB, username string) (rv bool, err error)
- modifyUser func(db *sql.DB, username, password string, admin int) (rv int, err error)
- deleteUser func(db *sql.DB, username string) (rv int, err error)
-)
-
-func init() {
+func TestUserAuth(t *testing.T) {
// Create database connection
+ var conn *SQLiteConn
sql.Register("sqlite3_with_conn",
&SQLiteDriver{
ConnectHook: func(c *SQLiteConn) error {
@@ -39,21 +27,7 @@ func init() {
},
})
- create = func(t *testing.T, username, password string) (file string, err error) {
- var db *sql.DB
- file, db, _, err = connect(t, "", username, password)
- db.Close()
- return
- }
-
- createWithCrypt = func(t *testing.T, username, password, crypt, salt string) (file string, err error) {
- var db *sql.DB
- file, db, _, err = connectWithCrypt(t, "", "admin", "admin", crypt, salt)
- db.Close()
- return
- }
-
- connect = func(t *testing.T, f string, username, password string) (file string, db *sql.DB, c *SQLiteConn, err error) {
+ connect := func(t *testing.T, f string, username, password string) (file string, db *sql.DB, c *SQLiteConn, err error) {
conn = nil // Clear connection
file = f // Copy provided file (f) => file
if file == "" {
@@ -75,7 +49,7 @@ func init() {
}
// Dummy query to force connection and database creation
- // Will return ErrUnauthorized (SQLITE_AUTH) if user authentication fails
+ // Will return errUserAuthNoLongerSupported if user authentication fails
if _, err = db.Exec("SELECT 1;"); err != nil {
defer os.Remove(file)
defer db.Close()
@@ -86,559 +60,11 @@ func init() {
return
}
- connectWithCrypt = func(t *testing.T, f string, username, password string, crypt string, salt string) (file string, db *sql.DB, c *SQLiteConn, err error) {
- conn = nil // Clear connection
- file = f // Copy provided file (f) => file
- if file == "" {
- // Create dummy file
- file = TempFilename(t)
- }
-
- db, err = sql.Open("sqlite3_with_conn", "file:"+file+fmt.Sprintf("?_auth&_auth_user=%s&_auth_pass=%s&_auth_crypt=%s&_auth_salt=%s", username, password, crypt, salt))
- if err != nil {
- defer os.Remove(file)
- return file, nil, nil, err
- }
-
- // Dummy query to force connection and database creation
- // Will return ErrUnauthorized (SQLITE_AUTH) if user authentication fails
- if _, err = db.Exec("SELECT 1;"); err != nil {
- defer os.Remove(file)
- defer db.Close()
- return file, nil, nil, err
- }
- c = conn
-
- return
- }
-
- authEnabled = func(db *sql.DB) (exists bool, err error) {
- err = db.QueryRow("select count(type) from sqlite_master WHERE type='table' and name='sqlite_user';").Scan(&exists)
- return
- }
-
- addUser = func(db *sql.DB, username, password string, admin int) (rv int, err error) {
- err = db.QueryRow("select auth_user_add(?, ?, ?);", username, password, admin).Scan(&rv)
- return
- }
-
- userExists = func(db *sql.DB, username string) (rv int, err error) {
- err = db.QueryRow("select count(uname) from sqlite_user where uname=?", username).Scan(&rv)
- return
- }
-
- isAdmin = func(db *sql.DB, username string) (rv bool, err error) {
- err = db.QueryRow("select isAdmin from sqlite_user where uname=?", username).Scan(&rv)
- return
- }
-
- modifyUser = func(db *sql.DB, username, password string, admin int) (rv int, err error) {
- err = db.QueryRow("select auth_user_change(?, ?, ?);", username, password, admin).Scan(&rv)
- return
- }
-
- deleteUser = func(db *sql.DB, username string) (rv int, err error) {
- err = db.QueryRow("select auth_user_delete(?);", username).Scan(&rv)
- return
- }
-}
-
-func TestUserAuthCreateDatabase(t *testing.T) {
- f, db, c, err := connect(t, "", "admin", "admin")
- if err != nil && c == nil && db == nil {
- t.Fatal(err)
- }
- defer db.Close()
- defer os.Remove(f)
-
- enabled, err := authEnabled(db)
- if err != nil || !enabled {
- t.Fatalf("UserAuth not enabled: %s", err)
- }
-
- e, err := userExists(db, "admin")
- if err != nil {
- t.Fatal(err)
- }
- if e != 1 {
- t.Fatal("UserAuth: admin does not exists")
- }
- a, err := isAdmin(db, "admin")
- if err != nil {
- t.Fatal(err)
- }
- if !a {
- t.Fatal("UserAuth: User is not administrator")
- }
-}
-
-func TestUserAuthCreateDatabaseWithoutArgs(t *testing.T) {
- _, db, c, err := connect(t, "", "", "")
- if err == nil && c == nil && db == nil {
- t.Fatal("Should have failed due to missing _auth_* parameters")
- }
-
- _, db, c, err = connect(t, "", "", "admin")
- if err == nil && c == nil && db == nil {
- t.Fatal("Should have failed due to missing _auth_user parameter")
- }
-
- _, db, c, err = connect(t, "", "admin", "")
- if err == nil && c == nil && db == nil {
- t.Fatal("Should have failed due to missing _auth_pass parameter")
- }
-}
-
-func TestUserAuthLogin(t *testing.T) {
- f1, err := create(t, "admin", "admin")
- if err != nil {
- t.Fatal(err)
- }
- defer os.Remove(f1)
-
- f2, db2, c2, err := connect(t, f1, "admin", "admin")
- if err != nil {
- t.Fatal(err)
- }
- defer db2.Close()
- if f1 != f2 {
- t.Fatal("UserAuth: Database file mismatch")
- }
-
- // Test lower level authentication
- err = c2.Authenticate("admin", "admin")
- if err != nil {
- t.Fatalf("UserAuth: *SQLiteConn.Authenticate() Failed: %s", err)
- }
-
- // Test Login Failed
- _, _, _, err = connect(t, f1, "admin", "invalid")
+ _, _, _, err := connect(t, "", "admin", "admin")
if err == nil {
- t.Fatal("Login successful while expecting to fail")
- }
- if err != ErrUnauthorized {
- t.Fatal(err)
- }
- err = c2.Authenticate("admin", "invalid")
- if err == nil {
- t.Fatal("Login successful while expecting to fail")
- }
- if err != ErrUnauthorized {
- t.Fatal(err)
- }
-}
-
-func TestUserAuthAddAdmin(t *testing.T) {
- f, db, c, err := connect(t, "", "admin", "admin")
- if err != nil && c == nil && db == nil {
- t.Fatal(err)
- }
- defer db.Close()
- defer os.Remove(f)
-
- // Add Admin User through SQL call
- rv, err := addUser(db, "admin2", "admin2", 1)
- if err != nil {
- t.Fatal(err)
- }
- if rv != 0 {
- t.Fatal("Failed to add user")
- }
-
- // Check if user was created
- exists, err := userExists(db, "admin2")
- if err != nil {
- t.Fatal(err)
- }
- if exists != 1 {
- t.Fatal("UserAuth: 'admin2' does not exists")
- }
-
- // Check if user was created as an Administrator
- admin, err := isAdmin(db, "admin2")
- if err != nil {
- t.Fatal(err)
- }
- if !admin {
- t.Fatal("UserAuth: 'admin2' is not administrator")
- }
-
- // Test *SQLiteConn
- err = c.AuthUserAdd("admin3", "admin3", true)
- if err != nil {
- t.Fatal(err)
- }
-
- // Check if user was created
- exists, err = userExists(db, "admin2")
- if err != nil {
- t.Fatal(err)
- }
- if exists != 1 {
- t.Fatal("UserAuth: 'admin3' does not exists")
- }
-
- // Check if the user was created as an Administrator
- admin, err = isAdmin(db, "admin3")
- if err != nil {
- t.Fatal(err)
- }
- if !admin {
- t.Fatal("UserAuth: 'admin3' is not administrator")
- }
-}
-
-func TestUserAuthAddUser(t *testing.T) {
- f1, db1, c, err := connect(t, "", "admin", "admin")
- if err != nil && c == nil && db == nil {
- t.Fatal(err)
- }
- defer os.Remove(f1)
-
- // Add user through SQL call
- rv, err := addUser(db1, "user", "user", 0)
- if err != nil {
- t.Fatal(err)
- }
- if rv != 0 {
- t.Fatal("Failed to add user")
- }
-
- // Check if user was created
- exists, err := userExists(db1, "user")
- if err != nil {
- t.Fatal(err)
- }
- if exists != 1 {
- t.Fatal("UserAuth: 'user' does not exists")
- }
-
- // Check if user was created as an Administrator
- admin, err := isAdmin(db1, "user")
- if err != nil {
- t.Fatal(err)
- }
- if admin {
- t.Fatal("UserAuth: 'user' is administrator")
- }
-
- // Test *SQLiteConn
- err = c.AuthUserAdd("user2", "user2", false)
- if err != nil {
- t.Fatal(err)
- }
-
- // Check if user was created
- exists, err = userExists(db1, "user2")
- if err != nil {
- t.Fatal(err)
- }
- if exists != 1 {
- t.Fatal("UserAuth: 'user2' does not exists")
- }
-
- // Check if the user was created as an Administrator
- admin, err = isAdmin(db1, "user2")
- if err != nil {
- t.Fatal(err)
- }
- if admin {
- t.Fatal("UserAuth: 'user2' is administrator")
- }
-
- // Reconnect as normal user
- db1.Close()
- _, db2, c2, err := connect(t, f1, "user", "user")
- if err != nil {
- t.Fatal(err)
- }
- defer db2.Close()
-
- // Try to create admin user while logged in as normal user
- rv, err = addUser(db2, "admin2", "admin2", 1)
- if err != nil {
- t.Fatal(err)
- }
- if rv != SQLITE_AUTH {
- t.Fatal("Created admin user while not allowed")
- }
-
- err = c2.AuthUserAdd("admin3", "admin3", true)
- if err != ErrAdminRequired {
- t.Fatal("Created admin user while not allowed")
- }
-
- // Try to create normal user while logged in as normal user
- rv, err = addUser(db2, "user3", "user3", 0)
- if err != nil {
- t.Fatal(err)
- }
- if rv != SQLITE_AUTH {
- t.Fatal("Created user while not allowed")
- }
-
- err = c2.AuthUserAdd("user4", "user4", false)
- if err != ErrAdminRequired {
- t.Fatal("Created user while not allowed")
- }
-}
-
-func TestUserAuthModifyUser(t *testing.T) {
- f1, db1, c1, err := connect(t, "", "admin", "admin")
- if err != nil && c1 == nil && db == nil {
- t.Fatal(err)
- }
- defer os.Remove(f1)
-
- // Modify Password for current logged in admin
- // through SQL
- rv, err := modifyUser(db1, "admin", "admin2", 1)
- if err != nil {
- t.Fatal(err)
- }
- if rv != 0 {
- t.Fatal("Failed to modify password for admin")
- }
-
- // Modify password for current logged in admin
- // through *SQLiteConn
- err = c1.AuthUserChange("admin", "admin3", true)
- if err != nil {
- t.Fatal(err)
- }
-
- // Modify Administrator Flag
- // Because we are current logged in as 'admin'
- // Changing our own admin flag should fail.
- rv, err = modifyUser(db1, "admin", "admin3", 0)
- if err != nil {
- t.Fatal(err)
- }
- if rv != SQLITE_AUTH {
- t.Fatal("Successfully changed admin flag while not allowed")
- }
-
- // Modify admin flag through (*SQLiteConn)
- // Because we are current logged in as 'admin'
- // Changing our own admin flag should fail.
- err = c1.AuthUserChange("admin", "admin3", false)
- if err != ErrAdminRequired {
- t.Fatal("Successfully changed admin flag while not allowed")
- }
-
- // Add normal user
- rv, err = addUser(db1, "user", "password", 0)
- if err != nil {
- t.Fatal(err)
- }
- if rv != 0 {
- t.Fatal("Failed to add user")
- }
-
- rv, err = addUser(db1, "user2", "user2", 0)
- if err != nil {
- t.Fatal(err)
- }
- if rv != 0 {
- t.Fatal("Failed to add user")
- }
-
- // Modify other user password and flag through SQL
- rv, err = modifyUser(db1, "user", "pass", 1)
- if err != nil {
- t.Fatal(err)
- }
- if rv != 0 {
- t.Fatal("Failed to modify password for user")
- }
-
- // Modify other user password and flag through *SQLiteConn
- err = c1.AuthUserChange("user", "newpass", false)
- if err != nil {
- t.Fatal(err)
- }
-
- // Disconnect database for reconnect
- db1.Close()
- _, db2, c2, err := connect(t, f1, "user", "newpass")
- if err != nil {
- t.Fatal(err)
- }
- defer db2.Close()
-
- // Modify other user password through SQL
- rv, err = modifyUser(db2, "user2", "newpass", 0)
- if err != nil {
- t.Fatal(err)
- }
- if rv != SQLITE_AUTH {
- t.Fatal("Password change successful while not allowed")
- }
-
- // Modify other user password and flag through *SQLiteConn
- err = c2.AuthUserChange("user2", "invalid", false)
- if err != ErrAdminRequired {
- t.Fatal("Password change successful while not allowed")
- }
-}
-
-func TestUserAuthDeleteUser(t *testing.T) {
- f1, db1, c, err := connect(t, "", "admin", "admin")
- if err != nil && c == nil && db == nil {
- t.Fatal(err)
- }
- defer os.Remove(f1)
-
- // Add Admin User 2
- rv, err := addUser(db1, "admin2", "admin2", 1)
- if err != nil {
- t.Fatal(err)
- }
- if rv != 0 {
- t.Fatal("Failed to add user")
- }
-
- rv, err = addUser(db1, "admin3", "admin3", 1)
- if err != nil {
- t.Fatal(err)
- }
- if rv != 0 {
- t.Fatal("Failed to add user")
- }
-
- // Check if user was created
- exists, err := userExists(db1, "admin2")
- if err != nil {
- t.Fatal(err)
- }
- if exists != 1 {
- t.Fatal("UserAuth: 'admin2' does not exists")
- }
-
- exists, err = userExists(db1, "admin3")
- if err != nil {
- t.Fatal(err)
- }
- if exists != 1 {
- t.Fatal("UserAuth: 'admin2' does not exists")
- }
-
- // Delete user through SQL
- rv, err = deleteUser(db1, "admin2")
- if err != nil {
- t.Fatal(err)
- }
- if rv != 0 {
- t.Fatal("Failed to delete admin2")
- }
-
- // Verify user admin2 deleted
- exists, err = userExists(db1, "admin2")
- if err != nil {
- t.Fatal(err)
- }
- if exists != 0 {
- t.Fatal("UserAuth: 'admin2' still exists")
- }
-
- // Delete user through *SQLiteConn
- rv, err = deleteUser(db1, "admin3")
- if err != nil {
- t.Fatal(err)
- }
- if rv != 0 {
- t.Fatal("Failed to delete admin3")
- }
-
- // Verify user admin3 deleted
- exists, err = userExists(db1, "admin3")
- if err != nil {
- t.Fatal(err)
- }
- if exists != 0 {
- t.Fatal("UserAuth: 'admin3' still exists")
- }
-
- // Add normal user for reconnect and privileges check
- rv, err = addUser(db1, "reconnect", "reconnect", 0)
- if err != nil {
- t.Fatal(err)
- }
- if rv != 0 {
- t.Fatal("Failed to add user")
- }
-
- // Add normal user for deletion through SQL
- rv, err = addUser(db1, "user", "user", 0)
- if err != nil {
- t.Fatal(err)
- }
- if rv != 0 {
- t.Fatal("Failed to add user")
- }
-
- rv, err = addUser(db1, "user2", "user2", 0)
- if err != nil {
- t.Fatal(err)
- }
- if rv != 0 {
- t.Fatal("Failed to add user")
- }
-
- // Close database for reconnect
- db1.Close()
-
- // Reconnect as normal user
- _, db2, c2, err := connect(t, f1, "reconnect", "reconnect")
- if err != nil {
- t.Fatal(err)
+ t.Fatalf("UserAuth not enabled: %s", err)
}
- defer db2.Close()
-
- // Delete user while logged in as normal user
- // through SQL
- rv, err = deleteUser(db2, "user")
- if err != nil {
+ if !errors.Is(err, errUserAuthNoLongerSupported) {
t.Fatal(err)
}
- if rv != SQLITE_AUTH {
- t.Fatal("Successfully deleted user wthout proper privileges")
- }
-
- // Delete user while logged in as normal user
- // through *SQLiteConn
- err = c2.AuthUserDelete("user2")
- if err != ErrAdminRequired {
- t.Fatal("Successfully deleted user wthout proper privileges")
- }
-}
-
-func TestUserAuthEncoders(t *testing.T) {
- cases := map[string]string{
- "sha1": "",
- "ssha1": "salted",
- "sha256": "",
- "ssha256": "salted",
- "sha384": "",
- "ssha384": "salted",
- "sha512": "",
- "ssha512": "salted",
- }
-
- for enc, salt := range cases {
- f, err := createWithCrypt(t, "admin", "admin", enc, salt)
- if err != nil {
- t.Fatal(err)
- }
- defer os.Remove(f)
-
- _, db, _, err := connectWithCrypt(t, f, "admin", "admin", enc, salt)
- if err != nil {
- t.Fatal(err)
- }
- defer db.Close()
- if e, err := authEnabled(db); err != nil && !e {
- t.Fatalf("UserAuth (%s) not enabled %s", enc, err)
- }
- }
}
diff --git a/sqlite3_test.go b/sqlite3_test.go
index 6684aefd..b40eb948 100644
--- a/sqlite3_test.go
+++ b/sqlite3_test.go
@@ -252,39 +252,37 @@ func TestForeignKeys(t *testing.T) {
func TestDeferredForeignKey(t *testing.T) {
fname := TempFilename(t)
+ defer os.Remove(fname)
uri := "file:" + fname + "?_foreign_keys=1"
db, err := sql.Open("sqlite3", uri)
if err != nil {
- os.Remove(fname)
- t.Errorf("sql.Open(\"sqlite3\", %q): %v", uri, err)
+ t.Fatalf("sql.Open(\"sqlite3\", %q): %v", uri, err)
}
+ defer db.Close()
_, err = db.Exec("CREATE TABLE bar (id INTEGER PRIMARY KEY)")
if err != nil {
- t.Errorf("failed creating tables: %v", err)
+ t.Fatalf("failed creating tables: %v", err)
}
_, err = db.Exec("CREATE TABLE foo (bar_id INTEGER, FOREIGN KEY(bar_id) REFERENCES bar(id) DEFERRABLE INITIALLY DEFERRED)")
if err != nil {
- t.Errorf("failed creating tables: %v", err)
+ t.Fatalf("failed creating tables: %v", err)
}
tx, err := db.Begin()
if err != nil {
- t.Errorf("Failed to begin transaction: %v", err)
+ t.Fatalf("Failed to begin transaction: %v", err)
}
_, err = tx.Exec("INSERT INTO foo (bar_id) VALUES (123)")
if err != nil {
- t.Errorf("Failed to insert row: %v", err)
+ t.Fatalf("Failed to insert row: %v", err)
}
err = tx.Commit()
if err == nil {
- t.Errorf("Expected an error: %v", err)
+ t.Fatalf("Expected an error: %v", err)
}
_, err = db.Begin()
if err != nil {
- t.Errorf("Failed to begin transaction: %v", err)
+ t.Fatalf("Failed to begin transaction: %v", err)
}
-
- db.Close()
- os.Remove(fname)
}
func TestRecursiveTriggers(t *testing.T) {
@@ -1226,7 +1224,7 @@ func TestQueryer(t *testing.T) {
select id from foo order by id;
`)
if err != nil {
- t.Error("Failed to call db.Query:", err)
+ t.Fatal("Failed to call db.Query:", err)
}
defer rows.Close()
n := 0
@@ -1427,7 +1425,7 @@ func TestStress(t *testing.T) {
for j := 0; j < 3; j++ {
rows, err := db.Query("select * from foo where id=1;")
if err != nil {
- t.Error("Failed to call db.Query:", err)
+ t.Fatal("Failed to call db.Query:", err)
}
for rows.Next() {
var i int