diff --git a/packages/Extenstions/SETUP.md b/packages/Extenstions/SETUP.md deleted file mode 100644 index 2602ddd5..00000000 --- a/packages/Extenstions/SETUP.md +++ /dev/null @@ -1,86 +0,0 @@ -# Zecrypt Browser Extension Setup - -## Environment Configuration - -⚠️ **SECURITY NOTICE**: This extension requires proper environment configuration to work securely. Never commit sensitive keys to version control. - -### Development Setup - -1. **Create Environment File** - - Create a `.env` file in the `packages/Extenstions/` directory: - - ```bash - cd packages/Extenstions/ - cp .env.example .env # If example exists, or create manually - ``` - -2. **Configure Environment Variables** - - Add the following to your `.env` file: - - ``` - INDEXED_DB_AES_KEY="HxmfPmPwqQZ3gHKwfHXi6TmPwVDppr0oDKyPwCdopDI=" - ``` - - **Note**: The key should match the `NEXT_PUBLIC_INDEXED_DB_AES_KEY` from the frontend-web `.env.local` file. - -3. **Verify Setup** - - - The `.env` file should NOT be committed to git (it's already in `.gitignore`) - - Check that the extension loads without console errors - - Verify that crypto operations work correctly - -### Production Deployment - -For production environments, consider: - -1. **Build-time Injection**: Use a build script to inject environment variables -2. **Secure Key Management**: Use proper secrets management systems -3. **Key Rotation**: Implement regular key rotation procedures - -### File Structure - -``` -packages/Extenstions/ -├── .env # Your environment file (NOT committed) -├── .gitignore # Ensures .env is ignored -├── config.js # Configuration loader -├── crypto-utils.js # Crypto utilities (uses config) -├── background.js # Background script (initializes config) -└── ... other files -``` - -### Troubleshooting - -**Error: "Extension configuration not loaded"** -- Ensure `.env` file exists in the extensions directory -- Check that `INDEXED_DB_AES_KEY` is properly set in `.env` -- Verify the key format (should be base64 encoded) - -**Error: "Configuration key not found"** -- Check that the key in `.env` matches exactly: `INDEXED_DB_AES_KEY` -- Ensure there are no extra spaces or characters -- Verify the file is saved properly - -**Error: "Invalid encryption key format"** -- The key should be a valid base64 string -- Check that the key length is correct (32 bytes when decoded) -- Ensure the key matches the one used in the web application - -### Security Best Practices - -1. **Never hardcode keys** in source code -2. **Use different keys** for different environments (dev/staging/prod) -3. **Rotate keys regularly** and update all environments -4. **Restrict access** to environment files and key management systems -5. **Monitor usage** and implement key usage auditing - -### Getting the Key - -The `INDEXED_DB_AES_KEY` should be obtained from: -1. Your development team's secure key management system -2. The frontend-web application's environment configuration -3. Your organization's secrets management platform - -Contact your development team if you don't have access to the required keys. \ No newline at end of file diff --git a/packages/Extenstions/background.js b/packages/Extenstions/background.js index 47b4b192..ab487f45 100644 --- a/packages/Extenstions/background.js +++ b/packages/Extenstions/background.js @@ -1,20 +1,31 @@ -// Base API URL -const API_BASE_URL = 'https://preview.api.zecrypt.io/api/v1/web'; - // Import configuration and crypto utilities importScripts('config.js'); importScripts('crypto-utils.js'); +// API Base URL will be set after configuration is loaded +let API_BASE_URL = null; + // Initialize configuration when extension starts (async function initializeExtension() { try { await ExtensionConfig.initConfig(); + API_BASE_URL = ExtensionConfig.getApiBaseUrl(); + console.log('Extension initialized with API Base URL:', API_BASE_URL); } catch (error) { - console.error('Failed to load extension configuration:', error); - console.error('Please ensure you have created a .env file in the extensions directory with the required keys'); + console.error('Failed to initialize extension configuration:', error); + // Fallback to production URL if config fails + API_BASE_URL = 'https://api.zecrypt.io/api/v1/web'; } })(); +// Function to ensure configuration is loaded +function ensureConfigLoaded() { + if (!API_BASE_URL) { + throw new Error('Extension configuration not loaded. Please reload the extension.'); + } + return API_BASE_URL; +} + // Helper function to check if URL is accessible for script injection function isValidUrl(url) { // Exclude chrome:// URLs, chrome-extension:// URLs, and other restricted schemes @@ -36,8 +47,8 @@ const ENDPOINTS = { cards: function(workspaceId, projectId) { return `/${workspaceId}/${projectId}/cards`; }, - emails: function(workspaceId, projectId) { - return `/${workspaceId}/${projectId}/emails`; + accounts: function(workspaceId, projectId) { + return `/${workspaceId}/${projectId}/accounts`; } }; @@ -164,53 +175,59 @@ async function processCardData(cardRaw) { } } -// Enhanced function to process and decrypt email data -async function processEmailData(emailRaw) { +// Enhanced function to process and decrypt account data +async function processAccountData(accountRaw) { try { const projectAesKey = await getDecryptedProjectAesKey(); if (!projectAesKey) { console.error("Project AES key not found for decryption"); return { - ...emailRaw, - email: 'Key missing' + ...accountRaw, + username: 'Key missing', + password: 'Key missing', + website: accountRaw.url || accountRaw.website || 'undefined' }; } - if (emailRaw.data && emailRaw.data.includes('.')) { + if (accountRaw.data && accountRaw.data.includes('.')) { try { - const decryptedData = await CryptoUtils.decryptDataField(emailRaw.data, projectAesKey); + const decryptedData = await CryptoUtils.decryptDataField(accountRaw.data, projectAesKey); const parsedData = JSON.parse(decryptedData); return { - ...emailRaw, - email: parsedData.email_address || 'undefined', - password: parsedData.password || 'undefined' + ...accountRaw, + username: parsedData.username || 'undefined', + password: parsedData.password || 'undefined', + website: accountRaw.url || accountRaw.website || 'undefined' }; } catch (decryptError) { - console.error("Failed to decrypt email data:", decryptError); + console.error("Failed to decrypt account data:", decryptError); return { - ...emailRaw, - email: 'Decrypt failed' + ...accountRaw, + username: 'Decrypt failed', + password: 'Decrypt failed', + website: accountRaw.url || accountRaw.website || 'undefined' }; } } else { // Data might not be encrypted (legacy format) try { - const parsedData = JSON.parse(emailRaw.data); + const parsedData = JSON.parse(accountRaw.data); return { - ...emailRaw, - email: parsedData.email_address || 'undefined', - password: parsedData.password || 'undefined' + ...accountRaw, + username: parsedData.username || 'undefined', + password: parsedData.password || 'undefined', + website: accountRaw.url || accountRaw.website || 'undefined' }; } catch (parseError) { - console.error("Error parsing email data:", parseError); - return emailRaw; + console.error("Error parsing account data:", parseError); + return accountRaw; } } } catch (error) { - console.error("Error processing email data:", error); - return emailRaw; + console.error("Error processing account data:", error); + return accountRaw; } } @@ -243,21 +260,43 @@ function apiRequest(endpoint, method, data) { options.body = JSON.stringify(data); } - return fetch(API_BASE_URL + resolvedEndpoint, options); + const apiUrl = ensureConfigLoaded() + resolvedEndpoint; + console.log('Making API request:', { + url: apiUrl, + method: method, + hasToken: !!authData.token, + tokenPrefix: authData.token ? authData.token.substring(0, 10) + '...' : 'none', + workspaceId: authData.workspaceId, + projectId: authData.projectId + }); + + return fetch(apiUrl, options); }) .then(function(response) { + console.log('API response status:', response.status, response.statusText); + if (!response.ok) { if (response.status === 401) { + console.error('401 Unauthorized - clearing stored tokens'); chrome.storage.local.remove(['zecryptToken', 'zecryptWorkspaceId', 'zecryptProjectId']); throw new Error('Authentication failed. Please log in again.'); } - throw new Error('API request failed with status ' + response.status); + // Try to get response text for better error details + return response.text().then(errorText => { + console.error('API request failed:', { + status: response.status, + statusText: response.statusText, + errorText: errorText + }); + throw new Error(`API request failed with status ${response.status}: ${errorText}`); + }); } return response.json(); }) .then(function(data) { + console.log('API request successful'); resolve(data); }) .catch(function(error) { @@ -289,17 +328,17 @@ function getCards() { }); } -// Enhanced getEmails function with decryption -function getEmails() { +// Enhanced getAccounts function with decryption +function getAccounts() { return new Promise(function(resolve, reject) { - apiRequest(ENDPOINTS.emails) + apiRequest(ENDPOINTS.accounts) .then(async function(response) { - const emails = response.data || []; - const processedEmails = await Promise.all(emails.map(processEmailData)); + const accounts = response.data || []; + const processedAccounts = await Promise.all(accounts.map(processAccountData)); resolve({ success: true, - data: processedEmails + data: processedAccounts }); }) .catch(function(error) { @@ -351,32 +390,45 @@ function checkLocalStorageAuth() { func: () => { try { const authData = localStorage.getItem('zecrypt_extension_auth'); + console.log('Extension: Checking localStorage for auth data:', !!authData); + if (authData) { try { const parsed = JSON.parse(authData); + console.log('Extension: Found auth data:', { + hasToken: !!parsed.token, + hasWorkspaceId: !!parsed.workspaceId, + hasProjectId: !!parsed.projectId, + hasProjectAesKey: !!parsed.projectAesKey, + timestamp: parsed.timestamp + }); + // Remove the auth data after reading it localStorage.removeItem('zecrypt_extension_auth'); return parsed; } catch (e) { - console.error('Error parsing auth data:', e); + console.error('Extension: Error parsing auth data:', e); localStorage.removeItem('zecrypt_extension_auth'); return null; } } return null; } catch (error) { - console.error('Error accessing localStorage:', error); + console.error('Extension: Error accessing localStorage:', error); return null; } } }, (results) => { if (chrome.runtime.lastError) { + console.error('Extension: Script execution failed:', chrome.runtime.lastError.message); resolve({ success: false, error: chrome.runtime.lastError.message }); return; } if (results && results[0] && results[0].result) { const authData = results[0].result; + console.log('Extension: Processing auth data from localStorage'); + // Store in extension storage chrome.storage.local.set({ zecryptToken: authData.token, @@ -384,26 +436,31 @@ function checkLocalStorageAuth() { zecryptProjectId: authData.projectId }, async () => { if (chrome.runtime.lastError) { - console.error('Error storing auth data:', chrome.runtime.lastError); + console.error('Extension: Error storing auth data:', chrome.runtime.lastError); resolve({ success: false, error: chrome.runtime.lastError.message }); } else { + console.log('Extension: Successfully stored auth data in chrome.storage.local'); + // Store project AES key securely if provided if (authData.projectAesKey) { await storeProjectAesKey(authData.projectAesKey); + console.log('Extension: Successfully stored project AES key'); } resolve({ success: true, authData }); } }); } else { + console.log('Extension: No auth data found in localStorage'); resolve({ success: false, error: 'No auth data found' }); } }); } else { + console.log('Extension: No accessible tab found for localStorage check'); resolve({ success: false, error: 'No accessible tab found' }); } }); } catch (error) { - console.error('Error checking localStorage:', error); + console.error('Extension: Error in checkLocalStorageAuth:', error); resolve({ success: false, error: error.message }); } }); @@ -562,8 +619,8 @@ chrome.runtime.onMessage.addListener((message, sender, sendResponse) => { return true; } - if (message.dataType === 'emails') { - getEmails() + if (message.dataType === 'accounts') { + getAccounts() .then(response => { sendResponse(response); }) @@ -580,8 +637,8 @@ chrome.runtime.onMessage.addListener((message, sender, sendResponse) => { getCards() .then(response => { if (response.success && response.data && response.data.length > 0) { - // Return all cards - for now use first one, but structure allows for future selector UI - sendResponse({ success: true, data: response.data, multiple: response.data.length > 1 }); + // Always show selector UI for cards, even for single card + sendResponse({ success: true, data: response.data, multiple: true }); } else { sendResponse({ success: false, error: 'No cards available' }); } @@ -592,14 +649,14 @@ chrome.runtime.onMessage.addListener((message, sender, sendResponse) => { return true; } - if (message.dataType === 'email') { - getEmails() + if (message.dataType === 'account') { + getAccounts() .then(response => { if (response.success && response.data && response.data.length > 0) { - // Return all emails so the content script can show a selector UI - sendResponse({ success: true, data: response.data, multiple: response.data.length > 1 }); + // Always show selector UI for accounts, even for single account + sendResponse({ success: true, data: response.data, multiple: true }); } else { - sendResponse({ success: false, error: 'No emails available' }); + sendResponse({ success: false, error: 'No accounts available' }); } }) .catch(error => { diff --git a/packages/Extenstions/config.js b/packages/Extenstions/config.js index b4fa945c..afdc8c62 100644 --- a/packages/Extenstions/config.js +++ b/packages/Extenstions/config.js @@ -11,6 +11,30 @@ // This will hold our configuration let CONFIG = null; +/** + * Default configuration values + */ +const DEFAULT_CONFIG = { + // Development environment + DEVELOPMENT: { + API_BASE_URL: 'http://localhost:8000/api/v1/web', + WEB_APP_BASE_URL: 'http://localhost:3000', + IS_DEVELOPMENT: true + }, + // Production environment + PRODUCTION: { + API_BASE_URL: 'https://api.zecrypt.io/api/v1/web', + WEB_APP_BASE_URL: 'https://app.zecrypt.io', + IS_DEVELOPMENT: false + }, + // Preview environment + PREVIEW: { + API_BASE_URL: 'https://preview.api.zecrypt.io/api/v1/web', + WEB_APP_BASE_URL: 'https://preview.app.zecrypt.io', + IS_DEVELOPMENT: false + } +}; + /** * Load configuration from environment file * Note: This is a simplified approach for browser extensions @@ -57,22 +81,39 @@ async function loadConfigFromEnv() { */ async function initConfig() { // Try to load from .env file first - CONFIG = await loadConfigFromEnv(); + let envConfig = await loadConfigFromEnv(); // If no config loaded, check for injected config (build-time injection) - if (!CONFIG && typeof window !== 'undefined' && window.INJECTED_CONFIG) { - CONFIG = window.INJECTED_CONFIG; + if (!envConfig && typeof window !== 'undefined' && window.INJECTED_CONFIG) { + envConfig = window.INJECTED_CONFIG; } - // If still no config, throw an error - if (!CONFIG || !CONFIG.INDEXED_DB_AES_KEY) { + // Determine environment + const environment = envConfig?.ENVIRONMENT || 'PRODUCTION'; + + // Merge default config with environment-specific config and .env overrides + CONFIG = { + ...DEFAULT_CONFIG[environment], + ...envConfig + }; + + // If still no encryption key, throw an error + if (!CONFIG.INDEXED_DB_AES_KEY) { throw new Error( 'Configuration not found! Please create a .env file in the extensions directory with:\n' + - 'INDEXED_DB_AES_KEY="your_key_here"\n\n' + + 'INDEXED_DB_AES_KEY="your_key_here"\n' + + 'ENVIRONMENT="PRODUCTION" # or DEVELOPMENT or PREVIEW\n\n' + 'See README.md for setup instructions.' ); } + console.log('Extension configuration loaded:', { + environment, + apiBaseUrl: CONFIG.API_BASE_URL, + webAppBaseUrl: CONFIG.WEB_APP_BASE_URL, + isDevelopment: CONFIG.IS_DEVELOPMENT + }); + return CONFIG; } @@ -85,7 +126,7 @@ function getConfig(key) { } const value = CONFIG[key]; - if (!value) { + if (value === undefined) { throw new Error(`Configuration key '${key}' not found.`); } @@ -99,6 +140,27 @@ function getIndexedDbAesKey() { return getConfig('INDEXED_DB_AES_KEY'); } +/** + * Get the API base URL + */ +function getApiBaseUrl() { + return getConfig('API_BASE_URL'); +} + +/** + * Get the web app base URL + */ +function getWebAppBaseUrl() { + return getConfig('WEB_APP_BASE_URL'); +} + +/** + * Check if running in development mode + */ +function isDevelopment() { + return getConfig('IS_DEVELOPMENT'); +} + /** * Check if configuration is loaded */ @@ -111,6 +173,9 @@ const ExtensionConfig = { initConfig, getConfig, getIndexedDbAesKey, + getApiBaseUrl, + getWebAppBaseUrl, + isDevelopment, isConfigLoaded }; @@ -119,7 +184,6 @@ if (typeof globalThis !== 'undefined') { globalThis.ExtensionConfig = ExtensionConfig; } -// Also support module exports for potential build tools -if (typeof module !== 'undefined' && module.exports) { - module.exports = ExtensionConfig; +if (typeof self !== 'undefined') { + self.ExtensionConfig = ExtensionConfig; } \ No newline at end of file diff --git a/packages/Extenstions/content.js b/packages/Extenstions/content.js index 2dbf4db2..c58edc76 100644 --- a/packages/Extenstions/content.js +++ b/packages/Extenstions/content.js @@ -3,17 +3,17 @@ function detectForms() { // Look for credit card forms const cardNumberInputs = document.querySelectorAll('input[autocomplete="cc-number"], input[name*="card_number"], input[name*="cardNumber"], input[id*="card-number"], input[id*="cardNumber"]'); - // Look for email inputs - const emailInputs = document.querySelectorAll('input[type="email"], input[name*="email"], input[id*="email"]'); + // Look for username/login inputs + const usernameInputs = document.querySelectorAll('input[type="email"], input[type="text"][name*="username"], input[type="text"][name*="user"], input[type="text"][name*="login"], input[type="text"][id*="username"], input[type="text"][id*="user"], input[type="text"][id*="login"], input[name*="email"], input[id*="email"]'); // Process card number inputs cardNumberInputs.forEach(input => { setupAutofillButton(input, 'card'); }); - // Process email inputs - emailInputs.forEach(input => { - setupAutofillButton(input, 'email'); + // Process username inputs + usernameInputs.forEach(input => { + setupAutofillButton(input, 'account'); }); } @@ -55,21 +55,11 @@ function fetchAndFillData(type, input) { }, (response) => { if (response && response.success) { if (type === 'card') { - // Check if there are multiple cards - if (response.multiple && response.data.length > 1) { - showCardSelector(input, response.data); - } else { - // Single card, fill directly - fillCardData(input, response.data[0] || response.data); - } - } else if (type === 'email') { - // Check if there are multiple emails - if (response.multiple && response.data.length > 1) { - showEmailSelector(input, response.data); - } else { - // Single email, fill directly - fillEmailData(input, response.data[0] || response.data); - } + // Always show card selector for user confirmation + showCardSelector(input, response.data); + } else if (type === 'account') { + // Always show account selector for user confirmation + showAccountSelector(input, response.data); } } else { // Show error or prompt to log in @@ -78,14 +68,14 @@ function fetchAndFillData(type, input) { }); } -// Show email selector UI when multiple emails are available -function showEmailSelector(input, emails) { +// Show account selector UI when multiple accounts are available +function showAccountSelector(input, accounts) { // Remove any existing selector - removeEmailSelector(); + removeAccountSelector(); // Create overlay const overlay = document.createElement('div'); - overlay.id = 'zecrypt-email-selector-overlay'; + overlay.id = 'zecrypt-account-selector-overlay'; overlay.style.cssText = ` position: fixed; top: 0; @@ -123,7 +113,7 @@ function showEmailSelector(input, emails) { `; const title = document.createElement('h3'); - title.textContent = 'Select Email Account'; + title.textContent = 'Select Account'; title.style.cssText = ` margin: 0; font-size: 18px; @@ -146,21 +136,21 @@ function showEmailSelector(input, emails) { align-items: center; justify-content: center; `; - closeBtn.addEventListener('click', removeEmailSelector); + closeBtn.addEventListener('click', removeAccountSelector); header.appendChild(title); header.appendChild(closeBtn); - // Create email list - const emailList = document.createElement('div'); - emailList.style.cssText = ` + // Create account list + const accountList = document.createElement('div'); + accountList.style.cssText = ` max-height: 300px; overflow-y: auto; `; - emails.forEach((email, index) => { - const emailItem = document.createElement('div'); - emailItem.style.cssText = ` + accounts.forEach((account, index) => { + const accountItem = document.createElement('div'); + accountItem.style.cssText = ` padding: 12px; border: 1px solid #e5e7eb; border-radius: 6px; @@ -170,44 +160,54 @@ function showEmailSelector(input, emails) { background: #f9fafb; `; - emailItem.addEventListener('mouseenter', () => { - emailItem.style.backgroundColor = '#f3f4f6'; - emailItem.style.borderColor = '#4f46e5'; + accountItem.addEventListener('mouseenter', () => { + accountItem.style.backgroundColor = '#f3f4f6'; + accountItem.style.borderColor = '#4f46e5'; }); - emailItem.addEventListener('mouseleave', () => { - emailItem.style.backgroundColor = '#f9fafb'; - emailItem.style.borderColor = '#e5e7eb'; + accountItem.addEventListener('mouseleave', () => { + accountItem.style.backgroundColor = '#f9fafb'; + accountItem.style.borderColor = '#e5e7eb'; }); - emailItem.addEventListener('click', () => { - fillEmailData(input, email); - removeEmailSelector(); + accountItem.addEventListener('click', () => { + fillAccountData(input, account); + removeAccountSelector(); }); - const emailAddress = document.createElement('div'); - emailAddress.textContent = email.email || 'No email address'; - emailAddress.style.cssText = ` + const accountUsername = document.createElement('div'); + accountUsername.textContent = account.username || 'No username'; + accountUsername.style.cssText = ` font-weight: 500; color: #1f2937; margin-bottom: 4px; `; - const emailTitle = document.createElement('div'); - emailTitle.textContent = email.title || 'Untitled Email'; - emailTitle.style.cssText = ` + const accountTitle = document.createElement('div'); + const website = account.website || account.url || ''; + let displayText = account.title || account.name || 'Untitled Account'; + if (website) { + try { + const domain = new URL(website).hostname.replace('www.', ''); + displayText += ` • ${domain}`; + } catch (e) { + displayText += ` • ${website}`; + } + } + accountTitle.textContent = displayText; + accountTitle.style.cssText = ` font-size: 14px; color: #6b7280; `; - emailItem.appendChild(emailAddress); - emailItem.appendChild(emailTitle); - emailList.appendChild(emailItem); + accountItem.appendChild(accountUsername); + accountItem.appendChild(accountTitle); + accountList.appendChild(accountItem); }); // Assemble modal modal.appendChild(header); - modal.appendChild(emailList); + modal.appendChild(accountList); overlay.appendChild(modal); // Add to page @@ -216,23 +216,23 @@ function showEmailSelector(input, emails) { // Close on overlay click overlay.addEventListener('click', (e) => { if (e.target === overlay) { - removeEmailSelector(); + removeAccountSelector(); } }); // Close on escape key const escapeHandler = (e) => { if (e.key === 'Escape') { - removeEmailSelector(); + removeAccountSelector(); document.removeEventListener('keydown', escapeHandler); } }; document.addEventListener('keydown', escapeHandler); } -// Remove email selector UI -function removeEmailSelector() { - const overlay = document.getElementById('zecrypt-email-selector-overlay'); +// Remove account selector UI +function removeAccountSelector() { + const overlay = document.getElementById('zecrypt-account-selector-overlay'); if (overlay) { overlay.remove(); } @@ -509,10 +509,10 @@ function fillCardData(input, cardData) { } } -// Fill email data into form -function fillEmailData(input, emailData) { - // Fill the email address - input.value = emailData.email; +// Fill account data into form +function fillAccountData(input, accountData) { + // Fill the username (could be email or username field) + input.value = accountData.username; triggerInputEvent(input); // Define search scope: the form, or the whole document as a fallback @@ -523,8 +523,8 @@ function fillEmailData(input, emailData) { if (passwordInputs.length > 0) { // Find the first visible password input const visiblePasswordInput = Array.from(passwordInputs).find(el => el.offsetParent !== null); - if (visiblePasswordInput) { - visiblePasswordInput.value = emailData.password; + if (visiblePasswordInput && accountData.password) { + visiblePasswordInput.value = accountData.password; triggerInputEvent(visiblePasswordInput); } } @@ -574,10 +574,10 @@ chrome.runtime.onMessage.addListener((message, sender, sendResponse) => { if (cardInputs.length > 0) { fillCardData(cardInputs[0], message.data); } - } else if (message.dataType === 'email') { - const emailInputs = document.querySelectorAll('input[type="email"], input[name*="email"], input[id*="email"]'); - if (emailInputs.length > 0) { - fillEmailData(emailInputs[0], message.data); + } else if (message.dataType === 'account') { + const usernameInputs = document.querySelectorAll('input[type="email"], input[type="text"][name*="username"], input[type="text"][name*="user"], input[type="text"][name*="login"], input[type="text"][id*="username"], input[type="text"][id*="user"], input[type="text"][id*="login"], input[name*="email"], input[id*="email"]'); + if (usernameInputs.length > 0) { + fillAccountData(usernameInputs[0], message.data); } } diff --git a/packages/Extenstions/popup.html b/packages/Extenstions/popup.html index cc1a0485..2d4e2f76 100644 --- a/packages/Extenstions/popup.html +++ b/packages/Extenstions/popup.html @@ -309,11 +309,11 @@
- - Email Addresses + + Accounts
-
- +
+
diff --git a/packages/Extenstions/popup.js b/packages/Extenstions/popup.js index ac77462c..78563c6f 100644 --- a/packages/Extenstions/popup.js +++ b/packages/Extenstions/popup.js @@ -6,7 +6,31 @@ document.addEventListener('DOMContentLoaded', () => { const loginBtn = document.getElementById('loginBtn'); const logoutBtn = document.getElementById('logoutBtn'); const cardsList = document.getElementById('cardsList'); - const emailsList = document.getElementById('emailsList'); + const accountsList = document.getElementById('accountsList'); + + // Configuration will be loaded when needed + let BASE_URL = null; + + // Function to get web app base URL + function getWebAppBaseUrl() { + if (!BASE_URL) { + try { + // Try to get from extension config + if (chrome.extension.getBackgroundPage() && + chrome.extension.getBackgroundPage().ExtensionConfig && + chrome.extension.getBackgroundPage().ExtensionConfig.isConfigLoaded()) { + BASE_URL = chrome.extension.getBackgroundPage().ExtensionConfig.getWebAppBaseUrl(); + } else { + // Fallback to production URL + BASE_URL = 'https://app.zecrypt.io'; + } + } catch (error) { + console.warn('Could not load config, using fallback URL:', error); + BASE_URL = 'https://app.zecrypt.io'; + } + } + return BASE_URL; + } // Listen for messages from the extension login page window.addEventListener('message', (event) => { // Verify origin for security (in production, be more specific) @@ -59,16 +83,13 @@ document.addEventListener('DOMContentLoaded', () => { } }); // Configuration for development vs production const isDevelopment = false; // Set to false for production - const BASE_URL = isDevelopment - ? 'http://localhost:3000' - : 'https://app.zecrypt.io'; - // Login button click handler + // Login button click handler loginBtn.addEventListener('click', () => { // Start auth checking in background chrome.runtime.sendMessage({ type: 'START_AUTH_CHECK' }); // Open the extension login page in a new tab (with locale prefix) - chrome.tabs.create({ url: `${BASE_URL}/en/extension-login?from=extension` }); + chrome.tabs.create({ url: `${getWebAppBaseUrl()}/en/extension-login?from=extension` }); }); // Logout button click handler logoutBtn.addEventListener('click', () => { @@ -99,15 +120,15 @@ document.addEventListener('DOMContentLoaded', () => { // Clear any existing data cardsList.innerHTML = ''; - emailsList.innerHTML = ''; + accountsList.innerHTML = ''; } - // Fetch cards and emails data + // Fetch cards and accounts data function fetchData() { // Show loading indicator loadingSection.style.display = 'block'; contentSection.style.display = 'none'; - // Fetch cards and emails in parallel + // Fetch cards and accounts in parallel Promise.all([ new Promise((resolve) => { chrome.runtime.sendMessage({ @@ -120,12 +141,12 @@ document.addEventListener('DOMContentLoaded', () => { new Promise((resolve) => { chrome.runtime.sendMessage({ type: 'FETCH_DATA', - dataType: 'emails' + dataType: 'accounts' }, (response) => { resolve(response || { success: false, error: 'No response' }); }); }) - ]).then(([cardsResponse, emailsResponse]) => { + ]).then(([cardsResponse, accountsResponse]) => { // Hide loading indicator loadingSection.style.display = 'none'; contentSection.style.display = 'block'; @@ -138,11 +159,11 @@ document.addEventListener('DOMContentLoaded', () => { console.error('Failed to fetch cards:', cardsResponse?.error); } - if (emailsResponse && emailsResponse.success) { - renderEmails(emailsResponse.data); + if (accountsResponse && accountsResponse.success) { + renderAccounts(accountsResponse.data); } else { - renderEmails([]); - console.error('Failed to fetch emails:', emailsResponse?.error); + renderAccounts([]); + console.error('Failed to fetch accounts:', accountsResponse?.error); } }); } @@ -173,28 +194,40 @@ document.addEventListener('DOMContentLoaded', () => { }); } - // Render email items - function renderEmails(emails) { - emailsList.innerHTML = ''; + // Render account items + function renderAccounts(accounts) { + accountsList.innerHTML = ''; - if (!emails || emails.length === 0) { - emailsList.innerHTML = '
No email addresses found
'; + if (!accounts || accounts.length === 0) { + accountsList.innerHTML = '
No accounts found
'; return; } - emails.forEach(email => { - const emailItem = document.createElement('div'); - emailItem.className = 'item'; + accounts.forEach(account => { + const accountItem = document.createElement('div'); + accountItem.className = 'item'; + + const accountName = account.title || account.name || 'Unknown Account'; + const username = account.username || 'No username'; + const website = account.website || account.url || ''; - const emailAddress = email.email || 'Unknown Email'; - const passwordDisplay = email.password ? '•'.repeat(email.password.length) : 'No password'; + // Show website domain if available + let displayText = username; + if (website) { + try { + const domain = new URL(website).hostname.replace('www.', ''); + displayText = `${username} • ${domain}`; + } catch (e) { + displayText = `${username} • ${website}`; + } + } - emailItem.innerHTML = ` -
${emailAddress}
-
${passwordDisplay}
+ accountItem.innerHTML = ` +
${accountName}
+
${displayText}
`; - emailsList.appendChild(emailItem); + accountsList.appendChild(accountItem); }); } }); \ No newline at end of file