{"id":30275905,"url":"https://github.com/mgoyal98/e2ee-adapter","last_synced_at":"2025-08-16T10:11:02.138Z","repository":{"id":308167640,"uuid":"1031318039","full_name":"mgoyal98/e2ee-adapter","owner":"mgoyal98","description":"A plug-and-play TypeScript package providing End-to-End Encryption (E2EE) middleware for Express.js and NestJS applications using hybrid encryption (AES-CBC + RSA).","archived":false,"fork":false,"pushed_at":"2025-08-04T09:51:38.000Z","size":219,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2025-08-04T17:25:16.040Z","etag":null,"topics":["aes-cbc","cryptography","e2ee","encryption","end-to-end-encryption","express","hybrid-encryption","key-exchange","middleware","nestjs","no-code-e2ee","plug-and-play","rsa","secure-communication","security","typescript","zero-config"],"latest_commit_sha":null,"homepage":"https://www.npmjs.com/package/e2ee-adapter","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/mgoyal98.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2025-08-03T13:45:16.000Z","updated_at":"2025-08-04T12:22:06.000Z","dependencies_parsed_at":"2025-08-04T17:25:23.540Z","dependency_job_id":"7e21ef85-7357-4a00-a349-ffd5cbe5d501","html_url":"https://github.com/mgoyal98/e2ee-adapter","commit_stats":null,"previous_names":["mgoyal98/e2ee-adapter"],"tags_count":12,"template":false,"template_full_name":null,"purl":"pkg:github/mgoyal98/e2ee-adapter","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mgoyal98%2Fe2ee-adapter","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mgoyal98%2Fe2ee-adapter/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mgoyal98%2Fe2ee-adapter/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mgoyal98%2Fe2ee-adapter/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/mgoyal98","download_url":"https://codeload.github.com/mgoyal98/e2ee-adapter/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mgoyal98%2Fe2ee-adapter/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":270697160,"owners_count":24630007,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-08-16T02:00:11.002Z","response_time":91,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["aes-cbc","cryptography","e2ee","encryption","end-to-end-encryption","express","hybrid-encryption","key-exchange","middleware","nestjs","no-code-e2ee","plug-and-play","rsa","secure-communication","security","typescript","zero-config"],"created_at":"2025-08-16T10:10:59.733Z","updated_at":"2025-08-16T10:11:02.122Z","avatar_url":"https://github.com/mgoyal98.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# E2EE Adapter\n\n\u003e \"60% of this code was written by an AI (Cursor), but I am not a passive coder — every line has been verified, fixed, and tested by me (a human).\"\n\nA **plug-and-play** TypeScript package providing End-to-End Encryption (E2EE) middleware for Express.js and NestJS applications using hybrid encryption (AES-CBC + RSA).\n\n## 🚀 Features\n\n- **Hybrid Encryption**: AES-CBC for data encryption + RSA for key exchange\n- **Express.js Middleware**: Easy integration with Express applications\n- **NestJS Interceptor**: Seamless integration with NestJS applications\n- **Client SDK**: TypeScript client for making encrypted requests\n- **Header-based Flow**: Secure transmission using custom headers\n- **Automatic Key Management**: Server generates and manages RSA key pairs\n- **Full Bidirectional Encryption**: Request and response encryption support\n- **GET Request Encryption**: Encrypt responses for GET requests (even with empty request bodies)\n- **Multi-Domain Support**: Multiple encryption keys for different domains/tenants\n- **Custom Header Configuration**: Configurable header names for flexibility\n- **Path \u0026 Method Exclusion**: Exclude specific paths and HTTP methods from encryption\n- **Enforcement Modes**: Strict or flexible encryption enforcement\n- **Empty Request Body Support**: Encrypt responses for requests without data\n- **Callback Hooks**: Error handling, decryption, and encryption callbacks\n- **Utility Functions**: Key generation, encryption, and decryption utilities\n- **Automatic Response Encryption**: Transparent response encryption using `res.send()`\n- **Plug-and-Play Integration**: Zero configuration required for basic setup\n\n## 🔐 Security Features\n\n- **AES-256-CBC**: Symmetric encryption for data\n- **RSA-2048-OAEP**: Asymmetric encryption for key exchange\n- **Random IV Generation**: Unique initialization vectors for each request\n- **Secure Key Exchange**: RSA encryption for AES key transmission\n\n## 📦 Installation\n\n### For Express.js Applications\n\n```bash\nnpm install e2ee-adapter express\n```\n\n### For NestJS Applications\n\n```bash\nnpm install e2ee-adapter @nestjs/common rxjs\n```\n\n## 🏗️ Architecture\n\nThe middleware implements a secure hybrid encryption flow that supports both request encryption and response encryption for all HTTP methods, including GET requests with empty bodies:\n\n```\n+-------------------------+                                  +-------------------------+\n|        CLIENT           |                                  |         SERVER          |\n+-------------------------+                                  +-------------------------+\n|                                                         ▲\n| 1. Fetch server's public key from /e2ee.json            |\n|    → key: RSA public PEM                                |\n|    → key_id: version info                               |\n|                                                         |\n| 2. Generate AES key (32 bytes) and IV (16 bytes)        |\n|                                                         |\n| 3. Encrypt request payload using:                       |\n|    AES-CBC(payload, AES_key, IV)                        |\n|                                                         |\n| 4. Encrypt AES key using server's RSA public key        |\n|    RSA_encrypt(AES_key, server_pubkey)                  |\n|                                                         |\n| 5. Send HTTPS request:                                  |\n|    ----------------------------------------------       |\n|    Headers:                                             |\n|      x-custom-key: RSA_encrypted_AES_key (base64)       |\n|      x-custom-iv:  IV (base64)                          |\n|      x-key-id:     key_id                               |\n|      Content-Type: application/json                     |\n|    Body:                                                |\n|      Encrypted AES payload (base64)                     |\n|    ----------------------------------------------       |\n|                                                         |\n|                                                         ▼\n|                                         +------------------------------------------+\n|                                         | 6. Decrypt x-custom-key using RSA private|\n|                                         |    AES_key = RSA_decrypt(x-custom-key)   |\n|                                         +------------------------------------------+\n|                                                         ▼\n|                                         +------------------------------------------+\n|                                         | 7. Decrypt payload using AES-CBC         |\n|                                         |    plaintext = AES_decrypt(body, AES_key,|\n|                                         |                                        IV)|\n|                                         +------------------------------------------+\n|                                                         ▼\n|                                         +------------------------------------------+\n|                                         | 8. Process request, prepare response JSON |\n|                                         +------------------------------------------+\n|                                                         ▼\n|                                         +------------------------------------------+\n|                                         | 9. Encrypt response using AES-CBC        |\n|                                         |    response_encrypted = AES_encrypt(     |\n|                                         |            JSON, AES_key, IV)            |\n|                                         +------------------------------------------+\n|                                                         ▼\n|                                         +------------------------------------------+\n|                                         | 10. Send encrypted response              |\n|                                         |     Body: response_encrypted (base64)    |\n|                                         +------------------------------------------+\n|                                                         ▲\n| 11. Decrypt response using AES_key and IV              |\n|     plaintext_response = AES_decrypt(body, key, IV)    |\n|                                                         |\n+-------------------------+                                  +-------------------------+\n```\n\n## 🛠️ Usage\n\n### 🚀 Plug-and-Play Setup\n\nThe E2EE adapter is designed to be **plug-and-play** - you can get started with minimal configuration:\n\n```typescript\n// Express.js - Just add the middleware\nimport { createE2EEMiddleware, generateMultipleKeyPairs } from 'e2ee-adapter';\n\nconst keys = await generateMultipleKeyPairs(['domain1']);\nconst e2eeMiddleware = createE2EEMiddleware({ config: { keys } });\napp.use(e2eeMiddleware); // That's it!\n\n// NestJS - Just add the interceptor\nimport { E2EEInterceptor } from 'e2ee-adapter';\n\n@UseInterceptors(E2EEInterceptor)\n@Controller('api')\nexport class UsersController {\n  // Your endpoints are now encrypted!\n}\n```\n\n### ⚠️ Important: Middleware/Interceptor Priority\n\n**The E2EE middleware and interceptor should be the first one to be used in your application stack.** This ensures that:\n\n- **Request decryption** happens before any other middleware processes the request\n- **Response encryption** happens after your application logic but before any response middleware\n- **Security headers** are properly set and maintained throughout the request lifecycle\n- **No data leakage** occurs through other middleware that might log or process request/response data\n\n**For Express.js:** Place the E2EE middleware as early as possible in your middleware stack, typically right after basic middleware like `express.json()` and `express.urlencoded()`.\n\n**For NestJS:** Apply the E2EE interceptor globally or at the controller level to ensure it runs before other interceptors and guards.\n\n### Module Paths\n\nThe package provides specific module paths for middleware, client, and interceptor:\n\n```typescript\n// Main exports (everything)\nimport { createE2EEMiddleware, E2EEClient, E2EEInterceptor, generateMultipleKeyPairs } from 'e2ee-adapter';\n\n// Specific modules (optional)\nimport { createE2EEMiddleware } from 'e2ee-adapter/middleware';\nimport { E2EEClient } from 'e2ee-adapter/client';\nimport { E2EEInterceptor } from 'e2ee-adapter/interceptor';\n```\n\n### Express.js Setup\n\n```typescript\nimport express from 'express';\nimport { generateMultipleKeyPairs } from 'e2ee-adapter';\nimport { createE2EEMiddleware } from 'e2ee-adapter/middleware';\n\nconst app = express();\n\n// Generate multiple RSA key pairs\nconst keys = await generateMultipleKeyPairs(['domain1', 'domain2', 'domain3']);\n\n// Create E2EE middleware\nconst e2eeMiddleware = createE2EEMiddleware({\n  config: {\n    keys,\n    enableRequestDecryption: true,\n    enableResponseEncryption: true,\n    excludePaths: ['/health', '/keys', '/e2ee.json'],\n    excludeMethods: ['GET', 'HEAD', 'OPTIONS'],\n    enforced: false // Allow both encrypted and non-encrypted requests\n  },\n  onError: (error, req, res) =\u003e {\n    console.error('E2EE Error:', error.message);\n  },\n  onDecrypt: (decryptedData, req) =\u003e {\n    console.log('Request decrypted successfully');\n  },\n  onEncrypt: (encryptedData, res) =\u003e {\n    console.log('Response encrypted successfully');\n  }\n});\n\n// Apply middleware (IMPORTANT: Place this early in your middleware stack)\napp.use(e2eeMiddleware);\n\n// Add server configuration endpoint\napp.get('/e2ee.json', (req, res) =\u003e {\n  res.json({\n    keys: {\n      domain1: keys.domain1.publicKey,\n      domain2: keys.domain2.publicKey,\n      domain3: keys.domain3.publicKey\n    },\n    keySize: 2048\n  });\n});\n\n// Protected endpoints\napp.post('/api/users', (req, res) =\u003e {\n  // req.body contains decrypted data\n  const user = { id: Date.now(), ...req.body };\n  \n  // The middleware will automatically encrypt the response if encryption context is available\n  res.send({ success: true, user });\n});\n\n// GET endpoint with encrypted response\napp.get('/api/users/:id', (req, res) =\u003e {\n  const user = { id: req.params.id, name: 'John Doe' };\n  res.send({ success: true, user }); // Will be automatically encrypted\n});\n```\n\n### NestJS Setup\n\n**Important: Configure bodyParser for plain text requests**\n\nBefore setting up the E2EE interceptor, you need to configure your NestJS application to handle plain text requests:\n\n```typescript\nimport * as bodyParser from 'body-parser';\n\n// Add this to your main.ts or app.module.ts\napp.use(bodyParser.text({ type: 'text/plain' }));\n```\n\n**E2EE Interceptor Setup:**\n\n```typescript\nimport { Injectable, NestInterceptor, ExecutionContext, CallHandler } from '@nestjs/common';\nimport { E2EEInterceptor } from 'e2ee-adapter/interceptor';\n\n@Injectable()\nexport class E2EEInterceptor extends E2EEInterceptor {\n  constructor() {\n    super({\n      config: {\n        keys: {\n          domain1: {\n            privateKey: process.env.E2EE_DOMAIN1_PRIVATE_KEY,\n            publicKey: process.env.E2EE_DOMAIN1_PUBLIC_KEY\n          },\n          domain2: {\n            privateKey: process.env.E2EE_DOMAIN2_PRIVATE_KEY,\n            publicKey: process.env.E2EE_DOMAIN2_PUBLIC_KEY\n          }\n        },\n\n        enableRequestDecryption: true,\n        enableResponseEncryption: true,\n        enforced: true // Strictly require encryption for all requests\n      }\n    });\n  }\n}\n\n// Apply to controller or globally (IMPORTANT: Apply early in the interceptor chain)\n@UseInterceptors(E2EEInterceptor)\n@Controller('api')\nexport class UsersController {\n  @Post('users')\n  createUser(@Body() userData: any) {\n    // userData is automatically decrypted\n    return { success: true, user: userData };\n  }\n}\n```\n\n### Client Usage\n\n```typescript\nimport { E2EEClient } from 'e2ee-adapter/client';\n\n// Create client with multiple server keys\nconst client = new E2EEClient({\n  serverKeys: {\n    domain1: '-----BEGIN PUBLIC KEY-----\\n...\\n-----END PUBLIC KEY-----',\n    domain2: '-----BEGIN PUBLIC KEY-----\\n...\\n-----END PUBLIC KEY-----'\n  }\n});\n\n// Make encrypted requests\nconst response = await client.request({\n  url: 'https://api.example.com/api/users',\n  method: 'POST',\n  data: {\n    name: 'John Doe',\n    email: 'john@example.com'\n  },\n  keyId: 'domain1' // Required: specify which key to use\n});\n\nconsole.log(response.data); // Automatically decrypted response\n```\n\n## 📋 API Reference\n\n### Configuration Options\n\n```typescript\ninterface KeyPair {\n  /** RSA public key in PEM format */\n  publicKey: string;\n  /** RSA private key in PEM format */\n  privateKey: string;\n}\n\ninterface KeyStore {\n  /** Mapping of keyId to key pair */\n  [keyId: string]: KeyPair;\n}\n\ninterface E2EEConfig {\n  /** Multiple keys store for multi-domain support */\n  keys: KeyStore;\n  /** Custom key header name (default: x-custom-key) */\n  customKeyHeader?: string;\n  /** Custom IV header name (default: x-custom-iv) */\n  customIVHeader?: string;\n  /** Key ID header name (default: x-key-id) */\n  keyIdHeader?: string;\n  /** Enable request decryption (default: true) */\n  enableRequestDecryption?: boolean;\n  /** Enable response encryption (default: true) */\n  enableResponseEncryption?: boolean;\n  /** Paths to exclude from encryption (default: ['/health', '/keys', '/e2ee.json']) */\n  excludePaths?: string[];\n  /** HTTP methods to exclude from encryption (default: ['GET', 'HEAD', 'OPTIONS']) */\n  excludeMethods?: string[];\n  /** If true, strictly enforce encryption for all requests. If false, only check for encryption after identifying headers (default: false) */\n  enforced?: boolean;\n  /** If true, allow empty request bodies while still enabling encrypted responses (default: false) */\n  allowEmptyRequestBody?: boolean;\n}\n\ninterface E2EEMiddlewareOptions {\n  /** E2EE configuration */\n  config: E2EEConfig;\n  /** Error callback for handling E2EE errors */\n  onError?: (error: Error, req: any, res: any) =\u003e void;\n  /** Callback triggered when request is successfully decrypted */\n  onDecrypt?: (decryptedData: DecryptedData, req: any) =\u003e void;\n  /** Callback triggered when response is successfully encrypted */\n  onEncrypt?: (encryptedData: EncryptedData, res: any) =\u003e void;\n}\n```\n\n### Client Configuration\n\n```typescript\ninterface E2EEClientConfig {\n  /** Multiple server keys for multi-domain support */\n  serverKeys: { [keyId: string]: string };\n  /** Key ID for versioning */\n  keyId?: string;\n}\n```\n\n### Response Encryption\n\nThe middleware automatically encrypts responses when encryption context is available. Simply use the standard `res.send()` method:\n\n```typescript\n// Encrypted response (when E2EE context exists)\napp.post('/api/data', (req, res) =\u003e {\n  const data = { message: 'Hello World' };\n  res.send(data); // Automatically encrypted\n});\n\n// Encrypted response for GET requests\napp.get('/api/data', (req, res) =\u003e {\n  const data = { message: 'Hello World' };\n  res.send(data); // Automatically encrypted if E2EE context exists\n});\n\n// Non-encrypted response (bypasses E2EE)\napp.get('/api/public', (req, res) =\u003e {\n  const data = { message: 'Public data' };\n  res.json(data); // Never encrypted\n});\n```\n\n## 🔧 Examples\n\n### Complete Express.js Example\n\nSee `examples/express-server/server.js` for a complete working example.\n\n### Complete Client Example\n\nSee `examples/client-example/client.js` for a complete working example.\n\n### Vanilla JavaScript Client Example\n\nSee `examples/vanilla-js-client/` for a browser-based vanilla JavaScript client with interactive UI.\n\n### Complete NestJS Example\n\nSee `examples/nestjs-server/` for a complete NestJS application with proper architecture, DTOs, entities, and global E2EE interceptor configuration.\n\n\n\n## 🚀 Quick Start\n\n1. **Install the package:**\n   ```bash\n   # For Express.js\n   npm install e2ee-adapter express\n   \n   # For NestJS\n   npm install e2ee-adapter @nestjs/common rxjs\n   ```\n\n2. **Generate multiple key pairs:**\n   ```typescript\n   import { generateMultipleKeyPairs } from 'e2ee-adapter';\n   \n   const keys = await generateMultipleKeyPairs(['domain1', 'domain2', 'domain3']);\n   ```\n\n3. **Set up Express middleware:**\n   ```typescript\n   import { createE2EEMiddleware } from 'e2ee-adapter/middleware';\n   \n   const e2eeMiddleware = createE2EEMiddleware({\n     config: { \n       keys\n     }\n   });\n   \n   // IMPORTANT: Place this early in your middleware stack\n   app.use(e2eeMiddleware);\n   ```\n\n4. **Create client:**\n   ```typescript\n   import { E2EEClient } from 'e2ee-adapter/client';\n   \n   const client = new E2EEClient({\n     serverKeys: {\n       domain1: keys.domain1.publicKey,\n       domain2: keys.domain2.publicKey,\n       domain3: keys.domain3.publicKey\n     }\n   });\n   ```\n\n5. **Make encrypted requests:**\n   ```typescript\n   // POST request with encrypted data\n   const response = await client.request({\n     url: 'http://localhost:3000/api/users',\n     method: 'POST',\n     data: { name: 'John Doe' },\n     keyId: 'domain1' // Required: specify which key to use\n   });\n\n   // GET request with encrypted response (no request body needed)\n   const userResponse = await client.request({\n     url: 'http://localhost:3000/api/users/123',\n     method: 'GET',\n     keyId: 'domain1' // Required: specify which key to use\n   });\n   ```\n\n\n## 🌐 Multi-Domain Support\n\nThe library supports multiple encryption keys for different domains or tenants sharing the same server infrastructure. This is useful for:\n\n- **Multi-tenant applications** where each tenant has their own encryption keys\n- **Domain-specific encryption** where different domains use different keys\n- **Key rotation** where new keys can be added while old ones remain valid\n- **Isolation** ensuring data encrypted with one key cannot be decrypted with another\n- **Explicit key selection** requiring users to specify which key to use for each request\n\n### How it works:\n\n1. **Server Configuration**: Configure multiple key pairs with unique keyIds\n2. **Client Configuration**: Store public keys for all domains you need to communicate with\n3. **Request-Level Key Selection**: Specify which keyId to use for each request (required)\n4. **Automatic Key Resolution**: Server automatically selects the correct private key based on the keyId header\n\n### Example Use Case:\n\n```typescript\n// Server setup for multiple domains\nconst keys = await generateMultipleKeyPairs(['tenant1', 'tenant2', 'tenant3']);\n\nconst middleware = createE2EEMiddleware({\n  config: { keys }\n});\n\n// Client setup for multiple domains\nconst client = new E2EEClient({\n  serverKeys: {\n    tenant1: keys.tenant1.publicKey,\n    tenant2: keys.tenant2.publicKey,\n    tenant3: keys.tenant3.publicKey\n  }\n});\n\n// Use different keys for different requests (keyId is required)\nawait client.request({ url: '/api/data', method: 'POST', data: data1, keyId: 'tenant1' });\nawait client.request({ url: '/api/data', method: 'POST', data: data2, keyId: 'tenant2' });\n```\n\n## 🔒 Security Considerations\n\n- **Key Management**: Store private keys securely and never expose them\n- **Key Rotation**: Implement key rotation mechanisms for production use\n- **HTTPS**: Always use HTTPS in production to protect against MITM attacks\n- **Key Size**: Use 2048-bit RSA keys minimum for production\n- **Algorithm**: The middleware uses RSA-OAEP with SHA-256 for optimal security\n- **Key Isolation**: Ensure proper key isolation between different domains/tenants\n\n## 🛡️ Enforcement Mode\n\nThe library supports two enforcement modes to control how encryption is handled:\n\n### Non-Enforced Mode (Default: `enforced: false`)\n- Only processes requests that include encryption headers\n- Allows both encrypted and non-encrypted requests to coexist\n- Useful for gradual migration or mixed environments\n- Requests without encryption headers are passed through unchanged\n\n### Enforced Mode (`enforced: true`)\n- Strictly requires all requests to include encryption headers\n- Rejects requests without proper encryption headers with a 400 error\n- Ensures complete end-to-end encryption compliance\n- Recommended for production environments with strict security requirements\n\n### Example Configuration:\n\n```typescript\n// Non-enforced mode (default) - allows mixed requests\nconst middleware = createE2EEMiddleware({\n  config: {\n    keys,\n    enforced: false // or omit this line\n  }\n});\n\n// Enforced mode - requires all requests to be encrypted\nconst middleware = createE2EEMiddleware({\n  config: {\n    keys,\n    enforced: true\n  }\n});\n```\n\n### Use Cases:\n\n- **Development/Testing**: Use non-enforced mode to test both encrypted and non-encrypted endpoints\n- **Gradual Migration**: Start with non-enforced mode and gradually migrate clients\n- **Production**: Use enforced mode to ensure all traffic is encrypted\n- **Mixed Environments**: Use non-enforced mode when some clients cannot support encryption\n\n## 🔧 Utility Functions\n\nThe package provides several utility functions for key generation and encryption operations:\n\n```typescript\nimport { \n  generateKeyPair, \n  generateMultipleKeyPairs,\n  encrypt,\n  decrypt,\n  encryptAES,\n  decryptAES,\n  decryptAESKey\n} from 'e2ee-adapter';\n\n// Generate a single RSA key pair\nconst keyPair = await generateKeyPair(2048);\n\n// Generate multiple key pairs for different domains\nconst keys = await generateMultipleKeyPairs(['domain1', 'domain2', 'domain3']);\n\n// Encrypt data using hybrid encryption\nconst encrypted = await encrypt('sensitive data', publicKey);\n\n// Decrypt data\nconst decrypted = await decrypt(encryptedData, encryptedKey, iv, privateKey);\n\n// AES-only encryption/decryption\nconst aesEncrypted = encryptAES('data', aesKey, iv);\nconst aesDecrypted = decryptAES(encryptedData, aesKey, iv);\n\n// Decrypt AES key from headers (for empty request bodies)\nconst { aesKey, iv } = await decryptAESKey(encryptedKey, iv, privateKey);\n```\n\n## 🔐 GET Request Encryption\n\n**One of the key features of this library is the ability to encrypt responses for GET requests, even when they have no request body.** This is particularly useful for:\n\n- **Secure Data Retrieval**: GET requests that return sensitive data\n- **API Endpoints**: Public APIs that need to return encrypted responses\n- **Stateless Operations**: Operations that don't require request data but need secure responses\n\n### How GET Request Encryption Works:\n\n1. **Client sends GET request** with encryption headers (AES key encrypted with RSA)\n2. **No request body needed** - the encryption context is established via headers\n3. **Server processes request** and generates response data\n4. **Response is automatically encrypted** using the AES key from headers\n5. **Client decrypts response** using the same AES key\n\n### Example GET Request with Encrypted Response:\n\n```typescript\n// Server endpoint\napp.get('/api/users/:id', (req, res) =\u003e {\n  const user = { id: req.params.id, name: 'John Doe', email: 'john@example.com' };\n  res.send(user); // Automatically encrypted response\n});\n\n// Client request\nconst response = await client.request({\n  url: 'https://api.example.com/api/users/123',\n  method: 'GET',\n  keyId: 'domain1' // No data needed, but encryption headers required\n});\n\nconsole.log(response.data); // Automatically decrypted user data\n```\n\n## 📤 Empty Request Body Support\n\nThe library supports encrypted responses even for requests with empty bodies (like GET requests or POST requests without data). This is useful when you want to:\n\n- **GET requests with encrypted responses**: Retrieve data securely without sending any request body\n- **POST requests without data**: Submit forms or trigger actions that don't require request data\n- **API endpoints that only return data**: Endpoints that don't accept input but should return encrypted responses\n\n### Configuration:\n\n```typescript\n// Enable empty request body support\nconst middleware = createE2EEMiddleware({\n  config: {\n    keys,\n    allowEmptyRequestBody: true, // Enable this feature\n    enableRequestDecryption: true,\n    enableResponseEncryption: true\n  }\n});\n```\n\n### How it works:\n\n1. **Client sends request** with encryption headers but no request body\n2. **Server processes request** by decrypting the AES key from headers\n3. **Server generates response** and encrypts it using the decrypted AES key\n4. **Client receives encrypted response** and decrypts it\n\n### Example Use Cases:\n\n```typescript\n// GET request with encrypted response\napp.get('/api/users', (req, res) =\u003e {\n  const users = [{ id: 1, name: 'John' }, { id: 2, name: 'Jane' }];\n  res.send(users); // Response will be automatically encrypted\n});\n\n// POST request without body but with encrypted response\napp.post('/api/health-check', (req, res) =\u003e {\n  const status = { status: 'healthy', timestamp: Date.now() };\n  res.send(status); // Response will be automatically encrypted\n});\n```\n\n### Client Example:\n\n```typescript\n// GET request with encrypted response\nconst response = await client.request({\n  url: 'https://api.example.com/api/users',\n  method: 'GET',\n  keyId: 'domain1' // No data needed, but encryption headers required\n});\n\nconsole.log(response.data); // Automatically decrypted response\n\n// POST request without body but with encrypted response\nconst healthResponse = await client.request({\n  url: 'https://api.example.com/api/health-check',\n  method: 'POST',\n  keyId: 'domain1' // No data needed, but encryption headers required\n});\n\nconsole.log(healthResponse.data); // Automatically decrypted response\n```\n\n## 🤝 Contributing\n\n1. Fork the repository\n2. Create a feature branch\n3. Make your changes\n4. Add tests\n5. Submit a pull request\n\n## 📄 License\n\nThis project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details. ","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmgoyal98%2Fe2ee-adapter","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmgoyal98%2Fe2ee-adapter","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmgoyal98%2Fe2ee-adapter/lists"}