@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.
Files changed (170) hide show
  1. package/dist/WebhookService-BCgL1bLF.d.cts +112 -0
  2. package/dist/WebhookService-BPVJUgTl.d.ts +112 -0
  3. package/dist/{base-DlhVlwnN.d.cts → base-B0Y6isUJ.d.cts} +1 -1
  4. package/dist/{base-CQkFzqQl.d.ts → base-DaP-5PPG.d.ts} +1 -1
  5. package/dist/bootstrap-BMWVB2T6.cjs +31 -0
  6. package/dist/{bootstrap-X6TP3NKX.cjs.map → bootstrap-BMWVB2T6.cjs.map} +1 -1
  7. package/dist/bootstrap-LL6O7PWO.js +6 -0
  8. package/dist/{bootstrap-BDTTUGY2.js.map → bootstrap-LL6O7PWO.js.map} +1 -1
  9. package/dist/{chunk-3VZCX4DF.cjs → chunk-42JPONZU.cjs} +77 -14
  10. package/dist/chunk-42JPONZU.cjs.map +1 -0
  11. package/dist/{chunk-MHS6CPO5.cjs → chunk-4M5PHMUE.cjs} +66 -346
  12. package/dist/chunk-4M5PHMUE.cjs.map +1 -0
  13. package/dist/chunk-4PWRCMTQ.cjs +15 -0
  14. package/dist/chunk-4PWRCMTQ.cjs.map +1 -0
  15. package/dist/chunk-6COM32WF.js +47 -0
  16. package/dist/chunk-6COM32WF.js.map +1 -0
  17. package/dist/chunk-6MSSF46R.js +941 -0
  18. package/dist/chunk-6MSSF46R.js.map +1 -0
  19. package/dist/{chunk-TZFJMPCH.cjs → chunk-7YITG2US.cjs} +9 -18
  20. package/dist/chunk-7YITG2US.cjs.map +1 -0
  21. package/dist/{chunk-A3RQWHKD.cjs → chunk-BLMFBDBG.cjs} +56 -6
  22. package/dist/chunk-BLMFBDBG.cjs.map +1 -0
  23. package/dist/{chunk-EINVJPFM.js → chunk-BTOE3VUK.js} +65 -3
  24. package/dist/chunk-BTOE3VUK.js.map +1 -0
  25. package/dist/chunk-E5X75WNB.js +497 -0
  26. package/dist/chunk-E5X75WNB.js.map +1 -0
  27. package/dist/chunk-E63IF3MD.cjs +951 -0
  28. package/dist/chunk-E63IF3MD.cjs.map +1 -0
  29. package/dist/{chunk-K7QF2QCM.cjs → chunk-FTSSDDZQ.cjs} +7 -3
  30. package/dist/chunk-FTSSDDZQ.cjs.map +1 -0
  31. package/dist/chunk-G7VZBCD6.cjs +35 -0
  32. package/dist/{chunk-5BLDMQED.cjs.map → chunk-G7VZBCD6.cjs.map} +1 -1
  33. package/dist/{chunk-VMSRTAH7.js → chunk-GLCPGZPM.js} +56 -6
  34. package/dist/chunk-GLCPGZPM.js.map +1 -0
  35. package/dist/{chunk-V3B25QOK.cjs → chunk-GVFB5C6O.cjs} +74 -2
  36. package/dist/chunk-GVFB5C6O.cjs.map +1 -0
  37. package/dist/chunk-HVSQDZZJ.cjs +765 -0
  38. package/dist/chunk-HVSQDZZJ.cjs.map +1 -0
  39. package/dist/chunk-HYC4GNHX.js +758 -0
  40. package/dist/chunk-HYC4GNHX.js.map +1 -0
  41. package/dist/chunk-KDVDIZ4Y.cjs +3479 -0
  42. package/dist/chunk-KDVDIZ4Y.cjs.map +1 -0
  43. package/dist/{chunk-OG3KX56O.js → chunk-KWGNR4HM.js} +7 -3
  44. package/dist/chunk-KWGNR4HM.js.map +1 -0
  45. package/dist/chunk-LIJVWQKU.cjs +256 -0
  46. package/dist/chunk-LIJVWQKU.cjs.map +1 -0
  47. package/dist/{chunk-XTZSUDSI.js → chunk-LTRCYJAG.js} +3 -18
  48. package/dist/chunk-LTRCYJAG.js.map +1 -0
  49. package/dist/{chunk-UEYC46RL.js → chunk-OUGKLCYF.js} +71 -8
  50. package/dist/chunk-OUGKLCYF.js.map +1 -0
  51. package/dist/chunk-RONAX6UU.js +3456 -0
  52. package/dist/chunk-RONAX6UU.js.map +1 -0
  53. package/dist/{chunk-C74MQIRL.js → chunk-RRYXQMZG.js} +66 -344
  54. package/dist/chunk-RRYXQMZG.js.map +1 -0
  55. package/dist/{chunk-QUJ4OLSC.js → chunk-U74F3YZU.js} +87 -7
  56. package/dist/chunk-U74F3YZU.js.map +1 -0
  57. package/dist/chunk-VIONYQ2K.cjs +517 -0
  58. package/dist/chunk-VIONYQ2K.cjs.map +1 -0
  59. package/dist/chunk-VSTRLXMQ.cjs +50 -0
  60. package/dist/chunk-VSTRLXMQ.cjs.map +1 -0
  61. package/dist/chunk-YT7HXXVN.js +13 -0
  62. package/dist/chunk-YT7HXXVN.js.map +1 -0
  63. package/dist/chunk-Z6ZWNWWR.js +30 -0
  64. package/dist/{chunk-NSBPE2FW.js.map → chunk-Z6ZWNWWR.js.map} +1 -1
  65. package/dist/cli/index.cjs +11 -7
  66. package/dist/cli/index.cjs.map +1 -1
  67. package/dist/cli/index.js +11 -7
  68. package/dist/cli/index.js.map +1 -1
  69. package/dist/drizzle/index.cjs +20 -17
  70. package/dist/drizzle/index.d.cts +4 -4
  71. package/dist/drizzle/index.d.ts +4 -4
  72. package/dist/drizzle/index.js +4 -5
  73. package/dist/graphql/index.cjs +4 -4
  74. package/dist/graphql/index.d.cts +3 -2
  75. package/dist/graphql/index.d.ts +3 -2
  76. package/dist/graphql/index.js +2 -2
  77. package/dist/{index-DI0DRPNv.d.cts → index-BwE4NueJ.d.cts} +1 -1
  78. package/dist/{index-CMUNCIWQ.d.ts → index-DUKmDSeC.d.cts} +96 -24
  79. package/dist/{index-BMySjW6o.d.cts → index-DtBi3zP0.d.ts} +96 -24
  80. package/dist/{index-4fJKLFK2.d.ts → index-DupWTmW6.d.ts} +1 -1
  81. package/dist/index.cjs +3317 -352
  82. package/dist/index.cjs.map +1 -1
  83. package/dist/index.d.cts +379 -105
  84. package/dist/index.d.ts +379 -105
  85. package/dist/index.js +3211 -310
  86. package/dist/index.js.map +1 -1
  87. package/dist/media-HOT3O7RW.js +4 -0
  88. package/dist/media-HOT3O7RW.js.map +1 -0
  89. package/dist/media-WKP5AOX2.cjs +17 -0
  90. package/dist/media-WKP5AOX2.cjs.map +1 -0
  91. package/dist/mongodb/index.cjs +1 -1
  92. package/dist/mongodb/index.d.cts +2 -2
  93. package/dist/mongodb/index.d.ts +2 -2
  94. package/dist/mongodb/index.js +1 -1
  95. package/dist/mysql-media-AI6YK767.cjs +48 -0
  96. package/dist/mysql-media-AI6YK767.cjs.map +1 -0
  97. package/dist/mysql-media-CDZUS7YX.js +45 -0
  98. package/dist/mysql-media-CDZUS7YX.js.map +1 -0
  99. package/dist/postgres-auth-adapter-EVRPO7BQ.cjs +14 -0
  100. package/dist/{postgres-auth-adapter-VK6GY7LX.cjs.map → postgres-auth-adapter-EVRPO7BQ.cjs.map} +1 -1
  101. package/dist/postgres-auth-adapter-OTRWSTT5.js +5 -0
  102. package/dist/{postgres-auth-adapter-REJFUMP7.js.map → postgres-auth-adapter-OTRWSTT5.js.map} +1 -1
  103. package/dist/redis-adapter-2N6VA7BI.cjs +13 -0
  104. package/dist/{redis-adapter-LBLNKGNS.cjs.map → redis-adapter-2N6VA7BI.cjs.map} +1 -1
  105. package/dist/redis-adapter-RA24FNCX.js +4 -0
  106. package/dist/{redis-adapter-4YDY4LWE.js.map → redis-adapter-RA24FNCX.js.map} +1 -1
  107. package/dist/rest/index.cjs +7 -5
  108. package/dist/rest/index.d.cts +29 -3
  109. package/dist/rest/index.d.ts +29 -3
  110. package/dist/rest/index.js +5 -3
  111. package/dist/schema-CNB2DDTX.js +6 -0
  112. package/dist/schema-CNB2DDTX.js.map +1 -0
  113. package/dist/schema-Y777CQQS.cjs +67 -0
  114. package/dist/schema-Y777CQQS.cjs.map +1 -0
  115. package/dist/templates/index.cjs +24 -28
  116. package/dist/templates/index.d.cts +2 -4
  117. package/dist/templates/index.d.ts +2 -4
  118. package/dist/templates/index.js +2 -2
  119. package/dist/trpc/index.cjs +12 -12
  120. package/dist/trpc/index.d.cts +19 -14
  121. package/dist/trpc/index.d.ts +19 -14
  122. package/dist/trpc/index.js +3 -3
  123. package/dist/{types-BGM5MV_K.d.cts → types-BM0s_YOy.d.cts} +67 -35
  124. package/dist/{types-BGM5MV_K.d.ts → types-BM0s_YOy.d.ts} +67 -35
  125. package/dist/ws/index.cjs +1 -1
  126. package/dist/ws/index.js +1 -1
  127. package/package.json +11 -1
  128. package/dist/bootstrap-BDTTUGY2.js +0 -4
  129. package/dist/bootstrap-X6TP3NKX.cjs +0 -29
  130. package/dist/chunk-3QX6KG2S.js +0 -2125
  131. package/dist/chunk-3QX6KG2S.js.map +0 -1
  132. package/dist/chunk-3VZCX4DF.cjs.map +0 -1
  133. package/dist/chunk-5BLDMQED.cjs +0 -18
  134. package/dist/chunk-7G6EVYCU.cjs +0 -94
  135. package/dist/chunk-7G6EVYCU.cjs.map +0 -1
  136. package/dist/chunk-A3RQWHKD.cjs.map +0 -1
  137. package/dist/chunk-C74MQIRL.js.map +0 -1
  138. package/dist/chunk-EINVJPFM.js.map +0 -1
  139. package/dist/chunk-F5B64H5S.cjs +0 -2149
  140. package/dist/chunk-F5B64H5S.cjs.map +0 -1
  141. package/dist/chunk-K7QF2QCM.cjs.map +0 -1
  142. package/dist/chunk-LRTZJJPD.js +0 -86
  143. package/dist/chunk-LRTZJJPD.js.map +0 -1
  144. package/dist/chunk-MHS6CPO5.cjs.map +0 -1
  145. package/dist/chunk-NSBPE2FW.js +0 -15
  146. package/dist/chunk-OG3KX56O.js.map +0 -1
  147. package/dist/chunk-QUJ4OLSC.js.map +0 -1
  148. package/dist/chunk-R3XIBBAW.cjs +0 -34
  149. package/dist/chunk-R3XIBBAW.cjs.map +0 -1
  150. package/dist/chunk-SDMNUYVU.js +0 -30
  151. package/dist/chunk-SDMNUYVU.js.map +0 -1
  152. package/dist/chunk-TZFJMPCH.cjs.map +0 -1
  153. package/dist/chunk-UEG7KMKC.cjs +0 -228
  154. package/dist/chunk-UEG7KMKC.cjs.map +0 -1
  155. package/dist/chunk-UEYC46RL.js.map +0 -1
  156. package/dist/chunk-V3B25QOK.cjs.map +0 -1
  157. package/dist/chunk-VMSRTAH7.js.map +0 -1
  158. package/dist/chunk-XTZSUDSI.js.map +0 -1
  159. package/dist/chunk-YD7Y25W7.cjs +0 -176
  160. package/dist/chunk-YD7Y25W7.cjs.map +0 -1
  161. package/dist/chunk-YPAFJ7EV.js +0 -225
  162. package/dist/chunk-YPAFJ7EV.js.map +0 -1
  163. package/dist/database-7CJOXEZR.js +0 -5
  164. package/dist/database-7CJOXEZR.js.map +0 -1
  165. package/dist/database-QOIV44GT.cjs +0 -22
  166. package/dist/database-QOIV44GT.cjs.map +0 -1
  167. package/dist/postgres-auth-adapter-REJFUMP7.js +0 -5
  168. package/dist/postgres-auth-adapter-VK6GY7LX.cjs +0 -14
  169. package/dist/redis-adapter-4YDY4LWE.js +0 -4
  170. package/dist/redis-adapter-LBLNKGNS.cjs +0 -13
@@ -1,8 +1,9 @@
1
+ import { EmailTransport } from './chunk-HYC4GNHX.js';
1
2
  import bcrypt from 'bcryptjs';
2
3
  import { randomBytes } from 'crypto';
3
- import nodemailer from 'nodemailer';
4
+ import { mkdirSync } from 'fs';
5
+ import { dirname } from 'path';
4
6
 
5
- // src/auth/sqlite-adapter.ts
6
7
  var DEFAULT_BUSY_TIMEOUT = 5e3;
7
8
  var DEFAULT_WAL_CHECKPOINT = 1e3;
8
9
  var DEFAULT_CACHE_SIZE = -64e3;
@@ -31,6 +32,10 @@ var SQLiteAuthAdapter = class {
31
32
  }
32
33
  async connect() {
33
34
  if (this.db) return;
35
+ const dir = dirname(this.path);
36
+ if (dir && dir !== ".") {
37
+ mkdirSync(dir, { recursive: true });
38
+ }
34
39
  const Database = (await import('better-sqlite3')).default;
35
40
  this.db = new Database(this.path, {
36
41
  timeout: this.busyTimeout
@@ -263,10 +268,11 @@ var SQLiteAuthAdapter = class {
263
268
  if (!this.db) throw new Error("Not connected");
264
269
  const id = randomBytes(16).toString("hex");
265
270
  const now = (/* @__PURE__ */ new Date()).toISOString();
271
+ const passwordHash = await this.hashPassword(data.password);
266
272
  const user = {
267
273
  id,
268
274
  email: data.email.toLowerCase(),
269
- passwordHash: data.passwordHash,
275
+ passwordHash,
270
276
  role: data.role || "customer",
271
277
  tenantId: data.tenantId,
272
278
  createdAt: now,
@@ -350,8 +356,14 @@ var SQLiteAuthAdapter = class {
350
356
  async hashPassword(password) {
351
357
  return bcrypt.hash(password, this.saltRounds);
352
358
  }
353
- async verifyPassword(password, hash) {
354
- return bcrypt.compare(password, hash);
359
+ async verifyPassword(email, password) {
360
+ if (!this.db) throw new Error("Not connected");
361
+ const user = await this.findUserByEmail(email);
362
+ if (!user) return null;
363
+ const stored = this.db.prepare("SELECT password_hash FROM users WHERE id = ?").get(user.id);
364
+ if (!stored?.password_hash) return null;
365
+ const valid = await bcrypt.compare(password, stored.password_hash);
366
+ return valid ? user : null;
355
367
  }
356
368
  async createSession(userId, data = {}) {
357
369
  if (!this.db) throw new Error("Not connected");
@@ -585,337 +597,45 @@ var SQLiteAuthAdapter = class {
585
597
  userAgent: row.user_agent
586
598
  };
587
599
  }
588
- };
589
- var defaultTemplates = {
590
- verifyEmail: (link, userName = "User") => ({
591
- subject: "Verify your email address",
592
- html: `
593
- <!DOCTYPE html>
594
- <html>
595
- <head>
596
- <meta charset="utf-8">
597
- <meta name="viewport" content="width=device-width, initial-scale=1">
598
- <title>Verify Email</title>
599
- <style>
600
- body { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; line-height: 1.6; color: #333; }
601
- .container { max-width: 600px; margin: 0 auto; padding: 20px; }
602
- .button { display: inline-block; padding: 12px 24px; background: #0b1222; color: white; text-decoration: none; border-radius: 6px; font-weight: 600; }
603
- .footer { margin-top: 30px; font-size: 12px; color: #666; }
604
- </style>
605
- </head>
606
- <body>
607
- <div class="container">
608
- <h1>Welcome, ${userName}!</h1>
609
- <p>Please verify your email address by clicking the button below:</p>
610
- <p style="text-align: center; margin: 30px 0;">
611
- <a href="${link}" class="button">Verify Email</a>
612
- </p>
613
- <p>Or copy and paste this link into your browser:</p>
614
- <p style="word-break: break-all; color: #666;">${link}</p>
615
- <p>This link will expire in 24 hours.</p>
616
- <div class="footer">
617
- <p>If you didn't create an account, you can safely ignore this email.</p>
618
- </div>
619
- </div>
620
- </body>
621
- </html>
622
- `,
623
- text: `Welcome ${userName}!
624
-
625
- Please verify your email by clicking this link: ${link}
626
-
627
- This link will expire in 24 hours.
628
-
629
- If you didn't create an account, you can safely ignore this email.`
630
- }),
631
- resetPassword: (link, userName = "User") => ({
632
- subject: "Reset your password",
633
- html: `
634
- <!DOCTYPE html>
635
- <html>
636
- <head>
637
- <meta charset="utf-8">
638
- <meta name="viewport" content="width=device-width, initial-scale=1">
639
- <title>Reset Password</title>
640
- <style>
641
- body { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; line-height: 1.6; color: #333; }
642
- .container { max-width: 600px; margin: 0 auto; padding: 20px; }
643
- .button { display: inline-block; padding: 12px 24px; background: #dc2626; color: white; text-decoration: none; border-radius: 6px; font-weight: 600; }
644
- .warning { background: #fef3c7; border: 1px solid #f59e0b; padding: 12px; border-radius: 6px; margin: 20px 0; }
645
- .footer { margin-top: 30px; font-size: 12px; color: #666; }
646
- </style>
647
- </head>
648
- <body>
649
- <div class="container">
650
- <h1>Password Reset Request</h1>
651
- <p>Hello ${userName},</p>
652
- <p>We received a request to reset your password. Click the button below to create a new password:</p>
653
- <p style="text-align: center; margin: 30px 0;">
654
- <a href="${link}" class="button">Reset Password</a>
655
- </p>
656
- <p>Or copy and paste this link into your browser:</p>
657
- <p style="word-break: break-all; color: #666;">${link}</p>
658
- <div class="warning">
659
- <strong>\u26A0\uFE0F Important:</strong> This link will expire in 1 hour. If you didn't request a password reset, please ignore this email or contact support if you have concerns.
660
- </div>
661
- <div class="footer">
662
- <p>For security reasons, please don't share this email with anyone.</p>
663
- </div>
664
- </div>
665
- </body>
666
- </html>
667
- `,
668
- text: `Password Reset Request
669
-
670
- Hello ${userName},
671
-
672
- We received a request to reset your password. Click this link to create a new password: ${link}
673
-
674
- This link will expire in 1 hour.
675
-
676
- If you didn't request a password reset, please ignore this email.`
677
- }),
678
- welcome: (userName = "User") => ({
679
- subject: "Welcome to Kyro CMS",
680
- html: `
681
- <!DOCTYPE html>
682
- <html>
683
- <head>
684
- <meta charset="utf-8">
685
- <meta name="viewport" content="width=device-width, initial-scale=1">
686
- <title>Welcome</title>
687
- <style>
688
- body { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; line-height: 1.6; color: #333; }
689
- .container { max-width: 600px; margin: 0 auto; padding: 20px; }
690
- .button { display: inline-block; padding: 12px 24px; background: #0b1222; color: white; text-decoration: none; border-radius: 6px; font-weight: 600; }
691
- </style>
692
- </head>
693
- <body>
694
- <div class="container">
695
- <h1>Welcome to Kyro CMS, ${userName}!</h1>
696
- <p>Your account has been created successfully.</p>
697
- <p>You can now:</p>
698
- <ul>
699
- <li>Manage your content collections</li>
700
- <li>Upload and organize media</li>
701
- <li>Configure settings</li>
702
- <li>And much more...</li>
703
- </ul>
704
- <p style="text-align: center; margin: 30px 0;">
705
- <a href="#" class="button">Get Started</a>
706
- </p>
707
- <p>If you have any questions, feel free to reach out to our support team.</p>
708
- </div>
709
- </body>
710
- </html>
711
- `,
712
- text: `Welcome to Kyro CMS, ${userName}!
713
-
714
- Your account has been created successfully.
715
-
716
- You can now:
717
- - Manage your content collections
718
- - Upload and organize media
719
- - Configure settings
720
- - And much more...
721
-
722
- Get started by logging into your dashboard.`
723
- }),
724
- accountLocked: (attempts, duration, userName = "User") => ({
725
- subject: "Account Security Alert - Account Locked",
726
- html: `
727
- <!DOCTYPE html>
728
- <html>
729
- <head>
730
- <meta charset="utf-8">
731
- <meta name="viewport" content="width=device-width, initial-scale=1">
732
- <title>Account Locked</title>
733
- <style>
734
- body { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; line-height: 1.6; color: #333; }
735
- .container { max-width: 600px; margin: 0 auto; padding: 20px; }
736
- .alert { background: #fef2f2; border: 1px solid #ef4444; padding: 16px; border-radius: 8px; margin: 20px 0; }
737
- .footer { margin-top: 30px; font-size: 12px; color: #666; }
738
- </style>
739
- </head>
740
- <body>
741
- <div class="container">
742
- <h1>Account Security Alert</h1>
743
- <p>Hello ${userName},</p>
744
- <div class="alert">
745
- <p><strong>\u26A0\uFE0F Your account has been temporarily locked due to multiple failed login attempts.</strong></p>
746
- <p>Failed attempts: ${attempts}</p>
747
- <p>Lockout duration: ${Math.round(duration / 6e4)} minutes</p>
748
- </div>
749
- <p>Your account will automatically unlock after the lockout period expires.</p>
750
- <p>If this wasn't you, we recommend:</p>
751
- <ul>
752
- <li>Using a strong, unique password</li>
753
- <li>Enabling two-factor authentication (coming soon)</li>
754
- <li>Reviewing your recent account activity</li>
755
- </ul>
756
- <div class="footer">
757
- <p>If you need immediate assistance, please contact support.</p>
758
- </div>
759
- </div>
760
- </body>
761
- </html>
762
- `,
763
- text: `Account Security Alert
764
-
765
- Hello ${userName},
766
-
767
- Your account has been temporarily locked due to multiple failed login attempts (${attempts}).
768
-
769
- Lockout duration: ${Math.round(duration / 6e4)} minutes
770
-
771
- Your account will automatically unlock after this period.
772
-
773
- If this wasn't you, we recommend using a strong, unique password.`
774
- }),
775
- passwordChanged: (userName = "User") => ({
776
- subject: "Your password has been changed",
777
- html: `
778
- <!DOCTYPE html>
779
- <html>
780
- <head>
781
- <meta charset="utf-8">
782
- <meta name="viewport" content="width=device-width, initial-scale=1">
783
- <title>Password Changed</title>
784
- <style>
785
- body { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; line-height: 1.6; color: #333; }
786
- .container { max-width: 600px; margin: 0 auto; padding: 20px; }
787
- .info { background: #f0fdf4; border: 1px solid #22c55e; padding: 12px; border-radius: 6px; margin: 20px 0; }
788
- </style>
789
- </head>
790
- <body>
791
- <div class="container">
792
- <h1>Password Changed</h1>
793
- <p>Hello ${userName},</p>
794
- <div class="info">
795
- <p>Your password was recently changed.</p>
796
- </div>
797
- <p>If you did this, you can safely ignore this email.</p>
798
- <p><strong>If you didn't change your password</strong>, please contact our support team immediately as your account may have been compromised.</p>
799
- </div>
800
- </body>
801
- </html>
802
- `,
803
- text: `Password Changed
804
-
805
- Hello ${userName},
806
-
807
- Your password was recently changed.
808
-
809
- If you did this, you can safely ignore this email.
810
-
811
- If you didn't change your password, please contact support immediately.`
812
- }),
813
- newLogin: (location, time, userName = "User") => ({
814
- subject: "New login to your account",
815
- html: `
816
- <!DOCTYPE html>
817
- <html>
818
- <head>
819
- <meta charset="utf-8">
820
- <meta name="viewport" content="width=device-width, initial-scale=1">
821
- <title>New Login</title>
822
- <style>
823
- body { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; line-height: 1.6; color: #333; }
824
- .container { max-width: 600px; margin: 0 auto; padding: 20px; }
825
- .info-box { background: #f8fafc; border: 1px solid #e2e8f0; padding: 16px; border-radius: 8px; margin: 20px 0; }
826
- .footer { margin-top: 30px; font-size: 12px; color: #666; }
827
- </style>
828
- </head>
829
- <body>
830
- <div class="container">
831
- <h1>New Login Detected</h1>
832
- <p>Hello ${userName},</p>
833
- <p>We detected a new login to your account:</p>
834
- <div class="info-box">
835
- <p><strong>Location:</strong> ${location}</p>
836
- <p><strong>Time:</strong> ${time}</p>
837
- </div>
838
- <p><strong>If this was you</strong>, no action is needed.</p>
839
- <p><strong>If this wasn't you</strong>, your account may be compromised. Please:</p>
840
- <ol>
841
- <li>Change your password immediately</li>
842
- <li>Review your recent account activity</li>
843
- <li>Contact support if needed</li>
844
- </ol>
845
- <div class="footer">
846
- <p>This is an automated security notification.</p>
847
- </div>
848
- </div>
849
- </body>
850
- </html>
851
- `,
852
- text: `New Login Detected
853
-
854
- Hello ${userName},
855
-
856
- We detected a new login to your account:
857
-
858
- Location: ${location}
859
- Time: ${time}
860
-
861
- If this wasn't you, please change your password immediately and contact support.`
862
- })
863
- };
864
- var EmailTransport = class _EmailTransport {
865
- transporter;
866
- from;
867
- fromName;
868
- templates;
869
- constructor(config, templates) {
870
- this.transporter = nodemailer.createTransport({
871
- host: config.host,
872
- port: config.port,
873
- secure: config.secure,
874
- auth: config.auth
600
+ async findAuditLogs(filter) {
601
+ const result = await this.queryAuditLogs({
602
+ action: filter.action,
603
+ userId: filter.userId,
604
+ resource: filter.resource,
605
+ success: filter.success,
606
+ startDate: filter.startDate,
607
+ endDate: filter.endDate,
608
+ limit: filter.limit,
609
+ offset: filter.offset
875
610
  });
876
- this.from = config.from;
877
- this.fromName = config.fromName || "Kyro CMS";
878
- this.templates = { ...defaultTemplates, ...templates };
879
- }
880
- async send(options) {
881
- return this.transporter.sendMail({
882
- from: `"${this.fromName}" <${this.from}>`,
883
- to: Array.isArray(options.to) ? options.to.join(", ") : options.to,
884
- subject: options.subject,
885
- html: options.html,
886
- text: options.text
887
- });
888
- }
889
- getTemplates() {
890
- return this.templates;
891
- }
892
- async verifyConnection() {
893
- try {
894
- await this.transporter.verify();
895
- return true;
896
- } catch {
897
- return false;
898
- }
611
+ return {
612
+ logs: result.logs.map((log) => ({
613
+ ...log,
614
+ action: log.action
615
+ })),
616
+ total: result.total
617
+ };
899
618
  }
900
- static fromEnv() {
901
- const host = process.env.SMTP_HOST;
902
- const port = parseInt(process.env.SMTP_PORT || "587", 10);
903
- const secure = process.env.SMTP_SECURE === "true";
904
- const user = process.env.SMTP_USER;
905
- const pass = process.env.SMTP_PASS;
906
- const from = process.env.SMTP_FROM || process.env.DEFAULT_FROM || "noreply@example.com";
907
- const fromName = process.env.SMTP_FROM_NAME || "Kyro CMS";
908
- if (!host || !user || !pass) {
909
- return null;
910
- }
911
- return new _EmailTransport({
912
- host,
913
- port,
914
- secure,
915
- auth: { user, pass },
916
- from,
917
- fromName
619
+ async createAuditLog(data) {
620
+ const id = await this.logAudit({
621
+ action: data.action,
622
+ userId: data.userId,
623
+ userEmail: data.userEmail,
624
+ role: data.role,
625
+ resource: data.resource,
626
+ resourceId: data.resourceId,
627
+ ipAddress: data.ipAddress,
628
+ userAgent: data.userAgent,
629
+ success: data.success,
630
+ error: data.error,
631
+ metadata: data.metadata
918
632
  });
633
+ const row = this.db?.prepare("SELECT * FROM kyro_audit_logs WHERE id = ?").get(id);
634
+ return {
635
+ ...data,
636
+ id,
637
+ timestamp: row ? new Date(row.timestamp) : /* @__PURE__ */ new Date()
638
+ };
919
639
  }
920
640
  };
921
641
 
@@ -1114,10 +834,9 @@ async function bootstrapAdmin(config) {
1114
834
  };
1115
835
  }
1116
836
  try {
1117
- const passwordHash = await authAdapter.hashPassword(adminPassword);
1118
837
  const user = await authAdapter.createUser({
1119
838
  email: adminEmail,
1120
- passwordHash,
839
+ password: adminPassword,
1121
840
  role: adminRole || "admin",
1122
841
  tenantId
1123
842
  });
@@ -1160,12 +879,15 @@ function getBootstrapFromEnv() {
1160
879
  adminRole: process.env.KYRO_ADMIN_ROLE || "super_admin",
1161
880
  tenantId: process.env.KYRO_ADMIN_TENANT_ID,
1162
881
  emailConfig: process.env.SMTP_HOST ? {
1163
- host: process.env.SMTP_HOST,
1164
- port: parseInt(process.env.SMTP_PORT || "587", 10),
1165
- secure: process.env.SMTP_SECURE === "true",
1166
- auth: {
1167
- user: process.env.SMTP_USER || "",
1168
- pass: process.env.SMTP_PASS || ""
882
+ provider: "smtp",
883
+ smtp: {
884
+ host: process.env.SMTP_HOST,
885
+ port: parseInt(process.env.SMTP_PORT || "587", 10),
886
+ secure: process.env.SMTP_SECURE === "true",
887
+ auth: {
888
+ user: process.env.SMTP_USER || "",
889
+ pass: process.env.SMTP_PASS || ""
890
+ }
1169
891
  },
1170
892
  from: process.env.SMTP_FROM || "noreply@example.com",
1171
893
  fromName: process.env.SMTP_FROM_NAME
@@ -1208,6 +930,6 @@ async function bootstrapWithRetry(config, maxRetries = 3, retryDelayMs = 2e3) {
1208
930
  };
1209
931
  }
1210
932
 
1211
- export { EmailTransport, PasswordPolicy, SQLiteAuthAdapter, autoBootstrap, bootstrapAdmin, bootstrapWithRetry, checkBootstrapRequired, getBootstrapFromEnv };
1212
- //# sourceMappingURL=chunk-C74MQIRL.js.map
1213
- //# sourceMappingURL=chunk-C74MQIRL.js.map
933
+ export { PasswordPolicy, SQLiteAuthAdapter, autoBootstrap, bootstrapAdmin, bootstrapWithRetry, checkBootstrapRequired, getBootstrapFromEnv };
934
+ //# sourceMappingURL=chunk-RRYXQMZG.js.map
935
+ //# sourceMappingURL=chunk-RRYXQMZG.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/auth/sqlite-adapter.ts","../src/auth/security/password-policy.ts","../src/auth/bootstrap.ts"],"names":[],"mappings":"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","file":"chunk-RRYXQMZG.js","sourcesContent":["import type Database from \"better-sqlite3\";\nimport bcrypt from \"bcryptjs\";\nimport { randomBytes } from \"crypto\";\nimport { mkdirSync } from \"fs\";\nimport { dirname } from \"path\";\nimport type { AuthAdapter, AuthUser, Session, UserRole } from \"./types.js\";\nimport type { AuditLog, AuditLogFilter } from \"./security/audit-log.js\";\n\nexport interface SQLiteAuthAdapterOptions {\n path?: string;\n db?: Database.Database;\n saltRounds?: number;\n busyTimeout?: number;\n walAutoCheckpoint?: number;\n cacheSize?: number;\n mmapSize?: number;\n}\n\nconst DEFAULT_BUSY_TIMEOUT = 5000;\nconst DEFAULT_WAL_CHECKPOINT = 1000;\nconst DEFAULT_CACHE_SIZE = -64000;\nconst DEFAULT_MMAP_SIZE = 268435456;\n\nexport class SQLiteAuthAdapter implements AuthAdapter {\n private db: Database.Database | null = null;\n private path: string;\n private saltRounds: number;\n private externalDb: boolean;\n private busyTimeout: number;\n private walAutoCheckpoint: number;\n private cacheSize: number;\n private mmapSize: number;\n\n private preparedStatements: Map<string, Database.Statement> = new Map();\n\n constructor(options: SQLiteAuthAdapterOptions = {}) {\n this.path = options.path || \"./data/auth.db\";\n this.saltRounds = options.saltRounds || 12;\n this.externalDb = !!options.db;\n this.busyTimeout = options.busyTimeout ?? DEFAULT_BUSY_TIMEOUT;\n this.walAutoCheckpoint =\n options.walAutoCheckpoint ?? DEFAULT_WAL_CHECKPOINT;\n this.cacheSize = options.cacheSize ?? DEFAULT_CACHE_SIZE;\n this.mmapSize = options.mmapSize ?? DEFAULT_MMAP_SIZE;\n\n if (options.db) {\n this.db = options.db;\n }\n }\n\n async connect(): Promise<void> {\n if (this.db) return;\n\n const dir = dirname(this.path);\n if (dir && dir !== \".\") {\n mkdirSync(dir, { recursive: true });\n }\n\n const Database = (await import(\"better-sqlite3\")).default;\n this.db = new Database(this.path, {\n timeout: this.busyTimeout,\n });\n\n this.db.pragma(\"journal_mode = WAL\");\n this.db.pragma(\"synchronous = NORMAL\");\n this.db.pragma(\"cache_size = \" + this.cacheSize);\n this.db.pragma(\"mmap_size = \" + this.mmapSize);\n this.db.pragma(\"wal_autocheckpoint = \" + this.walAutoCheckpoint);\n this.db.pragma(\"foreign_keys = ON\");\n this.db.pragma(\"temp_store = MEMORY\");\n\n this.ensureTables();\n this.prepareStatements();\n }\n\n async disconnect(): Promise<void> {\n if (this.db && !this.externalDb) {\n this.db.pragma(\"wal_checkpoint(TRUNCATE)\");\n this.db.close();\n this.db = null;\n this.preparedStatements.clear();\n }\n }\n\n private ensureTables(): void {\n if (!this.db) return;\n\n this.db.exec(`\n CREATE TABLE IF NOT EXISTS kyro_users (\n id TEXT PRIMARY KEY,\n email TEXT UNIQUE NOT NULL,\n password_hash TEXT NOT NULL,\n role TEXT NOT NULL DEFAULT 'customer',\n tenant_id TEXT,\n email_verified INTEGER DEFAULT 0,\n locked INTEGER DEFAULT 0,\n last_login TEXT,\n failed_login_attempts INTEGER DEFAULT 0,\n locked_until TEXT,\n created_at TEXT NOT NULL,\n updated_at TEXT NOT NULL\n );\n\n CREATE TABLE IF NOT EXISTS kyro_sessions (\n id TEXT PRIMARY KEY,\n user_id TEXT NOT NULL,\n token TEXT NOT NULL,\n refresh_token TEXT,\n expires_at TEXT NOT NULL,\n created_at TEXT NOT NULL,\n ip_address TEXT,\n user_agent TEXT,\n FOREIGN KEY (user_id) REFERENCES kyro_users(id) ON DELETE CASCADE\n );\n\n CREATE TABLE IF NOT EXISTS kyro_password_history (\n id INTEGER PRIMARY KEY AUTOINCREMENT,\n user_id TEXT NOT NULL,\n password_hash TEXT NOT NULL,\n created_at TEXT NOT NULL,\n FOREIGN KEY (user_id) REFERENCES kyro_users(id) ON DELETE CASCADE\n );\n\n CREATE TABLE IF NOT EXISTS kyro_rate_limits (\n id INTEGER PRIMARY KEY AUTOINCREMENT,\n key TEXT NOT NULL,\n window_start INTEGER NOT NULL,\n count INTEGER NOT NULL DEFAULT 1,\n UNIQUE(key, window_start)\n );\n\n CREATE TABLE IF NOT EXISTS kyro_lockouts (\n user_id TEXT PRIMARY KEY,\n attempts INTEGER NOT NULL DEFAULT 0,\n last_attempt INTEGER,\n locked_at INTEGER,\n locked_until INTEGER\n );\n\n CREATE TABLE IF NOT EXISTS kyro_audit_logs (\n id TEXT PRIMARY KEY,\n timestamp TEXT NOT NULL,\n action TEXT NOT NULL,\n user_id TEXT,\n user_email TEXT,\n role TEXT,\n resource TEXT NOT NULL,\n resource_id TEXT,\n ip_address TEXT,\n user_agent TEXT,\n success INTEGER NOT NULL,\n error TEXT,\n metadata TEXT,\n created_at TEXT NOT NULL DEFAULT (datetime('now'))\n );\n\n CREATE INDEX IF NOT EXISTS idx_kyro_users_email ON kyro_users(email);\n CREATE INDEX IF NOT EXISTS idx_kyro_sessions_user_id ON kyro_sessions(user_id);\n CREATE INDEX IF NOT EXISTS idx_kyro_sessions_token ON kyro_sessions(token);\n CREATE INDEX IF NOT EXISTS idx_kyro_sessions_refresh_token ON kyro_sessions(refresh_token);\n CREATE INDEX IF NOT EXISTS idx_kyro_sessions_expires ON kyro_sessions(expires_at);\n CREATE INDEX IF NOT EXISTS idx_kyro_password_history_user_id ON kyro_password_history(user_id);\n CREATE INDEX IF NOT EXISTS idx_kyro_rate_limits_key ON kyro_rate_limits(key);\n CREATE INDEX IF NOT EXISTS idx_kyro_rate_limits_window ON kyro_rate_limits(window_start);\n CREATE INDEX IF NOT EXISTS idx_kyro_lockouts_locked_until ON kyro_lockouts(locked_until);\n CREATE INDEX IF NOT EXISTS idx_kyro_audit_logs_timestamp ON kyro_audit_logs(timestamp);\n CREATE INDEX IF NOT EXISTS idx_kyro_audit_logs_action ON kyro_audit_logs(action);\n CREATE INDEX IF NOT EXISTS idx_kyro_audit_logs_user_id ON kyro_audit_logs(user_id);\n CREATE INDEX IF NOT EXISTS idx_kyro_audit_logs_resource ON kyro_audit_logs(resource);\n `);\n }\n\n private prepareStatements(): void {\n if (!this.db) return;\n\n this.preparedStatements.set(\n \"findUserByEmail\",\n this.db.prepare(\"SELECT * FROM kyro_users WHERE email = ?\"),\n );\n this.preparedStatements.set(\n \"findUserById\",\n this.db.prepare(\"SELECT * FROM kyro_users WHERE id = ?\"),\n );\n this.preparedStatements.set(\n \"findSessionByToken\",\n this.db.prepare(\"SELECT * FROM kyro_sessions WHERE token = ?\"),\n );\n this.preparedStatements.set(\n \"findSessionByRefreshToken\",\n this.db.prepare(\"SELECT * FROM kyro_sessions WHERE refresh_token = ?\"),\n );\n this.preparedStatements.set(\n \"deleteSession\",\n this.db.prepare(\"DELETE FROM kyro_sessions WHERE id = ? OR token = ?\"),\n );\n this.preparedStatements.set(\n \"deleteUserSessions\",\n this.db.prepare(\"DELETE FROM kyro_sessions WHERE user_id = ?\"),\n );\n this.preparedStatements.set(\n \"countUsers\",\n this.db.prepare(\"SELECT COUNT(*) as count FROM kyro_users\"),\n );\n this.preparedStatements.set(\n \"deleteUser\",\n this.db.prepare(\"DELETE FROM kyro_users WHERE id = ?\"),\n );\n this.preparedStatements.set(\n \"getPasswordHistory\",\n this.db.prepare(\n \"SELECT password_hash FROM kyro_password_history WHERE user_id = ? ORDER BY created_at DESC LIMIT ?\",\n ),\n );\n this.preparedStatements.set(\n \"addPasswordHistory\",\n this.db.prepare(\n \"INSERT INTO kyro_password_history (user_id, password_hash, created_at) VALUES (?, ?, ?)\",\n ),\n );\n this.preparedStatements.set(\n \"trimPasswordHistory\",\n this.db.prepare(\n `DELETE FROM kyro_password_history WHERE id IN (\n SELECT id FROM kyro_password_history WHERE user_id = ? ORDER BY created_at DESC LIMIT -1 OFFSET 5\n )`,\n ),\n );\n this.preparedStatements.set(\n \"deleteExpiredSessions\",\n this.db.prepare(\"DELETE FROM kyro_sessions WHERE expires_at < ?\"),\n );\n this.preparedStatements.set(\n \"cleanupOldAuditLogs\",\n this.db.prepare(\"DELETE FROM kyro_audit_logs WHERE timestamp < ?\"),\n );\n this.preparedStatements.set(\n \"cleanupExpiredLockouts\",\n this.db.prepare(\n \"UPDATE kyro_lockouts SET attempts = 0, locked_at = NULL, locked_until = NULL WHERE locked_until < ?\",\n ),\n );\n this.preparedStatements.set(\n \"getLockout\",\n this.db.prepare(\"SELECT * FROM kyro_lockouts WHERE user_id = ?\"),\n );\n this.preparedStatements.set(\n \"upsertLockout\",\n this.db.prepare(`\n INSERT INTO kyro_lockouts (user_id, attempts, last_attempt, locked_at, locked_until)\n VALUES (?, ?, ?, ?, ?)\n ON CONFLICT(user_id) DO UPDATE SET\n attempts = excluded.attempts,\n last_attempt = excluded.last_attempt,\n locked_at = excluded.locked_at,\n locked_until = excluded.locked_until\n `),\n );\n this.preparedStatements.set(\n \"resetLockout\",\n this.db.prepare(\n \"UPDATE kyro_lockouts SET attempts = 0, locked_at = NULL, locked_until = NULL WHERE user_id = ?\",\n ),\n );\n }\n\n private stmt(name: string): Database.Statement {\n const stmt = this.preparedStatements.get(name);\n if (!stmt) throw new Error(`Prepared statement not found: ${name}`);\n return stmt;\n }\n\n async cleanupExpiredSessions(): Promise<number> {\n if (!this.db) throw new Error(\"Not connected\");\n const result = this.stmt(\"deleteExpiredSessions\").run(\n new Date().toISOString(),\n );\n return result.changes;\n }\n\n async cleanupOldAuditLogs(retentionDays: number = 30): Promise<number> {\n if (!this.db) throw new Error(\"Not connected\");\n const cutoff = new Date(\n Date.now() - retentionDays * 24 * 60 * 60 * 1000,\n ).toISOString();\n const result = this.stmt(\"cleanupOldAuditLogs\").run(cutoff);\n return result.changes;\n }\n\n async getStats(): Promise<{\n userCount: number;\n activeSessionCount: number;\n auditLogCount: number;\n }> {\n if (!this.db) throw new Error(\"Not connected\");\n\n const userCount = (this.stmt(\"countUsers\").get() as { count: number })\n .count;\n\n const activeSessionCount = (\n this.db\n .prepare(\n \"SELECT COUNT(*) as count FROM kyro_sessions WHERE expires_at > ?\",\n )\n .get(new Date().toISOString()) as { count: number }\n ).count;\n\n const auditLogCount = (\n this.db\n .prepare(\"SELECT COUNT(*) as count FROM kyro_audit_logs\")\n .get() as { count: number }\n ).count;\n\n return { userCount, activeSessionCount, auditLogCount };\n }\n\n async createUser(data: {\n email: string;\n password: string;\n role?: UserRole;\n tenantId?: string;\n }): Promise<AuthUser> {\n if (!this.db) throw new Error(\"Not connected\");\n\n const id = randomBytes(16).toString(\"hex\");\n const now = new Date().toISOString();\n const passwordHash = await this.hashPassword(data.password);\n\n const user: AuthUser = {\n id,\n email: data.email.toLowerCase(),\n passwordHash,\n role: (data.role || \"customer\") as UserRole,\n tenantId: data.tenantId,\n createdAt: now,\n updatedAt: now,\n };\n\n this.db\n .prepare(\n `INSERT INTO kyro_users (id, email, password_hash, role, tenant_id, created_at, updated_at)\n VALUES (?, ?, ?, ?, ?, ?, ?)`,\n )\n .run(\n id,\n user.email,\n user.passwordHash,\n user.role,\n user.tenantId,\n now,\n now,\n );\n\n return user;\n }\n\n async findUserByEmail(email: string): Promise<AuthUser | null> {\n if (!this.db) throw new Error(\"Not connected\");\n\n const row = this.stmt(\"findUserByEmail\").get(email.toLowerCase()) as\n | Record<string, unknown>\n | undefined;\n\n if (!row) return null;\n return this.rowToUser(row);\n }\n\n async findUserById(userId: string): Promise<AuthUser | null> {\n if (!this.db) throw new Error(\"Not connected\");\n\n const row = this.stmt(\"findUserById\").get(userId) as\n | Record<string, unknown>\n | undefined;\n\n if (!row) return null;\n return this.rowToUser(row);\n }\n\n async updateUser(\n userId: string,\n data: Partial<AuthUser>,\n ): Promise<AuthUser | null> {\n if (!this.db) throw new Error(\"Not connected\");\n\n const existing = await this.findUserById(userId);\n if (!existing) return null;\n\n const updates: string[] = [];\n const values: unknown[] = [];\n\n if (data.email !== undefined) {\n updates.push(\"email = ?\");\n values.push(data.email.toLowerCase());\n }\n if (data.passwordHash !== undefined) {\n updates.push(\"password_hash = ?\");\n values.push(data.passwordHash);\n }\n if (data.role !== undefined) {\n updates.push(\"role = ?\");\n values.push(data.role);\n }\n if (data.tenantId !== undefined) {\n updates.push(\"tenant_id = ?\");\n values.push(data.tenantId);\n }\n if (data.emailVerified !== undefined) {\n updates.push(\"email_verified = ?\");\n values.push(data.emailVerified ? 1 : 0);\n }\n if (data.locked !== undefined) {\n updates.push(\"locked = ?\");\n values.push(data.locked ? 1 : 0);\n }\n if (data.lastLogin !== undefined) {\n updates.push(\"last_login = ?\");\n values.push(data.lastLogin);\n }\n if (data.failedLoginAttempts !== undefined) {\n updates.push(\"failed_login_attempts = ?\");\n values.push(data.failedLoginAttempts);\n }\n\n updates.push(\"updated_at = ?\");\n values.push(new Date().toISOString());\n\n values.push(userId);\n\n this.db\n .prepare(`UPDATE kyro_users SET ${updates.join(\", \")} WHERE id = ?`)\n .run(...values);\n\n return this.findUserById(userId);\n }\n\n async deleteUser(userId: string): Promise<boolean> {\n if (!this.db) throw new Error(\"Not connected\");\n\n const result = this.stmt(\"deleteUser\").run(userId);\n return result.changes > 0;\n }\n\n async hashPassword(password: string): Promise<string> {\n return bcrypt.hash(password, this.saltRounds);\n }\n\n async verifyPassword(\n email: string,\n password: string,\n ): Promise<AuthUser | null> {\n if (!this.db) throw new Error(\"Not connected\");\n const user = await this.findUserByEmail(email);\n if (!user) return null;\n const stored = this.db\n .prepare(\"SELECT password_hash FROM users WHERE id = ?\")\n .get(user.id) as { password_hash: string } | undefined;\n if (!stored?.password_hash) return null;\n const valid = await bcrypt.compare(password, stored.password_hash);\n return valid ? user : null;\n }\n\n async createSession(\n userId: string,\n data: {\n ipAddress?: string;\n userAgent?: string;\n } = {},\n ): Promise<Session> {\n if (!this.db) throw new Error(\"Not connected\");\n\n const id = randomBytes(32).toString(\"hex\");\n const token = randomBytes(32).toString(\"base64url\");\n const refreshToken = randomBytes(32).toString(\"base64url\");\n const now = new Date();\n const expiresAt = new Date(now.getTime() + 86400000).toISOString();\n\n const session: Session = {\n id,\n userId,\n token,\n refreshToken,\n expiresAt,\n createdAt: now.toISOString(),\n ipAddress: data.ipAddress,\n userAgent: data.userAgent,\n };\n\n this.db\n .prepare(\n `INSERT INTO kyro_sessions (id, user_id, token, refresh_token, expires_at, created_at, ip_address, user_agent)\n VALUES (?, ?, ?, ?, ?, ?, ?, ?)`,\n )\n .run(\n session.id,\n session.userId,\n session.token,\n session.refreshToken,\n session.expiresAt,\n session.createdAt,\n session.ipAddress,\n session.userAgent,\n );\n\n return session;\n }\n\n async findSessionByToken(token: string): Promise<Session | null> {\n if (!this.db) throw new Error(\"Not connected\");\n\n const row = this.stmt(\"findSessionByToken\").get(token) as\n | Record<string, unknown>\n | undefined;\n\n if (!row) return null;\n return this.rowToSession(row);\n }\n\n async findSessionByRefreshToken(\n refreshToken: string,\n ): Promise<Session | null> {\n if (!this.db) throw new Error(\"Not connected\");\n\n const row = this.stmt(\"findSessionByRefreshToken\").get(refreshToken) as\n | Record<string, unknown>\n | undefined;\n\n if (!row) return null;\n return this.rowToSession(row);\n }\n\n async deleteSession(sessionId: string): Promise<boolean> {\n if (!this.db) throw new Error(\"Not connected\");\n\n const result = this.stmt(\"deleteSession\").run(sessionId, sessionId);\n return result.changes > 0;\n }\n\n async deleteUserSessions(userId: string): Promise<number> {\n if (!this.db) throw new Error(\"Not connected\");\n\n const result = this.stmt(\"deleteUserSessions\").run(userId);\n return result.changes;\n }\n\n async hasAnyUsers(): Promise<boolean> {\n if (!this.db) throw new Error(\"Not connected\");\n\n const row = this.stmt(\"countUsers\").get() as { count: number };\n return row.count > 0;\n }\n\n async addPasswordToHistory(\n userId: string,\n passwordHash: string,\n ): Promise<void> {\n if (!this.db) throw new Error(\"Not connected\");\n\n this.stmt(\"addPasswordHistory\").run(\n userId,\n passwordHash,\n new Date().toISOString(),\n );\n this.stmt(\"trimPasswordHistory\").run(userId);\n }\n\n async getPasswordHistory(\n userId: string,\n count: number = 5,\n ): Promise<string[]> {\n if (!this.db) throw new Error(\"Not connected\");\n\n const rows = this.stmt(\"getPasswordHistory\").all(userId, count) as Array<{\n password_hash: string;\n }>;\n\n return rows.map((r) => r.password_hash);\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 for (const hash of history) {\n if (await bcrypt.compare(password, hash)) {\n return true;\n }\n }\n return false;\n }\n\n async recordFailedAttempt(userId: string): Promise<void> {\n if (!this.db) throw new Error(\"Not connected\");\n\n const now = Date.now();\n const lockout = this.stmt(\"getLockout\").get(userId) as\n | { attempts: number; locked_until: number | null }\n | undefined;\n\n const attempts = (lockout?.attempts || 0) + 1;\n const lockedUntil =\n attempts >= 5 ? now + 15 * 60 * 1000 : lockout?.locked_until || null;\n\n this.stmt(\"upsertLockout\").run(\n userId,\n attempts,\n now,\n lockedUntil !== null ? now : null,\n lockedUntil,\n );\n }\n\n async resetAttempts(userId: string): Promise<void> {\n if (!this.db) throw new Error(\"Not connected\");\n this.stmt(\"resetLockout\").run(userId);\n }\n\n async checkLockout(userId: string): Promise<{\n locked: boolean;\n attemptsRemaining: number;\n lockedUntil?: Date;\n totalAttempts: number;\n }> {\n if (!this.db) throw new Error(\"Not connected\");\n\n this.stmt(\"cleanupExpiredLockouts\").run(Date.now());\n\n const lockout = this.stmt(\"getLockout\").get(userId) as\n | { attempts: number; locked_until: number | null }\n | undefined;\n\n if (!lockout) {\n return {\n locked: false,\n attemptsRemaining: 5,\n totalAttempts: 0,\n };\n }\n\n if (lockout.locked_until !== null && lockout.locked_until > Date.now()) {\n return {\n locked: true,\n attemptsRemaining: 0,\n lockedUntil: new Date(lockout.locked_until),\n totalAttempts: lockout.attempts,\n };\n }\n\n return {\n locked: false,\n attemptsRemaining: Math.max(0, 5 - lockout.attempts),\n totalAttempts: lockout.attempts,\n };\n }\n\n async logAudit(data: {\n action: string;\n userId?: string;\n userEmail?: string;\n role?: string;\n resource: string;\n resourceId?: string;\n ipAddress?: string;\n userAgent?: string;\n success: boolean;\n error?: string;\n metadata?: Record<string, unknown>;\n }): Promise<string> {\n if (!this.db) throw new Error(\"Not connected\");\n\n const id = randomBytes(16).toString(\"hex\");\n const timestamp = new Date().toISOString();\n\n this.db\n .prepare(\n `INSERT INTO kyro_audit_logs (\n id, timestamp, action, user_id, user_email, role, resource, resource_id,\n ip_address, user_agent, success, error, metadata, created_at\n ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,\n )\n .run(\n id,\n timestamp,\n data.action,\n data.userId || null,\n data.userEmail || null,\n data.role || null,\n data.resource,\n data.resourceId || null,\n data.ipAddress || null,\n data.userAgent || null,\n data.success ? 1 : 0,\n data.error || null,\n data.metadata ? JSON.stringify(data.metadata) : null,\n new Date().toISOString(),\n );\n\n return id;\n }\n\n async queryAuditLogs(\n options: {\n action?: string;\n userId?: string;\n resource?: string;\n success?: boolean;\n startDate?: Date;\n endDate?: Date;\n limit?: number;\n offset?: number;\n } = {},\n ): Promise<{\n logs: Array<{\n id: string;\n timestamp: Date;\n action: string;\n userId?: string;\n userEmail?: string;\n resource: string;\n resourceId?: string;\n ipAddress?: string;\n userAgent?: string;\n success: boolean;\n error?: string;\n metadata?: Record<string, unknown>;\n }>;\n total: number;\n }> {\n if (!this.db) throw new Error(\"Not connected\");\n\n const conditions: string[] = [];\n const params: unknown[] = [];\n\n if (options.action) {\n conditions.push(\"action = ?\");\n params.push(options.action);\n }\n if (options.userId) {\n conditions.push(\"user_id = ?\");\n params.push(options.userId);\n }\n if (options.resource) {\n conditions.push(\"resource = ?\");\n params.push(options.resource);\n }\n if (options.success !== undefined) {\n conditions.push(\"success = ?\");\n params.push(options.success ? 1 : 0);\n }\n if (options.startDate) {\n conditions.push(\"timestamp >= ?\");\n params.push(options.startDate.toISOString());\n }\n if (options.endDate) {\n conditions.push(\"timestamp <= ?\");\n params.push(options.endDate.toISOString());\n }\n\n const where =\n conditions.length > 0 ? \"WHERE \" + conditions.join(\" AND \") : \"\";\n const limit = options.limit || 50;\n const offset = options.offset || 0;\n\n const totalResult = this.db\n .prepare(`SELECT COUNT(*) as count FROM kyro_audit_logs ${where}`)\n .get(...params) as { count: number };\n\n const rows = this.db\n .prepare(\n `SELECT * FROM kyro_audit_logs ${where} ORDER BY timestamp DESC LIMIT ? OFFSET ?`,\n )\n .all(...params, limit, offset) as Array<Record<string, unknown>>;\n\n return {\n total: totalResult.count,\n logs: rows.map((row) => ({\n id: row.id as string,\n timestamp: new Date(row.timestamp as string),\n action: row.action as string,\n userId: (row.user_id as string) || undefined,\n userEmail: (row.user_email as string) || undefined,\n resource: row.resource as string,\n resourceId: (row.resource_id as string) || undefined,\n ipAddress: (row.ip_address as string) || undefined,\n userAgent: (row.user_agent as string) || undefined,\n success: (row.success as number) === 1,\n error: (row.error as string) || undefined,\n metadata: row.metadata ? JSON.parse(row.metadata as string) : undefined,\n })),\n };\n }\n\n private rowToUser(row: Record<string, unknown>): AuthUser {\n return {\n id: row.id as string,\n email: row.email as string,\n passwordHash: row.password_hash as string,\n role: row.role as UserRole,\n tenantId: row.tenant_id as string | undefined,\n emailVerified: (row.email_verified as number) === 1,\n locked: (row.locked as number) === 1,\n lastLogin: row.last_login as string | undefined,\n failedLoginAttempts: (row.failed_login_attempts as number) || 0,\n createdAt: row.created_at as string,\n updatedAt: row.updated_at as string,\n };\n }\n\n private rowToSession(row: Record<string, unknown>): Session {\n return {\n id: row.id as string,\n userId: row.user_id as string,\n token: row.token as string,\n refreshToken: row.refresh_token as string | undefined,\n expiresAt: row.expires_at as string,\n createdAt: row.created_at as string,\n ipAddress: row.ip_address as string | undefined,\n userAgent: row.user_agent as string | undefined,\n };\n }\n\n async findAuditLogs(\n filter: AuditLogFilter,\n ): Promise<{ logs: AuditLog[]; total: number }> {\n const result = await this.queryAuditLogs({\n action: filter.action as string | undefined,\n userId: filter.userId,\n resource: filter.resource,\n success: filter.success,\n startDate: filter.startDate,\n endDate: filter.endDate,\n limit: filter.limit,\n offset: filter.offset,\n });\n return {\n logs: result.logs.map((log) => ({\n ...log,\n action: log.action as AuditLog[\"action\"],\n })),\n total: result.total,\n };\n }\n\n async createAuditLog(\n data: Omit<AuditLog, \"id\" | \"timestamp\">,\n ): Promise<AuditLog> {\n const id = await this.logAudit({\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 ipAddress: data.ipAddress,\n userAgent: data.userAgent,\n success: data.success,\n error: data.error,\n metadata: data.metadata,\n });\n const row = this.db\n ?.prepare(\"SELECT * FROM kyro_audit_logs WHERE id = ?\")\n .get(id) as Record<string, unknown> | undefined;\n return {\n ...data,\n id,\n timestamp: row ? new Date(row.timestamp as string) : new Date(),\n };\n }\n}\n","export interface PasswordPolicyConfig {\n minLength: number;\n requireUppercase: boolean;\n requireLowercase: boolean;\n requireNumbers: boolean;\n requireSpecialChars: boolean;\n preventReuse: number;\n maxLength?: number;\n}\n\nexport interface ValidationResult {\n valid: boolean;\n errors: string[];\n}\n\nexport const DEFAULT_PASSWORD_POLICY: PasswordPolicyConfig = {\n minLength: 12,\n requireUppercase: true,\n requireLowercase: true,\n requireNumbers: true,\n requireSpecialChars: true,\n preventReuse: 5,\n maxLength: 128,\n};\n\nexport class PasswordPolicy {\n private config: PasswordPolicyConfig;\n\n constructor(config: Partial<PasswordPolicyConfig> = {}) {\n this.config = { ...DEFAULT_PASSWORD_POLICY, ...config };\n }\n\n validate(password: string): ValidationResult {\n const errors: string[] = [];\n\n if (this.config.maxLength && password.length > this.config.maxLength) {\n errors.push(\n `Password must not exceed ${this.config.maxLength} characters`,\n );\n }\n\n if (password.length < this.config.minLength) {\n errors.push(\n `Password must be at least ${this.config.minLength} characters`,\n );\n }\n\n if (this.config.requireUppercase && !/[A-Z]/.test(password)) {\n errors.push(\"Password must contain at least one uppercase letter\");\n }\n\n if (this.config.requireLowercase && !/[a-z]/.test(password)) {\n errors.push(\"Password must contain at least one lowercase letter\");\n }\n\n if (this.config.requireNumbers && !/[0-9]/.test(password)) {\n errors.push(\"Password must contain at least one number\");\n }\n\n if (\n this.config.requireSpecialChars &&\n !/[!@#$%^&*()_+\\-=\\[\\]{};':\"\\\\|,.<>\\/?]/.test(password)\n ) {\n errors.push(\"Password must contain at least one special character\");\n }\n\n const commonPasswords = [\n \"password\",\n \"123456\",\n \"12345678\",\n \"qwerty\",\n \"abc123\",\n \"monkey\",\n \"1234567\",\n \"letmein\",\n \"trustno1\",\n \"dragon\",\n \"baseball\",\n \"iloveyou\",\n \"master\",\n \"sunshine\",\n \"ashley\",\n \"football\",\n \"password1\",\n \"shadow\",\n \"123123\",\n \"654321\",\n ];\n\n if (commonPasswords.includes(password.toLowerCase())) {\n errors.push(\n \"This password is too common. Please choose a more secure password\",\n );\n }\n\n if (/^[a-zA-Z]+$/.test(password) || /^[0-9]+$/.test(password)) {\n errors.push(\n \"Password must contain a mix of letters, numbers, and/or special characters\",\n );\n }\n\n if (/(.)\\1{2,}/.test(password)) {\n errors.push(\n \"Password must not contain more than 2 consecutive identical characters\",\n );\n }\n\n if (\n /^(012|123|234|345|456|567|678|789|890|098|987|876|765|654|543|432|321|210)+$/i.test(\n password,\n )\n ) {\n errors.push(\"Password must not contain sequential numbers or letters\");\n }\n\n return {\n valid: errors.length === 0,\n errors,\n };\n }\n\n async checkReuse(\n passwordHash: string,\n history: string[],\n verifyFn: (password: string, hash: string) => Promise<boolean>,\n ): Promise<ValidationResult> {\n return {\n valid: true,\n errors: [],\n };\n }\n\n async isInHistory(\n password: string,\n history: string[],\n verifyFn: (password: string, hash: string) => Promise<boolean>,\n ): Promise<boolean> {\n for (const hash of history) {\n if (await verifyFn(password, hash)) {\n return true;\n }\n }\n return false;\n }\n\n generatePassword(length: number = 16): string {\n const uppercase = \"ABCDEFGHIJKLMNOPQRSTUVWXYZ\";\n const lowercase = \"abcdefghijklmnopqrstuvwxyz\";\n const numbers = \"0123456789\";\n const special = \"!@#$%^&*()_+-=[]{}|;:,.<>?\";\n\n let password = \"\";\n\n password += uppercase[Math.floor(Math.random() * uppercase.length)];\n password += lowercase[Math.floor(Math.random() * lowercase.length)];\n password += numbers[Math.floor(Math.random() * numbers.length)];\n password += special[Math.floor(Math.random() * special.length)];\n\n const allChars = uppercase + lowercase + numbers + special;\n for (let i = password.length; i < length; i++) {\n password += allChars[Math.floor(Math.random() * allChars.length)];\n }\n\n return password\n .split(\"\")\n .sort(() => Math.random() - 0.5)\n .join(\"\");\n }\n\n getStrength(password: string): {\n score: number;\n label: string;\n feedback: string[];\n } {\n let score = 0;\n const feedback: string[] = [];\n\n if (password.length >= 8) score += 1;\n if (password.length >= 12) score += 1;\n if (password.length >= 16) score += 1;\n\n if (/[a-z]/.test(password)) score += 1;\n if (/[A-Z]/.test(password)) score += 1;\n if (/[0-9]/.test(password)) score += 1;\n if (/[!@#$%^&*()_+\\-=\\[\\]{}|;:,.<>?]/.test(password)) score += 1;\n\n if (password.length > 8) score += 1;\n if (password.length > 12) score += 1;\n\n const uniqueChars = new Set(password).size;\n if (uniqueChars > 6) score += 1;\n if (uniqueChars > 10) score += 1;\n\n let label: string;\n if (score <= 3) {\n label = \"Weak\";\n feedback.push(\"Add more characters\");\n feedback.push(\"Include uppercase and lowercase letters\");\n } else if (score <= 5) {\n label = \"Fair\";\n feedback.push(\"Add special characters\");\n feedback.push(\"Consider making it longer\");\n } else if (score <= 7) {\n label = \"Good\";\n feedback.push(\"Consider making it longer for extra security\");\n } else {\n label = \"Strong\";\n }\n\n return { score, label, feedback };\n }\n\n setConfig(config: Partial<PasswordPolicyConfig>): void {\n this.config = { ...this.config, ...config };\n }\n\n getConfig(): PasswordPolicyConfig {\n return { ...this.config };\n }\n}\n","import { SQLiteAuthAdapter } from \"./sqlite-adapter.js\";\nimport { EmailTransport, type EmailConfig } from \"./nodemailer-transport.js\";\nimport { PasswordPolicy } from \"./security/password-policy.js\";\nimport type { AuthUser, UserRole, AuthAdapter } from \"./types.js\";\n\nexport interface BootstrapConfig {\n authAdapter?: AuthAdapter;\n authDbPath?: string;\n adminEmail: string;\n adminPassword: string;\n adminRole?: string;\n tenantId?: string;\n emailConfig?: EmailConfig;\n sendWelcomeEmail?: boolean;\n}\n\nexport interface BootstrapResult {\n success: boolean;\n user?: AuthUser;\n error?: string;\n}\n\nexport async function bootstrapAdmin(\n config: BootstrapConfig,\n): Promise<BootstrapResult> {\n const {\n adminEmail,\n adminPassword,\n adminRole = \"super_admin\",\n tenantId,\n emailConfig,\n sendWelcomeEmail = false,\n } = config;\n\n const authAdapter =\n config.authAdapter ||\n new SQLiteAuthAdapter({\n path: config.authDbPath || \"./data/auth.db\",\n });\n\n try {\n await authAdapter.connect?.();\n } catch (error) {\n return {\n success: false,\n error: \"Failed to connect to auth storage\",\n };\n }\n\n const passwordPolicy = new PasswordPolicy();\n const passwordValidation = passwordPolicy.validate(adminPassword);\n if (!passwordValidation.valid) {\n await authAdapter.disconnect?.();\n return {\n success: false,\n error: `Invalid password: ${passwordValidation.errors.join(\", \")}`,\n };\n }\n\n const existingUser = await authAdapter.findUserByEmail(adminEmail);\n if (existingUser) {\n await authAdapter.disconnect?.();\n return {\n success: false,\n error: \"Admin user already exists\",\n };\n }\n\n try {\n const user = await authAdapter.createUser({\n email: adminEmail,\n password: adminPassword,\n role: (adminRole as UserRole) || \"admin\",\n tenantId,\n });\n\n if (sendWelcomeEmail && emailConfig) {\n const emailTransport = new EmailTransport(emailConfig);\n const templates = emailTransport.getTemplates();\n const welcomeTemplate = templates.welcome(adminEmail.split(\"@\")[0]);\n await emailTransport.send({\n to: adminEmail,\n ...welcomeTemplate,\n });\n }\n\n await authAdapter.disconnect?.();\n return {\n success: true,\n user,\n };\n } catch (error) {\n await authAdapter.disconnect?.();\n return {\n success: false,\n error:\n error instanceof Error ? error.message : \"Failed to create admin user\",\n };\n }\n}\n\nexport async function checkBootstrapRequired(\n authAdapter: AuthAdapter,\n adminEmail: string,\n): Promise<boolean> {\n const existingUser = await authAdapter.findUserByEmail(adminEmail);\n return !existingUser;\n}\n\nexport function getBootstrapFromEnv(): BootstrapConfig | null {\n const email = process.env.KYRO_ADMIN_EMAIL;\n const password = process.env.KYRO_ADMIN_PASSWORD;\n\n if (!email || !password) {\n return null;\n }\n\n return {\n authDbPath: process.env.KYRO_AUTH_DB_PATH || \"./data/auth.db\",\n adminEmail: email,\n adminPassword: password,\n adminRole: process.env.KYRO_ADMIN_ROLE || \"super_admin\",\n tenantId: process.env.KYRO_ADMIN_TENANT_ID,\n emailConfig: process.env.SMTP_HOST\n ? {\n provider: \"smtp\",\n smtp: {\n host: process.env.SMTP_HOST,\n port: parseInt(process.env.SMTP_PORT || \"587\", 10),\n secure: process.env.SMTP_SECURE === \"true\",\n auth: {\n user: process.env.SMTP_USER || \"\",\n pass: process.env.SMTP_PASS || \"\",\n },\n },\n from: process.env.SMTP_FROM || \"noreply@example.com\",\n fromName: process.env.SMTP_FROM_NAME,\n }\n : undefined,\n sendWelcomeEmail: process.env.KYRO_ADMIN_SEND_WELCOME === \"true\",\n };\n}\n\nexport async function autoBootstrap(): Promise<BootstrapResult | null> {\n const config = getBootstrapFromEnv();\n if (!config) {\n return null;\n }\n\n console.log(\"Auto-bootstrapping admin user...\");\n const result = await bootstrapAdmin(config);\n\n if (result.success) {\n console.log(`Admin user created: ${config.adminEmail}`);\n } else {\n console.error(`Bootstrap failed: ${result.error}`);\n }\n\n return result;\n}\n\nexport async function bootstrapWithRetry(\n config: BootstrapConfig,\n maxRetries: number = 3,\n retryDelayMs: number = 2000,\n): Promise<BootstrapResult> {\n let lastError: string = \"\";\n\n for (let i = 0; i < maxRetries; i++) {\n const result = await bootstrapAdmin(config);\n\n if (result.success) {\n return result;\n }\n\n lastError = result.error || \"Unknown error\";\n\n if (lastError.includes(\"already exists\")) {\n return result;\n }\n\n if (i < maxRetries - 1) {\n await new Promise((resolve) => setTimeout(resolve, retryDelayMs));\n }\n }\n\n return {\n success: false,\n error: `Failed after ${maxRetries} retries: ${lastError}`,\n };\n}\n"]}