@kyro-cms/core 0.1.5 → 0.1.7
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.
- package/dist/WebhookService-BCgL1bLF.d.cts +112 -0
- package/dist/WebhookService-BPVJUgTl.d.ts +112 -0
- package/dist/{base-DlhVlwnN.d.cts → base-B0Y6isUJ.d.cts} +1 -1
- package/dist/{base-CQkFzqQl.d.ts → base-DaP-5PPG.d.ts} +1 -1
- package/dist/bootstrap-BMWVB2T6.cjs +31 -0
- package/dist/{bootstrap-X6TP3NKX.cjs.map → bootstrap-BMWVB2T6.cjs.map} +1 -1
- package/dist/bootstrap-LL6O7PWO.js +6 -0
- package/dist/{bootstrap-BDTTUGY2.js.map → bootstrap-LL6O7PWO.js.map} +1 -1
- package/dist/{chunk-3VZCX4DF.cjs → chunk-42JPONZU.cjs} +77 -14
- package/dist/chunk-42JPONZU.cjs.map +1 -0
- package/dist/{chunk-MHS6CPO5.cjs → chunk-4M5PHMUE.cjs} +66 -346
- package/dist/chunk-4M5PHMUE.cjs.map +1 -0
- package/dist/chunk-4PWRCMTQ.cjs +15 -0
- package/dist/chunk-4PWRCMTQ.cjs.map +1 -0
- package/dist/chunk-6COM32WF.js +47 -0
- package/dist/chunk-6COM32WF.js.map +1 -0
- package/dist/chunk-6MSSF46R.js +941 -0
- package/dist/chunk-6MSSF46R.js.map +1 -0
- package/dist/{chunk-TZFJMPCH.cjs → chunk-7YITG2US.cjs} +9 -18
- package/dist/chunk-7YITG2US.cjs.map +1 -0
- package/dist/{chunk-A3RQWHKD.cjs → chunk-BLMFBDBG.cjs} +56 -6
- package/dist/chunk-BLMFBDBG.cjs.map +1 -0
- package/dist/{chunk-EINVJPFM.js → chunk-BTOE3VUK.js} +65 -3
- package/dist/chunk-BTOE3VUK.js.map +1 -0
- package/dist/chunk-E5X75WNB.js +497 -0
- package/dist/chunk-E5X75WNB.js.map +1 -0
- package/dist/chunk-E63IF3MD.cjs +951 -0
- package/dist/chunk-E63IF3MD.cjs.map +1 -0
- package/dist/{chunk-K7QF2QCM.cjs → chunk-FTSSDDZQ.cjs} +7 -3
- package/dist/chunk-FTSSDDZQ.cjs.map +1 -0
- package/dist/chunk-G7VZBCD6.cjs +35 -0
- package/dist/{chunk-5BLDMQED.cjs.map → chunk-G7VZBCD6.cjs.map} +1 -1
- package/dist/{chunk-VMSRTAH7.js → chunk-GLCPGZPM.js} +56 -6
- package/dist/chunk-GLCPGZPM.js.map +1 -0
- package/dist/{chunk-V3B25QOK.cjs → chunk-GVFB5C6O.cjs} +74 -2
- package/dist/chunk-GVFB5C6O.cjs.map +1 -0
- package/dist/chunk-HVSQDZZJ.cjs +765 -0
- package/dist/chunk-HVSQDZZJ.cjs.map +1 -0
- package/dist/chunk-HYC4GNHX.js +758 -0
- package/dist/chunk-HYC4GNHX.js.map +1 -0
- package/dist/chunk-KDVDIZ4Y.cjs +3479 -0
- package/dist/chunk-KDVDIZ4Y.cjs.map +1 -0
- package/dist/{chunk-OG3KX56O.js → chunk-KWGNR4HM.js} +7 -3
- package/dist/chunk-KWGNR4HM.js.map +1 -0
- package/dist/chunk-LIJVWQKU.cjs +256 -0
- package/dist/chunk-LIJVWQKU.cjs.map +1 -0
- package/dist/{chunk-XTZSUDSI.js → chunk-LTRCYJAG.js} +3 -18
- package/dist/chunk-LTRCYJAG.js.map +1 -0
- package/dist/{chunk-UEYC46RL.js → chunk-OUGKLCYF.js} +71 -8
- package/dist/chunk-OUGKLCYF.js.map +1 -0
- package/dist/chunk-RONAX6UU.js +3456 -0
- package/dist/chunk-RONAX6UU.js.map +1 -0
- package/dist/{chunk-C74MQIRL.js → chunk-RRYXQMZG.js} +66 -344
- package/dist/chunk-RRYXQMZG.js.map +1 -0
- package/dist/{chunk-QUJ4OLSC.js → chunk-U74F3YZU.js} +87 -7
- package/dist/chunk-U74F3YZU.js.map +1 -0
- package/dist/chunk-VIONYQ2K.cjs +517 -0
- package/dist/chunk-VIONYQ2K.cjs.map +1 -0
- package/dist/chunk-VSTRLXMQ.cjs +50 -0
- package/dist/chunk-VSTRLXMQ.cjs.map +1 -0
- package/dist/chunk-YT7HXXVN.js +13 -0
- package/dist/chunk-YT7HXXVN.js.map +1 -0
- package/dist/chunk-Z6ZWNWWR.js +30 -0
- package/dist/{chunk-NSBPE2FW.js.map → chunk-Z6ZWNWWR.js.map} +1 -1
- package/dist/cli/index.cjs +11 -7
- package/dist/cli/index.cjs.map +1 -1
- package/dist/cli/index.js +11 -7
- package/dist/cli/index.js.map +1 -1
- package/dist/drizzle/index.cjs +20 -17
- package/dist/drizzle/index.d.cts +4 -4
- package/dist/drizzle/index.d.ts +4 -4
- package/dist/drizzle/index.js +4 -5
- package/dist/graphql/index.cjs +4 -4
- package/dist/graphql/index.d.cts +3 -2
- package/dist/graphql/index.d.ts +3 -2
- package/dist/graphql/index.js +2 -2
- package/dist/{index-DI0DRPNv.d.cts → index-BwE4NueJ.d.cts} +1 -1
- package/dist/{index-CMUNCIWQ.d.ts → index-DUKmDSeC.d.cts} +96 -24
- package/dist/{index-BMySjW6o.d.cts → index-DtBi3zP0.d.ts} +96 -24
- package/dist/{index-4fJKLFK2.d.ts → index-DupWTmW6.d.ts} +1 -1
- package/dist/index.cjs +3317 -352
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +379 -105
- package/dist/index.d.ts +379 -105
- package/dist/index.js +3211 -310
- package/dist/index.js.map +1 -1
- package/dist/media-HOT3O7RW.js +4 -0
- package/dist/media-HOT3O7RW.js.map +1 -0
- package/dist/media-WKP5AOX2.cjs +17 -0
- package/dist/media-WKP5AOX2.cjs.map +1 -0
- package/dist/mongodb/index.cjs +1 -1
- package/dist/mongodb/index.d.cts +2 -2
- package/dist/mongodb/index.d.ts +2 -2
- package/dist/mongodb/index.js +1 -1
- package/dist/mysql-media-AI6YK767.cjs +48 -0
- package/dist/mysql-media-AI6YK767.cjs.map +1 -0
- package/dist/mysql-media-CDZUS7YX.js +45 -0
- package/dist/mysql-media-CDZUS7YX.js.map +1 -0
- package/dist/postgres-auth-adapter-EVRPO7BQ.cjs +14 -0
- package/dist/{postgres-auth-adapter-VK6GY7LX.cjs.map → postgres-auth-adapter-EVRPO7BQ.cjs.map} +1 -1
- package/dist/postgres-auth-adapter-OTRWSTT5.js +5 -0
- package/dist/{postgres-auth-adapter-REJFUMP7.js.map → postgres-auth-adapter-OTRWSTT5.js.map} +1 -1
- package/dist/redis-adapter-2N6VA7BI.cjs +13 -0
- package/dist/{redis-adapter-LBLNKGNS.cjs.map → redis-adapter-2N6VA7BI.cjs.map} +1 -1
- package/dist/redis-adapter-RA24FNCX.js +4 -0
- package/dist/{redis-adapter-4YDY4LWE.js.map → redis-adapter-RA24FNCX.js.map} +1 -1
- package/dist/rest/index.cjs +7 -5
- package/dist/rest/index.d.cts +29 -3
- package/dist/rest/index.d.ts +29 -3
- package/dist/rest/index.js +5 -3
- package/dist/schema-CNB2DDTX.js +6 -0
- package/dist/schema-CNB2DDTX.js.map +1 -0
- package/dist/schema-Y777CQQS.cjs +67 -0
- package/dist/schema-Y777CQQS.cjs.map +1 -0
- package/dist/templates/index.cjs +24 -28
- package/dist/templates/index.d.cts +2 -4
- package/dist/templates/index.d.ts +2 -4
- package/dist/templates/index.js +2 -2
- package/dist/trpc/index.cjs +12 -12
- package/dist/trpc/index.d.cts +19 -14
- package/dist/trpc/index.d.ts +19 -14
- package/dist/trpc/index.js +3 -3
- package/dist/{types-BGM5MV_K.d.cts → types-BM0s_YOy.d.cts} +67 -35
- package/dist/{types-BGM5MV_K.d.ts → types-BM0s_YOy.d.ts} +67 -35
- package/dist/ws/index.cjs +1 -1
- package/dist/ws/index.js +1 -1
- package/package.json +11 -1
- package/dist/bootstrap-BDTTUGY2.js +0 -4
- package/dist/bootstrap-X6TP3NKX.cjs +0 -29
- package/dist/chunk-3QX6KG2S.js +0 -2125
- package/dist/chunk-3QX6KG2S.js.map +0 -1
- package/dist/chunk-3VZCX4DF.cjs.map +0 -1
- package/dist/chunk-5BLDMQED.cjs +0 -18
- package/dist/chunk-7G6EVYCU.cjs +0 -94
- package/dist/chunk-7G6EVYCU.cjs.map +0 -1
- package/dist/chunk-A3RQWHKD.cjs.map +0 -1
- package/dist/chunk-C74MQIRL.js.map +0 -1
- package/dist/chunk-EINVJPFM.js.map +0 -1
- package/dist/chunk-F5B64H5S.cjs +0 -2149
- package/dist/chunk-F5B64H5S.cjs.map +0 -1
- package/dist/chunk-K7QF2QCM.cjs.map +0 -1
- package/dist/chunk-LRTZJJPD.js +0 -86
- package/dist/chunk-LRTZJJPD.js.map +0 -1
- package/dist/chunk-MHS6CPO5.cjs.map +0 -1
- package/dist/chunk-NSBPE2FW.js +0 -15
- package/dist/chunk-OG3KX56O.js.map +0 -1
- package/dist/chunk-QUJ4OLSC.js.map +0 -1
- package/dist/chunk-R3XIBBAW.cjs +0 -34
- package/dist/chunk-R3XIBBAW.cjs.map +0 -1
- package/dist/chunk-SDMNUYVU.js +0 -30
- package/dist/chunk-SDMNUYVU.js.map +0 -1
- package/dist/chunk-TZFJMPCH.cjs.map +0 -1
- package/dist/chunk-UEG7KMKC.cjs +0 -228
- package/dist/chunk-UEG7KMKC.cjs.map +0 -1
- package/dist/chunk-UEYC46RL.js.map +0 -1
- package/dist/chunk-V3B25QOK.cjs.map +0 -1
- package/dist/chunk-VMSRTAH7.js.map +0 -1
- package/dist/chunk-XTZSUDSI.js.map +0 -1
- package/dist/chunk-YD7Y25W7.cjs +0 -176
- package/dist/chunk-YD7Y25W7.cjs.map +0 -1
- package/dist/chunk-YPAFJ7EV.js +0 -225
- package/dist/chunk-YPAFJ7EV.js.map +0 -1
- package/dist/database-7CJOXEZR.js +0 -5
- package/dist/database-7CJOXEZR.js.map +0 -1
- package/dist/database-QOIV44GT.cjs +0 -22
- package/dist/database-QOIV44GT.cjs.map +0 -1
- package/dist/postgres-auth-adapter-REJFUMP7.js +0 -5
- package/dist/postgres-auth-adapter-VK6GY7LX.cjs +0 -14
- package/dist/redis-adapter-4YDY4LWE.js +0 -4
- package/dist/redis-adapter-LBLNKGNS.cjs +0 -13
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { users, sessions, passwordHistory, lockouts } from './chunk-
|
|
2
|
-
import { eq, and, gt, desc } from 'drizzle-orm';
|
|
1
|
+
import { users, sessions, passwordHistory, lockouts, auditLogs } from './chunk-LTRCYJAG.js';
|
|
2
|
+
import { eq, and, gt, desc, sql } from 'drizzle-orm';
|
|
3
3
|
import bcrypt from 'bcryptjs';
|
|
4
4
|
import { randomBytes } from 'crypto';
|
|
5
5
|
|
|
@@ -15,9 +15,10 @@ var PostgresAuthAdapter = class {
|
|
|
15
15
|
this.refreshTokenTTL = options.refreshTokenTTL || 604800;
|
|
16
16
|
}
|
|
17
17
|
async createUser(data) {
|
|
18
|
+
const passwordHash = await this.hashPassword(data.password);
|
|
18
19
|
const [user] = await this.db.insert(users).values({
|
|
19
20
|
email: data.email.toLowerCase(),
|
|
20
|
-
passwordHash
|
|
21
|
+
passwordHash,
|
|
21
22
|
role: data.role || "customer",
|
|
22
23
|
tenantId: data.tenantId
|
|
23
24
|
}).returning();
|
|
@@ -52,8 +53,13 @@ var PostgresAuthAdapter = class {
|
|
|
52
53
|
await this.db.delete(users).where(eq(users.id, id));
|
|
53
54
|
return true;
|
|
54
55
|
}
|
|
55
|
-
async verifyPassword(
|
|
56
|
-
|
|
56
|
+
async verifyPassword(email, password) {
|
|
57
|
+
const user = await this.findUserByEmail(email);
|
|
58
|
+
if (!user) return null;
|
|
59
|
+
const [stored] = await this.db.select().from(users).where(eq(users.email, email.toLowerCase())).limit(1);
|
|
60
|
+
if (!stored?.passwordHash) return null;
|
|
61
|
+
const valid = await bcrypt.compare(password, stored.passwordHash);
|
|
62
|
+
return valid ? user : null;
|
|
57
63
|
}
|
|
58
64
|
async hashPassword(password) {
|
|
59
65
|
return bcrypt.hash(password, 12);
|
|
@@ -136,6 +142,80 @@ var PostgresAuthAdapter = class {
|
|
|
136
142
|
async resetAttempts(userId) {
|
|
137
143
|
await this.updateUser(userId, { failedLoginAttempts: 0 });
|
|
138
144
|
}
|
|
145
|
+
async findAuditLogs(filter) {
|
|
146
|
+
const {
|
|
147
|
+
limit = 50,
|
|
148
|
+
offset = 0,
|
|
149
|
+
userId,
|
|
150
|
+
action,
|
|
151
|
+
resource,
|
|
152
|
+
resourceId,
|
|
153
|
+
success,
|
|
154
|
+
startDate,
|
|
155
|
+
endDate
|
|
156
|
+
} = filter;
|
|
157
|
+
const conditions = [];
|
|
158
|
+
if (userId) conditions.push(eq(auditLogs.userId, userId));
|
|
159
|
+
if (action) {
|
|
160
|
+
if (Array.isArray(action)) {
|
|
161
|
+
conditions.push(sql`${auditLogs.action} = ANY(${action})`);
|
|
162
|
+
} else {
|
|
163
|
+
conditions.push(eq(auditLogs.action, action));
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
if (resource) conditions.push(eq(auditLogs.resource, resource));
|
|
167
|
+
if (resourceId) conditions.push(eq(auditLogs.resourceId, resourceId));
|
|
168
|
+
if (success !== void 0) conditions.push(eq(auditLogs.success, success));
|
|
169
|
+
if (startDate) conditions.push(sql`${auditLogs.timestamp} >= ${startDate}`);
|
|
170
|
+
if (endDate) conditions.push(sql`${auditLogs.timestamp} <= ${endDate}`);
|
|
171
|
+
const whereClause = conditions.length > 0 ? and(...conditions) : void 0;
|
|
172
|
+
const countResult = await this.db.select({ count: sql`count(*)` }).from(auditLogs).where(whereClause);
|
|
173
|
+
const logs = await this.db.select().from(auditLogs).where(whereClause).orderBy(desc(auditLogs.timestamp)).limit(limit).offset(offset);
|
|
174
|
+
return {
|
|
175
|
+
logs: logs.map((log) => ({
|
|
176
|
+
id: log.id,
|
|
177
|
+
timestamp: log.timestamp,
|
|
178
|
+
action: log.action,
|
|
179
|
+
userId: log.userId || void 0,
|
|
180
|
+
userEmail: log.userEmail || void 0,
|
|
181
|
+
role: log.role || void 0,
|
|
182
|
+
resource: log.resource,
|
|
183
|
+
resourceId: log.resourceId || void 0,
|
|
184
|
+
changes: log.changes || void 0,
|
|
185
|
+
ipAddress: log.ipAddress || void 0,
|
|
186
|
+
userAgent: log.userAgent || void 0,
|
|
187
|
+
success: log.success,
|
|
188
|
+
error: log.error || void 0,
|
|
189
|
+
metadata: log.metadata || void 0
|
|
190
|
+
})),
|
|
191
|
+
total: Number(countResult[0]?.count || 0)
|
|
192
|
+
};
|
|
193
|
+
}
|
|
194
|
+
async createAuditLog(data) {
|
|
195
|
+
const id = crypto.randomUUID();
|
|
196
|
+
const timestamp = /* @__PURE__ */ new Date();
|
|
197
|
+
await this.db.insert(auditLogs).values({
|
|
198
|
+
id,
|
|
199
|
+
action: data.action,
|
|
200
|
+
userId: data.userId,
|
|
201
|
+
userEmail: data.userEmail,
|
|
202
|
+
role: data.role,
|
|
203
|
+
resource: data.resource,
|
|
204
|
+
resourceId: data.resourceId,
|
|
205
|
+
changes: data.changes,
|
|
206
|
+
ipAddress: data.ipAddress,
|
|
207
|
+
userAgent: data.userAgent,
|
|
208
|
+
success: data.success,
|
|
209
|
+
error: data.error,
|
|
210
|
+
metadata: data.metadata,
|
|
211
|
+
timestamp
|
|
212
|
+
});
|
|
213
|
+
return {
|
|
214
|
+
...data,
|
|
215
|
+
id,
|
|
216
|
+
timestamp
|
|
217
|
+
};
|
|
218
|
+
}
|
|
139
219
|
userToAuthUser(user) {
|
|
140
220
|
return {
|
|
141
221
|
id: user.id,
|
|
@@ -166,5 +246,5 @@ var PostgresAuthAdapter = class {
|
|
|
166
246
|
};
|
|
167
247
|
|
|
168
248
|
export { PostgresAuthAdapter };
|
|
169
|
-
//# sourceMappingURL=chunk-
|
|
170
|
-
//# sourceMappingURL=chunk-
|
|
249
|
+
//# sourceMappingURL=chunk-U74F3YZU.js.map
|
|
250
|
+
//# sourceMappingURL=chunk-U74F3YZU.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/database/drizzle/postgres-auth-adapter.ts"],"names":[],"mappings":"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","file":"chunk-U74F3YZU.js","sourcesContent":["import type { PostgresJsDatabase } from \"drizzle-orm/postgres-js\";\nimport { eq, and, gt, desc, sql } from \"drizzle-orm\";\nimport bcrypt from \"bcryptjs\";\nimport { randomBytes } from \"crypto\";\nimport type {\n AuthAdapter,\n AuthUser,\n Session,\n UserRole,\n} from \"../../auth/types.js\";\nimport {\n users,\n sessions,\n passwordHistory,\n auditLogs,\n lockouts,\n type AuthUser as AuthUserRow,\n} from \"./schema/auth.js\";\nimport type {\n AuditLog,\n AuditLogFilter,\n} from \"../../auth/security/audit-log.js\";\n\nexport interface PostgresAuthAdapterOptions {\n db: PostgresJsDatabase;\n prefix?: string;\n sessionTTL?: number;\n refreshTokenTTL?: number;\n}\n\nexport class PostgresAuthAdapter implements AuthAdapter {\n private db: PostgresJsDatabase;\n private prefix: string;\n private sessionTTL: number;\n private refreshTokenTTL: number;\n\n constructor(options: PostgresAuthAdapterOptions) {\n this.db = options.db;\n this.prefix = options.prefix || \"kyro:\";\n this.sessionTTL = options.sessionTTL || 86400;\n this.refreshTokenTTL = options.refreshTokenTTL || 604800;\n }\n\n async createUser(data: {\n email: string;\n password: string;\n role?: UserRole;\n tenantId?: string;\n }): Promise<AuthUser> {\n const passwordHash = await this.hashPassword(data.password);\n const [user] = await this.db\n .insert(users)\n .values({\n email: data.email.toLowerCase(),\n passwordHash,\n role: (data.role || \"customer\") as string,\n tenantId: data.tenantId,\n })\n .returning();\n\n return this.userToAuthUser(user);\n }\n\n async findUserByEmail(email: string): Promise<AuthUser | null> {\n const [user] = await this.db\n .select()\n .from(users)\n .where(eq(users.email, email.toLowerCase()))\n .limit(1);\n\n return user ? this.userToAuthUser(user) : null;\n }\n\n async findUserById(id: string): Promise<AuthUser | null> {\n const [user] = await this.db\n .select()\n .from(users)\n .where(eq(users.id, id))\n .limit(1);\n\n return user ? this.userToAuthUser(user) : null;\n }\n\n async updateUser(\n id: string,\n data: Partial<AuthUser>,\n ): Promise<AuthUser | null> {\n const dbData: Record<string, unknown> = { updatedAt: new Date() };\n if (data.email !== undefined) dbData.email = data.email;\n if (data.passwordHash !== undefined)\n dbData.passwordHash = data.passwordHash;\n if (data.role !== undefined) dbData.role = data.role;\n if (data.tenantId !== undefined) dbData.tenantId = data.tenantId;\n if (data.emailVerified !== undefined)\n dbData.emailVerified = data.emailVerified;\n if (data.locked !== undefined) dbData.locked = data.locked;\n if (data.lastLogin !== undefined)\n dbData.lastLogin = data.lastLogin ? new Date(data.lastLogin) : null;\n if (data.failedLoginAttempts !== undefined)\n dbData.failedLoginAttempts = data.failedLoginAttempts;\n\n const [user] = await this.db\n .update(users)\n .set(dbData)\n .where(eq(users.id, id))\n .returning();\n\n return user ? this.userToAuthUser(user) : null;\n }\n\n async deleteUser(id: string): Promise<boolean> {\n await this.db.delete(users).where(eq(users.id, id));\n return true;\n }\n\n async verifyPassword(\n email: string,\n password: string,\n ): Promise<AuthUser | null> {\n const user = await this.findUserByEmail(email);\n if (!user) return null;\n const [stored] = await this.db\n .select()\n .from(users)\n .where(eq(users.email, email.toLowerCase()))\n .limit(1);\n if (!stored?.passwordHash) return null;\n const valid = await bcrypt.compare(password, stored.passwordHash);\n return valid ? user : null;\n }\n\n async hashPassword(password: string): Promise<string> {\n return bcrypt.hash(password, 12);\n }\n\n async createSession(\n userId: string,\n data?: { ipAddress?: string; userAgent?: string },\n ): Promise<Session> {\n const token = randomBytes(32).toString(\"base64url\");\n const refreshToken = randomBytes(32).toString(\"base64url\");\n const expiresAt = new Date(Date.now() + this.sessionTTL * 1000);\n const refreshExpiresAt = new Date(Date.now() + this.refreshTokenTTL * 1000);\n\n const [session] = await this.db\n .insert(sessions)\n .values({\n userId,\n token,\n refreshToken,\n ipAddress: data?.ipAddress,\n userAgent: data?.userAgent,\n expiresAt,\n })\n .returning();\n\n return this.sessionToSession(session);\n }\n\n async findSessionByToken(token: string): Promise<Session | null> {\n const [session] = await this.db\n .select()\n .from(sessions)\n .where(and(eq(sessions.token, token), gt(sessions.expiresAt, new Date())))\n .limit(1);\n\n return session ? this.sessionToSession(session) : null;\n }\n\n async deleteSession(sessionId: string): Promise<boolean> {\n await this.db.delete(sessions).where(eq(sessions.id, sessionId));\n return true;\n }\n\n async deleteUserSessions(userId: string): Promise<number> {\n await this.db.delete(sessions).where(eq(sessions.userId, userId));\n return 1;\n }\n\n async addPasswordToHistory(\n userId: string,\n passwordHash: string,\n ): Promise<void> {\n await this.db.insert(passwordHistory).values({\n userId,\n passwordHash,\n });\n }\n\n async getPasswordHistory(\n userId: string,\n count: number = 5,\n ): Promise<string[]> {\n const history = await this.db\n .select({ passwordHash: passwordHistory.passwordHash })\n .from(passwordHistory)\n .where(eq(passwordHistory.userId, userId))\n .orderBy(desc(passwordHistory.createdAt))\n .limit(count);\n\n return history.map((h) => h.passwordHash);\n }\n\n async isPasswordInHistory(\n password: string,\n userId: string,\n historyCount: number = 5,\n ): Promise<boolean> {\n const history = await this.getPasswordHistory(userId, historyCount);\n\n for (const hash of history) {\n if (await this.verifyPassword(password, hash)) {\n return true;\n }\n }\n\n return false;\n }\n\n async isLocked(userId: string): Promise<boolean> {\n const [lockout] = await this.db\n .select()\n .from(lockouts)\n .where(\n and(eq(lockouts.userId, userId), gt(lockouts.lockedUntil, new Date())),\n )\n .limit(1);\n\n return !!lockout;\n }\n\n async getLockout(userId: string): Promise<{ lockedUntil: Date } | null> {\n const [lockout] = await this.db\n .select()\n .from(lockouts)\n .where(\n and(eq(lockouts.userId, userId), gt(lockouts.lockedUntil, new Date())),\n )\n .limit(1);\n\n return lockout ? { lockedUntil: lockout.lockedUntil } : null;\n }\n\n async recordFailedAttempt(\n userId: string,\n ipAddress?: string,\n ): Promise<{ attempts: number; locked: boolean }> {\n const user = await this.findUserById(userId);\n const attempts = (user?.failedLoginAttempts || 0) + 1;\n\n await this.updateUser(userId, { failedLoginAttempts: attempts });\n\n const maxAttempts = 5;\n const locked = attempts >= maxAttempts;\n\n if (locked) {\n const lockoutDuration = 15 * 60 * 1000;\n await this.db.insert(lockouts).values({\n userId,\n ipAddress,\n reason: \"Too many failed login attempts\",\n lockedUntil: new Date(Date.now() + lockoutDuration),\n });\n }\n\n return { attempts, locked };\n }\n\n async resetAttempts(userId: string): Promise<void> {\n await this.updateUser(userId, { failedLoginAttempts: 0 });\n }\n\n async findAuditLogs(\n filter: AuditLogFilter,\n ): Promise<{ logs: AuditLog[]; total: number }> {\n const {\n limit = 50,\n offset = 0,\n userId,\n action,\n resource,\n resourceId,\n success,\n startDate,\n endDate,\n } = filter;\n\n const conditions = [];\n if (userId) conditions.push(eq(auditLogs.userId, userId));\n if (action) {\n if (Array.isArray(action)) {\n conditions.push(sql`${auditLogs.action} = ANY(${action})`);\n } else {\n conditions.push(eq(auditLogs.action, action));\n }\n }\n if (resource) conditions.push(eq(auditLogs.resource, resource));\n if (resourceId) conditions.push(eq(auditLogs.resourceId, resourceId));\n if (success !== undefined) conditions.push(eq(auditLogs.success, success));\n if (startDate) conditions.push(sql`${auditLogs.timestamp} >= ${startDate}`);\n if (endDate) conditions.push(sql`${auditLogs.timestamp} <= ${endDate}`);\n\n const whereClause = conditions.length > 0 ? and(...conditions) : undefined;\n\n const countResult = await this.db\n .select({ count: sql<number>`count(*)` })\n .from(auditLogs)\n .where(whereClause);\n\n const logs = await this.db\n .select()\n .from(auditLogs)\n .where(whereClause)\n .orderBy(desc(auditLogs.timestamp))\n .limit(limit)\n .offset(offset);\n\n return {\n logs: logs.map((log) => ({\n id: log.id,\n timestamp: log.timestamp,\n action: log.action as AuditLog[\"action\"],\n userId: log.userId || undefined,\n userEmail: log.userEmail || undefined,\n role: log.role || undefined,\n resource: log.resource,\n resourceId: log.resourceId || undefined,\n changes: log.changes || undefined,\n ipAddress: log.ipAddress || undefined,\n userAgent: log.userAgent || undefined,\n success: log.success,\n error: log.error || undefined,\n metadata: log.metadata || undefined,\n })),\n total: Number(countResult[0]?.count || 0),\n };\n }\n\n async createAuditLog(\n data: Omit<AuditLog, \"id\" | \"timestamp\">,\n ): Promise<AuditLog> {\n const id = crypto.randomUUID();\n const timestamp = new Date();\n\n await this.db.insert(auditLogs).values({\n id,\n action: data.action,\n userId: data.userId,\n userEmail: data.userEmail,\n role: data.role,\n resource: data.resource,\n resourceId: data.resourceId,\n changes: data.changes,\n ipAddress: data.ipAddress,\n userAgent: data.userAgent,\n success: data.success,\n error: data.error,\n metadata: data.metadata,\n timestamp,\n });\n\n return {\n ...data,\n id,\n timestamp,\n };\n }\n\n private userToAuthUser(user: AuthUserRow): AuthUser {\n return {\n id: user.id,\n email: user.email,\n passwordHash: user.passwordHash || undefined,\n role: user.role as UserRole,\n tenantId: user.tenantId || undefined,\n emailVerified: user.emailVerified || false,\n locked: user.locked || false,\n lastLogin: user.lastLogin?.toISOString(),\n failedLoginAttempts: user.failedLoginAttempts || 0,\n createdAt: user.createdAt.toISOString(),\n updatedAt: user.updatedAt.toISOString(),\n };\n }\n\n private sessionToSession(session: typeof sessions.$inferSelect): Session {\n return {\n id: session.id,\n userId: session.userId,\n token: session.token,\n refreshToken: session.refreshToken || undefined,\n expiresAt: session.expiresAt.toISOString(),\n createdAt: session.createdAt.toISOString(),\n ipAddress: session.ipAddress || undefined,\n userAgent: session.userAgent || undefined,\n };\n }\n}\n"]}
|
|
@@ -0,0 +1,517 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var crypto = require('crypto');
|
|
4
|
+
|
|
5
|
+
// src/access/types.ts
|
|
6
|
+
async function evaluateAccess(access, args) {
|
|
7
|
+
if (typeof access === "boolean") {
|
|
8
|
+
return access;
|
|
9
|
+
}
|
|
10
|
+
if (typeof access === "function") {
|
|
11
|
+
return await access(args);
|
|
12
|
+
}
|
|
13
|
+
return true;
|
|
14
|
+
}
|
|
15
|
+
function mergeWhereClauses(...whereClauses) {
|
|
16
|
+
const result = {};
|
|
17
|
+
for (const clause of whereClauses) {
|
|
18
|
+
if (clause && typeof clause === "object") {
|
|
19
|
+
Object.assign(result, clause);
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
return result;
|
|
23
|
+
}
|
|
24
|
+
function getWhereClause(access, args) {
|
|
25
|
+
return evaluateAccess(access, args).then((result) => {
|
|
26
|
+
if (result === true) return void 0;
|
|
27
|
+
if (result === false) return { _id: { $eq: null } };
|
|
28
|
+
return result;
|
|
29
|
+
});
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
// src/webhooks/types.ts
|
|
33
|
+
var WEBHOOK_EVENTS = {
|
|
34
|
+
COLLECTION_CREATE: "collection.create",
|
|
35
|
+
COLLECTION_UPDATE: "collection.update",
|
|
36
|
+
COLLECTION_DELETE: "collection.delete",
|
|
37
|
+
MEDIA_UPLOAD: "media.upload",
|
|
38
|
+
MEDIA_DELETE: "media.delete",
|
|
39
|
+
AUTH_LOGIN: "auth.login",
|
|
40
|
+
AUTH_REGISTER: "auth.register",
|
|
41
|
+
AUTH_LOGOUT: "auth.logout",
|
|
42
|
+
ORDER_CREATED: "order.created",
|
|
43
|
+
ORDER_PAID: "order.paid",
|
|
44
|
+
ORDER_SHIPPED: "order.shipped",
|
|
45
|
+
ORDER_DELIVERED: "order.delivered"
|
|
46
|
+
};
|
|
47
|
+
var ALL_WEBHOOK_EVENTS = Object.values(WEBHOOK_EVENTS);
|
|
48
|
+
var WEBHOOK_COLLECTION = "_webhooks";
|
|
49
|
+
var WEBHOOK_DELIVERY_COLLECTION = "_webhook_deliveries";
|
|
50
|
+
function signPayload(payload, secret) {
|
|
51
|
+
return `sha256=${crypto.createHmac("sha256", secret).update(payload).digest("hex")}`;
|
|
52
|
+
}
|
|
53
|
+
function generateWebhookSecret() {
|
|
54
|
+
return crypto.randomBytes(32).toString("hex");
|
|
55
|
+
}
|
|
56
|
+
async function deliverWebhook(webhook, payload, options = {}) {
|
|
57
|
+
const timeout = options.timeout || 3e4;
|
|
58
|
+
const startTime = Date.now();
|
|
59
|
+
const body = JSON.stringify(payload);
|
|
60
|
+
const headers = {
|
|
61
|
+
"Content-Type": "application/json",
|
|
62
|
+
"User-Agent": "Kyro-CMS-Webhook/1.0",
|
|
63
|
+
"X-Webhook-Event": payload.event,
|
|
64
|
+
"X-Webhook-Delivery": payload.id,
|
|
65
|
+
"X-Webhook-Timestamp": payload.timestamp,
|
|
66
|
+
...webhook.headers || {}
|
|
67
|
+
};
|
|
68
|
+
if (webhook.secret) {
|
|
69
|
+
const signature = signPayload(body, webhook.secret);
|
|
70
|
+
headers["X-Webhook-Signature"] = signature;
|
|
71
|
+
}
|
|
72
|
+
const controller = new AbortController();
|
|
73
|
+
const timeoutId = setTimeout(() => controller.abort(), timeout);
|
|
74
|
+
try {
|
|
75
|
+
const response = await fetch(webhook.url, {
|
|
76
|
+
method: "POST",
|
|
77
|
+
headers,
|
|
78
|
+
body,
|
|
79
|
+
signal: controller.signal
|
|
80
|
+
});
|
|
81
|
+
clearTimeout(timeoutId);
|
|
82
|
+
const duration = Date.now() - startTime;
|
|
83
|
+
let responseBody;
|
|
84
|
+
try {
|
|
85
|
+
const text = await response.text();
|
|
86
|
+
responseBody = text.slice(0, 1e3);
|
|
87
|
+
} catch {
|
|
88
|
+
}
|
|
89
|
+
const result = {
|
|
90
|
+
success: response.ok,
|
|
91
|
+
status: response.status,
|
|
92
|
+
statusText: response.statusText,
|
|
93
|
+
body: responseBody,
|
|
94
|
+
duration
|
|
95
|
+
};
|
|
96
|
+
if (result.success && options.onSuccess) {
|
|
97
|
+
options.onSuccess(result);
|
|
98
|
+
} else if (!result.success && options.onFailure) {
|
|
99
|
+
options.onFailure(`HTTP ${response.status}: ${response.statusText}`);
|
|
100
|
+
}
|
|
101
|
+
return result;
|
|
102
|
+
} catch (error) {
|
|
103
|
+
clearTimeout(timeoutId);
|
|
104
|
+
const duration = Date.now() - startTime;
|
|
105
|
+
const errorMessage = error.name === "AbortError" ? `Request timed out after ${timeout}ms` : error.message || "Unknown error";
|
|
106
|
+
if (options.onFailure) {
|
|
107
|
+
options.onFailure(errorMessage);
|
|
108
|
+
}
|
|
109
|
+
return {
|
|
110
|
+
success: false,
|
|
111
|
+
status: 0,
|
|
112
|
+
duration,
|
|
113
|
+
error: errorMessage
|
|
114
|
+
};
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
async function deliverWithRetry(webhook, payload, deliveryId, options = {}) {
|
|
118
|
+
const maxRetries = options.maxRetries ?? 5;
|
|
119
|
+
const baseDelay = options.retryDelay ?? 1e3;
|
|
120
|
+
let lastResult = null;
|
|
121
|
+
for (let attempt = 0; attempt <= maxRetries; attempt++) {
|
|
122
|
+
if (attempt > 0) {
|
|
123
|
+
const delay = Math.min(baseDelay * Math.pow(2, attempt - 1), 3e4);
|
|
124
|
+
if (options.onRetry) {
|
|
125
|
+
options.onRetry(attempt, `Retrying in ${delay}ms...`);
|
|
126
|
+
}
|
|
127
|
+
await sleep(delay);
|
|
128
|
+
}
|
|
129
|
+
if (options.onRetry && attempt > 0) {
|
|
130
|
+
options.onRetry(attempt, `Attempt ${attempt + 1}/${maxRetries + 1}`);
|
|
131
|
+
}
|
|
132
|
+
lastResult = await deliverWebhook(webhook, payload, {
|
|
133
|
+
...options,
|
|
134
|
+
onRetry: void 0,
|
|
135
|
+
onSuccess: void 0,
|
|
136
|
+
onFailure: void 0
|
|
137
|
+
});
|
|
138
|
+
if (lastResult.success) {
|
|
139
|
+
return lastResult;
|
|
140
|
+
}
|
|
141
|
+
if (lastResult.error?.includes("timed out") && attempt < maxRetries) {
|
|
142
|
+
continue;
|
|
143
|
+
}
|
|
144
|
+
if (lastResult.status >= 400 && lastResult.status < 500) {
|
|
145
|
+
return lastResult;
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
return lastResult || {
|
|
149
|
+
success: false,
|
|
150
|
+
status: 0,
|
|
151
|
+
duration: 0,
|
|
152
|
+
error: "All delivery attempts failed"
|
|
153
|
+
};
|
|
154
|
+
}
|
|
155
|
+
function buildDeliveryRecord(deliveryId, webhookId, event, payload, attempt, result) {
|
|
156
|
+
return {
|
|
157
|
+
id: deliveryId,
|
|
158
|
+
webhookId,
|
|
159
|
+
event,
|
|
160
|
+
payload,
|
|
161
|
+
attempt,
|
|
162
|
+
status: result.success ? "success" : "failed",
|
|
163
|
+
responseStatus: result.status || void 0,
|
|
164
|
+
responseBody: result.body,
|
|
165
|
+
duration: result.duration,
|
|
166
|
+
error: result.error,
|
|
167
|
+
createdAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
168
|
+
deliveredAt: result.success ? (/* @__PURE__ */ new Date()).toISOString() : void 0
|
|
169
|
+
};
|
|
170
|
+
}
|
|
171
|
+
function sleep(ms) {
|
|
172
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
173
|
+
}
|
|
174
|
+
function createTestPayload() {
|
|
175
|
+
return {
|
|
176
|
+
id: `test_${Date.now()}`,
|
|
177
|
+
event: "collection.create",
|
|
178
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
179
|
+
collection: "test",
|
|
180
|
+
operation: "create",
|
|
181
|
+
data: { message: "This is a test webhook delivery" },
|
|
182
|
+
user: { id: "system", email: "system@kyro.dev", role: "super_admin" }
|
|
183
|
+
};
|
|
184
|
+
}
|
|
185
|
+
var WebhookService = class {
|
|
186
|
+
db;
|
|
187
|
+
constructor(db) {
|
|
188
|
+
this.db = db;
|
|
189
|
+
}
|
|
190
|
+
async getWebhooks(filters) {
|
|
191
|
+
const result = await this.db.find({
|
|
192
|
+
collection: WEBHOOK_COLLECTION,
|
|
193
|
+
where: filters?.status ? { status: { equals: filters.status } } : {},
|
|
194
|
+
limit: 100,
|
|
195
|
+
page: 1
|
|
196
|
+
});
|
|
197
|
+
const webhooks = result.docs;
|
|
198
|
+
if (filters?.event) {
|
|
199
|
+
return webhooks.filter(
|
|
200
|
+
(w) => w.events.includes(filters.event)
|
|
201
|
+
);
|
|
202
|
+
}
|
|
203
|
+
return webhooks;
|
|
204
|
+
}
|
|
205
|
+
async getWebhookById(id) {
|
|
206
|
+
return this.db.findByID({
|
|
207
|
+
collection: WEBHOOK_COLLECTION,
|
|
208
|
+
id
|
|
209
|
+
});
|
|
210
|
+
}
|
|
211
|
+
async createWebhook(data) {
|
|
212
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
213
|
+
const secret = data.secret || generateWebhookSecret();
|
|
214
|
+
const webhook = {
|
|
215
|
+
id: crypto.randomUUID(),
|
|
216
|
+
name: data.name,
|
|
217
|
+
url: data.url,
|
|
218
|
+
events: data.events,
|
|
219
|
+
status: data.status || "active",
|
|
220
|
+
secret,
|
|
221
|
+
headers: data.headers || {},
|
|
222
|
+
createdAt: now,
|
|
223
|
+
updatedAt: now
|
|
224
|
+
};
|
|
225
|
+
await this.db.create({
|
|
226
|
+
collection: WEBHOOK_COLLECTION,
|
|
227
|
+
data: webhook
|
|
228
|
+
});
|
|
229
|
+
return webhook;
|
|
230
|
+
}
|
|
231
|
+
async updateWebhook(id, data) {
|
|
232
|
+
const existing = await this.getWebhookById(id);
|
|
233
|
+
if (!existing) return null;
|
|
234
|
+
const updated = {
|
|
235
|
+
...existing,
|
|
236
|
+
...data,
|
|
237
|
+
updatedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
238
|
+
};
|
|
239
|
+
if (data.secret === "" && "secret" in data) {
|
|
240
|
+
delete updated.secret;
|
|
241
|
+
}
|
|
242
|
+
await this.db.update({
|
|
243
|
+
collection: WEBHOOK_COLLECTION,
|
|
244
|
+
id,
|
|
245
|
+
data: updated
|
|
246
|
+
});
|
|
247
|
+
return updated;
|
|
248
|
+
}
|
|
249
|
+
async deleteWebhook(id) {
|
|
250
|
+
await this.db.delete({
|
|
251
|
+
collection: WEBHOOK_COLLECTION,
|
|
252
|
+
id
|
|
253
|
+
});
|
|
254
|
+
}
|
|
255
|
+
async trigger(event, payloadData) {
|
|
256
|
+
const webhooks = await this.getWebhooks();
|
|
257
|
+
const activeWebhooks = webhooks.filter((w) => w.status === "active");
|
|
258
|
+
const matchingWebhooks = activeWebhooks.filter(
|
|
259
|
+
(w) => w.events.includes(event)
|
|
260
|
+
);
|
|
261
|
+
if (matchingWebhooks.length === 0) {
|
|
262
|
+
return [];
|
|
263
|
+
}
|
|
264
|
+
const payload = {
|
|
265
|
+
id: `wh_${Date.now()}_${crypto.randomUUID().slice(0, 8)}`,
|
|
266
|
+
event,
|
|
267
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
268
|
+
...payloadData
|
|
269
|
+
};
|
|
270
|
+
const results = [];
|
|
271
|
+
for (const webhook of matchingWebhooks) {
|
|
272
|
+
const result = await this.triggerWebhook(webhook, payload);
|
|
273
|
+
results.push(result);
|
|
274
|
+
}
|
|
275
|
+
return results;
|
|
276
|
+
}
|
|
277
|
+
async triggerWebhook(webhook, payload) {
|
|
278
|
+
const deliveryId = `dlv_${Date.now()}_${crypto.randomUUID().slice(0, 8)}`;
|
|
279
|
+
try {
|
|
280
|
+
const result = await deliverWithRetry(webhook, payload, deliveryId, {
|
|
281
|
+
maxRetries: 5,
|
|
282
|
+
retryDelay: 1e3
|
|
283
|
+
});
|
|
284
|
+
const deliveryRecord = buildDeliveryRecord(
|
|
285
|
+
deliveryId,
|
|
286
|
+
webhook.id,
|
|
287
|
+
webhook.events[0],
|
|
288
|
+
payload,
|
|
289
|
+
1,
|
|
290
|
+
result
|
|
291
|
+
);
|
|
292
|
+
try {
|
|
293
|
+
await this.db.create({
|
|
294
|
+
collection: WEBHOOK_DELIVERY_COLLECTION,
|
|
295
|
+
data: deliveryRecord
|
|
296
|
+
});
|
|
297
|
+
} catch {
|
|
298
|
+
console.warn(
|
|
299
|
+
"[WebhookService] Failed to save delivery record:",
|
|
300
|
+
deliveryId
|
|
301
|
+
);
|
|
302
|
+
}
|
|
303
|
+
if (!result.success) {
|
|
304
|
+
await this.updateWebhook(webhook.id, {
|
|
305
|
+
status: "error",
|
|
306
|
+
lastError: result.error
|
|
307
|
+
}).catch(() => {
|
|
308
|
+
});
|
|
309
|
+
} else {
|
|
310
|
+
await this.updateWebhook(webhook.id, {
|
|
311
|
+
status: "active",
|
|
312
|
+
lastTriggered: (/* @__PURE__ */ new Date()).toISOString()
|
|
313
|
+
}).catch(() => {
|
|
314
|
+
});
|
|
315
|
+
}
|
|
316
|
+
return {
|
|
317
|
+
deliveryId,
|
|
318
|
+
webhookId: webhook.id,
|
|
319
|
+
event: webhook.events[0],
|
|
320
|
+
status: result.success ? "success" : "failed",
|
|
321
|
+
responseStatus: result.status,
|
|
322
|
+
duration: result.duration,
|
|
323
|
+
error: result.error
|
|
324
|
+
};
|
|
325
|
+
} catch (error) {
|
|
326
|
+
return {
|
|
327
|
+
deliveryId,
|
|
328
|
+
webhookId: webhook.id,
|
|
329
|
+
event: webhook.events[0],
|
|
330
|
+
status: "failed",
|
|
331
|
+
error: error.message
|
|
332
|
+
};
|
|
333
|
+
}
|
|
334
|
+
}
|
|
335
|
+
async testWebhook(webhookId) {
|
|
336
|
+
const webhook = await this.getWebhookById(webhookId);
|
|
337
|
+
if (!webhook) return null;
|
|
338
|
+
const payload = {
|
|
339
|
+
id: `test_${Date.now()}`,
|
|
340
|
+
event: webhook.events[0] || "collection.create",
|
|
341
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
342
|
+
collection: "test",
|
|
343
|
+
operation: "create",
|
|
344
|
+
data: { message: "This is a test webhook delivery from Kyro CMS" },
|
|
345
|
+
user: {
|
|
346
|
+
id: "system",
|
|
347
|
+
email: "system@kyro.dev",
|
|
348
|
+
role: "super_admin"
|
|
349
|
+
}
|
|
350
|
+
};
|
|
351
|
+
return this.triggerWebhook(webhook, payload);
|
|
352
|
+
}
|
|
353
|
+
async getDeliveryHistory(webhookId, limit = 50) {
|
|
354
|
+
const result = await this.db.find({
|
|
355
|
+
collection: WEBHOOK_DELIVERY_COLLECTION,
|
|
356
|
+
where: { webhookId: { equals: webhookId } },
|
|
357
|
+
sort: "-createdAt",
|
|
358
|
+
limit,
|
|
359
|
+
page: 1
|
|
360
|
+
});
|
|
361
|
+
return result.docs;
|
|
362
|
+
}
|
|
363
|
+
async retryDelivery(deliveryId) {
|
|
364
|
+
const delivery = await this.db.findByID({
|
|
365
|
+
collection: WEBHOOK_DELIVERY_COLLECTION,
|
|
366
|
+
id: deliveryId
|
|
367
|
+
});
|
|
368
|
+
if (!delivery) return null;
|
|
369
|
+
const webhook = await this.getWebhookById(delivery.webhookId);
|
|
370
|
+
if (!webhook) return null;
|
|
371
|
+
return this.triggerWebhook(webhook, delivery.payload);
|
|
372
|
+
}
|
|
373
|
+
};
|
|
374
|
+
function createWebhookService(db) {
|
|
375
|
+
return new WebhookService(db);
|
|
376
|
+
}
|
|
377
|
+
var API_KEY_COLLECTION = "_api_keys";
|
|
378
|
+
function generateKeyPrefix(key) {
|
|
379
|
+
return key.substring(0, 8);
|
|
380
|
+
}
|
|
381
|
+
function constantTimeCompare(a, b) {
|
|
382
|
+
if (a.length !== b.length) {
|
|
383
|
+
return false;
|
|
384
|
+
}
|
|
385
|
+
try {
|
|
386
|
+
return crypto.timingSafeEqual(Buffer.from(a), Buffer.from(b));
|
|
387
|
+
} catch {
|
|
388
|
+
return false;
|
|
389
|
+
}
|
|
390
|
+
}
|
|
391
|
+
async function validateApiKey(rawKey, db, userLookup) {
|
|
392
|
+
if (!rawKey || typeof rawKey !== "string") {
|
|
393
|
+
return { valid: false, error: "No API key provided" };
|
|
394
|
+
}
|
|
395
|
+
if (!rawKey.startsWith("kyro_")) {
|
|
396
|
+
return { valid: false, error: "Invalid API key format" };
|
|
397
|
+
}
|
|
398
|
+
const keyPrefix = generateKeyPrefix(rawKey);
|
|
399
|
+
try {
|
|
400
|
+
const result = await db.find({
|
|
401
|
+
collection: API_KEY_COLLECTION,
|
|
402
|
+
where: { keyPrefix: { equals: keyPrefix } },
|
|
403
|
+
limit: 100,
|
|
404
|
+
page: 1
|
|
405
|
+
});
|
|
406
|
+
if (!result.docs || result.docs.length === 0) {
|
|
407
|
+
return { valid: false, error: "Invalid API key" };
|
|
408
|
+
}
|
|
409
|
+
let matchedKey = null;
|
|
410
|
+
for (const doc of result.docs) {
|
|
411
|
+
const record = doc;
|
|
412
|
+
if (constantTimeCompare(record.key, rawKey)) {
|
|
413
|
+
matchedKey = record;
|
|
414
|
+
break;
|
|
415
|
+
}
|
|
416
|
+
}
|
|
417
|
+
if (!matchedKey) {
|
|
418
|
+
return { valid: false, error: "Invalid API key" };
|
|
419
|
+
}
|
|
420
|
+
if (matchedKey.expiresAt) {
|
|
421
|
+
const expiresAt = new Date(matchedKey.expiresAt);
|
|
422
|
+
if (expiresAt < /* @__PURE__ */ new Date()) {
|
|
423
|
+
return { valid: false, error: "API key has expired" };
|
|
424
|
+
}
|
|
425
|
+
}
|
|
426
|
+
try {
|
|
427
|
+
await db.update({
|
|
428
|
+
collection: API_KEY_COLLECTION,
|
|
429
|
+
id: matchedKey.id,
|
|
430
|
+
data: { lastUsedAt: (/* @__PURE__ */ new Date()).toISOString() }
|
|
431
|
+
});
|
|
432
|
+
} catch {
|
|
433
|
+
}
|
|
434
|
+
const user = {
|
|
435
|
+
id: matchedKey.userId,
|
|
436
|
+
role: matchedKey.role || "author",
|
|
437
|
+
tenantId: matchedKey.tenantId
|
|
438
|
+
};
|
|
439
|
+
if (userLookup) {
|
|
440
|
+
const dbUser = await userLookup(matchedKey.userId);
|
|
441
|
+
if (dbUser) {
|
|
442
|
+
Object.assign(user, dbUser);
|
|
443
|
+
}
|
|
444
|
+
}
|
|
445
|
+
return {
|
|
446
|
+
valid: true,
|
|
447
|
+
userId: matchedKey.userId,
|
|
448
|
+
user,
|
|
449
|
+
permissions: matchedKey.permissions || [],
|
|
450
|
+
apiKeyId: matchedKey.id,
|
|
451
|
+
tenantId: user.tenantId,
|
|
452
|
+
role: user.role
|
|
453
|
+
};
|
|
454
|
+
} catch (error) {
|
|
455
|
+
console.error("[ApiKey] Validation error:", error);
|
|
456
|
+
return { valid: false, error: "Failed to validate API key" };
|
|
457
|
+
}
|
|
458
|
+
}
|
|
459
|
+
function extractApiKeyFromRequest(request) {
|
|
460
|
+
const authHeader = request.headers.get("Authorization");
|
|
461
|
+
if (authHeader) {
|
|
462
|
+
if (authHeader.startsWith("ApiKey ")) {
|
|
463
|
+
return authHeader.slice(7).trim();
|
|
464
|
+
}
|
|
465
|
+
if (authHeader.startsWith("Bearer ")) {
|
|
466
|
+
return null;
|
|
467
|
+
}
|
|
468
|
+
}
|
|
469
|
+
const xApiKey = request.headers.get("X-API-Key");
|
|
470
|
+
if (xApiKey) {
|
|
471
|
+
return xApiKey.trim();
|
|
472
|
+
}
|
|
473
|
+
return null;
|
|
474
|
+
}
|
|
475
|
+
function createApiKeyContext(result) {
|
|
476
|
+
if (!result.valid || !result.userId) {
|
|
477
|
+
return null;
|
|
478
|
+
}
|
|
479
|
+
return {
|
|
480
|
+
userId: result.userId,
|
|
481
|
+
user: result.user || {},
|
|
482
|
+
permissions: result.permissions || [],
|
|
483
|
+
apiKeyId: result.apiKeyId || "",
|
|
484
|
+
tenantId: result.tenantId,
|
|
485
|
+
role: result.role
|
|
486
|
+
};
|
|
487
|
+
}
|
|
488
|
+
function hasApiKeyPermission(permissions, required) {
|
|
489
|
+
if (permissions.length === 0) return false;
|
|
490
|
+
if (permissions.includes("*")) return true;
|
|
491
|
+
if (permissions.includes(required)) return true;
|
|
492
|
+
const [resource, action] = required.split(":");
|
|
493
|
+
if (permissions.includes(`${resource}:*`)) return true;
|
|
494
|
+
return false;
|
|
495
|
+
}
|
|
496
|
+
|
|
497
|
+
exports.ALL_WEBHOOK_EVENTS = ALL_WEBHOOK_EVENTS;
|
|
498
|
+
exports.WEBHOOK_COLLECTION = WEBHOOK_COLLECTION;
|
|
499
|
+
exports.WEBHOOK_DELIVERY_COLLECTION = WEBHOOK_DELIVERY_COLLECTION;
|
|
500
|
+
exports.WEBHOOK_EVENTS = WEBHOOK_EVENTS;
|
|
501
|
+
exports.WebhookService = WebhookService;
|
|
502
|
+
exports.buildDeliveryRecord = buildDeliveryRecord;
|
|
503
|
+
exports.createApiKeyContext = createApiKeyContext;
|
|
504
|
+
exports.createTestPayload = createTestPayload;
|
|
505
|
+
exports.createWebhookService = createWebhookService;
|
|
506
|
+
exports.deliverWebhook = deliverWebhook;
|
|
507
|
+
exports.deliverWithRetry = deliverWithRetry;
|
|
508
|
+
exports.evaluateAccess = evaluateAccess;
|
|
509
|
+
exports.extractApiKeyFromRequest = extractApiKeyFromRequest;
|
|
510
|
+
exports.generateWebhookSecret = generateWebhookSecret;
|
|
511
|
+
exports.getWhereClause = getWhereClause;
|
|
512
|
+
exports.hasApiKeyPermission = hasApiKeyPermission;
|
|
513
|
+
exports.mergeWhereClauses = mergeWhereClauses;
|
|
514
|
+
exports.signPayload = signPayload;
|
|
515
|
+
exports.validateApiKey = validateApiKey;
|
|
516
|
+
//# sourceMappingURL=chunk-VIONYQ2K.cjs.map
|
|
517
|
+
//# sourceMappingURL=chunk-VIONYQ2K.cjs.map
|