@metaadri/secureauth 1.2.3 → 1.2.4

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.
Files changed (2) hide show
  1. package/package.json +1 -1
  2. package/src/patcher.js +50 -32
package/package.json CHANGED
@@ -3,7 +3,7 @@
3
3
  "publishConfig": {
4
4
  "access": "public"
5
5
  },
6
- "version": "1.2.3",
6
+ "version": "1.2.4",
7
7
  "description": "SecureAuth CLI - Add enterprise authentication to any Express app in one command",
8
8
  "bin": {
9
9
  "secureauth": "bin/cli.js"
package/src/patcher.js CHANGED
@@ -188,14 +188,12 @@ function generateMigrationSql(dbType) {
188
188
  if (dbType === 'postgres') {
189
189
  return `-- SecureAuth: Add account lockout columns
190
190
  ALTER TABLE users ADD COLUMN IF NOT EXISTS failed_login_attempts INTEGER DEFAULT 0;
191
- ALTER TABLE users ADD COLUMN IF NOT EXISTS locked_until TEXT;
192
- ALTER TABLE users ADD COLUMN IF NOT EXISTS last_failed_login TEXT;
191
+ ALTER TABLE users ADD COLUMN IF NOT EXISTS locked_until TIMESTAMPTZ;
193
192
  `;
194
193
  }
195
194
  return `-- SecureAuth: Add account lockout columns
196
- ALTER TABLE users ADD COLUMN failed_login_attempts INTEGER DEFAULT 0;
197
- ALTER TABLE users ADD COLUMN locked_until TEXT;
198
- ALTER TABLE users ADD COLUMN last_failed_login TEXT;
195
+ ALTER TABLE users ADD COLUMN IF NOT EXISTS failed_login_attempts INTEGER DEFAULT 0;
196
+ ALTER TABLE users ADD COLUMN IF NOT EXISTS locked_until TEXT;
199
197
  `;
200
198
  }
201
199
 
@@ -218,7 +216,7 @@ function addEnvVars(content) {
218
216
  }
219
217
 
220
218
  function addHelper(content) {
221
- const loginRouteRegex = /(?:router|app)\s*\.\s*(?:post|get)\s*\(\s*['"](?:\/api\/)?(?:login|signin)['"]/;
219
+ const loginRouteRegex = /(?:router|app)\s*\.\s*(?:post|get)\s*\(\s*['"](?:\/(?:api\/)?)?(?:login|signin)['"]/;
222
220
  const loginMatch = content.match(loginRouteRegex);
223
221
  if (!loginMatch) return { content, modified: false };
224
222
 
@@ -253,27 +251,37 @@ function addIncrementReset(content, dbVar, paramStyle) {
253
251
  const incrementBlock = generateIncrementBlock(dbVar, paramStyle);
254
252
 
255
253
  const afterBrace = content.slice(blockStart + 1);
256
- const firstReturn = afterBrace.search(/\breturn\s+res\.status\(401\)/);
257
- if (firstReturn === -1) return { content, modified: false };
254
+ const errorResponsePatterns = [
255
+ /\breturn\s+res\.status\(40[13]\)/,
256
+ /\bres\.status\(40[13]\)/,
257
+ ];
258
+ let firstError = -1;
259
+ for (const p of errorResponsePatterns) {
260
+ const m = afterBrace.search(p);
261
+ if (m !== -1 && (firstError === -1 || m < firstError)) {
262
+ firstError = m;
263
+ }
264
+ }
265
+ if (firstError === -1) return { content, modified: false };
258
266
 
259
- const insertPos = blockStart + 1 + firstReturn;
267
+ const insertPos = blockStart + 1 + firstError;
260
268
  content = content.slice(0, insertPos) + incrementBlock + content.slice(insertPos);
261
269
 
262
270
  const closingBraceIndex = findMatchingBrace(content, blockStart);
263
271
  if (closingBraceIndex === -1) return { content, modified: false };
264
272
 
265
273
  const afterInvalidBlock = content.slice(closingBraceIndex + 1);
266
- const successPwMatch = afterInvalidBlock.match(/if\s*\(!is(?:Valid|PasswordValid)\)/);
267
- if (successPwMatch) {
268
- const secondBlockStart = afterInvalidBlock.indexOf('{', successPwMatch.index);
274
+ const secondInvalidMatch = afterInvalidBlock.match(/if\s*\(\s*!is(?:Valid|PasswordValid)\s*\)/);
275
+ if (secondInvalidMatch) {
276
+ const secondBlockStart = afterInvalidBlock.indexOf('{', secondInvalidMatch.index);
269
277
  if (secondBlockStart !== -1) {
270
278
  const secondClosing = findMatchingBrace(afterInvalidBlock, secondBlockStart);
271
279
  if (secondClosing !== -1) {
272
280
  const afterSecond = afterInvalidBlock.slice(secondClosing + 1);
273
281
  const resetBlock = generateResetBlock(dbVar, paramStyle);
274
- const successMatch = afterSecond.match(/\breturn\s+res\.status\(2\d{2}\)/);
275
- if (successMatch) {
276
- const insertAfterSecond = closingBraceIndex + 1 + secondClosing + 1 + successMatch.index;
282
+ const successPos = findSuccessResponse(afterSecond);
283
+ if (successPos !== -1) {
284
+ const insertAfterSecond = closingBraceIndex + 1 + secondClosing + 1 + successPos;
277
285
  content = content.slice(0, insertAfterSecond) + resetBlock + content.slice(insertAfterSecond);
278
286
  return { content, modified: true };
279
287
  }
@@ -281,23 +289,39 @@ function addIncrementReset(content, dbVar, paramStyle) {
281
289
  }
282
290
  }
283
291
 
284
- const afterInvalidBlockClean = content.slice(closingBraceIndex + 1);
285
- const awaitCompareMatch = afterInvalidBlockClean.match(/await\s+bcrypt\.compare\(/);
286
- if (awaitCompareMatch) {
292
+ const afterBlock = content.slice(closingBraceIndex + 1);
293
+ const hasAnotherCompare = afterBlock.match(/await\s+bcrypt\.compare\(/);
294
+ if (hasAnotherCompare) {
287
295
  return { content, modified: false };
288
296
  }
289
297
 
290
298
  const resetBlock = generateResetBlock(dbVar, paramStyle);
291
- const successMatch = afterInvalidBlockClean.match(/\breturn\s+res\.status\(2\d{2}\)/);
292
- if (successMatch) {
293
- const insertPos3 = closingBraceIndex + 1 + successMatch.index;
294
- content = content.slice(0, insertPos3) + resetBlock + content.slice(insertPos3);
299
+ const successPos = findSuccessResponse(afterBlock);
300
+ if (successPos !== -1) {
301
+ const insertPosReset = closingBraceIndex + 1 + successPos;
302
+ content = content.slice(0, insertPosReset) + resetBlock + content.slice(insertPosReset);
295
303
  return { content, modified: true };
296
304
  }
297
305
 
298
306
  return { content, modified: false };
299
307
  }
300
308
 
309
+ function findSuccessResponse(str) {
310
+ const patterns = [
311
+ /\breturn\s+res\.status\(2\d{2}\)\s*\.\s*json\(/,
312
+ /\breturn\s+res\.json\(/,
313
+ /\bres\.status\(2\d{2}\)\s*\.\s*json\(/,
314
+ /\bres\.json\(/
315
+ ];
316
+ for (const p of patterns) {
317
+ const m = str.match(p);
318
+ if (m) {
319
+ return m.index;
320
+ }
321
+ }
322
+ return -1;
323
+ }
324
+
301
325
  function addStatus423Return(content, dbVar, paramStyle) {
302
326
  const lockedResponse = `\n return res.status(423).json({
303
327
  error: 'Account locked',
@@ -334,23 +358,17 @@ function findMatchingBrace(str, openPos) {
334
358
  }
335
359
 
336
360
  function writeMigration(targetDir, dbType) {
337
- const migrationsDir = path.join(targetDir, 'migrations');
338
- if (!fs.existsSync(migrationsDir)) {
339
- fs.mkdirSync(migrationsDir, { recursive: true });
340
- }
341
-
342
- const timestamp = new Date().toISOString().replace(/[^0-9]/g, '').slice(0, 14);
343
- const fileName = `${timestamp}_add_account_lockout.sql`;
344
- const filePath = path.join(migrationsDir, fileName);
361
+ const fileName = 'migration_lockout.sql';
362
+ const filePath = path.join(targetDir, fileName);
345
363
 
346
364
  if (fs.existsSync(filePath)) {
347
- logger.warn(`Migration ${fileName} already exists — skipping`);
365
+ logger.warn(`${fileName} already exists — skipping`);
348
366
  return null;
349
367
  }
350
368
 
351
369
  const sql = generateMigrationSql(dbType);
352
370
  fs.writeFileSync(filePath, sql, 'utf-8');
353
- logger.success(`Created migration: migrations/${fileName}`);
371
+ logger.success(`Created ${fileName}`);
354
372
  return filePath;
355
373
  }
356
374