claudedesk 1.0.0

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 (182) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +431 -0
  3. package/config/repos.example.json +128 -0
  4. package/config/settings.example.json +64 -0
  5. package/config/skills/code-review.md +76 -0
  6. package/config/skills/full-check.md +26 -0
  7. package/config/skills/lint-fix.md +23 -0
  8. package/dist/api/agent-routes.d.ts +2 -0
  9. package/dist/api/agent-routes.d.ts.map +1 -0
  10. package/dist/api/agent-routes.js +251 -0
  11. package/dist/api/agent-routes.js.map +1 -0
  12. package/dist/api/app-routes.d.ts +2 -0
  13. package/dist/api/app-routes.d.ts.map +1 -0
  14. package/dist/api/app-routes.js +150 -0
  15. package/dist/api/app-routes.js.map +1 -0
  16. package/dist/api/docker-routes.d.ts +2 -0
  17. package/dist/api/docker-routes.d.ts.map +1 -0
  18. package/dist/api/docker-routes.js +167 -0
  19. package/dist/api/docker-routes.js.map +1 -0
  20. package/dist/api/middleware.d.ts +6 -0
  21. package/dist/api/middleware.d.ts.map +1 -0
  22. package/dist/api/middleware.js +293 -0
  23. package/dist/api/middleware.js.map +1 -0
  24. package/dist/api/pin-auth.d.ts +65 -0
  25. package/dist/api/pin-auth.d.ts.map +1 -0
  26. package/dist/api/pin-auth.js +218 -0
  27. package/dist/api/pin-auth.js.map +1 -0
  28. package/dist/api/routes.d.ts +2 -0
  29. package/dist/api/routes.d.ts.map +1 -0
  30. package/dist/api/routes.js +473 -0
  31. package/dist/api/routes.js.map +1 -0
  32. package/dist/api/settings-routes.d.ts +2 -0
  33. package/dist/api/settings-routes.d.ts.map +1 -0
  34. package/dist/api/settings-routes.js +570 -0
  35. package/dist/api/settings-routes.js.map +1 -0
  36. package/dist/api/skill-routes.d.ts +2 -0
  37. package/dist/api/skill-routes.d.ts.map +1 -0
  38. package/dist/api/skill-routes.js +88 -0
  39. package/dist/api/skill-routes.js.map +1 -0
  40. package/dist/api/terminal-routes.d.ts +2 -0
  41. package/dist/api/terminal-routes.d.ts.map +1 -0
  42. package/dist/api/terminal-routes.js +3524 -0
  43. package/dist/api/terminal-routes.js.map +1 -0
  44. package/dist/api/tunnel-routes.d.ts +2 -0
  45. package/dist/api/tunnel-routes.d.ts.map +1 -0
  46. package/dist/api/tunnel-routes.js +196 -0
  47. package/dist/api/tunnel-routes.js.map +1 -0
  48. package/dist/api/workspace-routes.d.ts +3 -0
  49. package/dist/api/workspace-routes.d.ts.map +1 -0
  50. package/dist/api/workspace-routes.js +649 -0
  51. package/dist/api/workspace-routes.js.map +1 -0
  52. package/dist/cli.d.ts +3 -0
  53. package/dist/cli.d.ts.map +1 -0
  54. package/dist/cli.js +276 -0
  55. package/dist/cli.js.map +1 -0
  56. package/dist/client/assets/index-B4r0njGe.js +780 -0
  57. package/dist/client/assets/index-CY_9MyE0.css +1 -0
  58. package/dist/client/favicon.svg +5 -0
  59. package/dist/client/icons/icon-192.svg +5 -0
  60. package/dist/client/icons/icon-512.svg +5 -0
  61. package/dist/client/icons/logo-with-message.png +0 -0
  62. package/dist/client/icons/logo.png +0 -0
  63. package/dist/client/index.html +25 -0
  64. package/dist/client/manifest.json +62 -0
  65. package/dist/client/sw.js +243 -0
  66. package/dist/config/agent-usage.d.ts +34 -0
  67. package/dist/config/agent-usage.d.ts.map +1 -0
  68. package/dist/config/agent-usage.js +87 -0
  69. package/dist/config/agent-usage.js.map +1 -0
  70. package/dist/config/repos.d.ts +34 -0
  71. package/dist/config/repos.d.ts.map +1 -0
  72. package/dist/config/repos.js +412 -0
  73. package/dist/config/repos.js.map +1 -0
  74. package/dist/config/settings.d.ts +634 -0
  75. package/dist/config/settings.d.ts.map +1 -0
  76. package/dist/config/settings.js +459 -0
  77. package/dist/config/settings.js.map +1 -0
  78. package/dist/config/skills.d.ts +18 -0
  79. package/dist/config/skills.d.ts.map +1 -0
  80. package/dist/config/skills.js +174 -0
  81. package/dist/config/skills.js.map +1 -0
  82. package/dist/config/workspaces.d.ts +961 -0
  83. package/dist/config/workspaces.d.ts.map +1 -0
  84. package/dist/config/workspaces.js +482 -0
  85. package/dist/config/workspaces.js.map +1 -0
  86. package/dist/core/app-manager.d.ts +85 -0
  87. package/dist/core/app-manager.d.ts.map +1 -0
  88. package/dist/core/app-manager.js +447 -0
  89. package/dist/core/app-manager.js.map +1 -0
  90. package/dist/core/claude-invoker.d.ts +49 -0
  91. package/dist/core/claude-invoker.d.ts.map +1 -0
  92. package/dist/core/claude-invoker.js +583 -0
  93. package/dist/core/claude-invoker.js.map +1 -0
  94. package/dist/core/claude-session-reader.d.ts +25 -0
  95. package/dist/core/claude-session-reader.d.ts.map +1 -0
  96. package/dist/core/claude-session-reader.js +184 -0
  97. package/dist/core/claude-session-reader.js.map +1 -0
  98. package/dist/core/claude-usage-query.d.ts +78 -0
  99. package/dist/core/claude-usage-query.d.ts.map +1 -0
  100. package/dist/core/claude-usage-query.js +294 -0
  101. package/dist/core/claude-usage-query.js.map +1 -0
  102. package/dist/core/git-credential-helper.d.ts +57 -0
  103. package/dist/core/git-credential-helper.d.ts.map +1 -0
  104. package/dist/core/git-credential-helper.js +176 -0
  105. package/dist/core/git-credential-helper.js.map +1 -0
  106. package/dist/core/git-sandbox.d.ts +135 -0
  107. package/dist/core/git-sandbox.d.ts.map +1 -0
  108. package/dist/core/git-sandbox.js +907 -0
  109. package/dist/core/git-sandbox.js.map +1 -0
  110. package/dist/core/github-integration.d.ts +66 -0
  111. package/dist/core/github-integration.d.ts.map +1 -0
  112. package/dist/core/github-integration.js +350 -0
  113. package/dist/core/github-integration.js.map +1 -0
  114. package/dist/core/github-oauth.d.ts +88 -0
  115. package/dist/core/github-oauth.d.ts.map +1 -0
  116. package/dist/core/github-oauth.js +244 -0
  117. package/dist/core/github-oauth.js.map +1 -0
  118. package/dist/core/gitlab-integration.d.ts +66 -0
  119. package/dist/core/gitlab-integration.d.ts.map +1 -0
  120. package/dist/core/gitlab-integration.js +353 -0
  121. package/dist/core/gitlab-integration.js.map +1 -0
  122. package/dist/core/gitlab-oauth.d.ts +100 -0
  123. package/dist/core/gitlab-oauth.d.ts.map +1 -0
  124. package/dist/core/gitlab-oauth.js +366 -0
  125. package/dist/core/gitlab-oauth.js.map +1 -0
  126. package/dist/core/insights-extractor.d.ts +68 -0
  127. package/dist/core/insights-extractor.d.ts.map +1 -0
  128. package/dist/core/insights-extractor.js +402 -0
  129. package/dist/core/insights-extractor.js.map +1 -0
  130. package/dist/core/logger.d.ts +27 -0
  131. package/dist/core/logger.d.ts.map +1 -0
  132. package/dist/core/logger.js +70 -0
  133. package/dist/core/logger.js.map +1 -0
  134. package/dist/core/process-runner.d.ts +27 -0
  135. package/dist/core/process-runner.d.ts.map +1 -0
  136. package/dist/core/process-runner.js +147 -0
  137. package/dist/core/process-runner.js.map +1 -0
  138. package/dist/core/project-detector.d.ts +30 -0
  139. package/dist/core/project-detector.d.ts.map +1 -0
  140. package/dist/core/project-detector.js +482 -0
  141. package/dist/core/project-detector.js.map +1 -0
  142. package/dist/core/qr-generator.d.ts +18 -0
  143. package/dist/core/qr-generator.d.ts.map +1 -0
  144. package/dist/core/qr-generator.js +61 -0
  145. package/dist/core/qr-generator.js.map +1 -0
  146. package/dist/core/remote-tunnel-manager.d.ts +59 -0
  147. package/dist/core/remote-tunnel-manager.d.ts.map +1 -0
  148. package/dist/core/remote-tunnel-manager.js +235 -0
  149. package/dist/core/remote-tunnel-manager.js.map +1 -0
  150. package/dist/core/shared-docker-manager.d.ts +41 -0
  151. package/dist/core/shared-docker-manager.d.ts.map +1 -0
  152. package/dist/core/shared-docker-manager.js +409 -0
  153. package/dist/core/shared-docker-manager.js.map +1 -0
  154. package/dist/core/skill-executor.d.ts +25 -0
  155. package/dist/core/skill-executor.d.ts.map +1 -0
  156. package/dist/core/skill-executor.js +171 -0
  157. package/dist/core/skill-executor.js.map +1 -0
  158. package/dist/core/terminal-session.d.ts +149 -0
  159. package/dist/core/terminal-session.d.ts.map +1 -0
  160. package/dist/core/terminal-session.js +2340 -0
  161. package/dist/core/terminal-session.js.map +1 -0
  162. package/dist/core/tunnel-manager.d.ts +35 -0
  163. package/dist/core/tunnel-manager.d.ts.map +1 -0
  164. package/dist/core/tunnel-manager.js +137 -0
  165. package/dist/core/tunnel-manager.js.map +1 -0
  166. package/dist/core/usage-manager.d.ts +57 -0
  167. package/dist/core/usage-manager.d.ts.map +1 -0
  168. package/dist/core/usage-manager.js +363 -0
  169. package/dist/core/usage-manager.js.map +1 -0
  170. package/dist/core/ws-manager.d.ts +39 -0
  171. package/dist/core/ws-manager.d.ts.map +1 -0
  172. package/dist/core/ws-manager.js +190 -0
  173. package/dist/core/ws-manager.js.map +1 -0
  174. package/dist/index.d.ts +7 -0
  175. package/dist/index.d.ts.map +1 -0
  176. package/dist/index.js +229 -0
  177. package/dist/index.js.map +1 -0
  178. package/dist/types.d.ts +868 -0
  179. package/dist/types.d.ts.map +1 -0
  180. package/dist/types.js +119 -0
  181. package/dist/types.js.map +1 -0
  182. package/package.json +96 -0
@@ -0,0 +1,167 @@
1
+ import { Router } from 'express';
2
+ import net from 'net';
3
+ import { sharedDockerManager } from '../core/shared-docker-manager.js';
4
+ import { settingsManager } from '../config/settings.js';
5
+ export const dockerRouter = Router();
6
+ // Get Docker availability
7
+ dockerRouter.get('/availability', async (_req, res) => {
8
+ try {
9
+ const dockerAvailable = await sharedDockerManager.isDockerAvailable();
10
+ const composeAvailable = await sharedDockerManager.isComposeAvailable();
11
+ res.json({
12
+ success: true,
13
+ data: {
14
+ docker: dockerAvailable,
15
+ compose: composeAvailable,
16
+ available: dockerAvailable && composeAvailable,
17
+ },
18
+ });
19
+ }
20
+ catch (error) {
21
+ const errorMsg = error instanceof Error ? error.message : String(error);
22
+ res.status(500).json({ success: false, error: errorMsg });
23
+ }
24
+ });
25
+ // Get Docker environment status
26
+ dockerRouter.get('/status', async (_req, res) => {
27
+ try {
28
+ const status = await sharedDockerManager.getStatus();
29
+ res.json({ success: true, data: status });
30
+ }
31
+ catch (error) {
32
+ const errorMsg = error instanceof Error ? error.message : String(error);
33
+ res.status(500).json({ success: false, error: errorMsg });
34
+ }
35
+ });
36
+ // Start Docker environment
37
+ dockerRouter.post('/start', async (_req, res) => {
38
+ try {
39
+ const status = await sharedDockerManager.start();
40
+ res.json({ success: true, data: status });
41
+ }
42
+ catch (error) {
43
+ const errorMsg = error instanceof Error ? error.message : String(error);
44
+ res.status(500).json({ success: false, error: errorMsg });
45
+ }
46
+ });
47
+ // Stop Docker environment
48
+ dockerRouter.post('/stop', async (_req, res) => {
49
+ try {
50
+ const status = await sharedDockerManager.stop();
51
+ res.json({ success: true, data: status });
52
+ }
53
+ catch (error) {
54
+ const errorMsg = error instanceof Error ? error.message : String(error);
55
+ res.status(500).json({ success: false, error: errorMsg });
56
+ }
57
+ });
58
+ // Restart Docker environment
59
+ dockerRouter.post('/restart', async (_req, res) => {
60
+ try {
61
+ const status = await sharedDockerManager.restart();
62
+ res.json({ success: true, data: status });
63
+ }
64
+ catch (error) {
65
+ const errorMsg = error instanceof Error ? error.message : String(error);
66
+ res.status(500).json({ success: false, error: errorMsg });
67
+ }
68
+ });
69
+ // Get logs for a specific service
70
+ dockerRouter.get('/logs/:service', async (req, res) => {
71
+ try {
72
+ const { service } = req.params;
73
+ const { tail } = req.query;
74
+ const logs = await sharedDockerManager.getServiceLogs(service, tail ? parseInt(tail) : 100);
75
+ res.json({ success: true, data: { service, logs } });
76
+ }
77
+ catch (error) {
78
+ const errorMsg = error instanceof Error ? error.message : String(error);
79
+ res.status(500).json({ success: false, error: errorMsg });
80
+ }
81
+ });
82
+ // Get connection info for all services
83
+ dockerRouter.get('/connections', async (_req, res) => {
84
+ try {
85
+ const connections = sharedDockerManager.getConnectionInfo();
86
+ res.json({ success: true, data: connections });
87
+ }
88
+ catch (error) {
89
+ const errorMsg = error instanceof Error ? error.message : String(error);
90
+ res.status(500).json({ success: false, error: errorMsg });
91
+ }
92
+ });
93
+ // Get Docker settings
94
+ dockerRouter.get('/settings', (_req, res) => {
95
+ try {
96
+ const settings = settingsManager.getDocker();
97
+ res.json({ success: true, data: settings });
98
+ }
99
+ catch (error) {
100
+ const errorMsg = error instanceof Error ? error.message : String(error);
101
+ res.status(500).json({ success: false, error: errorMsg });
102
+ }
103
+ });
104
+ // Update Docker settings
105
+ dockerRouter.put('/settings', (req, res) => {
106
+ try {
107
+ const updates = req.body;
108
+ const settings = settingsManager.updateDocker(updates);
109
+ res.json({ success: true, data: settings });
110
+ }
111
+ catch (error) {
112
+ const errorMsg = error instanceof Error ? error.message : String(error);
113
+ res.status(400).json({ success: false, error: errorMsg });
114
+ }
115
+ });
116
+ // ============================================
117
+ // Port Conflict Detection
118
+ // ============================================
119
+ /**
120
+ * Helper to check if a port is in use
121
+ */
122
+ function checkPortInUse(port) {
123
+ return new Promise((resolve) => {
124
+ const server = net.createServer();
125
+ server.once('error', (err) => {
126
+ if (err.code === 'EADDRINUSE') {
127
+ resolve(true);
128
+ }
129
+ else {
130
+ resolve(false);
131
+ }
132
+ });
133
+ server.once('listening', () => {
134
+ server.close();
135
+ resolve(false);
136
+ });
137
+ server.listen(port, '127.0.0.1');
138
+ });
139
+ }
140
+ /**
141
+ * GET /check-port
142
+ * Checks if a port is in use (for port conflict detection)
143
+ */
144
+ dockerRouter.get('/check-port', async (req, res) => {
145
+ try {
146
+ const port = parseInt(req.query.port, 10);
147
+ if (isNaN(port) || port < 1 || port > 65535) {
148
+ return res.status(400).json({
149
+ success: false,
150
+ error: 'Valid port number (1-65535) is required',
151
+ });
152
+ }
153
+ const inUse = await checkPortInUse(port);
154
+ res.json({
155
+ success: true,
156
+ data: {
157
+ port,
158
+ inUse,
159
+ },
160
+ });
161
+ }
162
+ catch (error) {
163
+ const errorMsg = error instanceof Error ? error.message : String(error);
164
+ res.status(500).json({ success: false, error: errorMsg });
165
+ }
166
+ });
167
+ //# sourceMappingURL=docker-routes.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"docker-routes.js","sourceRoot":"","sources":["../../src/api/docker-routes.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,6 @@
1
+ import { Request, Response, NextFunction } from 'express';
2
+ export declare function getAuthToken(): string;
3
+ export declare function authMiddleware(req: Request, res: Response, next: NextFunction): void;
4
+ export declare function rateLimitMiddleware(req: Request, res: Response, next: NextFunction): void;
5
+ export declare function errorHandler(err: Error, _req: Request, res: Response, _next: NextFunction): void;
6
+ //# sourceMappingURL=middleware.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"middleware.d.ts","sourceRoot":"","sources":["../../src/api/middleware.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAe1D,wBAAgB,YAAY,IAAI,MAAM,CAerC;AAoKD,wBAAgB,cAAc,CAAC,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,QAAQ,EAAE,IAAI,EAAE,YAAY,GAAG,IAAI,CAiHpF;AAED,wBAAgB,mBAAmB,CAAC,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,QAAQ,EAAE,IAAI,EAAE,YAAY,GAAG,IAAI,CAgCzF;AAGD,wBAAgB,YAAY,CAAC,GAAG,EAAE,KAAK,EAAE,IAAI,EAAE,OAAO,EAAE,GAAG,EAAE,QAAQ,EAAE,KAAK,EAAE,YAAY,GAAG,IAAI,CAMhG"}
@@ -0,0 +1,293 @@
1
+ import { settingsManager } from '../config/settings.js';
2
+ // Default token for local development (as documented in SECURITY.md)
3
+ const DEFAULT_LOCAL_TOKEN = 'claudedesk-local';
4
+ // Cookie name for persistent sessions
5
+ const AUTH_COOKIE_NAME = 'claudedesk_session';
6
+ const COOKIE_MAX_AGE = 30 * 24 * 60 * 60 * 1000; // 30 days
7
+ // Rate limiting for failed auth attempts (remote access security)
8
+ const failedAuthAttempts = new Map();
9
+ const MAX_FAILED_ATTEMPTS = 5;
10
+ const BLOCK_DURATION = 15 * 60 * 1000; // 15 minutes
11
+ export function getAuthToken() {
12
+ // For remote access, use tunnel token if enabled
13
+ const tunnelSettings = settingsManager.getTunnel();
14
+ if (tunnelSettings.enabled && tunnelSettings.authToken) {
15
+ return tunnelSettings.authToken;
16
+ }
17
+ // Environment variable takes precedence
18
+ if (process.env.CLAUDEDESK_TOKEN) {
19
+ return process.env.CLAUDEDESK_TOKEN;
20
+ }
21
+ // Default to 'claudedesk-local' for local development
22
+ // As documented in SECURITY.md - suitable only for local development
23
+ return DEFAULT_LOCAL_TOKEN;
24
+ }
25
+ /**
26
+ * Check if request is from remote (via Cloudflare Tunnel)
27
+ */
28
+ function isRemoteRequest(req) {
29
+ // Cloudflare adds X-Forwarded-For header
30
+ const forwardedFor = req.headers['x-forwarded-for'];
31
+ return !!forwardedFor;
32
+ }
33
+ /**
34
+ * Get client IP for rate limiting
35
+ */
36
+ function getClientIp(req) {
37
+ const forwardedFor = req.headers['x-forwarded-for'];
38
+ if (forwardedFor) {
39
+ // X-Forwarded-For can be a comma-separated list, take the first IP
40
+ const ips = typeof forwardedFor === 'string' ? forwardedFor.split(',') : forwardedFor;
41
+ return ips[0].trim();
42
+ }
43
+ return req.ip || req.socket.remoteAddress || 'unknown';
44
+ }
45
+ /**
46
+ * Check if IP is blocked due to failed auth attempts
47
+ */
48
+ function isIpBlocked(ip) {
49
+ const record = failedAuthAttempts.get(ip);
50
+ if (!record)
51
+ return false;
52
+ if (record.blockedUntil && Date.now() < record.blockedUntil) {
53
+ return true;
54
+ }
55
+ // Block expired, reset
56
+ if (record.blockedUntil && Date.now() >= record.blockedUntil) {
57
+ failedAuthAttempts.delete(ip);
58
+ return false;
59
+ }
60
+ return false;
61
+ }
62
+ /**
63
+ * Record failed auth attempt
64
+ */
65
+ function recordFailedAuth(ip) {
66
+ const record = failedAuthAttempts.get(ip) || { count: 0, blockedUntil: null };
67
+ record.count++;
68
+ if (record.count >= MAX_FAILED_ATTEMPTS) {
69
+ record.blockedUntil = Date.now() + BLOCK_DURATION;
70
+ console.warn(`[Auth] IP ${ip} blocked for ${BLOCK_DURATION / 1000}s after ${MAX_FAILED_ATTEMPTS} failed attempts`);
71
+ }
72
+ failedAuthAttempts.set(ip, record);
73
+ }
74
+ /**
75
+ * Clear failed auth attempts for IP (on successful auth)
76
+ */
77
+ function clearFailedAuth(ip) {
78
+ failedAuthAttempts.delete(ip);
79
+ }
80
+ /**
81
+ * Extract token from various sources (header, cookie, query param)
82
+ */
83
+ function extractToken(req) {
84
+ // 1. Check Authorization header
85
+ const authHeader = req.headers.authorization;
86
+ if (authHeader && authHeader.startsWith('Bearer ')) {
87
+ return authHeader.slice(7);
88
+ }
89
+ // 2. Check cookie
90
+ const cookies = req.headers.cookie;
91
+ if (cookies) {
92
+ const match = cookies.match(new RegExp(`${AUTH_COOKIE_NAME}=([^;]+)`));
93
+ if (match) {
94
+ return match[1];
95
+ }
96
+ }
97
+ // 3. Check query param (for QR code login)
98
+ const queryToken = req.query.token;
99
+ if (queryToken && typeof queryToken === 'string') {
100
+ return queryToken;
101
+ }
102
+ return null;
103
+ }
104
+ const rateLimitBuckets = new Map();
105
+ // Rate limit configurations by endpoint pattern
106
+ const RATE_LIMITS = {
107
+ // Expensive operations - strict limits
108
+ 'POST:/api/terminal/sessions': { window: 60000, max: 10 }, // Terminal session creation
109
+ 'POST:/api/terminal/sessions/*/send': { window: 60000, max: 60 }, // Claude messages
110
+ 'POST:/api/repos/*/publish': { window: 60000, max: 5 }, // GitHub repo creation
111
+ 'POST:/api/terminal/sessions/*/create-pr': { window: 60000, max: 10 }, // PR creation
112
+ 'POST:/api/terminal/sessions/*/ship': { window: 60000, max: 10 }, // Ship (commit+push+PR)
113
+ // Docker operations
114
+ 'POST:/api/docker/start': { window: 60000, max: 5 },
115
+ 'POST:/api/docker/stop': { window: 60000, max: 5 },
116
+ // Default for all other API routes
117
+ 'default': { window: 60000, max: 200 }, // 200 requests per minute
118
+ };
119
+ /**
120
+ * Get the rate limit configuration for a given request
121
+ */
122
+ function getRateLimitConfig(method, path) {
123
+ // Try exact match first
124
+ const exactKey = `${method}:${path}`;
125
+ if (RATE_LIMITS[exactKey]) {
126
+ return { key: exactKey, config: RATE_LIMITS[exactKey] };
127
+ }
128
+ // Try pattern match (replace UUIDs/IDs with *)
129
+ const normalizedPath = path.replace(/\/[a-f0-9-]{36}/gi, '/*').replace(/\/\d+/g, '/*');
130
+ const patternKey = `${method}:${normalizedPath}`;
131
+ if (RATE_LIMITS[patternKey]) {
132
+ return { key: patternKey, config: RATE_LIMITS[patternKey] };
133
+ }
134
+ // Fall back to default
135
+ return { key: 'default', config: RATE_LIMITS['default'] };
136
+ }
137
+ /**
138
+ * Check if request is rate limited
139
+ */
140
+ function isRateLimited(bucketKey, config) {
141
+ const now = Date.now();
142
+ let timestamps = rateLimitBuckets.get(bucketKey);
143
+ if (!timestamps) {
144
+ timestamps = [];
145
+ rateLimitBuckets.set(bucketKey, timestamps);
146
+ }
147
+ // Remove timestamps outside the window
148
+ while (timestamps.length > 0 && timestamps[0] < now - config.window) {
149
+ timestamps.shift();
150
+ }
151
+ if (timestamps.length >= config.max) {
152
+ return true;
153
+ }
154
+ timestamps.push(now);
155
+ return false;
156
+ }
157
+ export function authMiddleware(req, res, next) {
158
+ // Allow health check without auth
159
+ if (req.path === '/api/health') {
160
+ next();
161
+ return;
162
+ }
163
+ // Allow health status endpoint without auth (for setup wizard)
164
+ if (req.path === '/api/health/status') {
165
+ next();
166
+ return;
167
+ }
168
+ // Allow session check without auth (for PWA cookie restore)
169
+ if (req.path === '/api/auth/session') {
170
+ next();
171
+ return;
172
+ }
173
+ // Allow PIN validation without auth (it's the auth entry point)
174
+ if (req.path === '/api/auth/pin/validate') {
175
+ next();
176
+ return;
177
+ }
178
+ // Allow static files without auth (UI assets)
179
+ if (!req.path.startsWith('/api/')) {
180
+ // Check for token in query param for initial page load (QR code login)
181
+ const queryToken = req.query.token;
182
+ if (queryToken && typeof queryToken === 'string') {
183
+ const expectedToken = getAuthToken();
184
+ if (queryToken === expectedToken) {
185
+ // Set auth cookie for persistent session
186
+ res.cookie(AUTH_COOKIE_NAME, queryToken, {
187
+ httpOnly: true,
188
+ secure: req.secure || req.headers['x-forwarded-proto'] === 'https',
189
+ sameSite: 'lax',
190
+ maxAge: COOKIE_MAX_AGE,
191
+ });
192
+ }
193
+ }
194
+ next();
195
+ return;
196
+ }
197
+ // Allow screenshot artifacts without auth (job ID is already a hard-to-guess UUID)
198
+ if (req.path.match(/^\/api\/jobs\/[^/]+\/artifacts\/screenshot$/)) {
199
+ next();
200
+ return;
201
+ }
202
+ const expectedToken = getAuthToken();
203
+ const providedToken = extractToken(req);
204
+ const clientIp = getClientIp(req);
205
+ const isRemote = isRemoteRequest(req);
206
+ // Check if IP is blocked
207
+ if (isIpBlocked(clientIp)) {
208
+ res.status(429).json({
209
+ success: false,
210
+ error: 'Too many failed authentication attempts. Please try again later.',
211
+ });
212
+ return;
213
+ }
214
+ // Security: For remote requests, reject default local token
215
+ if (isRemote && providedToken === DEFAULT_LOCAL_TOKEN) {
216
+ console.warn('[Auth] Remote request attempted with default local token - rejecting');
217
+ recordFailedAuth(clientIp);
218
+ res.status(403).json({
219
+ success: false,
220
+ error: 'Remote access requires a secure authentication token. Please enable remote access in settings.',
221
+ });
222
+ return;
223
+ }
224
+ if (!providedToken) {
225
+ if (isRemote) {
226
+ recordFailedAuth(clientIp);
227
+ }
228
+ res.status(401).json({ success: false, error: 'Missing authorization' });
229
+ return;
230
+ }
231
+ // For local requests: accept either the default token OR the secure token
232
+ // For remote requests: only accept the secure token (default already rejected above)
233
+ const isValidToken = providedToken === expectedToken ||
234
+ (!isRemote && providedToken === DEFAULT_LOCAL_TOKEN);
235
+ if (!isValidToken) {
236
+ if (isRemote) {
237
+ recordFailedAuth(clientIp);
238
+ }
239
+ res.status(403).json({ success: false, error: 'Invalid token' });
240
+ return;
241
+ }
242
+ // Successful auth - clear failed attempts
243
+ if (isRemote) {
244
+ clearFailedAuth(clientIp);
245
+ }
246
+ // If token came from query param, set cookie for future requests
247
+ if (req.query.token && typeof req.query.token === 'string') {
248
+ res.cookie(AUTH_COOKIE_NAME, providedToken, {
249
+ httpOnly: true,
250
+ secure: req.secure || req.headers['x-forwarded-proto'] === 'https',
251
+ sameSite: 'lax',
252
+ maxAge: COOKIE_MAX_AGE,
253
+ });
254
+ }
255
+ next();
256
+ }
257
+ export function rateLimitMiddleware(req, res, next) {
258
+ // Only rate limit API routes
259
+ if (!req.path.startsWith('/api/')) {
260
+ next();
261
+ return;
262
+ }
263
+ // Skip rate limiting for read-only health checks
264
+ if (req.path === '/api/health' || req.path === '/api/health/status') {
265
+ next();
266
+ return;
267
+ }
268
+ // Get rate limit configuration for this endpoint
269
+ const { key, config } = getRateLimitConfig(req.method, req.path);
270
+ // Check if rate limited
271
+ // Use IP address as additional bucketing for global limits
272
+ const clientIp = req.ip || req.socket.remoteAddress || 'unknown';
273
+ const bucketKey = key === 'default' ? `${key}:${clientIp}` : key;
274
+ if (isRateLimited(bucketKey, config)) {
275
+ const retryAfter = Math.ceil(config.window / 1000);
276
+ res.setHeader('Retry-After', retryAfter.toString());
277
+ res.status(429).json({
278
+ success: false,
279
+ error: `Rate limit exceeded. Max ${config.max} requests per ${config.window / 1000}s for this endpoint.`,
280
+ });
281
+ return;
282
+ }
283
+ next();
284
+ }
285
+ // Error handler
286
+ export function errorHandler(err, _req, res, _next) {
287
+ console.error('API Error:', err);
288
+ res.status(500).json({
289
+ success: false,
290
+ error: err.message || 'Internal server error',
291
+ });
292
+ }
293
+ //# sourceMappingURL=middleware.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"middleware.js","sourceRoot":"","sources":["../../src/api/middleware.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,65 @@
1
+ export interface PairingPin {
2
+ pin: string;
3
+ token: string;
4
+ createdAt: number;
5
+ expiresAt: number;
6
+ attempts: number;
7
+ }
8
+ declare class PinAuthManager {
9
+ private activePin;
10
+ private rateLimitMap;
11
+ private cleanupInterval;
12
+ constructor();
13
+ /**
14
+ * Generate a cryptographically secure 6-digit PIN
15
+ */
16
+ private generatePin;
17
+ /**
18
+ * Generate a new pairing PIN
19
+ * Invalidates any existing PIN
20
+ */
21
+ generatePairingPin(authToken: string): {
22
+ pin: string;
23
+ expiresAt: number;
24
+ expiresInSeconds: number;
25
+ };
26
+ /**
27
+ * Get status of active PIN
28
+ */
29
+ getPinStatus(): {
30
+ hasActivePin: boolean;
31
+ expiresAt?: number;
32
+ expiresInSeconds?: number;
33
+ };
34
+ /**
35
+ * Invalidate the current PIN
36
+ */
37
+ invalidatePin(): boolean;
38
+ /**
39
+ * Check rate limiting for IP
40
+ */
41
+ checkRateLimit(ip: string): {
42
+ allowed: boolean;
43
+ attemptsRemaining?: number;
44
+ };
45
+ /**
46
+ * Validate a PIN with constant-time comparison
47
+ */
48
+ validatePin(pin: string, clientIp: string): {
49
+ success: boolean;
50
+ token?: string;
51
+ error?: string;
52
+ attemptsRemaining?: number;
53
+ };
54
+ /**
55
+ * Start periodic cleanup of expired data
56
+ */
57
+ private startCleanup;
58
+ /**
59
+ * Stop cleanup interval (for graceful shutdown)
60
+ */
61
+ stopCleanup(): void;
62
+ }
63
+ export declare const pinAuthManager: PinAuthManager;
64
+ export {};
65
+ //# sourceMappingURL=pin-auth.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pin-auth.d.ts","sourceRoot":"","sources":["../../src/api/pin-auth.ts"],"names":[],"mappings":"AAEA,MAAM,WAAW,UAAU;IACzB,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;CAClB;AAiBD,cAAM,cAAc;IAClB,OAAO,CAAC,SAAS,CAA2B;IAC5C,OAAO,CAAC,YAAY,CAA0C;IAC9D,OAAO,CAAC,eAAe,CAA+B;;IAOtD;;OAEG;IACH,OAAO,CAAC,WAAW;IAOnB;;;OAGG;IACH,kBAAkB,CAAC,SAAS,EAAE,MAAM,GAAG;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAC;QAAC,gBAAgB,EAAE,MAAM,CAAA;KAAE;IAsBnG;;OAEG;IACH,YAAY,IAAI;QAAE,YAAY,EAAE,OAAO,CAAC;QAAC,SAAS,CAAC,EAAE,MAAM,CAAC;QAAC,gBAAgB,CAAC,EAAE,MAAM,CAAA;KAAE;IAmBxF;;OAEG;IACH,aAAa,IAAI,OAAO;IASxB;;OAEG;IACH,cAAc,CAAC,EAAE,EAAE,MAAM,GAAG;QAAE,OAAO,EAAE,OAAO,CAAC;QAAC,iBAAiB,CAAC,EAAE,MAAM,CAAA;KAAE;IA6B5E;;OAEG;IACH,WAAW,CACT,GAAG,EAAE,MAAM,EACX,QAAQ,EAAE,MAAM,GACf;QACD,OAAO,EAAE,OAAO,CAAC;QACjB,KAAK,CAAC,EAAE,MAAM,CAAC;QACf,KAAK,CAAC,EAAE,MAAM,CAAC;QACf,iBAAiB,CAAC,EAAE,MAAM,CAAC;KAC5B;IA2FD;;OAEG;IACH,OAAO,CAAC,YAAY;IAoBpB;;OAEG;IACH,WAAW,IAAI,IAAI;CAMpB;AAGD,eAAO,MAAM,cAAc,gBAAuB,CAAC"}