Skip to content

Commit

Permalink
Roll sqlcipher into the iOS project
Browse files Browse the repository at this point in the history
  • Loading branch information
ospfranco committed Mar 12, 2024
1 parent 4a013dd commit c7c567c
Show file tree
Hide file tree
Showing 19 changed files with 266,254 additions and 95 deletions.
55 changes: 55 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -136,3 +136,58 @@ jobs:
- name: Build example for iOS
run: |
yarn turbo run build:ios --cache-dir="${{ env.TURBO_CACHE_DIR }}"
build-ios-sqlcipher:
runs-on: self-hosted
env:
TURBO_CACHE_DIR: .turbo/ios
steps:
- name: Checkout
uses: actions/checkout@v4

- name: Setup
uses: ./.github/actions/setup

- name: install bundler dependencies
run: |
cd example
bundle install
- name: Cache turborepo for iOS
uses: actions/cache@v3
with:
path: ${{ env.TURBO_CACHE_DIR }}
key: ${{ runner.os }}-turborepo-ios-${{ hashFiles('yarn.lock') }}
restore-keys: |
${{ runner.os }}-turborepo-ios-
- name: Check turborepo cache for iOS
run: |
TURBO_CACHE_STATUS=$(node -p "($(yarn turbo run build:ios --cache-dir="${{ env.TURBO_CACHE_DIR }}" --dry=json)).tasks.find(t => t.task === 'build:ios').cache.status")
if [[ $TURBO_CACHE_STATUS == "HIT" ]]; then
echo "turbo_cache_hit=1" >> $GITHUB_ENV
fi
- name: Cache cocoapods
if: env.turbo_cache_hit != 1
id: cocoapods-cache
uses: actions/cache@v3
with:
path: |
**/ios/Pods
key: ${{ runner.os }}-cocoapods-${{ hashFiles('example/ios/Podfile.lock') }}
restore-keys: |
${{ runner.os }}-cocoapods-
- name: Install cocoapods
# if: env.turbo_cache_hit != 1 && steps.cocoapods-cache.outputs.cache-hit != 'true'
run: |
cd example/ios
OP_SQLITE_USE_SQLCIPHER=1 bundle exec pod install
env:
NO_FLIPPER: 1

- name: Build example for iOS
run: |
yarn turbo run build:ios --cache-dir="${{ env.TURBO_CACHE_DIR }}"
Binary file modified .yarn/install-state.gz
Binary file not shown.
48 changes: 32 additions & 16 deletions cpp/bindings.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -55,32 +55,48 @@ void install(jsi::Runtime &rt,
throw std::runtime_error("[op-sqlite][open] database name is required");
}

if (!args[0].isString()) {
throw std::runtime_error(
"[op-sqlite][open] database name must be a string");
}

std::string dbName = args[0].asString(rt).utf8(rt);
jsi::Object options = args[0].asObject(rt);
std::string dbName = options.getProperty(rt, "name").asString(rt).utf8(rt);
std::string path = std::string(basePath);
std::string location;
std::string encryptionKey;

if (count > 1 && !args[1].isUndefined() && !args[1].isNull()) {
if (!args[1].isString()) {
throw std::runtime_error(
"[op-sqlite][open] database location must be a string");
}
if (options.hasProperty(rt, "location")) {
location = options.getProperty(rt, "location").asString(rt).utf8(rt);
}

if (options.hasProperty(rt, "encryptionKey")) {
encryptionKey =
options.getProperty(rt, "encryptionKey").asString(rt).utf8(rt);
}

std::string lastPath = args[1].asString(rt).utf8(rt);
#ifdef OP_SQLITE_USE_SQLCIPHER
if (encryptionKey.empty()) {
throw std::runtime_error(
"[OP SQLite] using SQLCipher encryption key is required");
}
#else
if (!encryptionKey.empty()) {
throw std::runtime_error("[OP SQLite] SQLCipher is not enabled, "
"encryption key is not allowed");
}
#endif

if (lastPath == ":memory:") {
if (!location.empty()) {
if (location == ":memory:") {
path = ":memory:";
} else if (lastPath.rfind("/", 0) == 0) {
path = lastPath;
} else if (location.rfind("/", 0) == 0) {
path = location;
} else {
path = path + "/" + lastPath;
path = path + "/" + location;
}
}

#ifdef OP_SQLITE_USE_SQLCIPHER
BridgeResult result = opsqlite_open(dbName, path, encryptionKey);
#else
BridgeResult result = opsqlite_open(dbName, path);
#endif

if (result.type == SQLiteError) {
throw std::runtime_error(result.message);
Expand Down
29 changes: 19 additions & 10 deletions cpp/bridge.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -41,9 +41,15 @@ std::string get_db_path(std::string const &db_name,
return location + "/" + db_name;
}

#ifdef OP_SQLITE_USE_SQLCIPHER
BridgeResult opsqlite_open(std::string const &dbName,
std::string const &last_path,
std::string const &encryptionKey) {
#else
BridgeResult opsqlite_open(std::string const &dbName,
std::string const &lastPath) {
std::string dbPath = get_db_path(dbName, lastPath);
#endif
std::string dbPath = get_db_path(dbName, last_path);

int sqlOpenFlags =
SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE | SQLITE_OPEN_FULLMUTEX;
Expand All @@ -57,7 +63,10 @@ BridgeResult opsqlite_open(std::string const &dbName,
}

dbMap[dbName] = db;

#ifdef OP_SQLITE_USE_SQLCIPHER
opsqlite_execute(dbName, "PRAGMA key = '" + encryptionKey + "'", nullptr,
nullptr, nullptr);
#endif
return BridgeResult{.type = SQLiteOk, .affectedRows = 0};
}

Expand Down Expand Up @@ -366,8 +375,8 @@ opsqlite_execute(std::string const &dbName, std::string const &query,
};
}

// The statement did not fail to parse but there is nothing to do, just skip
// to the end
// The statement did not fail to parse but there is nothing to do, just
// skip to the end
if (statement == NULL) {
continue;
}
Expand Down Expand Up @@ -502,8 +511,8 @@ opsqlite_execute(std::string const &dbName, std::string const &query,
.insertId = static_cast<double>(latestInsertRowId)};
}

/// Executes returning data in raw arrays, a small performance optimization for
/// certain use cases
/// Executes returning data in raw arrays, a small performance optimization
/// for certain use cases
BridgeResult
opsqlite_execute_raw(std::string const &dbName, std::string const &query,
const std::vector<JSVariant> *params,
Expand Down Expand Up @@ -540,8 +549,8 @@ opsqlite_execute_raw(std::string const &dbName, std::string const &query,
};
}

// The statement did not fail to parse but there is nothing to do, just skip
// to the end
// The statement did not fail to parse but there is nothing to do, just
// skip to the end
if (statement == NULL) {
continue;
}
Expand Down Expand Up @@ -661,8 +670,8 @@ opsqlite_execute_raw(std::string const &dbName, std::string const &query,

void opsqlite_close_all() {
for (auto const &x : dbMap) {
// Interrupt will make all pending operations to fail with SQLITE_INTERRUPT
// The ongoing work from threads will then fail ASAP
// Interrupt will make all pending operations to fail with
// SQLITE_INTERRUPT The ongoing work from threads will then fail ASAP
sqlite3_interrupt(x.second);
// Each DB connection can then be safely interrupted
sqlite3_close_v2(x.second);
Expand Down
5 changes: 5 additions & 0 deletions cpp/bridge.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,13 @@ typedef std::function<void(std::string dbName, std::string tableName,
typedef std::function<void(std::string dbName)> CommitCallback;
typedef std::function<void(std::string dbName)> RollbackCallback;

#ifdef OP_SQLITE_USE_SQLCIPHER
BridgeResult opsqlite_open(std::string const &dbName, std::string const &dbPath,
std::string const &encryptionKey);
#else
BridgeResult opsqlite_open(std::string const &dbName,
std::string const &dbPath);
#endif

BridgeResult opsqlite_close(std::string const &dbName);

Expand Down
Loading

0 comments on commit c7c567c

Please sign in to comment.