Created
January 6, 2024 15:03
-
-
Save appinteractive/3816bbbed73b25816a6b3bc191f74e55 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| import crypto from 'crypto' | |
| import PouchDB from 'pouchdb' | |
| import md5 from 'md5' | |
| import { app } from 'electron' | |
| import { join } from 'path' | |
| import { existsSync, mkdirSync, rmdirSync } from 'fs' | |
| class EncryptedPouchDB extends PouchDB { | |
| constructor(name, options = {}) { | |
| const userData = app.getPath('userData') | |
| const dir = join(userData, 'data') | |
| if (!existsSync(dir)) { | |
| console.log('DB - creating database directory', name, dir) | |
| mkdirSync(dir) | |
| } | |
| const dbDir = join(dir, name) | |
| if (!existsSync(dbDir)) { | |
| console.log('DB - need to created db dir', dbDir) | |
| } | |
| super(dbDir, options) | |
| this.cryptSalt = md5(name).slice(0, 16) | |
| this.cryptFields = options.cryptFields || [ | |
| 'name', | |
| 'title', | |
| 'amount', | |
| 'total', | |
| 'tags', | |
| 'account', | |
| ] | |
| } | |
| async remove() { | |
| const dir = this.name | |
| if (!existsSync(dir)) { | |
| return | |
| } | |
| rmdirSync(dir, { recursive: true }) | |
| return | |
| } | |
| async allDocs(...args) { | |
| const res = await super.allDocs(...args) | |
| if (res.total_rows) { | |
| res.rows.map((row) => { | |
| row.doc = this.encryptOrDecryptDoc(row.doc, false) | |
| return row | |
| }) | |
| } | |
| return res | |
| } | |
| async bulkDocs(...args) { | |
| const docs = args[0].docs || args[0] | |
| if (docs) { | |
| const encrypted = docs.map((doc) => this.encryptOrDecryptDoc(doc, true)) | |
| return await super.bulkDocs(encrypted, ...args.slice(1)) | |
| } | |
| return super.bulkDocs(docs) | |
| } | |
| async upsertBulk(docs, opts = {}) { | |
| const ids = docs.map((d) => d._id) | |
| const res = await this.allDocs({ keys: ids, include_docs: true }) | |
| res.rows.forEach((item, i) => { | |
| if (!item.error && item.doc) { | |
| docs[i] = { ...item.doc, ...docs[i], ...{ _rev: item.doc._rev } } | |
| } else { | |
| delete docs[i]._rev | |
| } | |
| }) | |
| return this.bulkDocs(docs) | |
| } | |
| encryptOrDecryptDoc(doc, encrypt = true) { | |
| const data = {} | |
| if (!doc) return data | |
| Object.keys(doc).forEach((key) => { | |
| if (this.cryptFields.includes(key)) { | |
| data[key] = encrypt ? this.encrypt(doc[key]) : this.decrypt(doc[key]) | |
| } else { | |
| data[key] = doc[key] | |
| } | |
| }) | |
| return data | |
| } | |
| encrypt(text) { | |
| const cipher = crypto.createCipheriv( | |
| 'aes-256-cbc', | |
| EncryptedPouchDB.cryptKey, | |
| this.cryptSalt | |
| ) | |
| const crypted = cipher.update(JSON.stringify(text), 'utf8', 'base64') | |
| return crypted + cipher.final('base64') | |
| } | |
| decrypt(text) { | |
| try { | |
| const decipher = crypto.createDecipheriv( | |
| 'aes-256-cbc', | |
| EncryptedPouchDB.cryptKey, | |
| this.cryptSalt | |
| ) | |
| const dec = decipher.update(text, 'base64', 'utf8') | |
| return JSON.parse(dec + decipher.final('utf8')) | |
| } catch (err) { | |
| console.log(`Error while decrypting`, err.message) | |
| console.error(err) | |
| return | |
| } | |
| } | |
| static setEncryptionKey(key) { | |
| EncryptedPouchDB.cryptKey = key ? Buffer.from(md5(key)) : null | |
| } | |
| } | |
| export default EncryptedPouchDB |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment