commit d778206940d435052780fe866513449a8aaf103c Author: mahmamdouh Date: Sun Nov 23 19:57:05 2025 +0100 init tools repo diff --git a/asf-cloud-server/TBM_devbench/.env.example b/asf-cloud-server/TBM_devbench/.env.example new file mode 100644 index 0000000..800526b --- /dev/null +++ b/asf-cloud-server/TBM_devbench/.env.example @@ -0,0 +1,16 @@ +# Server Configuration +PORT=3001 + +# Database Configuration +DB_PATH=./devbench.db + +# Session Configuration +SESSION_SECRET=your-secret-key-here + +# SSH Configuration (for provision script) +SSH_USER=asf +SSH_HOST=asf-tb.duckdns.org +SSH_PASS=ASF + +# Provision Script Configuration +PROVISION_SCRIPT=./provision_vm.sh \ No newline at end of file diff --git a/asf-cloud-server/TBM_devbench/.gitignore b/asf-cloud-server/TBM_devbench/.gitignore new file mode 100644 index 0000000..0e1b811 --- /dev/null +++ b/asf-cloud-server/TBM_devbench/.gitignore @@ -0,0 +1,52 @@ +# Dependencies +node_modules/ +npm-debug.log* +yarn-debug.log* +yarn-error.log* + +# Database +*.db +*.sqlite +*.sqlite3 +data/ + +# Logs +logs/ +*.log +/var/log/ + +# Runtime data +pids/ +*.pid +*.seed +*.pid.lock + +# Environment variables +.env +.env.local +.env.development.local +.env.test.local +.env.production.local + +# IDE +.vscode/ +.idea/ +*.swp +*.swo +*~ + +# OS +.DS_Store +.DS_Store? +._* +.Spotlight-V100 +.Trashes +ehthumbs.db +Thumbs.db + +# Docker +.dockerignore + +# Temporary files +tmp/ +temp/ \ No newline at end of file diff --git a/asf-cloud-server/TBM_devbench/CHANGELOG.md b/asf-cloud-server/TBM_devbench/CHANGELOG.md new file mode 100644 index 0000000..2c9d6a7 --- /dev/null +++ b/asf-cloud-server/TBM_devbench/CHANGELOG.md @@ -0,0 +1,121 @@ +# Changelog - DevBench Manager Updates + +## Changes Made + +### 1. Updated SSH Access Configuration +- **File**: `provision_vm.sh` +- **Changes**: + - Updated SSH connection to use port 49152 + - Changed SSH host to `asf@asf-server.duckdns.org -p 49152` + - Modified SSH command to include port parameter + +### 2. Updated Output Parsing +- **File**: `provision_vm.sh` +- **Changes**: + - Now extracts SSH Port and VNC Port from script output + - Removed IP address extraction + - Parses output format: `SSH Port: XXXX` and `VNC Port: XXXX` + - Extracts VM name from success message + +### 3. Updated Server-Side Processing +- **File**: `server.js` +- **Changes**: + - Modified DevBench creation to parse new output format (SSH_PORT, VNC_PORT, VM_NAME) + - Stores only port numbers in database (ssh_info and vnc_info fields) + - Removed vm_ip field from database schema + - Added `/help` route for help page + +### 4. Updated User Interface +- **File**: `views/dashboard.ejs` +- **Changes**: + - Display "SSH Port" instead of full SSH command + - Display "VNC Port" instead of full VNC info + - Added link to help page in connection info section + - Improved visual presentation with larger font for ports + +### 5. Updated Admin Interface +- **File**: `views/admin.ejs` +- **Changes**: + - Replaced "IP Address" column with "SSH Port" and "VNC Port" columns + - Shows port numbers for each DevBench + +### 6. Added Help Page +- **File**: `views/help.ejs` (NEW) +- **Features**: + - Step-by-step guide for using SSH Config Manager tool + - Instructions for configuring SSH access + - Download link for SSH Config Manager + - Connection information and important notes + - Styled with Bootstrap cards and custom CSS + +### 7. Updated Navigation +- **File**: `views/layout.ejs` +- **Changes**: + - Added Help icon/link in navbar + - Added TBM icon (tbm-icon.png) in navbar + - Added favicon using TBM icon + - Help link accessible from all pages + +### 8. Added Downloadable Tool +- **Location**: `public/downloads/db_vm_ssh_config_manager.exe` +- **Purpose**: SSH configuration management tool +- **Access**: Available at `/downloads/db_vm_ssh_config_manager.exe` + +### 9. Added TBM Icon +- **Location**: `public/images/tbm-icon.png` +- **Usage**: + - Favicon for all pages + - Icon in navbar next to logo + - Branding element + +### 10. Updated Documentation +- **File**: `README.md` +- **Changes**: + - Added SSH Configuration section + - Updated database schema documentation + - Added help page to user features + - Updated project structure + - Added help route to API endpoints + +## Summary of User-Facing Changes + +### For Users: +1. **Simplified Connection Info**: Now shows only SSH Port and VNC Port numbers +2. **Help Page**: Accessible via navbar, provides detailed setup instructions +3. **SSH Config Tool**: Downloadable tool to simplify SSH configuration +4. **Visual Improvements**: TBM icon added to branding + +### For Administrators: +1. **Updated Admin Dashboard**: Shows SSH and VNC ports instead of IP addresses +2. **Same management capabilities**: All admin functions remain unchanged + +## Technical Details + +### SSH Connection Format: +- **Old**: Full SSH command string +- **New**: Port number only (e.g., "6004") + +### VNC Connection Format: +- **Old**: Full VNC connection string +- **New**: Port number only (e.g., "5004") + +### Database Changes: +- Removed: `vm_ip` field +- Modified: `ssh_info` now stores SSH port number +- Modified: `vnc_info` now stores VNC port number + +## Testing Recommendations + +1. Test DevBench creation with new output parsing +2. Verify SSH port and VNC port display correctly +3. Test help page accessibility +4. Verify SSH Config Manager download +5. Check TBM icon display on all pages +6. Test on different browsers for favicon display + +## Migration Notes + +If you have existing DevBenches in the database: +- Old entries may still have full SSH/VNC strings or IP addresses +- New entries will have port numbers only +- Consider running a migration script if needed to update old entries diff --git a/asf-cloud-server/TBM_devbench/Dockerfile b/asf-cloud-server/TBM_devbench/Dockerfile new file mode 100644 index 0000000..77c5baa --- /dev/null +++ b/asf-cloud-server/TBM_devbench/Dockerfile @@ -0,0 +1,27 @@ +FROM node:18-alpine + +# Install bash and other dependencies +RUN apk add --no-cache bash sshpass openssh-client wget + +WORKDIR /app + +# Copy package files +COPY package*.json ./ + +# Install dependencies +RUN npm install + +# Copy application files +COPY . . + +# Ensure public directory permissions +RUN chmod -R 755 /app/public + +# Create directories for database and logs +RUN mkdir -p /app/data /app/logs + +# Expose port +EXPOSE 3001 + +# Start the application +CMD ["npm", "start"] \ No newline at end of file diff --git a/asf-cloud-server/TBM_devbench/QUICK_START.md b/asf-cloud-server/TBM_devbench/QUICK_START.md new file mode 100644 index 0000000..9873049 --- /dev/null +++ b/asf-cloud-server/TBM_devbench/QUICK_START.md @@ -0,0 +1,248 @@ +# ๐Ÿš€ DevBench Manager - Quick Start Guide + +## One-Minute Setup + +```bash +# 1. Clone and enter directory +git clone +cd ASF_devbench + +# 2. Deploy +chmod +x deploy.sh +./deploy.sh + +# 3. Access +# Open: http://localhost:9090 +# Login: admin / admin123 +``` + +## That's It! ๐ŸŽ‰ + +--- + +## What You Get + +### ๐ŸŒ Web Interface +- **URL**: http://localhost:9090 +- **Caddy**: https://tbm.nabd-co.com (if configured) + +### ๐Ÿ‘ค Default Login +- **Username**: `admin` +- **Password**: `admin123` +- โš ๏ธ Change this after first login! + +### โœจ Features +- โœ… Create and manage VMs +- โœ… Real-time log streaming +- โœ… SSH/VNC connection info +- โœ… Dark/Light theme toggle +- โœ… Help page with guides +- โœ… SSH Config Manager download + +--- + +## Quick Commands + +### Check Status +```bash +docker ps | grep devbench-manager +``` + +### View Logs +```bash +docker-compose logs -f +``` + +### Health Check +```bash +curl http://localhost:9090/health +``` + +### Stop +```bash +docker-compose down +``` + +### Restart +```bash +docker-compose restart +``` + +--- + +## First Steps + +### 1. Login +- Open http://localhost:9090 +- Enter: admin / admin123 + +### 2. Change Password +- Go to Admin Panel +- Click "Reset Password" +- Enter new secure password + +### 3. Add Users +- Click "Add User" +- Enter username (letters only) +- Enter email and password + +### 4. Create DevBench +- User logs in +- Click "Create DevBench" +- Enter name (alphanumeric, hyphens, underscores) +- Watch real-time creation logs + +### 5. Access VM +- Copy SSH Port from connection info +- Download SSH Config Manager from Help page +- Follow setup guide + +--- + +## Theme Toggle + +Click the floating button (bottom-right) to switch between: +- ๐ŸŒž Light Theme +- ๐ŸŒ™ Dark Theme + +Your preference is saved automatically! + +--- + +## Need Help? + +### In-App +- Click the **Help** icon in navbar +- Download SSH Config Manager +- Follow step-by-step guide + +### Documentation +- `README.md` - Overview +- `docs/ARCHITECTURE.md` - System design +- `docs/STRUCTURE.md` - Code structure +- `docs/DEPLOYMENT.md` - Deployment guide +- `docs/API.md` - API reference + +### Troubleshooting +```bash +# Container not running? +docker-compose logs + +# Port in use? +sudo lsof -i :9090 + +# Permission issues? +sudo chown -R $USER:$USER data logs + +# Network issues? +docker network inspect caddy_network +``` + +--- + +## Common Tasks + +### Add a User +1. Login as admin +2. Go to Admin Panel +3. Click "Add User" +4. Fill in details +5. Click "Add User" + +### Create a DevBench +1. Login as user +2. Click "Create DevBench" +3. Enter name +4. Watch creation progress +5. Copy connection info + +### Access VM via SSH +1. Note SSH Port from DevBench +2. Download SSH Config Manager +3. Add VM to config +4. Use: `ssh vm-name` + +### Check VM Status +1. Go to Dashboard +2. Click "Check Status" +3. View current status + +--- + +## Configuration + +### Change Port +Edit `docker-compose.yml`: +```yaml +ports: + - "8080:3001" # Change 9090 to 8080 +``` + +### Environment Variables +Create `.env`: +```bash +NODE_ENV=production +SECRET_KEY=your-secret-key +ADMIN_PASSWORD=your-password +``` + +### Caddy Proxy +Add to Caddyfile: +``` +tbm.nabd-co.com { + reverse_proxy devbench-manager:3001 +} +``` + +--- + +## Maintenance + +### Backup Database +```bash +cp data/devbench.db backups/devbench-$(date +%Y%m%d).db +``` + +### View Logs +```bash +docker-compose logs --tail=100 +``` + +### Update Application +```bash +git pull +./deploy.sh +``` + +### Clean Up +```bash +./cleanup.sh +``` + +--- + +## Support + +๐Ÿ“ง **Email**: admin@nabd-co.com +๐Ÿ“š **Docs**: `/docs` directory +๐Ÿ› **Issues**: Check logs first + +--- + +## Quick Reference + +| Task | Command | +|------|---------| +| Deploy | `./deploy.sh` | +| Start | `docker-compose up -d` | +| Stop | `docker-compose down` | +| Logs | `docker-compose logs -f` | +| Health | `curl http://localhost:9090/health` | +| Backup | `cp data/devbench.db backups/` | +| Clean | `./cleanup.sh` | + +--- + +**Ready to go!** ๐Ÿš€ + +For detailed information, see `README.md` or `/docs` directory. diff --git a/asf-cloud-server/TBM_devbench/README.md b/asf-cloud-server/TBM_devbench/README.md new file mode 100644 index 0000000..ef561be --- /dev/null +++ b/asf-cloud-server/TBM_devbench/README.md @@ -0,0 +1,456 @@ +# DevBench Manager ๐Ÿš€ + +A modern web application for managing DevBench virtual machines with user authentication, real-time monitoring, and dark theme support. + +![Version](https://img.shields.io/badge/version-1.0.0-blue.svg) +![License](https://img.shields.io/badge/license-MIT-green.svg) +![Node](https://img.shields.io/badge/node-%3E%3D18.0.0-brightgreen.svg) +![Docker](https://img.shields.io/badge/docker-required-blue.svg) + +## ๐Ÿ“‹ Table of Contents + +- [Overview](#overview) +- [Features](#features) +- [Quick Start](#quick-start) +- [Documentation](#documentation) +- [Project Structure](#project-structure) +- [Configuration](#configuration) +- [Usage](#usage) +- [API](#api) +- [Troubleshooting](#troubleshooting) +- [Contributing](#contributing) +- [License](#license) + +## ๐ŸŽฏ Overview + +DevBench Manager provides a centralized web interface for creating, managing, and accessing virtual machine development environments. Built with Node.js and Express, it offers real-time monitoring, WebSocket-based updates, and a modern responsive UI with dark theme support. + +## โœจ Features + +### ๐Ÿ‘ค User Features +- ๐Ÿ” Secure authentication with session management +- ๐Ÿ–ฅ๏ธ Create and manage personal DevBenches +- ๐Ÿ“Š Real-time status monitoring +- ๐Ÿ“ Live log streaming during VM creation +- ๐Ÿ”Œ Easy access to SSH and VNC connection info +- ๐Ÿ“š Comprehensive help page with setup guide +- ๐Ÿ“ฅ Download SSH Config Manager tool +- ๐ŸŒ“ Dark/Light theme toggle +- ๐Ÿ“ฑ Responsive design for mobile and desktop + +### ๐Ÿ‘จโ€๐Ÿ’ผ Admin Features +- ๐Ÿ‘ฅ User management (add, delete, reset passwords) +- ๐Ÿ—‚๏ธ View all users and their DevBenches +- ๐Ÿ“ˆ System-wide DevBench overview +- ๐Ÿ”ง Centralized management dashboard +- ๐Ÿ“Š User activity monitoring + +### ๐Ÿ› ๏ธ Technical Features +- โšก Real-time WebSocket updates +- ๐Ÿ”’ Secure password hashing (bcrypt) +- ๐Ÿ’พ SQLite database for persistence +- ๐Ÿณ Docker containerization +- ๐Ÿ”„ Automatic status checks (60-second interval) +- ๐ŸŽจ Modern Bootstrap 5 UI +- ๐ŸŒ Caddy reverse proxy support +- ๐Ÿ“ก SSH-based VM provisioning +- ๐Ÿ” Health check endpoint +- ๐Ÿ“‹ Comprehensive logging + +## ๐Ÿš€ Quick Start + +### Prerequisites + +- **Docker**: Version 20.10+ ([Install Docker](https://docs.docker.com/get-docker/)) +- **Docker Compose**: Version 2.0+ ([Install Compose](https://docs.docker.com/compose/install/)) +- **Git**: For cloning the repository +- **SSH Access**: To VM host (asf-server.duckdns.org:49152) + +### One-Command Deployment + +```bash +# Clone the repository +git clone +cd ASF_devbench + +# Deploy +chmod +x deploy.sh +./deploy.sh +``` + +That's it! ๐ŸŽ‰ + +### Access the Application + +- **Direct Access**: http://localhost:9090 +- **Via Caddy Proxy**: https://tbm.nabd-co.com + +### Default Credentials + +``` +Username: admin +Password: admin123 +``` + +โš ๏ธ **Important**: Change the default password after first login! + +### Alternative: Manual Installation + +For development without Docker: + +```bash +# Install dependencies +npm install + +# Start application +npm start + +# Or with auto-reload +npm run dev +``` + +Access at: http://localhost:3001 + +## Configuration + +### Caddy Proxy Configuration +Add this to your Caddyfile: +``` +tbm.nabd-co.com { + reverse_proxy devbench-manager:3001 +} +``` + +Make sure your Caddy container is on the same `caddy_network`. If you need to create the network: +```bash +docker network create caddy_network +``` + +### Default Admin Account +- Username: `admin` +- Password: `admin123` +- Email: `admin@nabd-co.com` + +**Important:** Change the default admin password after first login! + +## Usage + +### For Administrators +1. Login with admin credentials +2. Add users through the "Add User" button +3. Monitor all DevBenches from the admin dashboard +4. Manage users (reset passwords, delete users) + +### For Users +1. Login with provided credentials +2. Create DevBenches using the "Create DevBench" button +3. Monitor DevBench status and connection information +4. Activate or delete DevBenches as needed + +### DevBench Naming Rules +- DevBench names can only contain letters, numbers, hyphens (-), and underscores (_) +- Final DevBench name format: `username_devbenchname` +- Example: User "john" creates "test-db" โ†’ Final name: "john_test-db" + +### SSH Configuration +The application includes a downloadable SSH Config Manager tool (`db_vm_ssh_config_manager.exe`) that helps users configure SSH access to their VMs. The tool: +- Configures SSH jump host (asf-jump) +- Sets up VM-specific SSH configurations +- Generates easy-to-use SSH commands +- Available at `/downloads/db_vm_ssh_config_manager.exe` + +Access the help page at `/help` for detailed instructions on using the SSH Config Manager. + +## API Endpoints + +### Authentication +- `GET /login` - Login page +- `POST /login` - Login submission +- `GET /logout` - Logout + +### Admin Routes +- `GET /admin` - Admin dashboard +- `POST /admin/add-user` - Add new user +- `POST /admin/delete-user/:id` - Delete user +- `POST /admin/reset-password/:id` - Reset user password + +### User Routes +- `GET /dashboard` - User dashboard +- `GET /help` - Help page with SSH configuration guide +- `POST /create-devbench` - Create new DevBench +- `POST /delete-devbench/:id` - Delete DevBench +- `POST /activate-devbench/:id` - Activate DevBench +- `GET /check-status/:id` - Check DevBench status + +## Database Schema + +### Users Table +- `id` - Primary key +- `username` - Unique username +- `email` - User email +- `password` - Hashed password +- `is_admin` - Admin flag +- `created_at` - Creation timestamp + +### DevBenches Table +- `id` - Primary key +- `user_id` - Foreign key to users +- `name` - DevBench name (user input) +- `actual_name` - Actual VM name from script +- `status` - Current status (active/inactive/creating) +- `ssh_info` - SSH port number +- `vnc_info` - VNC port number +- `created_at` - Creation timestamp +- `updated_at` - Last update timestamp + +## Security Features + +- Password hashing with bcryptjs +- Session-based authentication +- Input validation and sanitization +- Admin-only routes protection +- SQL injection prevention with parameterized queries + +## Monitoring + +- Automatic status checking every minute +- Real-time WebSocket updates +- Live log streaming during DevBench creation +- Connection information extraction and display + +## Troubleshooting + +### Common Issues + +1. **Cannot access via Caddy**: + - Ensure `caddy_network` exists: `docker network create caddy_network` + - Check if Caddy container is on the same network + - Verify Caddyfile configuration points to `devbench-manager:3001` + +2. **Script timeout**: DevBench creation takes up to 30 minutes + +3. **SSH connection issues**: Ensure sshpass is installed and SSH credentials are correct + +4. **Permission issues**: Make sure the provision script is executable + +5. **Database issues**: Check SQLite file permissions + +6. **Container networking**: + - Check networks: `docker network ls` + - Inspect container: `docker inspect devbench-manager` + - Check if both containers are on caddy_network + +### Logs +Application logs are available in the container or local environment where the app is running. + +## ๐Ÿ“š Documentation + +Comprehensive documentation is available in the `/docs` directory: + +- **[Architecture](docs/ARCHITECTURE.md)**: System architecture, components, and data flow +- **[Structure](docs/STRUCTURE.md)**: Project structure and file descriptions +- **[Deployment](docs/DEPLOYMENT.md)**: Detailed deployment guide and troubleshooting +- **[API](docs/API.md)**: Complete API reference and examples + +## ๐Ÿ“ Project Structure + +``` +ASF_devbench/ +โ”œโ”€โ”€ docs/ # Documentation +โ”‚ โ”œโ”€โ”€ ARCHITECTURE.md # System architecture +โ”‚ โ”œโ”€โ”€ STRUCTURE.md # Project structure +โ”‚ โ”œโ”€โ”€ DEPLOYMENT.md # Deployment guide +โ”‚ โ””โ”€โ”€ API.md # API documentation +โ”œโ”€โ”€ public/ # Static assets +โ”‚ โ”œโ”€โ”€ css/ # Stylesheets (with dark theme) +โ”‚ โ”œโ”€โ”€ images/ # Logos and icons +โ”‚ โ””โ”€โ”€ downloads/ # SSH Config Manager tool +โ”œโ”€โ”€ views/ # EJS templates +โ”‚ โ”œโ”€โ”€ layout.ejs # Base layout +โ”‚ โ”œโ”€โ”€ login.ejs # Login page +โ”‚ โ”œโ”€โ”€ dashboard.ejs # User dashboard +โ”‚ โ”œโ”€โ”€ admin.ejs # Admin panel +โ”‚ โ””โ”€โ”€ help.ejs # Help page +โ”œโ”€โ”€ data/ # Database (created on deploy) +โ”œโ”€โ”€ logs/ # Application logs +โ”œโ”€โ”€ server.js # Main application +โ”œโ”€โ”€ config.js # Configuration +โ”œโ”€โ”€ provision_vm.sh # VM provisioning script +โ”œโ”€โ”€ deploy.sh # Deployment script +โ”œโ”€โ”€ docker-compose.yml # Container orchestration +โ”œโ”€โ”€ Dockerfile # Container definition +โ””โ”€โ”€ README.md # This file +``` + +## ๐ŸŽจ Theme Support + +DevBench Manager includes a beautiful dark theme: + +- **Toggle**: Click the theme button (bottom-right corner) +- **Persistence**: Theme preference saved in browser +- **Smooth Transitions**: Animated theme switching +- **Full Coverage**: All pages and components themed + +## ๐Ÿ”ง Configuration + +### Environment Variables + +Create a `.env` file: + +```bash +NODE_ENV=production +PORT=3001 +SECRET_KEY=your-secure-secret-key +ADMIN_EMAIL=admin@yourdomain.com +ADMIN_PASSWORD=your-secure-password +``` + +### Docker Configuration + +Edit `docker-compose.yml` to customize: + +```yaml +ports: + - "9090:3001" # Change external port +environment: + - NODE_ENV=production + - SECRET_KEY=${SECRET_KEY} +volumes: + - ./data:/app/data + - ./logs:/app/logs +``` + +### Caddy Reverse Proxy + +Add to your Caddyfile: + +``` +tbm.nabd-co.com { + reverse_proxy devbench-manager:3001 +} +``` + +## ๐Ÿ“– Usage + +### For Users + +1. **Login**: Use provided credentials +2. **Create DevBench**: Click "Create DevBench" button +3. **Monitor Progress**: Watch real-time log output +4. **Access VM**: Use displayed SSH/VNC ports +5. **Get Help**: Click help icon for setup guide + +### For Administrators + +1. **Add Users**: Click "Add User" in admin panel +2. **Manage DevBenches**: View and delete any DevBench +3. **Reset Passwords**: Reset user passwords as needed +4. **Monitor System**: View all users and their activity + +### SSH Configuration + +Download the SSH Config Manager tool from the help page to easily configure SSH access to your VMs. + +## ๐Ÿ”Œ API + +### Health Check + +```bash +curl http://localhost:9090/health +``` + +### Create DevBench + +```bash +curl -X POST http://localhost:9090/create-devbench \ + -H "Content-Type: application/json" \ + -d '{"name":"my-vm"}' +``` + +See [API Documentation](docs/API.md) for complete reference. + +## ๐Ÿ› Troubleshooting + +### Container Won't Start + +```bash +# Check logs +docker-compose logs + +# Verify port availability +sudo lsof -i :9090 + +# Check permissions +sudo chown -R $USER:$USER data logs +``` + +### Cannot Access Web Interface + +```bash +# Verify container is running +docker ps | grep devbench-manager + +# Test health endpoint +curl http://localhost:9090/health + +# Check firewall +sudo ufw allow 9090/tcp +``` + +### SSH Connection Fails + +```bash +# Test SSH manually +ssh -p 49152 asf@asf-server.duckdns.org + +# Check from container +docker exec devbench-manager ./provision_vm.sh status test_vm +``` + +See [Deployment Guide](docs/DEPLOYMENT.md) for more troubleshooting steps. + +## ๐Ÿ”„ Updating + +```bash +# Pull latest changes +git pull origin main + +# Backup database +cp data/devbench.db data/devbench.db.backup + +# Redeploy +./deploy.sh +``` + +## ๐Ÿค Contributing + +Contributions are welcome! Please: + +1. Fork the repository +2. Create a feature branch +3. Make your changes +4. Test thoroughly +5. Submit a pull request + +## ๐Ÿ“ License + +MIT License - see LICENSE file for details + +## ๐Ÿ™ Acknowledgments + +- Built with [Express.js](https://expressjs.com/) +- UI powered by [Bootstrap 5](https://getbootstrap.com/) +- Icons from [Font Awesome](https://fontawesome.com/) +- Reverse proxy by [Caddy](https://caddyserver.com/) + +## ๐Ÿ“ž Support + +For issues, questions, or contributions: + +- ๐Ÿ“ง Email: admin@nabd-co.com +- ๐Ÿ“š Documentation: `/docs` directory +- ๐Ÿ› Issues: GitHub Issues (if applicable) + +--- + +Made with โค๏ธ by NABD Solutions \ No newline at end of file diff --git a/asf-cloud-server/TBM_devbench/UPDATES_SUMMARY.md b/asf-cloud-server/TBM_devbench/UPDATES_SUMMARY.md new file mode 100644 index 0000000..aee626c --- /dev/null +++ b/asf-cloud-server/TBM_devbench/UPDATES_SUMMARY.md @@ -0,0 +1,462 @@ +# DevBench Manager - Final Updates Summary + +## ๐ŸŽ‰ Completed Updates + +### 1. โœ… Dark Theme Implementation + +**Added Files:** +- Enhanced `public/css/style.css` with comprehensive dark theme styles + +**Modified Files:** +- `views/layout.ejs`: Added theme toggle button and JavaScript + +**Features:** +- ๐ŸŒ“ Floating theme toggle button (bottom-right) +- ๐Ÿ’พ Theme preference saved in localStorage +- ๐ŸŽจ Complete dark theme for all components +- โœจ Smooth transitions between themes +- ๐ŸŒ™ Moon/Sun icon toggle + +**Usage:** +- Click the floating button in bottom-right corner +- Theme preference persists across sessions +- Works on all pages (dashboard, admin, help, login) + +--- + +### 2. โœ… Script Cleanup + +**Removed Scripts:** +- โŒ `check-network.sh` (debug script) +- โŒ `debug-deploy.sh` (debug script) +- โŒ `deploy.sh` (old version) +- โŒ `test-script.sh` (debug script) +- โŒ `update-ui.sh` (debug script) +- โŒ `fix-deployment.sh` (debug script) +- โŒ `DEPLOYMENT.md` (old, replaced with docs/) + +**Renamed Scripts:** +- โœ… `deploy-final.sh` โ†’ `deploy.sh` (simplified name) + +**Kept Scripts:** +- โœ… `deploy.sh` - Main deployment script +- โœ… `install.sh` - Local installation +- โœ… `start.sh` - Start application +- โœ… `cleanup.sh` - Container cleanup +- โœ… `provision_vm.sh` - VM provisioning + +**Result:** +- Clean, organized project structure +- Only essential scripts remain +- Clear purpose for each script + +--- + +### 3. โœ… Comprehensive Documentation + +**Created `/docs` Folder:** + +#### `docs/ARCHITECTURE.md` +- ๐Ÿ“ System architecture diagrams +- ๐Ÿ—๏ธ Component descriptions +- ๐Ÿ”„ Data flow diagrams +- ๐Ÿ”’ Security architecture +- ๐Ÿ“Š Technology stack +- ๐Ÿš€ Deployment architecture +- โšก Performance considerations +- ๐Ÿ› ๏ธ Maintenance guidelines + +#### `docs/STRUCTURE.md` +- ๐Ÿ“ Complete directory tree +- ๐Ÿ“„ File descriptions +- ๐Ÿ”— Data flow through files +- โš™๏ธ Configuration hierarchy +- ๐ŸŒ Network architecture +- ๐Ÿ” File permissions +- ๐Ÿ—๏ธ Build process +- โšก Runtime process + +#### `docs/DEPLOYMENT.md` +- ๐Ÿ“‹ Prerequisites checklist +- ๐Ÿš€ Quick start guide +- ๐Ÿ“ Detailed deployment steps +- โš™๏ธ Configuration options +- โœ… Verification procedures +- ๐Ÿ› Troubleshooting guide +- ๐Ÿ”ง Maintenance tasks +- ๐Ÿ’พ Backup & recovery +- ๐Ÿ”’ Security hardening +- ๐Ÿ“Š Monitoring setup + +#### `docs/API.md` +- ๐Ÿ”Œ Complete API reference +- ๐Ÿ“ก WebSocket documentation +- ๐Ÿ” Authentication details +- ๐Ÿ“Š Data models +- ๐Ÿ’ก Usage examples +- ๐Ÿ”’ Security considerations +- ๐Ÿ“ Error responses +- ๐Ÿš€ Rate limiting (future) + +**Documentation Features:** +- Clear, structured format +- Code examples included +- Diagrams and visual aids +- Troubleshooting sections +- Best practices +- Security guidelines + +--- + +### 4. โœ… Enhanced README.md + +**New Sections:** +- ๐ŸŽฏ Overview with badges +- ๐Ÿ“‹ Table of contents +- โœจ Feature highlights with emojis +- ๐Ÿš€ Quick start guide +- ๐Ÿ“š Documentation links +- ๐Ÿ“ Project structure +- ๐ŸŽจ Theme support +- ๐Ÿ”ง Configuration guide +- ๐Ÿ“– Usage instructions +- ๐Ÿ”Œ API quick reference +- ๐Ÿ› Troubleshooting +- ๐Ÿ”„ Update instructions +- ๐Ÿค Contributing guidelines +- ๐Ÿ“ž Support information + +**Improvements:** +- More visual and engaging +- Better organized +- Quick access to information +- Clear deployment steps +- Professional presentation + +--- + +## ๐Ÿ“Š Project Statistics + +### Files Summary + +**Total Files:** 25 core files + +**By Category:** +- Documentation: 5 files (README.md + 4 in docs/) +- Source Code: 2 files (server.js, config.js) +- Templates: 5 files (views/*.ejs) +- Static Assets: 6 files (CSS, images, downloads) +- Scripts: 5 files (deploy, install, start, cleanup, provision) +- Configuration: 5 files (package.json, Dockerfile, docker-compose.yml, .env.example, .gitignore) + +### Lines of Code + +**Estimated:** +- JavaScript: ~1,500 lines +- EJS Templates: ~800 lines +- CSS: ~500 lines +- Shell Scripts: ~400 lines +- Documentation: ~3,000 lines +- **Total: ~6,200 lines** + +--- + +## ๐ŸŽจ Theme Implementation Details + +### Color Scheme + +**Light Theme:** +- Background: #ffffff +- Text: #212529 +- Primary: #1a365d (NABD Blue) +- Accent: #f39c12 (NABD Orange) + +**Dark Theme:** +- Background: #1a1a1a +- Text: #e0e0e0 +- Cards: #2d2d2d +- Primary: #1a365d +- Accent: #f39c12 + +### Components Themed + +โœ… Navbar +โœ… Cards +โœ… Tables +โœ… Forms +โœ… Modals +โœ… Buttons +โœ… Alerts +โœ… Code blocks +โœ… Connection info +โœ… Help page +โœ… Login page + +--- + +## ๐Ÿ“ Final Project Structure + +``` +ASF_devbench/ +โ”œโ”€โ”€ docs/ โœจ NEW +โ”‚ โ”œโ”€โ”€ ARCHITECTURE.md โœจ NEW +โ”‚ โ”œโ”€โ”€ STRUCTURE.md โœจ NEW +โ”‚ โ”œโ”€โ”€ DEPLOYMENT.md โœจ NEW +โ”‚ โ””โ”€โ”€ API.md โœจ NEW +โ”œโ”€โ”€ public/ +โ”‚ โ”œโ”€โ”€ css/ +โ”‚ โ”‚ โ””โ”€โ”€ style.css ๐Ÿ”„ UPDATED (dark theme) +โ”‚ โ”œโ”€โ”€ images/ +โ”‚ โ”‚ โ”œโ”€โ”€ nabd-logo.svg +โ”‚ โ”‚ โ”œโ”€โ”€ nabd-logo-white.svg +โ”‚ โ”‚ โ””โ”€โ”€ tbm-icon.png +โ”‚ โ””โ”€โ”€ downloads/ +โ”‚ โ””โ”€โ”€ db_vm_ssh_config_manager.exe +โ”œโ”€โ”€ views/ +โ”‚ โ”œโ”€โ”€ layout.ejs ๐Ÿ”„ UPDATED (theme toggle) +โ”‚ โ”œโ”€โ”€ login.ejs +โ”‚ โ”œโ”€โ”€ dashboard.ejs +โ”‚ โ”œโ”€โ”€ admin.ejs +โ”‚ โ””โ”€โ”€ help.ejs +โ”œโ”€โ”€ server.js +โ”œโ”€โ”€ config.js +โ”œโ”€โ”€ provision_vm.sh +โ”œโ”€โ”€ deploy.sh ๐Ÿ”„ RENAMED (from deploy-final.sh) +โ”œโ”€โ”€ install.sh +โ”œโ”€โ”€ start.sh +โ”œโ”€โ”€ cleanup.sh +โ”œโ”€โ”€ docker-compose.yml +โ”œโ”€โ”€ Dockerfile +โ”œโ”€โ”€ package.json +โ”œโ”€โ”€ .env.example +โ”œโ”€โ”€ .gitignore +โ”œโ”€โ”€ README.md ๐Ÿ”„ UPDATED (comprehensive) +โ”œโ”€โ”€ CHANGELOG.md +โ””โ”€โ”€ UPDATES_SUMMARY.md โœจ NEW (this file) +``` + +--- + +## ๐Ÿš€ Deployment Instructions + +### Quick Deploy + +```bash +# 1. Navigate to project +cd ASF_devbench + +# 2. Deploy +./deploy.sh + +# 3. Access +# http://localhost:9090 +# https://tbm.nabd-co.com +``` + +### What Gets Deployed + +โœ… Docker container with Node.js app +โœ… SQLite database (persistent) +โœ… Application logs (persistent) +โœ… Provision script (mounted) +โœ… Static assets (CSS, images, downloads) +โœ… All views and templates +โœ… Dark theme support +โœ… WebSocket server +โœ… Health check endpoint + +--- + +## ๐ŸŽฏ Key Features Summary + +### User Experience +- ๐ŸŒ“ Dark/Light theme toggle +- ๐Ÿ“ฑ Responsive design +- โšก Real-time updates +- ๐Ÿ“Š Live log streaming +- ๐Ÿ”Œ Easy connection info +- ๐Ÿ“š Comprehensive help + +### Administration +- ๐Ÿ‘ฅ User management +- ๐Ÿ—‚๏ธ DevBench overview +- ๐Ÿ”ง System monitoring +- ๐Ÿ“ˆ Activity tracking + +### Technical +- ๐Ÿณ Docker containerized +- ๐Ÿ”’ Secure authentication +- ๐Ÿ’พ Persistent storage +- ๐ŸŒ Reverse proxy ready +- ๐Ÿ“ก WebSocket support +- ๐Ÿ” Health monitoring + +--- + +## ๐Ÿ“š Documentation Access + +All documentation is in the `/docs` folder: + +1. **Architecture**: `docs/ARCHITECTURE.md` + - System design and components + - Data flow and security + +2. **Structure**: `docs/STRUCTURE.md` + - File organization + - Code structure + +3. **Deployment**: `docs/DEPLOYMENT.md` + - Installation guide + - Troubleshooting + +4. **API**: `docs/API.md` + - Endpoint reference + - Examples + +--- + +## โœ… Verification Checklist + +### Before Deployment +- [ ] Docker and Docker Compose installed +- [ ] SSH access to VM host verified +- [ ] Port 9090 available +- [ ] Caddy network created (if using proxy) + +### After Deployment +- [ ] Container running: `docker ps | grep devbench-manager` +- [ ] Health check: `curl http://localhost:9090/health` +- [ ] Web interface accessible +- [ ] Login works with default credentials +- [ ] Theme toggle works +- [ ] Help page accessible +- [ ] SSH Config Manager downloadable + +### Testing +- [ ] Create test DevBench +- [ ] Monitor real-time logs +- [ ] Check connection info +- [ ] Test dark theme +- [ ] Verify admin panel +- [ ] Test user management + +--- + +## ๐Ÿ”„ Migration Notes + +### From Previous Version + +**No breaking changes!** + +All existing data and functionality preserved: +- โœ… Database schema unchanged +- โœ… API endpoints unchanged +- โœ… Authentication unchanged +- โœ… DevBench management unchanged + +**New additions:** +- โœจ Dark theme (optional) +- ๐Ÿ“š Documentation (reference) +- ๐Ÿงน Cleaner project structure + +--- + +## ๐ŸŽ“ Learning Resources + +### For Developers +- Read `docs/ARCHITECTURE.md` for system design +- Read `docs/STRUCTURE.md` for code organization +- Read `docs/API.md` for endpoint details + +### For Operators +- Read `docs/DEPLOYMENT.md` for deployment +- Read `README.md` for quick start +- Check `CHANGELOG.md` for updates + +### For Users +- Click Help icon in navbar +- Download SSH Config Manager +- Follow step-by-step guide + +--- + +## ๐ŸŽ‰ What's New + +### Version 1.0.0 (2025-11-23) + +**Major Updates:** +1. ๐ŸŒ“ Dark theme support with toggle +2. ๐Ÿ“š Comprehensive documentation (4 guides) +3. ๐Ÿงน Cleaned up debug scripts +4. ๐Ÿ“– Enhanced README with quick start +5. ๐ŸŽจ Improved visual design +6. ๐Ÿ“Š Better project organization + +**Technical Improvements:** +- Cleaner codebase +- Better documentation +- Easier deployment +- Professional presentation + +--- + +## ๐Ÿš€ Next Steps + +### Immediate +1. Deploy using `./deploy.sh` +2. Change default admin password +3. Add users +4. Create test DevBenches + +### Short Term +- Configure Caddy reverse proxy +- Set up SSL/TLS +- Configure backups +- Monitor logs + +### Long Term +- Consider PostgreSQL migration +- Implement rate limiting +- Add CSRF protection +- Set up monitoring dashboard + +--- + +## ๐Ÿ“ž Support + +**Documentation:** +- README.md - Quick start +- docs/ARCHITECTURE.md - System design +- docs/STRUCTURE.md - Code structure +- docs/DEPLOYMENT.md - Deployment guide +- docs/API.md - API reference + +**Contact:** +- Email: admin@nabd-co.com +- Help Page: Click help icon in app + +--- + +## ๐ŸŽŠ Conclusion + +All requested updates have been successfully implemented: + +โœ… **Dark Theme**: Fully functional with toggle button +โœ… **Script Cleanup**: Removed all debug scripts +โœ… **Documentation**: 4 comprehensive guides created +โœ… **README**: Enhanced with quick start and structure +โœ… **Project Organization**: Clean and professional + +The DevBench Manager is now production-ready with: +- Modern UI with theme support +- Comprehensive documentation +- Clean project structure +- Easy deployment process +- Professional presentation + +**Ready to deploy!** ๐Ÿš€ + +--- + +*Last Updated: November 23, 2025* +*Version: 1.0.0* diff --git a/asf-cloud-server/TBM_devbench/cleanup.sh b/asf-cloud-server/TBM_devbench/cleanup.sh new file mode 100644 index 0000000..b84e7fc --- /dev/null +++ b/asf-cloud-server/TBM_devbench/cleanup.sh @@ -0,0 +1,23 @@ +#!/bin/bash + +echo "Cleaning up DevBench Manager containers and volumes..." + +# Stop and remove containers +echo "Stopping containers..." +docker-compose down --remove-orphans + +# Remove any existing containers with the same name +echo "Removing existing containers..." +docker rm -f devbench-manager 2>/dev/null || true + +# Remove dangling containers +echo "Removing dangling containers..." +docker container prune -f + +# List and optionally remove volumes +echo "Current volumes:" +docker volume ls | grep devbench + +echo "" +echo "Cleanup complete!" +echo "You can now run: docker-compose up -d --build" \ No newline at end of file diff --git a/asf-cloud-server/TBM_devbench/config.js b/asf-cloud-server/TBM_devbench/config.js new file mode 100644 index 0000000..f32d4e9 --- /dev/null +++ b/asf-cloud-server/TBM_devbench/config.js @@ -0,0 +1,42 @@ +module.exports = { + // Server configuration + port: process.env.PORT || 3001, + + // Database configuration + database: { + path: process.env.DB_PATH || './data/devbench.db' + }, + + // Session configuration + session: { + secret: process.env.SESSION_SECRET || 'devbench-secret-key', + maxAge: 24 * 60 * 60 * 1000 // 24 hours + }, + + // SSH configuration for provision script + ssh: { + user: process.env.SSH_USER || 'asf', + host: process.env.SSH_HOST || 'asf-tb.duckdns.org', + password: process.env.SSH_PASS || 'ASF' + }, + + // Provision script configuration + provision: { + scriptPath: process.env.PROVISION_SCRIPT || './provision_vm.sh', + timeout: 30 * 60 * 1000, // 30 minutes + statusCheckInterval: 60 * 1000 // 1 minute + }, + + // Default admin user + defaultAdmin: { + username: 'admin', + email: process.env.ADMIN_EMAIL || 'admin@nabd-co.com', + password: process.env.ADMIN_PASSWORD || 'admin123' + }, + + // Validation rules + validation: { + username: /^[a-zA-Z]+$/, // Only letters for admin usernames + devbenchName: /^[a-zA-Z0-9_-]+$/ // Letters, numbers, hyphens, underscores for devbench names + } +}; \ No newline at end of file diff --git a/asf-cloud-server/TBM_devbench/db_vm_ssh_config_manager.exe b/asf-cloud-server/TBM_devbench/db_vm_ssh_config_manager.exe new file mode 100644 index 0000000..9692e9e Binary files /dev/null and b/asf-cloud-server/TBM_devbench/db_vm_ssh_config_manager.exe differ diff --git a/asf-cloud-server/TBM_devbench/deploy.sh b/asf-cloud-server/TBM_devbench/deploy.sh new file mode 100644 index 0000000..11a2393 --- /dev/null +++ b/asf-cloud-server/TBM_devbench/deploy.sh @@ -0,0 +1,81 @@ +#!/bin/bash + +echo "๐Ÿš€ Deploying DevBench Manager with all improvements..." + +# Create directories +echo "๐Ÿ“ Creating directories..." +mkdir -p data logs public/css public/images public/downloads + +# Make scripts executable +echo "๐Ÿ”ง Setting permissions..." +chmod +x provision_vm.sh *.sh + +# Clean up containers +echo "๐Ÿงน Cleaning up existing containers..." +docker-compose down --remove-orphans 2>/dev/null || true +docker rm -f devbench-manager 2>/dev/null || true + +# Create network +if ! docker network ls | grep -q caddy_network; then + echo "๐ŸŒ Creating caddy_network..." + docker network create caddy_network +else + echo "โœ… caddy_network already exists" +fi + +# Build and deploy +echo "๐Ÿ—๏ธ Building and starting container..." +docker-compose up -d --build + +# Wait for startup +echo "โณ Waiting for container startup..." +sleep 15 + +# Check status +if docker ps | grep -q devbench-manager; then + echo "" + echo "๐ŸŽ‰ SUCCESS! DevBench Manager is running with latest updates:" + echo "" + echo "โœ… Updated SSH access (asf@asf-server.duckdns.org:49152)" + echo "โœ… Simplified connection info (SSH Port & VNC Port only)" + echo "โœ… Added Help page with SSH Config Manager guide" + echo "โœ… Added TBM icon branding" + echo "โœ… SSH Config Manager tool available for download" + echo "โœ… Enhanced UI with copy-to-clipboard functionality" + echo "" + echo "๐ŸŒ Access Points:" + echo " Direct: http://localhost:9090" + echo " Via Caddy: https://tbm.nabd-co.com" + echo "" + echo "๐Ÿ” Default Login:" + echo " Username: admin" + echo " Password: admin123" + echo "" + echo "๐Ÿ› ๏ธ Useful Commands:" + echo " Check logs: docker-compose logs -f" + echo " Check health: curl http://localhost:9090/health" + echo " Stop: docker-compose down" + + # Test health endpoint + echo "" + echo "๐Ÿฅ Health Check:" + if curl -s http://localhost:9090/health > /dev/null; then + echo "โœ… Application is healthy" + else + echo "โš ๏ธ Health check failed (may need more time)" + fi + +else + echo "" + echo "โŒ DEPLOYMENT FAILED!" + echo "" + echo "๐Ÿ“‹ Checking logs:" + docker-compose logs --tail=20 + echo "" + echo "๐Ÿ” Container status:" + docker ps -a | grep devbench-manager + exit 1 +fi + +echo "" +echo "๐ŸŽฏ Deployment completed successfully!" \ No newline at end of file diff --git a/asf-cloud-server/TBM_devbench/docker-compose.yml b/asf-cloud-server/TBM_devbench/docker-compose.yml new file mode 100644 index 0000000..4b63f46 --- /dev/null +++ b/asf-cloud-server/TBM_devbench/docker-compose.yml @@ -0,0 +1,33 @@ +version: '3.8' + +services: + devbench-manager: + build: . + container_name: devbench-manager + restart: unless-stopped + ports: + - "9090:3001" + environment: + - NODE_ENV=production + - PORT=3001 + - SECRET_KEY=${SECRET_KEY:-dev-secret-key-change-in-production} + - ADMIN_EMAIL=${ADMIN_EMAIL:-admin@nabd-co.com} + - ADMIN_PASSWORD=${ADMIN_PASSWORD:-admin123} + volumes: + - ./data:/app/data + - ./logs:/app/logs + - ./provision_vm.sh:/app/provision_vm.sh:ro + healthcheck: + test: [ "CMD", "wget", "--no-verbose", "--tries=1", "--spider", "http://localhost:3001/health" ] + interval: 30s + timeout: 10s + retries: 3 + networks: + - app-network + - caddy_network + +networks: + app-network: + driver: bridge + caddy_network: + external: true diff --git a/asf-cloud-server/TBM_devbench/docs/API.md b/asf-cloud-server/TBM_devbench/docs/API.md new file mode 100644 index 0000000..bb70143 --- /dev/null +++ b/asf-cloud-server/TBM_devbench/docs/API.md @@ -0,0 +1,649 @@ +# DevBench Manager - API Documentation + +## Base URL + +``` +http://localhost:9090 +https://tbm.nabd-co.com +``` + +## Authentication + +All API endpoints (except `/login` and `/health`) require authentication via session cookies. + +### Session Cookie +- **Name**: `connect.sid` +- **Type**: HTTP-only +- **Secure**: true (in production with HTTPS) +- **SameSite**: Lax + +## Endpoints + +### Health Check + +#### GET /health + +Check application health status. + +**Authentication**: Not required + +**Response**: +```json +{ + "status": "ok", + "timestamp": "2025-11-23T12:00:00.000Z", + "version": "1.0.0" +} +``` + +**Status Codes**: +- `200`: Application is healthy + +--- + +### Authentication + +#### GET /login + +Display login page. + +**Authentication**: Not required + +**Response**: HTML page + +--- + +#### POST /login + +Authenticate user and create session. + +**Authentication**: Not required + +**Request Body**: +```json +{ + "username": "admin", + "password": "admin123" +} +``` + +**Response**: Redirect to `/dashboard` or `/admin` + +**Status Codes**: +- `302`: Success, redirect to dashboard +- `200`: Failed, re-render login with error + +--- + +#### GET /logout + +Destroy session and logout user. + +**Authentication**: Required + +**Response**: Redirect to `/login` + +**Status Codes**: +- `302`: Success, redirect to login + +--- + +### User Dashboard + +#### GET /dashboard + +Display user's DevBench dashboard. + +**Authentication**: Required (User role) + +**Response**: HTML page with user's DevBenches + +**Status Codes**: +- `200`: Success +- `302`: Redirect to `/admin` if user is admin +- `302`: Redirect to `/login` if not authenticated + +--- + +#### GET /help + +Display help page with SSH configuration guide. + +**Authentication**: Required + +**Response**: HTML page with documentation + +**Status Codes**: +- `200`: Success +- `302`: Redirect to `/login` if not authenticated + +--- + +### DevBench Management + +#### POST /create-devbench + +Create a new DevBench. + +**Authentication**: Required (User role) + +**Request Body**: +```json +{ + "name": "test-vm" +} +``` + +**Validation**: +- Name must match pattern: `[a-zA-Z0-9_-]+` +- Name must be unique for user + +**Response**: +```json +{ + "success": true, + "devbenchId": 123 +} +``` + +**Error Response**: +```json +{ + "error": "DevBench with this name already exists" +} +``` + +**Status Codes**: +- `200`: Success +- `400`: Validation error +- `500`: Database error + +**Side Effects**: +- Creates database record with status "creating" +- Spawns provision script execution +- Sends real-time updates via WebSocket + +--- + +#### POST /delete-devbench/:id + +Delete a DevBench. + +**Authentication**: Required (User role, owner only) + +**Parameters**: +- `id`: DevBench ID (integer) + +**Response**: +```json +{ + "success": true +} +``` + +**Error Response**: +```json +{ + "error": "DevBench not found" +} +``` + +**Status Codes**: +- `200`: Success +- `404`: DevBench not found +- `500`: Database error + +**Side Effects**: +- Executes delete command on remote host +- Removes database record + +--- + +#### POST /activate-devbench/:id + +Activate a DevBench. + +**Authentication**: Required (User role, owner only) + +**Parameters**: +- `id`: DevBench ID (integer) + +**Response**: +```json +{ + "success": true +} +``` + +**Error Response**: +```json +{ + "error": "DevBench not found" +} +``` + +**Status Codes**: +- `200`: Success +- `404`: DevBench not found + +**Side Effects**: +- Executes activate command on remote host +- Updates status via WebSocket + +--- + +#### GET /check-status/:id + +Check DevBench status. + +**Authentication**: Required (User role, owner only) + +**Parameters**: +- `id`: DevBench ID (integer) + +**Response**: +```json +{ + "status": "active" +} +``` + +**Possible Status Values**: +- `active`: VM is running +- `inactive`: VM is stopped +- `creating`: VM is being created +- `error`: VM creation failed +- `unknown`: Status cannot be determined + +**Status Codes**: +- `200`: Success + +**Side Effects**: +- Updates database with current status + +--- + +### Admin Panel + +#### GET /admin + +Display admin dashboard. + +**Authentication**: Required (Admin role) + +**Response**: HTML page with users and DevBenches + +**Status Codes**: +- `200`: Success +- `403`: Access denied (not admin) +- `302`: Redirect to `/login` if not authenticated + +--- + +#### POST /admin/add-user + +Create a new user. + +**Authentication**: Required (Admin role) + +**Request Body**: +```json +{ + "username": "john", + "email": "john@example.com", + "password": "password123" +} +``` + +**Validation**: +- Username must match pattern: `[a-zA-Z]+` (letters only) +- Username must be unique +- Email must be valid format +- Password required + +**Response**: +```json +{ + "success": true +} +``` + +**Error Response**: +```json +{ + "error": "Username already exists" +} +``` + +**Status Codes**: +- `200`: Success +- `400`: Validation error +- `500`: Database error + +--- + +#### POST /admin/delete-user/:id + +Delete a user and all their DevBenches. + +**Authentication**: Required (Admin role) + +**Parameters**: +- `id`: User ID (integer) + +**Response**: +```json +{ + "success": true +} +``` + +**Error Response**: +```json +{ + "error": "Database error" +} +``` + +**Status Codes**: +- `200`: Success +- `500`: Database error + +**Side Effects**: +- Deletes all user's DevBenches +- Deletes user record +- Cannot delete admin users + +--- + +#### POST /admin/reset-password/:id + +Reset user password. + +**Authentication**: Required (Admin role) + +**Parameters**: +- `id`: User ID (integer) + +**Request Body**: +```json +{ + "newPassword": "newpassword123" +} +``` + +**Response**: +```json +{ + "success": true +} +``` + +**Error Response**: +```json +{ + "error": "Database error" +} +``` + +**Status Codes**: +- `200`: Success +- `500`: Database error + +**Side Effects**: +- Updates user password (hashed with bcrypt) +- Cannot reset admin passwords + +--- + +### User Info + +#### GET /api/user-info + +Get current user information for WebSocket registration. + +**Authentication**: Required + +**Response**: +```json +{ + "userId": 1, + "username": "admin", + "isAdmin": true +} +``` + +**Status Codes**: +- `200`: Success +- `302`: Redirect to `/login` if not authenticated + +--- + +## WebSocket API + +### Connection + +```javascript +const ws = new WebSocket('ws://localhost:9090'); +``` + +### Registration + +After connection, register with user ID: + +```javascript +ws.send(JSON.stringify({ + type: 'register', + userId: 1 +})); +``` + +### Message Types + +#### script_output + +Real-time output from provision script. + +```json +{ + "type": "script_output", + "devbenchId": 123, + "data": "Cloning VM...\n" +} +``` + +#### script_complete + +Script execution completed. + +```json +{ + "type": "script_complete", + "devbenchId": 123, + "exitCode": 0 +} +``` + +#### status_update + +DevBench status changed. + +```json +{ + "type": "status_update", + "devbenchId": 123, + "status": "active" +} +``` + +--- + +## Error Responses + +### Standard Error Format + +```json +{ + "error": "Error message description" +} +``` + +### Common HTTP Status Codes + +- `200`: Success +- `302`: Redirect +- `400`: Bad Request (validation error) +- `401`: Unauthorized (not authenticated) +- `403`: Forbidden (insufficient permissions) +- `404`: Not Found +- `500`: Internal Server Error + +--- + +## Rate Limiting + +Currently not implemented. Consider adding rate limiting for production: + +- Login attempts: 5 per minute +- DevBench creation: 10 per hour per user +- API calls: 100 per minute per user + +--- + +## Data Models + +### User + +```json +{ + "id": 1, + "username": "admin", + "email": "admin@example.com", + "password": "$2a$10$...", // bcrypt hash + "is_admin": 1, + "created_at": "2025-11-23T12:00:00.000Z" +} +``` + +### DevBench + +```json +{ + "id": 1, + "user_id": 1, + "name": "test-vm", + "actual_name": "admin_test-vm", + "status": "active", + "ssh_info": "6004", + "vnc_info": "5004", + "created_at": "2025-11-23T12:00:00.000Z", + "updated_at": "2025-11-23T12:05:00.000Z" +} +``` + +--- + +## Examples + +### Create DevBench with cURL + +```bash +# Login first to get session cookie +curl -c cookies.txt -X POST http://localhost:9090/login \ + -H "Content-Type: application/x-www-form-urlencoded" \ + -d "username=admin&password=admin123" + +# Create DevBench +curl -b cookies.txt -X POST http://localhost:9090/create-devbench \ + -H "Content-Type: application/json" \ + -d '{"name":"test-vm"}' +``` + +### Check Status with cURL + +```bash +curl -b cookies.txt http://localhost:9090/check-status/1 +``` + +### Add User with cURL + +```bash +curl -b cookies.txt -X POST http://localhost:9090/admin/add-user \ + -H "Content-Type: application/json" \ + -d '{ + "username":"john", + "email":"john@example.com", + "password":"password123" + }' +``` + +### WebSocket with JavaScript + +```javascript +// Connect +const ws = new WebSocket('ws://localhost:9090'); + +// Register +ws.onopen = () => { + fetch('/api/user-info') + .then(res => res.json()) + .then(data => { + ws.send(JSON.stringify({ + type: 'register', + userId: data.userId + })); + }); +}; + +// Listen for messages +ws.onmessage = (event) => { + const message = JSON.parse(event.data); + console.log('Received:', message); + + if (message.type === 'script_output') { + // Update UI with script output + document.getElementById('log').textContent += message.data; + } +}; +``` + +--- + +## Security Considerations + +### Authentication +- Session-based authentication +- HTTP-only cookies +- Password hashing with bcrypt (10 rounds) + +### Authorization +- Role-based access control (Admin/User) +- Owner-only access to DevBenches +- Admin-only routes protected + +### Input Validation +- Username: Letters only +- DevBench name: Alphanumeric, hyphens, underscores +- SQL injection prevention: Parameterized queries +- XSS prevention: EJS auto-escaping + +### Best Practices +- Always use HTTPS in production +- Change default admin password +- Use strong session secret +- Implement rate limiting +- Add CSRF protection +- Enable security headers + +--- + +## Changelog + +### Version 1.0.0 (2025-11-23) +- Initial API release +- User authentication +- DevBench management +- Admin panel +- WebSocket support +- Help page +- Dark theme support diff --git a/asf-cloud-server/TBM_devbench/docs/ARCHITECTURE.md b/asf-cloud-server/TBM_devbench/docs/ARCHITECTURE.md new file mode 100644 index 0000000..651298e --- /dev/null +++ b/asf-cloud-server/TBM_devbench/docs/ARCHITECTURE.md @@ -0,0 +1,400 @@ +# DevBench Manager - Architecture Documentation + +## System Overview + +DevBench Manager is a web-based application for managing virtual machine (VM) development environments. It provides a centralized interface for users to create, manage, and access their DevBench VMs through a secure web portal. + +## Architecture Diagram + +``` +โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” +โ”‚ User Browser โ”‚ +โ”‚ โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”‚ +โ”‚ โ”‚ Dashboard โ”‚ โ”‚ Admin Panel โ”‚ โ”‚ Help Page โ”‚ โ”‚ +โ”‚ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ”‚ +โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ + โ”‚ HTTPS/WSS + โ–ผ +โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” +โ”‚ Caddy Reverse Proxy โ”‚ +โ”‚ (tbm.nabd-co.com) โ”‚ +โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ + โ”‚ + โ–ผ +โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” +โ”‚ DevBench Manager Container โ”‚ +โ”‚ โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”‚ +โ”‚ โ”‚ Express.js Server โ”‚ โ”‚ +โ”‚ โ”‚ โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”‚ โ”‚ +โ”‚ โ”‚ โ”‚ Routes โ”‚ โ”‚ WebSocket โ”‚ โ”‚ Auth โ”‚ โ”‚ โ”‚ +โ”‚ โ”‚ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ”‚ โ”‚ +โ”‚ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ”‚ +โ”‚ โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”‚ +โ”‚ โ”‚ SQLite Database โ”‚ โ”‚ +โ”‚ โ”‚ โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”‚ โ”‚ +โ”‚ โ”‚ โ”‚ Users โ”‚ โ”‚ DevBenches โ”‚ โ”‚ โ”‚ +โ”‚ โ”‚ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ”‚ โ”‚ +โ”‚ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ”‚ +โ”‚ โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”‚ +โ”‚ โ”‚ Provision Script Executor โ”‚ โ”‚ +โ”‚ โ”‚ (provision_vm.sh) โ”‚ โ”‚ +โ”‚ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ”‚ +โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ + โ”‚ SSH (Port 49152) + โ–ผ +โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” +โ”‚ Remote VM Host Server โ”‚ +โ”‚ (asf-server.duckdns.org) โ”‚ +โ”‚ โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”‚ +โ”‚ โ”‚ VirtualBox Manager โ”‚ โ”‚ +โ”‚ โ”‚ โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”‚ โ”‚ +โ”‚ โ”‚ โ”‚ VM 1 โ”‚ โ”‚ VM 2 โ”‚ โ”‚ VM 3 โ”‚ โ”‚ VM N โ”‚ โ”‚ โ”‚ +โ”‚ โ”‚ โ”‚ SSH: โ”‚ โ”‚ SSH: โ”‚ โ”‚ SSH: โ”‚ โ”‚ SSH: โ”‚ โ”‚ โ”‚ +โ”‚ โ”‚ โ”‚ 6001 โ”‚ โ”‚ 6002 โ”‚ โ”‚ 6003 โ”‚ โ”‚ 600N โ”‚ โ”‚ โ”‚ +โ”‚ โ”‚ โ”‚ VNC: โ”‚ โ”‚ VNC: โ”‚ โ”‚ VNC: โ”‚ โ”‚ VNC: โ”‚ โ”‚ โ”‚ +โ”‚ โ”‚ โ”‚ 5001 โ”‚ โ”‚ 5002 โ”‚ โ”‚ 5003 โ”‚ โ”‚ 500N โ”‚ โ”‚ โ”‚ +โ”‚ โ”‚ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ”‚ โ”‚ +โ”‚ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ”‚ +โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ +``` + +## Component Architecture + +### 1. Frontend Layer + +#### Technologies +- **EJS Templates**: Server-side rendering +- **Bootstrap 5**: UI framework +- **Font Awesome**: Icons +- **Custom CSS**: Theming (light/dark mode) +- **Vanilla JavaScript**: Client-side interactivity + +#### Components +- **Dashboard**: User's DevBench management interface +- **Admin Panel**: User and system management +- **Help Page**: Documentation and SSH config guide +- **Login Page**: Authentication interface + +### 2. Backend Layer + +#### Technologies +- **Node.js**: Runtime environment +- **Express.js**: Web framework +- **WebSocket (ws)**: Real-time communication +- **SQLite3**: Database +- **bcryptjs**: Password hashing +- **express-session**: Session management + +#### Core Modules + +##### Authentication Module +```javascript +- Session-based authentication +- Password hashing with bcrypt +- Role-based access control (Admin/User) +- Middleware for route protection +``` + +##### DevBench Management Module +```javascript +- Create DevBench +- Delete DevBench +- Activate DevBench +- Status monitoring +- Real-time log streaming +``` + +##### WebSocket Module +```javascript +- Real-time script output +- Status updates +- User-specific broadcasting +- Connection management +``` + +##### Provision Script Executor +```javascript +- SSH connection to remote host +- Script execution via sshpass +- Output parsing +- Error handling +- Timeout management (30 minutes) +``` + +### 3. Database Layer + +#### Schema + +**Users Table** +```sql +CREATE TABLE users ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + username TEXT UNIQUE NOT NULL, + email TEXT NOT NULL, + password TEXT NOT NULL, + is_admin INTEGER DEFAULT 0, + created_at DATETIME DEFAULT CURRENT_TIMESTAMP +) +``` + +**DevBenches Table** +```sql +CREATE TABLE devbenches ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + user_id INTEGER NOT NULL, + name TEXT NOT NULL, + actual_name TEXT, + status TEXT DEFAULT 'inactive', + ssh_info TEXT, + vnc_info TEXT, + created_at DATETIME DEFAULT CURRENT_TIMESTAMP, + updated_at DATETIME DEFAULT CURRENT_TIMESTAMP, + FOREIGN KEY (user_id) REFERENCES users (id) +) +``` + +### 4. Infrastructure Layer + +#### Docker Container +```yaml +- Base Image: Node.js 18 +- Exposed Port: 3001 (mapped to 9090) +- Volumes: + - ./data:/app/data (Database persistence) + - ./logs:/app/logs (Log files) + - ./provision_vm.sh:/app/provision_vm.sh (Script) +- Networks: + - app-network (Internal) + - caddy_network (External proxy) +``` + +#### Reverse Proxy (Caddy) +``` +- Domain: tbm.nabd-co.com +- SSL/TLS: Automatic (Let's Encrypt) +- Proxy Target: devbench-manager:3001 +``` + +## Data Flow + +### DevBench Creation Flow + +``` +1. User clicks "Create DevBench" + โ†“ +2. Frontend sends POST /create-devbench + โ†“ +3. Backend validates input + โ†“ +4. Database record created (status: creating) + โ†“ +5. WebSocket connection established + โ†“ +6. provision_vm.sh executed via SSH + โ†“ +7. Real-time output streamed via WebSocket + โ†“ +8. Script parses VM info (name, SSH port, VNC port) + โ†“ +9. Database updated with connection info + โ†“ +10. Frontend receives completion notification + โ†“ +11. Page refreshes to show active DevBench +``` + +### Authentication Flow + +``` +1. User submits login form + โ†“ +2. Backend validates credentials + โ†“ +3. Password compared with bcrypt + โ†“ +4. Session created on success + โ†“ +5. User redirected to dashboard/admin + โ†“ +6. Session cookie stored in browser + โ†“ +7. Subsequent requests include session + โ†“ +8. Middleware validates session +``` + +### Status Monitoring Flow + +``` +1. Periodic check (every 60 seconds) + โ†“ +2. For each DevBench in database + โ†“ +3. Execute provision_vm.sh status + โ†“ +4. Parse output for status + โ†“ +5. Update database if changed + โ†“ +6. Broadcast update via WebSocket + โ†“ +7. Frontend updates UI in real-time +``` + +## Security Architecture + +### Authentication & Authorization +- **Password Hashing**: bcrypt with salt rounds +- **Session Management**: Secure HTTP-only cookies +- **Role-Based Access**: Admin vs User permissions +- **Route Protection**: Middleware guards + +### Input Validation +- **Username**: Letters only, no special characters +- **DevBench Name**: Alphanumeric, hyphens, underscores +- **SQL Injection**: Parameterized queries +- **XSS Prevention**: EJS auto-escaping + +### Network Security +- **HTTPS**: Enforced via Caddy +- **SSH**: Password-based (sshpass) with timeout +- **Container Isolation**: Docker networking +- **Port Exposure**: Minimal (only 9090) + +## Scalability Considerations + +### Current Limitations +- Single SQLite database (not suitable for high concurrency) +- SSH-based provisioning (sequential, not parallel) +- In-memory WebSocket connections (lost on restart) +- Single container deployment + +### Future Improvements +- **Database**: Migrate to PostgreSQL/MySQL +- **Queue System**: Redis/RabbitMQ for async jobs +- **Load Balancing**: Multiple container instances +- **Persistent WebSocket**: Redis pub/sub +- **Caching**: Redis for session and status data + +## Monitoring & Logging + +### Application Logs +- Location: `/app/logs/` +- Format: Timestamped console output +- Rotation: Manual (not automated) + +### Provision Script Logs +- Location: `/var/log/devbench/` +- Format: Timestamped with operation details +- Retention: Indefinite + +### Health Checks +- Endpoint: `/health` +- Interval: 30 seconds +- Timeout: 10 seconds +- Retries: 3 + +## Technology Stack Summary + +| Layer | Technology | Purpose | +|-------|-----------|---------| +| Frontend | EJS, Bootstrap 5, JavaScript | UI rendering and interactivity | +| Backend | Node.js, Express.js | Web server and API | +| Real-time | WebSocket (ws) | Live updates | +| Database | SQLite3 | Data persistence | +| Authentication | bcryptjs, express-session | Security | +| Container | Docker, Docker Compose | Deployment | +| Proxy | Caddy | SSL/TLS and routing | +| VM Management | Bash, SSH, VirtualBox | VM provisioning | + +## Deployment Architecture + +### Production Environment +``` +Internet + โ†“ +Caddy (Port 443) โ†’ SSL Termination + โ†“ +Docker Network (caddy_network) + โ†“ +DevBench Manager Container (Port 3001) + โ†“ +SQLite Database (Volume: ./data) + โ†“ +SSH Connection (Port 49152) + โ†“ +Remote VM Host +``` + +### Development Environment +``` +localhost:9090 + โ†“ +DevBench Manager Container + โ†“ +Local SQLite Database + โ†“ +SSH to Remote Host +``` + +## Configuration Management + +### Environment Variables +- `NODE_ENV`: production/development +- `PORT`: Application port (default: 3001) +- `SECRET_KEY`: Session secret +- `ADMIN_EMAIL`: Default admin email +- `ADMIN_PASSWORD`: Default admin password + +### Configuration Files +- `config.js`: Application configuration +- `docker-compose.yml`: Container orchestration +- `Dockerfile`: Container build instructions +- `.env`: Environment variables (optional) + +## Error Handling + +### Application Errors +- Database errors: Logged and returned as 500 +- Authentication errors: Returned as 401/403 +- Validation errors: Returned as 400 +- Script errors: Logged and broadcast via WebSocket + +### Script Errors +- Timeout: 30 minutes (1800 seconds) +- SSH failures: Logged and status set to 'error' +- Parsing failures: Status set to 'error' +- Network issues: Retry not implemented + +## Performance Considerations + +### Bottlenecks +1. **SSH Connection**: Sequential, blocking +2. **Script Execution**: Long-running (up to 30 min) +3. **Status Checks**: Every 60 seconds for all VMs +4. **SQLite**: Limited concurrent writes + +### Optimizations +- WebSocket for real-time updates (no polling) +- Session caching in memory +- Static asset serving via Express +- Minimal database queries + +## Maintenance & Operations + +### Backup Strategy +- Database: Copy `./data/devbench.db` +- Logs: Archive `./logs/` directory +- Configuration: Version control + +### Update Procedure +1. Pull latest code +2. Run `./deploy.sh` +3. Verify health endpoint +4. Check logs for errors + +### Troubleshooting +- Check container logs: `docker-compose logs -f` +- Verify network: `docker network inspect caddy_network` +- Test SSH: `ssh -p 49152 asf@asf-server.duckdns.org` +- Check database: `sqlite3 data/devbench.db` diff --git a/asf-cloud-server/TBM_devbench/docs/DEPLOYMENT.md b/asf-cloud-server/TBM_devbench/docs/DEPLOYMENT.md new file mode 100644 index 0000000..35152e1 --- /dev/null +++ b/asf-cloud-server/TBM_devbench/docs/DEPLOYMENT.md @@ -0,0 +1,679 @@ +# DevBench Manager - Deployment Guide + +## Table of Contents +1. [Prerequisites](#prerequisites) +2. [Quick Start](#quick-start) +3. [Detailed Deployment](#detailed-deployment) +4. [Configuration](#configuration) +5. [Verification](#verification) +6. [Troubleshooting](#troubleshooting) +7. [Maintenance](#maintenance) +8. [Backup & Recovery](#backup--recovery) + +## Prerequisites + +### Required Software +- **Docker**: Version 20.10 or higher +- **Docker Compose**: Version 2.0 or higher +- **Git**: For cloning the repository +- **SSH Access**: To remote VM host (asf-server.duckdns.org:49152) + +### System Requirements +- **OS**: Linux (Ubuntu 20.04+ recommended), macOS, or Windows with WSL2 +- **RAM**: Minimum 512MB for container +- **Disk**: Minimum 1GB free space +- **Network**: Internet connection for Docker images and SSH + +### Access Requirements +- SSH credentials for VM host +- Domain name configured (optional, for Caddy) +- Port 9090 available (or configure different port) + +## Quick Start + +### One-Command Deployment + +```bash +# Clone the repository +git clone +cd ASF_devbench + +# Run deployment script +chmod +x deploy.sh +./deploy.sh +``` + +That's it! The application will be available at: +- **Direct**: http://localhost:9090 +- **Via Caddy**: https://tbm.nabd-co.com (if configured) + +### Default Credentials +- **Username**: admin +- **Password**: admin123 + +โš ๏ธ **Important**: Change the default password after first login! + +## Detailed Deployment + +### Step 1: Clone Repository + +```bash +git clone +cd ASF_devbench +``` + +### Step 2: Review Configuration + +Check `config.js` for default settings: +```javascript +{ + port: 3001, + database: { path: './data/devbench.db' }, + session: { secret: 'your-secret-key' }, + defaultAdmin: { + username: 'admin', + password: 'admin123', + email: 'admin@nabd-co.com' + } +} +``` + +### Step 3: Set Environment Variables (Optional) + +Create `.env` file: +```bash +NODE_ENV=production +PORT=3001 +SECRET_KEY=your-secure-secret-key +ADMIN_EMAIL=admin@yourdomain.com +ADMIN_PASSWORD=your-secure-password +``` + +### Step 4: Prepare Directories + +```bash +# Create necessary directories +mkdir -p data logs public/downloads + +# Set permissions +chmod 755 data logs +chmod +x provision_vm.sh deploy.sh +``` + +### Step 5: Configure Docker Network + +```bash +# Create Caddy network (if using reverse proxy) +docker network create caddy_network +``` + +### Step 6: Deploy with Docker Compose + +```bash +# Build and start container +docker-compose up -d --build + +# Check status +docker-compose ps + +# View logs +docker-compose logs -f +``` + +### Step 7: Verify Deployment + +```bash +# Check health endpoint +curl http://localhost:9090/health + +# Expected response: +# {"status":"ok","timestamp":"2025-11-23T...","version":"1.0.0"} +``` + +## Configuration + +### Docker Compose Configuration + +Edit `docker-compose.yml`: + +```yaml +services: + devbench-manager: + ports: + - "9090:3001" # Change external port here + environment: + - NODE_ENV=production + - SECRET_KEY=${SECRET_KEY:-dev-secret-key} + volumes: + - ./data:/app/data + - ./logs:/app/logs + - ./provision_vm.sh:/app/provision_vm.sh:ro +``` + +### Caddy Reverse Proxy + +Add to your Caddyfile: + +``` +tbm.nabd-co.com { + reverse_proxy devbench-manager:3001 +} +``` + +Ensure Caddy container is on `caddy_network`: + +```bash +# Check Caddy network +docker network inspect caddy_network + +# Connect Caddy to network if needed +docker network connect caddy_network caddy-container-name +``` + +### SSH Configuration + +The application connects to the VM host via SSH. Ensure: + +1. **Host**: asf-server.duckdns.org +2. **Port**: 49152 +3. **User**: asf +4. **Password**: ASF (configured in provision_vm.sh) + +Test SSH connection: +```bash +ssh -p 49152 asf@asf-server.duckdns.org +``` + +### Firewall Configuration + +Open required ports: + +```bash +# For direct access +sudo ufw allow 9090/tcp + +# For Caddy (if using) +sudo ufw allow 80/tcp +sudo ufw allow 443/tcp +``` + +## Verification + +### 1. Container Status + +```bash +# Check if container is running +docker ps | grep devbench-manager + +# Expected output: +# CONTAINER ID IMAGE STATUS PORTS +# abc123... devbench-manager:latest Up 2 minutes 0.0.0.0:9090->3001/tcp +``` + +### 2. Health Check + +```bash +# Test health endpoint +curl http://localhost:9090/health + +# Or with jq for formatted output +curl -s http://localhost:9090/health | jq +``` + +### 3. Network Connectivity + +```bash +# Check networks +docker inspect devbench-manager --format='{{range $k, $v := .NetworkSettings.Networks}}{{$k}} {{end}}' + +# Expected: app-network caddy_network +``` + +### 4. Database + +```bash +# Check if database was created +ls -la data/devbench.db + +# Connect to database +docker exec -it devbench-manager sqlite3 /app/data/devbench.db + +# Run query +sqlite> SELECT * FROM users; +``` + +### 5. Logs + +```bash +# View application logs +docker-compose logs -f + +# View last 50 lines +docker-compose logs --tail=50 + +# View specific service +docker-compose logs devbench-manager +``` + +### 6. Web Interface + +1. Open browser: http://localhost:9090 +2. Login with admin credentials +3. Create a test DevBench +4. Verify real-time log output +5. Check connection information + +## Troubleshooting + +### Container Won't Start + +**Problem**: Container exits immediately + +**Solution**: +```bash +# Check logs +docker-compose logs + +# Common issues: +# 1. Port already in use +sudo lsof -i :9090 +# Kill process or change port in docker-compose.yml + +# 2. Permission issues +sudo chown -R $USER:$USER data logs + +# 3. Missing provision script +ls -la provision_vm.sh +chmod +x provision_vm.sh +``` + +### Cannot Access Web Interface + +**Problem**: Connection refused or timeout + +**Solution**: +```bash +# 1. Check if container is running +docker ps | grep devbench-manager + +# 2. Check port mapping +docker port devbench-manager + +# 3. Test from inside container +docker exec devbench-manager wget -O- http://localhost:3001/health + +# 4. Check firewall +sudo ufw status +sudo ufw allow 9090/tcp + +# 5. Check if port is listening +sudo netstat -tlnp | grep 9090 +``` + +### Caddy Proxy Not Working + +**Problem**: Cannot access via domain + +**Solution**: +```bash +# 1. Check if both containers are on caddy_network +docker network inspect caddy_network + +# 2. Connect devbench-manager to network +docker network connect caddy_network devbench-manager + +# 3. Restart Caddy +docker restart caddy-container-name + +# 4. Check Caddy logs +docker logs caddy-container-name + +# 5. Test from Caddy container +docker exec caddy-container-name wget -O- http://devbench-manager:3001/health +``` + +### SSH Connection Fails + +**Problem**: Cannot connect to VM host + +**Solution**: +```bash +# 1. Test SSH manually +ssh -p 49152 asf@asf-server.duckdns.org + +# 2. Check if sshpass is installed in container +docker exec devbench-manager which sshpass + +# 3. Check provision script +docker exec devbench-manager cat /app/provision_vm.sh | grep SSH_ + +# 4. Test from container +docker exec -it devbench-manager bash +./provision_vm.sh status test_vm +``` + +### Database Errors + +**Problem**: Database locked or corrupted + +**Solution**: +```bash +# 1. Stop container +docker-compose down + +# 2. Backup database +cp data/devbench.db data/devbench.db.backup + +# 3. Check database integrity +sqlite3 data/devbench.db "PRAGMA integrity_check;" + +# 4. If corrupted, restore from backup or recreate +rm data/devbench.db +docker-compose up -d +``` + +### WebSocket Not Working + +**Problem**: Real-time updates not appearing + +**Solution**: +```bash +# 1. Check browser console for errors +# Open DevTools โ†’ Console + +# 2. Verify WebSocket connection +# Look for "WebSocket connected" message + +# 3. Check if behind proxy +# Ensure proxy supports WebSocket upgrade + +# 4. Test WebSocket endpoint +wscat -c ws://localhost:9090 +``` + +## Maintenance + +### Regular Tasks + +#### Daily +- Monitor logs for errors +- Check disk space +- Verify health endpoint + +#### Weekly +- Review user activity +- Clean up old logs +- Check for updates + +#### Monthly +- Backup database +- Review security +- Update dependencies + +### Updating the Application + +```bash +# 1. Pull latest changes +git pull origin main + +# 2. Backup database +cp data/devbench.db data/devbench.db.$(date +%Y%m%d) + +# 3. Rebuild and restart +docker-compose down +docker-compose up -d --build + +# 4. Verify +curl http://localhost:9090/health +``` + +### Viewing Logs + +```bash +# Real-time logs +docker-compose logs -f + +# Last 100 lines +docker-compose logs --tail=100 + +# Specific time range +docker-compose logs --since 2h + +# Save logs to file +docker-compose logs > logs/docker-$(date +%Y%m%d).log +``` + +### Cleaning Up + +```bash +# Remove stopped containers +docker container prune -f + +# Remove unused images +docker image prune -a -f + +# Remove unused volumes +docker volume prune -f + +# Clean everything +docker system prune -a -f +``` + +### Scaling (Future) + +For multiple instances: + +```bash +# Scale to 3 instances +docker-compose up -d --scale devbench-manager=3 + +# Use load balancer (nginx/haproxy) +# Configure session persistence +``` + +## Backup & Recovery + +### Backup Strategy + +#### Database Backup + +```bash +# Manual backup +cp data/devbench.db backups/devbench-$(date +%Y%m%d-%H%M%S).db + +# Automated backup script +#!/bin/bash +BACKUP_DIR="backups" +mkdir -p $BACKUP_DIR +cp data/devbench.db $BACKUP_DIR/devbench-$(date +%Y%m%d).db +# Keep only last 7 days +find $BACKUP_DIR -name "devbench-*.db" -mtime +7 -delete +``` + +#### Full Backup + +```bash +# Backup everything +tar -czf devbench-backup-$(date +%Y%m%d).tar.gz \ + data/ \ + logs/ \ + config.js \ + .env \ + docker-compose.yml +``` + +### Recovery + +#### Restore Database + +```bash +# 1. Stop container +docker-compose down + +# 2. Restore database +cp backups/devbench-20251123.db data/devbench.db + +# 3. Start container +docker-compose up -d + +# 4. Verify +curl http://localhost:9090/health +``` + +#### Full Recovery + +```bash +# 1. Extract backup +tar -xzf devbench-backup-20251123.tar.gz + +# 2. Deploy +./deploy.sh + +# 3. Verify all services +``` + +### Disaster Recovery + +#### Complete System Failure + +```bash +# 1. Fresh installation +git clone +cd ASF_devbench + +# 2. Restore backups +cp /backup/location/devbench.db data/ +cp /backup/location/.env . + +# 3. Deploy +./deploy.sh + +# 4. Verify users and DevBenches +``` + +## Security Hardening + +### Change Default Credentials + +```bash +# 1. Login as admin +# 2. Go to admin panel +# 3. Reset admin password +# Or use API: +curl -X POST http://localhost:9090/admin/reset-password/1 \ + -H "Content-Type: application/json" \ + -d '{"newPassword":"new-secure-password"}' +``` + +### Update Session Secret + +Edit `.env`: +```bash +SECRET_KEY=$(openssl rand -base64 32) +``` + +Restart: +```bash +docker-compose restart +``` + +### Enable HTTPS + +Use Caddy for automatic HTTPS: +``` +tbm.nabd-co.com { + reverse_proxy devbench-manager:3001 +} +``` + +### Restrict Access + +Use firewall: +```bash +# Allow only specific IPs +sudo ufw allow from 192.168.1.0/24 to any port 9090 +``` + +## Monitoring + +### Health Monitoring + +```bash +# Simple health check script +#!/bin/bash +if curl -sf http://localhost:9090/health > /dev/null; then + echo "OK" +else + echo "FAILED" + # Send alert +fi +``` + +### Log Monitoring + +```bash +# Watch for errors +docker-compose logs -f | grep -i error + +# Count errors +docker-compose logs | grep -i error | wc -l +``` + +### Resource Monitoring + +```bash +# Container stats +docker stats devbench-manager + +# Disk usage +du -sh data/ logs/ + +# Database size +ls -lh data/devbench.db +``` + +## Performance Tuning + +### Database Optimization + +```bash +# Vacuum database +docker exec devbench-manager sqlite3 /app/data/devbench.db "VACUUM;" + +# Analyze database +docker exec devbench-manager sqlite3 /app/data/devbench.db "ANALYZE;" +``` + +### Container Resources + +Edit `docker-compose.yml`: +```yaml +services: + devbench-manager: + deploy: + resources: + limits: + cpus: '1.0' + memory: 512M + reservations: + cpus: '0.5' + memory: 256M +``` + +## Support + +### Getting Help + +1. Check logs: `docker-compose logs` +2. Review documentation in `/docs` +3. Check GitHub issues +4. Contact system administrator + +### Reporting Issues + +Include: +- Docker version: `docker --version` +- Docker Compose version: `docker-compose --version` +- Container logs: `docker-compose logs` +- Error messages +- Steps to reproduce diff --git a/asf-cloud-server/TBM_devbench/docs/STRUCTURE.md b/asf-cloud-server/TBM_devbench/docs/STRUCTURE.md new file mode 100644 index 0000000..55568de --- /dev/null +++ b/asf-cloud-server/TBM_devbench/docs/STRUCTURE.md @@ -0,0 +1,530 @@ +# DevBench Manager - Project Structure + +## Directory Tree + +``` +ASF_devbench/ +โ”œโ”€โ”€ docs/ # Documentation +โ”‚ โ”œโ”€โ”€ ARCHITECTURE.md # System architecture +โ”‚ โ”œโ”€โ”€ STRUCTURE.md # This file +โ”‚ โ”œโ”€โ”€ DEPLOYMENT.md # Deployment guide +โ”‚ โ””โ”€โ”€ API.md # API documentation +โ”‚ +โ”œโ”€โ”€ public/ # Static assets +โ”‚ โ”œโ”€โ”€ css/ +โ”‚ โ”‚ โ””โ”€โ”€ style.css # Custom styles + dark theme +โ”‚ โ”œโ”€โ”€ images/ +โ”‚ โ”‚ โ”œโ”€โ”€ nabd-logo.svg # Company logo (light) +โ”‚ โ”‚ โ”œโ”€โ”€ nabd-logo-white.svg # Company logo (dark) +โ”‚ โ”‚ โ””โ”€โ”€ tbm-icon.png # TBM branding icon +โ”‚ โ””โ”€โ”€ downloads/ +โ”‚ โ””โ”€โ”€ db_vm_ssh_config_manager.exe # SSH config tool +โ”‚ +โ”œโ”€โ”€ views/ # EJS templates +โ”‚ โ”œโ”€โ”€ layout.ejs # Base layout with navbar +โ”‚ โ”œโ”€โ”€ login.ejs # Login page +โ”‚ โ”œโ”€โ”€ dashboard.ejs # User dashboard +โ”‚ โ”œโ”€โ”€ admin.ejs # Admin panel +โ”‚ โ””โ”€โ”€ help.ejs # Help/documentation page +โ”‚ +โ”œโ”€โ”€ data/ # Database storage (created on deploy) +โ”‚ โ””โ”€โ”€ devbench.db # SQLite database +โ”‚ +โ”œโ”€โ”€ logs/ # Application logs (created on deploy) +โ”‚ โ””โ”€โ”€ *.log # Log files +โ”‚ +โ”œโ”€โ”€ server.js # Main application server +โ”œโ”€โ”€ config.js # Configuration settings +โ”œโ”€โ”€ package.json # Node.js dependencies +โ”œโ”€โ”€ provision_vm.sh # VM provisioning script +โ”‚ +โ”œโ”€โ”€ Dockerfile # Docker image definition +โ”œโ”€โ”€ docker-compose.yml # Container orchestration +โ”œโ”€โ”€ .dockerignore # Docker build exclusions +โ”‚ +โ”œโ”€โ”€ deploy.sh # Deployment script +โ”œโ”€โ”€ install.sh # Local installation script +โ”œโ”€โ”€ start.sh # Start script (Docker/Node) +โ”œโ”€โ”€ cleanup.sh # Cleanup script +โ”‚ +โ”œโ”€โ”€ .env.example # Environment variables template +โ”œโ”€โ”€ .gitignore # Git exclusions +โ”œโ”€โ”€ README.md # Main documentation +โ””โ”€โ”€ CHANGELOG.md # Change history +``` + +## File Descriptions + +### Core Application Files + +#### `server.js` +**Purpose**: Main Express.js application server + +**Key Components**: +- Express app initialization +- Database setup and schema +- Route definitions +- WebSocket server +- Authentication middleware +- DevBench management logic +- Provision script executor +- Status monitoring (60-second interval) + +**Dependencies**: +- express +- express-session +- sqlite3 +- bcryptjs +- ws (WebSocket) +- child_process (for script execution) + +**Key Functions**: +```javascript +- requireAuth() // Authentication middleware +- requireAdmin() // Admin authorization middleware +- executeProvisionScript() // Execute VM provisioning +- broadcastToUser() // WebSocket messaging +``` + +#### `config.js` +**Purpose**: Centralized configuration + +**Settings**: +- Server port +- Database path +- Session configuration +- Default admin credentials +- Validation patterns +- Provision script settings + +#### `provision_vm.sh` +**Purpose**: VM provisioning and management + +**Commands**: +- `create `: Create new VM +- `status `: Check VM status +- `delete `: Delete VM +- `activate `: Activate VM +- `start `: Start VM +- `stop `: Stop VM + +**Features**: +- SSH connection to remote host +- Output logging +- Connection info extraction +- Error handling +- Timeout management (30 minutes) + +### Frontend Files + +#### `views/layout.ejs` +**Purpose**: Base template for all pages + +**Features**: +- Navigation bar with logo +- Help link +- Theme toggle button +- WebSocket initialization +- Bootstrap and Font Awesome imports +- Dark theme JavaScript + +#### `views/dashboard.ejs` +**Purpose**: User dashboard + +**Features**: +- DevBench list with cards +- Create DevBench modal +- Connection info display (SSH/VNC ports) +- Real-time log output +- Status indicators +- Copy-to-clipboard functionality + +#### `views/admin.ejs` +**Purpose**: Admin panel + +**Features**: +- User management table +- Add user modal +- DevBench overview table +- Password reset +- User deletion +- DevBench deletion + +#### `views/help.ejs` +**Purpose**: Help and documentation + +**Features**: +- SSH Config Manager guide +- Step-by-step instructions +- Download link for tool +- Connection information +- Important notes + +#### `views/login.ejs` +**Purpose**: Authentication page + +**Features**: +- Login form +- Error messages +- Branding + +### Static Assets + +#### `public/css/style.css` +**Purpose**: Custom styling + +**Features**: +- NABD brand colors +- Dark theme styles +- Component styling +- Responsive design +- Smooth transitions + +#### `public/images/` +**Purpose**: Image assets + +**Files**: +- `nabd-logo.svg`: Light theme logo +- `nabd-logo-white.svg`: Dark theme logo +- `tbm-icon.png`: Branding icon and favicon + +#### `public/downloads/` +**Purpose**: Downloadable files + +**Files**: +- `db_vm_ssh_config_manager.exe`: SSH configuration tool + +### Deployment Files + +#### `Dockerfile` +**Purpose**: Docker image definition + +**Base Image**: node:18-alpine + +**Steps**: +1. Set working directory +2. Copy package files +3. Install dependencies +4. Copy application files +5. Create data/logs directories +6. Expose port 3001 +7. Set start command + +#### `docker-compose.yml` +**Purpose**: Container orchestration + +**Configuration**: +- Service: devbench-manager +- Port mapping: 9090:3001 +- Volumes: data, logs, provision script +- Networks: app-network, caddy_network +- Health check: /health endpoint +- Restart policy: unless-stopped + +#### `deploy.sh` +**Purpose**: Automated deployment + +**Steps**: +1. Create directories +2. Set permissions +3. Clean up old containers +4. Create Docker network +5. Build and start container +6. Wait for startup +7. Verify health +8. Display access information + +### Configuration Files + +#### `package.json` +**Purpose**: Node.js project configuration + +**Scripts**: +- `start`: Run production server +- `dev`: Run with nodemon (auto-reload) + +**Dependencies**: +- express: Web framework +- express-session: Session management +- bcryptjs: Password hashing +- sqlite3: Database +- body-parser: Request parsing +- ejs: Template engine +- ws: WebSocket +- child_process: Script execution + +#### `.env.example` +**Purpose**: Environment variables template + +**Variables**: +- NODE_ENV +- PORT +- SECRET_KEY +- ADMIN_EMAIL +- ADMIN_PASSWORD + +#### `.gitignore` +**Purpose**: Git exclusions + +**Excluded**: +- node_modules/ +- data/ +- logs/ +- .env +- *.log +- .DS_Store + +### Utility Scripts + +#### `install.sh` +**Purpose**: Local installation + +**Actions**: +- Check Node.js version +- Install npm dependencies +- Display start instructions + +#### `start.sh` +**Purpose**: Start application + +**Logic**: +- Check for Docker +- Start with Docker Compose if available +- Fall back to Node.js +- Install dependencies if needed + +#### `cleanup.sh` +**Purpose**: Clean up containers + +**Actions**: +- Stop containers +- Remove containers +- Prune dangling containers +- List volumes + +### Documentation Files + +#### `README.md` +**Purpose**: Main project documentation + +**Sections**: +- Features overview +- Installation instructions +- Configuration guide +- Usage instructions +- API endpoints +- Troubleshooting + +#### `CHANGELOG.md` +**Purpose**: Change history + +**Content**: +- Recent updates +- SSH configuration changes +- Output format changes +- New features +- Migration notes + +#### `docs/ARCHITECTURE.md` +**Purpose**: System architecture + +**Content**: +- Architecture diagrams +- Component descriptions +- Data flow +- Security architecture +- Technology stack + +#### `docs/DEPLOYMENT.md` +**Purpose**: Deployment guide + +**Content**: +- Prerequisites +- Deployment steps +- Configuration +- Troubleshooting +- Maintenance + +## Data Flow Through Files + +### DevBench Creation +``` +1. views/dashboard.ejs + โ†“ (User clicks Create) +2. server.js (POST /create-devbench) + โ†“ (Validates and creates DB record) +3. server.js (executeProvisionScript) + โ†“ (Spawns child process) +4. provision_vm.sh + โ†“ (SSH to remote host) +5. Remote VM Host + โ†“ (Creates VM, returns info) +6. provision_vm.sh + โ†“ (Parses output) +7. server.js + โ†“ (Updates database) +8. WebSocket + โ†“ (Broadcasts to user) +9. views/dashboard.ejs + โ†“ (Updates UI) +``` + +### Authentication +``` +1. views/login.ejs + โ†“ (User submits form) +2. server.js (POST /login) + โ†“ (Validates credentials) +3. config.js (validation patterns) + โ†“ +4. server.js (bcrypt compare) + โ†“ (Creates session) +5. express-session + โ†“ (Stores session) +6. server.js (redirect) + โ†“ +7. views/dashboard.ejs or views/admin.ejs +``` + +### Theme Toggle +``` +1. views/layout.ejs (Theme toggle button) + โ†“ (User clicks) +2. JavaScript (theme toggle handler) + โ†“ (Toggles class) +3. public/css/style.css (dark-theme styles) + โ†“ (Applies styles) +4. localStorage + โ†“ (Saves preference) +``` + +## Key Directories + +### `/data` +- **Created**: On first deployment +- **Purpose**: SQLite database storage +- **Persistence**: Docker volume +- **Backup**: Copy devbench.db file + +### `/logs` +- **Created**: On first deployment +- **Purpose**: Application logs +- **Persistence**: Docker volume +- **Rotation**: Manual + +### `/public` +- **Purpose**: Static assets served by Express +- **Access**: Direct URL paths +- **Caching**: Browser caching enabled + +### `/views` +- **Purpose**: EJS templates +- **Rendering**: Server-side +- **Access**: Via routes only + +### `/docs` +- **Purpose**: Project documentation +- **Format**: Markdown +- **Access**: File system only + +## Configuration Hierarchy + +``` +1. Environment Variables (.env) + โ†“ +2. config.js (defaults) + โ†“ +3. docker-compose.yml (container env) + โ†“ +4. Application runtime +``` + +## Port Mapping + +``` +External โ†’ Container โ†’ Application +9090 โ†’ 3001 โ†’ Express Server +``` + +## Network Architecture + +``` +Internet + โ†“ +Caddy (caddy_network) + โ†“ +DevBench Manager (caddy_network + app-network) + โ†“ +SQLite (local file) + โ†“ +SSH (external) + โ†“ +Remote VM Host +``` + +## File Permissions + +### Scripts +- `provision_vm.sh`: 755 (executable) +- `deploy.sh`: 755 (executable) +- `install.sh`: 755 (executable) +- `start.sh`: 755 (executable) +- `cleanup.sh`: 755 (executable) + +### Directories +- `data/`: 755 +- `logs/`: 755 +- `public/`: 755 + +### Database +- `devbench.db`: 644 (read/write for owner) + +## Build Process + +### Docker Build +``` +1. Read Dockerfile +2. Pull node:18-alpine +3. Copy package.json +4. npm install +5. Copy application files +6. Set permissions +7. Create image +``` + +### Docker Compose +``` +1. Read docker-compose.yml +2. Create networks +3. Build image (if needed) +4. Create container +5. Mount volumes +6. Start container +7. Run health checks +``` + +## Runtime Process + +### Container Startup +``` +1. Docker starts container +2. Node.js starts +3. server.js executes +4. Database initialized +5. Express server starts +6. WebSocket server starts +7. Health check passes +8. Ready for connections +``` + +### Request Handling +``` +1. Request arrives at Caddy +2. Proxied to container +3. Express routes request +4. Middleware checks auth +5. Controller handles logic +6. Database query (if needed) +7. Template rendered +8. Response sent +``` diff --git a/asf-cloud-server/TBM_devbench/icon.png b/asf-cloud-server/TBM_devbench/icon.png new file mode 100644 index 0000000..af7f26f Binary files /dev/null and b/asf-cloud-server/TBM_devbench/icon.png differ diff --git a/asf-cloud-server/TBM_devbench/icone.ico b/asf-cloud-server/TBM_devbench/icone.ico new file mode 100644 index 0000000..249f007 Binary files /dev/null and b/asf-cloud-server/TBM_devbench/icone.ico differ diff --git a/asf-cloud-server/TBM_devbench/install.sh b/asf-cloud-server/TBM_devbench/install.sh new file mode 100644 index 0000000..2dd70e4 --- /dev/null +++ b/asf-cloud-server/TBM_devbench/install.sh @@ -0,0 +1,38 @@ +#!/bin/bash + +echo "Installing DevBench Manager..." + +# Check if Node.js is installed +if ! command -v node &> /dev/null; then + echo "Node.js is not installed. Please install Node.js 18+ first." + echo "Visit: https://nodejs.org/" + exit 1 +fi + +# Check Node.js version +NODE_VERSION=$(node -v | cut -d'v' -f2 | cut -d'.' -f1) +if [ "$NODE_VERSION" -lt 18 ]; then + echo "Node.js version 18 or higher is required. Current version: $(node -v)" + exit 1 +fi + +echo "Node.js version: $(node -v) โœ“" + +# Install npm dependencies +echo "Installing npm dependencies..." +npm install + +if [ $? -eq 0 ]; then + echo "โœ“ Dependencies installed successfully!" + echo "" + echo "Setup complete! You can now start the application with:" + echo " npm start" + echo " or" + echo " ./start.sh" + echo "" + echo "The application will be available at: http://localhost:3001" + echo "Default admin login: admin / admin123" +else + echo "โœ— Failed to install dependencies" + exit 1 +fi \ No newline at end of file diff --git a/asf-cloud-server/TBM_devbench/package.json b/asf-cloud-server/TBM_devbench/package.json new file mode 100644 index 0000000..ce61d15 --- /dev/null +++ b/asf-cloud-server/TBM_devbench/package.json @@ -0,0 +1,26 @@ +{ + "name": "devbench-manager", + "version": "1.0.0", + "description": "DevBench Manager Web Application", + "main": "server.js", + "scripts": { + "start": "node server.js", + "dev": "nodemon server.js" + }, + "dependencies": { + "express": "^4.18.2", + "express-session": "^1.17.3", + "bcryptjs": "^2.4.3", + "sqlite3": "^5.1.6", + "body-parser": "^1.20.2", + "ejs": "^3.1.9", + "child_process": "^1.0.2", + "ws": "^8.14.2" + }, + "devDependencies": { + "nodemon": "^3.0.1" + }, + "keywords": ["devbench", "vm", "manager"], + "author": "", + "license": "MIT" +} \ No newline at end of file diff --git a/asf-cloud-server/TBM_devbench/provision_vm.sh b/asf-cloud-server/TBM_devbench/provision_vm.sh new file mode 100644 index 0000000..d2a1178 --- /dev/null +++ b/asf-cloud-server/TBM_devbench/provision_vm.sh @@ -0,0 +1,155 @@ +#!/bin/bash + +# Set up logging +LOG_DIR="/var/log/devbench" +LOG_FILE="$LOG_DIR/provision_vm_$(date +%Y%m%d_%H%M%S).log" + +# Create log directory if it doesn't exist +mkdir -p "$LOG_DIR" +chmod 777 "$LOG_DIR" + +# Function to log messages +log() { + local timestamp=$(date '+%Y-%m-%d %H:%M:%S') + echo "[$timestamp] $1" | tee -a "$LOG_FILE" +} + +log "Starting provision_vm.sh with arguments: $*" + +# Check if enough arguments were provided for the remote script. +# The remote 'provision_vm.sh' script expects at least 2 arguments: . +if [ "$#" -lt 2 ]; then + error_msg="Error: Please provide at least two arguments for the remote command." + log "$error_msg" + echo "Usage: $0 " + echo "Example: $0 create username_vmname" + echo " $0 status username_vmname" + exit 1 +fi + +# SSH connection details +SSH_USER="asf" +SSH_HOST="asf-server.duckdns.org" +SSH_PORT="49152" +SSH_PASS="ASF" + +# The path to the script on the remote server +REMOTE_SCRIPT_PATH="./provision_vm.sh" + +# Get command and VM name from arguments +COMMAND="$1" +VM_NAME="$2" + +# Validate command +if [[ ! "$COMMAND" =~ ^(create|status|delete|start|stop|activate)$ ]]; then + log "Error: Invalid command '$COMMAND'. Must be one of: create, status, delete, start, stop, activate" + exit 1 +fi + +# Validate VM name format (username_vmname) +if [[ ! "$VM_NAME" =~ ^[a-zA-Z0-9_]+_[a-zA-Z0-9_-]+$ ]]; then + log "Error: Invalid VM name format. Must be in format: username_vmname" + exit 1 +fi + +# Extract username from VM name (everything before first underscore) +USERNAME="${VM_NAME%%_*}" + +log "Command: $COMMAND, VM: $VM_NAME, User: $USERNAME" + +# Check if sshpass is available +if ! command -v sshpass &> /dev/null; then + log "Error: sshpass is not installed. Please install it with 'apt-get install sshpass'" + exit 1 +fi + +# Check if we can resolve the host +if ! getent hosts "$SSH_HOST" >/dev/null 2>&1; then + log "Error: Cannot resolve host $SSH_HOST" + exit 1 +fi + +# Create a temporary file to capture output +TEMP_OUTPUT=$(mktemp) +log "Temporary output file: $TEMP_OUTPUT" + +# Function to clean up temp file +cleanup() { + if [ -f "$TEMP_OUTPUT" ]; then + rm -f "$TEMP_OUTPUT" + log "Temporary files cleaned up" + fi +} +# Set up trap to ensure cleanup happens on script exit +trap cleanup EXIT + +# Build the full SSH command +SSH_CMD="ssh -p $SSH_PORT -o StrictHostKeyChecking=no -o ConnectTimeout=10 -o ServerAliveInterval=60 -o ServerAliveCountMax=30" +FULL_CMD="$REMOTE_SCRIPT_PATH $COMMAND $VM_NAME" + +log "Executing remote command: $FULL_CMD" + +# Execute the remote command with sshpass and capture output +{ + # Increase timeout to 1800 seconds (30 minutes) and ensure we capture all output + if ! output=$(timeout 1800 sshpass -p "$SSH_PASS" $SSH_CMD "$SSH_USER@$SSH_HOST" "$FULL_CMD" 2>&1); then + EXIT_CODE=$? + # Capture any partial output even if command failed + echo "$output" + if [ $EXIT_CODE -eq 124 ]; then + log "ERROR: Command timed out after 30 minutes" + exit 124 + else + log "ERROR: Command failed with exit code $EXIT_CODE" + exit $EXIT_CODE + fi + else + # Command succeeded, output the result + echo "$output" + fi +} | tee "$TEMP_OUTPUT" + +# Process the output to extract connection information +SSH_PORT="" +VNC_PORT="" +VM_NAME_ACTUAL="" + +# Read the output line by line to parse connection info +while IFS= read -r line; do + # Extract SSH port (e.g., "SSH Port: 6004") + if [[ $line == *"SSH Port:"* ]]; then + SSH_PORT=$(echo "$line" | grep -oE 'SSH Port: [0-9]+' | cut -d' ' -f3) + # Extract VNC port (e.g., "VNC Port: 5004") + elif [[ $line == *"VNC Port:"* ]]; then + VNC_PORT=$(echo "$line" | grep -oE 'VNC Port: [0-9]+' | cut -d' ' -f3) + # Extract VM name from success message + elif [[ $line == *"VM"*"Created and Ready"* ]]; then + VM_NAME_ACTUAL=$(echo "$line" | sed -n 's/.*VM \([^ ]*\) Created and Ready.*/\1/p') + fi + + # Log each line to the log file + log "$line" +done < "$TEMP_OUTPUT" + +# Output the connection information in a structured format +echo "VM_CREATION_COMPLETE" +if [ -n "$VM_NAME_ACTUAL" ]; then + echo "VM_NAME=$VM_NAME_ACTUAL" +fi +if [ -n "$SSH_PORT" ]; then + echo "SSH_PORT=$SSH_PORT" +fi +if [ -n "$VNC_PORT" ]; then + echo "VNC_PORT=$VNC_PORT" +fi + +# Check if the command was successful +if [ ${PIPESTATUS[0]} -eq 0 ]; then + log "Remote command executed successfully" + exit 0 +else + log "Remote command failed" + exit 1 +fi + +log "Provisioning script completed successfully" \ No newline at end of file diff --git a/asf-cloud-server/TBM_devbench/public/css/style.css b/asf-cloud-server/TBM_devbench/public/css/style.css new file mode 100644 index 0000000..daee8dc --- /dev/null +++ b/asf-cloud-server/TBM_devbench/public/css/style.css @@ -0,0 +1,308 @@ +/* Custom styles for DevBench Manager */ + +.navbar-brand { + font-weight: bold; + color: #ffffff !important; + display: flex; + align-items: center; +} + +.navbar-brand img { + height: 40px; + margin-right: 10px; +} + +.company-logo { + max-height: 40px; + width: auto; +} + +.status-active { + color: #28a745; +} + +.status-inactive { + color: #dc3545; +} + +.status-creating { + color: #ffc107; +} + +.log-output { + background-color: #1e1e1e; + color: #ffffff; + font-family: 'Courier New', monospace; + font-size: 12px; + padding: 15px; + border-radius: 5px; + max-height: 400px; + overflow-y: auto; + white-space: pre-wrap; +} + +.connection-info { + background-color: #f8f9fa; + border: 1px solid #dee2e6; + border-radius: 5px; + padding: 10px; + margin-top: 10px; +} + +.connection-info code { + background-color: #e9ecef; + padding: 2px 4px; + border-radius: 3px; + word-break: break-all; +} + +.login-card { + box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1); +} + +.brand-colors { + background: linear-gradient(135deg, #f39c12 0%, #1a365d 100%); + -webkit-background-clip: text; + -webkit-text-fill-color: transparent; + background-clip: text; +} + +/* NABD Solutions brand colors */ +.nabd-orange { + color: #f39c12; +} + +.nabd-blue { + color: #1a365d; +} + +.bg-nabd-gradient { + background: linear-gradient(135deg, #f39c12 0%, #1a365d 100%); +} + +/* Dark blue theme overrides */ +.bg-primary { + background-color: #1a365d !important; +} + +.btn-primary { + background-color: #1a365d; + border-color: #1a365d; +} + +.btn-primary:hover { + background-color: #2c5282; + border-color: #2c5282; +} + +.btn-primary:focus { + background-color: #2c5282; + border-color: #2c5282; + box-shadow: 0 0 0 0.2rem rgba(26, 54, 93, 0.25); +} + +.btn-outline-primary { + color: #1a365d; + border-color: #1a365d; +} + +.btn-outline-primary:hover { + background-color: #1a365d; + border-color: #1a365d; +} + +.text-primary { + color: #1a365d !important; +} + +.card-header.bg-primary { + background-color: #1a365d !important; +} + +/* Password info styling */ +.connection-info small { + display: block; + margin-top: 5px; + padding: 3px 8px; + background-color: #e8f4fd; + border-radius: 3px; + border-left: 3px solid #1a365d; +} + +/* ============================================ + DARK THEME + ============================================ */ + +/* Dark theme toggle button */ +.theme-toggle { + position: fixed; + bottom: 20px; + right: 20px; + z-index: 1000; + width: 50px; + height: 50px; + border-radius: 50%; + background: linear-gradient(135deg, #f39c12 0%, #1a365d 100%); + border: none; + color: white; + font-size: 20px; + cursor: pointer; + box-shadow: 0 4px 12px rgba(0, 0, 0, 0.3); + transition: transform 0.3s ease, box-shadow 0.3s ease; +} + +.theme-toggle:hover { + transform: scale(1.1); + box-shadow: 0 6px 16px rgba(0, 0, 0, 0.4); +} + +/* Dark theme styles */ +body.dark-theme { + background-color: #1a1a1a; + color: #e0e0e0; +} + +body.dark-theme .navbar { + background-color: #0d1b2a !important; +} + +body.dark-theme .card { + background-color: #2d2d2d; + border-color: #404040; + color: #e0e0e0; +} + +body.dark-theme .card-header { + background-color: #1a365d; + border-color: #404040; + color: #ffffff; +} + +body.dark-theme .card-header.bg-info { + background-color: #0c5460 !important; +} + +body.dark-theme .card-header.bg-warning { + background-color: #856404 !important; +} + +body.dark-theme .table { + color: #e0e0e0; +} + +body.dark-theme .table-striped tbody tr:nth-of-type(odd) { + background-color: #333333; +} + +body.dark-theme .table-striped tbody tr:nth-of-type(even) { + background-color: #2d2d2d; +} + +body.dark-theme .modal-content { + background-color: #2d2d2d; + color: #e0e0e0; +} + +body.dark-theme .modal-header { + border-bottom-color: #404040; +} + +body.dark-theme .modal-footer { + border-top-color: #404040; +} + +body.dark-theme .form-control { + background-color: #1a1a1a; + border-color: #404040; + color: #e0e0e0; +} + +body.dark-theme .form-control:focus { + background-color: #1a1a1a; + border-color: #1a365d; + color: #e0e0e0; +} + +body.dark-theme .connection-info { + background-color: #1a1a1a; + border-color: #404040; +} + +body.dark-theme .connection-info code { + background-color: #0d1b2a; + color: #f39c12; +} + +body.dark-theme .alert-info { + background-color: #0c5460; + border-color: #0c5460; + color: #d1ecf1; +} + +body.dark-theme .alert-info .alert-link { + color: #bee5eb; +} + +body.dark-theme .text-muted { + color: #999999 !important; +} + +body.dark-theme .btn-secondary { + background-color: #404040; + border-color: #404040; +} + +body.dark-theme .btn-secondary:hover { + background-color: #555555; + border-color: #555555; +} + +body.dark-theme .btn-outline-primary { + color: #f39c12; + border-color: #f39c12; +} + +body.dark-theme .btn-outline-primary:hover { + background-color: #f39c12; + border-color: #f39c12; + color: #1a1a1a; +} + +body.dark-theme .login-card { + background-color: #2d2d2d; + box-shadow: 0 4px 12px rgba(0, 0, 0, 0.5); +} + +body.dark-theme .form-text { + color: #999999; +} + +body.dark-theme .connection-info small { + background-color: #0d1b2a; + border-left-color: #f39c12; + color: #e0e0e0; +} + +body.dark-theme .help-steps code { + background-color: #0d1b2a; + color: #f39c12; +} + +body.dark-theme .help-steps strong { + color: #f39c12; +} + +body.dark-theme pre { + background-color: #0d1b2a !important; + color: #e0e0e0; +} + +/* Smooth transitions for theme switching */ +body, +.card, +.modal-content, +.form-control, +.connection-info, +.table { + transition: background-color 0.3s ease, color 0.3s ease, border-color 0.3s ease; +} \ No newline at end of file diff --git a/asf-cloud-server/TBM_devbench/public/downloads/db_vm_ssh_config_manager.exe b/asf-cloud-server/TBM_devbench/public/downloads/db_vm_ssh_config_manager.exe new file mode 100644 index 0000000..9692e9e Binary files /dev/null and b/asf-cloud-server/TBM_devbench/public/downloads/db_vm_ssh_config_manager.exe differ diff --git a/asf-cloud-server/TBM_devbench/public/images/nabd-logo-white.svg b/asf-cloud-server/TBM_devbench/public/images/nabd-logo-white.svg new file mode 100644 index 0000000..5e37817 --- /dev/null +++ b/asf-cloud-server/TBM_devbench/public/images/nabd-logo-white.svg @@ -0,0 +1,13 @@ + + + + + + + + + NABD + + + SOLUTIONS + \ No newline at end of file diff --git a/asf-cloud-server/TBM_devbench/public/images/nabd-logo.svg b/asf-cloud-server/TBM_devbench/public/images/nabd-logo.svg new file mode 100644 index 0000000..c280685 --- /dev/null +++ b/asf-cloud-server/TBM_devbench/public/images/nabd-logo.svg @@ -0,0 +1,13 @@ + + + + + + + + + NABD + + + SOLUTIONS + \ No newline at end of file diff --git a/asf-cloud-server/TBM_devbench/public/images/tbm-icon.png b/asf-cloud-server/TBM_devbench/public/images/tbm-icon.png new file mode 100644 index 0000000..af7f26f Binary files /dev/null and b/asf-cloud-server/TBM_devbench/public/images/tbm-icon.png differ diff --git a/asf-cloud-server/TBM_devbench/server.js b/asf-cloud-server/TBM_devbench/server.js new file mode 100644 index 0000000..791770f --- /dev/null +++ b/asf-cloud-server/TBM_devbench/server.js @@ -0,0 +1,593 @@ +const express = require('express'); +const session = require('express-session'); +const bcrypt = require('bcryptjs'); +const sqlite3 = require('sqlite3').verbose(); +const bodyParser = require('body-parser'); +const { spawn } = require('child_process'); +const WebSocket = require('ws'); +const http = require('http'); +const path = require('path'); +const config = require('./config'); + +const app = express(); +const server = http.createServer(app); +const wss = new WebSocket.Server({ server }); + +// Database setup +const db = new sqlite3.Database(config.database.path); + +// Initialize database tables +db.serialize(() => { + // Users table + db.run(`CREATE TABLE IF NOT EXISTS users ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + username TEXT UNIQUE NOT NULL, + email TEXT NOT NULL, + password TEXT NOT NULL, + is_admin INTEGER DEFAULT 0, + created_at DATETIME DEFAULT CURRENT_TIMESTAMP + )`); + + // DevBenches table + db.run(`CREATE TABLE IF NOT EXISTS devbenches ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + user_id INTEGER NOT NULL, + name TEXT NOT NULL, + actual_name TEXT, + status TEXT DEFAULT 'inactive', + ssh_info TEXT, + vnc_info TEXT, + created_at DATETIME DEFAULT CURRENT_TIMESTAMP, + updated_at DATETIME DEFAULT CURRENT_TIMESTAMP, + FOREIGN KEY (user_id) REFERENCES users (id) + )`); + + // Create default admin user if not exists + const adminPassword = bcrypt.hashSync(config.defaultAdmin.password, 10); + db.run(`INSERT OR IGNORE INTO users (username, email, password, is_admin) + VALUES (?, ?, ?, 1)`, [config.defaultAdmin.username, config.defaultAdmin.email, adminPassword]); +}); + +// Middleware +app.use(bodyParser.urlencoded({ extended: true })); +app.use(bodyParser.json()); +app.use(express.static('public')); +app.set('view engine', 'ejs'); + +app.use(session({ + secret: config.session.secret, + resave: false, + saveUninitialized: false, + cookie: { secure: false, maxAge: config.session.maxAge } +})); + +// Authentication middleware +const requireAuth = (req, res, next) => { + if (req.session.userId) { + next(); + } else { + res.redirect('/login'); + } +}; + +const requireAdmin = (req, res, next) => { + if (req.session.userId && req.session.isAdmin) { + next(); + } else { + res.status(403).send('Access denied'); + } +}; + +// WebSocket connections for real-time updates +const clients = new Map(); + +wss.on('connection', (ws, req) => { + console.log('WebSocket connection established'); + + ws.on('message', (message) => { + try { + const data = JSON.parse(message); + if (data.type === 'register' && data.userId) { + clients.set(data.userId, ws); + console.log(`User ${data.userId} registered for WebSocket updates`); + } + } catch (error) { + console.error('WebSocket message error:', error); + } + }); + + ws.on('close', () => { + // Remove this connection from all users + for (const [userId, client] of clients.entries()) { + if (client === ws) { + clients.delete(userId); + console.log(`User ${userId} WebSocket disconnected`); + break; + } + } + }); +}); + +// Broadcast to specific user +const broadcastToUser = (userId, message) => { + const client = clients.get(userId); + if (client && client.readyState === WebSocket.OPEN) { + try { + client.send(JSON.stringify(message)); + console.log(`Sent message to user ${userId}:`, message.type); + } catch (error) { + console.error(`Error sending message to user ${userId}:`, error); + clients.delete(userId); + } + } else { + console.log(`No active WebSocket for user ${userId}`); + } +}; + +// Health check endpoint +app.get('/health', (req, res) => { + res.json({ + status: 'ok', + timestamp: new Date().toISOString(), + version: '1.0.0' + }); +}); + +// User info endpoint for WebSocket registration +app.get('/api/user-info', requireAuth, (req, res) => { + res.json({ + userId: req.session.userId, + username: req.session.username, + isAdmin: req.session.isAdmin + }); +}); + +// Routes +app.get('/', (req, res) => { + if (req.session.userId) { + if (req.session.isAdmin) { + res.redirect('/admin'); + } else { + res.redirect('/dashboard'); + } + } else { + res.redirect('/login'); + } +}); + +app.get('/login', (req, res) => { + res.render('login', { error: null }); +}); + +app.post('/login', (req, res) => { + const { username, password } = req.body; + + db.get('SELECT * FROM users WHERE username = ?', [username], (err, user) => { + if (err || !user || !bcrypt.compareSync(password, user.password)) { + return res.render('login', { error: 'Invalid username or password' }); + } + + req.session.userId = user.id; + req.session.username = user.username; + req.session.isAdmin = user.is_admin === 1; + + if (user.is_admin) { + res.redirect('/admin'); + } else { + res.redirect('/dashboard'); + } + }); +}); + +app.get('/logout', (req, res) => { + req.session.destroy(); + res.redirect('/login'); +}); + +// Admin routes +app.get('/admin', requireAuth, requireAdmin, (req, res) => { + db.all(`SELECT u.*, COUNT(d.id) as devbench_count + FROM users u + LEFT JOIN devbenches d ON u.id = d.user_id + WHERE u.is_admin = 0 + GROUP BY u.id`, (err, users) => { + if (err) { + console.error(err); + return res.status(500).send('Database error'); + } + + db.all(`SELECT d.*, u.username + FROM devbenches d + JOIN users u ON d.user_id = u.id + ORDER BY d.created_at DESC`, (err, devbenches) => { + if (err) { + console.error(err); + return res.status(500).send('Database error'); + } + + res.render('admin', { users, devbenches }); + }); + }); +}); + +app.post('/admin/add-user', requireAuth, requireAdmin, (req, res) => { + const { username, email, password } = req.body; + + // Validate username (no spaces, numbers, or special characters) + if (!config.validation.username.test(username)) { + return res.status(400).json({ error: 'Username must contain only letters' }); + } + + const hashedPassword = bcrypt.hashSync(password, 10); + + db.run('INSERT INTO users (username, email, password) VALUES (?, ?, ?)', + [username, email, hashedPassword], function(err) { + if (err) { + if (err.code === 'SQLITE_CONSTRAINT') { + return res.status(400).json({ error: 'Username already exists' }); + } + return res.status(500).json({ error: 'Database error' }); + } + res.json({ success: true }); + }); +}); + +app.post('/admin/delete-user/:id', requireAuth, requireAdmin, (req, res) => { + const userId = req.params.id; + + // Delete user's devbenches first + db.run('DELETE FROM devbenches WHERE user_id = ?', [userId], (err) => { + if (err) { + return res.status(500).json({ error: 'Database error' }); + } + + // Delete user + db.run('DELETE FROM users WHERE id = ? AND is_admin = 0', [userId], (err) => { + if (err) { + return res.status(500).json({ error: 'Database error' }); + } + res.json({ success: true }); + }); + }); +}); + +app.post('/admin/reset-password/:id', requireAuth, requireAdmin, (req, res) => { + const userId = req.params.id; + const { newPassword } = req.body; + + const hashedPassword = bcrypt.hashSync(newPassword, 10); + + db.run('UPDATE users SET password = ? WHERE id = ? AND is_admin = 0', + [hashedPassword, userId], (err) => { + if (err) { + return res.status(500).json({ error: 'Database error' }); + } + res.json({ success: true }); + }); +}); + +// Help page +app.get('/help', requireAuth, (req, res) => { + res.render('help', { + username: req.session.username + }); +}); + +// User dashboard +app.get('/dashboard', requireAuth, (req, res) => { + if (req.session.isAdmin) { + return res.redirect('/admin'); + } + + db.all('SELECT * FROM devbenches WHERE user_id = ? ORDER BY created_at DESC', + [req.session.userId], (err, devbenches) => { + if (err) { + console.error(err); + return res.status(500).send('Database error'); + } + + res.render('dashboard', { + username: req.session.username, + devbenches + }); + }); +}); + +// DevBench operations +app.post('/create-devbench', requireAuth, (req, res) => { + const { name } = req.body; + + // Validate devbench name (only letters, numbers, hyphens, underscores) + if (!config.validation.devbenchName.test(name)) { + return res.status(400).json({ + error: 'DevBench name can only contain letters, numbers, hyphens, and underscores' + }); + } + + const fullName = `${req.session.username}_${name}`; + + // Check if devbench already exists + db.get('SELECT * FROM devbenches WHERE user_id = ? AND name = ?', + [req.session.userId, name], (err, existing) => { + if (err) { + return res.status(500).json({ error: 'Database error' }); + } + + if (existing) { + return res.status(400).json({ error: 'DevBench with this name already exists' }); + } + + // Insert into database first + db.run('INSERT INTO devbenches (user_id, name, status) VALUES (?, ?, ?)', + [req.session.userId, name, 'creating'], function(err) { + if (err) { + console.error('Database error:', err); + return res.status(500).json({ error: 'Database error' }); + } + + const devbenchId = this.lastID; + console.log(`Created devbench record with ID: ${devbenchId}, full name: ${fullName}`); + + // Start the provision script + setTimeout(() => { + executeProvisionScript('create', fullName, req.session.userId, devbenchId); + }, 1000); // Small delay to ensure WebSocket is ready + + res.json({ success: true, devbenchId }); + }); + }); +}); + +app.post('/delete-devbench/:id', requireAuth, (req, res) => { + const devbenchId = req.params.id; + + db.get('SELECT * FROM devbenches WHERE id = ? AND user_id = ?', + [devbenchId, req.session.userId], (err, devbench) => { + if (err || !devbench) { + return res.status(404).json({ error: 'DevBench not found' }); + } + + if (devbench.actual_name) { + executeProvisionScript('delete', devbench.actual_name, req.session.userId, devbenchId); + } + + db.run('DELETE FROM devbenches WHERE id = ?', [devbenchId], (err) => { + if (err) { + return res.status(500).json({ error: 'Database error' }); + } + res.json({ success: true }); + }); + }); +}); + +app.post('/activate-devbench/:id', requireAuth, (req, res) => { + const devbenchId = req.params.id; + + db.get('SELECT * FROM devbenches WHERE id = ? AND user_id = ?', + [devbenchId, req.session.userId], (err, devbench) => { + if (err || !devbench) { + return res.status(404).json({ error: 'DevBench not found' }); + } + + if (devbench.actual_name) { + executeProvisionScript('activate', devbench.actual_name, req.session.userId, devbenchId); + } + + res.json({ success: true }); + }); +}); + +// Function to execute provision script +function executeProvisionScript(command, vmName, userId, devbenchId) { + console.log(`Executing provision script: ${command} ${vmName} for user ${userId}`); + + const scriptPath = config.provision.scriptPath; + let output = ''; + + // Check if script exists + const fs = require('fs'); + if (!fs.existsSync(scriptPath)) { + console.error(`Script not found: ${scriptPath}`); + broadcastToUser(userId, { + type: 'script_output', + devbenchId, + data: `Error: Script not found at ${scriptPath}\n` + }); + + // Update database to reflect error + db.run('UPDATE devbenches SET status = ? WHERE id = ?', ['error', devbenchId]); + return; + } + + // Send initial message + broadcastToUser(userId, { + type: 'script_output', + devbenchId, + data: `Starting ${command} operation for ${vmName}...\n` + }); + + const child = spawn('bash', [scriptPath, command, vmName], { + cwd: process.cwd(), + env: process.env + }); + + child.stdout.on('data', (data) => { + const chunk = data.toString(); + output += chunk; + console.log(`Script output: ${chunk.trim()}`); + + // Broadcast real-time output to user + broadcastToUser(userId, { + type: 'script_output', + devbenchId, + data: chunk + }); + }); + + child.stderr.on('data', (data) => { + const chunk = data.toString(); + output += chunk; + console.log(`Script error: ${chunk.trim()}`); + + broadcastToUser(userId, { + type: 'script_output', + devbenchId, + data: `ERROR: ${chunk}` + }); + }); + + child.on('error', (error) => { + console.error(`Script execution error:`, error); + broadcastToUser(userId, { + type: 'script_output', + devbenchId, + data: `Execution Error: ${error.message}\n` + }); + + db.run('UPDATE devbenches SET status = ? WHERE id = ?', ['error', devbenchId]); + }); + + child.on('close', (code) => { + console.log(`Script finished with exit code: ${code}`); + + if (command === 'create') { + if (code === 0) { + // Parse the output to extract VM name, SSH port, and VNC port + const vmNameMatch = output.match(/VM_NAME=(.+)/); + const sshPortMatch = output.match(/SSH_PORT=(\d+)/); + const vncPortMatch = output.match(/VNC_PORT=(\d+)/); + + if (vmNameMatch && sshPortMatch && vncPortMatch) { + const actualName = vmNameMatch[1].trim(); + const sshPort = sshPortMatch[1]; + const vncPort = vncPortMatch[1]; + + // Generate SSH and VNC info + const sshInfo = sshPort; + const vncInfo = vncPort; + + console.log(`Updating database: ${actualName}, SSH Port: ${sshPort}, VNC Port: ${vncPort}`); + + db.run(`UPDATE devbenches SET + actual_name = ?, status = 'active', + ssh_info = ?, vnc_info = ?, updated_at = CURRENT_TIMESTAMP + WHERE id = ?`, + [actualName, sshInfo, vncInfo, devbenchId], (err) => { + if (err) { + console.error('Database update error:', err); + } else { + console.log('Database updated successfully'); + } + }); + } else { + console.log('Could not parse VM info from output'); + db.run('UPDATE devbenches SET status = ? WHERE id = ?', ['error', devbenchId]); + } + } else { + console.log('Script failed, updating status to error'); + db.run('UPDATE devbenches SET status = ? WHERE id = ?', ['error', devbenchId]); + } + } + + broadcastToUser(userId, { + type: 'script_complete', + devbenchId, + exitCode: code + }); + }); +} + +// Status check endpoint +app.get('/check-status/:id', requireAuth, (req, res) => { + const devbenchId = req.params.id; + + db.get('SELECT * FROM devbenches WHERE id = ? AND user_id = ?', + [devbenchId, req.session.userId], (err, devbench) => { + if (err || !devbench || !devbench.actual_name) { + return res.json({ status: 'unknown' }); + } + + const child = spawn('bash', [config.provision.scriptPath, 'status', devbench.actual_name]); + let output = ''; + + child.stdout.on('data', (data) => { + output += data.toString(); + }); + + child.stderr.on('data', (data) => { + output += data.toString(); + }); + + child.on('close', (code) => { + // Parse status from output - look for "active" or "inactive" in the output + let status = 'inactive'; + if (output.includes('active')) { + status = 'active'; + } + + console.log(`Status check for ${devbench.actual_name}: ${status} (exit code: ${code})`); + + db.run('UPDATE devbenches SET status = ?, updated_at = CURRENT_TIMESTAMP WHERE id = ?', + [status, devbenchId]); + + res.json({ status }); + }); + }); +}); + +// Periodic status check (every minute) +setInterval(() => { + db.all('SELECT * FROM devbenches WHERE actual_name IS NOT NULL', (err, devbenches) => { + if (err) return; + + devbenches.forEach(devbench => { + const child = spawn('bash', [config.provision.scriptPath, 'status', devbench.actual_name]); + let output = ''; + + child.stdout.on('data', (data) => { + output += data.toString(); + }); + + child.stderr.on('data', (data) => { + output += data.toString(); + }); + + child.on('close', (code) => { + // Parse status from output - look for "active" in the output + let status = 'inactive'; + if (output.includes('active')) { + status = 'active'; + } + + if (status !== devbench.status) { + console.log(`Status changed for ${devbench.actual_name}: ${devbench.status} -> ${status}`); + + db.run('UPDATE devbenches SET status = ?, updated_at = CURRENT_TIMESTAMP WHERE id = ?', + [status, devbench.id]); + + // Notify user of status change + broadcastToUser(devbench.user_id, { + type: 'status_update', + devbenchId: devbench.id, + status + }); + } + }); + }); + }); +}, config.provision.statusCheckInterval); + +const PORT = config.port; +server.listen(PORT, () => { + console.log(`DevBench Manager running on port ${PORT}`); + console.log(`Database path: ${config.database.path}`); + console.log(`Provision script path: ${config.provision.scriptPath}`); + + // Check if provision script exists + const fs = require('fs'); + if (fs.existsSync(config.provision.scriptPath)) { + console.log('โœ“ Provision script found'); + } else { + console.log('โœ— Provision script NOT found'); + } +}); \ No newline at end of file diff --git a/asf-cloud-server/TBM_devbench/start.sh b/asf-cloud-server/TBM_devbench/start.sh new file mode 100644 index 0000000..f417891 --- /dev/null +++ b/asf-cloud-server/TBM_devbench/start.sh @@ -0,0 +1,31 @@ +#!/bin/bash + +echo "Starting DevBench Manager..." + +# Check if Docker is available +if command -v docker &> /dev/null && command -v docker-compose &> /dev/null; then + echo "Using Docker Compose..." + docker-compose up -d + echo "DevBench Manager started with Docker!" + echo "Access it at: http://localhost:3001" + echo "Default admin login: admin / admin123" +else + echo "Docker not found, starting with Node.js..." + + # Check if Node.js is available + if ! command -v node &> /dev/null; then + echo "Error: Node.js is not installed!" + echo "Please install Node.js 18+ or Docker to run this application." + exit 1 + fi + + # Install dependencies if node_modules doesn't exist + if [ ! -d "node_modules" ]; then + echo "Installing dependencies..." + npm install + fi + + # Start the application + echo "Starting application..." + npm start +fi \ No newline at end of file diff --git a/asf-cloud-server/TBM_devbench/views/admin.ejs b/asf-cloud-server/TBM_devbench/views/admin.ejs new file mode 100644 index 0000000..392f19b --- /dev/null +++ b/asf-cloud-server/TBM_devbench/views/admin.ejs @@ -0,0 +1,212 @@ +<%- include('layout', { body: ` +
+

Admin Dashboard

+ +
+ + +
+
+
Users Management
+
+
+
+ + + + + + + + + + + + ${users.map(user => ` + + + + + + + + `).join('')} + +
UsernameEmailDevBenchesCreatedActions
${user.username}${user.email}${user.devbench_count}${new Date(user.created_at).toLocaleDateString()} + + +
+
+
+
+ + +
+
+
All DevBenches
+ Default SSH/VNC Password: ASF +
+
+
+ + + + + + + + + + + + + + + ${devbenches.map(db => ` + + + + + + + + + + + `).join('')} + +
UserDevBench NameActual NameStatusSSH PortVNC PortCreatedActions
${db.username}${db.name}${db.actual_name || 'N/A'} + + ${db.status} + + ${db.ssh_info || 'N/A'}${db.vnc_info || 'N/A'}${new Date(db.created_at).toLocaleDateString()} + +
+
+
+
+ + + + + +`, username: typeof username !== 'undefined' ? username : 'admin' }) %> \ No newline at end of file diff --git a/asf-cloud-server/TBM_devbench/views/dashboard.ejs b/asf-cloud-server/TBM_devbench/views/dashboard.ejs new file mode 100644 index 0000000..86199bc --- /dev/null +++ b/asf-cloud-server/TBM_devbench/views/dashboard.ejs @@ -0,0 +1,208 @@ +<%- include('layout', { body: ` +
+

My DevBenches

+ +
+ +
+ ${devbenches.map(db => ` +
+
+
+
${db.name}
+ + ${db.status} + +
+
+ ${db.actual_name ? ` +

VM Name: ${db.actual_name}

+ + ${db.ssh_info || db.vnc_info ? ` +
+
Connection Info:
+ ${db.ssh_info ? ` +
+ SSH Port:
+ ${db.ssh_info} + +
+ ` : ''} + ${db.vnc_info ? ` +
+ VNC Port:
+ ${db.vnc_info} + +
+ ` : ''} +
+ Need help connecting? + View setup guide +
+
+ ` : ''} + ` : ` +

DevBench is being created...

+
+ `} + +

+ Created: ${new Date(db.created_at).toLocaleString()} +

+
+ +
+
+ `).join('')} + + ${devbenches.length === 0 ? ` +
+
+ +

No DevBenches Yet

+

Create your first DevBench to get started!

+
+
+ ` : ''} +
+ + + + + +`, username }) %> \ No newline at end of file diff --git a/asf-cloud-server/TBM_devbench/views/help.ejs b/asf-cloud-server/TBM_devbench/views/help.ejs new file mode 100644 index 0000000..6084e78 --- /dev/null +++ b/asf-cloud-server/TBM_devbench/views/help.ejs @@ -0,0 +1,125 @@ +<%- include('layout', { body: ` +
+

Help - How to Use DevBench Manager

+ + Back to Dashboard + +
+ +
+
+
SSH Configuration Tool
+
+
+

Follow these steps to configure SSH access to your VM:

+ +
    +
  1. + Download the VM SSH Config Tool +

    Download the configuration tool from here:

    + + Download SSH Config Manager + +
  2. + +
  3. + Open the Tool +

    Run the db_vm_ssh_config_manager.exe application.

    +
  4. + +
  5. + Add Friendly Name +

    In the "Host" field, enter a friendly name for your VM (e.g., vm-test1).

    +
  6. + +
  7. + Add SSH Port +

    Enter the SSH port number shown in your DevBench connection info (e.g., 6004).

    +
  8. + +
  9. + Add Username +

    Enter the username: asf_user

    +
  10. + +
  11. + Keep Jump Proxy +

    Keep the jump proxy as: asf-jump

    +
  12. + +
  13. + Press Add VM +

    Click the "Add VM" button to save the configuration.

    +
  14. + +
  15. + Select VM Host and Show Command +

    In the "Select VM Host" dropdown, choose your VM name and click "Show Commands".

    +
  16. + +
  17. + Access Your VM +

    You will now see the SSH command to access your VM. Copy and use it in your terminal.

    +
  18. +
+
+
+ +
+
+
Connection Information
+
+
+
SSH Connection:
+

After configuring the SSH tool, you can connect using:

+
ssh [your-vm-name]
+ +
VNC Connection:
+

For graphical access, use your VNC client with the port shown in your DevBench info.

+

Default Password: ASF

+
+
+ +
+
+
Important Notes
+
+
+
    +
  • The default password for both SSH and VNC is: ASF
  • +
  • Make sure to keep your SSH config tool updated with the correct ports
  • +
  • Each DevBench has unique SSH and VNC ports
  • +
  • Contact your administrator if you encounter any issues
  • +
+
+
+ + +`, username }) %> diff --git a/asf-cloud-server/TBM_devbench/views/layout.ejs b/asf-cloud-server/TBM_devbench/views/layout.ejs new file mode 100644 index 0000000..76d1c31 --- /dev/null +++ b/asf-cloud-server/TBM_devbench/views/layout.ejs @@ -0,0 +1,134 @@ + + + + + + DevBench Manager + + + + + + + + +
+ <%- body %> +
+ + + + + + + + + \ No newline at end of file diff --git a/asf-cloud-server/TBM_devbench/views/login.ejs b/asf-cloud-server/TBM_devbench/views/login.ejs new file mode 100644 index 0000000..6c1bb7b --- /dev/null +++ b/asf-cloud-server/TBM_devbench/views/login.ejs @@ -0,0 +1,31 @@ +<%- include('layout', { body: ` +
+
+ +
+
+` }) %> \ No newline at end of file diff --git a/asf-dev-tools/ssh_config_manager.py b/asf-dev-tools/ssh_config_manager.py new file mode 100644 index 0000000..1ee6f7c --- /dev/null +++ b/asf-dev-tools/ssh_config_manager.py @@ -0,0 +1,220 @@ +import sys +import os +import re # We need the regex module for easier parsing + +from PyQt6.QtWidgets import ( + QApplication, QWidget, QVBoxLayout, QHBoxLayout, + QLineEdit, QLabel, QPushButton, QTextEdit, QMessageBox +) +from PyQt6.QtCore import Qt + +class SSHConfigManager(QWidget): + # --- Configuration for the Jump Host --- + JUMP_HOST_NAME = "asf-jump" + JUMP_HOST_DETAILS = f""" +Host {JUMP_HOST_NAME} + Hostname asf-server.duckdns.org + Port 49152 + User asf +""" + + def __init__(self): + super().__init__() + self.setWindowTitle("SSH Config Manager (PyQt6)") + self.setMinimumWidth(500) + self.config_path = os.path.expanduser("~/.ssh/config") + self.init_ui() + + # Ensure directory and file exist + os.makedirs(os.path.dirname(self.config_path), exist_ok=True) + if not os.path.exists(self.config_path): + with open(self.config_path, 'w') as f: + f.write("") + + self.ensure_jump_host_defined() # Check and add jump host immediately + self.load_config() + + def init_ui(self): + main_layout = QVBoxLayout() + + # --- 1. Input Fields for New VM --- + input_group = QVBoxLayout() + input_group.addWidget(QLabel("## ๐Ÿ› ๏ธ Add New VM Entry")) + + self.host_input = QLineEdit() + self.host_input.setPlaceholderText("Host (e.g., vm-test1)") + + self.port_input = QLineEdit() + self.port_input.setPlaceholderText("Port (e.g., 6002)") + + self.user_input = QLineEdit() + self.user_input.setPlaceholderText("User (e.g., asf_user)") + + self.proxy_input = QLineEdit() + self.proxy_input.setPlaceholderText(f"ProxyJump (Default: {self.JUMP_HOST_NAME})") + self.proxy_input.setText(self.JUMP_HOST_NAME) # Pre-fill the jump host name + + input_group.addWidget(self.host_input) + input_group.addWidget(self.port_input) + input_group.addWidget(self.user_input) + input_group.addWidget(self.proxy_input) + + add_button = QPushButton("โž• Add VM & Save Config") + add_button.clicked.connect(self.add_vm_entry) + input_group.addWidget(add_button) + + main_layout.addLayout(input_group) + main_layout.addWidget(QLabel("---")) + + # --- 2. Existing Config Viewer --- + main_layout.addWidget(QLabel("## ๐Ÿ“œ Current ~/.ssh/config Content")) + self.config_viewer = QTextEdit() + self.config_viewer.setReadOnly(True) + self.config_viewer.setMinimumHeight(150) + main_layout.addWidget(self.config_viewer) + + # --- 3. Connection Instructions & Display --- + main_layout.addWidget(QLabel("## ๐Ÿ”— Connection Info")) + + info_layout = QHBoxLayout() + info_layout.addWidget(QLabel("Select VM Host:")) + self.vm_select = QLineEdit() + self.vm_select.setPlaceholderText("Enter Host name (e.g., vm-test1)") + info_layout.addWidget(self.vm_select) + + show_button = QPushButton("Show Commands") + show_button.clicked.connect(self.show_connection_commands) + info_layout.addWidget(show_button) + + main_layout.addLayout(info_layout) + + self.command_output = QTextEdit() + self.command_output.setReadOnly(True) + self.command_output.setMinimumHeight(100) + main_layout.addWidget(self.command_output) + + self.setLayout(main_layout) + + def load_config(self): + """Loads the current config file content into the viewer.""" + try: + with open(self.config_path, 'r') as f: + content = f.read() + self.config_viewer.setText(content) + except Exception as e: + self.config_viewer.setText(f"Error loading config: {e}") + + def ensure_jump_host_defined(self): + """Checks if the JUMP_HOST_NAME is defined and adds it if missing.""" + try: + with open(self.config_path, 'r+') as f: + content = f.read() + + # Use regex to find if the Host definition already exists + if re.search(rf"^Host\s+{re.escape(self.JUMP_HOST_NAME)}\s*$", content, re.MULTILINE | re.IGNORECASE): + # print("Jump host already defined.") # For debugging + return + + # If not found, append the definition to the beginning of the file + f.seek(0) + f.write(self.JUMP_HOST_DETAILS + "\n" + content) + f.truncate() + + QMessageBox.information(self, "Setup Complete", + f"Automatically added the '{self.JUMP_HOST_NAME}' jump host definition to the config file.") + + except Exception as e: + QMessageBox.critical(self, "Setup Error", f"Failed to ensure jump host definition: {e}") + + def add_vm_entry(self): + """Validates inputs, formats the entry, and appends it to the config file.""" + host = self.host_input.text().strip() + port = self.port_input.text().strip() + user = self.user_input.text().strip() + proxy = self.proxy_input.text().strip() + + if not all([host, port, user, proxy]): + QMessageBox.warning(self, "Input Error", "All fields must be filled out.") + return + + # Ensure jump host is defined before adding dependent VMs + self.ensure_jump_host_defined() + + new_entry = f""" + +Host {host} + Hostname 127.0.0.1 + Port {port} + User {user} + ProxyJump {proxy} +""" + + try: + with open(self.config_path, 'a') as f: + f.write(new_entry) + + QMessageBox.information(self, "Success", f"VM '{host}' successfully added to {self.config_path}!") + self.load_config() # Refresh the viewer + + # Clear inputs + self.host_input.clear() + self.port_input.clear() + self.user_input.clear() + self.proxy_input.setText(self.JUMP_HOST_NAME) # Reset ProxyJump field + + except Exception as e: + QMessageBox.critical(self, "Error", f"Failed to save file: {e}") + + def show_connection_commands(self): + """Generates and displays the connection commands for the selected VM.""" + host = self.vm_select.text().strip() + + if not host: + self.command_output.setText("Please enter a Host name to look up.") + return + + ssh_port = None + try: + with open(self.config_path, 'r') as f: + content = f.read().splitlines() + + # Simple line-by-line parser to find the port + current_host = None + for line in content: + line = line.strip() + if line.startswith('Host '): + current_host = line.split()[1] + elif current_host == host and line.startswith('Port '): + ssh_port = line.split()[1] + break + except Exception: + self.command_output.setText(f"Error reading config file to find port for {host}.") + return + + if not ssh_port: + self.command_output.setText(f"Host '{host}' not found or Port not specified in config.") + return + + # VNC Port (Assuming VNC Port = SSH Port - 1000, based on your ranges 6002/5002) + vnc_port = int(ssh_port) - 1000 + + # 2. Generate Commands + commands = f""" +โœ… **SSH Command** (for direct console access via Jump Host): +ssh {host} + +๐Ÿ–ฅ๏ธ **VNC Command** (for secure graphical access via SSH Tunnel): +1. Establish the tunnel (keep this window open/running): + ssh -L 5900:127.0.0.1:{vnc_port} {host} -N & + +2. Connect VNC Client to your local machine: + VNC Host/Port: 127.0.0.1:5900 +""" + self.command_output.setText(commands) + + +if __name__ == '__main__': + app = QApplication(sys.argv) + manager = SSHConfigManager() + manager.show() + sys.exit(app.exec()) \ No newline at end of file diff --git a/asf-pc-server/provision_vm.sh b/asf-pc-server/provision_vm.sh new file mode 100644 index 0000000..7193848 --- /dev/null +++ b/asf-pc-server/provision_vm.sh @@ -0,0 +1,271 @@ +#!/bin/bash + +# ====================================================== +# ๐Ÿš€ Automated VirtualBox VM Management Script (Updated) +# ====================================================== + +# --- Configuration --- +BASE_VM_NAME="DB_Image" # Name of the template/base VM to clone from +VM_USER="asf_user" # User inside the VM (for IP detection and final output) +VM_PASSWORD="ASF" # Password for the VM user (for IP detection) + +# Ports Configuration +BASE_SSH_PORT=6002 # Starting SSH NAT port +BASE_VNC_PORT=5002 # Starting VNC (VRDE) port +PORT_DB_FILE="$HOME/.vms_ports_db.json" # JSON file for port persistence + +# VM Resources (50 GB is 51200 MB) +VM_MEMORY=51200 +VM_VRAM=128 +VM_CPUS=2 + +# --- Utility Functions (All functions remain the same) --- + +usage() { + echo "Usage:" + echo " $0 create " + echo " $0 status " + echo " $0 activate " + echo " $0 delete " + exit 1 +} + +# Function to remove VM port entry from JSON +remove_port_entry() { + local vm_name="$1" + init_port_db # Ensure DB exists + + if [[ -f "$PORT_DB_FILE" ]]; then + if grep -q "\"$vm_name\"" "$PORT_DB_FILE"; then + # Use grep and sed to remove the entry, handling list structure complexities + grep -v "\"$VM_NAME\"" "$PORT_DB_FILE" | sed 's/}, /}/' | sed 's/, }/}/' > "${PORT_DB_FILE}.tmp" + + if grep -q "^{.*}$" "${PORT_DB_FILE}.tmp"; then + mv "${PORT_DB_FILE}.tmp" "$PORT_DB_FILE" + else + echo "{}" > "$PORT_DB_FILE" + fi + # NOTE: Removed the success echo to keep the main flow cleaner + fi + fi +} + +# Function to safely create/initialize the JSON port database +init_port_db() { + if [[ ! -f "$PORT_DB_FILE" ]]; then + echo "{}" > "$PORT_DB_FILE" + fi +} + +# Function to get VM status +get_vm_status() { + local vm_name="$1" + local status + status=$(VBoxManage showvminfo "$vm_name" --machinereadable 2>/dev/null | grep -i "^VMState=" | cut -d'"' -f2) + + if [[ "$status" == "running" ]]; then + echo "active" + else + echo "not active" + fi +} + +# Function to start VM if not running +activate_vm() { + local vm_name="$1" + local status + status=$(get_vm_status "$vm_name") + if [[ "$status" == "active" ]]; then + echo "โœ… VM '$vm_name' is already active." + return 0 + fi + + echo "๐Ÿš€ Starting VM '$vm_name'..." + VBoxManage startvm "$vm_name" --type headless + if [[ $? -eq 0 ]]; then + echo "โœ… VM '$vm_name' started successfully." + else + echo "โŒ Failed to start VM '$vm_name'." + return 1 + fi +} + +# Function to read ports from JSON +get_vm_ports() { + local vm_name="$1" + local ports + + # Check if the VM entry exists in the JSON file + ports=$(cat "$PORT_DB_FILE" | grep "\"$vm_name\"" | awk -F': ' '{print $2}' | tr -d '",}{') + + if [[ -z "$ports" ]]; then + echo "" # Return empty if not found + else + # Assuming the format in the JSON is {"vm_name": "SSH_PORT VNC_PORT"} + echo "$ports" + fi +} + +# Function to assign unique ports for SSH/VNC per VM using JSON +assign_ports() { + local vm_name="$1" + init_port_db + + # 1. Check if ports already assigned in JSON + local assigned_ports + assigned_ports=$(get_vm_ports "$vm_name") + + if [[ -n "$assigned_ports" ]]; then + echo "$assigned_ports" + return 0 + fi + + # 2. Collect ALL currently used ports from the JSON file + local used_ports + used_ports=$(grep -oE "[0-9]+" "$PORT_DB_FILE" 2>/dev/null) + + local ssh_port=$BASE_SSH_PORT + local vnc_port=$BASE_VNC_PORT + + # Find unique SSH port + while grep -qw "$ssh_port" <<<"$used_ports" || netstat -tln 2>/dev/null | grep -q ":$ssh_port"; do + ssh_port=$((ssh_port + 1)) + done + + # Find unique VNC port + while grep -qw "$vnc_port" <<<"$used_ports" || netstat -tln 2>/dev/null | grep -q ":$vnc_port"; do + vnc_port=$((vnc_port + 1)) + done + + # 3. Save new ports to JSON using a simple tool for JSON manipulation + local new_entry="\"$vm_name\": \"$ssh_port $vnc_port\"" + + local current_content + current_content=$(cat "$PORT_DB_FILE") + + if [[ "$current_content" == "{}" ]]; then + echo "{$new_entry}" > "$PORT_DB_FILE" + else + sed '$s/}$/, '"$new_entry"'}' "$PORT_DB_FILE" > "${PORT_DB_FILE}.tmp" && mv "${PORT_DB_FILE}.tmp" "$PORT_DB_FILE" + fi + + echo "$ssh_port $vnc_port" +} + +# --- Main Logic --- + +if [[ $# -lt 2 && "$1" != "create" ]]; then + usage +fi + +COMMAND="$1" +ARG="$2" + +case "$COMMAND" in + status) + get_vm_status "$ARG" + ;; + + activate) + activate_vm "$ARG" + ;; + + create) + NEW_VM_NAME="$ARG" + init_port_db # Ensure DB exists + + if VBoxManage showvminfo "$NEW_VM_NAME" &>/dev/null; then + echo "VM '$NEW_VM_NAME' already exists. Please delete it or choose another name." + exit 1 + fi + + # Assign ports and store them in the JSON + read -r SSH_PORT VNC_PORT < <(assign_ports "$NEW_VM_NAME") + + echo "Cloning VM '$BASE_VM_NAME' to '$NEW_VM_NAME' (SSH:$SSH_PORT, VNC:$VNC_PORT)..." + VBoxManage clonevm "$BASE_VM_NAME" --name "$NEW_VM_NAME" --register --mode all + + if [[ $? -ne 0 ]]; then + echo "โŒ Failed to clone VM. Aborting." + remove_port_entry "$NEW_VM_NAME" + exit 1 + fi + + # Configure VM resources + echo "Configuring VM resources (Memory: $VM_MEMORY MB, CPUs: $VM_CPUS)..." + VBoxManage modifyvm "$NEW_VM_NAME" --memory "$VM_MEMORY" --vram "$VM_VRAM" --cpus "$VM_CPUS" + VBoxManage modifyvm "$NEW_VM_NAME" --nic1 nat + VBoxManage modifyvm "$NEW_VM_NAME" --cableconnected1 on + + # --- PHASE 1: Initial Boot and Shutdown --- + + echo "Starting VM '$NEW_VM_NAME' for initial boot (1 minute)..." + VBoxManage startvm "$NEW_VM_NAME" --type headless + + # Wait for 1 minute (60 seconds) for first boot/OS initialization + sleep 60 + echo "Initial boot complete. Shutting down VM." + + VBoxManage controlvm "$NEW_VM_NAME" poweroff + + # --- PHASE 2: Setting Network Ports --- + echo "Setting up network port forwarding (SSH:$SSH_PORT, VNC:$VNC_PORT)..." + + # Remove old (potentially conflicting) rules and add the new one + VBoxManage modifyvm "$NEW_VM_NAME" --natpf1 delete ssh 2>/dev/null || true + + # Add the new NAT port forwarding rules + VBoxManage modifyvm "$NEW_VM_NAME" --natpf1 "ssh,tcp,,${SSH_PORT},,22" + VBoxManage modifyvm "$NEW_VM_NAME" --vrde on --vrdeport "$VNC_PORT" + + # --- PHASE 3: Final Start and Wait --- + echo "Starting VM '$NEW_VM_NAME' headless for final usage (Waiting 5 minutes)..." + VBoxManage startvm "$NEW_VM_NAME" --type headless + + # Wait for 5 minutes (300 seconds) for the system and services to fully initialize + sleep 300 + echo "Initialization complete. VM should be ready." + + # --- PHASE 4: Final Output --- + + echo "--- โœ… VM $NEW_VM_NAME Created and Ready ---" + echo "Host: 127.0.0.1 (use your external DDNS for remote access)" + echo "User: $VM_USER" + echo "SSH Port: $SSH_PORT" + echo "VNC Port: $VNC_PORT" + + ;; + + delete) + VM_NAME="$ARG" + init_port_db # Ensure DB exists + + echo "๐Ÿ›‘ Powering off VM '$VM_NAME'..." + VBoxManage controlvm "$VM_NAME" poweroff 2>/dev/null || true + + echo "๐Ÿ—‘๏ธ Unregistering and deleting VM '$VM_NAME'..." + VBoxManage unregistervm "$VM_NAME" --delete + + # Remove entry from port DB + if [[ -f "$PORT_DB_FILE" ]]; then + + if grep -q "\"$VM_NAME\"" "$PORT_DB_FILE"; then + # Remove the entire line containing the VM entry + grep -v "\"$VM_NAME\"" "$PORT_DB_FILE" | sed 's/}, /}/' | sed 's/, }/}/' > "${PORT_DB_FILE}.tmp" + + # Check if the file is now just "{}" and fix it + if grep -q "^{.*}$" "${PORT_DB_FILE}.tmp"; then + mv "${PORT_DB_FILE}.tmp" "$PORT_DB_FILE" + else + echo "{}" > "$PORT_DB_FILE" + fi + + echo "โœ… Removed '$VM_NAME' entry from $PORT_DB_FILE" + fi + fi + ;; + + *) + usage + ;; +esac \ No newline at end of file