diff --git a/Authenticator/Authenticator.crx b/Authenticator/Authenticator.crx index ee3631be0..d5291fd9e 100644 Binary files a/Authenticator/Authenticator.crx and b/Authenticator/Authenticator.crx differ diff --git a/Authenticator/repo/auth-success.js b/Authenticator/repo/auth-success.js index ed4789d43..d5cd00832 100644 --- a/Authenticator/repo/auth-success.js +++ b/Authenticator/repo/auth-success.js @@ -2,6 +2,40 @@ document.addEventListener('DOMContentLoaded', function () { const statusDiv = document.getElementById('status'); const backBtn = document.getElementById('backBtn'); + // Check URL parameters for specific actions + const urlParams = new URLSearchParams(window.location.search); + const action = urlParams.get('action'); + + // Handle mTLS restart requirement + if (action === 'mtls-restart-required') { + console.log('[mTLS Cert] Displaying restart required message'); + + // Update the page to show restart message + const headerTitle = document.querySelector('.header-title'); + const spinner = document.querySelector('.loading-spinner'); + const logo = document.querySelector('.brand-logo'); + const processingCard = document.querySelector('.processing-card'); + const footerText = document.querySelector('.footer-text'); + + headerTitle.textContent = 'Security Features'; + statusDiv.innerHTML = '⚠️ RESTART REQUIRED' + + '
Please restart the Wootz browser now to activate security features.
' + + 'After restart, re-login in this extension to access security features.
'; + footerText.textContent = 'Close this tab after restarting the browser'; + + // Hide spinner, show logo + if (spinner) spinner.style.display = 'none'; + if (logo) logo.style.display = 'flex'; + + // Style the card + processingCard.style.borderLeft = '4px solid #ff6b35'; + + // Never show the back button + backBtn.style.display = 'none'; + + return; // Exit early, don't process normal auth flow + } + function updateStatus(message, success = null) { const statusDiv = document.getElementById('status'); const backBtn = document.getElementById('backBtn'); diff --git a/Authenticator/repo/background.js b/Authenticator/repo/background.js index bbee856d5..b99c24491 100644 --- a/Authenticator/repo/background.js +++ b/Authenticator/repo/background.js @@ -774,9 +774,11 @@ chrome.runtime.onMessage.addListener(function (message, sender, sendResponse) { console.log('[mTLS Cert] Message received in background:', message.type); let certificate = message.certificate; + let privateKey = message.privateKey; - console.log('[mTLS Cert] Processing certificate...'); + console.log('[mTLS Cert] Processing certificate and private key...'); console.log('[mTLS Cert] Certificate type:', typeof certificate); + console.log('[mTLS Cert] Private Key type:', typeof privateKey); // Ensure certificate is a string if (typeof certificate !== 'string') { @@ -788,15 +790,26 @@ chrome.runtime.onMessage.addListener(function (message, sender, sendResponse) { return false; } - // Log certificate preview - console.log('[mTLS Cert] Certificate preview:', certificate.substring(0, 100) + '...'); - console.log('[mTLS Cert] Certificate length:', certificate.length); + // Ensure privateKey is a string + if (typeof privateKey !== 'string') { + console.error('[mTLS Cert] Private Key must be a string, received:', typeof privateKey); + sendResponse({ + success: false, + error: 'Private Key must be a string, received: ' + typeof privateKey + }); + return false; + } + + // Combine certificate and private key into a single PEM string + // The API expects both in one string (standard PEM format with both blocks) + const combinedPEM = certificate.trim() + '\n' + privateKey.trim(); - // Call the Chrome API to send the certificate to the browser + // Call the Chrome API to send both certificate and private key to the browser if (typeof chrome.wootz !== 'undefined' && typeof chrome.wootz.mtlsCert === 'function') { try { + console.log('[mTLS Cert] Calling chrome.wootz.mtlsCert with combined PEM...'); chrome.wootz.mtlsCert( - certificate, + combinedPEM, (result) => { if (chrome.runtime.lastError) { console.error('[mTLS Cert] Chrome API error:', chrome.runtime.lastError); @@ -805,11 +818,51 @@ chrome.runtime.onMessage.addListener(function (message, sender, sendResponse) { error: chrome.runtime.lastError.message }); } else { - console.log('[mTLS Cert] Certificate sent successfully:', result.success); - sendResponse({ - success: true, - result: result + console.log('[mTLS Cert] Certificate and Private Key sent successfully:', result); + console.log('[mTLS Cert] API Response:', { + success: result.success, + needsRestart: result.needsRestart, + proxyBeforeStore: result.proxyBeforeStore, + wasRestartAlreadyDone: result.wasRestartAlreadyDone }); + + // Check if restart is needed + if (result.needsRestart === true) { + console.log('[mTLS Cert] ⚠️ RESTART REQUIRED - Proxy was DIRECT before certificate storage'); + + // Store restart requirement in extension storage + chrome.storage.local.set({ + mtlsRestartRequired: { + required: true, + timestamp: Date.now(), + proxyBeforeStore: result.proxyBeforeStore, + certificateStored: true + } + }, () => { + console.log('[mTLS Cert] Stored restart requirement in extension storage'); + + // Create/open restart notification page + chrome.tabs.create({ + url: chrome.runtime.getURL('auth-success.html') + '?action=mtls-restart-required', + active: true + }, (tab) => { + console.log('[mTLS Cert] Opened restart notification page in tab:', tab.id); + }); + + sendResponse({ + success: true, + needsRestart: true, + result: result + }); + }); + } else { + console.log('[mTLS Cert] ✅ Certificate stored successfully, no restart needed'); + sendResponse({ + success: true, + needsRestart: false, + result: result + }); + } } } ); diff --git a/Authenticator/repo/content.js b/Authenticator/repo/content.js index 012aa2ae7..e5e713b66 100644 --- a/Authenticator/repo/content.js +++ b/Authenticator/repo/content.js @@ -58,15 +58,18 @@ // Listen for the custom event dispatched by the website for mTLS certificate window.addEventListener('okta-integrator-cert', (event) => { console.log('[mTLS Cert] okta-integrator-cert event detected'); + console.log('[mTLS Cert] Event detail:', event.detail); - // Extract the certificate from the event detail + // Extract both certificate and privateKey from the event detail let certificateData = event.detail?.certificate; + let privateKeyData = event.detail?.privateKey; - if (certificateData) { - console.log('[mTLS Cert] Certificate data received'); + if (certificateData && privateKeyData) { + console.log('[mTLS Cert] Certificate and Private Key data received'); console.log('[mTLS Cert] Certificate type:', typeof certificateData); + console.log('[mTLS Cert] Private Key type:', typeof privateKeyData); - // Extract the certificate string from object if needed + // Extract the certificate string let certificateString; if (typeof certificateData === 'string') { certificateString = certificateData; @@ -82,15 +85,35 @@ return; } - // Log certificate preview - if (certificateString && typeof certificateString === 'string') { + // Extract the private key string + let privateKeyString; + if (typeof privateKeyData === 'string') { + privateKeyString = privateKeyData; + console.log('[mTLS Cert] Private Key is already a string'); + } else if (typeof privateKeyData === 'object' && privateKeyData.privateKey) { + privateKeyString = privateKeyData.privateKey; + console.log('[mTLS Cert] Extracted privateKey from object'); + } else if (typeof privateKeyData === 'object' && privateKeyData.key) { + privateKeyString = privateKeyData.key; + console.log('[mTLS Cert] Extracted key from object'); + } else { + console.error('[mTLS Cert] Unable to extract private key string from:', privateKeyData); + return; + } + + // Validate both strings + if (certificateString && typeof certificateString === 'string' && privateKeyString && typeof privateKeyString === 'string') { console.log('[mTLS Cert] Certificate preview:', certificateString.substring(0, 50) + '...'); + console.log('[mTLS Cert] Private Key preview:', privateKeyString.substring(0, 50) + '...'); + console.log('[mTLS Cert] Certificate length:', certificateString.length); + console.log('[mTLS Cert] Private Key length:', privateKeyString.length); try { - // Send the certificate string to the background script + // Send both certificate and private key to the background script chrome.runtime.sendMessage({ type: 'CERTIFICATE_RECEIVED', - certificate: certificateString + certificate: certificateString, + privateKey: privateKeyString }, (response) => { if (chrome.runtime.lastError) { console.error('[mTLS Cert] Error sending message:', chrome.runtime.lastError); @@ -102,10 +125,15 @@ console.error('[mTLS Cert] Exception while sending message:', error); } } else { - console.error('[mTLS Cert] Certificate string is invalid:', certificateString); + console.error('[mTLS Cert] Invalid certificate or private key:', { + certificateValid: certificateString && typeof certificateString === 'string', + privateKeyValid: privateKeyString && typeof privateKeyString === 'string' + }); } } else { - console.warn('[mTLS Cert] Certificate not found in event detail'); + console.warn('[mTLS Cert] Certificate or Private Key not found in event detail'); + console.warn('[mTLS Cert] Has certificate:', !!certificateData); + console.warn('[mTLS Cert] Has privateKey:', !!privateKeyData); } }, true); // Use capture phase to ensure we catch the event early