Skip to content

Commit

Permalink
Initial support for encryption on the web
Browse files Browse the repository at this point in the history
  • Loading branch information
simolus3 committed Jan 6, 2025
1 parent b58f8a6 commit bb28586
Show file tree
Hide file tree
Showing 7 changed files with 72 additions and 13 deletions.
8 changes: 5 additions & 3 deletions sqlite3/assets/wasm/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ include(FetchContent)
FetchContent_Declare(
sqlite3
# NOTE: When changing this, also update `test/wasm/sqlite3_test.dart`
URL https://sqlite.org/2024/sqlite-autoconf-3470200.tar.gz
URL https://github.com/utelle/SQLite3MultipleCiphers/releases/download/v1.9.2/sqlite3mc-1.9.2-sqlite-3.47.2-amalgamation.zip
DOWNLOAD_EXTRACT_TIMESTAMP NEW
)

Expand All @@ -38,13 +38,13 @@ macro(base_sqlite3_target name debug)
set(sources
${CMAKE_CURRENT_SOURCE_DIR}/os_web.c
${CMAKE_CURRENT_SOURCE_DIR}/helpers.c
${sqlite3_SOURCE_DIR}/sqlite3.c
${sqlite3_SOURCE_DIR}/sqlite3mc_amalgamation.c
)
set(flags -Wall -Wextra -Wno-unused-parameter -Wno-unused-function)

if(${debug})
list(APPEND sources "${CMAKE_BINARY_DIR}/vfstrace.c")
list(APPEND flags "-g" "-DDEBUG")
list(APPEND flags "-g" "-DDEBUG" "-O1")
else()
list(APPEND flags "-Oz" "-DNDEBUG" "-flto")
endif()
Expand All @@ -56,6 +56,8 @@ macro(base_sqlite3_target name debug)
-o ${clang_output}
-I ${PROJECT_SOURCE_DIR} -I ${sqlite3_SOURCE_DIR}
-D_HAVE_SQLITE_CONFIG_H
-DSQLITE_OMIT_AUTOINIT
-D__WASM__
-mcpu=generic
-mexec-model=reactor
-fno-stack-protector -fno-stack-clash-protection
Expand Down
6 changes: 5 additions & 1 deletion sqlite3/assets/wasm/helpers.c
Original file line number Diff line number Diff line change
Expand Up @@ -187,7 +187,11 @@ SQLITE_API sqlite3_vfs *dart_sqlite3_register_vfs(const char *name, int dartId,
vfstrace_register(traceName, name, &dartvfs_trace_log1, NULL, makeDefault);
#else
// Just register the VFS as is.
sqlite3_vfs_register(vfs, makeDefault);
int rc = sqlite3_vfs_register(vfs, makeDefault);
if (rc) {
free(vfs);
return NULL;
}
#endif
return vfs;
}
Expand Down
11 changes: 10 additions & 1 deletion sqlite3/assets/wasm/os_web.c
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,15 @@
#include "bridge.h"
#include "sqlite3.h"

int sqlite3_os_init(void) { return SQLITE_OK; }
extern int sqlite3_powersync_init(sqlite3 *db, char **pzErrMsg,
const sqlite3_api_routines *pApi);

int getentropy(void* buf, size_t n) {
return xRandomness(-1, (int) n, (char*) buf);
}

int sqlite3_os_init(void) {
return SQLITE_OK;
}

int sqlite3_os_end(void) { return SQLITE_OK; }
5 changes: 3 additions & 2 deletions sqlite3/example/web/main.dart
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,12 @@ Future<void> main() async {
print(sqlite3.version);

sqlite3.registerVirtualFileSystem(
await IndexedDbFileSystem.open(dbName: 'sqlite3-example'),
InMemoryFileSystem(),
makeDefault: true,
);

sqlite3.open('/database')
sqlite3.open('/database', vfs: 'multipleciphers-dart-memory')
..execute("pragma key = 'test';")
..execute('pragma user_version = 1')
..execute('CREATE TABLE foo (bar INTEGER NOT NULL);')
..execute('INSERT INTO foo (bar) VALUES (?)', [3])
Expand Down
18 changes: 15 additions & 3 deletions sqlite3/lib/src/vfs.dart
Original file line number Diff line number Diff line change
Expand Up @@ -132,18 +132,30 @@ abstract base class BaseVirtualFileSystem extends VirtualFileSystem {
final Random random;

BaseVirtualFileSystem({Random? random, required String name})
: random = random ?? Random.secure(),
: random = random ?? _fallbackRandom,
super(name);

@override
void xRandomness(Uint8List target) {
generateRandomness(target, random);
}

@override
DateTime xCurrentTime() => DateTime.now();

/// Fills [target] with random bytes.
///
/// An optional [random] source can be provided, otherwise a default instance
/// of [Random.secure] will be used.
static void generateRandomness(Uint8List target, [Random? random]) {
random ??= _fallbackRandom;

for (var i = 0; i < target.length; i++) {
target[i] = random.nextInt(1 << 8);
}
}

@override
DateTime xCurrentTime() => DateTime.now();
static final Random _fallbackRandom = Random.secure();
}

/// A [VirtualFileSystemFile] base class that implements [xRead] to zero-fill
Expand Down
14 changes: 14 additions & 0 deletions sqlite3/lib/src/wasm/bindings.dart
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import 'dart:typed_data';
import 'package:sqlite3/src/vfs.dart';

import '../constants.dart';
import '../exception.dart';
import '../functions.dart';
import '../implementation/bindings.dart';
import 'wasm_interop.dart' as wasm;
Expand Down Expand Up @@ -55,6 +56,8 @@ final class WasmSqliteBindings extends RawSqliteBindings {
@override
SqliteResult<RawSqliteDatabase> sqlite3_open_v2(
String name, int flags, String? zVfs) {
sqlite3_initialize();

final namePtr = bindings.allocateZeroTerminated(name);
final outDb = bindings.malloc(wasm.WasmBindings.pointerSize);
final vfsPtr = zVfs == null ? 0 : bindings.allocateZeroTerminated(zVfs);
Expand All @@ -76,12 +79,23 @@ final class WasmSqliteBindings extends RawSqliteBindings {
return bindings.memory.readString(bindings.sqlite3_sourceid());
}

void sqlite3_initialize() {
final rc = bindings.sqlite3_initialize();
if (rc != 0) {
throw SqliteException(rc, 'sqlite3_initialize call failed');
}
}

@override
void registerVirtualFileSystem(VirtualFileSystem vfs, int makeDefault) {
final name = bindings.allocateZeroTerminated(vfs.name);
final id = bindings.callbacks.registerVfs(vfs);

final ptr = bindings.dart_sqlite3_register_vfs(name, id, makeDefault);
if (ptr == 0) {
throw StateError('could not register vfs');
}
sqlite3_initialize();
DartCallbacks.sqliteVfsPointer[vfs] = ptr;
}

Expand Down
23 changes: 20 additions & 3 deletions sqlite3/lib/src/wasm/wasm_interop.dart
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ class WasmBindings {
_sqlite3_stmt_readonly,
_sqlite3_stmt_isexplain;

final JSFunction? _sqlite3_db_config;
final JSFunction? _sqlite3_db_config, _sqlite3_initialize;

final Global _sqlite3_temp_directory;

Expand Down Expand Up @@ -160,7 +160,9 @@ class WasmBindings {
_sqlite3_stmt_isexplain = instance.functions['sqlite3_stmt_isexplain']!,
_sqlite3_stmt_readonly = instance.functions['sqlite3_stmt_readonly']!,
_sqlite3_db_config = instance.functions['dart_sqlite3_db_config_int'],
_sqlite3_initialize = instance.functions['sqlite3_initialize'],
_sqlite3_temp_directory = instance.globals['sqlite3_temp_directory']!

// Note when adding new fields: We remove functions from the wasm module that
// aren't referenced in Dart. We consider a symbol used when it appears in a
// string literal in an initializer of this constructor (`tool/wasm_dce.dart`).
Expand Down Expand Up @@ -210,6 +212,13 @@ class WasmBindings {

void sqlite3_free(Pointer ptr) => _sqlite3_free.callReturningVoid(ptr.toJS);

int sqlite3_initialize() {
return switch (_sqlite3_initialize) {
final fun? => fun.callReturningInt0(),
null => 0,
};
}

int create_scalar_function(
Pointer db, Pointer functionName, int nArg, int eTextRep, int id) {
return _create_scalar.callReturningInt5(
Expand Down Expand Up @@ -601,10 +610,18 @@ class _InjectedValues {
});
}).toJS,
'xRandomness': ((int vfsId, int nByte, Pointer zOut) {
final vfs = callbacks.registeredVfs[vfsId]!;
final vfs = callbacks.registeredVfs[vfsId];

return _runVfs(() {
vfs.xRandomness(memory.buffer.toDart.asUint8List(zOut, nByte));
final target = memory.buffer.toDart.asUint8List(zOut, nByte);

if (vfs != null) {
vfs.xRandomness(target);
} else {
// Fall back to a default random source. We're using this to
// implement `getentropy` in C which is used by sqlite3mc.
return BaseVirtualFileSystem.generateRandomness(target);
}
});
}).toJS,
'xSleep': ((int vfsId, int micros) {
Expand Down

0 comments on commit bb28586

Please sign in to comment.