diff --git a/static/js/launch_progress.js b/static/js/launch_progress.js index 49ea4c8..ce373b5 100644 --- a/static/js/launch_progress.js +++ b/static/js/launch_progress.js @@ -123,6 +123,18 @@ function initializeSteps() { `; stepsContainer.appendChild(healthStep); + + // Add Authentication step + const authStep = document.createElement('div'); + authStep.className = 'step-item'; + authStep.innerHTML = ` +
+
+
Instance Authentication
+

Setting up instance authentication...

+
+ `; + stepsContainer.appendChild(authStep); } async function startLaunch(data) { @@ -410,9 +422,65 @@ async function startLaunch(data) { healthStep.querySelector('.step-content').appendChild(retryButton); } + // After health check, add authentication step + await updateStep(10, 'Instance Authentication', 'Setting up instance authentication...'); + const authResult = await authenticateInstance(`https://${data.webAddresses[0]}`, data.instanceId); + + if (!authResult.success) { + throw new Error(`Authentication failed: ${authResult.error}`); + } + + // Update the auth step to show success + const authStep = document.querySelectorAll('.step-item')[9]; + authStep.classList.remove('active'); + authStep.classList.add('completed'); + authStep.querySelector('.step-status').textContent = authResult.alreadyAuthenticated ? + 'Instance is already authenticated' : + 'Successfully authenticated instance'; + + // Add authentication details + const authDetails = document.createElement('div'); + authDetails.className = 'mt-3'; + authDetails.innerHTML = ` +
+
+
Authentication Details
+
+ + + + + + + + + + + + + + + + + + + + + + + + + +
PropertyValue
StatusAuthenticated
Default Adminadministrator@docupulse.com
Connection TypeManagement API Key
Authentication Type${authResult.alreadyAuthenticated ? 'Existing' : 'New'}
+
+
+
+ `; + authStep.querySelector('.step-content').appendChild(authDetails); + } catch (error) { console.error('Launch failed:', error); - await updateStep(9, 'Health Check', `Error: ${error.message}`); + await updateStep(10, 'Instance Authentication', `Error: ${error.message}`); showError(error.message); } } @@ -1018,8 +1086,8 @@ function updateStep(stepNumber, title, description) { document.getElementById('currentStep').textContent = title; document.getElementById('stepDescription').textContent = description; - // Calculate progress based on total number of steps (9 steps total) - const totalSteps = 9; + // Calculate progress based on total number of steps (10 steps total) + const totalSteps = 10; const progress = ((stepNumber - 1) / (totalSteps - 1)) * 100; const progressBar = document.getElementById('launchProgress'); progressBar.style.width = `${progress}%`; @@ -1302,4 +1370,125 @@ async function checkInstanceHealth(instanceUrl) { currentAttempt++; } } +} + +async function authenticateInstance(instanceUrl, instanceId) { + try { + // First check if instance is already authenticated + const instancesResponse = await fetch('/instances'); + const text = await instancesResponse.text(); + const parser = new DOMParser(); + const doc = parser.parseFromString(text, 'text/html'); + + // Find the instance with matching URL + const instanceRow = Array.from(doc.querySelectorAll('table tbody tr')).find(row => { + const urlCell = row.querySelector('td:nth-child(7) a'); // URL is in the 7th column + return urlCell && urlCell.textContent.trim() === instanceUrl; + }); + + if (!instanceRow) { + throw new Error('Instance not found in database'); + } + + // Get the instance ID from the status badge's data attribute + const statusBadge = instanceRow.querySelector('[data-instance-id]'); + if (!statusBadge) { + throw new Error('Could not find instance ID'); + } + + const dbInstanceId = statusBadge.dataset.instanceId; + + // Check if already authenticated + const authStatusResponse = await fetch(`/instances/${dbInstanceId}/auth-status`); + if (!authStatusResponse.ok) { + throw new Error('Failed to check authentication status'); + } + + const authStatus = await authStatusResponse.json(); + if (authStatus.authenticated) { + console.log('Instance is already authenticated'); + return { + success: true, + message: 'Instance is already authenticated', + alreadyAuthenticated: true + }; + } + + console.log('Attempting login to:', `${instanceUrl}/api/admin/login`); + + // First login to get token + const loginResponse = await fetch(`${instanceUrl}/api/admin/login`, { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + 'Accept': 'application/json' + }, + body: JSON.stringify({ + email: 'administrator@docupulse.com', + password: 'changeme' + }) + }); + + if (!loginResponse.ok) { + const errorText = await loginResponse.text(); + throw new Error(`Login failed: ${errorText}`); + } + + const loginData = await loginResponse.json(); + if (loginData.status !== 'success' || !loginData.token) { + throw new Error('Login failed: Invalid response from server'); + } + + const token = loginData.token; + + // Then create management API key + const keyResponse = await fetch(`${instanceUrl}/api/admin/management-api-key`, { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + 'Accept': 'application/json', + 'Authorization': `Bearer ${token}` + }, + body: JSON.stringify({ + name: `Connection from ${window.location.hostname}` + }) + }); + + if (!keyResponse.ok) { + const errorText = await keyResponse.text(); + throw new Error(`Failed to create API key: ${errorText}`); + } + + const keyData = await keyResponse.json(); + if (!keyData.api_key) { + throw new Error('No API key received from server'); + } + + // Save the token to our database + const saveResponse = await fetch(`/instances/${dbInstanceId}/save-token`, { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + 'X-CSRF-Token': document.querySelector('meta[name="csrf-token"]').content + }, + body: JSON.stringify({ token: keyData.api_key }) + }); + + if (!saveResponse.ok) { + const errorText = await saveResponse.text(); + throw new Error(`Failed to save token: ${errorText}`); + } + + return { + success: true, + message: 'Successfully authenticated instance', + alreadyAuthenticated: false + }; + } catch (error) { + console.error('Authentication error:', error); + return { + success: false, + error: error.message + }; + } } \ No newline at end of file