Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Encryption - is this possible? #31

Open
cuuupid opened this issue Sep 21, 2021 · 5 comments
Open

Encryption - is this possible? #31

cuuupid opened this issue Sep 21, 2021 · 5 comments

Comments

@cuuupid
Copy link

cuuupid commented Sep 21, 2021

Normal SQLite has extensions/Pager support for adding encryption to the entire DB file i.e. AES ciphers. I was wondering if this project had similar capabilities.

Looking at how the DB is read/parsed, this may be as easy as encrypting/decryption on read/write of chunks.

@kukagg
Copy link

kukagg commented Oct 23, 2021

@pshah123 Have you managed to set it up?

@michaelpeterlee
Copy link

I recommend applying encryption at the application-level, storing data as blob/string and exposing indexes, as required. Encryption at lower-levels of the stack are a bonus and whilst they add layers around the onion, your application won't be dependent on them.

@imannms
Copy link

imannms commented Nov 9, 2021

Someone has done this https://github.com/wireapp/websql
He uses sql.js with encryption enabled.

I've tried this and it worked.

It would be nice if this was also implemented in absurd-sql.

@hoangqwe159
Copy link

@imannms the repo link is expired. Can you give me some guidance about this problem, please?

@hoangqwe159
Copy link

hoangqwe159 commented Nov 7, 2024

https://github.com/hoangqwe159/better-absurd-sql

It is my solution for Encryption. Encryption for SharedArrayBuffer is not implemented. To make absurd-sql work across tabs, I use SharedWorker instead. The usage here:

import initSqlJs from "@kikko-land/sql.js";
import { SQLiteFS } from "@tashelix/better-absurd-sql";
import IndexedDBBackend from "@tashelix/better-absurd-sql/dist/indexeddb-backend";
import { expose } from "comlink";

/// <reference types="@types/sharedworker" />

// This is an any, as that is the return type from `initSqlJs`
const dbsMap = new Map<string, any>();

const passwordMap = new Map<string, string>();

const dbPath = (name: string): string => `${name}.sqlite`;

let SQL: any;
let isSqlInitialized = false;

async function initializeSql() {
    if (isSqlInitialized) return;

    isSqlInitialized = true;

    SQL = await initSqlJs({ locateFile: (file: any) => file });

    const sqlFS = new SQLiteFS(SQL.FS, new IndexedDBBackend(undefined, passwordMap));

    SQL.register_for_idb(sqlFS);

    SQL.FS.mkdir("/sql");
    SQL.FS.mount(sqlFS, {}, "/sql");
}

async function openDb(dbName: string, password?: string) {
    await initializeSql();

    if (password) passwordMap.set(dbPath(dbName), password);
    if (dbsMap.has(dbName)) return dbsMap.get(dbName);

    const path = `/sql/${dbName}.sqlite`;
    if (typeof SharedArrayBuffer === "undefined") {
        const stream = SQL.FS.open(path, "a+");
        await stream.node.contents.readIfFallback();
        SQL.FS.close(stream);
    }

    const db = new SQL.Database(path, { filename: true });

    db.exec(`PRAGMA cache_size=5000; PRAGMA page_size=8192; PRAGMA journal_mode=MEMORY;`);

    dbsMap.set(dbName, db);

    return db;
}

async function closeDb(dbName: string) {
    const db = dbsMap.get(dbName);
    if (!db) return;

    db.close();
    dbsMap.delete(dbName);
    passwordMap.delete(dbPath(dbName));
}

async function deleteDb(dbName: string) {
    if (dbsMap.has(dbName)) await closeDb(dbName);

    const path = `/sql/${dbName}.sqlite`;

    try {
        (globalThis as any).indexedDB?.deleteDatabase?.(`${dbName}.sqlite`);

        // console.log(SQL);
        // console.log(SQL.FS);

        let exists = true;
        try {
            SQL.FS.stat(path);
        } catch (e) {
            exists = false;
        }

        if (exists) {
            SQL.FS.unlink(path);
        }
    } catch (err) {
        console.error(`Failed to unlink db 'sql/${dbName}.sqlite', reason:`, err);
    }
}

async function dbRun(dbName: string, func: string, ...args: unknown[]) {
    return (await openDb(dbName))[func](...args);
}

async function dbExec(dbName: string, sql: string, params: unknown[] | Record<string, unknown>, password?: string) {
    return await (await openDb(dbName, password)).exec(sql, params, {});
}

// TODO: There is also a db.prepare function, look into using it: https://github.com/jlongster/absurd-example-project/blob/master/src/index.worker.js

// * Exposing the API

const api = { openDb, closeDb, deleteDb, dbRun, dbExec };
export type Api = typeof api;

expose(api);

// biome-ignore lint/suspicious/noGlobalAssign: This is how you initialize shared workers
onconnect = event => {
    const port = event.ports[0];
    expose(api, port);
};

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

5 participants