Sure! Pl
This commit is contained in:
419
Extension/background/service-worker.js
Normal file
419
Extension/background/service-worker.js
Normal file
@@ -0,0 +1,419 @@
|
||||
// EShip Extension - Background Service Worker
|
||||
// Handles Appwrite authentication and message passing
|
||||
|
||||
console.log('[SW] Service Worker starting...');
|
||||
|
||||
// Define APPWRITE_CONFIG directly (fallback if config.js fails to load)
|
||||
var APPWRITE_CONFIG = {
|
||||
endpoint: 'https://appwrite.webklar.com/v1',
|
||||
projectId: '696b82bb0036d2e547ad',
|
||||
apiKey: 'standard_d48c6eebe825b55e685d8e66ea056161105470702da77b730aca08c106ffbadfa2375ff675dbe9e01d7bb72b4a9fa001ff7c365b73759bc5fb3da432c3cd9cee1151e67517e9838d1f96f942d9891ce66ddc6f11c0fdd67a24f7c84e0fa9999a74dacf2c6aa3533998c177f190fc87ffb5a30b27474be21aece4c70d71d205ba'
|
||||
};
|
||||
|
||||
// Global state
|
||||
let client, account;
|
||||
let scriptsLoaded = false;
|
||||
let initError = null;
|
||||
let DEFAULT_TOOLS = [
|
||||
{
|
||||
id: 'highlight_prices',
|
||||
name: 'Preise hervorheben',
|
||||
enabled: false,
|
||||
settings: {
|
||||
selector: '.price',
|
||||
borderColor: '#ff0000',
|
||||
borderWidth: '2px'
|
||||
}
|
||||
}
|
||||
];
|
||||
|
||||
// Register message listener FIRST - before any initialization
|
||||
chrome.runtime.onMessage.addListener((request, sender, sendResponse) => {
|
||||
console.log('[SW] Message received:', request.action);
|
||||
|
||||
// PING handler - synchronous response
|
||||
if (request.action === 'PING') {
|
||||
console.log('[SW] PING received, responding');
|
||||
sendResponse({ success: true, message: 'Service Worker is alive' });
|
||||
return false; // Synchronous response
|
||||
}
|
||||
|
||||
// Handle other messages asynchronously
|
||||
(async () => {
|
||||
try {
|
||||
// Ensure scripts are loaded (synchronous operation)
|
||||
if (!scriptsLoaded) {
|
||||
loadScripts();
|
||||
}
|
||||
|
||||
// Ensure Appwrite is initialized
|
||||
if (!client || !account) {
|
||||
initAppwrite();
|
||||
}
|
||||
|
||||
// Handle the message
|
||||
const response = await handleMessage(request, sender);
|
||||
console.log('[SW] Sending response:', response);
|
||||
sendResponse(response);
|
||||
} catch (error) {
|
||||
console.error('[SW] Error handling message:', error);
|
||||
sendResponse({
|
||||
success: false,
|
||||
error: error.message || 'Unbekannter Fehler'
|
||||
});
|
||||
}
|
||||
})();
|
||||
|
||||
return true; // Keep channel open for async
|
||||
});
|
||||
|
||||
// Load scripts - try relative path first, then fallback to inline
|
||||
function loadScripts() {
|
||||
if (scriptsLoaded) return;
|
||||
|
||||
try {
|
||||
console.log('[SW] Loading scripts...');
|
||||
|
||||
// Try loading config first (smaller file) - will override default if successful
|
||||
try {
|
||||
importScripts('../config.js');
|
||||
console.log('[SW] config.js loaded (overriding default)');
|
||||
} catch (e) {
|
||||
console.error('[SW] Failed to load config.js:', e);
|
||||
console.log('[SW] Using default inline config');
|
||||
}
|
||||
|
||||
// Try loading Appwrite SDK
|
||||
try {
|
||||
importScripts('../lib/appwrite.min.js');
|
||||
console.log('[SW] appwrite.min.js loaded via importScripts');
|
||||
} catch (e) {
|
||||
console.error('[SW] Failed to load appwrite.min.js via importScripts:', e);
|
||||
// Load Appwrite SDK inline
|
||||
loadAppwriteSDKInline();
|
||||
console.log('[SW] appwrite.min.js loaded inline');
|
||||
}
|
||||
|
||||
scriptsLoaded = true;
|
||||
console.log('[SW] Scripts loaded successfully');
|
||||
} catch (error) {
|
||||
console.error('[SW] Failed to load scripts:', error);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
// Load Appwrite SDK inline if importScripts fails
|
||||
function loadAppwriteSDKInline() {
|
||||
if (typeof Appwrite !== 'undefined') return;
|
||||
|
||||
(function(global) {
|
||||
'use strict';
|
||||
const Appwrite = {};
|
||||
|
||||
class Client {
|
||||
constructor() {
|
||||
this.config = { endpoint: 'https://appwrite.webklar.com/v1', project: '' };
|
||||
this.headers = {
|
||||
'content-type': 'application/json',
|
||||
'x-sdk-name': 'Chrome Extension',
|
||||
'x-sdk-platform': 'client',
|
||||
'x-sdk-language': 'web',
|
||||
'x-sdk-version': '21.0.0',
|
||||
};
|
||||
}
|
||||
setEndpoint(endpoint) { this.config.endpoint = endpoint; return this; }
|
||||
setProject(project) { this.config.project = project; this.headers['x-appwrite-project'] = project; return this; }
|
||||
setKey(key) { if (key) this.headers['x-appwrite-key'] = key; else delete this.headers['x-appwrite-key']; return this; }
|
||||
async call(method, path, headers = {}, params = {}) {
|
||||
const url = new URL(this.config.endpoint + path);
|
||||
const options = { method: method.toUpperCase(), headers: { ...this.headers, ...headers }, credentials: 'include' };
|
||||
if (method === 'GET') {
|
||||
for (const [key, value] of Object.entries(params)) {
|
||||
if (value !== undefined) url.searchParams.append(key, value);
|
||||
}
|
||||
} else {
|
||||
options.body = JSON.stringify(params);
|
||||
}
|
||||
const response = await fetch(url.toString(), options);
|
||||
const contentType = response.headers.get('content-type') || '';
|
||||
let data = contentType.includes('application/json') ? await response.json() : await response.text();
|
||||
if (response.status >= 400) {
|
||||
throw new AppwriteException(data.message || 'Unknown error', response.status, data.type || '', data);
|
||||
}
|
||||
return data;
|
||||
}
|
||||
}
|
||||
|
||||
class Account {
|
||||
constructor(client) { this.client = client; }
|
||||
async get() { return await this.client.call('GET', '/account'); }
|
||||
async createEmailPasswordSession(email, password) {
|
||||
return await this.client.call('POST', '/account/sessions/email', {}, { email, password });
|
||||
}
|
||||
async deleteSession(sessionId) { return await this.client.call('DELETE', `/account/sessions/${sessionId}`); }
|
||||
async getSession(sessionId) { return await this.client.call('GET', `/account/sessions/${sessionId}`); }
|
||||
}
|
||||
|
||||
class AppwriteException extends Error {
|
||||
constructor(message, code = 0, type = '', response = null) {
|
||||
super(message);
|
||||
this.name = 'AppwriteException';
|
||||
this.code = code;
|
||||
this.type = type;
|
||||
this.response = response;
|
||||
}
|
||||
}
|
||||
|
||||
Appwrite.Client = Client;
|
||||
Appwrite.Account = Account;
|
||||
Appwrite.AppwriteException = AppwriteException;
|
||||
global.Appwrite = Appwrite;
|
||||
})(typeof self !== 'undefined' ? self : this);
|
||||
}
|
||||
|
||||
// Initialize Appwrite
|
||||
// Note: For user authentication, we don't use API key (only for server operations)
|
||||
function initAppwrite() {
|
||||
try {
|
||||
if (!scriptsLoaded) {
|
||||
throw new Error('Scripts nicht geladen');
|
||||
}
|
||||
if (typeof Appwrite === 'undefined') {
|
||||
throw new Error('Appwrite SDK nicht geladen');
|
||||
}
|
||||
|
||||
// APPWRITE_CONFIG should be available (defined at top of file or loaded from config.js)
|
||||
if (typeof APPWRITE_CONFIG === 'undefined') {
|
||||
throw new Error('APPWRITE_CONFIG nicht definiert');
|
||||
}
|
||||
|
||||
const config = APPWRITE_CONFIG;
|
||||
console.log('[SW] Using config:', {
|
||||
endpoint: config.endpoint,
|
||||
projectId: config.projectId
|
||||
});
|
||||
|
||||
// Initialize client WITHOUT API key for user authentication
|
||||
// API key is only for server-side operations, not user login
|
||||
client = new Appwrite.Client();
|
||||
client
|
||||
.setEndpoint(config.endpoint)
|
||||
.setProject(config.projectId);
|
||||
// Do NOT set API key here - it conflicts with user sessions
|
||||
|
||||
console.log('[SW] Client configured with project:', config.projectId);
|
||||
console.log('[SW] Note: API Key not set (only for server operations, not user auth)');
|
||||
|
||||
account = new Appwrite.Account(client);
|
||||
initError = null;
|
||||
console.log('[SW] Appwrite Client initialized (session-based, no API key)');
|
||||
return true;
|
||||
} catch (error) {
|
||||
console.error('[SW] Failed to initialize Appwrite:', error);
|
||||
initError = error.message;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Handle messages
|
||||
async function handleMessage(request, sender) {
|
||||
switch (request.action) {
|
||||
case 'CHECK_AUTH':
|
||||
return await checkAuth();
|
||||
|
||||
case 'LOGIN':
|
||||
return await login(request.email, request.password);
|
||||
|
||||
case 'LOGOUT':
|
||||
return await logout();
|
||||
|
||||
case 'GET_USER':
|
||||
return await getUser();
|
||||
|
||||
case 'GET_SETTINGS':
|
||||
return await getSettings();
|
||||
|
||||
case 'SAVE_SETTINGS':
|
||||
return await saveSettings(request.settings);
|
||||
|
||||
case 'GET_SESSION':
|
||||
return await getSession();
|
||||
|
||||
default:
|
||||
return { success: false, error: 'Unknown action: ' + request.action };
|
||||
}
|
||||
}
|
||||
|
||||
// Check if user is authenticated
|
||||
async function checkAuth() {
|
||||
try {
|
||||
// Check if we have a stored session
|
||||
const stored = await chrome.storage.local.get(['session']);
|
||||
if (!stored.session || !stored.session.sessionToken) {
|
||||
return { success: true, authenticated: false, user: null };
|
||||
}
|
||||
|
||||
// Verify session with API server
|
||||
const API_SERVER_URL = 'http://localhost:3001';
|
||||
try {
|
||||
const response = await fetch(`${API_SERVER_URL}/api/extension/auth`, {
|
||||
method: 'GET',
|
||||
headers: {
|
||||
'x-session-token': stored.session.sessionToken
|
||||
}
|
||||
});
|
||||
const data = await response.json();
|
||||
|
||||
if (data.success && data.authenticated) {
|
||||
return { success: true, authenticated: true, user: data.user };
|
||||
}
|
||||
} catch (e) {
|
||||
console.log('[SW] API server check failed:', e.message);
|
||||
}
|
||||
|
||||
return { success: true, authenticated: false, user: null };
|
||||
} catch (error) {
|
||||
console.log('[SW] Auth check failed:', error.message);
|
||||
return { success: true, authenticated: false, user: null };
|
||||
}
|
||||
}
|
||||
|
||||
// Login with email and password
|
||||
// Uses API server proxy to avoid platform registration issues
|
||||
async function login(email, password) {
|
||||
try {
|
||||
console.log('[SW] Attempting login for:', email);
|
||||
|
||||
// Use API server instead of direct Appwrite call
|
||||
// This avoids the need to register Extension ID as platform
|
||||
const API_SERVER_URL = 'http://localhost:3001';
|
||||
|
||||
const response = await fetch(`${API_SERVER_URL}/api/extension/login`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
body: JSON.stringify({ email, password })
|
||||
});
|
||||
|
||||
const data = await response.json();
|
||||
|
||||
if (!data.success) {
|
||||
throw new Error(data.error || 'Login fehlgeschlagen');
|
||||
}
|
||||
|
||||
// Store session info including token
|
||||
await chrome.storage.local.set({
|
||||
session: {
|
||||
userId: data.user.$id,
|
||||
sessionId: data.session.$id,
|
||||
sessionToken: data.session.token || data.session.$id,
|
||||
expire: data.session.expire
|
||||
}
|
||||
});
|
||||
|
||||
console.log('[SW] Login successful for:', data.user.email);
|
||||
|
||||
// Initialize Appwrite client with session for future requests
|
||||
if (!client || !account) {
|
||||
initAppwrite();
|
||||
}
|
||||
|
||||
return { success: true, user: data.user, session: data.session };
|
||||
} catch (error) {
|
||||
console.error('[SW] Login error:', error);
|
||||
return { success: false, error: error.message || 'Login fehlgeschlagen' };
|
||||
}
|
||||
}
|
||||
|
||||
// Logout
|
||||
async function logout() {
|
||||
try {
|
||||
// Get session token
|
||||
const stored = await chrome.storage.local.get(['session']);
|
||||
const sessionToken = stored.session?.sessionToken;
|
||||
|
||||
if (sessionToken) {
|
||||
// Logout via API server
|
||||
const API_SERVER_URL = 'http://localhost:3001';
|
||||
try {
|
||||
await fetch(`${API_SERVER_URL}/api/extension/logout`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'x-session-token': sessionToken
|
||||
}
|
||||
});
|
||||
} catch (e) {
|
||||
// Ignore errors
|
||||
}
|
||||
}
|
||||
|
||||
await chrome.storage.local.remove(['session']);
|
||||
return { success: true };
|
||||
} catch (error) {
|
||||
await chrome.storage.local.remove(['session']);
|
||||
return { success: true };
|
||||
}
|
||||
}
|
||||
|
||||
// Get current user
|
||||
async function getUser() {
|
||||
try {
|
||||
const user = await account.get();
|
||||
return { success: true, user };
|
||||
} catch (error) {
|
||||
return { success: false, error: error.message };
|
||||
}
|
||||
}
|
||||
|
||||
// Get session
|
||||
async function getSession() {
|
||||
try {
|
||||
const session = await account.getSession('current');
|
||||
return { success: true, session };
|
||||
} catch (error) {
|
||||
return { success: false, error: error.message };
|
||||
}
|
||||
}
|
||||
|
||||
// Get tool settings
|
||||
async function getSettings() {
|
||||
try {
|
||||
const result = await chrome.storage.sync.get(['tools']);
|
||||
const tools = result.tools || DEFAULT_TOOLS;
|
||||
return { success: true, tools };
|
||||
} catch (error) {
|
||||
return { success: true, tools: DEFAULT_TOOLS };
|
||||
}
|
||||
}
|
||||
|
||||
// Save tool settings
|
||||
async function saveSettings(tools) {
|
||||
try {
|
||||
await chrome.storage.sync.set({ tools });
|
||||
|
||||
// Notify content scripts
|
||||
const tabs = await chrome.tabs.query({ url: ['http://localhost:5173/*', 'http://localhost:3000/*'] });
|
||||
for (const tab of tabs) {
|
||||
try {
|
||||
await chrome.tabs.sendMessage(tab.id, { action: 'SETTINGS_UPDATED', tools });
|
||||
} catch (e) {
|
||||
// Tab might not have content script
|
||||
}
|
||||
}
|
||||
|
||||
return { success: true };
|
||||
} catch (error) {
|
||||
return { success: false, error: error.message };
|
||||
}
|
||||
}
|
||||
|
||||
// Initialize on install
|
||||
chrome.runtime.onInstalled.addListener(async (details) => {
|
||||
if (details.reason === 'install') {
|
||||
await chrome.storage.sync.set({ tools: DEFAULT_TOOLS });
|
||||
console.log('[SW] Extension installed');
|
||||
}
|
||||
});
|
||||
|
||||
console.log('[SW] Service Worker ready');
|
||||
Reference in New Issue
Block a user