Compare commits
57 Commits
Author | SHA1 | Date | |
---|---|---|---|
103a92ba41 | |||
cbf0c1e9a2 | |||
886ddf5673 | |||
26458e21ef | |||
b411b12c08 | |||
76a94416a5 | |||
943261b762 | |||
3455a60ff0 | |||
29809d1d0f | |||
6b9fbb2b85 | |||
459c9563ba | |||
8bfed9885c | |||
1b72915e7b | |||
cf1e0666ab | |||
571bd40736 | |||
3b417ca6f4 | |||
1d90ec8eef | |||
f8db8d8b5d | |||
68300c10a8 | |||
84e4a262b6 | |||
d38605742d | |||
f29c7c001e | |||
9834a845ff | |||
4c213d6eca | |||
65b5162cad | |||
bf5838f555 | |||
1a7b1b8126 | |||
b6c7edf6af | |||
755440fbd6 | |||
a7d46901df | |||
94c4c0dd50 | |||
e2ab83ab39 | |||
0b5b46260e | |||
38c8039f95 | |||
52e51d4ff2 | |||
cb6cfb3213 | |||
f3a3b2e34c | |||
a639a35bb7 | |||
e441bab7ec | |||
d4d9f03afa | |||
6825e9eab4 | |||
0db34c6506 | |||
90eb1f7182 | |||
411d6b5549 | |||
86a1336e01 | |||
77c0ed7893 | |||
11d059cf9c | |||
7a2b341839 | |||
54527c6af3 | |||
fb1bbaf574 | |||
a23de26582 | |||
4864a86096 | |||
2b57d75c08 | |||
f2bd48ada9 | |||
3a38a01c51 | |||
eabb67ceb9 | |||
191a6e15e9 |
18
LICENSE
Normal file
18
LICENSE
Normal file
@ -0,0 +1,18 @@
|
||||
Copyright 2019 The I2P Project, meeh, idk
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and associated documentation files (the "Software"), to deal in
|
||||
the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
54
Readme.md
54
Readme.md
@ -1,12 +1,60 @@
|
||||
# I2Pbutton
|
||||
|
||||
I2PButton is an XUL plugin which we incorporate into the I2P Browser in order
|
||||
to enable I2P-specific features and improve the user experience of the I2P
|
||||
Browser. It can only be used in I2P Browser where it is specifically enabled,
|
||||
but developers can build the plugin from source and side-load it to test their
|
||||
changes.
|
||||
|
||||
## Development howto
|
||||
|
||||
You can build and update i2pbutton without the need of recompiling firefox for most tasks luckly :)
|
||||
You can build and update i2pbutton without the need of recompiling I2P browser
|
||||
for most tasks.
|
||||
|
||||
To do this build it and copy it into your data directory. Note that these
|
||||
examples assume that you only have one version of the .xpi file in the pkg/
|
||||
directory where the finished product is built.
|
||||
|
||||
### OSX
|
||||
|
||||
On OSX, you will have an I2P Browser Data directory under ~/I2PBrowser-Data and
|
||||
you can swap the plugin by copying it over the plugin in your working profile,
|
||||
like in the following example:
|
||||
|
||||
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
|
||||
cp pkg/i2pbutton-*.xpi ~/I2PBrowser-Data/Browser/914o5i1s.default/extensions/i2pbutton@geti2p.net.xpi
|
||||
```
|
||||
|
||||
### Linux
|
||||
|
||||
Although the browser on Linux can be run from any location available to the
|
||||
user, it was probably downloaded and extracted to your ~/Downloads/ directory.
|
||||
If that is the case, then you may simply:
|
||||
|
||||
```
|
||||
./makexpi.sh
|
||||
find $HOME/Downloads/i2p-browser_en-US/ -name 'i2pbutton*.xpi' -exec cp -v {} i2pbutton.xpi.bak \;
|
||||
find $HOME/Downloads/i2p-browser_en-US/ -name 'i2pbutton*.xpi' -exec cp -v pkg/i2pbutton-*.xpi {} \;
|
||||
```
|
||||
|
||||
to automatically replace the I2PButton in your I2P browser with your working
|
||||
copy. If you want to reverse this process, then:
|
||||
|
||||
```
|
||||
find $HOME/Downloads/i2p-browser_en-US/ -name 'i2pbutton*.xpi' -exec cp -v i2pbutton.xpi.bak {} \;
|
||||
```
|
||||
|
||||
### Windows
|
||||
|
||||
On Windows, your browser is usually installed to your Desktop where it's
|
||||
configuration can be accessed. Your profile will be in the following directory
|
||||
under, along with a default profile called "profile.default." You should usually
|
||||
use the working profile directory and not the default.
|
||||
|
||||
To test local changes, you need to copy the pkg/i2pbutton-*.xpi over the
|
||||
i2pbutton@geti2p.net.xpi
|
||||
|
||||
```
|
||||
Desktop\I2P Browser Beta\Browser\I2PBrowser\Data\Browser\%profile_directory%\extensions\
|
||||
```
|
@ -1,57 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?> <!-- -*- Mode: HTML -*- -->
|
||||
<?xml-stylesheet href="chrome://i2pbutton/skin/aboutDialog.css" type="text/css"?>
|
||||
|
||||
<!DOCTYPE window [
|
||||
<!ENTITY % brandDTD SYSTEM "chrome://branding/locale/brand.dtd" >
|
||||
%brandDTD;
|
||||
<!ENTITY % aboutDialogDTD SYSTEM "chrome://i2pbutton/locale/aboutDialog.dtd" >
|
||||
%aboutDialogDTD;
|
||||
]>
|
||||
|
||||
<overlay id="main-overlay"
|
||||
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
|
||||
<vbox id="rightBox">
|
||||
<vbox id="detailsBox">
|
||||
<description class="text-blurb" id="projectDesc">
|
||||
&project.start;
|
||||
<label class="text-link"
|
||||
href="https://geti2p.net/">
|
||||
&project.tpoLink;
|
||||
</label>&project.end;
|
||||
</description>
|
||||
<description class="text-blurb" id="helpDesc">
|
||||
&help.start;
|
||||
<label class="text-link"
|
||||
href="https://geti2p.net/en/get-involved/donate">
|
||||
&help.donateLink;
|
||||
</label>
|
||||
&help.or;
|
||||
<label class="text-link"
|
||||
href="https://geti2p.net/en/get-involved">
|
||||
&help.getInvolvedLink;
|
||||
</label>&help.end;
|
||||
</description>
|
||||
</vbox>
|
||||
</vbox>
|
||||
|
||||
<vbox id="bottomBox">
|
||||
<hbox id="newBottom" pack="center" position="1">
|
||||
<label class="text-link bottom-link"
|
||||
href="https://geti2p.net/en/faq">
|
||||
&bottomLinks.questions;
|
||||
</label>
|
||||
<label class="text-link bottom-link"
|
||||
href="https://geti2p.net/en/get-involved">
|
||||
&bottomLinks.grow;
|
||||
</label>
|
||||
<label class="text-link bottom-link"
|
||||
href="about:license">
|
||||
&bottomLinks.license;
|
||||
</label>
|
||||
</hbox>
|
||||
<description id="trademarkI2p" insertafter="trademark">
|
||||
Test test.
|
||||
</description>
|
||||
</vbox>
|
||||
</overlay>
|
||||
|
@ -79,6 +79,12 @@ var AboutI2pListener = {
|
||||
body.removeAttribute("i2pconsoleon")
|
||||
}
|
||||
|
||||
if (aData.i2pProxyOn) {
|
||||
body.setAttribute("i2pproxyon", "yes")
|
||||
} else {
|
||||
body.removeAttribute("i2pproxyon")
|
||||
}
|
||||
|
||||
if (aData.updateChannel)
|
||||
body.setAttribute("updatechannel", aData.updateChannel);
|
||||
else
|
||||
|
@ -28,44 +28,113 @@ window.addEventListener("pageshow", function() {
|
||||
</script>
|
||||
</head>
|
||||
<body dir="&locale.dir;">
|
||||
<div>
|
||||
<!--<div>-->
|
||||
<div class='background'>
|
||||
<div class='content'>
|
||||
<div class='section-header'>
|
||||
<h1>&aboutI2p.browser_name;</h1>
|
||||
</div>
|
||||
<div id="i2pbrowser-version"></div>
|
||||
<p>
|
||||
&aboutI2p.browser_name; ( &aboutI2p.browser_short_name; ) &aboutI2p.browser_description; <br />
|
||||
&aboutI2p.startup; <a href="&aboutI2p.routerconsole;">&aboutI2p.rc;</a> &aboutI2p.startup_b;
|
||||
|
||||
<h3>&aboutI2p.links;</h3>
|
||||
<p>
|
||||
<div id="i2pbrowser-description">
|
||||
<p id="description">&aboutI2p.browser_name; ( &aboutI2p.browser_short_name; ) &aboutI2p.browser_description;</p>
|
||||
<p class="version">&aboutI2p.browser_version_declare; &aboutI2p.browser_version;</p>
|
||||
<p class="beta">&aboutI2p.warn_experimental;</p>
|
||||
</div>
|
||||
<div id="readyness">
|
||||
<div id="consoleOn" class="hideIfI2PConsoleOff">&aboutI2p.all_checks_ok;</div>
|
||||
<div id="proxyUnready" class="hideIfI2PProxyOn">&aboutI2p.startup;</div>
|
||||
<div id="proxyReady" class="hideIfI2PProxyOff">&aboutI2p.proxyready;</div>
|
||||
</div>
|
||||
<div id="onboarding" class="hideIfI2PConsoleOff">
|
||||
<h3 id="onboardingTitle">&aboutI2p.onboardingTitle;</h3>
|
||||
<h4 id="onboardingZero"><button class="showhider" onclick="flipVisibility('onboardingContentZero')">&aboutI2p.ZeroTitle;</button></h4>
|
||||
<p id="onboardingContentZero" class="onboardingContent">&aboutI2p.Zero;</p>
|
||||
<h4 id="onboardingOne"><button class="showhider" onclick="flipVisibility('onboardingContentOne')">&aboutI2p.OneTitle;</button></h4>
|
||||
<p id="onboardingContentOne" class="onboardingContent">&aboutI2p.One;</p>
|
||||
<h4 id="onboardingTwo"><button class="showhider" onclick="flipVisibility('onboardingContentTwo')">&aboutI2p.TwoTitle;</button></h4>
|
||||
<p id="onboardingContentTwo" class="onboardingContent">&aboutI2p.Two;</p>
|
||||
<h4 id="onboardingThree"><button class="showhider" onclick="flipVisibility('onboardingContentThree')">&aboutI2p.ThreeTitle;</button></h4>
|
||||
<p id="onboardingContentThree" class="onboardingContent">&aboutI2p.Three;</p>
|
||||
<h4 id="onboardingFour"><button class="showhider" onclick="flipVisibility('onboardingContentFour')">&aboutI2p.FourTitle;</button></h4>
|
||||
<p id="onboardingContentFour" class="onboardingContent">&aboutI2p.Four;</p>
|
||||
</div>
|
||||
<!--<p class="hideIfI2POn">&aboutI2p.warn_not_running; <a href="about:i2p">&aboutI2p.refresh_text;</a> &aboutI2p.reccommend_not_running;</p>-->
|
||||
<div class="application-info">
|
||||
<p class="hideIfI2PConsoleOff">
|
||||
<h3>&aboutI2p.applications;</h3>
|
||||
<p id="applicationExplain">&aboutI2p.appExplain;</p>
|
||||
<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>
|
||||
<a class="applicationName" href="&aboutI2p.routerconsole;/i2ptunnel">
|
||||
<li class="application">
|
||||
&aboutI2p.i2ptunnel; <span class="applicationDesc">&aboutI2p.i2ptunnel_visit_msg;</span>
|
||||
</li>
|
||||
</a>
|
||||
<a class="applicationName" href="&aboutI2p.routerconsole;/susimail">
|
||||
<li class="application">
|
||||
&aboutI2p.email; <span class="applicationDesc">&aboutI2p.email_visit_msg;</span>
|
||||
</li>
|
||||
</a>
|
||||
<a class="applicationName" href="&aboutI2p.routerconsole;/i2psnark">
|
||||
<li class="application">
|
||||
&aboutI2p.torrent; <span class="applicationDesc">&aboutI2p.torrent_visit_msg;</span>
|
||||
</li>
|
||||
</a>
|
||||
</ul>
|
||||
</p>
|
||||
|
||||
&aboutI2p.warn_experimental;
|
||||
</p>
|
||||
<!--<p class="hideIfI2POn">&aboutI2p.warn_not_running; <a href="about:i2p">&aboutI2p.refresh_text;</a> &aboutI2p.reccommend_not_running;</p>-->
|
||||
<p class="hideIfI2PConsoleOff">&aboutI2p.all_checks_ok;</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 class="extended-info">
|
||||
<h3 id="links"><button class="showhider" onclick="flipVisibility('info-content')">&aboutI2p.links;</button></h3>
|
||||
<div id="info-content">
|
||||
<p id="linksExplain">&aboutI2p.linkExplain;</p>
|
||||
<p>
|
||||
<ul>
|
||||
<a href="&aboutI2p.github;/i2p-browser">
|
||||
<li>
|
||||
&aboutI2p.source; <span class="applicationDesc">&aboutI2p.browsersrc;</span>
|
||||
</li>
|
||||
</a>
|
||||
<a href="&aboutI2p.github;/i2pbutton">
|
||||
<li>
|
||||
&aboutI2p.i2pbutton_source; <span class="applicationDesc">&aboutI2p.extsrc;</span>
|
||||
</li>
|
||||
</a>
|
||||
<a href="&aboutI2p.githubdev;/i2p-browser-build-scripts">
|
||||
<li>
|
||||
&aboutI2p.build_scripts; <span class="applicationDesc">&aboutI2p.makesrc;</span>
|
||||
</li>
|
||||
</a>
|
||||
<a href="&aboutI2p.githubdev;/i2p-browser-design-docs">
|
||||
<li>
|
||||
&aboutI2p.design; <span class="applicationDesc">&aboutI2p.designsrc;</span>
|
||||
</li>
|
||||
</a>
|
||||
<a href="&aboutI2p.trac;/">
|
||||
<li>
|
||||
&aboutI2p.bug_tracker; <span class="applicationDesc">&aboutI2p.tracwiki;</span>
|
||||
</li>
|
||||
</a>
|
||||
<a href="&aboutI2p.site;/get-involved/donate">
|
||||
<li>
|
||||
<em>&aboutI2p.supportus;</em> <span class="applicationDesc">&aboutI2p.donatecta;</span>
|
||||
</li>
|
||||
</a>
|
||||
</ul>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<script type="text/javascript">
|
||||
function flipVisibility(div) {
|
||||
var x = document.getElementById(div);
|
||||
if (x.style.display === "none") {
|
||||
x.style.display = "block";
|
||||
} else {
|
||||
x.style.display = "none";
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<!--</div>-->
|
||||
</body>
|
||||
</html>
|
||||
|
||||
|
@ -1,10 +1,10 @@
|
||||
let { Services } = Cu.import("resource://gre/modules/Services.jsm", {})
|
||||
const {AppConstants} = ChromeUtils.import("resource://gre/modules/AppConstants.jsm")
|
||||
var { Services } = Cu.import("resource://gre/modules/Services.jsm", {})
|
||||
var {AppConstants} = ChromeUtils.import("resource://gre/modules/AppConstants.jsm")
|
||||
|
||||
//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)
|
||||
var m_ib_prefs = Services.prefs;
|
||||
var m_ib_domWindowUtils = window.windowUtils;
|
||||
|
||||
const k_ib_last_browser_version_pref = "extensions.i2pbutton.lastBrowserVersion";
|
||||
const k_ib_browser_update_needed_pref = "extensions.i2pbutton.updateNeeded";
|
||||
@ -21,7 +21,11 @@ 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
|
||||
let routerCtrl = Cc["@geti2p.net/i2pbutton-process-service;1"].getService(Ci.nsISupports).wrappedJSObject
|
||||
//let routerCtrl = Cc["@geti2p.net/i2pbutton-process-service;1"].getService(Ci.nsISupports).wrappedJSObject
|
||||
|
||||
function i2pbutton_log(lvl, msg) {
|
||||
console.log(`[i2pbutton:${lvl}] ${msg}`)
|
||||
}
|
||||
|
||||
function checkI2P(callback,proxyCallback) {
|
||||
let req = checkSvc.createCheckConsoleRequest(true);
|
||||
@ -53,14 +57,17 @@ function i2pbutton_i2p_check_ok()
|
||||
}
|
||||
function i2pbutton_i2p_console_check_ok() {
|
||||
// This check will now test if the router subprocess is running
|
||||
if (routerCtrl.mI2PProcess != null) {
|
||||
/*if (routerCtrl.mI2PProcess != null) {
|
||||
if (routerCtrl.mI2PProcess.isRunning) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
}*/
|
||||
return false
|
||||
}
|
||||
|
||||
function i2pbutton_i2p_proxy_check_ok() {
|
||||
i2pbutton_log(3, "I2P Proxy readiness: " + checkSvc.isProxyWorking)
|
||||
return (checkSvc.isProxyWorking)
|
||||
}
|
||||
var i2pbutton_window_pref_observer =
|
||||
{
|
||||
register: function()
|
||||
@ -197,7 +204,8 @@ var i2pbutton_abouti2p_message_handler = {
|
||||
let dataObj = {
|
||||
updateChannel: AppConstants.MOZ_UPDATE_CHANNEL,
|
||||
i2pOn: i2pbutton_i2p_check_ok(),
|
||||
i2pConsoleOn: i2pbutton_i2p_console_check_ok()
|
||||
i2pConsoleOn: i2pbutton_i2p_console_check_ok(),
|
||||
i2pProxyOn: i2pbutton_i2p_proxy_check_ok()
|
||||
};
|
||||
|
||||
if (aIsRespondingToPageLoad) {
|
||||
@ -780,36 +788,7 @@ function i2pbutton_do_new_identity() {
|
||||
|
||||
// Run garbage collection and cycle collection after window is gone.
|
||||
// This ensures that blob URIs are forgotten.
|
||||
window.addEventListener("unload", function (event) {
|
||||
i2pbutton_log(3, "Initiating New Identity GC pass");
|
||||
// Clear out potential pending sInterSliceGCTimer:
|
||||
m_ib_domWindowUtils.runNextCollectorTimer();
|
||||
|
||||
// Clear out potential pending sICCTimer:
|
||||
m_ib_domWindowUtils.runNextCollectorTimer();
|
||||
|
||||
// Schedule a garbage collection in 4000-1000ms...
|
||||
m_ib_domWindowUtils.garbageCollect();
|
||||
|
||||
// To ensure the GC runs immediately instead of 4-10s from now, we need
|
||||
// to poke it at least 11 times.
|
||||
// We need 5 pokes for GC, 1 poke for the interSliceGC, and 5 pokes for CC.
|
||||
// See nsJSContext::RunNextCollectorTimer() in
|
||||
// https://mxr.mozilla.org/mozilla-central/source/dom/base/nsJSEnvironment.cpp#1970.
|
||||
// XXX: We might want to make our own method for immediate full GC...
|
||||
for (let poke = 0; poke < 11; poke++) {
|
||||
m_ib_domWindowUtils.runNextCollectorTimer();
|
||||
}
|
||||
|
||||
// And now, since the GC probably actually ran *after* the CC last time,
|
||||
// run the whole thing again.
|
||||
m_ib_domWindowUtils.garbageCollect();
|
||||
for (let poke = 0; poke < 11; poke++) {
|
||||
m_ib_domWindowUtils.runNextCollectorTimer();
|
||||
}
|
||||
|
||||
i2pbutton_log(3, "Completed New Identity GC pass");
|
||||
});
|
||||
window.addEventListener("unload", function (event) {});
|
||||
|
||||
// Close the current window for added safety
|
||||
window.close();
|
||||
@ -1121,7 +1100,6 @@ var i2pbutton_resizelistener =
|
||||
// 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);
|
||||
@ -1194,7 +1172,6 @@ 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
|
||||
@ -1315,7 +1292,6 @@ function i2pbutton_new_window(event)
|
||||
// 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);
|
||||
|
@ -1,43 +0,0 @@
|
||||
<?xml version="1.0"?>
|
||||
<?xml-stylesheet href="chrome://i2pbutton/skin/torbutton.css" type="text/css"?>
|
||||
<?xul-overlay href="chrome://i2pbutton/content/popup.xul"?>
|
||||
|
||||
<!DOCTYPE overlay SYSTEM "chrome://i2pbutton/locale/i2pbutton.dtd">
|
||||
|
||||
<overlay id="i2pbutton-overlay"
|
||||
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
|
||||
|
||||
<script type="application/x-javascript" src="chrome://i2pbutton/content/i2pbutton_util.js" />
|
||||
<script type="application/x-javascript" src="chrome://i2pbutton/content/i2pbutton.js" />
|
||||
<script language="JavaScript">
|
||||
//onLoad Hander
|
||||
try{window.addEventListener("load", i2pbutton_init, false);}catch(e){}
|
||||
</script>
|
||||
|
||||
<stringbundleset id="i2pbutton-stringbundleset">
|
||||
<stringbundle id="i2pbutton-bundle" src="chrome://i2pbutton/locale/i2pbutton.properties"/>
|
||||
</stringbundleset>
|
||||
|
||||
<!-- Place the context menu in the nav bar, so that the lack
|
||||
of the status bar on FF4 doesn't make it invisible -->
|
||||
<toolbar id="nav-bar">
|
||||
<menupopup id="i2pbutton-context-menu"/>
|
||||
</toolbar>
|
||||
|
||||
<toolbarpalette id="BrowserToolbarPalette">
|
||||
<toolbarbutton
|
||||
id="i2pbutton-button"
|
||||
class="toolbarbutton-1 chromeclass-toolbar-additional"
|
||||
type="menu"
|
||||
orient="horizontal"
|
||||
label="I2Pbutton"
|
||||
tooltiptext="&i2pbutton.button.tooltip;"
|
||||
menu="i2pbutton-context-menu"
|
||||
context="i2pbutton-context-menu"/>
|
||||
</toolbarpalette>
|
||||
|
||||
<!-- Global keyboard shortcuts for new identity. -->
|
||||
<keyset>
|
||||
<key id="i2pbutton-new-identity-key" modifiers="accel shift" key="U" oncommand="i2pbutton_new_identity()"/>
|
||||
</keyset>
|
||||
</overlay>
|
@ -1,38 +0,0 @@
|
||||
<?xml version="1.0"?>
|
||||
<?xml-stylesheet href="chrome://i2pbutton/skin/i2pbutton.css" type="text/css"?>
|
||||
<?xul-overlay href="chrome://i2pbutton/content/popup.xul"?>
|
||||
|
||||
<!DOCTYPE overlay SYSTEM "chrome://i2pbutton/locale/i2pbutton.dtd">
|
||||
|
||||
<overlay id="i2pbutton-overlay"
|
||||
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
|
||||
<script type="application/x-javascript" src="chrome://i2pbutton/content/i2pbutton_util.js" />
|
||||
<script type="application/x-javascript" src="chrome://i2pbutton/content/i2pbutton.js" />
|
||||
<script language="JavaScript">
|
||||
//onLoad Hander
|
||||
try{window.addEventListener("load", i2pbutton_init, false);}catch(e){}
|
||||
</script>
|
||||
|
||||
<stringbundleset id="i2pbutton-stringbundleset">
|
||||
<stringbundle id="i2pbutton-bundle" src="chrome://i2pbutton/locale/i2pbutton.properties"/>
|
||||
</stringbundleset>
|
||||
|
||||
<toolbarpalette id="MailToolbarPalette">
|
||||
<toolbarbutton
|
||||
id="i2pbutton-button-tb"
|
||||
class="toolbarbutton-1"
|
||||
label="i2pbutton"
|
||||
tooltiptext="&i2pbutton.button.tooltip;"
|
||||
context="i2pbutton-context-menu" />
|
||||
</toolbarpalette>
|
||||
|
||||
<toolbarpalette id="MsgComposeToolbarPalette">
|
||||
<toolbarbutton
|
||||
id="i2pbutton-button-tb-msg"
|
||||
class="toolbarbutton-1"
|
||||
label="i2pbutton"
|
||||
tooltiptext="&i2pbutton.button.tooltip;"
|
||||
context="i2pbutton-context-menu" />
|
||||
</toolbarpalette>
|
||||
|
||||
</overlay>
|
@ -1,21 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?> <!-- -*- Mode: HTML -*- -->
|
||||
|
||||
<!DOCTYPE overlay SYSTEM "chrome://i2pbutton/locale/i2pbutton.dtd">
|
||||
|
||||
<overlay id="i2pbutton-menu-overlay"
|
||||
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
|
||||
<menuitem id="menu_newIdentity"
|
||||
accesskey="&i2pbutton.context_menu.new_identity_key;"
|
||||
key="i2pbutton-new-identity-key"
|
||||
label="&i2pbutton.context_menu.new_identity;"
|
||||
oncommand="i2pbutton_new_identity();"/>
|
||||
<toolbarbutton id="appMenuNewIdentity"
|
||||
class="subviewbutton subviewbutton-iconic"
|
||||
key="i2pbutton-new-identity-key"
|
||||
label="&i2pbutton.context_menu.new_identity;"
|
||||
oncommand="i2pbutton_new_identity();"/>
|
||||
<toolbarbutton id="appMenu-private-window-button"
|
||||
hidden="true"/>
|
||||
<toolbarbutton id="appMenuRestoreLastSession"
|
||||
hidden="true"/>
|
||||
</overlay>
|
@ -1,29 +0,0 @@
|
||||
<?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>
|
@ -1,38 +0,0 @@
|
||||
<?xml version="1.0"?>
|
||||
<?xml-stylesheet href="chrome://i2pbutton/skin/i2pbutton.css" type="text/css"?>
|
||||
|
||||
<!DOCTYPE overlay SYSTEM "chrome://i2pbutton/locale/i2pbutton.dtd">
|
||||
|
||||
<overlay id="i2pbutton-popup-overlay"
|
||||
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
|
||||
|
||||
<stringbundleset id="i2pbutton-stringbundleset">
|
||||
<stringbundle id="i2pbutton-bundle" src="chrome://i2pbutton/locale/i2pbutton.properties"/>
|
||||
</stringbundleset>
|
||||
<panel id="i2pbutton-context-menu"
|
||||
onpopupshowing="i2pbutton_check_protections();"
|
||||
titlebar="normal" noautohide="true"
|
||||
anchor="i2pbutton-button" position="after_start" >
|
||||
<hbox align="start">
|
||||
<vbox>
|
||||
<menuitem id="i2pbutton-new-identity"
|
||||
label="&i2pbutton.context_menu.new_identity;"
|
||||
accesskey="&i2pbutton.context_menu.new_identity_key;"
|
||||
insertafter="context-stop"
|
||||
oncommand="i2pbutton_new_identity()"/>
|
||||
<menuitem id="i2pbutton-cookie-protector"
|
||||
label="&i2pbutton.context_menu.cookieProtections;"
|
||||
accesskey="&i2pbutton.context_menu.cookieProtections.key;"
|
||||
insertafter="i2pbutton-new-identity"
|
||||
hidden="true"
|
||||
oncommand="i2pbutton_open_cookie_dialog()"/>
|
||||
<menuseparator id="i2pbutton-checkForUpdateSeparator"/>
|
||||
<menuitem id="i2pbutton-checkForUpdate"
|
||||
label="&i2pbutton.context_menu.downloadUpdate;"
|
||||
accesskey="&i2pbutton.context_menu.downloadUpdate.key;"
|
||||
insertafter="i2pbutton-cookie-protector"
|
||||
oncommand="i2pbutton_check_for_update()"/>
|
||||
</vbox>
|
||||
</hbox>
|
||||
</panel>
|
||||
</overlay>
|
@ -9,4 +9,4 @@
|
||||
<!ENTITY bottomLinks.questions "Questions?">
|
||||
<!ENTITY bottomLinks.grow "Help the I2P Network Grow!">
|
||||
<!ENTITY bottomLinks.license "Licensing Information">
|
||||
<!ENTITY tor.TrademarkStatement "'I2P' are registered trademarks of the I2P Project.">
|
||||
<!ENTITY i2p.TrademarkStatement "'I2P' are registered trademarks of the I2P Project.">
|
||||
|
@ -3,38 +3,63 @@
|
||||
|
||||
<!ENTITY aboutI2p.viewChangelog.label "View Changelog">
|
||||
|
||||
<!ENTITY aboutI2p.browser_name "The Invisible Internet Browser">
|
||||
<!ENTITY aboutI2p.browser_name "I2P Browser: Communications Security Toolkit">
|
||||
<!ENTITY aboutI2p.browser_short_name "I2P Browser">
|
||||
<!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.browser_description "is preconfigured to get your content using the anonymous and private I2P network and to provide accessible, first-class access to I2P Peer-to-Peer applications.">
|
||||
<!ENTITY aboutI2p.browser_version_declare "This build of I2P Browser was made with">
|
||||
<!ENTITY aboutI2p.browser_version "0.9.43">
|
||||
<!ENTITY aboutI2p.donate "Donate">
|
||||
<!ENTITY aboutI2p.supportus "Support I2P development">
|
||||
|
||||
<!ENTITY aboutI2p.warn_not_running "It currently seems like your router is NOT running :(">
|
||||
<!ENTITY aboutI2p.warn_not_running "I2P hasn't started.">
|
||||
<!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.all_checks_ok "I2P is running.">
|
||||
<!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.appExplain "These applications use I2P to provide them with security and privacy.">
|
||||
<!ENTITY aboutI2p.applications "Applications">
|
||||
<!ENTITY aboutI2p.console "Console:">
|
||||
<!ENTITY aboutI2p.torrent "Torrents:">
|
||||
<!ENTITY aboutI2p.i2ptunnel "Tunnels:">
|
||||
<!ENTITY aboutI2p.email "E-Mail:">
|
||||
<!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 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.design "Design Document">
|
||||
<!ENTITY aboutI2p.console_visit_msg "It seems like your console is up, click to visit:">
|
||||
|
||||
<!ENTITY aboutI2p.refresh_text "Try refreshing the page.">
|
||||
<!ENTITY aboutI2p.refresh_link "Refresh">
|
||||
|
||||
<!ENTITY aboutI2p.links "Links">
|
||||
<!ENTITY aboutI2p.linkExplain "If you want to get more information about I2P, you can visit these links.">
|
||||
<!ENTITY aboutI2p.site "http://i2p-projekt.i2p/en">
|
||||
<!ENTITY aboutI2p.routerconsole "http://localhost:7647">
|
||||
<!ENTITY aboutI2p.github "https://github.com/mikalv">
|
||||
<!ENTITY aboutI2p.github "https://github.com/i2p">
|
||||
<!ENTITY aboutI2p.githubdev "https://github.com/mikal">
|
||||
<!ENTITY aboutI2p.trac "http://trac.i2p2.i2p">
|
||||
<!ENTITY aboutI2p.i2pbutton_source "I2P Button Source Code:">
|
||||
<!ENTITY aboutI2p.build_scripts "I2P Browser Build Scripts:">
|
||||
<!ENTITY aboutI2p.source "I2P Browser Source Code:">
|
||||
<!ENTITY aboutI2p.bug_tracker "Submit a Bug Report:">
|
||||
<!ENTITY aboutI2p.design "I2P Browser Design Document:">
|
||||
<!ENTITY aboutI2p.browsersrc "Go here to browse the source code of our Firefox fork.">
|
||||
<!ENTITY aboutI2p.extsrc "Much of the functionality of the I2P Browser is implemented in the I2PButton plugin.">
|
||||
<!ENTITY aboutI2p.makesrc "These scripts are used to build the browser.">
|
||||
<!ENTITY aboutI2p.designsrc "This is the I2P Browser Design Document.">
|
||||
<!ENTITY aboutI2p.tracwiki "To report a bug, visit the Trac Wiki.">
|
||||
<!ENTITY aboutI2p.donatecta "I2P is funded by donations. In order to make a donation visit the project web site.">
|
||||
|
||||
<!ENTITY aboutI2p.startup "Sometimes it takes a minute or two for I2P to get started for the first time. While you wait, visit the">
|
||||
<!ENTITY aboutI2p.startup_b "to get acquainted with all the capabilities of I2P.">
|
||||
<!ENTITY aboutI2p.startup "Proxy starting up.">
|
||||
<!ENTITY aboutI2p.rc "Router Console">
|
||||
<!ENTITY aboutI2p.proxyready "Proxy Ready">
|
||||
|
||||
<!ENTITY aboutI2p.onboardingTitle "New to I2P? Learn more here.">
|
||||
<!ENTITY aboutI2p.Zero "I2P Browser allows you to surf the internet using the private and secure I2P network. When using it, you are protected against tracking, surveillance, and censorship as a first-class participant in the I2P network. I2P Browser isolates cookies and deletes your browser history after your session. These modifications ensure your privacy and security are protected in the browser.">
|
||||
<!ENTITY aboutI2p.One "We also provide you with additional settings for bumping up your browser security. Our Security Settings allow you to block elements that could be used to attack your computer. Click below to see what the different options do. Note: By default, NoScript and HTTPS Everywhere are not included on the toolbar, but you can customize your toolbar to add them. With all the security and privacy features provided by I2P, your experience while browsing the internet may be a little different. Things may be a bit slower, and depending on your security level, some elements may not work or load. You may also be asked to prove you are a human and not a robot.">
|
||||
<!ENTITY aboutI2p.Two "I2P is capable of using peer-to-peer applications like BitTorrent, protecting your identity when you share files. Our anonymous bittorrent client is available in the browser.">
|
||||
<!ENTITY aboutI2p.Three "There is also an anonymous e-mail service available inside of I2P, which is accessible from our browser via the menu directly below.">
|
||||
<!ENTITY aboutI2p.Four "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.">
|
||||
<!ENTITY aboutI2p.ZeroTitle "Protect your Privacy">
|
||||
<!ENTITY aboutI2p.OneTitle "Configure your Experience">
|
||||
<!ENTITY aboutI2p.TwoTitle "Share Files">
|
||||
<!ENTITY aboutI2p.ThreeTitle "Hidden e-mail">
|
||||
<!ENTITY aboutI2p.FourTitle "Experience Tips">
|
||||
|
@ -4,3 +4,8 @@
|
||||
<!ENTITY vendorShortName "I2P Project">
|
||||
<!ENTITY trademarkInfo.part1 "Firefox and the Firefox logos are trademarks of the Mozilla Foundation.">
|
||||
|
||||
<!ENTITY plugins.installed.find "Click to load installed system plugins">
|
||||
<!ENTITY plugins.installed.enable "Enable plugins">
|
||||
<!ENTITY plugins.installed.disable "Disable plugins">
|
||||
<!ENTITY plugins.installed.disable.tip "Click to prevent loading system plugins">
|
||||
|
||||
|
@ -1,77 +1,290 @@
|
||||
* {
|
||||
padding: 0px;
|
||||
margin: 0px;
|
||||
padding: 0;
|
||||
margin: 0
|
||||
}
|
||||
|
||||
html {
|
||||
height: 100%;
|
||||
height: 100%
|
||||
}
|
||||
a {
|
||||
color: #3b6bbf;
|
||||
text-decoration: none;
|
||||
font-weight: 700;
|
||||
word-wrap: break-word;
|
||||
outline: 0
|
||||
}
|
||||
.beta,
|
||||
.version {
|
||||
font-style: italic
|
||||
}
|
||||
.applicationDesc {
|
||||
color: #81888f;
|
||||
text-decoration: none;
|
||||
font-weight: 700;
|
||||
word-wrap: break-word;
|
||||
outline: 0
|
||||
}
|
||||
.applicationDesc:hover,
|
||||
a:hover {
|
||||
color: #495057;
|
||||
text-decoration: none;
|
||||
font-weight: 700;
|
||||
word-wrap: break-word;
|
||||
outline: 0
|
||||
}
|
||||
|
||||
body {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
font-family: "Droid Sans","Noto Sans",Ubuntu,"Segoe UI","Lucida Grande",Verdana,Helvetica,sans-serif;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
margin: 0px auto;
|
||||
padding: 0px 0px;
|
||||
font-family: Helvetica, Arial, sans-serif;
|
||||
color: var(--abouttor-text-color);
|
||||
background-color: var(--abouttor-bg-toroff-color);
|
||||
margin: 0 auto;
|
||||
padding: 0;
|
||||
color: #495057;
|
||||
background-attachment: fixed;
|
||||
background-size: 100% 100%;
|
||||
text-decoration: none;
|
||||
font-weight: 700;
|
||||
word-wrap: break-word;
|
||||
outline: 0
|
||||
}
|
||||
|
||||
/* Hide the entire document by default to avoid showing the incorrect
|
||||
* I2P on / off status (that info must be retrieved from the chrome
|
||||
* process, which involves IPC when multiprocess mode is enabled). An
|
||||
* initialized attribute will be added as soon as the status is known.
|
||||
*/
|
||||
body:not([initialized]) {
|
||||
display: none;
|
||||
body:not([initialized]) {
|
||||
display: none
|
||||
}
|
||||
|
||||
.background {
|
||||
background-color: #3960b5;
|
||||
padding: 120px;
|
||||
height: 100%;
|
||||
background-color: #f8f8ff;
|
||||
height: 100%
|
||||
}
|
||||
|
||||
p {
|
||||
margin-top: 40px;
|
||||
font-family: Open Sans, sans-serif;
|
||||
font-weight: 300;
|
||||
line-height: 32px;
|
||||
font-size: 17px;
|
||||
font-family: "Droid Sans","Noto Sans",Ubuntu,"Segoe UI","Lucida Grande",Verdana,Helvetica,sans-serif;
|
||||
text-decoration: none;
|
||||
color: #495057;
|
||||
font-weight: 700;
|
||||
word-wrap: break-word;
|
||||
outline: 0
|
||||
}
|
||||
|
||||
.content {
|
||||
padding: 110px;
|
||||
background-color: #FFFFFF;
|
||||
border-radius: 15px;
|
||||
box-shadow: 0px 30px 200px rgba(61,0,84,0.7);
|
||||
min-height: 3rem;
|
||||
padding: 1rem;
|
||||
margin: 1.5rem;
|
||||
display: inline-block;
|
||||
border: 1px solid #d9d9d6;
|
||||
border-radius: 2px;
|
||||
box-shadow: inset 0 0 0 1px #fff,0 0 1px #ccc;
|
||||
background: #f8f8ff
|
||||
}
|
||||
.extended-info {
|
||||
min-height: 3rem;
|
||||
padding: 1rem;
|
||||
margin-top: 1.5rem;
|
||||
display: inline-block;
|
||||
border: 1px solid #d9d9d6;
|
||||
border-radius: 2px;
|
||||
box-shadow: inset 0 0 0 1px #fff,0 0 1px #ccc;
|
||||
background: #f8f8ff;
|
||||
min-width: 50%
|
||||
}
|
||||
.application-info {
|
||||
min-height: 3rem;
|
||||
padding: 1rem;
|
||||
margin-top: 1.5rem;
|
||||
display: inline-block;
|
||||
border: 1px solid #d9d9d6;
|
||||
border-radius: 2px;
|
||||
box-shadow: inset 0 0 0 1px #fff,0 0 1px #ccc;
|
||||
background: #f8f8ff
|
||||
}
|
||||
|
||||
h1 {
|
||||
margin-right: auto;
|
||||
font-family: Montserrat, sans-serif;
|
||||
font-family: "Droid Sans","Noto Sans",Ubuntu,"Segoe UI","Lucida Grande",Verdana,Helvetica,sans-serif;
|
||||
font-weight: 600;
|
||||
font-size: 32px;
|
||||
text-transform: uppercase;
|
||||
color: #41465f;
|
||||
border: 1px solid #dee2e6;
|
||||
border-radius: 2px 2px 0 0;
|
||||
width: 90%;
|
||||
padding-left: 5%
|
||||
}
|
||||
h2,
|
||||
h3 {
|
||||
margin-right: auto;
|
||||
font-family: "Droid Sans","Noto Sans",Ubuntu,"Segoe UI","Lucida Grande",Verdana,Helvetica,sans-serif;
|
||||
font-weight: 600;
|
||||
font-size: 25px;
|
||||
text-transform: uppercase;
|
||||
color: #41465f;
|
||||
border: 1px solid #dee2e6;
|
||||
border-radius: 2px 2px 0 0;
|
||||
width: 90%;
|
||||
padding-left: 5%
|
||||
}
|
||||
h4 {
|
||||
margin-right: auto;
|
||||
font-family: "Droid Sans","Noto Sans",Ubuntu,"Segoe UI","Lucida Grande",Verdana,Helvetica,sans-serif;
|
||||
font-weight: 600;
|
||||
font-size: 20px!important;
|
||||
text-transform: uppercase;
|
||||
color: #41465f;
|
||||
border: 1px solid #dee2e6;
|
||||
border-radius: 2px 2px 0 0;
|
||||
width: 90%;
|
||||
padding-left: 5%
|
||||
}
|
||||
.showhider {
|
||||
margin-right: auto;
|
||||
font-family: "Droid Sans","Noto Sans",Ubuntu,"Segoe UI","Lucida Grande",Verdana,Helvetica,sans-serif;
|
||||
text-transform: uppercase;
|
||||
background: 0 0!important;
|
||||
border: none;
|
||||
padding: 0!important;
|
||||
width: 90%;
|
||||
color: #3b6bbf;
|
||||
text-decoration: none;
|
||||
font-weight: 700;
|
||||
word-wrap: break-word;
|
||||
outline: 0;
|
||||
text-align: left
|
||||
}
|
||||
#links .showhider {
|
||||
font-size: 25px
|
||||
}
|
||||
#info-content {
|
||||
display: none
|
||||
}
|
||||
|
||||
.section-header {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
margin-bottom: 80px;
|
||||
margin-bottom: 80px
|
||||
}
|
||||
|
||||
body[i2pon] .hideIfI2POn,
|
||||
body:not([i2pconsoleon]) .hideIfI2PConsoleOff,
|
||||
body:not([i2pon]) .hideIfI2POff,
|
||||
body:not([i2pproxyon]) .hideIfI2PProxyOff,
|
||||
body[i2pconsoleon] .hideIfI2PConsoleOn,
|
||||
body:not([i2pconsoleon]) .hideIfI2PConsoleOff {
|
||||
display: none;
|
||||
body[i2pon] .hideIfI2POn,
|
||||
body[i2pproxyon] .hideIfI2PProxyOn {
|
||||
display: none!important
|
||||
}
|
||||
|
||||
ul {
|
||||
margin-left: 2rem;
|
||||
list-style: none
|
||||
}
|
||||
li {
|
||||
min-height: 3rem;
|
||||
padding: .5rem;
|
||||
background: #dee2e6;
|
||||
border: 1px solid #dee2e6;
|
||||
width: 64%;
|
||||
min-width: 64%;
|
||||
border-radius: 2px;
|
||||
box-shadow: inset 0 0 0 1px #fff,0 0 1px #ccc;
|
||||
margin: .5rem .5rem .5rem 32%
|
||||
}
|
||||
#readyness {
|
||||
min-height: 5rem;
|
||||
padding: .5rem;
|
||||
margin: .5rem;
|
||||
width: 42%;
|
||||
min-width: 42%;
|
||||
background: #dee2e6;
|
||||
text-align: center!important;
|
||||
border: 1px solid #dee2e6;
|
||||
border-radius: 2px;
|
||||
box-shadow: inset 0 0 0 1px #fff,0 0 1px #ccc
|
||||
}
|
||||
#onboarding {
|
||||
min-height: 5rem;
|
||||
padding: .5rem;
|
||||
margin: .5rem;
|
||||
width: 42%;
|
||||
min-width: 42%;
|
||||
font-size: 2rem;
|
||||
background: #a48fe1;
|
||||
text-align: center!important;
|
||||
border: 1px solid #a48fe1;
|
||||
border-radius: 2px;
|
||||
box-shadow: inset 0 0 0 1px #fff,0 0 1px #ccc
|
||||
}
|
||||
#i2pbrowser-description {
|
||||
width: 50%;
|
||||
min-width: 50%;
|
||||
min-height: 5rem;
|
||||
padding: .5rem;
|
||||
display: inline;
|
||||
background: #dee2e6;
|
||||
float: right;
|
||||
border: 1px solid #dee2e6;
|
||||
border-radius: 2px;
|
||||
box-shadow: inset 0 0 0 1px #fff,0 0 1px #ccc
|
||||
}
|
||||
#applicationExplain,
|
||||
#linksExplain {
|
||||
min-height: 5rem;
|
||||
padding: .5rem;
|
||||
margin: .5rem;
|
||||
width: 30%;
|
||||
min-width: 30%;
|
||||
background: #dee2e6;
|
||||
float: left;
|
||||
text-align: center!important;
|
||||
border: 1px solid #dee2e6;
|
||||
border-radius: 2px;
|
||||
box-shadow: inset 0 0 0 1px #fff,0 0 1px #ccc
|
||||
}
|
||||
#proxyReady {
|
||||
height: 3.5rem;
|
||||
padding: .5rem;
|
||||
margin: .2rem;
|
||||
width: 38%;
|
||||
min-width: 38%;
|
||||
display: inline;
|
||||
background: #d9d9d6;
|
||||
float: right;
|
||||
text-align: center!important;
|
||||
border: 1px solid #d9d9d6;
|
||||
border-radius: 2px;
|
||||
box-shadow: inset 0 0 0 1px #fff,0 0 1px #ccc
|
||||
}
|
||||
#proxyUnready {
|
||||
height: 3.5rem;
|
||||
padding: .5rem;
|
||||
margin: .2rem;
|
||||
width: 38%;
|
||||
min-width: 38%;
|
||||
display: inline;
|
||||
float: right;
|
||||
text-align: center!important;
|
||||
border: 1px solid #ffc56d;
|
||||
border-radius: 2px;
|
||||
background: #ffc56d;
|
||||
box-shadow: inset 0 0 0 1px #fff,0 0 1px #ccc
|
||||
}
|
||||
#consoleOn {
|
||||
height: 3.5rem;
|
||||
padding: .5rem;
|
||||
margin: .2rem;
|
||||
width: 38%;
|
||||
min-width: 38%;
|
||||
display: inline;
|
||||
float: left;
|
||||
text-align: center!important;
|
||||
border: 1px solid #f7e59a;
|
||||
border-radius: 2px;
|
||||
background: #f7e59a;
|
||||
box-shadow: inset 0 0 0 1px #fff,0 0 1px #ccc
|
||||
}
|
||||
#onboardingContentFour,
|
||||
#onboardingContentOne,
|
||||
#onboardingContentThree,
|
||||
#onboardingContentTwo,
|
||||
#onboardingContentZero {
|
||||
display: none
|
||||
}
|
||||
.onboardingContent {
|
||||
font-size: .8rem!important;
|
||||
text-align: left
|
||||
}
|
||||
#onboarding-overlay-button {
|
||||
display: none
|
||||
}
|
@ -4,14 +4,9 @@
|
||||
* Implements an observer that filters drag events to prevent OS
|
||||
* access to URLs (a potential proxy bypass vector).
|
||||
*************************************************************************/
|
||||
const { XPCOMUtils } = ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
const { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm");
|
||||
|
||||
const Cc = Components.classes;
|
||||
const Ci = Components.interfaces;
|
||||
const Cu = Components.utils;
|
||||
|
||||
Cu.import("resource://i2pbutton/modules/default-prefs.js", {}).ensureDefaultPrefs();
|
||||
|
||||
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
|
||||
// Module specific constants
|
||||
const kMODULE_NAME = "I2pbutton Drag and Drop Handler";
|
||||
@ -21,22 +16,19 @@ const kMODULE_CID = Components.ID("f605ec27-d867-44b5-ad97-2a29276642c3");
|
||||
const kInterfaces = [Ci.nsIObserver, Ci.nsIClassInfo];
|
||||
|
||||
function DragDropFilter() {
|
||||
this.logger = Cc["@geti2p.net/i2pbutton-logger;1"]
|
||||
.getService(Ci.nsISupports).wrappedJSObject;
|
||||
this.logger = Cc["@geti2p.net/i2pbutton-logger;1"].getService(Ci.nsISupports).wrappedJSObject;
|
||||
this.logger.log(3, "Component Load 0: New DragDropFilter.");
|
||||
|
||||
try {
|
||||
var observerService = Cc["@mozilla.org/observer-service;1"].
|
||||
getService(Ci.nsIObserverService);
|
||||
observerService.addObserver(this, "on-datatransfer-available", false);
|
||||
} catch(e) {
|
||||
Services.obs.addObserver(this, "on-datatransfer-available");
|
||||
} catch (e) {
|
||||
this.logger.log(5, "Failed to register drag observer");
|
||||
}
|
||||
}
|
||||
|
||||
DragDropFilter.prototype =
|
||||
{
|
||||
QueryInterface: XPCOMUtils.generateQI([Ci.nsISupports, Ci.nsIObserver]),
|
||||
QueryInterface: ChromeUtils.generateQI([Ci.nsIObserver]),
|
||||
|
||||
// make this an nsIClassInfo object
|
||||
flags: Ci.nsIClassInfo.DOM_OBJECT,
|
||||
@ -86,3 +78,5 @@ DragDropFilter.prototype =
|
||||
};
|
||||
|
||||
var NSGetFactory = XPCOMUtils.generateNSGetFactory([DragDropFilter]);
|
||||
|
||||
|
||||
|
@ -5,6 +5,11 @@ const Ci = Components.interfaces
|
||||
const Cr = Components.results
|
||||
const Cu = Components.utils
|
||||
|
||||
const nsISupports = Components.interfaces.nsISupports;
|
||||
const nsIClassInfo = Components.interfaces.nsIClassInfo;
|
||||
const nsIComponentRegistrar = Components.interfaces.nsIComponentRegistrar;
|
||||
const nsIObserverService = Components.interfaces.nsIObserverService;
|
||||
|
||||
// ctypes can be disabled at build time
|
||||
try { Cu.import("resource://gre/modules/ctypes.jsm") } catch(e) {}
|
||||
Cu.import("resource://gre/modules/XPCOMUtils.jsm")
|
||||
@ -41,11 +46,15 @@ function I2PProcessService()
|
||||
|
||||
I2PProcessService.prototype =
|
||||
{
|
||||
kContractID : "@geti2p.net/i2pbutton-process-service;1",
|
||||
kServiceName : "I2P Launcher Process Service",
|
||||
kClassID: Components.ID("{f77babef-dead-b00b-beff-babe6c9afda7}"),
|
||||
contractID : "@geti2p.net/i2pbutton-process-service;1",
|
||||
serviceName : "I2P Launcher Process Service",
|
||||
classID: Components.ID("{f77babef-dead-b00b-beff-babe6c9afda7}"),
|
||||
kI2PLauncherExtPath: "i2pbutton@geti2p.net", // This could vary.
|
||||
|
||||
|
||||
classDescription: this.kServiceName,
|
||||
flags: Ci.nsIClassInfo.SINGLETON,
|
||||
|
||||
kPrefPromptAtStartup: "extensions.i2pbutton.prompt_at_startup",
|
||||
|
||||
kWizardProgressPageID: "progress",
|
||||
@ -66,18 +75,7 @@ I2PProcessService.prototype =
|
||||
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;
|
||||
},
|
||||
QueryInterface: ChromeUtils.generateQI([Ci.nsIClassInfo]),
|
||||
|
||||
// nsIFactory implementation.
|
||||
createInstance: function(aOuter, aIID)
|
||||
@ -88,6 +86,16 @@ I2PProcessService.prototype =
|
||||
return this.QueryInterface(aIID);
|
||||
},
|
||||
|
||||
QueryInterface: function(iid)
|
||||
{
|
||||
if (!iid.equals(nsIClassInfo) &&
|
||||
!iid.equals(nsISupports)) {
|
||||
Components.returnCode = Cr.NS_ERROR_NO_INTERFACE;
|
||||
return null;
|
||||
}
|
||||
return this;
|
||||
},
|
||||
|
||||
init: function(aWindow) {},
|
||||
uninit: function unit() {},
|
||||
|
||||
@ -236,28 +244,6 @@ I2PProcessService.prototype =
|
||||
|
||||
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()
|
||||
@ -715,4 +701,4 @@ function NSGetFactory(aClassID)
|
||||
|
||||
|
||||
// This is the new stuff, stay away from generateNSGetModule which is the old stuff..
|
||||
//var NSGetFactory = XPCOMUtils.generateNSGetFactory([I2PProcessService])
|
||||
var NSGetFactory = XPCOMUtils.generateNSGetFactory([I2PProcessService])
|
||||
|
@ -4,13 +4,14 @@ 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 { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm");
|
||||
const { XPCOMUtils } = ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
|
||||
Cu.import("resource://i2pbutton/modules/default-prefs.js", {}).ensureDefaultPrefs()
|
||||
Cu.import("resource://gre/modules/Services.jsm")
|
||||
Cu.import("resource://gre/modules/Log.jsm")
|
||||
|
||||
let console = (Cu.import("resource://gre/modules/Console.jsm", {})).console
|
||||
@ -23,14 +24,12 @@ function I2pbuttonLogger() {
|
||||
this.logmethod = Services.prefs.getIntPref("extensions.i2pbutton.logmethod");
|
||||
|
||||
try {
|
||||
var logMngr = Components.classes["@mozmonkey.com/debuglogger/manager;1"]
|
||||
.getService(Components.interfaces.nsIDebugLoggerManager);
|
||||
var logMngr = Cc["@mozmonkey.com/debuglogger/manager;1"].getService(Ci.nsIDebugLoggerManager);
|
||||
this._debuglog = logMngr.registerLogger("i2pbutton");
|
||||
} catch (exErr) {
|
||||
this._debuglog = false;
|
||||
}
|
||||
this._console = Components.classes["@mozilla.org/consoleservice;1"]
|
||||
.getService(Components.interfaces.nsIConsoleService);
|
||||
this._console = Services.console;
|
||||
|
||||
// This JSObject is exported directly to chrome
|
||||
this.wrappedJSObject = this;
|
||||
@ -118,8 +117,8 @@ I2pbuttonLogger.prototype =
|
||||
log: function(level, str) {
|
||||
switch(this.logmethod) {
|
||||
case 2: // debuglogger
|
||||
if(this._debuglog) {
|
||||
this._debuglog.log((6-level), this.formatLog(str,level));
|
||||
if(this._console) {
|
||||
this._console.log((6-level), this.formatLog(str,level));
|
||||
break;
|
||||
}
|
||||
// fallthrough
|
||||
|
@ -5,6 +5,11 @@ const Ci = Components.interfaces
|
||||
const Cr = Components.results
|
||||
const Cu = Components.utils
|
||||
|
||||
const nsISupports = Components.interfaces.nsISupports;
|
||||
const nsIClassInfo = Components.interfaces.nsIClassInfo;
|
||||
const nsIComponentRegistrar = Components.interfaces.nsIComponentRegistrar;
|
||||
const nsIObserverService = Components.interfaces.nsIObserverService;
|
||||
|
||||
/*const ZipReader = Components.Constructor(
|
||||
"@mozilla.org/libjar/zip-reader;1",
|
||||
"nsIZipReader",
|
||||
@ -24,6 +29,8 @@ XPCOMUtils.defineLazyModuleGetter(this, "LauncherUtil", "resource://i2pbutton/mo
|
||||
|
||||
let consolePort = Services.prefs.getIntPref("extensions.i2pbutton.console_port_i2pj", 7647)
|
||||
let httpProxyPort = Services.prefs.getIntPref("network.proxy.http_port", 7644)
|
||||
let popClientPort = Services.prefs.getIntPref("extensions.i2pbutton.pop3_port", 7645)
|
||||
let smtpClientPort = Services.prefs.getIntPref("extensions.i2pbutton.smtp_port", 7646)
|
||||
|
||||
const defaultWebappsConfig = `# Autogenerated by I2P Browser
|
||||
webapps.jsonrpc.startOnLoad=true
|
||||
@ -45,7 +52,7 @@ 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.SSLOutproxies=false.i2p,exitulbsnsksxmxeokehe56i4ixfiy7q54psybce2wcfdojtghla.b32.i2p,exitkbklp7cpv326cnwniaj4mcbvt5fxbi6o5fgokpjqqz2yq6aa.b32.i2p,exitrts24sirf36zxmohswnqdjwfeee56id6pq2mbsidmpyo5i2a.b32.i2p,exitffc43eewzqmdgjekatq7svkddxznmifyyet35suetr5v7tzq.b32.i2p,exitogozlvokfzegkposvub53qtc7honedk6jggip35i5g74d2tq.b32.i2p,exitxwqntj5ix76yj2l34k53cwnswm4mv6kkuo65djyvd2xtek3q.b32.i2p,exitkvfpe5newfmj6vjo36whhuczaco54vrnkxwcbnb4jyqbqieq.b32.i2p,exittheiaghqhegtaifebrhgubf5x2lgxvdwtyfx6pcyzyccnbza.b32.i2p,exitvjf23kkrwfys2rmdlksqmntpcbwl22jgp7xz5d54kswlv2ea.b32.i2p,exiton6zhnnbvibjf6af2f35k6zty2twfizkixigv3lspzrt6jiq.b32.i2p,exit2t6lpxdfa7lh7myo74ndimkqdld5dcvbksf2ir2bineee4kq.b32.i2p,exit4shkhrjivffa6me7rk6z3qeqtlowkfmmegtlh4s6r42udyba.b32.i2p,exitsbu7rdzut7w2cta3deefloqtm6vlqvc5tl2qlxksdtsgdtzq.b32.i2p,exitc3ixaawclcrfqtdkqx3dz7z4kmqqwb6xjdcjxhiqpyqaxykq.b32.i2p,exit3324w3wmxf4dm557oyb7xu22h27dzfrlsfomfju55c7vzunq.b32.i2p,exitfeu3f52m3t4quju35rbboqio7p6hb2u3ufsyapcujtw45sdq.b32.i2p,exity5apnxal6p4v5irknmvcahsruccauxizycd7rr5jj3xfvrpq.b32.i2p,exitq45yln7rufb2nds5n3wtbq5onxaquclouoqe2rgw7uux5kea.b32.i2p,exithmchu47w4ykmsuhu2ixuwgj7m47nlu7xdooeykcerl5nps2a.b32.i2p,exit24yuwd4lvbfylahr7z5hxddn7dy5z6wzn77pjmg3uujfpxna.b32.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
|
||||
@ -67,10 +74,45 @@ 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.proxyList=false.i2p,exitulbsnsksxmxeokehe56i4ixfiy7q54psybce2wcfdojtghla.b32.i2p,exitkbklp7cpv326cnwniaj4mcbvt5fxbi6o5fgokpjqqz2yq6aa.b32.i2p,exitrts24sirf36zxmohswnqdjwfeee56id6pq2mbsidmpyo5i2a.b32.i2p,exitffc43eewzqmdgjekatq7svkddxznmifyyet35suetr5v7tzq.b32.i2p,exitogozlvokfzegkposvub53qtc7honedk6jggip35i5g74d2tq.b32.i2p,exitxwqntj5ix76yj2l34k53cwnswm4mv6kkuo65djyvd2xtek3q.b32.i2p,exitkvfpe5newfmj6vjo36whhuczaco54vrnkxwcbnb4jyqbqieq.b32.i2p,exittheiaghqhegtaifebrhgubf5x2lgxvdwtyfx6pcyzyccnbza.b32.i2p,exitvjf23kkrwfys2rmdlksqmntpcbwl22jgp7xz5d54kswlv2ea.b32.i2p,exiton6zhnnbvibjf6af2f35k6zty2twfizkixigv3lspzrt6jiq.b32.i2p,exit2t6lpxdfa7lh7myo74ndimkqdld5dcvbksf2ir2bineee4kq.b32.i2p,exit4shkhrjivffa6me7rk6z3qeqtlowkfmmegtlh4s6r42udyba.b32.i2p,exitsbu7rdzut7w2cta3deefloqtm6vlqvc5tl2qlxksdtsgdtzq.b32.i2p,exitc3ixaawclcrfqtdkqx3dz7z4kmqqwb6xjdcjxhiqpyqaxykq.b32.i2p,exit3324w3wmxf4dm557oyb7xu22h27dzfrlsfomfju55c7vzunq.b32.i2p,exitfeu3f52m3t4quju35rbboqio7p6hb2u3ufsyapcujtw45sdq.b32.i2p,exity5apnxal6p4v5irknmvcahsruccauxizycd7rr5jj3xfvrpq.b32.i2p,exitq45yln7rufb2nds5n3wtbq5onxaquclouoqe2rgw7uux5kea.b32.i2p,exithmchu47w4ykmsuhu2ixuwgj7m47nlu7xdooeykcerl5nps2a.b32.i2p,exit24yuwd4lvbfylahr7z5hxddn7dy5z6wzn77pjmg3uujfpxna.b32.i2p
|
||||
tunnel.0.sharedClient=true
|
||||
tunnel.0.startOnLoad=true
|
||||
tunnel.0.type=httpclient
|
||||
tunnel.1.description=smtp server
|
||||
tunnel.1.interface=127.0.0.1
|
||||
tunnel.1.listenPort=${smtpClientPort}
|
||||
tunnel.1.name=smtp.postman.i2p
|
||||
tunnel.1.option.inbound.nickname=shared clients
|
||||
tunnel.1.option.outbound.nickname=shared clients
|
||||
tunnel.1.option.i2cp.reduceIdleTime=900000
|
||||
tunnel.1.option.i2cp.reduceOnIdle=true
|
||||
tunnel.1.option.i2cp.reduceQuantity=1
|
||||
tunnel.1.option.inbound.length=3
|
||||
tunnel.1.option.inbound.lengthVariance=0
|
||||
tunnel.1.option.outbound.length=3
|
||||
tunnel.1.option.outbound.lengthVariance=0
|
||||
tunnel.1.startOnLoad=true
|
||||
tunnel.1.targetDestination=smtp.postman.i2p:25
|
||||
tunnel.1.type=client
|
||||
tunnel.1.sharedClient=true
|
||||
tunnel.2.name=pop3.postman.i2p
|
||||
tunnel.2.description=pop3 server
|
||||
tunnel.2.interface=127.0.0.1
|
||||
tunnel.2.listenPort=${popClientPort}
|
||||
tunnel.2.option.inbound.nickname=shared clients
|
||||
tunnel.2.option.outbound.nickname=shared clients
|
||||
tunnel.2.option.i2cp.reduceIdleTime=900000
|
||||
tunnel.2.option.i2cp.reduceOnIdle=true
|
||||
tunnel.2.option.i2cp.reduceQuantity=1
|
||||
tunnel.2.option.i2p.streaming.connectDelay=1000
|
||||
tunnel.2.option.inbound.length=3
|
||||
tunnel.2.option.inbound.lengthVariance=0
|
||||
tunnel.2.option.outbound.length=3
|
||||
tunnel.2.option.outbound.lengthVariance=0
|
||||
tunnel.2.startOnLoad=true
|
||||
tunnel.2.targetDestination=pop.postman.i2p:110
|
||||
tunnel.2.type=client
|
||||
tunnel.2.sharedClient=true
|
||||
`
|
||||
|
||||
const defaultClientsConfig = `# Autogenerated by I2P Browser
|
||||
@ -123,11 +165,44 @@ tunnel.1.startOnLoad=false
|
||||
tunnel.1.type=sockstunnel
|
||||
`
|
||||
|
||||
const defaultSusiMailConfig = `# Autogenerated by I2P Browser
|
||||
susimail.composer.cols=80
|
||||
susimail.composer.copy.to.sent=true
|
||||
susimail.composer.rows=15
|
||||
susimail.debug=false
|
||||
susimail.host=localhost
|
||||
susimail.pager.pagesize=30
|
||||
susimail.pop3.check.enable=false
|
||||
susimail.pop3.check.interval.minutes=180
|
||||
susimail.pop3.idle.timeout.seconds=240
|
||||
susimail.pop3.leave.on.server=false
|
||||
susimail.ports.fixed=true
|
||||
susimail.ports.pop3=${popClientPort}
|
||||
susimail.ports.smtp=${smtpClientPort}
|
||||
susimail.sender.domain=mail.i2p
|
||||
susimail.sender.fixed=true
|
||||
`
|
||||
|
||||
const defaultSnarkConfig = `# Autogenerated by I2P Browser
|
||||
i2psnark.autoStart=false
|
||||
i2psnark.collapsePanels=true
|
||||
i2psnark.comments=true
|
||||
i2psnark.commentsName=
|
||||
i2psnark.dir=i2psnark
|
||||
i2psnark.i2cpOptions=inbound.length=3 outbound.length=3 inbound.quantity=3 outbound.quantity=3
|
||||
i2psnark.pageSize=50
|
||||
i2psnark.ratings=true
|
||||
i2psnark.refreshSeconds=60
|
||||
i2psnark.startupDelay=3
|
||||
i2psnark.theme=light
|
||||
i2psnark.uploaders.total=20
|
||||
`
|
||||
|
||||
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/
|
||||
i2p.reseedURL=https://download.xxlspeed.com/,https://i2p.mooo.com/netDb/,https://i2p.novg.net/,https://i2pseed.creativecowpat.net:8443/,https://netdb.i2p2.no/,https://reseed.i2p-projekt.de/,https://reseed.i2p.net.in/,https://reseed.memcpy.io/,https://reseed.onion.im/,https://reseed.i2p2.no/,https://reseed2.i2p2.no/
|
||||
router.outboundPool.quantity=7
|
||||
router.inboundPool.quantity=7
|
||||
router.sharePercentage=50
|
||||
@ -137,9 +212,6 @@ router.startup.jetty9.migrated=true
|
||||
routerconsole.welcomeWizardComplete=true
|
||||
`
|
||||
|
||||
let noscript = Cu.import("resource://i2pbutton/modules/noscript-control.js")
|
||||
noscript.initialize()
|
||||
|
||||
function RouterConfigManager() {
|
||||
this.version = '0.1'
|
||||
this._logger = Cc["@geti2p.net/i2pbutton-logger;1"].getService(Ci.nsISupports).wrappedJSObject
|
||||
@ -160,14 +232,22 @@ RouterConfigManager.prototype = {
|
||||
// State
|
||||
mDoesRouterConfigExists: false,
|
||||
mDoesClientsConfigExists: false,
|
||||
mDoesSusiConfigExists: false,
|
||||
mDoesSnarkConfigExists: false,
|
||||
mDoesTunnelConfigExists: false,
|
||||
mDoesWebappsConfigExists: false,
|
||||
mHasChecksStarted: false,
|
||||
mIsChecksDone: false,
|
||||
|
||||
|
||||
// nsISupports implementation.
|
||||
QueryInterface: XPCOMUtils.generateQI([Components.interfaces.nsISupports]),
|
||||
QueryInterface: function(iid)
|
||||
{
|
||||
if (!iid.equals(nsIClassInfo) &&
|
||||
!iid.equals(nsISupports)) {
|
||||
Components.returnCode = Cr.NS_ERROR_NO_INTERFACE;
|
||||
return null;
|
||||
}
|
||||
return this;
|
||||
},
|
||||
|
||||
canRouterStart: function() {
|
||||
return (this.mDoesRouterConfigExists && this.mDoesClientsConfigExists && this.mDoesTunnelConfigExists)
|
||||
@ -239,6 +319,10 @@ RouterConfigManager.prototype = {
|
||||
routerConfigFile.append('router.config')
|
||||
let tunnelConfigFile = configDirectory.clone()
|
||||
tunnelConfigFile.append('i2ptunnel.config')
|
||||
let susiConfigFile = configDirectory.clone()
|
||||
susiConfigFile.append('susimail.config')
|
||||
let snarkConfigFile = configDirectory.clone()
|
||||
snarkConfigFile.append('i2psnark.config')
|
||||
let clientsConfigFile = configDirectory.clone()
|
||||
clientsConfigFile.append('clients.config')
|
||||
let webappsConfigFile = configDirectory.clone()
|
||||
@ -311,6 +395,40 @@ RouterConfigManager.prototype = {
|
||||
})
|
||||
}
|
||||
|
||||
this.ensureSusiConfigPromise = () => {
|
||||
return new Promise(resolve => {
|
||||
if (!susiConfigFile.exists()) {
|
||||
self._write_config(susiConfigFile, defaultSusiMailConfig, tfile => {
|
||||
self._logger.log(3, 'Wrote susimail.config')
|
||||
self.mDoesSusiConfigExists = true
|
||||
if (typeof onCompleteCallback === 'function') onCompleteCallback(tfile)
|
||||
resolve(susiConfigFile)
|
||||
})
|
||||
} else {
|
||||
self._logger.log(3, 'Found susimail.config from earlier')
|
||||
self.mDoesSusiConfigExists = true
|
||||
resolve(null)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
this.ensureSnarkConfigPromise = () => {
|
||||
return new Promise(resolve => {
|
||||
if (!snarkConfigFile.exists()) {
|
||||
self._write_config(snarkConfigFile, defaultSnarkConfig, tfile => {
|
||||
self._logger.log(3, 'Wrote i2psnark.config')
|
||||
self.mDoesSnarkConfigExists = true
|
||||
if (typeof onCompleteCallback === 'function') onCompleteCallback(tfile)
|
||||
resolve(snarkConfigFile)
|
||||
})
|
||||
} else {
|
||||
self._logger.log(3, 'Found i2psnark.config from earlier')
|
||||
self.mDoesSnarkConfigExists = true
|
||||
resolve(null)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
this.ensureClientsConfigPromise = () => {
|
||||
return new Promise(resolve => {
|
||||
if (!clientsConfigFile.exists()) {
|
||||
@ -350,6 +468,8 @@ RouterConfigManager.prototype = {
|
||||
return Promise.all([
|
||||
this.ensureRouterConfigPromise(),
|
||||
this.ensureTunnelConfigPromise(),
|
||||
this.ensureSusiConfigPromise(),
|
||||
this.ensureSnarkConfigPromise(),
|
||||
this.ensureClientsConfigPromise(),
|
||||
this.ensureWebappsConfigPromise(),
|
||||
])
|
||||
|
@ -18,7 +18,6 @@ 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://i2pbutton/modules/noscript-control.js", {})
|
||||
|
||||
// Module specific constants
|
||||
const kMODULE_NAME = "Startup"
|
||||
|
@ -1,11 +1,11 @@
|
||||
// debug prefs
|
||||
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.logmethod", 1); // 0=stdout, 1=errorconsole, 2=debuglog
|
||||
|
||||
pref("extensions.i2pbutton@geti2p.net.description", "chrome://i2pbutton/locale/i2pbutton.properties");
|
||||
pref("extensions.i2pbutton.updateNeeded", false);
|
||||
|
||||
pref("app.update.url.details", "https://geti2p.net/en/download/lab")
|
||||
pref("app.update.url.details", "https://geti2p.net/en/download/lab");
|
||||
|
||||
// I2P check and proxy prefs
|
||||
pref("extensions.i2pbutton.test_enabled",true);
|
||||
@ -59,6 +59,8 @@ pref("extensions.i2pbutton.console_host", "127.0.0.1");
|
||||
pref("extensions.i2pbutton.console_port_i2pj", 7647);
|
||||
pref("extensions.i2pbutton.console_port_i2pd", 17070);
|
||||
|
||||
pref("extensions.i2pbutton.pop3_port", 7645);
|
||||
pref("extensions.i2pbutton.smtp_port", 7646);
|
||||
|
||||
// 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.3.8</em:version>
|
||||
<em:version>0.3.9</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>
|
||||
|
@ -21,6 +21,25 @@ let logger = {
|
||||
}
|
||||
}
|
||||
|
||||
// ## Environment variables
|
||||
|
||||
// __env__.
|
||||
// Provides access to process environment variables.
|
||||
let env = Cc["@mozilla.org/process/environment;1"]
|
||||
.getService(Ci.nsIEnvironment);
|
||||
|
||||
// __getEnv(name)__.
|
||||
// Reads the environment variable of the given name.
|
||||
var getEnv = function (name) {
|
||||
return env.exists(name) ? env.get(name) : undefined;
|
||||
};
|
||||
|
||||
// __getLocale
|
||||
// Reads the browser locale, the default locale is en-US.
|
||||
var getLocale = function() {
|
||||
return Services.locale.requestedLocale || "en-US";
|
||||
};
|
||||
|
||||
const Timer = Components.Constructor("@mozilla.org/timer;1", "nsITimer", "initWithCallback");
|
||||
|
||||
function delay(timeout, func) {
|
||||
@ -185,18 +204,6 @@ const LauncherUtil = {
|
||||
|
||||
cleanupTempDirectories: function()
|
||||
{
|
||||
try
|
||||
{
|
||||
let dirPath = this.getCharPref(LauncherUtilInternal.kIPCDirPrefName);
|
||||
this.clearUserPref(LauncherUtilInternal.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() {
|
||||
|
@ -1,202 +0,0 @@
|
||||
// # 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", {});
|
||||
let logger = Components.classes["@geti2p.net/i2pbutton-logger;1"]
|
||||
.getService(Components.interfaces.nsISupports).wrappedJSObject;
|
||||
let log = (level, msg) => logger.log(level, msg);
|
||||
|
||||
|
||||
// __prefs__. A shortcut to Mozilla Services.prefs.
|
||||
let prefs = Services.prefs;
|
||||
|
||||
// __getPrefValue(prefName)__
|
||||
// Returns the current value of a preference, regardless of its type.
|
||||
var getPrefValue = function (prefName) {
|
||||
switch(prefs.getPrefType(prefName)) {
|
||||
case prefs.PREF_BOOL: return prefs.getBoolPref(prefName);
|
||||
case prefs.PREF_INT: return prefs.getIntPref(prefName);
|
||||
case prefs.PREF_STRING: return prefs.getCharPref(prefName);
|
||||
default: return null;
|
||||
}
|
||||
};
|
||||
|
||||
// __bindPref(prefName, prefHandler, init)__
|
||||
// Applies prefHandler whenever the value of the pref changes.
|
||||
// If init is true, applies prefHandler to the current value.
|
||||
// Returns a zero-arg function that unbinds the pref.
|
||||
var bindPref = function (prefName, prefHandler, init = false) {
|
||||
let update = () => { prefHandler(getPrefValue(prefName)); },
|
||||
observer = { observe : function (subject, topic, data) {
|
||||
if (data === prefName) {
|
||||
update();
|
||||
}
|
||||
} };
|
||||
prefs.addObserver(prefName, observer, false);
|
||||
if (init) {
|
||||
update();
|
||||
}
|
||||
return () => { prefs.removeObserver(prefName, observer); };
|
||||
};
|
||||
|
||||
// __bindPrefAndInit(prefName, prefHandler)__
|
||||
// Applies prefHandler to the current value of pref specified by prefName.
|
||||
// Re-applies prefHandler whenever the value of the pref changes.
|
||||
// Returns a zero-arg function that unbinds the pref.
|
||||
var bindPrefAndInit = (prefName, prefHandler) =>
|
||||
bindPref(prefName, prefHandler, true);
|
||||
|
||||
// ## 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"];
|
@ -1,5 +1,5 @@
|
||||
// ### Shortcut
|
||||
const { Cu: utils, Cr: results } = Components
|
||||
let {classes: Cc, utils: Cu } = Components;
|
||||
|
||||
// ### Import Mozilla Services
|
||||
Cu.import("resource://gre/modules/Services.jsm")
|
||||
@ -203,7 +203,7 @@ var getEnv = function (name) {
|
||||
// __getLocale
|
||||
// Reads the browser locale, the default locale is en-US.
|
||||
var getLocale = function() {
|
||||
return Services.locale.getRequestedLocale() || "en-US";
|
||||
return "en-US";
|
||||
}
|
||||
|
||||
// ## Windows
|
||||
|
Reference in New Issue
Block a user