Skip to content

Commit 10d8451

Browse files
committed
Setup encryption by passing key
1 parent c135361 commit 10d8451

File tree

8 files changed

+80
-35
lines changed

8 files changed

+80
-35
lines changed

demos/react-supabase-todolist/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
"@powersync/web": "workspace:*",
1414
"@emotion/react": "11.11.4",
1515
"@emotion/styled": "11.11.5",
16-
"@journeyapps/wa-sqlite": "0.0.0-dev-20241126093237",
16+
"@journeyapps/wa-sqlite": "0.0.0-dev-20241126145151",
1717
"@mui/icons-material": "^5.15.12",
1818
"@mui/material": "^5.15.12",
1919
"@mui/x-data-grid": "^6.19.6",

packages/web/package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@
6060
"author": "JOURNEYAPPS",
6161
"license": "Apache-2.0",
6262
"peerDependencies": {
63-
"@journeyapps/wa-sqlite": "0.0.0-dev-20241126093237",
63+
"@journeyapps/wa-sqlite": "0.0.0-dev-20241126145151",
6464
"@powersync/common": "workspace:^1.21.0"
6565
},
6666
"dependencies": {
@@ -72,7 +72,7 @@
7272
"js-logger": "^1.6.1"
7373
},
7474
"devDependencies": {
75-
"@journeyapps/wa-sqlite": "0.0.0-dev-20241126093237",
75+
"@journeyapps/wa-sqlite": "0.0.0-dev-20241126145151",
7676
"@types/uuid": "^9.0.6",
7777
"@vitest/browser": "^2.1.4",
7878
"crypto-browserify": "^3.12.0",

packages/web/src/db/PowerSyncDatabase.ts

Lines changed: 20 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -55,17 +55,31 @@ type WithWebSyncOptions<Base> = Base & {
5555
sync?: WebSyncOptions;
5656
};
5757

58+
export interface WebEncryptionOptions {
59+
/**
60+
* Encryption key for the database.
61+
* If set, the database will be encrypted using Multiple Ciphers.
62+
*/
63+
encryptionKey?: string;
64+
}
65+
66+
type WithWebEncryptionOptions<Base> = Base & {
67+
encryptionKey?: string;
68+
};
69+
5870
export type WebPowerSyncDatabaseOptionsWithAdapter = WithWebSyncOptions<
59-
WithWebFlags<PowerSyncDatabaseOptionsWithDBAdapter>
71+
WithWebFlags<WithWebEncryptionOptions<PowerSyncDatabaseOptionsWithDBAdapter>>
6072
>;
6173
export type WebPowerSyncDatabaseOptionsWithOpenFactory = WithWebSyncOptions<
62-
WithWebFlags<PowerSyncDatabaseOptionsWithOpenFactory>
74+
WithWebFlags<WithWebEncryptionOptions<PowerSyncDatabaseOptionsWithOpenFactory>>
6375
>;
6476
export type WebPowerSyncDatabaseOptionsWithSettings = WithWebSyncOptions<
65-
WithWebFlags<PowerSyncDatabaseOptionsWithSettings>
77+
WithWebFlags<WithWebEncryptionOptions<PowerSyncDatabaseOptionsWithSettings>>
6678
>;
6779

68-
export type WebPowerSyncDatabaseOptions = WithWebSyncOptions<WithWebFlags<PowerSyncDatabaseOptions>>;
80+
export type WebPowerSyncDatabaseOptions = WithWebSyncOptions<
81+
WithWebFlags<WithWebEncryptionOptions<PowerSyncDatabaseOptions>>
82+
>;
6983

7084
export const DEFAULT_POWERSYNC_FLAGS: Required<WebPowerSyncFlags> = {
7185
...DEFAULT_WEB_SQL_FLAGS,
@@ -120,7 +134,8 @@ export class PowerSyncDatabase extends AbstractPowerSyncDatabase {
120134
protected openDBAdapter(options: WebPowerSyncDatabaseOptionsWithSettings): DBAdapter {
121135
const defaultFactory = new WASQLiteOpenFactory({
122136
...options.database,
123-
flags: resolveWebPowerSyncFlags(options.flags)
137+
flags: resolveWebPowerSyncFlags(options.flags),
138+
encryptionKey: options.encryptionKey
124139
});
125140
return defaultFactory.openDB();
126141
}

packages/web/src/db/adapters/wa-sqlite/WASQLiteDBAdapter.ts

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,12 @@ export interface WASQLiteDBAdapterOptions extends Omit<PowerSyncOpenFactoryOptio
3232
workerPort?: MessagePort;
3333

3434
worker?: string | URL | ((options: ResolvedWebSQLOpenOptions) => Worker | SharedWorker);
35+
36+
/**
37+
* Encryption key for the database.
38+
* If set, the database will be encrypted using SQLCipher.
39+
*/
40+
encryptionKey?: string;
3541
}
3642

3743
/**
@@ -111,7 +117,7 @@ export class WASQLiteDBAdapter extends BaseObserver<DBAdapterListener> implement
111117

112118
return;
113119
}
114-
this.methods = await _openDB(this.options.dbFilename, { useWebWorker: false });
120+
this.methods = await _openDB(this.options.dbFilename, this.options.encryptionKey, { useWebWorker: false });
115121
this.methods.registerOnTableChange((event) => {
116122
this.iterateListeners((cb) => cb.tablesUpdated?.(event));
117123
});

packages/web/src/db/adapters/wa-sqlite/WASQLiteOpenFactory.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,8 @@ export class WASQLiteOpenFactory extends AbstractWebSQLOpenFactory {
99
protected openAdapter(): DBAdapter {
1010
return new WASQLiteDBAdapter({
1111
...this.options,
12-
flags: this.resolvedFlags
12+
flags: this.resolvedFlags,
13+
encryptionKey: this.options.encryptionKey
1314
});
1415
}
1516
}

packages/web/src/db/adapters/web-sql-flags.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,12 @@ export interface WebSQLOpenFactoryOptions extends SQLOpenOptions {
5555
* or a factory method that returns a worker.
5656
*/
5757
worker?: string | URL | ((options: ResolvedWebSQLOpenOptions) => Worker | SharedWorker);
58+
59+
/**
60+
* Encryption key for the database.
61+
* If set, the database will be encrypted using Multiple Ciphers.
62+
*/
63+
encryptionKey?: string;
5864
}
5965

6066
export function isServerSide() {

packages/web/src/shared/open-db.ts

Lines changed: 21 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -9,45 +9,48 @@ let nextId = 1;
99

1010
export async function _openDB(
1111
dbFileName: string,
12+
encryptionKey?: string,
1213
options: { useWebWorker: boolean } = { useWebWorker: true }
1314
): Promise<DBFunctionsInterface> {
14-
const { default: moduleFactory } = await import('@journeyapps/wa-sqlite/dist/mc-wa-sqlite-async.mjs');
15+
let moduleFactory;
16+
if (encryptionKey) {
17+
console.log('Using encrypted database');
18+
moduleFactory = (await import('@journeyapps/wa-sqlite/dist/mc-wa-sqlite-async.mjs')).default;
19+
} else {
20+
console.log('Using unencrypted database');
21+
moduleFactory = (await import('@journeyapps/wa-sqlite/dist/wa-sqlite-async.mjs')).default;
22+
}
23+
// const { default: moduleFactory } = await import('@journeyapps/wa-sqlite/dist/mc-wa-sqlite-async.mjs');
1524
const module = await moduleFactory();
1625
const sqlite3 = SQLite.Factory(module);
17-
console.log('sqlite3', sqlite3);
1826

1927
/**
2028
* Register the PowerSync core SQLite extension
2129
*/
2230
module.ccall('powersync_init_static', 'int', []);
2331

24-
console.log('powerync init');
25-
2632
const { IDBBatchAtomicVFS } = await import('@journeyapps/wa-sqlite/src/examples/IDBBatchAtomicVFS.js');
27-
console.log('DbFileName', dbFileName);
2833
// @ts-expect-error The types for this static method are missing upstream
2934
const vfs = await IDBBatchAtomicVFS.create(dbFileName, module, {
3035
lockPolicy: 'exclusive'
3136
});
32-
33-
console.log('vfs before', vfs);
3437
sqlite3.vfs_register(vfs, true);
3538

36-
const createResult = module.ccall('sqlite3mc_vfs_create', 'int', ['string', 'int'], [dbFileName, 1]);
37-
console.log('result from creation', createResult);
38-
if (createResult !== 0) {
39-
throw new Error('Failed to create multiple cipher vfs');
39+
if (encryptionKey) {
40+
const createResult = module.ccall('sqlite3mc_vfs_create', 'int', ['string', 'int'], [dbFileName, 1]);
41+
if (createResult !== 0) {
42+
throw new Error('Failed to create multiple cipher vfs');
43+
}
4044
}
41-
console.log('vfs after', vfs);
4245

4346
const db = await sqlite3.open_v2(dbFileName);
44-
console.log('db', db);
4547

46-
// const pragma = await sqlite3.exec(db, 'PRAGMA key = "key"');
47-
// console.log('pragma', pragma);
48-
// if (pragma !== SQLite.SQLITE_OK) {
49-
// throw new Error('Failed to set key');
50-
// }
48+
if (encryptionKey) {
49+
const pragma = await sqlite3.exec(db, `PRAGMA key = "${encryptionKey}"`);
50+
if (pragma !== SQLite.SQLITE_OK) {
51+
throw new Error('Failed to set encryption key');
52+
}
53+
}
5154

5255
const statementMutex = new Mutex();
5356

pnpm-lock.yaml

Lines changed: 21 additions & 7 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)