{"id":16611,"library":"crypto-pouch","title":"PouchDB Encryption Plugin","description":"Crypto-Pouch is a PouchDB plugin designed to provide transparent, field-level encryption for document data stored in PouchDB and CouchDB databases. It currently operates at version 4.0.2 and integrates seamlessly with existing PouchDB instances. The plugin leverages the TweetNaCl.js library, an independently audited cryptographic library, utilizing the xsalsa20-poly1305 algorithm for robust authenticated encryption. Once initialized with a password, it transparently encrypts document contents on write operations and decrypts them on read operations, transforming the original document into a 'payload' property containing the ciphertext. A key differentiation is its explicit focus on document *contents*, leaving `_id`s, `_rev`s, and PouchDB view keys/values unencrypted. Attachments are also not encrypted by default, requiring careful consideration for applications needing full data at rest encryption. While a formal release cadence isn't published, updates are typically released as needed for maintenance or feature enhancements.","status":"active","version":"4.0.2","language":"javascript","source_language":"en","source_url":"https://github.com/calvinmetcalf/crypto-pouch","tags":["javascript","pouchdb","couchdb","encrypted"],"install":[{"cmd":"npm install crypto-pouch","lang":"bash","label":"npm"},{"cmd":"yarn add crypto-pouch","lang":"bash","label":"yarn"},{"cmd":"pnpm add crypto-pouch","lang":"bash","label":"pnpm"}],"dependencies":[{"reason":"Crypto-Pouch is a plugin for PouchDB and requires a PouchDB instance to operate.","package":"pouchdb","optional":false},{"reason":"Provides TypeScript type definitions for `crypto-pouch`.","package":"@types/crypto-pouch","optional":true}],"imports":[{"note":"PouchDB is typically consumed via CommonJS `require` for plugin ecosystems, though modern setups might use dynamic `import()` or bundlers for ESM. Ensure PouchDB itself is correctly imported.","wrong":"import PouchDB from 'pouchdb'","symbol":"PouchDB","correct":"const PouchDB = require('pouchdb')"},{"note":"The plugin is designed to be loaded as a CommonJS module and applied directly to the PouchDB global or constructor via `PouchDB.plugin()`.","wrong":"import { plugin } from 'crypto-pouch'; PouchDB.plugin(plugin);","symbol":"CryptoPouchPlugin","correct":"PouchDB.plugin(require('crypto-pouch'))"},{"note":"For TypeScript users, importing the package directly (for its side effects) augments the PouchDB type definitions with the `crypto` and `removeCrypto` methods.","symbol":"CryptoPouchTypes","correct":"import 'crypto-pouch'"}],"quickstart":{"code":"const PouchDB = require('pouchdb');\nPouchDB.plugin(require('crypto-pouch'));\n\nasync function setupEncryptedDb(dbName, password) {\n  const db = new PouchDB(dbName);\n\n  // Initialize encryption; documents will be transparently en/decrypted after this.\n  // Make sure to use a strong password for security.\n  await db.crypto(password).then(() => {\n    console.log('Database encryption enabled.');\n  });\n\n  // Example usage: putting and getting an encrypted document\n  const docId = 'mydoc';\n  const originalDoc = { _id: docId, message: 'hello world', sensitiveData: 'top secret' };\n  await db.put(originalDoc);\n  console.log('Document put:', originalDoc);\n\n  const fetchedDoc = await db.get(docId);\n  console.log('Document fetched (decrypted):', fetchedDoc);\n\n  // Showing a limitation: attachments are not encrypted by default.\n  // The README notes db.putAttachment/db.getAttachment are not supported.\n  // Instead, manage attachments directly within the document object:\n  await db.put({\n    _id: docId,\n    _attachments: {\n      'myAttachment.txt': {\n        content_type: 'text/plain',\n        data: Buffer.from('Hello, world! Attachment not encrypted.').toString('base64')\n      }\n    }\n  });\n  console.log('Document with unencrypted attachment put.');\n\n  // Remove encryption (forgets password, but existing docs remain encrypted)\n  // db.removeCrypto();\n  // console.log('Encryption removed.');\n\n  return db;\n}\n\n// Example execution (replace with your actual database name and password)\nsetupEncryptedDb('my_encrypted_db_quickstart', process.env.DB_PASSWORD ?? 'myStrongPassword123!')\n  .then(db => console.log('Setup complete for database:', db.name))\n  .catch(err => console.error('Error during quickstart setup:', err));\n","lang":"javascript","description":"This quickstart demonstrates how to initialize `crypto-pouch` on a PouchDB database, add and retrieve encrypted documents, and highlights the recommended approach for handling unencrypted attachments."},"warnings":[{"fix":"Use the `options.ignore` array to explicitly acknowledge unencrypted attachments (e.g., `ignore: ['_attachments']`). For critical data, encrypt attachments manually before adding them to PouchDB documents.","message":"Attachments are not encrypted by `crypto-pouch` by default. If sensitive binary data needs encryption, it must be handled externally before being attached or an alternative solution employed.","severity":"gotcha","affected_versions":">=1.0.0"},{"fix":"Instead of `db.putAttachment()`/`db.getAttachment()`, manage attachments directly within the document object using `db.put()` and `db.get({binary: true, attachment: true})`.","message":"`db.putAttachment` and `db.getAttachment` methods are not supported when `crypto-pouch` is active. Using these methods may lead to unexpected behavior or errors.","severity":"breaking","affected_versions":">=1.0.0"},{"fix":"Design your data model and view functions to ensure that sensitive information is never stored in `_id`, `_rev`, or emitted as view keys/values. Consider using hashes or non-sensitive identifiers for these fields.","message":"Document `_id` and `_rev` fields, along with any keys or values emitted by PouchDB view functions, are not encrypted. These fields remain in plaintext within the database.","severity":"gotcha","affected_versions":">=1.0.0"},{"fix":"Avoid modifying the `_id` of documents once they have been encrypted. If an `_id` change is necessary, the document must be decrypted, a new document created with the new `_id`, and then re-encrypted.","message":"Changing the `_id` of an encrypted document after it has been saved will cause decryption failures upon retrieval.","severity":"gotcha","affected_versions":">=1.0.0"},{"fix":"Always use PouchDB's built-in replication functionality to transfer encrypted documents between databases, as `crypto-pouch` handles the necessary decryption and re-encryption during the replication process.","message":"Manually moving encrypted documents (e.g., by direct database manipulation or without PouchDB's replication mechanisms) between databases will prevent their correct decryption.","severity":"gotcha","affected_versions":">=1.0.0"},{"fix":"Enforce strong password policies. Do not hardcode passwords in client-side code, and consider using secure key derivation functions if a simple password is the only input.","message":"The security of the encrypted data is directly dependent on the strength and confidentiality of the `password` provided to `db.crypto()`. Weak or compromised passwords render the encryption ineffective.","severity":"gotcha","affected_versions":">=1.0.0"}],"env_vars":null,"last_verified":"2026-04-22T00:00:00.000Z","next_check":"2026-07-21T00:00:00.000Z","problems":[{"fix":"Do not modify the `_id` of encrypted documents after they are saved. For transferring encrypted documents between databases, always use PouchDB's native replication feature.","cause":"The encrypted document's integrity check (Message Authentication Code - MAC) failed, likely because the document's `_id` was changed after encryption, or the document was manually moved between databases without PouchDB's replication.","error":"Error: Could not decrypt document payload: MAC verification failed"},{"fix":"To manage attachments, embed them directly within the document object when using `db.put()` and retrieve them with `db.get()` by specifying `binary: true, attachment: true` in the options.","cause":"`crypto-pouch` overrides or disables the standard PouchDB `putAttachment` and `getAttachment` methods.","error":"TypeError: db.putAttachment is not a function"},{"fix":"Redesign view map functions to only emit non-sensitive or hashed data. For applications requiring complete data privacy at rest, evaluate alternative PouchDB plugins like ComDB or implement field-level hashing for view keys/values.","cause":"`crypto-pouch` specifically encrypts only document *contents* and explicitly does not encrypt `_id`, `_rev`, or any data emitted as keys/values from PouchDB view functions.","error":"Sensitive data appears unencrypted in view query results or `_all_docs`."}],"ecosystem":"npm"}