@kyro-cms/core 0.12.60 → 0.12.62
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/api-handler-graphql.cjs +1 -1
- package/dist/api-handler-graphql.js +1 -1
- package/dist/api-handler-trpc.cjs +1 -1
- package/dist/api-handler-trpc.js +1 -1
- package/dist/api-handler.cjs +1 -1
- package/dist/api-handler.js +1 -1
- package/dist/{bootstrap-VUWX45QN.js → bootstrap-WB6FDH2T.js} +1 -1
- package/dist/bootstrap-XDT4MRML.cjs +1 -0
- package/dist/{chunk-33E4YN62.js → chunk-26MOA3HJ.js} +10 -10
- package/dist/{chunk-M56F4LQ5.cjs → chunk-3XLXKGEU.cjs} +1 -1
- package/dist/{chunk-WQCLLM4S.cjs → chunk-4FHWIGHO.cjs} +10 -10
- package/dist/chunk-4ZWLNGLS.js +2 -0
- package/dist/{chunk-VOQUO2EZ.cjs → chunk-5DWQGEM2.cjs} +22 -22
- package/dist/{chunk-OXGJOYEO.js → chunk-637PTUHF.js} +1 -1
- package/dist/chunk-6QWX3DEB.cjs +120 -0
- package/dist/{chunk-ZMG7Z3KF.js → chunk-75BFTYBS.js} +23 -23
- package/dist/{chunk-YZEMLLD2.js → chunk-AWQGDMOE.js} +3 -3
- package/dist/chunk-D6SDGHY6.js +2 -0
- package/dist/{chunk-MP5VC5ER.cjs → chunk-FP5UK272.cjs} +1 -1
- package/dist/{chunk-AK754S3T.cjs → chunk-FSL3NLRT.cjs} +2 -2
- package/dist/{chunk-RTHJ6SS5.js → chunk-GQGFNTDZ.js} +1 -1
- package/dist/chunk-HKYBQYAJ.cjs +19 -0
- package/dist/{chunk-TDGSIF5H.cjs → chunk-JU3UAZRY.cjs} +10 -11
- package/dist/chunk-KMFLHGD5.cjs +1 -0
- package/dist/{chunk-NTKIONEC.cjs → chunk-LOP464VR.cjs} +1 -1
- package/dist/{chunk-R25WLKX4.js → chunk-N6MNQIQU.js} +101 -101
- package/dist/{chunk-BHR7OAU4.cjs → chunk-OPTVCCQQ.cjs} +101 -101
- package/dist/chunk-RDFGJHEG.js +2 -0
- package/dist/chunk-RILJCH6H.js +121 -0
- package/dist/{chunk-KCHPADCH.cjs → chunk-SOCBJPYB.cjs} +1 -1
- package/dist/chunk-T4JJVUGT.js +20 -0
- package/dist/{chunk-7N6TW4JB.js → chunk-TBTQXIHP.js} +1 -1
- package/dist/{chunk-KNOFTUQV.js → chunk-VJODUKKM.js} +11 -12
- package/dist/{chunk-DUO523BH.cjs → chunk-ZHA446FA.cjs} +1 -1
- package/dist/cli/index.cjs +1 -1
- package/dist/cli/index.js +1 -1
- package/dist/client.cjs +1 -1
- package/dist/client.js +1 -1
- package/dist/drizzle/index.cjs +1 -1
- package/dist/drizzle/index.d.cts +2 -1
- package/dist/drizzle/index.d.ts +2 -1
- package/dist/drizzle/index.js +1 -1
- package/dist/fields/index.cjs +1 -1
- package/dist/fields/index.js +1 -1
- package/dist/graphql/index.cjs +1 -1
- package/dist/graphql/index.d.cts +2 -0
- package/dist/graphql/index.d.ts +2 -0
- package/dist/graphql/index.js +1 -1
- package/dist/index.cjs +3 -3
- package/dist/index.d.cts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +5 -5
- package/dist/{local-2IFOTHAA.js → local-4MZ7KOL3.js} +1 -1
- package/dist/{local-UESCNPQP.cjs → local-NDTKWJQ6.cjs} +1 -1
- package/dist/postgres-auth-adapter-SK3N3OSS.js +1 -1
- package/dist/postgres-auth-adapter-ZO6HK5AK.cjs +1 -1
- package/dist/postgres-js-GXZX3AGZ.cjs +1 -0
- package/dist/{postgres-js-4CI7FMYS.js → postgres-js-WE3NBRFO.js} +1 -1
- package/dist/rest/index.cjs +1 -1
- package/dist/rest/index.d.cts +3 -3
- package/dist/rest/index.d.ts +3 -3
- package/dist/rest/index.js +1 -1
- package/dist/{sqlite-adapter-4TPNROJK.js → sqlite-adapter-52PL52VU.js} +1 -1
- package/dist/{sqlite-adapter-ZTABLT2X.cjs → sqlite-adapter-MNNZZXGX.cjs} +1 -1
- package/dist/trpc/index.cjs +1 -1
- package/dist/trpc/index.js +1 -1
- package/package.json +2 -2
- package/dist/bootstrap-JF6Q4L6P.cjs +0 -1
- package/dist/chunk-5LPNEYK5.cjs +0 -1
- package/dist/chunk-72VOOMJI.js +0 -20
- package/dist/chunk-AO2IXWV4.js +0 -2
- package/dist/chunk-OUMUIICN.cjs +0 -264
- package/dist/chunk-PA4ZZREG.js +0 -2
- package/dist/chunk-PCVQNVSU.cjs +0 -19
- package/dist/chunk-SQBTIMWF.js +0 -2
- package/dist/chunk-T4TSELDS.js +0 -265
- package/dist/postgres-js-3Y54EXVQ.cjs +0 -1
|
@@ -1,111 +1,111 @@
|
|
|
1
1
|
import {a}from'./chunk-7NH7H3WA.js';import {g,e}from'./chunk-Y2YAKDEQ.js';import {randomBytes}from'crypto';import {mkdirSync}from'fs';import {dirname}from'path';import {createRequire}from'module';if (typeof window === "undefined") { const { createRequire } = await import(/* @vite-ignore */ 'module'); createRequire(import.meta.url); }
|
|
2
|
-
g();var
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
2
|
+
g();var l=e(a(),1);g();var p=`
|
|
3
|
+
CREATE TABLE IF NOT EXISTS kyro_users (
|
|
4
|
+
id TEXT PRIMARY KEY,
|
|
5
|
+
name TEXT,
|
|
6
|
+
email TEXT UNIQUE NOT NULL,
|
|
7
|
+
password_hash TEXT NOT NULL,
|
|
8
|
+
role TEXT NOT NULL DEFAULT 'customer',
|
|
9
|
+
tenant_id TEXT,
|
|
10
|
+
email_verified INTEGER DEFAULT 0,
|
|
11
|
+
locked INTEGER DEFAULT 0,
|
|
12
|
+
last_login TEXT,
|
|
13
|
+
failed_login_attempts INTEGER DEFAULT 0,
|
|
14
|
+
locked_until TEXT,
|
|
15
|
+
avatar TEXT,
|
|
16
|
+
created_at TEXT NOT NULL,
|
|
17
|
+
updated_at TEXT NOT NULL
|
|
18
|
+
);
|
|
19
19
|
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
20
|
+
CREATE TABLE IF NOT EXISTS kyro_sessions (
|
|
21
|
+
id TEXT PRIMARY KEY,
|
|
22
|
+
user_id TEXT NOT NULL,
|
|
23
|
+
token TEXT NOT NULL,
|
|
24
|
+
refresh_token TEXT,
|
|
25
|
+
expires_at TEXT NOT NULL,
|
|
26
|
+
created_at TEXT NOT NULL,
|
|
27
|
+
ip_address TEXT,
|
|
28
|
+
user_agent TEXT,
|
|
29
|
+
FOREIGN KEY (user_id) REFERENCES kyro_users(id) ON DELETE CASCADE
|
|
30
|
+
);
|
|
31
31
|
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
32
|
+
CREATE TABLE IF NOT EXISTS kyro_password_history (
|
|
33
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
34
|
+
user_id TEXT NOT NULL,
|
|
35
|
+
password_hash TEXT NOT NULL,
|
|
36
|
+
created_at TEXT NOT NULL,
|
|
37
|
+
FOREIGN KEY (user_id) REFERENCES kyro_users(id) ON DELETE CASCADE
|
|
38
|
+
);
|
|
39
39
|
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
40
|
+
CREATE TABLE IF NOT EXISTS kyro_rate_limits (
|
|
41
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
42
|
+
key TEXT NOT NULL,
|
|
43
|
+
window_start INTEGER NOT NULL,
|
|
44
|
+
count INTEGER NOT NULL DEFAULT 1,
|
|
45
|
+
UNIQUE(key, window_start)
|
|
46
|
+
);
|
|
47
47
|
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
48
|
+
CREATE TABLE IF NOT EXISTS kyro_lockouts (
|
|
49
|
+
user_id TEXT PRIMARY KEY,
|
|
50
|
+
attempts INTEGER NOT NULL DEFAULT 0,
|
|
51
|
+
last_attempt INTEGER,
|
|
52
|
+
locked_at INTEGER,
|
|
53
|
+
locked_until INTEGER
|
|
54
|
+
);
|
|
55
55
|
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
56
|
+
CREATE TABLE IF NOT EXISTS kyro_audit_logs (
|
|
57
|
+
id TEXT PRIMARY KEY,
|
|
58
|
+
timestamp TEXT NOT NULL,
|
|
59
|
+
action TEXT NOT NULL,
|
|
60
|
+
user_id TEXT,
|
|
61
|
+
user_email TEXT,
|
|
62
|
+
role TEXT,
|
|
63
|
+
resource TEXT NOT NULL,
|
|
64
|
+
resource_id TEXT,
|
|
65
|
+
ip_address TEXT,
|
|
66
|
+
user_agent TEXT,
|
|
67
|
+
success INTEGER NOT NULL,
|
|
68
|
+
error TEXT,
|
|
69
|
+
metadata TEXT,
|
|
70
|
+
created_at TEXT NOT NULL DEFAULT (datetime('now'))
|
|
71
|
+
);
|
|
72
72
|
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
73
|
+
CREATE INDEX IF NOT EXISTS idx_kyro_users_email ON kyro_users(email);
|
|
74
|
+
CREATE INDEX IF NOT EXISTS idx_kyro_sessions_user_id ON kyro_sessions(user_id);
|
|
75
|
+
CREATE INDEX IF NOT EXISTS idx_kyro_sessions_token ON kyro_sessions(token);
|
|
76
|
+
CREATE INDEX IF NOT EXISTS idx_kyro_sessions_refresh_token ON kyro_sessions(refresh_token);
|
|
77
|
+
CREATE INDEX IF NOT EXISTS idx_kyro_sessions_expires ON kyro_sessions(expires_at);
|
|
78
|
+
CREATE INDEX IF NOT EXISTS idx_kyro_password_history_user_id ON kyro_password_history(user_id);
|
|
79
|
+
CREATE INDEX IF NOT EXISTS idx_kyro_rate_limits_key ON kyro_rate_limits(key);
|
|
80
|
+
CREATE INDEX IF NOT EXISTS idx_kyro_rate_limits_window ON kyro_rate_limits(window_start);
|
|
81
|
+
CREATE INDEX IF NOT EXISTS idx_kyro_lockouts_locked_until ON kyro_lockouts(locked_until);
|
|
82
|
+
CREATE INDEX IF NOT EXISTS idx_kyro_audit_logs_timestamp ON kyro_audit_logs(timestamp);
|
|
83
|
+
CREATE INDEX IF NOT EXISTS idx_kyro_audit_logs_action ON kyro_audit_logs(action);
|
|
84
|
+
CREATE INDEX IF NOT EXISTS idx_kyro_audit_logs_user_id ON kyro_audit_logs(user_id);
|
|
85
|
+
CREATE INDEX IF NOT EXISTS idx_kyro_audit_logs_resource ON kyro_audit_logs(resource);
|
|
86
86
|
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
87
|
+
CREATE TABLE IF NOT EXISTS kyro_email_verifications (
|
|
88
|
+
id TEXT PRIMARY KEY,
|
|
89
|
+
user_id TEXT NOT NULL,
|
|
90
|
+
token TEXT UNIQUE NOT NULL,
|
|
91
|
+
expires_at TEXT NOT NULL,
|
|
92
|
+
created_at TEXT NOT NULL DEFAULT (datetime('now')),
|
|
93
|
+
FOREIGN KEY (user_id) REFERENCES kyro_users(id) ON DELETE CASCADE
|
|
94
|
+
);
|
|
95
95
|
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
96
|
+
CREATE TABLE IF NOT EXISTS kyro_password_resets (
|
|
97
|
+
id TEXT PRIMARY KEY,
|
|
98
|
+
user_id TEXT NOT NULL,
|
|
99
|
+
token TEXT UNIQUE NOT NULL,
|
|
100
|
+
expires_at TEXT NOT NULL,
|
|
101
|
+
used_at TEXT,
|
|
102
|
+
created_at TEXT NOT NULL DEFAULT (datetime('now')),
|
|
103
|
+
FOREIGN KEY (user_id) REFERENCES kyro_users(id) ON DELETE CASCADE
|
|
104
|
+
);
|
|
105
105
|
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
106
|
+
CREATE INDEX IF NOT EXISTS idx_kyro_email_verifications_token ON kyro_email_verifications(token);
|
|
107
|
+
CREATE INDEX IF NOT EXISTS idx_kyro_password_resets_token ON kyro_password_resets(token);
|
|
108
|
+
`;var E;function R(){return E||(E=createRequire("file:///")("node:sqlite").DatabaseSync,E)}var L=5e3,N=1e3,I=-64e3,f=268435456,T=class{db=null;path;saltRounds;externalDb;busyTimeout;walAutoCheckpoint;cacheSize;mmapSize;preparedStatements=new Map;constructor(e={}){this.path=e.path||"./data/auth.db",this.saltRounds=e.saltRounds||12,this.externalDb=!!e.db,this.busyTimeout=e.busyTimeout??L,this.walAutoCheckpoint=e.walAutoCheckpoint??N,this.cacheSize=e.cacheSize??I,this.mmapSize=e.mmapSize??f,e.db&&(this.db=e.db);}async connect(){if(this.db)return;let e=dirname(this.path);e&&e!=="."&&mkdirSync(e,{recursive:true}),this.db=new(R())(this.path),this.db.exec(`PRAGMA busy_timeout = ${this.busyTimeout}`),this.db.exec("PRAGMA journal_mode = WAL"),this.db.exec("PRAGMA synchronous = NORMAL"),this.db.exec("PRAGMA cache_size = "+this.cacheSize),this.db.exec("PRAGMA mmap_size = "+this.mmapSize),this.db.exec("PRAGMA wal_autocheckpoint = "+this.walAutoCheckpoint),this.db.exec("PRAGMA foreign_keys = ON"),this.db.exec("PRAGMA temp_store = MEMORY"),this.ensureTables(),this.prepareStatements();}async disconnect(){this.db&&!this.externalDb&&(this.db.exec("PRAGMA wal_checkpoint(TRUNCATE)"),this.db.close(),this.db=null,this.preparedStatements.clear());}async ensureConnected(){if(this.db||await this.connect(),!this.db)throw new Error("Failed to connect to SQLite database");return this.db}ensureTables(){if(this.db){this.db.exec(p);try{this.db.exec("ALTER TABLE kyro_users ADD COLUMN name TEXT");}catch{}try{this.db.exec("ALTER TABLE kyro_users ADD COLUMN avatar TEXT");}catch{}}}prepareStatements(){this.db&&(this.preparedStatements.set("findUserByEmail",this.db.prepare("SELECT * FROM kyro_users WHERE email = ?")),this.preparedStatements.set("findUserById",this.db.prepare("SELECT * FROM kyro_users WHERE id = ?")),this.preparedStatements.set("findSessionByToken",this.db.prepare("SELECT * FROM kyro_sessions WHERE token = ?")),this.preparedStatements.set("findSessionByRefreshToken",this.db.prepare("SELECT * FROM kyro_sessions WHERE refresh_token = ?")),this.preparedStatements.set("deleteSession",this.db.prepare("DELETE FROM kyro_sessions WHERE id = ? OR token = ?")),this.preparedStatements.set("deleteUserSessions",this.db.prepare("DELETE FROM kyro_sessions WHERE user_id = ?")),this.preparedStatements.set("countUsers",this.db.prepare("SELECT COUNT(*) as count FROM kyro_users")),this.preparedStatements.set("deleteUser",this.db.prepare("DELETE FROM kyro_users WHERE id = ?")),this.preparedStatements.set("findUsersPaginated",this.db.prepare("SELECT * FROM kyro_users ORDER BY created_at DESC LIMIT ? OFFSET ?")),this.preparedStatements.set("findUsersWithSearch",this.db.prepare("SELECT * FROM kyro_users WHERE email LIKE ? ORDER BY created_at DESC LIMIT ? OFFSET ?")),this.preparedStatements.set("countUsersWithSearch",this.db.prepare("SELECT COUNT(*) as count FROM kyro_users WHERE email LIKE ?")),this.preparedStatements.set("getPasswordHistory",this.db.prepare("SELECT password_hash FROM kyro_password_history WHERE user_id = ? ORDER BY created_at DESC LIMIT ?")),this.preparedStatements.set("addPasswordHistory",this.db.prepare("INSERT INTO kyro_password_history (user_id, password_hash, created_at) VALUES (?, ?, ?)")),this.preparedStatements.set("trimPasswordHistory",this.db.prepare(`DELETE FROM kyro_password_history WHERE id IN (
|
|
109
109
|
SELECT id FROM kyro_password_history WHERE user_id = ? ORDER BY created_at DESC LIMIT -1 OFFSET 5
|
|
110
110
|
)`)),this.preparedStatements.set("deleteExpiredSessions",this.db.prepare("DELETE FROM kyro_sessions WHERE expires_at < ?")),this.preparedStatements.set("cleanupOldAuditLogs",this.db.prepare("DELETE FROM kyro_audit_logs WHERE timestamp < ?")),this.preparedStatements.set("cleanupExpiredLockouts",this.db.prepare("UPDATE kyro_lockouts SET attempts = 0, locked_at = NULL, locked_until = NULL WHERE locked_until < ?")),this.preparedStatements.set("getLockout",this.db.prepare("SELECT * FROM kyro_lockouts WHERE user_id = ?")),this.preparedStatements.set("upsertLockout",this.db.prepare(`
|
|
111
111
|
INSERT INTO kyro_lockouts (user_id, attempts, last_attempt, locked_at, locked_until)
|
|
@@ -116,8 +116,8 @@ g();var E=e(a(),1);var c;function k(){return c||(c=createRequire("file:///")("no
|
|
|
116
116
|
locked_at = excluded.locked_at,
|
|
117
117
|
locked_until = excluded.locked_until
|
|
118
118
|
`)),this.preparedStatements.set("resetLockout",this.db.prepare("UPDATE kyro_lockouts SET attempts = 0, locked_at = NULL, locked_until = NULL WHERE user_id = ?")));}stmt(e){let s=this.preparedStatements.get(e);if(!s)throw new Error(`Prepared statement not found: ${e}`);return s}async cleanupExpiredSessions(){return await this.ensureConnected(),this.stmt("deleteExpiredSessions").run(new Date().toISOString()).changes}async cleanupOldAuditLogs(e=30){await this.ensureConnected();let s=new Date(Date.now()-e*24*60*60*1e3).toISOString();return this.stmt("cleanupOldAuditLogs").run(s).changes}async getStats(){await this.ensureConnected();let e=this.stmt("countUsers").get().count,s=this.db.prepare("SELECT COUNT(*) as count FROM kyro_sessions WHERE expires_at > ?").get(new Date().toISOString()).count,t=this.db.prepare("SELECT COUNT(*) as count FROM kyro_audit_logs").get().count;return {userCount:e,activeSessionCount:s,auditLogCount:t}}async createUser(e){await this.ensureConnected();let s=randomBytes(16).toString("hex"),t=new Date().toISOString(),r=await this.hashPassword(e.password),n={id:s,name:e.name,email:e.email.toLowerCase(),passwordHash:r,role:e.role||"customer",avatar:e.avatar,tenantId:e.tenantId,createdAt:t,updatedAt:t};return this.db.prepare(`INSERT INTO kyro_users (id, name, email, password_hash, role, avatar, tenant_id, created_at, updated_at)
|
|
119
|
-
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)`).run(s,n.name||null,n.email,n.passwordHash,n.role,n.avatar||null,n.tenantId||null,t,t),n}async findUserByEmail(e){await this.ensureConnected();let s=this.stmt("findUserByEmail").get(e.toLowerCase());return s?this.rowToUser(s):null}async findUserById(e){await this.ensureConnected();let s=this.stmt("findUserById").get(e);return s?this.rowToUser(s):null}async updateUser(e,s){if(await this.ensureConnected(),!await this.findUserById(e))return null;let r=[],n=[];return s.email!==void 0&&(r.push("email = ?"),n.push(s.email.toLowerCase())),s.name!==void 0&&(r.push("name = ?"),n.push(s.name)),s.passwordHash!==void 0&&(r.push("password_hash = ?"),n.push(s.passwordHash)),s.role!==void 0&&(r.push("role = ?"),n.push(s.role)),s.avatar!==void 0&&(r.push("avatar = ?"),n.push(s.avatar)),s.tenantId!==void 0&&(r.push("tenant_id = ?"),n.push(s.tenantId)),s.emailVerified!==void 0&&(r.push("email_verified = ?"),n.push(s.emailVerified?1:0)),s.locked!==void 0&&(r.push("locked = ?"),n.push(s.locked?1:0)),s.lastLogin!==void 0&&(r.push("last_login = ?"),n.push(s.lastLogin)),s.failedLoginAttempts!==void 0&&(r.push("failed_login_attempts = ?"),n.push(s.failedLoginAttempts)),r.push("updated_at = ?"),n.push(new Date().toISOString()),n.push(e),this.db.prepare(`UPDATE kyro_users SET ${r.join(", ")} WHERE id = ?`).run(...n),this.findUserById(e)}async deleteUser(e){return await this.ensureConnected(),this.stmt("deleteUser").run(e).changes>0}async hashPassword(e){return
|
|
120
|
-
VALUES (?, ?, ?, ?, ?, ?, ?, ?)`).run(i.id,i.userId,i.token,i.refreshToken??null,i.expiresAt,i.createdAt,i.ipAddress??null,i.userAgent??null),i}async findSessionByToken(e){await this.ensureConnected();let s=this.stmt("findSessionByToken").get(e);return s?this.rowToSession(s):null}async findSessionByRefreshToken(e){await this.ensureConnected();let s=this.stmt("findSessionByRefreshToken").get(e);return s?this.rowToSession(s):null}async deleteSession(e){return await this.ensureConnected(),this.stmt("deleteSession").run(e,e).changes>0}async deleteUserSessions(e){return await this.ensureConnected(),this.stmt("deleteUserSessions").run(e).changes}async hasAnyUsers(){return await this.ensureConnected(),this.stmt("countUsers").get().count>0}async findUsers(e={}){await this.ensureConnected();let s=e.page??1,t=e.limit??10,r=(s-1)*t,n=e.search,d,u;if(n){let i=`%${n}%`;d=this.stmt("countUsersWithSearch").get(i).count,u=this.stmt("findUsersWithSearch").all(i,t,r);}else d=this.stmt("countUsers").get().count,u=this.stmt("findUsersPaginated").all(t,r);return {users:u.map(i=>this.rowToUser(i)),total:d}}async addPasswordToHistory(e,s){await this.ensureConnected(),this.stmt("addPasswordHistory").run(e,s,new Date().toISOString()),this.stmt("trimPasswordHistory").run(e);}async getPasswordHistory(e,s=5){return await this.ensureConnected(),this.stmt("getPasswordHistory").all(e,s).map(r=>r.password_hash)}async isPasswordInHistory(e,s,t=5){let r=await this.getPasswordHistory(s,t);for(let n of r)if(await
|
|
119
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)`).run(s,n.name||null,n.email,n.passwordHash,n.role,n.avatar||null,n.tenantId||null,t,t),n}async findUserByEmail(e){await this.ensureConnected();let s=this.stmt("findUserByEmail").get(e.toLowerCase());return s?this.rowToUser(s):null}async findUserById(e){await this.ensureConnected();let s=this.stmt("findUserById").get(e);return s?this.rowToUser(s):null}async updateUser(e,s){if(await this.ensureConnected(),!await this.findUserById(e))return null;let r=[],n=[];return s.email!==void 0&&(r.push("email = ?"),n.push(s.email.toLowerCase())),s.name!==void 0&&(r.push("name = ?"),n.push(s.name)),s.passwordHash!==void 0&&(r.push("password_hash = ?"),n.push(s.passwordHash)),s.role!==void 0&&(r.push("role = ?"),n.push(s.role)),s.avatar!==void 0&&(r.push("avatar = ?"),n.push(s.avatar)),s.tenantId!==void 0&&(r.push("tenant_id = ?"),n.push(s.tenantId)),s.emailVerified!==void 0&&(r.push("email_verified = ?"),n.push(s.emailVerified?1:0)),s.locked!==void 0&&(r.push("locked = ?"),n.push(s.locked?1:0)),s.lastLogin!==void 0&&(r.push("last_login = ?"),n.push(s.lastLogin)),s.failedLoginAttempts!==void 0&&(r.push("failed_login_attempts = ?"),n.push(s.failedLoginAttempts)),r.push("updated_at = ?"),n.push(new Date().toISOString()),n.push(e),this.db.prepare(`UPDATE kyro_users SET ${r.join(", ")} WHERE id = ?`).run(...n),this.findUserById(e)}async deleteUser(e){return await this.ensureConnected(),this.stmt("deleteUser").run(e).changes>0}async hashPassword(e){return l.default.hash(e,this.saltRounds)}async verifyPassword(e,s){await this.ensureConnected();let t=await this.findUserByEmail(e);if(!t)return null;let r=this.db.prepare("SELECT password_hash FROM kyro_users WHERE id = ?").get(t.id);return r?.password_hash&&await l.default.compare(s,r.password_hash)?t:null}async createSession(e,s={}){await this.ensureConnected();let t=randomBytes(32).toString("hex"),r=randomBytes(32).toString("base64url"),n=randomBytes(32).toString("base64url"),d=new Date,u=new Date(d.getTime()+864e5).toISOString(),i={id:t,userId:e,token:r,refreshToken:n,expiresAt:u,createdAt:d.toISOString(),ipAddress:s.ipAddress,userAgent:s.userAgent};return this.db.prepare(`INSERT INTO kyro_sessions (id, user_id, token, refresh_token, expires_at, created_at, ip_address, user_agent)
|
|
120
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?)`).run(i.id,i.userId,i.token,i.refreshToken??null,i.expiresAt,i.createdAt,i.ipAddress??null,i.userAgent??null),i}async findSessionByToken(e){await this.ensureConnected();let s=this.stmt("findSessionByToken").get(e);return s?this.rowToSession(s):null}async findSessionByRefreshToken(e){await this.ensureConnected();let s=this.stmt("findSessionByRefreshToken").get(e);return s?this.rowToSession(s):null}async deleteSession(e){return await this.ensureConnected(),this.stmt("deleteSession").run(e,e).changes>0}async deleteUserSessions(e){return await this.ensureConnected(),this.stmt("deleteUserSessions").run(e).changes}async hasAnyUsers(){return await this.ensureConnected(),this.stmt("countUsers").get().count>0}async findUsers(e={}){await this.ensureConnected();let s=e.page??1,t=e.limit??10,r=(s-1)*t,n=e.search,d,u;if(n){let i=`%${n}%`;d=this.stmt("countUsersWithSearch").get(i).count,u=this.stmt("findUsersWithSearch").all(i,t,r);}else d=this.stmt("countUsers").get().count,u=this.stmt("findUsersPaginated").all(t,r);return {users:u.map(i=>this.rowToUser(i)),total:d}}async addPasswordToHistory(e,s){await this.ensureConnected(),this.stmt("addPasswordHistory").run(e,s,new Date().toISOString()),this.stmt("trimPasswordHistory").run(e);}async getPasswordHistory(e,s=5){return await this.ensureConnected(),this.stmt("getPasswordHistory").all(e,s).map(r=>r.password_hash)}async isPasswordInHistory(e,s,t=5){let r=await this.getPasswordHistory(s,t);for(let n of r)if(await l.default.compare(e,n))return true;return false}async recordFailedAttempt(e){await this.ensureConnected();let s=Date.now(),t=this.stmt("getLockout").get(e),r=(t?.attempts||0)+1,n=r>=5?s+900*1e3:t?.locked_until||null;this.stmt("upsertLockout").run(e,r,s,n!==null?s:null,n);}async resetAttempts(e){await this.ensureConnected(),this.stmt("resetLockout").run(e);}async checkLockout(e){await this.ensureConnected(),this.stmt("cleanupExpiredLockouts").run(Date.now());let s=this.stmt("getLockout").get(e);return s?s.locked_until!==null&&s.locked_until>Date.now()?{locked:true,attemptsRemaining:0,lockedUntil:new Date(s.locked_until),totalAttempts:s.attempts}:{locked:false,attemptsRemaining:Math.max(0,5-s.attempts),totalAttempts:s.attempts}:{locked:false,attemptsRemaining:5,totalAttempts:0}}async logAudit(e){await this.ensureConnected();let s=randomBytes(16).toString("hex"),t=new Date().toISOString();return this.db.prepare(`INSERT INTO kyro_audit_logs (
|
|
121
121
|
id, timestamp, action, user_id, user_email, role, resource, resource_id,
|
|
122
122
|
ip_address, user_agent, success, error, metadata, created_at
|
|
123
|
-
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`).run(s,t,e.action,e.userId||null,e.userEmail||null,e.role||null,e.resource,e.resourceId||null,e.ipAddress||null,e.userAgent||null,e.success?1:0,e.error||null,e.metadata?JSON.stringify(e.metadata):null,new Date().toISOString()),s}async queryAuditLogs(e={}){await this.ensureConnected();let s=[],t=[];e.action&&(s.push("action = ?"),t.push(e.action)),e.userId&&(s.push("user_id = ?"),t.push(e.userId)),e.resource&&(s.push("resource = ?"),t.push(e.resource)),e.success!==void 0&&(s.push("success = ?"),t.push(e.success?1:0)),e.startDate&&(s.push("timestamp >= ?"),t.push(e.startDate.toISOString())),e.endDate&&(s.push("timestamp <= ?"),t.push(e.endDate.toISOString()));let r=s.length>0?"WHERE "+s.join(" AND "):"",n=e.limit||50,d=e.offset||0,u=this.db.prepare(`SELECT COUNT(*) as count FROM kyro_audit_logs ${r}`).get(...t),i=this.db.prepare(`SELECT * FROM kyro_audit_logs ${r} ORDER BY timestamp DESC LIMIT ? OFFSET ?`).all(...t,n,d);return {total:u.count,logs:i.map(a=>({id:a.id,timestamp:new Date(a.timestamp),action:a.action,userId:a.user_id||void 0,userEmail:a.user_email||void 0,resource:a.resource,resourceId:a.resource_id||void 0,ipAddress:a.ip_address||void 0,userAgent:a.user_agent||void 0,success:a.success===1,error:a.error||void 0,metadata:a.metadata?JSON.parse(a.metadata):void 0}))}}rowToUser(e){return {id:e.id,name:e.name||void 0,email:e.email,passwordHash:e.password_hash,role:e.role,tenantId:e.tenant_id,avatar:e.avatar,emailVerified:e.email_verified===1,locked:e.locked===1,lastLogin:e.last_login,failedLoginAttempts:e.failed_login_attempts||0,createdAt:e.created_at,updatedAt:e.updated_at}}rowToSession(e){return {id:e.id,userId:e.user_id,token:e.token,refreshToken:e.refresh_token,expiresAt:e.expires_at,createdAt:e.created_at,ipAddress:e.ip_address,userAgent:e.user_agent}}async findAuditLogs(e){let s=await this.queryAuditLogs({action:e.action,userId:e.userId,resource:e.resource,success:e.success,startDate:e.startDate,endDate:e.endDate,limit:e.limit,offset:e.offset});return {logs:s.logs.map(t=>({...t,action:t.action})),total:s.total}}async createAuditLog(e){let s=await this.logAudit({action:e.action,userId:e.userId,userEmail:e.userEmail,role:e.role,resource:e.resource,resourceId:e.resourceId,ipAddress:e.ipAddress,userAgent:e.userAgent,success:e.success,error:e.error,metadata:e.metadata}),t=this.db?.prepare("SELECT * FROM kyro_audit_logs WHERE id = ?").get(s);return {...e,id:s,timestamp:t?new Date(t.timestamp):new Date}}async createEmailVerificationToken(e){await this.ensureConnected();let s=randomBytes(16).toString("hex"),t=randomBytes(32).toString("hex"),r=new Date(Date.now()+1440*60*1e3);return this.db.prepare("INSERT INTO kyro_email_verifications (id, user_id, token, expires_at, created_at) VALUES (?, ?, ?, ?, ?)").run(s,e,t,r.toISOString(),new Date().toISOString()),{token:t,expiresAt:r}}async verifyEmailToken(e){await this.ensureConnected();let s=this.db.prepare("SELECT * FROM kyro_email_verifications WHERE token = ?").get(e);return s?new Date(s.expires_at)<new Date?{success:false,error:"Verification token has expired"}:(this.db.prepare("UPDATE kyro_users SET email_verified = 1 WHERE id = ?").run(s.user_id),this.db.prepare("DELETE FROM kyro_email_verifications WHERE id = ?").run(s.id),{success:true,userId:s.user_id}):{success:false,error:"Invalid verification token"}}async createPasswordResetToken(e){await this.ensureConnected();let s=await this.findUserByEmail(e);if(!s)return {token:"",expiresAt:new Date,error:"User not found"};let t=randomBytes(16).toString("hex"),r=randomBytes(32).toString("hex"),n=new Date(Date.now()+3600*1e3);return this.db.prepare("INSERT INTO kyro_password_resets (id, user_id, token, expires_at, created_at) VALUES (?, ?, ?, ?, ?)").run(t,s.id,r,n.toISOString(),new Date().toISOString()),{token:r,expiresAt:n}}async resetPasswordWithToken(e,s){await this.ensureConnected();let t=this.db.prepare("SELECT * FROM kyro_password_resets WHERE token = ?").get(e);if(!t)return {success:false,error:"Invalid reset token"};if(new Date(t.expires_at)<new Date)return {success:false,error:"Reset token has expired"};if(t.used_at)return {success:false,error:"Reset token has already been used"};let r=await this.hashPassword(s);return this.db.prepare("UPDATE kyro_users SET password_hash = ?, updated_at = ? WHERE id = ?").run(r,new Date().toISOString(),t.user_id),this.db.prepare("UPDATE kyro_password_resets SET used_at = ? WHERE id = ?").run(new Date().toISOString(),t.id),this.db.prepare("DELETE FROM kyro_sessions WHERE user_id = ?").run(t.user_id),{success:true}}};export{
|
|
123
|
+
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`).run(s,t,e.action,e.userId||null,e.userEmail||null,e.role||null,e.resource,e.resourceId||null,e.ipAddress||null,e.userAgent||null,e.success?1:0,e.error||null,e.metadata?JSON.stringify(e.metadata):null,new Date().toISOString()),s}async queryAuditLogs(e={}){await this.ensureConnected();let s=[],t=[];e.action&&(s.push("action = ?"),t.push(e.action)),e.userId&&(s.push("user_id = ?"),t.push(e.userId)),e.resource&&(s.push("resource = ?"),t.push(e.resource)),e.success!==void 0&&(s.push("success = ?"),t.push(e.success?1:0)),e.startDate&&(s.push("timestamp >= ?"),t.push(e.startDate.toISOString())),e.endDate&&(s.push("timestamp <= ?"),t.push(e.endDate.toISOString()));let r=s.length>0?"WHERE "+s.join(" AND "):"",n=e.limit||50,d=e.offset||0,u=this.db.prepare(`SELECT COUNT(*) as count FROM kyro_audit_logs ${r}`).get(...t),i=this.db.prepare(`SELECT * FROM kyro_audit_logs ${r} ORDER BY timestamp DESC LIMIT ? OFFSET ?`).all(...t,n,d);return {total:u.count,logs:i.map(a=>({id:a.id,timestamp:new Date(a.timestamp),action:a.action,userId:a.user_id||void 0,userEmail:a.user_email||void 0,resource:a.resource,resourceId:a.resource_id||void 0,ipAddress:a.ip_address||void 0,userAgent:a.user_agent||void 0,success:a.success===1,error:a.error||void 0,metadata:a.metadata?JSON.parse(a.metadata):void 0}))}}rowToUser(e){return {id:e.id,name:e.name||void 0,email:e.email,passwordHash:e.password_hash,role:e.role,tenantId:e.tenant_id,avatar:e.avatar,emailVerified:e.email_verified===1,locked:e.locked===1,lastLogin:e.last_login,failedLoginAttempts:e.failed_login_attempts||0,createdAt:e.created_at,updatedAt:e.updated_at}}rowToSession(e){return {id:e.id,userId:e.user_id,token:e.token,refreshToken:e.refresh_token,expiresAt:e.expires_at,createdAt:e.created_at,ipAddress:e.ip_address,userAgent:e.user_agent}}async findAuditLogs(e){let s=await this.queryAuditLogs({action:e.action,userId:e.userId,resource:e.resource,success:e.success,startDate:e.startDate,endDate:e.endDate,limit:e.limit,offset:e.offset});return {logs:s.logs.map(t=>({...t,action:t.action})),total:s.total}}async createAuditLog(e){let s=await this.logAudit({action:e.action,userId:e.userId,userEmail:e.userEmail,role:e.role,resource:e.resource,resourceId:e.resourceId,ipAddress:e.ipAddress,userAgent:e.userAgent,success:e.success,error:e.error,metadata:e.metadata}),t=this.db?.prepare("SELECT * FROM kyro_audit_logs WHERE id = ?").get(s);return {...e,id:s,timestamp:t?new Date(t.timestamp):new Date}}async createEmailVerificationToken(e){await this.ensureConnected();let s=randomBytes(16).toString("hex"),t=randomBytes(32).toString("hex"),r=new Date(Date.now()+1440*60*1e3);return this.db.prepare("INSERT INTO kyro_email_verifications (id, user_id, token, expires_at, created_at) VALUES (?, ?, ?, ?, ?)").run(s,e,t,r.toISOString(),new Date().toISOString()),{token:t,expiresAt:r}}async verifyEmailToken(e){await this.ensureConnected();let s=this.db.prepare("SELECT * FROM kyro_email_verifications WHERE token = ?").get(e);return s?new Date(s.expires_at)<new Date?{success:false,error:"Verification token has expired"}:(this.db.prepare("UPDATE kyro_users SET email_verified = 1 WHERE id = ?").run(s.user_id),this.db.prepare("DELETE FROM kyro_email_verifications WHERE id = ?").run(s.id),{success:true,userId:s.user_id}):{success:false,error:"Invalid verification token"}}async createPasswordResetToken(e){await this.ensureConnected();let s=await this.findUserByEmail(e);if(!s)return {token:"",expiresAt:new Date,error:"User not found"};let t=randomBytes(16).toString("hex"),r=randomBytes(32).toString("hex"),n=new Date(Date.now()+3600*1e3);return this.db.prepare("INSERT INTO kyro_password_resets (id, user_id, token, expires_at, created_at) VALUES (?, ?, ?, ?, ?)").run(t,s.id,r,n.toISOString(),new Date().toISOString()),{token:r,expiresAt:n}}async resetPasswordWithToken(e,s){await this.ensureConnected();let t=this.db.prepare("SELECT * FROM kyro_password_resets WHERE token = ?").get(e);if(!t)return {success:false,error:"Invalid reset token"};if(new Date(t.expires_at)<new Date)return {success:false,error:"Reset token has expired"};if(t.used_at)return {success:false,error:"Reset token has already been used"};let r=await this.hashPassword(s);return this.db.prepare("UPDATE kyro_users SET password_hash = ?, updated_at = ? WHERE id = ?").run(r,new Date().toISOString(),t.user_id),this.db.prepare("UPDATE kyro_password_resets SET used_at = ? WHERE id = ?").run(new Date().toISOString(),t.id),this.db.prepare("DELETE FROM kyro_sessions WHERE user_id = ?").run(t.user_id),{success:true}}};export{T as a};
|
|
@@ -1,110 +1,110 @@
|
|
|
1
|
-
'use strict';var chunkHTYVI2HK_cjs=require('./chunk-HTYVI2HK.cjs'),chunkBUNLC3II_cjs=require('./chunk-BUNLC3II.cjs'),crypto=require('crypto'),fs=require('fs'),path=require('path'),module$1=require('module');chunkBUNLC3II_cjs.h();var
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
1
|
+
'use strict';var chunkHTYVI2HK_cjs=require('./chunk-HTYVI2HK.cjs'),chunkBUNLC3II_cjs=require('./chunk-BUNLC3II.cjs'),crypto=require('crypto'),fs=require('fs'),path=require('path'),module$1=require('module');chunkBUNLC3II_cjs.h();var l=chunkBUNLC3II_cjs.e(chunkHTYVI2HK_cjs.a(),1);chunkBUNLC3II_cjs.h();var p=`
|
|
2
|
+
CREATE TABLE IF NOT EXISTS kyro_users (
|
|
3
|
+
id TEXT PRIMARY KEY,
|
|
4
|
+
name TEXT,
|
|
5
|
+
email TEXT UNIQUE NOT NULL,
|
|
6
|
+
password_hash TEXT NOT NULL,
|
|
7
|
+
role TEXT NOT NULL DEFAULT 'customer',
|
|
8
|
+
tenant_id TEXT,
|
|
9
|
+
email_verified INTEGER DEFAULT 0,
|
|
10
|
+
locked INTEGER DEFAULT 0,
|
|
11
|
+
last_login TEXT,
|
|
12
|
+
failed_login_attempts INTEGER DEFAULT 0,
|
|
13
|
+
locked_until TEXT,
|
|
14
|
+
avatar TEXT,
|
|
15
|
+
created_at TEXT NOT NULL,
|
|
16
|
+
updated_at TEXT NOT NULL
|
|
17
|
+
);
|
|
18
18
|
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
19
|
+
CREATE TABLE IF NOT EXISTS kyro_sessions (
|
|
20
|
+
id TEXT PRIMARY KEY,
|
|
21
|
+
user_id TEXT NOT NULL,
|
|
22
|
+
token TEXT NOT NULL,
|
|
23
|
+
refresh_token TEXT,
|
|
24
|
+
expires_at TEXT NOT NULL,
|
|
25
|
+
created_at TEXT NOT NULL,
|
|
26
|
+
ip_address TEXT,
|
|
27
|
+
user_agent TEXT,
|
|
28
|
+
FOREIGN KEY (user_id) REFERENCES kyro_users(id) ON DELETE CASCADE
|
|
29
|
+
);
|
|
30
30
|
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
31
|
+
CREATE TABLE IF NOT EXISTS kyro_password_history (
|
|
32
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
33
|
+
user_id TEXT NOT NULL,
|
|
34
|
+
password_hash TEXT NOT NULL,
|
|
35
|
+
created_at TEXT NOT NULL,
|
|
36
|
+
FOREIGN KEY (user_id) REFERENCES kyro_users(id) ON DELETE CASCADE
|
|
37
|
+
);
|
|
38
38
|
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
39
|
+
CREATE TABLE IF NOT EXISTS kyro_rate_limits (
|
|
40
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
41
|
+
key TEXT NOT NULL,
|
|
42
|
+
window_start INTEGER NOT NULL,
|
|
43
|
+
count INTEGER NOT NULL DEFAULT 1,
|
|
44
|
+
UNIQUE(key, window_start)
|
|
45
|
+
);
|
|
46
46
|
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
47
|
+
CREATE TABLE IF NOT EXISTS kyro_lockouts (
|
|
48
|
+
user_id TEXT PRIMARY KEY,
|
|
49
|
+
attempts INTEGER NOT NULL DEFAULT 0,
|
|
50
|
+
last_attempt INTEGER,
|
|
51
|
+
locked_at INTEGER,
|
|
52
|
+
locked_until INTEGER
|
|
53
|
+
);
|
|
54
54
|
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
55
|
+
CREATE TABLE IF NOT EXISTS kyro_audit_logs (
|
|
56
|
+
id TEXT PRIMARY KEY,
|
|
57
|
+
timestamp TEXT NOT NULL,
|
|
58
|
+
action TEXT NOT NULL,
|
|
59
|
+
user_id TEXT,
|
|
60
|
+
user_email TEXT,
|
|
61
|
+
role TEXT,
|
|
62
|
+
resource TEXT NOT NULL,
|
|
63
|
+
resource_id TEXT,
|
|
64
|
+
ip_address TEXT,
|
|
65
|
+
user_agent TEXT,
|
|
66
|
+
success INTEGER NOT NULL,
|
|
67
|
+
error TEXT,
|
|
68
|
+
metadata TEXT,
|
|
69
|
+
created_at TEXT NOT NULL DEFAULT (datetime('now'))
|
|
70
|
+
);
|
|
71
71
|
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
72
|
+
CREATE INDEX IF NOT EXISTS idx_kyro_users_email ON kyro_users(email);
|
|
73
|
+
CREATE INDEX IF NOT EXISTS idx_kyro_sessions_user_id ON kyro_sessions(user_id);
|
|
74
|
+
CREATE INDEX IF NOT EXISTS idx_kyro_sessions_token ON kyro_sessions(token);
|
|
75
|
+
CREATE INDEX IF NOT EXISTS idx_kyro_sessions_refresh_token ON kyro_sessions(refresh_token);
|
|
76
|
+
CREATE INDEX IF NOT EXISTS idx_kyro_sessions_expires ON kyro_sessions(expires_at);
|
|
77
|
+
CREATE INDEX IF NOT EXISTS idx_kyro_password_history_user_id ON kyro_password_history(user_id);
|
|
78
|
+
CREATE INDEX IF NOT EXISTS idx_kyro_rate_limits_key ON kyro_rate_limits(key);
|
|
79
|
+
CREATE INDEX IF NOT EXISTS idx_kyro_rate_limits_window ON kyro_rate_limits(window_start);
|
|
80
|
+
CREATE INDEX IF NOT EXISTS idx_kyro_lockouts_locked_until ON kyro_lockouts(locked_until);
|
|
81
|
+
CREATE INDEX IF NOT EXISTS idx_kyro_audit_logs_timestamp ON kyro_audit_logs(timestamp);
|
|
82
|
+
CREATE INDEX IF NOT EXISTS idx_kyro_audit_logs_action ON kyro_audit_logs(action);
|
|
83
|
+
CREATE INDEX IF NOT EXISTS idx_kyro_audit_logs_user_id ON kyro_audit_logs(user_id);
|
|
84
|
+
CREATE INDEX IF NOT EXISTS idx_kyro_audit_logs_resource ON kyro_audit_logs(resource);
|
|
85
85
|
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
86
|
+
CREATE TABLE IF NOT EXISTS kyro_email_verifications (
|
|
87
|
+
id TEXT PRIMARY KEY,
|
|
88
|
+
user_id TEXT NOT NULL,
|
|
89
|
+
token TEXT UNIQUE NOT NULL,
|
|
90
|
+
expires_at TEXT NOT NULL,
|
|
91
|
+
created_at TEXT NOT NULL DEFAULT (datetime('now')),
|
|
92
|
+
FOREIGN KEY (user_id) REFERENCES kyro_users(id) ON DELETE CASCADE
|
|
93
|
+
);
|
|
94
94
|
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
95
|
+
CREATE TABLE IF NOT EXISTS kyro_password_resets (
|
|
96
|
+
id TEXT PRIMARY KEY,
|
|
97
|
+
user_id TEXT NOT NULL,
|
|
98
|
+
token TEXT UNIQUE NOT NULL,
|
|
99
|
+
expires_at TEXT NOT NULL,
|
|
100
|
+
used_at TEXT,
|
|
101
|
+
created_at TEXT NOT NULL DEFAULT (datetime('now')),
|
|
102
|
+
FOREIGN KEY (user_id) REFERENCES kyro_users(id) ON DELETE CASCADE
|
|
103
|
+
);
|
|
104
104
|
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
105
|
+
CREATE INDEX IF NOT EXISTS idx_kyro_email_verifications_token ON kyro_email_verifications(token);
|
|
106
|
+
CREATE INDEX IF NOT EXISTS idx_kyro_password_resets_token ON kyro_password_resets(token);
|
|
107
|
+
`;var E;function y(){return E||(E=module$1.createRequire("file:///")("node:sqlite").DatabaseSync,E)}var R=5e3,L=1e3,N=-64e3,I=268435456,T=class{db=null;path;saltRounds;externalDb;busyTimeout;walAutoCheckpoint;cacheSize;mmapSize;preparedStatements=new Map;constructor(e={}){this.path=e.path||"./data/auth.db",this.saltRounds=e.saltRounds||12,this.externalDb=!!e.db,this.busyTimeout=e.busyTimeout??R,this.walAutoCheckpoint=e.walAutoCheckpoint??L,this.cacheSize=e.cacheSize??N,this.mmapSize=e.mmapSize??I,e.db&&(this.db=e.db);}async connect(){if(this.db)return;let e=path.dirname(this.path);e&&e!=="."&&fs.mkdirSync(e,{recursive:true}),this.db=new(y())(this.path),this.db.exec(`PRAGMA busy_timeout = ${this.busyTimeout}`),this.db.exec("PRAGMA journal_mode = WAL"),this.db.exec("PRAGMA synchronous = NORMAL"),this.db.exec("PRAGMA cache_size = "+this.cacheSize),this.db.exec("PRAGMA mmap_size = "+this.mmapSize),this.db.exec("PRAGMA wal_autocheckpoint = "+this.walAutoCheckpoint),this.db.exec("PRAGMA foreign_keys = ON"),this.db.exec("PRAGMA temp_store = MEMORY"),this.ensureTables(),this.prepareStatements();}async disconnect(){this.db&&!this.externalDb&&(this.db.exec("PRAGMA wal_checkpoint(TRUNCATE)"),this.db.close(),this.db=null,this.preparedStatements.clear());}async ensureConnected(){if(this.db||await this.connect(),!this.db)throw new Error("Failed to connect to SQLite database");return this.db}ensureTables(){if(this.db){this.db.exec(p);try{this.db.exec("ALTER TABLE kyro_users ADD COLUMN name TEXT");}catch{}try{this.db.exec("ALTER TABLE kyro_users ADD COLUMN avatar TEXT");}catch{}}}prepareStatements(){this.db&&(this.preparedStatements.set("findUserByEmail",this.db.prepare("SELECT * FROM kyro_users WHERE email = ?")),this.preparedStatements.set("findUserById",this.db.prepare("SELECT * FROM kyro_users WHERE id = ?")),this.preparedStatements.set("findSessionByToken",this.db.prepare("SELECT * FROM kyro_sessions WHERE token = ?")),this.preparedStatements.set("findSessionByRefreshToken",this.db.prepare("SELECT * FROM kyro_sessions WHERE refresh_token = ?")),this.preparedStatements.set("deleteSession",this.db.prepare("DELETE FROM kyro_sessions WHERE id = ? OR token = ?")),this.preparedStatements.set("deleteUserSessions",this.db.prepare("DELETE FROM kyro_sessions WHERE user_id = ?")),this.preparedStatements.set("countUsers",this.db.prepare("SELECT COUNT(*) as count FROM kyro_users")),this.preparedStatements.set("deleteUser",this.db.prepare("DELETE FROM kyro_users WHERE id = ?")),this.preparedStatements.set("findUsersPaginated",this.db.prepare("SELECT * FROM kyro_users ORDER BY created_at DESC LIMIT ? OFFSET ?")),this.preparedStatements.set("findUsersWithSearch",this.db.prepare("SELECT * FROM kyro_users WHERE email LIKE ? ORDER BY created_at DESC LIMIT ? OFFSET ?")),this.preparedStatements.set("countUsersWithSearch",this.db.prepare("SELECT COUNT(*) as count FROM kyro_users WHERE email LIKE ?")),this.preparedStatements.set("getPasswordHistory",this.db.prepare("SELECT password_hash FROM kyro_password_history WHERE user_id = ? ORDER BY created_at DESC LIMIT ?")),this.preparedStatements.set("addPasswordHistory",this.db.prepare("INSERT INTO kyro_password_history (user_id, password_hash, created_at) VALUES (?, ?, ?)")),this.preparedStatements.set("trimPasswordHistory",this.db.prepare(`DELETE FROM kyro_password_history WHERE id IN (
|
|
108
108
|
SELECT id FROM kyro_password_history WHERE user_id = ? ORDER BY created_at DESC LIMIT -1 OFFSET 5
|
|
109
109
|
)`)),this.preparedStatements.set("deleteExpiredSessions",this.db.prepare("DELETE FROM kyro_sessions WHERE expires_at < ?")),this.preparedStatements.set("cleanupOldAuditLogs",this.db.prepare("DELETE FROM kyro_audit_logs WHERE timestamp < ?")),this.preparedStatements.set("cleanupExpiredLockouts",this.db.prepare("UPDATE kyro_lockouts SET attempts = 0, locked_at = NULL, locked_until = NULL WHERE locked_until < ?")),this.preparedStatements.set("getLockout",this.db.prepare("SELECT * FROM kyro_lockouts WHERE user_id = ?")),this.preparedStatements.set("upsertLockout",this.db.prepare(`
|
|
110
110
|
INSERT INTO kyro_lockouts (user_id, attempts, last_attempt, locked_at, locked_until)
|
|
@@ -115,8 +115,8 @@
|
|
|
115
115
|
locked_at = excluded.locked_at,
|
|
116
116
|
locked_until = excluded.locked_until
|
|
117
117
|
`)),this.preparedStatements.set("resetLockout",this.db.prepare("UPDATE kyro_lockouts SET attempts = 0, locked_at = NULL, locked_until = NULL WHERE user_id = ?")));}stmt(e){let s=this.preparedStatements.get(e);if(!s)throw new Error(`Prepared statement not found: ${e}`);return s}async cleanupExpiredSessions(){return await this.ensureConnected(),this.stmt("deleteExpiredSessions").run(new Date().toISOString()).changes}async cleanupOldAuditLogs(e=30){await this.ensureConnected();let s=new Date(Date.now()-e*24*60*60*1e3).toISOString();return this.stmt("cleanupOldAuditLogs").run(s).changes}async getStats(){await this.ensureConnected();let e=this.stmt("countUsers").get().count,s=this.db.prepare("SELECT COUNT(*) as count FROM kyro_sessions WHERE expires_at > ?").get(new Date().toISOString()).count,t=this.db.prepare("SELECT COUNT(*) as count FROM kyro_audit_logs").get().count;return {userCount:e,activeSessionCount:s,auditLogCount:t}}async createUser(e){await this.ensureConnected();let s=crypto.randomBytes(16).toString("hex"),t=new Date().toISOString(),r=await this.hashPassword(e.password),n={id:s,name:e.name,email:e.email.toLowerCase(),passwordHash:r,role:e.role||"customer",avatar:e.avatar,tenantId:e.tenantId,createdAt:t,updatedAt:t};return this.db.prepare(`INSERT INTO kyro_users (id, name, email, password_hash, role, avatar, tenant_id, created_at, updated_at)
|
|
118
|
-
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)`).run(s,n.name||null,n.email,n.passwordHash,n.role,n.avatar||null,n.tenantId||null,t,t),n}async findUserByEmail(e){await this.ensureConnected();let s=this.stmt("findUserByEmail").get(e.toLowerCase());return s?this.rowToUser(s):null}async findUserById(e){await this.ensureConnected();let s=this.stmt("findUserById").get(e);return s?this.rowToUser(s):null}async updateUser(e,s){if(await this.ensureConnected(),!await this.findUserById(e))return null;let r=[],n=[];return s.email!==void 0&&(r.push("email = ?"),n.push(s.email.toLowerCase())),s.name!==void 0&&(r.push("name = ?"),n.push(s.name)),s.passwordHash!==void 0&&(r.push("password_hash = ?"),n.push(s.passwordHash)),s.role!==void 0&&(r.push("role = ?"),n.push(s.role)),s.avatar!==void 0&&(r.push("avatar = ?"),n.push(s.avatar)),s.tenantId!==void 0&&(r.push("tenant_id = ?"),n.push(s.tenantId)),s.emailVerified!==void 0&&(r.push("email_verified = ?"),n.push(s.emailVerified?1:0)),s.locked!==void 0&&(r.push("locked = ?"),n.push(s.locked?1:0)),s.lastLogin!==void 0&&(r.push("last_login = ?"),n.push(s.lastLogin)),s.failedLoginAttempts!==void 0&&(r.push("failed_login_attempts = ?"),n.push(s.failedLoginAttempts)),r.push("updated_at = ?"),n.push(new Date().toISOString()),n.push(e),this.db.prepare(`UPDATE kyro_users SET ${r.join(", ")} WHERE id = ?`).run(...n),this.findUserById(e)}async deleteUser(e){return await this.ensureConnected(),this.stmt("deleteUser").run(e).changes>0}async hashPassword(e){return
|
|
119
|
-
VALUES (?, ?, ?, ?, ?, ?, ?, ?)`).run(i.id,i.userId,i.token,i.refreshToken??null,i.expiresAt,i.createdAt,i.ipAddress??null,i.userAgent??null),i}async findSessionByToken(e){await this.ensureConnected();let s=this.stmt("findSessionByToken").get(e);return s?this.rowToSession(s):null}async findSessionByRefreshToken(e){await this.ensureConnected();let s=this.stmt("findSessionByRefreshToken").get(e);return s?this.rowToSession(s):null}async deleteSession(e){return await this.ensureConnected(),this.stmt("deleteSession").run(e,e).changes>0}async deleteUserSessions(e){return await this.ensureConnected(),this.stmt("deleteUserSessions").run(e).changes}async hasAnyUsers(){return await this.ensureConnected(),this.stmt("countUsers").get().count>0}async findUsers(e={}){await this.ensureConnected();let s=e.page??1,t=e.limit??10,r=(s-1)*t,n=e.search,d,u;if(n){let i=`%${n}%`;d=this.stmt("countUsersWithSearch").get(i).count,u=this.stmt("findUsersWithSearch").all(i,t,r);}else d=this.stmt("countUsers").get().count,u=this.stmt("findUsersPaginated").all(t,r);return {users:u.map(i=>this.rowToUser(i)),total:d}}async addPasswordToHistory(e,s){await this.ensureConnected(),this.stmt("addPasswordHistory").run(e,s,new Date().toISOString()),this.stmt("trimPasswordHistory").run(e);}async getPasswordHistory(e,s=5){return await this.ensureConnected(),this.stmt("getPasswordHistory").all(e,s).map(r=>r.password_hash)}async isPasswordInHistory(e,s,t=5){let r=await this.getPasswordHistory(s,t);for(let n of r)if(await
|
|
118
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)`).run(s,n.name||null,n.email,n.passwordHash,n.role,n.avatar||null,n.tenantId||null,t,t),n}async findUserByEmail(e){await this.ensureConnected();let s=this.stmt("findUserByEmail").get(e.toLowerCase());return s?this.rowToUser(s):null}async findUserById(e){await this.ensureConnected();let s=this.stmt("findUserById").get(e);return s?this.rowToUser(s):null}async updateUser(e,s){if(await this.ensureConnected(),!await this.findUserById(e))return null;let r=[],n=[];return s.email!==void 0&&(r.push("email = ?"),n.push(s.email.toLowerCase())),s.name!==void 0&&(r.push("name = ?"),n.push(s.name)),s.passwordHash!==void 0&&(r.push("password_hash = ?"),n.push(s.passwordHash)),s.role!==void 0&&(r.push("role = ?"),n.push(s.role)),s.avatar!==void 0&&(r.push("avatar = ?"),n.push(s.avatar)),s.tenantId!==void 0&&(r.push("tenant_id = ?"),n.push(s.tenantId)),s.emailVerified!==void 0&&(r.push("email_verified = ?"),n.push(s.emailVerified?1:0)),s.locked!==void 0&&(r.push("locked = ?"),n.push(s.locked?1:0)),s.lastLogin!==void 0&&(r.push("last_login = ?"),n.push(s.lastLogin)),s.failedLoginAttempts!==void 0&&(r.push("failed_login_attempts = ?"),n.push(s.failedLoginAttempts)),r.push("updated_at = ?"),n.push(new Date().toISOString()),n.push(e),this.db.prepare(`UPDATE kyro_users SET ${r.join(", ")} WHERE id = ?`).run(...n),this.findUserById(e)}async deleteUser(e){return await this.ensureConnected(),this.stmt("deleteUser").run(e).changes>0}async hashPassword(e){return l.default.hash(e,this.saltRounds)}async verifyPassword(e,s){await this.ensureConnected();let t=await this.findUserByEmail(e);if(!t)return null;let r=this.db.prepare("SELECT password_hash FROM kyro_users WHERE id = ?").get(t.id);return r?.password_hash&&await l.default.compare(s,r.password_hash)?t:null}async createSession(e,s={}){await this.ensureConnected();let t=crypto.randomBytes(32).toString("hex"),r=crypto.randomBytes(32).toString("base64url"),n=crypto.randomBytes(32).toString("base64url"),d=new Date,u=new Date(d.getTime()+864e5).toISOString(),i={id:t,userId:e,token:r,refreshToken:n,expiresAt:u,createdAt:d.toISOString(),ipAddress:s.ipAddress,userAgent:s.userAgent};return this.db.prepare(`INSERT INTO kyro_sessions (id, user_id, token, refresh_token, expires_at, created_at, ip_address, user_agent)
|
|
119
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?)`).run(i.id,i.userId,i.token,i.refreshToken??null,i.expiresAt,i.createdAt,i.ipAddress??null,i.userAgent??null),i}async findSessionByToken(e){await this.ensureConnected();let s=this.stmt("findSessionByToken").get(e);return s?this.rowToSession(s):null}async findSessionByRefreshToken(e){await this.ensureConnected();let s=this.stmt("findSessionByRefreshToken").get(e);return s?this.rowToSession(s):null}async deleteSession(e){return await this.ensureConnected(),this.stmt("deleteSession").run(e,e).changes>0}async deleteUserSessions(e){return await this.ensureConnected(),this.stmt("deleteUserSessions").run(e).changes}async hasAnyUsers(){return await this.ensureConnected(),this.stmt("countUsers").get().count>0}async findUsers(e={}){await this.ensureConnected();let s=e.page??1,t=e.limit??10,r=(s-1)*t,n=e.search,d,u;if(n){let i=`%${n}%`;d=this.stmt("countUsersWithSearch").get(i).count,u=this.stmt("findUsersWithSearch").all(i,t,r);}else d=this.stmt("countUsers").get().count,u=this.stmt("findUsersPaginated").all(t,r);return {users:u.map(i=>this.rowToUser(i)),total:d}}async addPasswordToHistory(e,s){await this.ensureConnected(),this.stmt("addPasswordHistory").run(e,s,new Date().toISOString()),this.stmt("trimPasswordHistory").run(e);}async getPasswordHistory(e,s=5){return await this.ensureConnected(),this.stmt("getPasswordHistory").all(e,s).map(r=>r.password_hash)}async isPasswordInHistory(e,s,t=5){let r=await this.getPasswordHistory(s,t);for(let n of r)if(await l.default.compare(e,n))return true;return false}async recordFailedAttempt(e){await this.ensureConnected();let s=Date.now(),t=this.stmt("getLockout").get(e),r=(t?.attempts||0)+1,n=r>=5?s+900*1e3:t?.locked_until||null;this.stmt("upsertLockout").run(e,r,s,n!==null?s:null,n);}async resetAttempts(e){await this.ensureConnected(),this.stmt("resetLockout").run(e);}async checkLockout(e){await this.ensureConnected(),this.stmt("cleanupExpiredLockouts").run(Date.now());let s=this.stmt("getLockout").get(e);return s?s.locked_until!==null&&s.locked_until>Date.now()?{locked:true,attemptsRemaining:0,lockedUntil:new Date(s.locked_until),totalAttempts:s.attempts}:{locked:false,attemptsRemaining:Math.max(0,5-s.attempts),totalAttempts:s.attempts}:{locked:false,attemptsRemaining:5,totalAttempts:0}}async logAudit(e){await this.ensureConnected();let s=crypto.randomBytes(16).toString("hex"),t=new Date().toISOString();return this.db.prepare(`INSERT INTO kyro_audit_logs (
|
|
120
120
|
id, timestamp, action, user_id, user_email, role, resource, resource_id,
|
|
121
121
|
ip_address, user_agent, success, error, metadata, created_at
|
|
122
|
-
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`).run(s,t,e.action,e.userId||null,e.userEmail||null,e.role||null,e.resource,e.resourceId||null,e.ipAddress||null,e.userAgent||null,e.success?1:0,e.error||null,e.metadata?JSON.stringify(e.metadata):null,new Date().toISOString()),s}async queryAuditLogs(e={}){await this.ensureConnected();let s=[],t=[];e.action&&(s.push("action = ?"),t.push(e.action)),e.userId&&(s.push("user_id = ?"),t.push(e.userId)),e.resource&&(s.push("resource = ?"),t.push(e.resource)),e.success!==void 0&&(s.push("success = ?"),t.push(e.success?1:0)),e.startDate&&(s.push("timestamp >= ?"),t.push(e.startDate.toISOString())),e.endDate&&(s.push("timestamp <= ?"),t.push(e.endDate.toISOString()));let r=s.length>0?"WHERE "+s.join(" AND "):"",n=e.limit||50,d=e.offset||0,u=this.db.prepare(`SELECT COUNT(*) as count FROM kyro_audit_logs ${r}`).get(...t),i=this.db.prepare(`SELECT * FROM kyro_audit_logs ${r} ORDER BY timestamp DESC LIMIT ? OFFSET ?`).all(...t,n,d);return {total:u.count,logs:i.map(a=>({id:a.id,timestamp:new Date(a.timestamp),action:a.action,userId:a.user_id||void 0,userEmail:a.user_email||void 0,resource:a.resource,resourceId:a.resource_id||void 0,ipAddress:a.ip_address||void 0,userAgent:a.user_agent||void 0,success:a.success===1,error:a.error||void 0,metadata:a.metadata?JSON.parse(a.metadata):void 0}))}}rowToUser(e){return {id:e.id,name:e.name||void 0,email:e.email,passwordHash:e.password_hash,role:e.role,tenantId:e.tenant_id,avatar:e.avatar,emailVerified:e.email_verified===1,locked:e.locked===1,lastLogin:e.last_login,failedLoginAttempts:e.failed_login_attempts||0,createdAt:e.created_at,updatedAt:e.updated_at}}rowToSession(e){return {id:e.id,userId:e.user_id,token:e.token,refreshToken:e.refresh_token,expiresAt:e.expires_at,createdAt:e.created_at,ipAddress:e.ip_address,userAgent:e.user_agent}}async findAuditLogs(e){let s=await this.queryAuditLogs({action:e.action,userId:e.userId,resource:e.resource,success:e.success,startDate:e.startDate,endDate:e.endDate,limit:e.limit,offset:e.offset});return {logs:s.logs.map(t=>({...t,action:t.action})),total:s.total}}async createAuditLog(e){let s=await this.logAudit({action:e.action,userId:e.userId,userEmail:e.userEmail,role:e.role,resource:e.resource,resourceId:e.resourceId,ipAddress:e.ipAddress,userAgent:e.userAgent,success:e.success,error:e.error,metadata:e.metadata}),t=this.db?.prepare("SELECT * FROM kyro_audit_logs WHERE id = ?").get(s);return {...e,id:s,timestamp:t?new Date(t.timestamp):new Date}}async createEmailVerificationToken(e){await this.ensureConnected();let s=crypto.randomBytes(16).toString("hex"),t=crypto.randomBytes(32).toString("hex"),r=new Date(Date.now()+1440*60*1e3);return this.db.prepare("INSERT INTO kyro_email_verifications (id, user_id, token, expires_at, created_at) VALUES (?, ?, ?, ?, ?)").run(s,e,t,r.toISOString(),new Date().toISOString()),{token:t,expiresAt:r}}async verifyEmailToken(e){await this.ensureConnected();let s=this.db.prepare("SELECT * FROM kyro_email_verifications WHERE token = ?").get(e);return s?new Date(s.expires_at)<new Date?{success:false,error:"Verification token has expired"}:(this.db.prepare("UPDATE kyro_users SET email_verified = 1 WHERE id = ?").run(s.user_id),this.db.prepare("DELETE FROM kyro_email_verifications WHERE id = ?").run(s.id),{success:true,userId:s.user_id}):{success:false,error:"Invalid verification token"}}async createPasswordResetToken(e){await this.ensureConnected();let s=await this.findUserByEmail(e);if(!s)return {token:"",expiresAt:new Date,error:"User not found"};let t=crypto.randomBytes(16).toString("hex"),r=crypto.randomBytes(32).toString("hex"),n=new Date(Date.now()+3600*1e3);return this.db.prepare("INSERT INTO kyro_password_resets (id, user_id, token, expires_at, created_at) VALUES (?, ?, ?, ?, ?)").run(t,s.id,r,n.toISOString(),new Date().toISOString()),{token:r,expiresAt:n}}async resetPasswordWithToken(e,s){await this.ensureConnected();let t=this.db.prepare("SELECT * FROM kyro_password_resets WHERE token = ?").get(e);if(!t)return {success:false,error:"Invalid reset token"};if(new Date(t.expires_at)<new Date)return {success:false,error:"Reset token has expired"};if(t.used_at)return {success:false,error:"Reset token has already been used"};let r=await this.hashPassword(s);return this.db.prepare("UPDATE kyro_users SET password_hash = ?, updated_at = ? WHERE id = ?").run(r,new Date().toISOString(),t.user_id),this.db.prepare("UPDATE kyro_password_resets SET used_at = ? WHERE id = ?").run(new Date().toISOString(),t.id),this.db.prepare("DELETE FROM kyro_sessions WHERE user_id = ?").run(t.user_id),{success:true}}};exports.a=
|
|
122
|
+
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`).run(s,t,e.action,e.userId||null,e.userEmail||null,e.role||null,e.resource,e.resourceId||null,e.ipAddress||null,e.userAgent||null,e.success?1:0,e.error||null,e.metadata?JSON.stringify(e.metadata):null,new Date().toISOString()),s}async queryAuditLogs(e={}){await this.ensureConnected();let s=[],t=[];e.action&&(s.push("action = ?"),t.push(e.action)),e.userId&&(s.push("user_id = ?"),t.push(e.userId)),e.resource&&(s.push("resource = ?"),t.push(e.resource)),e.success!==void 0&&(s.push("success = ?"),t.push(e.success?1:0)),e.startDate&&(s.push("timestamp >= ?"),t.push(e.startDate.toISOString())),e.endDate&&(s.push("timestamp <= ?"),t.push(e.endDate.toISOString()));let r=s.length>0?"WHERE "+s.join(" AND "):"",n=e.limit||50,d=e.offset||0,u=this.db.prepare(`SELECT COUNT(*) as count FROM kyro_audit_logs ${r}`).get(...t),i=this.db.prepare(`SELECT * FROM kyro_audit_logs ${r} ORDER BY timestamp DESC LIMIT ? OFFSET ?`).all(...t,n,d);return {total:u.count,logs:i.map(a=>({id:a.id,timestamp:new Date(a.timestamp),action:a.action,userId:a.user_id||void 0,userEmail:a.user_email||void 0,resource:a.resource,resourceId:a.resource_id||void 0,ipAddress:a.ip_address||void 0,userAgent:a.user_agent||void 0,success:a.success===1,error:a.error||void 0,metadata:a.metadata?JSON.parse(a.metadata):void 0}))}}rowToUser(e){return {id:e.id,name:e.name||void 0,email:e.email,passwordHash:e.password_hash,role:e.role,tenantId:e.tenant_id,avatar:e.avatar,emailVerified:e.email_verified===1,locked:e.locked===1,lastLogin:e.last_login,failedLoginAttempts:e.failed_login_attempts||0,createdAt:e.created_at,updatedAt:e.updated_at}}rowToSession(e){return {id:e.id,userId:e.user_id,token:e.token,refreshToken:e.refresh_token,expiresAt:e.expires_at,createdAt:e.created_at,ipAddress:e.ip_address,userAgent:e.user_agent}}async findAuditLogs(e){let s=await this.queryAuditLogs({action:e.action,userId:e.userId,resource:e.resource,success:e.success,startDate:e.startDate,endDate:e.endDate,limit:e.limit,offset:e.offset});return {logs:s.logs.map(t=>({...t,action:t.action})),total:s.total}}async createAuditLog(e){let s=await this.logAudit({action:e.action,userId:e.userId,userEmail:e.userEmail,role:e.role,resource:e.resource,resourceId:e.resourceId,ipAddress:e.ipAddress,userAgent:e.userAgent,success:e.success,error:e.error,metadata:e.metadata}),t=this.db?.prepare("SELECT * FROM kyro_audit_logs WHERE id = ?").get(s);return {...e,id:s,timestamp:t?new Date(t.timestamp):new Date}}async createEmailVerificationToken(e){await this.ensureConnected();let s=crypto.randomBytes(16).toString("hex"),t=crypto.randomBytes(32).toString("hex"),r=new Date(Date.now()+1440*60*1e3);return this.db.prepare("INSERT INTO kyro_email_verifications (id, user_id, token, expires_at, created_at) VALUES (?, ?, ?, ?, ?)").run(s,e,t,r.toISOString(),new Date().toISOString()),{token:t,expiresAt:r}}async verifyEmailToken(e){await this.ensureConnected();let s=this.db.prepare("SELECT * FROM kyro_email_verifications WHERE token = ?").get(e);return s?new Date(s.expires_at)<new Date?{success:false,error:"Verification token has expired"}:(this.db.prepare("UPDATE kyro_users SET email_verified = 1 WHERE id = ?").run(s.user_id),this.db.prepare("DELETE FROM kyro_email_verifications WHERE id = ?").run(s.id),{success:true,userId:s.user_id}):{success:false,error:"Invalid verification token"}}async createPasswordResetToken(e){await this.ensureConnected();let s=await this.findUserByEmail(e);if(!s)return {token:"",expiresAt:new Date,error:"User not found"};let t=crypto.randomBytes(16).toString("hex"),r=crypto.randomBytes(32).toString("hex"),n=new Date(Date.now()+3600*1e3);return this.db.prepare("INSERT INTO kyro_password_resets (id, user_id, token, expires_at, created_at) VALUES (?, ?, ?, ?, ?)").run(t,s.id,r,n.toISOString(),new Date().toISOString()),{token:r,expiresAt:n}}async resetPasswordWithToken(e,s){await this.ensureConnected();let t=this.db.prepare("SELECT * FROM kyro_password_resets WHERE token = ?").get(e);if(!t)return {success:false,error:"Invalid reset token"};if(new Date(t.expires_at)<new Date)return {success:false,error:"Reset token has expired"};if(t.used_at)return {success:false,error:"Reset token has already been used"};let r=await this.hashPassword(s);return this.db.prepare("UPDATE kyro_users SET password_hash = ?, updated_at = ? WHERE id = ?").run(r,new Date().toISOString(),t.user_id),this.db.prepare("UPDATE kyro_password_resets SET used_at = ? WHERE id = ?").run(new Date().toISOString(),t.id),this.db.prepare("DELETE FROM kyro_sessions WHERE user_id = ?").run(t.user_id),{success:true}}};exports.a=T;
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import {D,A}from'./chunk-26MOA3HJ.js';import {e}from'./chunk-TBTQXIHP.js';import {hb}from'./chunk-RILJCH6H.js';import {a as a$1}from'./chunk-N6MNQIQU.js';import {g as g$1}from'./chunk-VJODUKKM.js';import {a}from'./chunk-ZWDBPEXL.js';import {a as a$2}from'./chunk-5ZEYOFAK.js';import {g}from'./chunk-Y2YAKDEQ.js';import w from'kyro:config';if (typeof window === "undefined") { const { createRequire } = await import(/* @vite-ignore */ 'module'); createRequire(import.meta.url); }
|
|
2
|
+
g();var r=null,l=null;async function b(){if(!r){if(globalThis.__KYRO_INSTANCE__)try{await globalThis.__KYRO_INSTANCE__.shutdown();}catch{}try{let e$1=w.default||w,t=e$1.adapter,o=t&&!t.dialect&&typeof t.connect=="function";if(globalThis.DB&&(!t||o)){let s=globalThis.DB;e$1.adapter=new g$1({type:"sqlite",client:s}),D.info("Hot-swapped to D1 DrizzleAdapter");}r=A(e$1),await r.init();let a$3=e$1.adapter,p=a$3&&a$3.dialect&&(a$3.dialect==="postgres"||a$3.dialect==="sqlite"),c=a$3&&a$3.dialect==="mongodb",n;if(p)a$3.dialect==="postgres"?n=new a({db:a$3.client}):a$3.dialect==="sqlite"&&(n=new hb({db:a$3.rawClient||a$3.client}));else if(o&&!globalThis.DB){let s=process.env.KYRO_AUTH_DB_PATH||"./data/auth.db";n=new a$1({path:s});}else c&&(n=new a$2({adapter:a$3}));if(n?.connect)try{await n.connect();}catch(s){D.warn("Auth connect warning:",s);}try{await r.loadSettings();}catch(s){D.warn("loadSettings warning:",s);}try{await e(n);}catch(s){D.warn("autoBootstrap warning:",s);}globalThis.__KYRO_INSTANCE__=r;}catch(e){throw r=null,l=null,D.error("Init failed, will retry:",e),e}}}async function E(e){let t=globalThis.DB?globalThis:null;try{let{env:o}=await import('cloudflare:workers');o&&(t=o);}catch{}if(e)try{t=e.locals?.cfContext?.env||e?.env||t;}catch{}if(!t)try{t=process.env;}catch{}t?.DB&&(globalThis.DB=t.DB),t?.STORAGE_BUCKET&&(globalThis.STORAGE_BUCKET=t.STORAGE_BUCKET),l||(l=b()),await l;}var _={graphqlEnabled:false,trpcEnabled:false,wsEnabled:false,requireAuth:false};function T(e){return r?r.settings?.access?.apiAccess?.[e]??_[e]??true:_[e]??true}var R=async e=>{if(!r)try{await Promise.race([E(e),new Promise((t,o)=>setTimeout(()=>o(new Error("Initialization timeout")),3e4))]);}catch(t){return console.error("[Kyro API] Warm error:",t?.stack||t?.message||t),new Response(JSON.stringify({error:"Service Unavailable",message:"Kyro CMS is still starting up. Please try again in a moment."}),{status:503,headers:{"Content-Type":"application/json","Retry-After":"5"}})}try{let o=new URL(e.request.url).pathname,a=__KYRO_API_PATH__;if(o===`${a}/graphql`&&typeof r.getGraphQL=="function"){if(!T("graphqlEnabled"))return new Response(JSON.stringify({error:"GraphQL is disabled"}),{status:503,headers:{"Content-Type":"application/json"}});let n=await r.getGraphQL().fetch(e.request,e.locals);return new Response(n.body,n)}if(o.startsWith(`${a}/trpc/`)&&typeof r.getTRPC=="function"){if(!T("trpcEnabled"))return new Response(JSON.stringify({error:"tRPC is disabled"}),{status:503,headers:{"Content-Type":"application/json"}});let n=await r.getTRPC().fetch(e.request,e.locals);return new Response(n.body,n)}return await(await r.getREST()).fetch(e.request,e.locals)}catch(t){return console.error("[Kyro API Execution Error]:",t?.stack||t?.message||t),new Response(JSON.stringify({error:"Internal Server Error",message:t?.message||String(t),stack:t?.stack}),{status:500,headers:{"Content-Type":"application/json"}})}},N=R;export{r as a,E as b,R as c,N as d};
|