Files

733 lines
29 KiB
Swift

#if SQLITE_HAS_CODEC
import XCTest
import GRDB
class EncryptionTests: GRDBTestCase {
func testDatabaseQueueWithPassphraseToDatabaseQueueWithPassphrase() throws {
do {
var config = Configuration()
config.prepareDatabase { db in
try db.usePassphrase("secret")
}
let dbQueue = try makeDatabaseQueue(filename: "test.sqlite", configuration: config)
try dbQueue.inDatabase { db in
try db.execute(sql: "CREATE TABLE data (value INTEGER)")
try db.execute(sql: "INSERT INTO data (value) VALUES (1)")
}
}
do {
var config = Configuration()
config.prepareDatabase { db in
try db.usePassphrase("secret")
}
let dbQueue = try makeDatabaseQueue(filename: "test.sqlite", configuration: config)
try dbQueue.inDatabase { db in
XCTAssertEqual(try Int.fetchOne(db, sql: "SELECT COUNT(*) FROM data")!, 1)
}
}
}
func testDatabaseConfigWithEmptyPassphrase() throws {
do {
var config = Configuration()
config.prepareDatabase { db in
XCTAssertThrowsError(try db.usePassphrase(""))
}
let dbQueue = try makeDatabaseQueue(filename: "test.sqlite", configuration: config)
try dbQueue.inDatabase { db in
try db.execute(sql: "CREATE TABLE data (value INTEGER)")
try db.execute(sql: "INSERT INTO data (value) VALUES (1)")
}
}
}
func testDatabaseConfigWithEmptyDataPassphrase() throws {
do {
var config = Configuration()
config.prepareDatabase { db in
XCTAssertThrowsError(try db.usePassphrase(Data()))
}
let dbQueue = try makeDatabaseQueue(filename: "test.sqlite", configuration: config)
try dbQueue.inDatabase { db in
try db.execute(sql: "CREATE TABLE data (value INTEGER)")
try db.execute(sql: "INSERT INTO data (value) VALUES (1)")
}
}
}
func testDatabaseQueueWithDataPassphraseToDatabaseQueueWithDataPassphrase() throws {
let secretData = "Secret".data(using: .utf8)!
do {
var config = Configuration()
config.prepareDatabase { db in
try db.usePassphrase(secretData)
}
let dbQueue = try makeDatabaseQueue(filename: "test.sqlite", configuration: config)
try dbQueue.inDatabase { db in
try db.execute(sql: "CREATE TABLE data (value INTEGER)")
try db.execute(sql: "INSERT INTO data (value) VALUES (1)")
}
}
do {
var config = Configuration()
config.prepareDatabase { db in
try db.usePassphrase(secretData)
}
let dbQueue = try makeDatabaseQueue(filename: "test.sqlite", configuration: config)
try dbQueue.inDatabase { db in
XCTAssertEqual(try Int.fetchOne(db, sql: "SELECT COUNT(*) FROM data")!, 1)
}
}
}
func testDatabaseQueueWithPassphraseToDatabaseQueueWithoutPassphrase() throws {
do {
var config = Configuration()
config.prepareDatabase { db in
try db.usePassphrase("secret")
}
let dbQueue = try makeDatabaseQueue(filename: "test.sqlite", configuration: config)
try dbQueue.inDatabase { db in
try db.execute(sql: "CREATE TABLE data (value INTEGER)")
try db.execute(sql: "INSERT INTO data (value) VALUES (1)")
}
}
do {
do {
_ = try makeDatabaseQueue(filename: "test.sqlite", configuration: Configuration())
XCTFail("Expected error")
} catch let error as DatabaseError {
XCTAssertEqual(error.resultCode, .SQLITE_NOTADB)
XCTAssertEqual(error.message!, "file is not a database")
}
}
}
func testDatabaseQueueWithPassphraseToDatabaseQueueWithWrongPassphrase() throws {
do {
var config = Configuration()
config.prepareDatabase { db in
try db.usePassphrase("secret")
}
let dbQueue = try makeDatabaseQueue(filename: "test.sqlite", configuration: config)
try dbQueue.inDatabase { db in
try db.execute(sql: "CREATE TABLE data (value INTEGER)")
try db.execute(sql: "INSERT INTO data (value) VALUES (1)")
}
}
do {
var config = Configuration()
config.prepareDatabase { db in
try db.usePassphrase("wrong")
}
do {
_ = try makeDatabaseQueue(filename: "test.sqlite", configuration: config)
XCTFail("Expected error")
} catch let error as DatabaseError {
XCTAssertEqual(error.resultCode, .SQLITE_NOTADB)
XCTAssertEqual(error.message!, "file is not a database")
}
}
}
func testDatabaseQueueWithPassphraseToDatabaseQueueWithNewPassphrase() throws {
do {
var config = Configuration()
config.prepareDatabase { db in
try db.usePassphrase("secret")
}
let dbQueue = try makeDatabaseQueue(filename: "test.sqlite", configuration: config)
try dbQueue.inDatabase { db in
try db.execute(sql: "CREATE TABLE data (value INTEGER)")
try db.execute(sql: "INSERT INTO data (value) VALUES (1)")
}
}
do {
var config = Configuration()
config.prepareDatabase { db in
try db.usePassphrase("secret")
}
let dbQueue = try makeDatabaseQueue(filename: "test.sqlite", configuration: config)
try dbQueue.inDatabase { db in
XCTAssertEqual(try Int.fetchOne(db, sql: "SELECT COUNT(*) FROM data")!, 1)
}
try dbQueue.write { db in
try db.changePassphrase("newSecret")
}
try dbQueue.inDatabase { db in
try db.execute(sql: "INSERT INTO data (value) VALUES (2)")
}
try dbQueue.inDatabase { db in
XCTAssertEqual(try Int.fetchOne(db, sql: "SELECT COUNT(*) FROM data")!, 2)
}
}
do {
var config = Configuration()
config.prepareDatabase { db in
try db.usePassphrase("newSecret")
}
let dbQueue = try makeDatabaseQueue(filename: "test.sqlite", configuration: config)
try dbQueue.inDatabase { db in
XCTAssertEqual(try Int.fetchOne(db, sql: "SELECT COUNT(*) FROM data")!, 2)
}
}
}
func testDatabaseQueueWithDataPassphraseToDatabaseQueueWithNewDataPassphrase() throws {
let initialPassphrase = "Secret".data(using: .utf8)!
let finalPassphrase = "MoreSecret".data(using: .utf8)!
do {
var config = Configuration()
config.prepareDatabase { db in
try db.usePassphrase(initialPassphrase)
}
let dbQueue = try makeDatabaseQueue(filename: "test.sqlite", configuration: config)
try dbQueue.inDatabase { db in
try db.execute(sql: "CREATE TABLE data (value INTEGER)")
try db.execute(sql: "INSERT INTO data (value) VALUES (1)")
}
}
do {
var config = Configuration()
config.prepareDatabase { db in
try db.usePassphrase(initialPassphrase)
}
let dbQueue = try makeDatabaseQueue(filename: "test.sqlite", configuration: config)
try dbQueue.inDatabase { db in
XCTAssertEqual(try Int.fetchOne(db, sql: "SELECT COUNT(*) FROM data")!, 1)
}
try dbQueue.write { db in
try db.changePassphrase(finalPassphrase)
}
try dbQueue.inDatabase { db in
try db.execute(sql: "INSERT INTO data (value) VALUES (2)")
}
try dbQueue.inDatabase { db in
XCTAssertEqual(try Int.fetchOne(db, sql: "SELECT COUNT(*) FROM data")!, 2)
}
}
do {
var config = Configuration()
config.prepareDatabase { db in
try db.usePassphrase(finalPassphrase)
}
let dbQueue = try makeDatabaseQueue(filename: "test.sqlite", configuration: config)
try dbQueue.inDatabase { db in
XCTAssertEqual(try Int.fetchOne(db, sql: "SELECT COUNT(*) FROM data")!, 2)
}
}
}
func testDatabaseQueueWithPassphraseToDatabasePoolWithPassphrase() throws {
do {
var config = Configuration()
config.prepareDatabase { db in
try db.usePassphrase("secret")
}
let dbQueue = try makeDatabaseQueue(filename: "test.sqlite", configuration: config)
try dbQueue.inDatabase { db in
try db.execute(sql: "CREATE TABLE data (value INTEGER)")
try db.execute(sql: "INSERT INTO data (value) VALUES (1)")
}
}
do {
var config = Configuration()
config.prepareDatabase { db in
try db.usePassphrase("secret")
}
let dbPool = try makeDatabasePool(filename: "test.sqlite", configuration: config)
try dbPool.read { db in
XCTAssertEqual(try Int.fetchOne(db, sql: "SELECT COUNT(*) FROM data")!, 1)
}
}
}
func testDatabaseQueueWithPassphraseToDatabasePoolWithoutPassphrase() throws {
do {
var config = Configuration()
config.prepareDatabase { db in
try db.usePassphrase("secret")
}
let dbQueue = try makeDatabaseQueue(filename: "test.sqlite", configuration: config)
try dbQueue.inDatabase { db in
try db.execute(sql: "CREATE TABLE data (value INTEGER)")
try db.execute(sql: "INSERT INTO data (value) VALUES (1)")
}
}
do {
do {
_ = try makeDatabasePool(filename: "test.sqlite", configuration: Configuration())
XCTFail("Expected error")
} catch let error as DatabaseError {
XCTAssertEqual(error.resultCode, .SQLITE_NOTADB)
XCTAssertEqual(error.message!, "file is not a database")
}
}
}
func testDatabaseQueueWithPassphraseToDatabasePoolWithWrongPassphrase() throws {
do {
var config = Configuration()
config.prepareDatabase { db in
try db.usePassphrase("secret")
}
let dbQueue = try makeDatabaseQueue(filename: "test.sqlite", configuration: config)
try dbQueue.inDatabase { db in
try db.execute(sql: "CREATE TABLE data (value INTEGER)")
try db.execute(sql: "INSERT INTO data (value) VALUES (1)")
}
}
do {
var config = Configuration()
config.prepareDatabase { db in
try db.usePassphrase("wrong")
}
do {
_ = try makeDatabasePool(filename: "test.sqlite", configuration: config)
XCTFail("Expected error")
} catch let error as DatabaseError {
XCTAssertEqual(error.resultCode, .SQLITE_NOTADB)
XCTAssertEqual(error.message!, "file is not a database")
}
}
}
func testDatabaseQueueWithPassphraseToDatabasePoolWithNewPassphrase() throws {
do {
var config = Configuration()
config.prepareDatabase { db in
try db.usePassphrase("secret")
}
let dbQueue = try makeDatabaseQueue(filename: "test.sqlite", configuration: config)
try dbQueue.inDatabase { db in
try db.execute(sql: "CREATE TABLE data (value INTEGER)")
try db.execute(sql: "INSERT INTO data (value) VALUES (1)")
}
}
do {
var passphrase = "secret"
var config = Configuration()
config.prepareDatabase { db in
try db.usePassphrase(passphrase)
}
let dbPool = try makeDatabasePool(filename: "test.sqlite", configuration: config)
try dbPool.read { db in
XCTAssertEqual(try Int.fetchOne(db, sql: "SELECT COUNT(*) FROM data")!, 1)
}
try dbPool.barrierWriteWithoutTransaction { db in
passphrase = "newSecret"
try db.changePassphrase(passphrase)
dbPool.invalidateReadOnlyConnections()
}
try dbPool.write { db in
try db.execute(sql: "INSERT INTO data (value) VALUES (2)")
XCTAssertEqual(try Int.fetchOne(db, sql: "SELECT COUNT(*) FROM data")!, 2)
}
try dbPool.read { db in
XCTAssertEqual(try Int.fetchOne(db, sql: "SELECT COUNT(*) FROM data")!, 2)
}
}
do {
var config = Configuration()
config.prepareDatabase { db in
try db.usePassphrase("newSecret")
}
let dbPool = try makeDatabasePool(filename: "test.sqlite", configuration: config)
try dbPool.read { db in
XCTAssertEqual(try Int.fetchOne(db, sql: "SELECT COUNT(*) FROM data")!, 2)
}
}
}
func testDatabasePoolWithPassphraseToDatabasePoolWithPassphrase() throws {
do {
var config = Configuration()
config.prepareDatabase { db in
try db.usePassphrase("secret")
}
let dbPool = try makeDatabasePool(filename: "test.sqlite", configuration: config)
try dbPool.write { db in
try db.execute(sql: "CREATE TABLE data (value INTEGER)")
try db.execute(sql: "INSERT INTO data (value) VALUES (1)")
}
}
do {
var config = Configuration()
config.prepareDatabase { db in
try db.usePassphrase("secret")
}
let dbPool = try makeDatabasePool(filename: "test.sqlite", configuration: config)
try dbPool.read { db in
XCTAssertEqual(try Int.fetchOne(db, sql: "SELECT COUNT(*) FROM data")!, 1)
}
}
}
func testDatabasePoolWithPassphraseToDatabasePoolWithoutPassphrase() throws {
do {
var config = Configuration()
config.prepareDatabase { db in
try db.usePassphrase("secret")
}
let dbPool = try makeDatabasePool(filename: "test.sqlite", configuration: config)
try dbPool.write { db in
try db.execute(sql: "CREATE TABLE data (value INTEGER)")
try db.execute(sql: "INSERT INTO data (value) VALUES (1)")
}
}
do {
do {
_ = try makeDatabasePool(filename: "test.sqlite", configuration: Configuration())
XCTFail("Expected error")
} catch let error as DatabaseError {
XCTAssertEqual(error.resultCode, .SQLITE_NOTADB)
XCTAssertEqual(error.message!, "file is not a database")
}
}
}
func testDatabasePoolWithPassphraseToDatabasePoolWithWrongPassphrase() throws {
do {
var config = Configuration()
config.prepareDatabase { db in
try db.usePassphrase("secret")
}
let dbPool = try makeDatabasePool(filename: "test.sqlite", configuration: config)
try dbPool.write { db in
try db.execute(sql: "CREATE TABLE data (value INTEGER)")
try db.execute(sql: "INSERT INTO data (value) VALUES (1)")
}
}
do {
var config = Configuration()
config.prepareDatabase { db in
try db.usePassphrase("wrong")
}
do {
_ = try makeDatabasePool(filename: "test.sqlite", configuration: config)
XCTFail("Expected error")
} catch let error as DatabaseError {
XCTAssertEqual(error.resultCode, .SQLITE_NOTADB)
XCTAssertEqual(error.message!, "file is not a database")
}
}
}
func testDatabasePoolWithPassphraseToDatabasePoolWithNewPassphrase() throws {
do {
var config = Configuration()
config.prepareDatabase { db in
try db.usePassphrase("secret")
}
let dbPool = try makeDatabasePool(filename: "test.sqlite", configuration: config)
try dbPool.write { db in
try db.execute(sql: "CREATE TABLE data (value INTEGER)")
try db.execute(sql: "INSERT INTO data (value) VALUES (1)")
}
}
do {
var passphrase = "secret"
var config = Configuration()
config.prepareDatabase { db in
try db.usePassphrase(passphrase)
}
let dbPool = try makeDatabasePool(filename: "test.sqlite", configuration: config)
try dbPool.read { db in
XCTAssertEqual(try Int.fetchOne(db, sql: "SELECT COUNT(*) FROM data")!, 1)
}
try dbPool.barrierWriteWithoutTransaction { db in
passphrase = "newSecret"
try db.changePassphrase(passphrase)
dbPool.invalidateReadOnlyConnections()
}
try dbPool.write { db in
try db.execute(sql: "INSERT INTO data (value) VALUES (2)")
XCTAssertEqual(try Int.fetchOne(db, sql: "SELECT COUNT(*) FROM data")!, 2)
}
try dbPool.read { db in
XCTAssertEqual(try Int.fetchOne(db, sql: "SELECT COUNT(*) FROM data")!, 2)
}
}
do {
var config = Configuration()
config.prepareDatabase { db in
try db.usePassphrase("newSecret")
}
let dbPool = try makeDatabasePool(filename: "test.sqlite", configuration: config)
try dbPool.read { db in
XCTAssertEqual(try Int.fetchOne(db, sql: "SELECT COUNT(*) FROM data")!, 2)
}
}
}
func testDatabaseQueueWithPragmaPassphraseToDatabaseQueueWithPassphrase() throws {
do {
let dbQueue = try makeDatabaseQueue(filename: "test.sqlite", configuration: Configuration())
try dbQueue.inDatabase { db in
try db.execute(sql: "PRAGMA key = 'secret'")
try db.execute(sql: "CREATE TABLE data (value INTEGER)")
try db.execute(sql: "INSERT INTO data (value) VALUES (1)")
}
}
do {
var config = Configuration()
config.prepareDatabase { db in
try db.usePassphrase("secret")
}
let dbQueue = try makeDatabaseQueue(filename: "test.sqlite", configuration: config)
try dbQueue.inDatabase { db in
XCTAssertEqual(try Int.fetchOne(db, sql: "SELECT COUNT(*) FROM data")!, 1)
}
}
}
func testDatabaseQueueWithPragmaPassphraseToDatabaseQueueWithoutPassphrase() throws {
do {
let dbQueue = try makeDatabaseQueue(filename: "test.sqlite", configuration: Configuration())
try dbQueue.inDatabase { db in
try db.execute(sql: "PRAGMA key = 'secret'")
try db.execute(sql: "CREATE TABLE data (value INTEGER)")
try db.execute(sql: "INSERT INTO data (value) VALUES (1)")
}
}
do {
do {
_ = try makeDatabaseQueue(filename: "test.sqlite", configuration: Configuration())
XCTFail("Expected error")
} catch let error as DatabaseError {
XCTAssertEqual(error.resultCode, .SQLITE_NOTADB)
XCTAssertEqual(error.message!, "file is not a database")
}
}
}
func testCipherPageSize() throws {
do {
var config = Configuration()
config.prepareDatabase { db in
try db.usePassphrase("secret")
try db.execute(sql: "PRAGMA cipher_page_size = 8192")
}
let dbQueue = try makeDatabaseQueue(filename: "test.sqlite", configuration: config)
try dbQueue.inDatabase { db in
XCTAssertEqual(try Int.fetchOne(db, sql: "PRAGMA cipher_page_size")!, 8192)
}
}
do {
var config = Configuration()
config.prepareDatabase { db in
try db.usePassphrase("secret")
try db.execute(sql: "PRAGMA cipher_page_size = 4096")
}
let dbPool = try makeDatabasePool(filename: "testpool.sqlite", configuration: config)
try dbPool.write { db in
XCTAssertEqual(try Int.fetchOne(db, sql: "PRAGMA cipher_page_size")!, 4096)
try db.execute(sql: "CREATE TABLE data(value INTEGER)")
try db.execute(sql: "INSERT INTO data(value) VALUES(1)")
}
try dbPool.read { db in
XCTAssertEqual(try Int.fetchOne(db, sql: "PRAGMA cipher_page_size")!, 4096)
XCTAssertEqual(try Int.fetchOne(db, sql: "SELECT value FROM data"), 1)
}
}
}
func testCipherKDFIterations() throws {
do {
var config = Configuration()
config.prepareDatabase { db in
try db.usePassphrase("secret")
try db.execute(sql: "PRAGMA kdf_iter = 128000")
}
let dbQueue = try makeDatabaseQueue(filename: "test.sqlite", configuration: config)
try dbQueue.inDatabase { db in
XCTAssertEqual(try Int.fetchOne(db, sql: "PRAGMA kdf_iter"), 128000)
}
}
do {
var config = Configuration()
config.prepareDatabase { db in
try db.usePassphrase("secret")
try db.execute(sql: "PRAGMA kdf_iter = 128000")
}
let dbPool = try makeDatabasePool(filename: "testpool.sqlite", configuration: config)
try dbPool.write { db in
XCTAssertEqual(try Int.fetchOne(db, sql: "PRAGMA kdf_iter"), 128000)
try db.execute(sql: "CREATE TABLE data(value INTEGER)")
try db.execute(sql: "INSERT INTO data(value) VALUES(1)")
}
try dbPool.read { db in
XCTAssertEqual(try Int.fetchOne(db, sql: "PRAGMA kdf_iter"), 128000)
XCTAssertEqual(try Int.fetchOne(db, sql: "SELECT value FROM data"), 1)
}
}
}
func testCipherWithMismatchedKDFIterations() throws {
do {
var config = Configuration()
config.prepareDatabase { db in
try db.usePassphrase("secret")
try db.execute(sql: "PRAGMA kdf_iter = 128000")
}
let dbPool = try makeDatabasePool(filename: "testpool.sqlite", configuration: config)
try dbPool.write { db in
XCTAssertEqual(try Int.fetchOne(db, sql: "PRAGMA kdf_iter"), 128000)
try db.execute(sql: "CREATE TABLE data(value INTEGER)")
try db.execute(sql: "INSERT INTO data(value) VALUES(1)")
}
try dbPool.read { db in
XCTAssertEqual(try Int.fetchOne(db, sql: "PRAGMA kdf_iter"), 128000)
XCTAssertEqual(try Int.fetchOne(db, sql: "SELECT value FROM data"), 1)
}
}
do {
var config = Configuration()
config.prepareDatabase { db in
try db.usePassphrase("secret")
try db.execute(sql: "PRAGMA kdf_iter = 64000")
}
do {
let dbPool = try makeDatabasePool(filename: "testpool.sqlite", configuration: config)
try dbPool.read { db in
XCTAssertEqual(try Int.fetchOne(db, sql: "PRAGMA kdf_iter"), 64000)
XCTAssertEqual(try Int.fetchOne(db, sql: "SELECT value FROM data"), 1)
}
XCTFail("Expected error")
} catch let error as DatabaseError {
XCTAssertEqual(error.resultCode, .SQLITE_NOTADB)
XCTAssertEqual(error.message!, "file is not a database")
}
}
}
// Test for the use case described in <https://github.com/groue/GRDB.swift/discussions/1517>
func testEncryptedDatabaseCanBeAttached() throws {
// Create encrypted db
var config = Configuration()
config.prepareDatabase { db in
try db.usePassphrase("secret")
}
let encryptedDBQueue = try makeDatabaseQueue(filename: "encrypted.sqlite", configuration: config)
try encryptedDBQueue.write { db in
try db.execute(sql: "CREATE TABLE t(a)")
}
let attachingDBQueue = try makeDatabaseQueue()
try attachingDBQueue.inDatabase { db in
try db.execute(sql: "ATTACH DATABASE ? AS encrypted KEY ?", arguments: [encryptedDBQueue.path, "secret"])
let count = try Table("t").fetchCount(db)
XCTAssertEqual(count, 0)
}
}
func testExportPlainTextDatabaseToEncryptedDatabase() throws {
// See https://discuss.zetetic.net/t/how-to-encrypt-a-plaintext-sqlite-database-to-use-sqlcipher-and-avoid-file-is-encrypted-or-is-not-a-database-errors/868?source_topic_id=939
do {
let plainTextDBQueue = try makeDatabaseQueue(filename: "plaintext.sqlite", configuration: Configuration())
try plainTextDBQueue.inDatabase { db in
try db.execute(sql: "CREATE TABLE data (value INTEGER)")
try db.execute(sql: "INSERT INTO data (value) VALUES (1)")
}
var config = Configuration()
config.prepareDatabase { db in
try db.usePassphrase("secret")
}
do {
_ = try makeDatabaseQueue(filename: "plaintext.sqlite", configuration: config)
XCTFail("Expected error")
} catch let error as DatabaseError {
XCTAssertEqual(error.resultCode, .SQLITE_NOTADB)
XCTAssertEqual(error.message!, "file is not a database")
}
let encryptedDBQueue = try makeDatabaseQueue(filename: "encrypted.sqlite", configuration: config)
try plainTextDBQueue.inDatabase { db in
try db.execute(sql: "ATTACH DATABASE ? AS encrypted KEY ?", arguments: [encryptedDBQueue.path, "secret"])
try db.execute(sql: "SELECT sqlcipher_export('encrypted')")
try db.execute(sql: "DETACH DATABASE encrypted")
}
}
do {
var config = Configuration()
config.prepareDatabase { db in
try db.usePassphrase("secret")
}
let dbQueue = try makeDatabaseQueue(filename: "encrypted.sqlite", configuration: config)
try dbQueue.inDatabase { db in
XCTAssertEqual(try Int.fetchOne(db, sql: "SELECT COUNT(*) FROM data")!, 1)
}
}
}
func testSQLCipher3Compatibility() throws {
guard let cipherMajorVersion = try DatabaseQueue()
.read({ try String.fetchOne($0, sql: "PRAGMA cipher_version") })
.flatMap({ $0.split(separator: ".").first })
.flatMap({ Int($0) })
else { XCTFail("Unknown SQLCipher version"); return }
if cipherMajorVersion >= 4 {
let testBundle = Bundle(for: type(of: self))
let path = testBundle.url(forResource: "db", withExtension: "SQLCipher3")!.path
var configuration = Configuration()
configuration.prepareDatabase { db in
try db.usePassphrase("secret")
try db.execute(sql: "PRAGMA cipher_compatibility = 3")
}
do {
let dbQueue = try DatabaseQueue(path: path, configuration: configuration)
let success = try dbQueue.read { try String.fetchOne($0, sql: "SELECT a FROM t") }
XCTAssertEqual(success, "success")
}
do {
let dbPool = try DatabasePool(path: path, configuration: configuration)
let success = try dbPool.read { try String.fetchOne($0, sql: "SELECT a FROM t") }
XCTAssertEqual(success, "success")
}
}
}
}
#endif