Compare commits
50 Commits
Author | SHA1 | Date | |
---|---|---|---|
d3b043fc23 | |||
a9e70d19a7 | |||
4e6117faf9 | |||
015e20c06a | |||
96ad84bf2c | |||
45b13ef209 | |||
fbf7ced2c7 | |||
d2403362ba | |||
fe23ea2047 | |||
5b01b19688 | |||
7664b3530d | |||
87faaa3e74 | |||
e66bc441d3 | |||
13eaf1f035 | |||
8106f114ca | |||
e796ce750f | |||
7301cbd7ba | |||
3bb805b40c | |||
4a880b973d | |||
60c455b6af | |||
9dc5b365ed | |||
d754930a66 | |||
0a7a44e05c | |||
76c4d07a21 | |||
721a3b9242 | |||
1886a5ffc9 | |||
40d97cd420 | |||
9fa2ff01b7 | |||
364adf0c8b | |||
3c200e80fb | |||
3153ee6442 | |||
d7f2e84c02 | |||
6993346862 | |||
26919254a6 | |||
4c0df6593d | |||
65e183e129 | |||
e1c719d5e6 | |||
61d896354a | |||
f38b0b29b2 | |||
be15eef145 | |||
ad295b5007 | |||
81cdb918b2 | |||
56c4187687 | |||
fec6e62941 | |||
9ee26aadf4 | |||
8d971606cf | |||
6472a721ba | |||
901b4381df | |||
af4b4397cc | |||
e5fc437cc1 |
12
Readme.md
Normal file
12
Readme.md
Normal file
@ -0,0 +1,12 @@
|
||||
# I2Pbutton
|
||||
|
||||
## Development howto
|
||||
|
||||
You can build and update i2pbutton without the need of recompiling firefox for most tasks luckly :)
|
||||
|
||||
To do this build it and copy it into your data directory:
|
||||
```
|
||||
./makexpi.sh
|
||||
cp pkg/i2pbutton-0.2.xpi ~/I2PBrowser-Data/Browser/914o5i1s.default/extensions/i2pbutton@geti2p.net.xpi
|
||||
```
|
||||
|
@ -15,6 +15,7 @@ overlay chrome://browser/content/aboutDialog.xul chrome://i2pbutton/content/abou
|
||||
|
||||
# UI customization
|
||||
overlay chrome://browser/content/browser.xul chrome://i2pbutton/content/menu-items-overlay.xul
|
||||
overlay chrome://browser/content/browser.xul chrome://i2pbutton/content/menu-overlay.xul
|
||||
|
||||
# Strings for the about:ibupdate page
|
||||
override chrome://browser/locale/aboutIBUpdate.dtd chrome://i2pbutton/locale/aboutIBUpdate.dtd
|
||||
@ -28,6 +29,9 @@ style chrome://global/content/customizeToolbar.xul chrome://i2pbutton/skin/i2pbu
|
||||
component {f605ec27-d867-44b5-ad97-2a29276642c3} components/dragDropFilter.js
|
||||
contract @geti2p.net/i2pbutton-dragDropFilter;1 {f605ec27-d867-44b5-ad97-2a29276642c3}
|
||||
|
||||
component {3da0269f-fc29-4e9e-a678-c3b1cafcf13f} components/external-app-blocker.js
|
||||
contract @geti2p.net/i2pbutton-extAppBlocker;1 {3da0269f-fc29-4e9e-a678-c3b1cafcf13f}
|
||||
|
||||
component {06322def-6fde-4c06-aef6-47ae8e799629} components/startup-observer.js
|
||||
contract @geti2p.net/startup-observer;1 {06322def-6fde-4c06-aef6-47ae8e799629}
|
||||
|
||||
@ -40,6 +44,19 @@ contract @geti2p.net/i2pbutton-i2pCheckService;1 {5d57312b-5d8c-4169-b4af-e80d6a
|
||||
component {f36d72c9-9718-4134-b550-e109638331d7} components/i2pbutton-logger.js
|
||||
contract @geti2p.net/i2pbutton-logger;1 {f36d72c9-9718-4134-b550-e109638331d7}
|
||||
|
||||
component {E2AA62BB-AFD0-4D94-9408-90CE39784086} components/router-config-manager.js
|
||||
contract @geti2p.net/i2pbutton-router-config-mgr;1 {E2AA62BB-AFD0-4D94-9408-90CE39784086}
|
||||
|
||||
component {f77babef-dead-b00b-beff-babe6c9afda7} components/i2p-router-process.js
|
||||
contract @geti2p.net/i2pbutton-process-service;1 {f77babef-dead-b00b-beff-babe6c9afda7}
|
||||
|
||||
component {aa132730-beef-dead-babe-0800200c9a66} components/about-outproxies.js
|
||||
contract @geti2p.net/i2pbutton-about-outproxies;1 {aa132730-beef-dead-babe-0800200c9a66}
|
||||
|
||||
category profile-after-change I2PProcessService @geti2p.net/i2pbutton-process-service;1
|
||||
|
||||
category profile-after-change CookieJarSelector @geti2p.net/cookie-jar-selector;1
|
||||
|
||||
category profile-after-change StartupObserver @geti2p.net/startup-observer;1
|
||||
category profile-after-change DragDropFilter @geti2p.net/i2pbutton-dragDropFilter;1
|
||||
|
||||
|
@ -38,20 +38,28 @@ window.addEventListener("pageshow", function() {
|
||||
&aboutI2p.browser_name; ( &aboutI2p.browser_short_name; ) &aboutI2p.browser_description;
|
||||
<h3>&aboutI2p.links;</h3>
|
||||
<p>
|
||||
&aboutI2p.source;: <a href="https://github.com/mikalv/test-i2p-browser/tree/i2p-browser-60.7.0esr-9.0-1-build3">https://github.com/mikalv/test-i2p-browser/tree/i2p-browser-60.7.0esr-9.0-1-build3</a><br />
|
||||
&aboutI2p.bug_tracker;: <a href="https://trac.i2p2.de/">https://trac.i2p2.de/</a><br />
|
||||
&aboutI2p.build_scripts;: <a href="https://github.com/mikalv/i2p-browser-build-scripts">https://github.com/mikalv/i2p-browser-build-scripts</a><br />
|
||||
&aboutI2p.i2pbutton_source;: <a href="https://github.com/mikalv/i2pbutton">https://github.com/mikalv/i2pbutton</a><br />
|
||||
<ul>
|
||||
<li>&aboutI2p.source;: <a href="&aboutI2p.github;/test-i2p-browser/tree/i2p-browser-60.7.0esr-9.0-1-build3">&aboutI2p.github;/test-i2p-browser/tree/i2p-browser-60.7.0esr-9.0-1-build3</a></li>
|
||||
<li>&aboutI2p.design;: <a href="&aboutI2p.github;/i2p-browser-design-docs">&aboutI2p.github;/i2p-browser-design-docs</a></li>
|
||||
<li>&aboutI2p.bug_tracker;: <a href="&aboutI2p.trac;/">&aboutI2p.trac;/</a></li>
|
||||
<li>&aboutI2p.build_scripts;: <a href="&aboutI2p.github;/i2p-browser-build-scripts">&aboutI2p.github;/i2p-browser-build-scripts</a></li>
|
||||
<li>&aboutI2p.i2pbutton_source;: <a href="&aboutI2p.github;/i2pbutton">&aboutI2p.github;/i2pbutton</a></li>
|
||||
<li><em>&aboutI2p.donate;: <a href="&aboutI2p.site;/get-involved/donate">&aboutI2p.supportus;</a></em></li>
|
||||
</ul>
|
||||
</p>
|
||||
|
||||
&aboutI2p.warn_experimental;
|
||||
</p>
|
||||
<p>
|
||||
&aboutI2p.refresh_text; <a href="about:i2p">&aboutI2p.refresh_link;</a>
|
||||
</p>
|
||||
<p class="hideIfI2POn">&aboutI2p.warn_not_running;</p>
|
||||
<p class="hideIfI2POn">&aboutI2p.warn_not_running; <a href="about:i2p">&aboutI2p.refresh_text;</a> &aboutI2p.reccommend_not_running;</p>
|
||||
<p class="hideIfI2POff">&aboutI2p.all_checks_ok;</p>
|
||||
<p class="hideIfI2PConsoleOff">&aboutI2p.console_visit_msg; <a href="http://127.0.0.1:7657">&aboutI2p.console;</a></p>
|
||||
<p class="hideIfI2PConsoleOff">
|
||||
<ul>
|
||||
<li>&aboutI2p.i2ptunnel_visit_msg; <a href="&aboutI2p.routerconsole;/i2ptunnelmgr">&aboutI2p.i2ptunnel;</a></li>
|
||||
<li>&aboutI2p.email_visit_msg; <a href="&aboutI2p.routerconsole;/webmail">&aboutI2p.email;</a></li>
|
||||
<li>&aboutI2p.torrent_visit_msg; <a href="&aboutI2p.routerconsole;/torrents">&aboutI2p.torrent;</a></li>
|
||||
<li>&aboutI2p.console_visit_msg; <a href="&aboutI2p.routerconsole;">&aboutI2p.console;</a></li>
|
||||
</ul>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -5,7 +5,7 @@
|
||||
<overlay id="i2pbutton-extensions-overlay"
|
||||
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
|
||||
|
||||
<vbox id="plugin-enable-button" class="alert-container" flex="1"
|
||||
<!-- <vbox id="plugin-enable-button" class="alert-container" flex="1"
|
||||
hidden="true">
|
||||
<spacer class="alert-spacer-before"/>
|
||||
<vbox class="alert">
|
||||
@ -23,6 +23,6 @@
|
||||
tooltiptext="&plugins.installed.disable.tip;"
|
||||
command="cmd_pluginDisable"/>
|
||||
<spacer flex="5000"/>
|
||||
</vbox>
|
||||
</vbox>-->
|
||||
|
||||
</overlay>
|
||||
|
@ -1,11 +1,28 @@
|
||||
let { Services } = Cu.import("resource://gre/modules/Services.jsm", {});
|
||||
let { Services } = Cu.import("resource://gre/modules/Services.jsm", {})
|
||||
const {AppConstants} = ChromeUtils.import("resource://gre/modules/AppConstants.jsm")
|
||||
|
||||
const m_ib_prefs = Services.prefs
|
||||
const m_ib_domWindowUtils = window.QueryInterface(Ci.nsIInterfaceRequestor).getInterface(Ci.nsIDOMWindowUtils)
|
||||
//let SecurityPrefs = Cu.import("resource://i2pbutton/modules/security-prefs.js", {})
|
||||
|
||||
var m_ib_prefs = Services.prefs
|
||||
var m_ib_domWindowUtils = window.QueryInterface(Ci.nsIInterfaceRequestor).getInterface(Ci.nsIDOMWindowUtils)
|
||||
|
||||
const k_ib_last_browser_version_pref = "extensions.i2pbutton.lastBrowserVersion";
|
||||
const k_ib_browser_update_needed_pref = "extensions.i2pbutton.updateNeeded";
|
||||
const k_ib_last_update_check_pref = "extensions.i2pbutton.lastUpdateCheck";
|
||||
|
||||
var m_ib_is_initialized = false
|
||||
var m_ib_is_router_running = false
|
||||
var m_ib_browser_router = false
|
||||
var m_ib_ibb = false
|
||||
var m_ib_is_main_window = false
|
||||
var m_ib_confirming_plugins = false
|
||||
|
||||
var m_ib_window_height = window.outerHeight
|
||||
var m_ib_window_width = window.outerWidth
|
||||
|
||||
let checkSvc = Cc["@geti2p.net/i2pbutton-i2pCheckService;1"].getService(Ci.nsISupports).wrappedJSObject
|
||||
|
||||
function checkI2P(callback,proxyCallback) {
|
||||
let checkSvc = Cc["@geti2p.net/i2pbutton-i2pCheckService;1"].getService(Ci.nsISupports).wrappedJSObject;
|
||||
let req = checkSvc.createCheckConsoleRequest(true);
|
||||
req.onreadystatechange = function(event) {
|
||||
if (req.readyState === 4) {
|
||||
@ -28,40 +45,102 @@ function checkI2P(callback,proxyCallback) {
|
||||
proxyReq.send(null)
|
||||
}
|
||||
|
||||
function i2pbutton_init() {
|
||||
checkI2P(function (res) {
|
||||
i2pbutton_log(3, `Check: ${res}`)
|
||||
},function (res) {
|
||||
i2pbutton_log(3, `Check: ${res}`)
|
||||
})
|
||||
|
||||
// Add about:i2p IPC message listener.
|
||||
window.messageManager.addMessageListener("AboutI2p:Loaded", i2pbutton_abouti2p_message_handler);
|
||||
|
||||
// Arrange for our about:i2p content script to be loaded in each frame.
|
||||
window.messageManager.loadFrameScript("chrome://i2pbutton/content/aboutI2p/aboutI2p-content.js", true);
|
||||
|
||||
i2pbutton_log(3, 'init completed');
|
||||
}
|
||||
|
||||
function i2pbutton_is_mobile() {
|
||||
return false;
|
||||
}
|
||||
|
||||
function i2pbutton_i2p_check_ok()
|
||||
{
|
||||
let checkSvc = Cc["@geti2p.net/i2pbutton-i2pCheckService;1"].getService(Ci.nsISupports).wrappedJSObject
|
||||
// It's important to check both if failed and if it's initialised to not report wrong to the end user
|
||||
return (checkSvc.isConsoleWorking && checkSvc.isProxyWorking && checkSvc.kCheckNotInitiated != checkSvc.statusOfI2PCheck)
|
||||
}
|
||||
function i2pbutton_i2p_console_check_ok()
|
||||
{
|
||||
let checkSvc = Cc["@geti2p.net/i2pbutton-i2pCheckService;1"].getService(Ci.nsISupports).wrappedJSObject
|
||||
// It's important to check both if failed and if it's initialised to not report wrong to the end user
|
||||
return (checkSvc.isConsoleWorking && checkSvc.kCheckNotInitiated != checkSvc.statusOfI2PCheck)
|
||||
}
|
||||
|
||||
let i2pbutton_abouti2p_message_handler = {
|
||||
var i2pbutton_unique_pref_observer =
|
||||
{
|
||||
register: function()
|
||||
{
|
||||
this.forced_ua = false;
|
||||
m_ib_prefs.addObserver("extensions.i2pbutton", this, false);
|
||||
m_ib_prefs.addObserver("network.cookie", this, false);
|
||||
m_ib_prefs.addObserver("browser.privatebrowsing.autostart", this, false);
|
||||
m_ib_prefs.addObserver("javascript", this, false);
|
||||
m_ib_prefs.addObserver("plugin.disable", this, false);
|
||||
m_ib_prefs.addObserver("privacy.firstparty.isolate", this, false);
|
||||
m_ib_prefs.addObserver("privacy.resistFingerprinting", this, false);
|
||||
|
||||
// We observe xpcom-category-entry-added for plugins w/ Gecko-Content-Viewers
|
||||
var observerService = Cc["@mozilla.org/observer-service;1"].
|
||||
getService(Ci.nsIObserverService);
|
||||
observerService.addObserver(this, "xpcom-category-entry-added", false);
|
||||
},
|
||||
|
||||
unregister: function()
|
||||
{
|
||||
m_ib_prefs.removeObserver("extensions.i2pbutton", this);
|
||||
m_ib_prefs.removeObserver("network.cookie", this);
|
||||
m_ib_prefs.removeObserver("browser.privatebrowsing.autostart", this);
|
||||
m_ib_prefs.removeObserver("javascript", this);
|
||||
m_ib_prefs.removeObserver("plugin.disable", this);
|
||||
m_ib_prefs.removeObserver("privacy.firstparty.isolate", this);
|
||||
m_ib_prefs.removeObserver("privacy.resistFingerprinting", this);
|
||||
|
||||
var observerService = Cc["@mozilla.org/observer-service;1"].
|
||||
getService(Ci.nsIObserverService);
|
||||
observerService.removeObserver(this, "xpcom-category-entry-added");
|
||||
},
|
||||
|
||||
// topic: what event occurred
|
||||
// subject: what nsIPrefBranch we're observing
|
||||
// data: which pref has been changed (relative to subject)
|
||||
observe: function(subject, topic, data)
|
||||
{
|
||||
if (topic == "xpcom-category-entry-added") {
|
||||
// Hrmm. should we inspect subject too? it's just mime type..
|
||||
subject.QueryInterface(Ci.nsISupportsCString);
|
||||
if (data == "Gecko-Content-Viewers" &&
|
||||
!m_ib_prefs.getBoolPref("extensions.i2pbutton.startup") &&
|
||||
m_ib_prefs.getBoolPref("extensions.i2pbutton.confirm_plugins")) {
|
||||
i2pbutton_log(3, "Got plugin enabled notification: "+subject);
|
||||
|
||||
/* We need to protect this call with a flag becuase we can
|
||||
* get multiple observer events for each mime type a plugin
|
||||
* registers. Thankfully, these notifications arrive only on
|
||||
* the main thread, *however*, our confirmation dialog suspends
|
||||
* execution and allows more events to arrive until it is answered
|
||||
*/
|
||||
if (!m_ib_confirming_plugins) {
|
||||
m_ib_confirming_plugins = true;
|
||||
i2pbutton_confirm_plugins();
|
||||
m_ib_confirming_plugins = false;
|
||||
} else {
|
||||
i2pbutton_log(3, "Skipping notification for mime type: "+subject);
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (topic != "nsPref:changed") return;
|
||||
|
||||
switch (data) {
|
||||
case "plugin.disable":
|
||||
i2pbutton_toggle_plugins(m_ib_prefs.getBoolPref("plugin.disable"));
|
||||
break;
|
||||
case "browser.privatebrowsing.autostart":
|
||||
i2pbutton_update_disk_prefs();
|
||||
break;
|
||||
case "extensions.i2pbutton.use_noni2p_proxy":
|
||||
i2pbutton_use_noni2p_proxy();
|
||||
break;
|
||||
case "privacy.resistFingerprinting":
|
||||
i2pbutton_update_fingerprinting_prefs();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// For some odd reason, this fails if it's defined with let/const and must be var.
|
||||
var i2pbutton_abouti2p_message_handler = {
|
||||
// Receive IPC messages from the about:i2p content script.
|
||||
receiveMessage: function(aMessage) {
|
||||
switch(aMessage.name) {
|
||||
@ -85,7 +164,6 @@ let i2pbutton_abouti2p_message_handler = {
|
||||
// not working.
|
||||
getChromeData: function(aIsRespondingToPageLoad) {
|
||||
let dataObj = {
|
||||
mobile: i2pbutton_is_mobile(),
|
||||
updateChannel: AppConstants.MOZ_UPDATE_CHANNEL,
|
||||
i2pOn: i2pbutton_i2p_check_ok(),
|
||||
i2pConsoleOn: i2pbutton_i2p_console_check_ok()
|
||||
@ -113,6 +191,12 @@ let i2pbutton_abouti2p_message_handler = {
|
||||
}
|
||||
};
|
||||
|
||||
function i2pbutton_is_mobile() {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// This function closes all XUL browser windows except this one. For this
|
||||
// window, it closes all existing tabs and creates one about:blank tab.
|
||||
function i2pbutton_close_tabs_on_new_identity() {
|
||||
@ -166,10 +250,96 @@ function i2pbutton_close_tabs_on_new_identity() {
|
||||
i2pbutton_log(3, "Closed all tabs");
|
||||
}
|
||||
|
||||
function i2pbutton_confirm_plugins() {
|
||||
var any_plugins_enabled = false;
|
||||
var PH=Cc["@mozilla.org/plugin/host;1"].getService(Ci.nsIPluginHost);
|
||||
var P=PH.getPluginTags({});
|
||||
for(var i=0; i<P.length; i++) {
|
||||
if (!P[i].disabled)
|
||||
any_plugins_enabled = true;
|
||||
}
|
||||
|
||||
if (!any_plugins_enabled) {
|
||||
i2pbutton_log(3, "False positive on plugin notification. Ignoring");
|
||||
return;
|
||||
}
|
||||
|
||||
i2pbutton_log(3, "Confirming plugin usage.");
|
||||
|
||||
var prompts = Cc["@mozilla.org/embedcomp/prompt-service;1"]
|
||||
.getService(Components.interfaces.nsIPromptService);
|
||||
|
||||
// Display two buttons, both with string titles.
|
||||
var flags = prompts.STD_YES_NO_BUTTONS + prompts.BUTTON_DELAY_ENABLE;
|
||||
|
||||
var message = i2pbutton_get_property_string("i2pbutton.popup.confirm_plugins");
|
||||
var askAgainText = i2pbutton_get_property_string("i2pbutton.popup.never_ask_again");
|
||||
var askAgain = {value: false};
|
||||
|
||||
var wm = Cc["@mozilla.org/appshell/window-mediator;1"]
|
||||
.getService(Components.interfaces.nsIWindowMediator);
|
||||
var win = wm.getMostRecentWindow("navigator:browser");
|
||||
var no_plugins = (prompts.confirmEx(win, "", message, flags, null, null, null,
|
||||
askAgainText, askAgain) == 1);
|
||||
|
||||
m_ib_prefs.setBoolPref("extensions.i2pbutton.confirm_plugins", !askAgain.value);
|
||||
|
||||
// The pref observer for "plugin.disable" will set the appropriate plugin state.
|
||||
// So, we only touch the pref if it has changed.
|
||||
if (no_plugins !=
|
||||
m_ib_prefs.getBoolPref("plugin.disable"))
|
||||
m_ib_prefs.setBoolPref("plugin.disable", no_plugins);
|
||||
else
|
||||
i2pbutton_toggle_plugins(no_plugins);
|
||||
|
||||
// Now, if any tabs were open to about:addons, reload them. Our popup
|
||||
// messed up that page.
|
||||
var wm = Components.classes["@mozilla.org/appshell/window-mediator;1"]
|
||||
.getService(Components.interfaces.nsIWindowMediator);
|
||||
var browserEnumerator = wm.getEnumerator("navigator:browser");
|
||||
|
||||
// Check each browser instance for our URL
|
||||
while (browserEnumerator.hasMoreElements()) {
|
||||
var browserWin = browserEnumerator.getNext();
|
||||
var tabbrowser = browserWin.gBrowser;
|
||||
|
||||
// Check each tab of this browser instance
|
||||
var numTabs = tabbrowser.browsers.length;
|
||||
for (var index = 0; index < numTabs; index++) {
|
||||
var currentBrowser = tabbrowser.getBrowserAtIndex(index);
|
||||
if ("about:addons" == currentBrowser.currentURI.spec) {
|
||||
i2pbutton_log(3, "Got browser: "+currentBrowser.currentURI.spec);
|
||||
currentBrowser.reload();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function i2pbutton_inform_about_ibb() {
|
||||
var prompts = Cc["@mozilla.org/embedcomp/prompt-service;1"]
|
||||
.getService(Components.interfaces.nsIPromptService);
|
||||
|
||||
var message = i2pbutton_get_property_string("i2pbutton.popup.prompt_i2pbrowser");
|
||||
var title = i2pbutton_get_property_string("i2pbutton.title.prompt_i2pbrowser");
|
||||
var checkbox = {value: false};
|
||||
|
||||
var sb = Components.classes["@mozilla.org/intl/stringbundle;1"]
|
||||
.getService(Components.interfaces.nsIStringBundleService);
|
||||
var browserstrings = sb.createBundle("chrome://browser/locale/browser.properties");
|
||||
|
||||
var askagain = browserstrings.GetStringFromName("privateBrowsingNeverAsk");
|
||||
|
||||
var response = prompts.alertCheck(null, title, message, askagain, checkbox);
|
||||
|
||||
// Update preferences to reflect their response and to prevent the prompt from
|
||||
// being displayed again.
|
||||
m_ib_prefs.setBoolPref("extensions.i2pbutton.prompt_i2pbrowser", !checkbox.value);
|
||||
}
|
||||
|
||||
function i2pbutton_check_protections()
|
||||
{
|
||||
var env = Cc["@mozilla.org/process/environment;1"]
|
||||
.getService(Ci.nsIEnvironment);
|
||||
var env = Cc["@mozilla.org/process/environment;1"].getService(Ci.nsIEnvironment);
|
||||
|
||||
// Bug 21091: check for the existence of an environment variable
|
||||
// in order to toggle the visibility of the i2pbutton-checkForUpdate
|
||||
@ -182,26 +352,51 @@ function i2pbutton_check_protections()
|
||||
document.getElementById("i2pbutton-checkForUpdate").hidden = false;
|
||||
}
|
||||
|
||||
var cookie_pref = m_tb_prefs.getBoolPref("extensions.i2pbutton.cookie_protections");
|
||||
var cookie_pref = m_ib_prefs.getBoolPref("extensions.i2pbutton.cookie_protections", true);
|
||||
document.getElementById("i2pbutton-cookie-protector").disabled = !cookie_pref;
|
||||
|
||||
// XXX: Bug 14632: The cookie dialog is useless in private browsing mode in FF31ESR
|
||||
// See https://trac.torproject.org/projects/tor/ticket/10353 for more info.
|
||||
document.getElementById("i2pbutton-cookie-protector").hidden = m_tb_prefs.getBoolPref("browser.privatebrowsing.autostart");
|
||||
document.getElementById("i2pbutton-cookie-protector").hidden = m_ib_prefs.getBoolPref("browser.privatebrowsing.autostart");
|
||||
|
||||
if (!m_tb_control_pass || (!m_tb_control_ipc_file && !m_tb_control_port)) {
|
||||
// TODO: Remove the Torbutton menu entry again once we have done our
|
||||
// security control redesign.
|
||||
document.getElementById("i2pbutton-new-identity").disabled = true;
|
||||
document.getElementById("menu_newIdentity").disabled = true;
|
||||
document.getElementById("appMenuNewIdentity").disabled = true;
|
||||
}
|
||||
|
||||
if (!m_tb_tbb && m_tb_prefs.getBoolPref("extensions.i2pbutton.prompt_i2pbrowser")) {
|
||||
i2pbutton_inform_about_tbb();
|
||||
if (/*!m_ib_ibb &&*/ m_ib_prefs.getBoolPref("extensions.i2pbutton.prompt_i2pbrowser")) {
|
||||
i2pbutton_inform_about_ibb();
|
||||
}
|
||||
}
|
||||
|
||||
function i2pbutton_check_for_update() {
|
||||
// Open the update prompt in the correct mode. The update state
|
||||
// checks used here were adapted from isPending() and isApplied() in
|
||||
// Mozilla's browser/base/content/aboutDialog.js code.
|
||||
let updateMgr = Cc["@mozilla.org/updates/update-manager;1"].getService(Ci.nsIUpdateManager);
|
||||
let update = updateMgr.activeUpdate;
|
||||
let updateState = (update) ? update.state : undefined;
|
||||
let pendingStates = [ "pending", "pending-service", "applied", "applied-service" ];
|
||||
let isPending = (updateState && (pendingStates.indexOf(updateState) >= 0));
|
||||
|
||||
let prompter = Cc["@mozilla.org/updates/update-prompt;1"].createInstance(Ci.nsIUpdatePrompt);
|
||||
if (isPending)
|
||||
prompter.showUpdateDownloaded(update, false);
|
||||
else
|
||||
prompter.checkForUpdates();
|
||||
}
|
||||
|
||||
function i2pbutton_open_cookie_dialog() {
|
||||
showDialog(window, 'chrome://i2pbutton/content/i2pcookiedialog.xul',
|
||||
'Cookie Protections', 'centerscreen,chrome,dialog,modal,resizable');
|
||||
}
|
||||
|
||||
// -------------- HISTORY & COOKIES ---------------------
|
||||
|
||||
// Bug 1506 P4: Used by New Identity if cookie protections are
|
||||
// not in use.
|
||||
function i2pbutton_clear_cookies() {
|
||||
i2pbutton_log(2, 'called i2pbutton_clear_cookies');
|
||||
var cm = Components.classes["@mozilla.org/cookiemanager;1"].getService(Components.interfaces.nsICookieManager);
|
||||
cm.removeAll();
|
||||
}
|
||||
|
||||
|
||||
function i2pbutton_new_identity() {
|
||||
try {
|
||||
// Make sure that we can only click once on New Identiy to avoid race
|
||||
@ -432,8 +627,7 @@ function i2pbutton_do_new_identity() {
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "PrivateBrowsingUtils",
|
||||
"resource://gre/modules/PrivateBrowsingUtils.jsm");
|
||||
var pbCtxt = PrivateBrowsingUtils.privacyContextFromWindow(window);
|
||||
var cps = Cc["@mozilla.org/content-pref/service;1"]
|
||||
.getService(Ci.nsIContentPrefService2);
|
||||
var cps = Cc["@mozilla.org/content-pref/service;1"].getService(Ci.nsIContentPrefService2);
|
||||
cps.removeAllDomains(pbCtxt);
|
||||
} else { // Firefox < 20
|
||||
var cps = Cc["@mozilla.org/content-pref/service;1"].
|
||||
@ -448,8 +642,7 @@ function i2pbutton_do_new_identity() {
|
||||
|
||||
i2pbutton_log(3, "New Identity: Clearing permissions");
|
||||
|
||||
let pm = Cc["@mozilla.org/permissionmanager;1"].
|
||||
getService(Ci.nsIPermissionManager);
|
||||
let pm = Cc["@mozilla.org/permissionmanager;1"].getService(Ci.nsIPermissionManager);
|
||||
pm.removeAll();
|
||||
|
||||
i2pbutton_log(3, "Ending any remaining private browsing sessions.");
|
||||
@ -521,8 +714,7 @@ function i2pbutton_clear_image_caches()
|
||||
// Try to clear the private browsing cache. To do so, we must locate
|
||||
// a content document that is contained within a private browsing window.
|
||||
let didClearPBCache = false;
|
||||
let wm = Cc["@mozilla.org/appshell/window-mediator;1"]
|
||||
.getService(Ci.nsIWindowMediator);
|
||||
let wm = Cc["@mozilla.org/appshell/window-mediator;1"].getService(Ci.nsIWindowMediator);
|
||||
let enumerator = wm.getEnumerator("navigator:browser");
|
||||
while (!didClearPBCache && enumerator.hasMoreElements()) {
|
||||
let win = enumerator.getNext();
|
||||
@ -556,7 +748,7 @@ function i2pbutton_clear_image_caches()
|
||||
}
|
||||
|
||||
function i2pbutton_toggle_plugins(disable_plugins) {
|
||||
if (m_tb_tbb) {
|
||||
if (m_ib_ibb) {
|
||||
var PH=Cc["@mozilla.org/plugin/host;1"].getService(Ci.nsIPluginHost);
|
||||
var P=PH.getPluginTags({});
|
||||
for(var i=0; i<P.length; i++) {
|
||||
@ -585,7 +777,7 @@ function i2pbutton_update_disk_prefs() {
|
||||
// No way to clear this beast during New Identity. Leave it off.
|
||||
//m_ib_prefs.setBoolPref("dom.indexedDB.enabled", !mode);
|
||||
|
||||
if (m_tb_tbb) m_ib_prefs.setBoolPref("permissions.memory_only", mode);
|
||||
if (m_ib_ibb) m_ib_prefs.setBoolPref("permissions.memory_only", mode);
|
||||
|
||||
// Third party abuse. Leave it off for now.
|
||||
//m_ib_prefs.setBoolPref("browser.cache.offline.enable", !mode);
|
||||
@ -619,42 +811,42 @@ function i2pbutton_update_fingerprinting_prefs() {
|
||||
|
||||
function i2pbutton_do_startup()
|
||||
{
|
||||
if(m_ib_prefs.getBoolPref("extensions.i2pbutton.startup")) {
|
||||
// Bug 1506: Still want to do this
|
||||
i2pbutton_toggle_plugins(
|
||||
m_ib_prefs.getBoolPref("plugin.disable"));
|
||||
if(m_ib_prefs.getBoolPref("extensions.i2pbutton.startup")) {
|
||||
// Bug 1506: Still want to do this
|
||||
i2pbutton_toggle_plugins(
|
||||
m_ib_prefs.getBoolPref("plugin.disable"));
|
||||
|
||||
// Bug 1506: Should probably be moved to an XPCOM component
|
||||
i2pbutton_do_main_window_startup();
|
||||
// Bug 1506: Should probably be moved to an XPCOM component
|
||||
i2pbutton_do_main_window_startup();
|
||||
|
||||
// For charsets
|
||||
i2pbutton_update_fingerprinting_prefs();
|
||||
// For charsets
|
||||
i2pbutton_update_fingerprinting_prefs();
|
||||
|
||||
// Bug 30565: sync browser.privatebrowsing.autostart with security.nocertdb
|
||||
i2pbutton_update_disk_prefs();
|
||||
// Bug 30565: sync browser.privatebrowsing.autostart with security.nocertdb
|
||||
i2pbutton_update_disk_prefs();
|
||||
|
||||
// #5758: Last ditch effort to keep Vanilla i2pbutton users from totally
|
||||
// being pwnt. This is a pretty darn ugly hack, too. But because of #5863,
|
||||
// we really don't care about preserving the user's values for this.
|
||||
if (!m_tb_tbb) {
|
||||
// Bug 1506 P5: You have to set these two for non-TBB Firefoxen
|
||||
m_ib_prefs.setBoolPref("network.websocket.enabled", false);
|
||||
m_ib_prefs.setBoolPref("dom.indexedDB.enabled", false);
|
||||
}
|
||||
|
||||
// Still need this in case people shove this thing back into FF
|
||||
if (!m_tb_tbb && m_ib_prefs.getBoolPref("extensions.i2pbutton.prompt_i2pbrowser")) {
|
||||
var warning = i2pbutton_get_property_string("i2pbutton.popup.short_i2pbrowser");
|
||||
var title = i2pbutton_get_property_string("i2pbutton.title.prompt_i2pbrowser");
|
||||
var prompts = Cc["@mozilla.org/embedcomp/prompt-service;1"].getService(Components.interfaces.nsIPromptService);
|
||||
prompts.alert(null, title, warning);
|
||||
}
|
||||
|
||||
// For general pref fixups to handle pref damage in older versions
|
||||
i2pbutton_fixup_old_prefs();
|
||||
|
||||
m_ib_prefs.setBoolPref("extensions.i2pbutton.startup", false);
|
||||
// #5758: Last ditch effort to keep Vanilla i2pbutton users from totally
|
||||
// being pwnt. This is a pretty darn ugly hack, too. But because of #5863,
|
||||
// we really don't care about preserving the user's values for this.
|
||||
if (!m_ib_ibb) {
|
||||
// Bug 1506 P5: You have to set these two for non-TBB Firefoxen
|
||||
m_ib_prefs.setBoolPref("network.websocket.enabled", false);
|
||||
m_ib_prefs.setBoolPref("dom.indexedDB.enabled", false);
|
||||
}
|
||||
|
||||
// Still need this in case people shove this thing back into FF
|
||||
if (!m_ib_ibb && m_ib_prefs.getBoolPref("extensions.i2pbutton.prompt_i2pbrowser")) {
|
||||
var warning = i2pbutton_get_property_string("i2pbutton.popup.short_i2pbrowser");
|
||||
var title = i2pbutton_get_property_string("i2pbutton.title.prompt_i2pbrowser");
|
||||
var prompts = Cc["@mozilla.org/embedcomp/prompt-service;1"].getService(Components.interfaces.nsIPromptService);
|
||||
prompts.alert(null, title, warning);
|
||||
}
|
||||
|
||||
// For general pref fixups to handle pref damage in older versions
|
||||
i2pbutton_fixup_old_prefs();
|
||||
|
||||
m_ib_prefs.setBoolPref("extensions.i2pbutton.startup", false);
|
||||
}
|
||||
}
|
||||
|
||||
// Bug 1506 P3: This is needed pretty much only for the version check
|
||||
@ -662,46 +854,155 @@ function i2pbutton_do_startup()
|
||||
// details
|
||||
function i2pbutton_new_window(event)
|
||||
{
|
||||
i2pbutton_log(3, "New window");
|
||||
var browser = window.gBrowser;
|
||||
i2pbutton_log(3, "New window");
|
||||
var browser = window.gBrowser;
|
||||
|
||||
if(!browser) {
|
||||
i2pbutton_log(5, "No browser for new window.");
|
||||
return;
|
||||
}
|
||||
if(!browser) {
|
||||
i2pbutton_log(5, "No browser for new window.");
|
||||
return;
|
||||
}
|
||||
|
||||
m_tb_window_height = window.outerHeight;
|
||||
m_tb_window_width = window.outerWidth;
|
||||
m_tb_window_height = window.outerHeight;
|
||||
m_tb_window_width = window.outerWidth;
|
||||
|
||||
if (!m_tb_wasinited) {
|
||||
i2pbutton_init();
|
||||
}
|
||||
// Add tab open listener..
|
||||
browser.tabContainer.addEventListener("TabOpen", i2pbutton_new_tab, false);
|
||||
if (!m_tb_wasinited) {
|
||||
i2pbutton_init();
|
||||
}
|
||||
// Add tab open listener..
|
||||
browser.tabContainer.addEventListener("TabOpen", i2pbutton_new_tab, false);
|
||||
|
||||
i2pbutton_do_startup();
|
||||
i2pbutton_do_startup();
|
||||
|
||||
let progress = Cc["@mozilla.org/docloaderservice;1"]
|
||||
.getService(Ci.nsIWebProgress);
|
||||
let progress = Cc["@mozilla.org/docloaderservice;1"]
|
||||
.getService(Ci.nsIWebProgress);
|
||||
|
||||
if (m_ib_prefs.getBoolPref("extensions.i2pbutton.resize_new_windows")
|
||||
&& i2pbutton_is_windowed(window)) {
|
||||
progress.addProgressListener(i2pbutton_resizelistener,
|
||||
Ci.nsIWebProgress.NOTIFY_STATE_DOCUMENT);
|
||||
}
|
||||
if (m_ib_prefs.getBoolPref("extensions.i2pbutton.resize_new_windows")
|
||||
&& i2pbutton_is_windowed(window)) {
|
||||
progress.addProgressListener(i2pbutton_resizelistener,
|
||||
Ci.nsIWebProgress.NOTIFY_STATE_DOCUMENT);
|
||||
}
|
||||
|
||||
// Check the version on every new window. We're already pinging check in these cases.
|
||||
i2pbutton_do_async_versioncheck();
|
||||
// Check the version on every new window. We're already pinging check in these cases.
|
||||
//i2pbutton_do_async_versioncheck();
|
||||
|
||||
}
|
||||
|
||||
// Bug 1506 P1/P3: Setting a fixed window size is important, but
|
||||
// probably not for android.
|
||||
var i2pbutton_resizelistener =
|
||||
{
|
||||
QueryInterface: function(aIID)
|
||||
{
|
||||
if (aIID.equals(Ci.nsIWebProgressListener) ||
|
||||
aIID.equals(Ci.nsISupportsWeakReference) ||
|
||||
aIID.equals(Ci.nsISupports))
|
||||
return this;
|
||||
throw Cr.NS_NOINTERFACE;
|
||||
},
|
||||
|
||||
onLocationChange: function(aProgress, aRequest, aURI) {},
|
||||
onStateChange: function(aProgress, aRequest, aFlag, aStatus) {
|
||||
if (aFlag & Ci.nsIWebProgressListener.STATE_STOP) {
|
||||
m_ib_resize_handler = async function() {
|
||||
// Wait for end of execution queue to ensure we have correct windowState.
|
||||
await new Promise(resolve => setTimeout(resolve, 0));
|
||||
if (window.windowState === window.STATE_MAXIMIZED ||
|
||||
window.windowState === window.STATE_FULLSCREEN) {
|
||||
if (m_tb_prefs.
|
||||
getIntPref("extensions.i2pbutton.maximize_warnings_remaining") > 0) {
|
||||
|
||||
// Do not add another notification if one is already showing.
|
||||
const kNotificationName = "i2pbutton-maximize-notification";
|
||||
let box = gBrowser.getNotificationBox();
|
||||
if (box.getNotificationWithValue(kNotificationName))
|
||||
return;
|
||||
|
||||
// Rate-limit showing our notification if needed.
|
||||
if (m_ib_resize_date === null) {
|
||||
m_ib_resize_date = Date.now();
|
||||
} else {
|
||||
// We wait at least another second before we show a new
|
||||
// notification. Should be enough to rule out OSes that call our
|
||||
// handler rapidly due to internal workings.
|
||||
if (Date.now() - m_ib_resize_date < 1000) {
|
||||
return;
|
||||
}
|
||||
// Resizing but we need to reset |m_tb_resize_date| now.
|
||||
m_ib_resize_date = Date.now();
|
||||
}
|
||||
|
||||
let sb = i2pbutton_get_stringbundle();
|
||||
// No need to get "OK" translated again.
|
||||
let sbSvc = Cc["@mozilla.org/intl/stringbundle;1"].
|
||||
getService(Ci.nsIStringBundleService);
|
||||
let bundle = sbSvc.
|
||||
createBundle("chrome://global/locale/commonDialogs.properties");
|
||||
let button_label = bundle.GetStringFromName("OK");
|
||||
|
||||
let buttons = [{
|
||||
label: button_label,
|
||||
accessKey: 'O',
|
||||
popup: null,
|
||||
callback:
|
||||
function() {
|
||||
m_ib_prefs.setIntPref("extensions.i2pbutton.maximize_warnings_remaining",
|
||||
m_ib_prefs.getIntPref("extensions.i2pbutton.maximize_warnings_remaining") - 1);
|
||||
}
|
||||
}];
|
||||
|
||||
let priority = box.PRIORITY_WARNING_LOW;
|
||||
let message =
|
||||
i2pbutton_get_property_string("i2pbutton.maximize_warning");
|
||||
|
||||
box.appendNotification(message, kNotificationName, null,
|
||||
priority, buttons);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}; // m_ib_resize_handler
|
||||
|
||||
// We need to handle OSes that auto-maximize windows depending on user
|
||||
// settings and/or screen resolution in the start-up phase and users that
|
||||
// try to shoot themselves in the foot by maximizing the window manually.
|
||||
// We add a listener which is triggerred as soon as the window gets
|
||||
// maximized (windowState = 1). We are resizing during start-up but not
|
||||
// later as the user should see only a warning there as a stopgap before
|
||||
// #14229 lands.
|
||||
// Alas, the Firefox window code is handling the event not itself:
|
||||
// "// Note the current implementation of SetSizeMode just stores
|
||||
// // the new state; it doesn't actually resize. So here we store
|
||||
// // the state and pass the event on to the OS."
|
||||
// (See: https://mxr.mozilla.org/mozilla-esr31/source/xpfe/appshell/src/
|
||||
// nsWebShellWindow.cpp#348)
|
||||
// This means we have to cope with race conditions and resizing in the
|
||||
// sizemodechange listener is likely to fail. Thus, we add a specific
|
||||
// resize listener that is doing the work for us. It seems (at least on
|
||||
// Ubuntu) to be the case that maximizing (and then again normalizing) of
|
||||
// the window triggers more than one resize event the first being not the
|
||||
// one we need. Thus we can't remove the listener after the first resize
|
||||
// event got fired. Thus, we have the rather klunky setTimeout() call.
|
||||
window.addEventListener("sizemodechange", m_ib_resize_handler, false);
|
||||
|
||||
let progress = Cc["@mozilla.org/docloaderservice;1"]
|
||||
.getService(Ci.nsIWebProgress);
|
||||
progress.removeProgressListener(this);
|
||||
}
|
||||
}, // onStateChange
|
||||
|
||||
onProgressChange: function(aProgress, aRequest, curSelfProgress,
|
||||
maxSelfProgress, curTotalProgress,
|
||||
maxTotalProgress) {},
|
||||
onStatusChange: function(aProgress, aRequest, stat, message) {},
|
||||
onSecurityChange: function() {}
|
||||
};
|
||||
|
||||
// Bug 1506 P2: This is only needed because we have observers
|
||||
// in XUL that should be in an XPCOM component
|
||||
function i2pbutton_close_window(event) {
|
||||
i2pbutton_window_pref_observer.unregister();
|
||||
i2pbutton_tor_check_observer.unregister();
|
||||
|
||||
window.removeEventListener("sizemodechange", m_tb_resize_handler,
|
||||
window.removeEventListener("sizemodechange", m_ib_resize_handler,
|
||||
false);
|
||||
|
||||
// TODO: This is a real ghetto hack.. When the original window
|
||||
@ -740,3 +1041,347 @@ function i2pbutton_close_window(event) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function showSecurityPreferencesPanel(chromeWindow) {
|
||||
const tabBrowser = chromeWindow.BrowserApp;
|
||||
let settingsTab = null;
|
||||
|
||||
const SECURITY_PREFERENCES_URI = 'chrome://i2pbutton/content/preferences.xhtml';
|
||||
|
||||
tabBrowser.tabs.some(function (tab) {
|
||||
// If the security prefs tab is opened, send the user to it
|
||||
if (tab.browser.currentURI.spec === SECURITY_PREFERENCES_URI) {
|
||||
settingsTab = tab;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
});
|
||||
|
||||
if (settingsTab === null) {
|
||||
// Open up the settings panel in a new tab.
|
||||
tabBrowser.addTab(SECURITY_PREFERENCES_URI, {
|
||||
'selected': true,
|
||||
'parentId': tabBrowser.selectedTab.id
|
||||
});
|
||||
} else {
|
||||
// Activate an existing settings panel tab.
|
||||
tabBrowser.selectTab(settingsTab);
|
||||
}
|
||||
}
|
||||
|
||||
function i2pbutton_do_main_window_startup()
|
||||
{
|
||||
i2pbutton_log(3, "I2pbutton main window startup");
|
||||
m_ib_is_main_window = true;
|
||||
i2pbutton_unique_pref_observer.register();
|
||||
}
|
||||
|
||||
// Bug 1506 P4: Most of this function is now useless, save
|
||||
// for the very important SOCKS environment vars at the end.
|
||||
// Those could probably be rolled into a function with the
|
||||
// control port vars, though. See 1506 comments inside.
|
||||
function i2pbutton_do_startup()
|
||||
{
|
||||
if(m_ib_prefs.getBoolPref("extensions.i2pbutton.startup")) {
|
||||
// Bug 1506: Still want to do this
|
||||
i2pbutton_toggle_plugins(
|
||||
m_ib_prefs.getBoolPref("plugin.disable"));
|
||||
|
||||
// Bug 1506: Should probably be moved to an XPCOM component
|
||||
i2pbutton_do_main_window_startup();
|
||||
|
||||
// For charsets
|
||||
i2pbutton_update_fingerprinting_prefs();
|
||||
|
||||
// Bug 30565: sync browser.privatebrowsing.autostart with security.nocertdb
|
||||
i2pbutton_update_disk_prefs();
|
||||
|
||||
// #5758: Last ditch effort to keep Vanilla Torbutton users from totally
|
||||
// being pwnt. This is a pretty darn ugly hack, too. But because of #5863,
|
||||
// we really don't care about preserving the user's values for this.
|
||||
if (!m_ib_ibb) {
|
||||
// Bug 1506 P5: You have to set these two for non-TBB Firefoxen
|
||||
m_ib_prefs.setBoolPref("network.websocket.enabled", false);
|
||||
m_ib_prefs.setBoolPref("dom.indexedDB.enabled", false);
|
||||
}
|
||||
|
||||
// Still need this in case people shove this thing back into FF
|
||||
if (!m_ib_ibb && m_ib_prefs.getBoolPref("extensions.i2pbutton.prompt_i2pbrowser")) {
|
||||
var warning = i2pbutton_get_property_string("i2pbutton.popup.short_i2pbrowser");
|
||||
var title = i2pbutton_get_property_string("i2pbutton.title.prompt_i2pbrowser");
|
||||
var prompts = Cc["@mozilla.org/embedcomp/prompt-service;1"].getService(Components.interfaces.nsIPromptService);
|
||||
prompts.alert(null, title, warning);
|
||||
}
|
||||
|
||||
m_ib_prefs.setBoolPref("extensions.i2pbutton.startup", false);
|
||||
}
|
||||
}
|
||||
|
||||
// Perform version check when a new tab is opened.
|
||||
function i2pbutton_new_tab(event)
|
||||
{
|
||||
// listening for new tabs
|
||||
i2pbutton_log(3, "New tab");
|
||||
|
||||
/* Perform the version check on new tab, module timer */
|
||||
//i2pbutton_do_async_versioncheck();
|
||||
}
|
||||
|
||||
// Returns true if the window wind is neither maximized, full screen,
|
||||
// ratpoisioned/evilwmed, nor minimized.
|
||||
function i2pbutton_is_windowed(wind) {
|
||||
i2pbutton_log(3, "Window: (" + wind.outerWidth + "," + wind.outerHeight + ") ?= ("
|
||||
+ wind.screen.availWidth + "," + wind.screen.availHeight + ")");
|
||||
if(wind.windowState == Components.interfaces.nsIDOMChromeWindow.STATE_MINIMIZED
|
||||
|| wind.windowState == Components.interfaces.nsIDOMChromeWindow.STATE_MAXIMIZED) {
|
||||
i2pbutton_log(2, "Window is minimized/maximized");
|
||||
return false;
|
||||
}
|
||||
if ("fullScreen" in wind && wind.fullScreen) {
|
||||
i2pbutton_log(2, "Window is fullScreen");
|
||||
return false;
|
||||
}
|
||||
if(wind.outerHeight == wind.screen.availHeight
|
||||
&& wind.outerWidth == wind.screen.availWidth) {
|
||||
i2pbutton_log(3, "Window is ratpoisoned/evilwm'ed");
|
||||
return false;
|
||||
}
|
||||
|
||||
i2pbutton_log(2, "Window is normal");
|
||||
return true;
|
||||
}
|
||||
|
||||
// Bug 1506 P3: This is needed pretty much only for the version check
|
||||
// and the window resizing. See comments for individual functions for
|
||||
// details
|
||||
function i2pbutton_new_window(event)
|
||||
{
|
||||
i2pbutton_log(3, "New window");
|
||||
var browser = window.gBrowser;
|
||||
|
||||
if(!browser) {
|
||||
i2pbutton_log(5, "No browser for new window.");
|
||||
return;
|
||||
}
|
||||
|
||||
m_ib_window_height = window.outerHeight;
|
||||
m_ib_window_width = window.outerWidth;
|
||||
|
||||
if (!m_ib_is_initialized) {
|
||||
i2pbutton_init();
|
||||
}
|
||||
// Add tab open listener..
|
||||
browser.tabContainer.addEventListener("TabOpen", i2pbutton_new_tab, false);
|
||||
|
||||
i2pbutton_do_startup();
|
||||
|
||||
let progress = Cc["@mozilla.org/docloaderservice;1"]
|
||||
.getService(Ci.nsIWebProgress);
|
||||
|
||||
if (m_ib_prefs.getBoolPref("extensions.i2pbutton.resize_new_windows")
|
||||
&& i2pbutton_is_windowed(window)) {
|
||||
progress.addProgressListener(i2pbutton_resizelistener,
|
||||
Ci.nsIWebProgress.NOTIFY_STATE_DOCUMENT);
|
||||
}
|
||||
|
||||
// Check the version on every new window. We're already pinging check in these cases.
|
||||
//i2pbutton_do_async_versioncheck();
|
||||
|
||||
//i2pbutton_do_i2p_check();
|
||||
}
|
||||
|
||||
// Bug 1506 P2: This is only needed because we have observers
|
||||
// in XUL that should be in an XPCOM component
|
||||
function i2pbutton_close_window(event) {
|
||||
i2pbutton_window_pref_observer.unregister();
|
||||
i2pbutton_i2p_check_observer.unregister();
|
||||
|
||||
window.removeEventListener("sizemodechange", m_ib_resize_handler,
|
||||
false);
|
||||
|
||||
// TODO: This is a real ghetto hack.. When the original window
|
||||
// closes, we need to find another window to handle observing
|
||||
// unique events... The right way to do this is to move the
|
||||
// majority of i2pbutton functionality into a XPCOM component..
|
||||
// But that is a major overhaul..
|
||||
if (m_ib_is_main_window) {
|
||||
i2pbutton_log(3, "Original window closed. Searching for another");
|
||||
var wm = Components.classes["@mozilla.org/appshell/window-mediator;1"]
|
||||
.getService(Components.interfaces.nsIWindowMediator);
|
||||
var enumerator = wm.getEnumerator("navigator:browser");
|
||||
while(enumerator.hasMoreElements()) {
|
||||
var win = enumerator.getNext();
|
||||
// For some reason, when New Identity is called from a pref
|
||||
// observer (ex: i2pbutton_use_nontor_proxy) on an ASAN build,
|
||||
// we sometimes don't have this symbol set in the new window yet.
|
||||
// However, the new window will run this init later in that case,
|
||||
// as it does in the OSX case.
|
||||
if(win != window && "i2pbutton_do_main_window_startup" in win) {
|
||||
i2pbutton_log(3, "Found another window");
|
||||
win.i2pbutton_do_main_window_startup();
|
||||
m_ib_is_main_window = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
i2pbutton_unique_pref_observer.unregister();
|
||||
|
||||
if(m_ib_is_main_window) { // main window not reset above
|
||||
// This happens on Mac OS because they allow firefox
|
||||
// to still persist without a navigator window
|
||||
i2pbutton_log(3, "Last window closed. None remain.");
|
||||
m_ib_prefs.setBoolPref("extensions.i2pbutton.startup", true);
|
||||
m_ib_is_main_window = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
window.addEventListener('load', i2pbutton_new_window, false);
|
||||
window.addEventListener('unload', i2pbutton_close_window, false);
|
||||
|
||||
|
||||
// -------------- JS/PLUGIN HANDLING CODE ---------------------
|
||||
// Bug 1506 P3: Defense in depth. Disables JS and events for New Identity.
|
||||
function i2pbutton_disable_browser_js(browser) {
|
||||
var eventSuppressor = null;
|
||||
|
||||
/* Solution from: https://bugzilla.mozilla.org/show_bug.cgi?id=409737 */
|
||||
// XXX: This kills the entire window. We need to redirect
|
||||
// focus and inform the user via a lightbox.
|
||||
try {
|
||||
if (!browser.contentWindow)
|
||||
i2pbutton_log(3, "No content window to disable JS events.");
|
||||
else
|
||||
eventSuppressor = browser.contentWindow.
|
||||
QueryInterface(Components.interfaces.nsIInterfaceRequestor).
|
||||
getInterface(Ci.nsIDOMWindowUtils);
|
||||
} catch(e) {
|
||||
i2pbutton_log(4, "Failed to disable JS events: "+e)
|
||||
}
|
||||
|
||||
if (browser.docShell)
|
||||
browser.docShell.allowJavascript = false;
|
||||
|
||||
try {
|
||||
// My estimation is that this does not get the inner iframe windows,
|
||||
// but that does not matter, because iframes should be destroyed
|
||||
// on the next load.
|
||||
browser.contentWindow.name = null;
|
||||
browser.contentWindow.window.name = null;
|
||||
} catch(e) {
|
||||
i2pbutton_log(4, "Failed to reset window.name: "+e)
|
||||
}
|
||||
|
||||
if (eventSuppressor)
|
||||
eventSuppressor.suppressEventHandling(true);
|
||||
}
|
||||
|
||||
// Bug 1506 P3: The JS-killing bits of this are used by
|
||||
// New Identity as a defense-in-depth measure.
|
||||
function i2pbutton_disable_window_js(win) {
|
||||
var browser = win.getBrowser();
|
||||
if(!browser) {
|
||||
i2pbutton_log(5, "No browser for plugin window...");
|
||||
return;
|
||||
}
|
||||
var browsers = browser.browsers;
|
||||
i2pbutton_log(1, "Toggle window plugins");
|
||||
|
||||
for (var i = 0; i < browsers.length; ++i) {
|
||||
var b = browser.browsers[i];
|
||||
if (b && !b.docShell) {
|
||||
try {
|
||||
if (b.currentURI)
|
||||
i2pbutton_log(5, "DocShell is null for: "+b.currentURI.spec);
|
||||
else
|
||||
i2pbutton_log(5, "DocShell is null for unknown URL");
|
||||
} catch(e) {
|
||||
i2pbutton_log(5, "DocShell is null for unparsable URL: "+e);
|
||||
}
|
||||
}
|
||||
if (b && b.docShell) {
|
||||
i2pbutton_disable_browser_js(b);
|
||||
|
||||
// kill meta-refresh and existing page loading
|
||||
// XXX: Despite having JUST checked b.docShell, it can
|
||||
// actually end up NULL here in some cases?
|
||||
try {
|
||||
if (b.docShell && b.webNavigation)
|
||||
b.webNavigation.stop(b.webNavigation.STOP_ALL);
|
||||
} catch(e) {
|
||||
i2pbutton_log(4, "DocShell error: "+e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Bug 1506 P3: The JS-killing bits of this are used by
|
||||
// New Identity as a defense-in-depth measure.
|
||||
//
|
||||
// This is an ugly beast.. But unfortunately it has to be so..
|
||||
// Looping over all tabs twice is not somethign we wanna do..
|
||||
function i2pbutton_disable_all_js() {
|
||||
var wm = Components.classes["@mozilla.org/appshell/window-mediator;1"]
|
||||
.getService(Components.interfaces.nsIWindowMediator);
|
||||
var enumerator = wm.getEnumerator("navigator:browser");
|
||||
while(enumerator.hasMoreElements()) {
|
||||
var win = enumerator.getNext();
|
||||
i2pbutton_disable_window_js(win);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
function i2pbutton_init() {
|
||||
//SecurityPrefs.initialize()
|
||||
|
||||
checkI2P(function (res) {
|
||||
i2pbutton_log(3, `Check: ${res}`)
|
||||
},function (res) {
|
||||
i2pbutton_log(3, `Check: ${res}`)
|
||||
})
|
||||
|
||||
if (m_ib_is_initialized) {
|
||||
return
|
||||
}
|
||||
m_ib_is_initialized = true
|
||||
|
||||
// Determine if we are running inside I2P Browser.
|
||||
var cur_version;
|
||||
try {
|
||||
cur_version = m_ib_prefs.getCharPref("i2pbrowser.version")
|
||||
m_ib_ibb = true
|
||||
i2pbutton_log(3, "This is a I2P Browser")
|
||||
} catch(e) {
|
||||
i2pbutton_log(3, "This is not a I2P Browser: "+e)
|
||||
}
|
||||
|
||||
// If the I2P Browser version has changed since the last time I2pbutton
|
||||
// was loaded, reset the version check preferences in order to avoid
|
||||
// incorrectly reporting that the browser needs to be updated.
|
||||
var last_version
|
||||
try {
|
||||
last_version = m_ib_prefs.getCharPref(k_ib_last_browser_version_pref)
|
||||
} catch (e) {}
|
||||
if (cur_version != last_version) {
|
||||
m_ib_prefs.setBoolPref(k_ib_browser_update_needed_pref, false)
|
||||
if (m_ib_prefs.prefHasUserValue(k_ib_last_update_check_pref)) {
|
||||
m_ib_prefs.clearUserPref(k_ib_last_update_check_pref)
|
||||
}
|
||||
|
||||
if (cur_version) {
|
||||
m_ib_prefs.setCharPref(k_ib_last_browser_version_pref, cur_version)
|
||||
}
|
||||
}
|
||||
|
||||
var environ = Components.classes["@mozilla.org/process/environment;1"].getService(Components.interfaces.nsIEnvironment)
|
||||
|
||||
// Add about:i2p IPC message listener.
|
||||
window.messageManager.addMessageListener("AboutI2p:Loaded", i2pbutton_abouti2p_message_handler)
|
||||
|
||||
// Arrange for our about:i2p content script to be loaded in each frame.
|
||||
window.messageManager.loadFrameScript("chrome://i2pbutton/content/aboutI2p/aboutI2p-content.js", true)
|
||||
|
||||
i2pbutton_log(3, 'init completed')
|
||||
}
|
||||
|
||||
|
@ -30,7 +30,7 @@
|
||||
class="toolbarbutton-1 chromeclass-toolbar-additional"
|
||||
type="menu"
|
||||
orient="horizontal"
|
||||
label="I2pbutton"
|
||||
label="I2Pbutton"
|
||||
tooltiptext="&i2pbutton.button.tooltip;"
|
||||
menu="i2pbutton-context-menu"
|
||||
context="i2pbutton-context-menu"/>
|
||||
|
@ -1,5 +1,4 @@
|
||||
var m_ib_i2plog = Components.classes["@geti2p.net/i2pbutton-logger;1"]
|
||||
.getService(Components.interfaces.nsISupports).wrappedJSObject;
|
||||
let m_ib_i2plog = Components.classes["@geti2p.net/i2pbutton-logger;1"].getService(Components.interfaces.nsISupports).wrappedJSObject;
|
||||
|
||||
var m_ib_string_bundle = i2pbutton_get_stringbundle();
|
||||
|
||||
|
383
src/chrome/content/i2pcookie.js
Normal file
383
src/chrome/content/i2pcookie.js
Normal file
@ -0,0 +1,383 @@
|
||||
var cookiesTree = null;
|
||||
var prefs = null;
|
||||
var cookies = [];
|
||||
var protectedCookies = [];
|
||||
var deletedCookies = [];
|
||||
var lastCookieSortColumn = "";
|
||||
var lastCookieSortAscending = false;
|
||||
var cookiemanager = null;
|
||||
var selector = null;
|
||||
//custom tree view, this is how we dynamically add the cookies
|
||||
var cookiesTreeView = {
|
||||
rowCount : 0,
|
||||
setTree : function(tree){},
|
||||
getImageSrc : function(row,column) {},
|
||||
getProgressMode : function(row,column) {},
|
||||
getCellValue : function(row,column) {},
|
||||
getCellText : function(row,column){
|
||||
var rv="";
|
||||
switch (column.id) {
|
||||
case "domainCol" : rv = cookies[row].rawHost; break;
|
||||
case "nameCol" : rv = cookies[row].name; break;
|
||||
case "lockCol" : rv = cookies[row].isProtected; break;
|
||||
case "pathCol" : rv = cookies[row].path; break;
|
||||
}
|
||||
return rv;
|
||||
},
|
||||
isSeparator : function(index) {return false;},
|
||||
isSorted: function() { return false; },
|
||||
isContainer : function(index) {return false;},
|
||||
cycleHeader : function(column, aElt) {},
|
||||
getRowProperties : function(row,column,prop){},
|
||||
getColumnProperties : function(column,columnElement,prop){},
|
||||
getCellProperties : function(row,column,prop) {}
|
||||
};
|
||||
|
||||
// XXX: Must match the definition in cookie-jar-selector :/
|
||||
function Cookie(number,name,value,isDomain,host,rawHost,HttpOnly,path,isSecure,isSession,
|
||||
expires,isProtected) {
|
||||
this.number = number;
|
||||
this.name = name;
|
||||
this.value = value;
|
||||
this.isDomain = isDomain;
|
||||
this.host = host;
|
||||
this.rawHost = rawHost;
|
||||
this.isHttpOnly = HttpOnly;
|
||||
this.path = path;
|
||||
this.isSecure = isSecure;
|
||||
this.isSession = isSession;
|
||||
this.expires = expires;
|
||||
this.isProtected = isProtected;
|
||||
}
|
||||
|
||||
function initDialog() {
|
||||
cookiesTree = document.getElementById("cookiesTree");
|
||||
prefs =Components.classes["@mozilla.org/preferences-service;1"]
|
||||
.getService(Components.interfaces.nsIPrefBranch);
|
||||
selector = Components.classes["@geti2p.net/cookie-jar-selector;1"]
|
||||
.getService(Components.interfaces.nsISupports)
|
||||
.wrappedJSObject;
|
||||
//init cookie manager
|
||||
cookiemanager = Components.classes["@mozilla.org/cookiemanager;1"].getService();
|
||||
cookiemanager = cookiemanager.QueryInterface(Components.interfaces.nsICookieManager);
|
||||
var enumerator = cookiemanager.enumerator;
|
||||
var count = 0;
|
||||
getProtectedCookies();
|
||||
while (enumerator.hasMoreElements()) {
|
||||
var nextCookie = enumerator.getNext();
|
||||
if (!nextCookie) break;
|
||||
nextCookie = nextCookie.QueryInterface(Components.interfaces.nsICookie);
|
||||
var host = nextCookie.host;
|
||||
var isProt = checkIfProtected(nextCookie.name, host, nextCookie.path);
|
||||
//populate list
|
||||
cookies[count] =
|
||||
new Cookie(count++, nextCookie.name, nextCookie.value, nextCookie.isDomain, host,
|
||||
(host.charAt(0)==".") ? host.substring(1,host.length) : host, nextCookie.isHttpOnly,
|
||||
nextCookie.path, nextCookie.isSecure, nextCookie.isSession, nextCookie.expires,
|
||||
isProt);
|
||||
}
|
||||
//apply custom view
|
||||
cookiesTreeView.rowCount = cookies.length;
|
||||
cookiesTree.treeBoxObject.view = cookiesTreeView;
|
||||
document.getElementById('defaultCookieGroup').selectedIndex = prefs.getBoolPref("extensions.i2pbutton.cookie_auto_protect")? 0 : 1;
|
||||
}
|
||||
function protectCookie()
|
||||
{
|
||||
ProtectInTree(cookiesTree, cookiesTreeView,
|
||||
cookies, "protectCookie", "unprotectCookie", "removeCookie");
|
||||
}
|
||||
function unprotectCookie() {
|
||||
UnProtectInTree(cookiesTree, cookiesTreeView,
|
||||
cookies, "protectCookie", "unprotectCookie", "removeCookie");
|
||||
}
|
||||
function checkIfProtected(name, host, path)
|
||||
{
|
||||
for (var i = 0; i < protectedCookies.length; i++)
|
||||
{
|
||||
var cookie = protectedCookies[i];
|
||||
if (cookie.name == name && cookie.host == host && cookie.path == path)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
function itemSelected() {
|
||||
var selections = getTreeSelections(cookiesTree);
|
||||
if (selections.length) {
|
||||
|
||||
//DY - check if (the last in list) selection is protected/unprotected, set buttons
|
||||
if (cookies[selections[(selections.length)-1]].isProtected) {
|
||||
document.getElementById("removeCookie").disabled = true;
|
||||
document.getElementById("unprotectCookie").disabled = false;
|
||||
document.getElementById("protectCookie").disabled = true;
|
||||
} else {
|
||||
document.getElementById("removeCookie").disabled = false;
|
||||
document.getElementById("unprotectCookie").disabled = true;
|
||||
document.getElementById("protectCookie").disabled = false;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
function acceptDialog() {
|
||||
|
||||
FinalizeCookieDeletions();
|
||||
var protectedcount = 0;
|
||||
var protcookies = [];
|
||||
for (var i = 0; i < cookies.length; i++)
|
||||
{
|
||||
if (cookies[i].isProtected)
|
||||
{
|
||||
protcookies[protectedcount] = cookies[i];
|
||||
protectedcount++;
|
||||
}
|
||||
}
|
||||
selector.protectCookies(protcookies);
|
||||
//output protected cookies
|
||||
prefs.setBoolPref("extensions.i2pbutton.cookie_auto_protect",document.getElementById('saveAllCookies').selected);
|
||||
}
|
||||
function CookieColumnSort(column) {
|
||||
lastCookieSortAscending =
|
||||
SortTree(cookiesTree, cookiesTreeView, cookies,
|
||||
column, lastCookieSortColumn, lastCookieSortAscending);
|
||||
lastCookieSortColumn = column;
|
||||
}
|
||||
function DeleteCookie() {
|
||||
//DY - check if any selection is protected
|
||||
var selections = getTreeSelections(cookiesTree);
|
||||
var protect = false;
|
||||
var i;
|
||||
for (i=0; i<selections.length; i++) {
|
||||
if (cookies[selections[i]].isProtected) {
|
||||
protect = true;
|
||||
}
|
||||
}
|
||||
if (!protect && i>0 ) {
|
||||
DeleteSelectedItemFromTree(cookiesTree, cookiesTreeView,
|
||||
cookies, deletedCookies,
|
||||
"removeCookie", "removeAllCookies",
|
||||
"protectCookie", "unprotectCookie");
|
||||
if (!cookies.length) {
|
||||
;//ClearCookieProperties();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
function getProtectedCookies()
|
||||
{
|
||||
var gotCookies = selector.getProtectedCookies("tor");
|
||||
if (gotCookies == null)
|
||||
return;
|
||||
protectedCookies = gotCookies;
|
||||
}
|
||||
|
||||
//Tree Utils
|
||||
|
||||
function SortTree(tree, view, table, column, lastSortColumn, lastSortAscending, updateSelection) {
|
||||
|
||||
// remember which item was selected so we can restore it after the sort
|
||||
var selections = getTreeSelections(tree);
|
||||
var selectedNumber = selections.length ? table[selections[0]].number : -1;
|
||||
|
||||
// determine if sort is to be ascending or descending
|
||||
var ascending = (column == lastSortColumn) ? !lastSortAscending : true;
|
||||
|
||||
// do the sort or re-sort
|
||||
var compareFunc = function compare(first, second) {
|
||||
if (column=="isProtected") {
|
||||
return second[column].toString().localeCompare(first[column].toString());
|
||||
} else {
|
||||
return first[column].toLowerCase().localeCompare(second[column].toLowerCase());
|
||||
}
|
||||
}
|
||||
table.sort(compareFunc);
|
||||
if (!ascending)
|
||||
table.reverse();
|
||||
|
||||
// restore the selection
|
||||
var selectedRow = -1;
|
||||
if (selectedNumber>=0 && updateSelection) {
|
||||
for (var s=0; s<table.length; s++) {
|
||||
if (table[s].number == selectedNumber) {
|
||||
// update selection
|
||||
// note: we need to deselect before reselecting in order to trigger ...Selected()
|
||||
tree.view.selection.select(-1);
|
||||
tree.view.selection.select(s);
|
||||
selectedRow = s;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// display the results
|
||||
tree.treeBoxObject.invalidate();
|
||||
if (selectedRow >= 0) {
|
||||
tree.treeBoxObject.ensureRowIsVisible(selectedRow)
|
||||
}
|
||||
|
||||
return ascending;
|
||||
}
|
||||
function FinalizeCookieDeletions() {
|
||||
for (var c=0; c<deletedCookies.length; c++) {
|
||||
cookiemanager.remove(deletedCookies[c].host,
|
||||
deletedCookies[c].name,
|
||||
deletedCookies[c].path,
|
||||
false);
|
||||
}
|
||||
deletedCookies.length = 0;
|
||||
}
|
||||
function getTreeSelections(tree) {
|
||||
var selections = [];
|
||||
var select;
|
||||
|
||||
select = tree.view.selection;
|
||||
if (select) {
|
||||
var count = select.getRangeCount();
|
||||
var min = new Object();
|
||||
var max = new Object();
|
||||
for (var i=0; i<count; i++) {
|
||||
select.getRangeAt(i, min, max);
|
||||
for (var k=min.value; k<=max.value; k++) {
|
||||
if (k != -1) {
|
||||
selections[selections.length] = k;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return selections;
|
||||
}
|
||||
function ProtectInTree
|
||||
(tree, view, table, protButton, unprotButton, removeButton) {
|
||||
|
||||
var selections = getTreeSelections(tree);
|
||||
for (var s=selections.length-1; s>= 0; s--) {
|
||||
var i = selections[s];
|
||||
table[i].isProtected = true;
|
||||
}
|
||||
|
||||
//update tree view
|
||||
tree.treeBoxObject.invalidate();
|
||||
//DY - Update selections
|
||||
tree.treeBoxObject.ensureRowIsVisible(selections[0]);
|
||||
// disable/enable buttons
|
||||
document.getElementById(unprotButton).disabled = false;
|
||||
document.getElementById(protButton).disabled = true;
|
||||
document.getElementById(removeButton).disabled = true;
|
||||
}
|
||||
function UnProtectInTree
|
||||
(tree, view, table, protButton, unprotButton, removeButton) {
|
||||
|
||||
var selections = getTreeSelections(tree);
|
||||
for (var s=selections.length-1; s>= 0; s--) {
|
||||
var i = selections[s];
|
||||
table[i].isProtected = false;
|
||||
}
|
||||
|
||||
//update tree view
|
||||
tree.treeBoxObject.invalidate();
|
||||
//DY - Update selections
|
||||
tree.treeBoxObject.ensureRowIsVisible(selections[0]);
|
||||
// disable/enable buttons
|
||||
document.getElementById(unprotButton).disabled = true;
|
||||
document.getElementById(protButton).disabled = false;
|
||||
document.getElementById(removeButton).disabled = false;
|
||||
}
|
||||
function DeleteAllCookies() {
|
||||
|
||||
DeleteAllFromTree(cookiesTree, cookiesTreeView,
|
||||
cookies, deletedCookies,
|
||||
"removeCookie", "removeAllCookies",
|
||||
"protectCookie", "unprotectCookie");
|
||||
|
||||
}
|
||||
function DeleteSelectedItemFromTree
|
||||
(tree, view, table, deletedTable, removeButton, removeAllButton, protButton, unprotButton) {
|
||||
|
||||
var selections = getTreeSelections(tree);
|
||||
|
||||
tree.view.selection.clearSelection();
|
||||
|
||||
|
||||
// remove selected items from list (by setting them to null) and place in deleted list
|
||||
for (var s=selections.length-1; s>= 0; s--) {
|
||||
var i = selections[s];
|
||||
deletedTable[deletedTable.length] = table[i];
|
||||
table[i] = null;
|
||||
}
|
||||
// collapse list by removing all the null entries
|
||||
for (var j=0; j<table.length; j++) {
|
||||
if (table[j] == null) {
|
||||
var k = j;
|
||||
while ((k < table.length) && (table[k] == null)) {
|
||||
k++;
|
||||
}
|
||||
table.splice(j, k-j);
|
||||
view.rowCount -= k - j;
|
||||
tree.treeBoxObject.rowCountChanged(j, j - k);
|
||||
}
|
||||
}
|
||||
//DY - update selection and/or buttons
|
||||
if (table.length) {
|
||||
|
||||
//DY - update selection to previous (first of) selected position or bottom
|
||||
var nextSelection = (selections[0] < table.length) ? selections[0] : table.length-1;
|
||||
|
||||
tree.view.selection.select(nextSelection);
|
||||
tree.treeBoxObject.ensureRowIsVisible(nextSelection);
|
||||
if (table[nextSelection].isProtected) {
|
||||
document.getElementById(unprotButton).disabled = false;
|
||||
document.getElementById(protButton).disabled = true;
|
||||
} else {
|
||||
document.getElementById(unprotButton).disabled = true;
|
||||
document.getElementById(protButton).disabled = false;
|
||||
}
|
||||
} else {
|
||||
// disable buttons
|
||||
document.getElementById(removeButton).disabled = true;
|
||||
document.getElementById(removeAllButton).disabled = true;
|
||||
document.getElementById(unprotButton).disabled = true;
|
||||
document.getElementById(protButton).disabled = true;
|
||||
}
|
||||
}
|
||||
function DeleteAllFromTree
|
||||
(tree, view, table, deletedTable, removeButton, removeAllButton, protButton, unprotButton) {
|
||||
|
||||
// remove items from table and place in deleted table
|
||||
for (var i=0; i<table.length; i++) {
|
||||
//DY - only if unprotected
|
||||
if (!table[i].isProtected) {
|
||||
deletedTable[deletedTable.length] = table[i];
|
||||
table[i] = null;
|
||||
}
|
||||
}
|
||||
|
||||
tree.view.selection.clearSelection();
|
||||
|
||||
//DY - fix up tree
|
||||
// collapse list by removing all the null entries
|
||||
for (var j=0; j<table.length; j++) {
|
||||
if (table[j] == null) {
|
||||
var k = j;
|
||||
while ((k < table.length) && (table[k] == null)) {
|
||||
k++;
|
||||
}
|
||||
table.splice(j, k-j);
|
||||
view.rowCount -= k - j;
|
||||
tree.treeBoxObject.rowCountChanged(j, j - k);
|
||||
}
|
||||
}
|
||||
// update selection and/or buttons
|
||||
if (table.length) {
|
||||
// update selection to top
|
||||
tree.view.selection.select(0);
|
||||
tree.treeBoxObject.ensureRowIsVisible(0);
|
||||
//if it exists is must already be protected
|
||||
document.getElementById(unprotButton).disabled = false;
|
||||
document.getElementById(protButton).disabled = true;
|
||||
} else {
|
||||
// disable all buttons
|
||||
document.getElementById(removeButton).disabled = true;
|
||||
document.getElementById(removeAllButton).disabled = true;
|
||||
document.getElementById(unprotButton).disabled = true;
|
||||
document.getElementById(protButton).disabled = true;
|
||||
}
|
||||
}
|
71
src/chrome/content/i2pcookiedialog.xul
Normal file
71
src/chrome/content/i2pcookiedialog.xul
Normal file
@ -0,0 +1,71 @@
|
||||
<?xml version="1.0"?>
|
||||
<?xml-stylesheet href="chrome://i2pbutton/skin/i2pbutton.css" type="text/css"?>
|
||||
<?xml-stylesheet href="chrome://global/skin/" type="text/css"?>
|
||||
|
||||
<!DOCTYPE overlay SYSTEM "chrome://i2pbutton/locale/i2pbutton.dtd">
|
||||
|
||||
<dialog id="TorCookieDialog"
|
||||
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
|
||||
title="&i2pbutton.cookiedialog.title;"
|
||||
buttons="accept,cancel"
|
||||
style="width: 30em;"
|
||||
onload="initDialog();"
|
||||
ondialogaccept="acceptDialog();"
|
||||
persist="screenX screenY width height">
|
||||
<script src="chrome://i2pbutton/content/i2pbutton.js" type="application/x-javascript"/>
|
||||
<script src="chrome://i2pbutton/content/i2pcookie.js" type="application/x-javascript"/>
|
||||
<stringbundleset id="i2pbutton-stringbundleset">
|
||||
<stringbundle id="i2pbutton-bundle" src="chrome://i2pbutton/locale/i2pbutton.properties"/>
|
||||
</stringbundleset>
|
||||
|
||||
<label value=""/>
|
||||
<separator class="thin"/>
|
||||
<vbox flex="1">
|
||||
<tree id="cookiesTree" flex="1" style="height: 10em;"
|
||||
onkeypress="return;//do this later"
|
||||
onselect="itemSelected();"
|
||||
hidecolumnpicker="true">
|
||||
<treecols>
|
||||
<treecol id="lockCol" label="&i2pbutton.cookiedialog.lockCol;" flex="1"
|
||||
onclick="CookieColumnSort('isProtected', true);" persist="width"/>
|
||||
<splitter class="tree-splitter"/>
|
||||
<treecol id="domainCol" label="&i2pbutton.cookiedialog.domainCol;" flex="2"
|
||||
onclick="CookieColumnSort('rawHost', true);" persist="width"/>
|
||||
<splitter class="tree-splitter"/>
|
||||
<treecol id="nameCol" label="&i2pbutton.cookiedialog.nameCol;" flex="1"
|
||||
onclick="CookieColumnSort('name', true);" persist="width"/>
|
||||
<treecol id="pathCol" label="&i2pbutton.cookiedialog.pathCol;" flex="1"
|
||||
onclick="CookieColumnSort('path', true);" persist="width"/>
|
||||
|
||||
</treecols>
|
||||
<treechildren/>
|
||||
</tree>
|
||||
</vbox>
|
||||
<groupbox>
|
||||
<hbox>
|
||||
<vbox>
|
||||
<button id="protectCookie" disabled="true"
|
||||
label="&i2pbutton.cookiedialog.protectCookie;"
|
||||
oncommand="protectCookie();"/>
|
||||
<button id="removeCookie" disabled="true"
|
||||
label="&i2pbutton.cookiedialog.removeCookie;"
|
||||
oncommand="DeleteCookie();"/>
|
||||
</vbox>
|
||||
<vbox>
|
||||
<button id="unprotectCookie" disabled="true"
|
||||
label="&i2pbutton.cookiedialog.unprotectCookie;"
|
||||
oncommand="unprotectCookie();"/>
|
||||
<button id="removeAllCookies"
|
||||
label="&i2pbutton.cookiedialog.removeAllBut;"
|
||||
oncommand="DeleteAllCookies();"/>
|
||||
</vbox>
|
||||
</hbox>
|
||||
<hbox>
|
||||
<radiogroup id="defaultCookieGroup">
|
||||
<radio id="saveAllCookies" label="&i2pbutton.cookiedialog.saveAllCookies;" />
|
||||
<radio id="donnotsaveCookies" label="&i2pbutton.cookiedialog.doNotSaveAllCookies;" />
|
||||
</radiogroup>
|
||||
</hbox>
|
||||
</groupbox>
|
||||
|
||||
</dialog>
|
29
src/chrome/content/menu-overlay.xul
Normal file
29
src/chrome/content/menu-overlay.xul
Normal file
@ -0,0 +1,29 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?> <!-- -*- Mode: HTML -*- -->
|
||||
|
||||
<!DOCTYPE overlay SYSTEM "chrome://i2pbutton/locale/aboutI2p.dtd">
|
||||
|
||||
<overlay id="i2pbutton-menu-overlay"
|
||||
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
|
||||
<menupopup id="menu_HelpPopup">
|
||||
<!-- Bug 18905: Hide unused help menu items -->
|
||||
<menuitem id="menu_openHelp" removeelement="true"/>
|
||||
<menuitem id="menu_openTour" removeelement="true"/>
|
||||
<menuitem id="healthReport" removeelement="true"/>
|
||||
<menuitem id="feedbackPage" removeelement="true"/>
|
||||
<menuitem id="helpSafeMode" removeelement="true"/>
|
||||
<menuitem id="menu_HelpPopup_reportPhishingtoolmenu" removeelement="true"/>
|
||||
<menuitem id="menu_HelpPopup_reportPhishingErrortoolmenu" removeelement="true"/>
|
||||
<!-- dummy elements to avoid 'getElementById' errors -->
|
||||
<box id="feedbackPage"/>
|
||||
<box id="helpSafeMode"/>
|
||||
<box id="menu_HelpPopup_reportPhishingtoolmenu"/>
|
||||
<box id="menu_HelpPopup_reportPhishingErrortoolmenu"/>
|
||||
<!-- Add I2P Browser manual link -->
|
||||
<!--<menuitem name="i2pBrowserUserManual"
|
||||
id="i2pBrowserUserManual"
|
||||
position="1"
|
||||
label="&aboutI2p.i2pbrowser_user_manual.label;"
|
||||
accesskey="&aboutI2p.i2pbrowser_user_manual.accesskey;"
|
||||
oncommand="gBrowser.selectedTab = gBrowser.addTab('https://geti2p.net/en/browser/' + Services.locale.getRequestedLocale())" />-->
|
||||
</menupopup>
|
||||
</overlay>
|
83
src/chrome/content/preferences.xhtml
Normal file
83
src/chrome/content/preferences.xhtml
Normal file
@ -0,0 +1,83 @@
|
||||
<!DOCTYPE overlay SYSTEM "chrome://i2pbutton/locale/i2pbutton.dtd">
|
||||
<html xmlns="http://www.w3.org/1999/xhtml">
|
||||
<meta charset="UTF-8"/>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1"/>
|
||||
<head>
|
||||
<title>&i2pbutton.prefs.security_settings;</title>
|
||||
<link type="text/css" rel="stylesheet" charset="UTF-8" href="chrome://i2pbutton/skin/preferences.css"/>
|
||||
<script type="text/javascript" src="i2pbutton_util.js"></script>
|
||||
<style>
|
||||
</style>
|
||||
</head>
|
||||
<body onload="i2pbutton_init_security_ui()">
|
||||
<div class="wrapper outer-wrapper">
|
||||
<div class="title">
|
||||
&i2pbutton.prefs.sec_caption;
|
||||
</div>
|
||||
<div class="wrapper inner-wrapper">
|
||||
<input id="i2pbutton_sec_slider" type="range" min="1" max="3" list="datalist" onchange="i2pbutton_set_slider(parseInt(this.value, 10))"/>
|
||||
<datalist id="datalist">
|
||||
<option onclick="i2pbutton_set_slider(1)">
|
||||
&i2pbutton.prefs.sec_standard_label;
|
||||
</option>
|
||||
<option onclick="i2pbutton_set_slider(2)">
|
||||
&i2pbutton.prefs.sec_safer_label;
|
||||
</option>
|
||||
<option onclick="i2pbutton_set_slider(3)">
|
||||
&i2pbutton.prefs.sec_safest_label;
|
||||
</option>
|
||||
</datalist>
|
||||
<div class="description-wrapper">
|
||||
<div id="desc_safest" class="description">
|
||||
<p class="slider-text-size slider-text-weight">
|
||||
&i2pbutton.prefs.sec_safest_description;
|
||||
</p>
|
||||
<p class="slider-text-size slider-text-weight">
|
||||
&i2pbutton.prefs.sec_safest_list_label;
|
||||
</p>
|
||||
<p class="slider-text-size">
|
||||
&i2pbutton.prefs.sec_js_disabled;
|
||||
</p>
|
||||
<p class="slider-text-size">
|
||||
&i2pbutton.prefs.sec_limit_graphics_and_typography;
|
||||
</p>
|
||||
<p class="slider-text-size">
|
||||
&i2pbutton.prefs.sec_click_to_play_media;
|
||||
</p>
|
||||
<a id="link_safest" class="text-link">
|
||||
&i2pbutton.prefs.sec_learn_more_label;
|
||||
</a>
|
||||
</div>
|
||||
<div id="desc_safer" class="description">
|
||||
<p class="slider-text-size slider-text-weight">
|
||||
&i2pbutton.prefs.sec_safer_description;
|
||||
</p>
|
||||
<p class="slider-text-size slider-text-weight">
|
||||
&i2pbutton.prefs.sec_safer_list_label;
|
||||
</p>
|
||||
<p class="slider-text-size">
|
||||
&i2pbutton.prefs.sec_js_on_https_sites_only;
|
||||
</p>
|
||||
<p class="slider-text-size">
|
||||
&i2pbutton.prefs.sec_limit_typography;
|
||||
</p>
|
||||
<p class="slider-text-size">
|
||||
&i2pbutton.prefs.sec_click_to_play_media;
|
||||
</p>
|
||||
<a id="link_safer" class="text-link">
|
||||
&i2pbutton.prefs.sec_learn_more_label;
|
||||
</a>
|
||||
</div>
|
||||
<div id="desc_standard" class="description">
|
||||
<p class="slider-text-size slider-text-weight">
|
||||
&i2pbutton.prefs.sec_standard_description;
|
||||
</p>
|
||||
<a id="link_standard" class="text-link">
|
||||
&i2pbutton.prefs.sec_learn_more_label;
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
@ -5,21 +5,32 @@
|
||||
|
||||
<!ENTITY aboutI2p.browser_name "The Invisible Internet Browser">
|
||||
<!ENTITY aboutI2p.browser_short_name "I2P Browser">
|
||||
<!ENTITY aboutI2p.browser_description "is preconfigured to search for content on the I2P network. In this release, I2P Browser does not launch its own router and is dependent on having the I2P router pre installed and running. The I2P Browser is preconfigured with default router settings.">
|
||||
<!ENTITY aboutI2p.browser_description "is preconfigured to get your content using the anonymous and private I2P network. In this release, I2P Browser bundles it's own I2P Router, which starts and stops when you open and close the browser application. It does not require an existing I2P router installed.">
|
||||
<!ENTITY aboutI2p.donate "Donate">
|
||||
<!ENTITY aboutI2p.supportus "Support I2P development">
|
||||
|
||||
<!ENTITY aboutI2p.warn_not_running "It currently seems like your router is NOT running :( However, if you just started the router, please try again in two minutes cause it need time to start.">
|
||||
<!ENTITY aboutI2p.warn_not_running "It currently seems like your router is NOT running :(">
|
||||
<!ENTITY aboutI2p.reccommend_not_running "If you just started the router, it may take up to 2 minutes for the router to start the proxy.">
|
||||
<!ENTITY aboutI2p.all_checks_ok "Super! The browser detected I2P running in background! :)">
|
||||
<!ENTITY aboutI2p.warn_experimental "This is a experimental sub-project of I2P.">
|
||||
<!ENTITY aboutI2p.console_visit_msg "It seems like your console is up, click the to visit:">
|
||||
<!ENTITY aboutI2p.warn_experimental "This is a experimental sub-project of I2P. It is currently Beta software.">
|
||||
<!ENTITY aboutI2p.console_visit_msg "It seems like your console is up, click to visit:">
|
||||
<!ENTITY aboutI2p.i2ptunnel_visit_msg "I2P has a web-based interface for configuring .i2p services like web sites, to set up your own web sites, go here:">
|
||||
<!ENTITY aboutI2p.email_visit_msg "I2P also bundles a webmail client which can be used to access in-I2P e-mail. To use it, go here:">
|
||||
<!ENTITY aboutI2p.torrent_visit_msg "I2P is capable of anonymous Peer-to-Peer file sharing, to use the built-in bittorrent client go here:">
|
||||
<!ENTITY aboutI2p.console "Console">
|
||||
<!ENTITY aboutI2p.torrent "Torrents">
|
||||
<!ENTITY aboutI2p.i2ptunnel "Tunnels">
|
||||
<!ENTITY aboutI2p.email "E-Mail">
|
||||
<!ENTITY aboutI2p.i2pbutton_source "I2P Button source">
|
||||
<!ENTITY aboutI2p.build_scripts "Build scripts">
|
||||
<!ENTITY aboutI2p.source "Source">
|
||||
<!ENTITY aboutI2p.bug_tracker "Bugtracker">
|
||||
<!ENTITY aboutI2p.build_scripts "Build scripts to compile from source">
|
||||
<!ENTITY aboutI2p.source "Browse the source code">
|
||||
<!ENTITY aboutI2p.bug_tracker "Submit a Bug Report">
|
||||
<!ENTITY aboutI2p.links "Links">
|
||||
<!ENTITY aboutI2p.refresh_text "Click the link to refresh the page (In case the router is starting up):">
|
||||
<!ENTITY aboutI2p.design "Design Document">
|
||||
<!ENTITY aboutI2p.refresh_text "Try refreshing the page.">
|
||||
<!ENTITY aboutI2p.refresh_link "Refresh">
|
||||
|
||||
<!ENTITY aboutI2p.getInvolved.label "Get Involved »">
|
||||
<!ENTITY aboutI2p.getInvolved.link "https://geti2p.net/en/get-involved">
|
||||
|
||||
<!ENTITY aboutI2p.site "http://i2p-projekt.i2p/en">
|
||||
<!ENTITY aboutI2p.routerconsole "http://localhost:7657">
|
||||
<!ENTITY aboutI2p.github "https://github.com/mikalv">
|
||||
<!ENTITY aboutI2p.trac "http://trac.i2p2.i2p">
|
||||
|
@ -1,44 +1,53 @@
|
||||
# vim: set sw=2 sts=2 ts=8 et:
|
||||
|
||||
onboarding.tour-i2p-welcome=Welcome
|
||||
onboarding.tour-i2p-welcome.title=You’re ready.
|
||||
onboarding.tour-i2p-welcome.description=I2P Browser offers the highest standard of privacy and security while browsing the web. You’re now protected against tracking, surveillance, and censorship. This quick onboarding will show you how.
|
||||
onboarding.tour-i2p-welcome.title=Welcome to I2P Browser
|
||||
onboarding.tour-i2p-welcome.description=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.
|
||||
# onboarding.tour-i2p-welcome.description-suffix=I2P Browser isolates cookies and deletes your browser history after your session. These modifications ensure your privacy and security are protected in the browser.
|
||||
onboarding.tour-i2p-welcome.next-button=Go to Privacy
|
||||
|
||||
onboarding.tour-i2p-privacy=Privacy
|
||||
onboarding.tour-i2p-privacy.title=Snub trackers and snoopers.
|
||||
onboarding.tour-i2p-privacy.description=I2P Browser isolates cookies and deletes your browser hisi2py after your session. These modifications ensure your privacy and security are protected in the browser. Click ‘I2P Network’ to learn how we protect you on the network level.
|
||||
onboarding.tour-i2p-privacy.button=Go to I2P Network
|
||||
onboarding.tour-i2p-privacy.title=Stay in control of your Data
|
||||
onboarding.tour-i2p-privacy.description=I2P Browser isolates cookies and deletes your browser history after your session. These modifications ensure your privacy and security are protected in the browser.
|
||||
onboarding.tour-i2p-privacy.button=Go to Security and Experience
|
||||
|
||||
onboarding.tour-i2p-network=I2P Network
|
||||
# This slide is not currently use in the I2P Browser Onboarding slideshow
|
||||
#onboarding.tour-i2p-network=I2P Network
|
||||
onboarding.tour-i2p-network.title=Travel a decentralized network.
|
||||
onboarding.tour-i2p-network.description=I2P Browser connects you to the I2P network run by thousands of volunteers around the world. Unlike a VPN, there’s no one point of failure or centralized entity you need to trust in order to enjoy the internet privately.
|
||||
onboarding.tour-i2p-network.button=Go to Circuit Display
|
||||
onboarding.tour-i2p-network.button=Go to Tunnel Display
|
||||
# End
|
||||
|
||||
onboarding.tour-i2p-circuit-display=Circuit Display
|
||||
# This slide is not currently use in the I2P Browser Onboarding slideshow
|
||||
onboarding.tour-i2p-circuit-display=Tunnel Display
|
||||
onboarding.tour-i2p-circuit-display.title=See your path.
|
||||
onboarding.tour-i2p-circuit-display.description=For each domain you visit, your traffic is relayed and encrypted in a circuit across three I2P relays around the world. No website knows where you are connecting from. You can request a new circuit by clicking ‘New Circuit for this Site’ on our Circuit Display.
|
||||
onboarding.tour-i2p-circuit-display.button=See My Path
|
||||
onboarding.tour-i2p-circuit-display.description=For each domain you visit, your traffic is relayed and encrypted in a tunnel across three I2P routers around the world. Currently displaying this information is still under development.
|
||||
onboarding.tour-i2p-circuit-display.button=Sorry, come back later.
|
||||
onboarding.tour-i2p-circuit-display.next-button=Go to Security
|
||||
# end
|
||||
|
||||
onboarding.tour-i2p-security=Security
|
||||
onboarding.tour-i2p-security=Security and Experience
|
||||
onboarding.tour-i2p-security.title=Choose your experience.
|
||||
onboarding.tour-i2p-security.description=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.
|
||||
onboarding.tour-i2p-security.description-suffix=Note: By default, NoScript and HTTPS Everywhere are not included on the toolbar, but you can customize your toolbar to add them.
|
||||
onboarding.tour-i2p-security.description=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.\n Note: By default, NoScript and HTTPS Everywhere are not included on the toolbar, but you can customize your toolbar to add them.
|
||||
onboarding.tour-i2p-security.description-suffix=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.
|
||||
onboarding.tour-i2p-security-level.button=See Your Security Level
|
||||
onboarding.tour-i2p-security-level.next-button=Go to Experience Tips
|
||||
|
||||
onboarding.tour-i2p-expect-differences=Experience Tips
|
||||
onboarding.tour-i2p-expect-differences.title=Expect some differences.
|
||||
onboarding.tour-i2p-expect-differences.description=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.
|
||||
onboarding.tour-i2p-expect-differences.button=See FAQs
|
||||
onboarding.tour-i2p-expect-differences.next-button=Go to Onion Services
|
||||
onboarding.tour-i2p-expect-differences.button=Done
|
||||
# onboarding.tour-i2p-expect-differences.button=See FAQs
|
||||
onboarding.tour-i2p-expect-differences.next-button=Done
|
||||
# onboarding.tour-i2p-expect-differences.next-button=Go to Hidden Services
|
||||
|
||||
onboarding.tour-i2p-onion-services=Onion Services
|
||||
onboarding.tour-i2p-onion-services.title=Be extra protected.
|
||||
onboarding.tour-i2p-onion-services.description=Onion services are sites that end with a .onion that provide extra protections to publishers and visii2ps, including added safeguards against censorship. Onion services allow anyone to provide content and services anonymously. Click below to visit the DuckDuckGo onion site.
|
||||
onboarding.tour-i2p-onion-services.button=Visit an Onion
|
||||
onboarding.tour-i2p-onion-services.next-button=Done
|
||||
# This slide is not currently use in the I2P Browser Onboarding slideshow
|
||||
#onboarding.tour-i2p-onion-services=Hidden Services
|
||||
#onboarding.tour-i2p-onion-services.title=Be extra protected.
|
||||
#onboarding.tour-i2p-onion-services.description=Hidden services are sites that end with a .i2p that provide extra protections to publishers and visitors, including added safeguards against censorship. Onion services allow anyone to provide content and services anonymously.
|
||||
#onboarding.tour-i2p-onion-services.button=Visit an Hidden
|
||||
#onboarding.tour-i2p-onion-services.next-button=Done
|
||||
# End
|
||||
|
||||
onboarding.overlay-icon-tooltip-updated2=See what's new\nin %S
|
||||
onboarding.tour-i2p-update.prefix-new=New
|
||||
|
@ -15,7 +15,7 @@ i2pbutton.panel.label.disabled = I2P Disabled
|
||||
i2pbutton.panel.label.enabled = I2P Enabled
|
||||
extensions.i2pbutton@geti2p.net.description = i2pbutton provides a button to configure I2P settings and quickly and easily clear private browsing data.
|
||||
i2pbutton.popup.external.title = Download an external file type?
|
||||
i2pbutton.popup.external.app = Tor Browser cannot display this file. You will need to open it with another application.\n\n
|
||||
i2pbutton.popup.external.app = I2P Browser cannot display this file. You will need to open it with another application.\n\n
|
||||
i2pbutton.popup.external.note = Some types of files can cause applications to connect to the Internet without using I2P.\n\n
|
||||
i2pbutton.popup.external.suggest = To be safe, you should only open downloaded files while offline, or use a I2P Live CD such as Tails.\n
|
||||
i2pbutton.popup.launch = Download file
|
||||
@ -24,12 +24,12 @@ i2pbutton.popup.dontask = Automatically download files from now on
|
||||
i2pbutton.popup.no_newnym = i2pbutton cannot safely give you a new identity. It does not have access to the I2P Control Port.\n\nAre you running I2P Browser Bundle?
|
||||
i2pbutton.security_settings.menu.title = Security Settings
|
||||
i2pbutton.title.prompt_i2pbrowser = Important i2pbutton Information
|
||||
i2pbutton.popup.prompt_i2pbrowser = i2pbutton works differently now: you can't turn it off any more.\n\nWe made this change because it isn't safe to use i2pbutton in a browser that's also used for non-Tor browsing. There were too many bugs there that we couldn't fix any other way.\n\nIf you want to keep using Firefox normally, you should uninstall i2pbutton and download Tor Browser Bundle. The privacy properties of Tor Browser are also superior to those of normal Firefox, even when Firefox is used with i2pbutton.\n\nTo remove i2pbutton, go to Tools->Addons->Extensions and then click the Remove button next to i2pbutton.
|
||||
i2pbutton.popup.prompt_i2pbrowser = i2pbutton works differently now: you can't turn it off any more.\n\nWe made this change because it isn't safe to use i2pbutton in a browser that's also used for non-I2P browsing. There were too many bugs there that we couldn't fix any other way.\n\nIf you want to keep using Firefox normally, you should uninstall i2pbutton and download I2P Browser Bundle. The privacy properties of I2P Browser are also superior to those of normal Firefox, even when Firefox is used with i2pbutton.\n\nTo remove i2pbutton, go to Tools->Addons->Extensions and then click the Remove button next to i2pbutton.
|
||||
i2pbutton.popup.short_i2pbrowser = Important i2pbutton Information!\n\ni2pbutton is now always enabled.\n\nClick on the i2pbutton for more information.
|
||||
|
||||
i2pbutton.popup.confirm_plugins = Plugins such as Flash can harm your privacy and anonymity.\n\nThey can also bypass I2P to reveal your current location and IP address.\n\nAre you sure you want to enable plugins?\n\n
|
||||
i2pbutton.popup.never_ask_again = Never ask me again
|
||||
i2pbutton.popup.confirm_newnym = Tor Browser will close all windows and tabs. All website sessions will be lost.\n\nRestart I2P Browser now to reset your identity?\n\n
|
||||
i2pbutton.popup.confirm_newnym = I2P Browser will close all windows and tabs. All website sessions will be lost.\n\nRestart I2P Browser now to reset your identity?\n\n
|
||||
|
||||
i2pbutton.maximize_warning = Maximizing I2P Browser can allow websites to determine your monitor size, which can be used to track you. We recommend that you leave I2P Browser windows in their original default size.
|
||||
|
||||
|
@ -72,3 +72,6 @@ body:not([i2pconsoleon]) .hideIfI2PConsoleOff {
|
||||
display: none;
|
||||
}
|
||||
|
||||
ul {
|
||||
margin-left: 2rem;
|
||||
}
|
||||
|
124
src/components/external-app-blocker.js
Normal file
124
src/components/external-app-blocker.js
Normal file
@ -0,0 +1,124 @@
|
||||
const Cc = Components.classes;
|
||||
const Ci = Components.interfaces;
|
||||
const Cr = Components.results;
|
||||
const Cu = Components.utils;
|
||||
|
||||
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
Cu.import("resource://gre/modules/Services.jsm");
|
||||
Cu.import("resource://gre/modules/SharedPromptUtils.jsm");
|
||||
|
||||
// Module specific constants
|
||||
const kMODULE_NAME = "I2pbutton External App Handler";
|
||||
const kCONTRACT_ID = "@geti2p.net/i2pbutton-extAppBlocker;1";
|
||||
const kMODULE_CID = Components.ID("3da0269f-fc29-4e9e-a678-c3b1cafcf13f");
|
||||
|
||||
const kInterfaces = [Ci.nsIObserver, Ci.nsIClassInfo];
|
||||
|
||||
function ExternalAppBlocker() {
|
||||
this.logger = Cc["@geti2p.net/i2pbutton-logger;1"]
|
||||
.getService(Ci.nsISupports).wrappedJSObject;
|
||||
this.logger.log(3, "Component Load 0: New ExternalAppBlocker.");
|
||||
}
|
||||
|
||||
ExternalAppBlocker.prototype =
|
||||
{
|
||||
_helperAppLauncher: undefined,
|
||||
|
||||
QueryInterface: XPCOMUtils.generateQI([Ci.nsISupports, Ci.nsIObserver,
|
||||
Ci.nsIHelperAppWarningDialog]),
|
||||
|
||||
// make this an nsIClassInfo object
|
||||
flags: Ci.nsIClassInfo.DOM_OBJECT,
|
||||
classDescription: kMODULE_NAME,
|
||||
contractID: kCONTRACT_ID,
|
||||
classID: kMODULE_CID,
|
||||
|
||||
// method of nsIClassInfo
|
||||
getInterfaces: function(count) {
|
||||
count.value = kInterfaces.length;
|
||||
return kInterfaces;
|
||||
},
|
||||
|
||||
// method of nsIClassInfo
|
||||
getHelperForLanguage: function(count) { return null; },
|
||||
|
||||
// method of nsIHelperAppWarningDialog
|
||||
maybeShow: function(aLauncher, aWindowContext)
|
||||
{
|
||||
// Hold a reference to the object that called this component. This is
|
||||
// important not just because we need to later invoke the
|
||||
// continueRequest() or cancelRequest() callback on aLauncher, but also
|
||||
// so that the launcher object (which is a reference counted object) is
|
||||
// not released too soon.
|
||||
this._helperAppLauncher = aLauncher;
|
||||
|
||||
if (!Services.prefs.getBoolPref("extensions.i2pbutton.launch_warning")) {
|
||||
this._helperAppLauncher.continueRequest();
|
||||
return;
|
||||
}
|
||||
|
||||
this._showPrompt(aWindowContext);
|
||||
},
|
||||
|
||||
/*
|
||||
* The _showPrompt() implementation uses some XUL and JS that is part of the
|
||||
* browser's confirmEx() implementation. Specifically, _showPrompt() depends
|
||||
* on chrome://global/content/commonDialog.xul as well as some of the code
|
||||
* in resource://gre/modules/SharedPromptUtils.jsm.
|
||||
*/
|
||||
_showPrompt: function(aWindowContext) {
|
||||
let parentWin;
|
||||
try {
|
||||
parentWin = aWindowContext.getInterface(Ci.nsIDOMWindow);
|
||||
} catch (e) {
|
||||
parentWin = Services.wm.getMostRecentWindow("navigator:browser");
|
||||
}
|
||||
|
||||
let title = parentWin.i2pbutton_get_property_string("i2pbutton.popup.external.title");
|
||||
let app = parentWin.i2pbutton_get_property_string("i2pbutton.popup.external.app");
|
||||
let note = parentWin.i2pbutton_get_property_string("i2pbutton.popup.external.note");
|
||||
let suggest = parentWin.i2pbutton_get_property_string("i2pbutton.popup.external.suggest");
|
||||
let launch = parentWin.i2pbutton_get_property_string("i2pbutton.popup.launch");
|
||||
let cancel = parentWin.i2pbutton_get_property_string("i2pbutton.popup.cancel");
|
||||
let dontask = parentWin.i2pbutton_get_property_string("i2pbutton.popup.dontask");
|
||||
|
||||
let args = {
|
||||
promptType: "confirmEx",
|
||||
title: title,
|
||||
text: app+note+suggest+" ",
|
||||
checkLabel: dontask,
|
||||
checked: false,
|
||||
ok: false,
|
||||
button0Label: launch,
|
||||
button1Label: cancel,
|
||||
defaultButtonNum: 1, // Cancel
|
||||
buttonNumClicked: 1, // Cancel
|
||||
enableDelay: true,
|
||||
};
|
||||
|
||||
let propBag = PromptUtils.objectToPropBag(args);
|
||||
let uri = "chrome://global/content/commonDialog.xul";
|
||||
let promptWin = Services.ww.openWindow(parentWin, uri, "_blank",
|
||||
"centerscreen,chrome,titlebar", propBag);
|
||||
promptWin.addEventListener("load", aEvent => {
|
||||
promptWin.addEventListener("unload", aEvent => {
|
||||
PromptUtils.propBagToObject(propBag, args);
|
||||
|
||||
if (0 == args.buttonNumClicked) {
|
||||
// Save the checkbox value and tell the browser's external helper app
|
||||
// module about the user's choice.
|
||||
if (args.checked) {
|
||||
Services.prefs.setBoolPref("extensions.i2pbutton.launch_warning",
|
||||
false);
|
||||
}
|
||||
|
||||
this._helperAppLauncher.continueRequest();
|
||||
} else {
|
||||
this._helperAppLauncher.cancelRequest(Cr.NS_BINDING_ABORTED);
|
||||
}
|
||||
}, false);
|
||||
}, false);
|
||||
},
|
||||
};
|
||||
|
||||
var NSGetFactory = XPCOMUtils.generateNSGetFactory([ExternalAppBlocker]);
|
@ -9,12 +9,11 @@ const Ci = Components.interfaces;
|
||||
const Cu = Components.utils;
|
||||
|
||||
function IBI2PCheckService() {
|
||||
this._logger = Cc["@geti2p.net/i2pbutton-logger;1"]
|
||||
.getService(Ci.nsISupports).wrappedJSObject;
|
||||
this._logger.log(3, "I2pbutton I2P Check Service initialized");
|
||||
this._logger = Cc["@geti2p.net/i2pbutton-logger;1"].getService(Ci.nsISupports).wrappedJSObject
|
||||
this._logger.info("I2pbutton I2P Check Service initialized")
|
||||
|
||||
this._statusOfI2PCheck = this.kCheckNotInitiated;
|
||||
this.wrappedJSObject = this;
|
||||
this._statusOfI2PCheck = this.kCheckNotInitiated
|
||||
this.wrappedJSObject = this
|
||||
}
|
||||
|
||||
IBI2PCheckService.prototype =
|
||||
@ -89,25 +88,27 @@ IBI2PCheckService.prototype =
|
||||
},
|
||||
|
||||
_createRequest: function(url, aAsync, mimetype) {
|
||||
Cu.importGlobalProperties(["XMLHttpRequest"]);
|
||||
let req = new XMLHttpRequest();
|
||||
req.open('GET', url, aAsync);
|
||||
req.channel.loadFlags |= Ci.nsIRequest.LOAD_BYPASS_CACHE;
|
||||
req.overrideMimeType(mimetype);
|
||||
req.timeout = 120000; // Wait at most two minutes for a response.
|
||||
return req;
|
||||
Cu.importGlobalProperties(["XMLHttpRequest"])
|
||||
let req = new XMLHttpRequest()
|
||||
req.open('GET', url, aAsync)
|
||||
req.channel.loadFlags |= Ci.nsIRequest.LOAD_BYPASS_CACHE
|
||||
req.overrideMimeType(mimetype)
|
||||
req.timeout = 120000 // Wait at most two minutes for a response.
|
||||
return req
|
||||
},
|
||||
|
||||
createCheckConsoleRequest: function(aAsync)
|
||||
{
|
||||
let url = 'http://localhost:7657/netdb?r=.';
|
||||
return this._createRequest(url, aAsync, "text/html");
|
||||
let prefs = Cc["@mozilla.org/preferences-service;1"].getService(Ci.nsIPrefBranch)
|
||||
let port = prefs.getIntPref("extensions.i2pbutton.console_port_i2pj", 17657)
|
||||
let url = `http://localhost:${port}/netdb?r=.`
|
||||
return this._createRequest(url, aAsync, "text/html")
|
||||
},
|
||||
|
||||
createCheckProxyRequest: function(aAsync) {
|
||||
let prefs = Cc["@mozilla.org/preferences-service;1"].getService(Ci.nsIPrefBranch);
|
||||
let url = prefs.getCharPref("extensions.i2pbutton.test_url");
|
||||
return this._createRequest(url, aAsync, "application/json");
|
||||
let prefs = Cc["@mozilla.org/preferences-service;1"].getService(Ci.nsIPrefBranch)
|
||||
let url = prefs.getCharPref("extensions.i2pbutton.test_url")
|
||||
return this._createRequest(url, aAsync, "application/json")
|
||||
},
|
||||
|
||||
parseCheckConsoleResponse: function(aReq)
|
||||
@ -115,7 +116,7 @@ IBI2PCheckService.prototype =
|
||||
let ret = 0;
|
||||
if(aReq.status == 200) {
|
||||
if(!aReq.response) {
|
||||
this._logger.log(5, "Check failed! Not text/html!");
|
||||
this._logger.log(5, "Check failed! Not text/html!")
|
||||
this._statusOfI2PCheck = this.kCheckFailed
|
||||
ret = 1;
|
||||
} else {
|
||||
@ -141,7 +142,7 @@ IBI2PCheckService.prototype =
|
||||
if(aReq.status == 200) {
|
||||
console.log(aReq)
|
||||
if(!aReq.response) {
|
||||
this._logger.log(5, "Check failed! Not text/html!");
|
||||
this._logger.log(5, "Check failed! Not text/html!")
|
||||
this._statusOfI2PCheck = this.kCheckFailed
|
||||
ret = 1;
|
||||
} else {
|
||||
@ -182,5 +183,5 @@ IBI2PCheckService.prototype =
|
||||
}
|
||||
};
|
||||
|
||||
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
var NSGetFactory = XPCOMUtils.generateNSGetFactory([IBI2PCheckService]);
|
||||
Cu.import("resource://gre/modules/XPCOMUtils.jsm")
|
||||
var NSGetFactory = XPCOMUtils.generateNSGetFactory([IBI2PCheckService])
|
||||
|
568
src/components/i2p-router-process.js
Normal file
568
src/components/i2p-router-process.js
Normal file
@ -0,0 +1,568 @@
|
||||
// vim: set sw=2 sts=2 ts=8 et syntax=javascript:
|
||||
|
||||
const Cc = Components.classes
|
||||
const Ci = Components.interfaces
|
||||
const Cr = Components.results
|
||||
const Cu = Components.utils
|
||||
|
||||
// ctypes can be disabled at build time
|
||||
try { Cu.import("resource://gre/modules/ctypes.jsm") } catch(e) {}
|
||||
Cu.import("resource://gre/modules/XPCOMUtils.jsm")
|
||||
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "LauncherUtil", "resource://i2pbutton/modules/launcher-util.jsm")
|
||||
|
||||
//let observerService = Cc["@mozilla.org/observer-service;1"].getService(Ci.nsIObserverService)
|
||||
|
||||
function I2PProcessService()
|
||||
{
|
||||
this._logger = Cc["@geti2p.net/i2pbutton-logger;1"].getService(Ci.nsISupports).wrappedJSObject
|
||||
this._config_checker = Cc["@geti2p.net/i2pbutton-router-config-mgr;1"].getService(Ci.nsISupports).wrappedJSObject
|
||||
this._logger.log(3, "I2pbutton I2P Router Process Service initialized")
|
||||
this.wrappedJSObject = this
|
||||
}
|
||||
|
||||
I2PProcessService.prototype =
|
||||
{
|
||||
kContractID : "@geti2p.net/i2pbutton-process-service;1",
|
||||
kServiceName : "I2P Launcher Process Service",
|
||||
kClassID: Components.ID("{f77babef-dead-b00b-beff-babe6c9afda7}"),
|
||||
kI2PLauncherExtPath: "i2pbutton@geti2p.net", // This could vary.
|
||||
|
||||
kPrefPromptAtStartup: "extensions.i2pbutton.prompt_at_startup",
|
||||
|
||||
kWizardProgressPageID: "progress",
|
||||
|
||||
kInitialControlConnDelayMS: 25,
|
||||
kMaxControlConnRetryMS: 2000, // Retry at least every 2 seconds.
|
||||
kControlConnTimeoutMS: 5*60*1000, // Wait at most 5 minutes for i2p to start.
|
||||
|
||||
kStatusUnknown: 0, // I2P process status.
|
||||
kStatusStarting: 1,
|
||||
kStatusRunning: 2,
|
||||
kStatusExited: 3, // Exited or failed to start.
|
||||
|
||||
kI2PImplJava: "i2pj",
|
||||
kI2PImplCpp: "i2pd",
|
||||
|
||||
kI2PProcessDidNotStartTopic: "I2PProcessDidNotStart",
|
||||
kI2PBootstrapErrorTopic: "I2PBootstrapError",
|
||||
|
||||
// nsISupports implementation.
|
||||
QueryInterface: function(aIID)
|
||||
{
|
||||
if (!aIID.equals(Ci.nsISupports) &&
|
||||
!aIID.equals(Ci.nsIFactory) &&
|
||||
!aIID.equals(Ci.nsIObserver) &&
|
||||
!aIID.equals(Ci.nsIClassInfo))
|
||||
{
|
||||
throw Cr.NS_ERROR_NO_INTERFACE;
|
||||
}
|
||||
|
||||
return this;
|
||||
},
|
||||
|
||||
// nsIFactory implementation.
|
||||
createInstance: function(aOuter, aIID)
|
||||
{
|
||||
if (null != aOuter)
|
||||
throw Cr.NS_ERROR_NO_AGGREGATION;
|
||||
|
||||
return this.QueryInterface(aIID);
|
||||
},
|
||||
|
||||
init: function(aWindow) {},
|
||||
uninit: function unit() {},
|
||||
|
||||
lockFactory: function(aDoLock) {},
|
||||
|
||||
// nsIObserver implementation.
|
||||
observe: function(aSubject, aTopic, aParam)
|
||||
{
|
||||
const kUserQuitTopic = "I2PUserRequestedQuit"
|
||||
const kBootstrapStatusTopic = "I2PBootstrapStatus"
|
||||
|
||||
if (!this.mObsSvc)
|
||||
{
|
||||
this.mObsSvc = Cc["@mozilla.org/observer-service;1"].getService(Ci.nsIObserverService)
|
||||
}
|
||||
|
||||
if ("profile-after-change" == aTopic)
|
||||
{
|
||||
this.mObsSvc.addObserver(this, "quit-application-granted", false)
|
||||
this.mObsSvc.addObserver(this, kUserQuitTopic, false)
|
||||
this.mObsSvc.addObserver(this, kBootstrapStatusTopic, false)
|
||||
|
||||
|
||||
const self = this
|
||||
this._logger.log(3, 'Checking if a console is already up (an router already running)')
|
||||
this._isConsoleRunning(function(res) {
|
||||
if (res!=4) {
|
||||
// Yes, 4 is success
|
||||
let canStartPromise = this._config_checker.ensure_config()
|
||||
canStartPromise.then(() => {
|
||||
self._logger.log(3, 'Starting the router')
|
||||
self.I2PStartAndControlI2P(true)
|
||||
})
|
||||
} else {
|
||||
self._logger.log(3, 'Already found a router, won\'t launch.')
|
||||
}
|
||||
})
|
||||
}
|
||||
else if ("quit-application-granted" == aTopic)
|
||||
{
|
||||
this.mIsQuitting = true;
|
||||
this.mObsSvc.removeObserver(this, "quit-application-granted");
|
||||
this.mObsSvc.removeObserver(this, kUserQuitTopic);
|
||||
this.mObsSvc.removeObserver(this, kBootstrapStatusTopic);
|
||||
if (this.mI2PProcess)
|
||||
{
|
||||
let prefs = Cc["@mozilla.org/preferences-service;1"].getService(Ci.nsIPrefBranch)
|
||||
let shouldKillRouter = prefs.getBoolPref("extensions.i2pbutton.kill_router_on_exit", true)
|
||||
if (shouldKillRouter) this.mI2PProcess.kill()
|
||||
this._logger.log(4, "Disconnecting from i2p process (pid " + this.mI2PProcess.pid + ")");
|
||||
this.mI2PProcess = null;
|
||||
}
|
||||
}
|
||||
else if (("process-failed" == aTopic) || ("process-finished" == aTopic))
|
||||
{
|
||||
if (this.mControlConnTimer)
|
||||
{
|
||||
this.mControlConnTimer.cancel();
|
||||
this.mControlConnTimer = null;
|
||||
}
|
||||
|
||||
this.mI2PProcess = null;
|
||||
this.mI2PProcessStatus = this.kStatusExited;
|
||||
this.mIsBootstrapDone = false;
|
||||
|
||||
this.mObsSvc.notifyObservers(null, "I2PProcessExited", null);
|
||||
|
||||
if (this.mIsQuitting)
|
||||
{
|
||||
LauncherUtil.cleanupTempDirectories();
|
||||
}
|
||||
else
|
||||
{
|
||||
var defaultBtnLabel = LauncherUtil.getLocalizedString("restart_i2p");
|
||||
var cancelBtnLabel = "OK";
|
||||
try
|
||||
{
|
||||
const kSysBundleURI = "chrome://global/locale/commonDialogs.properties";
|
||||
var sysBundle = Cc["@mozilla.org/intl/stringbundle;1"].getService(Ci.nsIStringBundleService).createBundle(kSysBundleURI);
|
||||
cancelBtnLabel = sysBundle.GetStringFromName(cancelBtnLabel);
|
||||
} catch(e) {}
|
||||
|
||||
this._logger.log(3, 'The router stopped..')
|
||||
|
||||
/*if (LauncherUtil.showConfirm(null, s, defaultBtnLabel, cancelBtnLabel) && !this.mIsQuitting)
|
||||
{
|
||||
this.I2PStartAndControlI2P(false);
|
||||
}*/
|
||||
}
|
||||
}
|
||||
else if ("timer-callback" == aTopic)
|
||||
{
|
||||
if (aSubject == this.mControlConnTimer)
|
||||
{
|
||||
this.mObsSvc.notifyObservers(null, "I2PProcessIsReady", null)
|
||||
}
|
||||
} else if (kBootstrapStatusTopic == aTopic) {
|
||||
//this._processBootstrapStatus(aSubject.wrappedJSObject);
|
||||
} else if (kUserQuitTopic == aTopic) {
|
||||
this.mQuitSoon = true;
|
||||
}
|
||||
},
|
||||
|
||||
canUnload: function(aCompMgr) { return true; },
|
||||
|
||||
// nsIClassInfo implementation.
|
||||
getInterfaces: function(aCount)
|
||||
{
|
||||
var iList = [ Ci.nsISupports,
|
||||
Ci.nsIFactory,
|
||||
Ci.nsIObserver,
|
||||
Ci.nsIClassInfo ];
|
||||
aCount.value = iList.length;
|
||||
return iList;
|
||||
},
|
||||
|
||||
getHelperForLanguage: function (aLanguage) { return null; },
|
||||
|
||||
contractID: this.kContractID,
|
||||
classDescription: this.kServiceName,
|
||||
classID: this.kClassID,
|
||||
flags: Ci.nsIClassInfo.SINGLETON,
|
||||
|
||||
classInfo : XPCOMUtils.generateCI({
|
||||
classID: this.kClassID,
|
||||
contractID: this.kContractID,
|
||||
classDescription: this.kServiceName,
|
||||
interfaces: [
|
||||
Ci.nsISupports,
|
||||
Ci.nsIFactory,
|
||||
Ci.nsIObserver,
|
||||
Ci.nsIClassInfo
|
||||
],
|
||||
flags: Ci.nsIClassInfo.SINGLETON
|
||||
}),
|
||||
|
||||
|
||||
// Hack to get us registered early to observe recovery
|
||||
_xpcom_categories: [{category:"profile-after-change"}],
|
||||
|
||||
|
||||
// Public Properties and Methods ///////////////////////////////////////////
|
||||
get I2PProcessStatus()
|
||||
{
|
||||
return this.mI2PProcessStatus;
|
||||
},
|
||||
|
||||
get I2PIsBootstrapDone()
|
||||
{
|
||||
return this.mIsBootstrapDone;
|
||||
},
|
||||
|
||||
get I2PBootstrapErrorOccurred()
|
||||
{
|
||||
|
||||
},
|
||||
|
||||
I2PStartAndControlI2P: function()
|
||||
{
|
||||
this._startI2P()
|
||||
let isRunningI2P = (this.mI2PProcessStatus == this.kStatusStarting) || (this.mI2PProcessStatus == this.kStatusRunning)
|
||||
this._controlI2P(isRunningI2P)
|
||||
},
|
||||
|
||||
I2PClearBootstrapError: function()
|
||||
{
|
||||
this.mBootstrapErrorOccurred = false
|
||||
this.mLastI2PWarningPhase = null
|
||||
this.mLastI2PWarningReason = null
|
||||
},
|
||||
|
||||
// Private Member Variables ////////////////////////////////////////////////
|
||||
mI2PProcessStatus: 0, // kStatusUnknown
|
||||
mIsBootstrapDone: false,
|
||||
mBootstrapErrorOccurred: false,
|
||||
mIsQuitting: false,
|
||||
mObsSvc: null,
|
||||
mI2PUseImpl: this.kI2PImplJava,
|
||||
mI2PProcess: null, // nsIProcess
|
||||
mI2PProcessStartTime: null, // JS Date.now()
|
||||
mControlConnTimer: null,
|
||||
mControlConnDelayMS: 0,
|
||||
mQuitSoon: false, // Quit was requested by the user; do so soon.
|
||||
mLastI2PWarningPhase: null,
|
||||
mLastI2PWarningReason: null,
|
||||
mDefaultPreferencesAreLoaded: false,
|
||||
|
||||
// Private Methods /////////////////////////////////////////////////////////
|
||||
_startI2P: function()
|
||||
{
|
||||
this.mI2PProcessStatus = this.kStatusUnknown;
|
||||
|
||||
// Avoid starting the router if extensions.i2pbutton.start_i2p is set to false.
|
||||
let prefs = Cc["@mozilla.org/preferences-service;1"].getService(Ci.nsIPrefBranch)
|
||||
let shouldStart = prefs.getBoolPref("extensions.i2pbutton.start_i2p")
|
||||
if (!shouldStart) return
|
||||
|
||||
try
|
||||
{
|
||||
// Ideally, we would cd to the Firefox application directory before
|
||||
// starting tor (but we don't know how to do that). Instead, we
|
||||
// rely on the TBB launcher to start Firefox from the right place.
|
||||
|
||||
// Get the I2P data directory first so it is created before we try to
|
||||
// construct paths to files that will be inside it.
|
||||
let dataDir = LauncherUtil.getI2PConfigPath(true)
|
||||
let exeFile = LauncherUtil.getI2PFile("i2p", false)
|
||||
this._logger.log(3, `Datadir => ${dataDir.path}\nExeFile => ${exeFile.path}`)
|
||||
|
||||
var detailsKey;
|
||||
if (!exeFile)
|
||||
detailsKey = "i2p_missing";
|
||||
else if (!dataDir)
|
||||
detailsKey = "datadir_missing";
|
||||
|
||||
if (detailsKey)
|
||||
{
|
||||
var details = LauncherUtil.getLocalizedString(detailsKey);
|
||||
var key = "unable_to_start_i2p";
|
||||
var err = LauncherUtil.getFormattedLocalizedString(key, [details], 1);
|
||||
this._notifyUserOfError(err, null, this.kI2PProcessDidNotStartTopic);
|
||||
return;
|
||||
}
|
||||
|
||||
let args = LauncherUtil.getRouterDefaultArgs()
|
||||
|
||||
// Set an environment variable that points to the I2P data directory.
|
||||
// This is used by meek-client-torbrowser to find the location for
|
||||
// the meek browser profile.
|
||||
let env = Cc["@mozilla.org/process/environment;1"].getService(Ci.nsIEnvironment)
|
||||
env.set("I2P_BROWSER_I2P_DATA_DIR", dataDir.path)
|
||||
|
||||
// On Windows, prepend the I2P program directory to PATH. This is
|
||||
// needed so that pluggable transports can find OpenSSL DLLs, etc.
|
||||
// See https://trac.torproject.org/projects/tor/ticket/10845
|
||||
if (LauncherUtil.isWindows)
|
||||
{
|
||||
var path = exeFile.parent.path
|
||||
if (env.exists("PATH"))
|
||||
path += ";" + env.get("PATH")
|
||||
env.set("PATH", path)
|
||||
}
|
||||
|
||||
this.mI2PProcessStatus = this.kStatusStarting
|
||||
|
||||
this._logger.log(3, `Trying to start with ${args}`)
|
||||
|
||||
this._logger.log(2, "Starting " + exeFile.path)
|
||||
var p = Cc["@mozilla.org/process/util;1"].createInstance(Ci.nsIProcess)
|
||||
p.init(exeFile)
|
||||
|
||||
for (var i = 0; i < args.length; ++i)
|
||||
this._logger.log(2, " " + args[i])
|
||||
|
||||
// Possible fix for Windows and cmd.exe window spawn.
|
||||
p.startHidden = true
|
||||
p.noShell = true
|
||||
|
||||
p.runwAsync(args, args.length, this, false)
|
||||
this.mI2PProcess = p
|
||||
this.mI2PProcessStartTime = Date.now()
|
||||
}
|
||||
catch (e)
|
||||
{
|
||||
this.mI2PProcessStatus = this.kStatusExited
|
||||
//var s = LauncherUtil.getLocalizedString("i2p_failed_to_start");
|
||||
//this._notifyUserOfError(s, null, this.kI2PProcessDidNotStartTopic);
|
||||
this._logger.log(4, "_startI2P error: ", e)
|
||||
}
|
||||
}, // _startI2P()
|
||||
|
||||
_isConsoleRunning: function(callback) {
|
||||
let checkSvc = Cc["@geti2p.net/i2pbutton-i2pCheckService;1"].getService(Ci.nsISupports).wrappedJSObject
|
||||
let req = checkSvc.createCheckConsoleRequest(true);
|
||||
req.onreadystatechange = function(event) {
|
||||
if (req.readyState === 4) {
|
||||
// Done
|
||||
let result = checkSvc.parseCheckConsoleResponse(req)
|
||||
callback(result)
|
||||
}
|
||||
}
|
||||
req.send(null)
|
||||
},
|
||||
|
||||
_controlI2P: function(aIsRunningI2P)
|
||||
{
|
||||
|
||||
try
|
||||
{
|
||||
if (aIsRunningI2P)
|
||||
this._monitorI2PProcessStartup();
|
||||
|
||||
// If the user pressed "Quit" within settings/progress, exit.
|
||||
if (this.mQuitSoon)
|
||||
this._quitApp();
|
||||
}
|
||||
catch (e)
|
||||
{
|
||||
this.mI2PProcessStatus = this.kStatusExited;
|
||||
var s = LauncherUtil.getLocalizedString("i2p_control_failed");
|
||||
this._notifyUserOfError(s, null, null);
|
||||
this._logger.log(4, "_controlI2P error: ", e);
|
||||
}
|
||||
}, // controlI2P()
|
||||
|
||||
_quitApp: function()
|
||||
{
|
||||
try
|
||||
{
|
||||
this.mQuitSoon = false;
|
||||
if (this.mI2PProcess != null) {
|
||||
this.mI2PProcess.kill()
|
||||
}
|
||||
|
||||
var asSvc = Cc["@mozilla.org/toolkit/app-startup;1"].getService(Ci.nsIAppStartup);
|
||||
var flags = asSvc.eAttemptQuit;
|
||||
asSvc.quit(flags);
|
||||
}
|
||||
catch (e)
|
||||
{
|
||||
this._logger.log(4, "unable to quit", e);
|
||||
}
|
||||
},
|
||||
|
||||
_monitorI2PProcessStartup: function()
|
||||
{
|
||||
this.mControlConnDelayMS = this.kInitialControlConnDelayMS
|
||||
this.mControlConnTimer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer)
|
||||
this.mControlConnTimer.init(this, this.mControlConnDelayMS, this.mControlConnTimer.TYPE_ONE_SHOT)
|
||||
},
|
||||
|
||||
_notifyUserOfError: function(aMessage, aDetails, aNotifyTopic)
|
||||
{
|
||||
let errorObj = { handled: false, message: aMessage };
|
||||
if (aDetails)
|
||||
errorObj.details = aDetails;
|
||||
|
||||
if (aNotifyTopic)
|
||||
{
|
||||
// Give other code an opportunity to handle this error, e.g., if the
|
||||
// network settings window is open, errors are displayed using an
|
||||
// overlaid XUL element.
|
||||
errorObj.wrappedJSObject = errorObj;
|
||||
this.mObsSvc.notifyObservers(errorObj, aNotifyTopic, null);
|
||||
}
|
||||
|
||||
if (!errorObj.handled)
|
||||
{
|
||||
let msg = aMessage;
|
||||
if (aDetails)
|
||||
msg += "\n\n" + aDetails;
|
||||
I2PLauncherUtil.showAlert(null, msg);
|
||||
}
|
||||
},
|
||||
|
||||
_getpid: function()
|
||||
{
|
||||
// Use nsIXULRuntime.processID if it is available.
|
||||
var pid = 0;
|
||||
|
||||
try
|
||||
{
|
||||
var xreSvc = Cc["@mozilla.org/xre/app-info;1"].getService(Ci.nsIXULRuntime);
|
||||
pid = xreSvc.processID;
|
||||
}
|
||||
catch (e)
|
||||
{
|
||||
this._logger.log(2, "failed to get process ID via XUL runtime:", e);
|
||||
}
|
||||
|
||||
// Try libc.getpid() via js-ctypes.
|
||||
if (!pid) try
|
||||
{
|
||||
var getpid;
|
||||
if (LauncherUtil.isMac) {
|
||||
var libc = ctypes.open("libc.dylib")
|
||||
getpid = libc.declare("getpid", ctypes.default_abi, ctypes.uint32_t)
|
||||
} else if (LauncherUtil.isWindows) {
|
||||
var libc = ctypes.open("Kernel32.dll")
|
||||
getpid = libc.declare("GetCurrentProcessId", ctypes.default_abi, ctypes.uint32_t)
|
||||
} else {// Linux and others.
|
||||
var libc;
|
||||
try {
|
||||
libc = ctypes.open("libc.so.6")
|
||||
} catch(e) {
|
||||
libc = ctypes.open("libc.so")
|
||||
}
|
||||
|
||||
getpid = libc.declare("getpid", ctypes.default_abi, ctypes.int)
|
||||
}
|
||||
|
||||
pid = getpid()
|
||||
} catch(e) {
|
||||
this._logger.log(4, "unable to get process ID: ", e)
|
||||
}
|
||||
|
||||
return pid;
|
||||
},
|
||||
|
||||
// Returns undefined if file contents could not be read.
|
||||
_getFileAsString: function(aFile)
|
||||
{
|
||||
let str = ""
|
||||
let inStream;
|
||||
try
|
||||
{
|
||||
let fis = Cc['@mozilla.org/network/file-input-stream;1'].createInstance(Ci.nsIFileInputStream);
|
||||
const kOpenFlagsReadOnly = 0x01;
|
||||
fis.init(aFile, kOpenFlagsReadOnly, 0, 0);
|
||||
inStream = Cc["@mozilla.org/intl/converter-input-stream;1"].createInstance(Ci.nsIConverterInputStream);
|
||||
inStream.init(fis, "UTF-8", 0, Ci.nsIConverterInputStream.DEFAULT_REPLACEMENT_CHARACTER);
|
||||
const kReadSize = 0xffffffff; // PR_UINT32_MAX
|
||||
while (true)
|
||||
{
|
||||
let outStr = {};
|
||||
let count = inStream.readString(kReadSize, outStr);
|
||||
if (count == 0)
|
||||
break;
|
||||
|
||||
str += outStr.value;
|
||||
}
|
||||
}
|
||||
catch (e)
|
||||
{
|
||||
this._logger.log(5, "_getFileAsString " + aFile.path + " error: " + e);
|
||||
str = undefined;
|
||||
}
|
||||
|
||||
if (inStream)
|
||||
inStream.close();
|
||||
|
||||
return str;
|
||||
},
|
||||
|
||||
// After making a backup, replace the contents of aFile with aStr.
|
||||
// Returns true if successful.
|
||||
_overwriteFile: function(aFile, aStr)
|
||||
{
|
||||
let backupFile;
|
||||
|
||||
try
|
||||
{
|
||||
// Convert the data to UTF-8.
|
||||
let conv = Cc["@mozilla.org/intl/scriptableunicodeconverter"].createInstance(Ci.nsIScriptableUnicodeConverter);
|
||||
conv.charset = "UTF-8";
|
||||
let data = conv.ConvertFromUnicode(aStr) + conv.Finish();
|
||||
|
||||
// Rename the file to .bak (we avoid .orig because tor uses it). This
|
||||
// backup will be left on disk so the user can recover the original
|
||||
// file contents.
|
||||
backupFile = aFile.clone();
|
||||
backupFile.leafName += ".bak";
|
||||
backupFile.createUnique(Ci.nsIFile.NORMAL_FILE_TYPE, aFile.permissions);
|
||||
aFile.renameTo(null, backupFile.leafName);
|
||||
this._logger.log(3, "created backup of " + aFile.leafName + " in " + backupFile.leafName);
|
||||
|
||||
// Write the new data to the file.
|
||||
let stream = Cc["@mozilla.org/network/safe-file-output-stream;1"].createInstance(Ci.nsIFileOutputStream);
|
||||
stream.init(aFile, 0x02 | 0x08 | 0x20, /* WRONLY CREATE TRUNCATE */
|
||||
0o600, 0);
|
||||
stream.write(data, data.length);
|
||||
stream.QueryInterface(Ci.nsISafeOutputStream).finish();
|
||||
}
|
||||
catch (e)
|
||||
{
|
||||
// Report an error and try to recover by renaming the backup to the
|
||||
// original name.
|
||||
this._logger.log(5, "failed to overwrite file " + aFile.path + ": " + e);
|
||||
if (backupFile)
|
||||
backupFile.renameTo(null, aFile.leafName);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
},
|
||||
|
||||
endOfObject: true
|
||||
}
|
||||
|
||||
let gI2PProcessService = new I2PProcessService
|
||||
|
||||
|
||||
// TODO: Mark wants to research use of XPCOMUtils.generateNSGetFactory
|
||||
// Components.utils.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
function NSGetFactory(aClassID)
|
||||
{
|
||||
if (!aClassID.equals(gI2PProcessService.kClassID))
|
||||
throw Cr.NS_ERROR_FACTORY_NOT_REGISTERED
|
||||
|
||||
return gI2PProcessService
|
||||
}
|
||||
|
||||
|
||||
// This is the new stuff, stay away from generateNSGetModule which is the old stuff..
|
||||
//var NSGetFactory = XPCOMUtils.generateNSGetFactory([I2PProcessService])
|
@ -1,47 +1,39 @@
|
||||
// Bug 1506 P1: This is just a handy logger. If you have a better one, toss
|
||||
// this in the trash.
|
||||
|
||||
/*************************************************************************
|
||||
* TBLogger (JavaScript XPCOM component)
|
||||
*
|
||||
* Allows loglevel-based logging to different logging mechanisms.
|
||||
*
|
||||
*************************************************************************/
|
||||
|
||||
// TODO: Slowly migrate to firefox's Log module "resource://gre/modules/Log.jsm"
|
||||
// Module specific constants
|
||||
const kMODULE_NAME = "I2pbutton Logger";
|
||||
const kMODULE_CONTRACTID = "@geti2p.net/i2pbutton-logger;1";
|
||||
const kMODULE_CID = Components.ID("f36d72c9-9718-4134-b550-e109638331d7");
|
||||
const kMODULE_NAME = "I2pbutton Logger"
|
||||
const kMODULE_CONTRACTID = "@geti2p.net/i2pbutton-logger;1"
|
||||
const kMODULE_CID = Components.ID("f36d72c9-9718-4134-b550-e109638331d7")
|
||||
|
||||
const Cr = Components.results;
|
||||
const Cc = Components.classes;
|
||||
const Ci = Components.interfaces;
|
||||
const Cu = Components.utils;
|
||||
const Cr = Components.results
|
||||
const Cc = Components.classes
|
||||
const Ci = Components.interfaces
|
||||
const Cu = Components.utils
|
||||
|
||||
Cu.import("resource://i2pbutton/modules/default-prefs.js", {}).ensureDefaultPrefs();
|
||||
Cu.import("resource://i2pbutton/modules/default-prefs.js", {}).ensureDefaultPrefs()
|
||||
Cu.import("resource://gre/modules/Services.jsm")
|
||||
|
||||
Cu.import("resource://gre/modules/Services.jsm");
|
||||
let console = (Cu.import("resource://gre/modules/Console.jsm", {})).console
|
||||
|
||||
function I2pbuttonLogger() {
|
||||
// Register observer
|
||||
Services.prefs.addObserver("extensions.i2pbutton", this, false);
|
||||
// Register observer
|
||||
Services.prefs.addObserver("extensions.i2pbutton", this, false);
|
||||
|
||||
this.loglevel = Services.prefs.getIntPref("extensions.i2pbutton.loglevel");
|
||||
this.logmethod = Services.prefs.getIntPref("extensions.i2pbutton.logmethod");
|
||||
this.loglevel = Services.prefs.getIntPref("extensions.i2pbutton.loglevel");
|
||||
this.logmethod = Services.prefs.getIntPref("extensions.i2pbutton.logmethod");
|
||||
|
||||
try {
|
||||
var logMngr = Components.classes["@mozmonkey.com/debuglogger/manager;1"]
|
||||
.getService(Components.interfaces.nsIDebugLoggerManager);
|
||||
this._debuglog = logMngr.registerLogger("i2pbutton");
|
||||
} catch (exErr) {
|
||||
this._debuglog = false;
|
||||
}
|
||||
this._console = Components.classes["@mozilla.org/consoleservice;1"]
|
||||
.getService(Components.interfaces.nsIConsoleService);
|
||||
try {
|
||||
var logMngr = Components.classes["@mozmonkey.com/debuglogger/manager;1"]
|
||||
.getService(Components.interfaces.nsIDebugLoggerManager);
|
||||
this._debuglog = logMngr.registerLogger("i2pbutton");
|
||||
} catch (exErr) {
|
||||
this._debuglog = false;
|
||||
}
|
||||
this._console = Components.classes["@mozilla.org/consoleservice;1"]
|
||||
.getService(Components.interfaces.nsIConsoleService);
|
||||
|
||||
// This JSObject is exported directly to chrome
|
||||
this.wrappedJSObject = this;
|
||||
this.log(3, "I2pbutton debug output ready");
|
||||
// This JSObject is exported directly to chrome
|
||||
this.wrappedJSObject = this;
|
||||
this.log(3, "I2pbutton debug output ready");
|
||||
}
|
||||
|
||||
/**
|
||||
@ -55,11 +47,11 @@ const nsIClassInfo = Components.interfaces.nsIClassInfo;
|
||||
const nsIComponentRegistrar = Components.interfaces.nsIComponentRegistrar;
|
||||
const nsIObserverService = Components.interfaces.nsIObserverService;
|
||||
|
||||
const logString = { 1:"VERB", 2:"DBUG", 3: "INFO", 4:"NOTE", 5:"WARN" };
|
||||
const logString = { 1:"VERB", 2:"DBUG", 3: "INFO", 4:"NOTE", 5:"WARN", 6:"ERRO" };
|
||||
|
||||
function padInt(i)
|
||||
{
|
||||
return (i < 10) ? '0' + i : i;
|
||||
return (i < 10) ? '0' + i : i;
|
||||
}
|
||||
|
||||
I2pbuttonLogger.prototype =
|
||||
@ -95,23 +87,23 @@ I2pbuttonLogger.prototype =
|
||||
getHelperForLanguage: function(count) { return null; },
|
||||
|
||||
formatLog: function(str, level) {
|
||||
var d = new Date();
|
||||
var now = padInt(d.getUTCMonth()+1)+"-"+padInt(d.getUTCDate())+" "+padInt(d.getUTCHours())+":"+padInt(d.getUTCMinutes())+":"+padInt(d.getUTCSeconds());
|
||||
return "["+now+"] I2pbutton "+logString[level]+": "+str;
|
||||
var d = new Date()
|
||||
var now = padInt(d.getUTCMonth()+1)+"-"+padInt(d.getUTCDate())+" "+padInt(d.getUTCHours())+":"+padInt(d.getUTCMinutes())+":"+padInt(d.getUTCSeconds())
|
||||
return "["+now+"] I2pbutton "+logString[level]+": "+str
|
||||
},
|
||||
|
||||
// error console log
|
||||
eclog: function(level, str) {
|
||||
switch(this.logmethod) {
|
||||
case 0: // stderr
|
||||
if(this.loglevel <= level)
|
||||
dump(this.formatLog(str, level)+"\n");
|
||||
break;
|
||||
default: // errorconsole
|
||||
if(this.loglevel <= level)
|
||||
this._console.logStringMessage(this.formatLog(str,level));
|
||||
break;
|
||||
}
|
||||
switch(this.logmethod) {
|
||||
case 0: // stderr
|
||||
if(this.loglevel <= level)
|
||||
dump(this.formatLog(str, level)+"\n");
|
||||
break;
|
||||
default: // errorconsole
|
||||
if(this.loglevel <= level)
|
||||
this._console.logStringMessage(this.formatLog(str,level));
|
||||
break;
|
||||
}
|
||||
},
|
||||
|
||||
safe_log: function(level, str, scrub) {
|
||||
@ -143,6 +135,13 @@ I2pbuttonLogger.prototype =
|
||||
}
|
||||
},
|
||||
|
||||
error: function(str) { this.log(6, str) },
|
||||
warn: function(str) { this.log(5, str) },
|
||||
note: function(str) { this.log(4, str) },
|
||||
info: function(str) { this.log(3, str) },
|
||||
debug: function(str) { this.log(2, str) },
|
||||
verbose: function(str) { this.log(1, str) },
|
||||
|
||||
// Pref observer interface implementation
|
||||
|
||||
// topic: what event occurred
|
||||
@ -172,13 +171,5 @@ I2pbuttonLogger.prototype =
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* XPCOMUtils.generateNSGetFactory was introduced in Mozilla 2 (Firefox 4).
|
||||
* XPCOMUtils.generateNSGetModule is for Mozilla 1.9.2 (Firefox 3.6).
|
||||
*/
|
||||
Components.utils.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
if (XPCOMUtils.generateNSGetFactory)
|
||||
var NSGetFactory = XPCOMUtils.generateNSGetFactory([I2pbuttonLogger]);
|
||||
else
|
||||
var NSGetModule = XPCOMUtils.generateNSGetModule([I2pbuttonLogger]);
|
||||
|
||||
Components.utils.import("resource://gre/modules/XPCOMUtils.jsm")
|
||||
var NSGetFactory = XPCOMUtils.generateNSGetFactory([I2pbuttonLogger])
|
||||
|
259
src/components/router-config-manager.js
Normal file
259
src/components/router-config-manager.js
Normal file
@ -0,0 +1,259 @@
|
||||
// vim: set sw=2 sts=2 ts=8 et syntax=javascript:
|
||||
|
||||
const Cc = Components.classes
|
||||
const Ci = Components.interfaces
|
||||
const Cr = Components.results
|
||||
const Cu = Components.utils
|
||||
|
||||
/*const ZipReader = Components.Constructor(
|
||||
"@mozilla.org/libjar/zip-reader;1",
|
||||
"nsIZipReader",
|
||||
"open"
|
||||
)*/
|
||||
const nsFile = Components.Constructor(
|
||||
"@mozilla.org/file/local;1",
|
||||
"nsIFile",
|
||||
"initWithPath"
|
||||
)
|
||||
Cu.import("resource://gre/modules/XPCOMUtils.jsm")
|
||||
Cu.import("resource://gre/modules/Services.jsm")
|
||||
Cu.import('resource://gre/modules/osfile.jsm')
|
||||
Cu.import('resource://gre/modules/FileUtils.jsm')
|
||||
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "LauncherUtil", "resource://i2pbutton/modules/launcher-util.jsm")
|
||||
|
||||
let consolePort = Services.prefs.getIntPref("extensions.i2pbutton.console_port_i2pj", 17657)
|
||||
let httpProxyPort = Services.prefs.getIntPref("network.proxy.http_port", 14444)
|
||||
|
||||
const defaultProxyTunnels = `# Autogenerated by I2P Browser
|
||||
tunnel.0.description=HTTP proxy for browsing eepsites and the web
|
||||
tunnel.0.interface=127.0.0.1
|
||||
tunnel.0.listenPort=${httpProxyPort}
|
||||
tunnel.0.name=I2P HTTP Proxy
|
||||
tunnel.0.option.i2cp.closeIdleTime=1800000
|
||||
tunnel.0.option.i2cp.closeOnIdle=false
|
||||
tunnel.0.option.i2cp.delayOpen=false
|
||||
tunnel.0.option.i2cp.destination.sigType=7
|
||||
tunnel.0.option.i2cp.newDestOnResume=false
|
||||
tunnel.0.option.i2cp.reduceIdleTime=900000
|
||||
tunnel.0.option.i2cp.reduceOnIdle=true
|
||||
tunnel.0.option.i2cp.reduceQuantity=1
|
||||
tunnel.0.option.i2p.streaming.connectDelay=0
|
||||
tunnel.0.option.i2ptunnel.httpclient.SSLOutproxies=false.i2p
|
||||
tunnel.0.option.i2ptunnel.httpclient.allowInternalSSL=true
|
||||
tunnel.0.option.i2ptunnel.httpclient.jumpServers=http://stats.i2p/cgi-bin/jump.cgi?a=,http://i2pjump.i2p/jump/
|
||||
tunnel.0.option.i2ptunnel.httpclient.sendAccept=false
|
||||
tunnel.0.option.i2ptunnel.httpclient.sendReferer=false
|
||||
tunnel.0.option.i2ptunnel.httpclient.sendUserAgent=false
|
||||
tunnel.0.option.i2ptunnel.useLocalOutproxy=false
|
||||
tunnel.0.option.inbound.backupQuantity=0
|
||||
tunnel.0.option.inbound.length=3
|
||||
tunnel.0.option.inbound.lengthVariance=0
|
||||
tunnel.0.option.inbound.nickname=shared clients
|
||||
tunnel.0.option.inbound.quantity=6
|
||||
tunnel.0.option.outbound.backupQuantity=0
|
||||
tunnel.0.option.outbound.length=3
|
||||
tunnel.0.option.outbound.lengthVariance=0
|
||||
tunnel.0.option.outbound.nickname=shared clients
|
||||
tunnel.0.option.outbound.priority=10
|
||||
tunnel.0.option.outbound.quantity=6
|
||||
tunnel.0.option.outproxyAuth=false
|
||||
tunnel.0.option.persistentClientKey=false
|
||||
tunnel.0.option.sslManuallySet=true
|
||||
tunnel.0.option.useSSL=false
|
||||
tunnel.0.proxyList=false.i2p
|
||||
tunnel.0.sharedClient=true
|
||||
tunnel.0.startOnLoad=true
|
||||
tunnel.0.type=httpclient
|
||||
`
|
||||
|
||||
const defaultClientsConfig = `# Autogenerated by I2P Browser
|
||||
clientApp.0.args=${consolePort} ::1,127.0.0.1 ./webapps/
|
||||
clientApp.0.main=net.i2p.router.web.RouterConsoleRunner
|
||||
clientApp.0.name=I2P Router Console
|
||||
clientApp.0.onBoot=true
|
||||
clientApp.0.startOnLoad=true
|
||||
clientApp.1.main=net.i2p.i2ptunnel.TunnelControllerGroup
|
||||
clientApp.1.name=Application tunnels
|
||||
clientApp.1.args=i2ptunnel.config
|
||||
clientApp.1.delay=-1
|
||||
clientApp.1.startOnLoad=true
|
||||
`
|
||||
|
||||
const defaultSocksProxyTunnels = `# Autogenerated by I2P Browser
|
||||
tunnel.1.interface=127.0.0.1
|
||||
tunnel.1.listenPort=4455
|
||||
tunnel.1.name=SOCKS
|
||||
tunnel.1.option.i2cp.closeIdleTime=1800000
|
||||
tunnel.1.option.i2cp.closeOnIdle=false
|
||||
tunnel.1.option.i2cp.delayOpen=false
|
||||
tunnel.1.option.i2cp.destination.sigType=7
|
||||
tunnel.1.option.i2cp.newDestOnResume=false
|
||||
tunnel.1.option.i2cp.reduceIdleTime=1200000
|
||||
tunnel.1.option.i2cp.reduceOnIdle=false
|
||||
tunnel.1.option.i2cp.reduceQuantity=1
|
||||
tunnel.1.option.i2p.streaming.connectDelay=0
|
||||
tunnel.1.option.i2ptunnel.httpclient.allowInternalSSL=false
|
||||
tunnel.1.option.i2ptunnel.httpclient.sendAccept=false
|
||||
tunnel.1.option.i2ptunnel.httpclient.sendReferer=false
|
||||
tunnel.1.option.i2ptunnel.httpclient.sendUserAgent=false
|
||||
tunnel.1.option.i2ptunnel.useLocalOutproxy=true
|
||||
tunnel.1.option.inbound.backupQuantity=0
|
||||
tunnel.1.option.inbound.length=3
|
||||
tunnel.1.option.inbound.lengthVariance=0
|
||||
tunnel.1.option.inbound.nickname=SOCKS
|
||||
tunnel.1.option.inbound.quantity=3
|
||||
tunnel.1.option.outbound.backupQuantity=0
|
||||
tunnel.1.option.outbound.length=3
|
||||
tunnel.1.option.outbound.lengthVariance=0
|
||||
tunnel.1.option.outbound.nickname=SOCKS
|
||||
tunnel.1.option.outbound.quantity=3
|
||||
tunnel.1.option.outproxyAuth=false
|
||||
tunnel.1.option.persistentClientKey=false
|
||||
tunnel.1.option.useSSL=false
|
||||
tunnel.1.proxyList=exitpoint.i2p
|
||||
tunnel.1.sharedClient=false
|
||||
tunnel.1.startOnLoad=false
|
||||
tunnel.1.type=sockstunnel
|
||||
`
|
||||
|
||||
const defaultRouterConfig = `# Autogenerated by I2P Browser
|
||||
i2np.laptopMode=true
|
||||
i2np.upnp.enable=true
|
||||
i2np.udp.addressSources=local,upnp,ssu
|
||||
i2p.reseedURL=https://download.xxlspeed.com/,https://i2p.mooo.com/netDb/,https://i2p.novg.net/,https://i2pseed.creativecowpat.net:8443/,https://itoopie.atomike.ninja/,https://netdb.i2p2.no/,https://reseed.i2p-projekt.de/,https://reseed.i2p.net.in/,https://reseed.memcpy.io/,https://reseed.onion.im/
|
||||
router.outboundPool.quantity=7
|
||||
router.inboundPool.quantity=7
|
||||
router.sharePercentage=50
|
||||
`
|
||||
|
||||
|
||||
function RouterConfigManager() {
|
||||
this.version = '0.1'
|
||||
this._logger = Cc["@geti2p.net/i2pbutton-logger;1"].getService(Ci.nsISupports).wrappedJSObject
|
||||
this._logger.log(3, "I2pbutton I2P RouterConfigManager Service initialized")
|
||||
this.wrappedJSObject = this
|
||||
}
|
||||
|
||||
RouterConfigManager.prototype = {
|
||||
// properties required for XPCOM registration:
|
||||
classDescription: "A component for handling the embedded router config",
|
||||
classID: Components.ID("{E2AA62BB-AFD0-4D94-9408-90CE39784086}"),
|
||||
contractID: "@geti2p.net/i2pbutton-router-config-mgr;1",
|
||||
serviceName: 'RouterConfigManager',
|
||||
wrappedJSObject: null,
|
||||
_logger: null,
|
||||
state: {},
|
||||
|
||||
// State
|
||||
mDoesRouterConfigExists: false,
|
||||
mDoesClientsConfigExists: false,
|
||||
mDoesTunnelConfigExists: false,
|
||||
mHasChecksStarted: false,
|
||||
mIsChecksDone: false,
|
||||
|
||||
|
||||
// nsISupports implementation.
|
||||
QueryInterface: XPCOMUtils.generateQI([Components.interfaces.nsISupports]),
|
||||
|
||||
canRouterStart: function() {
|
||||
return (this.mDoesRouterConfigExists && this.mDoesClientsConfigExists && this.mDoesTunnelConfigExists)
|
||||
},
|
||||
|
||||
|
||||
_write_router_config: function(configfile,onComplete) {
|
||||
const self = this
|
||||
LauncherUtil.writeFileWithData(configfile, defaultRouterConfig, file => { onComplete(file) }, (err) => {
|
||||
this._logger.log(6,`Can't write router config file :( - path was ${configfile.path}`)
|
||||
})
|
||||
},
|
||||
_write_tunnel_config: function(configfile,onComplete) {
|
||||
const self = this
|
||||
LauncherUtil.writeFileWithData(configfile, defaultProxyTunnels, file => { onComplete(file) }, (err) => {
|
||||
this._logger.log(6,`Can't write tunnel proxy config file :( - path was ${configfile.path}`)
|
||||
})
|
||||
},
|
||||
_write_clients_config: function(configfile,onComplete) {
|
||||
const self = this
|
||||
LauncherUtil.writeFileWithData(configfile, defaultClientsConfig, file => { onComplete(file) }, (err) => {
|
||||
this._logger.log(6,`Can't write clients config file :( - path was ${configfile.path}`)
|
||||
})
|
||||
},
|
||||
|
||||
|
||||
ensure_config: async function(onCompleteCallback) {
|
||||
this.mHasChecksStarted = true
|
||||
|
||||
let configDirectory = LauncherUtil.getI2PConfigPath(true)
|
||||
let routerConfigFile = configDirectory.clone()
|
||||
routerConfigFile.append('router.config')
|
||||
let tunnelConfigFile = configDirectory.clone()
|
||||
tunnelConfigFile.append('i2ptunnel.config')
|
||||
let clientsConfigFile = configDirectory.clone()
|
||||
clientsConfigFile.append('clients.config')
|
||||
|
||||
// Ensure they exists
|
||||
const self = this
|
||||
|
||||
this.ensureRouterConfigPromise = () => {
|
||||
return new Promise(resolve => {
|
||||
if (!routerConfigFile.exists()) {
|
||||
self._write_router_config(routerConfigFile, file => {
|
||||
self.mDoesRouterConfigExists = true
|
||||
self._logger.log(3, 'Wrote router.config')
|
||||
if (typeof onCompleteCallback === 'function') onCompleteCallback(file)
|
||||
resolve(routerConfigFile)
|
||||
})
|
||||
} else {
|
||||
self._logger.log(3, 'Found router.config from earlier')
|
||||
self.mDoesRouterConfigExists = true
|
||||
resolve(null)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
this.ensureTunnelConfigPromise = () => {
|
||||
return new Promise(resolve => {
|
||||
if (!tunnelConfigFile.exists()) {
|
||||
self._write_tunnel_config(tunnelConfigFile, tfile => {
|
||||
self._logger.log(3, 'Wrote i2ptunnel.config')
|
||||
self.mDoesTunnelConfigExists = true
|
||||
if (typeof onCompleteCallback === 'function') onCompleteCallback(tfile)
|
||||
resolve(tunnelConfigFile)
|
||||
})
|
||||
} else {
|
||||
self._logger.log(3, 'Found i2ptunnel.config from earlier')
|
||||
self.mDoesTunnelConfigExists = true
|
||||
resolve(null)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
this.ensureClientsConfigPromise = () => {
|
||||
return new Promise(resolve => {
|
||||
if (!clientsConfigFile.exists()) {
|
||||
self._write_tunnel_config(tunnelConfigFile, tfile => {
|
||||
self._logger.log(3, 'Wrote clients.config')
|
||||
self.mDoesClientsConfigExists = true
|
||||
if (typeof onCompleteCallback === 'function') onCompleteCallback(tfile)
|
||||
resolve(clientsConfigFile)
|
||||
})
|
||||
} else {
|
||||
self._logger.log(3, 'Found clients.config from earlier')
|
||||
self.mDoesClientsConfigExists = true
|
||||
resolve(null)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// Promises are not done but at least done here.
|
||||
this.mIsChecksDone = true
|
||||
return Promise.all([
|
||||
this.ensureRouterConfigPromise(),
|
||||
this.ensureTunnelConfigPromise(),
|
||||
this.ensureClientsConfigPromise(),
|
||||
])
|
||||
},
|
||||
}
|
||||
|
||||
var NSGetFactory = XPCOMUtils.generateNSGetFactory([RouterConfigManager])
|
@ -8,37 +8,34 @@
|
||||
*
|
||||
*************************************************************************/
|
||||
|
||||
const Cc = Components.classes;
|
||||
const Ci = Components.interfaces;
|
||||
const Cr = Components.results;
|
||||
const Cu = Components.utils;
|
||||
const Cc = Components.classes
|
||||
const Ci = Components.interfaces
|
||||
const Cr = Components.results
|
||||
const Cu = Components.utils
|
||||
|
||||
Cu.import("resource://gre/modules/Services.jsm");
|
||||
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "FileUtils",
|
||||
"resource://gre/modules/FileUtils.jsm");
|
||||
Cu.import("resource://gre/modules/Services.jsm")
|
||||
Cu.import("resource://gre/modules/XPCOMUtils.jsm")
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "FileUtils", "resource://gre/modules/FileUtils.jsm")
|
||||
|
||||
Cu.import("resource://i2pbutton/modules/default-prefs.js", {}).ensureDefaultPrefs();
|
||||
//let NoScriptControl = Cu.import("resource://torbutton/modules/noscript-control.js", {});
|
||||
Cu.import("resource://i2pbutton/modules/default-prefs.js", {}).ensureDefaultPrefs()
|
||||
let NoScriptControl = Cu.import("resource://i2pbutton/modules/noscript-control.js", {})
|
||||
|
||||
// Module specific constants
|
||||
const kMODULE_NAME = "Startup";
|
||||
const kMODULE_CONTRACTID = "@geti2p.net/startup-observer;1";
|
||||
const kMODULE_CID = Components.ID("06322def-6fde-4c06-aef6-47ae8e799629");
|
||||
const kMODULE_NAME = "Startup"
|
||||
const kMODULE_CONTRACTID = "@geti2p.net/startup-observer;1"
|
||||
const kMODULE_CID = Components.ID("06322def-6fde-4c06-aef6-47ae8e799629")
|
||||
|
||||
function StartupObserver() {
|
||||
this.logger = Cc["@geti2p.net/i2pbutton-logger;1"]
|
||||
.getService(Ci.nsISupports).wrappedJSObject;
|
||||
this._prefs = Services.prefs;
|
||||
this.logger.log(3, "Startup Observer created");
|
||||
this.logger = Cc["@geti2p.net/i2pbutton-logger;1"].getService(Ci.nsISupports).wrappedJSObject
|
||||
this._prefs = Services.prefs
|
||||
this.logger.log(3, "Startup Observer created")
|
||||
|
||||
var env = Cc["@mozilla.org/process/environment;1"]
|
||||
.getService(Ci.nsIEnvironment);
|
||||
var prefName = "browser.startup.homepage";
|
||||
var env = Cc["@mozilla.org/process/environment;1"].getService(Ci.nsIEnvironment)
|
||||
var prefName = "browser.startup.homepage"
|
||||
if (env.exists("I2P_DEFAULT_HOMEPAGE")) {
|
||||
// if the user has set this value in a previous installation, don't override it
|
||||
if (!this._prefs.prefHasUserValue(prefName)) {
|
||||
this._prefs.setCharPref(prefName, env.get("I2P_DEFAULT_HOMEPAGE"));
|
||||
this._prefs.setCharPref(prefName, env.get("I2P_DEFAULT_HOMEPAGE"))
|
||||
}
|
||||
}
|
||||
|
||||
@ -51,20 +48,16 @@ function StartupObserver() {
|
||||
}
|
||||
|
||||
try {
|
||||
// XXX: We're in a race with HTTPS-Everywhere to update our proxy settings
|
||||
// before the initial SSL-Observatory test... If we lose the race, Firefox
|
||||
// caches the old proxy settings for check.tp.o somehwere, and it never loads :(
|
||||
this.setProxySettings();
|
||||
} catch(e) {
|
||||
this.logger.log(4, "Early proxy change failed. Will try again at profile load. Error: "+e);
|
||||
}
|
||||
|
||||
// Arrange for our about:tor handler to be loaded in the default (chrome)
|
||||
// Arrange for our about:i2p handler to be loaded in the default (chrome)
|
||||
// process as well as in each content process.
|
||||
let ppmm = Cc["@mozilla.org/parentprocessmessagemanager;1"]
|
||||
.getService(Ci.nsIProcessScriptLoader);
|
||||
ppmm.loadProcessScript("resource://i2pbutton/components/aboutI2p.js",
|
||||
true);
|
||||
ppmm.loadProcessScript("resource://i2pbutton/components/aboutI2p.js", true)
|
||||
}
|
||||
|
||||
StartupObserver.prototype = {
|
||||
@ -80,12 +73,13 @@ StartupObserver.prototype = {
|
||||
this._prefs.setIntPref("network.proxy.type", 1);
|
||||
this._prefs.setIntPref("network.proxy.socks_port", 0);
|
||||
this._prefs.setCharPref("network.proxy.socks", "");
|
||||
this._prefs.setIntPref("extensions.i2pbutton.console_port_i2pj", 17657);
|
||||
this._prefs.setCharPref("network.proxy.http", "127.0.0.1");
|
||||
this._prefs.setIntPref("network.proxy.http_port", 4444);
|
||||
this._prefs.setIntPref("network.proxy.http_port", 14444);
|
||||
this._prefs.setCharPref("network.proxy.ssl", "127.0.0.1");
|
||||
this._prefs.setIntPref("network.proxy.ssl_port", 4445);
|
||||
this._prefs.setIntPref("network.proxy.ssl_port", 14444);
|
||||
this._prefs.setCharPref("network.proxy.ftp", "127.0.0.1");
|
||||
this._prefs.setIntPref("network.proxy.ftp_port", 4444);
|
||||
this._prefs.setIntPref("network.proxy.ftp_port", 14444);
|
||||
this._prefs.setCharPref("network.proxy.no_proxies_on", "localhost, 127.0.0.1");
|
||||
|
||||
// Force prefs to be synced to disk
|
||||
@ -100,8 +94,8 @@ StartupObserver.prototype = {
|
||||
// but only for hackish reasons.
|
||||
this._prefs.setBoolPref("extensions.i2pbutton.startup", true);
|
||||
|
||||
// We need to listen for NoScript before it starts.
|
||||
//NoScriptControl.initialize();
|
||||
// We need to listen for NoScript before it starts.
|
||||
NoScriptControl.initialize();
|
||||
|
||||
this.setProxySettings();
|
||||
}
|
||||
|
@ -1,78 +0,0 @@
|
||||
const Cc = Components.classes;
|
||||
const Ci = Components.interfaces;
|
||||
const Cr = Components.results;
|
||||
const Cu = Components.utils;
|
||||
|
||||
Cu.import("resource://gre/modules/Services.jsm");
|
||||
Cu.import("resource://gre/modules/Subprocess.jsm");
|
||||
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
|
||||
let EXPORTED_SYMBOLS = [ 'IILauncherSubProcess' ]
|
||||
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "LauncherUtil",
|
||||
"resource://i2pbutton/modules/launcher-util.jsm")
|
||||
|
||||
function _SubProcess(opts)
|
||||
{
|
||||
this.kCurrentSubProcessOpts = Object.assign({} ,opts, {
|
||||
//command: '/bin/ls',
|
||||
//arguments: ['/'],
|
||||
workdir: '/',
|
||||
environment: [],
|
||||
stderr: "pipe"
|
||||
})
|
||||
}
|
||||
|
||||
let IILauncherSubProcess = {
|
||||
createSubProcess: function(opts) {
|
||||
return new _SubProcess(opts)
|
||||
}
|
||||
}
|
||||
|
||||
Object.freeze(IILauncherSubProcess)
|
||||
|
||||
_SubProcess.prototype = {
|
||||
kLibVersion: '0.0.1',
|
||||
kCurrentSubProcess: null,
|
||||
kCurrentSubProcessStdOutBuffer: null,
|
||||
init: function() {
|
||||
//
|
||||
},
|
||||
close: function() {
|
||||
if (this.kCurrentSubProcess !== null)
|
||||
{
|
||||
this.kCurrentSubProcess.kill()
|
||||
this.kCurrentSubProcess = null
|
||||
}
|
||||
},
|
||||
exec: function() {
|
||||
Subprocess.call(this.kCurrentSubProcessOpts).then(aProc => {
|
||||
this.kCurrentSubProcess = aProc
|
||||
new Promise((aResolve, aReject) =>
|
||||
{
|
||||
this._readStdOut(aResolve, aReject)
|
||||
})
|
||||
})
|
||||
},
|
||||
_readStdOut: function (aProc, errReject) {
|
||||
this.kCurrentSubProcess.stdout.readString().then(out => {
|
||||
/*if (!out || (out.length == 0))
|
||||
{
|
||||
throw new Error('Error: stdout is empty')
|
||||
}*/
|
||||
if (this.kCurrentSubProcessStdOutBuffer === null) {
|
||||
this.kCurrentSubProcessStdOutBuffer = out
|
||||
} else {
|
||||
this.kCurrentSubProcessStdOutBuffer += out
|
||||
}
|
||||
this._readStdOut(aProc, errReject)
|
||||
}).catch(err => {
|
||||
errReject(err)
|
||||
})
|
||||
},
|
||||
await: function() {
|
||||
let {exitCode} = await this.kCurrentSubProcess.wait()
|
||||
this.kCurrentSubProcessExitCode = exitCode
|
||||
return exitCode
|
||||
}
|
||||
}
|
@ -1,11 +1,13 @@
|
||||
// debug prefs
|
||||
pref("extensions.i2pbutton.loglevel",4);
|
||||
pref("extensions.i2pbutton.loglevel", 3); // Loglevel = info would be nice for the beta period.
|
||||
pref("extensions.i2pbutton.logmethod",1); // 0=stdout, 1=errorconsole, 2=debuglog
|
||||
|
||||
pref("extensions.i2pbutton@geti2p.net.description", "chrome://i2pbutton/locale/i2pbutton.properties");
|
||||
pref("extensions.i2pbutton.updateNeeded", false);
|
||||
|
||||
// Tor check and proxy prefs
|
||||
pref("app.update.url.details", "https://geti2p.net/en/download/lab")
|
||||
|
||||
// I2P check and proxy prefs
|
||||
pref("extensions.i2pbutton.test_enabled",true);
|
||||
pref("extensions.i2pbutton.test_url","http://4mucxjk5rxn2pmlgnjdbfdflhjmqqile5zxrltzl5o77mutl7jiq.b32.i2p/index.json?I2PButton=true");
|
||||
pref("extensions.i2pbutton.local_i2p_check",true);
|
||||
@ -14,7 +16,32 @@ pref("extensions.i2pbutton.local_i2p_check",true);
|
||||
// https://developer.mozilla.org/en/Addons/Working_with_AMO
|
||||
pref("extensions.i2pbutton@geti2p.net.getAddons.cache.enabled", false);
|
||||
|
||||
pref("extensions.i2pbutton.clear_http_auth", true);
|
||||
// I2P router control prefs:
|
||||
pref("extensions.i2pbutton.start_i2p", true);
|
||||
pref("extensions.i2pbutton.kill_router_on_exit", true);
|
||||
|
||||
// State prefs:
|
||||
pref("extensions.i2pbutton.startup",false);
|
||||
pref("extensions.i2pbutton.inserted_button",false);
|
||||
pref("extensions.i2pbutton.inserted_security_level",false);
|
||||
|
||||
// Security prefs:
|
||||
pref("extensions.i2pbutton.cookie_protections",true);
|
||||
pref("extensions.i2pbutton.cookie_auto_protect",false);
|
||||
pref("extensions.i2pbutton.clear_http_auth",true);
|
||||
pref("extensions.i2pbutton.close_newnym",true);
|
||||
pref("extensions.i2pbutton.resize_new_windows",true);
|
||||
pref("extensions.i2pbutton.startup_state", 2); // 0=non-i2p, 1=i2p, 2=last
|
||||
pref("extensions.i2pbutton.i2p_memory_jar",false);
|
||||
pref("extensions.i2pbutton.noni2p_memory_jar",false);
|
||||
pref("extensions.i2pbutton.launch_warning",true);
|
||||
|
||||
// Security Slider
|
||||
pref("extensions.i2pbutton.security_slider", 4);
|
||||
pref("extensions.i2pbutton.security_custom", false);
|
||||
|
||||
pref("extensions.i2pbutton.noscript_inited", false);
|
||||
pref("extensions.i2pbutton.noscript_persist", false);
|
||||
|
||||
pref("extensions.i2pbutton.prompt_i2pbrowser", true);
|
||||
pref("extensions.i2pbutton.confirm_plugins", true);
|
||||
@ -23,3 +50,15 @@ pref("extensions.i2pbutton.confirm_newnym", true);
|
||||
pref("extensions.i2pbutton.close_newnym", true);
|
||||
// Browser home page:
|
||||
pref("browser.startup.homepage", "chrome://i2pbutton/content/locale/non-localized.properties");
|
||||
|
||||
|
||||
// I2P Startup etc
|
||||
pref("extensions.i2pbutton.start_i2p", true);
|
||||
pref("extensions.i2pbutton.kill_router_on_exit", true);
|
||||
pref("extensions.i2pbutton.console_host", "127.0.0.1");
|
||||
pref("extensions.i2pbutton.console_port_i2pj", 17657);
|
||||
pref("extensions.i2pbutton.console_port_i2pd", 17070);
|
||||
|
||||
// I2P Implementation
|
||||
pref("extensions.i2pbutton.i2pimpl_driver", "i2pj");
|
||||
|
||||
|
@ -6,7 +6,7 @@
|
||||
<em:name>I2pbutton</em:name>
|
||||
<em:creator>Meeh, Mikal Villa</em:creator>
|
||||
<em:id>i2pbutton@geti2p.net</em:id>
|
||||
<em:version>0.1</em:version>
|
||||
<em:version>0.3.1</em:version>
|
||||
<em:multiprocessCompatible>true</em:multiprocessCompatible>
|
||||
<em:homepageURL>https://geti2p.net/en/download/lab</em:homepageURL>
|
||||
<em:iconURL>chrome://i2pbutton/skin/i2p.png</em:iconURL>
|
||||
|
20
src/jar.mn
20
src/jar.mn
@ -11,6 +11,7 @@ i2pbutton.jar:
|
||||
skin/ (chrome/skin/*)
|
||||
|
||||
% overlay chrome://browser/content/browser.xul chrome://i2pbutton/content/i2pbutton.xul
|
||||
% overlay chrome://browser/content/preferences/connection.xul chrome://i2pbutton/content/pref-connection.xul
|
||||
% overlay chrome://messenger/content/messenger.xul chrome://i2pbutton/content/i2pbutton_tb.xul
|
||||
% overlay chrome://messenger/content/messengercompose/messengercompose.xul chrome://i2pbutton/content/i2pbutton_tb.xul
|
||||
% overlay about:addons chrome://i2pbutton/content/i2pbutton-extensions.xul
|
||||
@ -26,7 +27,7 @@ i2pbutton.jar:
|
||||
|
||||
# UI customization
|
||||
% overlay chrome://browser/content/browser.xul chrome://i2pbutton/content/menu-items-overlay.xul
|
||||
|
||||
% overlay chrome://browser/content/browser.xul chrome://i2pbutton/content/menu-overlay.xul
|
||||
|
||||
# Strings for the about:ibupdate page
|
||||
% override chrome://browser/locale/aboutIBUpdate.dtd chrome://i2pbutton/locale/aboutIBUpdate.dtd
|
||||
@ -42,6 +43,9 @@ i2pbutton.jar:
|
||||
% component {f605ec27-d867-44b5-ad97-2a29276642c3} %components/dragDropFilter.js
|
||||
% contract @geti2p.net/i2pbutton-dragDropFilter;1 {f605ec27-d867-44b5-ad97-2a29276642c3}
|
||||
|
||||
% component {3da0269f-fc29-4e9e-a678-c3b1cafcf13f} %components/external-app-blocker.js
|
||||
% contract @geti2p.net/i2pbutton-extAppBlocker;1 {3da0269f-fc29-4e9e-a678-c3b1cafcf13f}
|
||||
|
||||
% component {e6204253-b690-4159-bfe8-d4eedab6b3be} %components/cookie-jar-selector.js
|
||||
% contract @geti2p.net/cookie-jar-selector;1 {e6204253-b690-4159-bfe8-d4eedab6b3be}
|
||||
|
||||
@ -51,5 +55,19 @@ i2pbutton.jar:
|
||||
% component {f36d72c9-9718-4134-b550-e109638331d7} %components/i2pbutton-logger.js
|
||||
% contract @geti2p.net/i2pbutton-logger;1 {f36d72c9-9718-4134-b550-e109638331d7}
|
||||
|
||||
% component {E2AA62BB-AFD0-4D94-9408-90CE39784086} %components/router-config-manager.js
|
||||
% contract @geti2p.net/i2pbutton-router-config-mgr;1 {E2AA62BB-AFD0-4D94-9408-90CE39784086}
|
||||
|
||||
% component {f77babef-dead-b00b-beff-babe6c9afda7} %components/i2p-router-process.js
|
||||
% contract @geti2p.net/i2pbutton-process-service;1 {f77babef-dead-b00b-beff-babe6c9afda7}
|
||||
|
||||
% component {aa132730-beef-dead-babe-0800200c9a66} %components/about-outproxies.js
|
||||
% contract @geti2p.net/i2pbutton-about-outproxies;1 {aa132730-beef-dead-babe-0800200c9a66}
|
||||
|
||||
% category profile-after-change I2PProcessService @geti2p.net/i2pbutton-process-service;1
|
||||
|
||||
% category profile-after-change CookieJarSelector @geti2p.net/cookie-jar-selector;1
|
||||
|
||||
% category profile-after-change StartupObserver @geti2p.net/startup-observer;1
|
||||
% category profile-after-change DragDropFilter @geti2p.net/i2pbutton-dragDropFilter;1
|
||||
|
||||
|
@ -1,21 +1,34 @@
|
||||
let EXPORTED_SYMBOLS = [ 'LauncherUtil' ]
|
||||
|
||||
const Cc = Components.classes;
|
||||
const Ci = Components.interfaces;
|
||||
const Cu = Components.utils;
|
||||
const Cr = Components.results;
|
||||
const Cc = Components.classes
|
||||
const Ci = Components.interfaces
|
||||
const Cu = Components.utils
|
||||
const Cr = Components.results
|
||||
|
||||
const kPropBundleURI = "chrome://i2pbutton/locale/i2pbutton.properties"
|
||||
const kPropNamePrefix = "i2pbutton."
|
||||
|
||||
Cu.import("resource://gre/modules/XPCOMUtils.jsm")
|
||||
Cu.import("resource://gre/modules/Services.jsm")
|
||||
//const logger = Cc["@geti2p.net/i2pbutton-logger;1"].getService(Ci.nsISupports).wrappedJSObject
|
||||
let console = (Cu.import("resource://gre/modules/Console.jsm", {})).console
|
||||
|
||||
let LauncherUtil = {
|
||||
let logger = {
|
||||
log:function(level, message) {
|
||||
console.log(message)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
const LauncherUtil = {
|
||||
get isMac()
|
||||
{
|
||||
return LauncherUtilInternal._isMac;
|
||||
return ("Darwin" == LauncherUtilInternal._OS)
|
||||
},
|
||||
|
||||
get isWindows()
|
||||
{
|
||||
return ("WINNT" == LauncherUtilInternal._OS);
|
||||
return ("WINNT" == LauncherUtilInternal._OS)
|
||||
},
|
||||
|
||||
isAppVersionAtLeast: function(aVersion)
|
||||
@ -26,46 +39,465 @@ let LauncherUtil = {
|
||||
.getService(Ci.nsIVersionComparator);
|
||||
return (vc.compare(appInfo.version, aVersion) >= 0);
|
||||
},
|
||||
// Error Reporting / Prompting
|
||||
showAlert: function(aParentWindow, aMsg)
|
||||
{
|
||||
// TODO: alert() does not always resize correctly to fit the message.
|
||||
try
|
||||
{
|
||||
if (!aParentWindow)
|
||||
{
|
||||
var wm = Cc["@mozilla.org/appshell/window-mediator;1"].getService(Ci.nsIWindowMediator)
|
||||
let browserWindow = wm.getMostRecentWindow("navigator:browser")
|
||||
if (TLUtilInternal._isWindowVisible(browserWindow))
|
||||
aParentWindow = browserWindow;
|
||||
}
|
||||
|
||||
var ps = Cc["@mozilla.org/embedcomp/prompt-service;1"]
|
||||
.getService(Ci.nsIPromptService);
|
||||
var title = this.getLocalizedString("error_title");
|
||||
ps.alert(aParentWindow, title, aMsg);
|
||||
}
|
||||
catch (e)
|
||||
{
|
||||
alert(aMsg);
|
||||
}
|
||||
},
|
||||
_createOpenWindowArgsArray: function(aArg1, aArg2)
|
||||
{
|
||||
var argsArray = Cc["@mozilla.org/array;1"]
|
||||
.createInstance(Ci.nsIMutableArray);
|
||||
var variant = Cc["@mozilla.org/variant;1"]
|
||||
.createInstance(Ci.nsIWritableVariant);
|
||||
variant.setFromVariant(aArg1);
|
||||
argsArray.appendElement(variant, false);
|
||||
|
||||
if (aArg2)
|
||||
{
|
||||
variant = Cc["@mozilla.org/variant;1"]
|
||||
.createInstance(Ci.nsIWritableVariant);
|
||||
variant.setFromVariant(aArg2);
|
||||
argsArray.appendElement(variant, false);
|
||||
}
|
||||
|
||||
return argsArray;
|
||||
},
|
||||
|
||||
get _networkSettingsWindow()
|
||||
{
|
||||
var wm = Cc["@mozilla.org/appshell/window-mediator;1"]
|
||||
.getService(Ci.nsIWindowMediator);
|
||||
return wm.getMostRecentWindow("I2PLauncher:NetworkSettings");
|
||||
},
|
||||
_openNetworkSettings: function(aIsInitialBootstrap, aStartAtWizardPanel)
|
||||
{
|
||||
var win = this._networkSettingsWindow;
|
||||
if (win)
|
||||
{
|
||||
// Return to "Starting i2p" panel if being asked to open & dlog already exists.
|
||||
//win.showStartingTorPanel();
|
||||
win.focus();
|
||||
return;
|
||||
}
|
||||
|
||||
const kSettingsURL = "chrome://i2pbutton/content/network-settings.xul";
|
||||
const kWizardURL = "chrome://i2pbutton/content/network-settings-wizard.xul";
|
||||
|
||||
var wwSvc = Cc["@mozilla.org/embedcomp/window-watcher;1"]
|
||||
.getService(Ci.nsIWindowWatcher);
|
||||
var winFeatures = "chrome,dialog=yes,modal,all";
|
||||
var argsArray = this._createOpenWindowArgsArray(aIsInitialBootstrap,
|
||||
aStartAtWizardPanel);
|
||||
let isProgress = (this.kWizardProgressPageID == aStartAtWizardPanel);
|
||||
let url = (aIsInitialBootstrap || isProgress) ? kWizardURL : kSettingsURL;
|
||||
wwSvc.openWindow(null, url, "_blank", winFeatures, argsArray);
|
||||
},
|
||||
|
||||
// Returns true if user confirms; false if not.
|
||||
// Note that no prompt is shown (and false is returned) if the Network Settings
|
||||
// window is open.
|
||||
showConfirm: function(aParentWindow, aMsg, aDefaultButtonLabel, aCancelButtonLabel)
|
||||
{
|
||||
try {
|
||||
if (!aParentWindow) {
|
||||
var wm = Cc["@mozilla.org/appshell/window-mediator;1"].getService(Ci.nsIWindowMediator);
|
||||
|
||||
aParentWindow = wm.getMostRecentWindow("navigator:browser");
|
||||
}
|
||||
|
||||
var ps = Cc["@mozilla.org/embedcomp/prompt-service;1"].getService(Ci.nsIPromptService);
|
||||
var title = this.getLocalizedString("error_title");
|
||||
var btnFlags = (ps.BUTTON_POS_0 * ps.BUTTON_TITLE_IS_STRING)
|
||||
+ ps.BUTTON_POS_0_DEFAULT
|
||||
+ (ps.BUTTON_POS_1 * ps.BUTTON_TITLE_IS_STRING);
|
||||
|
||||
var notUsed = { value: false };
|
||||
var btnIndex = ps.confirmEx(aParentWindow, title, aMsg, btnFlags,
|
||||
aDefaultButtonLabel, aCancelButtonLabel,
|
||||
null, null, notUsed);
|
||||
return (0 == btnIndex);
|
||||
} catch (e) {
|
||||
return confirm(aMsg);
|
||||
}
|
||||
|
||||
return false
|
||||
},
|
||||
|
||||
cleanupTempDirectories: function()
|
||||
{
|
||||
try
|
||||
{
|
||||
let dirPath = this.getCharPref(TLUtilInternal.kIPCDirPrefName);
|
||||
this.clearUserPref(TLUtilInternal.kIPCDirPrefName);
|
||||
if (dirPath)
|
||||
{
|
||||
let f = Cc['@mozilla.org/file/local;1'].createInstance(Ci.nsIFile);
|
||||
f.initWithPath(dirPath);
|
||||
if (f.exists())
|
||||
f.remove(false) // Remove directory if it is empty
|
||||
}
|
||||
} catch(e) {}
|
||||
},
|
||||
|
||||
restartBrowser: function() {
|
||||
let asSvc = Cc["@mozilla.org/toolkit/app-startup;1"].getService(Ci.nsIAppStartup)
|
||||
asSvc.quit(0x12) // eAttemptQuit (0x02) + eRestart (0x10)
|
||||
},
|
||||
|
||||
getRouterDefaultArgs: function() {
|
||||
let dataDir = this.getI2PConfigPath(true)
|
||||
let exeFile = this.getI2PBinary()
|
||||
let libDir = dataDir.clone()
|
||||
let i2pDir = libDir.clone()
|
||||
libDir.append('lib')
|
||||
let args = []
|
||||
// NOTE: Don't mind spaces as nsIProcess escapes them.
|
||||
args.push(`-Di2p.dir.base=${i2pDir.path}`)
|
||||
logger.log(2, `Path for base is => ${i2pDir.path}`)
|
||||
args.push(`-Duser.dir=${dataDir.path}`) // make PWD equal dataDir
|
||||
let logFile = dataDir.clone()
|
||||
logFile.append('wrapper.log')
|
||||
args.push(`-Dwrapper.logfile=${logFile.path}`)
|
||||
args.push(`-Djetty.home=${i2pDir.path}`)
|
||||
args.push(`-Di2p.dir.config=${dataDir.path}`)
|
||||
args.push(`-Di2p.dir.router=${dataDir.path}`)
|
||||
args.push(`-Di2p.dir.app=${dataDir.path}`)
|
||||
let clientConfigFile = dataDir.clone()
|
||||
clientConfigFile.append('clients.config')
|
||||
let routerCofigFile = dataDir.clone()
|
||||
routerCofigFile.append('router.config')
|
||||
args.push(`-Drouter.clientConfigFile=${clientConfigFile.path}`)
|
||||
args.push(`-Drouter.configLocation=${routerCofigFile.path}`)
|
||||
args.push('-Di2p.dir.portableMode=false')
|
||||
args.push('-Dwrapper.name=i2pbrowser')
|
||||
args.push('-Dwrapper.displayname=I2PBrowser')
|
||||
args.push('-cp')
|
||||
args.push(`${i2pDir.path}:${libDir.path}:${dataDir.path}`)
|
||||
args.push("-Djava.awt.headless=true")
|
||||
args.push("-Dwrapper.console.loglevel=DEBUG")
|
||||
// Main class to execute
|
||||
args.push("net.i2p.router.Router")
|
||||
return args
|
||||
},
|
||||
|
||||
writeFileWithData: (file,data,onComplete,onErrorFunc) => {
|
||||
let converter = Components.classes["@mozilla.org/intl/converter-output-stream;1"].createInstance(Components.interfaces.nsIConverterOutputStream)
|
||||
try {
|
||||
// file is nsIFile, data is a string
|
||||
let foStream = Components.classes["@mozilla.org/network/file-output-stream;1"].createInstance(Components.interfaces.nsIFileOutputStream)
|
||||
|
||||
// use 0x02 | 0x10 to open file for appending.
|
||||
foStream.init(file, 0x02 | 0x08 | 0x20, 0o666, 0)
|
||||
// write, create, truncate
|
||||
// In a c file operation, we have no need to set file mode with or operation,
|
||||
// directly using "r" or "w" usually.
|
||||
converter.init(foStream, 'UTF-8', 0, 0)
|
||||
converter.writeString(data)
|
||||
} catch (err) {
|
||||
if (typeof onErrorFunc === 'function') {
|
||||
onErrorFunc(err)
|
||||
}
|
||||
} finally {
|
||||
converter.close() // this closes foStream
|
||||
if (typeof onComplete === 'function') {
|
||||
onComplete(file)
|
||||
}
|
||||
}
|
||||
},
|
||||
/*
|
||||
spawnRouterWorker: function(handleMessageFunc) {
|
||||
if (this._currentWorker === undefined) {
|
||||
let workerFactory = Components.classes['@mozilla.org/threads/workerfactory;1'].createInstance(Components.interfaces.nsIWorkerFactory)
|
||||
|
||||
let worker = workerFactory.newChromeWorker('resource://i2pbutton/modules/router-worker.js')
|
||||
worker.addEventListener('message', handleMessageFunc)
|
||||
this._currentWorker = worker
|
||||
}
|
||||
return this._currentWorker
|
||||
},
|
||||
*/
|
||||
getI2PBinary: function() {
|
||||
return this.getI2PFile('i2p').clone()
|
||||
},
|
||||
|
||||
getI2PPath: (aI2PFileType, aCreate) => {
|
||||
return this.getI2PFile(aI2PFileType, aCreate).clone()
|
||||
},
|
||||
|
||||
getI2PConfigPath: (create) => {
|
||||
// Going backwards from profile works on all OS.
|
||||
let profDir = Services.dirsvc.get("ProfD", Ci.nsIFile)
|
||||
let dataDir = profDir.parent.parent.clone()
|
||||
dataDir.append('I2P')
|
||||
if (!dataDir.exists() && create) {
|
||||
dataDir.create(dataDir.DIRECTORY_TYPE, 0o775)
|
||||
}
|
||||
|
||||
return dataDir
|
||||
},
|
||||
|
||||
getI2PFile: function(aI2PFileType, aCreate) {
|
||||
if (!aI2PFileType) {
|
||||
aI2PFileType = 'i2p'
|
||||
}
|
||||
let i2pFile
|
||||
let path = ''
|
||||
let useAppDir = false
|
||||
let isRelativePath = true
|
||||
let isUserData = false
|
||||
let appBaseDir = this.appDirectoryObject.clone()
|
||||
|
||||
logger.log(2, `appBaseDir => ${appBaseDir.path}`)
|
||||
|
||||
if (this.isWindows) {
|
||||
//
|
||||
if ("i2p" == aI2PFileType) {
|
||||
appBaseDir.append('I2P')
|
||||
appBaseDir.append('bin')
|
||||
appBaseDir.append('java.exe')
|
||||
return appBaseDir
|
||||
}
|
||||
} else if (this.isMac) {
|
||||
if ("i2p" == aI2PFileType) {
|
||||
path = "Contents/Resources/I2PBrowser/I2P/bin/java"
|
||||
}
|
||||
} else {
|
||||
if ("i2p" == aI2PFileType) {
|
||||
appBaseDir.append('I2P')
|
||||
appBaseDir.append('bin')
|
||||
appBaseDir.append('java')
|
||||
return appBaseDir
|
||||
}
|
||||
}
|
||||
|
||||
i2pFile = LauncherUtilInternal._appDir.clone()
|
||||
try {
|
||||
|
||||
// Turn 'path' into an absolute path.
|
||||
i2pFile = LauncherUtilInternal._appDir.clone()
|
||||
if (this.isMac) {
|
||||
i2pFile.append("I2PBrowser")
|
||||
} else {
|
||||
let lnxpath = i2pFile.clone()
|
||||
lnxpath.append(path)
|
||||
return lnxpath
|
||||
}
|
||||
i2pFile.appendRelativePath(path)
|
||||
logger.log(2, `getI2PFile - Gonna try path ${i2pFile.path}`)
|
||||
|
||||
if (i2pFile.exists()) {
|
||||
try { i2pFile.normalize() } catch(e) {}
|
||||
logger.log(3, `Decided to use file ${i2pFile.path}`)
|
||||
return i2pFile
|
||||
} else {
|
||||
logger.log(4, aI2PFileType + " file not found: "+ i2pFile.path)
|
||||
return ''
|
||||
}
|
||||
|
||||
} catch(e) {
|
||||
logger.log(4, `getI2PFile ${aI2PFileType} failed for ${path}: ${e}`)
|
||||
return null
|
||||
}
|
||||
|
||||
},
|
||||
get internal() {
|
||||
return LauncherUtilInternal
|
||||
},
|
||||
get dataDirectoryObject() {
|
||||
let dataDir = LauncherUtilInternal._dataDir
|
||||
try { dataDir.normalize() } catch(e) {}
|
||||
logger.log(3, `Decided to use file ${dataDir.path}`)
|
||||
return dataDir.clone()
|
||||
},
|
||||
get appDirectoryObject() {
|
||||
return LauncherUtilInternal._appDir.clone()
|
||||
},
|
||||
flushLocalizedStringCache: function()
|
||||
{
|
||||
LauncherUtilInternal.mStringBundle = undefined
|
||||
},
|
||||
// "i2pbutton." is prepended to aStringName.
|
||||
getLocalizedString: function(aStringName)
|
||||
{
|
||||
if (!aStringName)
|
||||
return aStringName;
|
||||
|
||||
try
|
||||
{
|
||||
var key = kPropNamePrefix + aStringName;
|
||||
return TLUtilInternal._stringBundle.GetStringFromName(key);
|
||||
} catch(e) {}
|
||||
|
||||
return aStringName;
|
||||
},
|
||||
|
||||
// "i2pbutton." is prepended to aStringName.
|
||||
getFormattedLocalizedString: function(aStringName, aArray, aLen)
|
||||
{
|
||||
if (!aStringName || !aArray)
|
||||
return aStringName;
|
||||
|
||||
try
|
||||
{
|
||||
var key = kPropNamePrefix + aStringName;
|
||||
return TLUtilInternal._stringBundle.formatStringFromName(key, aArray, aLen)
|
||||
} catch(e) {}
|
||||
|
||||
return aStringName;
|
||||
},
|
||||
|
||||
getLocalizedStringForError: function(aNSResult)
|
||||
{
|
||||
for (let prop in Cr)
|
||||
{
|
||||
if (Cr[prop] == aNSResult)
|
||||
{
|
||||
let key = "nsresult." + prop;
|
||||
let rv = this.getLocalizedString(key);
|
||||
if (rv !== key)
|
||||
return rv;
|
||||
|
||||
return prop; // As a fallback, return the NS_ERROR... name.
|
||||
}
|
||||
}
|
||||
|
||||
return undefined;
|
||||
},
|
||||
}
|
||||
|
||||
Object.freeze(LauncherUtil)
|
||||
|
||||
let LauncherUtilInternal = {
|
||||
kThunderbirdID: "{3550f703-e582-4d05-9a08-453d09bdfdc6}",
|
||||
kInstantbirdID: "{33cb9019-c295-46dd-be21-8c4936574bee}",
|
||||
|
||||
mOS: '',
|
||||
mStringBundle : null,
|
||||
mPrefsSvc : null,
|
||||
mAppDir: null, // nsIFile (cached; access via this._appDir)
|
||||
mDataDir: null, // nsIFile (cached; access via this._dataDir)
|
||||
mIsUserDataOutsideOfAppDir: undefined,
|
||||
|
||||
_init: function() {
|
||||
// Init
|
||||
this.mPrefsSvc = Cc["@mozilla.org/preferences-service;1"].getService(Ci.nsIPrefBranch)
|
||||
this._appDir
|
||||
this._dataDir
|
||||
},
|
||||
|
||||
get _OS()
|
||||
{
|
||||
if (!this.mOS) try
|
||||
{
|
||||
var xr = Cc["@mozilla.org/xre/app-info;1"].getService(Ci.nsIXULRuntime);
|
||||
this.mOS = xr.OS;
|
||||
const xr = Cc["@mozilla.org/xre/app-info;1"].getService(Ci.nsIXULRuntime)
|
||||
this.mOS = xr.OS
|
||||
} catch (e) {}
|
||||
|
||||
return this.mOS;
|
||||
},
|
||||
|
||||
get _isMac()
|
||||
{
|
||||
return ("Darwin" == this._OS);
|
||||
return this.mOS
|
||||
},
|
||||
get _stringBundle()
|
||||
{
|
||||
if (!this.mStringBundle)
|
||||
{
|
||||
this.mStringBundle = Cc["@mozilla.org/intl/stringbundle;1"]
|
||||
.getService(Ci.nsIStringBundleService)
|
||||
.createBundle(kPropBundleURI);
|
||||
this.mStringBundle = Cc["@mozilla.org/intl/stringbundle;1"].getService(Ci.nsIStringBundleService).createBundle(kPropBundleURI)
|
||||
}
|
||||
|
||||
return this.mStringBundle;
|
||||
},
|
||||
get _dataDir()
|
||||
{
|
||||
if (!this.mDataDir)
|
||||
{
|
||||
let ds = Cc["@mozilla.org/file/directory_service;1"]
|
||||
.getService(Ci.nsIProperties);
|
||||
let profDir = ds.get("ProfD", Ci.nsIFile);
|
||||
this.mDataDir = profDir.parent.parent;
|
||||
|
||||
get _isUserDataOutsideOfAppDir() {
|
||||
if (this.mIsUserDataOutsideOfAppDir == undefined) {
|
||||
// Determine if we are using a "side-by-side" data model by checking
|
||||
// whether the user profile is outside of the app directory.
|
||||
try {
|
||||
let ds = Cc["@mozilla.org/file/directory_service;1"].getService(Ci.nsIProperties)
|
||||
let profDir = ds.get("ProfD", Ci.nsIFile)
|
||||
this.mIsUserDataOutsideOfAppDir = !this._appDir.contains(profDir);
|
||||
} catch (e) {
|
||||
this.mIsUserDataOutsideOfAppDir = false;
|
||||
}
|
||||
}
|
||||
|
||||
return this.mDataDir;
|
||||
return this.mIsUserDataOutsideOfAppDir;
|
||||
}, // get _isUserDataOutsideOfAppDir
|
||||
|
||||
// Returns an nsIFile that points to the application directory.
|
||||
// May throw.
|
||||
get _appDir() {
|
||||
if (!this.mAppDir) {
|
||||
let topDir = Cc["@mozilla.org/file/directory_service;1"].getService(Ci.nsIProperties).get("CurProcD", Ci.nsIFile)
|
||||
let appInfo = Cc["@mozilla.org/xre/app-info;1"].getService(Ci.nsIXULAppInfo)
|
||||
// On Linux and Windows, we want to return the Browser/ directory.
|
||||
// Because topDir ("CurProcD") points to Browser/browser on those
|
||||
// platforms, we need to go up one level.
|
||||
// On Mac OS, we want to return the I2PBrowser.app/ directory.
|
||||
// Because topDir points to Contents/Resources/browser on Mac OS,
|
||||
// we need to go up 3 levels.
|
||||
let i2bbBrowserDepth = (this._OS == "Darwin") ? 3 : 1;
|
||||
if ((appInfo.ID == this.kThunderbirdID) ||
|
||||
(appInfo.ID == this.kInstantbirdID)) {
|
||||
// On Thunderbird/Instantbird, the topDir is the root dir and not
|
||||
// browser/, so we need to iterate one level less than Firefox.
|
||||
--i2bbBrowserDepth;
|
||||
}
|
||||
|
||||
while (i2bbBrowserDepth > 0) {
|
||||
let didRemove = (topDir.leafName != ".")
|
||||
topDir = topDir.parent
|
||||
if (didRemove)
|
||||
i2bbBrowserDepth--
|
||||
}
|
||||
|
||||
this.mAppDir = topDir
|
||||
}
|
||||
|
||||
return this.mAppDir
|
||||
}, // get _appDir
|
||||
|
||||
// Returns an nsIFile that points to the I2PBrowser-Data/ directory.
|
||||
// This function is only used when this._isUserDataOutsideOfAppDir == true.
|
||||
// May throw.
|
||||
get _dataDir() {
|
||||
if (!this.mDataDir) {
|
||||
let ds = Cc["@mozilla.org/file/directory_service;1"].getService(Ci.nsIProperties)
|
||||
let profDir = ds.get("ProfD", Ci.nsIFile)
|
||||
this.mDataDir = profDir.parent.parent.clone()
|
||||
}
|
||||
return this.mDataDir.clone()
|
||||
}, // get _dataDir
|
||||
|
||||
_isWindowVisible: function(aWindow) {
|
||||
if (!aWindow)
|
||||
return false
|
||||
|
||||
try {
|
||||
let winUtils = aWindow.QueryInterface(Ci.nsIInterfaceRequestor).getInterface(Ci.nsIDOMWindowUtils)
|
||||
return winUtils.isParentWindowMainWidgetVisible
|
||||
} catch(e) {}
|
||||
|
||||
return false
|
||||
},
|
||||
}
|
||||
|
||||
LauncherUtilInternal._init()
|
||||
|
||||
|
164
src/modules/noscript-control.js
Normal file
164
src/modules/noscript-control.js
Normal file
@ -0,0 +1,164 @@
|
||||
// # NoScript settings control (for binding to Security Slider)
|
||||
|
||||
/* jshint esversion:6 */
|
||||
|
||||
// ## Utilities
|
||||
|
||||
const { utils: Cu } = Components;
|
||||
const { Services } = Cu.import("resource://gre/modules/Services.jsm", {});
|
||||
const { LegacyExtensionContext } =
|
||||
Cu.import("resource://gre/modules/LegacyExtensionsUtils.jsm", {});
|
||||
const { bindPref } =
|
||||
Cu.import("resource://i2pbutton/modules/utils.js", {});
|
||||
let logger = Components.classes["@geti2p.net/i2pbutton-logger;1"]
|
||||
.getService(Components.interfaces.nsISupports).wrappedJSObject;
|
||||
let log = (level, msg) => logger.log(level, msg);
|
||||
|
||||
// ## NoScript settings
|
||||
|
||||
// Minimum and maximum capability states as controlled by NoScript.
|
||||
const max_caps = ["fetch", "font", "frame", "media", "object", "other", "script", "webgl"];
|
||||
const min_caps = ["frame", "other"];
|
||||
|
||||
// Untrusted capabilities for [Standard, Safer, Safest] safety levels.
|
||||
const untrusted_caps = [
|
||||
max_caps, // standard safety: neither http nor https
|
||||
["frame", "font", "object", "other"], // safer: http
|
||||
min_caps, // safest: neither http nor https
|
||||
];
|
||||
|
||||
// Default capabilities for [Standard, Safer, Safest] safety levels.
|
||||
const default_caps = [
|
||||
max_caps, // standard: both http and https
|
||||
["fetch", "font", "frame", "object", "other", "script"], // safer: https only
|
||||
min_caps, // safest: both http and https
|
||||
];
|
||||
|
||||
// __noscriptSettings(safetyLevel)__.
|
||||
// Produces NoScript settings with policy according to
|
||||
// the safetyLevel which can be:
|
||||
// 0 = Standard, 1 = Safer, 2 = Safest
|
||||
//
|
||||
// At the "Standard" safety level, we leave all sites at
|
||||
// default with maximal capabilities. Essentially no content
|
||||
// is blocked.
|
||||
//
|
||||
// At "Safer", we set all http sites to untrusted,
|
||||
// and all https sites to default. Scripts are only permitted
|
||||
// on https sites. Neither type of site is supposed to allow
|
||||
// media, but both allow fonts (as we used in legacy NoScript).
|
||||
//
|
||||
// At "Safest", all sites are at default with minimal
|
||||
// capabilities. Most things are blocked.
|
||||
let noscriptSettings = safetyLevel => (
|
||||
{
|
||||
"__meta": {
|
||||
"name": "updateSettings",
|
||||
"recipientInfo": null
|
||||
},
|
||||
"policy": {
|
||||
"DEFAULT": {
|
||||
"capabilities": default_caps[safetyLevel],
|
||||
"temp": false
|
||||
},
|
||||
"TRUSTED": {
|
||||
"capabilities": max_caps,
|
||||
"temp": false
|
||||
},
|
||||
"UNTRUSTED": {
|
||||
"capabilities": untrusted_caps[safetyLevel],
|
||||
"temp": false
|
||||
},
|
||||
"sites": {
|
||||
"trusted": [],
|
||||
"untrusted": [[], ["http:"], []][safetyLevel],
|
||||
"custom": {},
|
||||
"temp": []
|
||||
},
|
||||
"enforced": true,
|
||||
"autoAllowTop": false
|
||||
},
|
||||
"isI2PBrowser": true,
|
||||
"tabId": -1
|
||||
});
|
||||
|
||||
// ## Communications
|
||||
|
||||
// The extension ID for NoScript (WebExtension)
|
||||
const noscriptID = "{73a6fe31-595d-460b-a920-fcc0f8843232}";
|
||||
|
||||
// Ensure binding only occurs once.
|
||||
let initialized = false;
|
||||
|
||||
// __initialize()__.
|
||||
// The main function that binds the NoScript settings to the security
|
||||
// slider pref state.
|
||||
var initialize = () => {
|
||||
if (initialized) {
|
||||
return;
|
||||
}
|
||||
initialized = true;
|
||||
|
||||
try {
|
||||
// A mock extension object that can communicate with another extension
|
||||
// via the WebExtensions sendMessage/onMessage mechanism.
|
||||
let extensionContext = new LegacyExtensionContext({ id : noscriptID });
|
||||
|
||||
// The component that handles WebExtensions' sendMessage.
|
||||
let messageManager = extensionContext.messenger.messageManagers[0];
|
||||
|
||||
// __setNoScriptSettings(settings)__.
|
||||
// NoScript listens for internal settings with onMessage. We can send
|
||||
// a new settings JSON object according to NoScript's
|
||||
// protocol and these are accepted! See the use of
|
||||
// `browser.runtime.onMessage.addListener(...)` in NoScript's bg/main.js.
|
||||
let sendNoScriptSettings = settings =>
|
||||
extensionContext.messenger.sendMessage(messageManager, settings, noscriptID);
|
||||
|
||||
// __setNoScriptSafetyLevel(safetyLevel)__.
|
||||
// Set NoScript settings according to a particular safety level
|
||||
// (security slider level): 0 = Standard, 1 = Safer, 2 = Safest
|
||||
let setNoScriptSafetyLevel = safetyLevel =>
|
||||
sendNoScriptSettings(noscriptSettings(safetyLevel));
|
||||
|
||||
// __securitySliderToSafetyLevel(sliderState)__.
|
||||
// Converts the "extensions.i2pbutton.security_slider" pref value
|
||||
// to a "safety level" value: 0 = Standard, 1 = Safer, 2 = Safest
|
||||
let securitySliderToSafetyLevel = sliderState =>
|
||||
[undefined, 2, 1, 1, 0][sliderState];
|
||||
|
||||
// Wait for the first message from NoScript to arrive, and then
|
||||
// bind the security_slider pref to the NoScript settings.
|
||||
let messageListener = (a,b,c) => {
|
||||
try {
|
||||
log(3, `Message received from NoScript: ${JSON.stringify([a,b,c])}`);
|
||||
if (!["started", "pageshow"].includes(a.__meta.name)) {
|
||||
return;
|
||||
}
|
||||
extensionContext.api.browser.runtime.onMessage.removeListener(messageListener);
|
||||
let noscriptPersist = Services.prefs.getBoolPref("extensions.i2pbutton.noscript_persist", false);
|
||||
let noscriptInited = Services.prefs.getBoolPref("extensions.i2pbutton.noscript_inited", false);
|
||||
// Set the noscript safety level once if we have never run noscript
|
||||
// before, or if we are not allowing noscript per-site settings to be
|
||||
// persisted between browser sessions. Otherwise make sure that the
|
||||
// security slider position, if changed, will rewrite the noscript
|
||||
// settings.
|
||||
bindPref("extensions.i2pbutton.security_slider",
|
||||
sliderState => setNoScriptSafetyLevel(securitySliderToSafetyLevel(sliderState)),
|
||||
!noscriptPersist || !noscriptInited);
|
||||
if (!noscriptInited) {
|
||||
Services.prefs.setBoolPref("extensions.i2pbutton.noscript_inited", true);
|
||||
}
|
||||
} catch (e) {
|
||||
log(5, e.message);
|
||||
}
|
||||
};
|
||||
extensionContext.api.browser.runtime.onMessage.addListener(messageListener);
|
||||
log(3, "Listening for message from NoScript.");
|
||||
} catch (e) {
|
||||
log(5, e.message);
|
||||
}
|
||||
};
|
||||
|
||||
// Export initialize() function for external use.
|
||||
let EXPORTED_SYMBOLS = ["initialize"];
|
135
src/modules/security-prefs.js
Normal file
135
src/modules/security-prefs.js
Normal file
@ -0,0 +1,135 @@
|
||||
// # Security Settings prefs (as controlled by the Security Slider)
|
||||
|
||||
// ### Utilities
|
||||
|
||||
let {classes: Cc, utils: Cu } = Components;
|
||||
let { getBoolPref, setBoolPref, getIntPref, setIntPref } =
|
||||
Cu.import("resource://gre/modules/Services.jsm", {}).Services.prefs;
|
||||
let { bindPref, bindPrefAndInit } =
|
||||
Cu.import("resource://i2pbutton/modules/utils.js", {});
|
||||
let logger = Components.classes["@geti2p.net/i2pbutton-logger;1"]
|
||||
.getService(Components.interfaces.nsISupports).wrappedJSObject;
|
||||
let log = (level, msg) => logger.log(level, msg);
|
||||
|
||||
// ### Constants
|
||||
|
||||
// __kSecuritySettings__.
|
||||
// A table of all prefs bound to the security slider, and the value
|
||||
// for each security setting. Note that 2-m and 3-m are identical,
|
||||
// corresponding to the old 2-medium-high setting. We also separately
|
||||
// bind NoScript settings to the extensions.i2pbutton.security_slider
|
||||
// (see noscript-control.js).
|
||||
const kSecuritySettings = {
|
||||
// Preference name : [0, 1-high 2-m 3-m 4-low]
|
||||
"javascript.options.ion" : [, false, false, false, true ],
|
||||
"javascript.options.baselinejit" : [, false, false, false, true ],
|
||||
"javascript.options.native_regexp" : [, false, false, false, true ],
|
||||
"media.webaudio.enabled" : [, false, false, false, true ],
|
||||
"mathml.disabled" : [, true, true, true, false],
|
||||
"gfx.font_rendering.opentype_svg.enabled" : [, false, false, false, true ],
|
||||
"svg.disabled" : [, true, false, false, false],
|
||||
};
|
||||
|
||||
// The Security Settings prefs in question.
|
||||
const kSliderPref = "extensions.i2pbutton.security_slider";
|
||||
const kCustomPref = "extensions.i2pbutton.security_custom";
|
||||
|
||||
// ### Prefs
|
||||
|
||||
// __write_setting_to_prefs(settingIndex)__.
|
||||
// Take a given setting index and write the appropriate pref values
|
||||
// to the pref database.
|
||||
var write_setting_to_prefs = function (settingIndex) {
|
||||
Object.keys(kSecuritySettings).forEach(
|
||||
prefName => setBoolPref(
|
||||
prefName, kSecuritySettings[prefName][settingIndex]));
|
||||
};
|
||||
|
||||
// __read_setting_from_prefs()__.
|
||||
// Read the current pref values, and decide if any of our
|
||||
// security settings matches. Otherwise return null.
|
||||
var read_setting_from_prefs = function () {
|
||||
let prefNames = Object.keys(kSecuritySettings);
|
||||
for (let settingIndex of [1, 2, 3, 4]) {
|
||||
let possibleSetting = true;
|
||||
// For the given settingIndex, check if all current pref values
|
||||
// match the setting.
|
||||
for (let prefName of prefNames) {
|
||||
if (kSecuritySettings[prefName][settingIndex] !==
|
||||
getBoolPref(prefName)) {
|
||||
possibleSetting = false;
|
||||
}
|
||||
}
|
||||
if (possibleSetting) {
|
||||
// We have a match!
|
||||
return settingIndex;
|
||||
}
|
||||
}
|
||||
// No matching setting; return null.
|
||||
return null;
|
||||
};
|
||||
|
||||
// __watch_security_prefs(onSettingChanged)__.
|
||||
// Whenever a pref bound to the security slider changes, onSettingChanged
|
||||
// is called with the new security setting value (1,2,3,4 or null).
|
||||
// Returns a zero-arg function that ends this binding.
|
||||
var watch_security_prefs = function (onSettingChanged) {
|
||||
let prefNames = Object.keys(kSecuritySettings);
|
||||
let unbindFuncs = [];
|
||||
for (let prefName of prefNames) {
|
||||
unbindFuncs.push(bindPrefAndInit(
|
||||
prefName, () => onSettingChanged(read_setting_from_prefs())));
|
||||
}
|
||||
// Call all the unbind functions.
|
||||
return () => unbindFuncs.forEach(unbind => unbind());
|
||||
};
|
||||
|
||||
// __initialized__.
|
||||
// Have we called initialize() yet?
|
||||
var initialized = false;
|
||||
|
||||
// __initialize()__.
|
||||
// Defines the behavior of "extensions.i2pbutton.security_custom",
|
||||
// "extensions.i2pbutton.security_slider", and the security-sensitive
|
||||
// prefs declared in kSecuritySettings.
|
||||
var initialize = function () {
|
||||
// Only run once.
|
||||
if (initialized) {
|
||||
return;
|
||||
}
|
||||
log(4, "Initializing security-prefs.js");
|
||||
initialized = true;
|
||||
// When security_custom is set to false, apply security_slider setting
|
||||
// to the security-sensitive prefs.
|
||||
bindPrefAndInit(kCustomPref, function (custom) {
|
||||
if (custom === false) {
|
||||
write_setting_to_prefs(getIntPref(kSliderPref));
|
||||
}
|
||||
});
|
||||
// If security_slider is given a new value, then security_custom should
|
||||
// be set to false.
|
||||
bindPref(kSliderPref, function (prefIndex) {
|
||||
setBoolPref(kCustomPref, false);
|
||||
write_setting_to_prefs(prefIndex);
|
||||
});
|
||||
// If a security-sensitive pref changes, then decide if the set of pref values
|
||||
// constitutes a security_slider setting or a custom value.
|
||||
watch_security_prefs(settingIndex => {
|
||||
if (settingIndex === null) {
|
||||
setBoolPref(kCustomPref, true);
|
||||
} else {
|
||||
setIntPref(kSliderPref, settingIndex);
|
||||
setBoolPref(kCustomPref, false);
|
||||
}
|
||||
});
|
||||
// Migrate from old medium-low (3) to new medium (2).
|
||||
if (getBoolPref("extensions.i2pbutton.security_custom") === false &&
|
||||
getIntPref("extensions.i2pbutton.security_slider") === 3) {
|
||||
setIntPref("extensions.i2pbutton.security_slider", 2);
|
||||
write_setting_to_prefs(2);
|
||||
}
|
||||
log(4, "security-prefs.js initialization complete");
|
||||
};
|
||||
|
||||
// Export initialize() function for external use.
|
||||
let EXPORTED_SYMBOLS = ["initialize"];
|
@ -3,12 +3,52 @@ const { Cu: utils, Cr: results } = Components
|
||||
|
||||
// ### Import Mozilla Services
|
||||
Cu.import("resource://gre/modules/Services.jsm")
|
||||
Cu.import("resource://gre/modules/FileUtils.jsm")
|
||||
//Cu.import("resource://gre/modules/FileUtils.jsm")
|
||||
|
||||
// ### Import global URL
|
||||
Cu.importGlobalProperties(["URL"])
|
||||
|
||||
const ioService = Components.classes['@mozilla.org/network/io-service;1'].getService(Components.interfaces.nsIIOService)
|
||||
//const ioService = Components.classes['@mozilla.org/network/io-service;1'].getService(Components.interfaces.nsIIOService)
|
||||
|
||||
String.prototype.trim = function () {
|
||||
return this.replace(/^\s*/, "").replace(/\s*$/, "");
|
||||
}
|
||||
|
||||
/*
|
||||
Array.prototype.contains = function(obj) {
|
||||
var i = this.length;
|
||||
while (i--) {
|
||||
if (this[i] === obj) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
*/
|
||||
|
||||
function loadScript(name, context) {
|
||||
// Create the Sandbox
|
||||
let sandbox = Components.utils.Sandbox(context, {
|
||||
sandboxPrototype: context,
|
||||
wantXrays: false
|
||||
});
|
||||
// Get the caller's filename
|
||||
let file = Components.caller.stack.filename;
|
||||
// Strip off any prefixes added by the sub-script loader
|
||||
// and the trailing filename
|
||||
let directory = file.replace(/.* -> |[^\/]+$/g, "");
|
||||
Services.scriptloader.loadSubScript(directory + name, sandbox, "UTF-8");
|
||||
}
|
||||
// The following function will import an arbitrary module into a singleton object,
|
||||
// which it returns. If the argument is not an absolute path, the module is
|
||||
// imported relative to the caller's filename.
|
||||
function module(uri) {
|
||||
if (!/^[a-z-]+:/.exec(uri))
|
||||
uri = /([^ ]+\/)[^\/]+$/.exec(Components.stack.caller.filename)[1] + uri + ".jsm";
|
||||
let obj = {};
|
||||
Components.utils.import(uri, obj);
|
||||
return obj;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
@ -40,6 +80,38 @@ const getProfileDir = function() {
|
||||
return localDir.path
|
||||
}
|
||||
|
||||
function openFile(path, mode) {
|
||||
let file = Cc["@mozilla.org/file/local;1"].
|
||||
createInstance(Ci.nsILocalFile);
|
||||
file.initWithPath(path);
|
||||
let stream = Cc["@mozilla.org/network/file-output-stream;1"].
|
||||
createInstance(Ci.nsIFileOutputStream);
|
||||
stream.init(file, mode, -1, 0);
|
||||
return stream
|
||||
}
|
||||
|
||||
function readfile(path) {
|
||||
var file = Components.classes['@mozilla.org/file/local;1'].createInstance(Components.interfaces.nsIFile);
|
||||
file.initWithPath(path);
|
||||
var fileStream = Components.classes['@mozilla.org/network/file-input-stream;1']
|
||||
.createInstance(Components.interfaces.nsIFileInputStream);
|
||||
fileStream.init(file, 1, 0, false);
|
||||
var binaryStream = Components.classes['@mozilla.org/binaryinputstream;1']
|
||||
.createInstance(Components.interfaces.nsIBinaryInputStream);
|
||||
binaryStream.setInputStream(fileStream);
|
||||
var array = binaryStream.readByteArray(fileStream.available());
|
||||
binaryStream.close();
|
||||
fileStream.close();
|
||||
return array_to_hexdigits(array);
|
||||
}
|
||||
|
||||
// Bug 1506 P4: Control port interaction. Needed for New Identity.
|
||||
function array_to_hexdigits(array) {
|
||||
return array.map(function(c) {
|
||||
return String("0" + c.toString(16)).slice(-2)
|
||||
}).join('');
|
||||
}
|
||||
|
||||
//window.open("chrome://browser/content/browser.xul", "bmarks", "chrome,width=600,height=300")
|
||||
|
||||
// __prefs__. A shortcut to Mozilla Services.prefs.
|
||||
@ -133,8 +205,7 @@ var showDialog = function (parent, url, name, features) {
|
||||
existingDialog.focus();
|
||||
return existingDialog;
|
||||
} else {
|
||||
let newDialog = parent.openDialog.apply(parent,
|
||||
Array.slice(arguments, 1));
|
||||
let newDialog = parent.openDialog.apply(parent, Array.slice(arguments, 1));
|
||||
dialogsByName[name] = newDialog;
|
||||
return newDialog;
|
||||
}
|
||||
@ -143,3 +214,9 @@ var showDialog = function (parent, url, name, features) {
|
||||
var openTabWithFocus = function (url) {
|
||||
gBrowser.selectedTab = gBrowser.addTab(url)
|
||||
}
|
||||
|
||||
|
||||
// Export utility functions for external use.
|
||||
let EXPORTED_SYMBOLS = ['bindPref', 'bindPrefAndInit', 'getEnv', 'getLocale',
|
||||
'loadScript', 'module', 'readfile', 'getProfileDir',
|
||||
'getPrefValue', 'observe', 'showDialog'];
|
10
src/searchplugins/legwork.xml
Normal file
10
src/searchplugins/legwork.xml
Normal file
@ -0,0 +1,10 @@
|
||||
<SearchPlugin xmlns="http://www.mozilla.org/2006/browser/search/">
|
||||
<ShortName>Legwork</ShortName>
|
||||
<Description>Legwork YaCy Search Engine</Description>
|
||||
<InputEncoding>UTF-8</InputEncoding>
|
||||
<Image width="16" height="16">
|
||||
<!-- Insert data:image/x-icon;base64,blablabla here -->
|
||||
</Image>
|
||||
<Url type="text/html" method="GET" template="http://legwork.i2p/yacysearch.html?query={searchTerms}"/>
|
||||
<SearchForm>http://legwork.i2p/</SearchForm>
|
||||
</SearchPlugin>
|
10
src/searchplugins/seeker.xml
Normal file
10
src/searchplugins/seeker.xml
Normal file
@ -0,0 +1,10 @@
|
||||
<SearchPlugin xmlns="http://www.mozilla.org/2006/browser/search/">
|
||||
<ShortName>Seeker</ShortName>
|
||||
<Description>Seeker Search Engine</Description>
|
||||
<InputEncoding>UTF-8</InputEncoding>
|
||||
<Image width="16" height="16">
|
||||
<!-- Insert data:image/x-icon;base64,blablabla here -->
|
||||
</Image>
|
||||
<Url type="text/html" method="GET" template="http://seeker.i2p/index.php?query={searchTerms}"/>
|
||||
<SearchForm>http://seeker.i2p/</SearchForm>
|
||||
</SearchPlugin>
|
Reference in New Issue
Block a user