| import type { Request, Response, Application } from 'express'; | |
| import path from 'path'; | |
| import { readFileSync, existsSync } from 'fs'; | |
| function safeReadFile(filePath: string, encoding: BufferEncoding = 'utf-8'): string { | |
| if (existsSync(filePath)) { | |
| try { | |
| return readFileSync(filePath, encoding); | |
| } catch (e) { | |
| console.error(`Error reading file ${filePath} (safeReadFile):`, e); | |
| return ''; | |
| } | |
| } | |
| console.warn(`Warning: File not found at ${filePath} (safeReadFile). Returning empty string.`); | |
| return ''; | |
| } | |
| export function html(app: Application): void { | |
| const fileSystemPublicBasePath = path.resolve(__dirname, '..', 'public'); | |
| const header = safeReadFile(path.join(fileSystemPublicBasePath, 'templates', 'header.html')); | |
| const chatheadai = safeReadFile(path.join(fileSystemPublicBasePath, 'templates', 'chatheadai.html')); | |
| const footer = safeReadFile(path.join(fileSystemPublicBasePath, 'templates', 'footer.html')); | |
| function renderPage(title: string, scriptPath: string): string { | |
| const hostScript = safeReadFile(path.join(fileSystemPublicBasePath, 'src', scriptPath)); | |
| const basePublicPath = '/private/server/exocore/web/public'; | |
| return ` | |
| <!DOCTYPE html> | |
| <html lang="en"> | |
| <head> | |
| <meta charset="UTF-8" /> | |
| <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no"> | |
| <link rel="icon" type="image/jpeg" href="https://i.ibb.co/G4vDj7Fm/FB-IMG-1749809298614.jpg"> | |
| <title>${title}</title> | |
| <script> | |
| (function() { | |
| const getToken = () => localStorage.getItem('exocore-token') || ''; | |
| const getCookies = () => localStorage.getItem('exocore-cookies') || ''; | |
| const baseRedirectPath = '/private/server/exocore/web/public'; | |
| const panelLoginLandingUrl = baseRedirectPath; | |
| const accountLoginUrl = \`\${baseRedirectPath}/login\`; | |
| const registerUrl = \`\${baseRedirectPath}/register\`; | |
| const otpUrl = \`\${baseRedirectPath}/otp\`; | |
| const forgotPasswordUrl = \`\${baseRedirectPath}/forgot-password\`; | |
| const currentPathname = window.location.pathname; | |
| const isPanelLoginSuccess = localStorage.getItem('panelLogin') === 'success'; | |
| const hasAccountAuthTokens = getToken() && getCookies(); | |
| if (!isPanelLoginSuccess) { | |
| if (currentPathname !== panelLoginLandingUrl) { | |
| console.log("'panelLogin' is not 'success'. Redirecting to panel login landing page..."); | |
| window.location.href = panelLoginLandingUrl; | |
| throw new Error("Redirecting to panel login landing to halt script execution."); | |
| } | |
| return; | |
| } | |
| const postPanelLogin_AccountAuthPages = [accountLoginUrl, registerUrl, otpUrl, forgotPasswordUrl]; | |
| if (!hasAccountAuthTokens) { | |
| if (!postPanelLogin_AccountAuthPages.includes(currentPathname)) { | |
| console.log('User has panel access but no account session tokens. Redirecting to account login page...'); | |
| window.location.href = accountLoginUrl; | |
| throw new Error("Redirecting to account login to halt script execution."); | |
| } | |
| return; | |
| } | |
| })(); | |
| </script> | |
| <script src="https://cdn.jsdelivr.net/npm/ansi_up@5.1.0/ansi_up.min.js"></script> | |
| <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" rel="stylesheet" /> | |
| <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/flatpickr/dist/flatpickr.min.css" /> | |
| <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/styles/atom-one-dark.min.css"> | |
| <style> | |
| html, body { height: 100%; margin: 0; } | |
| .page-wrapper { min-height: 100%; display: flex; flex-direction: column; } | |
| .page-content { flex: 1; } | |
| #app { min-height: 100vh; } | |
| h2, h3, h4 { color: #333; margin-top: 0.5rem; margin-bottom: 1rem; } | |
| ul { list-style-type: none; padding: 0; margin: 0; } | |
| li { padding: 0.2rem 0; } | |
| .status-box { padding: 0.5rem; margin: 0.5rem 0; border: 1px solid #ddd; background: #f9f9f9; border-radius: 4px; display: flex; align-items: center; justify-content: space-between; } | |
| input[type="file"] { display: none; } | |
| @media (max-width: 767px) { | |
| .main-content-flex { flex-direction: column; gap: 15px !important; } | |
| .file-list-panel, .file-editor-panel { width: 100%; min-width: unset !important; } | |
| } | |
| pre { background: #1e1e1e; padding: 1em; overflow: auto; border-radius: 5px; color: #ccc; } | |
| code { font-family: 'monospace'; display: block; } | |
| </style> | |
| </head> | |
| <body> | |
| <div class="page-wrapper"> | |
| ${header} | |
| <div id="app" class="page-content"></div> | |
| ${chatheadai} | |
| ${footer} | |
| </div> | |
| <script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/highlight.min.js"></script> | |
| <script> | |
| document.addEventListener('DOMContentLoaded', () => { | |
| if (typeof hljs !== 'undefined') { | |
| hljs.highlightAll(); | |
| } | |
| }); | |
| </script> | |
| <script> | |
| async function checkProjectStatusAndRedirect() { | |
| const projectStatusUrl = '/private/server/exocore/web/project/status'; | |
| const redirectUrl = '${basePublicPath}/project'; | |
| if (window.location.pathname === redirectUrl) { | |
| console.log('Currently on the project setup page. Status check will not redirect further from here.'); | |
| return; | |
| } | |
| try { | |
| const response = await fetch(projectStatusUrl, { | |
| method: 'POST', | |
| headers: { 'Content-Type': 'application/json' }, | |
| }); | |
| if (!response.ok) { | |
| console.error(\`Failed to fetch project status. Server responded with \${response.status}: \${response.statusText}\`); | |
| return; | |
| } | |
| const statusData = await response.json(); | |
| if (statusData && typeof statusData.exists === 'boolean' && !statusData.exists) { | |
| console.log('Project status indicates it does not exist or is not properly configured. Redirecting to project setup...'); | |
| window.location.href = redirectUrl; | |
| } else if (statusData && statusData.exists === true) { | |
| console.log('Project exists. No redirection necessary from project status check.'); | |
| } else { | |
| console.warn('Received an unexpected or malformed response from the project status API:', statusData); | |
| } | |
| } catch (error) { | |
| console.error('Error during project status check or processing:', error); | |
| } | |
| } | |
| const currentPathnameForProjectCheck = window.location.pathname; | |
| const baseRedirectPathForProjectCheck = '/private/server/exocore/web/public'; | |
| const accountLoginUrlForProjectCheck = \`\${baseRedirectPathForProjectCheck}/login\`; | |
| const registerUrlForProjectCheck = \`\${baseRedirectPathForProjectCheck}/register\`; | |
| const otpUrlForProjectCheck = \`\${baseRedirectPathForProjectCheck}/otp\`; | |
| if ( localStorage.getItem('exocore-token') && | |
| localStorage.getItem('exocore-cookies') && | |
| localStorage.getItem('panelLogin') === 'success' && | |
| currentPathnameForProjectCheck !== accountLoginUrlForProjectCheck && | |
| currentPathnameForProjectCheck !== registerUrlForProjectCheck && | |
| currentPathnameForProjectCheck !== otpUrlForProjectCheck | |
| ) { | |
| checkProjectStatusAndRedirect(); | |
| } | |
| </script> | |
| <script type="module">${hostScript}</script> | |
| </body> | |
| </html>`; | |
| } | |
| const urlSegmentForPublicRoutes = '/private/server/exocore/web/public'; | |
| app.get(`${urlSegmentForPublicRoutes}/register`, (_req: Request, res: Response): void => { | |
| res.setHeader('Content-Type', 'text/html'); | |
| res.send(renderPage('Signup', 'register.js')); | |
| }); | |
| app.get(`${urlSegmentForPublicRoutes}/login`, (_req: Request, res: Response): void => { | |
| res.setHeader('Content-Type', 'text/html'); | |
| res.send(renderPage('Login', 'login.js')); | |
| }); | |
| app.get(`${urlSegmentForPublicRoutes}/project`, (_req: Request, res: Response): void => { | |
| res.setHeader('Content-Type', 'text/html'); | |
| res.send(renderPage('Project', 'project.js')); | |
| }); | |
| app.get(`${urlSegmentForPublicRoutes}/otp`, (_req: Request, res: Response): void => { | |
| res.setHeader('Content-Type', 'text/html'); | |
| res.send(renderPage('Otp', 'otp.js')); | |
| }); | |
| app.get(`${urlSegmentForPublicRoutes}/profile`, (_req: Request, res: Response): void => { | |
| res.setHeader('Content-Type', 'text/html'); | |
| res.send(renderPage('Profile', 'profile.js')); | |
| }); | |
| app.get(`${urlSegmentForPublicRoutes}/forgot-password`, (_req: Request, res: Response): void => { | |
| res.setHeader('Content-Type', 'text/html'); | |
| res.send(renderPage('ForgotPass', 'forgot.js')); | |
| }); | |
| app.get(`${urlSegmentForPublicRoutes}/dashboard`, (_req: Request, res: Response): void => { | |
| res.setHeader('Content-Type', 'text/html'); | |
| res.send(renderPage('Dashboard', 'dashboard.js')); | |
| }); | |
| app.get(`${urlSegmentForPublicRoutes}/plans`, (_req: Request, res: Response): void => { | |
| res.setHeader('Content-Type', 'text/html'); | |
| res.send(renderPage('plans', 'plans.js')); | |
| }); | |
| app.get(`${urlSegmentForPublicRoutes}/console`, (_req: Request, res: Response): void => { | |
| res.setHeader('Content-Type', 'text/html'); | |
| res.send(renderPage('Console', 'console.js')); | |
| }); | |
| app.get(`${urlSegmentForPublicRoutes}/shell`, (_req: Request, res: Response): void => { | |
| res.setHeader('Content-Type', 'text/html'); | |
| res.send(renderPage('Shell', 'shell.js')); | |
| }); | |
| app.get(`${urlSegmentForPublicRoutes}/manager`, (_req: Request, res: Response): void => { | |
| res.setHeader('Content-Type', 'text/html'); | |
| res.send(renderPage('File Manager', 'FileManager.js')); | |
| }); | |
| app.get(urlSegmentForPublicRoutes, (_req: Request, res: Response): void => { | |
| const panelHtmlFilePath = path.join(fileSystemPublicBasePath, 'panel.html'); | |
| if (!existsSync(panelHtmlFilePath)) { | |
| console.warn(`Static file not found: ${panelHtmlFilePath} for URL ${urlSegmentForPublicRoutes}. Sending 404.`); | |
| res.status(404).send('Page not found.'); | |
| return; | |
| } | |
| try { | |
| const fileContent = readFileSync(panelHtmlFilePath, 'utf-8'); | |
| res.setHeader('Content-Type', 'text/html'); | |
| res.send(fileContent); | |
| } catch (error) { | |
| console.error(`Error reading static file ${panelHtmlFilePath} for URL ${urlSegmentForPublicRoutes}:`, error); | |
| res.status(500).send('Error loading page.'); | |
| } | |
| }); | |
| } | |