diff --git a/.env.example b/.env.example index d4b83f1..4b3cbbc 100755 --- a/.env.example +++ b/.env.example @@ -35,6 +35,7 @@ VITE_PORT=5173 # DATABASE_PATH=/path/to/your/custom/auth.db # # Claude Code context window size (maximum tokens per session) -# Note: VITE_ prefix makes it available to frontend VITE_CONTEXT_WINDOW=160000 CONTEXT_WINDOW=160000 + +# VITE_IS_PLATFORM=false diff --git a/server/database/db.js b/server/database/db.js index b8c56a2..335e387 100644 --- a/server/database/db.js +++ b/server/database/db.js @@ -117,6 +117,15 @@ const userDb = { } catch (err) { throw err; } + }, + + getFirstUser: () => { + try { + const row = db.prepare('SELECT id, username, created_at, last_login FROM users WHERE is_active = 1 LIMIT 1').get(); + return row; + } catch (err) { + throw err; + } } }; diff --git a/server/index.js b/server/index.js index 28ba951..92082df 100755 --- a/server/index.js +++ b/server/index.js @@ -170,6 +170,19 @@ const wss = new WebSocketServer({ verifyClient: (info) => { console.log('WebSocket connection attempt to:', info.req.url); + // Platform mode: always allow connection + if (process.env.VITE_IS_PLATFORM === 'true') { + const user = authenticateWebSocket(null); // Will return first user + if (!user) { + console.log('[WARN] Platform mode: No user found in database'); + return false; + } + info.req.user = user; + console.log('[OK] Platform mode WebSocket authenticated for user:', user.username); + return true; + } + + // Normal mode: verify token // Extract token from query parameters or headers const url = new URL(info.req.url, 'http://localhost'); const token = url.searchParams.get('token') || @@ -196,6 +209,14 @@ app.use(cors()); app.use(express.json({ limit: '50mb' })); app.use(express.urlencoded({ limit: '50mb', extended: true })); +// Public health check endpoint (no authentication required) +app.get('/health', (req, res) => { + res.json({ + status: 'ok', + timestamp: new Date().toISOString() + }); +}); + // Optional API key validation (if configured) app.use('/api', validateApiKey); diff --git a/server/middleware/auth.js b/server/middleware/auth.js index 433c329..b9ff24f 100644 --- a/server/middleware/auth.js +++ b/server/middleware/auth.js @@ -20,6 +20,22 @@ const validateApiKey = (req, res, next) => { // JWT authentication middleware const authenticateToken = async (req, res, next) => { + // Platform mode: use single database user + if (process.env.VITE_IS_PLATFORM === 'true') { + try { + const user = userDb.getFirstUser(); + if (!user) { + return res.status(500).json({ error: 'Platform mode: No user found in database' }); + } + req.user = user; + return next(); + } catch (error) { + console.error('Platform mode error:', error); + return res.status(500).json({ error: 'Platform mode: Failed to fetch user' }); + } + } + + // Normal OSS JWT validation const authHeader = req.headers['authorization']; const token = authHeader && authHeader.split(' ')[1]; // Bearer TOKEN @@ -29,13 +45,13 @@ const authenticateToken = async (req, res, next) => { try { const decoded = jwt.verify(token, JWT_SECRET); - + // Verify user still exists and is active const user = userDb.getUserById(decoded.userId); if (!user) { return res.status(401).json({ error: 'Invalid token. User not found.' }); } - + req.user = user; next(); } catch (error) { @@ -58,10 +74,25 @@ const generateToken = (user) => { // WebSocket authentication function const authenticateWebSocket = (token) => { + // Platform mode: bypass token validation, return first user + if (process.env.VITE_IS_PLATFORM === 'true') { + try { + const user = userDb.getFirstUser(); + if (user) { + return { userId: user.id, username: user.username }; + } + return null; + } catch (error) { + console.error('Platform mode WebSocket error:', error); + return null; + } + } + + // Normal OSS JWT validation if (!token) { return null; } - + try { const decoded = jwt.verify(token, JWT_SECRET); return decoded; diff --git a/src/components/ProtectedRoute.jsx b/src/components/ProtectedRoute.jsx index 88b404b..16419d0 100644 --- a/src/components/ProtectedRoute.jsx +++ b/src/components/ProtectedRoute.jsx @@ -26,6 +26,12 @@ const LoadingScreen = () => ( const ProtectedRoute = ({ children }) => { const { user, isLoading, needsSetup } = useAuth(); + // Platform mode: skip all auth UI and directly render children + if (import.meta.env.VITE_IS_PLATFORM === 'true') { + return children; + } + + // Normal OSS mode: standard auth flow if (isLoading) { return ; } diff --git a/src/contexts/AuthContext.jsx b/src/contexts/AuthContext.jsx index c227814..4f9b200 100644 --- a/src/contexts/AuthContext.jsx +++ b/src/contexts/AuthContext.jsx @@ -29,31 +29,38 @@ export const AuthProvider = ({ children }) => { // Check authentication status on mount useEffect(() => { + // Platform mode: skip all auth checks, set dummy user + if (import.meta.env.VITE_IS_PLATFORM === 'true') { + setUser({ username: 'platform-user' }); + setNeedsSetup(false); + setIsLoading(false); + return; + } + + // Normal OSS mode: check auth status checkAuthStatus(); }, []); const checkAuthStatus = async () => { try { - console.log('[AuthContext] Checking auth status...'); setIsLoading(true); setError(null); // Check if system needs setup const statusResponse = await api.auth.status(); const statusData = await statusResponse.json(); - console.log('[AuthContext] Status response:', statusData); - + if (statusData.needsSetup) { setNeedsSetup(true); setIsLoading(false); return; } - + // If we have a token, verify it if (token) { try { const userResponse = await api.auth.user(); - + if (userResponse.ok) { const userData = await userResponse.json(); setUser(userData.user); @@ -75,7 +82,6 @@ export const AuthProvider = ({ children }) => { console.error('[AuthContext] Auth status check failed:', error); setError('Failed to check authentication status'); } finally { - console.log('[AuthContext] Auth check complete, isLoading=false'); setIsLoading(false); } };