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.
- package/LICENSE +21 -0
- package/README.md +431 -0
- package/config/repos.example.json +128 -0
- package/config/settings.example.json +64 -0
- package/config/skills/code-review.md +76 -0
- package/config/skills/full-check.md +26 -0
- package/config/skills/lint-fix.md +23 -0
- package/dist/api/agent-routes.d.ts +2 -0
- package/dist/api/agent-routes.d.ts.map +1 -0
- package/dist/api/agent-routes.js +251 -0
- package/dist/api/agent-routes.js.map +1 -0
- package/dist/api/app-routes.d.ts +2 -0
- package/dist/api/app-routes.d.ts.map +1 -0
- package/dist/api/app-routes.js +150 -0
- package/dist/api/app-routes.js.map +1 -0
- package/dist/api/docker-routes.d.ts +2 -0
- package/dist/api/docker-routes.d.ts.map +1 -0
- package/dist/api/docker-routes.js +167 -0
- package/dist/api/docker-routes.js.map +1 -0
- package/dist/api/middleware.d.ts +6 -0
- package/dist/api/middleware.d.ts.map +1 -0
- package/dist/api/middleware.js +293 -0
- package/dist/api/middleware.js.map +1 -0
- package/dist/api/pin-auth.d.ts +65 -0
- package/dist/api/pin-auth.d.ts.map +1 -0
- package/dist/api/pin-auth.js +218 -0
- package/dist/api/pin-auth.js.map +1 -0
- package/dist/api/routes.d.ts +2 -0
- package/dist/api/routes.d.ts.map +1 -0
- package/dist/api/routes.js +473 -0
- package/dist/api/routes.js.map +1 -0
- package/dist/api/settings-routes.d.ts +2 -0
- package/dist/api/settings-routes.d.ts.map +1 -0
- package/dist/api/settings-routes.js +570 -0
- package/dist/api/settings-routes.js.map +1 -0
- package/dist/api/skill-routes.d.ts +2 -0
- package/dist/api/skill-routes.d.ts.map +1 -0
- package/dist/api/skill-routes.js +88 -0
- package/dist/api/skill-routes.js.map +1 -0
- package/dist/api/terminal-routes.d.ts +2 -0
- package/dist/api/terminal-routes.d.ts.map +1 -0
- package/dist/api/terminal-routes.js +3524 -0
- package/dist/api/terminal-routes.js.map +1 -0
- package/dist/api/tunnel-routes.d.ts +2 -0
- package/dist/api/tunnel-routes.d.ts.map +1 -0
- package/dist/api/tunnel-routes.js +196 -0
- package/dist/api/tunnel-routes.js.map +1 -0
- package/dist/api/workspace-routes.d.ts +3 -0
- package/dist/api/workspace-routes.d.ts.map +1 -0
- package/dist/api/workspace-routes.js +649 -0
- package/dist/api/workspace-routes.js.map +1 -0
- package/dist/cli.d.ts +3 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +276 -0
- package/dist/cli.js.map +1 -0
- package/dist/client/assets/index-B4r0njGe.js +780 -0
- package/dist/client/assets/index-CY_9MyE0.css +1 -0
- package/dist/client/favicon.svg +5 -0
- package/dist/client/icons/icon-192.svg +5 -0
- package/dist/client/icons/icon-512.svg +5 -0
- package/dist/client/icons/logo-with-message.png +0 -0
- package/dist/client/icons/logo.png +0 -0
- package/dist/client/index.html +25 -0
- package/dist/client/manifest.json +62 -0
- package/dist/client/sw.js +243 -0
- package/dist/config/agent-usage.d.ts +34 -0
- package/dist/config/agent-usage.d.ts.map +1 -0
- package/dist/config/agent-usage.js +87 -0
- package/dist/config/agent-usage.js.map +1 -0
- package/dist/config/repos.d.ts +34 -0
- package/dist/config/repos.d.ts.map +1 -0
- package/dist/config/repos.js +412 -0
- package/dist/config/repos.js.map +1 -0
- package/dist/config/settings.d.ts +634 -0
- package/dist/config/settings.d.ts.map +1 -0
- package/dist/config/settings.js +459 -0
- package/dist/config/settings.js.map +1 -0
- package/dist/config/skills.d.ts +18 -0
- package/dist/config/skills.d.ts.map +1 -0
- package/dist/config/skills.js +174 -0
- package/dist/config/skills.js.map +1 -0
- package/dist/config/workspaces.d.ts +961 -0
- package/dist/config/workspaces.d.ts.map +1 -0
- package/dist/config/workspaces.js +482 -0
- package/dist/config/workspaces.js.map +1 -0
- package/dist/core/app-manager.d.ts +85 -0
- package/dist/core/app-manager.d.ts.map +1 -0
- package/dist/core/app-manager.js +447 -0
- package/dist/core/app-manager.js.map +1 -0
- package/dist/core/claude-invoker.d.ts +49 -0
- package/dist/core/claude-invoker.d.ts.map +1 -0
- package/dist/core/claude-invoker.js +583 -0
- package/dist/core/claude-invoker.js.map +1 -0
- package/dist/core/claude-session-reader.d.ts +25 -0
- package/dist/core/claude-session-reader.d.ts.map +1 -0
- package/dist/core/claude-session-reader.js +184 -0
- package/dist/core/claude-session-reader.js.map +1 -0
- package/dist/core/claude-usage-query.d.ts +78 -0
- package/dist/core/claude-usage-query.d.ts.map +1 -0
- package/dist/core/claude-usage-query.js +294 -0
- package/dist/core/claude-usage-query.js.map +1 -0
- package/dist/core/git-credential-helper.d.ts +57 -0
- package/dist/core/git-credential-helper.d.ts.map +1 -0
- package/dist/core/git-credential-helper.js +176 -0
- package/dist/core/git-credential-helper.js.map +1 -0
- package/dist/core/git-sandbox.d.ts +135 -0
- package/dist/core/git-sandbox.d.ts.map +1 -0
- package/dist/core/git-sandbox.js +907 -0
- package/dist/core/git-sandbox.js.map +1 -0
- package/dist/core/github-integration.d.ts +66 -0
- package/dist/core/github-integration.d.ts.map +1 -0
- package/dist/core/github-integration.js +350 -0
- package/dist/core/github-integration.js.map +1 -0
- package/dist/core/github-oauth.d.ts +88 -0
- package/dist/core/github-oauth.d.ts.map +1 -0
- package/dist/core/github-oauth.js +244 -0
- package/dist/core/github-oauth.js.map +1 -0
- package/dist/core/gitlab-integration.d.ts +66 -0
- package/dist/core/gitlab-integration.d.ts.map +1 -0
- package/dist/core/gitlab-integration.js +353 -0
- package/dist/core/gitlab-integration.js.map +1 -0
- package/dist/core/gitlab-oauth.d.ts +100 -0
- package/dist/core/gitlab-oauth.d.ts.map +1 -0
- package/dist/core/gitlab-oauth.js +366 -0
- package/dist/core/gitlab-oauth.js.map +1 -0
- package/dist/core/insights-extractor.d.ts +68 -0
- package/dist/core/insights-extractor.d.ts.map +1 -0
- package/dist/core/insights-extractor.js +402 -0
- package/dist/core/insights-extractor.js.map +1 -0
- package/dist/core/logger.d.ts +27 -0
- package/dist/core/logger.d.ts.map +1 -0
- package/dist/core/logger.js +70 -0
- package/dist/core/logger.js.map +1 -0
- package/dist/core/process-runner.d.ts +27 -0
- package/dist/core/process-runner.d.ts.map +1 -0
- package/dist/core/process-runner.js +147 -0
- package/dist/core/process-runner.js.map +1 -0
- package/dist/core/project-detector.d.ts +30 -0
- package/dist/core/project-detector.d.ts.map +1 -0
- package/dist/core/project-detector.js +482 -0
- package/dist/core/project-detector.js.map +1 -0
- package/dist/core/qr-generator.d.ts +18 -0
- package/dist/core/qr-generator.d.ts.map +1 -0
- package/dist/core/qr-generator.js +61 -0
- package/dist/core/qr-generator.js.map +1 -0
- package/dist/core/remote-tunnel-manager.d.ts +59 -0
- package/dist/core/remote-tunnel-manager.d.ts.map +1 -0
- package/dist/core/remote-tunnel-manager.js +235 -0
- package/dist/core/remote-tunnel-manager.js.map +1 -0
- package/dist/core/shared-docker-manager.d.ts +41 -0
- package/dist/core/shared-docker-manager.d.ts.map +1 -0
- package/dist/core/shared-docker-manager.js +409 -0
- package/dist/core/shared-docker-manager.js.map +1 -0
- package/dist/core/skill-executor.d.ts +25 -0
- package/dist/core/skill-executor.d.ts.map +1 -0
- package/dist/core/skill-executor.js +171 -0
- package/dist/core/skill-executor.js.map +1 -0
- package/dist/core/terminal-session.d.ts +149 -0
- package/dist/core/terminal-session.d.ts.map +1 -0
- package/dist/core/terminal-session.js +2340 -0
- package/dist/core/terminal-session.js.map +1 -0
- package/dist/core/tunnel-manager.d.ts +35 -0
- package/dist/core/tunnel-manager.d.ts.map +1 -0
- package/dist/core/tunnel-manager.js +137 -0
- package/dist/core/tunnel-manager.js.map +1 -0
- package/dist/core/usage-manager.d.ts +57 -0
- package/dist/core/usage-manager.d.ts.map +1 -0
- package/dist/core/usage-manager.js +363 -0
- package/dist/core/usage-manager.js.map +1 -0
- package/dist/core/ws-manager.d.ts +39 -0
- package/dist/core/ws-manager.d.ts.map +1 -0
- package/dist/core/ws-manager.js +190 -0
- package/dist/core/ws-manager.js.map +1 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +229 -0
- package/dist/index.js.map +1 -0
- package/dist/types.d.ts +868 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +119 -0
- package/dist/types.js.map +1 -0
- 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"}
|