Add SQLCipher _key DSN support
Some checks failed
Go / Test (1.24, macos-latest) (push) Has been cancelled
Go / Test (1.24, ubuntu-latest) (push) Has been cancelled
Go / Test (1.25, macos-latest) (push) Has been cancelled
Go / Test (1.25, ubuntu-latest) (push) Has been cancelled
Go / Test (1.26, macos-latest) (push) Has been cancelled
Go / Test (1.26, ubuntu-latest) (push) Has been cancelled
Go / Test for Windows (1.24) (push) Has been cancelled
Go / Test for Windows (1.25) (push) Has been cancelled
Go / Test for Windows (1.26) (push) Has been cancelled
dockerfile / Run Dockerfiles in examples (push) Has been cancelled
Some checks failed
Go / Test (1.24, macos-latest) (push) Has been cancelled
Go / Test (1.24, ubuntu-latest) (push) Has been cancelled
Go / Test (1.25, macos-latest) (push) Has been cancelled
Go / Test (1.25, ubuntu-latest) (push) Has been cancelled
Go / Test (1.26, macos-latest) (push) Has been cancelled
Go / Test (1.26, ubuntu-latest) (push) Has been cancelled
Go / Test for Windows (1.24) (push) Has been cancelled
Go / Test for Windows (1.25) (push) Has been cancelled
Go / Test for Windows (1.26) (push) Has been cancelled
dockerfile / Run Dockerfiles in examples (push) Has been cancelled
This commit is contained in:
46
sqlite3.go
46
sqlite3.go
@@ -946,6 +946,28 @@ func lastError(db *C.sqlite3) error {
|
||||
}
|
||||
}
|
||||
|
||||
func sqlCipherKeyPragma(key string) (string, error) {
|
||||
if strings.IndexByte(key, 0) >= 0 {
|
||||
return "", errors.New("Invalid _key: contains NUL")
|
||||
}
|
||||
if isSQLCipherRawKey(key) {
|
||||
return "PRAGMA key = \"" + key + "\";", nil
|
||||
}
|
||||
return "PRAGMA key = '" + strings.ReplaceAll(key, "'", "''") + "';", nil
|
||||
}
|
||||
|
||||
func isSQLCipherRawKey(key string) bool {
|
||||
if len(key) != 67 || (key[0] != 'x' && key[0] != 'X') || key[1] != '\'' || key[66] != '\'' {
|
||||
return false
|
||||
}
|
||||
for _, c := range key[2:66] {
|
||||
if !(c >= '0' && c <= '9') && !(c >= 'a' && c <= 'f') && !(c >= 'A' && c <= 'F') {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// Exec implements Execer.
|
||||
func (c *SQLiteConn) Exec(query string, args []driver.Value) (driver.Result, error) {
|
||||
return c.exec(context.Background(), query, valueToNamedValue(args))
|
||||
@@ -1137,6 +1159,11 @@ func (c *SQLiteConn) begin(ctx context.Context) (driver.Tx, error) {
|
||||
// _busy_timeout=XXX"| _timeout=XXX
|
||||
// Specify value for sqlite3_busy_timeout.
|
||||
//
|
||||
// _key=KEY
|
||||
// Set the SQLCipher key before any driver initialization PRAGMA. KEY is a
|
||||
// passphrase or a raw key expression of the form x'<64 hexadecimal digits>'.
|
||||
// Requires a SQLCipher library linked with the libsqlite3 build tag.
|
||||
//
|
||||
// _case_sensitive_like=Boolean | _cslike=Boolean
|
||||
// https://www.sqlite.org/pragma.html#pragma_case_sensitive_like
|
||||
// Default or disabled the LIKE operation is case-insensitive.
|
||||
@@ -1213,6 +1240,7 @@ func (d *SQLiteDriver) Open(dsn string) (driver.Conn, error) {
|
||||
vfsName := ""
|
||||
var cacheSize *int64
|
||||
stmtCacheSize := 0
|
||||
keyPragma := ""
|
||||
|
||||
pos := strings.IndexRune(dsn, '?')
|
||||
if pos >= 1 {
|
||||
@@ -1222,6 +1250,14 @@ func (d *SQLiteDriver) Open(dsn string) (driver.Conn, error) {
|
||||
}
|
||||
|
||||
// Authentication
|
||||
if _, ok := params["_key"]; ok {
|
||||
var err error
|
||||
keyPragma, err = sqlCipherKeyPragma(params.Get("_key"))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
if _, ok := params["_auth"]; ok {
|
||||
authCreate = true
|
||||
}
|
||||
@@ -1594,6 +1630,16 @@ func (d *SQLiteDriver) Open(dsn string) (driver.Conn, error) {
|
||||
if db == nil {
|
||||
return nil, errors.New("sqlite succeeded without returning a database")
|
||||
}
|
||||
if keyPragma != "" {
|
||||
cs := C.CString(keyPragma)
|
||||
rv := C.sqlite3_exec(db, cs, nil, nil, nil)
|
||||
C.free(unsafe.Pointer(cs))
|
||||
if rv != C.SQLITE_OK {
|
||||
err := lastError(db)
|
||||
C.sqlite3_close_v2(db)
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
// Create connection to SQLite
|
||||
conn := &SQLiteConn{db: db, loc: loc, txlock: txlock}
|
||||
|
||||
Reference in New Issue
Block a user