ace-auth 1.2.1 → 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.
@@ -1,11 +1,11 @@
1
1
  import { IStore } from "../interfaces/IStore";
2
2
  export declare class MongoStore implements IStore {
3
3
  private model;
4
- constructor(mongooseModel: any);
5
- findAllByUser(userId: string): Promise<string[]>;
6
- deleteByUser(userId: string): Promise<void>;
4
+ constructor(mongooseCollection: any);
7
5
  set(key: string, value: string, ttlSeconds: number): Promise<void>;
8
6
  get(key: string): Promise<string | null>;
9
- delete(key: string): Promise<void>;
10
7
  touch(key: string, ttlSeconds: number): Promise<void>;
8
+ delete(key: string): Promise<void>;
9
+ findAllByUser(userId: string): Promise<string[]>;
10
+ deleteByUser(userId: string): Promise<void>;
11
11
  }
@@ -2,40 +2,51 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.MongoStore = void 0;
4
4
  class MongoStore {
5
- constructor(mongooseModel) {
6
- this.model = mongooseModel;
7
- }
8
- async findAllByUser(userId) {
9
- const docs = await this.model.findOne({ userId });
10
- if (!docs)
11
- return [];
12
- return docs.map((doc) => doc.data);
13
- }
14
- async deleteByUser(userId) {
15
- await this.model.deleteOne({ userId });
5
+ constructor(mongooseCollection) {
6
+ this.model = mongooseCollection;
16
7
  }
8
+ // ==============================
9
+ // REQUIRED BY AceAuth
10
+ // ==============================
17
11
  async set(key, value, ttlSeconds) {
18
12
  const expiresAt = new Date(Date.now() + ttlSeconds * 1000);
19
- // Upsert: Update if exists, Insert if new
20
- await this.model.updateOne({ _id: key }, { _id: key, data: value, expiresAt }, { upsert: true });
13
+ const parsed = JSON.parse(value);
14
+ await this.model.updateOne({ _id: key }, {
15
+ $set: {
16
+ _id: key,
17
+ data: value,
18
+ userId: parsed.id, // 🔥 REQUIRED for logoutAll / devices
19
+ expiresAt
20
+ }
21
+ }, { upsert: true });
21
22
  }
22
23
  async get(key) {
23
24
  const doc = await this.model.findOne({ _id: key });
24
25
  if (!doc)
25
26
  return null;
26
- // MongoDB TTL indexes usually handle cleanup, but we double-check here
27
27
  if (new Date() > doc.expiresAt) {
28
+ // Clean up expired session eagerly
29
+ await this.delete(key);
28
30
  return null;
29
31
  }
30
32
  return doc.data;
31
33
  }
32
- async delete(key) {
33
- await this.model.deleteOne({ _id: key });
34
- }
35
34
  async touch(key, ttlSeconds) {
36
35
  const expiresAt = new Date(Date.now() + ttlSeconds * 1000);
37
- // The "Slide": Just update the date
38
36
  await this.model.updateOne({ _id: key }, { $set: { expiresAt } });
39
37
  }
38
+ async delete(key) {
39
+ await this.model.deleteOne({ _id: key });
40
+ }
41
+ // ==============================
42
+ // DEVICE / USER MANAGEMENT
43
+ // ==============================
44
+ async findAllByUser(userId) {
45
+ const docs = await this.model.find({ userId });
46
+ return docs.map(doc => doc.data);
47
+ }
48
+ async deleteByUser(userId) {
49
+ await this.model.deleteMany({ userId });
50
+ }
40
51
  }
41
52
  exports.MongoStore = MongoStore;
@@ -1,25 +1,29 @@
1
1
  import { IStore } from '../interfaces/IStore';
2
2
  /**
3
- * SQL SCHEMA REQUIREMENT:
4
- * * CREATE TABLE auth_sessions (
5
- * sid VARCHAR(255) PRIMARY KEY,
6
- * sess JSON NOT NULL,
7
- * expired_at TIMESTAMPTZ NOT NULL
3
+ * REQUIRED SQL SCHEMA:
4
+ *
5
+ * CREATE TABLE auth_sessions (
6
+ * sid TEXT PRIMARY KEY,
7
+ * sess JSONB NOT NULL,
8
+ * user_id TEXT NOT NULL,
9
+ * expired_at TIMESTAMPTZ NOT NULL
8
10
  * );
9
- * * CREATE INDEX idx_auth_sessions_expired_at ON auth_sessions(expired_at);
11
+ *
12
+ * CREATE INDEX idx_auth_sessions_user_id ON auth_sessions(user_id);
13
+ * CREATE INDEX idx_auth_sessions_expired_at ON auth_sessions(expired_at);
10
14
  */
11
15
  interface PgPool {
12
16
  query(text: string, params?: any[]): Promise<any>;
13
17
  }
14
18
  export declare class PostgresStore implements IStore {
15
19
  private pool;
16
- private tableName;
20
+ private table;
17
21
  constructor(pool: PgPool, tableName?: string);
18
- findAllByUser(userId: string): Promise<string[]>;
19
- deleteByUser(userId: string): Promise<void>;
20
22
  set(key: string, value: string, ttlSeconds: number): Promise<void>;
21
23
  get(key: string): Promise<string | null>;
22
- delete(key: string): Promise<void>;
23
24
  touch(key: string, ttlSeconds: number): Promise<void>;
25
+ delete(key: string): Promise<void>;
26
+ findAllByUser(userId: string): Promise<string[]>;
27
+ deleteByUser(userId: string): Promise<void>;
24
28
  }
25
29
  export {};
@@ -2,71 +2,79 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.PostgresStore = void 0;
4
4
  class PostgresStore {
5
- // Allow user to customize table name
6
5
  constructor(pool, tableName = 'auth_sessions') {
7
6
  this.pool = pool;
8
- this.tableName = tableName;
9
- }
10
- async findAllByUser(userId) {
11
- const query = `
12
- SELECT sess FROM ${this.tableName}
13
- WHERE sess->>'userId' = $1 AND expired_at > NOW()
14
- `;
15
- const result = await this.pool.query(query, [userId]);
16
- // Extract sessions and return them as an array of strings
17
- return result.rows.map((row) => {
18
- const data = row.sess;
19
- return typeof data === 'string' ? data : JSON.stringify(data);
20
- });
21
- }
22
- async deleteByUser(userId) {
23
- const query = `
24
- DELETE FROM ${this.tableName}
25
- WHERE sess->>'userId' = $1
26
- `;
27
- await this.pool.query(query, [userId]);
7
+ // 🛡️ Prevent SQL injection via table name
8
+ if (!/^[a-zA-Z_]+$/.test(tableName)) {
9
+ throw new Error('Invalid table name');
10
+ }
11
+ this.table = tableName;
28
12
  }
13
+ // ==============================
14
+ // CORE SESSION OPERATIONS
15
+ // ==============================
29
16
  async set(key, value, ttlSeconds) {
30
17
  const expiresAt = new Date(Date.now() + ttlSeconds * 1000);
31
- // We use ON CONFLICT to handle "Upserts" (Update if exists, Insert if new)
18
+ const parsed = JSON.parse(value);
32
19
  const query = `
33
- INSERT INTO ${this.tableName} (sid, sess, expired_at)
34
- VALUES ($1, $2, $3)
35
- ON CONFLICT (sid)
36
- DO UPDATE SET sess = $2, expired_at = $3
20
+ INSERT INTO ${this.table} (sid, sess, user_id, expired_at)
21
+ VALUES ($1, $2, $3, $4)
22
+ ON CONFLICT (sid)
23
+ DO UPDATE SET
24
+ sess = EXCLUDED.sess,
25
+ user_id = EXCLUDED.user_id,
26
+ expired_at = EXCLUDED.expired_at
37
27
  `;
38
- await this.pool.query(query, [key, value, expiresAt]);
28
+ await this.pool.query(query, [
29
+ key,
30
+ parsed,
31
+ parsed.id, // 🔥 REQUIRED for logoutAll & device management
32
+ expiresAt
33
+ ]);
39
34
  }
40
35
  async get(key) {
41
- // We perform a "Lazy Delete" check here.
42
- // Even if the row exists, if it's expired, we treat it as null.
43
36
  const query = `
44
- SELECT sess FROM ${this.tableName}
45
- WHERE sid = $1 AND expired_at > NOW()
37
+ SELECT sess, expired_at
38
+ FROM ${this.table}
39
+ WHERE sid = $1
46
40
  `;
47
41
  const result = await this.pool.query(query, [key]);
48
- if (result.rows && result.rows.length > 0) {
49
- // Postgres returns JSON columns as objects, but our interface expects a string
50
- // so we might need to stringify it back, or just return the data depending on implementation.
51
- // Since ZenAuth expects a stringified payload:
52
- const data = result.rows[0].sess;
53
- return typeof data === 'string' ? data : JSON.stringify(data);
42
+ if (!result.rows.length)
43
+ return null;
44
+ const { sess, expired_at } = result.rows[0];
45
+ if (new Date() > expired_at) {
46
+ // Lazy cleanup
47
+ await this.delete(key);
48
+ return null;
54
49
  }
55
- return null;
56
- }
57
- async delete(key) {
58
- const query = `DELETE FROM ${this.tableName} WHERE sid = $1`;
59
- await this.pool.query(query, [key]);
50
+ return JSON.stringify(sess);
60
51
  }
61
52
  async touch(key, ttlSeconds) {
62
53
  const expiresAt = new Date(Date.now() + ttlSeconds * 1000);
63
- // Just update the timestamp to keep the session alive
64
54
  const query = `
65
- UPDATE ${this.tableName}
66
- SET expired_at = $1
55
+ UPDATE ${this.table}
56
+ SET expired_at = $1
67
57
  WHERE sid = $2
68
58
  `;
69
59
  await this.pool.query(query, [expiresAt, key]);
70
60
  }
61
+ async delete(key) {
62
+ await this.pool.query(`DELETE FROM ${this.table} WHERE sid = $1`, [key]);
63
+ }
64
+ // ==============================
65
+ // USER / DEVICE MANAGEMENT
66
+ // ==============================
67
+ async findAllByUser(userId) {
68
+ const query = `
69
+ SELECT sess
70
+ FROM ${this.table}
71
+ WHERE user_id = $1 AND expired_at > NOW()
72
+ `;
73
+ const result = await this.pool.query(query, [userId]);
74
+ return result.rows.map((row) => JSON.stringify(row.sess));
75
+ }
76
+ async deleteByUser(userId) {
77
+ await this.pool.query(`DELETE FROM ${this.table} WHERE user_id = $1`, [userId]);
78
+ }
71
79
  }
72
80
  exports.PostgresStore = PostgresStore;
package/dist/index.d.ts CHANGED
@@ -4,3 +4,4 @@ export { MemoryStore } from './adapters/MemoryStore';
4
4
  export { MongoStore } from './adapters/MongoStore';
5
5
  export { RedisStore } from './adapters/RedisStore';
6
6
  export { PostgresStore } from './adapters/PostgressStore';
7
+ export { gatekeeper } from './middleware/gatekeeper';
package/dist/index.js CHANGED
@@ -1,7 +1,7 @@
1
1
  "use strict";
2
2
  // src/index.ts
3
3
  Object.defineProperty(exports, "__esModule", { value: true });
4
- exports.PostgresStore = exports.RedisStore = exports.MongoStore = exports.MemoryStore = exports.AceAuth = void 0;
4
+ exports.gatekeeper = exports.PostgresStore = exports.RedisStore = exports.MongoStore = exports.MemoryStore = exports.AceAuth = void 0;
5
5
  // Export Core
6
6
  var AceAuth_1 = require("./core/AceAuth");
7
7
  Object.defineProperty(exports, "AceAuth", { enumerable: true, get: function () { return AceAuth_1.AceAuth; } });
@@ -14,3 +14,5 @@ var RedisStore_1 = require("./adapters/RedisStore");
14
14
  Object.defineProperty(exports, "RedisStore", { enumerable: true, get: function () { return RedisStore_1.RedisStore; } });
15
15
  var PostgressStore_1 = require("./adapters/PostgressStore");
16
16
  Object.defineProperty(exports, "PostgresStore", { enumerable: true, get: function () { return PostgressStore_1.PostgresStore; } });
17
+ var gatekeeper_1 = require("./middleware/gatekeeper");
18
+ Object.defineProperty(exports, "gatekeeper", { enumerable: true, get: function () { return gatekeeper_1.gatekeeper; } });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ace-auth",
3
- "version": "1.2.1",
3
+ "version": "1.2.4",
4
4
  "description": "Enterprise-grade identity management with graceful token rotation",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",