@serve.zone/dcrouter 13.17.0 → 13.17.2

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 (387) hide show
  1. package/dist_serve/bundle.js +1 -1
  2. package/dist_ts/00_commitinfo_data.d.ts +8 -0
  3. package/dist_ts/00_commitinfo_data.js +9 -0
  4. package/dist_ts/acme/index.d.ts +1 -0
  5. package/dist_ts/acme/index.js +2 -0
  6. package/dist_ts/acme/manager.acme-config.d.ts +48 -0
  7. package/dist_ts/acme/manager.acme-config.js +156 -0
  8. package/dist_ts/classes.cert-provision-scheduler.d.ts +52 -0
  9. package/dist_ts/classes.cert-provision-scheduler.js +138 -0
  10. package/dist_ts/classes.dcrouter.d.ts +401 -0
  11. package/dist_ts/classes.dcrouter.js +1852 -0
  12. package/dist_ts/classes.storage-cert-manager.d.ts +15 -0
  13. package/dist_ts/classes.storage-cert-manager.js +53 -0
  14. package/dist_ts/config/classes.api-token-manager.d.ts +44 -0
  15. package/dist_ts/config/classes.api-token-manager.js +180 -0
  16. package/dist_ts/config/classes.db-seeder.d.ts +25 -0
  17. package/dist_ts/config/classes.db-seeder.js +69 -0
  18. package/dist_ts/config/classes.reference-resolver.d.ts +80 -0
  19. package/dist_ts/config/classes.reference-resolver.js +483 -0
  20. package/dist_ts/config/classes.route-config-manager.d.ts +54 -0
  21. package/dist_ts/config/classes.route-config-manager.js +370 -0
  22. package/dist_ts/config/classes.target-profile-manager.d.ts +82 -0
  23. package/dist_ts/config/classes.target-profile-manager.js +349 -0
  24. package/dist_ts/config/index.d.ts +6 -0
  25. package/dist_ts/config/index.js +8 -0
  26. package/dist_ts/config/validator.d.ts +104 -0
  27. package/dist_ts/config/validator.js +152 -0
  28. package/dist_ts/db/classes.cache.cleaner.d.ts +47 -0
  29. package/dist_ts/db/classes.cache.cleaner.js +130 -0
  30. package/dist_ts/db/classes.cached.document.d.ts +76 -0
  31. package/dist_ts/db/classes.cached.document.js +100 -0
  32. package/dist_ts/db/classes.dcrouter-db.d.ts +70 -0
  33. package/dist_ts/db/classes.dcrouter-db.js +146 -0
  34. package/dist_ts/db/documents/classes.accounting-session.doc.d.ts +32 -0
  35. package/dist_ts/db/documents/classes.accounting-session.doc.js +214 -0
  36. package/dist_ts/db/documents/classes.acme-cert.doc.d.ts +13 -0
  37. package/dist_ts/db/documents/classes.acme-cert.doc.js +109 -0
  38. package/dist_ts/db/documents/classes.acme-config.doc.d.ts +22 -0
  39. package/dist_ts/db/documents/classes.acme-config.doc.js +121 -0
  40. package/dist_ts/db/documents/classes.api-token.doc.d.ts +18 -0
  41. package/dist_ts/db/documents/classes.api-token.doc.js +127 -0
  42. package/dist_ts/db/documents/classes.cached.email.d.ts +125 -0
  43. package/dist_ts/db/documents/classes.cached.email.js +337 -0
  44. package/dist_ts/db/documents/classes.cached.ip.reputation.d.ts +119 -0
  45. package/dist_ts/db/documents/classes.cached.ip.reputation.js +323 -0
  46. package/dist_ts/db/documents/classes.cert-backoff.doc.d.ts +11 -0
  47. package/dist_ts/db/documents/classes.cert-backoff.doc.js +97 -0
  48. package/dist_ts/db/documents/classes.dns-provider.doc.d.ts +22 -0
  49. package/dist_ts/db/documents/classes.dns-provider.doc.js +134 -0
  50. package/dist_ts/db/documents/classes.dns-record.doc.d.ts +21 -0
  51. package/dist_ts/db/documents/classes.dns-record.doc.js +143 -0
  52. package/dist_ts/db/documents/classes.domain.doc.d.ts +22 -0
  53. package/dist_ts/db/documents/classes.domain.doc.js +146 -0
  54. package/dist_ts/db/documents/classes.email-domain.doc.d.ts +17 -0
  55. package/dist_ts/db/documents/classes.email-domain.doc.js +124 -0
  56. package/dist_ts/db/documents/classes.network-target.doc.d.ts +15 -0
  57. package/dist_ts/db/documents/classes.network-target.doc.js +118 -0
  58. package/dist_ts/db/documents/classes.proxy-cert.doc.d.ts +12 -0
  59. package/dist_ts/db/documents/classes.proxy-cert.doc.js +103 -0
  60. package/dist_ts/db/documents/classes.remote-ingress-edge.doc.d.ts +17 -0
  61. package/dist_ts/db/documents/classes.remote-ingress-edge.doc.js +130 -0
  62. package/dist_ts/db/documents/classes.route.doc.d.ts +18 -0
  63. package/dist_ts/db/documents/classes.route.doc.js +121 -0
  64. package/dist_ts/db/documents/classes.source-profile.doc.d.ts +15 -0
  65. package/dist_ts/db/documents/classes.source-profile.doc.js +115 -0
  66. package/dist_ts/db/documents/classes.target-profile.doc.d.ts +16 -0
  67. package/dist_ts/db/documents/classes.target-profile.doc.js +121 -0
  68. package/dist_ts/db/documents/classes.vlan-mappings.doc.d.ts +15 -0
  69. package/dist_ts/db/documents/classes.vlan-mappings.doc.js +77 -0
  70. package/dist_ts/db/documents/classes.vpn-client.doc.d.ts +23 -0
  71. package/dist_ts/db/documents/classes.vpn-client.doc.js +172 -0
  72. package/dist_ts/db/documents/classes.vpn-server-keys.doc.d.ts +10 -0
  73. package/dist_ts/db/documents/classes.vpn-server-keys.doc.js +94 -0
  74. package/dist_ts/db/documents/index.d.ts +20 -0
  75. package/dist_ts/db/documents/index.js +30 -0
  76. package/dist_ts/db/index.d.ts +4 -0
  77. package/dist_ts/db/index.js +9 -0
  78. package/dist_ts/dns/index.d.ts +2 -0
  79. package/dist_ts/dns/index.js +3 -0
  80. package/dist_ts/dns/manager.dns.d.ts +267 -0
  81. package/dist_ts/dns/manager.dns.js +906 -0
  82. package/dist_ts/dns/providers/cloudflare.provider.d.ts +21 -0
  83. package/dist_ts/dns/providers/cloudflare.provider.js +106 -0
  84. package/dist_ts/dns/providers/factory.d.ts +23 -0
  85. package/dist_ts/dns/providers/factory.js +47 -0
  86. package/dist_ts/dns/providers/index.d.ts +3 -0
  87. package/dist_ts/dns/providers/index.js +4 -0
  88. package/dist_ts/dns/providers/interfaces.d.ts +54 -0
  89. package/dist_ts/dns/providers/interfaces.js +2 -0
  90. package/dist_ts/email/classes.email-domain.manager.d.ts +46 -0
  91. package/dist_ts/email/classes.email-domain.manager.js +276 -0
  92. package/dist_ts/email/index.d.ts +1 -0
  93. package/dist_ts/email/index.js +2 -0
  94. package/dist_ts/errors/base.errors.d.ts +224 -0
  95. package/dist_ts/errors/base.errors.js +320 -0
  96. package/dist_ts/errors/error-handler.d.ts +98 -0
  97. package/dist_ts/errors/error-handler.js +282 -0
  98. package/dist_ts/errors/error.codes.d.ts +115 -0
  99. package/dist_ts/errors/error.codes.js +136 -0
  100. package/dist_ts/errors/index.d.ts +54 -0
  101. package/dist_ts/errors/index.js +136 -0
  102. package/dist_ts/errors/reputation.errors.d.ts +183 -0
  103. package/dist_ts/errors/reputation.errors.js +292 -0
  104. package/dist_ts/http3/http3-route-augmentation.d.ts +50 -0
  105. package/dist_ts/http3/http3-route-augmentation.js +98 -0
  106. package/dist_ts/http3/index.d.ts +1 -0
  107. package/dist_ts/http3/index.js +2 -0
  108. package/dist_ts/index.d.ts +8 -0
  109. package/dist_ts/index.js +29 -0
  110. package/dist_ts/logger.d.ts +21 -0
  111. package/dist_ts/logger.js +81 -0
  112. package/dist_ts/monitoring/classes.metricscache.d.ts +32 -0
  113. package/dist_ts/monitoring/classes.metricscache.js +63 -0
  114. package/dist_ts/monitoring/classes.metricsmanager.d.ts +235 -0
  115. package/dist_ts/monitoring/classes.metricsmanager.js +875 -0
  116. package/dist_ts/monitoring/index.d.ts +1 -0
  117. package/dist_ts/monitoring/index.js +2 -0
  118. package/dist_ts/opsserver/classes.opsserver.d.ts +47 -0
  119. package/dist_ts/opsserver/classes.opsserver.js +105 -0
  120. package/dist_ts/opsserver/handlers/acme-config.handler.d.ts +16 -0
  121. package/dist_ts/opsserver/handlers/acme-config.handler.js +77 -0
  122. package/dist_ts/opsserver/handlers/admin.handler.d.ts +40 -0
  123. package/dist_ts/opsserver/handlers/admin.handler.js +191 -0
  124. package/dist_ts/opsserver/handlers/api-token.handler.d.ts +6 -0
  125. package/dist_ts/opsserver/handlers/api-token.handler.js +62 -0
  126. package/dist_ts/opsserver/handlers/certificate.handler.d.ts +77 -0
  127. package/dist_ts/opsserver/handlers/certificate.handler.js +574 -0
  128. package/dist_ts/opsserver/handlers/config.handler.d.ts +7 -0
  129. package/dist_ts/opsserver/handlers/config.handler.js +200 -0
  130. package/dist_ts/opsserver/handlers/dns-provider.handler.d.ts +16 -0
  131. package/dist_ts/opsserver/handlers/dns-provider.handler.js +156 -0
  132. package/dist_ts/opsserver/handlers/dns-record.handler.d.ts +13 -0
  133. package/dist_ts/opsserver/handlers/dns-record.handler.js +98 -0
  134. package/dist_ts/opsserver/handlers/domain.handler.d.ts +13 -0
  135. package/dist_ts/opsserver/handlers/domain.handler.js +137 -0
  136. package/dist_ts/opsserver/handlers/email-domain.handler.d.ts +16 -0
  137. package/dist_ts/opsserver/handlers/email-domain.handler.js +150 -0
  138. package/dist_ts/opsserver/handlers/email-ops.handler.d.ts +30 -0
  139. package/dist_ts/opsserver/handlers/email-ops.handler.js +227 -0
  140. package/dist_ts/opsserver/handlers/index.d.ts +21 -0
  141. package/dist_ts/opsserver/handlers/index.js +22 -0
  142. package/dist_ts/opsserver/handlers/logs.handler.d.ts +25 -0
  143. package/dist_ts/opsserver/handlers/logs.handler.js +264 -0
  144. package/dist_ts/opsserver/handlers/network-target.handler.d.ts +10 -0
  145. package/dist_ts/opsserver/handlers/network-target.handler.js +117 -0
  146. package/dist_ts/opsserver/handlers/radius.handler.d.ts +6 -0
  147. package/dist_ts/opsserver/handlers/radius.handler.js +295 -0
  148. package/dist_ts/opsserver/handlers/remoteingress.handler.d.ts +6 -0
  149. package/dist_ts/opsserver/handlers/remoteingress.handler.js +156 -0
  150. package/dist_ts/opsserver/handlers/route-management.handler.d.ts +14 -0
  151. package/dist_ts/opsserver/handlers/route-management.handler.js +98 -0
  152. package/dist_ts/opsserver/handlers/security.handler.d.ts +9 -0
  153. package/dist_ts/opsserver/handlers/security.handler.js +237 -0
  154. package/dist_ts/opsserver/handlers/source-profile.handler.d.ts +10 -0
  155. package/dist_ts/opsserver/handlers/source-profile.handler.js +119 -0
  156. package/dist_ts/opsserver/handlers/stats.handler.d.ts +11 -0
  157. package/dist_ts/opsserver/handlers/stats.handler.js +461 -0
  158. package/dist_ts/opsserver/handlers/target-profile.handler.d.ts +10 -0
  159. package/dist_ts/opsserver/handlers/target-profile.handler.js +117 -0
  160. package/dist_ts/opsserver/handlers/users.handler.d.ts +12 -0
  161. package/dist_ts/opsserver/handlers/users.handler.js +24 -0
  162. package/dist_ts/opsserver/handlers/vpn.handler.d.ts +6 -0
  163. package/dist_ts/opsserver/handlers/vpn.handler.js +262 -0
  164. package/dist_ts/opsserver/helpers/guards.d.ts +27 -0
  165. package/dist_ts/opsserver/helpers/guards.js +43 -0
  166. package/dist_ts/opsserver/index.d.ts +1 -0
  167. package/dist_ts/opsserver/index.js +2 -0
  168. package/dist_ts/paths.d.ts +25 -0
  169. package/dist_ts/paths.js +44 -0
  170. package/dist_ts/plugins.d.ts +81 -0
  171. package/dist_ts/plugins.js +115 -0
  172. package/dist_ts/radius/classes.accounting.manager.d.ts +223 -0
  173. package/dist_ts/radius/classes.accounting.manager.js +449 -0
  174. package/dist_ts/radius/classes.radius.server.d.ts +169 -0
  175. package/dist_ts/radius/classes.radius.server.js +384 -0
  176. package/dist_ts/radius/classes.vlan.manager.d.ts +124 -0
  177. package/dist_ts/radius/classes.vlan.manager.js +272 -0
  178. package/dist_ts/radius/index.d.ts +13 -0
  179. package/dist_ts/radius/index.js +14 -0
  180. package/dist_ts/remoteingress/classes.remoteingress-manager.d.ts +92 -0
  181. package/dist_ts/remoteingress/classes.remoteingress-manager.js +291 -0
  182. package/dist_ts/remoteingress/classes.tunnel-manager.d.ts +59 -0
  183. package/dist_ts/remoteingress/classes.tunnel-manager.js +165 -0
  184. package/dist_ts/remoteingress/index.d.ts +2 -0
  185. package/dist_ts/remoteingress/index.js +3 -0
  186. package/dist_ts/security/classes.contentscanner.d.ts +164 -0
  187. package/dist_ts/security/classes.contentscanner.js +642 -0
  188. package/dist_ts/security/classes.ipreputationchecker.d.ts +145 -0
  189. package/dist_ts/security/classes.ipreputationchecker.js +458 -0
  190. package/dist_ts/security/classes.securitylogger.d.ts +144 -0
  191. package/dist_ts/security/classes.securitylogger.js +235 -0
  192. package/dist_ts/security/index.d.ts +3 -0
  193. package/dist_ts/security/index.js +4 -0
  194. package/dist_ts/sms/classes.smsservice.d.ts +15 -0
  195. package/dist_ts/sms/classes.smsservice.js +72 -0
  196. package/dist_ts/sms/config/sms.config.d.ts +93 -0
  197. package/dist_ts/sms/config/sms.config.js +2 -0
  198. package/dist_ts/sms/config/sms.schema.d.ts +5 -0
  199. package/dist_ts/sms/config/sms.schema.js +121 -0
  200. package/dist_ts/sms/index.d.ts +1 -0
  201. package/dist_ts/sms/index.js +2 -0
  202. package/dist_ts/vpn/classes.vpn-manager.d.ts +159 -0
  203. package/dist_ts/vpn/classes.vpn-manager.js +459 -0
  204. package/dist_ts/vpn/index.d.ts +1 -0
  205. package/dist_ts/vpn/index.js +2 -0
  206. package/dist_ts_apiclient/classes.apitoken.d.ts +41 -0
  207. package/dist_ts_apiclient/classes.apitoken.js +115 -0
  208. package/dist_ts_apiclient/classes.certificate.d.ts +57 -0
  209. package/dist_ts_apiclient/classes.certificate.js +69 -0
  210. package/dist_ts_apiclient/classes.config.d.ts +7 -0
  211. package/dist_ts_apiclient/classes.config.js +11 -0
  212. package/dist_ts_apiclient/classes.dcrouterapiclient.d.ts +41 -0
  213. package/dist_ts_apiclient/classes.dcrouterapiclient.js +81 -0
  214. package/dist_ts_apiclient/classes.email.d.ts +30 -0
  215. package/dist_ts_apiclient/classes.email.js +52 -0
  216. package/dist_ts_apiclient/classes.logs.d.ts +21 -0
  217. package/dist_ts_apiclient/classes.logs.js +14 -0
  218. package/dist_ts_apiclient/classes.radius.d.ts +59 -0
  219. package/dist_ts_apiclient/classes.radius.js +95 -0
  220. package/dist_ts_apiclient/classes.remoteingress.d.ts +54 -0
  221. package/dist_ts_apiclient/classes.remoteingress.js +136 -0
  222. package/dist_ts_apiclient/classes.route.d.ts +39 -0
  223. package/dist_ts_apiclient/classes.route.js +125 -0
  224. package/dist_ts_apiclient/classes.stats.d.ts +47 -0
  225. package/dist_ts_apiclient/classes.stats.js +38 -0
  226. package/dist_ts_apiclient/index.d.ts +10 -0
  227. package/dist_ts_apiclient/index.js +14 -0
  228. package/dist_ts_apiclient/plugins.d.ts +3 -0
  229. package/dist_ts_apiclient/plugins.js +5 -0
  230. package/dist_ts_interfaces/data/acme-config.d.ts +25 -0
  231. package/dist_ts_interfaces/data/acme-config.js +2 -0
  232. package/dist_ts_interfaces/data/auth.d.ts +8 -0
  233. package/dist_ts_interfaces/data/auth.js +2 -0
  234. package/dist_ts_interfaces/data/dns-provider.d.ts +136 -0
  235. package/dist_ts_interfaces/data/dns-provider.js +41 -0
  236. package/dist_ts_interfaces/data/dns-record.d.ts +42 -0
  237. package/dist_ts_interfaces/data/dns-record.js +2 -0
  238. package/dist_ts_interfaces/data/domain.d.ts +35 -0
  239. package/dist_ts_interfaces/data/domain.js +2 -0
  240. package/dist_ts_interfaces/data/email-domain.d.ts +70 -0
  241. package/dist_ts_interfaces/data/email-domain.js +2 -0
  242. package/dist_ts_interfaces/data/index.d.ts +11 -0
  243. package/dist_ts_interfaces/data/index.js +12 -0
  244. package/dist_ts_interfaces/data/remoteingress.d.ts +60 -0
  245. package/dist_ts_interfaces/data/remoteingress.js +2 -0
  246. package/dist_ts_interfaces/data/route-management.d.ts +110 -0
  247. package/dist_ts_interfaces/data/route-management.js +2 -0
  248. package/dist_ts_interfaces/data/stats.d.ts +239 -0
  249. package/dist_ts_interfaces/data/stats.js +2 -0
  250. package/dist_ts_interfaces/data/target-profile.d.ts +28 -0
  251. package/dist_ts_interfaces/data/target-profile.js +2 -0
  252. package/dist_ts_interfaces/data/vpn.d.ts +61 -0
  253. package/dist_ts_interfaces/data/vpn.js +2 -0
  254. package/dist_ts_interfaces/index.d.ts +5 -0
  255. package/dist_ts_interfaces/index.js +8 -0
  256. package/dist_ts_interfaces/plugins.d.ts +2 -0
  257. package/dist_ts_interfaces/plugins.js +4 -0
  258. package/dist_ts_interfaces/requests/acme-config.d.ts +42 -0
  259. package/dist_ts_interfaces/requests/acme-config.js +2 -0
  260. package/dist_ts_interfaces/requests/admin.d.ts +31 -0
  261. package/dist_ts_interfaces/requests/admin.js +3 -0
  262. package/dist_ts_interfaces/requests/api-tokens.d.ts +79 -0
  263. package/dist_ts_interfaces/requests/api-tokens.js +2 -0
  264. package/dist_ts_interfaces/requests/certificate.d.ts +111 -0
  265. package/dist_ts_interfaces/requests/certificate.js +3 -0
  266. package/dist_ts_interfaces/requests/combined.stats.d.ts +28 -0
  267. package/dist_ts_interfaces/requests/combined.stats.js +2 -0
  268. package/dist_ts_interfaces/requests/config.d.ts +90 -0
  269. package/dist_ts_interfaces/requests/config.js +3 -0
  270. package/dist_ts_interfaces/requests/dns-providers.d.ts +117 -0
  271. package/dist_ts_interfaces/requests/dns-providers.js +2 -0
  272. package/dist_ts_interfaces/requests/dns-records.d.ts +89 -0
  273. package/dist_ts_interfaces/requests/dns-records.js +2 -0
  274. package/dist_ts_interfaces/requests/domains.d.ts +142 -0
  275. package/dist_ts_interfaces/requests/domains.js +2 -0
  276. package/dist_ts_interfaces/requests/email-domains.d.ts +142 -0
  277. package/dist_ts_interfaces/requests/email-domains.js +2 -0
  278. package/dist_ts_interfaces/requests/email-ops.d.ts +82 -0
  279. package/dist_ts_interfaces/requests/email-ops.js +3 -0
  280. package/dist_ts_interfaces/requests/index.d.ts +21 -0
  281. package/dist_ts_interfaces/requests/index.js +22 -0
  282. package/dist_ts_interfaces/requests/logs.d.ts +41 -0
  283. package/dist_ts_interfaces/requests/logs.js +4 -0
  284. package/dist_ts_interfaces/requests/network-targets.d.ts +102 -0
  285. package/dist_ts_interfaces/requests/network-targets.js +2 -0
  286. package/dist_ts_interfaces/requests/radius.d.ts +268 -0
  287. package/dist_ts_interfaces/requests/radius.js +3 -0
  288. package/dist_ts_interfaces/requests/remoteingress.d.ts +108 -0
  289. package/dist_ts_interfaces/requests/remoteingress.js +3 -0
  290. package/dist_ts_interfaces/requests/route-management.d.ts +85 -0
  291. package/dist_ts_interfaces/requests/route-management.js +2 -0
  292. package/dist_ts_interfaces/requests/source-profiles.d.ts +102 -0
  293. package/dist_ts_interfaces/requests/source-profiles.js +2 -0
  294. package/dist_ts_interfaces/requests/stats.d.ts +177 -0
  295. package/dist_ts_interfaces/requests/stats.js +4 -0
  296. package/dist_ts_interfaces/requests/target-profiles.d.ts +103 -0
  297. package/dist_ts_interfaces/requests/target-profiles.js +2 -0
  298. package/dist_ts_interfaces/requests/users.d.ts +19 -0
  299. package/dist_ts_interfaces/requests/users.js +3 -0
  300. package/dist_ts_interfaces/requests/vpn.d.ts +177 -0
  301. package/dist_ts_interfaces/requests/vpn.js +3 -0
  302. package/dist_ts_migrations/index.d.ts +28 -0
  303. package/dist_ts_migrations/index.js +82 -0
  304. package/dist_ts_oci_container/index.d.ts +8 -0
  305. package/dist_ts_oci_container/index.js +110 -0
  306. package/dist_ts_oci_container/plugins.d.ts +3 -0
  307. package/dist_ts_oci_container/plugins.js +4 -0
  308. package/dist_ts_web/00_commitinfo_data.d.ts +8 -0
  309. package/dist_ts_web/00_commitinfo_data.js +9 -0
  310. package/dist_ts_web/appstate.d.ts +478 -0
  311. package/dist_ts_web/appstate.js +1968 -0
  312. package/dist_ts_web/elements/access/index.d.ts +2 -0
  313. package/dist_ts_web/elements/access/index.js +3 -0
  314. package/dist_ts_web/elements/access/ops-view-apitokens.d.ts +13 -0
  315. package/dist_ts_web/elements/access/ops-view-apitokens.js +372 -0
  316. package/dist_ts_web/elements/access/ops-view-users.d.ts +11 -0
  317. package/dist_ts_web/elements/access/ops-view-users.js +190 -0
  318. package/dist_ts_web/elements/domains/dns-provider-form.d.ts +60 -0
  319. package/dist_ts_web/elements/domains/dns-provider-form.js +259 -0
  320. package/dist_ts_web/elements/domains/index.d.ts +5 -0
  321. package/dist_ts_web/elements/domains/index.js +6 -0
  322. package/dist_ts_web/elements/domains/ops-view-certificates.d.ts +25 -0
  323. package/dist_ts_web/elements/domains/ops-view-certificates.js +669 -0
  324. package/dist_ts_web/elements/domains/ops-view-dns.d.ts +17 -0
  325. package/dist_ts_web/elements/domains/ops-view-dns.js +305 -0
  326. package/dist_ts_web/elements/domains/ops-view-domains.d.ts +19 -0
  327. package/dist_ts_web/elements/domains/ops-view-domains.js +456 -0
  328. package/dist_ts_web/elements/domains/ops-view-providers.d.ts +21 -0
  329. package/dist_ts_web/elements/domains/ops-view-providers.js +330 -0
  330. package/dist_ts_web/elements/email/index.d.ts +3 -0
  331. package/dist_ts_web/elements/email/index.js +4 -0
  332. package/dist_ts_web/elements/email/ops-view-email-domains.d.ts +19 -0
  333. package/dist_ts_web/elements/email/ops-view-email-domains.js +410 -0
  334. package/dist_ts_web/elements/email/ops-view-email-security.d.ts +14 -0
  335. package/dist_ts_web/elements/email/ops-view-email-security.js +178 -0
  336. package/dist_ts_web/elements/email/ops-view-emails.d.ts +21 -0
  337. package/dist_ts_web/elements/email/ops-view-emails.js +165 -0
  338. package/dist_ts_web/elements/index.d.ts +9 -0
  339. package/dist_ts_web/elements/index.js +10 -0
  340. package/dist_ts_web/elements/network/index.d.ts +7 -0
  341. package/dist_ts_web/elements/network/index.js +8 -0
  342. package/dist_ts_web/elements/network/ops-view-network-activity.d.ts +60 -0
  343. package/dist_ts_web/elements/network/ops-view-network-activity.js +754 -0
  344. package/dist_ts_web/elements/network/ops-view-networktargets.d.ts +17 -0
  345. package/dist_ts_web/elements/network/ops-view-networktargets.js +255 -0
  346. package/dist_ts_web/elements/network/ops-view-remoteingress.d.ts +20 -0
  347. package/dist_ts_web/elements/network/ops-view-remoteingress.js +497 -0
  348. package/dist_ts_web/elements/network/ops-view-routes.d.ts +17 -0
  349. package/dist_ts_web/elements/network/ops-view-routes.js +693 -0
  350. package/dist_ts_web/elements/network/ops-view-sourceprofiles.d.ts +17 -0
  351. package/dist_ts_web/elements/network/ops-view-sourceprofiles.js +278 -0
  352. package/dist_ts_web/elements/network/ops-view-targetprofiles.d.ts +21 -0
  353. package/dist_ts_web/elements/network/ops-view-targetprofiles.js +420 -0
  354. package/dist_ts_web/elements/network/ops-view-vpn.d.ts +31 -0
  355. package/dist_ts_web/elements/network/ops-view-vpn.js +873 -0
  356. package/dist_ts_web/elements/ops-dashboard.d.ts +31 -0
  357. package/dist_ts_web/elements/ops-dashboard.js +405 -0
  358. package/dist_ts_web/elements/ops-view-logs.d.ts +13 -0
  359. package/dist_ts_web/elements/ops-view-logs.js +159 -0
  360. package/dist_ts_web/elements/overview/index.d.ts +2 -0
  361. package/dist_ts_web/elements/overview/index.js +3 -0
  362. package/dist_ts_web/elements/overview/ops-view-config.d.ts +19 -0
  363. package/dist_ts_web/elements/overview/ops-view-config.js +339 -0
  364. package/dist_ts_web/elements/overview/ops-view-overview.d.ts +24 -0
  365. package/dist_ts_web/elements/overview/ops-view-overview.js +545 -0
  366. package/dist_ts_web/elements/security/index.d.ts +3 -0
  367. package/dist_ts_web/elements/security/index.js +4 -0
  368. package/dist_ts_web/elements/security/ops-view-security-authentication.d.ts +13 -0
  369. package/dist_ts_web/elements/security/ops-view-security-authentication.js +157 -0
  370. package/dist_ts_web/elements/security/ops-view-security-blocked.d.ts +15 -0
  371. package/dist_ts_web/elements/security/ops-view-security-blocked.js +153 -0
  372. package/dist_ts_web/elements/security/ops-view-security-overview.d.ts +16 -0
  373. package/dist_ts_web/elements/security/ops-view-security-overview.js +205 -0
  374. package/dist_ts_web/elements/shared/css.d.ts +1 -0
  375. package/dist_ts_web/elements/shared/css.js +10 -0
  376. package/dist_ts_web/elements/shared/index.d.ts +1 -0
  377. package/dist_ts_web/elements/shared/index.js +2 -0
  378. package/dist_ts_web/index.d.ts +1 -0
  379. package/dist_ts_web/index.js +10 -0
  380. package/dist_ts_web/plugins.d.ts +7 -0
  381. package/dist_ts_web/plugins.js +13 -0
  382. package/dist_ts_web/router.d.ts +21 -0
  383. package/dist_ts_web/router.js +151 -0
  384. package/package.json +1 -1
  385. package/ts/00_commitinfo_data.ts +1 -1
  386. package/ts/monitoring/classes.metricsmanager.ts +0 -25
  387. package/ts_web/00_commitinfo_data.ts +1 -1
@@ -0,0 +1,1852 @@
1
+ import * as plugins from './plugins.js';
2
+ import * as paths from './paths.js';
3
+ // Certificate types are available via plugins.tsclass
4
+ // Import the email server and its configuration from smartmta
5
+ import { UnifiedEmailServer, } from '@push.rocks/smartmta';
6
+ import { logger } from './logger.js';
7
+ import { StorageBackedCertManager } from './classes.storage-cert-manager.js';
8
+ import { CertProvisionScheduler } from './classes.cert-provision-scheduler.js';
9
+ // Import unified database
10
+ import { DcRouterDb, CacheCleaner, ProxyCertDoc, AcmeCertDoc } from './db/index.js';
11
+ // Import migration runner and app version
12
+ import { createMigrationRunner } from '../dist_ts_migrations/index.js';
13
+ import { commitinfo } from './00_commitinfo_data.js';
14
+ import { OpsServer } from './opsserver/index.js';
15
+ import { MetricsManager } from './monitoring/index.js';
16
+ import { RadiusServer } from './radius/index.js';
17
+ import { RemoteIngressManager, TunnelManager } from './remoteingress/index.js';
18
+ import { VpnManager } from './vpn/index.js';
19
+ import { RouteConfigManager, ApiTokenManager, ReferenceResolver, DbSeeder, TargetProfileManager } from './config/index.js';
20
+ import { SecurityLogger, ContentScanner, IPReputationChecker } from './security/index.js';
21
+ import { augmentRoutesWithHttp3 } from './http3/index.js';
22
+ import { DnsManager } from './dns/manager.dns.js';
23
+ import { AcmeConfigManager } from './acme/manager.acme-config.js';
24
+ import { EmailDomainManager } from './email/classes.email-domain.manager.js';
25
+ export class DcRouter {
26
+ options;
27
+ resolvedPaths;
28
+ // Core services
29
+ smartProxy;
30
+ smartAcme;
31
+ dnsServer;
32
+ emailServer;
33
+ radiusServer;
34
+ opsServer;
35
+ metricsManager;
36
+ // Compatibility shim for smartmta's DkimManager which calls dcRouter.storageManager.set()
37
+ storageManager = {
38
+ get: async (_key) => null,
39
+ set: async (_key, _value) => {
40
+ // DKIM keys from smartmta — logged but not yet migrated to smartdata
41
+ logger.log('debug', `storageManager.set() called (compat shim) for key: ${_key}`);
42
+ },
43
+ };
44
+ // Unified database (smartdata + LocalSmartDb or external MongoDB)
45
+ dcRouterDb;
46
+ cacheCleaner;
47
+ // Remote Ingress
48
+ remoteIngressManager;
49
+ tunnelManager;
50
+ // VPN
51
+ vpnManager;
52
+ // Programmatic config API
53
+ routeConfigManager;
54
+ apiTokenManager;
55
+ referenceResolver;
56
+ targetProfileManager;
57
+ // Domain / DNS management (DB-backed providers, domains, records)
58
+ dnsManager;
59
+ // ACME configuration (DB-backed singleton, replaces tls.contactEmail)
60
+ acmeConfigManager;
61
+ emailDomainManager;
62
+ // Auto-discovered public IP (populated by generateAuthoritativeRecords)
63
+ detectedPublicIp = null;
64
+ // DNS query logging rate limiter state
65
+ dnsLogWindowSecond = 0; // epoch second of current window
66
+ dnsLogWindowCount = 0; // queries logged this second
67
+ dnsBatchCount = 0;
68
+ dnsBatchTimer = null;
69
+ // Certificate status tracking from SmartProxy events (keyed by domain)
70
+ certificateStatusMap = new Map();
71
+ // Certificate provisioning scheduler with per-domain backoff
72
+ certProvisionScheduler;
73
+ // Service lifecycle management
74
+ serviceManager;
75
+ serviceSubjectSubscription;
76
+ smartAcmeReady = false;
77
+ // TypedRouter for API endpoints
78
+ typedrouter = new plugins.typedrequest.TypedRouter();
79
+ // Seed routes assembled during setupSmartProxy, passed to RouteConfigManager for DB seeding
80
+ seedConfigRoutes = [];
81
+ seedEmailRoutes = [];
82
+ seedDnsRoutes = [];
83
+ // Environment access
84
+ qenv = new plugins.qenv.Qenv('./', '.nogit/');
85
+ constructor(optionsArg) {
86
+ // Set defaults in options
87
+ this.options = {
88
+ ...optionsArg
89
+ };
90
+ // Resolve all data paths from baseDir
91
+ this.resolvedPaths = paths.resolvePaths(this.options.baseDir);
92
+ // Initialize service manager and register all services
93
+ this.serviceManager = new plugins.taskbuffer.ServiceManager({
94
+ name: 'dcrouter',
95
+ startupTimeoutMs: 120_000,
96
+ shutdownTimeoutMs: 30_000,
97
+ });
98
+ this.registerServices();
99
+ }
100
+ /**
101
+ * Register all dcrouter services with the ServiceManager.
102
+ * Services are started in dependency order, with failure isolation for optional services.
103
+ */
104
+ registerServices() {
105
+ // OpsServer: critical, no dependencies — provides visibility
106
+ this.serviceManager.addService(new plugins.taskbuffer.Service('OpsServer')
107
+ .critical()
108
+ .withStart(async () => {
109
+ this.opsServer = new OpsServer(this);
110
+ await this.opsServer.start();
111
+ })
112
+ .withStop(async () => {
113
+ await this.opsServer?.stop();
114
+ })
115
+ .withRetry({ maxRetries: 0 }));
116
+ // DcRouterDb: optional, no dependencies — unified database for all persistence
117
+ if (this.options.dbConfig?.enabled !== false) {
118
+ this.serviceManager.addService(new plugins.taskbuffer.Service('DcRouterDb')
119
+ .optional()
120
+ .withStart(async () => {
121
+ await this.setupDcRouterDb();
122
+ })
123
+ .withStop(async () => {
124
+ if (this.cacheCleaner) {
125
+ this.cacheCleaner.stop();
126
+ this.cacheCleaner = undefined;
127
+ }
128
+ if (this.dcRouterDb) {
129
+ await this.dcRouterDb.stop();
130
+ DcRouterDb.resetInstance();
131
+ this.dcRouterDb = undefined;
132
+ }
133
+ })
134
+ .withRetry({ maxRetries: 2, baseDelayMs: 1000, maxDelayMs: 5000 }));
135
+ }
136
+ // MetricsManager: optional, depends on OpsServer
137
+ this.serviceManager.addService(new plugins.taskbuffer.Service('MetricsManager')
138
+ .optional()
139
+ .dependsOn('OpsServer')
140
+ .withStart(async () => {
141
+ this.metricsManager = new MetricsManager(this);
142
+ await this.metricsManager.start();
143
+ })
144
+ .withStop(async () => {
145
+ if (this.metricsManager) {
146
+ await this.metricsManager.stop();
147
+ this.metricsManager = undefined;
148
+ }
149
+ })
150
+ .withRetry({ maxRetries: 1, baseDelayMs: 1000 }));
151
+ // DnsManager: optional, depends on DcRouterDb — owns DB-backed DNS state
152
+ // (providers, domains, records). Must run before SmartProxy so ACME DNS-01
153
+ // wiring can look up providers.
154
+ if (this.options.dbConfig?.enabled !== false) {
155
+ this.serviceManager.addService(new plugins.taskbuffer.Service('DnsManager')
156
+ .optional()
157
+ .dependsOn('DcRouterDb')
158
+ .withStart(async () => {
159
+ this.dnsManager = new DnsManager(this.options);
160
+ await this.dnsManager.start();
161
+ })
162
+ .withStop(async () => {
163
+ if (this.dnsManager) {
164
+ await this.dnsManager.stop();
165
+ this.dnsManager = undefined;
166
+ }
167
+ })
168
+ .withRetry({ maxRetries: 1, baseDelayMs: 500 }));
169
+ }
170
+ // AcmeConfigManager: optional, depends on DcRouterDb — owns the singleton
171
+ // ACME configuration (accountEmail, useProduction, etc.). Must run before
172
+ // SmartProxy so setupSmartProxy() can read the ACME config from the DB.
173
+ // On first boot, seeds from legacy `tls.contactEmail` / `smartProxyConfig.acme`.
174
+ if (this.options.dbConfig?.enabled !== false) {
175
+ this.serviceManager.addService(new plugins.taskbuffer.Service('AcmeConfigManager')
176
+ .optional()
177
+ .dependsOn('DcRouterDb')
178
+ .withStart(async () => {
179
+ this.acmeConfigManager = new AcmeConfigManager(this.options);
180
+ await this.acmeConfigManager.start();
181
+ })
182
+ .withStop(async () => {
183
+ if (this.acmeConfigManager) {
184
+ await this.acmeConfigManager.stop();
185
+ this.acmeConfigManager = undefined;
186
+ }
187
+ })
188
+ .withRetry({ maxRetries: 1, baseDelayMs: 500 }));
189
+ }
190
+ // Email Domain Manager: optional, depends on DcRouterDb
191
+ if (this.options.dbConfig?.enabled !== false) {
192
+ this.serviceManager.addService(new plugins.taskbuffer.Service('EmailDomainManager')
193
+ .optional()
194
+ .dependsOn('DcRouterDb')
195
+ .withStart(async () => {
196
+ this.emailDomainManager = new EmailDomainManager(this);
197
+ })
198
+ .withStop(async () => {
199
+ this.emailDomainManager = undefined;
200
+ }));
201
+ }
202
+ // SmartProxy: critical, depends on DcRouterDb + DnsManager + AcmeConfigManager (if enabled)
203
+ const smartProxyDeps = [];
204
+ if (this.options.dbConfig?.enabled !== false) {
205
+ smartProxyDeps.push('DcRouterDb');
206
+ smartProxyDeps.push('DnsManager');
207
+ smartProxyDeps.push('AcmeConfigManager');
208
+ }
209
+ this.serviceManager.addService(new plugins.taskbuffer.Service('SmartProxy')
210
+ .critical()
211
+ .dependsOn(...smartProxyDeps)
212
+ .withStart(async () => {
213
+ await this.setupSmartProxy();
214
+ })
215
+ .withStop(async () => {
216
+ if (this.smartProxy) {
217
+ this.smartProxy.removeAllListeners();
218
+ await this.smartProxy.stop();
219
+ this.smartProxy = undefined;
220
+ }
221
+ })
222
+ .withRetry({ maxRetries: 0 }));
223
+ // SmartAcme: optional, depends on SmartProxy — aggressive retry for rate limits.
224
+ // Always registered when the DB is enabled; setupSmartProxy() decides whether
225
+ // to actually instantiate SmartAcme based on whether any DnsProviderDoc exists.
226
+ // If `this.smartAcme` is unset by the time this service starts, withStart is a no-op.
227
+ if (this.options.dbConfig?.enabled !== false) {
228
+ this.serviceManager.addService(new plugins.taskbuffer.Service('SmartAcme')
229
+ .optional()
230
+ .dependsOn('SmartProxy')
231
+ .withStart(async () => {
232
+ if (this.smartAcme) {
233
+ await this.smartAcme.start();
234
+ this.smartAcmeReady = true;
235
+ logger.log('info', 'SmartAcme DNS-01 provider is now ready');
236
+ // Re-trigger certificate provisioning for all auto-cert routes.
237
+ // During startup, certProvisionFunction returned 'http01' (SmartAcme not ready),
238
+ // but Rust ACME is disabled when certProvisionFunction is set — so all domains
239
+ // failed silently (SmartProxy doesn't emit certificate-failed for this path).
240
+ // Calling updateRoutes() re-triggers provisionCertificatesViaCallback internally,
241
+ // which calls certProvisionFunction again — now with smartAcmeReady === true.
242
+ if (this.routeConfigManager) {
243
+ // Go through RouteConfigManager to get the full merged route set
244
+ // and serialize via the route-update mutex (prevents stale overwrites)
245
+ logger.log('info', 'Re-triggering certificate provisioning via RouteConfigManager');
246
+ this.routeConfigManager.applyRoutes().catch((err) => {
247
+ logger.log('warn', `Failed to re-trigger cert provisioning: ${err?.message || err}`);
248
+ });
249
+ }
250
+ else if (this.smartProxy) {
251
+ // No RouteConfigManager (DB disabled) — re-send current routes to trigger cert provisioning
252
+ if (this.certProvisionScheduler) {
253
+ this.certProvisionScheduler.clear();
254
+ }
255
+ const currentRoutes = this.smartProxy.routeManager.getRoutes();
256
+ logger.log('info', `Re-triggering certificate provisioning for ${currentRoutes.length} routes`);
257
+ this.smartProxy.updateRoutes(currentRoutes).catch((err) => {
258
+ logger.log('warn', `Failed to re-trigger cert provisioning: ${err?.message || err}`);
259
+ });
260
+ }
261
+ }
262
+ })
263
+ .withStop(async () => {
264
+ this.smartAcmeReady = false;
265
+ if (this.smartAcme) {
266
+ await this.smartAcme.stop();
267
+ this.smartAcme = undefined;
268
+ }
269
+ })
270
+ .withRetry({ maxRetries: 20, baseDelayMs: 5000, maxDelayMs: 3_600_000, backoffFactor: 2 }));
271
+ }
272
+ // ConfigManagers: optional, depends on SmartProxy + DcRouterDb
273
+ // Requires DcRouterDb to be enabled (document classes need the database)
274
+ if (this.options.dbConfig?.enabled !== false) {
275
+ this.serviceManager.addService(new plugins.taskbuffer.Service('ConfigManagers')
276
+ .optional()
277
+ .dependsOn('SmartProxy', 'DcRouterDb')
278
+ .withStart(async () => {
279
+ // Initialize reference resolver first (profiles + targets)
280
+ this.referenceResolver = new ReferenceResolver();
281
+ await this.referenceResolver.initialize();
282
+ // Initialize target profile manager
283
+ this.targetProfileManager = new TargetProfileManager();
284
+ await this.targetProfileManager.initialize();
285
+ this.routeConfigManager = new RouteConfigManager(() => this.smartProxy, () => this.options.http3, this.options.vpnConfig?.enabled
286
+ ? (route, routeId) => {
287
+ if (!this.vpnManager || !this.targetProfileManager) {
288
+ // VPN not ready yet — deny all until re-apply after VPN starts
289
+ return [];
290
+ }
291
+ return this.targetProfileManager.getMatchingClientIps(route, routeId, this.vpnManager.listClients());
292
+ }
293
+ : undefined, this.referenceResolver,
294
+ // Sync routes to RemoteIngressManager whenever routes change,
295
+ // then push updated derived ports to the Rust hub binary
296
+ (routes) => {
297
+ if (this.remoteIngressManager) {
298
+ this.remoteIngressManager.setRoutes(routes);
299
+ }
300
+ if (this.tunnelManager) {
301
+ this.tunnelManager.syncAllowedEdges();
302
+ }
303
+ });
304
+ this.apiTokenManager = new ApiTokenManager();
305
+ await this.apiTokenManager.initialize();
306
+ await this.routeConfigManager.initialize(this.seedConfigRoutes, this.seedEmailRoutes, this.seedDnsRoutes);
307
+ // Seed default profiles/targets if DB is empty and seeding is enabled
308
+ const seeder = new DbSeeder(this.referenceResolver);
309
+ await seeder.seedIfEmpty(this.options.dbConfig?.seedOnEmpty, this.options.dbConfig?.seedData);
310
+ })
311
+ .withStop(async () => {
312
+ this.routeConfigManager = undefined;
313
+ this.apiTokenManager = undefined;
314
+ this.referenceResolver = undefined;
315
+ this.targetProfileManager = undefined;
316
+ })
317
+ .withRetry({ maxRetries: 2, baseDelayMs: 1000 }));
318
+ }
319
+ // Email Server: optional, depends on SmartProxy
320
+ if (this.options.emailConfig) {
321
+ this.serviceManager.addService(new plugins.taskbuffer.Service('EmailServer')
322
+ .optional()
323
+ .dependsOn('SmartProxy')
324
+ .withStart(async () => {
325
+ await this.setupUnifiedEmailHandling();
326
+ })
327
+ .withStop(async () => {
328
+ if (this.emailServer) {
329
+ if (this.emailServer.deliverySystem) {
330
+ this.emailServer.deliverySystem.removeAllListeners();
331
+ }
332
+ this.emailServer.removeAllListeners();
333
+ await this.emailServer.stop();
334
+ this.emailServer = undefined;
335
+ }
336
+ })
337
+ .withRetry({ maxRetries: 3, baseDelayMs: 2000, maxDelayMs: 30_000 }));
338
+ }
339
+ // DNS Server: optional, depends on SmartProxy
340
+ if (this.options.dnsNsDomains && this.options.dnsNsDomains.length > 0 && this.options.dnsScopes && this.options.dnsScopes.length > 0) {
341
+ this.serviceManager.addService(new plugins.taskbuffer.Service('DnsServer')
342
+ .optional()
343
+ .dependsOn('SmartProxy')
344
+ .withStart(async () => {
345
+ await this.setupDnsWithSocketHandler();
346
+ })
347
+ .withStop(async () => {
348
+ // Flush pending DNS batch log
349
+ if (this.dnsBatchTimer) {
350
+ clearTimeout(this.dnsBatchTimer);
351
+ if (this.dnsBatchCount > 0) {
352
+ logger.log('info', `DNS: ${this.dnsBatchCount} queries processed (final flush)`, { zone: 'dns' });
353
+ }
354
+ this.dnsBatchTimer = null;
355
+ this.dnsBatchCount = 0;
356
+ this.dnsLogWindowSecond = 0;
357
+ this.dnsLogWindowCount = 0;
358
+ }
359
+ if (this.dnsServer) {
360
+ this.dnsServer.removeAllListeners();
361
+ await this.dnsServer.stop();
362
+ this.dnsServer = undefined;
363
+ }
364
+ })
365
+ .withRetry({ maxRetries: 3, baseDelayMs: 2000, maxDelayMs: 30_000 }));
366
+ }
367
+ // RADIUS Server: optional, no dependency on SmartProxy
368
+ if (this.options.radiusConfig) {
369
+ this.serviceManager.addService(new plugins.taskbuffer.Service('RadiusServer')
370
+ .optional()
371
+ .withStart(async () => {
372
+ await this.setupRadiusServer();
373
+ })
374
+ .withStop(async () => {
375
+ if (this.radiusServer) {
376
+ await this.radiusServer.stop();
377
+ this.radiusServer = undefined;
378
+ }
379
+ })
380
+ .withRetry({ maxRetries: 3, baseDelayMs: 2000, maxDelayMs: 30_000 }));
381
+ }
382
+ // Remote Ingress: optional, depends on SmartProxy
383
+ if (this.options.remoteIngressConfig?.enabled) {
384
+ this.serviceManager.addService(new plugins.taskbuffer.Service('RemoteIngress')
385
+ .optional()
386
+ .dependsOn('SmartProxy')
387
+ .withStart(async () => {
388
+ await this.setupRemoteIngress();
389
+ })
390
+ .withStop(async () => {
391
+ if (this.tunnelManager) {
392
+ await this.tunnelManager.stop();
393
+ this.tunnelManager = undefined;
394
+ }
395
+ this.remoteIngressManager = undefined;
396
+ })
397
+ .withRetry({ maxRetries: 3, baseDelayMs: 2000, maxDelayMs: 30_000 }));
398
+ }
399
+ // VPN Server: optional, depends on SmartProxy
400
+ if (this.options.vpnConfig?.enabled) {
401
+ this.serviceManager.addService(new plugins.taskbuffer.Service('VpnServer')
402
+ .optional()
403
+ .dependsOn('SmartProxy')
404
+ .withStart(async () => {
405
+ await this.setupVpnServer();
406
+ })
407
+ .withStop(async () => {
408
+ if (this.vpnManager) {
409
+ await this.vpnManager.stop();
410
+ this.vpnManager = undefined;
411
+ }
412
+ })
413
+ .withRetry({ maxRetries: 3, baseDelayMs: 2000, maxDelayMs: 30_000 }));
414
+ }
415
+ // Wire up aggregated events for logging
416
+ this.serviceSubjectSubscription = this.serviceManager.serviceSubject.subscribe((event) => {
417
+ const level = event.type === 'failed' ? 'error' : event.type === 'retrying' ? 'warn' : 'info';
418
+ logger.log(level, `Service '${event.serviceName}': ${event.type}`, {
419
+ state: event.state,
420
+ ...(event.error ? { error: event.error } : {}),
421
+ ...(event.attempt ? { attempt: event.attempt } : {}),
422
+ });
423
+ });
424
+ }
425
+ async start() {
426
+ await this.checkSystemLimits();
427
+ logger.log('info', 'Starting DcRouter Services');
428
+ await this.serviceManager.start();
429
+ this.logStartupSummary();
430
+ }
431
+ /**
432
+ * Detect OS-level resource limits and warn if they are too low for production use.
433
+ * This is detection only — no attempts to raise limits.
434
+ */
435
+ async checkSystemLimits() {
436
+ try {
437
+ const fs = new plugins.smartfs.SmartFs(new plugins.smartfs.SmartFsProviderNode());
438
+ const limitsContent = await fs.file('/proc/self/limits').encoding('utf8').read();
439
+ const nofileLine = limitsContent.split('\n').find((line) => line.startsWith('Max open files'));
440
+ if (nofileLine) {
441
+ const parts = nofileLine.split(/\s{2,}/);
442
+ const softLimit = parseInt(parts[1], 10);
443
+ const hardLimit = parseInt(parts[2], 10);
444
+ if (softLimit < 65536) {
445
+ logger.log('warn', `File descriptor soft limit is ${softLimit} (hard: ${hardLimit}). ` +
446
+ `For production use, set --ulimit nofile=65536:65536 on the container runtime.`);
447
+ }
448
+ else {
449
+ logger.log('info', `File descriptor limits: soft=${softLimit}, hard=${hardLimit}`);
450
+ }
451
+ }
452
+ }
453
+ catch {
454
+ // Non-Linux or /proc not available — silently skip
455
+ }
456
+ }
457
+ /**
458
+ * Log comprehensive startup summary
459
+ */
460
+ logStartupSummary() {
461
+ logger.log('info', 'DcRouter Started Successfully');
462
+ // Metrics summary
463
+ if (this.metricsManager) {
464
+ logger.log('info', 'Metrics Service: SmartMetrics active, SmartProxy stats active, real-time tracking enabled');
465
+ }
466
+ // SmartProxy summary
467
+ if (this.smartProxy) {
468
+ const routeCount = this.options.smartProxyConfig?.routes?.length || 0;
469
+ const acmeEnabled = this.options.smartProxyConfig?.acme?.enabled || false;
470
+ const acmeMode = acmeEnabled
471
+ ? `email=${this.options.smartProxyConfig.acme.email || 'not set'}, mode=${this.options.smartProxyConfig.acme.useProduction ? 'production' : 'staging'}`
472
+ : 'disabled';
473
+ logger.log('info', `SmartProxy Service: ${routeCount} routes, ACME: ${acmeMode}`);
474
+ }
475
+ // Email service summary
476
+ if (this.emailServer && this.options.emailConfig) {
477
+ const ports = this.options.emailConfig.ports || [];
478
+ const domainCount = this.options.emailConfig.domains?.length || 0;
479
+ const domainNames = this.options.emailConfig.domains?.map(d => `${d.domain} (${d.dnsMode || 'default'})`).join(', ') || 'none';
480
+ logger.log('info', `Email Service: ports=[${ports.join(', ')}], hostname=${this.options.emailConfig.hostname || 'localhost'}, domains=${domainCount} [${domainNames}], DKIM initialized`);
481
+ }
482
+ // DNS service summary
483
+ if (this.dnsServer && this.options.dnsNsDomains && this.options.dnsScopes) {
484
+ logger.log('info', `DNS Service: nameservers=[${this.options.dnsNsDomains.join(', ')}], authoritative for ${this.options.dnsScopes.length} domains [${this.options.dnsScopes.join(', ')}], UDP:53, DoH enabled`);
485
+ }
486
+ // RADIUS service summary
487
+ if (this.radiusServer && this.options.radiusConfig) {
488
+ const vlanStats = this.radiusServer.getVlanManager().getStats();
489
+ logger.log('info', `RADIUS Service: auth=${this.options.radiusConfig.authPort || 1812}, acct=${this.options.radiusConfig.acctPort || 1813}, clients=${this.options.radiusConfig.clients?.length || 0}, VLANs=${vlanStats.totalMappings}, accounting=${this.options.radiusConfig.accounting?.enabled ? 'enabled' : 'disabled'}`);
490
+ }
491
+ // VPN summary
492
+ if (this.vpnManager && this.options.vpnConfig?.enabled) {
493
+ const subnet = this.vpnManager.getSubnet();
494
+ const wgPort = this.options.vpnConfig.wgListenPort ?? 51820;
495
+ const clientCount = this.vpnManager.listClients().length;
496
+ logger.log('info', `VPN Service: subnet=${subnet}, wg=:${wgPort}, clients=${clientCount}`);
497
+ }
498
+ // Remote Ingress summary
499
+ if (this.tunnelManager && this.options.remoteIngressConfig?.enabled) {
500
+ const edgeCount = this.remoteIngressManager?.getAllEdges().length || 0;
501
+ const connectedCount = this.tunnelManager.getConnectedCount();
502
+ logger.log('info', `Remote Ingress: tunnel port=${this.options.remoteIngressConfig.tunnelPort || 8443}, edges=${edgeCount} registered/${connectedCount} connected`);
503
+ }
504
+ // Database summary
505
+ if (this.dcRouterDb) {
506
+ logger.log('info', `Database: ${this.dcRouterDb.isEmbedded() ? 'embedded' : 'external'}, db=${this.dcRouterDb.getDbName()}, cleaner=${this.cacheCleaner?.isActive() ? 'active' : 'inactive'} (${(this.options.dbConfig?.cleanupIntervalHours || 1)}h interval)`);
507
+ }
508
+ // Service status summary from ServiceManager
509
+ const health = this.serviceManager.getHealth();
510
+ const statuses = health.services;
511
+ const running = statuses.filter(s => s.state === 'running').length;
512
+ const failed = statuses.filter(s => s.state === 'failed').length;
513
+ const retrying = statuses.filter(s => s.state === 'starting' || s.state === 'degraded').length;
514
+ if (failed > 0) {
515
+ const failedNames = statuses.filter(s => s.state === 'failed').map(s => `${s.name}: ${s.lastError || 'unknown'}`);
516
+ logger.log('warn', `DcRouter started in degraded mode — ${running} running, ${failed} failed: ${failedNames.join('; ')}`);
517
+ }
518
+ else if (retrying > 0) {
519
+ logger.log('info', `DcRouter started — ${running} running, ${retrying} still initializing`);
520
+ }
521
+ else {
522
+ logger.log('info', `All ${running} services are running`);
523
+ }
524
+ }
525
+ /**
526
+ * Set up the unified database (smartdata + LocalSmartDb or external MongoDB)
527
+ */
528
+ async setupDcRouterDb() {
529
+ logger.log('info', 'Setting up DcRouterDb...');
530
+ const dbConfig = this.options.dbConfig || {};
531
+ // Initialize DcRouterDb singleton
532
+ this.dcRouterDb = DcRouterDb.getInstance({
533
+ mongoDbUrl: dbConfig.mongoDbUrl,
534
+ storagePath: dbConfig.storagePath || this.resolvedPaths.defaultTsmDbPath,
535
+ dbName: dbConfig.dbName || 'dcrouter',
536
+ debug: false,
537
+ });
538
+ await this.dcRouterDb.start();
539
+ // Run any pending data migrations before anything else reads from the DB.
540
+ // This must complete before ConfigManagers loads profiles.
541
+ const migration = await createMigrationRunner(this.dcRouterDb.getDb(), commitinfo.version);
542
+ const migrationResult = await migration.run();
543
+ if (migrationResult.stepsApplied.length > 0) {
544
+ logger.log('info', `smartmigration: ${migrationResult.currentVersionBefore ?? 'fresh'} → ${migrationResult.currentVersionAfter} ` +
545
+ `(${migrationResult.stepsApplied.length} step(s) applied in ${migrationResult.totalDurationMs}ms)`);
546
+ }
547
+ else if (migrationResult.wasFreshInstall) {
548
+ logger.log('info', `smartmigration: fresh install stamped to ${migrationResult.currentVersionAfter}`);
549
+ }
550
+ // Start the cache cleaner for TTL-based document cleanup
551
+ const cleanupIntervalMs = (dbConfig.cleanupIntervalHours || 1) * 60 * 60 * 1000;
552
+ this.cacheCleaner = new CacheCleaner(this.dcRouterDb, {
553
+ intervalMs: cleanupIntervalMs,
554
+ verbose: false,
555
+ });
556
+ this.cacheCleaner.start();
557
+ logger.log('info', `DcRouterDb ready (${this.dcRouterDb.isEmbedded() ? 'embedded' : 'external'})`);
558
+ }
559
+ /**
560
+ * Set up SmartProxy with direct configuration and automatic email routes
561
+ */
562
+ async setupSmartProxy() {
563
+ logger.log('info', 'Setting up SmartProxy...');
564
+ // Clean up any existing SmartProxy instance (e.g. from a retry)
565
+ if (this.smartProxy) {
566
+ this.smartProxy.removeAllListeners();
567
+ this.smartProxy = undefined;
568
+ }
569
+ // Assemble seed routes from constructor config — these will be seeded into DB
570
+ // by RouteConfigManager.initialize() when the ConfigManagers service starts.
571
+ this.seedConfigRoutes = (this.options.smartProxyConfig?.routes || []);
572
+ logger.log('info', `Found ${this.seedConfigRoutes.length} routes in config`);
573
+ this.seedEmailRoutes = [];
574
+ if (this.options.emailConfig) {
575
+ this.seedEmailRoutes = this.generateEmailRoutes(this.options.emailConfig);
576
+ logger.log('debug', 'Email routes generated', { routes: JSON.stringify(this.seedEmailRoutes) });
577
+ }
578
+ this.seedDnsRoutes = [];
579
+ if (this.options.dnsNsDomains && this.options.dnsNsDomains.length > 0) {
580
+ this.seedDnsRoutes = this.generateDnsRoutes();
581
+ logger.log('debug', `DNS routes for nameservers ${this.options.dnsNsDomains.join(', ')}`, { routes: JSON.stringify(this.seedDnsRoutes) });
582
+ }
583
+ // Combined routes for SmartProxy bootstrap (before DB routes are loaded)
584
+ let routes = [
585
+ ...this.seedConfigRoutes,
586
+ ...this.seedEmailRoutes,
587
+ ...this.seedDnsRoutes,
588
+ ];
589
+ // Build the ACME options for SmartProxy from the DB-backed AcmeConfigManager.
590
+ // If no config exists or it's disabled, SmartProxy's own ACME is turned off
591
+ // and dcrouter's SmartAcme / certProvisionFunction are not wired.
592
+ const dbAcme = this.acmeConfigManager?.getConfig();
593
+ const acmeConfig = dbAcme && dbAcme.enabled
594
+ ? {
595
+ accountEmail: dbAcme.accountEmail,
596
+ enabled: true,
597
+ useProduction: dbAcme.useProduction,
598
+ autoRenew: dbAcme.autoRenew,
599
+ renewThresholdDays: dbAcme.renewThresholdDays,
600
+ }
601
+ : undefined;
602
+ if (acmeConfig) {
603
+ logger.log('info', `ACME config: accountEmail=${acmeConfig.accountEmail}, useProduction=${acmeConfig.useProduction}, autoRenew=${acmeConfig.autoRenew}`);
604
+ }
605
+ else {
606
+ logger.log('info', 'ACME config: disabled or not yet configured in DB');
607
+ }
608
+ // Configure DNS-01 challenge if any DnsProviderDoc exists in the DB AND
609
+ // ACME is enabled. The DnsManager dispatches each challenge through the
610
+ // unified createRecord()/deleteRecord() path — works for both dcrouter-hosted
611
+ // zones and provider-managed zones. Only domains under management get certs.
612
+ let challengeHandlers = [];
613
+ if (acmeConfig &&
614
+ this.dnsManager &&
615
+ (await this.dnsManager.hasAnyManagedDomain())) {
616
+ logger.log('info', 'Configuring DNS-01 challenge for ACME via DnsManager (managed domains)');
617
+ const convenientDnsProvider = this.dnsManager.buildAcmeConvenientDnsProvider();
618
+ const dns01Handler = new plugins.smartacme.handlers.Dns01Handler(convenientDnsProvider);
619
+ challengeHandlers.push(dns01Handler);
620
+ }
621
+ // HTTP/3 augmentation (enabled by default unless explicitly disabled)
622
+ if (this.options.http3?.enabled !== false) {
623
+ const http3Config = { enabled: true, ...this.options.http3 };
624
+ routes = augmentRoutesWithHttp3(routes, http3Config);
625
+ logger.log('info', 'HTTP/3: Augmented qualifying HTTPS routes with QUIC/H3 configuration');
626
+ }
627
+ // If we have routes or need a basic SmartProxy instance, create it
628
+ if (routes.length > 0 || this.options.smartProxyConfig) {
629
+ logger.log('info', 'Setting up SmartProxy with combined configuration');
630
+ // Track cert entries loaded from cert store so we can populate certificateStatusMap after start
631
+ const loadedCertEntries = [];
632
+ // Create SmartProxy configuration with sensible gateway defaults.
633
+ // User's smartProxyConfig overrides these defaults via spread.
634
+ const smartProxyConfig = {
635
+ // --- dcrouter gateway defaults ---
636
+ maxConnectionsPerIP: 100,
637
+ connectionRateLimitPerMinute: 600,
638
+ socketTimeout: 120_000,
639
+ inactivityTimeout: 120_000,
640
+ keepAlive: true,
641
+ noDelay: true,
642
+ gracefulShutdownTimeout: 30_000,
643
+ // --- user overrides ---
644
+ ...this.options.smartProxyConfig,
645
+ // --- deep-merge defaults.security so user can override maxConnections ---
646
+ defaults: {
647
+ ...this.options.smartProxyConfig?.defaults,
648
+ security: {
649
+ maxConnections: 50_000,
650
+ ...this.options.smartProxyConfig?.defaults?.security,
651
+ },
652
+ },
653
+ // --- always set by dcrouter (after spread) ---
654
+ routes,
655
+ acme: acmeConfig,
656
+ certStore: {
657
+ loadAll: async () => {
658
+ const docs = await ProxyCertDoc.findAll();
659
+ const certs = [];
660
+ for (const doc of docs) {
661
+ certs.push({ domain: doc.domain, publicKey: doc.publicKey, privateKey: doc.privateKey, ca: doc.ca });
662
+ loadedCertEntries.push({ domain: doc.domain, publicKey: doc.publicKey, validUntil: doc.validUntil, validFrom: doc.validFrom });
663
+ }
664
+ return certs;
665
+ },
666
+ save: async (domain, publicKey, privateKey, ca) => {
667
+ let validUntil;
668
+ let validFrom;
669
+ try {
670
+ const x509 = new plugins.crypto.X509Certificate(publicKey);
671
+ validUntil = new Date(x509.validTo).getTime();
672
+ validFrom = new Date(x509.validFrom).getTime();
673
+ }
674
+ catch { /* PEM parsing failed */ }
675
+ let doc = await ProxyCertDoc.findByDomain(domain);
676
+ if (!doc) {
677
+ doc = new ProxyCertDoc();
678
+ doc.domain = domain;
679
+ }
680
+ doc.publicKey = publicKey;
681
+ doc.privateKey = privateKey;
682
+ doc.ca = ca || '';
683
+ doc.validUntil = validUntil || 0;
684
+ doc.validFrom = validFrom || 0;
685
+ await doc.save();
686
+ },
687
+ remove: async (domain) => {
688
+ const doc = await ProxyCertDoc.findByDomain(domain);
689
+ if (doc) {
690
+ await doc.delete();
691
+ }
692
+ },
693
+ },
694
+ };
695
+ // Initialize cert provision scheduler
696
+ this.certProvisionScheduler = new CertProvisionScheduler();
697
+ // If we have DNS challenge handlers, create SmartAcme instance and wire certProvisionFunction
698
+ // Note: SmartAcme.start() is NOT called here — it runs as a separate optional service
699
+ // via the ServiceManager, with aggressive retry for rate-limit resilience.
700
+ if (challengeHandlers.length > 0) {
701
+ // Stop old SmartAcme if it exists (e.g., during updateSmartProxyConfig)
702
+ if (this.smartAcme) {
703
+ this.smartAcmeReady = false;
704
+ await this.smartAcme.stop().catch(err => logger.log('error', 'Error stopping old SmartAcme', { error: String(err) }));
705
+ }
706
+ // Safe non-null: challengeHandlers.length > 0 implies both dnsManager
707
+ // and acmeConfig exist (enforced above).
708
+ this.smartAcme = new plugins.smartacme.SmartAcme({
709
+ accountEmail: dbAcme.accountEmail,
710
+ certManager: new StorageBackedCertManager(),
711
+ environment: dbAcme.useProduction ? 'production' : 'integration',
712
+ challengeHandlers: challengeHandlers,
713
+ challengePriority: ['dns-01'],
714
+ });
715
+ const scheduler = this.certProvisionScheduler;
716
+ smartProxyConfig.certProvisionFunction = async (domain, eventComms) => {
717
+ // If SmartAcme is not yet ready (still starting or retrying), fall back to HTTP-01
718
+ if (!this.smartAcmeReady) {
719
+ eventComms.warn(`SmartAcme not yet initialized, falling back to http-01 for ${domain}`);
720
+ return 'http01';
721
+ }
722
+ // Check backoff before attempting provision
723
+ if (await scheduler.isInBackoff(domain)) {
724
+ const info = await scheduler.getBackoffInfo(domain);
725
+ const msg = `Domain ${domain} is in backoff (${info?.failures} failures), retry after ${info?.retryAfter}`;
726
+ eventComms.warn(msg);
727
+ throw new Error(msg);
728
+ }
729
+ try {
730
+ // smartacme v9 handles concurrency, per-domain dedup, and rate limiting internally
731
+ eventComms.log(`Attempting DNS-01 via SmartAcme for ${domain}`);
732
+ eventComms.setSource('smartacme-dns-01');
733
+ const isWildcardDomain = domain.startsWith('*.');
734
+ const cert = await this.smartAcme.getCertificateForDomain(domain, {
735
+ includeWildcard: !isWildcardDomain,
736
+ });
737
+ // Parse real X509 expiry from PEM (defense-in-depth over SmartAcme's estimate)
738
+ let realValidUntil = cert.validUntil;
739
+ if (cert.publicKey) {
740
+ try {
741
+ const x509 = new plugins.crypto.X509Certificate(cert.publicKey);
742
+ realValidUntil = new Date(x509.validTo).getTime();
743
+ }
744
+ catch { /* fallback to SmartAcme's value */ }
745
+ }
746
+ if (realValidUntil) {
747
+ eventComms.setExpiryDate(new Date(realValidUntil));
748
+ }
749
+ const result = {
750
+ id: cert.id,
751
+ domainName: cert.domainName,
752
+ created: cert.created,
753
+ validUntil: realValidUntil,
754
+ privateKey: cert.privateKey,
755
+ publicKey: cert.publicKey,
756
+ csr: cert.csr,
757
+ };
758
+ // Success — clear any backoff
759
+ await scheduler.clearBackoff(domain);
760
+ return result;
761
+ }
762
+ catch (err) {
763
+ // Record failure for backoff tracking
764
+ await scheduler.recordFailure(domain, err.message);
765
+ eventComms.warn(`SmartAcme DNS-01 failed for ${domain}: ${err.message}, falling back to http-01`);
766
+ return 'http01';
767
+ }
768
+ };
769
+ }
770
+ // When remoteIngress is enabled, the hub binary forwards tunneled connections
771
+ // to SmartProxy with PROXY protocol v1 headers to preserve client IPs.
772
+ if (this.options.remoteIngressConfig?.enabled) {
773
+ smartProxyConfig.acceptProxyProtocol = true;
774
+ smartProxyConfig.proxyIPs = ['127.0.0.1'];
775
+ }
776
+ // VPN uses socket mode with PP v2 — SmartProxy must accept proxy protocol from localhost
777
+ if (this.options.vpnConfig?.enabled) {
778
+ smartProxyConfig.acceptProxyProtocol = true;
779
+ if (!smartProxyConfig.proxyIPs) {
780
+ smartProxyConfig.proxyIPs = [];
781
+ }
782
+ if (!smartProxyConfig.proxyIPs.includes('127.0.0.1')) {
783
+ smartProxyConfig.proxyIPs.push('127.0.0.1');
784
+ }
785
+ }
786
+ // Create SmartProxy instance
787
+ logger.log('info', `Creating SmartProxy instance: routes=${smartProxyConfig.routes?.length}, acme=${smartProxyConfig.acme?.enabled}, certProvisionFunction=${!!smartProxyConfig.certProvisionFunction}`);
788
+ this.smartProxy = new plugins.smartproxy.SmartProxy(smartProxyConfig);
789
+ // Set up event listeners
790
+ this.smartProxy.on('error', (err) => {
791
+ logger.log('error', `SmartProxy error: ${err.message}`, { stack: err.stack });
792
+ });
793
+ // Always listen for certificate events — emitted by both ACME and certProvisionFunction paths
794
+ // Events are keyed by domain for domain-centric certificate tracking
795
+ this.smartProxy.on('certificate-issued', (event) => {
796
+ logger.log('info', `Certificate issued for ${event.domain} via ${event.source}, expires ${event.expiryDate}`);
797
+ const routeNames = this.findRouteNamesForDomain(event.domain);
798
+ this.certificateStatusMap.set(event.domain, {
799
+ status: 'valid', routeNames,
800
+ expiryDate: event.expiryDate, issuedAt: new Date().toISOString(),
801
+ source: event.source,
802
+ });
803
+ });
804
+ // Note: smartproxy v27.5.0 emits only 'certificate-issued' and 'certificate-failed'.
805
+ // Renewals come through 'certificate-issued' (with optional isRenewal? in the payload).
806
+ // The vestigial 'certificate-renewed' event from common-types.ts is never emitted.
807
+ this.smartProxy.on('certificate-failed', (event) => {
808
+ logger.log('error', `Certificate failed for ${event.domain} (${event.source}): ${event.error}`);
809
+ const routeNames = this.findRouteNamesForDomain(event.domain);
810
+ this.certificateStatusMap.set(event.domain, {
811
+ status: 'failed', routeNames, error: event.error,
812
+ source: event.source,
813
+ });
814
+ });
815
+ // Start SmartProxy
816
+ logger.log('info', 'Starting SmartProxy...');
817
+ await this.smartProxy.start();
818
+ logger.log('info', 'SmartProxy started successfully');
819
+ // Populate certificateStatusMap for certs loaded from store at startup
820
+ for (const entry of loadedCertEntries) {
821
+ if (!this.certificateStatusMap.has(entry.domain)) {
822
+ const routeNames = this.findRouteNamesForDomain(entry.domain);
823
+ let expiryDate;
824
+ let issuedAt;
825
+ // Use validUntil/validFrom from stored proxy-certs data if available
826
+ if (entry.validUntil) {
827
+ expiryDate = new Date(entry.validUntil).toISOString();
828
+ }
829
+ if (entry.validFrom) {
830
+ issuedAt = new Date(entry.validFrom).toISOString();
831
+ }
832
+ // Try SmartAcme AcmeCertDoc metadata as secondary source
833
+ if (!expiryDate) {
834
+ try {
835
+ const cleanDomain = entry.domain.replace(/^\*\.?/, '');
836
+ const domParts = cleanDomain.split('.');
837
+ const baseDomain = domParts.length > 2 ? domParts.slice(-2).join('.') : cleanDomain;
838
+ const certDoc = await AcmeCertDoc.findByDomain(baseDomain)
839
+ || (baseDomain !== cleanDomain ? await AcmeCertDoc.findByDomain(cleanDomain) : null);
840
+ if (certDoc?.validUntil) {
841
+ expiryDate = new Date(certDoc.validUntil).toISOString();
842
+ }
843
+ if (certDoc?.created && !issuedAt) {
844
+ issuedAt = new Date(certDoc.created).toISOString();
845
+ }
846
+ }
847
+ catch { /* no metadata available */ }
848
+ }
849
+ // Fallback: parse X509 from PEM to get expiry
850
+ if (!expiryDate && entry.publicKey) {
851
+ try {
852
+ const x509 = new plugins.crypto.X509Certificate(entry.publicKey);
853
+ expiryDate = new Date(x509.validTo).toISOString();
854
+ if (!issuedAt) {
855
+ issuedAt = new Date(x509.validFrom).toISOString();
856
+ }
857
+ }
858
+ catch { /* PEM parsing failed */ }
859
+ }
860
+ this.certificateStatusMap.set(entry.domain, {
861
+ status: 'valid',
862
+ routeNames,
863
+ expiryDate,
864
+ issuedAt,
865
+ source: 'cert-store',
866
+ });
867
+ }
868
+ }
869
+ if (loadedCertEntries.length > 0) {
870
+ logger.log('info', `Populated certificate status for ${loadedCertEntries.length} store-loaded domain(s)`);
871
+ }
872
+ logger.log('info', `SmartProxy started with ${routes.length} routes`);
873
+ }
874
+ }
875
+ /**
876
+ * Generate SmartProxy routes for email configuration
877
+ */
878
+ generateEmailRoutes(emailConfig) {
879
+ const emailRoutes = [];
880
+ // Create routes for each email port
881
+ for (const port of emailConfig.ports) {
882
+ // Create a descriptive name for the route based on the port
883
+ let routeName = 'email-route';
884
+ let tlsMode = 'passthrough';
885
+ // Handle different email ports differently
886
+ switch (port) {
887
+ case 25: // SMTP
888
+ routeName = 'smtp-route';
889
+ tlsMode = 'passthrough'; // STARTTLS handled by email server
890
+ break;
891
+ case 587: // Submission
892
+ routeName = 'submission-route';
893
+ tlsMode = 'passthrough'; // STARTTLS handled by email server
894
+ break;
895
+ case 465: // SMTPS
896
+ routeName = 'smtps-route';
897
+ tlsMode = 'terminate'; // Terminate TLS and re-encrypt to email server
898
+ break;
899
+ default:
900
+ routeName = `email-port-${port}-route`;
901
+ tlsMode = 'passthrough';
902
+ // Check if we have specific settings for this port
903
+ if (this.options.emailPortConfig?.portSettings &&
904
+ this.options.emailPortConfig.portSettings[port]) {
905
+ const portSettings = this.options.emailPortConfig.portSettings[port];
906
+ // If this port requires TLS termination, set the mode accordingly
907
+ if (portSettings.terminateTls) {
908
+ tlsMode = 'terminate';
909
+ }
910
+ // Override the route name if specified
911
+ if (portSettings.routeName) {
912
+ routeName = portSettings.routeName;
913
+ }
914
+ }
915
+ break;
916
+ }
917
+ // Create forward action to route to internal email server ports
918
+ const defaultPortMapping = {
919
+ 25: 10025, // SMTP
920
+ 587: 10587, // Submission
921
+ 465: 10465 // SMTPS
922
+ };
923
+ const portMapping = this.options.emailPortConfig?.portMapping || defaultPortMapping;
924
+ const internalPort = portMapping[port] || port + 10000;
925
+ let action = {
926
+ type: 'forward',
927
+ targets: [{
928
+ host: 'localhost', // Forward to internal email server
929
+ port: internalPort
930
+ }],
931
+ tls: {
932
+ mode: tlsMode
933
+ }
934
+ };
935
+ // For TLS terminate mode, add certificate info
936
+ if (tlsMode === 'terminate' && action.tls) {
937
+ action.tls.certificate = 'auto';
938
+ }
939
+ // Create the route configuration
940
+ const routeConfig = {
941
+ name: routeName,
942
+ match: {
943
+ ports: [port]
944
+ },
945
+ action: action
946
+ };
947
+ // Add the route to our list
948
+ emailRoutes.push(routeConfig);
949
+ }
950
+ return emailRoutes;
951
+ }
952
+ /**
953
+ * Generate SmartProxy routes for DNS configuration
954
+ */
955
+ generateDnsRoutes() {
956
+ if (!this.options.dnsNsDomains || this.options.dnsNsDomains.length === 0) {
957
+ return [];
958
+ }
959
+ const dnsRoutes = [];
960
+ // Create routes for DNS-over-HTTPS paths
961
+ const dohPaths = ['/dns-query', '/resolve'];
962
+ // Use the first nameserver domain for DoH routes
963
+ const primaryNameserver = this.options.dnsNsDomains[0];
964
+ for (const path of dohPaths) {
965
+ const dohRoute = {
966
+ name: `dns-over-https-${path.replace('/', '')}`,
967
+ match: {
968
+ ports: [443], // HTTPS port for DoH
969
+ domains: [primaryNameserver],
970
+ path: path
971
+ },
972
+ action: {
973
+ type: 'socket-handler',
974
+ socketHandler: this.createDnsSocketHandler()
975
+ }
976
+ };
977
+ dnsRoutes.push(dohRoute);
978
+ }
979
+ return dnsRoutes;
980
+ }
981
+ /**
982
+ * Check if a domain matches a pattern (including wildcard support)
983
+ * @param domain The domain to check
984
+ * @param pattern The pattern to match against (e.g., "*.example.com")
985
+ * @returns Whether the domain matches the pattern
986
+ */
987
+ isDomainMatch(domain, pattern) {
988
+ domain = domain.toLowerCase();
989
+ pattern = pattern.toLowerCase();
990
+ if (domain === pattern)
991
+ return true;
992
+ // Routing-glob: *example.com matches example.com, sub.example.com, *.example.com
993
+ if (pattern.startsWith('*') && !pattern.startsWith('*.')) {
994
+ const baseDomain = pattern.slice(1); // *nevermind.cloud → nevermind.cloud
995
+ if (domain === baseDomain || domain === `*.${baseDomain}`)
996
+ return true;
997
+ if (domain.endsWith(baseDomain) && domain.length > baseDomain.length)
998
+ return true;
999
+ }
1000
+ // Standard wildcard: *.example.com matches sub.example.com and example.com
1001
+ if (pattern.startsWith('*.')) {
1002
+ const suffix = pattern.slice(2);
1003
+ if (domain === suffix)
1004
+ return true;
1005
+ return domain.endsWith(suffix) && domain.length > suffix.length;
1006
+ }
1007
+ return false;
1008
+ }
1009
+ /**
1010
+ * Find ALL route names that match a given domain
1011
+ */
1012
+ findRouteNamesForDomain(domain) {
1013
+ if (!this.smartProxy)
1014
+ return [];
1015
+ const names = [];
1016
+ for (const route of this.smartProxy.routeManager.getRoutes()) {
1017
+ if (!route.match.domains || !route.name)
1018
+ continue;
1019
+ const routeDomains = Array.isArray(route.match.domains)
1020
+ ? route.match.domains
1021
+ : [route.match.domains];
1022
+ for (const pattern of routeDomains) {
1023
+ if (this.isDomainMatch(domain, pattern)) {
1024
+ names.push(route.name);
1025
+ break; // This route already matched, no need to check other patterns
1026
+ }
1027
+ }
1028
+ }
1029
+ return names;
1030
+ }
1031
+ async stop() {
1032
+ logger.log('info', 'Stopping DcRouter services...');
1033
+ // Unsubscribe from service events before stopping services
1034
+ if (this.serviceSubjectSubscription) {
1035
+ this.serviceSubjectSubscription.unsubscribe();
1036
+ this.serviceSubjectSubscription = undefined;
1037
+ }
1038
+ // ServiceManager handles reverse-dependency-ordered shutdown
1039
+ await this.serviceManager.stop();
1040
+ // Clear backoff cache in cert scheduler
1041
+ if (this.certProvisionScheduler) {
1042
+ this.certProvisionScheduler.clear();
1043
+ this.certProvisionScheduler = undefined;
1044
+ }
1045
+ this.certificateStatusMap.clear();
1046
+ // Reset security singletons to allow GC
1047
+ SecurityLogger.resetInstance();
1048
+ ContentScanner.resetInstance();
1049
+ IPReputationChecker.resetInstance();
1050
+ logger.log('info', 'All DcRouter services stopped');
1051
+ }
1052
+ /**
1053
+ * Update SmartProxy configuration
1054
+ * @param config New SmartProxy configuration
1055
+ */
1056
+ async updateSmartProxyConfig(config) {
1057
+ // Stop existing SmartProxy if running
1058
+ if (this.smartProxy) {
1059
+ this.smartProxy.removeAllListeners();
1060
+ await this.smartProxy.stop();
1061
+ this.smartProxy = undefined;
1062
+ }
1063
+ // Update configuration
1064
+ this.options.smartProxyConfig = config;
1065
+ // Start new SmartProxy with updated configuration (rebuilds seed routes)
1066
+ await this.setupSmartProxy();
1067
+ // Re-seed and re-apply all routes after SmartProxy restart
1068
+ if (this.routeConfigManager) {
1069
+ await this.routeConfigManager.initialize(this.seedConfigRoutes, this.seedEmailRoutes, this.seedDnsRoutes);
1070
+ }
1071
+ logger.log('info', 'SmartProxy configuration updated');
1072
+ }
1073
+ /**
1074
+ * Set up unified email handling with pattern-based routing
1075
+ * This implements the consolidated emailConfig approach
1076
+ */
1077
+ async setupUnifiedEmailHandling() {
1078
+ if (!this.options.emailConfig) {
1079
+ throw new Error('Email configuration is required for unified email handling');
1080
+ }
1081
+ // Apply port mapping if behind SmartProxy
1082
+ const portMapping = this.options.emailPortConfig?.portMapping || {
1083
+ 25: 10025, // SMTP
1084
+ 587: 10587, // Submission
1085
+ 465: 10465 // SMTPS
1086
+ };
1087
+ // Transform domains if they are provided as strings
1088
+ let transformedDomains = this.options.emailConfig.domains;
1089
+ if (transformedDomains && transformedDomains.length > 0) {
1090
+ // Check if domains are strings (for backward compatibility)
1091
+ if (typeof transformedDomains[0] === 'string') {
1092
+ transformedDomains = transformedDomains.map((domain) => ({
1093
+ domain,
1094
+ dnsMode: 'external-dns',
1095
+ dkim: {
1096
+ selector: 'default',
1097
+ keySize: 2048,
1098
+ rotateKeys: false,
1099
+ rotationInterval: 90
1100
+ }
1101
+ }));
1102
+ }
1103
+ }
1104
+ // Create config with mapped ports
1105
+ const emailConfig = {
1106
+ ...this.options.emailConfig,
1107
+ domains: transformedDomains,
1108
+ ports: this.options.emailConfig.ports.map(port => portMapping[port] || port + 10000),
1109
+ hostname: 'localhost' // Listen on localhost for SmartProxy forwarding
1110
+ };
1111
+ // Create unified email server
1112
+ this.emailServer = new UnifiedEmailServer(this, emailConfig);
1113
+ // Set up error handling
1114
+ this.emailServer.on('error', (err) => {
1115
+ logger.log('error', `UnifiedEmailServer error: ${err.message}`);
1116
+ });
1117
+ // Start the server
1118
+ await this.emailServer.start();
1119
+ // Wire delivery events to MetricsManager and logger
1120
+ if (this.metricsManager && this.emailServer.deliverySystem) {
1121
+ this.emailServer.deliverySystem.on('deliveryStart', (item) => {
1122
+ this.metricsManager.trackEmailReceived(item?.from);
1123
+ logger.log('info', `Email delivery started: ${item?.from} → ${item?.to}`, { zone: 'email' });
1124
+ });
1125
+ this.emailServer.deliverySystem.on('deliverySuccess', (item) => {
1126
+ this.metricsManager.trackEmailSent(item?.to);
1127
+ logger.log('info', `Email delivered to ${item?.to}`, { zone: 'email' });
1128
+ });
1129
+ this.emailServer.deliverySystem.on('deliveryFailed', (item, error) => {
1130
+ this.metricsManager.trackEmailFailed(item?.to, error?.message);
1131
+ logger.log('warn', `Email delivery failed to ${item?.to}: ${error?.message}`, { zone: 'email' });
1132
+ });
1133
+ }
1134
+ if (this.metricsManager && this.emailServer) {
1135
+ this.emailServer.on('bounceProcessed', () => {
1136
+ this.metricsManager.trackEmailBounced();
1137
+ logger.log('warn', 'Email bounce processed', { zone: 'email' });
1138
+ });
1139
+ }
1140
+ logger.log('info', `Email server started on ports: ${emailConfig.ports.join(', ')}`);
1141
+ }
1142
+ /**
1143
+ * Update the unified email configuration
1144
+ * @param config New email configuration
1145
+ */
1146
+ async updateEmailConfig(config) {
1147
+ // Stop existing email components
1148
+ await this.stopUnifiedEmailComponents();
1149
+ // Update configuration
1150
+ this.options.emailConfig = config;
1151
+ // Start email handling with new configuration
1152
+ await this.setupUnifiedEmailHandling();
1153
+ logger.log('info', 'Unified email configuration updated');
1154
+ }
1155
+ /**
1156
+ * Stop all unified email components
1157
+ */
1158
+ async stopUnifiedEmailComponents() {
1159
+ try {
1160
+ // Stop the unified email server which contains all components
1161
+ if (this.emailServer) {
1162
+ // Remove listeners before stopping to prevent leaks on config update cycles
1163
+ if (this.emailServer.deliverySystem) {
1164
+ this.emailServer.deliverySystem.removeAllListeners();
1165
+ }
1166
+ this.emailServer.removeAllListeners();
1167
+ await this.emailServer.stop();
1168
+ logger.log('info', 'Unified email server stopped');
1169
+ this.emailServer = undefined;
1170
+ }
1171
+ logger.log('info', 'All unified email components stopped');
1172
+ }
1173
+ catch (error) {
1174
+ logger.log('error', `Error stopping unified email components: ${error.message}`);
1175
+ throw error;
1176
+ }
1177
+ }
1178
+ /**
1179
+ * Update domain rules for email routing
1180
+ * @param rules New domain rules to apply
1181
+ */
1182
+ async updateEmailRoutes(routes) {
1183
+ // Validate that email config exists
1184
+ if (!this.options.emailConfig) {
1185
+ throw new Error('Email configuration is required before updating routes');
1186
+ }
1187
+ // Update the configuration
1188
+ this.options.emailConfig.routes = routes;
1189
+ // Update the unified email server if it exists
1190
+ if (this.emailServer) {
1191
+ this.emailServer.updateEmailRoutes(routes);
1192
+ }
1193
+ logger.log('info', `Email routes updated with ${routes.length} routes`);
1194
+ }
1195
+ /**
1196
+ * Get statistics from all components
1197
+ */
1198
+ getStats() {
1199
+ const stats = {
1200
+ emailServer: this.emailServer?.getStats()
1201
+ };
1202
+ return stats;
1203
+ }
1204
+ /**
1205
+ * Register DNS records with the DNS server
1206
+ * @param records Array of DNS records to register
1207
+ */
1208
+ registerDnsRecords(records) {
1209
+ if (!this.dnsServer)
1210
+ return;
1211
+ // Register a separate handler for each record
1212
+ // This ensures multiple records of the same type (like NS records) are all served
1213
+ for (const record of records) {
1214
+ // Register handler for this specific record
1215
+ this.dnsServer.registerHandler(record.name, [record.type], (question) => {
1216
+ // Check if this handler matches the question
1217
+ if (question.name === record.name && question.type === record.type) {
1218
+ return {
1219
+ name: record.name,
1220
+ type: record.type,
1221
+ class: 'IN',
1222
+ ttl: record.ttl || 300,
1223
+ data: this.parseDnsRecordData(record.type, record.value)
1224
+ };
1225
+ }
1226
+ return null;
1227
+ });
1228
+ }
1229
+ logger.log('info', `Registered ${records.length} DNS handlers (one per record)`);
1230
+ }
1231
+ /**
1232
+ * Parse DNS record data based on record type
1233
+ * @param type DNS record type
1234
+ * @param value DNS record value
1235
+ * @returns Parsed data for the DNS response
1236
+ */
1237
+ parseDnsRecordData(type, value) {
1238
+ switch (type) {
1239
+ case 'A':
1240
+ return value; // IP address as string
1241
+ case 'MX':
1242
+ const [priority, exchange] = value.split(' ');
1243
+ return { priority: parseInt(priority), exchange };
1244
+ case 'TXT':
1245
+ return value;
1246
+ case 'NS':
1247
+ return value;
1248
+ case 'SOA':
1249
+ // SOA format: primary-ns admin-email serial refresh retry expire minimum
1250
+ const parts = value.split(' ');
1251
+ return {
1252
+ mname: parts[0],
1253
+ rname: parts[1],
1254
+ serial: parseInt(parts[2]),
1255
+ refresh: parseInt(parts[3]),
1256
+ retry: parseInt(parts[4]),
1257
+ expire: parseInt(parts[5]),
1258
+ minimum: parseInt(parts[6])
1259
+ };
1260
+ default:
1261
+ return value;
1262
+ }
1263
+ }
1264
+ /**
1265
+ * Set up DNS server with socket handler for DoH
1266
+ */
1267
+ async setupDnsWithSocketHandler() {
1268
+ if (!this.options.dnsNsDomains || this.options.dnsNsDomains.length === 0) {
1269
+ throw new Error('dnsNsDomains is required for DNS server setup');
1270
+ }
1271
+ if (!this.options.dnsScopes || this.options.dnsScopes.length === 0) {
1272
+ throw new Error('dnsScopes is required for DNS server setup');
1273
+ }
1274
+ const primaryNameserver = this.options.dnsNsDomains[0];
1275
+ logger.log('info', `Setting up DNS server with primary nameserver: ${primaryNameserver}`);
1276
+ // Get VM IP address for UDP binding
1277
+ const networkInterfaces = plugins.os.networkInterfaces();
1278
+ let vmIpAddress = '0.0.0.0'; // Default to all interfaces
1279
+ // Try to find the VM's internal IP address
1280
+ for (const [_name, interfaces] of Object.entries(networkInterfaces)) {
1281
+ if (interfaces) {
1282
+ for (const iface of interfaces) {
1283
+ if (!iface.internal && iface.family === 'IPv4') {
1284
+ vmIpAddress = iface.address;
1285
+ break;
1286
+ }
1287
+ }
1288
+ }
1289
+ }
1290
+ // Create DNS server instance with manual HTTPS mode
1291
+ this.dnsServer = new plugins.smartdns.dnsServerMod.DnsServer({
1292
+ udpPort: 53,
1293
+ udpBindInterface: vmIpAddress,
1294
+ httpsPort: 443, // Required but won't bind due to manual mode
1295
+ manualHttpsMode: true, // Enable manual HTTPS socket handling
1296
+ dnssecZone: primaryNameserver,
1297
+ primaryNameserver: primaryNameserver, // Automatically generates correct SOA records
1298
+ // For now, use self-signed cert until we integrate with Let's Encrypt
1299
+ httpsKey: '',
1300
+ httpsCert: ''
1301
+ });
1302
+ // Start the DNS server (UDP only)
1303
+ await this.dnsServer.start();
1304
+ logger.log('info', `DNS server started on UDP ${vmIpAddress}:53`);
1305
+ // Wire DNS query events to MetricsManager and logger with adaptive rate limiting
1306
+ if (this.metricsManager && this.dnsServer) {
1307
+ const flushDnsBatch = () => {
1308
+ if (this.dnsBatchCount > 0) {
1309
+ logger.log('info', `DNS: ${this.dnsBatchCount} queries processed (rate limited)`, { zone: 'dns' });
1310
+ this.dnsBatchCount = 0;
1311
+ }
1312
+ this.dnsBatchTimer = null;
1313
+ };
1314
+ this.dnsServer.on('query', (event) => {
1315
+ // Metrics tracking
1316
+ for (const question of event.questions) {
1317
+ this.metricsManager?.trackDnsQuery(question.type, question.name, false, event.responseTimeMs, event.answered);
1318
+ }
1319
+ // Adaptive logging: individual logs up to 2/sec, then batch
1320
+ const nowSec = Math.floor(Date.now() / 1000);
1321
+ if (nowSec !== this.dnsLogWindowSecond) {
1322
+ this.dnsLogWindowSecond = nowSec;
1323
+ this.dnsLogWindowCount = 0;
1324
+ }
1325
+ if (this.dnsLogWindowCount < 2) {
1326
+ this.dnsLogWindowCount++;
1327
+ const summary = event.questions.map(q => `${q.type} ${q.name}`).join(', ');
1328
+ logger.log('info', `DNS query: ${summary} (${event.responseTimeMs}ms, ${event.answered ? 'answered' : 'unanswered'})`, { zone: 'dns' });
1329
+ }
1330
+ else {
1331
+ this.dnsBatchCount++;
1332
+ if (!this.dnsBatchTimer) {
1333
+ this.dnsBatchTimer = setTimeout(flushDnsBatch, 5000);
1334
+ }
1335
+ }
1336
+ });
1337
+ }
1338
+ // Validate DNS configuration
1339
+ await this.validateDnsConfiguration();
1340
+ // Generate and register authoritative records
1341
+ const authoritativeRecords = await this.generateAuthoritativeRecords();
1342
+ // Generate email DNS records
1343
+ const emailDnsRecords = await this.generateEmailDnsRecords();
1344
+ // Initialize DKIM for all email domains
1345
+ await this.initializeDkimForEmailDomains();
1346
+ // Load DKIM records from JSON files (they should now exist)
1347
+ const dkimRecords = await this.loadDkimRecords();
1348
+ // Combine all records: authoritative, email, DKIM, and user-defined
1349
+ const allRecords = [...authoritativeRecords, ...emailDnsRecords, ...dkimRecords];
1350
+ if (this.options.dnsRecords && this.options.dnsRecords.length > 0) {
1351
+ allRecords.push(...this.options.dnsRecords);
1352
+ }
1353
+ // Apply proxy IP replacement if configured
1354
+ await this.applyProxyIpReplacement(allRecords);
1355
+ // Register all DNS records
1356
+ if (allRecords.length > 0) {
1357
+ this.registerDnsRecords(allRecords);
1358
+ logger.log('info', `Registered ${allRecords.length} DNS records (${authoritativeRecords.length} authoritative, ${emailDnsRecords.length} email, ${dkimRecords.length} DKIM, ${this.options.dnsRecords?.length || 0} user-defined)`);
1359
+ }
1360
+ // Hand the DnsServer to DnsManager so DB-backed local records on
1361
+ // dcrouter-hosted domains get registered too.
1362
+ if (this.dnsManager && this.dnsServer) {
1363
+ await this.dnsManager.attachDnsServer(this.dnsServer);
1364
+ }
1365
+ }
1366
+ /**
1367
+ * Create DNS socket handler for DoH
1368
+ */
1369
+ createDnsSocketHandler() {
1370
+ return async (socket) => {
1371
+ if (!this.dnsServer) {
1372
+ logger.log('error', 'DNS socket handler called but DNS server not initialized');
1373
+ socket.end();
1374
+ return;
1375
+ }
1376
+ // Prevent uncaught exception from socket 'error' events
1377
+ socket.on('error', (err) => {
1378
+ logger.log('error', `DNS socket error: ${err.message}`);
1379
+ if (!socket.destroyed) {
1380
+ socket.destroy();
1381
+ }
1382
+ });
1383
+ logger.log('debug', 'DNS socket handler: passing socket to DnsServer');
1384
+ try {
1385
+ // Use the built-in socket handler from smartdns
1386
+ // This handles HTTP/2, DoH protocol, etc.
1387
+ await this.dnsServer.handleHttpsSocket(socket);
1388
+ }
1389
+ catch (error) {
1390
+ logger.log('error', `DNS socket handler error: ${error.message}`);
1391
+ if (!socket.destroyed) {
1392
+ socket.destroy();
1393
+ }
1394
+ }
1395
+ };
1396
+ }
1397
+ /**
1398
+ * Validate DNS configuration
1399
+ */
1400
+ async validateDnsConfiguration() {
1401
+ if (!this.options.dnsNsDomains || !this.options.dnsScopes) {
1402
+ return;
1403
+ }
1404
+ logger.log('info', 'Validating DNS configuration...');
1405
+ // Check if email domains with internal-dns are in dnsScopes
1406
+ if (this.options.emailConfig?.domains) {
1407
+ for (const domainConfig of this.options.emailConfig.domains) {
1408
+ if (domainConfig.dnsMode === 'internal-dns' &&
1409
+ !this.options.dnsScopes.includes(domainConfig.domain)) {
1410
+ logger.log('warn', `Email domain '${domainConfig.domain}' with internal-dns mode is not in dnsScopes. It should be added to dnsScopes.`);
1411
+ }
1412
+ }
1413
+ }
1414
+ // Validate user-provided DNS records are within scopes
1415
+ if (this.options.dnsRecords) {
1416
+ for (const record of this.options.dnsRecords) {
1417
+ const recordDomain = this.extractDomain(record.name);
1418
+ const isInScope = this.options.dnsScopes.some(scope => recordDomain === scope || recordDomain.endsWith(`.${scope}`));
1419
+ if (!isInScope) {
1420
+ logger.log('warn', `DNS record for '${record.name}' is outside defined scopes [${this.options.dnsScopes.join(', ')}]`);
1421
+ }
1422
+ }
1423
+ }
1424
+ }
1425
+ /**
1426
+ * Generate email DNS records for domains with internal-dns mode
1427
+ */
1428
+ async generateEmailDnsRecords() {
1429
+ const records = [];
1430
+ if (!this.options.emailConfig?.domains) {
1431
+ return records;
1432
+ }
1433
+ // Filter domains with internal-dns mode
1434
+ const internalDnsDomains = this.options.emailConfig.domains.filter(domain => domain.dnsMode === 'internal-dns');
1435
+ for (const domainConfig of internalDnsDomains) {
1436
+ const domain = domainConfig.domain;
1437
+ const ttl = domainConfig.dns?.internal?.ttl || 3600;
1438
+ const mxPriority = domainConfig.dns?.internal?.mxPriority || 10;
1439
+ // MX record - points to the domain itself for email handling
1440
+ records.push({
1441
+ name: domain,
1442
+ type: 'MX',
1443
+ value: `${mxPriority} ${domain}`,
1444
+ ttl
1445
+ });
1446
+ // SPF record - using sensible defaults
1447
+ const spfRecord = 'v=spf1 a mx ~all';
1448
+ records.push({
1449
+ name: domain,
1450
+ type: 'TXT',
1451
+ value: spfRecord,
1452
+ ttl
1453
+ });
1454
+ // DMARC record - using sensible defaults
1455
+ const dmarcPolicy = 'none'; // Start with 'none' policy for monitoring
1456
+ const dmarcEmail = `dmarc@${domain}`;
1457
+ records.push({
1458
+ name: `_dmarc.${domain}`,
1459
+ type: 'TXT',
1460
+ value: `v=DMARC1; p=${dmarcPolicy}; rua=mailto:${dmarcEmail}`,
1461
+ ttl
1462
+ });
1463
+ // Note: DKIM records will be generated later when DKIM keys are available
1464
+ // They require the DKIMCreator which is part of the email server
1465
+ }
1466
+ logger.log('info', `Generated ${records.length} email DNS records for ${internalDnsDomains.length} internal-dns domains`);
1467
+ return records;
1468
+ }
1469
+ /**
1470
+ * Load DKIM records from JSON files
1471
+ * Reads all *.dkimrecord.json files from the DNS records directory
1472
+ */
1473
+ async loadDkimRecords() {
1474
+ const records = [];
1475
+ try {
1476
+ // Ensure paths are imported
1477
+ const dnsDir = this.resolvedPaths.dnsRecordsDir;
1478
+ // Check if directory exists
1479
+ if (!plugins.fs.existsSync(dnsDir)) {
1480
+ logger.log('debug', 'No DNS records directory found, skipping DKIM record loading');
1481
+ return records;
1482
+ }
1483
+ // Read all files in the directory
1484
+ const files = plugins.fs.readdirSync(dnsDir);
1485
+ const dkimFiles = files.filter(f => f.endsWith('.dkimrecord.json'));
1486
+ logger.log('info', `Found ${dkimFiles.length} DKIM record files`);
1487
+ // Load each DKIM record
1488
+ for (const file of dkimFiles) {
1489
+ try {
1490
+ const filePath = plugins.path.join(dnsDir, file);
1491
+ const fileContent = plugins.fs.readFileSync(filePath, 'utf8');
1492
+ const dkimRecord = JSON.parse(fileContent);
1493
+ // Validate record structure
1494
+ if (dkimRecord.name && dkimRecord.type === 'TXT' && dkimRecord.value) {
1495
+ records.push({
1496
+ name: dkimRecord.name,
1497
+ type: 'TXT',
1498
+ value: dkimRecord.value,
1499
+ ttl: 3600 // Standard DKIM TTL
1500
+ });
1501
+ logger.log('info', `Loaded DKIM record for ${dkimRecord.name}`);
1502
+ }
1503
+ else {
1504
+ logger.log('warn', `Invalid DKIM record structure in ${file}`);
1505
+ }
1506
+ }
1507
+ catch (error) {
1508
+ logger.log('error', `Failed to load DKIM record from ${file}: ${error.message}`);
1509
+ }
1510
+ }
1511
+ }
1512
+ catch (error) {
1513
+ logger.log('error', `Failed to load DKIM records: ${error.message}`);
1514
+ }
1515
+ return records;
1516
+ }
1517
+ /**
1518
+ * Initialize DKIM keys for all configured email domains
1519
+ * This ensures DKIM records are available immediately at startup
1520
+ */
1521
+ async initializeDkimForEmailDomains() {
1522
+ if (!this.options.emailConfig?.domains || !this.emailServer) {
1523
+ return;
1524
+ }
1525
+ logger.log('info', 'Initializing DKIM keys for email domains...');
1526
+ // Get DKIMCreator instance from email server (public in smartmta)
1527
+ const dkimCreator = this.emailServer.dkimCreator;
1528
+ if (!dkimCreator) {
1529
+ logger.log('warn', 'DKIMCreator not available, skipping DKIM initialization');
1530
+ return;
1531
+ }
1532
+ // Ensure necessary directories exist
1533
+ paths.ensureDataDirectories(this.resolvedPaths);
1534
+ // Generate DKIM keys for each email domain
1535
+ for (const domainConfig of this.options.emailConfig.domains) {
1536
+ try {
1537
+ // Generate DKIM keys for all domains, regardless of DNS mode
1538
+ // This ensures keys are ready even if DNS mode changes later
1539
+ await dkimCreator.handleDKIMKeysForDomain(domainConfig.domain);
1540
+ logger.log('info', `DKIM keys initialized for ${domainConfig.domain}`);
1541
+ }
1542
+ catch (error) {
1543
+ logger.log('error', `Failed to initialize DKIM for ${domainConfig.domain}: ${error.message}`);
1544
+ }
1545
+ }
1546
+ logger.log('info', 'DKIM initialization complete');
1547
+ }
1548
+ /**
1549
+ * Generate authoritative DNS records (NS only) for all domains in dnsScopes
1550
+ * SOA records are now automatically generated by smartdns with primaryNameserver setting
1551
+ */
1552
+ async generateAuthoritativeRecords() {
1553
+ const records = [];
1554
+ if (!this.options.dnsNsDomains || !this.options.dnsScopes) {
1555
+ return records;
1556
+ }
1557
+ // Determine the public IP for nameserver A records
1558
+ let publicIp = null;
1559
+ // Use proxy IPs if configured (these should be public IPs)
1560
+ if (this.options.proxyIps && this.options.proxyIps.length > 0) {
1561
+ publicIp = this.options.proxyIps[0]; // Use first proxy IP
1562
+ logger.log('info', `Using proxy IP for nameserver A records: ${publicIp}`);
1563
+ }
1564
+ else if (this.options.publicIp) {
1565
+ // Use explicitly configured public IP
1566
+ publicIp = this.options.publicIp;
1567
+ this.detectedPublicIp = publicIp;
1568
+ logger.log('info', `Using configured public IP for nameserver A records: ${publicIp}`);
1569
+ }
1570
+ else {
1571
+ // Auto-discover public IP using smartnetwork
1572
+ try {
1573
+ logger.log('info', 'Auto-discovering public IP address...');
1574
+ const smartNetwork = new plugins.smartnetwork.SmartNetwork();
1575
+ const publicIps = await smartNetwork.getPublicIps();
1576
+ if (publicIps.v4) {
1577
+ publicIp = publicIps.v4;
1578
+ this.detectedPublicIp = publicIp;
1579
+ logger.log('info', `Auto-discovered public IPv4: ${publicIp}`);
1580
+ }
1581
+ else {
1582
+ logger.log('warn', 'Could not auto-discover public IPv4 address');
1583
+ }
1584
+ }
1585
+ catch (error) {
1586
+ logger.log('error', `Failed to auto-discover public IP: ${error.message}`);
1587
+ }
1588
+ if (!publicIp) {
1589
+ logger.log('warn', 'No public IP available. Nameserver A records require either proxyIps, publicIp, or successful auto-discovery.');
1590
+ }
1591
+ }
1592
+ // Generate A records for nameservers if we have a public IP
1593
+ if (publicIp) {
1594
+ for (const nsDomain of this.options.dnsNsDomains) {
1595
+ records.push({
1596
+ name: nsDomain,
1597
+ type: 'A',
1598
+ value: publicIp,
1599
+ ttl: 3600
1600
+ });
1601
+ }
1602
+ logger.log('info', `Generated A records for ${this.options.dnsNsDomains.length} nameservers`);
1603
+ }
1604
+ // Generate NS records for each domain in scopes
1605
+ for (const domain of this.options.dnsScopes) {
1606
+ // Add NS records for all nameservers
1607
+ for (const nsDomain of this.options.dnsNsDomains) {
1608
+ records.push({
1609
+ name: domain,
1610
+ type: 'NS',
1611
+ value: nsDomain,
1612
+ ttl: 3600
1613
+ });
1614
+ }
1615
+ // SOA records are now automatically generated by smartdns DnsServer
1616
+ // with the primaryNameserver configuration option
1617
+ }
1618
+ logger.log('info', `Generated ${records.length} total records (A + NS) for ${this.options.dnsScopes.length} domains`);
1619
+ return records;
1620
+ }
1621
+ /**
1622
+ * Extract the base domain from a DNS record name
1623
+ */
1624
+ extractDomain(recordName) {
1625
+ // Handle wildcards
1626
+ if (recordName.startsWith('*.')) {
1627
+ recordName = recordName.substring(2);
1628
+ }
1629
+ return recordName;
1630
+ }
1631
+ /**
1632
+ * Apply proxy IP replacement logic to DNS records
1633
+ */
1634
+ async applyProxyIpReplacement(records) {
1635
+ if (!this.options.proxyIps || this.options.proxyIps.length === 0) {
1636
+ return; // No proxy IPs configured, skip replacement
1637
+ }
1638
+ // Get server's public IP
1639
+ const serverIp = await this.detectServerPublicIp();
1640
+ if (!serverIp) {
1641
+ logger.log('warn', 'Could not detect server public IP, skipping proxy IP replacement');
1642
+ return;
1643
+ }
1644
+ logger.log('info', `Applying proxy IP replacement. Server IP: ${serverIp}, Proxy IPs: ${this.options.proxyIps.join(', ')}`);
1645
+ let proxyIndex = 0;
1646
+ for (const record of records) {
1647
+ if (record.type === 'A' &&
1648
+ record.value === serverIp &&
1649
+ record.useIngressProxy !== false) {
1650
+ // Round-robin through proxy IPs
1651
+ const proxyIp = this.options.proxyIps[proxyIndex % this.options.proxyIps.length];
1652
+ logger.log('info', `Replacing A record for ${record.name}: ${record.value} → ${proxyIp}`);
1653
+ record.value = proxyIp;
1654
+ proxyIndex++;
1655
+ }
1656
+ }
1657
+ }
1658
+ /**
1659
+ * Detect the server's public IP address
1660
+ */
1661
+ async detectServerPublicIp() {
1662
+ try {
1663
+ const smartNetwork = new plugins.smartnetwork.SmartNetwork();
1664
+ const publicIps = await smartNetwork.getPublicIps();
1665
+ if (publicIps.v4) {
1666
+ return publicIps.v4;
1667
+ }
1668
+ return null;
1669
+ }
1670
+ catch (error) {
1671
+ logger.log('warn', `Failed to detect public IP: ${error.message}`);
1672
+ return null;
1673
+ }
1674
+ }
1675
+ /**
1676
+ * Set up Remote Ingress hub for edge tunnel connections
1677
+ */
1678
+ async setupRemoteIngress() {
1679
+ if (!this.options.remoteIngressConfig?.enabled) {
1680
+ return;
1681
+ }
1682
+ logger.log('info', 'Setting up Remote Ingress hub...');
1683
+ // Initialize the edge registration manager
1684
+ this.remoteIngressManager = new RemoteIngressManager();
1685
+ await this.remoteIngressManager.initialize();
1686
+ // Pass current bootstrap routes so the manager can derive edge ports initially.
1687
+ // Once RouteConfigManager applies the full DB set, the onRoutesApplied callback
1688
+ // will push the complete merged routes here.
1689
+ const bootstrapRoutes = [...this.seedConfigRoutes, ...this.seedEmailRoutes, ...this.seedDnsRoutes];
1690
+ this.remoteIngressManager.setRoutes(bootstrapRoutes);
1691
+ // If ConfigManagers finished before us, re-apply routes
1692
+ // so the callback delivers the full DB set to our newly-created remoteIngressManager.
1693
+ if (this.routeConfigManager) {
1694
+ await this.routeConfigManager.applyRoutes();
1695
+ }
1696
+ // Resolve TLS certs for tunnel: explicit paths > ACME for hubDomain > self-signed (Rust default)
1697
+ const riCfg = this.options.remoteIngressConfig;
1698
+ let tlsConfig;
1699
+ // Priority 1: Explicit cert/key file paths
1700
+ if (riCfg.tls?.certPath && riCfg.tls?.keyPath) {
1701
+ try {
1702
+ const certPem = plugins.fs.readFileSync(riCfg.tls.certPath, 'utf8');
1703
+ const keyPem = plugins.fs.readFileSync(riCfg.tls.keyPath, 'utf8');
1704
+ tlsConfig = { certPem, keyPem };
1705
+ logger.log('info', 'Using explicit TLS cert/key for RemoteIngress tunnel');
1706
+ }
1707
+ catch (err) {
1708
+ logger.log('warn', `Failed to read RemoteIngress TLS cert/key files: ${err.message}`);
1709
+ }
1710
+ }
1711
+ // Priority 2: Existing cert from SmartProxy cert store for hubDomain
1712
+ if (!tlsConfig && riCfg.hubDomain) {
1713
+ try {
1714
+ const stored = await ProxyCertDoc.findByDomain(riCfg.hubDomain);
1715
+ if (stored?.publicKey && stored?.privateKey) {
1716
+ tlsConfig = { certPem: stored.publicKey, keyPem: stored.privateKey };
1717
+ logger.log('info', `Using stored ACME cert for RemoteIngress tunnel TLS: ${riCfg.hubDomain}`);
1718
+ }
1719
+ }
1720
+ catch { /* no stored cert, fall through */ }
1721
+ }
1722
+ if (!tlsConfig) {
1723
+ logger.log('info', 'No TLS cert configured for RemoteIngress tunnel — using auto-generated self-signed');
1724
+ }
1725
+ // Create and start the tunnel manager
1726
+ this.tunnelManager = new TunnelManager(this.remoteIngressManager, {
1727
+ tunnelPort: riCfg.tunnelPort ?? 8443,
1728
+ targetHost: '127.0.0.1',
1729
+ tls: tlsConfig,
1730
+ });
1731
+ await this.tunnelManager.start();
1732
+ const edgeCount = this.remoteIngressManager.getAllEdges().length;
1733
+ logger.log('info', `Remote Ingress hub started on port ${this.options.remoteIngressConfig.tunnelPort || 8443} with ${edgeCount} registered edge(s)`);
1734
+ }
1735
+ /**
1736
+ * Set up VPN server for VPN-based route access control.
1737
+ */
1738
+ async setupVpnServer() {
1739
+ if (!this.options.vpnConfig?.enabled) {
1740
+ return;
1741
+ }
1742
+ logger.log('info', 'Setting up VPN server...');
1743
+ this.vpnManager = new VpnManager({
1744
+ subnet: this.options.vpnConfig.subnet,
1745
+ wgListenPort: this.options.vpnConfig.wgListenPort,
1746
+ dns: this.options.vpnConfig.dns,
1747
+ serverEndpoint: this.options.vpnConfig.serverEndpoint,
1748
+ initialClients: this.options.vpnConfig.clients,
1749
+ destinationPolicy: this.options.vpnConfig.destinationPolicy,
1750
+ forwardingMode: this.options.vpnConfig.forwardingMode,
1751
+ bridgeLanSubnet: this.options.vpnConfig.bridgeLanSubnet,
1752
+ bridgePhysicalInterface: this.options.vpnConfig.bridgePhysicalInterface,
1753
+ bridgeIpRangeStart: this.options.vpnConfig.bridgeIpRangeStart,
1754
+ bridgeIpRangeEnd: this.options.vpnConfig.bridgeIpRangeEnd,
1755
+ onClientChanged: () => {
1756
+ // Re-apply routes so profile-based ipAllowLists get updated
1757
+ // (serialized by RouteConfigManager's mutex — safe as fire-and-forget)
1758
+ this.routeConfigManager?.applyRoutes().catch((err) => {
1759
+ logger.log('warn', `Failed to re-apply routes after VPN client change: ${err?.message || err}`);
1760
+ });
1761
+ },
1762
+ getClientDirectTargets: (targetProfileIds) => {
1763
+ if (!this.targetProfileManager)
1764
+ return [];
1765
+ return this.targetProfileManager.getDirectTargetIps(targetProfileIds);
1766
+ },
1767
+ getClientAllowedIPs: async (targetProfileIds) => {
1768
+ const subnet = this.options.vpnConfig?.subnet || '10.8.0.0/24';
1769
+ const ips = new Set([subnet]);
1770
+ if (!this.targetProfileManager)
1771
+ return [...ips];
1772
+ const allRoutes = this.routeConfigManager?.getRoutes() || new Map();
1773
+ const { domains, targetIps } = this.targetProfileManager.getClientAccessSpec(targetProfileIds, allRoutes);
1774
+ // Add target IPs directly
1775
+ for (const ip of targetIps) {
1776
+ ips.add(`${ip}/32`);
1777
+ }
1778
+ // Resolve DNS A records for matched domains (with caching)
1779
+ for (const domain of domains) {
1780
+ const stripped = domain.replace(/^\*\./, '');
1781
+ const resolvedIps = await this.resolveVpnDomainIPs(stripped);
1782
+ for (const ip of resolvedIps) {
1783
+ ips.add(`${ip}/32`);
1784
+ }
1785
+ }
1786
+ return [...ips];
1787
+ },
1788
+ });
1789
+ await this.vpnManager.start();
1790
+ // Re-apply routes now that VPN clients are loaded — ensures vpnOnly routes
1791
+ // get correct profile-based ipAllowLists
1792
+ await this.routeConfigManager?.applyRoutes();
1793
+ }
1794
+ /** Cache for DNS-resolved IPs of VPN-gated domains. TTL: 5 minutes. */
1795
+ vpnDomainIpCache = new Map();
1796
+ /**
1797
+ * Resolve a domain's A record(s) for VPN AllowedIPs, with a 5-minute cache.
1798
+ */
1799
+ async resolveVpnDomainIPs(domain) {
1800
+ const cached = this.vpnDomainIpCache.get(domain);
1801
+ if (cached && cached.expiresAt > Date.now()) {
1802
+ return cached.ips;
1803
+ }
1804
+ try {
1805
+ const { promises: dnsPromises } = await import('dns');
1806
+ const ips = await dnsPromises.resolve4(domain);
1807
+ this.vpnDomainIpCache.set(domain, { ips, expiresAt: Date.now() + 5 * 60 * 1000 });
1808
+ // Evict oldest entries if cache exceeds 1000 entries
1809
+ if (this.vpnDomainIpCache.size > 1000) {
1810
+ const firstKey = this.vpnDomainIpCache.keys().next().value;
1811
+ if (firstKey)
1812
+ this.vpnDomainIpCache.delete(firstKey);
1813
+ }
1814
+ return ips;
1815
+ }
1816
+ catch (err) {
1817
+ logger.log('warn', `VPN: Failed to resolve ${domain} for AllowedIPs: ${err.message}`);
1818
+ return cached?.ips || []; // Return stale cache on failure, or empty
1819
+ }
1820
+ }
1821
+ // VPN security injection is now handled dynamically by RouteConfigManager.applyRoutes()
1822
+ // via the getVpnAllowList callback — no longer a separate method here.
1823
+ /**
1824
+ * Set up RADIUS server for network authentication
1825
+ */
1826
+ async setupRadiusServer() {
1827
+ if (!this.options.radiusConfig) {
1828
+ return;
1829
+ }
1830
+ logger.log('info', 'Setting up RADIUS server...');
1831
+ this.radiusServer = new RadiusServer(this.options.radiusConfig);
1832
+ await this.radiusServer.start();
1833
+ logger.log('info', `RADIUS server started on ports ${this.options.radiusConfig.authPort || 1812} (auth) and ${this.options.radiusConfig.acctPort || 1813} (acct)`);
1834
+ }
1835
+ /**
1836
+ * Update RADIUS configuration at runtime
1837
+ */
1838
+ async updateRadiusConfig(config) {
1839
+ // Stop existing RADIUS server if running
1840
+ if (this.radiusServer) {
1841
+ await this.radiusServer.stop();
1842
+ this.radiusServer = undefined;
1843
+ }
1844
+ // Update configuration
1845
+ this.options.radiusConfig = config;
1846
+ // Start with new configuration
1847
+ await this.setupRadiusServer();
1848
+ logger.log('info', 'RADIUS configuration updated');
1849
+ }
1850
+ }
1851
+ export default DcRouter;
1852
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY2xhc3Nlcy5kY3JvdXRlci5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3RzL2NsYXNzZXMuZGNyb3V0ZXIudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxLQUFLLE9BQU8sTUFBTSxjQUFjLENBQUM7QUFDeEMsT0FBTyxLQUFLLEtBQUssTUFBTSxZQUFZLENBQUM7QUFFcEMsc0RBQXNEO0FBRXRELDhEQUE4RDtBQUM5RCxPQUFPLEVBQ0wsa0JBQWtCLEdBSW5CLE1BQU0sc0JBQXNCLENBQUM7QUFDOUIsT0FBTyxFQUFFLE1BQU0sRUFBRSxNQUFNLGFBQWEsQ0FBQztBQUNyQyxPQUFPLEVBQUUsd0JBQXdCLEVBQUUsTUFBTSxtQ0FBbUMsQ0FBQztBQUM3RSxPQUFPLEVBQUUsc0JBQXNCLEVBQUUsTUFBTSx1Q0FBdUMsQ0FBQztBQUMvRSwwQkFBMEI7QUFDMUIsT0FBTyxFQUFFLFVBQVUsRUFBMEIsWUFBWSxFQUFFLFlBQVksRUFBRSxXQUFXLEVBQUUsTUFBTSxlQUFlLENBQUM7QUFDNUcsMENBQTBDO0FBQzFDLE9BQU8sRUFBRSxxQkFBcUIsRUFBRSxNQUFNLDJCQUEyQixDQUFDO0FBQ2xFLE9BQU8sRUFBRSxVQUFVLEVBQUUsTUFBTSx5QkFBeUIsQ0FBQztBQUVyRCxPQUFPLEVBQUUsU0FBUyxFQUFFLE1BQU0sc0JBQXNCLENBQUM7QUFDakQsT0FBTyxFQUFFLGNBQWMsRUFBRSxNQUFNLHVCQUF1QixDQUFDO0FBQ3ZELE9BQU8sRUFBRSxZQUFZLEVBQTRCLE1BQU0sbUJBQW1CLENBQUM7QUFDM0UsT0FBTyxFQUFFLG9CQUFvQixFQUFFLGFBQWEsRUFBRSxNQUFNLDBCQUEwQixDQUFDO0FBQy9FLE9BQU8sRUFBRSxVQUFVLEVBQTBCLE1BQU0sZ0JBQWdCLENBQUM7QUFDcEUsT0FBTyxFQUFFLGtCQUFrQixFQUFFLGVBQWUsRUFBRSxpQkFBaUIsRUFBRSxRQUFRLEVBQUUsb0JBQW9CLEVBQUUsTUFBTSxtQkFBbUIsQ0FB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