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";
const BlindSignature = require('blind-signatures');
const { v4: uuidv4 } = require('uuid');
const { blind, unblind } = require('blind-signatures');
const NodeRSA = require('node-rsa');
const APIBASEURL = "https://metager.de";
const sites = ["https://metager.de","https://metager.org","https://metager3.de"];
function updateStorageFromCookies() {sites.forEach((site) => {
let siteURL = new URL(site);
//console.log("reading cookies for site "+siteURL.hostname+"...");
//console.log(siteURL);
browser.cookies.getAll({
domain: siteURL.hostname,
firstPartyDomain: null,
}).then(cookies => {
//console.log("found "+cookies.length+" cookies.")
//console.log(cookies);
let tosave = {};
cookies.forEach(cookie => {
prefCookies.forEach(wListEntry => {
let regExp = new RegExp(wListEntry);
if (regExp.test(cookie.name)) {
//console.log("Found preference cookie "+cookie.name+".");
if (cookie.name == "key") { //keys are saved without prefix
tosave["key"] = cookie.value;
} else {
tosave["pref_"+ cookie.domain +"_"+ cookie.name] = cookie.value;
}
const sites = ["https://metager.de", "https://metager.org", "https://metager3.de"];
function updateStorageFromCookies() {
sites.forEach((site) => {
let siteURL = new URL(site);
//console.log("reading cookies for site "+siteURL.hostname+"...");
//console.log(siteURL);
browser.cookies.getAll({
domain: siteURL.hostname,
firstPartyDomain: null,
}).then(cookies => {
//console.log("found "+cookies.length+" cookies.")
//console.log(cookies);
let tosave = {};
cookies.forEach(cookie => {
prefCookies.forEach(wListEntry => {
let regExp = new RegExp(wListEntry);
if (regExp.test(cookie.name)) {
//console.log("Found preference cookie "+cookie.name+".");
if (cookie.name == "key") { //keys are saved without prefix
tosave["key"] = cookie.value;
} else {
tosave["pref_" + cookie.domain + "_" + cookie.name] = cookie.value;
}
});
}
});
browser.storage.local.set(tosave)
});
browser.storage.local.set(tosave)
});
});
}
//updateStorageFromCookies();
......@@ -53,23 +54,23 @@ function updateStorageFromCookies() {sites.forEach((site) => {
async function refillTokenStash(count) { // TODO: handle count >10
console.log("refilling tokens");
let tokensToBlind = [];
for (let i = 0; i <= Math.min(count,9); i++) {
tokensToBlind.push(uuidv4());
for (let i = 0; i <= Math.min(count, 9); i++) {
tokensToBlind.push(uuidv4());
}
console.log("tokensToBlind:");
console.log(tokensToBlind);
const pubkeyReq = new XMLHttpRequest();
pubkeyReq.addEventListener("load", async () => {
//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;
//console.log("pubkey Response: ");
//console.log(pubkeyReq.response);
let tokensToSign = [];
let tokenRs = [];
tokensToBlind.forEach( (t) => {
let blinded = BlindSignature.blind({
tokensToBlind.forEach((t) => {
let blinded = blind({
message: t,
key: pubkey
});
......@@ -83,14 +84,14 @@ async function refillTokenStash(count) { // TODO: handle count >10
let requestContent = {
key: await getKey(),
date: pubkeyDate,
blinded_tokens: tokensToSign.map(t=>t.toString())
blinded_tokens: tokensToSign.map(t => t.toString())
};
//console.log("requestContent: ");
//console.log(requestContent);
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.send(JSON.stringify(requestContent));
//console.log(keySignReq.response);
......@@ -98,7 +99,7 @@ async function refillTokenStash(count) { // TODO: handle count >10
let signedTokens = Object.entries(JSON.parse(keySignReq.response).signed_tokens);
let obtainedTokens = [];
for (let i = 0; i < tokensToBlind.length; i++) {
let unblinded = BlindSignature.unblind({
let unblinded = unblind({
signed: signedTokens[i][1],
key: pubkey,
r: tokenRs[i]
......@@ -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();
}
......@@ -136,7 +137,7 @@ async function getTokensPerSearch() {
* @returns {number}
*/
function getRefillThresholdSize() {
return getTokensPerSearch().then((x) => x*3);
return getTokensPerSearch().then((x) => x * 3);
}
/**
......@@ -144,7 +145,7 @@ function getRefillThresholdSize() {
* @returns {number}
*/
function getTargetStashSize() {
return getTokensPerSearch().then((x) => x*7);
return getTokensPerSearch().then((x) => x * 7);
}
/**
......@@ -152,17 +153,17 @@ function getTargetStashSize() {
* @returns {String|boolean} key or false if none found
*/
async function getKey() {
let {key: storedKey} = await browser.storage.local.get({"key": false});
console.log("gotKey:"+storedKey);
let { key: storedKey } = await browser.storage.local.get({ "key": false });
console.log("gotKey:" + storedKey);
if (storedKey === false) {
sites.forEach(async (site) => {
console.log("checking for saved keys ("+site+")");
console.log("checking for saved keys (" + site + ")");
let found = await browser.cookies.get({
url: site,
name: "key",
});
if (found && found.value && found.value.length>0) {
await browser.storage.local.set({"key": found.value});
if (found && found.value && found.value.length > 0) {
await browser.storage.local.set({ "key": found.value });
return found.value;
}
});
......@@ -180,14 +181,14 @@ async function checkTokenStash(refill) {
console.log("checking token stash");
let {
tokenStash: currentStash,
key: activeKey
key: activeKey
} = await browser.storage.local.get(
{
"tokenStash": [],
"key": null
}
);
console.log("current stash size: "+currentStash.length);
console.log("current stash size: " + currentStash.length);
console.log(activeKey);
let refillThresholdSize = await getRefillThresholdSize();
let targetStashSize = await getTargetStashSize();
......@@ -199,7 +200,7 @@ async function checkTokenStash(refill) {
return false;
}
}
setTimeout(()=>{checkTokenStash(true)},5000);
setTimeout(() => { checkTokenStash(true) }, 5000);
/**
......@@ -208,8 +209,8 @@ setTimeout(()=>{checkTokenStash(true)},5000);
* @returns {Array|boolean} tokens or false if unsuccessful
*/
async function popTokens(count) {
console.log("popping: "+count);
let { tokenStash: currentStash } = await browser.storage.local.get({"tokenStash": []});
console.log("popping: " + count);
let { tokenStash: currentStash } = await browser.storage.local.get({ "tokenStash": [] });
if (currentStash.length < count) {
return false;
}
......@@ -217,7 +218,7 @@ async function popTokens(count) {
for (let i = 0; i < count; i++) {
tokens.push(currentStash.pop());
}
await browser.storage.local.set({tokenStash: currentStash});
await browser.storage.local.set({ tokenStash: currentStash });
return tokens;
}
......@@ -227,11 +228,11 @@ async function popTokens(count) {
* @returns {boolean} Resolves with true afterwards
*/
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) {
currentStash.push(input.pop());
}
await browser.storage.local.set({tokenStash: currentStash});
await browser.storage.local.set({ tokenStash: currentStash });
return true;
}
......@@ -240,11 +241,11 @@ async function pushTokens(input) {
* Remove duplicates from stash
*/
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) =>
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) {
try {
//console.log("tokenscookie:");
//console.log(e.cookie);
JSON.parse(decodeURIComponent(e.cookie.value)).forEach((token)=> {
JSON.parse(decodeURIComponent(e.cookie.value)).forEach((token) => {
//console.log("found token!");
storageGlobal.tokenStash.push(token);
});
tosave["tokenStash"] = storageGlobal.tokenStash;
browser.storage.local.set({tokenStash:storageGlobal.tokenStash});
browser.storage.local.set({ tokenStash: storageGlobal.tokenStash });
} catch (err) {
}
}
prefCookies.forEach(wListEntry => { //check if we're interested in the cookie (i.e. it's a preference)
let regExp = new RegExp(wListEntry);
if (regExp.test(e.cookie.name)) {
if(e.removed || e.cookie.value.length == 0) { //cookie removed, remove from storage
browser.storage.local.remove("pref_"+ e.cookie.domain +"_"+ e.cookie.name);
//console.log("Preference "+e.cookie.name+" deleted.");
} else { // cookie changed, update storage
let tosave = {};
if (e.cookie.name == "key") { //keys are saved without prefix
tosave["key"] = e.cookie.value;
} else {
tosave["pref_"+ e.cookie.domain +"_"+ e.cookie.name] = e.cookie.value;
}
browser.storage.local.set(tosave)
updateStorageGlobal();
//console.log("Preference "+e.cookie.name+" updated.");
}
}
});
let regExp = new RegExp(wListEntry);
if (regExp.test(e.cookie.name)) {
if (e.removed || e.cookie.value.length == 0) { //cookie removed, remove from storage
browser.storage.local.remove("pref_" + e.cookie.domain + "_" + e.cookie.name);
//console.log("Preference "+e.cookie.name+" deleted.");
} else { // cookie changed, update storage
let tosave = {};
if (e.cookie.name == "key") { //keys are saved without prefix
tosave["key"] = e.cookie.value;
} else {
tosave["pref_" + e.cookie.domain + "_" + e.cookie.name] = e.cookie.value;
}
browser.storage.local.set(tosave)
updateStorageGlobal();
//console.log("Preference "+e.cookie.name+" updated.");
}
}
});
}
......@@ -299,12 +300,12 @@ function parseCookieHeader(input) { // source: https://github.com/30-seconds/30-
function genCookieHeader(input) {
//console.log("genCookieHeader("+input+")");
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);
}
function genCookiesToInject(eURL, input) {
let prefix = "pref_"+eURL.hostname+"_";
let prefix = "pref_" + eURL.hostname + "_";
//console.log("domain: "+eURL.hostname);
//console.log(input);
if (eURL.pathname.startsWith("/meta/meta.ger3") && eURL.searchParams.has("mgv") && checkTokenStash()) {
......@@ -347,10 +348,10 @@ function injectPrefs(e) {
*/
let eURL = new URL(e.url);
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"});
resolve({requestHeaders: e.requestHeaders});
e.requestHeaders.push({ name: "tokenauthorization", value: "full" });
resolve({ requestHeaders: e.requestHeaders });
});
......@@ -375,13 +376,13 @@ browser.cookies.onChanged.addListener(cookieChanged);
browser.webRequest.onCompleted.addListener(
mgLoadComplete,
{urls: sites.map(s => s.concat("/meta/meta.ger3*"))},
{ urls: sites.map(s => s.concat("/meta/meta.ger3*")) },
["responseHeaders"]
);
browser.webRequest.onBeforeSendHeaders.addListener(
injectPrefs,
{urls: sites.map(s => s.concat("/*"))},
{ urls: sites.map(s => s.concat("/*")) },
["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: 64px | H: 64px

icons/favicon.ico

208 KiB | W: 196px | H: 196px

icons/favicon.ico
icons/favicon.ico
icons/favicon.ico
icons/favicon.ico
  • 2-up
  • Swipe
  • Onion skin
{
"author": "SUMA-EV",
"manifest_version": 2,
"name": "MetaGer Search",
"manifest_version": 3,
"name": "__MSG_searchProviderName__",
"version": "0.1.0.0",
"description": "Privacy has never been that easy. Configures MetaGer as default search engine.",
"description": "__MSG_extensionDescription__",
"default_locale": "en",
"applications": {
"browser_specific_settings": {
"gecko": {
"id": "firefoxextension@metager.org",
"strict_min_version": "57.0"
......@@ -18,33 +18,38 @@
"webRequest",
"webRequestBlocking",
"storage",
"cookies",
"*://*.metager.de/*",
"*://*.metager.org/*",
"*://*.metager3.de/*"
"cookies"
],
"content_scripts": [
{
"matches": [
"https://metager.org/"
"https://metager.org/*",
"https://metager.de/*",
"https://metager3.de/*"
],
"js": [
"removeUnusedContent.js"
"js/removeUnusedContent.js"
]
}
],
"host_permissions": [
"https://metager.org/*",
"https://metager.de/*",
"https://metager3.de/*"
],
"background": {
"scripts": ["bundle.js"]
"scripts": [
"js/app.js"
]
},
"web_accessible_resources": [],
"chrome_settings_overrides": {
"search_provider": {
"name": "__MSG_searchProviderName__",
"favicon_url": "https://metager.org/favicon.ico",
"search_url": "__MSG_searchURL__",
"favicon_url": "icons/favicon.ico",
"search_url": "https://__MSG_searchProviderHost__/meta/meta.ger3?eingabe={searchTerms}",
"is_default": true,
"keyword": "metager"
}
}
}
}
\ No newline at end of file
File deleted
This diff is collapsed.
{
"dependencies": {
"blind-signatures": "^1.0.7",
"node-rsa": "^1.1.1",
"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