@tapflowio/relay 0.8.2 → 0.9.1

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 (214) hide show
  1. package/dist/RelayServer.d.ts +10 -0
  2. package/dist/RelayServer.d.ts.map +1 -1
  3. package/dist/RelayServer.js +53 -5
  4. package/dist/RelayServer.js.map +1 -1
  5. package/dist/api/builds.d.ts.map +1 -1
  6. package/dist/api/builds.js +14 -13
  7. package/dist/api/builds.js.map +1 -1
  8. package/dist/api/comments.d.ts.map +1 -1
  9. package/dist/api/comments.js +23 -10
  10. package/dist/api/comments.js.map +1 -1
  11. package/dist/api/team.d.ts.map +1 -1
  12. package/dist/api/team.js +4 -2
  13. package/dist/api/team.js.map +1 -1
  14. package/dist/index.d.ts +7 -1
  15. package/dist/index.d.ts.map +1 -1
  16. package/dist/index.js +3 -1
  17. package/dist/index.js.map +1 -1
  18. package/dist/lib/cert/AcmeCertProvider.d.ts +55 -0
  19. package/dist/lib/cert/AcmeCertProvider.d.ts.map +1 -0
  20. package/dist/lib/cert/AcmeCertProvider.js +62 -0
  21. package/dist/lib/cert/AcmeCertProvider.js.map +1 -0
  22. package/dist/lib/cert/AcmeClientIssuer.d.ts +23 -0
  23. package/dist/lib/cert/AcmeClientIssuer.d.ts.map +1 -0
  24. package/dist/lib/cert/AcmeClientIssuer.js +54 -0
  25. package/dist/lib/cert/AcmeClientIssuer.js.map +1 -0
  26. package/dist/lib/cert/CertProvider.d.ts +30 -0
  27. package/dist/lib/cert/CertProvider.d.ts.map +1 -0
  28. package/dist/lib/cert/CertProvider.js +4 -0
  29. package/dist/lib/cert/CertProvider.js.map +1 -0
  30. package/dist/lib/cert/CloudflareDnsProvider.d.ts +40 -0
  31. package/dist/lib/cert/CloudflareDnsProvider.d.ts.map +1 -0
  32. package/dist/lib/cert/CloudflareDnsProvider.js +93 -0
  33. package/dist/lib/cert/CloudflareDnsProvider.js.map +1 -0
  34. package/dist/lib/cert/DiskCertStore.d.ts +10 -0
  35. package/dist/lib/cert/DiskCertStore.d.ts.map +1 -0
  36. package/dist/lib/cert/DiskCertStore.js +35 -0
  37. package/dist/lib/cert/DiskCertStore.js.map +1 -0
  38. package/dist/lib/cert/DnsProvider.d.ts +7 -0
  39. package/dist/lib/cert/DnsProvider.d.ts.map +1 -0
  40. package/dist/lib/cert/DnsProvider.js +2 -0
  41. package/dist/lib/cert/DnsProvider.js.map +1 -0
  42. package/dist/lib/cert/ImportCertProvider.d.ts +20 -0
  43. package/dist/lib/cert/ImportCertProvider.d.ts.map +1 -0
  44. package/dist/lib/cert/ImportCertProvider.js +24 -0
  45. package/dist/lib/cert/ImportCertProvider.js.map +1 -0
  46. package/dist/lib/cert/VercelDnsProvider.d.ts +38 -0
  47. package/dist/lib/cert/VercelDnsProvider.d.ts.map +1 -0
  48. package/dist/lib/cert/VercelDnsProvider.js +146 -0
  49. package/dist/lib/cert/VercelDnsProvider.js.map +1 -0
  50. package/dist/lib/cert/accountKey.d.ts +2 -0
  51. package/dist/lib/cert/accountKey.d.ts.map +1 -0
  52. package/dist/lib/cert/accountKey.js +23 -0
  53. package/dist/lib/cert/accountKey.js.map +1 -0
  54. package/dist/lib/cert/addressPublisher.d.ts +20 -0
  55. package/dist/lib/cert/addressPublisher.d.ts.map +1 -0
  56. package/dist/lib/cert/addressPublisher.js +103 -0
  57. package/dist/lib/cert/addressPublisher.js.map +1 -0
  58. package/dist/lib/cert/createCertProvider.d.ts +20 -0
  59. package/dist/lib/cert/createCertProvider.d.ts.map +1 -0
  60. package/dist/lib/cert/createCertProvider.js +25 -0
  61. package/dist/lib/cert/createCertProvider.js.map +1 -0
  62. package/dist/lib/cert/dnsRegistry.d.ts +24 -0
  63. package/dist/lib/cert/dnsRegistry.d.ts.map +1 -0
  64. package/dist/lib/cert/dnsRegistry.js +36 -0
  65. package/dist/lib/cert/dnsRegistry.js.map +1 -0
  66. package/dist/lib/cert/index.d.ts +23 -0
  67. package/dist/lib/cert/index.d.ts.map +1 -0
  68. package/dist/lib/cert/index.js +12 -0
  69. package/dist/lib/cert/index.js.map +1 -0
  70. package/dist/lib/cert/parseCert.d.ts +3 -0
  71. package/dist/lib/cert/parseCert.d.ts.map +1 -0
  72. package/dist/lib/cert/parseCert.js +6 -0
  73. package/dist/lib/cert/parseCert.js.map +1 -0
  74. package/dist/lib/cert/renewal.d.ts +13 -0
  75. package/dist/lib/cert/renewal.d.ts.map +1 -0
  76. package/dist/lib/cert/renewal.js +28 -0
  77. package/dist/lib/cert/renewal.js.map +1 -0
  78. package/dist/lib/config.d.ts +23 -0
  79. package/dist/lib/config.d.ts.map +1 -1
  80. package/dist/lib/config.js +51 -3
  81. package/dist/lib/config.js.map +1 -1
  82. package/dist/lib/cors.d.ts +2 -0
  83. package/dist/lib/cors.d.ts.map +1 -0
  84. package/dist/lib/cors.js +18 -0
  85. package/dist/lib/cors.js.map +1 -0
  86. package/dist/lib/csrf.d.ts +3 -0
  87. package/dist/lib/csrf.d.ts.map +1 -0
  88. package/dist/lib/csrf.js +42 -0
  89. package/dist/lib/csrf.js.map +1 -0
  90. package/dist/lib/loadEnvFile.d.ts +2 -0
  91. package/dist/lib/loadEnvFile.d.ts.map +1 -0
  92. package/dist/lib/loadEnvFile.js +19 -0
  93. package/dist/lib/loadEnvFile.js.map +1 -0
  94. package/dist/lib/proxyConfig.d.ts +6 -0
  95. package/dist/lib/proxyConfig.d.ts.map +1 -0
  96. package/dist/lib/proxyConfig.js +27 -0
  97. package/dist/lib/proxyConfig.js.map +1 -0
  98. package/dist/lib/publicUrl.d.ts +3 -0
  99. package/dist/lib/publicUrl.d.ts.map +1 -0
  100. package/dist/lib/publicUrl.js +17 -0
  101. package/dist/lib/publicUrl.js.map +1 -0
  102. package/dist/lib/uploads.d.ts +2 -0
  103. package/dist/lib/uploads.d.ts.map +1 -0
  104. package/dist/lib/uploads.js +14 -0
  105. package/dist/lib/uploads.js.map +1 -0
  106. package/dist/router.d.ts.map +1 -1
  107. package/dist/router.js +13 -1
  108. package/dist/router.js.map +1 -1
  109. package/dist/server.js +43 -6
  110. package/dist/server.js.map +1 -1
  111. package/package.json +9 -8
  112. package/public/assets/AppCenter-CH3MXel8.js +16 -0
  113. package/public/assets/AppCenter-CH3MXel8.js.br +0 -0
  114. package/public/assets/Default-CK_yhJO6.js +1 -0
  115. package/public/assets/Default-CK_yhJO6.js.br +0 -0
  116. package/public/assets/Invite-9g1gI701.js +1 -0
  117. package/public/assets/Invite-9g1gI701.js.br +0 -0
  118. package/public/assets/MacResources-41d3_9X2.js +5 -0
  119. package/public/assets/MacResources-41d3_9X2.js.br +0 -0
  120. package/public/assets/NotFound-DsMP9eZN.js +1 -0
  121. package/public/assets/NotFound-DsMP9eZN.js.br +2 -0
  122. package/public/assets/QASession-B02bILlB.js +130 -0
  123. package/public/assets/QASession-B02bILlB.js.br +0 -0
  124. package/public/assets/ResetPassword-DsXsNFTA.js +1 -0
  125. package/public/assets/ResetPassword-DsXsNFTA.js.br +0 -0
  126. package/public/assets/Setup-CouJNq4v.js +1 -0
  127. package/public/assets/Setup-CouJNq4v.js.br +0 -0
  128. package/public/assets/Team-DUG0YTtb.js +6 -0
  129. package/public/assets/Team-DUG0YTtb.js.br +0 -0
  130. package/public/assets/Tokens-BWBEl4ax.js +6 -0
  131. package/public/assets/Tokens-BWBEl4ax.js.br +0 -0
  132. package/public/assets/alert-dialog-qlHDtr4B.js +1 -0
  133. package/public/assets/alert-dialog-qlHDtr4B.js.br +0 -0
  134. package/public/assets/badge-Cx2-XXcg.js +1 -0
  135. package/public/assets/badge-Cx2-XXcg.js.br +0 -0
  136. package/public/assets/build-format-BvNznvYq.js +11 -0
  137. package/public/assets/build-format-BvNznvYq.js.br +0 -0
  138. package/public/assets/dialog-DzNUT3NF.js +11 -0
  139. package/public/assets/dialog-DzNUT3NF.js.br +0 -0
  140. package/public/assets/index-BI7E3MD-.css +1 -0
  141. package/public/assets/index-BI7E3MD-.css.br +0 -0
  142. package/public/assets/index-Dfs85Uiw.js +274 -0
  143. package/public/assets/index-Dfs85Uiw.js.br +0 -0
  144. package/public/assets/inter-latin-ext-standard-normal-DpK-iCPk.woff2 +0 -0
  145. package/public/assets/inter-latin-standard-normal-BwkfbSeq.woff2 +0 -0
  146. package/public/assets/jetbrains-mono-latin-ext-wght-normal-DBQx-q_a.woff2 +0 -0
  147. package/public/assets/jetbrains-mono-latin-wght-normal-B9CIFXIH.woff2 +0 -0
  148. package/public/assets/pencil-CrO7Me4O.js +6 -0
  149. package/public/assets/pencil-CrO7Me4O.js.br +0 -0
  150. package/public/assets/plus-DnAOz8DL.js +6 -0
  151. package/public/assets/plus-DnAOz8DL.js.br +0 -0
  152. package/public/assets/table-BXnp_tRt.js +1 -0
  153. package/public/assets/table-BXnp_tRt.js.br +0 -0
  154. package/public/assets/tabs-BTnhanO2.js +1 -0
  155. package/public/assets/tabs-BTnhanO2.js.br +0 -0
  156. package/public/assets/tinyh264.worker-DiJ50Hai.js.br +0 -0
  157. package/public/favicon.svg.br +0 -0
  158. package/public/index.html +2 -2
  159. package/public/index.html.br +0 -0
  160. package/public/logo-dark.svg.br +0 -0
  161. package/public/logo.svg.br +0 -0
  162. package/public/assets/index-Bhoumejm.js +0 -520
  163. package/public/assets/index-DX5Pf9T6.css +0 -1
  164. package/public/assets/inter-cyrillic-400-normal-HOLc17fK.woff +0 -0
  165. package/public/assets/inter-cyrillic-400-normal-obahsSVq.woff2 +0 -0
  166. package/public/assets/inter-cyrillic-500-normal-BasfLYem.woff2 +0 -0
  167. package/public/assets/inter-cyrillic-500-normal-CxZf_p3X.woff +0 -0
  168. package/public/assets/inter-cyrillic-600-normal-4D_pXhcN.woff +0 -0
  169. package/public/assets/inter-cyrillic-600-normal-CWCymEST.woff2 +0 -0
  170. package/public/assets/inter-cyrillic-ext-400-normal-BQZuk6qB.woff2 +0 -0
  171. package/public/assets/inter-cyrillic-ext-400-normal-DQukG94-.woff +0 -0
  172. package/public/assets/inter-cyrillic-ext-500-normal-B0yAr1jD.woff2 +0 -0
  173. package/public/assets/inter-cyrillic-ext-500-normal-BmqWE9Dz.woff +0 -0
  174. package/public/assets/inter-cyrillic-ext-600-normal-Bcila6Z-.woff +0 -0
  175. package/public/assets/inter-cyrillic-ext-600-normal-Dfes3d0z.woff2 +0 -0
  176. package/public/assets/inter-greek-400-normal-B4URO6DV.woff2 +0 -0
  177. package/public/assets/inter-greek-400-normal-q2sYcFCs.woff +0 -0
  178. package/public/assets/inter-greek-500-normal-BIZE56-Y.woff2 +0 -0
  179. package/public/assets/inter-greek-500-normal-Xzm54t5V.woff +0 -0
  180. package/public/assets/inter-greek-600-normal-BZpKdvQh.woff +0 -0
  181. package/public/assets/inter-greek-600-normal-plRanbMR.woff2 +0 -0
  182. package/public/assets/inter-greek-ext-400-normal-DGGRlc-M.woff2 +0 -0
  183. package/public/assets/inter-greek-ext-400-normal-KugGGMne.woff +0 -0
  184. package/public/assets/inter-greek-ext-500-normal-2j5mBUwD.woff +0 -0
  185. package/public/assets/inter-greek-ext-500-normal-C4iEst2y.woff2 +0 -0
  186. package/public/assets/inter-greek-ext-600-normal-B8X0CLgF.woff +0 -0
  187. package/public/assets/inter-greek-ext-600-normal-DRtmH8MT.woff2 +0 -0
  188. package/public/assets/inter-latin-400-normal-C38fXH4l.woff2 +0 -0
  189. package/public/assets/inter-latin-400-normal-CyCys3Eg.woff +0 -0
  190. package/public/assets/inter-latin-500-normal-BL9OpVg8.woff +0 -0
  191. package/public/assets/inter-latin-500-normal-Cerq10X2.woff2 +0 -0
  192. package/public/assets/inter-latin-600-normal-CiBQ2DWP.woff +0 -0
  193. package/public/assets/inter-latin-600-normal-LgqL8muc.woff2 +0 -0
  194. package/public/assets/inter-latin-ext-400-normal-77YHD8bZ.woff +0 -0
  195. package/public/assets/inter-latin-ext-400-normal-C1nco2VV.woff2 +0 -0
  196. package/public/assets/inter-latin-ext-500-normal-BxGbmqWO.woff +0 -0
  197. package/public/assets/inter-latin-ext-500-normal-CV4jyFjo.woff2 +0 -0
  198. package/public/assets/inter-latin-ext-600-normal-CIVaiw4L.woff +0 -0
  199. package/public/assets/inter-latin-ext-600-normal-D2bJ5OIk.woff2 +0 -0
  200. package/public/assets/inter-vietnamese-400-normal-Bbgyi5SW.woff +0 -0
  201. package/public/assets/inter-vietnamese-400-normal-DMkecbls.woff2 +0 -0
  202. package/public/assets/inter-vietnamese-500-normal-DOriooB6.woff2 +0 -0
  203. package/public/assets/inter-vietnamese-500-normal-mJboJaSs.woff +0 -0
  204. package/public/assets/inter-vietnamese-600-normal-BuLX-rYi.woff +0 -0
  205. package/public/assets/inter-vietnamese-600-normal-Cc8MFFhd.woff2 +0 -0
  206. package/public/assets/jetbrains-mono-cyrillic-400-normal-BEIGL1Tu.woff2 +0 -0
  207. package/public/assets/jetbrains-mono-cyrillic-400-normal-ugxPyKxw.woff +0 -0
  208. package/public/assets/jetbrains-mono-greek-400-normal-B9oWc5Lo.woff +0 -0
  209. package/public/assets/jetbrains-mono-greek-400-normal-C190GLew.woff2 +0 -0
  210. package/public/assets/jetbrains-mono-latin-400-normal-6-qcROiO.woff +0 -0
  211. package/public/assets/jetbrains-mono-latin-400-normal-V6pRDFza.woff2 +0 -0
  212. package/public/assets/jetbrains-mono-latin-ext-400-normal-Bc8Ftmh3.woff2 +0 -0
  213. package/public/assets/jetbrains-mono-latin-ext-400-normal-fXTG6kC5.woff +0 -0
  214. package/public/assets/jetbrains-mono-vietnamese-400-normal-CqNFfHCs.woff +0 -0
@@ -22,6 +22,17 @@ declare const configSchema: z.ZodObject<{
22
22
  provider: z.ZodLiteral<"tailscale">;
23
23
  publicUrl: z.ZodOptional<z.ZodString>;
24
24
  }, z.core.$strip>], "provider">>;
25
+ tls: z.ZodNullable<z.ZodDiscriminatedUnion<[z.ZodObject<{
26
+ mode: z.ZodLiteral<"byo-api-token">;
27
+ domain: z.ZodString;
28
+ dnsProvider: z.ZodString;
29
+ publishAddress: z.ZodOptional<z.ZodBoolean>;
30
+ address: z.ZodOptional<z.ZodString>;
31
+ }, z.core.$strip>, z.ZodObject<{
32
+ mode: z.ZodLiteral<"import-cert">;
33
+ certPath: z.ZodString;
34
+ keyPath: z.ZodString;
35
+ }, z.core.$strip>], "mode">>;
25
36
  smtp: z.ZodObject<{
26
37
  host: z.ZodString;
27
38
  port: z.ZodNumber;
@@ -32,6 +43,7 @@ declare const configSchema: z.ZodObject<{
32
43
  }, z.core.$strip>;
33
44
  }, z.core.$strip>;
34
45
  export type TapflowConfig = z.infer<typeof configSchema>;
46
+ export declare let loadedEnvPath: string | null;
35
47
  export declare function loadOrCreatePersistedSecret(dataDir: string): string;
36
48
  export declare const config: {
37
49
  local: {
@@ -56,6 +68,17 @@ export declare const config: {
56
68
  provider: "tailscale";
57
69
  publicUrl?: string | undefined;
58
70
  } | null;
71
+ tls: {
72
+ mode: "byo-api-token";
73
+ domain: string;
74
+ dnsProvider: string;
75
+ publishAddress?: boolean | undefined;
76
+ address?: string | undefined;
77
+ } | {
78
+ mode: "import-cert";
79
+ certPath: string;
80
+ keyPath: string;
81
+ } | null;
59
82
  smtp: {
60
83
  host: string;
61
84
  port: number;
@@ -1 +1 @@
1
- {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/lib/config.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AA0BvB,QAAA,MAAM,YAAY;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAmBhB,CAAA;AAEF,MAAM,MAAM,aAAa,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,YAAY,CAAC,CAAA;AA8GxD,wBAAgB,2BAA2B,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAkBnE;AAaD,eAAO,MAAM,MAAM;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAAS,CAAA;AAC5B,eAAO,MAAM,SAAS,QAAkB,CAAA"}
1
+ {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/lib/config.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AAmDvB,QAAA,MAAM,YAAY;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAoBhB,CAAA;AAEF,MAAM,MAAM,aAAa,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,YAAY,CAAC,CAAA;AA+BxD,eAAO,IAAI,aAAa,EAAE,MAAM,GAAG,IAAW,CAAA;AA4G9C,wBAAgB,2BAA2B,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAkBnE;AAaD,eAAO,MAAM,MAAM;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAAS,CAAA;AAC5B,eAAO,MAAM,SAAS,QAAkB,CAAA"}
@@ -4,6 +4,8 @@ import crypto from 'crypto';
4
4
  import { z } from 'zod';
5
5
  import { createLogger } from '@tapflowio/agent-core';
6
6
  import { parseTrustedProxies } from './clientAddress.js';
7
+ import { dnsProviders } from './cert/dnsRegistry.js';
8
+ import { loadDataDirEnv } from './loadEnvFile.js';
7
9
  const logger = createLogger('relay:config');
8
10
  const tunnelSshSchema = z.object({
9
11
  host: z.string().min(1),
@@ -21,6 +23,26 @@ const tailscaleTunnelSchema = z.object({
21
23
  publicUrl: z.string().optional(),
22
24
  });
23
25
  const tunnelSchema = z.discriminatedUnion('provider', [ratholeTunnelSchema, tailscaleTunnelSchema]);
26
+ // LAN HTTPS (issue #232) — secure context용 TLS 종단 설정. 골격: v1은 LAN 가지만 구현.
27
+ // 비밀(DNS API 토큰)은 config 파일이 아니라 env에서 읽는다(예: TAPFLOW_CLOUDFLARE_TOKEN).
28
+ const importCertTlsSchema = z.object({
29
+ mode: z.literal('import-cert'),
30
+ certPath: z.string().min(1),
31
+ keyPath: z.string().min(1),
32
+ });
33
+ const byoApiTokenTlsSchema = z.object({
34
+ mode: z.literal('byo-api-token'),
35
+ domain: z.string().min(1),
36
+ // 유효 provider는 레지스트리가 정한다(새 provider 추가 시 스키마 무변경).
37
+ dnsProvider: z.string().min(1).refine((n) => dnsProviders.has(n), {
38
+ message: `unknown dnsProvider (available: ${dnsProviders.names().join(', ')})`,
39
+ }),
40
+ // 도메인 A 레코드를 LAN IP로 자동 발행(기본 ON). false면 사용자가 직접 관리.
41
+ publishAddress: z.boolean().optional(),
42
+ // 자동 감지 대신 쓸 고정 LAN IP(멀티NIC/VPN 환경 오버라이드).
43
+ address: z.string().min(1).optional(),
44
+ });
45
+ const tlsSchema = z.discriminatedUnion('mode', [byoApiTokenTlsSchema, importCertTlsSchema]);
24
46
  const configSchema = z.object({
25
47
  local: z.object({
26
48
  port: z.number().int().min(1).max(65535),
@@ -32,6 +54,7 @@ const configSchema = z.object({
32
54
  url: z.string().nullable(),
33
55
  }),
34
56
  tunnel: tunnelSchema.nullable(),
57
+ tls: tlsSchema.nullable(),
35
58
  smtp: z.object({
36
59
  host: z.string(),
37
60
  port: z.number().int().min(1).max(65535),
@@ -52,6 +75,7 @@ const DEFAULTS = {
52
75
  url: null,
53
76
  },
54
77
  tunnel: null,
78
+ tls: null,
55
79
  smtp: {
56
80
  host: '',
57
81
  port: 587,
@@ -64,6 +88,8 @@ const DEFAULTS = {
64
88
  function resolveDataDir(raw) {
65
89
  return path.isAbsolute(raw) ? raw : path.join(process.cwd(), raw);
66
90
  }
91
+ // Populated by load(): path of the dataDir/.env that was loaded, or null. CLI/server use it for a "loaded credentials" log.
92
+ export let loadedEnvPath = null;
67
93
  function load() {
68
94
  let file = {};
69
95
  const configPath = path.join(process.cwd(), 'tapflow.config.json');
@@ -78,10 +104,17 @@ function load() {
78
104
  if (file.local != null && 'jwtSecret' in file.local) {
79
105
  logger.warn('local.jwtSecret in tapflow.config.json is deprecated — use JWT_SECRET env var instead');
80
106
  }
107
+ // Resolve dataDir first, then load <dataDir>/.env, so every secret read below (JWT_SECRET, SMTP,
108
+ // DNS/ACME tokens) defaults to the .env file. dataDir itself can't come from .env (chicken-and-egg):
109
+ // it's set only by config.json or TAPFLOW_DATA_DIR. ambient process.env still wins over the file.
110
+ let dataDir = resolveDataDir(file.local?.dataDir ?? DEFAULTS.local.dataDir);
111
+ if (process.env.TAPFLOW_DATA_DIR)
112
+ dataDir = resolveDataDir(process.env.TAPFLOW_DATA_DIR);
113
+ loadedEnvPath = loadDataDirEnv(dataDir);
81
114
  const cfg = {
82
115
  local: {
83
116
  port: file.local?.port ?? DEFAULTS.local.port,
84
- dataDir: resolveDataDir(file.local?.dataDir ?? DEFAULTS.local.dataDir),
117
+ dataDir,
85
118
  wsBackpressureBytes: DEFAULTS.local.wsBackpressureBytes,
86
119
  trustedProxies: parseTrustedProxies(process.env.TAPFLOW_TRUSTED_PROXIES),
87
120
  },
@@ -105,6 +138,22 @@ function load() {
105
138
  : null,
106
139
  };
107
140
  })(),
141
+ tls: (() => {
142
+ if (file.tls == null)
143
+ return null;
144
+ const t = file.tls;
145
+ if (t.mode === 'import-cert') {
146
+ return { mode: 'import-cert', certPath: t.certPath ?? '', keyPath: t.keyPath ?? '' };
147
+ }
148
+ // Pass mode/provider through (no silent default) so zod rejects a missing/misspelled provider.
149
+ return {
150
+ mode: t.mode,
151
+ domain: t.domain ?? '',
152
+ dnsProvider: t.dnsProvider ?? '',
153
+ ...(t.publishAddress !== undefined ? { publishAddress: t.publishAddress } : {}),
154
+ ...(t.address !== undefined ? { address: t.address } : {}),
155
+ };
156
+ })(),
108
157
  smtp: {
109
158
  host: file.smtp?.host ?? DEFAULTS.smtp.host,
110
159
  port: file.smtp?.port ?? DEFAULTS.smtp.port,
@@ -116,8 +165,7 @@ function load() {
116
165
  };
117
166
  if (process.env.TAPFLOW_PORT)
118
167
  cfg.local.port = Number(process.env.TAPFLOW_PORT);
119
- if (process.env.TAPFLOW_DATA_DIR)
120
- cfg.local.dataDir = resolveDataDir(process.env.TAPFLOW_DATA_DIR);
168
+ // TAPFLOW_DATA_DIR is already applied above (before the .env load) — it can't be set from .env.
121
169
  if (process.env.TAPFLOW_WS_BACKPRESSURE_BYTES)
122
170
  cfg.local.wsBackpressureBytes = Number(process.env.TAPFLOW_WS_BACKPRESSURE_BYTES);
123
171
  if (process.env.TAPFLOW_RELAY_URL)
@@ -1 +1 @@
1
- {"version":3,"file":"config.js","sourceRoot":"","sources":["../../src/lib/config.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"config.js","sourceRoot":"","sources":["../../src/lib/config.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export declare function resolveCorsHeaders(origin: string | undefined, allowedOrigins: Set<string>): Record<string, string> | null;
2
+ //# sourceMappingURL=cors.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cors.d.ts","sourceRoot":"","sources":["../../src/lib/cors.ts"],"names":[],"mappings":"AAKA,wBAAgB,kBAAkB,CAChC,MAAM,EAAE,MAAM,GAAG,SAAS,EAC1B,cAAc,EAAE,GAAG,CAAC,MAAM,CAAC,GAC1B,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,IAAI,CAS/B"}
@@ -0,0 +1,18 @@
1
+ // #4 — CORS 출처 제한.
2
+ // 기존엔 모든 응답에 `Access-Control-Allow-Origin: *` + `Allow-Headers: Authorization`을 줘서,
3
+ // PAT(Authorization 헤더)를 cross-origin 스크립트에서 사용할 수 있었다. 허용 출처 allowlist에
4
+ // 든 origin만 에코하고, 그 외에는 CORS 헤더를 부여하지 않는다(브라우저가 cross-origin을 차단).
5
+ // same-origin 요청과 비-브라우저(CLI/서버-서버, Origin 헤더 없음)는 CORS와 무관하게 그대로 동작한다.
6
+ export function resolveCorsHeaders(origin, allowedOrigins) {
7
+ if (!origin)
8
+ return null;
9
+ if (!allowedOrigins.has(origin))
10
+ return null;
11
+ return {
12
+ 'Access-Control-Allow-Origin': origin,
13
+ 'Vary': 'Origin',
14
+ 'Access-Control-Allow-Headers': 'Content-Type, Authorization',
15
+ 'Access-Control-Allow-Methods': 'GET, POST, PATCH, DELETE, OPTIONS',
16
+ };
17
+ }
18
+ //# sourceMappingURL=cors.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cors.js","sourceRoot":"","sources":["../../src/lib/cors.ts"],"names":[],"mappings":"AAAA,mBAAmB;AACnB,oFAAoF;AACpF,yEAAyE;AACzE,mEAAmE;AACnE,wEAAwE;AACxE,MAAM,UAAU,kBAAkB,CAChC,MAA0B,EAC1B,cAA2B;IAE3B,IAAI,CAAC,MAAM;QAAE,OAAO,IAAI,CAAA;IACxB,IAAI,CAAC,cAAc,CAAC,GAAG,CAAC,MAAM,CAAC;QAAE,OAAO,IAAI,CAAA;IAC5C,OAAO;QACL,6BAA6B,EAAE,MAAM;QACrC,MAAM,EAAE,QAAQ;QAChB,8BAA8B,EAAE,6BAA6B;QAC7D,8BAA8B,EAAE,mCAAmC;KACpE,CAAA;AACH,CAAC"}
@@ -0,0 +1,3 @@
1
+ import type http from 'http';
2
+ export declare function isCsrfBlocked(method: string | undefined, headers: http.IncomingHttpHeaders, allowedOrigins: Set<string>): boolean;
3
+ //# sourceMappingURL=csrf.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"csrf.d.ts","sourceRoot":"","sources":["../../src/lib/csrf.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,IAAI,MAAM,MAAM,CAAA;AAkB5B,wBAAgB,aAAa,CAC3B,MAAM,EAAE,MAAM,GAAG,SAAS,EAC1B,OAAO,EAAE,IAAI,CAAC,mBAAmB,EACjC,cAAc,EAAE,GAAG,CAAC,MAAM,CAAC,GAC1B,OAAO,CAoBT"}
@@ -0,0 +1,42 @@
1
+ // #5 — CSRF 경량 가드.
2
+ // 상태 변경 API가 `SameSite=Lax` 쿠키에만 의존하면 일부 cross-site 요청이 통과할 수 있다.
3
+ // 쿠키로 인증된 상태 변경 요청은 Origin이 same-origin(Host 일치)이거나 신뢰 allowlist에 있을 때만
4
+ // 허용하고, 그 외 cross-origin은 차단한다. 브라우저는 상태 변경 요청에 Origin을 강제로 붙이므로
5
+ // 대시보드(same-origin)는 그대로 통과하고, 공격자 origin은 막힌다.
6
+ // 면제: 안전 메서드(GET/HEAD/OPTIONS), PAT 인증(Authorization — 쿠키 자동 전송이 아님),
7
+ // 쿠키 없는 요청(미인증/login/init), Origin 없는 요청(비-브라우저; 브라우저는 cross-site에 Origin을 생략하지 못한다).
8
+ const SAFE_METHODS = new Set(['GET', 'HEAD', 'OPTIONS']);
9
+ // Loopback origins are the local dev machine (e.g. Vite :3001 proxying to the relay :4000), never a
10
+ // remote attacker — a cross-site page can't forge a localhost Origin, so exempting these is safe.
11
+ function isLoopbackHost(hostname) {
12
+ const h = hostname.replace(/^\[|\]$/g, '');
13
+ return h === 'localhost' || h === '127.0.0.1' || h === '::1';
14
+ }
15
+ export function isCsrfBlocked(method, headers, allowedOrigins) {
16
+ if (SAFE_METHODS.has((method ?? 'GET').toUpperCase()))
17
+ return false;
18
+ if (headers['authorization'])
19
+ return false;
20
+ const cookie = headers['cookie'];
21
+ const hasCookieAuth = typeof cookie === 'string' && cookie.includes('tapflow_token=');
22
+ if (!hasCookieAuth)
23
+ return false;
24
+ const origin = headers['origin'];
25
+ if (!origin)
26
+ return false;
27
+ if (allowedOrigins.has(origin))
28
+ return false;
29
+ const host = headers['host'];
30
+ try {
31
+ const url = new URL(origin);
32
+ if (host && url.host === host)
33
+ return false;
34
+ if (isLoopbackHost(url.hostname))
35
+ return false;
36
+ }
37
+ catch {
38
+ // malformed Origin → treat as cross-origin (blocked below)
39
+ }
40
+ return true;
41
+ }
42
+ //# sourceMappingURL=csrf.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"csrf.js","sourceRoot":"","sources":["../../src/lib/csrf.ts"],"names":[],"mappings":"AAEA,mBAAmB;AACnB,kEAAkE;AAClE,wEAAwE;AACxE,iEAAiE;AACjE,gDAAgD;AAChD,sEAAsE;AACtE,4FAA4F;AAC5F,MAAM,YAAY,GAAG,IAAI,GAAG,CAAC,CAAC,KAAK,EAAE,MAAM,EAAE,SAAS,CAAC,CAAC,CAAA;AAExD,oGAAoG;AACpG,kGAAkG;AAClG,SAAS,cAAc,CAAC,QAAgB;IACtC,MAAM,CAAC,GAAG,QAAQ,CAAC,OAAO,CAAC,UAAU,EAAE,EAAE,CAAC,CAAA;IAC1C,OAAO,CAAC,KAAK,WAAW,IAAI,CAAC,KAAK,WAAW,IAAI,CAAC,KAAK,KAAK,CAAA;AAC9D,CAAC;AAED,MAAM,UAAU,aAAa,CAC3B,MAA0B,EAC1B,OAAiC,EACjC,cAA2B;IAE3B,IAAI,YAAY,CAAC,GAAG,CAAC,CAAC,MAAM,IAAI,KAAK,CAAC,CAAC,WAAW,EAAE,CAAC;QAAE,OAAO,KAAK,CAAA;IACnE,IAAI,OAAO,CAAC,eAAe,CAAC;QAAE,OAAO,KAAK,CAAA;IAC1C,MAAM,MAAM,GAAG,OAAO,CAAC,QAAQ,CAAC,CAAA;IAChC,MAAM,aAAa,GAAG,OAAO,MAAM,KAAK,QAAQ,IAAI,MAAM,CAAC,QAAQ,CAAC,gBAAgB,CAAC,CAAA;IACrF,IAAI,CAAC,aAAa;QAAE,OAAO,KAAK,CAAA;IAEhC,MAAM,MAAM,GAAG,OAAO,CAAC,QAAQ,CAAC,CAAA;IAChC,IAAI,CAAC,MAAM;QAAE,OAAO,KAAK,CAAA;IACzB,IAAI,cAAc,CAAC,GAAG,CAAC,MAAM,CAAC;QAAE,OAAO,KAAK,CAAA;IAE5C,MAAM,IAAI,GAAG,OAAO,CAAC,MAAM,CAAC,CAAA;IAC5B,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,MAAM,CAAC,CAAA;QAC3B,IAAI,IAAI,IAAI,GAAG,CAAC,IAAI,KAAK,IAAI;YAAE,OAAO,KAAK,CAAA;QAC3C,IAAI,cAAc,CAAC,GAAG,CAAC,QAAQ,CAAC;YAAE,OAAO,KAAK,CAAA;IAChD,CAAC;IAAC,MAAM,CAAC;QACP,2DAA2D;IAC7D,CAAC;IACD,OAAO,IAAI,CAAA;AACb,CAAC"}
@@ -0,0 +1,2 @@
1
+ export declare function loadDataDirEnv(dataDir: string): string | null;
2
+ //# sourceMappingURL=loadEnvFile.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"loadEnvFile.d.ts","sourceRoot":"","sources":["../../src/lib/loadEnvFile.ts"],"names":[],"mappings":"AAMA,wBAAgB,cAAc,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAU7D"}
@@ -0,0 +1,19 @@
1
+ import fs from 'fs';
2
+ import path from 'path';
3
+ // gitignore된 <dataDir>/.env 에서 자격 증명(JWT_SECRET·SMTP·DNS/ACME 토큰 등)을 로드한다.
4
+ // config.load()가 secret을 읽기 전에 호출되어 .env가 모든 비밀의 기본 경로가 된다(#287에서 시작).
5
+ // process.loadEnvFile 은 기존 process.env 값을 안 덮으므로 ambient(셸) 가 항상 우선.
6
+ export function loadDataDirEnv(dataDir) {
7
+ const envPath = path.join(dataDir, '.env');
8
+ if (!fs.existsSync(envPath))
9
+ return null;
10
+ try {
11
+ process.loadEnvFile(envPath);
12
+ return envPath;
13
+ }
14
+ catch {
15
+ // 손상된 파일은 무시 — 자격 증명이 없으면 cert 발급 시점에 명확히 실패한다.
16
+ return null;
17
+ }
18
+ }
19
+ //# sourceMappingURL=loadEnvFile.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"loadEnvFile.js","sourceRoot":"","sources":["../../src/lib/loadEnvFile.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,IAAI,CAAA;AACnB,OAAO,IAAI,MAAM,MAAM,CAAA;AAEvB,2EAA2E;AAC3E,uEAAuE;AACvE,qEAAqE;AACrE,MAAM,UAAU,cAAc,CAAC,OAAe;IAC5C,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,MAAM,CAAC,CAAA;IAC1C,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,OAAO,CAAC;QAAE,OAAO,IAAI,CAAA;IACxC,IAAI,CAAC;QACH,OAAO,CAAC,WAAW,CAAC,OAAO,CAAC,CAAA;QAC5B,OAAO,OAAO,CAAA;IAChB,CAAC;IAAC,MAAM,CAAC;QACP,gDAAgD;QAChD,OAAO,IAAI,CAAA;IACb,CAAC;AACH,CAAC"}
@@ -0,0 +1,6 @@
1
+ import type { TapflowConfig } from './config.js';
2
+ type ProxyCfg = Pick<TapflowConfig, 'tunnel' | 'relay' | 'local'>;
3
+ export declare function buildCorsOrigins(cfg: ProxyCfg, port: number): string[];
4
+ export declare function proxyWithoutPublicUrlWarning(cfg: ProxyCfg): string | null;
5
+ export {};
6
+ //# sourceMappingURL=proxyConfig.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"proxyConfig.d.ts","sourceRoot":"","sources":["../../src/lib/proxyConfig.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAA;AAGhD,KAAK,QAAQ,GAAG,IAAI,CAAC,aAAa,EAAE,QAAQ,GAAG,OAAO,GAAG,OAAO,CAAC,CAAA;AAGjE,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,EAAE,CAStE;AAGD,wBAAgB,4BAA4B,CAAC,GAAG,EAAE,QAAQ,GAAG,MAAM,GAAG,IAAI,CAQzE"}
@@ -0,0 +1,27 @@
1
+ import { buildInviteBaseUrl } from './publicUrl.js';
2
+ // Allow cross-origin PAT use only from the configured public origin + loopback (LAN is same-origin).
3
+ export function buildCorsOrigins(cfg, port) {
4
+ // Skip buildInviteBaseUrl's localhost fallback — it would allowlist a stale loopback at config.local.port under a different --port.
5
+ const configuredOrigin = (() => {
6
+ if (!cfg.tunnel?.publicUrl && !cfg.relay.url)
7
+ return null;
8
+ try {
9
+ return new URL(buildInviteBaseUrl(cfg)).origin;
10
+ }
11
+ catch {
12
+ return null;
13
+ }
14
+ })();
15
+ const origins = [configuredOrigin, `http://localhost:${port}`, `http://127.0.0.1:${port}`]
16
+ .filter((o) => o !== null);
17
+ return [...new Set(origins)];
18
+ }
19
+ // A proxied/tunneled relay needs a public URL, or the CSRF/CORS allowlist stays loopback-only and blocks proxied POSTs.
20
+ export function proxyWithoutPublicUrlWarning(cfg) {
21
+ if (cfg.local.trustedProxies.length > 0 && !cfg.tunnel?.publicUrl && !cfg.relay.url) {
22
+ return ('TAPFLOW_TRUSTED_PROXIES is set but no public URL (tunnel.publicUrl / relay.url) is configured. ' +
23
+ 'Cross-origin dashboard requests may be blocked by the CSRF guard — set the public URL for proxied deployments.');
24
+ }
25
+ return null;
26
+ }
27
+ //# sourceMappingURL=proxyConfig.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"proxyConfig.js","sourceRoot":"","sources":["../../src/lib/proxyConfig.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,kBAAkB,EAAE,MAAM,gBAAgB,CAAA;AAInD,qGAAqG;AACrG,MAAM,UAAU,gBAAgB,CAAC,GAAa,EAAE,IAAY;IAC1D,oIAAoI;IACpI,MAAM,gBAAgB,GAAG,CAAC,GAAG,EAAE;QAC7B,IAAI,CAAC,GAAG,CAAC,MAAM,EAAE,SAAS,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG;YAAE,OAAO,IAAI,CAAA;QACzD,IAAI,CAAC;YAAC,OAAO,IAAI,GAAG,CAAC,kBAAkB,CAAC,GAAG,CAAC,CAAC,CAAC,MAAM,CAAA;QAAC,CAAC;QAAC,MAAM,CAAC;YAAC,OAAO,IAAI,CAAA;QAAC,CAAC;IAC9E,CAAC,CAAC,EAAE,CAAA;IACJ,MAAM,OAAO,GAAG,CAAC,gBAAgB,EAAE,oBAAoB,IAAI,EAAE,EAAE,oBAAoB,IAAI,EAAE,CAAC;SACvF,MAAM,CAAC,CAAC,CAAC,EAAe,EAAE,CAAC,CAAC,KAAK,IAAI,CAAC,CAAA;IACzC,OAAO,CAAC,GAAG,IAAI,GAAG,CAAC,OAAO,CAAC,CAAC,CAAA;AAC9B,CAAC;AAED,wHAAwH;AACxH,MAAM,UAAU,4BAA4B,CAAC,GAAa;IACxD,IAAI,GAAG,CAAC,KAAK,CAAC,cAAc,CAAC,MAAM,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,MAAM,EAAE,SAAS,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC;QACpF,OAAO,CACL,iGAAiG;YACjG,gHAAgH,CACjH,CAAA;IACH,CAAC;IACD,OAAO,IAAI,CAAA;AACb,CAAC"}
@@ -0,0 +1,3 @@
1
+ import type { TapflowConfig } from './config.js';
2
+ export declare function buildInviteBaseUrl(cfg: Pick<TapflowConfig, 'tunnel' | 'relay' | 'local'>): string;
3
+ //# sourceMappingURL=publicUrl.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"publicUrl.d.ts","sourceRoot":"","sources":["../../src/lib/publicUrl.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAA;AAMhD,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,IAAI,CAAC,aAAa,EAAE,QAAQ,GAAG,OAAO,GAAG,OAAO,CAAC,GAAG,MAAM,CAOjG"}
@@ -0,0 +1,17 @@
1
+ // #6 — 초대/공개 링크의 신뢰 base URL.
2
+ // `req.headers.host`/`x-forwarded-proto`는 클라이언트가 조작할 수 있어(Host 인젝션) 피싱 링크가
3
+ // 정상 메일로 발송될 수 있다. 따라서 Host 헤더 대신 설정값에서만 base를 도출한다.
4
+ // 우선순위: 터널 공개 URL → 설정된 relay URL(ws→http 변환) → localhost 폴백.
5
+ export function buildInviteBaseUrl(cfg) {
6
+ if (cfg.tunnel?.publicUrl)
7
+ return stripTrailingSlash(cfg.tunnel.publicUrl);
8
+ if (cfg.relay.url) {
9
+ const http = cfg.relay.url.replace(/^ws:\/\//i, 'http://').replace(/^wss:\/\//i, 'https://');
10
+ return stripTrailingSlash(http);
11
+ }
12
+ return `http://localhost:${cfg.local.port}`;
13
+ }
14
+ function stripTrailingSlash(u) {
15
+ return u.replace(/\/+$/, '');
16
+ }
17
+ //# sourceMappingURL=publicUrl.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"publicUrl.js","sourceRoot":"","sources":["../../src/lib/publicUrl.ts"],"names":[],"mappings":"AAEA,8BAA8B;AAC9B,2EAA2E;AAC3E,qDAAqD;AACrD,8DAA8D;AAC9D,MAAM,UAAU,kBAAkB,CAAC,GAAsD;IACvF,IAAI,GAAG,CAAC,MAAM,EAAE,SAAS;QAAE,OAAO,kBAAkB,CAAC,GAAG,CAAC,MAAM,CAAC,SAAS,CAAC,CAAA;IAC1E,IAAI,GAAG,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC;QAClB,MAAM,IAAI,GAAG,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,OAAO,CAAC,WAAW,EAAE,SAAS,CAAC,CAAC,OAAO,CAAC,YAAY,EAAE,UAAU,CAAC,CAAA;QAC5F,OAAO,kBAAkB,CAAC,IAAI,CAAC,CAAA;IACjC,CAAC;IACD,OAAO,oBAAoB,GAAG,CAAC,KAAK,CAAC,IAAI,EAAE,CAAA;AAC7C,CAAC;AAED,SAAS,kBAAkB,CAAC,CAAS;IACnC,OAAO,CAAC,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,CAAA;AAC9B,CAAC"}
@@ -0,0 +1,2 @@
1
+ export declare function unlinkSafe(filePath: string, label: string): void;
2
+ //# sourceMappingURL=uploads.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"uploads.d.ts","sourceRoot":"","sources":["../../src/lib/uploads.ts"],"names":[],"mappings":"AAIA,wBAAgB,UAAU,CAAC,QAAQ,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI,CAQhE"}
@@ -0,0 +1,14 @@
1
+ import fs from 'fs';
2
+ // 업로드 정리: 파일을 삭제하되 이미 없으면(ENOENT) 조용히 넘기고, 그 외 에러만 경고한다.
3
+ // builds/comments 업로드 핸들러가 거부·만료된 파일을 정리할 때 공유한다.
4
+ export function unlinkSafe(filePath, label) {
5
+ try {
6
+ fs.unlinkSync(filePath);
7
+ }
8
+ catch (err) {
9
+ if (err.code !== 'ENOENT') {
10
+ console.warn(`[tapflow] failed to delete ${label}`, err.message);
11
+ }
12
+ }
13
+ }
14
+ //# sourceMappingURL=uploads.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"uploads.js","sourceRoot":"","sources":["../../src/lib/uploads.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,IAAI,CAAA;AAEnB,yDAAyD;AACzD,kDAAkD;AAClD,MAAM,UAAU,UAAU,CAAC,QAAgB,EAAE,KAAa;IACxD,IAAI,CAAC;QACH,EAAE,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAA;IACzB,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,IAAK,GAA6B,CAAC,IAAI,KAAK,QAAQ,EAAE,CAAC;YACrD,OAAO,CAAC,IAAI,CAAC,8BAA8B,KAAK,EAAE,EAAG,GAAa,CAAC,OAAO,CAAC,CAAA;QAC7E,CAAC;IACH,CAAC;AACH,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"router.d.ts","sourceRoot":"","sources":["../src/router.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,IAAI,MAAM,MAAM,CAAA;AAE5B,KAAK,OAAO,GAAG,CAAC,GAAG,EAAE,IAAI,CAAC,eAAe,EAAE,GAAG,EAAE,IAAI,CAAC,cAAc,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;AAS5H,qBAAa,MAAM;IACjB,OAAO,CAAC,MAAM,CAAc;IAE5B,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,GAAG,IAAI;IAQxD,GAAG,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO;IAClC,IAAI,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO;IACnC,KAAK,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO;IACpC,MAAM,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO;IAE/B,MAAM,CAAC,GAAG,EAAE,IAAI,CAAC,eAAe,EAAE,GAAG,EAAE,IAAI,CAAC,cAAc,GAAG,OAAO,CAAC,OAAO,CAAC;CAmBpF;AAED,wBAAgB,IAAI,CAAC,GAAG,EAAE,IAAI,CAAC,cAAc,EAAE,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,GAAG,IAAI,CAIlF;AAED,wBAAgB,QAAQ,CAAC,GAAG,EAAE,IAAI,CAAC,eAAe,GAAG,OAAO,CAAC,MAAM,CAAC,CAOnE;AAED,wBAAsB,QAAQ,CAAC,CAAC,GAAG,OAAO,EAAE,GAAG,EAAE,IAAI,CAAC,eAAe,GAAG,OAAO,CAAC,CAAC,CAAC,CAGjF"}
1
+ {"version":3,"file":"router.d.ts","sourceRoot":"","sources":["../src/router.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,IAAI,MAAM,MAAM,CAAA;AAa5B,KAAK,OAAO,GAAG,CAAC,GAAG,EAAE,IAAI,CAAC,eAAe,EAAE,GAAG,EAAE,IAAI,CAAC,cAAc,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;AAS5H,qBAAa,MAAM;IACjB,OAAO,CAAC,MAAM,CAAc;IAE5B,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,GAAG,IAAI;IAQxD,GAAG,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO;IAClC,IAAI,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO;IACnC,KAAK,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO;IACpC,MAAM,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO;IAE/B,MAAM,CAAC,GAAG,EAAE,IAAI,CAAC,eAAe,EAAE,GAAG,EAAE,IAAI,CAAC,cAAc,GAAG,OAAO,CAAC,OAAO,CAAC;CAsBpF;AAED,wBAAgB,IAAI,CAAC,GAAG,EAAE,IAAI,CAAC,cAAc,EAAE,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,GAAG,IAAI,CAIlF;AAED,wBAAgB,QAAQ,CAAC,GAAG,EAAE,IAAI,CAAC,eAAe,GAAG,OAAO,CAAC,MAAM,CAAC,CAOnE;AAED,wBAAsB,QAAQ,CAAC,CAAC,GAAG,OAAO,EAAE,GAAG,EAAE,IAAI,CAAC,eAAe,GAAG,OAAO,CAAC,CAAC,CAAC,CAGjF"}
package/dist/router.js CHANGED
@@ -1,3 +1,12 @@
1
+ import { createLogger } from '@tapflowio/agent-core';
2
+ const logger = createLogger('relay:router');
3
+ // 로그에 토큰이 새지 않도록 마스킹: PAT(tflw_pat_…)와 세션 JWT(eyJ….….…).
4
+ // 메시지·스택뿐 아니라 method/url(경로 파라미터에 토큰이 섞인 경우)까지 포함해 로그 라인 전체에 적용한다.
5
+ function redactSecrets(s) {
6
+ return s
7
+ .replace(/tflw_pat_[A-Za-z0-9_-]+/g, 'tflw_pat_***')
8
+ .replace(/eyJ[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+/g, '[jwt]');
9
+ }
1
10
  export class Router {
2
11
  routes = [];
3
12
  on(method, path, handler) {
@@ -25,7 +34,10 @@ export class Router {
25
34
  try {
26
35
  await route.handler(req, res, params);
27
36
  }
28
- catch (_err) {
37
+ catch (err) {
38
+ // 관측성: 스택을 삼키지 말고 기록한다. 단 응답 본문에는 상세를 노출하지 않는다.
39
+ const detail = err instanceof Error ? (err.stack ?? err.message) : String(err);
40
+ logger.error(redactSecrets(`${method} ${url} — handler error: ${detail}`));
29
41
  json(res, 500, { error: 'Internal server error' });
30
42
  }
31
43
  return true;
@@ -1 +1 @@
1
- {"version":3,"file":"router.js","sourceRoot":"","sources":["../src/router.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"router.js","sourceRoot":"","sources":["../src/router.ts"],"names":[],"mappings":"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"}
package/dist/server.js CHANGED
@@ -1,17 +1,54 @@
1
1
  import path from 'path';
2
2
  import { initDb } from './db.js';
3
3
  import { RelayServer } from './RelayServer.js';
4
- import { config } from './lib/config.js';
4
+ import { config, loadedEnvPath } from './lib/config.js';
5
+ import { buildCorsOrigins, proxyWithoutPublicUrlWarning } from './lib/proxyConfig.js';
6
+ import { createCertProvider, startCertRenewal, startAddressPublisher } from './lib/cert/index.js';
5
7
  import { createLogger } from '@tapflowio/agent-core';
6
8
  const logger = createLogger('relay');
7
9
  const { port, dataDir } = config.local;
10
+ // config loaded <dataDir>/.env before reading any secret (JWT/SMTP/DNS tokens); just report it here.
11
+ if (loadedEnvPath)
12
+ logger.info(`Loaded credentials from ${loadedEnvPath}`);
8
13
  const dbPath = path.join(dataDir, 'tapflow.db');
9
14
  const uploadsDir = path.join(dataDir, 'uploads');
10
15
  initDb(dbPath);
11
- const server = new RelayServer({ port, uploadsDir, wsBackpressureBytes: config.local.wsBackpressureBytes, trustedProxies: config.local.trustedProxies });
12
- void server.start().then(() => {
13
- logger.info(`tapflow relay running on port ${port}`);
16
+ const corsOrigins = buildCorsOrigins(config, port);
17
+ const proxyWarning = proxyWithoutPublicUrlWarning(config);
18
+ if (proxyWarning)
19
+ logger.warn(proxyWarning);
20
+ async function main() {
21
+ let tls;
22
+ let provider = null;
23
+ if (config.tls) {
24
+ provider = createCertProvider(config.tls, { dataDir });
25
+ const material = await provider.ensureCert();
26
+ tls = { cert: material.cert, key: material.key };
27
+ }
28
+ else {
29
+ logger.info('TLS disabled — serving HTTP. Secure-context features (e.g. WebCodecs hardware decode) require HTTPS; ' +
30
+ 'configure tls in tapflow.config.json to enable.');
31
+ }
32
+ const server = new RelayServer({ port, uploadsDir, wsBackpressureBytes: config.local.wsBackpressureBytes, trustedProxies: config.local.trustedProxies, corsOrigins, tls });
33
+ await server.start();
34
+ logger.info(`tapflow relay running on port ${port} (${tls ? 'https' : 'http'})`);
35
+ const stopRenewal = provider
36
+ ? startCertRenewal(provider, { onRenew: (m) => server.updateTlsContext({ cert: m.cert, key: m.key }) })
37
+ : null;
38
+ // byo-api-token: publish the relay's LAN IP to the domain's A record so teammates just open the URL.
39
+ const stopPublish = config.tls?.mode === 'byo-api-token' && config.tls.publishAddress !== false
40
+ ? startAddressPublisher(config.tls)
41
+ : null;
42
+ const shutdown = () => {
43
+ stopRenewal?.();
44
+ stopPublish?.();
45
+ void server.stop().then(() => process.exit(0));
46
+ };
47
+ process.on('SIGTERM', shutdown);
48
+ process.on('SIGINT', shutdown);
49
+ }
50
+ void main().catch((err) => {
51
+ logger.error(`relay failed to start: ${String(err)}`);
52
+ process.exit(1);
14
53
  });
15
- process.on('SIGTERM', () => server.stop().then(() => process.exit(0)));
16
- process.on('SIGINT', () => server.stop().then(() => process.exit(0)));
17
54
  //# sourceMappingURL=server.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"server.js","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAAA,OAAO,IAAI,MAAM,MAAM,CAAA;AACvB,OAAO,EAAE,MAAM,EAAE,MAAM,SAAS,CAAA;AAChC,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAA;AAC9C,OAAO,EAAE,MAAM,EAAE,MAAM,iBAAiB,CAAA;AACxC,OAAO,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAA;AAEpD,MAAM,MAAM,GAAG,YAAY,CAAC,OAAO,CAAC,CAAA;AAEpC,MAAM,EAAE,IAAI,EAAE,OAAO,EAAE,GAAG,MAAM,CAAC,KAAK,CAAA;AACtC,MAAM,MAAM,GAAG,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,YAAY,CAAC,CAAA;AAC/C,MAAM,UAAU,GAAG,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,SAAS,CAAC,CAAA;AAEhD,MAAM,CAAC,MAAM,CAAC,CAAA;AAEd,MAAM,MAAM,GAAG,IAAI,WAAW,CAAC,EAAE,IAAI,EAAE,UAAU,EAAE,mBAAmB,EAAE,MAAM,CAAC,KAAK,CAAC,mBAAmB,EAAE,cAAc,EAAE,MAAM,CAAC,KAAK,CAAC,cAAc,EAAE,CAAC,CAAA;AAExJ,KAAK,MAAM,CAAC,KAAK,EAAE,CAAC,IAAI,CAAC,GAAG,EAAE;IAC5B,MAAM,CAAC,IAAI,CAAC,iCAAiC,IAAI,EAAE,CAAC,CAAA;AACtD,CAAC,CAAC,CAAA;AAEF,OAAO,CAAC,EAAE,CAAC,SAAS,EAAE,GAAG,EAAE,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAA;AACtE,OAAO,CAAC,EAAE,CAAC,QAAQ,EAAE,GAAG,EAAE,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAA"}
1
+ {"version":3,"file":"server.js","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tapflowio/relay",
3
- "version": "0.8.2",
3
+ "version": "0.9.1",
4
4
  "description": "WebSocket relay server for tapflow — NAT traversal, session routing, JWT auth, bundled dashboard",
5
5
  "keywords": [
6
6
  "tapflow",
@@ -39,29 +39,30 @@
39
39
  "LICENSE"
40
40
  ],
41
41
  "engines": {
42
- "node": ">=20"
42
+ "node": ">=20.12.0"
43
43
  },
44
44
  "publishConfig": {
45
45
  "access": "public"
46
46
  },
47
47
  "dependencies": {
48
- "better-sqlite3": "^12.9.0",
48
+ "acme-client": "^5.4.0",
49
+ "better-sqlite3": "^12.11.1",
49
50
  "busboy": "^1.6.0",
50
51
  "jsonwebtoken": "^9.0.3",
51
- "nodemailer": "^8.0.7",
52
- "ws": "^8.0.0",
52
+ "nodemailer": "^8.0.11",
53
+ "ws": "^8.21.0",
53
54
  "zod": "^4.4.3",
54
- "@tapflowio/agent-core": "0.8.2"
55
+ "@tapflowio/agent-core": "0.9.1"
55
56
  },
56
57
  "devDependencies": {
57
58
  "@types/better-sqlite3": "^7.6.13",
58
59
  "@types/busboy": "^1.5.4",
59
60
  "@types/jsonwebtoken": "^9.0.10",
60
- "@types/node": "^20.0.0",
61
+ "@types/node": "^20.19.43",
61
62
  "@types/nodemailer": "^8.0.0",
62
63
  "@types/ws": "^8.0.0",
63
64
  "typescript": "^5.0.0",
64
- "vitest": "^4.1.8"
65
+ "vitest": "^4.1.9"
65
66
  },
66
67
  "scripts": {
67
68
  "build": "tsc && rm -rf dist/migrations && cp -r src/migrations dist/migrations",