Skip to content
Snippets Groups Projects
Commit 5e8090f4 authored by Dominik Hebeler's avatar Dominik Hebeler
Browse files

create base files for new extension

parent 8986bed3
No related branches found
No related tags found
No related merge requests found
/node_modules
/js
\ No newline at end of file
{
"extensionDescription": {
"message": "Datenschutz war noch nie so einfach. Konfiguriert MetaGer optional als Standard-Suchmaschine und speichert Sucheinstellungen auch ohne Cookies. Bei Verwendung eines MetaGer Schlüssels können anonyme Tokens verwendet werden.",
"description": "Description of the Webextension"
},
"searchProviderName": {
"message": "MetaGer Suche",
"description": "Name of the search provider to be installed in the browser"
},
"searchProviderHost": {
"message": "metager.de",
"description": "Host of the search provider to be installed in the browser"
}
}
\ No newline at end of file
{
"extensionDescription": {
"message": "Data protection has never been so easy. Configures MetaGer optionally as the default search engine and saves search settings even without cookies. When using a MetaGer key, anonymous tokens can be used.",
"description": "Description of the Webextension"
},
"searchProviderName": {
"message": "MetaGer Search",
"description": "Name of the search provider to be installed in the browser"
},
"searchProviderHost": {
"message": "metager.org",
"description": "Host of the search provider to be installed in the browser"
}
}
\ No newline at end of file
NODE_VERSION=21
\ No newline at end of file
#!/bin/bash
# Verify that docker is installed
if ! command -v docker &> /dev/null
then
echo "docker seems to not be installed on your system";
exit 1;
fi
CURRENT_DIR=`dirname $BASH_SOURCE`;
# Export variables to this environment
source $CURRENT_DIR/.env
docker run -it --rm -v $CURRENT_DIR/../../:/data --workdir=/data node:$NODE_VERSION npm run dev
(() => {
const permissionsToRequest = {
permissions: ["webRequest"],
origins: ["https://metager.de/*"]
};
browser.permissions.request(permissionsToRequest).then(response => {
console.log(response);
browser.webRequest.onBeforeRequest.addListener(details => {
console.log(details.url);
}, { urls: ["https://metager.de/*"] });
})
})();
\ No newline at end of file
"use strict"; "use strict";
const BlindSignature = require('blind-signatures');
const { v4: uuidv4 } = require('uuid'); const { v4: uuidv4 } = require('uuid');
const { blind, unblind } = require('blind-signatures');
const NodeRSA = require('node-rsa'); const NodeRSA = require('node-rsa');
const APIBASEURL = "https://metager.de"; const APIBASEURL = "https://metager.de";
const sites = ["https://metager.de","https://metager.org","https://metager3.de"]; const sites = ["https://metager.de", "https://metager.org", "https://metager3.de"];
function updateStorageFromCookies() {sites.forEach((site) => { function updateStorageFromCookies() {
let siteURL = new URL(site); sites.forEach((site) => {
//console.log("reading cookies for site "+siteURL.hostname+"..."); let siteURL = new URL(site);
//console.log(siteURL); //console.log("reading cookies for site "+siteURL.hostname+"...");
browser.cookies.getAll({ //console.log(siteURL);
domain: siteURL.hostname, browser.cookies.getAll({
firstPartyDomain: null, domain: siteURL.hostname,
}).then(cookies => { firstPartyDomain: null,
//console.log("found "+cookies.length+" cookies.") }).then(cookies => {
//console.log(cookies); //console.log("found "+cookies.length+" cookies.")
let tosave = {}; //console.log(cookies);
cookies.forEach(cookie => { let tosave = {};
prefCookies.forEach(wListEntry => { cookies.forEach(cookie => {
let regExp = new RegExp(wListEntry); prefCookies.forEach(wListEntry => {
if (regExp.test(cookie.name)) { let regExp = new RegExp(wListEntry);
//console.log("Found preference cookie "+cookie.name+"."); if (regExp.test(cookie.name)) {
if (cookie.name == "key") { //keys are saved without prefix //console.log("Found preference cookie "+cookie.name+".");
tosave["key"] = cookie.value; if (cookie.name == "key") { //keys are saved without prefix
} else { tosave["key"] = cookie.value;
tosave["pref_"+ cookie.domain +"_"+ cookie.name] = cookie.value; } else {
} tosave["pref_" + cookie.domain + "_" + cookie.name] = cookie.value;
} }
}); }
}); });
browser.storage.local.set(tosave)
}); });
browser.storage.local.set(tosave)
}); });
});
} }
//updateStorageFromCookies(); //updateStorageFromCookies();
...@@ -53,23 +54,23 @@ function updateStorageFromCookies() {sites.forEach((site) => { ...@@ -53,23 +54,23 @@ function updateStorageFromCookies() {sites.forEach((site) => {
async function refillTokenStash(count) { // TODO: handle count >10 async function refillTokenStash(count) { // TODO: handle count >10
console.log("refilling tokens"); console.log("refilling tokens");
let tokensToBlind = []; let tokensToBlind = [];
for (let i = 0; i <= Math.min(count,9); i++) { for (let i = 0; i <= Math.min(count, 9); i++) {
tokensToBlind.push(uuidv4()); tokensToBlind.push(uuidv4());
} }
console.log("tokensToBlind:"); console.log("tokensToBlind:");
console.log(tokensToBlind); console.log(tokensToBlind);
const pubkeyReq = new XMLHttpRequest(); const pubkeyReq = new XMLHttpRequest();
pubkeyReq.addEventListener("load", async () => { pubkeyReq.addEventListener("load", async () => {
//console.log(JSON.parse(pubkeyReq.response)); //console.log(JSON.parse(pubkeyReq.response));
let pubkey = NodeRSA(JSON.parse(pubkeyReq.response).pubkey_pem); let pubkey = NodeRSA({ key: JSON.parse(pubkeyReq.response).pubkey_pem });
let pubkeyDate = JSON.parse(pubkeyReq.response).date; let pubkeyDate = JSON.parse(pubkeyReq.response).date;
//console.log("pubkey Response: "); //console.log("pubkey Response: ");
//console.log(pubkeyReq.response); //console.log(pubkeyReq.response);
let tokensToSign = []; let tokensToSign = [];
let tokenRs = []; let tokenRs = [];
tokensToBlind.forEach( (t) => { tokensToBlind.forEach((t) => {
let blinded = BlindSignature.blind({ let blinded = blind({
message: t, message: t,
key: pubkey key: pubkey
}); });
...@@ -83,14 +84,14 @@ async function refillTokenStash(count) { // TODO: handle count >10 ...@@ -83,14 +84,14 @@ async function refillTokenStash(count) { // TODO: handle count >10
let requestContent = { let requestContent = {
key: await getKey(), key: await getKey(),
date: pubkeyDate, date: pubkeyDate,
blinded_tokens: tokensToSign.map(t=>t.toString()) blinded_tokens: tokensToSign.map(t => t.toString())
}; };
//console.log("requestContent: "); //console.log("requestContent: ");
//console.log(requestContent); //console.log(requestContent);
const keySignReq = new XMLHttpRequest(); const keySignReq = new XMLHttpRequest();
keySignReq.open("POST", APIBASEURL+"/keys/api/json/token/sign", false); keySignReq.open("POST", APIBASEURL + "/keys/api/json/token/sign", false);
keySignReq.setRequestHeader("Content-type", "application/json"); keySignReq.setRequestHeader("Content-type", "application/json");
keySignReq.send(JSON.stringify(requestContent)); keySignReq.send(JSON.stringify(requestContent));
//console.log(keySignReq.response); //console.log(keySignReq.response);
...@@ -98,7 +99,7 @@ async function refillTokenStash(count) { // TODO: handle count >10 ...@@ -98,7 +99,7 @@ async function refillTokenStash(count) { // TODO: handle count >10
let signedTokens = Object.entries(JSON.parse(keySignReq.response).signed_tokens); let signedTokens = Object.entries(JSON.parse(keySignReq.response).signed_tokens);
let obtainedTokens = []; let obtainedTokens = [];
for (let i = 0; i < tokensToBlind.length; i++) { for (let i = 0; i < tokensToBlind.length; i++) {
let unblinded = BlindSignature.unblind({ let unblinded = unblind({
signed: signedTokens[i][1], signed: signedTokens[i][1],
key: pubkey, key: pubkey,
r: tokenRs[i] r: tokenRs[i]
...@@ -113,7 +114,7 @@ async function refillTokenStash(count) { // TODO: handle count >10 ...@@ -113,7 +114,7 @@ async function refillTokenStash(count) { // TODO: handle count >10
}); });
pubkeyReq.open("GET", APIBASEURL+"/keys/api/json/token/pubkey"); pubkeyReq.open("GET", APIBASEURL + "/keys/api/json/token/pubkey");
pubkeyReq.send(); pubkeyReq.send();
} }
...@@ -136,7 +137,7 @@ async function getTokensPerSearch() { ...@@ -136,7 +137,7 @@ async function getTokensPerSearch() {
* @returns {number} * @returns {number}
*/ */
function getRefillThresholdSize() { function getRefillThresholdSize() {
return getTokensPerSearch().then((x) => x*3); return getTokensPerSearch().then((x) => x * 3);
} }
/** /**
...@@ -144,7 +145,7 @@ function getRefillThresholdSize() { ...@@ -144,7 +145,7 @@ function getRefillThresholdSize() {
* @returns {number} * @returns {number}
*/ */
function getTargetStashSize() { function getTargetStashSize() {
return getTokensPerSearch().then((x) => x*7); return getTokensPerSearch().then((x) => x * 7);
} }
/** /**
...@@ -152,17 +153,17 @@ function getTargetStashSize() { ...@@ -152,17 +153,17 @@ function getTargetStashSize() {
* @returns {String|boolean} key or false if none found * @returns {String|boolean} key or false if none found
*/ */
async function getKey() { async function getKey() {
let {key: storedKey} = await browser.storage.local.get({"key": false}); let { key: storedKey } = await browser.storage.local.get({ "key": false });
console.log("gotKey:"+storedKey); console.log("gotKey:" + storedKey);
if (storedKey === false) { if (storedKey === false) {
sites.forEach(async (site) => { sites.forEach(async (site) => {
console.log("checking for saved keys ("+site+")"); console.log("checking for saved keys (" + site + ")");
let found = await browser.cookies.get({ let found = await browser.cookies.get({
url: site, url: site,
name: "key", name: "key",
}); });
if (found && found.value && found.value.length>0) { if (found && found.value && found.value.length > 0) {
await browser.storage.local.set({"key": found.value}); await browser.storage.local.set({ "key": found.value });
return found.value; return found.value;
} }
}); });
...@@ -180,14 +181,14 @@ async function checkTokenStash(refill) { ...@@ -180,14 +181,14 @@ async function checkTokenStash(refill) {
console.log("checking token stash"); console.log("checking token stash");
let { let {
tokenStash: currentStash, tokenStash: currentStash,
key: activeKey key: activeKey
} = await browser.storage.local.get( } = await browser.storage.local.get(
{ {
"tokenStash": [], "tokenStash": [],
"key": null "key": null
} }
); );
console.log("current stash size: "+currentStash.length); console.log("current stash size: " + currentStash.length);
console.log(activeKey); console.log(activeKey);
let refillThresholdSize = await getRefillThresholdSize(); let refillThresholdSize = await getRefillThresholdSize();
let targetStashSize = await getTargetStashSize(); let targetStashSize = await getTargetStashSize();
...@@ -199,7 +200,7 @@ async function checkTokenStash(refill) { ...@@ -199,7 +200,7 @@ async function checkTokenStash(refill) {
return false; return false;
} }
} }
setTimeout(()=>{checkTokenStash(true)},5000); setTimeout(() => { checkTokenStash(true) }, 5000);
/** /**
...@@ -208,8 +209,8 @@ setTimeout(()=>{checkTokenStash(true)},5000); ...@@ -208,8 +209,8 @@ setTimeout(()=>{checkTokenStash(true)},5000);
* @returns {Array|boolean} tokens or false if unsuccessful * @returns {Array|boolean} tokens or false if unsuccessful
*/ */
async function popTokens(count) { async function popTokens(count) {
console.log("popping: "+count); console.log("popping: " + count);
let { tokenStash: currentStash } = await browser.storage.local.get({"tokenStash": []}); let { tokenStash: currentStash } = await browser.storage.local.get({ "tokenStash": [] });
if (currentStash.length < count) { if (currentStash.length < count) {
return false; return false;
} }
...@@ -217,7 +218,7 @@ async function popTokens(count) { ...@@ -217,7 +218,7 @@ async function popTokens(count) {
for (let i = 0; i < count; i++) { for (let i = 0; i < count; i++) {
tokens.push(currentStash.pop()); tokens.push(currentStash.pop());
} }
await browser.storage.local.set({tokenStash: currentStash}); await browser.storage.local.set({ tokenStash: currentStash });
return tokens; return tokens;
} }
...@@ -227,11 +228,11 @@ async function popTokens(count) { ...@@ -227,11 +228,11 @@ async function popTokens(count) {
* @returns {boolean} Resolves with true afterwards * @returns {boolean} Resolves with true afterwards
*/ */
async function pushTokens(input) { async function pushTokens(input) {
let { tokenStash: currentStash } = await browser.storage.local.get({"tokenStash": []}); let { tokenStash: currentStash } = await browser.storage.local.get({ "tokenStash": [] });
while (input.length > 0) { while (input.length > 0) {
currentStash.push(input.pop()); currentStash.push(input.pop());
} }
await browser.storage.local.set({tokenStash: currentStash}); await browser.storage.local.set({ tokenStash: currentStash });
return true; return true;
} }
...@@ -240,11 +241,11 @@ async function pushTokens(input) { ...@@ -240,11 +241,11 @@ async function pushTokens(input) {
* Remove duplicates from stash * Remove duplicates from stash
*/ */
async function cleanStash() { async function cleanStash() {
let { tokenStash: currentStash } = await browser.storage.local.get({"tokenStash": []}); let { tokenStash: currentStash } = await browser.storage.local.get({ "tokenStash": [] });
currentStash = currentStash.filter((value, index, self) => currentStash = currentStash.filter((value, index, self) =>
index === self.findIndex((t) => (t.token === value.token)) index === self.findIndex((t) => (t.token === value.token))
); );
await browser.storage.local.set({tokenStash: currentStash}); await browser.storage.local.set({ tokenStash: currentStash });
} }
...@@ -253,35 +254,35 @@ function cookieChanged(e) { ...@@ -253,35 +254,35 @@ function cookieChanged(e) {
try { try {
//console.log("tokenscookie:"); //console.log("tokenscookie:");
//console.log(e.cookie); //console.log(e.cookie);
JSON.parse(decodeURIComponent(e.cookie.value)).forEach((token)=> { JSON.parse(decodeURIComponent(e.cookie.value)).forEach((token) => {
//console.log("found token!"); //console.log("found token!");
storageGlobal.tokenStash.push(token); storageGlobal.tokenStash.push(token);
}); });
tosave["tokenStash"] = storageGlobal.tokenStash; tosave["tokenStash"] = storageGlobal.tokenStash;
browser.storage.local.set({tokenStash:storageGlobal.tokenStash}); browser.storage.local.set({ tokenStash: storageGlobal.tokenStash });
} catch (err) { } catch (err) {
} }
} }
prefCookies.forEach(wListEntry => { //check if we're interested in the cookie (i.e. it's a preference) prefCookies.forEach(wListEntry => { //check if we're interested in the cookie (i.e. it's a preference)
let regExp = new RegExp(wListEntry); let regExp = new RegExp(wListEntry);
if (regExp.test(e.cookie.name)) { if (regExp.test(e.cookie.name)) {
if(e.removed || e.cookie.value.length == 0) { //cookie removed, remove from storage if (e.removed || e.cookie.value.length == 0) { //cookie removed, remove from storage
browser.storage.local.remove("pref_"+ e.cookie.domain +"_"+ e.cookie.name); browser.storage.local.remove("pref_" + e.cookie.domain + "_" + e.cookie.name);
//console.log("Preference "+e.cookie.name+" deleted."); //console.log("Preference "+e.cookie.name+" deleted.");
} else { // cookie changed, update storage } else { // cookie changed, update storage
let tosave = {}; let tosave = {};
if (e.cookie.name == "key") { //keys are saved without prefix if (e.cookie.name == "key") { //keys are saved without prefix
tosave["key"] = e.cookie.value; tosave["key"] = e.cookie.value;
} else { } else {
tosave["pref_"+ e.cookie.domain +"_"+ e.cookie.name] = e.cookie.value; tosave["pref_" + e.cookie.domain + "_" + e.cookie.name] = e.cookie.value;
} }
browser.storage.local.set(tosave) browser.storage.local.set(tosave)
updateStorageGlobal(); updateStorageGlobal();
//console.log("Preference "+e.cookie.name+" updated."); //console.log("Preference "+e.cookie.name+" updated.");
} }
} }
}); });
} }
...@@ -299,12 +300,12 @@ function parseCookieHeader(input) { // source: https://github.com/30-seconds/30- ...@@ -299,12 +300,12 @@ function parseCookieHeader(input) { // source: https://github.com/30-seconds/30-
function genCookieHeader(input) { function genCookieHeader(input) {
//console.log("genCookieHeader("+input+")"); //console.log("genCookieHeader("+input+")");
return Object.entries(input).reduce((acc, v) => { return Object.entries(input).reduce((acc, v) => {
return acc+`${encodeURIComponent(v[0])}=${encodeURIComponent(v[1])}; `; return acc + `${encodeURIComponent(v[0])}=${encodeURIComponent(v[1])}; `;
}, "").slice(0, -2); }, "").slice(0, -2);
} }
function genCookiesToInject(eURL, input) { function genCookiesToInject(eURL, input) {
let prefix = "pref_"+eURL.hostname+"_"; let prefix = "pref_" + eURL.hostname + "_";
//console.log("domain: "+eURL.hostname); //console.log("domain: "+eURL.hostname);
//console.log(input); //console.log(input);
if (eURL.pathname.startsWith("/meta/meta.ger3") && eURL.searchParams.has("mgv") && checkTokenStash()) { if (eURL.pathname.startsWith("/meta/meta.ger3") && eURL.searchParams.has("mgv") && checkTokenStash()) {
...@@ -347,10 +348,10 @@ function injectPrefs(e) { ...@@ -347,10 +348,10 @@ function injectPrefs(e) {
*/ */
let eURL = new URL(e.url); let eURL = new URL(e.url);
if (eURL.pathname.startsWith("/meta/meta.ger3") && eURL.searchParams.has("mgv") && checkTokenStash()) { if (eURL.pathname.startsWith("/meta/meta.ger3") && eURL.searchParams.has("mgv") && checkTokenStash()) {
e.requestHeaders.push({name:"tokens",value:JSON.stringify(await popTokens(await getTokensPerSearch()))}); e.requestHeaders.push({ name: "tokens", value: JSON.stringify(await popTokens(await getTokensPerSearch())) });
} }
e.requestHeaders.push({name:"tokenauthorization",value:"full"}); e.requestHeaders.push({ name: "tokenauthorization", value: "full" });
resolve({requestHeaders: e.requestHeaders}); resolve({ requestHeaders: e.requestHeaders });
}); });
...@@ -375,13 +376,13 @@ browser.cookies.onChanged.addListener(cookieChanged); ...@@ -375,13 +376,13 @@ browser.cookies.onChanged.addListener(cookieChanged);
browser.webRequest.onCompleted.addListener( browser.webRequest.onCompleted.addListener(
mgLoadComplete, mgLoadComplete,
{urls: sites.map(s => s.concat("/meta/meta.ger3*"))}, { urls: sites.map(s => s.concat("/meta/meta.ger3*")) },
["responseHeaders"] ["responseHeaders"]
); );
browser.webRequest.onBeforeSendHeaders.addListener( browser.webRequest.onBeforeSendHeaders.addListener(
injectPrefs, injectPrefs,
{urls: sites.map(s => s.concat("/*"))}, { urls: sites.map(s => s.concat("/*")) },
["blocking", "requestHeaders"] ["blocking", "requestHeaders"]
); );
/**
* Function to modify content of our webpages
* i.e. removes install plugin button as plugin already is installed
*/
export function updateContent() {
removePluginButton();
}
/**
* Remove the install plugin button from our webpages
*/
function removePluginButton() {
}
\ No newline at end of file
let pluginButton = document.getElementById("plugin-btn");
if (pluginButton) {
pluginButton.remove();
}
\ No newline at end of file
icons/favicon.ico

5.56 KiB | W: | H:

icons/favicon.ico

208 KiB | W: | H:

icons/favicon.ico
icons/favicon.ico
icons/favicon.ico
icons/favicon.ico
  • 2-up
  • Swipe
  • Onion skin
{ {
"author": "SUMA-EV", "author": "SUMA-EV",
"manifest_version": 2, "manifest_version": 3,
"name": "MetaGer Search", "name": "__MSG_searchProviderName__",
"version": "0.1.0.0", "version": "0.1.0.0",
"description": "Privacy has never been that easy. Configures MetaGer as default search engine.", "description": "__MSG_extensionDescription__",
"default_locale": "en", "default_locale": "en",
"applications": { "browser_specific_settings": {
"gecko": { "gecko": {
"id": "firefoxextension@metager.org", "id": "firefoxextension@metager.org",
"strict_min_version": "57.0" "strict_min_version": "57.0"
...@@ -18,33 +18,38 @@ ...@@ -18,33 +18,38 @@
"webRequest", "webRequest",
"webRequestBlocking", "webRequestBlocking",
"storage", "storage",
"cookies", "cookies"
"*://*.metager.de/*",
"*://*.metager.org/*",
"*://*.metager3.de/*"
], ],
"content_scripts": [ "content_scripts": [
{ {
"matches": [ "matches": [
"https://metager.org/" "https://metager.org/*",
"https://metager.de/*",
"https://metager3.de/*"
], ],
"js": [ "js": [
"removeUnusedContent.js" "js/removeUnusedContent.js"
] ]
} }
], ],
"host_permissions": [
"https://metager.org/*",
"https://metager.de/*",
"https://metager3.de/*"
],
"background": { "background": {
"scripts": ["bundle.js"] "scripts": [
"js/app.js"
]
}, },
"web_accessible_resources": [], "web_accessible_resources": [],
"chrome_settings_overrides": { "chrome_settings_overrides": {
"search_provider": { "search_provider": {
"name": "__MSG_searchProviderName__", "name": "__MSG_searchProviderName__",
"favicon_url": "https://metager.org/favicon.ico", "favicon_url": "icons/favicon.ico",
"search_url": "__MSG_searchURL__", "search_url": "https://__MSG_searchProviderHost__/meta/meta.ger3?eingabe={searchTerms}",
"is_default": true, "is_default": true,
"keyword": "metager" "keyword": "metager"
} }
} }
} }
\ No newline at end of file
File deleted
This diff is collapsed.
{ {
"dependencies": { "dependencies": {
"blind-signatures": "^1.0.7", "blind-signatures": "^1.0.7",
"node-rsa": "^1.1.1",
"uuid": "^9.0.0" "uuid": "^9.0.0"
},
"devDependencies": {
"web-ext": "^7.11.0",
"webpack": "^5.90.3",
"webpack-cli": "^5.1.4"
},
"scripts": {
"dev": "npm i --clean && webpack --mode=development"
} }
} }
\ No newline at end of file
document.getElementById("plugin-btn").outerHTML = '';
\ No newline at end of file
const path = require('path');
module.exports = {
resolve: {
fallback: {
"assert": false,
"crypto": false,
"constants": false,
"buffer": false
},
},
entry: {
'app': './build/js/app.js',
'removeUnusedContent': './build/js/removeUnusedContent.js'
},
output: {
filename: '[name].js',
path: path.resolve(__dirname, 'js'),
},
devtool: false,
watch: true,
watchOptions: {
ignored: ['/node_modules']
}
};
\ No newline at end of file
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment