mirror of
https://github.com/blackboxprogramming/BlackRoad-Operating-System.git
synced 2026-03-17 06:57:17 -05:00
This commit transforms the BlackRoad OS from a static mockup into a fully functional web-based operating system with real backend integration. ## Major Changes ### Backend (New Features) 1. **Device Management System** (IoT/Raspberry Pi) - New models: Device, DeviceMetric, DeviceLog - Router: /api/devices with full CRUD operations - Device heartbeat system for status monitoring - Metrics tracking (CPU, RAM, temperature) 2. **Mining Stats & Control** (RoadCoin Miner) - Router: /api/miner with status, stats, control endpoints - Simulated mining with hashrate, shares, temperature - Start/stop mining controls - Lifetime statistics and recent blocks listing 3. **Static File Serving** - Backend now serves front-end from /backend/static/ - index.html served at root URL - API routes under /api/* namespace 4. **Updated User Model** - Added devices relationship ### Frontend (New Features) 1. **API Client Module** (api-client.js) - Centralized API communication layer - Automatic base URL detection (dev vs prod) - JWT token management with auto-refresh - Error handling and 401 redirects 2. **Authentication System** (auth.js) - Login/Register modal UI - Session persistence via localStorage - Auto-logout on token expiration - Keyboard shortcuts (Enter to submit) 3. **Application Modules** (apps.js) - Dynamic data loading for all desktop windows - Auto-refresh for real-time data (miner, blockchain) - Event-driven architecture - Lazy loading (data fetched only when window opens) 4. **Enhanced UI** - Added 380+ lines of CSS for new components - Auth modal styling - Miner dashboard layout - Blockchain explorer tables - Wallet balance display - Device management cards 5. **Live Window Integration** - RoadCoin Miner: Real mining stats, start/stop controls - RoadChain Explorer: Live blockchain data, mine block button - Wallet: Real-time balance, transaction history - Raspberry Pi: Device status dashboard - RoadMail: Live inbox from API - Social Feed: Real posts from database - BlackStream: Video grid from API - AI Assistant: Conversation UI ### Configuration - Updated .env.example with: - ROADCHAIN_RPC_URL, ROADCOIN_POOL_URL - MQTT broker settings for device management - Production CORS origins (www.blackroad.systems) - PORT configuration for Railway deployment ### Documentation - Added INTEGRATION_GUIDE.md (400+ lines) - Complete architecture overview - API endpoint documentation - Environment configuration guide - Development workflow - Troubleshooting section ## Technical Details - All windows now connect to real backend APIs - Authentication required before OS access - User-specific data isolation - Proper error handling and loading states - Retro Windows 95 aesthetic preserved ## What's Working ✅ Full authentication flow (login/register) ✅ Mining stats and control ✅ Blockchain explorer with live data ✅ Wallet with real balance ✅ Device management dashboard ✅ Email inbox integration ✅ Social feed integration ✅ Video platform integration ✅ Static file serving ✅ CORS configuration ## Future Enhancements - Real XMRig integration - WebSocket for real-time updates - MQTT broker for device heartbeats - OpenAI/Anthropic API integration - File uploads to S3 - Email sending via SMTP ## Files Added - backend/app/models/device.py - backend/app/routers/devices.py - backend/app/routers/miner.py - backend/static/index.html - backend/static/js/api-client.js - backend/static/js/auth.js - backend/static/js/apps.js - INTEGRATION_GUIDE.md ## Files Modified - backend/app/main.py (added routers, static file serving) - backend/app/models/user.py (added devices relationship) - backend/.env.example (added device & mining variables) Tested locally with Docker Compose (PostgreSQL + Redis). Ready for Railway deployment.
304 lines
10 KiB
JavaScript
304 lines
10 KiB
JavaScript
/**
|
|
* BlackRoad OS Authentication Module
|
|
* Handles login, registration, and session management
|
|
*/
|
|
|
|
class AuthManager {
|
|
constructor() {
|
|
this.currentUser = null;
|
|
this.api = window.BlackRoadAPI;
|
|
this.initialized = false;
|
|
}
|
|
|
|
/**
|
|
* Initialize authentication
|
|
*/
|
|
async initialize() {
|
|
if (this.initialized) return;
|
|
|
|
// Listen for logout events
|
|
window.addEventListener('auth:logout', () => {
|
|
this.handleLogout();
|
|
});
|
|
|
|
// Check if user is already logged in
|
|
if (this.api.isAuthenticated()) {
|
|
try {
|
|
await this.loadCurrentUser();
|
|
this.hideAuthModal();
|
|
window.dispatchEvent(new CustomEvent('auth:login', { detail: this.currentUser }));
|
|
} catch (error) {
|
|
console.error('Failed to load current user:', error);
|
|
this.showAuthModal();
|
|
}
|
|
} else {
|
|
// Show login modal if not authenticated
|
|
this.showAuthModal();
|
|
}
|
|
|
|
this.initialized = true;
|
|
}
|
|
|
|
/**
|
|
* Load current user data
|
|
*/
|
|
async loadCurrentUser() {
|
|
this.currentUser = await this.api.getCurrentUser();
|
|
return this.currentUser;
|
|
}
|
|
|
|
/**
|
|
* Get current user
|
|
*/
|
|
getCurrentUser() {
|
|
return this.currentUser;
|
|
}
|
|
|
|
/**
|
|
* Show authentication modal
|
|
*/
|
|
showAuthModal() {
|
|
const modal = document.getElementById('auth-modal');
|
|
if (modal) {
|
|
modal.style.display = 'flex';
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Hide authentication modal
|
|
*/
|
|
hideAuthModal() {
|
|
const modal = document.getElementById('auth-modal');
|
|
if (modal) {
|
|
modal.style.display = 'none';
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Handle login
|
|
*/
|
|
async handleLogin(username, password) {
|
|
try {
|
|
const response = await this.api.login(username, password);
|
|
await this.loadCurrentUser();
|
|
this.hideAuthModal();
|
|
window.dispatchEvent(new CustomEvent('auth:login', { detail: this.currentUser }));
|
|
return { success: true };
|
|
} catch (error) {
|
|
return { success: false, error: error.message };
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Handle registration
|
|
*/
|
|
async handleRegister(username, email, password, fullName) {
|
|
try {
|
|
await this.api.register(username, email, password, fullName);
|
|
// Auto-login after registration
|
|
return await this.handleLogin(username, password);
|
|
} catch (error) {
|
|
return { success: false, error: error.message };
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Handle logout
|
|
*/
|
|
async handleLogout() {
|
|
try {
|
|
await this.api.logout();
|
|
} catch (error) {
|
|
console.error('Logout error:', error);
|
|
} finally {
|
|
this.currentUser = null;
|
|
this.showAuthModal();
|
|
// Optionally reload the page to reset state
|
|
window.location.reload();
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Create auth modal HTML
|
|
*/
|
|
createAuthModal() {
|
|
const modal = document.createElement('div');
|
|
modal.id = 'auth-modal';
|
|
modal.className = 'auth-modal';
|
|
modal.innerHTML = `
|
|
<div class="auth-modal-content">
|
|
<div class="auth-window">
|
|
<div class="title-bar">
|
|
<div class="title-text">
|
|
<span>🛣️</span>
|
|
<span>BlackRoad OS - Login</span>
|
|
</div>
|
|
</div>
|
|
<div class="auth-container">
|
|
<div class="auth-header">
|
|
<h1 style="font-size: 24px; margin-bottom: 10px;">Welcome to BlackRoad OS</h1>
|
|
<p style="color: #666; font-size: 11px;">Please login or register to continue</p>
|
|
</div>
|
|
|
|
<!-- Login Form -->
|
|
<div id="login-form" class="auth-form">
|
|
<h3 style="margin-bottom: 15px;">Login</h3>
|
|
<div class="form-group">
|
|
<label>Username:</label>
|
|
<input type="text" id="login-username" class="form-input" />
|
|
</div>
|
|
<div class="form-group">
|
|
<label>Password:</label>
|
|
<input type="password" id="login-password" class="form-input" />
|
|
</div>
|
|
<div class="form-error" id="login-error"></div>
|
|
<div class="form-actions">
|
|
<button class="btn btn-primary" onclick="window.BlackRoadAuth.submitLogin()">Login</button>
|
|
<button class="btn btn-secondary" onclick="window.BlackRoadAuth.switchToRegister()">Register</button>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Register Form -->
|
|
<div id="register-form" class="auth-form" style="display: none;">
|
|
<h3 style="margin-bottom: 15px;">Create Account</h3>
|
|
<div class="form-group">
|
|
<label>Username:</label>
|
|
<input type="text" id="register-username" class="form-input" />
|
|
</div>
|
|
<div class="form-group">
|
|
<label>Email:</label>
|
|
<input type="email" id="register-email" class="form-input" />
|
|
</div>
|
|
<div class="form-group">
|
|
<label>Full Name:</label>
|
|
<input type="text" id="register-fullname" class="form-input" />
|
|
</div>
|
|
<div class="form-group">
|
|
<label>Password:</label>
|
|
<input type="password" id="register-password" class="form-input" />
|
|
</div>
|
|
<div class="form-group">
|
|
<label>Confirm Password:</label>
|
|
<input type="password" id="register-password2" class="form-input" />
|
|
</div>
|
|
<div class="form-error" id="register-error"></div>
|
|
<div class="form-actions">
|
|
<button class="btn btn-primary" onclick="window.BlackRoadAuth.submitRegister()">Create Account</button>
|
|
<button class="btn btn-secondary" onclick="window.BlackRoadAuth.switchToLogin()">Back to Login</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
`;
|
|
document.body.appendChild(modal);
|
|
}
|
|
|
|
/**
|
|
* Switch to register form
|
|
*/
|
|
switchToRegister() {
|
|
document.getElementById('login-form').style.display = 'none';
|
|
document.getElementById('register-form').style.display = 'block';
|
|
document.querySelector('.auth-window .title-text span:last-child').textContent = 'BlackRoad OS - Register';
|
|
}
|
|
|
|
/**
|
|
* Switch to login form
|
|
*/
|
|
switchToLogin() {
|
|
document.getElementById('register-form').style.display = 'none';
|
|
document.getElementById('login-form').style.display = 'block';
|
|
document.querySelector('.auth-window .title-text span:last-child').textContent = 'BlackRoad OS - Login';
|
|
}
|
|
|
|
/**
|
|
* Submit login form
|
|
*/
|
|
async submitLogin() {
|
|
const username = document.getElementById('login-username').value.trim();
|
|
const password = document.getElementById('login-password').value;
|
|
const errorEl = document.getElementById('login-error');
|
|
|
|
if (!username || !password) {
|
|
errorEl.textContent = 'Please enter username and password';
|
|
return;
|
|
}
|
|
|
|
errorEl.textContent = 'Logging in...';
|
|
const result = await this.handleLogin(username, password);
|
|
|
|
if (!result.success) {
|
|
errorEl.textContent = result.error;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Submit register form
|
|
*/
|
|
async submitRegister() {
|
|
const username = document.getElementById('register-username').value.trim();
|
|
const email = document.getElementById('register-email').value.trim();
|
|
const fullName = document.getElementById('register-fullname').value.trim();
|
|
const password = document.getElementById('register-password').value;
|
|
const password2 = document.getElementById('register-password2').value;
|
|
const errorEl = document.getElementById('register-error');
|
|
|
|
if (!username || !email || !password) {
|
|
errorEl.textContent = 'Please fill in all required fields';
|
|
return;
|
|
}
|
|
|
|
if (password !== password2) {
|
|
errorEl.textContent = 'Passwords do not match';
|
|
return;
|
|
}
|
|
|
|
if (password.length < 6) {
|
|
errorEl.textContent = 'Password must be at least 6 characters';
|
|
return;
|
|
}
|
|
|
|
errorEl.textContent = 'Creating account...';
|
|
const result = await this.handleRegister(username, email, password, fullName);
|
|
|
|
if (!result.success) {
|
|
errorEl.textContent = result.error;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Add Enter key support for forms
|
|
*/
|
|
setupKeyboardShortcuts() {
|
|
document.getElementById('login-password').addEventListener('keypress', (e) => {
|
|
if (e.key === 'Enter') {
|
|
this.submitLogin();
|
|
}
|
|
});
|
|
|
|
document.getElementById('register-password2').addEventListener('keypress', (e) => {
|
|
if (e.key === 'Enter') {
|
|
this.submitRegister();
|
|
}
|
|
});
|
|
}
|
|
}
|
|
|
|
// Create singleton instance
|
|
const authManager = new AuthManager();
|
|
window.BlackRoadAuth = authManager;
|
|
|
|
// Auto-initialize when DOM is ready
|
|
if (document.readyState === 'loading') {
|
|
document.addEventListener('DOMContentLoaded', () => {
|
|
authManager.createAuthModal();
|
|
authManager.setupKeyboardShortcuts();
|
|
authManager.initialize();
|
|
});
|
|
} else {
|
|
authManager.createAuthModal();
|
|
authManager.setupKeyboardShortcuts();
|
|
authManager.initialize();
|
|
}
|