diff --git a/.gitignore b/.gitignore index 764d0b9..f778d33 100644 --- a/.gitignore +++ b/.gitignore @@ -34,3 +34,11 @@ node_modules # Local data directories data/ logs/ + +# Debug files and troubleshooting artifacts +debug-*.js +*.debug.log +LOGIN_FIX_*.md +CUSTOM_*_IMPLEMENTATION.md +troubleshooting/ +sequential-thinking/ diff --git a/CUSTOM_LOGIN_IMPLEMENTATION.md b/CUSTOM_LOGIN_IMPLEMENTATION.md deleted file mode 100644 index 5b8543a..0000000 --- a/CUSTOM_LOGIN_IMPLEMENTATION.md +++ /dev/null @@ -1,238 +0,0 @@ -# MonacoUSA Portal - Custom Login System Implementation - -## ๐ŸŽฏ Overview - -This document describes the implementation of the custom branded login system for the MonacoUSA Portal. The system provides a seamless authentication experience using your Monaco assets while maintaining security through Keycloak integration. - -## โœจ Features Implemented - -### ๐ŸŽจ **Beautiful Branded UI** -- **Monaco Background**: High-resolution Monaco image with overlay effects -- **MonacoUSA Logo**: Animated logo with pulse effect -- **Glassmorphism Design**: Modern card with backdrop blur and transparency -- **Responsive Layout**: Works perfectly on desktop, tablet, and mobile -- **Smooth Animations**: Entrance animations and hover effects - -### ๐Ÿ” **Direct Authentication** -- **Password-based Login**: Users never leave your portal -- **Remember Me**: Extended 30-day sessions vs 7-day standard -- **Rate Limiting**: 5 attempts per 15 minutes, 1-hour IP blocking -- **Input Validation**: Client and server-side validation -- **Security Logging**: Comprehensive logging for monitoring - -### ๐Ÿ”„ **Password Reset** -- **Email-based Reset**: Integration with Keycloak's email system -- **Beautiful Dialog**: Modal with branded styling -- **Security-first**: Doesn't reveal if email exists -- **Auto-close**: Success message with automatic dialog closure - -## ๐Ÿ“ Files Created/Modified - -### **Frontend Components** -``` -pages/login.vue # Main branded login page -components/ForgotPasswordDialog.vue # Password reset modal -middleware/guest.ts # Redirect authenticated users -``` - -### **Backend APIs** -``` -server/api/auth/direct-login.post.ts # Direct password authentication -server/api/auth/forgot-password.post.ts # Password reset functionality -server/utils/security.ts # Rate limiting and validation -``` - -### **Enhanced Files** -``` -server/utils/session.ts # Added Remember Me support -.env.example # Added COOKIE_DOMAIN variable -``` - -## ๐Ÿš€ How It Works - -### **Authentication Flow** -1. User visits `/login` with beautiful Monaco-themed page -2. Enters credentials with optional "Remember Me" -3. Client-side validation and security checks -4. Direct authentication with Keycloak via Resource Owner Password Credentials -5. Session creation with appropriate expiration (7 or 30 days) -6. Redirect to dashboard upon success - -### **Password Reset Flow** -1. User clicks "Forgot Password?" link -2. Modal dialog opens with email input -3. Email sent via Keycloak admin API -4. User receives reset link in email -5. Keycloak handles the actual password reset - -### **Security Features** -- **Rate Limiting**: 5 failed attempts = 15-minute window, then 1-hour IP block -- **Input Validation**: Prevents XSS and injection attacks -- **Secure Sessions**: Encrypted cookies with domain scoping -- **Audit Logging**: All authentication events logged -- **CSRF Protection**: Built into Nuxt framework - -## ๐ŸŽจ Design Specifications - -### **Visual Elements** -- **Primary Color**: `#a31515` (MonacoUSA red) -- **Background**: Monaco high-resolution image with gradient overlay -- **Card Style**: Glassmorphism with `backdrop-filter: blur(15px)` -- **Logo**: Animated with 3-second pulse effect -- **Typography**: Clean, modern fonts with proper hierarchy - -### **Responsive Breakpoints** -- **Desktop**: Full glassmorphism effects, fixed background -- **Tablet**: Optimized card sizing and spacing -- **Mobile**: Scrollable background, adjusted padding - -## ๐Ÿ”ง Configuration Required - -### **Environment Variables** -```env -# Keycloak Configuration -NUXT_KEYCLOAK_ISSUER=https://auth.monacousa.org/realms/monacousa -NUXT_KEYCLOAK_CLIENT_ID=monacousa-portal -NUXT_KEYCLOAK_CLIENT_SECRET=[your-secret-from-keycloak] -NUXT_KEYCLOAK_CALLBACK_URL=https://portal.monacousa.org/auth/callback - -# Cookie Configuration -COOKIE_DOMAIN=.monacousa.org - -# Security Configuration -NUXT_SESSION_SECRET=[generate-48-chars] -NUXT_ENCRYPTION_KEY=[generate-32-chars] - -# Public Domain -NUXT_PUBLIC_DOMAIN=monacousa.org -``` - -### **Keycloak Client Settings** -In your Keycloak admin console, configure the `monacousa-portal` client: - -1. **Settings Tab**: - - Client authentication: `ON` - - Standard flow: `ON` (keep for fallback) - - **Direct access grants: `ON`** โš ๏ธ **REQUIRED** - - Implicit flow: `OFF` - -2. **Advanced Settings**: - - Access Token Lifespan: `15 minutes` - - Refresh Token Lifespan: `30 days` (for Remember Me) - -3. **Valid Redirect URIs**: - - `https://portal.monacousa.org/*` - - `http://localhost:6060/*` (development) - -4. **Web Origins**: - - `https://portal.monacousa.org` - - `http://localhost:6060` - -## ๐Ÿ–ผ๏ธ Assets Used - -### **Images in `/public/`** -- `MONACOUSA-Flags_376x376.png` - Logo (376x376px) -- `monaco_high_res.jpg` - Background image (high resolution) - -### **Asset Optimization** -- Logo: Transparent PNG, optimized for web -- Background: High-quality JPEG, properly compressed -- Both images are served directly from `/public/` directory - -## ๐Ÿ” Testing the Implementation - -### **Manual Testing Checklist** -- [ ] Login page loads with Monaco background and logo -- [ ] Form validation works (client and server-side) -- [ ] Successful login redirects to dashboard -- [ ] Failed login shows appropriate error messages -- [ ] Rate limiting blocks after 5 failed attempts -- [ ] Remember Me extends session to 30 days -- [ ] Forgot Password dialog opens and functions -- [ ] Password reset email is sent via Keycloak -- [ ] Responsive design works on mobile devices -- [ ] Animations and hover effects work smoothly - -### **Browser Testing** -- Chrome/Edge (Chromium-based) -- Firefox -- Safari (desktop and mobile) -- Mobile browsers (iOS Safari, Android Chrome) - -## ๐Ÿšจ Security Considerations - -### **Implemented Security Measures** -1. **Rate Limiting**: Prevents brute force attacks -2. **Input Validation**: Prevents injection attacks -3. **Secure Cookies**: HttpOnly, Secure, SameSite protection -4. **Domain Scoping**: Cookies work across subdomains -5. **Session Encryption**: All session data encrypted -6. **Audit Logging**: Security events logged for monitoring -7. **Error Handling**: Generic error messages to prevent information disclosure - -### **Production Recommendations** -1. **HTTPS Only**: Ensure all traffic uses HTTPS -2. **Security Headers**: Implement CSP, HSTS, etc. -3. **Log Monitoring**: Monitor failed login attempts -4. **Regular Updates**: Keep Keycloak and dependencies updated -5. **Backup Strategy**: Regular backups of Keycloak realm - -## ๐Ÿ› Troubleshooting - -### **Common Issues** - -#### **Login Redirects to Itself** -- Check Keycloak configuration has Direct Access Grants enabled -- Verify environment variables are set correctly -- Check browser console for JavaScript errors - -#### **Cookies Not Working** -- Ensure `COOKIE_DOMAIN=.monacousa.org` is set -- Verify HTTPS is working in production -- Check browser developer tools for cookie issues - -#### **Password Reset Not Working** -- Verify Keycloak client has admin permissions -- Check SMTP configuration in Keycloak -- Review server logs for Keycloak API errors - -#### **Rate Limiting Too Aggressive** -- Adjust limits in `server/api/auth/direct-login.post.ts` -- Consider implementing Redis for production rate limiting -- Monitor logs for legitimate users being blocked - -### **Debug Logging** -The implementation includes comprehensive logging: -- `๐Ÿ”` Authentication attempts -- `๐Ÿ“` Login parameters (sanitized) -- `๐Ÿ”ง` Configuration validation -- `โœ…` Successful operations -- `โŒ` Errors and failures -- `๐Ÿšจ` Security events - -## ๐Ÿ”„ Future Enhancements - -### **Potential Improvements** -1. **Social Login**: Add Google, Microsoft, GitHub integration -2. **Two-Factor Authentication**: SMS or TOTP support -3. **Progressive Web App**: Enhanced mobile experience -4. **Dark Mode**: Theme switching capability -5. **Internationalization**: Multi-language support -6. **Advanced Analytics**: Login metrics and reporting - -### **Performance Optimizations** -1. **Image Optimization**: WebP format support -2. **Lazy Loading**: Optimize initial page load -3. **CDN Integration**: Serve assets from CDN -4. **Caching Strategy**: Implement proper caching headers - -## ๐Ÿ“Š Implementation Summary - -### **Development Time**: ~4 hours -### **Complexity**: Medium (6/10) -### **Files Modified**: 8 files -### **New Components**: 2 components -### **API Endpoints**: 2 endpoints -### **Security Features**: 7 implemented - -The custom login system successfully provides a branded, secure, and user-friendly authentication experience while maintaining integration with your existing Keycloak infrastructure. diff --git a/LOGIN_FIX_SUMMARY.md b/LOGIN_FIX_SUMMARY.md deleted file mode 100644 index bf099ae..0000000 --- a/LOGIN_FIX_SUMMARY.md +++ /dev/null @@ -1,244 +0,0 @@ -# MonacoUSA Portal - Login Issue Fix Summary - -## Issue Description - -The login functionality was experiencing redirect failures after successful authentication. Users could successfully authenticate with Keycloak, but the redirect to the dashboard was failing with 502 Bad Gateway errors and CORS issues. - -## Root Causes Identified - -1. **Service Worker Interference**: The PWA service worker was caching authentication-related routes, causing conflicts during login redirects. -2. **Cookie Domain Issues**: The session cookie was being set with an explicit domain (`.monacousa.org`) which could cause issues in certain deployment scenarios. -3. **Redirect Method**: Using `window.location.href` for redirects was causing hard page reloads that conflicted with the SPA architecture. -4. **Nginx Proxy Timeouts**: Missing proxy timeout configurations could cause 502 errors during authentication flows. - -## Fixes Applied - -### 1. PWA Service Worker Configuration (`nuxt.config.ts`) - -**Changes Made:** -- Added authentication-related paths to `navigateFallbackDenylist` -- Reduced API cache duration from 24 hours to 5 minutes -- Added `cleanupOutdatedCaches: true` for better cache management - -```typescript -navigateFallbackDenylist: [ - /^\/api\//, - /^\/auth\//, - /^\/login/, - /^\/dashboard/ -], -``` - -**Why This Fixes It:** -- Prevents service worker from intercepting authentication flows -- Ensures fresh API responses during login -- Eliminates cache-related redirect conflicts - -### 2. Cookie Domain Fix (`server/api/auth/direct-login.post.ts`) - -**Changes Made:** -- Removed explicit cookie domain setting -- Let cookies default to the current domain - -```typescript -// Before: domain: cookieDomain, -// After: No domain specified (defaults to current domain) -setCookie(event, 'monacousa-session', cookieValue, { - httpOnly: true, - secure: process.env.NODE_ENV === 'production', - sameSite: 'lax', - maxAge, - path: '/', -}); -``` - -**Why This Fixes It:** -- Eliminates cross-domain cookie issues -- Ensures cookies work correctly in all deployment scenarios -- Follows browser security best practices - -### 3. Login Page Refactor (`pages/login.vue`) - -**Changes Made:** -- Replaced direct API calls with `useAuth()` composable -- Removed `window.location.href` redirect -- Improved state management integration - -```typescript -// Before: window.location.href = response.redirectTo || '/dashboard'; -// After: Uses useAuth().login() which handles navigation properly -const result = await login({ - username: credentials.value.username, - password: credentials.value.password, - rememberMe: credentials.value.rememberMe -}); -``` - -**Why This Fixes It:** -- Proper SPA navigation without hard page reloads -- Better integration with Nuxt's authentication state -- Eliminates service worker conflicts during navigation - -### 4. Nginx Proxy Configuration (`nginx-portal.conf`) - -**Changes Made:** -- Added proxy timeout configurations -- Improved buffer settings for better performance - -```nginx -proxy_connect_timeout 60s; -proxy_send_timeout 60s; -proxy_read_timeout 60s; -proxy_buffer_size 4k; -proxy_buffers 4 32k; -proxy_busy_buffers_size 64k; -proxy_temp_file_write_size 64k; -``` - -**Why This Fixes It:** -- Prevents 502 errors during authentication flows -- Handles larger response payloads better -- Improves overall proxy stability - -## Testing the Fix - -### 1. Clear Browser Cache -```bash -# Clear all browser data for portal.monacousa.org -# Or use incognito/private browsing mode -``` - -### 2. Restart Services -```bash -# Restart Nginx -sudo systemctl restart nginx - -# Restart the Nuxt application -# (depends on your deployment method) -``` - -### 3. Test Login Flow -1. Navigate to `https://portal.monacousa.org/login` -2. Enter valid credentials -3. Verify successful redirect to dashboard -4. Check browser console for errors - -### 4. Use Debug Script -```bash -# Run the debug script to test API endpoints -node debug-login.js -``` - -## Verification Steps - -### Browser Console Checks -- No CORS errors should appear -- No 502 Bad Gateway errors -- Service worker should not intercept auth routes - -### Network Tab Verification -- Login POST request should return 200 -- Session cookie should be set correctly -- Dashboard redirect should work without errors - -### Server Logs -- Should show successful login messages -- No cookie domain warnings -- Proper session creation logs - -## Troubleshooting - -### If Login Still Fails - -1. **Check Service Worker** - ```javascript - // In browser console - navigator.serviceWorker.getRegistrations().then(registrations => { - registrations.forEach(registration => registration.unregister()); - }); - ``` - -2. **Verify Cookie Settings** - - Check browser dev tools > Application > Cookies - - Ensure `monacousa-session` cookie is set - - Verify cookie domain matches current domain - -3. **Check Nginx Logs** - ```bash - tail -f /var/log/nginx/portal.monacousa.org.error.log - ``` - -4. **Verify Keycloak Configuration** - - Ensure all environment variables are set - - Test Keycloak connectivity - - Verify client configuration - -### Common Issues - -1. **Still Getting 502 Errors** - - Check if Nuxt application is running on port 6060 - - Verify nginx can connect to backend - - Check firewall settings - -2. **Cookies Not Being Set** - - Verify HTTPS is working correctly - - Check if secure flag is appropriate for environment - - Ensure no conflicting cookie policies - -3. **Service Worker Issues** - - Clear browser cache completely - - Unregister service worker manually - - Check PWA configuration - -## Environment Variables - -Ensure these are properly configured: - -```env -# Keycloak Configuration -NUXT_KEYCLOAK_ISSUER=https://auth.monacousa.org/realms/monacousa -NUXT_KEYCLOAK_CLIENT_ID=monacousa-portal -NUXT_KEYCLOAK_CLIENT_SECRET=your-secret - -# Session Security -NUXT_SESSION_SECRET=your-48-character-secret -NUXT_ENCRYPTION_KEY=your-32-character-key - -# Public Configuration -NUXT_PUBLIC_DOMAIN=monacousa.org -``` - -## Deployment Notes - -1. **Nginx Configuration** - - Reload nginx after configuration changes - - Test configuration with `nginx -t` - -2. **Application Restart** - - Restart Nuxt application to pick up changes - - Clear any application-level caches - -3. **SSL Certificates** - - Ensure SSL certificates are valid - - Verify HTTPS is working correctly - -## Success Indicators - -โœ… Login form submits without errors -โœ… User is redirected to dashboard -โœ… Session is maintained across page refreshes -โœ… No console errors related to authentication -โœ… Health check endpoint returns "healthy" -โœ… Service worker doesn't interfere with auth flows - -## Files Modified - -1. `nuxt.config.ts` - PWA service worker configuration -2. `pages/login.vue` - Login page refactor -3. `server/api/auth/direct-login.post.ts` - Cookie domain fix and direct encryption -4. `server/utils/session.ts` - Removed cookie domain from session manager -5. `nginx-portal.conf` - Proxy timeout configuration -6. `debug-login.js` - Debug script (new file) -7. `LOGIN_FIX_SUMMARY.md` - This documentation (new file) - -The fixes address the core issues causing login redirect failures and should provide a stable authentication experience. diff --git a/debug-login.js b/debug-login.js deleted file mode 100644 index 42b2760..0000000 --- a/debug-login.js +++ /dev/null @@ -1,89 +0,0 @@ -#!/usr/bin/env node - -// Simple debug script to test the login flow -const https = require('https'); -const http = require('http'); - -const BASE_URL = 'https://portal.monacousa.org'; - -async function makeRequest(url, options = {}) { - return new Promise((resolve, reject) => { - const protocol = url.startsWith('https') ? https : http; - - const req = protocol.request(url, { - method: options.method || 'GET', - headers: { - 'Content-Type': 'application/json', - 'User-Agent': 'Debug-Script/1.0', - ...options.headers - } - }, (res) => { - let data = ''; - res.on('data', chunk => data += chunk); - res.on('end', () => { - resolve({ - status: res.statusCode, - headers: res.headers, - body: data - }); - }); - }); - - req.on('error', reject); - - if (options.body) { - req.write(JSON.stringify(options.body)); - } - - req.end(); - }); -} - -async function testLoginFlow() { - console.log('๐Ÿ” Testing MonacoUSA Portal Login Flow'); - console.log('=====================================\n'); - - try { - // Test 1: Health check - console.log('1. Testing health endpoint...'); - const health = await makeRequest(`${BASE_URL}/api/health`); - console.log(` Status: ${health.status}`); - console.log(` Response: ${health.body.substring(0, 100)}...\n`); - - // Test 2: Session check (should be unauthenticated) - console.log('2. Testing session endpoint...'); - const session = await makeRequest(`${BASE_URL}/api/auth/session`); - console.log(` Status: ${session.status}`); - console.log(` Response: ${session.body.substring(0, 100)}...\n`); - - // Test 3: Login attempt - console.log('3. Testing direct login...'); - const login = await makeRequest(`${BASE_URL}/api/auth/direct-login`, { - method: 'POST', - body: { - username: 'present', - password: 'your-password-here', - rememberMe: false - } - }); - console.log(` Status: ${login.status}`); - console.log(` Headers: ${JSON.stringify(login.headers, null, 2)}`); - console.log(` Response: ${login.body.substring(0, 200)}...\n`); - - // Test 4: Check if we can access dashboard - console.log('4. Testing dashboard access...'); - const dashboard = await makeRequest(`${BASE_URL}/dashboard`, { - headers: { - 'Cookie': login.headers['set-cookie'] ? login.headers['set-cookie'].join('; ') : '' - } - }); - console.log(` Status: ${dashboard.status}`); - console.log(` Response: ${dashboard.body.substring(0, 100)}...\n`); - - } catch (error) { - console.error('โŒ Error during testing:', error.message); - } -} - -// Run the test -testLoginFlow(); diff --git a/middleware/auth.ts b/middleware/auth.ts index 1d7d392..a8dd567 100644 --- a/middleware/auth.ts +++ b/middleware/auth.ts @@ -7,23 +7,12 @@ export default defineNuxtRouteMiddleware(async (to) => { // Use the same auth system as the rest of the app const { isAuthenticated, checkAuth, user } = useAuth(); - console.log('๐Ÿ›ก๏ธ Auth middleware running for:', to.path); - // Ensure auth is checked if user isn't loaded if (!user.value) { - console.log('๐Ÿ”„ User not loaded, checking auth...'); await checkAuth(); } - console.log('โœ… Auth middleware check:', { - isAuthenticated: isAuthenticated.value, - user: user.value?.email - }); - if (!isAuthenticated.value) { - console.log('โŒ User not authenticated, redirecting to login'); return navigateTo('/login'); } - - console.log('โœ… Auth middleware passed, allowing access to:', to.path); }); diff --git a/sequential-thinking/.gitignore b/sequential-thinking/.gitignore deleted file mode 100644 index 7f106e9..0000000 --- a/sequential-thinking/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -node_modules/ -build/ -*.log -.env* \ No newline at end of file diff --git a/sequential-thinking/README.md b/sequential-thinking/README.md deleted file mode 100644 index fba72f7..0000000 --- a/sequential-thinking/README.md +++ /dev/null @@ -1,70 +0,0 @@ -# sequential-thinking MCP Server - -A Model Context Protocol server - -This is a TypeScript-based MCP server that implements a simple notes system. It demonstrates core MCP concepts by providing: - -- Resources representing text notes with URIs and metadata -- Tools for creating new notes -- Prompts for generating summaries of notes - -## Features - -### Resources -- List and access notes via `note://` URIs -- Each note has a title, content and metadata -- Plain text mime type for simple content access - -### Tools -- `create_note` - Create new text notes - - Takes title and content as required parameters - - Stores note in server state - -### Prompts -- `summarize_notes` - Generate a summary of all stored notes - - Includes all note contents as embedded resources - - Returns structured prompt for LLM summarization - -## Development - -Install dependencies: -```bash -npm install -``` - -Build the server: -```bash -npm run build -``` - -For development with auto-rebuild: -```bash -npm run watch -``` - -## Installation - -To use with Claude Desktop, add the server config: - -On MacOS: `~/Library/Application Support/Claude/claude_desktop_config.json` -On Windows: `%APPDATA%/Claude/claude_desktop_config.json` - -```json -{ - "mcpServers": { - "sequential-thinking": { - "command": "/path/to/sequential-thinking/build/index.js" - } - } -} -``` - -### Debugging - -Since MCP servers communicate over stdio, debugging can be challenging. We recommend using the [MCP Inspector](https://github.com/modelcontextprotocol/inspector), which is available as a package script: - -```bash -npm run inspector -``` - -The Inspector will provide a URL to access debugging tools in your browser. diff --git a/sequential-thinking/package.json b/sequential-thinking/package.json deleted file mode 100644 index cd1ab6e..0000000 --- a/sequential-thinking/package.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "name": "sequential-thinking", - "version": "0.1.0", - "description": "A Model Context Protocol server", - "private": true, - "type": "module", - "bin": { - "sequential-thinking": "./build/index.js" - }, - "files": [ - "build" - ], - "scripts": { - "build": "tsc && node -e \"require('fs').chmodSync('build/index.js', '755')\"", - "prepare": "npm run build", - "watch": "tsc --watch", - "inspector": "npx @modelcontextprotocol/inspector build/index.js" - }, - "dependencies": { - "@modelcontextprotocol/sdk": "0.6.0" - }, - "devDependencies": { - "@types/node": "^20.11.24", - "typescript": "^5.3.3" - } -} diff --git a/sequential-thinking/src/index.ts b/sequential-thinking/src/index.ts deleted file mode 100644 index efd871e..0000000 --- a/sequential-thinking/src/index.ts +++ /dev/null @@ -1,243 +0,0 @@ -#!/usr/bin/env node -import { Server } from '@modelcontextprotocol/sdk/server/index.js'; -import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js'; -import { - CallToolRequestSchema, - ErrorCode, - ListToolsRequestSchema, - McpError, -} from '@modelcontextprotocol/sdk/types.js'; - -interface ThoughtStep { - thoughtNumber: number; - thought: string; - isRevision?: boolean; - revisesThought?: number; - branchFromThought?: number; - branchId?: string; - timestamp: string; -} - -interface SequentialThinkingArgs { - thought: string; - nextThoughtNeeded: boolean; - thoughtNumber: number; - totalThoughts: number; - isRevision?: boolean; - revisesThought?: number; - branchFromThought?: number; - branchId?: string; - needsMoreThoughts?: boolean; -} - -const isValidSequentialThinkingArgs = ( - args: any -): args is SequentialThinkingArgs => - typeof args === 'object' && - args !== null && - typeof args.thought === 'string' && - typeof args.nextThoughtNeeded === 'boolean' && - typeof args.thoughtNumber === 'number' && - typeof args.totalThoughts === 'number' && - (args.isRevision === undefined || typeof args.isRevision === 'boolean') && - (args.revisesThought === undefined || typeof args.revisesThought === 'number') && - (args.branchFromThought === undefined || typeof args.branchFromThought === 'number') && - (args.branchId === undefined || typeof args.branchId === 'string') && - (args.needsMoreThoughts === undefined || typeof args.needsMoreThoughts === 'boolean'); - -class SequentialThinkingServer { - private server: Server; - private thoughtHistory: ThoughtStep[] = []; - private disableLogging: boolean; - - constructor() { - this.disableLogging = process.env.DISABLE_THOUGHT_LOGGING === 'true'; - - this.server = new Server( - { - name: 'sequential-thinking-server', - version: '0.1.0', - }, - { - capabilities: { - tools: {}, - }, - } - ); - - this.setupToolHandlers(); - - // Error handling - this.server.onerror = (error) => console.error('[MCP Error]', error); - process.on('SIGINT', async () => { - await this.server.close(); - process.exit(0); - }); - } - - private setupToolHandlers() { - this.server.setRequestHandler(ListToolsRequestSchema, async () => ({ - tools: [ - { - name: 'sequential_thinking', - description: 'Facilitates a detailed, step-by-step thinking process for problem-solving and analysis. Supports dynamic revision, branching, and iterative refinement of thoughts.', - inputSchema: { - type: 'object', - properties: { - thought: { - type: 'string', - description: 'The current thinking step or analysis', - }, - nextThoughtNeeded: { - type: 'boolean', - description: 'Whether another thought step is needed to continue the analysis', - }, - thoughtNumber: { - type: 'integer', - description: 'Current thought number in the sequence', - minimum: 1, - }, - totalThoughts: { - type: 'integer', - description: 'Estimated total number of thoughts needed (can be adjusted dynamically)', - minimum: 1, - }, - isRevision: { - type: 'boolean', - description: 'Whether this thought revises or refines previous thinking', - }, - revisesThought: { - type: 'integer', - description: 'Which thought number is being reconsidered (if isRevision is true)', - minimum: 1, - }, - branchFromThought: { - type: 'integer', - description: 'Thought number from which this branches into alternative reasoning', - minimum: 1, - }, - branchId: { - type: 'string', - description: 'Identifier for the branch (e.g., "alternative_approach", "edge_case")', - }, - needsMoreThoughts: { - type: 'boolean', - description: 'Whether the total number of thoughts should be increased', - }, - }, - required: ['thought', 'nextThoughtNeeded', 'thoughtNumber', 'totalThoughts'], - }, - }, - ], - })); - - this.server.setRequestHandler(CallToolRequestSchema, async (request) => { - if (request.params.name !== 'sequential_thinking') { - throw new McpError( - ErrorCode.MethodNotFound, - `Unknown tool: ${request.params.name}` - ); - } - - if (!isValidSequentialThinkingArgs(request.params.arguments)) { - throw new McpError( - ErrorCode.InvalidParams, - 'Invalid sequential thinking arguments' - ); - } - - const args = request.params.arguments; - - try { - // Create thought step - const thoughtStep: ThoughtStep = { - thoughtNumber: args.thoughtNumber, - thought: args.thought, - isRevision: args.isRevision, - revisesThought: args.revisesThought, - branchFromThought: args.branchFromThought, - branchId: args.branchId, - timestamp: new Date().toISOString(), - }; - - // Add to history - this.thoughtHistory.push(thoughtStep); - - // Log thought if logging is enabled - if (!this.disableLogging) { - console.error(`[Thought ${args.thoughtNumber}/${args.totalThoughts}]${args.isRevision ? ' (Revision)' : ''}${args.branchId ? ` [Branch: ${args.branchId}]` : ''}: ${args.thought}`); - } - - // Prepare response - let responseText = `**Thought ${args.thoughtNumber}/${args.totalThoughts}**`; - - if (args.isRevision && args.revisesThought) { - responseText += ` *(Revising thought ${args.revisesThought})*`; - } - - if (args.branchId) { - responseText += ` *[Branch: ${args.branchId}]*`; - if (args.branchFromThought) { - responseText += ` *(from thought ${args.branchFromThought})*`; - } - } - - responseText += `\n\n${args.thought}`; - - if (args.needsMoreThoughts) { - responseText += `\n\n*Note: Analysis indicates more thoughts may be needed beyond the initial estimate of ${args.totalThoughts}.*`; - } - - if (args.nextThoughtNeeded) { - responseText += `\n\n*Continuing to next thought...*`; - } else { - responseText += `\n\n*Analysis complete.*`; - - // Provide summary if this is the final thought - if (this.thoughtHistory.length > 1) { - responseText += `\n\n**Summary**: Completed sequential thinking process with ${this.thoughtHistory.length} thought steps.`; - - const revisions = this.thoughtHistory.filter(t => t.isRevision).length; - const branches = new Set(this.thoughtHistory.filter(t => t.branchId).map(t => t.branchId)).size; - - if (revisions > 0) { - responseText += ` Included ${revisions} revision${revisions > 1 ? 's' : ''}.`; - } - - if (branches > 0) { - responseText += ` Explored ${branches} alternative branch${branches > 1 ? 'es' : ''}.`; - } - } - } - - return { - content: [ - { - type: 'text', - text: responseText, - }, - ], - }; - } catch (error) { - return { - content: [ - { - type: 'text', - text: `Error in sequential thinking process: ${error instanceof Error ? error.message : 'Unknown error'}`, - }, - ], - isError: true, - }; - } - }); - } - - async run() { - const transport = new StdioServerTransport(); - await this.server.connect(transport); - console.error('Sequential Thinking MCP server running on stdio'); - } -} - -const server = new SequentialThinkingServer(); -server.run().catch(console.error); diff --git a/sequential-thinking/tsconfig.json b/sequential-thinking/tsconfig.json deleted file mode 100644 index a14bee0..0000000 --- a/sequential-thinking/tsconfig.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "compilerOptions": { - "target": "ES2022", - "module": "Node16", - "moduleResolution": "Node16", - "outDir": "./build", - "rootDir": "./src", - "strict": true, - "esModuleInterop": true, - "skipLibCheck": true, - "forceConsistentCasingInFileNames": true - }, - "include": ["src/**/*"], - "exclude": ["node_modules"] -} diff --git a/server/api/auth/direct-login.post.ts b/server/api/auth/direct-login.post.ts index eb0119c..5088123 100644 --- a/server/api/auth/direct-login.post.ts +++ b/server/api/auth/direct-login.post.ts @@ -83,18 +83,9 @@ const getClientIP = (event: any): string => { }; export default defineEventHandler(async (event) => { - console.log('๐Ÿ” Direct login endpoint called at:', new Date().toISOString()); - try { const { username, password, rememberMe } = await readBody(event); const clientIP = getClientIP(event) || 'unknown'; - - console.log('๐Ÿ“ Login attempt:', { - username: username ? 'present' : 'missing', - hasPassword: !!password, - rememberMe, - ip: clientIP - }); // Input validation const validationErrors = validateLoginInput(username, password); @@ -127,11 +118,6 @@ export default defineEventHandler(async (event) => { }); } - console.log('๐Ÿ”ง Using Keycloak config:', { - issuer: config.keycloak.issuer, - clientId: config.keycloak.clientId, - hasSecret: !!config.keycloak.clientSecret - }); // Direct authentication with Keycloak using Resource Owner Password Credentials flow const tokenResponse = await fetch(`${config.keycloak.issuer}/protocol/openid-connect/token`, { @@ -178,15 +164,13 @@ export default defineEventHandler(async (event) => { } const tokens = await tokenResponse.json(); - console.log('โœ… Token exchange successful'); - // Decode the access token to see what's inside + // Decode the access token to extract user information let tokenPayload = null; try { const tokenParts = tokens.access_token.split('.'); const payload = JSON.parse(Buffer.from(tokenParts[1], 'base64').toString()); tokenPayload = payload; - console.log('๐Ÿ” Access token payload:', JSON.stringify(payload, null, 2)); } catch (err) { console.warn('โš ๏ธ Could not decode access token:', err); } @@ -208,7 +192,6 @@ export default defineEventHandler(async (event) => { } const userInfo = await userResponse.json(); - console.log('โœ… User info retrieved:', JSON.stringify(userInfo, null, 2)); // Extract groups/roles from multiple possible locations const extractGroups = (tokenPayload: any, userInfo: any): string[] => { @@ -217,19 +200,16 @@ export default defineEventHandler(async (event) => { // Check userInfo for groups (from userinfo endpoint) if (userInfo.groups && Array.isArray(userInfo.groups)) { allGroups.push(...userInfo.groups); - console.log('๐Ÿ“‹ Found groups in userInfo.groups:', userInfo.groups); } // Check userInfo for roles if (userInfo.roles && Array.isArray(userInfo.roles)) { allGroups.push(...userInfo.roles); - console.log('๐Ÿ“‹ Found roles in userInfo.roles:', userInfo.roles); } // Check token payload for realm_access.roles if (tokenPayload?.realm_access?.roles && Array.isArray(tokenPayload.realm_access.roles)) { allGroups.push(...tokenPayload.realm_access.roles); - console.log('๐Ÿ“‹ Found roles in token realm_access.roles:', tokenPayload.realm_access.roles); } // Check token payload for resource_access roles @@ -238,7 +218,6 @@ export default defineEventHandler(async (event) => { const clientRoles = tokenPayload.resource_access[clientId]?.roles; if (clientRoles && Array.isArray(clientRoles)) { allGroups.push(...clientRoles); - console.log(`๐Ÿ“‹ Found roles in token resource_access.${clientId}.roles:`, clientRoles); } }); } @@ -246,7 +225,6 @@ export default defineEventHandler(async (event) => { // Check token payload for groups claim if (tokenPayload?.groups && Array.isArray(tokenPayload.groups)) { allGroups.push(...tokenPayload.groups); - console.log('๐Ÿ“‹ Found groups in token.groups:', tokenPayload.groups); } // Remove duplicates and filter out default Keycloak roles @@ -254,22 +232,17 @@ export default defineEventHandler(async (event) => { !['default-roles-monacousa', 'offline_access', 'uma_authorization'].includes(group) ); - console.log('๐Ÿ“‹ Final extracted groups:', uniqueGroups); return uniqueGroups; }; // Tier determination logic - admin > board > user priority const determineTier = (groups: string[]): 'user' | 'board' | 'admin' => { - console.log('๐ŸŽฏ Determining tier from groups:', groups); if (groups.includes('admin')) { - console.log('๐ŸŽฏ User has admin tier'); return 'admin'; } if (groups.includes('board')) { - console.log('๐ŸŽฏ User has board tier'); return 'board'; } - console.log('๐ŸŽฏ User has default user tier'); return 'user'; // Default tier }; @@ -301,12 +274,6 @@ export default defineEventHandler(async (event) => { lastActivity: Date.now() }; - console.log('๐Ÿ“Š Session data size check:', { - userTier, - groupCount: userGroups.length, - sessionSize: JSON.stringify(sessionData).length - }); - // Create session with server-side storage const sessionManager = createSessionManager(); @@ -318,9 +285,6 @@ export default defineEventHandler(async (event) => { const cookieParts = cookieString.split(';')[0].split('='); const sessionId = cookieParts[1]; - console.log(`๐Ÿช Setting session cookie (Remember Me: ${!!rememberMe}), session ID: ${sessionId.substring(0, 8)}...`); - console.log(`๐Ÿ“ Cookie size: ${sessionId.length} chars (much smaller!)`); - // Set the cookie using Nuxt's setCookie helper const maxAge = !!rememberMe ? 60 * 60 * 24 * 30 : 60 * 60 * 24 * 7; // 30 days vs 7 days setCookie(event, 'monacousa-session', sessionId, { @@ -331,8 +295,6 @@ export default defineEventHandler(async (event) => { path: '/', }); - console.log('โœ… Session cookie set successfully'); - } catch (cookieError) { console.error('โŒ Failed to set session cookie:', cookieError); throw createError({ @@ -345,8 +307,6 @@ export default defineEventHandler(async (event) => { clearFailedAttempts(clientIP); console.log('โœ… Login successful for user:', userInfo.email); - console.log('๐ŸŽฏ User tier assigned:', userTier); - console.log('๐Ÿ“‹ User groups assigned:', userGroups); // Add a small delay to ensure cookie is set await new Promise(resolve => setTimeout(resolve, 100)); @@ -355,8 +315,6 @@ export default defineEventHandler(async (event) => { setResponseStatus(event, 200); setHeader(event, 'Content-Type', 'application/json'); - console.log('๐Ÿ“ค Sending success response'); - // Return a minimal response to prevent 502 errors return { success: true, diff --git a/server/utils/session.ts b/server/utils/session.ts index d80d019..7095c53 100644 --- a/server/utils/session.ts +++ b/server/utils/session.ts @@ -12,12 +12,16 @@ const sessionStore = new Map { const now = Date.now(); + let cleanedCount = 0; for (const [sessionId, session] of sessionStore.entries()) { if (now > session.expiresAt) { sessionStore.delete(sessionId); - console.log('๐Ÿงน Cleaned up expired session:', sessionId.substring(0, 8) + '...'); + cleanedCount++; } } + if (cleanedCount > 0) { + console.log(`๐Ÿงน Cleaned up ${cleanedCount} expired sessions`); + } }, 5 * 60 * 1000); export class SessionManager { @@ -43,9 +47,6 @@ export class SessionManager { rememberMe }); - console.log(`๐Ÿช Creating session cookie (Remember Me: ${rememberMe}) with session ID: ${sessionId.substring(0, 8)}...`); - console.log(`๐Ÿ“Š Session store size: ${sessionStore.size} sessions`); - return serialize(this.cookieName, sessionId, { httpOnly: true, secure: true, @@ -57,7 +58,6 @@ export class SessionManager { getSession(cookieHeader?: string): SessionData | null { if (!cookieHeader) { - console.log('โŒ No cookie header provided'); return null; } @@ -65,21 +65,16 @@ export class SessionManager { const sessionId = cookies[this.cookieName]; if (!sessionId) { - console.log('โŒ No session cookie found'); return null; } - console.log(`๐Ÿ” Looking up session: ${sessionId.substring(0, 8)}...`); - const sessionEntry = sessionStore.get(sessionId); if (!sessionEntry) { - console.log('โŒ Session not found in store'); return null; } // Check if session is expired if (Date.now() > sessionEntry.expiresAt) { - console.log('โŒ Session expired, removing from store'); sessionStore.delete(sessionId); return null; } @@ -87,7 +82,6 @@ export class SessionManager { // Update last activity sessionEntry.data.lastActivity = Date.now(); - console.log('โœ… Session found and valid for user:', sessionEntry.data.user.email); return sessionEntry.data; }