Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 10 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -189,4 +189,13 @@ pnpm-lock.yaml
packages/*/node_modules
packages/*/dist
packages/*/build
packages/*/.next
packages/*/.next

# Cursor
cursor.rules

.cursor/
.cursorrules
.cursorignore


27 changes: 27 additions & 0 deletions packages/Extenstions/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
# Environment files
.env
.env.local
.env.development
.env.test
.env.production

# Node modules (if any build tools are added)
node_modules/

# Build outputs
dist/
build/

# Temporary files
*.tmp
*.temp

# IDE files
.vscode/
.idea/
*.swp
*.swo

# OS generated files
.DS_Store
Thumbs.db
22 changes: 17 additions & 5 deletions packages/Extenstions/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,14 +11,26 @@ This Chrome extension allows users to autofill card and email details from their

## Setup

### Environment Configuration

⚠️ **IMPORTANT**: Before setting up the extension, you must configure the environment variables for security.

**See [SETUP.md](./SETUP.md) for detailed environment configuration instructions.**

Quick setup:
1. Create a `.env` file in this directory
2. Add: `INDEXED_DB_AES_KEY="your_key_here"`
3. Get the key from your team or the frontend-web `.env.local` file

### Development Setup

1. Clone this repository
2. Open Chrome and navigate to `chrome://extensions/`
3. Enable "Developer mode" in the top-right corner
4. Click "Load unpacked" and select the `packages/Extenstions` directory
5. Note the Extension ID assigned by Chrome (you'll need it for the next step)
6. Update the `EXTENSION_ID` constant in `packages/frontend-web/app/extension-login/page.tsx` with your extension ID
2. **Configure environment variables** (see SETUP.md)
3. Open Chrome and navigate to `chrome://extensions/`
4. Enable "Developer mode" in the top-right corner
5. Click "Load unpacked" and select the `packages/Extenstions` directory
6. Note the Extension ID assigned by Chrome (you'll need it for the next step)
7. Update the `EXTENSION_ID` constant in `packages/frontend-web/app/extension-login/page.tsx` with your extension ID

### Frontend Setup

Expand Down
86 changes: 86 additions & 0 deletions packages/Extenstions/SETUP.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
# 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.
50 changes: 16 additions & 34 deletions packages/Extenstions/background.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,20 @@
// Base API URL
const API_BASE_URL = 'https://preview.api.zecrypt.io/api/v1/web';

// Import crypto utilities
// Import configuration and crypto utilities
importScripts('config.js');
importScripts('crypto-utils.js');

// Initialize configuration when extension starts
(async function initializeExtension() {
try {
await ExtensionConfig.initConfig();
} 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');
}
})();

// Helper function to check if URL is accessible for script injection
function isValidUrl(url) {
// Exclude chrome:// URLs, chrome-extension:// URLs, and other restricted schemes
Expand Down Expand Up @@ -56,7 +67,6 @@ async function storeProjectAesKey(projectAesKey) {
chrome.storage.local.set({
zecryptProjectAesKey: encryptedKey
});
console.log('Project AES key stored securely');
} catch (error) {
console.error('Error storing project AES key:', error);
}
Expand All @@ -69,7 +79,6 @@ async function getDecryptedProjectAesKey() {
if (result.zecryptProjectAesKey) {
try {
const decryptedKey = await CryptoUtils.decryptFromLocalStorage(result.zecryptProjectAesKey);
console.log('Project AES key retrieved and decrypted');
resolve(decryptedKey);
} catch (error) {
console.error('Error decrypting project AES key:', error);
Expand Down Expand Up @@ -107,7 +116,6 @@ async function processCardData(cardRaw) {
const decryptedData = await CryptoUtils.decryptDataField(cardRaw.data, projectAesKey);
const parsedData = JSON.parse(decryptedData);

console.log('Card data decrypted successfully');
return {
...cardRaw,
cardNumber: parsedData.number || 'undefined',
Expand Down Expand Up @@ -174,8 +182,6 @@ async function processEmailData(emailRaw) {
const decryptedData = await CryptoUtils.decryptDataField(emailRaw.data, projectAesKey);
const parsedData = JSON.parse(decryptedData);

console.log('Email data decrypted successfully');
console.log("[Zecrypt Debug] Decrypted Email Password:", parsedData.password);
return {
...emailRaw,
email: parsedData.email_address || 'undefined',
Expand All @@ -192,7 +198,6 @@ async function processEmailData(emailRaw) {
// Data might not be encrypted (legacy format)
try {
const parsedData = JSON.parse(emailRaw.data);
console.log("[Zecrypt Debug] Decrypted Email Password (legacy):", parsedData.password);
return {
...emailRaw,
email: parsedData.email_address || 'undefined',
Expand Down Expand Up @@ -268,7 +273,6 @@ function getCards() {
apiRequest(ENDPOINTS.cards)
.then(async function(response) {
const cards = response.data || [];
console.log(`Processing ${cards.length} cards for decryption`);
const processedCards = await Promise.all(cards.map(processCardData));

resolve({
Expand All @@ -291,7 +295,6 @@ function getEmails() {
apiRequest(ENDPOINTS.emails)
.then(async function(response) {
const emails = response.data || [];
console.log(`Processing ${emails.length} emails for decryption`);
const processedEmails = await Promise.all(emails.map(processEmailData));

resolve({
Expand All @@ -311,7 +314,6 @@ function getEmails() {
// Enhanced external message listener to handle project AES key
chrome.runtime.onMessageExternal.addListener(
(message, sender, sendResponse) => {
console.log('External message received:', message);
if (message.type === 'LOGIN' && message.token) {
// Store the token and workspace/project IDs securely in chrome.storage.local
chrome.storage.local.set({
Expand All @@ -323,12 +325,9 @@ chrome.runtime.onMessageExternal.addListener(
console.error('Error storing tokens:', chrome.runtime.lastError);
sendResponse({ success: false, error: chrome.runtime.lastError.message });
} else {
console.log('Token and workspace data stored successfully');

// Store project AES key securely if provided
if (message.projectAesKey) {
await storeProjectAesKey(message.projectAesKey);
console.log('Project AES key stored successfully');
}

sendResponse({ success: true });
Expand Down Expand Up @@ -372,7 +371,6 @@ function checkLocalStorageAuth() {
}
}, (results) => {
if (chrome.runtime.lastError) {
console.log('Script execution failed:', chrome.runtime.lastError.message);
resolve({ success: false, error: chrome.runtime.lastError.message });
return;
}
Expand All @@ -389,12 +387,9 @@ function checkLocalStorageAuth() {
console.error('Error storing auth data:', chrome.runtime.lastError);
resolve({ success: false, error: chrome.runtime.lastError.message });
} else {
console.log('Auth data retrieved from localStorage and stored');

// Store project AES key securely if provided
if (authData.projectAesKey) {
await storeProjectAesKey(authData.projectAesKey);
console.log('Project AES key from localStorage stored successfully');
}

resolve({ success: true, authData });
Expand All @@ -404,7 +399,6 @@ function checkLocalStorageAuth() {
resolve({ success: false, error: 'No auth data found' });
}
}); } else {
console.log('No valid tab found for localStorage check. Current tab:', tabs[0]?.url || 'No tab');
resolve({ success: false, error: 'No accessible tab found' });
}
});
Expand Down Expand Up @@ -432,7 +426,6 @@ function startAuthCheck() {

// Stop checking after max attempts
if (authCheckAttempts > MAX_AUTH_CHECK_ATTEMPTS) {
console.log('Auth check timeout after', MAX_AUTH_CHECK_ATTEMPTS, 'attempts');
stopAuthCheck();
return;
}
Expand All @@ -442,18 +435,15 @@ function startAuthCheck() {
if (result.success) {
clearInterval(authCheckInterval);
authCheckInterval = null;
console.log('Authentication successful via localStorage polling');

// Notify popup if it's open
try {
chrome.runtime.sendMessage({ type: 'AUTH_SUCCESS' });
} catch (e) {
// Popup might not be open, that's ok
console.log('Could not notify popup:', e.message);
}
} else if (result.error && result.error.includes('Cannot access')) {
// If we get access errors, reduce polling frequency
console.log('Access error during auth check, slowing down polling');
}
} catch (error) {
console.error('Error during auth check:', error);
Expand Down Expand Up @@ -491,10 +481,8 @@ function checkAuth() {

// Listen for messages from popup or content scripts
chrome.runtime.onMessage.addListener((message, sender, sendResponse) => {
console.log('Internal message received:', message);
if (message.type === 'CHECK_AUTH') {
checkAuth().then(result => {
console.log('Auth check result:', result);

// If not authenticated, try checking localStorage as fallback
if (!result.isAuthenticated) {
Expand All @@ -509,8 +497,6 @@ chrome.runtime.onMessage.addListener((message, sender, sendResponse) => {
// Only start periodic checking if we don't have access errors
if (!localResult.error || !localResult.error.includes('Cannot access')) {
startAuthCheck();
} else {
console.log('Skipping periodic auth check due to access restrictions');
}
}
});
Expand Down Expand Up @@ -541,10 +527,9 @@ chrome.runtime.onMessage.addListener((message, sender, sendResponse) => {
}
// Handle logout request
if (message.type === 'LOGOUT') {
chrome.storage.local.remove(['zecryptToken', 'zecryptWorkspaceId', 'zecryptProjectId', 'zecryptProjectAesKey'], () => {
console.log('Tokens and project key removed');
sendResponse({ success: true });
});
chrome.storage.local.remove(['zecryptToken', 'zecryptWorkspaceId', 'zecryptProjectId', 'zecryptProjectAesKey'], () => {
sendResponse({ success: true });
});
return true;
}

Expand All @@ -555,12 +540,9 @@ chrome.runtime.onMessage.addListener((message, sender, sendResponse) => {
zecryptWorkspaceId: message.workspaceId,
zecryptProjectId: message.projectId
}, async () => {
console.log('Token and workspace data stored successfully from popup');

// Store project AES key securely if provided
if (message.projectAesKey) {
await storeProjectAesKey(message.projectAesKey);
console.log('Project AES key stored successfully from popup');
}

sendResponse({ success: true });
Expand Down Expand Up @@ -630,5 +612,5 @@ chrome.runtime.onMessage.addListener((message, sender, sendResponse) => {

// Initialize when the extension is installed or updated
chrome.runtime.onInstalled.addListener(() => {
console.log('Zecrypt extension installed');
// Extension installed
});
Loading
Loading