diff --git a/build.xml b/build.xml index b41f90e..c28ff69 100755 --- a/build.xml +++ b/build.xml @@ -29,6 +29,13 @@ + + + + + + + diff --git a/src/i2p.chromium.base.profile/extensions/TODO.md b/src/i2p.chromium.base.profile/extensions/TODO.md deleted file mode 100644 index fcb5202..0000000 --- a/src/i2p.chromium.base.profile/extensions/TODO.md +++ /dev/null @@ -1 +0,0 @@ -put extensions here. \ No newline at end of file diff --git a/src/i2p.chromium.base.profile/extensions/i2pchrome.js/LICENSE b/src/i2p.chromium.base.profile/extensions/i2pchrome.js/LICENSE new file mode 100644 index 0000000..dde6ad3 --- /dev/null +++ b/src/i2p.chromium.base.profile/extensions/i2pchrome.js/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2019 idk + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/src/i2p.chromium.base.profile/extensions/i2pchrome.js/Makefile b/src/i2p.chromium.base.profile/extensions/i2pchrome.js/Makefile new file mode 100644 index 0000000..caa35b7 --- /dev/null +++ b/src/i2p.chromium.base.profile/extensions/i2pchrome.js/Makefile @@ -0,0 +1,64 @@ +default: zip + +install: uninstall + mkdir -p /usr/share/webext/i2pchrome.js@eyedeekay.github.io \ + /usr/share/mozilla/extensions/{ec8030f7-c20a-464f-9b0e-13a3a9e97384}/ + cp -rv options /usr/share/webext/i2pchrome.js@eyedeekay.github.io/options + cp -rv icons /usr/share/webext/i2pchrome.js@eyedeekay.github.io/icons + cp -rv _locales /usr/share/webext/i2pchrome.js@eyedeekay.github.io/_locales + cp background.js /usr/share/webext/i2pchrome.js@eyedeekay.github.io + cp proxy.js /usr/share/webext/i2pchrome.js@eyedeekay.github.io + cp info.js /usr/share/webext/i2pchrome.js@eyedeekay.github.io + cp content.js /usr/share/webext/i2pchrome.js@eyedeekay.github.io + cp info.css /usr/share/webext/i2pchrome.js@eyedeekay.github.io + cp window.html /usr/share/webext/i2pchrome.js@eyedeekay.github.io + cp manifest.json /usr/share/webext/i2pchrome.js@eyedeekay.github.io/ + cp README.md /usr/share/webext/i2pchrome.js@eyedeekay.github.io + cp LICENSE /usr/share/webext/i2pchrome.js@eyedeekay.github.io + ln -sf /usr/share/webext/i2pchrome.js@eyedeekay.github.io \ + /usr/share/mozilla/extensions/{ec8030f7-c20a-464f-9b0e-13a3a9e97384}/i2pchrome.js@eyedeekay.github.io + +uninstall: + rm -rf /usr/share/webext/i2pchrome.js@eyedeekay.github.io \ + /usr/share/mozilla/extensions/{ec8030f7-c20a-464f-9b0e-13a3a9e97384}/i2pchrome.js@eyedeekay.github.io + +clobber: + rm -f ../i2pchrome.js.zip ../i2p_proxy*.xpi + +VERSION=1.29 + +xpi: + mv ~/Downloads/i2p_proxy-$(VERSION)-an+fx.xpi ../i2pchrome.js@eyedeekay.github.io.xpi + +cp: + cp ../i2pchrome.js@eyedeekay.github.io.xpi ./i2pchrome.js@eyedeekay.github.io.xpi + +version: + sed -i 's|$(shell grep "\"version\": " manifest.json)| \"version\": \"$(VERSION)\",|g' manifest.json + +zip: version + zip --exclude="./i2pchrome.js@eyedeekay.github.io.xpi" \ + --exclude="i2pchrome.js.png" -r -FS ../i2pchrome.js.zip * + +profile-install: + cp ./i2pchrome.js@eyedeekay.github.io.xpi $(HOME)/.mozilla/firefox/firefox.profile.i2p/firefox.profile.i2p/extensions + cp ./i2pchrome.js@eyedeekay.github.io.xpi $(HOME)/.mozilla/firefox/.firefox.profile.i2p.default/extensions + +to-profile: + cp ./i2pchrome.js@eyedeekay.github.io.xpi /usr/local/lib/firefox.profile.i2p/firefox.profile.i2p/extensions/ + +pi: profile-install + +DESC="A simple plugin for configuring an i2p browser." + +release: + gothub release -u eyedeekay -r i2pchrome.js -t $(VERSION) -n $(VERSION) -d $(DESC) + +upload: + gothub upload -u eyedeekay -r i2pchrome.js -t $(VERSION) -n "i2pchrome.js@eyedeekay.github.io.xpi" -f "../i2pchrome.js@eyedeekay.github.io.xpi" + +fmt: + #cleancss -O1 all -O2 all --format beautify home.css -o .home.css && mv .home.css home.css + #cleancss -O1 all -O2 all --format beautify info.css -o .info.css && mv .info.css info.css + find . -path ./node_modules -prune -o -name '*.js' -exec prettier --write {} \; + find . -path ./node_modules -prune -o -name '*.json' -exec prettier --write {} \; diff --git a/src/i2p.chromium.base.profile/extensions/i2pchrome.js/README.md b/src/i2p.chromium.base.profile/extensions/i2pchrome.js/README.md new file mode 100644 index 0000000..7d6f790 --- /dev/null +++ b/src/i2p.chromium.base.profile/extensions/i2pchrome.js/README.md @@ -0,0 +1,2 @@ +I2P Plugin For Chromium Persona +=============================== diff --git a/src/i2p.chromium.base.profile/extensions/i2pchrome.js/_locales/en/messages.json b/src/i2p.chromium.base.profile/extensions/i2pchrome.js/_locales/en/messages.json new file mode 100644 index 0000000..d4f322a --- /dev/null +++ b/src/i2p.chromium.base.profile/extensions/i2pchrome.js/_locales/en/messages.json @@ -0,0 +1,66 @@ +{ + "extensionName": { + "message": "i2pchrome.js", + "description": "Name of the extension." + }, + "extensionDescription": { + "message": "Set up a browser to use the i2p http proxy automatically", + "description": "Description of the extension." + }, + "titlePreface": { + "message": "I2P Browser - ", + "description": "Preface for the browser titlebar" + }, + "titlePrefacePrivate": { + "message": "I2P Browser (Private) - ", + "description": "Preface for the browser titlebar" + }, + "resetMessage": { + "message": "Reset Tunnel", + "description": "Message for the Reset Tunnel button" + }, + "infoTitle": { + "message": "I2P Help", + "description": "Title for the help menu" + }, + "infoMessage": { + "message": "You are now free to browse the eepWeb! Your browser is now configured to browse anonymously on the I2P network. As you browse, your traffic will be routed through other network nodes to disguise it's origin, both from the server and from the nodes themselves.", + "description": "Help Message" + }, + "helpMessage": { + "message": "Get additional help", + "description": "Help Message" + }, + "newsMessage": { + "message": "Visit the I2P Blog to learn the latest about i2p.", + "description": "Help Message" + }, + "forumMessage": { + "message": "Visit the I2P Forum to learn more or ask for assistance", + "description": "Help Message" + }, + "clearData": { + "message": "Clear all browsing data", + "description": "Help Message" + }, + "hostText": { + "message": "Host: ", + "description": "Host for the HTTP or SOCKS5 Proxy" + }, + "portText": { + "message": "Port: ", + "description": "Port for the HTTP or SOCKS5 Proxy" + }, + "controlHelpText": { + "message": "These options will be inert if used with the default i2p HTTP or SOCKS proxy.", + "description": "Help for configuring the options for the Reset Tunnel button" + }, + "controlHostText": { + "message": "Control Host: ", + "description": "Host for the Reset Tunnel button" + }, + "controlPortText": { + "message": "Control Port: ", + "description": "Port for the Reset Tunnel button" + } +} diff --git a/src/i2p.chromium.base.profile/extensions/i2pchrome.js/_metadata/verified_contents.json b/src/i2p.chromium.base.profile/extensions/i2pchrome.js/_metadata/verified_contents.json new file mode 100644 index 0000000..d5bff86 --- /dev/null +++ b/src/i2p.chromium.base.profile/extensions/i2pchrome.js/_metadata/verified_contents.json @@ -0,0 +1 @@ +[{"description":"treehash per file","signed_content":{"payload":"eyJjb250ZW50X2hhc2hlcyI6W3siYmxvY2tfc2l6ZSI6NDA5NiwiZGlnZXN0Ijoic2hhMjU2IiwiZmlsZXMiOlt7InBhdGgiOiJMSUNFTlNFIiwicm9vdF9oYXNoIjoiTTVJb3kyR21yTExkazZaTllkNVJTMGpNM1VvNjlmWnVkT01OY1FfMkNodyJ9LHsicGF0aCI6Ik1ha2VmaWxlIiwicm9vdF9oYXNoIjoiR1MxYW40UEluMGZ2dnFCOUZCOXpqV1JCYjNDdWtQeFdDV09WOE1jU0N3ayJ9LHsicGF0aCI6IlJFQURNRS5tZCIsInJvb3RfaGFzaCI6ImdWd3B6TlpscVlGVm9LZVpWdTVKLXVaelhySTdQYlFtR2tic3NlR1cwNW8ifSx7InBhdGgiOiJfbG9jYWxlcy9lbi9tZXNzYWdlcy5qc29uIiwicm9vdF9oYXNoIjoiaDEzM2pHZXRsWGk2Z3RCbVNfYU5uUHY5cHhsTWhlaE51VHBtcEkyWVJoVSJ9LHsicGF0aCI6ImJhY2tncm91bmQuanMiLCJyb290X2hhc2giOiI0cWxYaDFOZGlGYWNpNGh0RGw3dGtKTkJsdWFfd0F5YTBib1JDMnh6QlA0In0seyJwYXRoIjoiYnJvd3Nlci1wb2x5ZmlsbC5qcyIsInJvb3RfaGFzaCI6IjFoWlVuR2JXeldjNmVBYmo3cUI2WGFPVGxBdk1BMU9aeDJoUDA0dF9zYVEifSx7InBhdGgiOiJjb250ZW50LmpzIiwicm9vdF9oYXNoIjoiYXgxZnpWUThpc05DWXh5UW5sWkRNbmNPRENnSWZQRFZRTzkzSkhYMmoyZyJ9LHsicGF0aCI6ImRldmVsb3Blci5wbmciLCJyb290X2hhc2giOiJ2ZGZwWTVwNDJNb2oybXFCeURLZFlvamFVSzhLYnFBZUkzNVJhTzQxbjNZIn0seyJwYXRoIjoiZGlyZWN0b3J5LnBuZyIsInJvb3RfaGFzaCI6Imk1eVhuTlJlWnBRT0w2VUxKUTNITjhxWkRxWEt4dUROWHBuUGt0Y0xBX1kifSx7InBhdGgiOiJkb25lLnBuZyIsInJvb3RfaGFzaCI6IjllTXctbmp5ZVpKYlU4a2xkZVlwQjdrTzFDMFloOXo1RHlfVFM4N00yd0kifSx7InBhdGgiOiJleHRlbnNpb25zLnBuZyIsInJvb3RfaGFzaCI6InVtZ2RfSFp6Rm1aRVZVT3NSWkFKOHg5ZG02QkU3UUlRQ002aFhNNXdMbWMifSx7InBhdGgiOiJmaW5pc2hlZC5wbmciLCJyb290X2hhc2giOiJuQ3Z6VFFQR0xpRHJCeUhuU001X0hzVVF3ak81VDAtM0phaXJ3VlF0Skd3In0seyJwYXRoIjoiaG9tZS5jc3MiLCJyb290X2hhc2giOiJDaUFNRVlfSFJKRHhsSHdiZmhFLTdDaGtrX1JzSFpnRVQzaHM3QWVZRVpJIn0seyJwYXRoIjoiaG9tZS5odG1sIiwicm9vdF9oYXNoIjoick1iOC1WZG4tWjhjVVlMeUNNbl9fZksta3NPVFJpR205bGk1WnJ1SHBBWSJ9LHsicGF0aCI6ImkycHNldHByb3h5LmpzLnBuZyIsInJvb3RfaGFzaCI6InlJamN1YmlBYTVTMWpsVGJhZGJkZV9qLXlIQ0FqREpCaDhUdHdWQUN5U1EifSx7InBhdGgiOiJpY29ucy90b29waWUucG5nIiwicm9vdF9oYXNoIjoiM3haaVZISTNtUU9jMFJHU1lnWFIxUXV3Z0xlNlZSVURsZWFvNVZwN0lfQSJ9LHsicGF0aCI6ImluZm8uY3NzIiwicm9vdF9oYXNoIjoialBsQVduNUs4Ulc3RnhvaGR4cF9HVndnN1ZBTWdvWXExZml0X0tRbzlSSSJ9LHsicGF0aCI6ImluZm8uanMiLCJyb290X2hhc2giOiJpSWtfZUdyTXdYdEFKTUpHVnpLUlhaRTg4ZWVHTjBrMGtEYTRuMTVLb2s4In0seyJwYXRoIjoibWFuYWdlci5wbmciLCJyb290X2hhc2giOiJyMC1kQ1BrVkpueHkyNDFwdzQwS3lIOWJEenM1TjhEdnY0NHJxQVhJSE9rIn0seyJwYXRoIjoibWFuaWZlc3QuanNvbiIsInJvb3RfaGFzaCI6ImVkcUt1WFNNTUFqS0dVNFlQV1dyUFFPYzBMRDhwVHRoRGZUVWtEVXdOZXcifSx7InBhdGgiOiJvcHRpb25zL29wdGlvbnMuY3NzIiwicm9vdF9oYXNoIjoiNmZQYlZCMTNoN2Q3NkNvY3VDNU5KN3ZqOE9HQ0I2ZVk0cEVETHJ6U3FKYyJ9LHsicGF0aCI6Im9wdGlvbnMvb3B0aW9ucy5odG1sIiwicm9vdF9oYXNoIjoiNkRFQnhvVWFSb2RETVBSODFnMGp3QTVNTTBmVXhuNmpXeXZzaHYzZ2dqUSJ9LHsicGF0aCI6Im9wdGlvbnMvb3B0aW9ucy5qcyIsInJvb3RfaGFzaCI6IjJSLXIyVlVFRzhRalZMdHFzVHlKbXBEM28zRXdGVjdFLUlyVk9qSmJWVE0ifSx7InBhdGgiOiJwZW9wbGUucG5nIiwicm9vdF9oYXNoIjoia0ZnbjdiTWU0WVJUSkViRXFvSTJZWEd5UnNLZlBpVUpwUXV6Y3l0YXhtYyJ9LHsicGF0aCI6InBsdWdpbnMucG5nIiwicm9vdF9oYXNoIjoiYkpnZkF1VUF1QnprVV9MRXdQVHZVYlF5dGYwQm4xSTV1TmFsOEtyU0hjcyJ9LHsicGF0aCI6InByaXZhY3kuanMiLCJyb290X2hhc2giOiJMTWZOdmRTWXMtVjh0YWpPbVplTDhjZ3hKUldKVmdnaVhqX3o0XzZkVzRzIn0seyJwYXRoIjoicHJveHkuanMiLCJyb290X2hhc2giOiJyVnhjQ2VvcDk1dmhLX3oxZGk5MHplOUd3M0steWgxdF8xMlViZTVsNG5nIn0seyJwYXRoIjoic2hhZGVzLnBuZyIsInJvb3RfaGFzaCI6IjhrQ1Z2QktuaWtMZVZtQnVMa01WNEZzNlQtWklieGoxMFZJS3lHRUtVNDAifSx7InBhdGgiOiJzeW5jLnBuZyIsInJvb3RfaGFzaCI6IjV6d1ZVWkdYMnlsRGN5d1hjdzJpaUR0N28yX1F2ajNPaHIwWG5QWEl5RnMifSx7InBhdGgiOiJ1bnBhY2tlZC5wbmciLCJyb290X2hhc2giOiJLUUZ3YXFIdU8yT01HZTZNNXd5ZG1xcnJwbkNEdW9yUFU3aVc3QVhRMmdJIn0seyJwYXRoIjoid2luZG93Lmh0bWwiLCJyb290X2hhc2giOiJBVU5OU1BqLVJabXYtRS13NnhXcXl5LS1iRVhsMkM5OEl4VDJEdWVGZDZRIn1dLCJmb3JtYXQiOiJ0cmVlaGFzaCIsImhhc2hfYmxvY2tfc2l6ZSI6NDA5Nn1dLCJpdGVtX2lkIjoiaWtkamNtb21nbGRmY2lvY25wZWtmbmRrbGtmZ2dscGUiLCJpdGVtX3ZlcnNpb24iOiIxLjI5IiwicHJvdG9jb2xfdmVyc2lvbiI6MX0","signatures":[{"header":{"kid":"publisher"},"protected":"eyJhbGciOiJSUzI1NiJ9","signature":"MnagjSc3N-RaPvxHuzypCDuVFz-JbwCW1LKcg4HqS5M-T9KkEH5NoNa9ipUdWBkwrSF0sFAU-jHUSHQ6Ht75SH3wROOS0chVQf7dYw7KjZMHLd-LAAIBygApS8DNrWE931b5XM-vh_F3VYlbvziiL1roW7OAZgoIUy_MPQ07Ynbfl0K-UyVXeUJY9qzYGCRdKFG_wsvajIGM1Y60aw66MKs2zKLarwLCRqKAN_A31nzYBm-QjoUPSK4jnzAm5Lv24oVfsWJNXmJ8nPQO3pRCF8AT0rA8ue2cEqA3zSLOkHQupmmLSmjBKBPMmPtFJCgeKvzPajo32JuAaCkWokhiwQ"},{"header":{"kid":"webstore"},"protected":"eyJhbGciOiJSUzI1NiJ9","signature":"P02kDKuZmltr_huxTnsbIzMzERDvbdwsce3ZbEJjWbE7n01TXoQr7Z62LtqZMcau2m78A-eydRwMQ6TnpvFxNoHIDFOA9d4mGdfhSwTSR4-rGJa3cSo_66VznYzMAVzfssW4_o1iTksdOtbebQCQ5TS7f2bNe1AQMx7lTDoiskVaFNeY2adByacpQp2yXWHAx9K_98hG1J-njNvokairY0ZdaJcR76pN2v9W-D8A6Wvaxy4WeAXZyFoJy_eFNjP4yG-6nZ1OtxirQ7kiDx1fKtvcDx2hEBC5noaMXygVZszAsvrrMgkhlsb1bBdptAJRPUAXXXjp6Ijk2U6z8S-V0g"}]}}] \ No newline at end of file diff --git a/src/i2p.chromium.base.profile/extensions/i2pchrome.js/background.js b/src/i2p.chromium.base.profile/extensions/i2pchrome.js/background.js new file mode 100644 index 0000000..98c4628 --- /dev/null +++ b/src/i2p.chromium.base.profile/extensions/i2pchrome.js/background.js @@ -0,0 +1,54 @@ +function platformCallback(platformInfo) { + if (platformInfo.PlatformOs == "android") { + console.log("android detected"); + return true; + } else { + console.log("desktop detected"); + return false; + } +} + +function isDroid() { + return chrome.runtime.getPlatformInfo(platformCallback); +} + +function isLocalHost(url) { + //var x = new RegExp("/(^127\.)|(^192\.168\.)|(^10\.)|(^172\.1[6-9]\.)|(^172\.2[0-9]\.)|(^172\.3[0-1]\.)|(^::1$)|(^[fF][cCdD])/") + var r = false; ///(^127\.)|(^192\.168\.)|(^10\.)|(^172\.1[6-9]\.)|(^172\.2[0-9]\.)|(^172\.3[0-1]\.)|(^::1$)|(^[fF][cCdD])/.test(url) + if (r == false) { + r = url.indexOf("://localhost:") != -1; + } + if (r == false) { + r = url.indexOf("://127.0.0.1:") != -1; + } + console.log("localhost:", r, "on url", url); + return r; +} + +function isRouterHost(url) { + var controlPort = 7657; //getControlPort(); + var r = false; + if (r == false) { + r = url.indexOf("://localhost:" + controlPort) != -1; + } + if (r == false) { + r = url.indexOf("://127.0.0.1:" + controlPort) != -1; + } + console.log("routerhost:", r, "on url", url); + return r; +} + +chrome.webRequest.onBeforeRequest.addListener( + function (details) { + let localhost = isLocalHost(details.url); + let routerhost = isRouterHost(details.url); + console.log("localhost: ", localhost, "routerhost: ", routerhost); + if (localhost) { + if (!routerhost) { + return { cancel: true }; + } + } + }, + { urls: [""] }, + ["blocking"] +); diff --git a/src/i2p.chromium.base.profile/extensions/i2pchrome.js/browser-polyfill.js b/src/i2p.chromium.base.profile/extensions/i2pchrome.js/browser-polyfill.js new file mode 100644 index 0000000..754d103 --- /dev/null +++ b/src/i2p.chromium.base.profile/extensions/i2pchrome.js/browser-polyfill.js @@ -0,0 +1,1292 @@ +(function (global, factory) { + if (typeof define === "function" && define.amd) { + define("webextension-polyfill", ["module"], factory); + } else if (typeof exports !== "undefined") { + factory(module); + } else { + var mod = { + exports: {}, + }; + factory(mod); + global.browser = mod.exports; + } +})( + typeof globalThis !== "undefined" + ? globalThis + : typeof self !== "undefined" + ? self + : this, + function (module) { + /* webextension-polyfill - v0.6.0 - Mon Dec 23 2019 12:32:53 */ + + /* -*- Mode: indent-tabs-mode: nil; js-indent-level: 2 -*- */ + + /* vim: set sts=2 sw=2 et tw=80: */ + + /* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + "use strict"; + + if ( + typeof browser === "undefined" || + Object.getPrototypeOf(browser) !== Object.prototype + ) { + const CHROME_SEND_MESSAGE_CALLBACK_NO_RESPONSE_MESSAGE = + "The message port closed before a response was received."; + const SEND_RESPONSE_DEPRECATION_WARNING = + "Returning a Promise is the preferred way to send a reply from an onMessage/onMessageExternal listener, as the sendResponse will be removed from the specs (See https://developer.mozilla.org/docs/Mozilla/Add-ons/WebExtensions/API/runtime/onMessage)"; // Wrapping the bulk of this polyfill in a one-time-use function is a minor + // optimization for Firefox. Since Spidermonkey does not fully parse the + // contents of a function until the first time it's called, and since it will + // never actually need to be called, this allows the polyfill to be included + // in Firefox nearly for free. + + const wrapAPIs = (extensionAPIs) => { + // NOTE: apiMetadata is associated to the content of the api-metadata.json file + // at build time by replacing the following "include" with the content of the + // JSON file. + const apiMetadata = { + alarms: { + clear: { + minArgs: 0, + maxArgs: 1, + }, + clearAll: { + minArgs: 0, + maxArgs: 0, + }, + get: { + minArgs: 0, + maxArgs: 1, + }, + getAll: { + minArgs: 0, + maxArgs: 0, + }, + }, + bookmarks: { + create: { + minArgs: 1, + maxArgs: 1, + }, + get: { + minArgs: 1, + maxArgs: 1, + }, + getChildren: { + minArgs: 1, + maxArgs: 1, + }, + getRecent: { + minArgs: 1, + maxArgs: 1, + }, + getSubTree: { + minArgs: 1, + maxArgs: 1, + }, + getTree: { + minArgs: 0, + maxArgs: 0, + }, + move: { + minArgs: 2, + maxArgs: 2, + }, + remove: { + minArgs: 1, + maxArgs: 1, + }, + removeTree: { + minArgs: 1, + maxArgs: 1, + }, + search: { + minArgs: 1, + maxArgs: 1, + }, + update: { + minArgs: 2, + maxArgs: 2, + }, + }, + browserAction: { + disable: { + minArgs: 0, + maxArgs: 1, + fallbackToNoCallback: true, + }, + enable: { + minArgs: 0, + maxArgs: 1, + fallbackToNoCallback: true, + }, + getBadgeBackgroundColor: { + minArgs: 1, + maxArgs: 1, + }, + getBadgeText: { + minArgs: 1, + maxArgs: 1, + }, + getPopup: { + minArgs: 1, + maxArgs: 1, + }, + getTitle: { + minArgs: 1, + maxArgs: 1, + }, + openPopup: { + minArgs: 0, + maxArgs: 0, + }, + setBadgeBackgroundColor: { + minArgs: 1, + maxArgs: 1, + fallbackToNoCallback: true, + }, + setBadgeText: { + minArgs: 1, + maxArgs: 1, + fallbackToNoCallback: true, + }, + setIcon: { + minArgs: 1, + maxArgs: 1, + }, + setPopup: { + minArgs: 1, + maxArgs: 1, + fallbackToNoCallback: true, + }, + setTitle: { + minArgs: 1, + maxArgs: 1, + fallbackToNoCallback: true, + }, + }, + browsingData: { + remove: { + minArgs: 2, + maxArgs: 2, + }, + removeCache: { + minArgs: 1, + maxArgs: 1, + }, + removeCookies: { + minArgs: 1, + maxArgs: 1, + }, + removeDownloads: { + minArgs: 1, + maxArgs: 1, + }, + removeFormData: { + minArgs: 1, + maxArgs: 1, + }, + removeHistory: { + minArgs: 1, + maxArgs: 1, + }, + removeLocalStorage: { + minArgs: 1, + maxArgs: 1, + }, + removePasswords: { + minArgs: 1, + maxArgs: 1, + }, + removePluginData: { + minArgs: 1, + maxArgs: 1, + }, + settings: { + minArgs: 0, + maxArgs: 0, + }, + }, + commands: { + getAll: { + minArgs: 0, + maxArgs: 0, + }, + }, + contextMenus: { + remove: { + minArgs: 1, + maxArgs: 1, + }, + removeAll: { + minArgs: 0, + maxArgs: 0, + }, + update: { + minArgs: 2, + maxArgs: 2, + }, + }, + cookies: { + get: { + minArgs: 1, + maxArgs: 1, + }, + getAll: { + minArgs: 1, + maxArgs: 1, + }, + getAllCookieStores: { + minArgs: 0, + maxArgs: 0, + }, + remove: { + minArgs: 1, + maxArgs: 1, + }, + set: { + minArgs: 1, + maxArgs: 1, + }, + }, + devtools: { + inspectedWindow: { + eval: { + minArgs: 1, + maxArgs: 2, + singleCallbackArg: false, + }, + }, + panels: { + create: { + minArgs: 3, + maxArgs: 3, + singleCallbackArg: true, + }, + }, + }, + downloads: { + cancel: { + minArgs: 1, + maxArgs: 1, + }, + download: { + minArgs: 1, + maxArgs: 1, + }, + erase: { + minArgs: 1, + maxArgs: 1, + }, + getFileIcon: { + minArgs: 1, + maxArgs: 2, + }, + open: { + minArgs: 1, + maxArgs: 1, + fallbackToNoCallback: true, + }, + pause: { + minArgs: 1, + maxArgs: 1, + }, + removeFile: { + minArgs: 1, + maxArgs: 1, + }, + resume: { + minArgs: 1, + maxArgs: 1, + }, + search: { + minArgs: 1, + maxArgs: 1, + }, + show: { + minArgs: 1, + maxArgs: 1, + fallbackToNoCallback: true, + }, + }, + extension: { + isAllowedFileSchemeAccess: { + minArgs: 0, + maxArgs: 0, + }, + isAllowedIncognitoAccess: { + minArgs: 0, + maxArgs: 0, + }, + }, + history: { + addUrl: { + minArgs: 1, + maxArgs: 1, + }, + deleteAll: { + minArgs: 0, + maxArgs: 0, + }, + deleteRange: { + minArgs: 1, + maxArgs: 1, + }, + deleteUrl: { + minArgs: 1, + maxArgs: 1, + }, + getVisits: { + minArgs: 1, + maxArgs: 1, + }, + search: { + minArgs: 1, + maxArgs: 1, + }, + }, + i18n: { + detectLanguage: { + minArgs: 1, + maxArgs: 1, + }, + getAcceptLanguages: { + minArgs: 0, + maxArgs: 0, + }, + }, + identity: { + launchWebAuthFlow: { + minArgs: 1, + maxArgs: 1, + }, + }, + idle: { + queryState: { + minArgs: 1, + maxArgs: 1, + }, + }, + management: { + get: { + minArgs: 1, + maxArgs: 1, + }, + getAll: { + minArgs: 0, + maxArgs: 0, + }, + getSelf: { + minArgs: 0, + maxArgs: 0, + }, + setEnabled: { + minArgs: 2, + maxArgs: 2, + }, + uninstallSelf: { + minArgs: 0, + maxArgs: 1, + }, + }, + notifications: { + clear: { + minArgs: 1, + maxArgs: 1, + }, + create: { + minArgs: 1, + maxArgs: 2, + }, + getAll: { + minArgs: 0, + maxArgs: 0, + }, + getPermissionLevel: { + minArgs: 0, + maxArgs: 0, + }, + update: { + minArgs: 2, + maxArgs: 2, + }, + }, + pageAction: { + getPopup: { + minArgs: 1, + maxArgs: 1, + }, + getTitle: { + minArgs: 1, + maxArgs: 1, + }, + hide: { + minArgs: 1, + maxArgs: 1, + fallbackToNoCallback: true, + }, + setIcon: { + minArgs: 1, + maxArgs: 1, + }, + setPopup: { + minArgs: 1, + maxArgs: 1, + fallbackToNoCallback: true, + }, + setTitle: { + minArgs: 1, + maxArgs: 1, + fallbackToNoCallback: true, + }, + show: { + minArgs: 1, + maxArgs: 1, + fallbackToNoCallback: true, + }, + }, + permissions: { + contains: { + minArgs: 1, + maxArgs: 1, + }, + getAll: { + minArgs: 0, + maxArgs: 0, + }, + remove: { + minArgs: 1, + maxArgs: 1, + }, + request: { + minArgs: 1, + maxArgs: 1, + }, + }, + runtime: { + getBackgroundPage: { + minArgs: 0, + maxArgs: 0, + }, + getPlatformInfo: { + minArgs: 0, + maxArgs: 0, + }, + openOptionsPage: { + minArgs: 0, + maxArgs: 0, + }, + requestUpdateCheck: { + minArgs: 0, + maxArgs: 0, + }, + sendMessage: { + minArgs: 1, + maxArgs: 3, + }, + sendNativeMessage: { + minArgs: 2, + maxArgs: 2, + }, + setUninstallURL: { + minArgs: 1, + maxArgs: 1, + }, + }, + sessions: { + getDevices: { + minArgs: 0, + maxArgs: 1, + }, + getRecentlyClosed: { + minArgs: 0, + maxArgs: 1, + }, + restore: { + minArgs: 0, + maxArgs: 1, + }, + }, + storage: { + local: { + clear: { + minArgs: 0, + maxArgs: 0, + }, + get: { + minArgs: 0, + maxArgs: 1, + }, + getBytesInUse: { + minArgs: 0, + maxArgs: 1, + }, + remove: { + minArgs: 1, + maxArgs: 1, + }, + set: { + minArgs: 1, + maxArgs: 1, + }, + }, + managed: { + get: { + minArgs: 0, + maxArgs: 1, + }, + getBytesInUse: { + minArgs: 0, + maxArgs: 1, + }, + }, + sync: { + clear: { + minArgs: 0, + maxArgs: 0, + }, + get: { + minArgs: 0, + maxArgs: 1, + }, + getBytesInUse: { + minArgs: 0, + maxArgs: 1, + }, + remove: { + minArgs: 1, + maxArgs: 1, + }, + set: { + minArgs: 1, + maxArgs: 1, + }, + }, + }, + tabs: { + captureVisibleTab: { + minArgs: 0, + maxArgs: 2, + }, + create: { + minArgs: 1, + maxArgs: 1, + }, + detectLanguage: { + minArgs: 0, + maxArgs: 1, + }, + discard: { + minArgs: 0, + maxArgs: 1, + }, + duplicate: { + minArgs: 1, + maxArgs: 1, + }, + executeScript: { + minArgs: 1, + maxArgs: 2, + }, + get: { + minArgs: 1, + maxArgs: 1, + }, + getCurrent: { + minArgs: 0, + maxArgs: 0, + }, + getZoom: { + minArgs: 0, + maxArgs: 1, + }, + getZoomSettings: { + minArgs: 0, + maxArgs: 1, + }, + highlight: { + minArgs: 1, + maxArgs: 1, + }, + insertCSS: { + minArgs: 1, + maxArgs: 2, + }, + move: { + minArgs: 2, + maxArgs: 2, + }, + query: { + minArgs: 1, + maxArgs: 1, + }, + reload: { + minArgs: 0, + maxArgs: 2, + }, + remove: { + minArgs: 1, + maxArgs: 1, + }, + removeCSS: { + minArgs: 1, + maxArgs: 2, + }, + sendMessage: { + minArgs: 2, + maxArgs: 3, + }, + setZoom: { + minArgs: 1, + maxArgs: 2, + }, + setZoomSettings: { + minArgs: 1, + maxArgs: 2, + }, + update: { + minArgs: 1, + maxArgs: 2, + }, + }, + topSites: { + get: { + minArgs: 0, + maxArgs: 0, + }, + }, + webNavigation: { + getAllFrames: { + minArgs: 1, + maxArgs: 1, + }, + getFrame: { + minArgs: 1, + maxArgs: 1, + }, + }, + webRequest: { + handlerBehaviorChanged: { + minArgs: 0, + maxArgs: 0, + }, + }, + windows: { + create: { + minArgs: 0, + maxArgs: 1, + }, + get: { + minArgs: 1, + maxArgs: 2, + }, + getAll: { + minArgs: 0, + maxArgs: 1, + }, + getCurrent: { + minArgs: 0, + maxArgs: 1, + }, + getLastFocused: { + minArgs: 0, + maxArgs: 1, + }, + remove: { + minArgs: 1, + maxArgs: 1, + }, + update: { + minArgs: 2, + maxArgs: 2, + }, + }, + }; + + if (Object.keys(apiMetadata).length === 0) { + throw new Error( + "api-metadata.json has not been included in browser-polyfill" + ); + } + /** + * A WeakMap subclass which creates and stores a value for any key which does + * not exist when accessed, but behaves exactly as an ordinary WeakMap + * otherwise. + * + * @param {function} createItem + * A function which will be called in order to create the value for any + * key which does not exist, the first time it is accessed. The + * function receives, as its only argument, the key being created. + */ + + class DefaultWeakMap extends WeakMap { + constructor(createItem, items = undefined) { + super(items); + this.createItem = createItem; + } + + get(key) { + if (!this.has(key)) { + this.set(key, this.createItem(key)); + } + + return super.get(key); + } + } + /** + * Returns true if the given object is an object with a `then` method, and can + * therefore be assumed to behave as a Promise. + * + * @param {*} value The value to test. + * @returns {boolean} True if the value is thenable. + */ + + const isThenable = (value) => { + return ( + value && + typeof value === "object" && + typeof value.then === "function" + ); + }; + /** + * Creates and returns a function which, when called, will resolve or reject + * the given promise based on how it is called: + * + * - If, when called, `chrome.runtime.lastError` contains a non-null object, + * the promise is rejected with that value. + * - If the function is called with exactly one argument, the promise is + * resolved to that value. + * - Otherwise, the promise is resolved to an array containing all of the + * function's arguments. + * + * @param {object} promise + * An object containing the resolution and rejection functions of a + * promise. + * @param {function} promise.resolve + * The promise's resolution function. + * @param {function} promise.rejection + * The promise's rejection function. + * @param {object} metadata + * Metadata about the wrapped method which has created the callback. + * @param {integer} metadata.maxResolvedArgs + * The maximum number of arguments which may be passed to the + * callback created by the wrapped async function. + * + * @returns {function} + * The generated callback function. + */ + + const makeCallback = (promise, metadata) => { + return (...callbackArgs) => { + if (extensionAPIs.runtime.lastError) { + promise.reject(extensionAPIs.runtime.lastError); + } else if ( + metadata.singleCallbackArg || + (callbackArgs.length <= 1 && metadata.singleCallbackArg !== false) + ) { + promise.resolve(callbackArgs[0]); + } else { + promise.resolve(callbackArgs); + } + }; + }; + + const pluralizeArguments = (numArgs) => + numArgs == 1 ? "argument" : "arguments"; + /** + * Creates a wrapper function for a method with the given name and metadata. + * + * @param {string} name + * The name of the method which is being wrapped. + * @param {object} metadata + * Metadata about the method being wrapped. + * @param {integer} metadata.minArgs + * The minimum number of arguments which must be passed to the + * function. If called with fewer than this number of arguments, the + * wrapper will raise an exception. + * @param {integer} metadata.maxArgs + * The maximum number of arguments which may be passed to the + * function. If called with more than this number of arguments, the + * wrapper will raise an exception. + * @param {integer} metadata.maxResolvedArgs + * The maximum number of arguments which may be passed to the + * callback created by the wrapped async function. + * + * @returns {function(object, ...*)} + * The generated wrapper function. + */ + + const wrapAsyncFunction = (name, metadata) => { + return function asyncFunctionWrapper(target, ...args) { + if (args.length < metadata.minArgs) { + throw new Error( + `Expected at least ${metadata.minArgs} ${pluralizeArguments( + metadata.minArgs + )} for ${name}(), got ${args.length}` + ); + } + + if (args.length > metadata.maxArgs) { + throw new Error( + `Expected at most ${metadata.maxArgs} ${pluralizeArguments( + metadata.maxArgs + )} for ${name}(), got ${args.length}` + ); + } + + return new Promise((resolve, reject) => { + if (metadata.fallbackToNoCallback) { + // This API method has currently no callback on Chrome, but it return a promise on Firefox, + // and so the polyfill will try to call it with a callback first, and it will fallback + // to not passing the callback if the first call fails. + try { + target[name]( + ...args, + makeCallback( + { + resolve, + reject, + }, + metadata + ) + ); + } catch (cbError) { + console.warn( + `${name} API method doesn't seem to support the callback parameter, ` + + "falling back to call it without a callback: ", + cbError + ); + target[name](...args); // Update the API method metadata, so that the next API calls will not try to + // use the unsupported callback anymore. + + metadata.fallbackToNoCallback = false; + metadata.noCallback = true; + resolve(); + } + } else if (metadata.noCallback) { + target[name](...args); + resolve(); + } else { + target[name]( + ...args, + makeCallback( + { + resolve, + reject, + }, + metadata + ) + ); + } + }); + }; + }; + /** + * Wraps an existing method of the target object, so that calls to it are + * intercepted by the given wrapper function. The wrapper function receives, + * as its first argument, the original `target` object, followed by each of + * the arguments passed to the original method. + * + * @param {object} target + * The original target object that the wrapped method belongs to. + * @param {function} method + * The method being wrapped. This is used as the target of the Proxy + * object which is created to wrap the method. + * @param {function} wrapper + * The wrapper function which is called in place of a direct invocation + * of the wrapped method. + * + * @returns {Proxy} + * A Proxy object for the given method, which invokes the given wrapper + * method in its place. + */ + + const wrapMethod = (target, method, wrapper) => { + return new Proxy(method, { + apply(targetMethod, thisObj, args) { + return wrapper.call(thisObj, target, ...args); + }, + }); + }; + + let hasOwnProperty = Function.call.bind( + Object.prototype.hasOwnProperty + ); + /** + * Wraps an object in a Proxy which intercepts and wraps certain methods + * based on the given `wrappers` and `metadata` objects. + * + * @param {object} target + * The target object to wrap. + * + * @param {object} [wrappers = {}] + * An object tree containing wrapper functions for special cases. Any + * function present in this object tree is called in place of the + * method in the same location in the `target` object tree. These + * wrapper methods are invoked as described in {@see wrapMethod}. + * + * @param {object} [metadata = {}] + * An object tree containing metadata used to automatically generate + * Promise-based wrapper functions for asynchronous. Any function in + * the `target` object tree which has a corresponding metadata object + * in the same location in the `metadata` tree is replaced with an + * automatically-generated wrapper function, as described in + * {@see wrapAsyncFunction} + * + * @returns {Proxy} + */ + + const wrapObject = (target, wrappers = {}, metadata = {}) => { + let cache = Object.create(null); + let handlers = { + has(proxyTarget, prop) { + return prop in target || prop in cache; + }, + + get(proxyTarget, prop, receiver) { + if (prop in cache) { + return cache[prop]; + } + + if (!(prop in target)) { + return undefined; + } + + let value = target[prop]; + + if (typeof value === "function") { + // This is a method on the underlying object. Check if we need to do + // any wrapping. + if (typeof wrappers[prop] === "function") { + // We have a special-case wrapper for this method. + value = wrapMethod(target, target[prop], wrappers[prop]); + } else if (hasOwnProperty(metadata, prop)) { + // This is an async method that we have metadata for. Create a + // Promise wrapper for it. + let wrapper = wrapAsyncFunction(prop, metadata[prop]); + value = wrapMethod(target, target[prop], wrapper); + } else { + // This is a method that we don't know or care about. Return the + // original method, bound to the underlying object. + value = value.bind(target); + } + } else if ( + typeof value === "object" && + value !== null && + (hasOwnProperty(wrappers, prop) || + hasOwnProperty(metadata, prop)) + ) { + // This is an object that we need to do some wrapping for the children + // of. Create a sub-object wrapper for it with the appropriate child + // metadata. + value = wrapObject(value, wrappers[prop], metadata[prop]); + } else if (hasOwnProperty(metadata, "*")) { + // Wrap all properties in * namespace. + value = wrapObject(value, wrappers[prop], metadata["*"]); + } else { + // We don't need to do any wrapping for this property, + // so just forward all access to the underlying object. + Object.defineProperty(cache, prop, { + configurable: true, + enumerable: true, + + get() { + return target[prop]; + }, + + set(value) { + target[prop] = value; + }, + }); + return value; + } + + cache[prop] = value; + return value; + }, + + set(proxyTarget, prop, value, receiver) { + if (prop in cache) { + cache[prop] = value; + } else { + target[prop] = value; + } + + return true; + }, + + defineProperty(proxyTarget, prop, desc) { + return Reflect.defineProperty(cache, prop, desc); + }, + + deleteProperty(proxyTarget, prop) { + return Reflect.deleteProperty(cache, prop); + }, + }; // Per contract of the Proxy API, the "get" proxy handler must return the + // original value of the target if that value is declared read-only and + // non-configurable. For this reason, we create an object with the + // prototype set to `target` instead of using `target` directly. + // Otherwise we cannot return a custom object for APIs that + // are declared read-only and non-configurable, such as `chrome.devtools`. + // + // The proxy handlers themselves will still use the original `target` + // instead of the `proxyTarget`, so that the methods and properties are + // dereferenced via the original targets. + + let proxyTarget = Object.create(target); + return new Proxy(proxyTarget, handlers); + }; + /** + * Creates a set of wrapper functions for an event object, which handles + * wrapping of listener functions that those messages are passed. + * + * A single wrapper is created for each listener function, and stored in a + * map. Subsequent calls to `addListener`, `hasListener`, or `removeListener` + * retrieve the original wrapper, so that attempts to remove a + * previously-added listener work as expected. + * + * @param {DefaultWeakMap} wrapperMap + * A DefaultWeakMap object which will create the appropriate wrapper + * for a given listener function when one does not exist, and retrieve + * an existing one when it does. + * + * @returns {object} + */ + + const wrapEvent = (wrapperMap) => ({ + addListener(target, listener, ...args) { + target.addListener(wrapperMap.get(listener), ...args); + }, + + hasListener(target, listener) { + return target.hasListener(wrapperMap.get(listener)); + }, + + removeListener(target, listener) { + target.removeListener(wrapperMap.get(listener)); + }, + }); // Keep track if the deprecation warning has been logged at least once. + + let loggedSendResponseDeprecationWarning = false; + const onMessageWrappers = new DefaultWeakMap((listener) => { + if (typeof listener !== "function") { + return listener; + } + /** + * Wraps a message listener function so that it may send responses based on + * its return value, rather than by returning a sentinel value and calling a + * callback. If the listener function returns a Promise, the response is + * sent when the promise either resolves or rejects. + * + * @param {*} message + * The message sent by the other end of the channel. + * @param {object} sender + * Details about the sender of the message. + * @param {function(*)} sendResponse + * A callback which, when called with an arbitrary argument, sends + * that value as a response. + * @returns {boolean} + * True if the wrapped listener returned a Promise, which will later + * yield a response. False otherwise. + */ + + return function onMessage(message, sender, sendResponse) { + let didCallSendResponse = false; + let wrappedSendResponse; + let sendResponsePromise = new Promise((resolve) => { + wrappedSendResponse = function (response) { + if (!loggedSendResponseDeprecationWarning) { + console.warn( + SEND_RESPONSE_DEPRECATION_WARNING, + new Error().stack + ); + loggedSendResponseDeprecationWarning = true; + } + + didCallSendResponse = true; + resolve(response); + }; + }); + let result; + + try { + result = listener(message, sender, wrappedSendResponse); + } catch (err) { + result = Promise.reject(err); + } + + const isResultThenable = result !== true && isThenable(result); // If the listener didn't returned true or a Promise, or called + // wrappedSendResponse synchronously, we can exit earlier + // because there will be no response sent from this listener. + + if (result !== true && !isResultThenable && !didCallSendResponse) { + return false; + } // A small helper to send the message if the promise resolves + // and an error if the promise rejects (a wrapped sendMessage has + // to translate the message into a resolved promise or a rejected + // promise). + + const sendPromisedResult = (promise) => { + promise + .then( + (msg) => { + // send the message value. + sendResponse(msg); + }, + (error) => { + // Send a JSON representation of the error if the rejected value + // is an instance of error, or the object itself otherwise. + let message; + + if ( + error && + (error instanceof Error || + typeof error.message === "string") + ) { + message = error.message; + } else { + message = "An unexpected error occurred"; + } + + sendResponse({ + __mozWebExtensionPolyfillReject__: true, + message, + }); + } + ) + .catch((err) => { + // Print an error on the console if unable to send the response. + console.error("Failed to send onMessage rejected reply", err); + }); + }; // If the listener returned a Promise, send the resolved value as a + // result, otherwise wait the promise related to the wrappedSendResponse + // callback to resolve and send it as a response. + + if (isResultThenable) { + sendPromisedResult(result); + } else { + sendPromisedResult(sendResponsePromise); + } // Let Chrome know that the listener is replying. + + return true; + }; + }); + + const wrappedSendMessageCallback = ({ reject, resolve }, reply) => { + if (extensionAPIs.runtime.lastError) { + // Detect when none of the listeners replied to the sendMessage call and resolve + // the promise to undefined as in Firefox. + // See https://github.com/mozilla/webextension-polyfill/issues/130 + if ( + extensionAPIs.runtime.lastError.message === + CHROME_SEND_MESSAGE_CALLBACK_NO_RESPONSE_MESSAGE + ) { + resolve(); + } else { + reject(extensionAPIs.runtime.lastError); + } + } else if (reply && reply.__mozWebExtensionPolyfillReject__) { + // Convert back the JSON representation of the error into + // an Error instance. + reject(new Error(reply.message)); + } else { + resolve(reply); + } + }; + + const wrappedSendMessage = ( + name, + metadata, + apiNamespaceObj, + ...args + ) => { + if (args.length < metadata.minArgs) { + throw new Error( + `Expected at least ${metadata.minArgs} ${pluralizeArguments( + metadata.minArgs + )} for ${name}(), got ${args.length}` + ); + } + + if (args.length > metadata.maxArgs) { + throw new Error( + `Expected at most ${metadata.maxArgs} ${pluralizeArguments( + metadata.maxArgs + )} for ${name}(), got ${args.length}` + ); + } + + return new Promise((resolve, reject) => { + const wrappedCb = wrappedSendMessageCallback.bind(null, { + resolve, + reject, + }); + args.push(wrappedCb); + apiNamespaceObj.sendMessage(...args); + }); + }; + + const staticWrappers = { + runtime: { + onMessage: wrapEvent(onMessageWrappers), + onMessageExternal: wrapEvent(onMessageWrappers), + sendMessage: wrappedSendMessage.bind(null, "sendMessage", { + minArgs: 1, + maxArgs: 3, + }), + }, + tabs: { + sendMessage: wrappedSendMessage.bind(null, "sendMessage", { + minArgs: 2, + maxArgs: 3, + }), + }, + }; + const settingMetadata = { + clear: { + minArgs: 1, + maxArgs: 1, + }, + get: { + minArgs: 1, + maxArgs: 1, + }, + set: { + minArgs: 1, + maxArgs: 1, + }, + }; + apiMetadata.privacy = { + network: { + "*": settingMetadata, + }, + services: { + "*": settingMetadata, + }, + websites: { + "*": settingMetadata, + }, + }; + return wrapObject(extensionAPIs, staticWrappers, apiMetadata); + }; + + if ( + typeof chrome != "object" || + !chrome || + !chrome.runtime || + !chrome.runtime.id + ) { + throw new Error( + "This script should only be loaded in a browser extension." + ); + } // The build process adds a UMD wrapper around this file, which makes the + // `module` variable available. + + module.exports = wrapAPIs(chrome); + } else { + module.exports = browser; + } + } +); +//# sourceMappingURL=browser-polyfill.js.map diff --git a/src/i2p.chromium.base.profile/extensions/i2pchrome.js/content.js b/src/i2p.chromium.base.profile/extensions/i2pchrome.js/content.js new file mode 100644 index 0000000..186a25f --- /dev/null +++ b/src/i2p.chromium.base.profile/extensions/i2pchrome.js/content.js @@ -0,0 +1,19 @@ +/*var infoTitle = document.getElementById("text-section-header"); +infoTitle.textContent = chrome.i18n.getMessage("infoTitle"); +*/ +/*var infoMessage = document.getElementById("text-section-helptext"); +infoMessage.textContent = chrome.i18n.getMessage("infoMessage"); + +var helpMessage = document.getElementById("window-create-forum-panel"); +helpMessage.textContent = chrome.i18n.getMessage("forumMessage");*/ +/* +var helpMessage = document.getElementById('window-create-help-panel'); +helpMessage.textContent = chrome.i18n.getMessage("helpMessage") +*/ +/* +var newsMessage = document.getElementById("window-create-news-panel"); +newsMessage.textContent = chrome.i18n.getMessage("newsMessage"); + +var clearData = document.getElementByID("clear-chrome-data"); +cleardata.textContent = chrome.i18n.getMessage("clearData"); +*/ diff --git a/src/i2p.chromium.base.profile/extensions/i2pchrome.js/developer.png b/src/i2p.chromium.base.profile/extensions/i2pchrome.js/developer.png new file mode 100644 index 0000000..d065dbe Binary files /dev/null and b/src/i2p.chromium.base.profile/extensions/i2pchrome.js/developer.png differ diff --git a/src/i2p.chromium.base.profile/extensions/i2pchrome.js/directory.png b/src/i2p.chromium.base.profile/extensions/i2pchrome.js/directory.png new file mode 100644 index 0000000..1aff1e7 Binary files /dev/null and b/src/i2p.chromium.base.profile/extensions/i2pchrome.js/directory.png differ diff --git a/src/i2p.chromium.base.profile/extensions/i2pchrome.js/done.png b/src/i2p.chromium.base.profile/extensions/i2pchrome.js/done.png new file mode 100644 index 0000000..021e745 Binary files /dev/null and b/src/i2p.chromium.base.profile/extensions/i2pchrome.js/done.png differ diff --git a/src/i2p.chromium.base.profile/extensions/i2pchrome.js/extensions.png b/src/i2p.chromium.base.profile/extensions/i2pchrome.js/extensions.png new file mode 100644 index 0000000..cd3e8ef Binary files /dev/null and b/src/i2p.chromium.base.profile/extensions/i2pchrome.js/extensions.png differ diff --git a/src/i2p.chromium.base.profile/extensions/i2pchrome.js/finished.png b/src/i2p.chromium.base.profile/extensions/i2pchrome.js/finished.png new file mode 100644 index 0000000..3cfbf15 Binary files /dev/null and b/src/i2p.chromium.base.profile/extensions/i2pchrome.js/finished.png differ diff --git a/src/i2p.chromium.base.profile/extensions/i2pchrome.js/home.css b/src/i2p.chromium.base.profile/extensions/i2pchrome.js/home.css new file mode 100644 index 0000000..9fdf1f3 --- /dev/null +++ b/src/i2p.chromium.base.profile/extensions/i2pchrome.js/home.css @@ -0,0 +1,290 @@ +* { + padding: 0; + margin: 0 +} +html { + height: 100% +} +a, +button { + color: #3b6bbf; + text-decoration: none; + font-weight: 700; + word-wrap: break-word; + outline: 0 +} +.applicationDesc { + color: #81888f; + text-decoration: none; + font-weight: 700; + word-wrap: break-word; + outline: 0 +} +.applicationDesc:hover, +a:hover, +button:hover { + color: #495057; + text-decoration: none; + font-weight: 700; + word-wrap: break-word; + outline: 0 +} +button { + border: none; + cursor: pointer; + color: #3b6bbf; + text-decoration: none; + font-weight: 700; + word-wrap: break-word; + outline: 0 +} +body { + display: flex; + flex-direction: column; + font-family: "Droid Sans","Noto Sans",Ubuntu,"Segoe UI","Lucida Grande",Verdana,Helvetica,sans-serif; + width: 100%; + height: 100%; + margin: 0 auto; + padding: 0; + color: #495057; + background-attachment: fixed; + background-size: 100% 100%; + text-decoration: none; + font-weight: 700; + word-wrap: break-word; + outline: 0 +} +.background { + background-color: #f8f8ff; + height: 100% +} +p { + line-height: 32px; + font-size: 17px; + font-family: "Droid Sans","Noto Sans",Ubuntu,"Segoe UI","Lucida Grande",Verdana,Helvetica,sans-serif; + text-decoration: none; + color: #495057; + font-weight: 700; + word-wrap: break-word; + outline: 0 +} +.content { + min-height: 3rem; + padding: 1rem; + margin: 1.5rem; + display: inline-block; + border: 1px solid #d9d9d6; + border-radius: 2px; + box-shadow: inset 0 0 0 1px #fff,0 0 1px #ccc; + background: #f8f8ff; + min-width: 95% +} +.application-info, +.extended-info { + min-height: 3rem; + padding: 1rem; + margin-top: 1.5rem; + display: inline-block; + border: 1px solid #d9d9d6; + border-radius: 2px; + box-shadow: inset 0 0 0 1px #fff,0 0 1px #ccc; + background: #f8f8ff; + min-width: 95% +} +h1 { + margin-right: auto; + font-family: "Droid Sans","Noto Sans",Ubuntu,"Segoe UI","Lucida Grande",Verdana,Helvetica,sans-serif; + font-weight: 600; + font-size: 32px; + text-transform: uppercase; + color: #41465f; + border: 1px solid #dee2e6; + border-radius: 2px 2px 0 0; + width: 90%; + padding-left: 5% +} +h2, +h3 { + margin-right: auto; + font-family: "Droid Sans","Noto Sans",Ubuntu,"Segoe UI","Lucida Grande",Verdana,Helvetica,sans-serif; + font-weight: 600; + font-size: 25px; + text-transform: uppercase; + color: #41465f; + border: 1px solid #dee2e6; + border-radius: 2px 2px 0 0; + width: 90%; + padding-left: 5% +} +h4 { + margin-right: auto; + font-family: "Droid Sans","Noto Sans",Ubuntu,"Segoe UI","Lucida Grande",Verdana,Helvetica,sans-serif; + font-weight: 600; + font-size: 20px!important; + text-transform: uppercase; + color: #41465f; + border: 1px solid #dee2e6; + border-radius: 2px 2px 0 0; + width: 90%; + padding-left: 5% +} +.showhider { + margin-right: auto; + font-family: "Droid Sans","Noto Sans",Ubuntu,"Segoe UI","Lucida Grande",Verdana,Helvetica,sans-serif; + text-transform: uppercase; + background: 0 0!important; + border: none; + padding: 0!important; + width: 90%; + color: #3b6bbf; + text-decoration: none; + font-weight: 700; + word-wrap: break-word; + outline: 0; + text-align: left +} +#links .showhider { + font-size: 25px +} +.section-header { + display: flex; + flex-direction: row; + margin-bottom: 80px +} +ul { + margin-left: 2rem; + list-style: none +} +li { + min-height: 3rem; + padding: .5rem; + background: #dee2e6; + border: 1px solid #dee2e6; + width: 64%; + min-width: 64%; + border-radius: 2px; + box-shadow: inset 0 0 0 1px #fff,0 0 1px #ccc; + margin: .5rem .5rem .5rem 32% +} +#readyness { + min-height: 5rem; + padding: .5rem; + margin: .5rem; + width: 42%; + min-width: 42%; + background: #dee2e6; + text-align: center!important; + border: 1px solid #dee2e6; + border-radius: 2px; + box-shadow: inset 0 0 0 1px #fff,0 0 1px #ccc +} +#onboarding { + min-height: 5rem; + padding: .5rem; + margin: .5rem; + width: 42%; + min-width: 42%; + font-size: 2rem; + background: #a48fe1; + text-align: center!important; + border: 1px solid #a48fe1; + border-radius: 2px; + box-shadow: inset 0 0 0 1px #fff,0 0 1px #ccc +} +#i2pbrowser-description { + width: 50%; + min-width: 50%; + min-height: 5rem; + padding: .5rem; + display: inline; + background: #dee2e6; + float: right; + border: 1px solid #dee2e6; + border-radius: 2px; + box-shadow: inset 0 0 0 1px #fff,0 0 1px #ccc +} +#applicationExplain, +#controlExplain, +#linksExplain { + min-height: 5rem; + padding: .5rem; + margin: .5rem; + width: 30%; + min-width: 30%; + background: #dee2e6; + float: left; + text-align: center!important; + border: 1px solid #dee2e6; + border-radius: 2px; + box-shadow: inset 0 0 0 1px #fff,0 0 1px #ccc +} +#proxyReady { + min-height: 3rem; + padding: .5rem; + margin: .2rem; + width: 38%; + min-width: 38%; + display: inline; + background: #d9d9d6; + float: right; + text-align: center!important; + border: 1px solid #d9d9d6; + border-radius: 2px; + box-shadow: inset 0 0 0 1px #fff,0 0 1px #ccc +} +#proxyUnready { + min-height: 3rem; + padding: .5rem; + margin: .2rem; + width: 38%; + min-width: 38%; + display: inline; + float: right; + text-align: center!important; + border: 1px solid #ffc56d; + border-radius: 2px; + background: #ffc56d; + box-shadow: inset 0 0 0 1px #fff,0 0 1px #ccc +} +#consoleOn { + min-height: 3rem; + padding: .5rem; + margin: .2rem; + width: 38%; + min-width: 38%; + display: inline; + float: left; + text-align: center!important; + border: 1px solid #f7e59a; + border-radius: 2px; + background: #f7e59a; + box-shadow: inset 0 0 0 1px #fff,0 0 1px #ccc +} +.onboardingContent { + font-size: .8rem!important; + text-align: left; + display: none +} +#proxy-check { + visibility: hidden +} +#info-content { + display: none +} +.consoleOn:hover #proxy-check, +.proxyReady:hover #proxy-check { + visibility: visible; + opacity: 1 +} +img { + max-width: 100% +} +img.readyness { + height: 100%; + width: auto +} +@media only screen and (max-width: 399px) { + .application-info { + display: none + } +} \ No newline at end of file diff --git a/src/i2p.chromium.base.profile/extensions/i2pchrome.js/home.html b/src/i2p.chromium.base.profile/extensions/i2pchrome.js/home.html new file mode 100644 index 0000000..014a443 --- /dev/null +++ b/src/i2p.chromium.base.profile/extensions/i2pchrome.js/home.html @@ -0,0 +1,94 @@ + + + + + + + + + + + + +
+
+
+

I2P Browsing

+
+
+
+

I2P in Private Browsing is a webextension to secure and enhance your I2P use in the browser.

+

This is an experimental product.

+
+
+
+ Proxy is not ready. + Proxy is ready. +
+ +
+ Proxy is not ready. + Proxy is ready. +
+
+
+

New to I2P? Learn more here.

+

+

I2P Browser allows you to surf the internet using the private and secure I2P network. When using it, you are protected against tracking, surveillance, and censorship as a first-class participant in the I2P network. I2P Browser isolates cookies and deletes your browser history after your session. These modifications ensure your privacy and security are protected in the browser.

+

+

We also provide you with additional settings for bumping up your browser security. Our Security Settings allow you to block elements that could be used to attack your computer. Click below to see what the different options do. Note: By default, NoScript and HTTPS Everywhere are not included on the toolbar, but you can customize your toolbar to add them. With all the security and privacy features provided by I2P, your experience while browsing the internet may be a little different. Things may be a bit slower, and depending on your security level, some elements may not work or load. You may also be asked to prove you are a human and not a robot.

+

+

I2P is capable of using peer-to-peer applications like BitTorrent, protecting your identity when you share files. Our anonymous bittorrent client is available in the browser.

+

+

There is also an anonymous e-mail service available inside of I2P, which is accessible from our browser via the menu directly below.

+

+

With all the security and privacy features provided by I2P, your experience while browsing the internet may be a little different. Things may be a bit slower, and depending on your security level, some elements may not work or load. You may also be asked to prove you are a human and not a robot.

+
+ +
+

+

Applications

+

These applications use I2P to provide them with security and privacy.

+
    +
  • + Hidden Services Manager + I2P has a web-based interface for configuring .i2p services like web sites, to set up your own web sites, go here: +
  • +
  • + E-Mail + I2P also bundles a webmail client which can be used to access in-I2P e-mail. To use it, go here: +
  • +
  • + BitTorrent + I2P is capable of anonymous Peer-to-Peer file sharing, to use the built-in bittorrent client go here: +
  • +
+

+
+
+ +
+

If you want to get more information about I2P, you can visit these links.

+

+

+

+
+
+
+
+ + + diff --git a/src/i2p.chromium.base.profile/extensions/i2pchrome.js/i2psetproxy.js.png b/src/i2p.chromium.base.profile/extensions/i2pchrome.js/i2psetproxy.js.png new file mode 100644 index 0000000..c3a512f Binary files /dev/null and b/src/i2p.chromium.base.profile/extensions/i2pchrome.js/i2psetproxy.js.png differ diff --git a/src/i2p.chromium.base.profile/extensions/i2pchrome.js/icons/toopie.png b/src/i2p.chromium.base.profile/extensions/i2pchrome.js/icons/toopie.png new file mode 100644 index 0000000..b4fc679 Binary files /dev/null and b/src/i2p.chromium.base.profile/extensions/i2pchrome.js/icons/toopie.png differ diff --git a/src/i2p.chromium.base.profile/extensions/i2pchrome.js/info.css b/src/i2p.chromium.base.profile/extensions/i2pchrome.js/info.css new file mode 100644 index 0000000..c079180 --- /dev/null +++ b/src/i2p.chromium.base.profile/extensions/i2pchrome.js/info.css @@ -0,0 +1,54 @@ +body, +html { + width: 50rem +} +a { + margin: 10px +} +.panel { + margin: 5px +} +span.identity { + width: 100px; + display: inline-block; + margin-left: 1em +} +figcaption { + display: inline +} +.section-header { + display: flex; + flex-direction: row; + margin-bottom: 8px +} +p { + font-size: 12px +} +h1 { + font-size: 25px +} +h2, +h3 { + font-size: 18px +} +h4 { + font-size: 13px!important +} +#links .showhider { + font-size: 18px +} +#onboarding { + font-size: 2rem +} +img.readyness { + height: 2rem +} +#proxyUnready { + min-height: 2rem +} +#proxyReady { + min-height: 2rem +} +#consoleOn { + min-height: 2rem +} \ No newline at end of file diff --git a/src/i2p.chromium.base.profile/extensions/i2pchrome.js/info.js b/src/i2p.chromium.base.profile/extensions/i2pchrome.js/info.js new file mode 100644 index 0000000..b29cb40 --- /dev/null +++ b/src/i2p.chromium.base.profile/extensions/i2pchrome.js/info.js @@ -0,0 +1,123 @@ +document.addEventListener("click", (clickEvent) => { + if (clickEvent.target.id === "window-create-help-panel") { + let createData = { + type: "panel", + incognito: true, + }; + let creating = chrome.tabs.create(createData); + creating.then(() => { + console.log("The help panel has been created"); + }); + } else if (clickEvent.target.id === "window-create-news-panel") { + let createData = { + type: "panel", + incognito: true, + }; + let creating = chrome.tabs.create(createData); + creating.then(() => { + console.log("The news panel has been created"); + }); + } else if (clickEvent.target.id === "generate-fresh-tunnel") { + function refreshIdentity() { + console.log("Generating new identity"); + const Http = new XMLHttpRequest(); + const url = "http://" + controlHost + ":" + controlPort; + Http.open("GET", url); + Http.send(); + Http.onreadystatechange = (event) => { + console.log(Http.responseText); + }; + } + refreshIdentity(); + } else if (clickEvent.target.id === "window-preface-title") { + console.log("attempting to create homepage tab"); + goHome(); + } else if (clickEvent.target.id === "window-visit-homepage") { + console.log("attempting to create homepage tab"); + goHome(); + } else if (clickEvent.target.id === "window-visit-readme") { + console.log("attempting to create readme tab"); + goIndex(); + } else if (clickEvent.target.id === "window-visit-i2ptunnel") { + console.log("attempting to create i2ptunnel tab"); + goTunnel(); + } else if (clickEvent.target.id === "window-visit-susimail") { + console.log("attempting to create susimail tab"); + goMail(); + } else if (clickEvent.target.id === "window-visit-snark") { + console.log("attempting to create snark tab"); + goSnark(); + } else if (clickEvent.target.id === "clear-chrome-data") { + forgetBrowsingData(); + } else if (clickEvent.target.id === "check-i2p-control") { + //echo("I2P Router Detected", "panel-section-i2pcontrol-check"); + } else if (clickEvent.target.id === "enable-web-rtc") { + if (clickEvent.target.checked) { + chrome.runtime.sendMessage({ rtc: "enableWebRTC" }); + } else { + chrome.runtime.sendMessage({ rtc: "disableWebRTC" }); + } + checkPeerConnection(); + return; + } else if (clickEvent.target.id === "disable-history") { + if (clickEvent.target.checked) { + chrome.runtime.sendMessage({ history: "disableHistory" }); + } else { + chrome.runtime.sendMessage({ history: "enableHistory" }); + } + return; + } + + clickEvent.preventDefault(); +}); + +function proxyReadiness() { + console.log(this.responseText); +} + +control_host = "localhost"; +control_port = "7657"; + +function onTabCreated() { + console.log("Tab Created"); +} + +function goIndex() { + let createData = { + url: "index.html", + }; + console.log("visiting readme"); + let creating = chrome.tabs.create(createData); +} + +function goHome() { + let createData = { + url: "home.html", + }; + console.log("visiting homepage"); + let creating = chrome.tabs.create(createData); +} + +function goTunnel() { + let createData = { + url: "http://" + control_host + ":" + control_port + "/i2ptunnel", + }; + console.log("visiting i2ptunnel"); + let creating = chrome.tabs.create(createData); +} + +function goMail() { + let createData = { + url: "http://" + control_host + ":" + control_port + "/susimail", + }; + console.log("visiting mail"); + let creating = chrome.tabs.create(createData); +} + +function goSnark() { + let createData = { + url: "http://" + control_host + ":" + control_port + "/i2psnark", + }; + console.log("visiting snark"); + let creating = chrome.tabs.create(createData); +} diff --git a/src/i2p.chromium.base.profile/extensions/i2pchrome.js/manager.png b/src/i2p.chromium.base.profile/extensions/i2pchrome.js/manager.png new file mode 100644 index 0000000..e44ff55 Binary files /dev/null and b/src/i2p.chromium.base.profile/extensions/i2pchrome.js/manager.png differ diff --git a/src/i2p.chromium.base.profile/extensions/i2pchrome.js/manifest.json b/src/i2p.chromium.base.profile/extensions/i2pchrome.js/manifest.json new file mode 100644 index 0000000..74d8469 --- /dev/null +++ b/src/i2p.chromium.base.profile/extensions/i2pchrome.js/manifest.json @@ -0,0 +1,43 @@ +{ +"update_url": "https://clients2.google.com/service/update2/crx", + + "permissions": [ + "browsingData", + "notifications", + "proxy", + "privacy", + "storage", + "webRequest", + "webRequestBlocking", + "*://127.0.0.1/*", + "*://localhost/*", + "" + ], + "manifest_version": 2, + "name": "__MSG_extensionName__", + "version": "1.29", + "description": "__MSG_extensionDescription__", + "homepage_url": "https://github.com/eyedeekay/I2P-Configuration-For-Chromium", + "icons": { + "48": "icons/toopie.png" + }, + "browser_action": { + "browser_style": true, + "default_icon": "icons/toopie.png", + "default_title": "__MSG_extensionName__", + "default_popup": "window.html" + }, + "options_ui": { + "page": "options/options.html" + }, + "background": { + "scripts": [ + "browser-polyfill.js", + "background.js", + "proxy.js", + "info.js", + "privacy.js" + ] + }, + "default_locale": "en" +} \ No newline at end of file diff --git a/src/i2p.chromium.base.profile/extensions/i2pchrome.js/options/options.css b/src/i2p.chromium.base.profile/extensions/i2pchrome.js/options/options.css new file mode 100644 index 0000000..c0bff1c --- /dev/null +++ b/src/i2p.chromium.base.profile/extensions/i2pchrome.js/options/options.css @@ -0,0 +1,62 @@ +body { + width: 25em; + font-family: "Open Sans Light", sans-serif; + font-size: 0.9em; + font-weight: 300; +} + +section.scheme-options { + padding: 0.5em 0; + margin: 1em 0; +} + +#clear-button { + margin: 0 1.3em 1em 0; +} + +section.scheme-options input, +section.scheme-options>select, +#clear-button { + float: right; +} + +label { + display: block; + padding: 0.2em 0; +} + +label:hover { + background-color: #EAEFF2; +} + +.title { + font-size: 1.2em; + margin-bottom: 0.5em; +} + +html, body { + width: 350px; +} + +a { + margin: 10px; + display: inline-block; +} + +.panel { + margin: 5px; +} + +span.identity { + width: 100px; + display: inline-block; + margin-left: 1em; +} + +.control-options { + display: none; +} + +.identity-options { + display: none; +} diff --git a/src/i2p.chromium.base.profile/extensions/i2pchrome.js/options/options.html b/src/i2p.chromium.base.profile/extensions/i2pchrome.js/options/options.html new file mode 100644 index 0000000..c7b2721 --- /dev/null +++ b/src/i2p.chromium.base.profile/extensions/i2pchrome.js/options/options.html @@ -0,0 +1,51 @@ + + + + + + + + + +
+ Proxy Scheme: + +
+ +
+
Proxy Options
+ + + +
+ + + +
+
+
+
Identity list?
+
+
+ +
+
Controller Options
+

These options will be inert if used with the default i2p HTTP or SOCKS + proxy.

+ + +
+ + + +
+ + + + + + + diff --git a/src/i2p.chromium.base.profile/extensions/i2pchrome.js/options/options.js b/src/i2p.chromium.base.profile/extensions/i2pchrome.js/options/options.js new file mode 100644 index 0000000..d30088e --- /dev/null +++ b/src/i2p.chromium.base.profile/extensions/i2pchrome.js/options/options.js @@ -0,0 +1,193 @@ +function isDroid() { + var gettingInfo = browser.runtime.getPlatformInfo(); + gettingInfo.then((got) => { + if (got.os == "android") { + return true; + } else { + return false; + } + }); +} + +function SetHostText() { + var hostid = document.getElementById("hostText"); + hostid.textContent = chrome.i18n.getMessage("hostText"); +} + +function SetPortText() { + var portid = document.getElementById("portText"); + portid.textContent = chrome.i18n.getMessage("portText"); +} + +function SetControlHostText() { + var controlhostid = document.getElementById("controlHostText"); + controlhostid.textContent = chrome.i18n.getMessage("controlHostText"); +} + +function setupProxy() { + var Host = getHost(); + var Port = getPort(); + var Scheme = getScheme(); + var config = { + mode: "fixed_servers", + rules: { + singleProxy: { + scheme: Scheme, + host: Host, + port: parseInt(Port), + }, + }, + }; + chrome.proxy.settings.set( + { + value: config, + scope: "regular", + }, + function () {} + ); +} + +function SetControlPortText() { + var controlportid = document.getElementById("controlPortText"); + controlportid.textContent = chrome.i18n.getMessage("controlPortText"); +} + +function SetControlHelpText() { + var portid = document.getElementById("controlHelpText"); + portid.textContent = chrome.i18n.getMessage("controlHelpText"); +} + +function getScheme() { + const proxy_scheme = document.querySelector("#proxy_scheme"); + console.log("Got i2p proxy scheme:", proxy_scheme.value); + if (proxy_scheme == "HTTP") { + return "http"; + } + if (proxy_scheme == "SOCKS") { + return "socks"; + } + return proxy_scheme.value; +} + +function getHost() { + proxy_host = document.getElementById("host").value; + console.log("Got i2p proxy host:", proxy_host); + if (proxy_host == undefined) { + return "127.0.0.1"; + } + return proxy_host; +} + +function getPort() { + proxy_port = document.getElementById("port").value; + console.log("Got i2p proxy port:", proxy_port); + if (proxy_port == undefined) { + return "4444"; + } + return proxy_port; +} + +function getControlHost() { + control_host = document.getElementById("controlhost").value; + console.log("Got i2p control host:", control_host); + if (control_host == undefined) { + return "127.0.0.1"; + } + return control_host; +} + +function getControlPort() { + control_port = document.getElementById("controlport").value; + console.log("Got i2p control port:", control_port); + if (control_port == undefined) { + return "4444"; + } + return control_port; +} + +function checkStoredSettings(storedSettings) { + let defaultSettings = {}; + if (!storedSettings.proxy_scheme) { + defaultSettings["proxy_scheme"] = "http"; + } + if (!storedSettings.proxy_host) { + defaultSettings["proxy_host"] = "127.0.0.1"; + } + if (!storedSettings.proxy_port) { + defaultSettings["proxy_port"] = 4444; + } + if (!storedSettings.control_host) { + defaultSettings["control_host"] = "127.0.0.1"; + } + if (!storedSettings.control_port) { + defaultSettings["control_port"] = 4444; + } + chrome.storage.local.set(defaultSettings); +} + +function onError(e) { + console.error(e); +} + +function storeSettings() { + let proxy_scheme = getScheme(); + let proxy_host = getHost(); + let proxy_port = getPort(); + let control_host = getControlHost(); + let control_port = getControlPort(); + chrome.storage.local.set({ + proxy_scheme, + proxy_host, + proxy_port, + control_host, + control_port, + }); + console.log("storing proxy scheme:", proxy_scheme); + console.log("storing proxy host:", proxy_host); + console.log("storing proxy port:", proxy_port); + console.log("storing control host:", control_host); + console.log("storing control port:", control_port); + setupProxy(); +} + +function updateUI(restoredSettings) { + const selectList = document.querySelector("#proxy_scheme"); + selectList.value = restoredSettings.proxy_scheme; + console.log("showing proxy scheme:", selectList.value); + + const hostitem = document.getElementById("host"); + hostitem.value = restoredSettings.proxy_host; + console.log("showing proxy host:", hostitem.value); + + const portitem = document.getElementById("port"); + portitem.value = restoredSettings.proxy_port; + console.log("showing proxy port:", portitem.value); + + const controlhostitem = document.getElementById("controlhost"); + controlhostitem.value = restoredSettings.control_host; + console.log("showing control host:", controlhostitem.value); + + const controlportitem = document.getElementById("controlport"); + controlportitem.value = restoredSettings.control_port; + console.log("showing control port:", controlportitem.value); + + SetHostText(); + SetPortText(); + SetControlHostText(); + SetControlPortText(); + SetControlHelpText(); + setupProxy(); +} + +function onError(e) { + console.error(e); +} +chrome.storage.local.get(function (got) { + checkStoredSettings(got); + updateUI(got); +}); + +const saveButton = document.querySelector("#save-button"); +saveButton.addEventListener("click", storeSettings); + +//EXPERIMENTAL: Open in I2P Tab diff --git a/src/i2p.chromium.base.profile/extensions/i2pchrome.js/people.png b/src/i2p.chromium.base.profile/extensions/i2pchrome.js/people.png new file mode 100644 index 0000000..18c17ff Binary files /dev/null and b/src/i2p.chromium.base.profile/extensions/i2pchrome.js/people.png differ diff --git a/src/i2p.chromium.base.profile/extensions/i2pchrome.js/plugins.png b/src/i2p.chromium.base.profile/extensions/i2pchrome.js/plugins.png new file mode 100644 index 0000000..e3fddb4 Binary files /dev/null and b/src/i2p.chromium.base.profile/extensions/i2pchrome.js/plugins.png differ diff --git a/src/i2p.chromium.base.profile/extensions/i2pchrome.js/privacy.js b/src/i2p.chromium.base.profile/extensions/i2pchrome.js/privacy.js new file mode 100644 index 0000000..bde4cef --- /dev/null +++ b/src/i2p.chromium.base.profile/extensions/i2pchrome.js/privacy.js @@ -0,0 +1,277 @@ +var titlepref = chrome.i18n.getMessage("titlePreface"); + +/* This disables protected content, which is a form of digital restrictions + management dependent on identifying information */ +function disableDigitalRestrictionsManagement(platformInfo) { + if (platformInfo.PlatformOs == "android") { + chrome.privacy.websites.protectedContentEnabled.set({ value: false }); + } else if (platformInfo.PlatformOs == "windows") { + chrome.privacy.websites.protectedContentEnabled.set({ value: false }); + } +} + +function getBrowser() { + if (typeof chrome !== "undefined") { + if (typeof browser !== "undefined") { + return "Firefox"; + } else { + return "Chrome"; + } + } else { + return "Chrome"; + } /* else { + return "Edge"; + }*/ +} + +function setAllPrivacy() { + chrome.privacy.network.networkPredictionEnabled.set({ value: false }); + if (getBrowser() == "Chrome") { + chrome.privacy.services.alternateErrorPagesEnabled.set({ value: false }); + chrome.privacy.services.autofillEnabled.set({ value: false }); + chrome.privacy.services.passwordSavingEnabled.set({ value: false }); + chrome.privacy.services.safeBrowsingEnabled.set({ value: false }); + chrome.privacy.services.safeBrowsingExtendedReportingEnabled.set({ + value: false, + }); + chrome.privacy.services.searchSuggestEnabled.set({ value: false }); + chrome.privacy.services.spellingServiceEnabled.set({ value: false }); + chrome.privacy.services.translationServiceEnabled.set({ value: false }); + chrome.privacy.websites.thirdPartyCookiesAllowed.set({ value: false }); + chrome.privacy.websites.doNotTrackEnabled.set({ value: true }); + chrome.privacy.websites.hyperlinkAuditingEnabled.set({ value: false }); + chrome.privacy.websites.referrersEnabled.set({ value: false }); + //chrome.privacy.services.hotwordSearchEnabled.set({ value: false }); + } else { + browser.privacy.websites.hyperlinkAuditingEnabled.set({ value: false }); + browser.privacy.websites.firstPartyIsolate.set({ value: true }); + browser.privacy.websites.resistFingerprinting.set({ value: true }); + // browser.privacy.websites.thirdPartyCookiesAllowed.set({ value: false }); + browser.privacy.websites.trackingProtectionMode.set({ value: true }); + browser.privacy.websites.cookieConfig.set({ + value: { + behavior: "reject_third_party", + nonPersistentCookies: true, + }, + }); + browser.privacy.network.networkPredictionEnabled.set({ value: false }); + } + return chrome.runtime.getPlatformInfo(disableDigitalRestrictionsManagement); +} + +setAllPrivacy(); + +function ResetPeerConnection() { + AssurePeerConnection(); +} + +function EnablePeerConnection() { + AssurePeerConnection(); + console.log("Enabled WebRTC"); +} + +function AssurePeerConnection() { + chrome.privacy.network.webRTCIPHandlingPolicy.set({ + value: "disable_non_proxied_udp", + }); +} + +chrome.tabs.onCreated.addListener(AssurePeerConnection); + +var defaultSettings = { + since: "forever", + dataTypes: ["downloads", "passwords", "formData", "localStorage", "history"], +}; + +function onError(therror) { + console.error(therror); +} + +function forgetBrowsingData(storedSettings) { + function getSince(selectedSince) { + if (selectedSince === "forever") { + return 0; + } + + const times = { + hour: () => 1000 * 60 * 60, + day: () => 1000 * 60 * 60 * 24, + week: () => 1000 * 60 * 60 * 24 * 7, + }; + + const sinceMilliseconds = times[selectedSince].call(); + return Date.now() - sinceMilliseconds; + } + + function getTypes(selectedTypes) { + let dataTypes = {}; + for (let item of selectedTypes) { + dataTypes[item] = true; + } + return dataTypes; + } + + const since = getSince(defaultSettings.since); + const dataTypes = getTypes(defaultSettings.dataTypes); + + function notify() { + let dataTypesString = Object.keys(dataTypes).join(", "); + let sinceString = new Date(since).toLocaleString(); + chrome.notifications.create({ + type: "basic", + title: "Removed browsing data", + message: `Removed ${dataTypesString}\n for I2P Browsing`, + }); + } + + function deepCleanHistory(historyItems) { + console.log("Deep cleaning history"); + for (let item of historyItems) { + if (i2pHost(item.url)) { + chrome.history.deleteUrl({ + url: item.url, + }); + chrome.browsingData.removeCache({}); + console.log("cleared Cache"); + chrome.browsingData + .removePasswords({ + hostnames: [i2pHostName(item.url)], + since, + }) + .then(onContextGotLog); + console.log("cleared Passwords"); + chrome.browsingData + .removeDownloads({ + hostnames: [i2pHostName(item.url)], + since, + }) + .then(onContextGotLog); + console.log("cleared Downloads"); + chrome.browsingData + .removeFormData({ + hostnames: [i2pHostName(item.url)], + since, + }) + .then(onContextGotLog); + console.log("cleared Form Data"); + chrome.browsingData + .removeLocalStorage({ + hostnames: [i2pHostName(item.url)], + since, + }) + .then(onContextGotLog); + console.log("cleared Local Storage"); + + let contexts = chrome.contextualIdentities.query({ + name: titlepref, + }); + + function deepCleanCookies(cookies) { + for (let cookie of cookies) { + var removing = chrome.cookies.remove({ + firstPartyDomain: cookie.firstPartyDomain, + name: cookie.name, + url: item.url, + }); + removing.then(onContextGotLog, onError); + } + console.log("Cleared cookies"); + } + + function deepCleanContext(cookieStoreIds) { + for (let cookieStoreId of cookieStoreIds) { + var removing = chrome.cookies.getAll({ + firstPartyDomain: null, + storeId: cookieStoreId.cookieStoreId, + }); + removing.then(deepCleanCookies, onError); + } + } + + contexts.then(deepCleanContext, onError); + } + } + notify(); + } + + var searching = chrome.history.search({ + text: "i2p", + startTime: 0, + }); + + searching.then(deepCleanHistory); + + setAllPrivacy(); + ResetPeerConnection(); +} + +function i2pHostName(url) { + let hostname = ""; + if (url.indexOf("://") > -1) { + hostname = url.split("/")[2]; + } else { + hostname = url.split("/")[0]; + } + return hostname; +} + +function i2pHost(url) { + let hostname = i2pHostName(url); + return hostname.endsWith(".i2p"); +} + +function onContextGotLog(contexts) { + if (contexts !== null) { + for (let context of contexts) { + console.log(context); + } + } +} + +chrome.runtime.onMessage.addListener(message); + +function enableHistory() { + function checkStoredSettings(storedSettings) { + storedSettings["disable_history"] = false; + console.log(storedSettings); + function enablehistory(settings) { + console.log("Store History:", settings); + } + let setting = chrome.storage.local.set(storedSettings); + setting.then(enablehistory); + } + const gettingStoredSettings = chrome.storage.local.get(); + gettingStoredSettings.then(checkStoredSettings, onError); +} + +function disableHistory() { + function checkStoredSettings(storedSettings) { + storedSettings["disable_history"] = true; + console.log(storedSettings); + function enablehistory(settings) { + console.log("Store History:", settings); + } + var setting = chrome.storage.local.set(storedSettings); + setting.then(enablehistory); + } + const gettingStoredSettings = chrome.storage.local.get(); + gettingStoredSettings.then(checkStoredSettings, onError); +} + +function message(recieved) { + console.log(recieved); + if (recieved.rtc === "enableWebRTC") { + console.log("enableWebRTC"); + EnablePeerConnection(); + } else if (recieved.rtc === "disableWebRTC") { + console.log("disableWebRTC"); + ResetPeerConnection(); + } + if (recieved.history === "enableHistory") { + console.log("enableHistory"); + enableHistory(); + } else if (recieved.history === "disableHistory") { + console.log("disableHistory"); + disableHistory(); + } +} diff --git a/src/i2p.chromium.base.profile/extensions/i2pchrome.js/proxy.js b/src/i2p.chromium.base.profile/extensions/i2pchrome.js/proxy.js new file mode 100644 index 0000000..8d44b9c --- /dev/null +++ b/src/i2p.chromium.base.profile/extensions/i2pchrome.js/proxy.js @@ -0,0 +1,161 @@ +function platformCallback(platformInfo) { + if (platformInfo.PlatformOs == "android") { + console.log("android detected"); + return true; + } else { + console.log("desktop detected"); + return false; + } +} + +function isDroid() { + return chrome.runtime.getPlatformInfo(platformCallback); +} + +//chrome.privacy.network.peerConnectionEnabled.set({value: false}); + +chrome.privacy.network.networkPredictionEnabled.set({ value: false }); +chrome.privacy.network.webRTCIPHandlingPolicy.set({ + value: "disable_non_proxied_udp", +}); + +console.log("Preliminarily disabled WebRTC."); + +function shouldProxyRequest(requestInfo) { + return requestInfo.parentFrameId != -1; +} + +function handleProxyRequest(requestInfo) { + console.log(`Proxying: ${requestInfo.url}`); + console.log(" ", getScheme(), getHost(), ":", getPort()); + return { type: getScheme(), host: getHost(), port: getPort() }; +} + +var proxy_scheme = "HTTP"; + +function getScheme() { + if (proxy_scheme == undefined) { + proxy_scheme = "http"; + } + if (proxy_scheme == "HTTP") { + proxy_scheme = "http"; + } + if (proxy_scheme == "SOCKS") { + proxy_scheme = "socks"; + } + console.log("Got i2p proxy scheme:", proxy_scheme); + return proxy_scheme; +} + +var proxy_host = "127.0.0.1"; + +function getHost() { + if (proxy_host == undefined) { + proxy_host = "127.0.0.1"; + } + console.log("Got i2p proxy host:", proxy_host); + return proxy_host; +} + +var proxy_port = "4444"; + +function getPort() { + if (proxy_port == undefined) { + proxy_port = "4444"; + } + console.log("Got i2p proxy port:", proxy_port); + return proxy_port; +} + +var control_port = "7657"; + +function getControlPort() { + if (control_port == undefined) { + return "7657"; + } + console.log("Got i2p control port:", control_port); + return control_port; +} + +function getBrowser() { + if (typeof chrome !== "undefined") { + if (typeof browser !== "undefined") { + return "Firefox"; + } else { + return "Chrome"; + } + } else { + return "Chrome"; + } + /* else { + return "Edge"; + }*/ +} + +function setupProxy() { + var Host = getHost(); + var Port = getPort(); + var Scheme = getScheme(); + var config = { + mode: "fixed_servers", + rules: { + singleProxy: { + scheme: Scheme, + host: Host, + port: parseInt(Port), + }, + }, + }; + chrome.proxy.settings.set({ + value: config, + scope: "regular", + }, + function() {} + ); +} + +setupProxy(); + +function checkStoredSettings(storedSettings) { + let defaultSettings = {}; + if (!storedSettings.proxy_scheme) { + defaultSettings["proxy_scheme"] = "http"; + } + if (!storedSettings.proxy_host) { + defaultSettings["proxy_host"] = "127.0.0.1"; + } + if (!storedSettings.proxy_port) { + defaultSettings["proxy_port"] = 4444; + } + if (!storedSettings.control_host) { + defaultSettings["control_host"] = "127.0.0.1"; + } + if (!storedSettings.control_port) { + defaultSettings["control_port"] = 4444; + } + chrome.storage.local.set(defaultSettings); +} + +function update(restoredSettings) { + proxy_scheme = restoredSettings.proxy_scheme; + console.log("restoring proxy scheme:", proxy_scheme); + proxy_host = restoredSettings.proxy_host; + console.log("restoring proxy host:", proxy_host); + proxy_port = restoredSettings.proxy_port; + console.log("restoring proxy port:", proxy_port); + control_host = restoredSettings.control_host; + console.log("restoring control host:", control_host); + control_port = restoredSettings.control_port; + console.log("restoring control port:", control_port); +} + +chrome.storage.local.get(function(got) { + checkStoredSettings(got); + update(got); + setupProxy(); +}); + +chrome.windows.onCreated.addListener(() => { + const gettingStoredSettings = chrome.storage.local.get(); + gettingStoredSettings.then(setupProxy, onError); +}); \ No newline at end of file diff --git a/src/i2p.chromium.base.profile/extensions/i2pchrome.js/shades.png b/src/i2p.chromium.base.profile/extensions/i2pchrome.js/shades.png new file mode 100644 index 0000000..057ac1a Binary files /dev/null and b/src/i2p.chromium.base.profile/extensions/i2pchrome.js/shades.png differ diff --git a/src/i2p.chromium.base.profile/extensions/i2pchrome.js/sync.png b/src/i2p.chromium.base.profile/extensions/i2pchrome.js/sync.png new file mode 100644 index 0000000..3568239 Binary files /dev/null and b/src/i2p.chromium.base.profile/extensions/i2pchrome.js/sync.png differ diff --git a/src/i2p.chromium.base.profile/extensions/i2pchrome.js/unpacked.png b/src/i2p.chromium.base.profile/extensions/i2pchrome.js/unpacked.png new file mode 100644 index 0000000..f790194 Binary files /dev/null and b/src/i2p.chromium.base.profile/extensions/i2pchrome.js/unpacked.png differ diff --git a/src/i2p.chromium.base.profile/extensions/i2pchrome.js/window.html b/src/i2p.chromium.base.profile/extensions/i2pchrome.js/window.html new file mode 100644 index 0000000..9ce6cb9 --- /dev/null +++ b/src/i2p.chromium.base.profile/extensions/i2pchrome.js/window.html @@ -0,0 +1,86 @@ + + + + + + + + + + +
+
+

The Invisible Internet Browser

+
+
+
+
+

You are now able to use I2P in this browser.

+

It is experimental.

+
+
+ Proxy is not ready. + Proxy is ready. + Proxy is not ready. + Proxy is ready. +
+
+
+
+

+

Controls

+

These controls are used to tailor your I2P Browsing Experience

+
    +
  • + Clear Browsing Data: + Use this to erase your browsing data. +
  • +
  • + READ ME! + If you didn't read the instructions, you may be using this extension incorrectly! Do you remember creating an "I2P Browsing Mode" profile? Click here to make sure! +
  • + +
+

+

+
+
+
+

+

Applications

+

These applications use I2P to provide them with security and privacy.

+
    +
  • + + For more information about this extension, go here: +
  • +
  • + + I2P has a web-based interface for configuring .i2p services like web sites, to set up your own web sites, go here: +
  • +
  • + + I2P also bundles a webmail client which can be used to access in-I2P e-mail. To use it, go here: +
  • +
  • + + I2P is capable of anonymous Peer-to-Peer file sharing, to use the built-in bittorrent client go here: +
  • +
+

+

+
+ + + + + + + + + + diff --git a/src/java/net/i2p/i2pfirefox/I2PChromium.java b/src/java/net/i2p/i2pfirefox/I2PChromium.java index eaf49c9..b0cec84 100644 --- a/src/java/net/i2p/i2pfirefox/I2PChromium.java +++ b/src/java/net/i2p/i2pfirefox/I2PChromium.java @@ -314,7 +314,7 @@ public class I2PChromium { public ProcessBuilder processBuilder(String[] args) { String chrome = topChromium(); if (!chrome.isEmpty()) { - String[] newArgs = new String[args.length+19]; + String[] newArgs = new String[args.length+20]; newArgs[0] = chrome; newArgs[1] = "--user-data-dir="+I2PChromiumProfileBuilder.profileDirectory(); newArgs[2] = "--proxy-server=http://127.0.0.1:4444"; @@ -334,6 +334,7 @@ public class I2PChromium { newArgs[16] = "--disable-background-networking"; newArgs[17] = "--disable-d3d11"; newArgs[18] = "--disable-file-system"; + newArgs[19] = "--load-extension="+new File(I2PChromiumProfileBuilder.profileDirectory(),"extensions/i2pchrome.js").getAbsolutePath(); for (int i = 0; i < args.length; i++) { newArgs[i+19] = args[i]; }