secure-comms-hybrid 1.0.4 → 1.0.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -9,14 +9,16 @@ function createEncryptionMiddleware(hybridCrypto, options = {}) {
9
9
  logLevel = 'info'
10
10
  } = options;
11
11
 
12
- // Decryption middleware
13
- const decryptRequest = (req, res, next) => {
12
+ // Decryption middleware - FIXED to handle raw body
13
+ const decryptRequest = async (req, res, next) => {
14
14
  // Check if path is excluded
15
15
  if (excludedPaths.includes(req.path)) {
16
+ console.log(`Path ${req.path} excluded from encryption`);
16
17
  return next();
17
18
  }
18
19
  const isEncrypted = req.headers[CRYPTO_CONFIG.HEADERS.ENCRYPTED] === 'true';
19
20
  const clientId = req.headers[CRYPTO_CONFIG.HEADERS.CLIENT_ID];
21
+ console.log(`🔍 Middleware check: Encrypted=${isEncrypted}, ClientID=${clientId}, Path=${req.path}`);
20
22
  if (!isEncrypted) {
21
23
  if (requireEncryption) {
22
24
  return res.status(400).json({
@@ -25,92 +27,153 @@ function createEncryptionMiddleware(hybridCrypto, options = {}) {
25
27
  timestamp: new Date().toISOString()
26
28
  });
27
29
  }
30
+ console.log('â„šī¸ No encryption requested, proceeding with plain request');
28
31
  return next();
29
32
  }
30
33
  if (!clientId) {
34
+ console.error('❌ Missing client ID for encrypted request');
31
35
  return res.status(400).json({
32
36
  success: false,
33
37
  error: ERRORS.MISSING_CLIENT_ID,
34
38
  timestamp: new Date().toISOString()
35
39
  });
36
40
  }
37
- let rawBody = '';
38
- req.on('data', chunk => {
39
- rawBody += chunk.toString();
40
- });
41
- req.on('end', async () => {
41
+ console.log(`🔐 Processing encrypted request for client: ${clientId}`);
42
+ try {
43
+ // IMPORTANT: Read raw body BEFORE express.json() consumes it
44
+ // We need to handle this differently
45
+
46
+ // Create a buffer to collect the raw body
47
+ const chunks = [];
48
+
49
+ // Listen for data chunks
50
+ req.on('data', chunk => {
51
+ chunks.push(chunk);
52
+ });
53
+
54
+ // Wait for the entire body
55
+ await new Promise((resolve, reject) => {
56
+ req.on('end', resolve);
57
+ req.on('error', reject);
58
+ });
59
+
60
+ // Combine chunks
61
+ const rawBody = Buffer.concat(chunks).toString();
62
+ console.log(`đŸ“Ĩ Raw body received (${rawBody.length} chars)`);
63
+ if (!rawBody) {
64
+ console.error('❌ Empty request body for encrypted request');
65
+ return res.status(400).json({
66
+ success: false,
67
+ error: 'Empty request body',
68
+ timestamp: new Date().toISOString()
69
+ });
70
+ }
71
+ let parsedBody;
42
72
  try {
43
- if (!rawBody) {
44
- return res.status(400).json({
45
- success: false,
46
- error: 'Empty request body',
47
- timestamp: new Date().toISOString()
48
- });
49
- }
50
- let parsedBody;
51
- try {
52
- parsedBody = JSON.parse(rawBody);
53
- } catch (error) {
54
- return res.status(400).json({
55
- success: false,
56
- error: 'Invalid JSON',
57
- timestamp: new Date().toISOString()
58
- });
59
- }
60
- if (!parsedBody.ciphertext || !parsedBody.iv || !parsedBody.authTag) {
61
- return res.status(400).json({
62
- success: false,
63
- error: ERRORS.INVALID_REQUEST,
64
- required: ['ciphertext', 'iv', 'authTag'],
65
- timestamp: new Date().toISOString()
66
- });
67
- }
68
- const decrypted = await hybridCrypto.decryptData(parsedBody.ciphertext, parsedBody.iv, parsedBody.authTag, clientId);
69
- if (!decrypted.success) {
70
- return res.status(400).json({
71
- success: false,
72
- error: ERRORS.DECRYPTION_FAILED,
73
- details: decrypted.error,
74
- timestamp: new Date().toISOString()
75
- });
76
- }
77
- req.originalEncryptedBody = parsedBody;
78
- req.body = decrypted.data;
79
- req.encryptionMetadata = {
80
- type: 'hybrid',
81
- clientId,
82
- decryptedAt: decrypted.timestamp,
83
- algorithm: 'RSA-AES-GCM'
84
- };
85
- next();
73
+ parsedBody = JSON.parse(rawBody);
74
+ console.log(`✅ Body parsed successfully, keys: ${Object.keys(parsedBody).join(', ')}`);
86
75
  } catch (error) {
87
- console.error('❌ Decryption middleware error:', error);
88
- return res.status(500).json({
76
+ console.error('❌ Invalid JSON in request body:', error.message);
77
+ return res.status(400).json({
78
+ success: false,
79
+ error: 'Invalid JSON',
80
+ timestamp: new Date().toISOString()
81
+ });
82
+ }
83
+
84
+ // Check for required encryption fields
85
+ if (!parsedBody.ciphertext || !parsedBody.iv || !parsedBody.authTag) {
86
+ console.error('❌ Missing encryption fields in request');
87
+ console.log('Received:', {
88
+ hasCiphertext: !!parsedBody.ciphertext,
89
+ hasIV: !!parsedBody.iv,
90
+ hasAuthTag: !!parsedBody.authTag,
91
+ allKeys: Object.keys(parsedBody)
92
+ });
93
+ return res.status(400).json({
94
+ success: false,
95
+ error: ERRORS.INVALID_REQUEST,
96
+ required: ['ciphertext', 'iv', 'authTag'],
97
+ received: Object.keys(parsedBody),
98
+ timestamp: new Date().toISOString()
99
+ });
100
+ }
101
+ console.log(`🔓 Attempting to decrypt data for client ${clientId}`);
102
+ console.log(` Ciphertext length: ${parsedBody.ciphertext.length}`);
103
+ console.log(` IV: ${parsedBody.iv}`);
104
+ console.log(` Auth Tag: ${parsedBody.authTag.substring(0, 20)}...`);
105
+ const decrypted = await hybridCrypto.decryptData(parsedBody.ciphertext, parsedBody.iv, parsedBody.authTag, clientId);
106
+ console.log(`📊 Decryption result:`, {
107
+ success: decrypted.success,
108
+ hasData: !!decrypted.data,
109
+ error: decrypted.error
110
+ });
111
+ if (!decrypted.success) {
112
+ console.error(`❌ Decryption failed: ${decrypted.error}`);
113
+ return res.status(400).json({
89
114
  success: false,
90
- error: 'Internal server error',
115
+ error: ERRORS.DECRYPTION_FAILED,
116
+ details: decrypted.error,
91
117
  timestamp: new Date().toISOString()
92
118
  });
93
119
  }
94
- });
120
+ console.log(`✅ Successfully decrypted data for client ${clientId}`);
121
+
122
+ // Store original encrypted body for debugging
123
+ req.originalEncryptedBody = parsedBody;
124
+ req.body = decrypted.data;
125
+ req.encryptionMetadata = {
126
+ type: 'hybrid',
127
+ clientId,
128
+ decryptedAt: decrypted.timestamp,
129
+ algorithm: 'RSA-AES-GCM',
130
+ originalBodySize: rawBody.length,
131
+ decryptedBodySize: JSON.stringify(decrypted.data).length
132
+ };
133
+ console.log(`📤 Decrypted body:`, {
134
+ type: typeof decrypted.data,
135
+ keys: Object.keys(decrypted.data || {}),
136
+ sample: JSON.stringify(decrypted.data).substring(0, 100)
137
+ });
138
+ next();
139
+ } catch (error) {
140
+ console.error('❌ Error in decryption middleware:', error);
141
+ return res.status(500).json({
142
+ success: false,
143
+ error: 'Internal server error',
144
+ message: error.message,
145
+ timestamp: new Date().toISOString()
146
+ });
147
+ }
95
148
  };
96
149
 
97
- // Encryption middleware
150
+ // Encryption middleware - FIXED
98
151
  const encryptResponse = (req, res, next) => {
99
152
  const wantsEncryption = req.headers[CRYPTO_CONFIG.HEADERS.ENCRYPTED] === 'true';
100
153
  const clientId = req.headers[CRYPTO_CONFIG.HEADERS.CLIENT_ID];
154
+ console.log(`🔒 Response encryption check: Encrypt=${wantsEncryption}, ClientID=${clientId}`);
101
155
  if (!wantsEncryption || !clientId || excludedPaths.includes(req.path)) {
156
+ console.log('â„šī¸ Response encryption not requested');
102
157
  return next();
103
158
  }
104
159
  const originalJson = res.json;
105
160
  res.json = async function (data) {
106
161
  try {
162
+ console.log(`🔐 Attempting to encrypt response for client ${clientId}`);
163
+
164
+ // Don't encrypt error responses
107
165
  if (res.statusCode >= 400) {
166
+ console.log('â„šī¸ Not encrypting error response');
108
167
  return originalJson.call(this, data);
109
168
  }
110
169
  const encrypted = await hybridCrypto.encryptData(data, clientId);
111
170
  if (!encrypted.success) {
171
+ console.error(`❌ Response encryption failed: ${encrypted.error}`);
112
172
  throw new Error(`${ERRORS.ENCRYPTION_FAILED}: ${encrypted.error}`);
113
173
  }
174
+ console.log(`✅ Response encrypted successfully`);
175
+ console.log(` Ciphertext length: ${encrypted.ciphertext.length}`);
176
+ console.log(` IV: ${encrypted.iv.substring(0, 20)}...`);
114
177
  const encryptedResponse = {
115
178
  success: true,
116
179
  encrypted: true,
@@ -121,17 +184,24 @@ function createEncryptionMiddleware(hybridCrypto, options = {}) {
121
184
  timestamp: encrypted.timestamp,
122
185
  metadata: {
123
186
  clientId,
124
- originalDataType: typeof data
187
+ originalDataType: typeof data,
188
+ encryptedAt: encrypted.timestamp
125
189
  }
126
190
  };
191
+
192
+ // Set encryption headers
127
193
  res.setHeader(CRYPTO_CONFIG.HEADERS.ENCRYPTED, 'true');
128
194
  res.setHeader(CRYPTO_CONFIG.HEADERS.ENCRYPTION_ALGORITHM, 'RSA-AES-GCM');
129
195
  res.setHeader(CRYPTO_CONFIG.HEADERS.CLIENT_ID, clientId);
196
+ console.log(`📤 Sending encrypted response`);
130
197
  return originalJson.call(this, encryptedResponse);
131
198
  } catch (error) {
132
199
  console.error('❌ Response encryption failed:', error);
200
+
201
+ // Remove encryption headers
133
202
  res.removeHeader(CRYPTO_CONFIG.HEADERS.ENCRYPTED);
134
203
  res.removeHeader(CRYPTO_CONFIG.HEADERS.ENCRYPTION_ALGORITHM);
204
+ console.log('âš ī¸ Falling back to plain response');
135
205
  return originalJson.call(this, {
136
206
  success: false,
137
207
  error: ERRORS.ENCRYPTION_FAILED,
@@ -151,64 +221,25 @@ function createEncryptionMiddleware(hybridCrypto, options = {}) {
151
221
  };
152
222
  }
153
223
 
154
- // Express.js specific middleware factory
224
+ // Express.js specific middleware factory - FIXED
155
225
  function createExpressMiddleware(hybridCrypto, options = {}) {
156
226
  const {
157
227
  decryptRequest,
158
228
  encryptResponse
159
229
  } = createEncryptionMiddleware(hybridCrypto, options);
160
- return function (req, res, next) {
161
- // Apply decryption
162
- decryptRequest(req, res, err => {
163
- if (err) return next(err);
164
- // Apply encryption
230
+ return async function (req, res, next) {
231
+ console.log(`🚀 Express middleware triggered for: ${req.method} ${req.path}`);
232
+ try {
233
+ await decryptRequest(req, res, next);
165
234
  encryptResponse(req, res, next);
166
- });
167
- };
168
- }
169
-
170
- // Koa.js middleware
171
- function createKoaMiddleware(hybridCrypto, options = {}) {
172
- const {
173
- decryptRequest,
174
- encryptResponse
175
- } = createEncryptionMiddleware(hybridCrypto, options);
176
- return async (ctx, next) => {
177
- // Convert Koa context to Express-like req/res
178
- const req = ctx.request;
179
- const res = {
180
- json: data => {
181
- ctx.body = data;
182
- ctx.type = 'application/json';
183
- },
184
- status: code => {
185
- ctx.status = code;
186
- return res;
187
- },
188
- setHeader: (name, value) => {
189
- ctx.set(name, value);
190
- },
191
- removeHeader: name => {
192
- ctx.remove(name);
193
- }
194
- };
195
- await new Promise(resolve => {
196
- decryptRequest(req, res, err => {
197
- if (err) throw err;
198
- resolve();
199
- });
200
- });
201
- await next();
202
- if (ctx.headers[CRYPTO_CONFIG.HEADERS.ENCRYPTED] === 'true') {
203
- await new Promise(resolve => {
204
- encryptResponse(req, res, () => resolve());
205
- });
235
+ } catch (error) {
236
+ console.error('Middleware error:', error);
237
+ next(error);
206
238
  }
207
239
  };
208
240
  }
209
241
  module.exports = {
210
242
  createEncryptionMiddleware,
211
243
  createExpressMiddleware,
212
- createKoaMiddleware,
213
244
  HybridCrypto: require('./HybridCrypto')
214
245
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "secure-comms-hybrid",
3
- "version": "1.0.4",
3
+ "version": "1.0.5",
4
4
  "description": "Hybrid encryption (RSA + AES) for secure client-server communications",
5
5
  "main": "lib/backend/index.js",
6
6
  "browser": "dist/frontend/index.js",