-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #13 from wsg-ariadne/v0.1.1
v0.1.1
- Loading branch information
Showing
29 changed files
with
868 additions
and
264 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
import { ApiPost } from "./request"; | ||
|
||
export const classifyText = (text, callback) => { | ||
ApiPost('/classify/text', { text }, callback, () => { | ||
console.error('api/calliope: Could not classify cookie banner text'); | ||
}); | ||
}; | ||
|
||
export const classifyImage = (imageData, callback) => { | ||
ApiPost('/classify/image', { image_data: imageData }, callback, () => { | ||
console.error('api/janus: Could not classify cookie banner screenshot'); | ||
}); | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
const baseUrl = import.meta.env.VITE_API_URL + '/api/v1'; | ||
|
||
export const ApiGet = (endpoint, callback, errorCallback) => { | ||
if (typeof callback !== 'function') { | ||
console.error('api/request(ApiGet): Expected function callback, got ' + typeof callback); | ||
} | ||
|
||
fetch(baseUrl + endpoint, { | ||
method: 'GET' | ||
}).then((response) => response.json()) | ||
.then((data) => callback(data)) | ||
.catch((error) => { | ||
console.error('api/request(ApiGet) Error fetching ' + endpoint + ':', error); | ||
if (typeof errorCallback === 'function') errorCallback(error); | ||
}); | ||
} | ||
|
||
export const ApiPost = (endpoint, body, callback, errorCallback) => { | ||
if (typeof callback !== 'function') { | ||
console.error('api/request(ApiPost): Expected function callback, got ' + typeof callback); | ||
} | ||
|
||
fetch(baseUrl + endpoint, { | ||
method: 'POST', | ||
headers: { | ||
'Content-Type': 'application/json' | ||
}, | ||
body: JSON.stringify(body) | ||
}).then((response) => response.json()) | ||
.then((data) => callback(data)) | ||
.catch((error) => { | ||
console.error('api/request(ApiPost) Error fetching ' + endpoint + ':', error); | ||
if (typeof errorCallback === 'function') errorCallback(error); | ||
}); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
import { ApiPost } from './request'; | ||
import { updateBadgeText } from '../browser/badge'; | ||
import { setTransaction } from '../browser/storage'; | ||
|
||
export const getStats = (tabUrl, successCallback, errorCallback) => { | ||
ApiPost('/reports/by-url', {'page_url': tabUrl}, (data) => { | ||
console.log('api/stats: Got stats for URL ' + tabUrl + ':', data); | ||
setTransaction('stats', { | ||
url: tabUrl, | ||
stats: data | ||
}).then(() => { | ||
updateBadgeText(data); | ||
if (successCallback !== undefined) successCallback(data); | ||
}).catch((e) => errorCallback(e)) | ||
}, errorCallback); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,175 +1,10 @@ | ||
import * as browser from 'webextension-polyfill'; | ||
|
||
class AriadneBackground { | ||
constructor() { | ||
this._tabStates = []; | ||
this._reportStats = {}; | ||
this._API_URL = import.meta.env.VITE_API_URL + '/api/v1'; | ||
|
||
// Alias if browser.action is defined, i.e. in Manifest V3 | ||
this.BrowserAction = browser.browserAction; | ||
if (browser.action !== undefined) { | ||
this.BrowserAction = browser.action; | ||
} | ||
} | ||
|
||
addListeners() { | ||
// Update badge on tab change | ||
browser.tabs.onActivated.addListener((activeInfo) => { | ||
// Get URL of active tab | ||
browser.tabs.get(activeInfo.tabId) | ||
.then((tab) => { | ||
console.log('[bg] Tab changed to', tab.url); | ||
this.toggleBadge(this._tabStates[activeInfo.tabId]); | ||
this.updateBadgeText(this._reportStats[tab.url]); | ||
this.getStats(tab.url); | ||
}); | ||
}); | ||
|
||
// Tab URL change listener | ||
browser.tabs.onUpdated.addListener((tabId, changeInfo, _) => { | ||
if (changeInfo.url) { | ||
// Request fresh stats | ||
console.log('[bg] Tab ' + tabId + ' URL changed to', changeInfo.url); | ||
this.getStats(changeInfo.url); | ||
} | ||
}); | ||
|
||
// Message listeners | ||
browser.runtime.onMessage.addListener((request, sender, sendResponse) => { | ||
console.log("[bg] Received message with action", request.action); | ||
if (request.action === "updateBadge") { | ||
// Listen to updateBadge requests | ||
this.toggleBadge(request.args.enabled); | ||
|
||
// Update the tab state | ||
this._tabStates[sender.tab.id] = request.args.enabled; | ||
} else if (request.action === "detection") { | ||
// Listen to detection requests from content scripts | ||
const cookieBannerText = request.args.body; | ||
console.log('[bg] Detection request received from tab', sender.tab.id, 'with body:', cookieBannerText); | ||
|
||
// POST to API | ||
fetch(this._API_URL + '/classify/text', { | ||
method: 'POST', | ||
body: JSON.stringify({ | ||
text: cookieBannerText | ||
}), | ||
headers: { | ||
'Content-Type': 'application/json' | ||
} | ||
}).then((response) => response.json()) | ||
.then((data) => { | ||
console.log('[bg] Detection result from API:', data); | ||
sendResponse(data); | ||
}); | ||
} else if (request.action === "visualDetection") { | ||
// Listen to visual detection requests from content scripts | ||
const imageData = request.args.screenshot; | ||
console.log('[bg] Visual detection request received from tab', sender.tab.id); | ||
|
||
// POST to API | ||
fetch(this._API_URL + '/classify/image', { | ||
method: 'POST', | ||
body: JSON.stringify({ | ||
image_data: imageData | ||
}), | ||
headers: { | ||
'Content-Type': 'application/json' | ||
} | ||
}).then((response) => response.json()) | ||
.then((data) => { | ||
console.log('[bg] Detection result from API:', data); | ||
sendResponse(data); | ||
}); | ||
} else if (request.action === "requestStats") { | ||
console.log("[bg] Received stats request from popup", request, sender); | ||
|
||
// If we have cached stats, send them before requesting new ones | ||
const tabUrl = request.args.url; | ||
let deferSending = false; | ||
if (this._reportStats[tabUrl]) { | ||
console.log("[bg] Sending cached stats to tab", tabUrl, this._reportStats[tabUrl]); | ||
sendResponse(this._reportStats[tabUrl]); | ||
deferSending = true; | ||
} | ||
|
||
this.getStats(tabUrl, (stats) => { | ||
if (!deferSending) { | ||
console.log('[bg] Sending stats to tab', tabUrl, this._reportStats[tabUrl]) | ||
sendResponse(stats); | ||
} else { | ||
console.log('[bg] Revalidated cache for tab', tabUrl, this._reportStats[tabUrl]) | ||
} | ||
}, (error) => { | ||
sendResponse({ | ||
success: false, | ||
error | ||
}); | ||
}); | ||
} | ||
|
||
return true; | ||
}); | ||
} | ||
|
||
toggleBadge(state) { | ||
if (state) { | ||
this.BrowserAction.setBadgeBackgroundColor({ | ||
color: "#B677FA", | ||
}); | ||
} else { | ||
this.BrowserAction.setBadgeBackgroundColor({ | ||
color: "#2A272A", | ||
}); | ||
} | ||
} | ||
|
||
updateBadgeText(stats) { | ||
console.log('[bg] Updating badge text with stats:', stats); | ||
if (stats !== undefined && stats.hasOwnProperty("success") && | ||
stats.hasOwnProperty("specific_reports") && stats["success"]) { | ||
const count = stats.specific_reports.count; | ||
console.log('[bg] Badge count:', count) | ||
if (count > 0) { | ||
this.BrowserAction.setBadgeText({ | ||
text: count.toString(), | ||
}); | ||
return; | ||
} | ||
} | ||
this.BrowserAction.setBadgeText({ | ||
text: "0", | ||
}); | ||
} | ||
|
||
getStats(tabUrl, successCallback, errorCallback) { | ||
fetch(this._API_URL + '/reports/by-url', { | ||
method: 'POST', | ||
headers: { | ||
'Content-Type': 'application/json' | ||
}, | ||
body: JSON.stringify({ | ||
'page_url': tabUrl | ||
}) | ||
}) | ||
.then((response) => response.json()) | ||
.then((data) => { | ||
console.log('[bg] Report stats from API:', data); | ||
this._reportStats[tabUrl] = data; | ||
|
||
// Update badge text | ||
this.updateBadgeText(data); | ||
|
||
if (successCallback !== undefined) successCallback(data); | ||
}) | ||
.catch((error) => { | ||
console.error('[bg] Error fetching report stats:', error); | ||
if (errorCallback !== undefined) errorCallback(error); | ||
} | ||
); | ||
} | ||
} | ||
|
||
const ariadneBackground = new AriadneBackground(); | ||
ariadneBackground.addListeners(); | ||
import { | ||
messageListener, | ||
tabChangeListener, | ||
tabUrlChangeListener | ||
} from './listeners'; | ||
|
||
browser.runtime.onMessage.addListener(messageListener); | ||
browser.tabs.onActivated.addListener(tabChangeListener); | ||
browser.tabs.onUpdated.addListener(tabUrlChangeListener); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
import { getAction } from './getAction'; | ||
|
||
const action = getAction(); | ||
|
||
export const toggleBadge = (state) => { | ||
if (state) { | ||
action.setBadgeBackgroundColor({ | ||
color: "#B677FA", | ||
}); | ||
} else { | ||
action.setBadgeBackgroundColor({ | ||
color: "#2A272A", | ||
}); | ||
} | ||
} | ||
|
||
export const updateBadgeText = (stats) => { | ||
console.log('browser/badge: Updating badge text with stats:', stats); | ||
if (stats !== undefined && stats.hasOwnProperty("success") && | ||
stats.hasOwnProperty("specific_reports") && stats["success"]) { | ||
const count = stats.specific_reports.count; | ||
console.log('browser/badge: Badge count:', count) | ||
if (count > 0) { | ||
action.setBadgeText({ | ||
text: count.toString(), | ||
}); | ||
return; | ||
} | ||
} | ||
action.setBadgeText({ | ||
text: "0", | ||
}); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
import * as browser from 'webextension-polyfill'; | ||
|
||
export const getAction = () => { | ||
if (chrome.runtime.getManifest().manifest_version === 3) { | ||
return browser.action; | ||
} | ||
return browser.browserAction; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,80 @@ | ||
const openDatabase = () => new Promise((res, rej) => { | ||
const request = indexedDB.open('ariadne', 1); | ||
request.onerror = (event) => { | ||
console.error(`browser/storage: Error ${event.target.errorCode}`) | ||
rej(); | ||
}; | ||
|
||
// Declare schema | ||
request.onupgradeneeded = (event) => { | ||
const db = event.target.result; | ||
|
||
// Create storage for stats per URL | ||
const urlStatsStore = db.createObjectStore('stats', { keyPath: 'url' }) | ||
urlStatsStore.createIndex('url', 'url', { unique: true }) | ||
|
||
// Create storage for badge states per tab | ||
const badgeStateStore = db.createObjectStore('badgeStates', { keyPath: 'tabId' }) | ||
badgeStateStore.createIndex('tabId', 'tabId', { unique: true }) | ||
|
||
// Create storage for Calliope results per URL | ||
const calliopeStore = db.createObjectStore('calliope', { keyPath: 'url' }) | ||
calliopeStore.createIndex('url', 'url', { unique: true }) | ||
|
||
// Create storage for Janus results per URL | ||
const janusStore = db.createObjectStore('janus', { keyPath: 'url' }) | ||
janusStore.createIndex('url', 'url', { unique: true }) | ||
} | ||
|
||
request.onsuccess = (event) => { | ||
console.log('browser/storage: Database ready'); | ||
res(event.target.result); | ||
} | ||
}); | ||
|
||
|
||
export const setTransaction = async (store, data) => { | ||
console.log('browser/storage(set): Opening DB'); | ||
|
||
const db = await openDatabase(); | ||
const t = db.transaction(store, 'readwrite'); | ||
const s = t.objectStore(store); | ||
return await new Promise((res, rej) => { | ||
t.oncomplete = () => console.log('browser/storage(set): Complete'); | ||
t.onerror = (e) => rej(e); | ||
|
||
const r = s.put(data); | ||
r.onsuccess = () => res(); | ||
}); | ||
} | ||
|
||
export const getTransaction = async (store, key) => { | ||
console.log('browser/storage(get): Opening DB'); | ||
|
||
const db = await openDatabase(); | ||
const t = db.transaction(store, 'readonly'); | ||
const s = t.objectStore(store); | ||
return await new Promise((res, rej) => { | ||
t.oncomplete = () => console.log('browser/storage(get): Complete'); | ||
t.onerror = (ev) => rej(ev); | ||
|
||
const r = s.get(key); | ||
r.onsuccess = (e) => res(e.target.result); | ||
}); | ||
} | ||
|
||
export const deleteTransaction = async (store, key) => { | ||
console.log('browser/storage(delete): Opening DB'); | ||
|
||
const db = await openDatabase(); | ||
const t = db.transaction(store, 'readwrite'); | ||
const s = t.objectStore(store); | ||
return await new Promise((res, rej) => { | ||
t.oncomplete = () => { | ||
console.log('browser/storage(delete): Complete'); | ||
res(); | ||
}; | ||
t.onerror = (e) => rej(e); | ||
s.delete(key); | ||
}); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
import messageListener from './message'; | ||
import tabChangeListener from './tabChange'; | ||
import tabUrlChangeListener from './tabUrlChange'; | ||
|
||
export { | ||
messageListener, | ||
tabChangeListener, | ||
tabUrlChangeListener | ||
} |
Oops, something went wrong.