diff --git a/Makefile b/Makefile index 9411012..0283cb0 100644 --- a/Makefile +++ b/Makefile @@ -5,12 +5,14 @@ default: zip install: uninstall mkdir -p $(PREFIX)/share/webext/i2ppb@eyedeekay.github.io \ $(PREFIX)/share/webext/i2ppb@eyedeekay.github.io/i2pcontrol \ + $(PREFIX)/share/webext/i2ppb@eyedeekay.github.io/torrent \ $(PREFIX)/share/mozilla/extensions/{ec8030f7-c20a-464f-9b0e-13a3a9e97384} cp -r ./icons/ $(PREFIX)/share/webext/i2ppb@eyedeekay.github.io/ cp -r ./_locales/ $(PREFIX)/share/webext/i2ppb@eyedeekay.github.io/ cp -r ./options/ $(PREFIX)/share/webext/i2ppb@eyedeekay.github.io/ cp ./*.js $(PREFIX)/share/webext/i2ppb@eyedeekay.github.io/ cp ./i2pcontrol/i2pcontrol.js $(PREFIX)/share/webext/i2ppb@eyedeekay.github.io/i2pcontrol/i2pcontrol.js + cp ./torrent/*.js $(PREFIX)/share/webext/i2ppb@eyedeekay.github.io/torrent/ cp ./*.html $(PREFIX)/share/webext/i2ppb@eyedeekay.github.io/ cp ./*.css $(PREFIX)/share/webext/i2ppb@eyedeekay.github.io/ cp ./*.md $(PREFIX)/share/webext/i2ppb@eyedeekay.github.io/ @@ -38,8 +40,8 @@ clean: ## EVEN RELEASES are AMO RELEASES ## ODD RELEASES are SELFHOSTED RELEASES -MOZ_VERSION=0.56 -VERSION=0.57 +MOZ_VERSION=0.58 +VERSION=0.59 ## INCREMENT THIS EVERY TIME YOU DO A RELEASE LAST_VERSION=0.55 @@ -80,6 +82,18 @@ index: @echo "" >> index.html @echo "" >> index.html +torrenthelp: + @echo "" > torrent/index.html + @echo "" >> torrent/index.html + @echo "" >> torrent/index.html + @echo " I2P in Private Browsing Mode" >> torrent/index.html + @echo " " >> torrent/index.html + @echo " " >> torrent/index.html + @echo "" >> torrent/index.html + @echo "" >> torrent/index.html + sed "s|magnetsub|[Magnet Link]($(MAGNET))|g" torrent/README.md | markdown >> torrent/index.html + @echo "" >> torrent/index.html + @echo "" >> torrent/index.html xpi: #wget -O ../i2ppb@eyedeekay.github.io.xpi \ @@ -116,7 +130,7 @@ zip: version --exclude="web-ext-artifacts" \ --exclude="./*.pdf" -r -FS ../i2psetproxy.js.zip * -release: +release: index torrenthelp cat desc debian/changelog | grep -B 10 "$(LAST_VERSION)" | gothub release -p -u eyedeekay -r I2P-in-Private-Browsing-Mode-Firefox -t $(VERSION) -n $(VERSION) -d -; true delete-release: @@ -246,6 +260,9 @@ fmt: tidy --as-xhtml --drop-empty-elements no --input-xml --tidy-mark no -indent --indent-spaces 4 -wrap 0 --new-blocklevel-tags article,header,footer --new-inline-tags video,audio,canvas,ruby,rt,rp --break-before-br yes --sort-attributes alpha --vertical-space yes home.html > .home.html; mv .home.html home.html tidy --as-xhtml --drop-empty-elements no --input-xml --tidy-mark no -indent --indent-spaces 4 -wrap 0 --new-blocklevel-tags article,header,footer --new-inline-tags video,audio,canvas,ruby,rt,rp --break-before-br yes --sort-attributes alpha --vertical-space yes toopie.html > .toopie.html; mv .toopie.html toopie.html tidy --as-xhtml --drop-empty-elements no --input-xml --tidy-mark no -indent --indent-spaces 4 -wrap 0 --new-blocklevel-tags article,header,footer --new-inline-tags video,audio,canvas,ruby,rt,rp --break-before-br yes --sort-attributes alpha --vertical-space yes options/options.html > options/.options.html; mv options/.options.html options/options.html + make fmt-js + +fmt-js: find . -path ./node_modules -prune -o -name '*.js' -exec prettier --write {} \; find . -path ./node_modules -prune -o -name '*.json' -exec prettier --write {} \; @@ -291,3 +308,5 @@ rss: torrent upload-rss: gothub upload -R -u eyedeekay -r I2P-in-Private-Browsing-Mode-Firefox -t docs -n "releases.atom" -f releases.atom +webext: + web-ext run -u "about:devtools-toolbox?type=extension&id=i2ppb%40eyedeekay.github.io" \ No newline at end of file diff --git a/README.md b/README.md index 46f2456..c853581 100644 --- a/README.md +++ b/README.md @@ -1,14 +1,14 @@ I2P in Private Browsing Mode(Firefox-Only) ========================================== -This is an **Experimental** webextension which introduces a set of new "Private -Browsing" modes to Firefox-based browsers(Supporting webextensions) that makes -it easier to configure a browser to use I2P securely and adds features for -making I2P applications easier to use. It does this by isolating I2P-specific -settings to Contextual Identities within Firefox, then loading them -automatically when the user requests them. It also adds convenience and -management features specific to I2P like protocol handlers and native messaging -systems. +This is an webextension which introduces a set of new "Private Browsing" modes +to Firefox-based browsers(Supporting webextensions) that makes it easier to +configure a browser to use I2P securely and adds features for making I2P +applications easier to use. It does this by isolating I2P-specific settings to +Contextual Identities within Firefox, then loading them automatically when the +user requests them. It also adds convenience and management features, like an +embedded I2P console and Bittorrent integration with clients using the +transmission-rpc API. Installation(Cross-Platform): ----------------------------- @@ -127,6 +127,7 @@ Documents * **[Smart Lander Design](https://github.com/eyedeekay/I2P-in-Private-Browsing-Mode-Firefox/releases/download/docs/Landing.Page.Documentation.pdf)**: This is the original outline of the smart landing page which became the I2P home page within the browser and the drop-down control panel. + * **[Other extensions](https://github.com/eyedeekay/I2P-in-Private-Browsing-Mode-Firefox/wiki/Other-Extensions)**: and how they work with this one. Super Extra Important Background Info: -------------------------------------- @@ -197,5 +198,3 @@ for updates, you can download the identical plugin from this repository's releases page. The latest AMO Plugin will always be identical to the latest github release, except for the version number, which must be incremented for submission to AMO. - -moz-extension://d63582fc-09fc-445a-b8aa-1c888ee2ffc0/toopie.html \ No newline at end of file diff --git a/_locales/en/messages.json b/_locales/en/messages.json index 7e8a3dc..93b683a 100644 --- a/_locales/en/messages.json +++ b/_locales/en/messages.json @@ -11,6 +11,10 @@ "message": "Your browser is now set up to use I2P.", "description": "Description of the extension." }, + "extensionVersion": { + "message": "0.57", + "description": "Version of the extension." + }, "extensionStatus": { "message": "It is a labs project for enhancing your I2P browsing experience.", "description": "Release status of the extension." @@ -63,6 +67,14 @@ "message": "These applications work with I2P directly to provide them with security and privacy.", "description": "Description for application section." }, + "windowVisitConsole": { + "message": "Router Console: ", + "description": "Router Console label." + }, + "routerConsole": { + "message": "The entrypoint for all other I2P applications is the I2P Router Console. To visit it, click here.", + "description": "Description for the router console." + }, "windowVisitHomepage": { "message": "Home Page: ", "description": "Home page for the extension label." diff --git a/bookmarks.js b/bookmarks.js index 3705f53..911baa3 100644 --- a/bookmarks.js +++ b/bookmarks.js @@ -93,7 +93,7 @@ gettingInfo.then(got => { let port = info.value.http.split(":")[1]; if (port == "7644") { var createBookmark = browser.bookmarks.create({ - url: "http://localhost:7647/i2ptunnelmgr", + url: "http://localhost:7647/i2ptunnel", title: "Hidden Services Manager", parentId: bookmarkToolbar[0].id }); @@ -101,11 +101,7 @@ gettingInfo.then(got => { } else { var createRhizomeBookmark = browser.bookmarks.create({ url: - "http://" + - control_host + - ":" + - control_port + - "/i2ptunnelmgr", + "http://" + control_host + ":" + control_port + "/i2ptunnel", title: "Hidden Services Manager", parentId: bookmarkToolbar[0].id }); diff --git a/config.js b/config.js index 6709690..0b8ff55 100644 --- a/config.js +++ b/config.js @@ -1,6 +1,18 @@ var proxy_scheme = "HTTP"; var proxy_host = "127.0.0.1"; var proxy_port = "4444"; + var control_host = "127.0.0.1"; var control_port = "7657"; + +var rpc_host = "127.0.0.1"; +var rpc_port = "7657"; +var rpc_path = "jsonrpc"; +var rpc_pass = "itoopie"; + +var bt_rpc_host = "127.0.0.1"; +var bt_rpc_port = "7657"; +var bt_rpc_path = "transmission/rpc"; +var bt_rpc_pass = "transmission"; + var disable_history = false; diff --git a/content.js b/content.js index f215d54..993fc58 100644 --- a/content.js +++ b/content.js @@ -11,6 +11,7 @@ function contentUpdateById(id, message) { // Information Section contentUpdateById("text-section-header", "extensionName"); contentUpdateById("description", "extensionDescription"); +contentUpdateById("i2pbrowser-version", "extensionVersion"); contentUpdateById("beta", "extensionStatus"); contentUpdateById("proxy-check", "proxyFailedStatus"); @@ -29,6 +30,8 @@ contentUpdateById("applicationHeader", "applicationHeader"); contentUpdateById("applicationExplain", "applicationExplain"); contentUpdateById("window-visit-index", "windowVisitHelppage"); contentUpdateById("help", "help"); +contentUpdateById("window-visit-router", "windowVisitConsole"); +contentUpdateById("routerConsole", "routerConsole"); contentUpdateById("window-visit-homepage", "windowVisitHomepage"); contentUpdateById("abouthome", "abouthome"); contentUpdateById("window-visit-i2ptunnel", "windowVisitI2ptunnel"); diff --git a/debian/rules b/debian/rules index 0a3a9ec..0d5cae4 100755 --- a/debian/rules +++ b/debian/rules @@ -6,12 +6,14 @@ override_dh_auto_install: mkdir -p $$(pwd)/debian/i2psetproxy.js/usr/share/webext/i2ppb@eyedeekay.github.io \ $$(pwd)/debian/i2psetproxy.js/usr/share/webext/i2ppb@eyedeekay.github.io/i2pcontrol \ + $$(pwd)/debian/i2psetproxy.js/usr/share/webext/i2ppb@eyedeekay.github.io/torrent \ $$(pwd)/debian/i2psetproxy.js/usr/share/mozilla/extensions/{ec8030f7-c20a-464f-9b0e-13a3a9e97384} cp -r ./icons/ $$(pwd)/debian/i2psetproxy.js/usr/share/webext/i2ppb@eyedeekay.github.io/ cp -r ./options/ $$(pwd)/debian/i2psetproxy.js/usr/share/webext/i2ppb@eyedeekay.github.io/ cp -r ./_locales/ $$(pwd)/debian/i2psetproxy.js/usr/share/webext/i2ppb@eyedeekay.github.io/ cp ./*.js $$(pwd)/debian/i2psetproxy.js/usr/share/webext/i2ppb@eyedeekay.github.io/ cp ./i2pcontrol/i2pcontrol.js $$(pwd)/debian/i2psetproxy.js/usr/share/webext/i2ppb@eyedeekay.github.io/i2pcontrol/ + cp ./torrent/*.js $$(pwd)/debian/i2psetproxy.js/usr/share/webext/i2ppb@eyedeekay.github.io/torrent/ cp ./*.html $$(pwd)/debian/i2psetproxy.js/usr/share/webext/i2ppb@eyedeekay.github.io/ cp ./*.css $$(pwd)/debian/i2psetproxy.js/usr/share/webext/i2ppb@eyedeekay.github.io/ cp ./*.md $$(pwd)/debian/i2psetproxy.js/usr/share/webext/i2ppb@eyedeekay.github.io/ diff --git a/handler.js b/handler.js index ae04606..d48f7b5 100644 --- a/handler.js +++ b/handler.js @@ -37,7 +37,14 @@ function routerHost(url) { path = url.replace(hostname + "/", ""); } if (hostname === control_host + ":" + control_port) { - console.log("(hostcheck) router console found on configured ports"); + //console.log("(hostcheck) router console found on configured ports"); + return pathcheck(path); + } + if (hostname === "localhost" + ":" + control_port) { + //console.log("(hostcheck) router console found on configured ports"); + return pathcheck(path); + } + if (hostname === "127.0.0.1" + ":" + control_port) { return pathcheck(path); } diff --git a/home.css b/home.css index 8d39392..9a53e36 100644 --- a/home.css +++ b/home.css @@ -79,8 +79,11 @@ p { background: #f8f8ff; min-width: 95% } +#header, .application-info, -.extended-info { +.browser-info, +.extended-info, +.search-info { min-height: 3rem; padding: 1rem; margin-top: 1.5rem; @@ -100,7 +103,6 @@ h1 { color: #41465f; border: 1px solid #dee2e6; border-radius: 2px 2px 0 0; - width: 90%; padding-left: 5% } h2, @@ -111,7 +113,6 @@ h3 { font-size: 25px; text-transform: uppercase; color: #41465f; - border: 1px solid #dee2e6; border-radius: 2px 2px 0 0; width: 90%; padding-left: 5% @@ -167,9 +168,8 @@ li { margin: .5rem .5rem .5rem 32% } #readyness { - float: left; - min-height: 5rem; padding-top: 1rem; + padding-bottom: 1rem; margin: 1rem; width: 42%; min-width: 42%; @@ -177,12 +177,14 @@ li { text-align: center!important; border: 1px solid #dee2e6; border-radius: 2px; - box-shadow: inset 0 0 0 1px #fff,0 0 1px #ccc + box-shadow: inset 0 0 0 1px #fff,0 0 1px #ccc; + display: inline-block } #onboarding { min-height: 5rem; padding: .5rem; margin: .5rem; + margin-top: 4rem; width: 42%; min-width: 42%; font-size: 2rem; @@ -193,19 +195,16 @@ li { box-shadow: inset 0 0 0 1px #fff,0 0 1px #ccc } #i2pbrowser-description { + padding-top: 1rem; + padding-bottom: 1rem; width: 50%; min-width: 50%; - min-height: 5rem; - margin-top: .8rem; display: inline-block; 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; @@ -213,12 +212,25 @@ li { 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 } +#applicationExplain, +#controlExplain { + min-height: 5rem; + padding: .5rem; + margin: .5rem; + width: 30%; + min-width: 30%; + 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; + float: left +} #proxyReady { min-height: 3rem; padding: .5rem; diff --git a/home.html b/home.html index ad555c6..ff1d249 100644 --- a/home.html +++ b/home.html @@ -10,11 +10,10 @@ - - +
-
+

I2P Browsing

@@ -88,19 +87,23 @@ -->
  • - Toopie For information about your I2P router status, go here: + Toopie For information about your I2P router status, go here:
  • - 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: + Router Console The entrypoint for all other I2P applications is the I2P Router Console. To visit it, click here.
  • - E-Mail I2P also bundles a webmail client which can be used to access in-I2P e-mail. To use it, go here: + 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:
  • - BitTorrent I2P is capable of anonymous Peer-to-Peer file sharing, to use the built-in bittorrent client 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:
  • @@ -120,15 +123,19 @@ @@ -138,6 +145,7 @@
    - + + diff --git a/host.js b/host.js index bb56ecc..6dea4ed 100644 --- a/host.js +++ b/host.js @@ -97,7 +97,14 @@ function routerHost(url) { path = url.replace(hostname + "/", ""); } if (hostname === control_host + ":" + control_port) { - console.log("(hostcheck) router console found on configured ports"); + //console.log("(hostcheck) router console found on configured ports"); + return pathcheck(path); + } + if (hostname === "localhost" + ":" + control_port) { + //console.log("(hostcheck) router console found on configured ports"); + return pathcheck(path); + } + if (hostname === "127.0.0.1" + ":" + control_port) { return pathcheck(path); } diff --git a/i2pcontrol/i2pcontrol.js b/i2pcontrol/i2pcontrol.js index ae7cdca..9439a9e 100644 --- a/i2pcontrol/i2pcontrol.js +++ b/i2pcontrol/i2pcontrol.js @@ -1,4 +1,3 @@ -var password = "itoopie"; var hello = "hello i2pcontrol"; function makeid(length) { @@ -12,11 +11,16 @@ function makeid(length) { return result; } -function send(message, control_host = "127.0.0.1", control_port = "7657") { +function send( + message, + control_host = "127.0.0.1", + control_port = "7657", + control_path = "jsonrpc" +) { async function postData(url = "", data = {}) { // Default options are marked with * let requestBody = JSON.stringify(data); - //console.log("(i2pcontrol)", requestBody, data); + //console.log("(i2pcontrol) sending request", requestBody); let opts = { method: "POST", // *GET, POST, PUT, DELETE, etc. mode: "cors", // no-cors, *cors, same-origin @@ -33,16 +37,18 @@ function send(message, control_host = "127.0.0.1", control_port = "7657") { return await response.json(); // parses JSON response into native JavaScript objects } + //console.log("http://" + control_host + ":" + control_port + "/" + control_path) return postData( - "http://" + control_host + ":" + control_port + "/jsonrpc/", + "http://" + control_host + ":" + control_port + "/" + control_path + "/", message ); } -function authenticate( - password, +async function authenticate( + password = "itoopie", control_host = "127.0.0.1", - control_port = "7657" + control_port = "7657", + control_path = "jsonrpc" ) { var json = new Object(); json["id"] = makeid(6); @@ -51,29 +57,31 @@ function authenticate( json["params"] = new Object(); json["params"]["API"] = 1; json["params"]["Password"] = password; - return send(json); + return send(json, control_host, control_port, control_path); } async function GetToken( - password, + password = "itoopie", control_host = "127.0.0.1", - control_port = "7657" + control_port = "7657", + control_path = "jsonrpc" ) { - let me = authenticate(password); + function gettoken(authtoken) { + return authtoken.result.Token; + } + let me = authenticate(password, control_host, control_port, control_path); return await me.then(gettoken); } -function gettoken(authtoken) { - return authtoken.result.Token; -} - -function Done(output) { - //console.log("(i2pcontrol) I2PControl connection tested,", output); - return output; -} - -function Echo(message, control_host = "127.0.0.1", control_port = "7657") { +async function Echo( + message, + control_host = "127.0.0.1", + control_port = "7657", + control_path = "jsonrpc", + password = "itoopie" +) { function echo(token) { + console.log("(i2pcontrol) testing I2PControl connection"); var json = new Object(); json["id"] = makeid(6); json["jsonrpc"] = "2.0"; @@ -81,10 +89,10 @@ function Echo(message, control_host = "127.0.0.1", control_port = "7657") { json["params"] = new Object(); json["params"]["Token"] = token; json["params"]["Echo"] = message; - return send(json); + return send(json, control_host, control_port, control_path); } - let token = GetToken(password); - let done = token.then(echo); + let token = GetToken(password, control_host, control_port, control_path); + let done = await token.then(echo); return done; } @@ -92,17 +100,25 @@ function UpdateEchoElementByID( Query, ID, control_host = "127.0.0.1", - control_port = "7657" + control_port = "7657", + control_path = "jsonrpc" ) { function updateelement(update) { //console.log("(i2pcontrol)", update); - document.getElementById(ID).innerText = update; + if (document.getElementById(ID) !== null) + document.getElementById(ID).innerText = update; } - let net = Echo(Query, control_host, control_port); + let net = Echo(Query, control_host, control_port, control_path, password); net.then(updateleement); } -function GetRate(Query, control_host = "127.0.0.1", control_port = "7657") { +async function GetRate( + Query, + control_host = "127.0.0.1", + control_port = "7657", + control_path = "jsonrpc", + password = "itoopie" +) { function getrate(token) { var json = new Object(); json["id"] = makeid(6); @@ -112,10 +128,10 @@ function GetRate(Query, control_host = "127.0.0.1", control_port = "7657") { json["params"]["Token"] = token; json["params"]["Stat"] = Query; json["params"]["Period"] = 2000; - return send(json); + return send(json, control_host, control_port, control_path); } - let token = GetToken(password); - let done = token.then(getrate); + let token = GetToken(password, control_host, control_port, control_path); + let done = await token.then(getrate); return done; } @@ -123,17 +139,25 @@ function UpdateGetRateElementByID( Query, ID, control_host = "127.0.0.1", - control_port = "7657" + control_port = "7657", + control_path = "jsonrpc" ) { function updateelement(update) { //console.log("(i2pcontrol)", update); - document.getElementById(ID).innerText = update; + if (document.getElementById(ID) !== null) + document.getElementById(ID).innerText = update; } - let net = GetRate(Query, control_host, control_port); + let net = GetRate(Query, control_host, control_port, control_path, password); net.then(updateleement); } -function I2PControl(Query, control_host = "127.0.0.1", control_port = "7657") { +async function I2PControl( + Query, + control_host = "127.0.0.1", + control_port = "7657", + control_path = "jsonrpc", + password = "itoopie" +) { function i2pcontrol(token) { var json = new Object(); json["id"] = makeid(6); @@ -142,10 +166,10 @@ function I2PControl(Query, control_host = "127.0.0.1", control_port = "7657") { json["params"] = new Object(); json["params"]["Token"] = token; json["params"][Query] = null; - return send(json); + return send(json, control_host, control_port, control_path); } - let token = GetToken(password); - let done = token.then(i2pcontrol); + let token = GetToken(password, control_host, control_port, control_path); + let done = await token.then(i2pcontrol); return done; } @@ -153,17 +177,31 @@ function UpdateI2PControlElementByID( Query, ID, control_host = "127.0.0.1", - control_port = "7657" + control_port = "7657", + control_path = "jsonrpc" ) { function updateelement(update) { //console.log("(i2pcontrol)", update); - document.getElementById(ID).innerText = update; + if (document.getElementById(ID) !== null) + document.getElementById(ID).innerText = update; } - let net = I2PControl(Query, control_host, control_port); + let net = I2PControl( + Query, + control_host, + control_port, + control_path, + password + ); net.then(updateleement); } -function RouterInfo(Query, control_host = "127.0.0.1", control_port = "7657") { +async function RouterInfo( + Query, + control_host = "127.0.0.1", + control_port = "7657", + control_path = "jsonrpc", + password = "itoopie" +) { function routerinfo(token) { var json = new Object(); json["id"] = makeid(6); @@ -172,10 +210,10 @@ function RouterInfo(Query, control_host = "127.0.0.1", control_port = "7657") { json["params"] = new Object(); json["params"]["Token"] = token; json["params"][Query] = null; - return send(json); + return send(json, control_host, control_port, control_path); } - let token = GetToken(password); - let done = token.then(routerinfo); + let token = GetToken(password, control_host, control_port, control_path); + let done = await token.then(routerinfo); return done; } @@ -183,25 +221,37 @@ function UpdateRouterInfoElementByID( Query, ID, control_host = "127.0.0.1", - control_port = "7657" + control_port = "7657", + control_path = "jsonrpc", + password = "itoopie" ) { function updateelement(update) { /*console.log( - "(i2pcontrol)", + "(i2pcontrol) element", update.result[Query], ID, document.getElementById(ID) );*/ - document.getElementById(ID).innerText = update.result[Query]; + if (document.getElementById(ID) !== null) + document.getElementById(ID).innerText = update.result[Query]; } - let net = RouterInfo(Query, control_host, control_port); + + let net = RouterInfo( + Query, + control_host, + control_port, + control_path, + password + ); net.then(updateelement); } -function RouterManager( +async function RouterManager( Query, control_host = "127.0.0.1", - control_port = "7657" + control_port = "7657", + control_path = "jsonrpc", + password = "itoopie" ) { function routermanager(token) { var json = new Object(); @@ -211,10 +261,10 @@ function RouterManager( json["params"] = new Object(); json["params"]["Token"] = token; json["params"][Query] = null; - return send(json); + return send(json, control_host, control_port, control_path); } - let token = GetToken(password); - let done = token.then(routermanager); + let token = GetToken(password, control_host, control_port, control_path); + let done = await token.then(routermanager); return done; } @@ -222,20 +272,31 @@ function UpdateRouterManagerElementByID( Query, ID, control_host = "127.0.0.1", - control_port = "7657" + control_port = "7657", + control_path = "jsonrpc", + password = "itoopie" ) { function updateelement(update) { //console.log("(i2pcontrol)", update); - document.getElementById(ID).innerText = update; + if (document.getElementById(ID) !== null) + document.getElementById(ID).innerText = update; } - let net = RouterManage(Query, control_host, control_port); + let net = RouterManager( + Query, + control_host, + control_port, + control_path, + password + ); net.then(updateleement); } -function NetworkSetting( +async function NetworkSetting( Query, control_host = "127.0.0.1", - control_port = "7657" + control_port = "7657", + control_path = "jsonrpc", + password = "itoopie" ) { function networksetting(token) { var json = new Object(); @@ -245,10 +306,10 @@ function NetworkSetting( json["params"] = new Object(); json["params"]["Token"] = token; json["params"][Query] = null; - return send(json); + return send(json, control_host, control_port, control_path); } - let token = GetToken(password); - let done = token.then(networksetting); + let token = GetToken(password, control_host, control_port, control_path); + let done = await token.then(networksetting); return done; } @@ -256,13 +317,21 @@ function UpdateNetworkSettingElementByID( Query, ID, control_host = "127.0.0.1", - control_port = "7657" + control_port = "7657", + control_path = "jsonrpc", + password = "itoopie" ) { function updateelement(update) { //console.log("(i2pcontrol)", update); document.getElementById(ID).innerText = update; } - let net = NetworkSetting(Query, control_host, control_port); + let net = NetworkSetting( + Query, + control_host, + control_port, + control_path, + password + ); net.then(updateleement); } @@ -315,3 +384,8 @@ function UpdateContents() { var done = Echo(hello); done.then(Done); + +function Done(output) { + console.log("(i2pcontrol) I2PControl connection tested,", output); + return output; +} diff --git a/i2ppb@eyedeekay.github.io.xpi b/i2ppb@eyedeekay.github.io.xpi new file mode 100644 index 0000000..22ab1ec Binary files /dev/null and b/i2ppb@eyedeekay.github.io.xpi differ diff --git a/index.html b/index.html index af6e157..de92816 100644 --- a/index.html +++ b/index.html @@ -8,14 +8,14 @@

    I2P in Private Browsing Mode(Firefox-Only)

    -

    This is an Experimental webextension which introduces a set of new "Private -Browsing" modes to Firefox-based browsers(Supporting webextensions) that makes -it easier to configure a browser to use I2P securely and adds features for -making I2P applications easier to use. It does this by isolating I2P-specific -settings to Contextual Identities within Firefox, then loading them -automatically when the user requests them. It also adds convenience and -management features specific to I2P like protocol handlers and native messaging -systems.

    +

    This is an webextension which introduces a set of new "Private Browsing" modes +to Firefox-based browsers(Supporting webextensions) that makes it easier to +configure a browser to use I2P securely and adds features for making I2P +applications easier to use. It does this by isolating I2P-specific settings to +Contextual Identities within Firefox, then loading them automatically when the +user requests them. It also adds convenience and management features, like an +embedded I2P console and Bittorrent integration with clients using the +transmission-rpc API.

    Installation(Cross-Platform):

    @@ -142,6 +142,7 @@ the browser extension's feature panels in presentation form.
  • Smart Lander Design: This is the original outline of the smart landing page which became the I2P home page within the browser and the drop-down control panel.
  • +
  • Other extensions: and how they work with this one.
  • Super Extra Important Background Info:

    @@ -215,7 +216,5 @@ for updates, you can download the identical plugin from this repository's releases page. The latest AMO Plugin will always be identical to the latest github release, except for the version number, which must be incremented for submission to AMO.

    - -

    moz-extension://d63582fc-09fc-445a-b8aa-1c888ee2ffc0/toopie.html

    diff --git a/info.css b/info.css index 032b236..1f1402e 100644 --- a/info.css +++ b/info.css @@ -54,4 +54,7 @@ img.readyness { } #torrentpanel { display: none +} +.torrent-progress { + width: 100% } \ No newline at end of file diff --git a/info.js b/info.js index ace9331..c935787 100644 --- a/info.js +++ b/info.js @@ -3,7 +3,8 @@ function checkPeerConnection() { getting.then(got => { let webrtc = got.value; console.log("checking webrtc", webrtc); - document.getElementById("enable-web-rtc").checked = webrtc; + if (document.getElementById("enable-web-rtc") !== null) + document.getElementById("enable-web-rtc").checked = webrtc; }); } @@ -34,7 +35,8 @@ function checkHistory() { disable_history = false; } console.log("checking history", disable_history); - document.getElementById("disable-history").checked = disable_history; + if (document.getElementById("disable-history") !== null) + document.getElementById("disable-history").checked = disable_history; }); } @@ -85,7 +87,7 @@ document.addEventListener("click", clickEvent => { showBrowsing(); } else if (clickEvent.target.id === "torrent-action") { console.log("showing a torrent action"); - showTorrents(); + showTorrentsMenu(); } else if (clickEvent.target.id === "window-preface-title") { console.log("attempting to create homepage tab"); goHome(); @@ -149,7 +151,7 @@ function showBrowsing() { y.style.display = "none"; } -function showTorrents() { +function showTorrentsMenu() { var x = document.getElementById("browserpanel"); x.style.display = "none"; var y = document.getElementById("torrentpanel"); @@ -212,7 +214,7 @@ function goSearch() { } let createData = { url: - "http://legwork.i2p/yacysearch.html?" + + "http://yacy.idk.i2p/yacysearch.html?" + "query=" + document.getElementById("search-query").value }; @@ -221,12 +223,18 @@ function goSearch() { creating.then(onTabCreated, onTabError); } +function routerAddr() { + if (!control_host) var control_host = "127.0.0.1"; + if (!control_port) var control_port = "7657"; + return control_host + ":" + control_port; +} + function goTunnel() { function onTabError() { console.log("I2PTunnel tab created"); } let createData = { - url: "http://" + control_host + ":" + control_port + "/i2ptunnel" + url: "http://" + routerAddr() + "/i2ptunnel" }; console.log("visiting i2ptunnel"); let creating = browser.tabs.create(createData); @@ -238,7 +246,7 @@ function goMail() { console.log("Mail tab created"); } let createData = { - url: "http://" + control_host + ":" + control_port + "/susimail" + url: "http://" + routerAddr() + "/susimail" }; console.log("visiting mail"); let creating = browser.tabs.create(createData); @@ -250,7 +258,7 @@ function goSnark() { console.log("Snark tab created"); } let createData = { - url: "http://" + control_host + ":" + control_port + "/i2psnark" + url: "http://" + routerAddr() + "/i2psnark" }; console.log("visiting snark"); let creating = browser.tabs.create(createData); @@ -281,11 +289,11 @@ function onVisited(historyItem) { } } -UpdateContents(); +if (UpdateContents !== undefined) UpdateContents(); const minutes = 0.2; const interval = minutes * 60 * 1000; setInterval(function() { - UpdateContents(); + if (UpdateContents !== undefined) UpdateContents(); }, interval); diff --git a/manifest.json b/manifest.json index a09a028..17a4ae1 100644 --- a/manifest.json +++ b/manifest.json @@ -7,8 +7,10 @@ }, "permissions": [ "theme", + "alarms", "browsingData", "bookmarks", + "contextMenus", "management", "notifications", "proxy", @@ -48,8 +50,11 @@ "page": "options/options.html" }, "background": { + "persistent": true, "scripts": [ "config.js", + "torrent/common.js", + "torrent/background.js", "i2pcontrol/i2pcontrol.js", "host.js", "privacy.js", @@ -69,11 +74,6 @@ "name": "RouterConsole", "uriTemplate": "http://127.0.0.1:7657/%s" }, - { - "protocol": "ext+dati2p", - "name": "Dat over I2P", - "uriTemplate": "/dat.html#!/%s" - }, { "protocol": "magnet", "name": "I2PTorrent", diff --git a/options/options.html b/options/options.html index c4cd499..a3f6fa5 100644 --- a/options/options.html +++ b/options/options.html @@ -19,7 +19,7 @@ -
    +
    Proxy Options
    @@ -36,45 +36,54 @@
    --> -
    -
    - Router Console Options -
    +
    +
    +
    + Router Console Options +
    -

    Configure your router console options here.

    - -
    - +

    Configure your router console options here.

    + +
    + +
    -
    -
    - I2PControl RPC Client Options -
    +
    +
    +
    + I2PControl RPC Client Options +
    -

    Configure your I2PControl options here.

    - -
    - -
    - +

    Configure your I2PControl options here.

    + +
    + +
    + +
    + +
    -
    +
    Bittorrent RPC Client Options

    Configure your Bittorrent options here.

    - +
    - +
    - + +
    +
    - + diff --git a/options/options.js b/options/options.js index 790434b..1458560 100644 --- a/options/options.js +++ b/options/options.js @@ -78,6 +78,78 @@ function getControlPort() { return control_port; } +function getRPCHost() { + rpc_host = document.getElementById("rpchost").value; + console.log("(options)Got i2pcontrol rpc host:", rpc_host); + if (rpc_host == undefined) { + return "127.0.0.1"; + } + return rpc_host; +} + +function getRPCPort() { + rpc_port = document.getElementById("rpcport").value; + console.log("(options)Got i2pcontrol rpc port:", rpc_port); + if (rpc_port == undefined) { + return "7657"; + } + return rpc_port; +} + +function getRPCPath() { + rpc_path = document.getElementById("rpcpath").value; + console.log("(options)Got i2pcontrol rpc path:", rpc_path); + if (rpc_path == undefined) { + return "jsonrpc"; + } + return rpc_path; +} + +function getRPCPass() { + rpc_pass = document.getElementById("rpcpass").value; + console.log("(options)Got i2pcontrol rpc password:"); + if (rpc_pass == undefined) { + return "itoopie"; + } + return rpc_pass; +} + +function getBTRPCHost() { + bt_rpc_host = document.getElementById("btrpchost").value; + console.log("(options)Got torrent rpc host:", bt_rpc_host); + if (bt_rpc_host == undefined) { + return "127.0.0.1"; + } + return bt_rpc_host; +} + +function getBTRPCPort() { + bt_rpc_port = document.getElementById("btrpcport").value; + console.log("(options)Got torrent rpc port:", bt_rpc_port); + if (bt_rpc_port == undefined) { + return "7657"; + } + return bt_rpc_port; +} + +function getBTRPCPath() { + bt_rpc_path = document.getElementById("btrpcpath").value; + console.log("(options)Got torrent rpc path:", bt_rpc_path); + if (bt_rpc_path == undefined) { + return "transmission/rpc"; + } + return bt_rpc_path; +} + +function getBTRPCPass() { + bt_rpc_pass = document.getElementById("btrpcpass").value; + console.log("(options)Got torrent rpc password:"); + if (bt_rpc_pass == undefined) { + return "itoopie"; + } + return bt_rpc_pass; +} + function checkStoredSettings(storedSettings) { function gotProxyInfo(info) { let defaultSettings = {}; @@ -93,36 +165,75 @@ function checkStoredSettings(storedSettings) { if (!storedSettings["proxy_host"]) { if (host == "") defaultSettings["proxy_host"] = "127.0.0.1"; else defaultSettings["proxy_host"] = host; - } else { - defaultSettings["proxy_host"] = storedSettings["proxy_host"]; - } + } else defaultSettings["proxy_host"] = storedSettings["proxy_host"]; + if (!storedSettings["proxy_port"]) { if (port == undefined) defaultSettings["proxy_port"] = 4444; else if (port == 7644) defaultSettings["proxy_port"] = port; else defaultSettings["proxy_port"] = 4444; - } else { - defaultSettings["proxy_port"] = storedSettings.proxy_port; - } + } else defaultSettings["proxy_port"] = storedSettings.proxy_port; + if (!storedSettings["control_host"]) { if (host == "") defaultSettings["control_host"] = "127.0.0.1"; else defaultSettings["control_host"] = host; - } else { - defaultSettings["control_host"] = storedSettings.control_host; - } + } else defaultSettings["control_host"] = storedSettings.control_host; + if (!storedSettings["control_port"]) { defaultSettings["control_port"] = 7657; - } else { - defaultSettings["control_port"] = storedSettings.control_port; - } + } else defaultSettings["control_port"] = storedSettings.control_port; + + if (!storedSettings["rpc_host"]) { + if (host == "") defaultSettings["rpc_host"] = "127.0.0.1"; + else defaultSettings["rpc_host"] = host; + } else defaultSettings["rpc_host"] = storedSettings.rpc_host; + + if (!storedSettings["rpc_port"]) { + defaultSettings["rpc_port"] = 7657; + } else defaultSettings["rpc_port"] = storedSettings.rpc_port; + + if (!storedSettings["rpc_path"]) { + defaultSettings["rpc_path"] = "jsonrpc"; + } else defaultSettings["rpc_path"] = storedSettings.rpc_path; + + if (!storedSettings["rpc_pass"]) { + defaultSettings["rpc_pass"] = "itoopie"; + } else defaultSettings["rpc_pass"] = storedSettings.rpc_pass; + + if (!storedSettings["bt_rpc_host"]) { + if (host == "") defaultSettings["bt_rpc_host"] = "127.0.0.1"; + else defaultSettings["bt_rpc_host"] = host; + } else defaultSettings["bt_rpc_host"] = storedSettings.bt_rpc_host; + + if (!storedSettings["bt_rpc_port"]) { + defaultSettings["bt_rpc_port"] = 7657; + } else defaultSettings["bt_rpc_port"] = storedSettings.bt_rpc_port; + + if (!storedSettings["bt_rpc_path"]) { + defaultSettings["bt_rpc_path"] = "transmission/"; + } else defaultSettings["bt_rpc_path"] = storedSettings.bt_rpc_path; + + if (!storedSettings["bt_rpc_pass"]) { + defaultSettings["bt_rpc_pass"] = "transmission"; + } else defaultSettings["bt_rpc_pass"] = storedSettings.bt_rpc_pass; + console.log("(options)(browserinfo) NATIVE PROXYSETTINGS", info.value); + defaultSettings["base_url"] = + "http://" + + defaultSettings["bt_rpc_host"] + + ":" + + defaultSettings["bt_rpc_port"] + + "/" + + defaultSettings["bt_rpc_path"]; console.log( "(options)", - defaultSettings["proxy_sheme"], + defaultSettings["proxy_scheme"], defaultSettings["proxy_host"], defaultSettings["proxy_port"], defaultSettings["control_host"], - defaultSettings["control_port"] + defaultSettings["control_port"], + defaultSettings["base_url"] ); + chrome.storage.local.set(defaultSettings); return defaultSettings; } @@ -139,27 +250,57 @@ function checkAndroidStoredSettings(storedSettings) { if (!storedSettings["proxy_host"]) { if (host == "") defaultSettings["proxy_host"] = "127.0.0.1"; else defaultSettings["proxy_host"] = host; - } else { - defaultSettings["proxy_host"] = storedSettings["proxy_host"]; - } + } else defaultSettings["proxy_host"] = storedSettings["proxy_host"]; + if (!storedSettings["proxy_port"]) { if (port == undefined) defaultSettings["proxy_port"] = 4444; else if (port == 7644) defaultSettings["proxy_port"] = port; else defaultSettings["proxy_port"] = 4444; - } else { - defaultSettings["proxy_port"] = storedSettings.proxy_port; - } + } else defaultSettings["proxy_port"] = storedSettings.proxy_port; + if (!storedSettings["control_host"]) { if (host == "") defaultSettings["control_host"] = "127.0.0.1"; else defaultSettings["control_host"] = host; - } else { - defaultSettings["control_host"] = storedSettings.control_host; - } + } else defaultSettings["control_host"] = storedSettings.control_host; + if (!storedSettings["control_port"]) { defaultSettings["control_port"] = 7657; - } else { - defaultSettings["control_port"] = storedSettings.control_port; - } + } else defaultSettings["control_port"] = storedSettings.control_port; + + if (!storedSettings["rpc_host"]) { + if (host == "") defaultSettings["rpc_host"] = "127.0.0.1"; + else defaultSettings["rpc_host"] = host; + } else defaultSettings["rpc_host"] = storedSettings.rpc_host; + + if (!storedSettings["rpc_port"]) { + defaultSettings["rpc_port"] = 7657; + } else defaultSettings["rpc_port"] = storedSettings.rpc_port; + + if (!storedSettings["rpc_path"]) { + defaultSettings["rpc_path"] = "jsonrpc"; + } else defaultSettings["rpc_path"] = storedSettings.rpc_path; + + if (!storedSettings["rpc_pass"]) { + defaultSettings["rpc_pass"] = "itoopie"; + } else defaultSettings["rpc_pass"] = storedSettings.rpc_pass; + + if (!storedSettings["bt_rpc_host"]) { + if (host == "") defaultSettings["bt_rpc_host"] = "127.0.0.1"; + else defaultSettings["bt_rpc_host"] = host; + } else defaultSettings["bt_rpc_host"] = storedSettings.bt_rpc_host; + + if (!storedSettings["bt_rpc_port"]) { + defaultSettings["bt_rpc_port"] = 7657; + } else defaultSettings["bt_rpc_port"] = storedSettings.bt_rpc_port; + + if (!storedSettings["bt_rpc_path"]) { + defaultSettings["bt_rpc_path"] = "transmission/rpc"; + } else defaultSettings["bt_rpc_path"] = storedSettings.bt_rpc_path; + + if (!storedSettings["bt_rpc_pass"]) { + defaultSettings["bt_rpc_pass"] = "transmission"; + } else defaultSettings["bt_rpc_pass"] = storedSettings.bt_rpc_pass; + console.log("(options)(browserinfo) NATIVE PROXYSETTINGS", info.value); console.log( "(options)", @@ -183,35 +324,91 @@ function storeSettings() { let proxy_port = getPort(); let control_host = getControlHost(); let control_port = getControlPort(); + let rpc_host = getRPCHost(); + let rpc_port = getRPCPort(); + let rpc_path = getRPCPath(); + let rpc_pass = getRPCPass(); + let bt_rpc_host = getBTRPCHost(); + let bt_rpc_port = getBTRPCPort(); + let bt_rpc_path = getBTRPCPath(); + let bt_rpc_pass = getBTRPCPass(); + let base_url = + "http://" + bt_rpc_host + ":" + bt_rpc_port + "/" + bt_rpc_path; chrome.storage.local.set({ proxy_scheme, proxy_host, proxy_port, control_host, - control_port + control_port, + rpc_host, + rpc_port, + rpc_path, + rpc_pass, + bt_rpc_host, + bt_rpc_port, + bt_rpc_path, + bt_rpc_pass }); } function updateUI(restoredSettings) { const selectList = document.querySelector("#proxy_scheme"); - selectList.value = restoredSettings.proxy_scheme; - console.log("(options)showing proxy scheme:", selectList.value); + if (selectList == undefined) selectList.value = restoredSettings.proxy_scheme; + //console.log("(options)showing proxy scheme:", selectList.value); const hostitem = document.getElementById("host"); - hostitem.value = restoredSettings.proxy_host; - console.log("(options)showing proxy host:", hostitem.value); + if (hostitem == undefined) hostitem.value = restoredSettings.proxy_host; + //console.log("(options)showing proxy host:", hostitem.value); const portitem = document.getElementById("port"); - portitem.value = restoredSettings.proxy_port; - console.log("(options)showing proxy port:", portitem.value); + if (portitem == undefined) portitem.value = restoredSettings.proxy_port; + //console.log("(options)showing proxy port:", portitem.value); const controlhostitem = document.getElementById("controlhost"); - controlhostitem.value = restoredSettings.control_host; - console.log("(options)showing control host:", controlhostitem.value); + if (controlhostitem == undefined) + controlhostitem.value = restoredSettings.control_host; + //console.log("(options)showing control host:", controlhostitem.value); const controlportitem = document.getElementById("controlport"); - controlportitem.value = restoredSettings.control_port; - console.log("(options)showing control port:", controlportitem.value); + if (controlportitem == undefined) + controlportitem.value = restoredSettings.control_port; + //console.log("(options)showing control port:", controlportitem.value); + + const rpchostitem = document.getElementById("rpchost"); + if (rpchostitem == undefined) rpchostitem.value = restoredSettings.rpc_host; + //console.log("(options)showing rpc host:", rpchostitem.value); + + const rpcportitem = document.getElementById("rpcport"); + if (rpcportitem == undefined) rpcportitem.value = restoredSettings.rpc_port; + //console.log("(options)showing rpc port:", rpcportitem.value); + + const rpcpathitem = document.getElementById("rpcpath"); + if (rpcpathitem == undefined) rpcpathitem.value = restoredSettings.rpc_path; + //console.log("(options)showing rpc path:", rpcpathitem.value); + + const rpcpassitem = document.getElementById("rpcpass"); + if (rpcpassitem == undefined) rpcpassitem.value = restoredSettings.rpc_pass; + //console.log("(options)showing rpc pass:"); + + const btrpchostitem = document.getElementById("btrpchost"); + if (btrpchostitem == undefined) + btrpchostitem.value = restoredSettings.rpc_host; + //console.log("(options)showing bt rpc host:", btrpchostitem.value); + + const btrpcportitem = document.getElementById("btrpcport"); + if (btrpcportitem == undefined) + btrpcportitem.value = restoredSettings.rpc_port; + //console.log("(options)showing rbt pc port:", rpcportitem.value); + + const btrpcpathitem = document.getElementById("btrpcpath"); + if (btrpcpathitem == undefined) + btrpcpathitem.value = restoredSettings.rpc_path; + //console.log("(options)showing bt rpc path:", btrpcpathitem.value); + + const btrpcpassitem = document.getElementById("btrpcpass"); + if (btrpcpassitem == undefined) + btrpcpassitem.value = restoredSettings.rpc_pass; + //console.log("(options)showing bt rpc pass:"); SetHostText(); SetPortText(); diff --git a/proxy.js b/proxy.js index 7f76838..9344705 100644 --- a/proxy.js +++ b/proxy.js @@ -20,7 +20,6 @@ function shouldProxyRequest(requestInfo) { } var handleContextProxyRequest = async function(requestDetails) { - console.log("(proxy)Searching for proxy by context"); try { var handleProxyRequest = function(context) { proxy = { @@ -100,12 +99,12 @@ var handleContextProxyRequest = async function(requestDetails) { }; var contextGet = async function(tabInfo) { try { - //console.log("(proxy)Tab info from Function", tabInfo); + console.log("(proxy)Tab info from Function", tabInfo); context = await browser.contextualIdentities.get(tabInfo.cookieStoreId); return context; } catch (error) { console.error(error); - //return; //"firefox-default"; + return "firefox-default"; } }; var tabGet = async function(tabId) { diff --git a/scrub.js b/scrub.js index 9d37b45..c26fb2e 100644 --- a/scrub.js +++ b/scrub.js @@ -11,12 +11,11 @@ var contextScrub = async function(requestDetails) { function onHeaderError() { console.log("Header scrub error"); } - console.log("(scrub)Scrubbing info from contextualized request"); + //console.log("(scrub)Scrubbing info from contextualized request"); try { var headerScrub = function(context) { var ua = "MYOB/6.66 (AN/ON)"; if (!context) { - console.log("Context not found", context); } else if (context.name == titlepref) { if (i2pHost(requestDetails.url)) { for (var header of requestDetails.requestHeaders) { @@ -45,7 +44,7 @@ var contextScrub = async function(requestDetails) { }; var contextGet = async function(tabInfo) { try { - console.log("(scrub)Tab info from Function", tabInfo); + //console.log("(scrub)Tab info from Function", tabInfo); let context = await browser.contextualIdentities.get( tabInfo.cookieStoreId ); @@ -56,7 +55,7 @@ var contextScrub = async function(requestDetails) { }; var tabGet = async function(tabId) { try { - console.log("(scrub)Tab ID from Request", tabId); + //console.log("(scrub)Tab ID from Request", tabId); let tabInfo = await browser.tabs.get(tabId); return tabInfo; } catch (error) { @@ -68,17 +67,17 @@ var contextScrub = async function(requestDetails) { var context = {}; var req = {}; if (i2pHost(requestDetails.url)) { - console.log("(scrub)I2P URL detected, "); + //console.log("(scrub)I2P URL detected, "); tab = tabGet(requestDetails.tabId); context = tab.then(contextGet, onHeaderError); req = await context.then(headerScrub, onHeaderError); - console.log("(scrub)Scrubbing I2P Request", req); + //console.log("(scrub)Scrubbing I2P Request", req); return req; } else if (routerHost(requestDetails.url)) { tab = tabGet(requestDetails.tabId); context = tab.then(contextGet, onHeaderError); req = await context.then(headerScrub, onHeaderError); - console.log("(scrub)Scrubbing non-I2P Request", req); + //console.log("(scrub)Scrubbing non-I2P Request", req); return req; } return req; @@ -92,7 +91,7 @@ var contextSetup = function(requestDetails) { function onContextError() { console.log("Context launcher error"); } - console.log("(isolate)Forcing I2P requests into context"); + //console.log("(isolate)Forcing I2P requests into context"); try { var i2pTabFind = async function(tabId) { try { @@ -100,8 +99,6 @@ var contextSetup = function(requestDetails) { name: titlepref }); if (tabId.cookieStoreId != context[0].cookieStoreId) { - console.log("(isolate) I2P context", context[0].cookieStoreId); - console.log("tab context", tabId.cookieStoreId); function Create() { function onCreated(tab) { function closeOldTab() { @@ -135,8 +132,6 @@ var contextSetup = function(requestDetails) { name: routerpref }); if (tabId.cookieStoreId != context[0].cookieStoreId) { - console.log("(isolate) I2P context", context[0].cookieStoreId); - console.log("tab context", tabId.cookieStoreId); function Create() { function onCreated(tab) { function closeOldTab() { @@ -170,8 +165,6 @@ var contextSetup = function(requestDetails) { name: tunnelpref }); if (tabId.cookieStoreId != context[0].cookieStoreId) { - console.log("(isolate) I2P context", context[0].cookieStoreId); - console.log("tab context", tabId.cookieStoreId); function Create() { function onCreated(tab) { function closeOldTab() { @@ -205,8 +198,6 @@ var contextSetup = function(requestDetails) { name: torrentpref }); if (tabId.cookieStoreId != context[0].cookieStoreId) { - console.log("(isolate) I2P context", context[0].cookieStoreId); - console.log("tab context", tabId.cookieStoreId); function Create() { function onCreated(tab) { function closeOldTab() { @@ -240,8 +231,6 @@ var contextSetup = function(requestDetails) { name: mailpref }); if (tabId.cookieStoreId != context[0].cookieStoreId) { - console.log("(isolate) I2P context", context[0].cookieStoreId); - console.log("tab context", tabId.cookieStoreId); function Create() { function onCreated(tab) { function closeOldTab() { @@ -275,8 +264,6 @@ var contextSetup = function(requestDetails) { name: localpref }); if (tabId.cookieStoreId != context[0].cookieStoreId) { - console.log("(isolate) I2P context", context[0].cookieStoreId); - console.log("tab context", tabId.cookieStoreId); function Create() { function onCreated(tab) { function closeOldTab() { @@ -304,42 +291,68 @@ var contextSetup = function(requestDetails) { console.log("(isolate)Context Error", error); } }; - var anyTabFind = async function(tabId) { + var normalTabFind = async function(tabId) { + if (tabId == undefined) { + return; + } try { - var context = await browser.contextualIdentities.query({ - name: webpref + var anoncontext = await browser.contextualIdentities.query({ + name: titlepref + }); + var localcontext = await browser.contextualIdentities.query({ + name: localpref }); - console.log("(ISOLATE)", tabId.cookieStoreId); if ( tabId.cookieStoreId == "firefox-default" || tabId.cookieStoreId == "firefox-private" ) { - if (tabId.cookieStoreId != context[0].cookieStoreId) { - console.log("(isolate) I2P context", context[0].cookieStoreId); - console.log("tab context", tabId.cookieStoreId); - function Create() { - function onCreated(tab) { - function closeOldTab() { - if (tabId.id != tab.id) { - console.log("(isolate) Closing un-isolated tab", tabId.id); - console.log("in favor of", tab.id); - console.log("with context", tab.cookieStoreId); - browser.tabs.remove(tabId.id); - } + console.log( + "(ISOLATE)", + tabId.cookieStoreId, + "not", + anoncontext[0].cookieStoreId, + localcontext[0].cookieStoreId + ); + return; + } + if ( + tabId.cookieStoreId != anoncontext[0].cookieStoreId || + tabId.cookieStoreId != localcontext[0].cookieStoreId + ) { + function Create() { + function onCreated(tab) { + function closeOldTab() { + if ( + tabId.id != tab.id && + tabId.cookieStoreId != tab.cookieStoreId + ) { + console.log( + "(isolate) Closing isolated tab", + tabId.id, + "with context", + tabId.cookieStoreId + ); + console.log( + "(isolate) in favor of", + tab.id, + "with context", + tab.cookieStoreId + ); + browser.tabs.remove(tabId.id); } - closeOldTab(tab); } - var created = browser.tabs.create({ - active: true, - cookieStoreId: context[0].cookieStoreId, - url: requestDetails.url - }); - created.then(onCreated, onContextError); + closeOldTab(tab); } - var gettab = browser.tabs.get(tabId.id); - gettab.then(Create, onContextError); - return tabId; + var created = browser.tabs.create({ + active: true, + cookieStoreId: "firefox-default", + url: requestDetails.url + }); + created.then(onCreated, onContextError); } + var gettab = browser.tabs.get(tabId.id); + gettab.then(Create, onContextError); + return tabId; } } catch (error) { console.log("(isolate)Context Error", error); @@ -347,7 +360,7 @@ var contextSetup = function(requestDetails) { }; var tabGet = async function(tabId) { try { - console.log("(isolate)Tab ID from Request", tabId); + //console.log("(isolate)Tab ID from Request", tabId); let tabInfo = await browser.tabs.get(tabId); return tabInfo; } catch (error) { @@ -384,12 +397,6 @@ var contextSetup = function(requestDetails) { } let localhost = localHost(requestDetails.url); let routerhost = routerHost(requestDetails.url); - if (!routerhost) { - if (localhost) { - var localtab = tab.then(localTabFind, onContextError); - return requestDetails; - } - } if (routerhost) { if (routerhost === "i2ptunnelmgr") { var tunneltab = tab.then(i2ptunnelTabFind, onContextError); @@ -405,7 +412,13 @@ var contextSetup = function(requestDetails) { return requestDetails; } } else { + if (localhost) { + var localtab = tab.then(localTabFind, onContextError); + return requestDetails; + } + var normalTab = tab.then(normalTabFind, onContextError); return requestDetails; + //return requestDetails; } } } catch (error) { diff --git a/sidebar.css b/sidebar.css index 3a41519..492be91 100644 --- a/sidebar.css +++ b/sidebar.css @@ -2,9 +2,6 @@ li { width: 90%; margin-left: 0 } -#readyness { - float: unset -} #applicationExplain { float: unset } \ No newline at end of file diff --git a/torrent/README.md b/torrent/README.md new file mode 100644 index 0000000..60e8893 --- /dev/null +++ b/torrent/README.md @@ -0,0 +1,14 @@ +Acknowledgement +=============== + +**Many, many thanks to the [Transmitter](https://github.com/myfreeweb/transmitter) +webextension.** + +This part of this plugin contains code which was adapted from the Transmitter +webextension, which is a minimal interface to the transmission-rpc interfaces of +many torrent clients, including for our purposes snark-rpc and BiglyBT. + +Transmitter is released under the UNLICENSE. An original copy is available at +this URL: https://github.com/myfreeweb/transmitter/blob/master/UNLICENSE + +A copy has also been included in this directory. \ No newline at end of file diff --git a/torrent/UNLICENSE b/torrent/UNLICENSE new file mode 100644 index 0000000..68a49da --- /dev/null +++ b/torrent/UNLICENSE @@ -0,0 +1,24 @@ +This is free and unencumbered software released into the public domain. + +Anyone is free to copy, modify, publish, use, compile, sell, or +distribute this software, either in source code form or as a compiled +binary, for any purpose, commercial or non-commercial, and by any +means. + +In jurisdictions that recognize copyright laws, the author or authors +of this software dedicate any and all copyright interest in the +software to the public domain. We make this dedication for the benefit +of the public at large and to the detriment of our heirs and +successors. We intend this dedication to be an overt act of +relinquishment in perpetuity of all present and future rights to this +software under copyright law. + +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 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. + +For more information, please refer to diff --git a/torrent/background.js b/torrent/background.js new file mode 100644 index 0000000..8bc27e0 --- /dev/null +++ b/torrent/background.js @@ -0,0 +1,247 @@ +"use strict"; + +////// Session extraction + +function setupExtractor() { + browser.webRequest.onHeadersReceived.removeListener(extractSession); + browser.storage.local.get("server").then(({ server }) => { + if (!server) { + return; + } + console.log("Session extractor setup for", server.base_url); + browser.webRequest.onBeforeSendHeaders.addListener( + extractSession, + { urls: [server.base_url + "*"] }, + ["requestHeaders"] + ); + }); +} + +setupExtractor(); + +function extractSession(requestDetails) { + const hdr = requestDetails.requestHeaders.filter( + x => x.name.toLowerCase() === "x-transmission-session-id" + )[0]; + if (!hdr) { + return; + } + browser.storage.local.get("server").then(({ server }) => { + server.session = hdr.value; + browser.storage.local.set({ server }); + }); +} + +////// Adding + +function blobToBase64(blob) { + return new Promise((resolve, reject) => { + const rdr = new FileReader(); + rdr.onload = () => resolve(rdr.result.substr(rdr.result.indexOf(",") + 1)); + rdr.onerror = reject; + rdr.readAsDataURL(blob); + }); +} + +function addUrl(torrentUrl, downloadDir) { + let p, + params = {}; + if (downloadDir) { + params = { "download-dir": downloadDir }; + } + if (torrentUrl.startsWith("magnet:")) { + console.log("Adding magnet", torrentUrl); + params.filename = torrentUrl; + p = rpcCall("torrent-add", params); + } else { + // Download the torrent file *in the browser* to support private torrents + console.log("Downloading torrent", torrentUrl); + p = fetch(torrentUrl, { + method: "GET", + credentials: "include" + }) + .then(resp => { + if (resp.ok) { + return resp.blob(); + } + throw new Error("Could not download torrent"); + }) + .then(blobToBase64) + .then(b64 => { + params.metainfo = b64; + return rpcCall("torrent-add", params); + }); + } + return p.then(x => { + updateBadge(); + return x; + }); +} + +////// magnet: Handler + +function handleUrl(requestDetails) { + return addUrl( + decodeURIComponent( + requestDetails.url.replace("http://transmitter.web-extension/", "") + ) + ).then(x => { + return browser.storage.local.get("server").then(({ server }) => { + return { redirectUrl: server.base_url + "web/" }; + }); + }); +} + +browser.webRequest.onBeforeRequest.addListener( + handleUrl, + { urls: ["http://transmitter.web-extension/*"] }, + ["blocking"] +); + +////// Context menu + +function createContextMenu() { + browser.storage.local.get("server").then(({ server }) => { + browser.contextMenus.removeAll(); + if (!server || !server.locations || !server.locations.length) { + browser.contextMenus.create({ + id: "transmitter-add", + title: "Download with Transmission remote", + contexts: ["link"] + }); + } else { + browser.contextMenus.create({ + id: "transmitter-add", + title: "Download to Default location", + contexts: ["link"] + }); + server.locations.forEach(location => { + browser.contextMenus.create({ + id: "transmitter-add-loc-" + location.index, + title: "Download to " + location.name, + contexts: ["link"] + }); + }); + } + }); +} + +createContextMenu(); + +browser.contextMenus.onClicked.addListener((info, tab) => { + if (info.menuItemId === "transmitter-add") { + return addUrl(info.linkUrl); + } else if (info.menuItemId.startsWith("transmitter-add-loc-")) { + let index = parseInt(info.menuItemId.substr("transmitter-add-loc-".length)); + browser.storage.local.get("server").then(({ server }) => { + let path = server.locations[index].path; + addUrl(info.linkUrl, path); + }); + } +}); + +////// Badge + +function updateBadge() { + browser.storage.local.get("server").then(({ server }) => { + if ( + server.badge !== "num" && + server.badge !== "dl" && + server.badge !== "ul" && + server.badge !== "auto" + ) { + return; + } + return rpcCall("session-stats", {}).then(response => { + const args = response.arguments; // lol the name 'arguments' means destructuring in strict mode is impossible + switch (server.badge) { + case "num": + browser.browserAction.setBadgeBackgroundColor({ color: "gray" }); + browser.browserAction.setBadgeText({ + text: "" + args.activeTorrentCount + }); + break; + case "dl": + browser.browserAction.setBadgeBackgroundColor({ color: "green" }); + browser.browserAction.setBadgeText({ + text: formatSpeed(args.downloadSpeed) + }); + break; + case "ul": + browser.browserAction.setBadgeBackgroundColor({ color: "blue" }); + browser.browserAction.setBadgeText({ + text: formatSpeed(args.uploadSpeed) + }); + break; + case "auto": + if (args.downloadSpeed > 0) { + browser.browserAction.setBadgeBackgroundColor({ color: "green" }); + browser.browserAction.setBadgeText({ + text: formatSpeed(args.downloadSpeed) + }); + } else if (args.uploadSpeed > 0) { + browser.browserAction.setBadgeBackgroundColor({ color: "blue" }); + browser.browserAction.setBadgeText({ + text: formatSpeed(args.uploadSpeed) + }); + } else { + browser.browserAction.setBadgeBackgroundColor({ color: "gray" }); + browser.browserAction.setBadgeText({ + text: "" + args.activeTorrentCount + }); + } + break; + } + }); + }); +} + +browser.alarms.onAlarm.addListener(alarm => { + if (alarm.name === "transmitter-badge-update") { + return updateBadge(); + } +}); + +function setupBadge() { + browser.alarms.clear("transmitter-badge-update").then(x => { + browser.storage.local.get("server").then(({ server }) => { + if (!server) { + return; + } + browser.alarms.create("transmitter-badge-update", { + periodInMinutes: parseInt(server.badge_interval || "1") + }); + updateBadge(); + }); + }); +} + +setupBadge(); + +////// Storage updates + +browser.storage.onChanged.addListener((changes, area) => { + if (!Object.keys(changes).includes("server")) { + return; + } + const oldv = changes.server.oldValue; + const newv = changes.server.newValue; + if ( + !oldv || + oldv.base_url !== newv.base_url || + oldv.username !== newv.username || + oldv.password !== newv.password || + oldv.badge_interval !== newv.badge_interval || + oldv.badge !== newv.badge || + arraysEqualDeep(oldv.locations, newv.locations) + ) { + setupExtractor(); + setupBadge(); + updateBadge(); + createContextMenu(); + } +}); + +function arraysEqualDeep(arr1, arr2) { + return JSON.stringify(arr1) !== JSON.stringify(arr2); +} diff --git a/torrent/common.js b/torrent/common.js new file mode 100644 index 0000000..577bf81 --- /dev/null +++ b/torrent/common.js @@ -0,0 +1,60 @@ +"use strict"; + +////// RPC + +function rpcCall(meth, args) { + return browser.storage.local.get(function(server) { + const myHeaders = { + "Content-Type": "application/json", + "x-transmission-session-id": server.session + }; + //console.log("(torrent)", server.session) + if (server.username !== "" || server.btrpcpass !== "") { + myHeaders["Authorization"] = + "Basic " + + btoa((server.username || "") + ":" + (server.btrpcpass || "")); + } + //console.log("(torrent) rpc", server.base_url); + return fetch(server.base_url + "rpc", { + method: "POST", + headers: myHeaders, + body: JSON.stringify({ method: meth, arguments: args }), + credentials: "include" // allows HTTPS client certs! + }) + .then(function(response) { + const session = response.headers.get("x-transmission-session-id"); + if (session) { + browser.storage.local.get({}).then(function(storage) { + storage.session = session; + browser.storage.local.set(storage); + }); + } + if (response.status === 409) { + return rpcCall(meth, args); + } + if (response.status >= 200 && response.status < 300) { + return response; + } + const error = new Error(response.statusText); + error.response = response; + throw error; + }) + .then(function(response) { + return response.json(); + }); + }); +} + +////// Util + +function formatSpeed(s) { + // Firefox shows 4 characters max + if (s < 1000 * 1000) { + return (s / 1000).toFixed() + "K"; + } + if (s < 1000 * 1000 * 1000) { + return (s / 1000 / 1000).toFixed() + "M"; + } + // You probably don't have that download speed… + return (s / 1000 / 1000 / 1000).toFixed() + "T"; +} diff --git a/torrent/index.html b/torrent/index.html new file mode 100644 index 0000000..609819e --- /dev/null +++ b/torrent/index.html @@ -0,0 +1,23 @@ + + + + I2P in Private Browsing Mode + + + + +

    Acknowledgement

    + +

    Many, many thanks to the Transmitter +webextension.

    + +

    This part of this plugin contains code which was adapted from the Transmitter +webextension, which is a minimal interface to the transmission-rpc interfaces of +many torrent clients, including for our purposes snark-rpc and BiglyBT.

    + +

    Transmitter is released under the UNLICENSE. An original copy is available at +this URL: https://github.com/myfreeweb/transmitter/blob/master/UNLICENSE

    + +

    A copy has also been included in this directory.

    + + diff --git a/torrent/popup.js b/torrent/popup.js new file mode 100644 index 0000000..45c0660 --- /dev/null +++ b/torrent/popup.js @@ -0,0 +1,153 @@ +"use strict"; + +var TrpcCall = async function(meth, args) { + const server = await browser.storage.local.get(null); + const myHeaders = { + "Content-Type": "application/json", + "x-transmission-session-id": server.session + }; + console.log("(torrent) session", server.session); + if (server.username !== "" || server.btrpcpass !== "") { + myHeaders["Authorization"] = + "Basic " + btoa((server.username || "") + ":" + (server.btrpcpass || "")); + } + console.log("(torrent) rpcurl", server.base_url + "rpc"); + return fetch(server.base_url + "rpc", { + method: "POST", + headers: myHeaders, + body: JSON.stringify({ method: meth, arguments: args }), + credentials: "include" // allows HTTPS client certs! + }); + + /*.then(function(response) { + console.log("(torrent) responses", response); + + if (response.status === 409) { + return TrpcCall(meth, args); + } + if (response.status >= 200 && response.status < 300) { + return response; + } + const error = new Error(response.statusText); + error.response = response; + throw error; + });*/ +}; + +const torrentsPane = document.getElementById("torrents-pane"); +const configPane = document.getElementById("config-pane"); + +for (const opener of document.querySelectorAll(".config-opener")) { + opener.addEventListener("click", e => { + browser.runtime.openOptionsPage(); + }); +} + +function showConfig(server) { + torrentsPane.hidden = true; + configPane.hidden = false; +} + +const torrentsSearch = document.getElementById("torrents-search"); +const torrentsList = document.getElementById("torrents-list"); +const torrentsTpl = document.getElementById("torrents-tpl"); +const torrentsError = document.getElementById("torrents-error"); +const getArgs = { + fields: ["name", "percentDone", "rateDownload", "rateUpload", "queuePosition"] +}; +let cachedTorrents = []; + +function renderTorrents(newTorrents) { + if (torrentsList.children.length < newTorrents.length) { + const dif = newTorrents.length - torrentsList.children.length; + for (let i = 0; i < dif; i++) { + const node = document.importNode(torrentsTpl.content, true); + torrentsList.appendChild(node); + } + } else if (torrentsList.children.length > newTorrents.length) { + const oldLen = torrentsList.children.length; + const dif = oldLen - newTorrents.length; + for (let i = 1; i <= dif; i++) { + torrentsList.removeChild(torrentsList.children[oldLen - i]); + } + } + for (let i = 0; i < newTorrents.length; i++) { + const torr = newTorrents[i]; + const cont = torrentsList.children[i]; + const speeds = + "↓ " + + formatSpeed(torr.rateDownload) + + "B/s ↑ " + + formatSpeed(torr.rateUpload) + + "B/s"; + cont.querySelector(".torrent-name").textContent = torr.name; + cont.querySelector(".torrent-speeds").textContent = speeds; + cont.querySelector(".torrent-progress").value = torr.percentDone * 100; + } +} + +function searchTorrents() { + let newTorrents = cachedTorrents; + const val = torrentsSearch.value.toLowerCase().trim(); + if (val.length > 0) { + newTorrents = newTorrents.filter(x => x.name.toLowerCase().includes(val)); + } + renderTorrents(newTorrents); +} +torrentsSearch.addEventListener("change", searchTorrents); +torrentsSearch.addEventListener("keyup", searchTorrents); + +function refreshTorrents(server) { + console.log("(torrent) initiating", server); + return TrpcCall("torrent-get", getArgs).then(function(response) { + const session = response.headers.get("x-transmission-session-id"); + if (session) { + browser.storage.local.get({}).then(function(storage) { + storage.session = session; + browser.storage.local.set(storage); + }); + } + let sponse = response.json(); + sponse.then(function(response) { + console.log("(torrent) refreshing", response); + let newTorrents = response.arguments.torrents; + newTorrents.sort((x, y) => y.queuePosition - x.queuePosition); + cachedTorrents = newTorrents; + torrentsSearch.hidden = newTorrents.length <= 8; + if (torrentsSearch.hidden) { + torrentsSearch.value = ""; + renderTorrents(newTorrents); + } else { + searchTorrents(); + } + }); + }); +} + +function refreshTorrentsLogErr(server) { + return refreshTorrents(server).catch(err => { + console.error(err); + torrentsError.textContent = "Error: " + err.toString(); + }); +} + +function showTorrents(server) { + torrentsPane.hidden = false; + configPane.hidden = true; + for (const opener of document.querySelectorAll(".webui-opener")) { + opener.href = server.base_url + "web/"; + } + console.log("(torrent) showing torrents"); + refreshTorrents(server).catch(_ => refreshTorrentsLogErr(server)); + setInterval(() => refreshTorrentsLogErr(server), 2000); +} + +//let store = +browser.storage.local.get(function(server) { + console.log("(torrent) querying storage", server); + if (server && server.base_url && server.base_url !== "") { + showTorrents(server); + } else { + showConfig(server); + } +}); diff --git a/torrent/torrent.js b/torrent/torrent.js deleted file mode 100644 index e69de29..0000000 diff --git a/transmissionrpc.png b/transmissionrpc.png new file mode 100644 index 0000000..04e3ac4 Binary files /dev/null and b/transmissionrpc.png differ diff --git a/window.html b/window.html index cfe5fff..f70e70a 100644 --- a/window.html +++ b/window.html @@ -4,7 +4,8 @@ - + + @@ -16,121 +17,155 @@
    -
    +
    -

    The Invisible Internet Browser

    +

    The Invisible Internet Browser

    - + +
    +
    +
    + +
    + Home Page +
    + +
    +
    + +
    + Proxy is ready. +
    + +
    +

    You are now able to use I2P in this browser.

    + +

    It is experimental.

    +
    +
    + +
    +

    +

    + +

    Controls

    + +

    These controls are used to tailor your I2P Browsing Experience

    + +
      +
    • + Clear Browsing Data: Use this to erase your browsing data. +
    • + +
    • WebRTC is disabled by default, but can be enabled by checking this box.
    • + +
    • +
      +
      + +
      +
      +
      +
      +
    • + +
    • History is automatically cleared when your I2P tabs are closed. If you want to clear history as you go, check this box.
    • +
    + +

    +

    + +

    +

    +
    -
    +
    +

    +

    + +

    Applications

    + +

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

    + +
      +
    • For more information about this extension, go here:
    • + +
    • For information about your I2P router status, 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:
    • +
    + +

    +

    + +

    +

    - -
    - Proxy is ready. -
    - -
    -

    You are now able to use I2P in this browser.

    - -

    It is experimental.

    -
    - -
    -
    - -
    -

    -

    - -

    Controls

    - -

    These controls are used to tailor your I2P Browsing Experience

    - -
      -
    • - Clear Browsing Data: Use this to erase your browsing data. -
    • - -
    • WebRTC is disabled by default, but can be enabled by checking this box.
    • - -
    • -
      -
      - -
      -
      -
      -
      -
    • - -
    • History is automatically cleared when your I2P tabs are closed. If you want to clear history as you go, check this box.
    • -
    - -

    -

    - -

    -

    -
    - -
    -
    - -
    -

    -

    - -

    Applications

    - -

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

    - -
      -
    • For more information about this extension, go here:
    • - -
    • For information about your I2P router status, 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:
    • -
    - -

    -

    - -

    -

    -
    - -
    -
    -
    -
    -

    Torrent Downloads

    -
    -
    - -
    - Torrents go here. -
    -
    -
    - - - - -
    + +
    +
    +
    +
    +

    Torrent Downloads

    +
    +
    + + + + +
    +
    + + + + + + +