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
5 changes: 4 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ Fluently is a cross-platform, open-source educational system for learning Englis
- 📈 Progress tracking
- 🧠 Adaptive learning based on user goals

**Platforms:** Android, iOS, Telegram Bot
**Platforms:** Android, iOS, Telegram Bot, Chrome Extension

## Links

Expand All @@ -19,6 +19,9 @@ https://fluently-app.ru
Telegram Bot
http://t.me/FluentlyInEnglishBot

Chrome Extension
[Installation guide here](web-extension/README.md)

Terms of Use
https://fluently-app.ru/terms

Expand Down
43 changes: 37 additions & 6 deletions frontend-website/auth-success.html
Original file line number Diff line number Diff line change
Expand Up @@ -214,6 +214,16 @@ <h1 class="success-title">Authentication Successful!</h1>
// Clean URL parameters
window.history.replaceState({}, document.title, '/auth-success.html');

// Notify extension about successful authentication
console.log('Notifying extension about auth success...');
setTimeout(() => {
window.postMessage({
type: 'AUTH_SUCCESS',
token: accessToken,
email: email
}, '*');
}, 500);

// Auto-close after 5 seconds if opened from extension
setTimeout(() => {
if (window.opener || window.name === 'fluently_auth') {
Expand All @@ -238,17 +248,38 @@ <h1 class="success-title">Authentication Successful!</h1>
});

function closeWindow() {
console.log('Closing window and notifying extension...');

// Get the stored user data
const userData = localStorage.getItem('fluently_user');
const accessToken = localStorage.getItem('fluently_access_token');

// Send message to extension if opened from it
if (window.opener) {
window.opener.postMessage({ type: 'AUTH_SUCCESS' }, '*');
const authData = {
type: 'AUTH_SUCCESS',
token: accessToken,
email: userData ? JSON.parse(userData).email : null
};
console.log('Sending auth data to opener:', authData);
window.opener.postMessage(authData, '*');
}

// Also try to communicate with extension via window messaging
window.postMessage({
type: 'AUTH_SUCCESS',
token: accessToken,
email: userData ? JSON.parse(userData).email : null
}, '*');

// Close window or redirect
if (window.name === 'fluently_auth') {
window.close();
} else {
window.location.href = '/index.html';
}
setTimeout(() => {
if (window.name === 'fluently_auth' || window.opener) {
window.close();
} else {
window.location.href = '/index.html';
}
}, 1000);
}
</script>
</body>
Expand Down
111 changes: 111 additions & 0 deletions web-extension/DEBUG_GUIDE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
# Fluently Chrome Extension - Authentication Debug Guide

## Recent Fixes Applied

### Issues Identified:
1. **localStorage key mismatch**: Auth page stored `fluently_access_token` but extension looked for `accessToken`
2. **Content script communication**: Message passing between auth page and extension was broken
3. **Manifest permissions**: Missing required permissions for proper operation
4. **Authentication flow**: Extension didn't properly detect auth success

### Fixes Applied:

#### 1. Updated `content.js`:
- Added proper localStorage key detection for both `fluently_user` and `fluently_access_token`
- Added message listener for `AUTH_SUCCESS` from auth page
- Added automatic detection when on auth-success page
- Added comprehensive logging for debugging

#### 2. Updated `manifest.json`:
- Added `scripting` and `tabs` permissions
- Fixed content script injection to only run on auth-success pages
- Set `run_at: "document_end"` for proper timing

#### 3. Updated `background.js`:
- Added proper logging and error handling
- Improved tab closing logic to handle both auth and auth-success tabs
- Added async response handling

#### 4. Updated `popup.js`:
- Improved auth tab detection to specifically look for auth-success pages
- Added longer timeout for content script communication
- Added proper cleanup of event listeners

#### 5. Updated `auth-success.html`:
- Added automatic notification to extension on page load
- Improved window messaging with actual token data
- Added better logging for debugging

## Testing Steps:

### 1. Load the Extension:
1. Open Chrome and go to `chrome://extensions/`
2. Enable "Developer mode"
3. Click "Load unpacked" and select the `web-extension` folder
4. Note the extension ID for debugging

### 2. Test Authentication:
1. Click the extension icon to open popup
2. Click "Login with Google"
3. Complete Google authentication
4. Check if extension popup shows authenticated state

### 3. Debug with Console:
1. Open extension popup
2. Right-click and select "Inspect" to open DevTools
3. Check Console tab for logs
4. For background script logs: go to `chrome://extensions/`, click "service worker" link

### 4. Check Storage:
1. In extension DevTools, go to Application tab
2. Look at Local Storage for the extension
3. Should see `accessToken` and `userEmail` keys

## Common Issues and Solutions:

### Extension Doesn't Detect Authentication:
- Check if content script is injected: DevTools → Sources → Content Scripts
- Verify localStorage contains the correct keys
- Check console for error messages

### Authentication Page Doesn't Close:
- Verify extension has `tabs` permission
- Check background script console for tab closing errors

### Token Not Saved:
- Check if `chrome.storage.local` is working
- Verify extension has `storage` permission
- Check for JavaScript errors in popup

## Debug Commands:

### Check Extension Storage:
```javascript
// In extension popup console
chrome.storage.local.get(['accessToken', 'userEmail'], console.log);
```

### Check Page LocalStorage:
```javascript
// In auth-success page console
console.log('User data:', localStorage.getItem('fluently_user'));
console.log('Token:', localStorage.getItem('fluently_access_token'));
```

### Test Content Script Communication:
```javascript
// In auth-success page console
window.postMessage({ type: 'AUTH_SUCCESS', token: 'test', email: 'test@example.com' }, '*');
```

## Expected Logs:

### Successful Flow:
1. Popup: "Starting login process..."
2. Content: "Fluently extension content script loaded on: https://fluently-app.ru/auth-success.html"
3. Content: "Received AUTH_SUCCESS message"
4. Background: "Background received message: {action: 'authCompleted', ...}"
5. Background: "Auth data saved to storage"
6. Popup: Shows authenticated state

If any of these logs are missing, that indicates where the issue is occurring.
169 changes: 161 additions & 8 deletions web-extension/background.js
Original file line number Diff line number Diff line change
@@ -1,18 +1,171 @@
// Background service worker
console.log('Background script loaded');

const AUTH_URL = 'https://fluently-app.ru/auth/google';
let authInProgress = false;

chrome.runtime.onMessage.addListener(function(request, sender, sendResponse) {
console.log('Background received message:', request);

if (request.action === 'startAuth') {
console.log('Starting authentication flow...');

// Prevent multiple auth attempts
if (authInProgress) {
console.log('Auth already in progress, ignoring duplicate request');
sendResponse({ success: false, error: 'Authentication already in progress' });
return;
}

authInProgress = true;

// Check if tabs API is available
if (!chrome || !chrome.tabs) {
console.error('Chrome tabs API not available in background!');
authInProgress = false;
sendResponse({ success: false, error: 'Tabs API not available' });
return;
}

// Open auth page in a new tab
chrome.tabs.create({
url: AUTH_URL,
active: true
}, function(tab) {
if (chrome.runtime.lastError) {
console.error('Failed to create auth tab:', chrome.runtime.lastError);
authInProgress = false;
sendResponse({ success: false, error: chrome.runtime.lastError.message });
return;
}

console.log('Auth tab created:', tab.id);

// Set up a listener for when the tab is updated
const listener = function(tabId, changeInfo, updatedTab) {
if (tabId === tab.id && changeInfo.status === 'complete') {
console.log('Auth tab updated:', updatedTab.url);

// Check if we're on the auth-success page
if (updatedTab.url && updatedTab.url.includes('auth-success')) {
console.log('Detected auth success page, waiting for token...');

// Wait a bit for the content script to process
setTimeout(() => {
chrome.tabs.sendMessage(tabId, { action: 'getAuthToken' }, function(response) {
if (chrome.runtime.lastError) {
console.log('Error getting auth token:', chrome.runtime.lastError.message);
return;
}

if (response && response.token) {
console.log('Got token from content script:', !!response.token);

// Save the auth token
saveAuthTokenInBackground(response.token, response.email);

// Close the auth tab
chrome.tabs.remove(tabId);
chrome.tabs.onUpdated.removeListener(listener);
authInProgress = false;
} else {
console.log('No token received from content script');
// Don't reset authInProgress here, let it timeout
}
});
}, 2000);
}
}
};

if (chrome.tabs.onUpdated) {
chrome.tabs.onUpdated.addListener(listener);

// Clean up listener after 5 minutes to prevent memory leaks
setTimeout(() => {
chrome.tabs.onUpdated.removeListener(listener);
authInProgress = false; // Reset auth flag on timeout
}, 300000);
} else {
console.error('tabs.onUpdated not available in background');
authInProgress = false;
sendResponse({ success: false, error: 'Cannot listen for tab updates' });
return;
}

sendResponse({ success: true, tabId: tab.id });
});

return true; // Keep message channel open for async response
}

if (request.action === 'authCompleted') {
// Store the auth data
chrome.storage.local.set({
accessToken: request.token,
userEmail: request.email
}, function() {
// Close the auth tab if it's still open
chrome.tabs.query({ url: 'https://fluently-app.ru/auth/*' }, function(tabs) {
console.log('Processing auth completion with token:', !!request.token);
saveAuthTokenInBackground(request.token, request.email);
sendResponse({ success: true });
}

return true; // Keep message channel open for async response
});

// Function to save auth token in background script
function saveAuthTokenInBackground(token, email) {
console.log('Saving auth token in background...', { token: !!token, email });

// Test if chrome.storage is available
if (!chrome || !chrome.storage) {
console.error('Chrome storage API not available in background!');
return;
}

// Store the auth data
chrome.storage.local.set({
accessToken: token,
userEmail: email
}, function() {
if (chrome.runtime.lastError) {
console.error('Error saving to storage in background:', chrome.runtime.lastError);
return;
}

console.log('Auth data saved to storage successfully in background');

// Test if chrome.tabs is available
if (!chrome.tabs) {
console.error('Chrome tabs API not available!');
return;
}

// Close auth-related tabs
chrome.tabs.query({ url: 'https://fluently-app.ru/auth*' }, function(tabs) {
if (chrome.runtime.lastError) {
console.error('Error querying tabs:', chrome.runtime.lastError);
} else {
tabs.forEach(tab => {
console.log('Closing auth tab:', tab.id);
chrome.tabs.remove(tab.id);
});
});
}
});

// Also close auth-success tabs
chrome.tabs.query({ url: 'https://fluently-app.ru/auth-success*' }, function(tabs) {
if (chrome.runtime.lastError) {
console.error('Error querying auth-success tabs:', chrome.runtime.lastError);
} else {
tabs.forEach(tab => {
console.log('Closing auth-success tab:', tab.id);
chrome.tabs.remove(tab.id);
});
}
});
});
}

// Handle extension installation
chrome.runtime.onInstalled.addListener(function(details) {
if (details.reason === 'install') {
console.log('Fluently Word Learner extension installed');
}
});

Expand Down
Loading