1
0
Fork 0

Adding upstream version 7.5.1+dfsg.

Signed-off-by: Daniel Baumann <daniel@debian.org>
This commit is contained in:
Daniel Baumann 2025-02-07 01:18:43 +01:00
parent caee58990d
commit 916e3d5336
Signed by: daniel
GPG key ID: FBB4F0E80A80222F
89 changed files with 16891 additions and 0 deletions

6
.editorconfig Normal file
View file

@ -0,0 +1,6 @@
[*]
indent_style = space
indent_size = 2
charset = utf-8
trim_trailing_whitespace = true
insert_final_newline = false

4
.gitignore vendored Normal file
View file

@ -0,0 +1,4 @@
node_modules
.DS_Store
archive.zip
target.zip

8
3rd-party-libs.txt Normal file
View file

@ -0,0 +1,8 @@
# 3rd-Party Libraries
## jscolor Color Picker
A very nice color picker, much better than HTML's native <input type="color">. No jQuery dependency.
Source: http://jscolor.com/release/latest.zip (Unfortunately, there is no specific URL for 2.0.5, the version I am using) <br>
Docs: http://jscolor.com/
Renamed to jscolor-2.0.5.js

18
Gruntfile.js Normal file
View file

@ -0,0 +1,18 @@
module.exports = function(grunt) {
grunt.initConfig({
compress: {
main: {
options: {
archive: 'target.zip'
},
files: [
{expand: true, cwd: 'src/', src: ['**/*', '!node_modules/**', '!.DS_Store', '!archive/**', '!tests/**'], dest: '/', filter: 'isFile'}
]
}
}
});
grunt.loadNpmTasks('grunt-contrib-compress');
grunt.registerTask('default', ['compress']);
};

339
LICENSE Normal file
View file

@ -0,0 +1,339 @@
GNU GENERAL PUBLIC LICENSE
Version 2, June 1991
Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The licenses for most software are designed to take away your
freedom to share and change it. By contrast, the GNU General Public
License is intended to guarantee your freedom to share and change free
software--to make sure the software is free for all its users. This
General Public License applies to most of the Free Software
Foundation's software and to any other program whose authors commit to
using it. (Some other Free Software Foundation software is covered by
the GNU Lesser General Public License instead.) You can apply it to
your programs, too.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
this service if you wish), that you receive source code or can get it
if you want it, that you can change the software or use pieces of it
in new free programs; and that you know you can do these things.
To protect your rights, we need to make restrictions that forbid
anyone to deny you these rights or to ask you to surrender the rights.
These restrictions translate to certain responsibilities for you if you
distribute copies of the software, or if you modify it.
For example, if you distribute copies of such a program, whether
gratis or for a fee, you must give the recipients all the rights that
you have. You must make sure that they, too, receive or can get the
source code. And you must show them these terms so they know their
rights.
We protect your rights with two steps: (1) copyright the software, and
(2) offer you this license which gives you legal permission to copy,
distribute and/or modify the software.
Also, for each author's protection and ours, we want to make certain
that everyone understands that there is no warranty for this free
software. If the software is modified by someone else and passed on, we
want its recipients to know that what they have is not the original, so
that any problems introduced by others will not reflect on the original
authors' reputations.
Finally, any free program is threatened constantly by software
patents. We wish to avoid the danger that redistributors of a free
program will individually obtain patent licenses, in effect making the
program proprietary. To prevent this, we have made it clear that any
patent must be licensed for everyone's free use or not licensed at all.
The precise terms and conditions for copying, distribution and
modification follow.
GNU GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. This License applies to any program or other work which contains
a notice placed by the copyright holder saying it may be distributed
under the terms of this General Public License. The "Program", below,
refers to any such program or work, and a "work based on the Program"
means either the Program or any derivative work under copyright law:
that is to say, a work containing the Program or a portion of it,
either verbatim or with modifications and/or translated into another
language. (Hereinafter, translation is included without limitation in
the term "modification".) Each licensee is addressed as "you".
Activities other than copying, distribution and modification are not
covered by this License; they are outside its scope. The act of
running the Program is not restricted, and the output from the Program
is covered only if its contents constitute a work based on the
Program (independent of having been made by running the Program).
Whether that is true depends on what the Program does.
1. You may copy and distribute verbatim copies of the Program's
source code as you receive it, in any medium, provided that you
conspicuously and appropriately publish on each copy an appropriate
copyright notice and disclaimer of warranty; keep intact all the
notices that refer to this License and to the absence of any warranty;
and give any other recipients of the Program a copy of this License
along with the Program.
You may charge a fee for the physical act of transferring a copy, and
you may at your option offer warranty protection in exchange for a fee.
2. You may modify your copy or copies of the Program or any portion
of it, thus forming a work based on the Program, and copy and
distribute such modifications or work under the terms of Section 1
above, provided that you also meet all of these conditions:
a) You must cause the modified files to carry prominent notices
stating that you changed the files and the date of any change.
b) You must cause any work that you distribute or publish, that in
whole or in part contains or is derived from the Program or any
part thereof, to be licensed as a whole at no charge to all third
parties under the terms of this License.
c) If the modified program normally reads commands interactively
when run, you must cause it, when started running for such
interactive use in the most ordinary way, to print or display an
announcement including an appropriate copyright notice and a
notice that there is no warranty (or else, saying that you provide
a warranty) and that users may redistribute the program under
these conditions, and telling the user how to view a copy of this
License. (Exception: if the Program itself is interactive but
does not normally print such an announcement, your work based on
the Program is not required to print an announcement.)
These requirements apply to the modified work as a whole. If
identifiable sections of that work are not derived from the Program,
and can be reasonably considered independent and separate works in
themselves, then this License, and its terms, do not apply to those
sections when you distribute them as separate works. But when you
distribute the same sections as part of a whole which is a work based
on the Program, the distribution of the whole must be on the terms of
this License, whose permissions for other licensees extend to the
entire whole, and thus to each and every part regardless of who wrote it.
Thus, it is not the intent of this section to claim rights or contest
your rights to work written entirely by you; rather, the intent is to
exercise the right to control the distribution of derivative or
collective works based on the Program.
In addition, mere aggregation of another work not based on the Program
with the Program (or with a work based on the Program) on a volume of
a storage or distribution medium does not bring the other work under
the scope of this License.
3. You may copy and distribute the Program (or a work based on it,
under Section 2) in object code or executable form under the terms of
Sections 1 and 2 above provided that you also do one of the following:
a) Accompany it with the complete corresponding machine-readable
source code, which must be distributed under the terms of Sections
1 and 2 above on a medium customarily used for software interchange; or,
b) Accompany it with a written offer, valid for at least three
years, to give any third party, for a charge no more than your
cost of physically performing source distribution, a complete
machine-readable copy of the corresponding source code, to be
distributed under the terms of Sections 1 and 2 above on a medium
customarily used for software interchange; or,
c) Accompany it with the information you received as to the offer
to distribute corresponding source code. (This alternative is
allowed only for noncommercial distribution and only if you
received the program in object code or executable form with such
an offer, in accord with Subsection b above.)
The source code for a work means the preferred form of the work for
making modifications to it. For an executable work, complete source
code means all the source code for all modules it contains, plus any
associated interface definition files, plus the scripts used to
control compilation and installation of the executable. However, as a
special exception, the source code distributed need not include
anything that is normally distributed (in either source or binary
form) with the major components (compiler, kernel, and so on) of the
operating system on which the executable runs, unless that component
itself accompanies the executable.
If distribution of executable or object code is made by offering
access to copy from a designated place, then offering equivalent
access to copy the source code from the same place counts as
distribution of the source code, even though third parties are not
compelled to copy the source along with the object code.
4. You may not copy, modify, sublicense, or distribute the Program
except as expressly provided under this License. Any attempt
otherwise to copy, modify, sublicense or distribute the Program is
void, and will automatically terminate your rights under this License.
However, parties who have received copies, or rights, from you under
this License will not have their licenses terminated so long as such
parties remain in full compliance.
5. You are not required to accept this License, since you have not
signed it. However, nothing else grants you permission to modify or
distribute the Program or its derivative works. These actions are
prohibited by law if you do not accept this License. Therefore, by
modifying or distributing the Program (or any work based on the
Program), you indicate your acceptance of this License to do so, and
all its terms and conditions for copying, distributing or modifying
the Program or works based on it.
6. Each time you redistribute the Program (or any work based on the
Program), the recipient automatically receives a license from the
original licensor to copy, distribute or modify the Program subject to
these terms and conditions. You may not impose any further
restrictions on the recipients' exercise of the rights granted herein.
You are not responsible for enforcing compliance by third parties to
this License.
7. If, as a consequence of a court judgment or allegation of patent
infringement or for any other reason (not limited to patent issues),
conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot
distribute so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you
may not distribute the Program at all. For example, if a patent
license would not permit royalty-free redistribution of the Program by
all those who receive copies directly or indirectly through you, then
the only way you could satisfy both it and this License would be to
refrain entirely from distribution of the Program.
If any portion of this section is held invalid or unenforceable under
any particular circumstance, the balance of the section is intended to
apply and the section as a whole is intended to apply in other
circumstances.
It is not the purpose of this section to induce you to infringe any
patents or other property right claims or to contest validity of any
such claims; this section has the sole purpose of protecting the
integrity of the free software distribution system, which is
implemented by public license practices. Many people have made
generous contributions to the wide range of software distributed
through that system in reliance on consistent application of that
system; it is up to the author/donor to decide if he or she is willing
to distribute software through any other system and a licensee cannot
impose that choice.
This section is intended to make thoroughly clear what is believed to
be a consequence of the rest of this License.
8. If the distribution and/or use of the Program is restricted in
certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Program under this License
may add an explicit geographical distribution limitation excluding
those countries, so that distribution is permitted only in or among
countries not thus excluded. In such case, this License incorporates
the limitation as if written in the body of this License.
9. The Free Software Foundation may publish revised and/or new versions
of the General Public License from time to time. Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the Program
specifies a version number of this License which applies to it and "any
later version", you have the option of following the terms and conditions
either of that version or of any later version published by the Free
Software Foundation. If the Program does not specify a version number of
this License, you may choose any version ever published by the Free Software
Foundation.
10. If you wish to incorporate parts of the Program into other free
programs whose distribution conditions are different, write to the author
to ask for permission. For software which is copyrighted by the Free
Software Foundation, write to the Free Software Foundation; we sometimes
make exceptions for this. Our decision will be guided by the two goals
of preserving the free status of all derivatives of our free software and
of promoting the sharing and reuse of software generally.
NO WARRANTY
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
REPAIR OR CORRECTION.
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
POSSIBILITY OF SUCH DAMAGES.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest
to attach them to the start of each source file to most effectively
convey the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
<one line to give the program's name and a brief idea of what it does.>
Copyright (C) <year> <name of author>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
Also add information on how to contact you by electronic and paper mail.
If the program is interactive, make it output a short notice like this
when it starts in an interactive mode:
Gnomovision version 69, Copyright (C) year name of author
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.
The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License. Of course, the commands you use may
be called something other than `show w' and `show c'; they could even be
mouse-clicks or menu items--whatever suits your program.
You should also get your employer (if you work as a programmer) or your
school, if any, to sign a "copyright disclaimer" for the program, if
necessary. Here is a sample; alter the names:
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
`Gnomovision' (which makes passes at compilers) written by James Hacker.
<signature of Ty Coon>, 1 April 1989
Ty Coon, President of Vice
This General Public License does not permit incorporating your program into
proprietary programs. If your program is a subroutine library, you may
consider it more useful to permit linking proprietary applications with the
library. If this is what you want to do, use the GNU Lesser General
Public License instead of this License.

69
README.md Normal file
View file

@ -0,0 +1,69 @@
# FoxyProxy for Firefox
The FoxyProxy extension has been around for almost 15 years as of 2019. It has been rewritten several times and is still maintained by the original developer, Eric H. Jung, with large contributions by others (e.g. erosman, Jesper Hansen, Georg Koppen, and others). As of 2019/2020, ericjung and erosman are primary developers.
Originally for Firefox, a Chrome edition was released years ago as well. It does not share the same codebase (yet), so this project is strictly for the Firefox edition. We hope they will share the same codebase sometime in 2020.
Pre-Firefox 57 (Quantum) versions are not maintained here. They are stored in a private git repo which I will release to github when time permits.
## Editions
FoxyProxy for Firefox comes in three editions. Two of these editions are in this repository.
### [Standard](https://addons.mozilla.org/firefox/addon/foxyproxy-standard/)
This edition switches requests between proxy servers based on domain/URL patterns or manually selecting a proxy server to use for all requests. This is the default build target for this project.
### [Basic](https://addons.mozilla.org/firefox/addon/foxyproxy-basic/)
This edition sends all requests through a proxy servers manually selected by the user. There is no domain/URL pattern switching like with Standard and Plus. This build target can be selected by TODO.
### Plus
No longer maintained since Firefox 57 dropped support for critical APIs. The source code is not in this repo. It had the same features as standard but also enabled switching by internal (LAN) IP address. For example, if your laptop connected to a work/school network and a home network, you could have different switching rules based on your location (providing the internal IP addresses were different, and they almost always are). Many people used this to automatically disable FoxyProxy while at home but enable it while at work or school.
## Translations!
FoxyProxy is internationalized! Translate [messages.json](https://github.com/foxyproxy/firefox-extension/blob/master/src/_locales/en/messages.json) then make a pull request or email the file to me. Pre-Firefox 57 (Quantum) editions had 33 or 35 languages!
## Building
FoxyProxy **Standard** edition is built by default. To build FoxyProxy **Basic** edition:
* change `FOXYPROXY_BASIC` from `false` to `true` in [utils.js](https://github.com/foxyproxy/firefox-extension/blob/master/src/scripts/utils.js)
* change browser_specific_settings.id in [manifest.json](https://github.com/foxyproxy/firefox-extension/blob/master/src/manifest.json) from `foxyproxy@eric.h.jung` to `foxyproxy-basic@eric.h.jung`
### Building With Grunt
[Install grunt](https://stackoverflow.com/questions/15703598/how-to-install-grunt-and-how-to-build-script-with-it), which requires npm and node.
Run grunt in top-level directory. The add-on is packaged into target.zip
### Building Without Grunt
Zip the [src](https://github.com/foxyproxy/firefox-extension/tree/master/src) directory.
## Running a development instance
0. Clone this repository: `git clone https://github.com/foxyproxy/firefox-extension.git`
1. In Firefox, navigate to `about:debugging#/runtime/this-firefox`
2. Click `Load Temporary Add-on`
3. Choose `manifest.json` in the cloned repository on your local system.
Note some items are cached by Firefox. Please refer to other online documentation for complete development and debugging of add-ons.
## Authors
* **Eric H. Jung** - [FoxyProxy](https://getfoxyproxy.org/team/)
* **[erosman](https://github.com/erosman)**
* **[FeralMeow](https://github.com/wsxy162)** - Chinese (Simplified) translation
* **[samuikaze](https://github.com/samuikaze)** - Chinese (traditional) translation
* **Vadim** - Russian translation
* **Your Name Here** if you contribute a language translation or other work
## License
This project is licensed under the GPL 2.0 License. Commercial re-licensing may be available on request.
## Feature Requests / RoadMap

View file

@ -0,0 +1,4 @@
<?xml version="1.0" encoding="UTF-8"?>
<foxyproxy mode="disabled" selectedTabIndex="0" toolbaricon="true" toolsMenu="true" contextMenu="true" advancedMenus="false" previousMode="disabled" resetIconColors="true" useStatusBarPrefix="true" excludePatternsFromCycling="false" excludeDisabledFromCycling="false" ignoreProxyScheme="false" apiDisabled="false" proxyForVersionCheck="2653187683"><random includeDirect="false" includeDisabled="false"/><statusbar icon="true" text="false" left="options" middle="cycle" right="contextmenu" width="0"/><toolbar left="options" middle="cycle" right="contextmenu"/><logg enabled="false" maxSize="500" noURLs="false" header="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&gt;
&lt;!DOCTYPE html PUBLIC &quot;-//W3C//DTD XHTML 1.0 Strict//EN&quot; &quot;http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd&quot;&gt;
&lt;html xmlns=&quot;http://www.w3.org/1999/xhtml&quot;&gt;&lt;head&gt;&lt;title&gt;&lt;/title&gt;&lt;link rel=&quot;icon&quot; href=&quot;http://getfoxyproxy.org/favicon.ico&quot;/&gt;&lt;link rel=&quot;shortcut icon&quot; href=&quot;http://getfoxyproxy.org/favicon.ico&quot;/&gt;&lt;link rel=&quot;stylesheet&quot; href=&quot;http://getfoxyproxy.org/styles/log.css&quot; type=&quot;text/css&quot;/&gt;&lt;/head&gt;&lt;body&gt;&lt;table class=&quot;log-table&quot;&gt;&lt;thead&gt;&lt;tr&gt;&lt;td class=&quot;heading&quot;&gt;${timestamp-heading}&lt;/td&gt;&lt;td class=&quot;heading&quot;&gt;${url-heading}&lt;/td&gt;&lt;td class=&quot;heading&quot;&gt;${proxy-name-heading}&lt;/td&gt;&lt;td class=&quot;heading&quot;&gt;${proxy-notes-heading}&lt;/td&gt;&lt;td class=&quot;heading&quot;&gt;${pattern-name-heading}&lt;/td&gt;&lt;td class=&quot;heading&quot;&gt;${pattern-heading}&lt;/td&gt;&lt;td class=&quot;heading&quot;&gt;${pattern-case-heading}&lt;/td&gt;&lt;td class=&quot;heading&quot;&gt;${pattern-type-heading}&lt;/td&gt;&lt;td class=&quot;heading&quot;&gt;${pattern-color-heading}&lt;/td&gt;&lt;td class=&quot;heading&quot;&gt;${pac-result-heading}&lt;/td&gt;&lt;td class=&quot;heading&quot;&gt;${error-msg-heading}&lt;/td&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tfoot&gt;&lt;tr&gt;&lt;td/&gt;&lt;/tr&gt;&lt;/tfoot&gt;&lt;tbody&gt;" row="&lt;tr&gt;&lt;td class=&quot;timestamp&quot;&gt;${timestamp}&lt;/td&gt;&lt;td class=&quot;url&quot;&gt;&lt;a href=&quot;${url}&quot;&gt;${url}&lt;/a&gt;&lt;/td&gt;&lt;td class=&quot;proxy-name&quot;&gt;${proxy-name}&lt;/td&gt;&lt;td class=&quot;proxy-notes&quot;&gt;${proxy-notes}&lt;/td&gt;&lt;td class=&quot;pattern-name&quot;&gt;${pattern-name}&lt;/td&gt;&lt;td class=&quot;pattern&quot;&gt;${pattern}&lt;/td&gt;&lt;td class=&quot;pattern-case&quot;&gt;${pattern-case}&lt;/td&gt;&lt;td class=&quot;pattern-type&quot;&gt;${pattern-type}&lt;/td&gt;&lt;td class=&quot;pattern-color&quot;&gt;${pattern-color}&lt;/td&gt;&lt;td class=&quot;pac-result&quot;&gt;${pac-result}&lt;/td&gt;&lt;td class=&quot;error-msg&quot;&gt;${error-msg}&lt;/td&gt;&lt;/tr&gt;" footer="&lt;/tbody&gt;&lt;/table&gt;&lt;/body&gt;&lt;/html&gt;"/><warnings/><autoadd enabled="false" temp="false" reload="true" notify="true" notifyWhenCanceled="true" prompt="true"><match enabled="true" name="Dynamic AutoAdd Pattern" pattern="*://${3}${6}/*" isRegEx="false" isBlackList="false" isMultiLine="false" caseSensitive="false" fromSubscription="false"/><match enabled="true" name="" pattern="*You are not authorized to view this page*" isRegEx="false" isBlackList="false" isMultiLine="true" caseSensitive="false" fromSubscription="false"/></autoadd><quickadd enabled="false" temp="false" reload="true" notify="true" notifyWhenCanceled="true" prompt="true"><match enabled="true" name="Dynamic QuickAdd Pattern" pattern="*://${3}${6}/*" isRegEx="false" isBlackList="false" isMultiLine="false" caseSensitive="false" fromSubscription="false"/></quickadd><defaultPrefs origPrefetch="18"/><proxies><proxy name="123.123.123.123:123" id="763274367" notes="" fromSubscription="false" enabled="false" mode="direct" selectedTabIndex="1" lastresort="false" animatedIcons="true" includeInCycle="true" color="#0055E5" proxyDNS="true" noInternalIPs="false" autoconfMode="pac" clearCacheBeforeUse="false" disableCache="false" clearCookiesBeforeUse="false" rejectCookies="false"><matches/><autoconf url="" loadNotification="true" errorNotification="true" autoReload="false" reloadFreqMins="60" disableOnBadPAC="true"/><autoconf url="http://wpad/wpad.dat" loadNotification="true" errorNotification="true" autoReload="false" reloadFreqMins="60" disableOnBadPAC="true"/><manualconf host="123" port="123" socksversion="5" isSocks="false" isHttps="true" username="eric" password="jung" domain=""/></proxy><proxy name="Default" id="2653187683" notes="These are the settings that are used when no patterns match a URL." fromSubscription="false" enabled="true" mode="system" selectedTabIndex="0" lastresort="true" animatedIcons="false" includeInCycle="true" color="#E62552" proxyDNS="true" noInternalIPs="false" autoconfMode="pac" clearCacheBeforeUse="false" disableCache="false" clearCookiesBeforeUse="false" rejectCookies="false"><matches><match enabled="true" name="All" pattern="*" isRegEx="false" isBlackList="false" isMultiLine="false" caseSensitive="false" fromSubscription="false"/></matches><autoconf url="" loadNotification="true" errorNotification="true" autoReload="false" reloadFreqMins="60" disableOnBadPAC="true"/><autoconf url="http://wpad/wpad.dat" loadNotification="true" errorNotification="true" autoReload="false" reloadFreqMins="60" disableOnBadPAC="true"/><manualconf host="foo.com" port="1111" socksversion="5" isSocks="false" isHttps="true" username="eric" password="jung" domain=""/></proxy></proxies></foxyproxy>

View file

@ -0,0 +1,4 @@
<?xml version="1.0" encoding="UTF-8"?>
<foxyproxy mode="1100165923" selectedTabIndex="0" toolbaricon="true" toolsMenu="true" contextMenu="true" advancedMenus="false" previousMode="disabled" resetIconColors="true" useStatusBarPrefix="true" excludePatternsFromCycling="false" excludeDisabledFromCycling="false" ignoreProxyScheme="false" apiDisabled="false" proxyForVersionCheck="3152644575"><random includeDirect="false" includeDisabled="false"/><statusbar icon="true" text="false" left="options" middle="cycle" right="contextmenu" width="0"/><toolbar left="options" middle="cycle" right="contextmenu"/><logg enabled="false" maxSize="500" noURLs="false" header="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&gt;
&lt;!DOCTYPE html PUBLIC &quot;-//W3C//DTD XHTML 1.0 Strict//EN&quot; &quot;http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd&quot;&gt;
&lt;html xmlns=&quot;http://www.w3.org/1999/xhtml&quot;&gt;&lt;head&gt;&lt;title&gt;&lt;/title&gt;&lt;link rel=&quot;icon&quot; href=&quot;http://getfoxyproxy.org/favicon.ico&quot;/&gt;&lt;link rel=&quot;shortcut icon&quot; href=&quot;http://getfoxyproxy.org/favicon.ico&quot;/&gt;&lt;link rel=&quot;stylesheet&quot; href=&quot;http://getfoxyproxy.org/styles/log.css&quot; type=&quot;text/css&quot;/&gt;&lt;/head&gt;&lt;body&gt;&lt;table class=&quot;log-table&quot;&gt;&lt;thead&gt;&lt;tr&gt;&lt;td class=&quot;heading&quot;&gt;${timestamp-heading}&lt;/td&gt;&lt;td class=&quot;heading&quot;&gt;${url-heading}&lt;/td&gt;&lt;td class=&quot;heading&quot;&gt;${proxy-name-heading}&lt;/td&gt;&lt;td class=&quot;heading&quot;&gt;${proxy-notes-heading}&lt;/td&gt;&lt;td class=&quot;heading&quot;&gt;${pattern-name-heading}&lt;/td&gt;&lt;td class=&quot;heading&quot;&gt;${pattern-heading}&lt;/td&gt;&lt;td class=&quot;heading&quot;&gt;${pattern-case-heading}&lt;/td&gt;&lt;td class=&quot;heading&quot;&gt;${pattern-type-heading}&lt;/td&gt;&lt;td class=&quot;heading&quot;&gt;${pattern-color-heading}&lt;/td&gt;&lt;td class=&quot;heading&quot;&gt;${pac-result-heading}&lt;/td&gt;&lt;td class=&quot;heading&quot;&gt;${error-msg-heading}&lt;/td&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tfoot&gt;&lt;tr&gt;&lt;td/&gt;&lt;/tr&gt;&lt;/tfoot&gt;&lt;tbody&gt;" row="&lt;tr&gt;&lt;td class=&quot;timestamp&quot;&gt;${timestamp}&lt;/td&gt;&lt;td class=&quot;url&quot;&gt;&lt;a href=&quot;${url}&quot;&gt;${url}&lt;/a&gt;&lt;/td&gt;&lt;td class=&quot;proxy-name&quot;&gt;${proxy-name}&lt;/td&gt;&lt;td class=&quot;proxy-notes&quot;&gt;${proxy-notes}&lt;/td&gt;&lt;td class=&quot;pattern-name&quot;&gt;${pattern-name}&lt;/td&gt;&lt;td class=&quot;pattern&quot;&gt;${pattern}&lt;/td&gt;&lt;td class=&quot;pattern-case&quot;&gt;${pattern-case}&lt;/td&gt;&lt;td class=&quot;pattern-type&quot;&gt;${pattern-type}&lt;/td&gt;&lt;td class=&quot;pattern-color&quot;&gt;${pattern-color}&lt;/td&gt;&lt;td class=&quot;pac-result&quot;&gt;${pac-result}&lt;/td&gt;&lt;td class=&quot;error-msg&quot;&gt;${error-msg}&lt;/td&gt;&lt;/tr&gt;" footer="&lt;/tbody&gt;&lt;/table&gt;&lt;/body&gt;&lt;/html&gt;"/><warnings retryAuthCredentials="false" confirmDeleteProxy="false"/><autoadd enabled="false" temp="false" reload="true" notify="true" notifyWhenCanceled="true" prompt="true"><match enabled="true" name="Dynamic AutoAdd Pattern" pattern="*://${3}${6}/*" isRegEx="false" isBlackList="false" isMultiLine="false" caseSensitive="false" fromSubscription="false"/><match enabled="true" name="" pattern="*You are not authorized to view this page*" isRegEx="false" isBlackList="false" isMultiLine="true" caseSensitive="false" fromSubscription="false"/></autoadd><quickadd enabled="false" temp="false" reload="true" notify="true" notifyWhenCanceled="true" prompt="true"><match enabled="true" name="Dynamic QuickAdd Pattern" pattern="*://${3}${6}/*" isRegEx="false" isBlackList="false" isMultiLine="false" caseSensitive="false" fromSubscription="false"/></quickadd><defaultPrefs origPrefetch="18"/><proxies><proxy name="MPP" id="1100165923" notes="" fromSubscription="false" enabled="true" mode="manual" selectedTabIndex="1" lastresort="false" animatedIcons="true" includeInCycle="true" color="#0055E5" proxyDNS="true" noInternalIPs="false" autoconfMode="pac" clearCacheBeforeUse="false" disableCache="false" clearCookiesBeforeUse="false" rejectCookies="false"><matches/><autoconf url="" loadNotification="true" errorNotification="true" autoReload="false" reloadFreqMins="60" disableOnBadPAC="true"/><autoconf url="http://wpad/wpad.dat" loadNotification="true" errorNotification="true" autoReload="false" reloadFreqMins="60" disableOnBadPAC="true"/><manualconf host="123.14.156.38" port="19842" socksversion="5" isSocks="false" username="smallguy" password="ApHJ1zzbp" domain=""/></proxy><proxy name="Default" id="3152644575" notes="These are the settings that are used when no patterns match a URL." fromSubscription="false" enabled="true" mode="direct" selectedTabIndex="0" lastresort="true" animatedIcons="false" includeInCycle="true" color="#0055E5" proxyDNS="true" noInternalIPs="false" autoconfMode="pac" clearCacheBeforeUse="false" disableCache="false" clearCookiesBeforeUse="false" rejectCookies="false"><matches><match enabled="true" name="All" pattern="*" isRegEx="false" isBlackList="false" isMultiLine="false" caseSensitive="false" fromSubscription="false"/></matches><autoconf url="" loadNotification="true" errorNotification="true" autoReload="false" reloadFreqMins="60" disableOnBadPAC="true"/><autoconf url="http://wpad/wpad.dat" loadNotification="true" errorNotification="true" autoReload="false" reloadFreqMins="60" disableOnBadPAC="true"/><manualconf host="" port="" socksversion="5" isSocks="false" username="" password="" domain=""/></proxy></proxies></foxyproxy>

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View file

@ -0,0 +1,16 @@
<foxyproxy>
<proxies>
<proxy name="emr-socks-proxy" id="2322596116" notes="" fromSubscription="false" enabled="true" mode="manual" selectedTabIndex="2" lastresort="false" animatedIcons="true" includeInCycle="true" color="#0055E5" proxyDNS="true" noInternalIPs="false" autoconfMode="pac" clearCacheBeforeUse="false" disableCache="false" clearCookiesBeforeUse="false" rejectCookies="false">
<matches>
<match enabled="true" name="*ec2*.amazonaws.com*" pattern="*ec2*.amazonaws.com*" isRegEx="false" isBlackList="false" isMultiLine="false" caseSensitive="false" fromSubscription="false" />
<match enabled="true" name="*ec2*.compute*" pattern="*ec2*.compute*" isRegEx="false" isBlackList="false" isMultiLine="false" caseSensitive="false" fromSubscription="false" />
<match enabled="true" name="10.*" pattern="http://10.*" isRegEx="false" isBlackList="false" isMultiLine="false" caseSensitive="false" fromSubscription="false" />
<match enabled="true" name="*10*.amazonaws.com*" pattern="*10*.amazonaws.com*" isRegEx="false" isBlackList="false" isMultiLine="false" caseSensitive="false" fromSubscription="false" />
<match enabled="true" name="*10*.compute*" pattern="*10*.compute*" isRegEx="false" isBlackList="false" isMultiLine="false" caseSensitive="false" fromSubscription="false" />
<match enabled="true" name="*.compute.internal*" pattern="*.compute.internal*" isRegEx="false" isBlackList="false" isMultiLine="false" caseSensitive="false" fromSubscription="false" />
<match enabled="true" name="*.ec2.internal*" pattern="*.ec2.internal*" isRegEx="false" isBlackList="false" isMultiLine="false" caseSensitive="false" fromSubscription="false" />
</matches>
<manualconf host="localhost" port="8157" socksversion="5" isSocks="true" username="" password="" domain="" />
</proxy>
</proxies>
</foxyproxy>

File diff suppressed because one or more lines are too long

View file

@ -0,0 +1,4 @@
<?xml version="1.0" encoding="UTF-8"?>
<foxyproxy mode="disabled" selectedTabIndex="0" toolbaricon="true" toolsMenu="true" contextMenu="true" advancedMenus="false" previousMode="disabled" resetIconColors="true" useStatusBarPrefix="true" excludePatternsFromCycling="false" excludeDisabledFromCycling="false" ignoreProxyScheme="false" apiDisabled="false" proxyForVersionCheck="2653187683"><random includeDirect="false" includeDisabled="false"/><statusbar icon="true" text="false" left="options" middle="cycle" right="contextmenu" width="0"/><toolbar left="options" middle="cycle" right="contextmenu"/><logg enabled="false" maxSize="500" noURLs="false" header="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&gt;
&lt;!DOCTYPE html PUBLIC &quot;-//W3C//DTD XHTML 1.0 Strict//EN&quot; &quot;http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd&quot;&gt;
&lt;html xmlns=&quot;http://www.w3.org/1999/xhtml&quot;&gt;&lt;head&gt;&lt;title&gt;&lt;/title&gt;&lt;link rel=&quot;icon&quot; href=&quot;http://getfoxyproxy.org/favicon.ico&quot;/&gt;&lt;link rel=&quot;shortcut icon&quot; href=&quot;http://getfoxyproxy.org/favicon.ico&quot;/&gt;&lt;link rel=&quot;stylesheet&quot; href=&quot;http://getfoxyproxy.org/styles/log.css&quot; type=&quot;text/css&quot;/&gt;&lt;/head&gt;&lt;body&gt;&lt;table class=&quot;log-table&quot;&gt;&lt;thead&gt;&lt;tr&gt;&lt;td class=&quot;heading&quot;&gt;${timestamp-heading}&lt;/td&gt;&lt;td class=&quot;heading&quot;&gt;${url-heading}&lt;/td&gt;&lt;td class=&quot;heading&quot;&gt;${proxy-name-heading}&lt;/td&gt;&lt;td class=&quot;heading&quot;&gt;${proxy-notes-heading}&lt;/td&gt;&lt;td class=&quot;heading&quot;&gt;${pattern-name-heading}&lt;/td&gt;&lt;td class=&quot;heading&quot;&gt;${pattern-heading}&lt;/td&gt;&lt;td class=&quot;heading&quot;&gt;${pattern-case-heading}&lt;/td&gt;&lt;td class=&quot;heading&quot;&gt;${pattern-type-heading}&lt;/td&gt;&lt;td class=&quot;heading&quot;&gt;${pattern-color-heading}&lt;/td&gt;&lt;td class=&quot;heading&quot;&gt;${pac-result-heading}&lt;/td&gt;&lt;td class=&quot;heading&quot;&gt;${error-msg-heading}&lt;/td&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tfoot&gt;&lt;tr&gt;&lt;td/&gt;&lt;/tr&gt;&lt;/tfoot&gt;&lt;tbody&gt;" row="&lt;tr&gt;&lt;td class=&quot;timestamp&quot;&gt;${timestamp}&lt;/td&gt;&lt;td class=&quot;url&quot;&gt;&lt;a href=&quot;${url}&quot;&gt;${url}&lt;/a&gt;&lt;/td&gt;&lt;td class=&quot;proxy-name&quot;&gt;${proxy-name}&lt;/td&gt;&lt;td class=&quot;proxy-notes&quot;&gt;${proxy-notes}&lt;/td&gt;&lt;td class=&quot;pattern-name&quot;&gt;${pattern-name}&lt;/td&gt;&lt;td class=&quot;pattern&quot;&gt;${pattern}&lt;/td&gt;&lt;td class=&quot;pattern-case&quot;&gt;${pattern-case}&lt;/td&gt;&lt;td class=&quot;pattern-type&quot;&gt;${pattern-type}&lt;/td&gt;&lt;td class=&quot;pattern-color&quot;&gt;${pattern-color}&lt;/td&gt;&lt;td class=&quot;pac-result&quot;&gt;${pac-result}&lt;/td&gt;&lt;td class=&quot;error-msg&quot;&gt;${error-msg}&lt;/td&gt;&lt;/tr&gt;" footer="&lt;/tbody&gt;&lt;/table&gt;&lt;/body&gt;&lt;/html&gt;"/><warnings/><autoadd enabled="false" temp="false" reload="true" notify="true" notifyWhenCanceled="true" prompt="true"><match enabled="true" name="Dynamic AutoAdd Pattern" pattern="*://${3}${6}/*" isRegEx="false" isBlackList="false" isMultiLine="false" caseSensitive="false" fromSubscription="false"/><match enabled="true" name="" pattern="*You are not authorized to view this page*" isRegEx="false" isBlackList="false" isMultiLine="true" caseSensitive="false" fromSubscription="false"/></autoadd><quickadd enabled="false" temp="false" reload="true" notify="true" notifyWhenCanceled="true" prompt="true"><match enabled="true" name="Dynamic QuickAdd Pattern" pattern="*://${3}${6}/*" isRegEx="false" isBlackList="false" isMultiLine="false" caseSensitive="false" fromSubscription="false"/></quickadd><defaultPrefs origPrefetch="18"/><proxies><proxy name="123.123.123.123:123" id="763274367" notes="" fromSubscription="false" enabled="false" mode="system" selectedTabIndex="1" lastresort="false" animatedIcons="true" includeInCycle="true" color="#0055E5" proxyDNS="true" noInternalIPs="false" autoconfMode="pac" clearCacheBeforeUse="false" disableCache="false" clearCookiesBeforeUse="false" rejectCookies="false"><matches/><autoconf url="" loadNotification="true" errorNotification="true" autoReload="false" reloadFreqMins="60" disableOnBadPAC="true"/><autoconf url="http://wpad/wpad.dat" loadNotification="true" errorNotification="true" autoReload="false" reloadFreqMins="60" disableOnBadPAC="true"/><manualconf host="123" port="123" socksversion="5" isSocks="false" isHttps="true" username="eric" password="jung" domain=""/></proxy><proxy name="Default" id="2653187683" notes="These are the settings that are used when no patterns match a URL." fromSubscription="false" enabled="true" mode="system" selectedTabIndex="0" lastresort="true" animatedIcons="false" includeInCycle="true" color="#E62552" proxyDNS="true" noInternalIPs="false" autoconfMode="pac" clearCacheBeforeUse="false" disableCache="false" clearCookiesBeforeUse="false" rejectCookies="false"><matches><match enabled="true" name="All" pattern="*" isRegEx="false" isBlackList="false" isMultiLine="false" caseSensitive="false" fromSubscription="false"/></matches><autoconf url="" loadNotification="true" errorNotification="true" autoReload="false" reloadFreqMins="60" disableOnBadPAC="true"/><autoconf url="http://wpad/wpad.dat" loadNotification="true" errorNotification="true" autoReload="false" reloadFreqMins="60" disableOnBadPAC="true"/><manualconf host="foo.com" port="1111" socksversion="5" isSocks="false" isHttps="true" username="eric" password="jung" domain=""/></proxy></proxies></foxyproxy>

View file

@ -0,0 +1,4 @@
<?xml version="1.0" encoding="UTF-8"?>
<foxyproxy mode="disabled" selectedTabIndex="0" toolbaricon="true" toolsMenu="true" contextMenu="true" advancedMenus="false" previousMode="disabled" resetIconColors="true" useStatusBarPrefix="true" excludePatternsFromCycling="false" excludeDisabledFromCycling="false" ignoreProxyScheme="false" apiDisabled="false" proxyForVersionCheck="2653187683"><random includeDirect="false" includeDisabled="false"/><statusbar icon="true" text="false" left="options" middle="cycle" right="contextmenu" width="0"/><toolbar left="options" middle="cycle" right="contextmenu"/><logg enabled="false" maxSize="500" noURLs="false" header="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&gt;
&lt;!DOCTYPE html PUBLIC &quot;-//W3C//DTD XHTML 1.0 Strict//EN&quot; &quot;http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd&quot;&gt;
&lt;html xmlns=&quot;http://www.w3.org/1999/xhtml&quot;&gt;&lt;head&gt;&lt;title&gt;&lt;/title&gt;&lt;link rel=&quot;icon&quot; href=&quot;http://getfoxyproxy.org/favicon.ico&quot;/&gt;&lt;link rel=&quot;shortcut icon&quot; href=&quot;http://getfoxyproxy.org/favicon.ico&quot;/&gt;&lt;link rel=&quot;stylesheet&quot; href=&quot;http://getfoxyproxy.org/styles/log.css&quot; type=&quot;text/css&quot;/&gt;&lt;/head&gt;&lt;body&gt;&lt;table class=&quot;log-table&quot;&gt;&lt;thead&gt;&lt;tr&gt;&lt;td class=&quot;heading&quot;&gt;${timestamp-heading}&lt;/td&gt;&lt;td class=&quot;heading&quot;&gt;${url-heading}&lt;/td&gt;&lt;td class=&quot;heading&quot;&gt;${proxy-name-heading}&lt;/td&gt;&lt;td class=&quot;heading&quot;&gt;${proxy-notes-heading}&lt;/td&gt;&lt;td class=&quot;heading&quot;&gt;${pattern-name-heading}&lt;/td&gt;&lt;td class=&quot;heading&quot;&gt;${pattern-heading}&lt;/td&gt;&lt;td class=&quot;heading&quot;&gt;${pattern-case-heading}&lt;/td&gt;&lt;td class=&quot;heading&quot;&gt;${pattern-type-heading}&lt;/td&gt;&lt;td class=&quot;heading&quot;&gt;${pattern-color-heading}&lt;/td&gt;&lt;td class=&quot;heading&quot;&gt;${pac-result-heading}&lt;/td&gt;&lt;td class=&quot;heading&quot;&gt;${error-msg-heading}&lt;/td&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tfoot&gt;&lt;tr&gt;&lt;td/&gt;&lt;/tr&gt;&lt;/tfoot&gt;&lt;tbody&gt;" row="&lt;tr&gt;&lt;td class=&quot;timestamp&quot;&gt;${timestamp}&lt;/td&gt;&lt;td class=&quot;url&quot;&gt;&lt;a href=&quot;${url}&quot;&gt;${url}&lt;/a&gt;&lt;/td&gt;&lt;td class=&quot;proxy-name&quot;&gt;${proxy-name}&lt;/td&gt;&lt;td class=&quot;proxy-notes&quot;&gt;${proxy-notes}&lt;/td&gt;&lt;td class=&quot;pattern-name&quot;&gt;${pattern-name}&lt;/td&gt;&lt;td class=&quot;pattern&quot;&gt;${pattern}&lt;/td&gt;&lt;td class=&quot;pattern-case&quot;&gt;${pattern-case}&lt;/td&gt;&lt;td class=&quot;pattern-type&quot;&gt;${pattern-type}&lt;/td&gt;&lt;td class=&quot;pattern-color&quot;&gt;${pattern-color}&lt;/td&gt;&lt;td class=&quot;pac-result&quot;&gt;${pac-result}&lt;/td&gt;&lt;td class=&quot;error-msg&quot;&gt;${error-msg}&lt;/td&gt;&lt;/tr&gt;" footer="&lt;/tbody&gt;&lt;/table&gt;&lt;/body&gt;&lt;/html&gt;"/><warnings/><autoadd enabled="false" temp="false" reload="true" notify="true" notifyWhenCanceled="true" prompt="true"><match enabled="true" name="Dynamic AutoAdd Pattern" pattern="*://${3}${6}/*" isRegEx="false" isBlackList="false" isMultiLine="false" caseSensitive="false" fromSubscription="false"/><match enabled="true" name="" pattern="*You are not authorized to view this page*" isRegEx="false" isBlackList="false" isMultiLine="true" caseSensitive="false" fromSubscription="false"/></autoadd><quickadd enabled="false" temp="false" reload="true" notify="true" notifyWhenCanceled="true" prompt="true"><match enabled="true" name="Dynamic QuickAdd Pattern" pattern="*://${3}${6}/*" isRegEx="false" isBlackList="false" isMultiLine="false" caseSensitive="false" fromSubscription="false"/></quickadd><defaultPrefs origPrefetch="18"/><proxies><proxy name="123.123.123.123:123" id="763274367" notes="" fromSubscription="false" enabled="false" mode="auto" selectedTabIndex="1" lastresort="false" animatedIcons="true" includeInCycle="true" color="#0055E5" proxyDNS="true" noInternalIPs="false" autoconfMode="wpad" clearCacheBeforeUse="false" disableCache="false" clearCookiesBeforeUse="false" rejectCookies="false"><matches/><autoconf url="http://some-pac.com" loadNotification="true" errorNotification="true" autoReload="false" reloadFreqMins="60" disableOnBadPAC="true"/><autoconf url="http://wpad/wpad.dat" loadNotification="true" errorNotification="true" autoReload="false" reloadFreqMins="60" disableOnBadPAC="true"/><manualconf host="123" port="123" socksversion="5" isSocks="false" isHttps="true" username="eric" password="jung" domain=""/></proxy><proxy name="Default" id="2653187683" notes="These are the settings that are used when no patterns match a URL." fromSubscription="false" enabled="true" mode="system" selectedTabIndex="0" lastresort="true" animatedIcons="false" includeInCycle="true" color="#E62552" proxyDNS="true" noInternalIPs="false" autoconfMode="pac" clearCacheBeforeUse="false" disableCache="false" clearCookiesBeforeUse="false" rejectCookies="false"><matches><match enabled="true" name="All" pattern="*" isRegEx="false" isBlackList="false" isMultiLine="false" caseSensitive="false" fromSubscription="false"/></matches><autoconf url="" loadNotification="true" errorNotification="true" autoReload="false" reloadFreqMins="60" disableOnBadPAC="true"/><autoconf url="http://wpad/wpad.dat" loadNotification="true" errorNotification="true" autoReload="false" reloadFreqMins="60" disableOnBadPAC="true"/><manualconf host="foo.com" port="1111" socksversion="5" isSocks="false" isHttps="true" username="eric" password="jung" domain=""/></proxy></proxies></foxyproxy>

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View file

@ -0,0 +1,69 @@
{
"mode": "patterns",
"proxySettings": [
{
"title": "some title",
"type": 3,
"color": "#3860cc",
"address": "123.123.123.123",
"port": 123,
"username": "foo",
"password": "bar",
"active": true,
"whitePatterns": [
{
"title": "everything",
"active": true,
"pattern": "*",
"type": 1,
"protocols": 1
}
],
"blackPatterns": [
{
"title": "local hostnames (usually no dots in the name). Pattern exists because 'Do not use this proxy for localhost and intranet/private IP addresses' is checked.",
"active": true,
"pattern": "^(?:[^:@/]+(?::[^@/]+)?@)?(?:localhost|127\\.\\d+\\.\\d+\\.\\d+)(?::\\d+)?(?:/.*)?$",
"type": 2,
"protocols": 1
},
{
"title": "local subnets (IANA reserved address space). Pattern exists because 'Do not use this proxy for localhost and intranet/private IP addresses' is checked.",
"active": true,
"pattern": "^(?:[^:@/]+(?::[^@/]+)?@)?(?:192\\.168\\.\\d+\\.\\d+|10\\.\\d+\\.\\d+\\.\\d+|172\\.(?:1[6789]|2[0-9]|3[01])\\.\\d+\\.\\d+)(?::\\d+)?(?:/.*)?$",
"type": 2,
"protocols": 1
},
{
"title": "localhost - matches the local host optionally prefixed by a user:password authentication string and optionally suffixed by a port number. The entire local subnet (127.0.0.0/8) matches. Pattern exists because 'Do not use this proxy for localhost and intranet/private IP addresses' is checked.",
"active": true,
"pattern": "^(?:[^:@/]+(?::[^@/]+)?@)?[\\w-]+(?::\\d+)?(?:/.*)?$",
"type": 2,
"protocols": 1
}
],
"id": "5yunu1562958387189"
},
{
"title": "Default",
"type": 5,
"color": "#0055e5",
"active": true,
"whitePatterns": [
{
"title": "all URLs",
"active": true,
"pattern": "*",
"type": 1,
"protocols": 1
}
],
"blackPatterns": [],
"id": "k20d21508277536715"
}
],
"logging": {
"size": 500,
"active": true
}
}

View file

@ -0,0 +1,15 @@
# Use foxyproxy-template.json to ouptut foxyproxy-5000-proxies-test-settings.json
# which has 5000 proxies defined. foxyproxy-template.json should have a least 1
# non-default proxy defined. All data in new file is same as the 1 non-default
# proxy except for the proxy id, which must be unqiue
import json, copy
with open('foxyproxy-template.json') as json_file:
data = json.load(json_file)
template = data['proxySettings'][0]['whitePatterns'][0]
for x in range(10000):
new_pattern = copy.deepcopy(template)
data['proxySettings'][0]['whitePatterns'].append(new_pattern)
with open("foxyproxy-10000-patterns-test-settings.json", "w") as write_file:
json.dump(data, write_file)

View file

@ -0,0 +1,17 @@
# Use foxyproxy-template.json to ouptut foxyproxy-5000-proxies-test-settings.json
# which has 5000 proxies defined. foxyproxy-template.json should have a least 1
# non-default proxy defined. All data in new file is same as the 1 non-default
# proxy except for the proxy id, which must be unqiue
import json, copy
with open('foxyproxy-template.json') as json_file:
data = json.load(json_file)
template = data['proxySettings'][0]
for x in range(5000):
new_settings = copy.deepcopy(template)
# Must have unique id
new_settings['id'] = template['id'] + str(x)
data['proxySettings'].append(new_settings)
with open("foxyproxy-5000-proxies-test-settings.json", "w") as write_file:
json.dump(data, write_file)

8
notes-to-reviewers.txt Normal file
View file

@ -0,0 +1,8 @@
# 3rd-Party Libraries
## jscolor Color Picker
A very nice color picker, much better than HTML's native input type="color". No jQuery dependency.
Source: http://jscolor.com/release/latest.zip (Unfortunately, there is no specific URL for 2.0.5, the version I am using)
Docs: http://jscolor.com/
Renamed to jscolor-2.0.5.js

8036
package-lock.json generated Normal file

File diff suppressed because it is too large Load diff

21
package.json Normal file
View file

@ -0,0 +1,21 @@
{
"name": "foxyproxy",
"description": "FoxyProxy Standard and Basic for Firefox 57+",
"author": "Eric H. Jung",
"version": "0.1.0",
"private": true,
"repository": {
"type": "git",
"url": "https://github.com/foxyproxy/firefox-extension"
},
"devDependencies": {
"grunt": "^1.0.4",
"grunt-contrib-compress": "^1.5.0"
},
"dependencies": {
"grunt-cli": "^1.3.2"
},
"scripts": {
"test": "jest"
}
}

84
pattern-specifications.md Normal file
View file

@ -0,0 +1,84 @@
# pseudo-code for proxy selection
## Suppose we have 6 proxy definitions + Default:
### Proxy foo1
a. http proxy on 123.123.123.123:8080
b. username/password auth
b. whitelist pattern "*.google.com"
c. blacklist pattern "foo.google.com"
### Proxy foo2
a. socks proxy on 999.999.99.999:1080
b. username/password auth
c. whitelist pattern "*.facebook.com"
### Proxy foo3
a. PAC at https://192.168.1.1/proxy.pac
b. no username/password auth
c. whitelist pattern "*.internalstuffs.zzz" (intranet address)
### Proxy foo4
a. PAC at https://192.168.1.2/proxy.pac
b no username/password auth
c. whitelist pattern "*.internalstuffs.yyy" (intranet address)
### Proxy foo5
a. System settings
b. no username/password auth (no applicable for system settings anyway)
c. whitelist pattern "*.bar.com"
### Proxy foo6
a. WPAD (auto-detect, not supported by Firefox proxyAPI right now)
b. no username/password auth (no applicable for system settings anyway)
c. whitelist pattern "*.bar.com"
### Default
a. Set to DIRECT (no proxy)
b. no username/password auth
c. no patterns -- not supported by FoxyProxy
## User sets mode to "patterns"
### Suppose URL about to be loaded by browser is https://www.google.com/
http proxy on 123.123.123.123:8080 is used to load the URL
```const proxySettings = {
proxyType: "manual",
http: "http://123.123.123.123:8080",
httpProxyAll: true,
autoLogin: true
};
proxy.settings.set(proxySettings)```
### Suppose URL about to be loaded by browser is https://foo.google.com/
This matches the blacklist pattern in proxy `foo1`. Blacklist patterns take precedence
over whitelist patterns. So `foo1` is not used to load this URL. The other proxy patterns
are checked. None match, so `Default` is used.
```const proxySettings = {
proxyType: "none",
autoLogin: true,
httpProxyAll: true // I don't know if this is necessary but cannot hurt
};
proxy.settings.set(proxySettings)```
### Suppose URL about to be loaded by browser is https://www.facebook.com/index.html
socks proxy on 999.999.99.999:1080 is used to load the URL
### Suppose URL about to be loaded by browser is https://internalstuffs.zzz/payroll/my-paycheck.pdf
https://192.168.1.1/proxy.pac is used to load the URL. FoxyProxy doesn't know what this PAC
is doing. Maybe it has its own URL pattern matching, maybe not. Does not matter.
```const proxySettings = {
autoConfigUrl: pacUrl that user specified
autoLogin: true,
httpProxyAll: true // I don't know if this is necessary but cannot hurt
};
proxy.settings.set(proxySettings)```

View file

@ -0,0 +1,180 @@
{
"extensionName": { "message": "FoxyProxy Standard" },
"extensionDescription": { "message": "Easy to use advanced Proxy Management tool for everyone" },
"extensionNameBasic": { "message": "FoxyProxy Basic" },
"error": { "message": "Error" },
"erroNoSettings": { "message": "No settings could be found. Please re-install FoxyProxy." },
"deleteAll": { "message": "Delete All" },
"export": { "message": "Export Settings" },
"import": { "message": "Import Settings" },
"importProxyList": { "message": "Import Proxy List" },
"log": { "message": "Log" },
"myIP": { "message": "What's My IP?" },
"deleteAllmessage": { "message": "All data deleted" },
"authError": { "message": "$1 is refusing connections\nCheck proxy username/password" },
"delete": { "message": "Delete" },
"deleteNot": { "message": "Do Not Delete" },
"deleteBrowserData": { "message": "Delete Browser Data" },
"deleteBrowserDataDescription": { "message": "Cache, cookies, indexedDB storage, DOM local storage, plugin data, service worker data." },
"deleteBrowserDataNotDescription": { "message": "Stored passwords, browsing and form history, download history, webSQL, and server-bound certificates." },
"done": { "message": "Done!" },
"about": { "message": "About" },
"syncSettings": { "message": "Synchronize Settings" },
"syncSettingsHelp": { "message": "Turn on to use Firefox Sync (settings are synchronized across all your Firefox browsers). Turn off to store settings locally. Notice you can have two different instances of settings, one sync and one local." },
// "onOff": { "message": "On/Off" },
"on": { "message": "On" },
"off": { "message": "Off" },
"confirmTransferToLocal": { "message": "Would you like to transfer the synced settings to your local profile?\nExisting Data will be merged." },
"confirmTransferToSync": { "message": "Would you like to transfer the local settings to your synced profile?\nExisting Data will be merged." },
"modePatterns": { "message": "Use Enabled Proxies By Patterns and Order" },
"modeDisabled": { "message": "Turn Off (Use Firefox Settings)" },
"forAll": { "message": "for all URLs" },
"noProxies": { "message": "You do not have any proxy settings."},
"edit": { "message": "Edit" },
"patterns": { "message": "Patterns" },
"confirmDelete": { "message": "Are you sure you want to delete?" },
"addProxy": { "message": "Add Proxy" },
"editProxy": { "message": "Edit Proxy $1" },
"editPatterns": { "message": "Edit Patterns" },
"editPatternsFor": { "message": "Edit Patterns of $1" },
"errorWas": { "message": "There was an error. Please try again." },
"errorSlash": { "message": "No slash in wildcard patterns. You cannot match URL paths because of Firefox restrictions." },
"errorEmpty": { "message": "Field can not be empty." },
"importEnd": { "message": "Settings were successfully imported" },
"patternsChanged": { "message": "Some patterns were changed because they contained slashes. Slashes in patterns are not supported anymore." },
"importEndSlash": { "message": "Import finished. Slashes in patterns are not supported because of a Firefox bug. Please review your patterns and remove slashes, if any." },
"errorUserPass": { "message": "Please enter both Username & Password." },
"errorFetch": { "message": "There was an error with the operation" },
"errorPattern": { "message": "Please enter a pattern" },
"importBW": { "message": "Imported $1 white and $2 black patterns." },
"up": { "message": "move up" },
"down": { "message": "move down" },
"disabled": { "message": "Disabled" },
"active": { "message": "Enabled" },
"activeNote": { "message": "FoxyProxy ignores everything on this page unless set to" },
"noMatch": { "message": "No Match" },
"none": { "message": "None" },
"name": { "message": "Name" },
"pattern": { "message": "Pattern" },
"type": { "message": "Type" },
"protocol": { "message": "Protocol" },
"whitePatterns": { "message": "White Patterns" },
"blackPatterns": { "message": "Black Patterns" },
"importedPattern": { "message": "This pattern was imported from an older version of FoxyProxy and changed during import. Here is the original, unchanged pattern:" },
"patternMatch": { "message": "Pattern matches URL!" },
"patternNotMatch": { "message": "Pattern does not match URL." },
"errorProtocol": { "message": "Protocol does not match." },
"proxyType": { "message": "Proxy Type" },
"color": { "message": "Color" },
"patternShortcuts": { "message": "Pattern Shortcuts"},
"title": { "message": "Title or Description (optional)" },
"ip": { "message": "Proxy IP address or DNS name" },
"port": { "message": "Port" },
"username": { "message": "Username (optional)" },
"password": { "message": "Password (optional)" },
"togglePW": { "message": "Toggle Password" },
"addWhitelist": { "message": "Add whitelist pattern to match all URLs" },
"noLocal": { "message": "Do not use for localhost and intranet/private IP addresses" },
"patternTester": { "message": "Pattern Tester" },
"patternHelp": { "message": "Pattern Help" },
"welcome": { "message": "Welcome" },
"options": { "message": "Options" },
"optionsPage": { "message": "FoxyProxy Options" },
"enterUrl": { "message": "Enter URL to test" },
"enterUrlNote": { "message": "(paths and query parameters are ignored)" },
"patternDetail": { "message": "Enter pattern details." },
"patternNote": { "message": "(no paths, no query parameters)" },
"clickTest": { "message": "Click 'Test' when ready" },
"ok": { "message": "OK" },
"clear": { "message": "Clear" },
"refresh": { "message": "Refresh" },
"cancel": { "message": "Cancel" },
"back": { "message": "Back" },
"test": { "message": "Test" },
"help": { "message": "Help" },
"importPatterns": { "message": "Import Patterns" },
"exportPatterns": { "message": "Export Patterns" },
"newWhite": { "message": "New White" },
"newBlack": { "message": "New Black" },
"save": { "message": "Save" },
"add": { "message": "Add" },
"saveAdd": { "message": "Save & Add Another" },
"saveEditPattern": { "message": "Save & Edit Patterns" },
"imported": { "message": "Imported" },
"addBlacklistTip": { "message": "Add blacklist patterns for localhost, 127.0.0.1, 192.168.*.*, 172.16.*.*, & 10.*.*.*" },
"addBlacklist": { "message": "Add black patterns to prevent this proxy being used for localhost & intranet/private IP addresses" },
"addWhitelistTip": { "message": "Add whitelist pattern *" },
"patternCheatSheet": { "message": "Pattern Cheat Sheet" },
"logSize": { "message": "Log Size" },
"url": { "message": "URL" },
"proxyTitle": { "message": "Proxy Title" },
"proxyAddress": { "message": "Proxy Address" },
"matchPattern": { "message": "Match Pattern" },
"whiteBlack": { "message": "White/Black" },
"white": { "message": "White" },
"black": { "message": "Black" },
"timestamp": { "message": "Timestamp" },
"notApplicable": {"message": "n/a"},
"matchedURLs": {"message": "URLs That Matched Patterns"},
"unmatchedURLs": {"message": "URLs That Did Not Match Patterns"},
"pasteList": { "message": "Paste a proxy list below."},
"formats": {"message": "Formats"},
"simple": { "message": "simple" },
"complete": { "message": "complete" },
"simpleFormat": { "message": "ip address/server and port are required. username:password are optional."},
"ipPort": {"message": "ip:port"},
"ipPortUsernamePassword": {"message": "ip:port:username:password"},
"examples": {"message": "Examples"},
"completeFormat": { "message": "With this format, you can specify all proxy settings. But only protocol and server are required."},
"overwriteProxies": { "message": "Overwrite existing proxies" },
"overwritProxiesHelp1": { "message": "Check to delete all existing proxies and replace them with proxies from this list." },
"overwritProxiesHelp2": { "message": "Uncheck to append proxies in this list to existing proxies." },
"confirmOverwrite": { "message": "Are you sure you want to overwrite existing proxies?" },
"importsSkipped": { "message": "Skipped $1 lines because they could not be parsed:\n\n$2" },
"importSucceeded": {
"message": "Read and stored $1 proxies."
}
}

View file

@ -0,0 +1,180 @@
{
"extensionName": { "message": "FoxyProxy Standard" },
"extensionDescription": { "message": "Gestionnaire de proxy avancé facile d'utilisation" },
"extensionNameBasic": { "message": "FoxyProxy Basique" },
"error": { "message": "Erreur" },
"erroNoSettings": { "message": "Aucun paramètre n'a été trouvé. Essayez de réinstaller FoxyProxy." },
"deleteAll": { "message": "Tous supprimer" },
"export": { "message": "Exporter les paramètres" },
"import": { "message": "Importer les paramètres" },
"importProxyList": { "message": "Importer la liste des Proxy" },
"log": { "message": "Journal" },
"myIP": { "message": "Quel est mon IP ?" },
"deleteAllmessage": { "message": "Toutes les données ont été supprimées" },
"authError": { "message": "$1 refuse la connection\nVérifiez les identifiants du proxy" },
"delete": { "message": "Supprimer" },
"deleteNot": { "message": "Ne Pas Supprimer" },
"deleteBrowserData": { "message": "Supprimer les données du navigateur" },
"deleteBrowserDataDescription": { "message": "Cache, cookies, base de donnée indexée, cache local du DOM, données du plugin, données du service." },
"deleteBrowserDataNotDescription": { "message": "Mot de passe sauvegardés, historique et formulaire du navigateur, historique de téléchargement, webSQL, et certificats de serveur." },
"done": { "message": "Fait !" },
"about": { "message": "A propos" },
"syncSettings": { "message": "Synchroniser les Paramètres" },
"syncSettingsHelp": { "message": "Activer pour utiliser Firefox Sync (les paramètres sont synchronisés entre tous vos navigateurs Firefox). Desactiver pour sauvegarder les paramètres localement. A noter que deux profils de paramètres peuvent coexister, un synchronisé et un local" },
// "onOff": { "message": "Activer/Desactiver" },
"on": { "message": "Activer" },
"off": { "message": "Desactiver" },
"confirmTransferToLocal": { "message": "Voulez-vous appliquez les paramètres synchronisés au profil local ?\nLes données existantes seront fusionnées." },
"confirmTransferToSync": { "message": "Voulez-vous appliquez les paramètres locaux au profil synchronisé ?\nLes données existantes seront fusionnées." },
"modePatterns": { "message": "Utiliser les proxys activés par modèle et ordre" },
"modeDisabled": { "message": "Désactiver (Utiliser les paramètres de firefox)" },
"forAll": { "message": "pour toutes les URLs" },
"noProxies": { "message": "Vous n'avez aucun paramètres de proxy."},
"edit": { "message": "Modifier" },
"patterns": { "message": "Modèles" },
"confirmDelete": { "message": "Etes-vous sûr de vouloir supprimer ?" },
"addProxy": { "message": "Ajouter un Proxy" },
"editProxy": { "message": "Modifier le Proxy $1" },
"editPatterns": { "message": "Editer les Modèles" },
"editPatternsFor": { "message": "Editer les Modèles de $1" },
"errorWas": { "message": "Une erreur est survenue. Merci de réessayer." },
"errorSlash": { "message": "Pas de barre oblique dans des modèles génériques. Vous ne pouvez pas associer d'URL à cause des restrictions de Firefox." },
"errorEmpty": { "message": "Le champ ne peut pas être vide." },
"importEnd": { "message": "Les paramètres ont été correctement importés" },
"patternsChanged": { "message": "Certains modèles ont été changés car ils contenaient des barres obliques. Elles ne sont plus supportées." },
"importEndSlash": { "message": "Import fini. Les barres obliques ne sont plus supportées dans les modèles à cause d'un bug de Firefox. Merci de revoir votre modèle et de supprimer les éventuelles barres obliques." },
"errorUserPass": { "message": "Merci d'entrer votre nom d'utilisateur et mot de passe." },
"errorFetch": { "message": "Une erreur est survenue durant l'opération" },
"errorPattern": { "message": "Merci d'entrer un modèle" },
"importBW": { "message": "$1 modèle(s) d'inclusions et $2 modèle(s) d'exclusions ont été importés." },
"up": { "message": "remonter" },
"down": { "message": "descendre" },
"disabled": { "message": "Désactiver" },
"active": { "message": "Activer" },
"activeNote": { "message": "FoxyProxy ignore tous sur cette page à moins d'être explicitement configuré pour" },
"noMatch": { "message": "Pas de Correspondance" },
"none": { "message": "Aucun" },
"name": { "message": "Nom" },
"pattern": { "message": "Modèle" },
"type": { "message": "Type" },
"protocol": { "message": "Protocole" },
"whitePatterns": { "message": "Modèle d'inclusion" },
"blackPatterns": { "message": "Modèle d'exclusion" },
"importedPattern": { "message": "Ce modèle a été importé à partir d'une ancienne version de FoxyProxy et a été modifié lors de l'import. Voici le modèle original non modifié:" },
"patternMatch": { "message": "Ce modèle correspond à l'URL!" },
"patternNotMatch": { "message": "Ce modèle ne correspond pas à l'URL." },
"errorProtocol": { "message": "Le protocole ne correspond pas." },
"proxyType": { "message": "Type de Proxy" },
"color": { "message": "Couleur" },
"patternShortcuts": { "message": "Raccourcis de Modèle"},
"title": { "message": "Nom ou Description (optionnel)" },
"ip": { "message": "Adresse IP du Proxy ou nom du DNS" },
"port": { "message": "Port" },
"username": { "message": "Nom d'utilisateur (optionnel)" },
"password": { "message": "Mot de passe (optionnel)" },
"togglePW": { "message": "Afficher/Masquer le mot de passe" },
"addWhitelist": { "message": "Ajouter un modèle d'inclusion qui correspond à toutes les urls" },
"noLocal": { "message": "Ne pas utiliser pour localhost et des adresses IP privées ou d'intranet" },
"patternTester": { "message": "Testeur de Modèles" },
"patternHelp": { "message": "Aide Modèle" },
"welcome": { "message": "Bienvenu" },
"options": { "message": "Options" },
"optionsPage": { "message": "Options FoxyProxy" },
"enterUrl": { "message": "Entrer l'URL à tester" },
"enterUrlNote": { "message": "(les chemins d'URL et les paramètres sont ignorés)" },
"patternDetail": { "message": "Entrer les informations du modèle." },
"patternNote": { "message": "(pas de chemins d'URL, pas de paramètres de requêtes)" },
"clickTest": { "message": "Cliquez sur 'Test' lorsque vous êtes prêt" },
"ok": { "message": "Accepter" },
"clear": { "message": "Effacer" },
"refresh": { "message": "Rafraîchir" },
"cancel": { "message": "Annuler" },
"back": { "message": "Retour" },
"test": { "message": "Tester" },
"help": { "message": "Aide" },
"importPatterns": { "message": "Importer les Modèles" },
"exportPatterns": { "message": "Exporter les Modèles" },
"newWhite": { "message": "Nouveau Modèle d'Inclusion" },
"newBlack": { "message": "Nouveau Modèle d'Exclusion" },
"save": { "message": "Sauvegarder" },
"add": { "message": "Ajouter" },
"saveAdd": { "message": "Sauvegarder et Ajouter un autre" },
"saveEditPattern": { "message": "Sauvegarder et Modifier les Modèles" },
"imported": { "message": "Importé" },
"addBlacklistTip": { "message": "Ajouter des modèles d'exclusions pour localhost, 127.0.0.1, 192.168.*.*, 172.16.*.*, & 10.*.*.*" },
"addBlacklist": { "message": "Ajouter des modèles d'exclusions pour empêcher ce proxy d'être utiliser pour localhost et des adresses IP privées ou d'intranet" },
"addWhitelistTip": { "message": "Ajouter un modèle d'inclusion *" },
"patternCheatSheet": { "message": "Aide-Mémoire pour les Modèles" },
"logSize": { "message": "Taille du Journal" },
"url": { "message": "URL" },
"proxyTitle": { "message": "Nom du Proxy" },
"proxyAddress": { "message": "Adresse du Proxy" },
"matchPattern": { "message": "Modèle de correspondance" },
"whiteBlack": { "message": "Inclusion/Exclusion" },
"white": { "message": "Inclusion" },
"black": { "message": "Exclusion" },
"timestamp": { "message": "Date" },
"notApplicable": {"message": "s/o"},
"matchedURLs": {"message": "URLs qui correspondent aux Modèles"},
"unmatchedURLs": {"message": "URLs qui ne correspondent pas aux Modèles"},
"pasteList": { "message": "Coller une liste de proxy ci-dessous."},
"formats": {"message": "Formats"},
"simple": { "message": "simple" },
"complete": { "message": "complet" },
"simpleFormat": { "message": "l'adresse ip ou nom du serveur et le port sont requis. login:mot de passe sont optionnels."},
"ipPort": {"message": "ip:port"},
"ipPortUsernamePassword": {"message": "ip:port:login:mot de passe"},
"examples": {"message": "Exemples"},
"completeFormat": { "message": "Dans ce format, vous pouvez spécifier tous les paramètres du proxy. Mais seulement le protocole et le nom du serveur sont requis."},
"overwriteProxies": { "message": "Ecraser les proxys existants" },
"overwritProxiesHelp1": { "message": "Cochez pour supprimer tous les proxys existants et les remplacer par ceux de la liste." },
"overwritProxiesHelp2": { "message": "Décocher pour ajouter les proxys de la liste à ceux déjà existant." },
"confirmOverwrite": { "message": "Etes-vous sûr de vouloir ecraser les proxys existants ?" },
"importsSkipped": { "message": "$1 lignes ignorées car elles ne pouvaient pas être interprétées:\n\n$2" },
"importSucceeded": {
"message": "$1 proxys interprétés et stockés."
}
}

View file

@ -0,0 +1,180 @@
{
"extensionName": { "message": "FoxyProxy Standard" },
"extensionDescription": { "message": "Продвинутый, но простой в использовании инструмент для управления прокси для каждого" },
"extensionNameBasic": { "message": "FoxyProxy Basic" },
"error": { "message": "Ошибка" },
"erroNoSettings": { "message": "Настройки не найдены. Пожалуйста, переустановите FoxyProxy." },
"deleteAll": { "message": " Удалить всё" },
"export": { "message": "Экспортировать настройки" },
"import": { "message": "Импортировать настройки" },
"importProxyList": { "message": "Импортировать список прокси" },
"log": { "message": "Лог" },
"myIP": { "message": "Какой у меня IP адрес?" },
"deleteAllmessage": { "message": "Все данные удалены" },
"authError": { "message": "Отказ подключения к $1\nПроверьте имя пользователя и пароль" },
"delete": { "message": "Удалить" },
"deleteNot": { "message": "Не удалять" },
"deleteBrowserData": { "message": "Удалить данные браузера" },
"deleteBrowserDataDescription": { "message": "Кэш, куки, база индексов, хранилище DOM, данные расширения, служебные данные." },
"deleteBrowserDataNotDescription": { "message": "Сохранённые пароли, история браузера и форм, исторя загрузок, webSQL, серверные сертификаты" },
"done": { "message": "Готово!" },
"about": { "message": "О расширении" },
"syncSettings": { "message": "Синхронизировать настройки" },
"syncSettingsHelp": { "message": "Включите, чтобы использовать синхронизацию Firefox (настройки синхронизируются между всеми вашими браузерами Firefox). Отключите, чтобы хранить настройки локально. Обратите внимание, что вы можете иметь два набора настроек — синхронизированный и локальный." },
// "onOff": { "message": "Вкл./Выкл." },
"on": { "message": "Вкл." },
"off": { "message": "Выкл." },
"confirmTransferToLocal": { "message": "Хотите переместить синхронизированные настройки в локальный профиль?\nОни будут объединены с существующими данными." },
"confirmTransferToSync": { "message": "Хотите переместить локальные настройки синхронизированный профиль?\nОни будут объединены с существующими данными." },
"modePatterns": { "message": "Использовать проки по шаблону и порядку" },
"modeDisabled": { "message": "Откоючить (Использовать настройки Firefox)" },
"forAll": { "message": "Для всех URL" },
"noProxies": { "message": "У вас нет каких-либо прокси настроек."},
"edit": { "message": "Редактировать" },
"patterns": { "message": "Шаблоны" },
"confirmDelete": { "message": "Вы уверены, что хотите удалить?" },
"addProxy": { "message": "Добавить прокси" },
"editProxy": { "message": "Редактировать прокси $1" },
"editPatterns": { "message": "Редактировать шаблон" },
"editPatternsFor": { "message": "Редактировать шаблон для $1" },
"errorWas": { "message": "Ошибка. Пожалуйста, попробуйте снова." },
"errorSlash": { "message": "Не разрешено использовать cимвол слэш в шаблонах. Вы не можете сопоставить URL пути вследствие ограничения Firefox." },
"errorEmpty": { "message": "Поле не может быть пустым." },
"importEnd": { "message": "Настройки успешно импортированы." },
"patternsChanged": { "message": "Некоторые шаблоны были изменены из-за того, что они содержали символ слэш. Символы слэш в шаблонах более не поддерживаются." },
"importEndSlash": { "message": "Импорт закончен. Символ слэш не поддерживается из-за проблемы в Firefox. Пожалуйста, проанализируйте ваши шаблоны и удалите символы слэш если вы их используете." },
"errorUserPass": { "message": "Пожалуйста, введите имя пользователя и пароль." },
"errorFetch": { "message": "Проблема с данным действием." },
"errorPattern": { "message": "Пожалуйста, введите шаблон" },
"importBW": { "message": "Импортировано $1 белых и $2 черных шаблонов." },
"up": { "message": "передвинуть выше" },
"down": { "message": "передвинуть ниже" },
"disabled": { "message": "Отключено" },
"active": { "message": "Включено" },
"activeNote": { "message": "FoxyProxy игнорирует все настройки на этой странице если не включено обратное" },
"noMatch": { "message": "Нет совпадения" },
"none": { "message": "Ничего" },
"name": { "message": "Название" },
"pattern": { "message": "Шаблон" },
"type": { "message": "Тип" },
"protocol": { "message": "Протокол" },
"whitePatterns": { "message": "Белые шаблоны" },
"blackPatterns": { "message": "Черные шаблоны" },
"importedPattern": { "message": "Этот шаблон был импортирован из предыдущей версии FoxyProxy и был изменен в процессе импорта. Оригинальный, не измененный шаблон тут:" },
"patternMatch": { "message": "Шаблон сопоставлен URL!" },
"patternNotMatch": { "message": "Шаблон не сопоставлен URL." },
"errorProtocol": { "message": "Протокол не совпадает." },
"proxyType": { "message": "Тип прокси" },
"color": { "message": "Цвет" },
"patternShortcuts": { "message": "Клавиатурная комбинация для шаблона"},
"title": { "message": "Название или описание (опционально)" },
"ip": { "message": " Прокси IP адрес или имя DNS" },
"port": { "message": "Порт" },
"username": { "message": "Имя пользователя (опционально)" },
"password": { "message": "Пароль (опционально)" },
"togglePW": { "message": "Показывать пароль" },
"addWhitelist": { "message": "Добавить whitelist шаблон совпадающий со всеми URL" },
"noLocal": { "message": "Не использовать локальный и внутренний/частный IP адрес" },
"patternTester": { "message": "Тестер шаблонов" },
"patternHelp": { "message": "Помощь с шаблонами" },
"welcome": { "message": "Добро пожаловать" },
"options": { "message": "Настройки" },
"optionsPage": { "message": "Настройки FoxyProxy" },
"enterUrl": { "message": "Введите URL на тест" },
"enterUrlNote": { "message": "(параметры путей и запросов будут проигнорированы)" },
"patternDetail": { "message": "Введите детали шаблона." },
"patternNote": { "message": "(без путей и параметров запросов)" },
"clickTest": { "message": "Нажмите 'Начать тест' как будете готовы" },
"ok": { "message": "OK" },
"clear": { "message": "Очистить" },
"refresh": { "message": "Обновить" },
"cancel": { "message": "Отменить" },
"back": { "message": "Назад" },
"test": { "message": "Тест" },
"help": { "message": "Помощь" },
"importPatterns": { "message": "Импортировать шаблон" },
"exportPatterns": { "message": "Экспортировать шаблон" },
"newWhite": { "message": "Новый белый" },
"newBlack": { "message": "Новый черный" },
"save": { "message": "Сохранить" },
"add": { "message": "Добавить" },
"saveAdd": { "message": "Сохранить & добавить еще" },
"saveEditPattern": { "message": "Сохранить & и редактировать шаблоны" },
"imported": { "message": "Импортитовано" },
"addBlacklistTip": { "message": "Добавть blacklist шаблоны для локального адреса, 127.0.0.1, 192.168.*.*, 172.16.*.*, & 10.*.*.*" },
"addBlacklist": { "message": "Добавить black шаблоны чтобы предотвратить использование этого прокси для локального адреса и внутренних/частных IP адресов" },
"addWhitelistTip": { "message": "Добавить whitelist шаблон *" },
"patternCheatSheet": { "message": "Шпаргалка по шаблонам" },
"logSize": { "message": "Размер лога" },
"url": { "message": "URL" },
"proxyTitle": { "message": "Название прокси" },
"proxyAddress": { "message": "Адрес прокси" },
"matchPattern": { "message": "Шаблон для совпадения" },
"whiteBlack": { "message": "Белый/Черный" },
"white": { "message": "Белый" },
"black": { "message": "Черный" },
"timestamp": { "message": "Время" },
"notApplicable": {"message": "n/a"},
"matchedURLs": {"message": "URL удовлетворяющие шаблону"},
"unmatchedURLs": {"message": "URLs не удовлетворяющие шаблону"},
"pasteList": { "message": "Вставте список прокси ниже."},
"formats": {"message": "Форматы"},
"simple": { "message": "простой" },
"complete": { "message": "полный" },
"simpleFormat": { "message": "Необходимы ip адрес/сервер и порт. Имя пользователя и пароль — опционально."},
"ipPort": {"message": "ip адрес:порт"},
"ipPortUsernamePassword": {"message": "ip адрес:порт:имя пользователя:пароль"},
"examples": {"message": "Примеры"},
"completeFormat": { "message": "Используя этот формат вы можете указать все прокси настройки, но только протокол и адрес прокси являются необходимыми."},
"overwriteProxies": { "message": "Перезаписать имеющиеся прокси" },
"overwritProxiesHelp1": { "message": "Активируйте чтобы заменить все существующие прокси новыми из этого списка." },
"overwritProxiesHelp2": { "message": "Дезактивируйте чтобы добавить прокси из списка к уже имеющимся." },
"confirmOverwrite": { "message": "Вы уверены, что хотите удалить все ранее добавленные прокси?" },
"importsSkipped": { "message": "Пропущено $1 линий потому что они не смогли быть обработаны:\n\n$2" },
"importSucceeded": {
"message": "Считано и сохранено $1 прокси."
}
}

View file

@ -0,0 +1,160 @@
{
"extensionName": { "message": "FoxyProxy 标准版" },
"extensionDescription": { "message": "易于使用,适用于任何人的高级代理管理工具" },
"extensionNameBasic": { "message": "FoxyProxy 基础版" },
"error": { "message": "错误" },
"erroNoSettings": { "message": "未找到设置。请重新安装 FoxyProxy。" },
"deleteAll": { "message": "全部删除" },
"export": { "message": "导出" },
"import": { "message": "导入" },
"log": { "message": "日志" },
"myIP": { "message": "查询我的 IP" },
"deleteAllmessage": { "message": "已删除所有数据" },
"authError": { "message": "$1 拒绝连接\n请检查代理用户名/密码" },
"delete": { "message": "删除" },
"deleteNot": { "message": "不要删除" },
"deleteBrowserData": { "message": "删除浏览器数据" },
"deleteBrowserDataDescription": { "message": "缓存、cookies、indexedDB 存储、DOM 本地存储、插件数据、service worker 数据。" },
"deleteBrowserDataNotDescription": { "message": "已保存的密码、浏览和表单历史、下载历史、webSQL 和服务器绑定证书。" },
"done": { "message": "完成!" },
"about": { "message": "关于" },
"syncSettings": { "message": "同步设置" },
"syncSettingsHelp": { "message": "开启以使用 Firefox 同步(将在你所有的 Firefox 浏览器间同步设置)。关闭则只在本地保存设置。注意你可以有两套不同的设置,一套同步的和一套本地的。" },
// "onOff": { "message": "开启/关闭" },
"on": { "message": "开启" },
"off": { "message": "关闭" },
"confirmTransferToLocal": { "message": "是否将已同步的设置传输到你的本地配置文件?\n将合并已有的数据。" },
"confirmTransferToSync": { "message": "是否将本地设置传输到你的同步配置文件?\n将合并已有的数据。" },
"modePatterns": { "message": "按模式和顺序使用启用的代理" },
"modeDisabled": { "message": "关闭(使用 Firefox 设置)" },
"forAll": { "message": "对全部 URLs 使用" },
"noProxies": { "message": "你没有设置任何代理。"},
"edit": { "message": "编辑" },
"patterns": { "message": "模式" },
"confirmDelete": { "message": "你确定要删除吗?" },
"addProxy": { "message": "添加代理" },
"editProxy": { "message": "编辑代理 $1" },
"editPatterns": { "message": "编辑模式" },
"editPatternsFor": { "message": "编辑 $1 的模式" },
"errorWas": { "message": "存在错误。请重试。" },
"errorSlash": { "message": "通配符模式不能有斜线 /。因为 Firefox 的限制你无法匹配 URL 路径。" },
"errorEmpty": { "message": "字段不能为空。" },
"importEnd": { "message": "设置已成功导入" },
"patternsChanged": { "message": "有些模式已做更改因为它们包含斜线。不再支持于模式里使用斜线。" },
"importEndSlash": { "message": "导入已完成。由于 Firefox 缺陷,已不再支持于模式里使用斜线。请复查你的模式并移除所有斜线。" },
"errorUserPass": { "message": "请输入用户名和密码。" },
"errorFetch": { "message": "操作出现错误" },
"errorPattern": { "message": "请输入一项模式" },
"importBW": { "message": "已导入 $1 项白名单和 $2 项黑名单模式。" },
"up": { "message": "上移" },
"down": { "message": "下移" },
"disabled": { "message": "已禁用" },
"active": { "message": "已启用" },
"activeNote": { "message": "FoxyProxy 将忽略此页面的所有选项,除非设为" },
"noMatch": { "message": "无匹配" },
"none": { "message": "无" },
"name": { "message": "名称" },
"pattern": { "message": "模式" },
"type": { "message": "类型" },
"protocol": { "message": "协议" },
"whitePatterns": { "message": "白名单模式" },
"blackPatterns": { "message": "黑名单模式" },
"importedPattern": { "message": "此模式来自自旧版本的 FoxyProxy且在导入过程中更改。下面为未更改的原模式" },
"patternMatch": { "message": "模式与 URL 匹配!" },
"patternNotMatch": { "message": "模式与 URL 不匹配。" },
"errorProtocol": { "message": "协议不匹配。" },
"proxyType": { "message": "代理类型" },
"color": { "message": "颜色" },
"patternShortcuts": { "message": "模式快捷选项"},
"title": { "message": "标题或描述(可选)" },
"ip": { "message": "代理 IP 地址或 DNS 名称" },
"port": { "message": "端口" },
"username": { "message": "用户名(可选)" },
"password": { "message": "密码(可选)" },
"togglePW": { "message": "显示密码" },
"addWhitelist": { "message": "添加匹配全部 URLs 的白名单模式" },
"noLocal": { "message": "不用于本地主机和内部网/私密 IP 地址" },
"patternTester": { "message": "模式测试器" },
"patternHelp": { "message": "模式帮助" },
"welcome": { "message": "欢迎" },
"options": { "message": "选项" },
"optionsPage": { "message": "FoxyProxy 选项" },
"enterUrl": { "message": "输入要测试的 URL" },
"enterUrlNote": { "message": "(已忽略路径和查询参数)" },
"patternDetail": { "message": "输入模式详细信息。" },
"patternNote": { "message": "(无路径,无查询参数)" },
"clickTest": { "message": "准备好后点击“测试”" },
"ok": { "message": "确定" },
"clear": { "message": "清除" },
"refresh": { "message": "刷新" },
"cancel": { "message": "取消" },
"back": { "message": "返回" },
"test": { "message": "测试" },
"help": { "message": "帮助" },
"importPatterns": { "message": "导入模式" },
"exportPatterns": { "message": "导出模式" },
"newWhite": { "message": "新增白名单" },
"newBlack": { "message": "新增黑名单" },
"save": { "message": "保存" },
"add": { "message": "添加" },
"saveAdd": { "message": "保存并添加另一个" },
"saveEditPattern": { "message": "保存并编辑模式" },
"imported": { "message": "已导入" },
"addBlacklistTip": { "message": "把本地主机、127.0.0.1、192.168.*.*、172.16.*.* 和 10.*.*.* 添加到黑名单模式" },
"addBlacklist": { "message": "添加黑名单模式可以防止代理用在本地主机和内部网/私密 IP 地址上" },
"addWhitelistTip": { "message": "添加白名单模式 *" },
"patternCheatSheet": { "message": "模式速查表" },
"logSize": { "message": "日志大小" },
"url": { "message": "URL" },
"proxyTitle": { "message": "代理标题" },
"proxyAddress": { "message": "代理地址" },
"matchPattern": { "message": "匹配模式" },
"whiteBlack": { "message": "白/黑名单" },
"white": { "message": "白名单" },
"black": { "message": "黑名单" },
"timestamp": { "message": "时间戳" },
"notApplicable": {"message": "不适用"},
"matchedURLs": {"message": "与模式匹配的 URLs"},
"unmatchedURLs": {"message": "与模式不匹配的 URLs"}
}

View file

@ -0,0 +1,180 @@
{
"extensionName": { "message": "FoxyProxy Standard" },
"extensionDescription": { "message": "任誰都能快速上手的進階代理伺服器管理工具" },
"extensionNameBasic": { "message": "FoxyProxy Basic" },
"error": { "message": "錯誤" },
"erroNoSettings": { "message": "找不到設定檔。 請重新安裝 FoxyProxy。" },
"deleteAll": { "message": "移除全部" },
"export": { "message": "匯出設定" },
"import": { "message": "匯入設定" },
"importProxyList": { "message": "匯入代理伺服器清單" },
"log": { "message": "日誌" },
"myIP": { "message": "我的 IP 為何?" },
"deleteAllmessage": { "message": "已將所有資料移除" },
"authError": { "message": "$1 拒絕連線\n請檢查代理伺服器的使用者帳號與密碼是否正確" },
"delete": { "message": "移除" },
"deleteNot": { "message": "不要移除" },
"deleteBrowserData": { "message": "移除瀏覽器資料" },
"deleteBrowserDataDescription": { "message": "快取、Cookies、indexedDB 儲存空間, DOM 本機儲存空間, 擴充套件資料、Service Worker 資料。" },
"deleteBrowserDataNotDescription": { "message": "以儲存的密碼、瀏覽與表單歷史紀錄、下載紀錄、WebSQL 和 Server-Bound 認證。" },
"done": { "message": "完成!" },
"about": { "message": "關於" },
"syncSettings": { "message": "同步設定" },
"syncSettingsHelp": { "message": "啟用此設定將會使用 Firefox Sync (設定將同步至所有的瀏覽器中)。 停用此設定僅將設定儲存於本機中。 小提醒:您可以儲存兩種設定,一種為本機設定,另一種為同步設定。" },
// "onOff": { "message": "On/Off" },
"on": { "message": "啟用" },
"off": { "message": "停用" },
"confirmTransferToLocal": { "message": "是否將您的設定同步至本機設定檔中?\n已經存在的資料將會被合併。" },
"confirmTransferToSync": { "message": "是否將您的本機設定同步至同步設定檔中?\n已經存在的資料將會被合併。" },
"modePatterns": { "message": "以設定的規則與順序套用代理伺服器設定" },
"modeDisabled": { "message": "停用 (使用 Firefox 內建設定)" },
"forAll": { "message": "於所有網址上啟用" },
"noProxies": { "message": "您尚未建立任何代理伺服器設定。"},
"edit": { "message": "編輯" },
"patterns": { "message": "規則" },
"confirmDelete": { "message": "您確定要移除此設定嗎?" },
"addProxy": { "message": "新增代理伺服器" },
"editProxy": { "message": "編輯代理伺服器 - $1" },
"editPatterns": { "message": "編輯規則" },
"editPatternsFor": { "message": "編輯規則 - $1" },
"errorWas": { "message": "發生錯誤。請重試。" },
"errorSlash": { "message": "萬用字元不能包含斜線。 由於 Firefox 的限制,您無法對應到任何的網址或路徑。" },
"errorEmpty": { "message": "該欄位不可留空。" },
"importEnd": { "message": "設定檔匯入成功。" },
"patternsChanged": { "message": "部分規則因含有斜線而被變更。 不支援斜線規則。" },
"importEndSlash": { "message": "匯入完成。 由於 Firefox 的一隻 Bug ,已不支援斜線規則。 請重新檢查您的規則是否仍含有斜線,若有請將之移除。" },
"errorUserPass": { "message": "請輸入使用者名稱和密碼。" },
"errorFetch": { "message": "該操作行為發生錯誤。" },
"errorPattern": { "message": "請輸入規則" },
"importBW": { "message": "已匯入 $1 個白名單與 $2 個黑名單規則。" },
"up": { "message": "上移" },
"down": { "message": "下移" },
"disabled": { "message": "已停用" },
"active": { "message": "已啟用" },
"activeNote": { "message": "FoxyProxy 將會略過此頁面上所有設定,除非設定為" },
"noMatch": { "message": "沒有對應結果" },
"none": { "message": "無" },
"name": { "message": "名稱" },
"pattern": { "message": "規則" },
"type": { "message": "類型" },
"protocol": { "message": "協定" },
"whitePatterns": { "message": "白名單規則" },
"blackPatterns": { "message": "黑名單規則" },
"importedPattern": { "message": "這個規則為舊版匯入的規則,且於匯入期間已被修改。 以下為其原始規則:" },
"patternMatch": { "message": "規則與網址相對應!" },
"patternNotMatch": { "message": "規則與網址無法對應。" },
"errorProtocol": { "message": "協定不對應。" },
"proxyType": { "message": "代理伺服器類型" },
"color": { "message": "顏色" },
"patternShortcuts": { "message": "規則快捷鍵"},
"title": { "message": "標題或描述(選填)" },
"ip": { "message": "代理伺服器 IP 位址或 DNS 域名" },
"port": { "message": "連接埠" },
"username": { "message": "使用者名稱(選填)" },
"password": { "message": "密碼(選填)" },
"togglePW": { "message": "顯示或隱藏密碼" },
"addWhitelist": { "message": "新增白名單規則以對應到所有網址" },
"noLocal": { "message": "請不要使用 localhost 或內部 / 私有 IP 位址" },
"patternTester": { "message": "規則測試器" },
"patternHelp": { "message": "規則說明" },
"welcome": { "message": "歡迎" },
"options": { "message": "選項" },
"optionsPage": { "message": "FoxyProxy 選項" },
"enterUrl": { "message": "請輸入網址以進行測試" },
"enterUrlNote": { "message": "(已略過路徑與查詢字串)" },
"patternDetail": { "message": "輸入規則詳細資料。" },
"patternNote": { "message": "(不包含路徑及查詢字串)" },
"clickTest": { "message": "準備就緒後按下「測試」開始進行測試。" },
"ok": { "message": "確定" },
"clear": { "message": "清除" },
"refresh": { "message": "重新整理" },
"cancel": { "message": "取消" },
"back": { "message": "返回" },
"test": { "message": "測試" },
"help": { "message": "說明" },
"importPatterns": { "message": "匯入規則" },
"exportPatterns": { "message": "匯出規則" },
"newWhite": { "message": "新增白名單" },
"newBlack": { "message": "新增黑名單" },
"save": { "message": "儲存" },
"add": { "message": "新建" },
"saveAdd": { "message": "儲存並新建" },
"saveEditPattern": { "message": "儲存並編輯規則" },
"imported": { "message": "已匯入" },
"addBlacklistTip": { "message": "將 localhost、127.0.0.1、192.168.*.*、172.16.*.* 和 10.*.*.* 新增至黑名單規則中" },
"addBlacklist": { "message": "新增黑名單規則可以防止這個代理伺服器設定被套用於 localhost 或內部 / 私有 IP 位址上。" },
"addWhitelistTip": { "message": "將 * 新增至白名單規則中" },
"patternCheatSheet": { "message": "規則速查表" },
"logSize": { "message": "日誌大小" },
"url": { "message": "網址" },
"proxyTitle": { "message": "代理伺服器標題" },
"proxyAddress": { "message": "代理伺服器位址" },
"matchPattern": { "message": "對應規則" },
"whiteBlack": { "message": "白名單 / 黑名單" },
"white": { "message": "白名單" },
"black": { "message": "黑名單" },
"timestamp": { "message": "時間戳" },
"notApplicable": {"message": "不適用"},
"matchedURLs": {"message": "與規則相對應的網址"},
"unmatchedURLs": {"message": "與規則不對應的網址"},
"pasteList": { "message": "在下方貼上代理伺服器清單。"},
"formats": {"message": "格式"},
"simple": { "message": "簡易版" },
"complete": { "message": "完整版" },
"simpleFormat": { "message": "IP 位址 / 伺服器及連接埠皆為必填。 username:password使用者名稱與密碼為選填。"},
"ipPort": {"message": "ip:port"},
"ipPortUsernamePassword": {"message": "ip:port:username:password"},
"examples": {"message": "範例"},
"completeFormat": { "message": "使用這種格式,您可以指定所有代理伺服器設定。其中僅有協定和伺服器為必填。"},
"overwriteProxies": { "message": "覆蓋已經存在的代理伺服器" },
"overwritProxiesHelp1": { "message": "若勾選此選項,則會將所有已存在的代理伺服器先行移除並取代為此清單上的代理伺服器設定。" },
"overwritProxiesHelp2": { "message": "若不勾選此選項,則會將此清單內的代理伺服器新增至已經存在的代理伺服器清單之後。" },
"confirmOverwrite": { "message": "您確定要覆蓋所有已存在的代理伺服器設定嗎?" },
"importsSkipped": { "message": "因為無法解析,已略過 $1 行:\n\n$2" },
"importSucceeded": {
"message": "讀取並匯入 $1 個代理伺服器設定"
}
}

85
src/about.html Normal file
View file

@ -0,0 +1,85 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title data-i18n="about">FoxyProxy </title>
<link rel="icon" type="image/png" href="/images/icon.svg">
<link rel="stylesheet" href="styles/fontawesome-4.6.3.css">
<link rel="stylesheet" href="styles/app.css">
<style>
h3 { border-bottom: 1px solid #ddd; max-width: 20em; }
h3:not(:first-of-type) { margin-top: 2em; }
h4 { margin-bottom: 0; display: inline-block; }
p, img { margin-left: 1em; }
i.fa {
font-size: 1.3em;
margin-right: 0.4em;
width: 1em;
}
i.fa.fa-lock { color: #080; }
li.sub { margin-left: 2em; list-style-type: circle; }
li.sub + li:not(.sub) { margin-top: 1em; }
</style>
</head>
<body>
<!-- header -->
<div class="prime header" data-i18n="about"></div>
<!-- main -->
<div class="prime">
<!-- welcome on install/update -->
<div class="welcome hide">
<h3>Welcome!</h3>
<p>FoxyProxy has been around for almost 15 years. So if you're upgrading from a legacy version, and your proxy settings are missing, please <a href="/import.html">import</a> them.<br>
<strong>(This message only appears after FoxyProxy has upgraded or is first installed.)</strong></p>
</div>
<h3>Info</h3>
<p><strong>Edition:</strong> <span id="edition"></span><br>
<strong>Version:</strong> <span id="version"></span><br>
<strong>Source Code:</strong> <a target="_blank" href="https://github.com/foxyproxy/firefox-extension">GitHub</a></p>
<h3>Help</h3>
<p>
<a href="https://support.getfoxyproxy.org/" target="_blank"><i class="fa fa-question"></i>Open a Support Ticket </a><i>(no registration required)</i><br>
<a href="mailto:support@getfoxyproxy.org"><i class="fa fa-envelope-o"></i>Email Support</a><br>
<span class="notForBasic"><a href="/pattern-tester.html"><i class="fa fa-flask"></i>Pattern Test</a> &amp; <a href="/pattern-help.html"><i class="fa fa-question-circle"></i>Pattern Help</a> <i>(no internet connection required)</i><br></span>
<a href="https://getfoxyproxy.org/geoip/" target="_blank"><i class="fa fa-globe"></i>What's my IP Address?</a>
</p>
<h3>Support Me</h3>
<p>Please <a href="https://www.paypal.me/ericjung2/5.99" target="_blank">donate</a> or <a href="https://getfoxyproxy.org/order/" target="_blank">buy dedicated VPN/Proxy Servers</a> in over 100 countries (including such remote places like <a href="https://wikipedia.org/wiki/Réunion" target="_blank">Reunion Island</a>).</p>
<p><strong>Thank you for using FoxyProxy!</strong></p>
<img src="/images/ericjung.png" alt=""><br>
<p>&mdash; <a href="mailto:eric.jung@getfoxyproxy.org">Eric H. Jung</a><br>Denver, Colorado, USA</p>
<h3>Release Notes for Recent Releases</h3>
<h4>Version 7.5.1</h4>
<ul>
<li>French translation -- Thanks <a target="_blank" href="https://github.com/samuikaze">samuikaze</a>.</li>
<li>Traditional Chinese translation -- Thanks <a target="_blank" href="https://github.com/Hugo-C">Hugo-C</a>.</li>
<li>Russian translation -- Thanks Vadim.</li>
</ul>
<h4>Version 7.5</h4>
<ul>
<li>Import Proxy Lists! Long requested feature. See <a href="https://github.com/foxyproxy/firefox-extension/wiki/Import-Proxy-List">help</a>.</li>
<li>Simplified Chinese translation -- Thanks <a target="_blank" href="https://github.com/wsxy162">FeralMeow</a>.</li>
<li>Display <strong>Synchronize Settings</strong> for new installations when there are no proxies defined. Reported <a href="https://github.com/foxyproxy/firefox-extension/issues/83">here</a>.</li>
<li>Fixed: <strong>Import Settings</strong> bug especially painful for people using the <a href="https://docs.aws.amazon.com/emr/latest/ManagementGuide/emr-connect-master-node-proxy.html">example at AWS</a>.
Reported <a href="https://github.com/foxyproxy/firefox-extension/issues/76">here</a>. Also fixed bug whereby spinner did not hide after import settings errors.</li>
<li>Minor security improvements -- do not accept embedded HTML/JS in other form fields</li>
<li><strong>Turn Off (Use Firefox Settings)</strong> should be first in list. Reported <a href="https://github.com/foxyproxy/firefox-extension/issues/78">here</a>.</li>
<li>Fixed: Firefox overflow menu displays wrong info for FoxyProxy. Reported <a href="https://github.com/foxyproxy/firefox-extension/issues/84">here</a>.</li>
</ul>
<div style="text-align: right;">
<button type="button" class="button" data-i18n="back">&#x25c1; </button>
</div>
</div>
<script src="scripts/utils.js"></script>
<script src="scripts/about.js"></script>
</body>
</html>

BIN
src/images/ericjung.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 68 KiB

197
src/images/gray.svg Normal file
View file

@ -0,0 +1,197 @@
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
xml:space="preserve"
viewBox="0 0 48 48"
height="48"
width="48"
version="1.1"
id="svg2837"><metadata
id="metadata2843"><rdf:RDF><cc:Work
rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" /><dc:title></dc:title></cc:Work></rdf:RDF></metadata><defs
id="defs2841"><linearGradient
id="linearGradient2861"
spreadMethod="pad"
gradientTransform="matrix(-7.9998322,76.665482,76.665482,7.9998322,231.64795,260.98437)"
gradientUnits="userSpaceOnUse"
y2="0"
x2="1"
y1="0"
x1="0"><stop
id="stop2863"
offset="0"
style="stop-opacity:1;stop-color:#f89734" /><stop
id="stop2865"
offset="1"
style="stop-opacity:1;stop-color:#fbb371" /></linearGradient><radialGradient
id="radialGradient2881"
spreadMethod="pad"
gradientTransform="matrix(50.959351,23.761917,23.092804,-49.525528,208.03369,303.08252)"
gradientUnits="userSpaceOnUse"
r="1"
cy="0"
cx="0"
fy="0"
fx="0"><stop
id="stop2883"
offset="0"
style="stop-opacity:1;stop-color:#e9eaeb" /><stop
id="stop2885"
offset="1"
style="stop-opacity:1;stop-color:#838487" /></radialGradient><clipPath
id="clipPath2893"
clipPathUnits="userSpaceOnUse"><path
id="path2895"
d="M 0,576 576,576 576,0 0,0 0,576 z" /></clipPath><linearGradient
id="linearGradient2953"
spreadMethod="pad"
gradientTransform="matrix(34.282654,-15.727585,-15.727585,-34.282654,213.80908,320.43213)"
gradientUnits="userSpaceOnUse"
y2="0"
x2="1"
y1="0"
x1="0"><stop
id="stop2955"
offset="0"
style="stop-opacity:1;stop-color:#faa858" /><stop
id="stop2957"
offset="1"
style="stop-opacity:1;stop-color:#fbb371" /></linearGradient><clipPath
id="clipPath2965"
clipPathUnits="userSpaceOnUse"><path
id="path2967"
d="M 0,576 576,576 576,0 0,0 0,576 z" /></clipPath><linearGradient
y2="0"
x2="1"
y1="0"
x1="0"
spreadMethod="pad"
gradientTransform="matrix(-7.9998322,76.665482,76.665482,7.9998322,231.64795,260.98437)"
gradientUnits="userSpaceOnUse"
id="linearGradient2917"
xlink:href="#linearGradient2861" /><radialGradient
r="1"
fy="0"
fx="0"
cy="0"
cx="0"
spreadMethod="pad"
gradientTransform="matrix(50.959351,23.761917,23.092804,-49.525528,208.03369,303.08252)"
gradientUnits="userSpaceOnUse"
id="radialGradient2919"
xlink:href="#radialGradient2881" /><linearGradient
y2="0"
x2="1"
y1="0"
x1="0"
spreadMethod="pad"
gradientTransform="matrix(34.282654,-15.727585,-15.727585,-34.282654,213.80908,320.43213)"
gradientUnits="userSpaceOnUse"
id="linearGradient2921"
xlink:href="#linearGradient2953" /><filter
id="filter3790"
style="color-interpolation-filters:sRGB;"><feColorMatrix
id="feColorMatrix3792"
values="0.21 0.72 0.07 0 0 0.21 0.72 0.07 0 0 0.21 0.72 0.07 0 0 0 0 0 1 0 " /></filter></defs><g
transform="matrix(1.25,0,0,-1.25,-224.11415,370.89237)"
id="g2847"><g
style="filter:url(#filter3790)"
transform="matrix(0.42687693,0,0,0.42687693,102.75599,148.99767)"
id="g2870"><g
id="g2849"><g
id="g2851"><g
id="g2857"><g
id="g2859"><path
d="m 185.797,300.527 c 0,-22.396 18.681,-40.552 41.725,-40.552 l 0,0 c 23.044,0 41.725,18.156 41.725,40.552 l 0,0 c 0,22.397 -18.681,40.554 -41.725,40.554 l 0,0 c -23.044,0 -41.725,-18.157 -41.725,-40.554"
style="fill:url(#linearGradient2917);stroke:none"
id="path2867" /></g></g></g></g><g
id="g2869"><g
id="g2871"><g
id="g2877"><g
id="g2879"><path
d="m 211.943,333.94 c -18.988,-8.854 -27.403,-30.99 -18.798,-49.443 l 0,0 c 8.604,-18.453 30.971,-26.234 49.958,-17.381 l 0,0 c 18.986,8.854 27.401,30.99 18.797,49.442 l 0,0 c -6.194,13.284 -19.518,21.037 -33.58,21.037 l 0,0 c -5.473,0 -11.058,-1.175 -16.377,-3.655"
style="fill:url(#radialGradient2919);stroke:none"
id="path2887" /></g></g></g></g><g
id="g2889"><g
id="g2891"
clip-path="url(#clipPath2893)"><g
id="g2897"
transform="translate(261.9004,316.5576)"><path
d="m 0,0 c 8.604,-18.451 0.188,-40.588 -18.798,-49.441 -18.986,-8.854 -41.353,-1.072 -49.958,17.38 -8.605,18.454 -0.189,40.589 18.798,49.443 C -30.972,26.235 -8.605,18.454 0,0 z"
style="fill:none;stroke:#ffffff;stroke-width:1.76999998;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
id="path2899" /></g><g
id="g2901"
transform="translate(253.9063,323.9209)"><path
d="m 0,0 c -0.38,6.903 -1.854,15.334 -6.533,20.806 -3.507,4.103 -8.978,-7.857 -10.103,-9.669 -1.38,-2.221 -2.706,-4.984 -4.8,-6.605 -2.945,-2.281 -6.431,-2.372 -9.833,-3.499 -5.391,-1.789 -10.688,-4.57 -14.938,-8.369 -5.214,-4.66 -10.154,-4.124 -16.67,-3.649 -2.711,0.199 -12.849,2.406 -11.04,-3.348 2.192,-6.973 7.778,-12.852 13.386,-17.248 5.302,-4.158 2.946,-8.926 -2.589,-11.503 5.72,-7.829 17.267,-8.914 26.01,-7.4 4.766,0.826 9.278,1.088 14.039,-0.052 3.533,-0.845 7.752,-4.399 11.49,-2.507 3.506,1.711 3.098,5.748 4.096,8.94 1.409,4.499 4.193,8.567 7.519,11.858 6.812,6.743 14.138,16.589 10.803,26.9 C 5.155,-8.506 -0.189,-7.015 0,0"
style="fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none"
id="path2903" /></g><g
id="g2905"
transform="translate(215.7368,321.6992)"><path
d="m 0,0 c 0,0 11.985,5.765 21.784,5.146 0,0 7.573,-2.107 11.927,-4.1 0,0 6.191,-4.964 7.201,-8.663 0,0 2.938,-8.511 -7.186,-19.298 0,0 -5.095,-6.523 -6.302,-12.757 0,0 -0.092,-4.189 -2.53,-5.651 0,0 -4.019,-1.141 -6.971,0.514 -2.393,0.678 -4.844,1.214 -7.298,1.626 -5.684,0.954 -11.46,0.006 -17.159,1.061 -4.659,0.859 -10.534,2.956 -11.796,8.135 0,0 -2.888,2.565 0.798,13.578 0,0 2.001,12.357 17.532,20.409"
style="fill:#f89734;fill-opacity:1;fill-rule:nonzero;stroke:none"
id="path2907" /></g><g
id="g2909"
transform="translate(196.5059,295.9878)"><path
d="m 0,0 c 2.679,-1.011 4.179,-2.636 10.782,-1.915 3.055,0.334 5.723,3.269 8.877,2.476 8.535,-2.152 22.752,-17.621 22.222,-18.163 -0.955,-0.761 -11.555,14.2 -19.136,10.842 -1.809,-0.8 -4.551,-2.507 -6.534,-2.023 -0.958,0.237 -1.792,0.686 -2.52,1.358 -0.96,0.89 -1.642,2.731 -2.91,3.235 -1.728,0.688 -3.12,0.784 -4.914,1.167 -1.929,0.412 -3.938,1.262 -5.436,2.518"
style="fill:#5c5d5d;fill-opacity:1;fill-rule:nonzero;stroke:none"
id="path2911" /></g><g
id="g2913"
transform="translate(243.0967,279.8789)"><path
d="m 0,0 c 0.714,-1.26 -0.438,-4.142 -0.984,-4.45 -0.544,-0.309 -3.745,0.106 -4.459,1.367 -0.713,1.258 0.327,2.263 1.83,3.114 C -2.109,0.883 -0.713,1.259 0,0"
style="fill:#5c5d5d;fill-opacity:1;fill-rule:nonzero;stroke:none"
id="path2915" /></g><g
id="g2917"
transform="translate(206.8965,302.1777)"><path
d="M 0,0 C -0.872,1.155 2.11,3.59 2.733,3.646 3.357,3.701 6.101,2.003 6.231,0.562 6.361,-0.879 3.944,0.677 2.223,0.523 0.502,0.367 0.369,-0.49 0,0"
style="fill:#5c5d5d;fill-opacity:1;fill-rule:nonzero;stroke:none"
id="path2919" /></g><g
id="g2921"
transform="translate(262.0864,311.4141)"><path
d="m 0,0 c -0.677,-9.71 -5.16,-14.594 -10.862,-21.908 -3.012,-3.861 -5.017,-8.005 -6.067,-12.766 -0.653,-2.955 -2.998,-5.396 -6.187,-5.296 -3.564,0.114 -6.928,2.23 -10.487,2.862 -4.641,0.826 -9.162,0.113 -13.801,-0.206 -4.671,-0.321 -8.985,0.475 -13.127,2.686 -0.069,0.036 -6.823,4.403 -6.476,4.649 4.916,3.463 2.528,8.458 -1.511,11.371 -5.349,3.857 -10.603,10.055 -12.841,16.365 -1.254,3.539 12.776,0.416 14.245,-0.23 4.956,-2.182 2.184,-9.504 1.431,-13.29 1.562,1.982 1.916,4.999 2.747,7.338 1.244,3.501 2.716,7.061 5.389,9.728 3.419,3.415 7.537,5.966 11.82,8.15 5.051,2.578 9.983,4.83 15.651,5.436 4.155,0.441 7.829,-0.055 11.682,-1.675 0.621,-0.264 4.807,-2.148 5.815,-1.898 -3.393,1.208 -10.569,4.446 -9.555,9.164 0.338,1.567 5.62,14.545 7.748,11.455 3.797,-5.514 5.733,-13.408 5.718,-20.002 C -8.68,6.954 -6.037,2.089 -0.348,4.037 -0.384,4.025 0.028,0.412 0,0 m -7.915,12.749 c -0.384,6.973 -1.874,15.488 -6.598,21.016 -3.544,4.145 -9.07,-7.937 -10.206,-9.767 -1.394,-2.243 -2.732,-5.033 -4.849,-6.672 -2.974,-2.305 -6.495,-2.395 -9.931,-3.535 -5.446,-1.808 -10.797,-4.617 -15.089,-8.453 -5.267,-4.707 -10.258,-4.165 -16.839,-3.686 -2.739,0.201 -12.979,2.429 -11.151,-3.382 2.213,-7.042 7.856,-12.98 13.52,-17.421 5.355,-4.199 2.976,-9.016 -2.615,-11.62 5.778,-7.908 17.443,-9.004 26.273,-7.474 4.815,0.834 9.372,1.096 14.18,-0.054 3.57,-0.851 7.831,-4.442 11.607,-2.531 3.541,1.728 3.129,5.806 4.139,9.031 1.422,4.543 4.234,8.652 7.594,11.977 C -1,-13.011 6.4,-3.065 3.032,7.352 -2.708,4.155 -8.107,5.663 -7.915,12.749"
style="fill:#5c5d5d;fill-opacity:1;fill-rule:nonzero;stroke:none"
id="path2923" /></g><g
id="g2925"
transform="translate(240.9268,311.4058)"><path
d="m 0,0 c 0.288,1.418 -3.452,2.332 -4.038,2.113 -0.587,-0.218 -2.331,-2.933 -1.827,-4.29 0.502,-1.358 2.012,1.088 3.634,1.692 C -0.613,0.115 -0.123,-0.601 0,0"
style="fill:#5c5d5d;fill-opacity:1;fill-rule:nonzero;stroke:none"
id="path2927" /></g><g
id="g2929"
transform="translate(215.5869,289.4712)"><path
d="M 0,0 C 0.181,0.136 0.365,0.415 0.297,0.387 0.506,0.79 0.527,1.284 0.305,1.718 -0.059,2.433 -0.937,2.72 -1.652,2.354 -2.369,1.99 -2.652,1.112 -2.286,0.396 -2.284,0.392 -2.281,0.389 -2.279,0.385 -2.35,0.414 -2.423,0.425 -2.492,0.459 -3.995,1.189 -4.734,2.865 -4.337,4.425 -4.47,4.253 -4.588,4.066 -4.688,3.865 -5.445,2.307 -4.793,0.431 -3.236,-0.324 c 0.9,-0.439 1.9,-0.392 2.733,0.017 0.058,0.021 0.117,0.039 0.174,0.068 C -0.204,-0.175 -0.098,-0.091 0,0"
style="fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none"
id="path2931" /></g><g
id="g2933"
transform="translate(201.3467,286.79)"><path
d="m 0,0 c 0,0 4.649,-8.012 17.098,-5.728 0,0 8.646,2.306 13.661,-2.572 -1.023,0.995 -1.912,2.037 -3.159,2.8 -3.88,2.374 -8.425,1.586 -12.74,2.007 C 11.729,-3.186 8.814,-2.129 6.012,-0.74 4.997,-0.237 -0.543,3.323 0,0"
style="fill:#f6ad44;fill-opacity:1;fill-rule:nonzero;stroke:none"
id="path2935" /></g><g
id="g2937"
transform="translate(254.4907,311.8257)"><path
d="m 0,0 c 0,0 2.953,-8.739 -7.189,-15.087 0,0 -5.659,-4.735 -5.408,-11.635 -0.051,1.406 -0.211,2.757 0.021,4.15 0.385,2.318 0.466,4.79 1.388,6.944 0.89,2.08 2.775,3.179 4.241,4.747 1.653,1.768 2.733,4.008 3.344,6.417 C -3.336,-3.416 -1.854,2.765 0,0"
style="fill:#f6ad44;fill-opacity:1;fill-rule:nonzero;stroke:none"
id="path2939" /></g></g></g><g
id="g2941"><g
id="g2943"><g
id="g2949"><g
id="g2951"><path
d="m 219.217,320.557 c -8.361,-3.819 -11.245,-7.843 -10.12,-9.455 l 0,0 c 1.232,-1.763 6.564,-3.975 10.462,-4.716 l 0,0 c 0.437,-0.084 0.615,0.54 0.788,1.164 l 0,0 c 0.175,0.625 0.345,1.251 0.769,1.164 l 0,0 c 2.49,-0.513 5.947,-3.826 7.154,-4.78 l 0,0 c 0.615,-0.486 1.778,-1.525 2.335,-1.306 l 0,0 c 0.448,0.18 -0.171,1.544 -0.27,2.567 l 0,0 c -0.129,1.34 -1.24,6.507 -0.799,8.453 l 0,0 c 0.16,0.711 0.67,0.604 1.192,0.498 l 0,0 c 0.53,-0.109 1.071,-0.219 1.268,0.538 l 0,0 c 1.018,3.921 1.895,7.666 0.749,9.206 l 0,0 c -0.292,0.393 -0.865,0.571 -1.664,0.571 l 0,0 c -2.414,0 -6.885,-1.63 -11.864,-3.904"
style="fill:url(#linearGradient2921);stroke:none"
id="path2959" /></g></g></g></g><g
id="g2961"><g
id="g2963"
clip-path="url(#clipPath2965)"><g
id="g3025"
transform="translate(250.4868,321.0234)"><path
d="m 0,0 c -1.953,-3.398 -2.12,-7.398 -9.162,-12.051 -1.332,-0.88 -2.181,-1.787 -2.848,-3.422 -3.239,-7.934 2.034,-25.066 2.768,-24.956 1.152,0.325 -5.615,14.689 -1.916,21.923 0.592,1.157 1.516,2.073 2.438,2.968 0.984,0.957 1.551,1.517 2.647,2.326 1.162,0.856 2.677,2.038 4.037,1.981 -0.91,0.038 -2.517,0.43 -3.432,0.469 0.717,1.218 2.645,3.181 3.182,4.031 1.328,2.1 1.92,4.192 2.286,6.731"
style="fill:#5c5d5d;fill-opacity:1;fill-rule:nonzero;stroke:none"
id="path3027" /></g><g
id="g3029"
transform="translate(245.6221,311.167)"><path
d="M 0,0 C 0.858,0.275 1.874,0.881 2.632,1.389 3.313,1.846 4.006,2.344 4.25,3.106 3.887,1.972 2.931,0.588 1.994,-0.055 1.517,-0.382 1.029,-0.701 0.617,-1.111 0.216,-1.509 -0.117,-1.482 -0.718,-1.59 -0.766,-1.337 -0.75,-1.075 -0.75,-0.813"
style="fill:#5c5d5d;fill-opacity:1;fill-rule:nonzero;stroke:none"
id="path3031" /></g></g></g></g></g></svg>

After

Width:  |  Height:  |  Size: 14 KiB

23
src/images/icon-off.svg Normal file
View file

@ -0,0 +1,23 @@
<svg xmlns="http://www.w3.org/2000/svg" width="48" height="48" viewBox="0 0 16 16" version="1.0">
<defs />
<g id="fp-toolbar-icon-wrapper">
<path
d="M 6.9528311,5.5392061 C 6.078693,5.9865447 5.1558911,7.1951946 4.1564529,7.411725 C 2.93869,7.6755556 0.32687179,6.9664456 0.15430293,7.5951656 C -0.047715679,8.331182 0.76226407,9.1562478 1.2788196,9.8302167 C 1.768913,10.46966 2.8447406,11.065076 3.2336907,11.770624 C 3.3555466,11.991667 3.327603,12.497042 3.2231514,12.726823 C 3.0441481,13.120608 2.4364022,12.999877 2.4186989,13.432075 C 2.3962947,13.979032 3.5542026,14.104873 3.9994847,14.423288 C 4.9507718,15.103545 7.7144436,14.39272 9.4389993,14.61604 C 10.221736,14.717399 11.148814,15.322006 11.847091,14.954095 C 12.396545,14.664595 12.407857,13.76107 12.638755,13.18453 C 13.274855,11.596224 15.339377,10.113117 15.809787,8.3770041 C 15.951135,7.8553401 16.051011,7.6443863 16.003543,6.5677102 C 15.985486,6.1627501 14.313661,6.6791933 14.181997,6.250809 C 13.877926,5.2614784 13.49069,1.5693024 12.492336,1.2418717 C 11.888559,1.0438517 10.685347,3.7418119 10.405836,4.0233778 C 9.5690224,4.8663364 8.0102037,4.9980972 6.9528311,5.5392061 z"
child="1" style="fill:#404141;fill-opacity:1;fill-rule:evenodd;"/>
<path
d="M 0.20568678,7.6645691 C 0.34341861,7.1394626 1.600145,7.6615473 2.1392725,7.8053546 C 2.6380008,7.938386 3.5316438,8.0278899 3.5818747,8.6214607 C 3.6321051,9.2150325 3.2384352,11.591761 3.2064979,11.559464 C 2.8655525,11.144845 2.7334657,11.050912 2.6112386,10.932857 C 2.3686973,10.726265 1.6615351,10.160608 1.428759,9.8838909 C 1.3015746,9.6805773 0.020150234,8.3719324 0.20568678,7.6645691 z M 12.549184,1.3457735 C 12.08794,1.0786303 11.823308,2.1859312 11.573845,2.6850383 C 11.343077,3.1467446 10.810782,3.9512951 11.303578,4.4207004 C 11.793649,4.8875075 13.965942,6.2236498 14.056531,6.1200186 C 13.950492,5.5038385 13.918276,5.4561008 13.887697,5.291173 C 13.836482,5.0149429 13.710036,4.3213368 13.585833,3.7901471 C 13.540272,3.5952949 13.181999,1.7122868 12.549184,1.3457735 z M 3.386261,12.385661 C 3.3570684,12.689383 3.2883504,12.877502 3.0628724,13.016513 C 2.7029847,13.2153 3.9697067,13.988726 4.538983,14.358195 C 5.205776,14.790955 7.8050167,14.411446 9.3377054,14.518677 C 9.8933234,14.536208 10.797184,15.013062 11.36776,14.979834 C 11.544589,14.969537 11.862801,14.88525 11.982838,14.754996 C 12.370109,14.334753 12.387909,13.452175 12.641905,12.940248 C 13.281597,11.650953 15.119024,10.063421 15.604578,8.7085325 C 15.68297,7.8356261 15.781428,6.5126663 15.520318,6.4870409 C 15.214754,6.4917744 14.561412,6.5346772 14.350326,6.479347 C 14.462374,6.9675086 14.625496,7.7809115 14.38129,8.4287458 C 14.285095,8.858654 13.966789,9.3695968 13.738912,9.7466211 C 13.372822,10.352321 12.684383,11.009494 12.364183,11.640657 C 12.224139,11.91671 12.208036,12.037577 12.087635,12.322745 C 12.06251,12.382254 11.982325,12.663208 11.945511,12.825914 C 11.90851,12.989448 11.906502,13.229117 11.9294,13.390753 C 11.944152,13.494889 11.975549,13.578024 11.973719,13.683186 C 11.970576,13.863807 11.914997,13.936036 11.788877,14.08214 C 11.682284,14.205627 11.555137,14.224132 11.39542,14.234519 C 11.300053,14.240721 11.130483,14.190616 11.036709,14.172199 C 10.876636,14.140759 10.662733,14.081069 10.502349,14.051254 C 10.22285,13.999299 9.9071515,13.847946 9.6320408,13.776307 C 9.3744382,13.709228 9.215233,13.569314 8.7517211,13.553732 C 8.3073216,13.538795 7.6077138,13.570923 5.3178657,13.413012 C 4.745423,13.21185 4.5368845,13.069772 4.2731323,12.917328 C 4.0311097,12.777446 3.4512118,12.2911 3.386261,12.385661 z M 5.9557144,10.876883 C 5.8265042,10.834827 5.8027499,10.862428 5.7567876,10.920405 C 5.6934488,11.033932 5.7252893,11.154962 5.752615,11.35181 C 5.922675,11.596936 6.1095328,11.882976 6.3873679,11.90327 C 6.773174,11.899855 6.9465841,11.754501 7.042559,11.476784 C 7.0639367,11.298034 6.933336,11.079698 6.7666373,11.003316 C 6.3332289,10.89082 6.3246031,11.190952 6.2272415,11.429915 C 5.8487682,11.245117 6.057563,10.972678 5.9557144,10.876883 z"
child="2" style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd;"/>
<path
d="M 3.369765,10.680671 C 3.5727317,10.690432 3.8770401,10.969605 4.1132953,11.031118 C 4.4925298,11.079283 4.8603067,11.022199 5.1959193,11.063738 C 5.5239398,11.119623 5.7350317,11.971153 6.3058989,12.030581 C 6.9914773,12.052432 7.2804998,11.497762 7.6468781,11.523929 C 7.8440671,11.539268 8.1556597,11.449823 8.3579343,11.51788 C 9.2222769,11.865234 10.14038,12.776892 10.906425,13.608604 C 10.960941,13.744537 10.945608,13.977947 10.937125,14.144287 C 10.437546,14.093775 9.6034124,13.761082 9.0892825,13.590076 C 8.1621687,13.499422 6.3869294,13.581782 5.3053032,13.416568 C 4.8841641,13.294572 4.2593683,12.934856 3.9216324,12.67248 C 3.5606357,12.441678 3.410735,12.347246 3.3913281,12.366665 C 3.4268388,12.053346 3.3589432,11.771177 3.2107471,11.576049 C 3.2655485,11.298117 3.3390792,10.896635 3.369765,10.680671 z M 13.412942,5.8487646 C 13.5582,5.8853679 13.838101,6.1039924 14.06634,6.1334002 C 14.108924,6.3685674 14.169958,6.4159442 14.352896,6.4740975 C 14.437858,6.844685 14.527194,7.2873813 14.517468,7.6877218 C 14.498132,8.5231032 14.106452,9.1193122 13.782707,9.6704315 C 13.48933,10.218339 12.915157,10.777331 12.585977,11.283218 C 12.320513,11.666175 12.082532,12.245602 11.976013,12.723691 C 11.939245,12.8923 11.924561,13.171505 11.923572,13.320214 C 11.791451,13.255802 11.786234,13.235417 11.673201,13.084437 C 11.37019,12.442011 11.140744,11.386563 11.098681,11.008291 C 11.094289,10.494878 11.015465,9.6640618 11.087424,9.2377371 C 11.571074,8.5220689 11.897515,8.3404393 12.615171,7.6136001 C 12.696253,7.5130635 12.875624,7.4851031 12.998103,7.4448331 C 12.881467,7.3852593 12.819701,7.388757 12.694765,7.3895745 C 12.741964,7.2853626 13.220837,6.9620062 13.180894,6.9105011 C 13.138931,6.8563922 12.781818,7.1186342 12.547034,7.3201739 C 12.715029,7.0815709 13.00214,6.7836699 13.146761,6.5203061 C 13.281717,6.2073113 13.343088,6.0209861 13.412942,5.8487646 z M 10.644357,4.5191651 C 10.318327,4.5218002 10.202455,4.5312156 9.7247459,4.5949623 C 8.8728289,5.0115836 7.6898876,5.2104852 6.8841482,5.6596449 C 6.1840911,6.10177 5.477202,6.852413 4.6863901,7.3044758 C 4.2872429,7.6149107 3.717839,8.3309511 3.5860504,8.8772274 C 3.5637732,9.3694763 3.452209,10.02604 3.4059454,10.447378 C 3.6032888,10.662574 3.8623409,10.769955 4.1569797,10.838372 C 4.5569612,10.913486 5.3467496,10.874895 5.5682779,10.784535 C 5.9804438,10.562302 6.1134111,10.424144 6.4011658,10.348694 C 6.6867327,10.340809 6.8697623,10.377065 7.097337,10.436888 C 7.4531131,10.601524 7.7818208,10.743226 8.1999155,10.971296 C 8.9191953,11.45319 10.132824,12.561882 10.981433,13.410362 C 11.230277,13.38687 11.412467,13.293967 11.502534,13.202009 C 11.27667,12.553901 11.185208,12.270242 11.007959,11.611453 C 10.926818,11.342381 10.822322,11.038836 10.83247,10.650862 C 10.836338,10.015912 10.794339,9.8058101 10.819836,9.1660101 C 10.974159,8.7381282 10.980631,8.639325 11.189429,8.3576426 C 11.939782,7.6883549 12.136335,7.4770773 12.578704,6.9445246 C 12.832039,6.6012321 13.45392,5.7981166 13.221929,5.7259871 C 12.46368,5.2805256 11.755423,4.7883885 11.544567,4.62131 C 11.28974,4.5420101 10.970386,4.5165307 10.644357,4.5191651 z M 10.870413,7.1211481 C 10.994166,7.0975313 11.113385,7.1507515 11.237243,7.2173728 C 11.320969,7.2652226 11.412631,7.3647636 11.396272,7.4722275 C 11.365214,7.517055 11.032028,7.4535045 10.868432,7.5028614 C 10.744846,7.5401476 10.746225,7.7022038 10.7092,7.8388548 C 10.675269,7.9040084 10.542151,7.9673098 10.453766,7.9299163 C 10.382429,7.8676599 10.470005,7.5833976 10.512504,7.4588313 C 10.575693,7.3246788 10.683931,7.1721997 10.870413,7.1211481 z M 5.4984246,8.7197829 C 5.6289133,8.6821513 5.8154856,8.7204717 5.9696433,8.7942046 C 6.0841061,8.8613794 6.3509112,9.1640647 6.3294408,9.2931018 C 6.2648944,9.3540877 6.164821,9.3259996 6.0521167,9.2693162 C 5.8813095,9.1427944 5.8379278,9.0525661 5.6524934,9.0060516 C 5.5015084,9.0316759 5.464792,9.1630934 5.3725201,9.2855559 C 5.2946105,9.2872545 5.2469955,9.2769124 5.1731311,9.2035927 C 5.1388143,9.0319441 5.3582827,8.7843901 5.4984246,8.7197829 z"
id="fp-toolbar-icon-3"
child="3" style="fill:#e78500;fill-opacity:1;fill-rule:evenodd;"/>
<path
d="M 7.7752361,8.0713883 C 8.2357511,8.1047023 9.0181331,9.1274945 9.593674,9.1644079 C 9.7939088,8.7551967 9.1818749,7.5334182 9.4605917,7.0426773 C 9.587645,6.9199001 9.7368859,7.1054057 9.8679577,6.9869243 C 10.045674,6.5266328 10.102021,5.7007475 10.030153,5.155492 C 8.773076,4.9278955 5.9665723,6.2696832 5.4895382,7.3692693 C 5.6671886,8.2743091 6.9507561,8.3704147 7.6433022,8.5430959 C 7.7899242,8.4001393 7.6360949,8.1250716 7.7752361,8.0713883 z M 4.056517,11.806542 C 4.7190124,11.855627 5.326614,12.352907 6.1331704,12.520895 C 6.5947575,12.727856 7.510389,12.356139 8.5293994,12.693972 C 8.9015172,12.793461 9.4077764,12.943647 9.5694597,13.255056 C 9.5734496,13.322804 9.4814885,13.406637 9.4139446,13.41324 C 9.0316557,13.322426 8.8843475,13.142724 8.689763,13.105677 C 7.6159931,12.907688 6.3497738,13.228414 5.3747241,13.102508 C 4.7221956,12.884416 4.3320393,12.661591 4.0172704,12.110141 C 3.9810438,12.02575 3.9784869,11.85497 4.056517,11.806542 z M 13.631863,7.1964869 C 13.40808,7.5562295 13.377639,7.5804303 13.242968,8.3535247 C 13.007705,9.0153875 12.561448,9.2550924 11.885833,10.249827 C 11.74228,10.607264 11.621856,11.133286 11.706563,11.502287 C 11.758383,11.546109 11.88062,11.522795 11.92641,11.472704 C 12.054549,10.840679 12.358602,10.465567 12.477289,10.318745 C 13.367218,9.5516987 14.073007,9.1412775 14.100137,8.0541158 C 14.118124,7.6930443 14.119515,7.6267509 14.097288,7.3768352 C 13.982226,7.1461924 13.819367,7.1622228 13.631863,7.1964869 z"
child="4" style="fill:#ffffff;fill-opacity:0.20392157;fill-rule:evenodd;"/>
</g>
<g id="fp-toolbar-disabled-wrapper" wrapper="true">
<path
d="M 8,0 C 3.584,8.8817842e-16 -3.006854e-17,3.584 0,8 C 0,12.416 3.584,16 8,16 C 12.416,16 16,12.416 16,8 C 16,3.584 12.416,-1.8665625e-15 8,0 z M 7.8125,1 C 9.8281648,0.94927401 11.856778,1.7662746 13.28125,3.40625 C 15.588012,6.0619933 15.589233,9.9390689 13.28125,12.59375 L 3.40625,2.71875 C 4.6817864,1.6108274 6.2447607,1.0394535 7.8125,1 z M 2.71875,3.40625 L 12.59375,13.28125 C 9.6776547,15.812973 5.2504728,15.509845 2.71875,12.59375 C 0.41476947,9.9399733 0.41589633,6.0610044 2.71875,3.40625 z"
child="5" style="fill: #c80000;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 10 KiB

231
src/images/icon.svg Normal file
View file

@ -0,0 +1,231 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
id="svg2837"
version="1.1"
inkscape:version="0.47pre4 r22446"
width="48"
height="48"
viewBox="0 0 48 48"
xml:space="preserve"
sodipodi:docname="24x24.svg"><metadata
id="metadata2843"><rdf:RDF><cc:Work
rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" /><dc:title></dc:title></cc:Work></rdf:RDF></metadata><defs
id="defs2841"><inkscape:perspective
sodipodi:type="inkscape:persp3d"
inkscape:vp_x="0 : 0.5 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_z="1 : 0.5 : 1"
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
id="perspective2845" /><linearGradient
x1="0"
y1="0"
x2="1"
y2="0"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(-7.9998322,76.665482,76.665482,7.9998322,231.64795,260.98437)"
spreadMethod="pad"
id="linearGradient2861"><stop
style="stop-opacity:1;stop-color:#f89734"
offset="0"
id="stop2863" /><stop
style="stop-opacity:1;stop-color:#fbb371"
offset="1"
id="stop2865" /></linearGradient><radialGradient
fx="0"
fy="0"
cx="0"
cy="0"
r="1"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(50.959351,23.761917,23.092804,-49.525528,208.03369,303.08252)"
spreadMethod="pad"
id="radialGradient2881"><stop
style="stop-opacity:1;stop-color:#e9eaeb"
offset="0"
id="stop2883" /><stop
style="stop-opacity:1;stop-color:#838487"
offset="1"
id="stop2885" /></radialGradient><clipPath
clipPathUnits="userSpaceOnUse"
id="clipPath2893"><path
d="M 0,576 576,576 576,0 0,0 0,576 z"
id="path2895" /></clipPath><linearGradient
x1="0"
y1="0"
x2="1"
y2="0"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(34.282654,-15.727585,-15.727585,-34.282654,213.80908,320.43213)"
spreadMethod="pad"
id="linearGradient2953"><stop
style="stop-opacity:1;stop-color:#faa858"
offset="0"
id="stop2955" /><stop
style="stop-opacity:1;stop-color:#fbb371"
offset="1"
id="stop2957" /></linearGradient><clipPath
clipPathUnits="userSpaceOnUse"
id="clipPath2965"><path
d="M 0,576 576,576 576,0 0,0 0,576 z"
id="path2967" /></clipPath><linearGradient
inkscape:collect="always"
xlink:href="#linearGradient2861"
id="linearGradient2917"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(-7.9998322,76.665482,76.665482,7.9998322,231.64795,260.98437)"
spreadMethod="pad"
x1="0"
y1="0"
x2="1"
y2="0" /><radialGradient
inkscape:collect="always"
xlink:href="#radialGradient2881"
id="radialGradient2919"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(50.959351,23.761917,23.092804,-49.525528,208.03369,303.08252)"
spreadMethod="pad"
cx="0"
cy="0"
fx="0"
fy="0"
r="1" /><linearGradient
inkscape:collect="always"
xlink:href="#linearGradient2953"
id="linearGradient2921"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(34.282654,-15.727585,-15.727585,-34.282654,213.80908,320.43213)"
spreadMethod="pad"
x1="0"
y1="0"
x2="1"
y2="0" /></defs><sodipodi:namedview
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1"
objecttolerance="10"
gridtolerance="10"
guidetolerance="10"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:window-width="1152"
inkscape:window-height="793"
id="namedview2839"
showgrid="false"
inkscape:zoom="2.6222222"
inkscape:cx="135.88584"
inkscape:cy="27.404163"
inkscape:window-x="0"
inkscape:window-y="25"
inkscape:window-maximized="1"
inkscape:current-layer="g2847"
inkscape:showpageshadow="false"
showborder="false" /><g
id="g2847"
inkscape:groupmode="layer"
inkscape:label="FOXYlogo"
transform="matrix(1.25,0,0,-1.25,-224.11415,370.89237)"><g
id="g2870"
transform="matrix(0.42687693,0,0,0.42687693,102.75599,148.99767)"><g
id="g2849"><g
id="g2851"><g
id="g2857"><g
id="g2859"><path
id="path2867"
style="fill:url(#linearGradient2917);stroke:none"
d="m 185.797,300.527 c 0,-22.396 18.681,-40.552 41.725,-40.552 l 0,0 c 23.044,0 41.725,18.156 41.725,40.552 l 0,0 c 0,22.397 -18.681,40.554 -41.725,40.554 l 0,0 c -23.044,0 -41.725,-18.157 -41.725,-40.554" /></g></g></g></g><g
id="g2869"><g
id="g2871"><g
id="g2877"><g
id="g2879"><path
id="path2887"
style="fill:url(#radialGradient2919);stroke:none"
d="m 211.943,333.94 c -18.988,-8.854 -27.403,-30.99 -18.798,-49.443 l 0,0 c 8.604,-18.453 30.971,-26.234 49.958,-17.381 l 0,0 c 18.986,8.854 27.401,30.99 18.797,49.442 l 0,0 c -6.194,13.284 -19.518,21.037 -33.58,21.037 l 0,0 c -5.473,0 -11.058,-1.175 -16.377,-3.655" /></g></g></g></g><g
id="g2889"><g
clip-path="url(#clipPath2893)"
id="g2891"><g
transform="translate(261.9004,316.5576)"
id="g2897"><path
id="path2899"
style="fill:none;stroke:#ffffff;stroke-width:1.76999998;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
d="m 0,0 c 8.604,-18.451 0.188,-40.588 -18.798,-49.441 -18.986,-8.854 -41.353,-1.072 -49.958,17.38 -8.605,18.454 -0.189,40.589 18.798,49.443 C -30.972,26.235 -8.605,18.454 0,0 z" /></g><g
transform="translate(253.9063,323.9209)"
id="g2901"><path
id="path2903"
style="fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none"
d="m 0,0 c -0.38,6.903 -1.854,15.334 -6.533,20.806 -3.507,4.103 -8.978,-7.857 -10.103,-9.669 -1.38,-2.221 -2.706,-4.984 -4.8,-6.605 -2.945,-2.281 -6.431,-2.372 -9.833,-3.499 -5.391,-1.789 -10.688,-4.57 -14.938,-8.369 -5.214,-4.66 -10.154,-4.124 -16.67,-3.649 -2.711,0.199 -12.849,2.406 -11.04,-3.348 2.192,-6.973 7.778,-12.852 13.386,-17.248 5.302,-4.158 2.946,-8.926 -2.589,-11.503 5.72,-7.829 17.267,-8.914 26.01,-7.4 4.766,0.826 9.278,1.088 14.039,-0.052 3.533,-0.845 7.752,-4.399 11.49,-2.507 3.506,1.711 3.098,5.748 4.096,8.94 1.409,4.499 4.193,8.567 7.519,11.858 6.812,6.743 14.138,16.589 10.803,26.9 C 5.155,-8.506 -0.189,-7.015 0,0" /></g><g
transform="translate(215.7368,321.6992)"
id="g2905"><path
id="path2907"
style="fill:#f89734;fill-opacity:1;fill-rule:nonzero;stroke:none"
d="m 0,0 c 0,0 11.985,5.765 21.784,5.146 0,0 7.573,-2.107 11.927,-4.1 0,0 6.191,-4.964 7.201,-8.663 0,0 2.938,-8.511 -7.186,-19.298 0,0 -5.095,-6.523 -6.302,-12.757 0,0 -0.092,-4.189 -2.53,-5.651 0,0 -4.019,-1.141 -6.971,0.514 -2.393,0.678 -4.844,1.214 -7.298,1.626 -5.684,0.954 -11.46,0.006 -17.159,1.061 -4.659,0.859 -10.534,2.956 -11.796,8.135 0,0 -2.888,2.565 0.798,13.578 0,0 2.001,12.357 17.532,20.409" /></g><g
transform="translate(196.5059,295.9878)"
id="g2909"><path
id="path2911"
style="fill:#5c5d5d;fill-opacity:1;fill-rule:nonzero;stroke:none"
d="m 0,0 c 2.679,-1.011 4.179,-2.636 10.782,-1.915 3.055,0.334 5.723,3.269 8.877,2.476 8.535,-2.152 22.752,-17.621 22.222,-18.163 -0.955,-0.761 -11.555,14.2 -19.136,10.842 -1.809,-0.8 -4.551,-2.507 -6.534,-2.023 -0.958,0.237 -1.792,0.686 -2.52,1.358 -0.96,0.89 -1.642,2.731 -2.91,3.235 -1.728,0.688 -3.12,0.784 -4.914,1.167 -1.929,0.412 -3.938,1.262 -5.436,2.518" /></g><g
transform="translate(243.0967,279.8789)"
id="g2913"><path
id="path2915"
style="fill:#5c5d5d;fill-opacity:1;fill-rule:nonzero;stroke:none"
d="m 0,0 c 0.714,-1.26 -0.438,-4.142 -0.984,-4.45 -0.544,-0.309 -3.745,0.106 -4.459,1.367 -0.713,1.258 0.327,2.263 1.83,3.114 C -2.109,0.883 -0.713,1.259 0,0" /></g><g
transform="translate(206.8965,302.1777)"
id="g2917"><path
id="path2919"
style="fill:#5c5d5d;fill-opacity:1;fill-rule:nonzero;stroke:none"
d="M 0,0 C -0.872,1.155 2.11,3.59 2.733,3.646 3.357,3.701 6.101,2.003 6.231,0.562 6.361,-0.879 3.944,0.677 2.223,0.523 0.502,0.367 0.369,-0.49 0,0" /></g><g
transform="translate(262.0864,311.4141)"
id="g2921"><path
id="path2923"
style="fill:#5c5d5d;fill-opacity:1;fill-rule:nonzero;stroke:none"
d="m 0,0 c -0.677,-9.71 -5.16,-14.594 -10.862,-21.908 -3.012,-3.861 -5.017,-8.005 -6.067,-12.766 -0.653,-2.955 -2.998,-5.396 -6.187,-5.296 -3.564,0.114 -6.928,2.23 -10.487,2.862 -4.641,0.826 -9.162,0.113 -13.801,-0.206 -4.671,-0.321 -8.985,0.475 -13.127,2.686 -0.069,0.036 -6.823,4.403 -6.476,4.649 4.916,3.463 2.528,8.458 -1.511,11.371 -5.349,3.857 -10.603,10.055 -12.841,16.365 -1.254,3.539 12.776,0.416 14.245,-0.23 4.956,-2.182 2.184,-9.504 1.431,-13.29 1.562,1.982 1.916,4.999 2.747,7.338 1.244,3.501 2.716,7.061 5.389,9.728 3.419,3.415 7.537,5.966 11.82,8.15 5.051,2.578 9.983,4.83 15.651,5.436 4.155,0.441 7.829,-0.055 11.682,-1.675 0.621,-0.264 4.807,-2.148 5.815,-1.898 -3.393,1.208 -10.569,4.446 -9.555,9.164 0.338,1.567 5.62,14.545 7.748,11.455 3.797,-5.514 5.733,-13.408 5.718,-20.002 C -8.68,6.954 -6.037,2.089 -0.348,4.037 -0.384,4.025 0.028,0.412 0,0 m -7.915,12.749 c -0.384,6.973 -1.874,15.488 -6.598,21.016 -3.544,4.145 -9.07,-7.937 -10.206,-9.767 -1.394,-2.243 -2.732,-5.033 -4.849,-6.672 -2.974,-2.305 -6.495,-2.395 -9.931,-3.535 -5.446,-1.808 -10.797,-4.617 -15.089,-8.453 -5.267,-4.707 -10.258,-4.165 -16.839,-3.686 -2.739,0.201 -12.979,2.429 -11.151,-3.382 2.213,-7.042 7.856,-12.98 13.52,-17.421 5.355,-4.199 2.976,-9.016 -2.615,-11.62 5.778,-7.908 17.443,-9.004 26.273,-7.474 4.815,0.834 9.372,1.096 14.18,-0.054 3.57,-0.851 7.831,-4.442 11.607,-2.531 3.541,1.728 3.129,5.806 4.139,9.031 1.422,4.543 4.234,8.652 7.594,11.977 C -1,-13.011 6.4,-3.065 3.032,7.352 -2.708,4.155 -8.107,5.663 -7.915,12.749" /></g><g
transform="translate(240.9268,311.4058)"
id="g2925"><path
id="path2927"
style="fill:#5c5d5d;fill-opacity:1;fill-rule:nonzero;stroke:none"
d="m 0,0 c 0.288,1.418 -3.452,2.332 -4.038,2.113 -0.587,-0.218 -2.331,-2.933 -1.827,-4.29 0.502,-1.358 2.012,1.088 3.634,1.692 C -0.613,0.115 -0.123,-0.601 0,0" /></g><g
transform="translate(215.5869,289.4712)"
id="g2929"><path
id="path2931"
style="fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none"
d="M 0,0 C 0.181,0.136 0.365,0.415 0.297,0.387 0.506,0.79 0.527,1.284 0.305,1.718 -0.059,2.433 -0.937,2.72 -1.652,2.354 -2.369,1.99 -2.652,1.112 -2.286,0.396 -2.284,0.392 -2.281,0.389 -2.279,0.385 -2.35,0.414 -2.423,0.425 -2.492,0.459 -3.995,1.189 -4.734,2.865 -4.337,4.425 -4.47,4.253 -4.588,4.066 -4.688,3.865 -5.445,2.307 -4.793,0.431 -3.236,-0.324 c 0.9,-0.439 1.9,-0.392 2.733,0.017 0.058,0.021 0.117,0.039 0.174,0.068 C -0.204,-0.175 -0.098,-0.091 0,0" /></g><g
transform="translate(201.3467,286.79)"
id="g2933"><path
id="path2935"
style="fill:#f6ad44;fill-opacity:1;fill-rule:nonzero;stroke:none"
d="m 0,0 c 0,0 4.649,-8.012 17.098,-5.728 0,0 8.646,2.306 13.661,-2.572 -1.023,0.995 -1.912,2.037 -3.159,2.8 -3.88,2.374 -8.425,1.586 -12.74,2.007 C 11.729,-3.186 8.814,-2.129 6.012,-0.74 4.997,-0.237 -0.543,3.323 0,0" /></g><g
transform="translate(254.4907,311.8257)"
id="g2937"><path
id="path2939"
style="fill:#f6ad44;fill-opacity:1;fill-rule:nonzero;stroke:none"
d="m 0,0 c 0,0 2.953,-8.739 -7.189,-15.087 0,0 -5.659,-4.735 -5.408,-11.635 -0.051,1.406 -0.211,2.757 0.021,4.15 0.385,2.318 0.466,4.79 1.388,6.944 0.89,2.08 2.775,3.179 4.241,4.747 1.653,1.768 2.733,4.008 3.344,6.417 C -3.336,-3.416 -1.854,2.765 0,0" /></g></g></g><g
id="g2941"><g
id="g2943"><g
id="g2949"><g
id="g2951"><path
id="path2959"
style="fill:url(#linearGradient2921);stroke:none"
d="m 219.217,320.557 c -8.361,-3.819 -11.245,-7.843 -10.12,-9.455 l 0,0 c 1.232,-1.763 6.564,-3.975 10.462,-4.716 l 0,0 c 0.437,-0.084 0.615,0.54 0.788,1.164 l 0,0 c 0.175,0.625 0.345,1.251 0.769,1.164 l 0,0 c 2.49,-0.513 5.947,-3.826 7.154,-4.78 l 0,0 c 0.615,-0.486 1.778,-1.525 2.335,-1.306 l 0,0 c 0.448,0.18 -0.171,1.544 -0.27,2.567 l 0,0 c -0.129,1.34 -1.24,6.507 -0.799,8.453 l 0,0 c 0.16,0.711 0.67,0.604 1.192,0.498 l 0,0 c 0.53,-0.109 1.071,-0.219 1.268,0.538 l 0,0 c 1.018,3.921 1.895,7.666 0.749,9.206 l 0,0 c -0.292,0.393 -0.865,0.571 -1.664,0.571 l 0,0 c -2.414,0 -6.885,-1.63 -11.864,-3.904" /></g></g></g></g><g
id="g2961"><g
clip-path="url(#clipPath2965)"
id="g2963"><g
transform="translate(250.4868,321.0234)"
id="g3025"><path
id="path3027"
style="fill:#5c5d5d;fill-opacity:1;fill-rule:nonzero;stroke:none"
d="m 0,0 c -1.953,-3.398 -2.12,-7.398 -9.162,-12.051 -1.332,-0.88 -2.181,-1.787 -2.848,-3.422 -3.239,-7.934 2.034,-25.066 2.768,-24.956 1.152,0.325 -5.615,14.689 -1.916,21.923 0.592,1.157 1.516,2.073 2.438,2.968 0.984,0.957 1.551,1.517 2.647,2.326 1.162,0.856 2.677,2.038 4.037,1.981 -0.91,0.038 -2.517,0.43 -3.432,0.469 0.717,1.218 2.645,3.181 3.182,4.031 1.328,2.1 1.92,4.192 2.286,6.731" /></g><g
transform="translate(245.6221,311.167)"
id="g3029"><path
id="path3031"
style="fill:#5c5d5d;fill-opacity:1;fill-rule:nonzero;stroke:none"
d="M 0,0 C 0.858,0.275 1.874,0.881 2.632,1.389 3.313,1.846 4.006,2.344 4.25,3.106 3.887,1.972 2.931,0.588 1.994,-0.055 1.517,-0.382 1.029,-0.701 0.617,-1.111 0.216,-1.509 -0.117,-1.482 -0.718,-1.59 -0.766,-1.337 -0.75,-1.075 -0.75,-0.813" /></g></g></g></g></g></svg>

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 123 KiB

316
src/images/logo.svg Normal file
View file

@ -0,0 +1,316 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
id="svg4071"
version="1.1"
inkscape:version="0.91 r13725"
xml:space="preserve"
width="119.26471"
height="145.2471"
viewBox="0 0 119.26471 145.2471"
sodipodi:docname="FOXYlogo.svg"><metadata
id="metadata4077"><rdf:RDF><cc:Work
rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" /><dc:title></dc:title></cc:Work></rdf:RDF></metadata><defs
id="defs4075"><clipPath
clipPathUnits="userSpaceOnUse"
id="clipPath4085"><path
d="m 185.797,300.527 c 0,-22.396 18.681,-40.552 41.725,-40.552 l 0,0 c 23.044,0 41.725,18.156 41.725,40.552 l 0,0 c 0,22.397 -18.681,40.554 -41.725,40.554 l 0,0 c -23.044,0 -41.725,-18.157 -41.725,-40.554"
id="path4087"
inkscape:connector-curvature="0" /></clipPath><linearGradient
x1="0"
y1="0"
x2="1"
y2="0"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(-7.9998322,76.665482,76.665482,7.9998322,231.64795,260.98437)"
spreadMethod="pad"
id="linearGradient4093"><stop
style="stop-opacity:1;stop-color:#f7931d"
offset="0"
id="stop4095" /><stop
style="stop-opacity:1;stop-color:#fbb16b"
offset="1"
id="stop4097" /></linearGradient><clipPath
clipPathUnits="userSpaceOnUse"
id="clipPath4105"><path
d="m 211.943,333.94 c -18.988,-8.854 -27.403,-30.99 -18.798,-49.443 l 0,0 c 8.604,-18.453 30.971,-26.234 49.958,-17.381 l 0,0 c 18.986,8.854 27.401,30.99 18.797,49.442 l 0,0 c -6.194,13.284 -19.518,21.037 -33.58,21.037 l 0,0 c -5.473,0 -11.058,-1.175 -16.377,-3.655"
id="path4107"
inkscape:connector-curvature="0" /></clipPath><radialGradient
fx="0"
fy="0"
cx="0"
cy="0"
r="1"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(50.959351,23.761917,23.092804,-49.525528,208.03369,303.08252)"
spreadMethod="pad"
id="radialGradient4113"><stop
style="stop-opacity:1;stop-color:#e9e9ea"
offset="0"
id="stop4115" /><stop
style="stop-opacity:1;stop-color:#e9e9ea"
offset="0.70231894"
id="stop4117" /><stop
style="stop-opacity:1;stop-color:#7e8082"
offset="1"
id="stop4119" /></radialGradient><clipPath
clipPathUnits="userSpaceOnUse"
id="clipPath4127"><path
d="M 0,576 576,576 576,0 0,0 0,576 Z"
id="path4129"
inkscape:connector-curvature="0" /></clipPath><clipPath
clipPathUnits="userSpaceOnUse"
id="clipPath4179"><path
d="m 219.217,320.557 c -8.361,-3.819 -11.245,-7.843 -10.12,-9.455 l 0,0 c 1.232,-1.763 6.564,-3.975 10.462,-4.716 l 0,0 c 0.437,-0.084 0.615,0.54 0.788,1.164 l 0,0 c 0.175,0.625 0.345,1.251 0.769,1.164 l 0,0 c 2.49,-0.513 5.947,-3.826 7.154,-4.78 l 0,0 c 0.615,-0.486 1.778,-1.525 2.335,-1.306 l 0,0 c 0.448,0.18 -0.171,1.544 -0.27,2.567 l 0,0 c -0.129,1.34 -1.24,6.507 -0.799,8.453 l 0,0 c 0.16,0.711 0.67,0.604 1.192,0.498 l 0,0 c 0.53,-0.109 1.071,-0.219 1.268,0.538 l 0,0 c 1.018,3.921 1.895,7.666 0.749,9.206 l 0,0 c -0.292,0.393 -0.865,0.571 -1.664,0.571 l 0,0 c -2.414,0 -6.885,-1.63 -11.864,-3.904"
id="path4181"
inkscape:connector-curvature="0" /></clipPath><linearGradient
x1="0"
y1="0"
x2="1"
y2="0"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(34.282654,-15.727585,-15.727585,-34.282654,213.80908,320.43213)"
spreadMethod="pad"
id="linearGradient4187"><stop
style="stop-opacity:1;stop-color:#faa54f"
offset="0"
id="stop4189" /><stop
style="stop-opacity:1;stop-color:#fbb16b"
offset="1"
id="stop4191" /></linearGradient><clipPath
clipPathUnits="userSpaceOnUse"
id="clipPath4199"><path
d="M 0,576 576,576 576,0 0,0 0,576 Z"
id="path4201"
inkscape:connector-curvature="0" /></clipPath></defs><sodipodi:namedview
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1"
objecttolerance="10"
gridtolerance="10"
guidetolerance="10"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:window-width="1440"
inkscape:window-height="810"
id="namedview4073"
showgrid="false"
fit-margin-top="0"
fit-margin-left="0"
fit-margin-right="0"
fit-margin-bottom="0"
showguides="true"
inkscape:zoom="2"
inkscape:cx="135.88583"
inkscape:cy="72.697884"
inkscape:window-x="0"
inkscape:window-y="0"
inkscape:window-maximized="1"
inkscape:current-layer="g4079" /><g
id="g4079"
inkscape:groupmode="layer"
inkscape:label="FOXYlogo"
transform="matrix(1.25,0,0,-1.25,-224.11416,432.54923)"><g
id="g4081"><g
id="g4083"
clip-path="url(#clipPath4085)"><g
id="g4089"><g
id="g4091"><path
d="m 185.797,300.527 c 0,-22.396 18.681,-40.552 41.725,-40.552 l 0,0 c 23.044,0 41.725,18.156 41.725,40.552 l 0,0 c 0,22.397 -18.681,40.554 -41.725,40.554 l 0,0 c -23.044,0 -41.725,-18.157 -41.725,-40.554"
style="fill:url(#linearGradient4093);stroke:none"
id="path4099"
inkscape:connector-curvature="0" /></g></g></g></g><g
id="g4101"><g
id="g4103"
clip-path="url(#clipPath4105)"><g
id="g4109"><g
id="g4111"><path
d="m 211.943,333.94 c -18.988,-8.854 -27.403,-30.99 -18.798,-49.443 l 0,0 c 8.604,-18.453 30.971,-26.234 49.958,-17.381 l 0,0 c 18.986,8.854 27.401,30.99 18.797,49.442 l 0,0 c -6.194,13.284 -19.518,21.037 -33.58,21.037 l 0,0 c -5.473,0 -11.058,-1.175 -16.377,-3.655"
style="fill:url(#radialGradient4113);stroke:none"
id="path4121"
inkscape:connector-curvature="0" /></g></g></g></g><g
id="g4123"><g
id="g4125"
clip-path="url(#clipPath4127)"><g
id="g4131"
transform="translate(261.9004,316.5576)"><path
d="m 0,0 c 8.604,-18.451 0.188,-40.588 -18.798,-49.441 -18.986,-8.854 -41.353,-1.072 -49.958,17.38 -8.605,18.454 -0.189,40.589 18.798,49.443 C -30.972,26.235 -8.605,18.454 0,0 Z"
style="fill:none;stroke:#ffffff;stroke-width:1.76999998;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
id="path4133"
inkscape:connector-curvature="0" /></g><g
id="g4135"
transform="translate(253.9063,323.9209)"><path
d="m 0,0 c -0.38,6.903 -1.854,15.334 -6.533,20.806 -3.507,4.103 -8.978,-7.857 -10.103,-9.669 -1.38,-2.221 -2.706,-4.984 -4.8,-6.605 -2.945,-2.281 -6.431,-2.372 -9.833,-3.499 -5.391,-1.789 -10.688,-4.57 -14.938,-8.369 -5.214,-4.66 -10.154,-4.124 -16.67,-3.649 -2.711,0.199 -12.849,2.406 -11.04,-3.348 2.192,-6.973 7.778,-12.852 13.386,-17.248 5.302,-4.158 2.946,-8.926 -2.589,-11.503 5.72,-7.829 17.267,-8.914 26.01,-7.4 4.766,0.826 9.278,1.088 14.039,-0.052 3.533,-0.845 7.752,-4.399 11.49,-2.507 3.506,1.711 3.098,5.748 4.096,8.94 1.409,4.499 4.193,8.567 7.519,11.858 6.812,6.743 14.138,16.589 10.803,26.9 C 5.155,-8.506 -0.189,-7.015 0,0"
style="fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none"
id="path4137"
inkscape:connector-curvature="0" /></g><g
id="g4139"
transform="translate(215.7368,321.6992)"><path
d="m 0,0 c 0,0 11.985,5.765 21.784,5.146 0,0 7.573,-2.107 11.927,-4.1 0,0 6.191,-4.964 7.201,-8.663 0,0 2.938,-8.511 -7.186,-19.298 0,0 -5.095,-6.523 -6.302,-12.757 0,0 -0.092,-4.189 -2.53,-5.651 0,0 -4.019,-1.141 -6.971,0.514 -2.393,0.678 -4.844,1.214 -7.298,1.626 -5.684,0.954 -11.46,0.006 -17.159,1.061 -4.659,0.859 -10.534,2.956 -11.796,8.135 0,0 -2.888,2.565 0.798,13.578 0,0 2.001,12.357 17.532,20.409"
style="fill:#f7931d;fill-opacity:1;fill-rule:nonzero;stroke:none"
id="path4141"
inkscape:connector-curvature="0" /></g><g
id="g4143"
transform="translate(196.5059,295.9878)"><path
d="m 0,0 c 2.679,-1.011 4.179,-2.636 10.782,-1.915 3.055,0.334 5.723,3.269 8.877,2.476 8.535,-2.152 22.752,-17.621 22.222,-18.163 -0.955,-0.761 -11.555,14.2 -19.136,10.842 -1.809,-0.8 -4.551,-2.507 -6.534,-2.023 -0.958,0.237 -1.792,0.686 -2.52,1.358 -0.96,0.89 -1.642,2.731 -2.91,3.235 -1.728,0.688 -3.12,0.784 -4.914,1.167 -1.929,0.412 -3.938,1.262 -5.436,2.518"
style="fill:#535454;fill-opacity:1;fill-rule:nonzero;stroke:none"
id="path4145"
inkscape:connector-curvature="0" /></g><g
id="g4147"
transform="translate(243.0967,279.8789)"><path
d="m 0,0 c 0.714,-1.26 -0.438,-4.142 -0.984,-4.45 -0.544,-0.309 -3.745,0.106 -4.459,1.367 -0.713,1.258 0.327,2.263 1.83,3.114 C -2.109,0.883 -0.713,1.259 0,0"
style="fill:#535454;fill-opacity:1;fill-rule:nonzero;stroke:none"
id="path4149"
inkscape:connector-curvature="0" /></g><g
id="g4151"
transform="translate(206.8965,302.1777)"><path
d="M 0,0 C -0.872,1.155 2.11,3.59 2.733,3.646 3.357,3.701 6.101,2.003 6.231,0.562 6.361,-0.879 3.944,0.677 2.223,0.523 0.502,0.367 0.369,-0.49 0,0"
style="fill:#535454;fill-opacity:1;fill-rule:nonzero;stroke:none"
id="path4153"
inkscape:connector-curvature="0" /></g><g
id="g4155"
transform="translate(262.0864,311.4141)"><path
d="m 0,0 c -0.677,-9.71 -5.16,-14.594 -10.862,-21.908 -3.012,-3.861 -5.017,-8.005 -6.067,-12.766 -0.653,-2.955 -2.998,-5.396 -6.187,-5.296 -3.564,0.114 -6.928,2.23 -10.487,2.862 -4.641,0.826 -9.162,0.113 -13.801,-0.206 -4.671,-0.321 -8.985,0.475 -13.127,2.686 -0.069,0.036 -6.823,4.403 -6.476,4.649 4.916,3.463 2.528,8.458 -1.511,11.371 -5.349,3.857 -10.603,10.055 -12.841,16.365 -1.254,3.539 12.776,0.416 14.245,-0.23 4.956,-2.182 2.184,-9.504 1.431,-13.29 1.562,1.982 1.916,4.999 2.747,7.338 1.244,3.501 2.716,7.061 5.389,9.728 3.419,3.415 7.537,5.966 11.82,8.15 5.051,2.578 9.983,4.83 15.651,5.436 4.155,0.441 7.829,-0.055 11.682,-1.675 0.621,-0.264 4.807,-2.148 5.815,-1.898 -3.393,1.208 -10.569,4.446 -9.555,9.164 0.338,1.567 5.62,14.545 7.748,11.455 3.797,-5.514 5.733,-13.408 5.718,-20.002 C -8.68,6.954 -6.037,2.089 -0.348,4.037 -0.384,4.025 0.028,0.412 0,0 m -7.915,12.749 c -0.384,6.973 -1.874,15.488 -6.598,21.016 -3.544,4.145 -9.07,-7.937 -10.206,-9.767 -1.394,-2.243 -2.732,-5.033 -4.849,-6.672 -2.974,-2.305 -6.495,-2.395 -9.931,-3.535 -5.446,-1.808 -10.797,-4.617 -15.089,-8.453 -5.267,-4.707 -10.258,-4.165 -16.839,-3.686 -2.739,0.201 -12.979,2.429 -11.151,-3.382 2.213,-7.042 7.856,-12.98 13.52,-17.421 5.355,-4.199 2.976,-9.016 -2.615,-11.62 5.778,-7.908 17.443,-9.004 26.273,-7.474 4.815,0.834 9.372,1.096 14.18,-0.054 3.57,-0.851 7.831,-4.442 11.607,-2.531 3.541,1.728 3.129,5.806 4.139,9.031 1.422,4.543 4.234,8.652 7.594,11.977 C -1,-13.011 6.4,-3.065 3.032,7.352 -2.708,4.155 -8.107,5.663 -7.915,12.749"
style="fill:#535454;fill-opacity:1;fill-rule:nonzero;stroke:none"
id="path4157"
inkscape:connector-curvature="0" /></g><g
id="g4159"
transform="translate(240.9268,311.4058)"><path
d="m 0,0 c 0.288,1.418 -3.452,2.332 -4.038,2.113 -0.587,-0.218 -2.331,-2.933 -1.827,-4.29 0.502,-1.358 2.012,1.088 3.634,1.692 C -0.613,0.115 -0.123,-0.601 0,0"
style="fill:#535454;fill-opacity:1;fill-rule:nonzero;stroke:none"
id="path4161"
inkscape:connector-curvature="0" /></g><g
id="g4163"
transform="translate(215.5869,289.4712)"><path
d="M 0,0 C 0.181,0.136 0.365,0.415 0.297,0.387 0.506,0.79 0.527,1.284 0.305,1.718 -0.059,2.433 -0.937,2.72 -1.652,2.354 -2.369,1.99 -2.652,1.112 -2.286,0.396 -2.284,0.392 -2.281,0.389 -2.279,0.385 -2.35,0.414 -2.423,0.425 -2.492,0.459 -3.995,1.189 -4.734,2.865 -4.337,4.425 -4.47,4.253 -4.588,4.066 -4.688,3.865 -5.445,2.307 -4.793,0.431 -3.236,-0.324 c 0.9,-0.439 1.9,-0.392 2.733,0.017 0.058,0.021 0.117,0.039 0.174,0.068 C -0.204,-0.175 -0.098,-0.091 0,0"
style="fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none"
id="path4165"
inkscape:connector-curvature="0" /></g><g
id="g4167"
transform="translate(201.3467,286.79)"><path
d="m 0,0 c 0,0 4.649,-8.012 17.098,-5.728 0,0 8.646,2.306 13.661,-2.572 -1.023,0.995 -1.912,2.037 -3.159,2.8 -3.88,2.374 -8.425,1.586 -12.74,2.007 C 11.729,-3.186 8.814,-2.129 6.012,-0.74 4.997,-0.237 -0.543,3.323 0,0"
style="fill:#f5aa35;fill-opacity:1;fill-rule:nonzero;stroke:none"
id="path4169"
inkscape:connector-curvature="0" /></g><g
id="g4171"
transform="translate(254.4907,311.8257)"><path
d="m 0,0 c 0,0 2.953,-8.739 -7.189,-15.087 0,0 -5.659,-4.735 -5.408,-11.635 -0.051,1.406 -0.211,2.757 0.021,4.15 0.385,2.318 0.466,4.79 1.388,6.944 0.89,2.08 2.775,3.179 4.241,4.747 1.653,1.768 2.733,4.008 3.344,6.417 C -3.336,-3.416 -1.854,2.765 0,0"
style="fill:#f5aa35;fill-opacity:1;fill-rule:nonzero;stroke:none"
id="path4173"
inkscape:connector-curvature="0" /></g></g></g><g
id="g4175"><g
id="g4177"
clip-path="url(#clipPath4179)"><g
id="g4183"><g
id="g4185"><path
d="m 219.217,320.557 c -8.361,-3.819 -11.245,-7.843 -10.12,-9.455 l 0,0 c 1.232,-1.763 6.564,-3.975 10.462,-4.716 l 0,0 c 0.437,-0.084 0.615,0.54 0.788,1.164 l 0,0 c 0.175,0.625 0.345,1.251 0.769,1.164 l 0,0 c 2.49,-0.513 5.947,-3.826 7.154,-4.78 l 0,0 c 0.615,-0.486 1.778,-1.525 2.335,-1.306 l 0,0 c 0.448,0.18 -0.171,1.544 -0.27,2.567 l 0,0 c -0.129,1.34 -1.24,6.507 -0.799,8.453 l 0,0 c 0.16,0.711 0.67,0.604 1.192,0.498 l 0,0 c 0.53,-0.109 1.071,-0.219 1.268,0.538 l 0,0 c 1.018,3.921 1.895,7.666 0.749,9.206 l 0,0 c -0.292,0.393 -0.865,0.571 -1.664,0.571 l 0,0 c -2.414,0 -6.885,-1.63 -11.864,-3.904"
style="fill:url(#linearGradient4187);stroke:none"
id="path4193"
inkscape:connector-curvature="0" /></g></g></g></g><g
id="g4195"><g
id="g4197"
clip-path="url(#clipPath4199)"><g
id="g4203"
transform="translate(190.7241,261.791)"><path
d="m 0,0 13.065,0 0,-5.588 -5.924,0 0,-2.017 5.2,0 0,-5.072 -5.2,0 0,-6.83 -7.141,0 L 0,0 Z"
style="fill:#f7931d;fill-opacity:1;fill-rule:nonzero;stroke:none"
id="path4205"
inkscape:connector-curvature="0" /></g><g
id="g4207"
transform="translate(214.5513,251.8828)"><path
d="m 0,0 c 0,-2.226 1.501,-3.752 3.648,-3.752 2.147,0 3.648,1.526 3.648,3.752 0,2.069 -1.397,3.803 -3.648,3.803 C 1.397,3.803 0,2.069 0,0 m 14.437,0.104 c 0,-6.261 -4.838,-10.013 -10.789,-10.013 -5.95,0 -10.789,3.752 -10.789,10.013 0,6.131 4.865,10.115 10.789,10.115 5.925,0 10.789,-3.984 10.789,-10.115"
style="fill:#f7931d;fill-opacity:1;fill-rule:nonzero;stroke:none"
id="path4209"
inkscape:connector-curvature="0" /></g><g
id="g4211"
transform="translate(251.9355,261.791)"><path
d="m 0,0 -6.105,-9.132 6.959,-10.375 -8.072,0 -2.225,4.14 c -0.207,0.388 -0.336,0.776 -0.414,1.189 l -0.207,0 c -0.129,-0.465 -0.311,-0.905 -0.543,-1.344 l -2.174,-3.985 -8.072,0 6.831,10.375 -6.132,9.132 7.994,0 1.449,-2.768 c 0.285,-0.517 0.44,-1.06 0.595,-1.604 l 0.156,0 c 0.129,0.569 0.362,1.087 0.621,1.604 L -7.994,0 0,0 Z"
style="fill:#f7931d;fill-opacity:1;fill-rule:nonzero;stroke:none"
id="path4213"
inkscape:connector-curvature="0" /></g><g
id="g4215"
transform="translate(262.3101,261.791)"><path
d="m 0,0 2.173,-5.097 0.207,0 c 0.207,0.621 0.388,1.243 0.647,1.837 L 4.424,0 l 7.969,0 -6.676,-11.099 0,-8.408 -6.933,0 0,8.408 L -8.021,0 0,0 Z"
style="fill:#f7931d;fill-opacity:1;fill-rule:nonzero;stroke:none"
id="path4217"
inkscape:connector-curvature="0" /></g><g
id="g4219"
transform="translate(196.2456,236.8574)"><path
d="m 0,0 -2.792,0 0,-2.57 2.803,0 c 0.543,0 0.984,0.105 1.323,0.317 0.369,0.227 0.554,0.535 0.554,0.928 C 1.888,-0.441 1.258,0 0,0 M 1.892,-3.091 C 1.333,-3.4 0.64,-3.555 -0.19,-3.555 l -2.602,0 0,-3.133 -1.086,0 0,7.672 3.813,0 c 2.036,0 3.054,-0.765 3.054,-2.297 0,-0.786 -0.365,-1.377 -1.097,-1.778"
style="fill:#535454;fill-opacity:1;fill-rule:nonzero;stroke:none"
id="path4221"
inkscape:connector-curvature="0" /></g><g
id="g4223"
transform="translate(196.2456,236.8574)"><path
d="m 0,0 -2.792,0 0,-2.57 2.803,0 c 0.543,0 0.984,0.105 1.323,0.317 0.369,0.227 0.554,0.535 0.554,0.928 C 1.888,-0.441 1.258,0 0,0 Z M 1.892,-3.091 C 1.333,-3.4 0.64,-3.555 -0.19,-3.555 l -2.602,0 0,-3.133 -1.086,0 0,7.672 3.813,0 c 2.036,0 3.054,-0.765 3.054,-2.297 0,-0.786 -0.365,-1.377 -1.097,-1.778 z"
style="fill:none;stroke:#535454;stroke-width:0.5;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
id="path4225"
inkscape:connector-curvature="0" /></g><g
id="g4227"
transform="translate(213.5576,236.8574)"><path
d="m 0,0 -2.888,0 0,-2.477 2.707,0 c 0.604,0 1.083,0.102 1.438,0.306 0.393,0.226 0.589,0.558 0.589,0.995 C 1.846,-0.392 1.23,0 0,0 m 1.935,-2.942 c 0.586,-0.37 0.88,-0.928 0.88,-1.675 l 0,-2.071 -1.086,0 0,2.036 c 0,0.784 -0.619,1.175 -1.856,1.175 l -2.761,0 0,-3.211 -1.086,0 0,7.672 3.951,0 c 1.97,0 2.955,-0.709 2.955,-2.127 0,-0.807 -0.332,-1.407 -0.997,-1.799"
style="fill:#535454;fill-opacity:1;fill-rule:nonzero;stroke:none"
id="path4229"
inkscape:connector-curvature="0" /></g><g
id="g4231"
transform="translate(213.5576,236.8574)"><path
d="m 0,0 -2.888,0 0,-2.477 2.707,0 c 0.604,0 1.083,0.102 1.438,0.306 0.393,0.226 0.589,0.558 0.589,0.995 C 1.846,-0.392 1.23,0 0,0 Z m 1.935,-2.942 c 0.586,-0.37 0.88,-0.928 0.88,-1.675 l 0,-2.071 -1.086,0 0,2.036 c 0,0.784 -0.619,1.175 -1.856,1.175 l -2.761,0 0,-3.211 -1.086,0 0,7.672 3.951,0 c 1.97,0 2.955,-0.709 2.955,-2.127 0,-0.807 -0.332,-1.407 -0.997,-1.799 z"
style="fill:none;stroke:#535454;stroke-width:0.5;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
id="path4233"
inkscape:connector-curvature="0" /></g><g
id="g4235"
transform="translate(233.5015,236.0957)"><path
d="m 0,0 c -0.565,0.487 -1.365,0.73 -2.397,0.73 -1.034,0 -1.829,-0.245 -2.387,-0.735 -0.558,-0.491 -0.837,-1.188 -0.837,-2.095 0,-0.905 0.283,-1.618 0.849,-2.138 0.565,-0.521 1.356,-0.782 2.375,-0.782 1.032,0 1.832,0.259 2.397,0.776 0.565,0.516 0.848,1.231 0.848,2.144 0,0.913 -0.283,1.614 -0.848,2.1 m 0.763,-4.951 c -0.781,-0.702 -1.835,-1.053 -3.163,-1.053 -1.335,0 -2.389,0.349 -3.163,1.047 -0.772,0.698 -1.159,1.65 -1.159,2.857 0,1.208 0.396,2.151 1.188,2.83 0.762,0.657 1.806,0.985 3.134,0.985 1.328,0 2.377,-0.328 3.146,-0.985 0.792,-0.679 1.188,-1.622 1.188,-2.83 0,-1.199 -0.391,-2.15 -1.171,-2.851"
style="fill:#535454;fill-opacity:1;fill-rule:nonzero;stroke:none"
id="path4237"
inkscape:connector-curvature="0" /></g><g
id="g4239"
transform="translate(233.5015,236.0957)"><path
d="m 0,0 c -0.565,0.487 -1.365,0.73 -2.397,0.73 -1.034,0 -1.829,-0.245 -2.387,-0.735 -0.558,-0.491 -0.837,-1.188 -0.837,-2.095 0,-0.905 0.283,-1.618 0.849,-2.138 0.565,-0.521 1.356,-0.782 2.375,-0.782 1.032,0 1.832,0.259 2.397,0.776 0.565,0.516 0.848,1.231 0.848,2.144 0,0.913 -0.283,1.614 -0.848,2.1 z m 0.763,-4.951 c -0.781,-0.702 -1.835,-1.053 -3.163,-1.053 -1.335,0 -2.389,0.349 -3.163,1.047 -0.772,0.698 -1.159,1.65 -1.159,2.857 0,1.208 0.396,2.151 1.188,2.83 0.762,0.657 1.806,0.985 3.134,0.985 1.328,0 2.377,-0.328 3.146,-0.985 0.792,-0.679 1.188,-1.622 1.188,-2.83 0,-1.199 -0.391,-2.15 -1.171,-2.851 z"
style="fill:none;stroke:#535454;stroke-width:0.5;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
id="path4241"
inkscape:connector-curvature="0" /></g><g
id="g4243"
transform="translate(251.9077,230.1699)"><path
d="M 0,0 -2.891,3.174 -5.832,0 l -1.417,0 3.63,3.93 -3.456,3.742 1.434,0 2.742,-2.978 2.759,2.978 1.416,0 L -2.175,3.936 1.399,0 0,0 Z"
style="fill:#535454;fill-opacity:1;fill-rule:nonzero;stroke:none"
id="path4245"
inkscape:connector-curvature="0" /></g><g
id="g4247"
transform="translate(251.9077,230.1699)"><path
d="M 0,0 -2.891,3.174 -5.832,0 l -1.417,0 3.63,3.93 -3.456,3.742 1.434,0 2.742,-2.978 2.759,2.978 1.416,0 L -2.175,3.936 1.399,0 0,0 Z"
style="fill:none;stroke:#535454;stroke-width:0.5;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
id="path4249"
inkscape:connector-curvature="0" /></g><g
id="g4251"
transform="translate(266.6904,233.792)"><path
d="m 0,0 0,-3.622 -1.086,0 0,3.621 -3.977,4.051 1.446,0 3.062,-3.108 3.073,3.108 1.429,0 L 0,0 Z"
style="fill:#535454;fill-opacity:1;fill-rule:nonzero;stroke:none"
id="path4253"
inkscape:connector-curvature="0" /></g><g
id="g4255"
transform="translate(266.6904,233.792)"><path
d="m 0,0 0,-3.622 -1.086,0 0,3.621 -3.977,4.051 1.446,0 3.062,-3.108 3.073,3.108 1.429,0 L 0,0 Z"
style="fill:none;stroke:#535454;stroke-width:0.5;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
id="path4257"
inkscape:connector-curvature="0" /></g><g
id="g4259"
transform="translate(250.4868,321.0234)"><path
d="m 0,0 c -1.953,-3.398 -2.12,-7.398 -9.162,-12.051 -1.332,-0.88 -2.181,-1.787 -2.848,-3.422 -3.239,-7.934 2.034,-25.066 2.768,-24.956 1.152,0.325 -5.615,14.689 -1.916,21.923 0.592,1.157 1.516,2.073 2.438,2.968 0.984,0.957 1.551,1.517 2.647,2.326 1.162,0.856 2.677,2.038 4.037,1.981 -0.91,0.038 -2.517,0.43 -3.432,0.469 0.717,1.218 2.645,3.181 3.182,4.031 1.328,2.1 1.92,4.192 2.286,6.731"
style="fill:#535454;fill-opacity:1;fill-rule:nonzero;stroke:none"
id="path4261"
inkscape:connector-curvature="0" /></g><g
id="g4263"
transform="translate(245.6221,311.167)"><path
d="M 0,0 C 0.858,0.275 1.874,0.881 2.632,1.389 3.313,1.846 4.006,2.344 4.25,3.106 3.887,1.972 2.931,0.588 1.994,-0.055 1.517,-0.382 1.029,-0.701 0.617,-1.111 0.216,-1.509 -0.117,-1.482 -0.718,-1.59 -0.766,-1.337 -0.75,-1.075 -0.75,-0.813"
style="fill:#535454;fill-opacity:1;fill-rule:nonzero;stroke:none"
id="path4265"
inkscape:connector-curvature="0" /></g></g></g></g></svg>

After

Width:  |  Height:  |  Size: 23 KiB

114
src/import-proxy-list.html Normal file
View file

@ -0,0 +1,114 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title data-i18n="import">FoxyProxy </title>
<link rel="icon" type="image/png" href="/images/icon.svg">
<link rel="stylesheet" href="styles/fontawesome-4.6.3.css">
<link rel="stylesheet" href="styles/app.css">
<style>
i.fa, i.fa:hover { color: inherit; font-size: inherit; }
i.fa.fa-eye, i.fa.fa-eye:hover {
font-size: 1.5em;
vertical-align: middle;
}
label {
display: inline-block;
}
textarea {
height: 10em;
}
div.tooltip hr {
color: white;
}
div.tooltip h3 {
margin: 0 0 .2em 0;
}
.align-right {
text-align: right;
}
.no-margin {
margin: 0;
}
#completeFormatTooltip {
width: 40rem;
}
</style>
</head>
<body>
<!-- header -->
<div class="prime header" data-i18n="importProxyList"></div>
<!-- spinner -->
<div class="spinner on"><i class="fa fa-refresh fa-spin"></i></div>
<!-- main -->
<div class="prime">
<div class="tooltip">
<span data-i18n="pasteList"></span> <span data-i18n="formats"></span> <span data-i18n="simple"></span>
<i class="fa fa-info-circle"></i>
<div class="tooltiptext bottom table">
<div class="tooltiptable">
<p class="no-margin" data-i18n="simpleFormat"></p>
<p class="monospace"><span data-i18n="ipPort"></span><br><span data-i18n="ipPort"></span><br><span data-i18n="ipPortUsernamePassword"></span></p>
</div>
<hr>
<div class="tooltiptablefooter">
<h3 data-i18n="examples"></h3>
78.205.12.1:6001<br>12.999.51.81:3128<br>foobar.com:12001<br>foobar.com:3128:kyleReese:hunterKiller
<p><a data-i18n="help" target="_blank" href="https://github.com/foxyproxy/firefox-extension/wiki/Import-Proxy-List"></a></p>
</div>
</div>
</div>
/
<div class="tooltip">
<span data-i18n="complete"></span>
<i class="fa fa-info-circle"></i>
<div id="completeFormatTooltip" class="tooltiptext bottom table">
<div class="tooltiptable">
<p data-i18n="completeFormat"></p>
<h3 data-i18n="examples"></h3>
<p class="monospace">* proxy://78.205.12.1:666<br>
* proxy://johnConnor:hunterKiller@192.168.100.9:5192?color=663300<br>
* socks://12.999.51.81?title=China&cc=CN&country=中国&proxyDns=false<br>
* socks://12.999.51.81:331?patternExcludesIntranet=false<br>
* https://192.168.100.9:5192?patternIncludesAll=false<br>
* ssl://kyleReese:passw0rd@78.205.12.1:21?color=ff00bc&title=work%20proxy</p>
</div>
<hr>
<div class="tooltiptablefooter">
<a data-i18n="help" target="_blank" href="https://github.com/foxyproxy/firefox-extension/wiki/Import-Proxy-List"></a>
</div>
</div>
</div>
<br><br>
<textarea id="proxyList"></textarea>
<label data-i18n="overwriteProxies"></label>
<input id="overwrite" type="checkbox" class="switch"><label for="overwrite"></label>
<div class="tooltip">
<i class="fa fa-info-circle"></i>
<div class="tooltiptext center bottom">
<div class="tooltiptable">
<span data-i18n="overwritProxiesHelp1"></span>
</div>
<br>
<div class="tooltiptable">
<span data-i18n="overwritProxiesHelp2"></span>
</div>
</div>
</div>
<br><br>
<button id="import" type="button" class="button" data-i18n="import"><i class="fa fa-download"></i> </button>
<div class="align-right">
<button type="button" class="button" data-i18n="back">&#x25c1; </button>
</div>
</div>
<script src="scripts/utils.js"></script>
<script src="scripts/import-proxy-list.js"></script>
</body>
</html>

96
src/import.html Normal file
View file

@ -0,0 +1,96 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title data-i18n="import">FoxyProxy </title>
<link rel="icon" type="image/png" href="/images/icon.svg">
<link rel="stylesheet" href="styles/fontawesome-4.6.3.css">
<link rel="stylesheet" href="styles/app.css">
<style>
i.fa, i.fa:hover { color: inherit; font-size: inherit; }
i.fa.fa-eye, i.fa.fa-eye:hover {
font-size: 1.5em;
vertical-align: middle;
}
button.plain {
vertical-align: text-bottom;
}
label {
display: inline-block;
min-width: 5em;
}
input[type="text"], input[type="password"] {
display: inline-block;
width: 10em;
height: auto;
padding: 0.1em
}
input#username {
margin-right: 1em;
}
fieldset {
margin-bottom: 1.5em;
}
</style>
</head>
<body>
<!-- header -->
<div class="prime header" data-i18n="import"></div>
<!-- spinner -->
<div class="spinner on"><i class="fa fa-refresh fa-spin"></i></div>
<!-- main -->
<div class="prime">
<fieldset>
<legend>Import VPN/Proxies from FoxyProxy Purchase</legend>
<p>If you have a paid account with <a href="https://getfoxyproxy.org/order/" target="_blank">FoxyProxy</a>, you can import your proxies here.</p>
<label>Username</label>
<input id="username" type="text" spellcheck="false" placeholder="username">
<label>Password</label>
<input id="password" type="password" spellcheck="false" placeholder="*****">
<button type="button" class="plain" data-i18n="togglePW|title"><i class="fa fa-eye"></i></button>
<br>
<button id="importFP" type="button" class="button" data-i18n="import"><i class="fa fa-download"></i> </button>
</fieldset>
<fieldset>
<legend>Import Settings from FoxyProxy 6.0+</legend>
<p>FoxyProxy can use <a href="https://support.mozilla.org/products/firefox/sync" target="_blank">Firefox Sync</a> to synchronize settings across different installations of Firefox. But if you don't use Firefox Sync or want to share your settings with friends,<button type="button" class="button small" data-i18n="export"><i class="fa fa-upload"></i> </button> FoxyProxy settings. Then use this page to import those settings. By default, the file is called <i><span data-i18n="extensionName"></span>_YYYY-MM-DD.json</i>.<br><br>
<input type="file" id="importJson" accept=".json">
<label for="importJson" class="button" data-i18n="import"><i class="fa fa-download"></i> </label>
</fieldset>
<fieldset>
<legend>Import Settings from FoxyProxy 4.x and earlier</legend>
<p>Firefox has completely changed the addon system since FoxyProxy 4.x and earlier. Older FoxyProxy versions used a pop-up window. It looked a little different on Windows, Mac, and Linux, but the essence was like the image below.</p>
<p>Unfortunately, due to Firefox 57+ limitations, we cannot read your FoxyProxy settings automatically. However, they are not lost. To import your old settings, please select the file <i>foxyproxy.xml</i> below. You can find it in the <a href="https://support.mozilla.org/en-US/kb/profiles-where-firefox-stores-user-data#w_how-do-i-find-my-profile" target="_blank">Firefox profile directory</a>.<br><br>
<input type="file" id="importXml" accept=".xml">
<label for="importXml" class="button" data-i18n="import"><i class="fa fa-download"></i> </label>
</p>
<p style="text-align: center;"><a target="_blank" href="/images/legacy-version.png"><img src="/images/legacy-version.png" style="width: 300px;"></a><br>
<i>(click image for larger picture)</i></p>
</fieldset>
<div style="text-align: right;">
<button type="button" class="button" data-i18n="back">&#x25c1; </button>
</div>
</div>
<script src="scripts/utils.js"></script>
<script src="scripts/import.js"></script>
</body>
</html>

128
src/log.html Normal file
View file

@ -0,0 +1,128 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title data-i18n="log">FoxyProxy </title>
<link rel="icon" type="image/png" href="/images/icon.svg">
<link rel="stylesheet" href="styles/fontawesome-4.6.3.css">
<link rel="stylesheet" href="styles/app.css">
<style>
tbody tr:hover a { color: #a0522d; }
tbody td { padding: 0em 0.2em; overflow-x: auto; text-overflow: ellipsis; white-space: nowrap; scrollbar-color: #ddd #f5f5f5; scrollbar-width: thin; }
td:nth-child(1) { max-width: 20em; }
td:nth-child(2) { max-width: 5em; }
td:nth-child(3) { width: 2em; border-radius: 5px; border: 2px solid #fff; }
td:nth-child(4) { max-width: 8em; }
td:nth-child(5) { max-width: 8em; }
td:nth-child(6) { max-width: 14em; }
.prime.warning { font-size: 0.9em; padding: 0.5em;}
tbody { counter-reset: n; }
tbody tr td:first-child::before {
display: inline-block;
color: #aaa;
min-width: 1.5em;
text-align: right;
vertical-align: middle;
margin-right: 0.4em;
pointer-events: none;
counter-increment: n;
content: counter(n);
font-size: 0.7em;
}
label[data-i18n] {
margin: 0 0.5em 0 1em;
}
input[type="text"] {
display: inline-block;
width: 5em;
padding: 0.2em;
height: auto;
}
i.fa, i.fa:hover { color: inherit; font-size: inherit; }
</style>
</head>
<body>
<!-- header -->
<div class="prime header" data-i18n="log"></div>
<!-- spinner --> <!-- options, patterns, log -->
<div class="spinner on"><i class="fa fa-refresh fa-spin"></i></div>
<!-- main -->
<div class="prime">
<div style="text-align: right;">
<label data-i18n="log"></label>
<input type="checkbox" class="switch" id="onOff"><label for="onOff"></label>
<label data-i18n="logSize"></label>
<input id="logSize" type="text">
</div>
<div class="prime warning"><strong>Failed URLs display here, too!</strong><br>
A row in this log does not mean the URL successfully loaded. The log shows only how <strong>attempts</strong> were made to load URLs. If the proxy server was not responding or there was some other problem which prevented the URL from loading, the URL still displays here. This is a limitation of Firefox 57+.
</div>
<h3 data-i18n="matchedURLs"></h3>
<div class="scroll">
<table>
<thead>
<tr>
<th data-i18n="url"></th><th data-i18n="proxyTitle"></th><th data-i18n="color"></th>
<th data-i18n="proxyAddress"></th><th data-i18n="matchPattern"></th><th data-i18n="whiteBlack"></th>
<th data-i18n="timestamp"></th>
</tr>
<!-- template -->
<tr class="matchedtemplate">
<td><a href="" target="_blank"></a></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
</thead>
<tbody></tbody>
</table>
</div>
<h3 data-i18n="unmatchedURLs"></h3>
<div class="scroll">
<table>
<thead>
<tr>
<th data-i18n="url"></th>
<th data-i18n="timestamp"></th>
</tr>
<!-- template -->
<tr class="unmatchedtemplate">
<td><a href="" target="_blank"></a></td>
<td></td>
</tr>
</thead>
<tbody></tbody>
</table>
</div>
<div style="margin-top: 1em; text-align: right;">
<button type="button" data-i18n="back">&#x25c1; </button>
<button type="button" data-i18n="refresh"><i class="fa fa-refresh"></i> </button>
<button type="button" class="alert" data-i18n="clear"><i class="fa fa-trash"></i> </button>
</div>
</div>
<script src="scripts/utils.js"></script>
<script src="scripts/log.js"></script>
</body>
</html>

54
src/manifest.json Normal file
View file

@ -0,0 +1,54 @@
{
"manifest_version": 2,
"name": "__MSG_extensionName__",
"description": "__MSG_extensionDescription__",
"version": "7.5.1",
"default_locale": "en",
"homepage_url": "https://getfoxyproxy.org/",
"author": "Eric Jung",
"icons": {
"16": "images/icon.svg",
"32": "images/icon.svg",
"48": "images/icon.svg",
"64": "images/icon.svg",
"128": "images/icon.svg"
},
"background": {
"scripts": ["scripts/utils.js", "scripts/background.js", "scripts/matcher.js"]
},
"options_ui": {
"page": "options.html",
"open_in_tab": true,
"browser_style": true
},
"browser_action": {
"default_icon": "images/icon.svg",
"default_title": "__MSG_extensionName__",
"default_popup": "popup.html",
"browser_style": true
},
"permissions": [
"browsingData",
"proxy",
"storage",
"tabs",
"webRequest",
"webRequestBlocking",
"downloads",
"notifications",
"<all_urls>"
],
"browser_specific_settings": {
"gecko": {
"id": "foxyproxy@eric.h.jung",
"strict_min_version": "60.0"
}
}
}

140
src/options.html Normal file
View file

@ -0,0 +1,140 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title data-i18n="options">FoxyProxy </title>
<link rel="icon" type="image/png" href="/images/icon.svg">
<link rel="stylesheet" href="styles/fontawesome-4.6.3.css">
<link rel="stylesheet" href="styles/app.css">
<style>
nav { width: 14em; margin-right: 0.5em; }
nav i.fa { margin-right: 0.4em; font-size: 1.6em; }
nav a { display: block; padding: 0.2em 0.5em; border-radius: 0 50px 50px 0; cursor: pointer; }
nav a:hover { background-color: #ffebcd; }
button i.fa { font-size: 1.8em; color: #ccc; }
button i.fa:hover { color: #f90; }
button[data-i18n="help|title"] { margin-right: 0.5em; }
i.fa-lock { color: #ccc; font-size: 1.3em; vertical-align: middle; margin-right: 0.3em; }
i.fa.fa-lock.on, i.fa-lock.on:hover { color: #080; }
.rightColumn { padding: 1em; flex-grow: 1; border: 1px solid #ccc; border-radius: 5px; }
.pxy { opacity: 1; transition: all 0.5s ease-in-out; border: 1px solid #ccc; border-radius: 5px;
margin: 0 0 0.2em 0; padding: 0.2em 0.4em; }
.pxy.on { box-shadow: 0px 2px 4px rgba(0,0,0,0.6); }
.pxy:first-of-type button.up,
.pxy:last-of-type button.down { visibility: hidden; }
#accounts { max-height: 60vh; }
#accounts div:last-of-type { margin: 0; }
.title, .address { display: inline-block; vertical-align: middle; }
.title { width: 6em; margin: 0 0.5em; }
.address { max-width: 10em; }
#accounts button.small { margin-left: 0.2em; }
.scroll { max-height: 40vh; padding-right: 0.2em; }
.color{
width: 2em;
display: inline-block;
border-radius: 5px;
border: 2px solid #fff;
box-shadow: 0px 2px 3px #777;
font-size: 0.8em;
width: 3em;
}
</style>
</head>
<body>
<!-- header -->
<div class="prime header" data-i18n="optionsPage"></div>
<!-- spinner -->
<div class="spinner on"><i class="fa fa-refresh fa-spin"></i></div>
<!-- error -->
<div id="error" class="prime hide"><h5 data-i18n="erroNoSettings"></h5></div>
<!-- main -->
<div class="prime">
<div style="display: flex;">
<nav>
<a data-i18n="add"><i class="fa fa-plus-circle"></i></a>
<a data-i18n="import"><i class="fa fa-download"></i></a>
<a data-i18n="importProxyList""><i class="fa fa-list"></i></a>
<a data-i18n="export"><i class="fa fa-upload"></i></a>
<a data-i18n="deleteAll"><i class="fa fa-trash"></i></a>
<a data-i18n="deleteBrowserData"><i class="fa fa-eraser" style="margin-right: 0.1em;"></i></a>
<a href="https://getfoxyproxy.org/geoip/" target="_blank" data-i18n="myIP"><i class="fa fa-globe"></i></a>
<a data-i18n="log"><i class="fa fa-file-text"></i></a>
<a data-i18n="about"><i class="fa fa-info-circle"></i></a>
</nav>
<div id="rightColumn" class="rightColumn">
<!-- select & sync -->
<div id="selectAndSync" class="flex">
<select id="mode">
<option value="patterns" style="color: #f90;" data-i18n="modePatterns"></option>
<option value="disabled" style="color: red;" data-i18n="modeDisabled"></option>
</select>
<div style="text-align: right;">
<span data-i18n="syncSettings"></span>
<button type="button" class="plain" data-i18n="help|title"><i class="fa fa-question-circle"></i></button>
<input type="checkbox" class="switch" id="syncOnOff"><label for="syncOnOff"></label>
</div>
</div>
<!-- proxy list -->
<div id="accounts" class="scroll"></div>
<div id="help" style="text-align: center;margin: 15% auto"> <!-- try to center -->
<span data-i18n="noProxies"></span>
Please click <a data-i18n="add" href="/proxy.html"><i class="fa fa-plus-circle"></i> </a> to start.
</div>
<!-- template -->
<div class="pxy flex template">
<div>
<span class="color">&nbsp;</span>
<span class="title ellipsis"></span>
<span class="address ellipsis"></span>
<span class="flag hide"></span>
</div>
<div style="text-align: right;">
<i class="fa fa-lock"></i>
<input type="checkbox" name="onOff" class="switch" id=""><label for=""></label>
<button type="button" class="small" data-i18n="edit"></button>
<button type="button" class="small" data-i18n="patterns"></button>
<button type="button" class="plain" data-i18n="delete|title"><i class="fa fa-trash"></i></button>
<button type="button" class="plain up" data-i18n="up|title"><i class="fa fa-caret-up"></i></button>
<button type="button" class="plain down" data-i18n="down|title"><i class="fa fa-sort-desc"></i></button>
</div>
</div>
</div>
</div>
</div>
<!-- popup -->
<div class="popup">
<div>
<h3></h3>
<div></div>
<div style="text-align: right;">
<button type="button" class="alert" data-i18n="cancel"></button>&nbsp;
<button type="submit" data-i18n="ok"></button>
</div>
</div>
</div>
<script src="scripts/utils.js"></script>
<script src="scripts/options.js"></script>
</body>
</html>

119
src/pattern-help.html Normal file
View file

@ -0,0 +1,119 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>FoxyProxy Pattern Help</title>
<link rel="icon" type="image/png" href="/images/icon.svg">
<link rel="stylesheet" href="styles/fontawesome-4.6.3.css">
<link rel="stylesheet" href="styles/app.css">
<style>
td { font-size: 0.9em; }
td:not(:first-of-type) { font-family: monospace; }
</style>
</head>
<body>
<!-- header -->
<div class="prime header">Pattern Help</div>
<!-- main -->
<div class="prime">
<div style="text-align: right;">
<div class="tooltip">
<span data-i18n="patternCheatSheet" class="fp-orange"></span>
<i class="fa fa-info-circle"></i>
<div class="tooltiptext bottom table">
<div class="tooltiptable">
<div class="monospace">*</div>
<div>all domains</div>
<div class="monospace">*.bbc.co.uk</div>
<div>exact domain and all subdomains</div>
<div class="monospace">**.bbc.co.uk</div>
<div>subdomains only (not bbc.co.uk)</div>
<div class="monospace">bbc.co.uk</div>
<div>exact domain only</div>
</div>
<hr>
<div class="tooltiptablefooter">
<div>Black patterns take precedence over white patterns. For example, a black pattern of <span class="monospace">*</span> means nothing will match, regardless of any white patterns.</div>
</div>
</div>
</div>
|
<a href="/pattern-tester.html" target="_blank"><span data-i18n="patternTester"></span> <i class="fa fa-flask"></i></a>
</div>
<p><h3 style="display: inline-block;">TL;DR</h3>: <a href="#examples">show me the examples</a></p>
<h3>What are they?</h3>
<p>Patterns are a way to specify groups of URLs: a pattern matches a specific set of URLs. If a white pattern matches a URL the browser wants to load, the proxy for that white pattern is used to load the URL <strong class="prime tiny warning">unless a black pattern also matches!</strong> Black patterns take precendence over white patterns and are always checked first. If both white and black patterns (in the same proxy) match a URL, that proxy is <strong>not</strong> used to load that URL.</p>
<div class="prime small warning">Patterns are <strong>ignored</strong> unless FoxyProxy is set to <i>Use Enabled Proxies By Patterns and Priority</i>.</div>
<h3>Ordering</h3>
<p>Every URL is compared with the patterns for each proxy. The white/black patterns for the top-most (first) proxy are checked first, then the next set of white/black patterns are checked, and on down the list of proxies until there is a match. If there is no match, Firefox's native proxy settings are used to load the URL. Older versions of FoxyProxy had a <i>Default</i> proxy that acted as a catch-all to matches all URLs. You may still have <i>Default</i> in FoxyProxy if you upgraded from a previous version.
<p>You can re-order the proxies using the arrow buttons as you like, but <strong>the white/black patterns for the top-most (first) proxy are checked first.</strong></p>
<p>If a black pattern matches, the proxy is not used for that URL <i>even if a white pattern also matches</i>. The black pattern takes priority. The URL may, however, load through another proxy you've defined if that proxy has a matching whitelist pattern and no matching blacklist pattern.</p>
<p>The order of white patterns and black patterns within a proxy do not matter.</p>
<h3>Wildcards</h3>
<div class="prime alert">
Because of <a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1337001">Firefox limitations</a>, only URL domains, subdomains, and ports are recognized in patterns. Do not use paths or query parameters in patterns. Example: <strong>*.foxyproxy.com:30053</strong> is OK but not <strong>*.foxyproxy.com:30053/help/*</strong>
</div>
<h4 id="examples">Examples</h4>
<table>
<thead><tr><th>Pattern</th><th>Example Matches</th><th>Example Non-Matches</th></thead>
<tbody>
<tr>
<td><strong>*.foxyproxy.com</strong><br>Match URLs at foxyproxy.com and all subdomains</td>
<td>foxyproxy.com/order.html<br>help.foxyproxy.com/index.html<br>foo.bar.foxyproxy.com<br>twostep.foxyproxy.com</td>
<td>mozilla.com</td>
</tr>
<tr>
<td><strong>.foxyproxy.com</strong><br>Match URLs at foxyproxy.com and all subdomains<br>(same as pattern above)</td>
<td>foxyproxy.com/order.html<br>help.foxyproxy.com/index.html<br>foo.bar.foxyproxy.com<br>twostep.foxyproxy.com</td>
<td>mozilla.com</td>
</tr>
<tr>
<td><strong>**.foxyproxy.com</strong><br>Match URLs <strong>only at subdomains</strong> of foxyproxy.com</td>
<td>help.foxyproxy.com<br>help.foxyproxy.com/index.html<br>foo.bar.foxyproxy.com</td>
<td>foxyproxy.com</td>
</tr>
<tr>
<td><strong>foxyproxy.com</strong><br>Match all URLs at foxyproxy.com but not subdomains</td>
<td>foxyproxy.com<br>foxyproxy.com/index.html</td>
<td>help.foxyproxy.com</td>
</tr>
<tr>
<td><strong>*foo*</strong><br>Match all URLs with a domain containing the letters foo</td>
<td>foo.com<br>foodle.com<br>one.befoo.org</td>
<td>bar.com</td>
</tr>
<tr>
<td><strong>*foo*.com</strong></td>
<td>foo.com<br>foodle.com<br>food.com</td>
<td>one.befoo.org<br>food.org</td>
</tr>
<tr>
<td><strong>g?ogle.*</strong><br>? matches any single character</td>
<td>google.com<br>grogle.org<br>google.com/maps</td>
<td>goog.com</td>
</tr>
<tr>
<td><strong>.catsinsinks.com:8080</strong><br>Port matching!</td>
<td>catsinsinks.com:8080<br>www.catsinsinks.com:8080<br>www.catsinsinks.com:8080/privacy</td>
<td>catinsinks.net</td>
</tr>
</tbody>
</table>
<h4>Notes</h4>
<p>If a wildcard pattern begins with <strong>.</strong> or <strong>*.</strong> then it matches the main domain and all subdomains in a URL.</p>
<p>To match <strong>only</strong> subdomains, use <strong>**</strong> instead of <strong>*</strong> in the beginning. Example: <strong>**.foxyproxy.com</strong> will match <strong>help.foxyproxy.com</strong> but will not match <strong>foxyproxy.com</strong>.</p>
</div>
<script src="scripts/pattern-tester.js"></script>
</body>
</html>

93
src/pattern-tester.html Normal file
View file

@ -0,0 +1,93 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title data-i18n="patternTester">FoxyProxy </title>
<link rel="icon" type="image/png" href="/images/icon.svg">
<link rel="stylesheet" href="styles/fontawesome-4.6.3.css">
<link rel="stylesheet" href="styles/app.css">
<style>
h3 { margin-bottom: 0; }
.prime > h3:first-of-type { margin-top: 0; }
#result { margin: 1em 0 0; }
label { display: inline-block; }
label + span { color: #f30; font-style: italic; margin-left: 0.5em; font-size: 0.9em; }
</style>
</head>
<body>
<!-- header -->
<div class="prime header" data-i18n="patternTester"></div>
<!-- main -->
<div class="prime">
<div style="text-align: right;">
<div class="tooltip">
<span data-i18n="patternCheatSheet" class="fp-orange"></span>
<i class="fa fa-info-circle"></i>
<div class="tooltiptext bottom table">
<div class="tooltiptable">
<div class="monospace">*</div>
<div>all domains</div>
<div class="monospace">*.bbc.co.uk</div>
<div>exact domain and all subdomains</div>
<div class="monospace">**.bbc.co.uk</div>
<div>subdomains only (not bbc.co.uk)</div>
<div class="monospace">bbc.co.uk</div>
<div>exact domain only</div>
</div>
<hr>
<div class="tooltiptablefooter">
<div>Black patterns take precedence over white patterns. For example, a black pattern of <span class="monospace">*</span> means nothing will match, regardless of any white patterns.</div>
</div>
</div>
</div>
|
<a href="/pattern-help.html" target="_blank"><span data-i18n="patternHelp"></span> <i class="fa fa-question-circle"></i></a>
</div>
<h3>Step 1</h3>
<label data-i18n="enterUrl"></label><span data-i18n="enterUrlNote"></span>
<input id="url" type="url" value="https://getfoxyproxy.org" placeholder="https://getfoxyproxy.org">
<h3>Step 2</h3>
<div class="flex">
<div style="flex: 3;">
<label data-i18n="patternDetail"></label><span data-i18n="patternNote"></span>
<input id="pattern" type="text" spellcheck="false">
</div>
<div style="margin-left: 1em;">
<label data-i18n="type"></label>
<select id="type">
<option value="1">Wildcard</option>
<option value="2">Reg Exp</option>
</select>
</div>
<div style="margin-left: 1em;">
<label data-i18n="protocol"></label>
<select id="protocols">
<option value="1">all</option>
<option value="2">http</option>
<option value="4">https</option>
</select>
</div>
</div>
<h3>Step 3</h3>
<p id="result" class="prime small success hide"></p><br>
<label data-i18n="clickTest"></label>
<div style="text-align: right;"><button type="button" data-i18n="test"></button></div>
</div>
<script src="scripts/common.js"></script>
<script src="scripts/utils.js"></script>
<script src="scripts/pattern-tester.js"></script>
</body>
</html>

202
src/patterns.html Normal file
View file

@ -0,0 +1,202 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title data-i18n="patterns">FoxyProxy </title>
<link rel="icon" type="image/png" href="/images/icon.svg">
<link rel="stylesheet" href="styles/fontawesome-4.6.3.css">
<link rel="stylesheet" href="styles/app.css">
<style>
td i.fa { font-size: 1.5em; color: #ccc; }
td i.fa:hover { font-size: 1.5em; color: #f90; }
tr { opacity: 1; transition: all 0.5s ease-in-out; }
td { padding: 0.2em 0.5em; }
td:nth-of-type(1), td:nth-of-type(2) { min-width: 10em; max-width: 15em; padding: 0 0.5em; }
td:nth-of-type(3), td:nth-of-type(4), td:nth-of-type(5) { width: 5em; text-align: center; }
td:nth-of-type(6) { width: 7em; }
input[type="text"], input[type="text"]:focus {
background-color: transparent;
box-shadow: none;
height: auto;
margin: 0;
padding: 0;
border: 1px solid transparent;
}
input[type="text"]:focus {
background-color: #f8f8ff;
}
input:invalid, input:invalid:focus {
background-color: #fff;
border-color: #f90;
}
select {
background: #f5fffa;
font-size: 0.9em;
height: auto;
margin: 0;
padding: 0.1em;
}
#result { margin: 1em 0 0; }
label[for="file"] { margin: 0; }
#links { float: right; }
hr { color: white; }
.addbuttoncontainer {
margin: 1em 0 2em;
text-align: center;
font-size: 0.9em;
}
.addbutton {
margin-left: 1em;
vertical-align: initial;
}
</style>
</head>
<body>
<!-- header -->
<div class="prime header" data-i18n="editPatterns"></div>
<!-- spinner --> <!-- options, patterns, log -->
<div class="spinner on"><i class="fa fa-refresh fa-spin"></i></div>
<!-- error -->
<div id="error" class="prime hide">
<h3 data-i18n="errorWas"></h3>
<button type="button" data-i18n="back">&#x25c1; </button>
</div>
<!-- main -->
<div class="prime main">
<div class="flex">
<div class="prime warning small" style="flex: 1.5">
<span data-i18n="activeNote"></span> <strong><span data-i18n="modePatterns"></span></strong>
</div>
<div style="text-align: right;">
<div class="tooltip">
<span data-i18n="patternCheatSheet" class="fp-orange"></span>
<i class="fa fa-info-circle"></i>
<div class="tooltiptext bottom table">
<div class="tooltiptable">
<div class="monospace">*</div>
<div>all domains</div>
<div class="monospace">*.bbc.co.uk</div>
<div>exact domain and all subdomains</div>
<div class="monospace">**.bbc.co.uk</div>
<div>subdomains only (not bbc.co.uk)</div>
<div class="monospace">bbc.co.uk</div>
<div>exact domain only</div>
</div>
<hr>
<div class="tooltiptablefooter">
<div>Black patterns take precedence over white patterns. For example, a black pattern of <span class="monospace">*</span> means nothing will match, regardless of any white patterns.</div>
</div>
</div>
</div>
|
<a href="/pattern-tester.html" target="_blank"><span data-i18n="patternTester"></span> <i class="fa fa-flask"></i></a>
|
<a href="/pattern-help.html" target="_blank">
<span data-i18n="patternHelp"></span>
</a>
</div>
</div>
<h3 data-i18n="whitePatterns"></h3>
<!-- table template -->
<div class="scroll" style="margin-bottom: 2em;">
<table style="width: 100%;">
<thead>
<tr>
<th data-i18n="name"></th><th data-i18n="pattern"></th><th data-i18n="type"></th>
<th>HTTP/s</th><th data-i18n="active"></th><th></th>
</tr>
<!-- template -->
<tr class="template">
<td><input type="text" spellcheck="false"></td>
<td><input type="text" spellcheck="false" required></td>
<td>
<select name="type">
<option value="1">Wildcard</option>
<option value="2">Reg Exp</option>
</select>
</td>
<td>
<select name="protocol">
<option value="1">all</option>
<option value="2">http</option>
<option value="4">https</option>
</select>
</td>
<td>
<input type="checkbox" class="switch" id=""><label for=""></label>
</td>
<td style="text-align: right;">
<button type="button" class="plain hide" data-i18n="imported|title"><i class="fa fa-download"></i></button>
<button type="button" class="plain" data-i18n="patternTester|title"><i class="fa fa-flask"></i></button>
<!-- <button type="button" class="plain" data-i18n="edit|title"><i class="fa fa-pencil"></i></button> -->
<button type="button" class="plain" data-i18n="delete|title"><i class="fa fa-trash"></i></button>
</td>
</tr>
</thead>
<tbody></tbody>
</table>
</div>
<div class="addbuttoncontainer">
<span data-i18n="addWhitelist"></span>
<div class="tooltip"><i class="fa fa-info-circle"></i><span class="tooltiptext center" data-i18n="addWhitelistTip"></span></div>
<button type="button" class="small addbutton" data-i18n="add" data-white></button>
</div>
<h3 data-i18n="blackPatterns"></h3>
<div class="scroll">
<table style="width: 100%;">
<thead>
<tr>
<th data-i18n="name"></th><th data-i18n="pattern"></th><th data-i18n="type"></th>
<th>HTTP/s</th><th data-i18n="active"></th><th></th>
</tr>
</thead>
<tbody></tbody>
</table>
</div>
<div class="addbuttoncontainer">
<span data-i18n="addBlacklist"></span>
<div class="tooltip"><i class="fa fa-info-circle"></i><span class="tooltiptext center" data-i18n="addBlacklistTip"></span></div>
<button type="button" class="small addbutton" data-i18n="add" data-black></button>
</div>
<div class="flex">
<div>
<input type="file" id="file" accept=".json">
<label for="file" class="button" data-i18n="importPatterns"></label>
<button type="button" data-i18n="exportPatterns"></button>
</div>
<div style="text-align: right;">
<button type="button" class="alert" data-i18n="cancel"></button>
<button type="button" data-i18n="newWhite"></button>
<button type="button" data-i18n="newBlack"></button>
<button type="submit" data-i18n="save"></button>
</div>
</div>
<p id="result" class="prime small success hide"></p>
</div>
<script src="scripts/common.js"></script>
<script src="scripts/utils.js"></script>
<script src="scripts/patterns.js"></script>
</body>
</html>

64
src/popup.html Normal file
View file

@ -0,0 +1,64 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<link rel="stylesheet" href="styles/app.css">
<style>
body { padding: 0.4em; animation: none; min-width: 25em; }
ul.scroll { margin: 0; padding: 0; max-height: 20em; }
li { cursor: pointer; border-radius: 10px; padding-left: 0.2em; }
li:hover { background-color: #ffebcd; }
li span { display: inline-block; vertical-align: text-bottom; }
li span:nth-of-type(1) { width: 10em; margin-right: 1em; }
li span:nth-of-type(2) { color: #aaa; font-style: italic; font-size: 0.9em;}
li:first-of-type { color: #f80; }
#disabled { color: red; }
li::before {
content: '\2714';
width: 1em;
display: inline-block;
vertical-align: text-bottom;
margin-right: 0.2em;
color: transparent;
font-weight: bold;
}
li.on::before {
color: inherit;
}
button:first-of-type { margin-left: 0; }
</style>
</head>
<body>
<!-- header -->
<div class="prime header browserPopup">FoxyProxy</div>
<!-- error -->
<div id="error" class="prime hide"><h5 data-i18n="errorWas"></h5></div>
<!-- main -->
<div class="prime" style="margin: 0;">
<ul id="scroll" class="scroll">
<li id="patterns" data-i18n="modePatterns"></li>
<!-- template -->
<li class="template ellipsis"><span class="ellipsis"></span><span class="ellipsis"></span></li>
<li id="disabled" data-i18n="modeDisabled"></li>
</ul>
<div style="margin-top: 1em; text-align: center;">
<button type="button" data-i18n="options"></button>
<button type="button" data-i18n="myIP"></button>
<button type="button" data-i18n="log"></button>
</div>
</div>
<script src="scripts/utils.js"></script>
<script src="scripts/popup.js"></script>
</body>
</html>

193
src/proxy.html Normal file
View file

@ -0,0 +1,193 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title data-i18n="add">FoxyProxy </title>
<link rel="icon" type="image/png" href="/images/icon.svg">
<link rel="stylesheet" href="styles/fontawesome-4.6.3.css">
<link rel="stylesheet" href="styles/app.css">
<style>
.main > div:nth-child(1) { flex: 1; margin-right: 1em; }
.main > div:nth-child(2) { flex: 1; }
input[type], select { margin-top: 0.3em; }
.onOff > label:first-of-type { flex: 0; flex-grow: 1; margin: 0 1em 0.5em 0; }
.onOff > div { flex: 0; }
.na { margin-top: 1.5em; }
.onOff, .pac, .na { display: none; }
input[name="nav"] { display: none; }
#http:checked ~ div .onOff:not(.dns),
#https:checked ~ div .onOff:not(.dns),
#socks4:checked ~ div .onOff:not(.dns) {
display: flex;
}
#socks5:checked ~ div .onOff { display: flex; }
#pac:checked ~ div .pac,
#wpad:checked ~ div .pac {
display: block;
}
#pac:checked ~ div div.na,
#wpad:checked ~ div div.na,
#system:checked ~ div div.na {
display: block;
}
#pac:checked ~ div .proxyData,
#wpad:checked ~ div .proxyData,
#system:checked ~ div .proxyData,
#direct:checked ~ div div.proxyData,
#pac:checked ~ div button:not(:first-of-type),
#wpad:checked ~ div button:not(:first-of-type),
#system:checked ~ div button:not(:first-of-type) {
display: none;
}
#http:checked ~ div .patternShortcuts,
#https:checked ~ div .patternShortcuts,
#socks4:checked ~ div .patternShortcuts,
#socks5:checked ~ div .patternShortcuts,
#direct:checked ~ div .patternShortcuts {
display: flex;
}
#pac:checked ~ div .patternShortcutsContainer,
#wpad:checked ~ div .patternShortcutsContainer,
#system:checked ~ div .patternShortcutsContainer {
display: none;
}
#direct:checked ~ div .patternShortcutsContainer {
display: block;
}
</style>
</head>
<body>
<!-- Navigation -->
<input type="radio" name="nav" id="http">
<input type="radio" name="nav" id="https" checked>
<input type="radio" name="nav" id="socks5">
<input type="radio" name="nav" id="socks4">
<input type="radio" name="nav" id="direct">
<input type="radio" name="nav" id="pac">
<input type="radio" name="nav" id="wpad">
<input type="radio" name="nav" id="system">
<!-- header -->
<div class="prime header" data-i18n="options"></div>
<!-- main -->
<div class="prime">
<div class="main flex">
<!-- left column -->
<div>
<div>
<label data-i18n="title"></label>
<input id="proxyTitle" type="text" spellcheck="false" placeholder="title">
<label data-i18n="color"></label>
<input id="colorChooser" type="text" style="text-align: center;">
</div>
<!-- SOCKS5 -->
<div class="flex onOff dns">
<label>Send DNS through SOCKS5 proxy</label>
<div>
<input type="checkbox" class="switch" id="proxyDNS" checked><label for="proxyDNS"></label>
</div>
</div>
<div class="patternShortcutsContainer notForBasic notForEdit">
<label data-i18n="patternShortcuts" class="notForBasic notForEdit"></label>
<div class="prime warning">
<div class="patternShortcuts flex onOff">
<label data-i18n="active"></label>
<div>
<input type="checkbox" class="switch" id="proxyActive" checked><label for="proxyActive"></label>
</div>
</div>
<div class="patternShortcuts onOff">
<label><span data-i18n="addWhitelist"></span>
<div class="tooltip"><i class="fa fa-info-circle"></i><span class="tooltiptext" data-i18n="addWhitelistTip"></span></div></label>
<div>
<input type="checkbox" class="switch" id="whiteAll" checked><label for="whiteAll"></label>
</div>
</div>
<div class="patternShortcuts onOff">
<label><span data-i18n="noLocal"></span>
<div class="tooltip"><i class="fa fa-info-circle"></i><span class="tooltiptext" data-i18n="addBlacklistTip"></span></div></label>
<div>
<input type="checkbox" class="switch" id="blackAll"><label for="blackAll"></label>
</div>
</div>
</div>
</div>
</div>
<!-- right column -->
<div>
<div class="rightData">
<label data-i18n="proxyType"></label>
<select id="proxyType">
<option value="1" selected>HTTP</option>
<option value="2">HTTPS/SSL</option>
<option value="3">SOCKS5</option>
<option value="4">SOCKS4</option>
<option value="6">PAC URL</option>
<option value="7">WPAD</option>
<option value="8">System (use system settings)</option>
<option value="5">Direct (no proxy)</option>
</select>
<div class="proxyData">
<label data-i18n="ip"></label> <i class="fa fa-star"></i>
<input id="proxyAddress" type="text" spellcheck="false" placeholder="111.111.111.111, www.example.com">
<label data-i18n="port"></label> <i class="fa fa-star"></i>
<input id="proxyPort" type="text" placeholder="3128">
<label data-i18n="username"></label>
<input id="proxyUsername" type="text" spellcheck="false" placeholder="username">
<label data-i18n="password"></label>
<button type="button" class="plain" data-i18n="togglePW|title"><i class="fa fa-eye"></i></button>
<input id="proxyPassword" type="password" spellcheck="false" placeholder="*****">
</div>
</div>
<!-- PAC/WPAD -->
<div class="pac">
<label>URL</label> <i class="fa fa-star"></i>
<input id="pacURL" type="text" placeholder="PAC URL">
</div>
<div class="prime alert small na">
<h3>Not supported</h3>
<p>Due to Firefox limitation, <a href="https://bugzilla.mozilla.org/show_bug.cgi?id=1396485" target="_blank">PAC</a>, <a href="https://bugzilla.mozilla.org/show_bug.cgi?id=1319631" target="_blank">WPAD</a>, and <a href="https://bugzilla.mozilla.org/show_bug.cgi?id=1319630" target="_blank">System Settings</a> are currently not supported, but they are due to be added.</p>
</div>
</div>
</div>
<div style="text-align: right;">
<button type="button" class="alert" data-i18n="cancel"></button>
<button type="button" data-i18n="saveAdd"></button>
<button type="button" class="notForBasic" data-i18n="saveEditPattern"></button>
<button type="submit" data-i18n="save"></button>
</div>
</div>
<script src="scripts/jscolor-2.0.5.js"></script><!-- only used here -->
<script src="scripts/utils.js"></script>
<script src="scripts/proxy.js"></script>
</body>
</html>

26
src/scripts/about.js Normal file
View file

@ -0,0 +1,26 @@
'use strict';
// ----------------- Internationalization ------------------
document.querySelectorAll('[data-i18n]').forEach(node => {
let [text, attr] = node.dataset.i18n.split('|');
text = chrome.i18n.getMessage(text);
attr ? node[attr] = text : node.appendChild(document.createTextNode(text));
});
// ----------------- /Internationalization -----------------
document.addEventListener('keyup', evt => {
if (evt.keyCode === 27) {
location.href = '/options.html';
}
});
const manifest = chrome.runtime.getManifest();
document.querySelector('#version').textContent = manifest.version;
document.querySelector('#edition').textContent = 'FoxyProxy ' + (FOXYPROXY_BASIC ? 'Basic' : 'Standard');
document.querySelector('button').addEventListener('click', () => location.href = '/options.html');
// --- remove nodes completely for FP Basic
FOXYPROXY_BASIC && document.querySelectorAll('.notForBasic').forEach(item => item.remove());
// --- welcome on install/update
location.search === '?welcome' && document.querySelector('.welcome').classList.remove('hide');

275
src/scripts/background.js Normal file
View file

@ -0,0 +1,275 @@
'use strict';
// ----- global
//const FF = typeof browser !== 'undefined'; // for later
let storageArea; // keeping track of sync
let bgDisable = false;
// Start in disabled mode because it's going to take time to load setings from storage
let activeSettings = {mode: 'disabled'};
// ----------------- logger --------------------------------
let logger;
function getLog() { return logger; }
class Logger {
constructor(size = 100, active = false) {
this.size = size;
this.matchedList = [];
this.unmatchedList = [];
this.active = active;
}
clear() {
this.matchedList = [];
this.unmatchedList = [];
}
addMatched(item) {
this.matchedList.push(item);
this.matchedList = this.matchedList.slice(-this.size); // slice to the ending size entries
}
addUnmatched(item) {
this.unmatchedList.push(item);
this.unmatchedList = this.unmatchedList.slice(-this.size); // slice to the ending size entries
}
updateStorage() {
this.matchedList = this.matchedList.slice(-this.size); // slice to the ending size entries
this.unmatchedList = this.unmatchedList.slice(-this.size); // slice to the ending size entries
storageArea.set({logging: {size: this.size, active: this.active} });
}
}
// ----------------- /logger -------------------------------
// --- registering persistent listener
// https://bugzilla.mozilla.org/show_bug.cgi?id=1359693 ...Resolution: --- ? WONTFIX
chrome.webRequest.onAuthRequired.addListener(sendAuth, {urls: ['*://*/*']}, ['blocking']);
chrome.webRequest.onCompleted.addListener(clearPending, {urls: ['*://*/*']});
chrome.webRequest.onErrorOccurred.addListener(clearPending, {urls: ['*://*/*']});
chrome.runtime.onInstalled.addListener((details) => { // Installs Update Listener
// reason: install | update | browser_update | shared_module_update
switch (true) {
case details.reason === 'install':
case details.reason === 'update' && /^(3\.|4\.|5\.5|5\.6)/.test(details.previousVersion):
chrome.tabs.create({url: '/about.html?welcome'});
break;
}
});
// ----------------- User Preference -----------------------
chrome.storage.local.get(null, result => {
// browserVersion is not used & runtime.getBrowserInfo() is not supported on Chrome
// sync is NOT set or it is false, use this result ELSE get it from storage.sync
// check both storage on start-up
if (!Object.keys(result)[0]) { // local is empty, check sync
chrome.storage.sync.get(null, syncResult => {
if (!Object.keys(syncResult)[0]) { // sync is also empty
storageArea = chrome.storage.local; // set storage as local
process(result);
}
else {
chrome.storage.local.set({sync: true}); // save sync as true
storageArea = chrome.storage.sync; // set storage as sync
process(syncResult);
}
});
}
else {
storageArea = result.sync ? chrome.storage.sync : chrome.storage.local; // cache for subsequent use
!result.sync ? process(result) : chrome.storage.sync.get(null, process);
}
});
// ----------------- /User Preference ----------------------
function process(settings) {
let update;
let prefKeys = Object.keys(settings);
if (!settings || !prefKeys[0]) { // create default settings if there are no settings
// default
settings = {
mode: 'disabled',
logging: {
size: 100,
active: false
}
};
update = true;
}
// update storage then add Change Listener
if (update) {
storageArea.set(settings, () => chrome.storage.onChanged.addListener(storageOnChanged));
}
else {
chrome.storage.onChanged.addListener(storageOnChanged);
}
logger = settings.logging ? new Logger(settings.logging.size, settings.logging.active) : new Logger();
setActiveSettings(settings);
console.log('background.js: loaded proxy settings from storage.');
}
function storageOnChanged(changes, area) {
// console.log(changes);
// update storageArea on sync on/off change from options
if (changes.hasOwnProperty('sync') && changes.sync.newValue !== changes.sync.oldValue) {
storageArea = changes.sync.newValue ? chrome.storage.sync : chrome.storage.local;
}
// update logger from log
if (Object.keys(changes).length === 1 && changes.logging) { return; }
// mode change from bg
if(changes.mode && changes.mode.newValue === 'disabled' && bgDisable) {
bgDisable = false;
return;
}
// default: changes from popup | options
storageArea.get(null, setActiveSettings);
}
function proxyRequest(requestInfo) {
return findProxyMatch(requestInfo.url, activeSettings);
}
function setActiveSettings(settings) {
browser.proxy.onRequest.hasListener(proxyRequest) && browser.proxy.onRequest.removeListener(proxyRequest);
const pref = settings;
const prefKeys = Object.keys(pref).filter(item => !['mode', 'logging', 'sync'].includes(item)); // not for these
// --- cache credentials in authData (only those with user/pass)
prefKeys.forEach(id => pref[id].username && pref[id].password &&
(authData[pref[id].address] = {username: pref[id].username, password: pref[id].password}) );
const mode = settings.mode;
activeSettings = { // global
mode,
proxySettings: []
};
if (mode === 'disabled' || (FOXYPROXY_BASIC && mode === 'patterns')){
setDisabled();
return;
}
if (['patterns', 'random', 'roundrobin'].includes(mode)) { // we only support 'patterns' ATM
// filter out the inactive proxy settings
prefKeys.forEach(id => pref[id].active && activeSettings.proxySettings.push(pref[id]));
activeSettings.proxySettings.sort((a, b) => a.index - b.index); // sort by index
function processPatternObjects(patternObjects) {
return patternObjects.reduce((accumulator, patternObject) => {
patternObject = Utils.processPatternObject(patternObject);
patternObject && accumulator.push(patternObject);
return accumulator;
}, []);
}
// Filter out the inactive patterns. that way, each comparison
// is a little faster (doesn't even know about inactive patterns). Also convert all patterns to reg exps.
for (const idx in activeSettings.proxySettings) {
activeSettings.proxySettings[idx].blackPatterns = processPatternObjects(activeSettings.proxySettings[idx].blackPatterns);
activeSettings.proxySettings[idx].whitePatterns = processPatternObjects(activeSettings.proxySettings[idx].whitePatterns);
}
browser.proxy.onRequest.addListener(proxyRequest, {urls: ["<all_urls>"]});
Utils.updateIcon('images/icon.svg', null, 'patterns', true);
console.log(activeSettings, "activeSettings in patterns mode");
}
else {
// User has selected a proxy for all URLs (not patterns, disabled, random, round-robin modes).
// mode is set to the proxySettings id to use for all URLs.
if (settings[mode]) {
activeSettings.proxySettings = [settings[mode]];
browser.proxy.onRequest.addListener(proxyRequest, {urls: ["<all_urls>"]});
const tmp = Utils.getProxyTitle(settings[mode]);
Utils.updateIcon('images/icon.svg', settings[mode].color, tmp, false, tmp, false);
console.log(activeSettings, "activeSettings in fixed mode");
}
else {
// This happens if user deletes the current proxy and mode is "use this proxy for all URLs"
// Don't remove this block.
bgDisable = true;
storageArea.set({mode: 'disabled'}); // only in case of error, otherwise mode is already set
setDisabled();
console.error(`Error: mode is set to ${mode} but no active proxySetting is found with that id. Disabling Due To Error`);
}
}
}
function setDisabled(isError) {
browser.proxy.onRequest.hasListener(proxyRequest) && browser.proxy.onRequest.removeListener(proxyRequest);
chrome.runtime.sendMessage({mode: 'disabled'}); // Update the options.html UI if it's open
Utils.updateIcon('images/icon-off.svg', null, 'disabled', true);
console.log('******* disabled mode');
}
// ----------------- Proxy Authentication ------------------
// ----- session global
let authData = {};
let authPending = {};
async function sendAuth(request) {
// Do nothing if this not proxy auth request:
// https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/API/webRequest/onAuthRequired
// "Take no action: the listener can do nothing, just observing the request. If this happens, it will
// have no effect on the handling of the request, and the browser will probably just ask the user to log in."
if (!request.isProxy) return;
// --- already sent once and pending
if (authPending[request.requestId]) { return {cancel: true}; }
// --- authData credentials not yet populated from storage
if(!Object.keys(authData)[0]) { await getAuth(request); }
// --- first authentication
// According to https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/API/webRequest/onAuthRequired :
// "request.challenger.host is the requested host instead of the proxy requesting the authentication"
// But in my tests (Fx 69.0.1 MacOS), it is indeed the proxy requesting the authentication
// TODO: test in future Fx releases to see if that changes.
// console.log(request.challenger.host, "challenger host");
if (authData[request.challenger.host]) {
authPending[request.requestId] = 1; // prevent bad authentication loop
return {authCredentials: authData[request.challenger.host]};
}
// --- no user/pass set for the challenger.host, leave the authentication to the browser
}
async function getAuth(request) {
await new Promise(resolve => {
chrome.storage.local.get(null, result => {
const host = result.hostData[request.challenger.host];
if (host && host.username) { // cache credentials in authData
authData[host] = {username: host.username, password: host.password};
}
resolve();
});
});
}
function clearPending(request) {
if(!authPending[request.requestId]) { return; }
if (request.error) {
const host = request.proxyInfo && request.proxyInfo.host ? request.proxyInfo.host : request.ip;
Utils.notify(chrome.i18n.getMessage('authError', host));
console.error(request.error);
return; // auth will be sent again
}
delete authPending[request.requestId]; // no error
}

63
src/scripts/common.js Normal file
View file

@ -0,0 +1,63 @@
'use strict';
// ----------------- Pattern Check ------------------
function checkPattern(pattern, type) {
const pat = pattern.value;
if (!pat) {
pattern.classList.add('invalid');
pattern.focus();
showResult(chrome.i18n.getMessage('errorEmpty'), true);
return;
}
const patternTypeSet = {
'1': 'wildcard',
'2': 'regex'
}
let regex;
switch (patternTypeSet[type.value]) {
// RegEx
case 'regex':
try { regex = new RegExp(pat); }
catch (e) {
pattern.classList.add('invalid');
showResult(e.message, true);
return false;
}
break;
// wildcard
default:
if (pat.includes('/')) {
pattern.classList.add('invalid');
showResult(chrome.i18n.getMessage('errorSlash'), true);
return false;
}
try { regex = new RegExp(Utils.wildcardToRegExp(pat)); }
catch (e) {
pattern.classList.add('invalid');
showResult(e.message, true);
return false;
}
}
// --- pattern is valid
return regex;
}
function showResult(text, fail) {
fail && result.classList.add('alert');
result.textContent = text;
result.classList.remove('hide');
}

View file

@ -0,0 +1,240 @@
'use strict';
// ----------------- Internationalization ------------------
document.querySelectorAll('[data-i18n]').forEach(node => {
let [text, attr] = node.dataset.i18n.split('|');
text = chrome.i18n.getMessage(text);
attr ? node[attr] = text : node.appendChild(document.createTextNode(text));
});
// ----------------- /Internationalization -----------------
document.addEventListener('keyup', evt => {
if (evt.keyCode === 27) {
location.href = '/options.html';
}
});
// ----------------- Spinner -------------------------------
const spinner = document.querySelector('.spinner');
function hideSpinner() {
spinner.classList.remove('on');
setTimeout(() => { spinner.style.display = 'none'; }, 600);
}
function showSpinner() {
spinner.style.display = 'flex';
spinner.classList.add('on');
}
// ----------------- /spinner ------------------------------
document.addEventListener('DOMContentLoaded', () => {
hideSpinner();
});
// addEventListener for all buttons & handle together
document.querySelectorAll('button').forEach(item => item.addEventListener('click', process));
let proxiesAdded = 0; // Global to this module in case user does multiple bulk imports before closing import-bulk.html
function process(e) {
switch (this.id || this.dataset.i18n) {
case 'back': location.href = '/options.html'; break;
case 'import': imp0rt(); break;
}
}
function imp0rt() {
const {parsedList, skippedList} = parseList(document.getElementById('proxyList').value);
if (parsedList.length > 0) {
if (document.querySelector('#overwrite').checked) {
if (confirm(chrome.i18n.getMessage('confirmOverwrite'))) {
showSpinner();
chrome.storage.local.clear(() => chrome.storage.sync.clear(() => {
hideSpinner();
storeProxies(parsedList);
}));
}
else {
return;
}
}
else {
storeProxies(parsedList);
}
}
if (skippedList.length > 0) {
alert(`${chrome.i18n.getMessage('importsSkipped', [skippedList.length + "", skippedList.toString()])}`);
}
if (parsedList.length > 0) {
alert(`${chrome.i18n.getMessage('importSucceeded', [parsedList.length])}`);
}
location.href = '/options.html';
}
function parseList(rawList) {
const parsedList = [], skippedList = [], colors = ['#663300', '#284B63', '#C99656', '#7B758C', '#171E1D'];
if (!rawList) {
return {parsedList, skippedList};
}
rawList.split('\n').forEach((item) => {
if (!item) {
return; // continue to next
}
let p, patternIncludesAll = true, patternExcludesIntranet = true;
// Is this line simple or complete format?
let protocol = item.match(/.+:\/\//); // null for strings like 127.0.0.1:3128 (simple format)
if (protocol) {
// This line is uses 'complete' format
let url;
try {
// In Firefox 78.0.2, the built-in javascript URL class will not parse URLs with custom schemes/protocols
// like socks://127.0.0.1. However, Chrome 84.0.4147.89 and Node 14.5.0 both do. In order to be compatible
// with Firefox, let's replace the scheme/protocol with 'http'. We could also instead write our own parsing
// logic with a regular expression, but that does not seems necessary.
if (protocol[0] !== 'http://' && protocol[0] !== 'https://') {
item = 'http://' + item.substring(protocol[0].length);
url = new URL(item);
protocol = protocol[0].substring(0, protocol[0].length-2); //strip ending //
}
else {
url = new URL(item);
protocol = url.protocol;
}
}
catch (e) {
console.log(e);
// URL couldn't be parsed
skippedList.push(item);
return; // continue to next
}
const type = protocol === 'proxy:' || protocol === 'http:' ? PROXY_TYPE_HTTP :
protocol === 'ssl:' || protocol === 'https:' ? PROXY_TYPE_HTTPS :
protocol === 'socks:' || protocol === 'socks5:' ? PROXY_TYPE_SOCKS5 :
protocol === 'socks4:' ? PROXY_TYPE_SOCKS4 : -1;
if (type === -1) {
console.log("unknown protocol");
skippedList.push(item);
return; // continue to next
}
// If color not specified in the URL, then rotate among the ones in the colors array.
const color = url.searchParams.get('color') ?
('#' + url.searchParams.get('color')) : colors[parsedList.length % colors.length];
const title = url.searchParams.get('title');
const countryCode = url.searchParams.get('countryCode') || url.searchParams.get('cc');
const country = url.searchParams.get('country') || countryCode;
// If paramName url param is not specified or it's specified and not 'false', then paramValue should equal true.
// We assume true in case the param is absent, which may be counterintuitive, but this fcn is used for params that
// we want to assume true when absent.
function parseBooleanParam(url, paramName, aliasParamName) {
const paramValue = url.searchParams.get(paramName) || (aliasParamName && url.searchParams.get(aliasParamName));
return paramValue ? !(paramValue.toLowerCase() === 'false') : true;
}
const proxyDNS = parseBooleanParam(url, 'proxyDns');
const active = parseBooleanParam(url, 'enabled', 'active');
patternIncludesAll = parseBooleanParam(url, 'patternIncludesAll');
patternExcludesIntranet = parseBooleanParam(url, 'patternExcludesIntranet');
// the URL class sets port === '' if not specified on the URL or it's an invalid port e.g. contains alpha chars
let port = url.port;
if (port === '') {
// Default ports are 3128 for HTTP proxy, 443 for tls/ssl/https proxy, 1080 for socks4/5
port = type === PROXY_TYPE_HTTP ? 3128 : type === PROXY_TYPE_HTTPS ? 443 : 1080;
}
console.log(url);
// the URL class sets username and password === '' if not specified on the URL
p = {type, username: url.username, password: url.password, address: url.hostname, port, color, title, proxyDNS, active, countryCode, country};
}
else {
// simple
const splitItem = item.split(':');
// Split always returns an array no matter what
p = {address: splitItem[0], port: splitItem[1], username: splitItem[2], password: splitItem[3], color: colors[parsedList.length % colors.length]};
}
const proxy = makeProxy(p, patternIncludesAll, patternExcludesIntranet);
if (proxy) {
parsedList.push(proxy);
}
else {
skippedList.push(item);
}
}); //forEach
return {parsedList, skippedList};
}
function makeProxy({type = PROXY_TYPE_HTTP, username, password, address, port, color, title, proxyDNS, active = true, countryCode, country},
patternIncludesAll, patternExcludesIntranet) {
port = port*1; // convert to digit
if (!port || port < 1) { // is port NaN or less than 1
console.log("port is NaN or less than 1");
return null;
}
// strip bad chars from all input except username, password, type, proxyDNS, and active
// (those last 3 are forced to boolean types before we are called)
// If we do strip bad chars from usernams or password, auth could fail.
address = Utils.stripBadChars(address);
color = Utils.stripBadChars(color);
title = Utils.stripBadChars(title);
countryCode = Utils.stripBadChars(countryCode);
country = Utils.stripBadChars(country);
if (!address) {
console.log("no address");
return null;
}
const proxy = {type, address, port, color, active};
// Only set the properties needed. null and undefined props seem to be saved if set, so don't set them.
function setPropertyIfHasValue(prop, value, proxy) {
if (value || value === 0) {
proxy[prop] = value;
}
}
setPropertyIfHasValue('username', username, proxy);
setPropertyIfHasValue('password', password, proxy);
setPropertyIfHasValue('title', title, proxy);
setPropertyIfHasValue('cc', countryCode, proxy);
setPropertyIfHasValue('country', country, proxy);
if (type === PROXY_TYPE_SOCKS5) {
// Only set if socks5
proxy.proxyDNS = proxyDNS;
}
if (FOXYPROXY_BASIC) {
proxy.whitePatterns = proxy.blackPatterns = [];
}
else {
proxy.whitePatterns = patternIncludesAll ? [PATTERN_ALL_WHITE] : [];
proxy.blackPatterns = patternExcludesIntranet ? [...blacklistSet] : [];
}
return proxy;
}
function storeProxies(parsedList) {
const sync = localStorage.getItem('sync') === 'true';
const storageArea = !sync ? chrome.storage.local : chrome.storage.sync;
for (const idx in parsedList) {
const proxy = parsedList[idx];
console.log(proxy);
// Get the nextIndex given to us by options.js and add by the number of proxies we've added.
// This ensures this proxy setting is last in list of all proxy settings.
proxy.index = (localStorage.getItem('nextIndex')) + (++proxiesAdded);
storageArea.set({[Utils.getUniqueId()]: proxy}, () => {
console.log(`stored proxy`);
});
}
}

440
src/scripts/import.js Normal file
View file

@ -0,0 +1,440 @@
'use strict';
// ----------------- Internationalization ------------------
document.querySelectorAll('[data-i18n]').forEach(node => {
let [text, attr] = node.dataset.i18n.split('|');
text = chrome.i18n.getMessage(text);
attr ? node[attr] = text : node.appendChild(document.createTextNode(text));
});
// ----------------- /Internationalization -----------------
document.addEventListener('keyup', evt => {
if (evt.keyCode === 27) {
close();
}
});
// ----------------- Spinner -------------------------------
const spinner = document.querySelector('.spinner');
function hideSpinner() {
spinner.classList.remove('on');
setTimeout(() => { spinner.style.display = 'none'; }, 600);
}
function showSpinner() {
spinner.style.display = 'flex';
spinner.classList.add('on');
}
// ----------------- /spinner ------------------------------
hideSpinner();
// addEventListener for all buttons & handle together
document.querySelectorAll('button').forEach(item => item.addEventListener('click', process));
document.querySelectorAll('input[type="file"]').forEach(item => item.addEventListener('change', process));
function process(e) {
switch (this.id || this.dataset.i18n) {
// click
case 'back': close(); break;
case 'export': Utils.exportFile(); break;
case 'togglePW|title':
const inp = this.previousElementSibling;
inp.type = inp.type === 'password' ? 'text' : 'password';
break;
// change
case 'importFP':
showSpinner();
foxyProxyImport();
break;
case 'importJson':
showSpinner();
Utils.importFile(e.target.files[0], ['application/json'], 1024*1024*10, 'json', importJson); // 10mb
hideSpinner(); // hide spinner in case importJson() was not called due to error
break;
case 'importXml':
showSpinner();
Utils.importFile(e.target.files[0], ['text/xml'], 1024*1024*10, 'xml', importXml); // 10mb
hideSpinner(); // hide spinner in case importXml() was not called due to error
break;
}
}
function importJson(result) {
if (!result) { // user cancelled
hideSpinner();
return;
}
// --- convert pre v7.0 export to db format
if (result.hasOwnProperty('proxySettings')) {
result = prepareForStorage(result);
}
save(result, end);
}
function save(result, callback) {
// Remove 'browserVersion', 'foxyProxyVersion', 'foxyProxyEdition' if they exist
// We don't need those imported.
delete result.browserVersion;
delete result.foxyProxyVersion;
delete result.foxyProxyEdition;
const storageArea = result.sync ? chrome.storage.sync : chrome.storage.local;
// clear the storages and set new
chrome.storage.local.clear(() => chrome.storage.sync.clear(() => {
if (result.sync) {
chrome.storage.local.set({sync: true}); // save sync state
delete result.sync;
}
storageArea.set(result, callback); // save to target
}));
}
function end() {
hideSpinner();
Utils.notify(chrome.i18n.getMessage('importEnd'));
location.href = '/options.html';
}
function importXml(doc) {
let lastResortFound = false;
// base format
const pref = {
mode: 'disabled',
logging: {
size: 100,
active: false
}
};
const FP = doc.querySelector('foxyproxy');
if (!FP) {
// Don't use Utils.notify() because at least on macOS,
// the message is too long and cut off
alert('There is an error with the XML file (missing <foxyproxy ....>)');
hideSpinner();
return;
}
const mode = FP.getAttribute('mode');
mode && (pref.mode = mode);
const badModes = [];
const proxies = doc.getElementsByTagName('proxy');
let patternsEdited = false;
const LASTRESORT = 'k20d21508277536715';
const DEFAULT_PROXY_SETTING = {
index: Number.MAX_SAFE_INTEGER,
id: LASTRESORT,
active: true,
title: 'Default',
notes: 'These are the settings that are used when no patterns match a URL.',
color: '#0055E5',
type: PROXY_TYPE_NONE,
whitePatterns: [PATTERN_ALL_WHITE],
blackPatterns: []
};
doc.querySelectorAll('proxy').forEach((item, index) => {
const proxy = {};
// type a.k.a. mode
const oldType = item.getAttribute('mode');
// Deactivate from patterns mode any unsupported types/modes
const allowedType = ['manual', 'direct'].includes(oldType);
proxy.active = allowedType ? item.getAttribute('enabled') === 'true' : false;
// switch is faster than a series of if/else
switch (oldType) {
case 'system':
badModes.push(item);
proxy.type = PROXY_TYPE_SYSTEM;
break;
case 'auto':
badModes.push(item);
if (item.getAttribute('autoconfMode') === 'pac') { // PAC
proxy.type = PROXY_TYPE_PAC;
proxy.pacURL = item.querySelector('autoconf').getAttribute('url');
}
else { // WPAD
proxy.type = PROXY_TYPE_WPAD;
proxy.pacURL = 'http://wpad/wpad.dat';
}
break;
case 'direct':
proxy.type = PROXY_TYPE_NONE;
break;
case 'manual':
const manualconf = item.querySelector('manualconf');
proxy.address = manualconf.getAttribute('host');
proxy.port = parseInt(manualconf.getAttribute('port'));
proxy.username = manualconf.getAttribute('username');
proxy.password = manualconf.getAttribute('password');
// There appears to be a bug in 4.6.5 and possibly earlier versions: socksversion is always 5, never 4
if (manualconf.getAttribute('isSocks') === 'true') {
proxy.type = PROXY_TYPE_SOCKS5;
if (item.getAttribute('proxyDNS') === 'true') { proxy.proxyDNS = true; }
}
else if (manualconf.getAttribute('isHttps') === 'true') { proxy.type = PROXY_TYPE_HTTPS; }
else { proxy.type = PROXY_TYPE_HTTP; }
break;
}
proxy.title = item.getAttribute('name');
proxy.color = item.getAttribute('color');
let newId;
const oldId = item.getAttribute('id');
if (item.getAttribute('lastresort') === 'true') {
lastResortFound = true;
newId = LASTRESORT; // this is a string
proxy.index = Number.MAX_SAFE_INTEGER;
if (!allowedType) { proxy.type = PROXY_TYPE_NONE; }
}
else {
proxy.index = index;
newId = 'import-' + oldId;
}
if (pref.mode === oldId) {
// If the old top-level mode points to a proxy setting with an unsupported mode (e.g. WPAD),
// we have to change the new top-level mode otherwise nothing will work w/o user intervention
pref.mode = !allowedType ? PROXY_TYPE_NONE : newId; // Update mode to the new id ("import-" prefix)
}
proxy.whitePatterns = [];
proxy.blackPatterns = [];
item.querySelectorAll('match').forEach(mtch => {
const newPattern = {};
/*
"whitePatterns": [
{
"title": "all URLs",
"active": true,
"pattern": "*",
"type": 1,
"protocols": 1
}
]
*/
newPattern.title = mtch.getAttribute('name');
newPattern.active = mtch.getAttribute('enabled') === 'true';
newPattern.importedPattern = newPattern.pattern = mtch.getAttribute('pattern');
newPattern.type = mtch.getAttribute('isRegEx') === 'true' ? PATTERN_TYPE_REGEXP : PATTERN_TYPE_WILDCARD;
// Do some simple parsing but only for wildcards. Anything else is going to fail.
if (newPattern.type === PATTERN_TYPE_WILDCARD) {
switch (true) {
case newPattern.pattern.startsWith('http://'):
newPattern.protocols = PROTOCOL_HTTP;
newPattern.pattern = newPattern.pattern.substring(7);
break;
case newPattern.pattern.startsWith('https://'):
newPattern.protocols = PROTOCOL_HTTPS;
newPattern.pattern = newPattern.pattern.substring(8);
break;
case newPattern.pattern.startsWith('*://'):
newPattern.protocols = PROTOCOL_ALL;
newPattern.pattern = newPattern.pattern.substring(4);
break;
default:
newPattern.protocols = PROTOCOL_ALL;
}
// Clip everything after slashes; it can't be used anymore: https://bugzilla.mozilla.org/show_bug.cgi?id=1337001
const idx = newPattern.pattern.indexOf('/');
if (idx > -1) {
newPattern.pattern = newPattern.pattern.substring(0, idx);
patternsEdited = true;
}
}
else { // e.g. ^https?://(?:[^:@/]+(?::[^@/]+)?@)?(?:localhost|127\.\d+\.\d+\.\d+)(?::\d+)?(?:/.*)?$
switch (true) {
case newPattern.pattern.indexOf('^http://') === 1:
newPattern.protocols = PROTOCOL_HTTP;
newPattern.pattern = '^' + newPattern.pattern.substring(8);
break;
case newPattern.pattern.indexOf('^https://') === 1:
newPattern.protocols = PROTOCOL_HTTPS;
newPattern.pattern = '^' + newPattern.pattern.substring(9);
break;
case newPattern.pattern.indexOf('^https?://') === 1:
newPattern.protocols = PROTOCOL_ALL;
newPattern.pattern = '^' + newPattern.pattern.substring(10);
break;
default:
newPattern.protocols = PROTOCOL_ALL;
}
}
mtch.getAttribute('isBlackList') === 'true' ? proxy.blackPatterns.push(newPattern) : proxy.whitePatterns.push(newPattern);
});
pref[newId] = proxy;
});
if (!lastResortFound) { pref[LASTRESORT] = DEFAULT_PROXY_SETTING; }
save(pref, () => endXML(patternsEdited));
}
function endXML(patternsEdited) {
hideSpinner();
if (patternsEdited) {
// Don't use Utils.notify() because at least on macOS,
// the message is too long and cut off
alert(chrome.i18n.getMessage('patternsChanged'));
location.href = '/options.html';
}
else {
// Don't use Utils.notify() because at least on macOS,
// the message is too long and cut off
alert(chrome.i18n.getMessage('importEndSlash'));
location.href = '/options.html';
}
}
function prepareForStorage(settings) {
if (!settings.hasOwnProperty('proxySettings') || !settings.proxySettings[0]) {
alert('Imported file doesn not have any proxies.');
return null;
}
// base format
const ret = {
mode: 'disabled',
logging: {
size: 100,
active: false
}
};
settings.mode && (ret.mode = settings.mode);
settings.logging && (ret.logging = settings.logging);
let idx = 0;
settings.proxySettings.forEach(item => {
const id = item.id;
item.index = idx++;
delete item.id; // Don't need id
ret[id] = item;
});
return ret;
}
// ----------------- FoxyProxy Import ----------------------
function foxyProxyImport() {
// --- check user/pass
const username = document.querySelector('#username').value.trim();
const password = document.querySelector('#password').value.trim();
if (!username || !password) {
hideSpinner();
alert(chrome.i18n.getMessage('errorUserPass'));
return;
}
// --- generate the form post data
const usernamePassword = { 'username': username, 'password': password };
const formBody = [];
for (const property in usernamePassword) {
const encodedKey = encodeURIComponent(property);
const encodedValue = encodeURIComponent(usernamePassword[property]);
formBody.push(encodedKey + "=" + encodedValue);
}
// --- fetch data
fetch('https://getfoxyproxy.org/webservices/get-accounts.php',
{ method: 'POST',
body: formBody.join("&"),
headers: {
'Content-Type': 'application/x-www-form-urlencoded;charset=UTF-8'
}
})
.then(response => response.json())
.then(response => {
if (!Array.isArray(response) || !response[0] || !response[0].hostname) {
hideSpinner();
Utils.notify(chrome.i18n.getMessage('errorFetch'));
return;
}
const sync = localStorage.getItem('sync') === 'true';
const storageArea = !sync ? chrome.storage.local : chrome.storage.sync;
storageArea.get(null, result => {
response.forEach(item => {
const hostname = item.hostname.substring(0, item.hostname.indexOf('.getfoxyproxy.org'));
if (hostname && item.ipaddress && item.port && item.port[0] && item.country_code && item.country) {
// --- creating proxy
result[Math.random().toString(36).substring(7) + new Date().getTime()] = {
index: -1,
active: item.active,
title: hostname,
color: '#ff9900',
type: 1, // HTTP
address: item.ipaddress,
port: item.port[0],
username: item.username,
password: item.password,
cc: item.country_code,
country: item.country,
whitePatterns: [],
blackPatterns: []
};
}
});
storageArea.set(result, end); // save to target
});
})
.catch(error => {
hideSpinner();
Utils.notify(chrome.i18n.getMessage('errorFetch'));
});
}
// ----------------- /FoxyProxy Import ---------------------
function close() {
document.querySelector('#password').value = ''; /* prevent Firefox's save password prompt */
location.href = '/options.html';
}

1855
src/scripts/jscolor-2.0.5.js Normal file

File diff suppressed because it is too large Load diff

151
src/scripts/log.js Normal file
View file

@ -0,0 +1,151 @@
'use strict';
// ----------------- Internationalization ------------------
document.querySelectorAll('[data-i18n]').forEach(node => {
let [text, attr] = node.dataset.i18n.split('|');
text = chrome.i18n.getMessage(text);
attr ? node[attr] = text : node.appendChild(document.createTextNode(text));
});
// ----------------- /Internationalization -----------------
document.addEventListener('keyup', evt => {
if (evt.keyCode === 27) {
// We either came from /options.html or were opened as a new tab from popup.html (in that case, do nothing)
history.back();
}
});
// ----------------- Spinner -------------------------------
const spinner = document.querySelector('.spinner');
function hideSpinner() {
spinner.classList.remove('on');
setTimeout(() => { spinner.style.display = 'none'; }, 600);
}
function showSpinner() {
spinner.style.display = 'flex';
spinner.classList.add('on');
}
// ----------------- /spinner ------------------------------
// ----- global
let logger;
const onOff = document.querySelector('#onOff');
const logSize = document.querySelector('#logSize');
chrome.runtime.getBackgroundPage(bg => {
logger = bg.getLog();
onOff.checked = logger.active;
logSize.value = logger.size;
renderMatchedLog(); // log content will be shown if there are any, regardless of onOff
renderUnmatchedLog(); // log content will be shown if there are any, regardless of onOff
hideSpinner();
});
onOff.addEventListener('change', (e) => {
logger.active = onOff.checked;
logger.updateStorage();
});
logSize.addEventListener('change', (e) => {
logSize.value = logSize.value*1 || logger.size; // defaults on bad number entry
if (logger.size !== logSize.value) { // update on change
logger.size = logSize.value;
logger.updateStorage();
}
});
document.querySelectorAll('button').forEach(item => item.addEventListener('click', process));
function process () {
switch (this.dataset.i18n) {
case 'back': location.href = '/options.html'; break;
case 'refresh':
renderMatchedLog();
renderUnmatchedLog();
break;
case 'clear':
logger.clear();
renderMatchedLog();
renderUnmatchedLog();
break;
}
}
function renderMatchedLog() {
// ----- templates & containers
const docfrag = document.createDocumentFragment();
const tr = document.querySelector('tr.matchedtemplate');
const tbody = tr.parentNode.nextElementSibling;
tbody.textContent = ''; // clearing the content
const forAll = chrome.i18n.getMessage('forAll');
const NA = chrome.i18n.getMessage('notApplicable');
logger.matchedList.forEach(item => {
const pattern = item.matchedPattern ?
(item.matchedPattern === 'all' ? forAll : item.matchedPattern) : 'No matches';
// Build a row for this log entry by cloning the tr containing 7 td
const row = tr.cloneNode(true);
row.className = item.matchedPattern ? 'success' : 'secondary'; // this will rest class .tamplate as well
const td = row.children;
const a = td[0].children[0];
a.href = item.url;
a.textContent = item.url;
td[1].textContent = item.title || NA;
td[2].style.backgroundColor = item.color || 'blue';
td[3].textContent = item.address || NA;
td[4].textContent = pattern;
td[5].textContent = item.whiteBlack || NA;
td[6].textContent = formatInt(item.timestamp);
docfrag.appendChild(row);
});
tbody.appendChild(docfrag);
}
function renderUnmatchedLog() {
// ----- templates & containers
const docfrag = document.createDocumentFragment();
const tr = document.querySelector('tr.unmatchedtemplate');
const tbody = tr.parentNode.nextElementSibling;
tbody.textContent = ''; // clearing the content
logger.unmatchedList.forEach(item => {
// Build a row for this log entry by cloning the tr containing 2 td
const row = tr.cloneNode(true);
const td = row.children;
const a = td[0].children[0];
a.href = item.url;
a.textContent = item.url;
td[1].textContent = formatInt(item.timestamp);
docfrag.appendChild(row);
});
tbody.appendChild(docfrag);
}
function formatInt(d) {
// International format based on user locale
// you can delete the other function if you like this
// you can adjust the content via the object properties
return new Intl.DateTimeFormat(navigator.language,
{weekday: 'short', year: 'numeric', month: 'short', day: 'numeric',
hour: '2-digit', minute: '2-digit', second: '2-digit', hour12: false}).format(new Date(d));
}

116
src/scripts/matcher.js Normal file
View file

@ -0,0 +1,116 @@
'use strict';
const schemeSet = {
all : 1,
http: 2,
https: 4
};
// Shortcuts so we dont perform i18n lookups for every non-match
const FOR_ALL = {originalPattern: chrome.i18n.getMessage('forAll')}
const NOMATCH_TEXT = chrome.i18n.getMessage('noMatch');
const NONE_TEXT = chrome.i18n.getMessage('none');
const NOMATCH_COLOR = '#D3D3D3';
const WHITE = chrome.i18n.getMessage('white');
const BLACK = chrome.i18n.getMessage('black');
function findProxyMatch(url, activeSettings) {
// note: we've already thrown out inactive settings and inactive patterns in background.js.
// we're not iterating over them
if (activeSettings.mode === 'patterns') {
// Unfortunately, since Firefox 57 and some releases afterwards, we were unable
// to get anything of the URL except scheme, port, and host (because of Fx's PAC
// implementation). Now we have access to rest of URL, like pre-57, but users
// have written their patterns not anticipating that. Need to do more research
// before using other parts of URL. For now, we ignore the other parts.
const parsedUrl = new URL(url);
const scheme = parsedUrl.protocol.substring(0, parsedUrl.protocol.length-1); // strip the colon
const hostPort = parsedUrl.host; // This includes port if one is specified
for (const proxy of activeSettings.proxySettings) {
// Check black patterns first
const blackMatch = proxy.blackPatterns.find(item =>
(item.protocols === schemeSet.all || item.protocols === schemeSet[scheme]) &&
item.pattern.test(hostPort));
if (blackMatch) {
sendToMatchedLog(url, proxy, Utils.getProxyTitle(proxy), blackMatch, BLACK);
continue; // if blacklist matched, continue to the next proxy
}
const whiteMatch = proxy.whitePatterns.find(item =>
(item.protocols === schemeSet.all || item.protocols === schemeSet[scheme]) &&
item.pattern.test(hostPort));
if (whiteMatch) {
// found a whitelist match, end here
const title = Utils.getProxyTitle(proxy);
Utils.updateIcon('images/icon.svg', proxy.color, title, false, title, false);
sendToMatchedLog(url, proxy, title, whiteMatch, WHITE);
return prepareSetting(proxy);
}
}
// no white matches in any settings
sendToUnmatchedLog(url);
Utils.updateIcon('images/gray.svg', null, NOMATCH_TEXT, false, NOMATCH_TEXT, false);
return {type: 'direct'};
}
else if (activeSettings.mode === 'disabled') {
// Generally we won't get to this block because our proxy handler is turned off in this mode.
// We will get here at startup and also if there is a race condition between removing our listener
// (when switching to disabled mode) and handaling requests.
return {type: 'direct'};
}
else {
// Fixed mode -- use 1 proxy for all URLs
const p = activeSettings.proxySettings[0];
const title = Utils.getProxyTitle(p);
Utils.updateIcon('images/icon.svg', p.color, title, false, title, false);
sendToMatchedLog(url, p, title, FOR_ALL);
return prepareSetting(p);
}
}
const typeSet = {
1: 'http', // PROXY_TYPE_HTTP
2: 'https', // PROXY_TYPE_HTTPS
3: 'socks', // PROXY_TYPE_SOCKS5
4: 'socks4', // PROXY_TYPE_SOCKS4
5: 'direct' // PROXY_TYPE_NONE
};
function prepareSetting(proxy) {
const ret = {
type: typeSet[proxy.type] || typeSet[5], // If 'direct', all other properties of this object are ignored.
host: proxy.address,
port: proxy.port
};
proxy.username && (ret.username = proxy.username);
proxy.password && (ret.password = proxy.password);
proxy.proxyDNS && (ret.proxyDNS = proxy.proxyDNS); // Only useful for SOCKS
//if ((proxy.type === PROXY_TYPE_HTTP || proxy.type === PROXY_TYPE_HTTPS) && proxy.username && proxy.password) {
// Using wireshark, I do not see this header being sent, contrary to
// https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/API/proxy/ProxyInfo
//ret.proxyAuthorizationHeader = 'Basic ' + btoa(proxy.username + ":" + proxy.password);
//}
return ret;
}
function sendToMatchedLog(url, proxy, title, matchedPattern, whiteBlack) {
// log only the data that is needed for display
logger && logger.active && logger.addMatched({
url,
title,
color: proxy.color,
address: proxy.address,
// Log should display whatever user typed, not our processed version of the pattern
matchedPattern: matchedPattern.originalPattern,
whiteBlack,
timestamp: Date.now()
});
}
function sendToUnmatchedLog(url) {
logger && logger.active && logger.addUnmatched({url, timestamp: Date.now()});
}

380
src/scripts/options.js Normal file
View file

@ -0,0 +1,380 @@
'use strict';
// ----------------- Internationalization ------------------
document.querySelectorAll('[data-i18n]').forEach(node => {
let [text, attr] = node.dataset.i18n.split('|');
text = chrome.i18n.getMessage(text);
attr ? node[attr] = text : node.appendChild(document.createTextNode(text));
});
// ----------------- /Internationalization -----------------
// ----- global
const accounts = document.querySelector('#accounts');
const mode = document.querySelector('#mode');
const syncOnOff = document.querySelector('#syncOnOff');
const popup = document.querySelector('.popup');
const popupMain = popup.children[0];
let storageArea, minIndex = Number.MAX_SAFE_INTEGER;
// ----------------- User Preference -----------------------
chrome.storage.local.get(null, result => {
// if sync is NOT set or it is false, use this result
syncOnOff.checked = result.sync;
localStorage.setItem('sync', syncOnOff.checked);
storageArea = result.sync ? chrome.storage.sync : chrome.storage.local;
result.sync ? chrome.storage.sync.get(null, processOptions) : processOptions(result);
});
// ----------------- /User Preference ----------------------
// ----------------- Spinner -------------------------------
const spinner = document.querySelector('.spinner');
function hideSpinner() {
spinner.classList.remove('on');
setTimeout(() => { spinner.style.display = 'none'; }, 600);
}
function showSpinner() {
spinner.style.display = 'flex';
spinner.classList.add('on');
}
// ----------------- /spinner ------------------------------
// ----- add Listeners for menu
document.querySelectorAll('nav a').forEach(item => item.addEventListener('click', process));
function process() {
switch (this.dataset.i18n) {
case 'add':
localStorage.removeItem('id'); // clear localStorage; this indicates an add not an edit
localStorage.setItem('nextIndex', minIndex); // index to use for this proxy so that it's added to the beginning
location.href = '/proxy.html';
break;
case 'export': Utils.exportFile(); break;
case 'import': location.href = '/import.html'; break;
case 'importProxyList': location.href = '/import-proxy-list.html'; break;
case 'log': location.href = '/log.html'; break;
case 'about': location.href = '/about.html'; break;
case 'deleteAll':
if (confirm(chrome.i18n.getMessage('confirmDelete'))) {
showSpinner();
chrome.storage.local.clear(() => chrome.storage.sync.clear(() => {
hideSpinner();
Utils.notify(chrome.i18n.getMessage('deleteAllmessage'));
location.href = '/options.html';
}));
}
break;
case 'deleteBrowserData':
const h4 = document.createElement('h4');
const p = document.createElement('p');
popupMain.children[0].textContent = chrome.i18n.getMessage('deleteBrowserData');
let h = h4.cloneNode();
h.textContent = chrome.i18n.getMessage('deleteNot');
let p1 = p.cloneNode();
p1.textContent = chrome.i18n.getMessage('deleteBrowserDataNotDescription');
popupMain.children[1].appendChild(h);
popupMain.children[1].appendChild(p1);
h = h4.cloneNode();
h.textContent = chrome.i18n.getMessage('delete');
p1 = p.cloneNode();
p1.textContent = chrome.i18n.getMessage('deleteBrowserDataDescription');
popupMain.children[1].appendChild(h);
popupMain.children[1].appendChild(p1);
popupMain.children[2].children[0].addEventListener('click', closePopup);
popupMain.children[2].children[1].addEventListener('click', () => // Not cancelled
chrome.browsingData.remove({}, {
//appcache: true,
cache: true,
cookies: true,
downloads: false,
//fileSystems: true,
formData: false,
history: false,
indexedDB: true,
localStorage: true,
pluginData: true,
//passwords: true,
//webSQL: true,
//serverBoundCertificates: true,
serviceWorkers: true
}, () => {
Utils.notify(chrome.i18n.getMessage('done'));
closePopup();
}
));
showPopup();
break;
}
}
// ----- add Listeners for initial elements
mode.addEventListener('change', selectMode);
function selectMode() {
// set color
mode.style.color = mode.children[mode.selectedIndex].style.color;
console.log(mode, "selectMode");
// we already know the state of sync | this is set when manually changing the select
// it is undefined when mode is switched from toolbar popup or on startup
this && storageArea.set({mode: mode.value});
// --- change the state of success/secondary
// change all success -> secondary
document.querySelectorAll('.success').forEach(item => item.classList.replace('success', 'secondary'));
switch (mode.value) {
case 'patterns':
document.querySelectorAll('input[name="onOff"]:checked').forEach(item => {
const node = item.parentNode.parentNode;
node.classList.replace('secondary', 'success'); // FF49, Ch 61
});
break;
case 'disabled': // do nothing
break;
default:
const node = document.getElementById(mode.value);
node && node.classList.replace('secondary', 'success');
}
}
syncOnOff.addEventListener('change', () => {
const useSync = syncOnOff.checked;
// sync value always CHECKED locally
// data is merged, replacing exisitng and adding new ones
localStorage.setItem('sync', syncOnOff.checked);
storageArea = syncOnOff.checked ? chrome.storage.sync : chrome.storage.local;
if (useSync && confirm(chrome.i18n.getMessage('confirmTransferToSync'))) {
showSpinner();
chrome.storage.local.set({sync: true}); // save sync state
chrome.storage.local.get(null, result => { // get source
delete result.sync;
chrome.storage.sync.set(result, hideSpinner); // save to target
}); // get source & save to target
}
else if (!useSync && confirm(chrome.i18n.getMessage('confirmTransferToLocal'))) {
showSpinner();
chrome.storage.sync.get(null, result => { // get source
result.sync = false; // set sync = false
chrome.storage.local.set(result, hideSpinner); // save to target
});
}
});
chrome.runtime.onMessage.addListener((message, sender) => { // from popup or bg
// console.log(message);
if(!message.mode || message.mode === mode.value) { return; } // change if it is different
mode.value = message.mode;
selectMode();
});
function processOptions(pref) {
// --- reset
accounts.textContent = '';
// remove all <option> elements except patterns and disabled
[...mode.children].forEach(item => !['patterns', 'disabled'].includes(item.value) && item.remove());
// ----- templates & containers
const docfrag = document.createDocumentFragment();
const docfrag2 = document.createDocumentFragment();
const temp = document.querySelector('.template');
// --- working directly with DB format
// add default lastresort if not there
//pref[LASTRESORT] || (pref[LASTRESORT] = DEFAULT_PROXY_SETTING);
const prefKeys = Object.keys(pref).filter(item => !NON_PROXY_KEYS.includes(item)); // not for these
prefKeys.sort((a, b) => pref[a].index - pref[b].index); // sort by index
if (prefKeys[0]) {
minIndex = pref[prefKeys[0]].index; // the first index after sort (if any)
}
pref.mode = pref.mode || 'disabled'; // defaults to disabled
prefKeys.forEach(id => {
const item = pref[id];
const div = temp.cloneNode(true);
const node = [...div.children[0].children, ...div.children[1].children];
div.classList.remove('template');
//id === LASTRESORT && div.children[1].classList.add('default');
div.id = id;
node[0].style.backgroundColor = item.color;
node[1].textContent = Utils.getProxyTitle(item);
node[2].textContent = item.address; // ellipsis is handled by CSS
if (item.cc) {
node[3].classList.remove('hide');
node[3].textContent = getFlag(item.cc);
node[3].title = item.country;
}
item.username && item.password && node[4].classList.add('on');
node[5].id = id + '-onoff';
node[5].checked = item.active;
node[6].setAttribute('for', node[5].id);
FOXYPROXY_BASIC && (node[8].style.display = 'none');
// setting div colors
switch (true) {
case Utils.isUnsupportedType(item.type):
div.classList.add('unsupported');
break;
case pref.mode === 'patterns':
case pref.mode === 'random':
case pref.mode === 'roundrobin':
div.classList.add(item.active ? 'success' : 'secondary');
break;
case pref.mode === 'disabled':
div.classList.add('secondary');
break;
default:
div.classList.add(pref.mode == id ? 'success' : 'secondary');
}
docfrag.appendChild(div);
// add to select
const opt = new Option(node[1].textContent, id);
opt.style.color = item.color;
docfrag2.appendChild(opt);
});
docfrag.hasChildNodes() && accounts.appendChild(docfrag);
docfrag2.hasChildNodes() && mode.appendChild(docfrag2, mode.lastElementChild);
if (FOXYPROXY_BASIC) {
mode.children[0].classList.add('hide'); // hide by pattern option
pref.mode === 'patterns' && (pref.mode = 'disabled');
}
const opt = mode.querySelector(`option[value="${pref.mode}"]`);
if (opt) {
opt.selected = true;
mode.style.color = opt.style.color;
}
// add Listeners
document.querySelectorAll('button').forEach(item => item.addEventListener('click', processButton));
document.querySelectorAll('input[name="onOff"]').forEach(item => item.addEventListener('change', function() {
const id = this.parentNode.parentNode.id;
storageArea.get(id, result => {
result[id].active = this.checked;
storageArea.set(result);
});
}));
doWeHaveProxiesDefined();
hideSpinner();
}
function doWeHaveProxiesDefined() {
if (!accounts.hasChildNodes()) {
document.querySelector('#help').style.display = 'block';
document.querySelector('#rightColumn').classList.add('secondary');
document.querySelector('#mode').style.display = 'none';
}
else {
document.querySelector('#help').style.display = 'none';
document.querySelector('#rightColumn').classList.remove('warning');
document.querySelector('#mode').style.display = 'flex';
}
}
function getFlag(cc) {
cc = /^[A-Z]{2}$/i.test(cc) && cc.toUpperCase();
return cc && String.fromCodePoint(...[...cc].map(c => c.charCodeAt() + 127397));
}
function processButton() {
const parent = this.parentNode.parentNode;
const id = parent.id;
switch (this.dataset.i18n) {
case 'help|title':
popupMain.children[0].textContent = chrome.i18n.getMessage('syncSettings');
popupMain.children[1].textContent = chrome.i18n.getMessage('syncSettingsHelp');
popupMain.children[2].children[0].style.visibility = 'hidden';
popupMain.children[2].children[1].addEventListener('click', closePopup);
showPopup();
break;
case 'edit':
localStorage.setItem('id', id);
location.href = '/proxy.html';
break;
case 'patterns':
localStorage.setItem('id', id);
location.href = '/patterns.html';
break;
case 'delete|title':
if (confirm(chrome.i18n.getMessage('confirmDelete'))) {
parent.style.opacity = 0;
setTimeout(() => { parent.remove(); doWeHaveProxiesDefined();}, 600); // remove row
storageArea.remove(id);
}
break;
case 'up|title':
case 'down|title':
const target = this.dataset.i18n === 'up|title' ? parent.previousElementSibling : parent.nextElementSibling;
const insert = this.dataset.i18n === 'up|title' ? target : target.nextElementSibling;
parent.parentNode.insertBefore(parent, insert);
parent.classList.add('on');
setTimeout(() => { parent.classList.remove('on'); }, 600);
storageArea.get(null, result => {
// re-index
//[...accounts.children].forEach((item, index) => item.id !== LASTRESORT && (result[item.id].index = index));
[...accounts.children].forEach((item, index) => result[item.id].index = index);
minIndex = 0; // minimum index is always 0 now
storageArea.set(result);
});
break;
}
}
function showPopup() {
popup.style.display = 'flex';
window.getComputedStyle(popup).opacity;
window.getComputedStyle(popup.children[0]).transform;
popup.classList.add('on');
}
function closePopup() {
popup.classList.remove('on');
setTimeout(() => {
popup.style.display = 'none';
// reset
popupMain.children[0].textContent = '';
popupMain.children[1].textContent = '';
popupMain.children[2].children[0].style.visibility = 'visible';
popupMain.replaceChild(popupMain.children[2].cloneNode(true), popupMain.children[2]); // cloning to remove listeners
}, 600);
}

View file

@ -0,0 +1,9 @@
'use strict';
// ----------------- Internationalization ------------------
document.querySelectorAll('[data-i18n]').forEach(node => {
let [text, attr] = node.dataset.i18n.split('|');
text = chrome.i18n.getMessage(text);
attr ? node[attr] = text : node.appendChild(document.createTextNode(text));
});
// ----------------- /Internationalization -----------------

View file

@ -0,0 +1,77 @@
'use strict';
// ----------------- Internationalization ------------------
document.querySelectorAll('[data-i18n]').forEach(node => {
let [text, attr] = node.dataset.i18n.split('|');
text = chrome.i18n.getMessage(text);
attr ? node[attr] = text : node.appendChild(document.createTextNode(text));
});
// ----------------- /Internationalization -----------------
// --- global
const url = document.querySelector('#url');
const pattern = document.querySelector('#pattern');
const type = document.querySelector('#type');
const protocols = document.querySelector('#protocols');
const result = document.querySelector('#result');
document.querySelector('button[data-i18n="test"]').addEventListener('click', testPattern);
// ----- check for Edit
const pat = localStorage.getItem('pattern');
if (pat) {
pattern.value = pat;
type.value = localStorage.getItem('type');
protocols.value = localStorage.getItem('protocols');
localStorage.removeItem('pattern');
localStorage.removeItem('type');
localStorage.removeItem('protocols');
}
function testPattern() {
// --- reset
url.classList.remove('invalid');
pattern.classList.remove('invalid');
result.classList.add('hide');
result.classList.remove('alert');
// --- trim text values
[url, pattern].forEach(item => item.value = item.value.trim());
// --- URL check
let parsedURL;
try { parsedURL = new URL(url.value); }
catch (e) {
url.classList.add('invalid');
showResult(e.message, true);
return;
}
// --- protocol check
const protocolSet = { // converting to meaningful terms
'1': ['http:', 'https:'],
'2': ['http:'],
'4': ['https:']
};
if (!protocolSet[protocols.value].includes(parsedURL.protocol)) {
showResult(chrome.i18n.getMessage('errorProtocol'), true);
return;
}
// --- pattern check
const regex = checkPattern(pattern, type);
if (!regex) { return; }
// --- pattern on URL check (pattern is valid)
regex.test(parsedURL.host) ? showResult(chrome.i18n.getMessage('patternMatch')) :
showResult(chrome.i18n.getMessage('patternNotMatch'), true);
}

283
src/scripts/patterns.js Normal file
View file

@ -0,0 +1,283 @@
'use strict';
// ----------------- Internationalization ------------------
document.querySelectorAll('[data-i18n]').forEach(node => {
let [text, attr] = node.dataset.i18n.split('|');
text = chrome.i18n.getMessage(text);
attr ? node[attr] = text : node.appendChild(document.createTextNode(text));
});
// ----------------- /Internationalization -----------------
document.addEventListener('keyup', evt => {
if (evt.keyCode === 27) {
history.back(); // We either came from /proxy.html or /options.html
}
});
// ----------------- Spinner -------------------------------
const spinner = document.querySelector('.spinner');
function hideSpinner() {
spinner.classList.remove('on');
setTimeout(() => { spinner.style.display = 'none'; }, 600);
}
function showSpinner() {
spinner.style.display = 'flex';
spinner.classList.add('on');
}
// ----------------- /spinner ------------------------------
// ----- global
let proxy = {};
const header = document.querySelector('.header');
const tbody = document.querySelectorAll('tbody'); // there are 2
const template = document.querySelector('tr.template');
const docfrag = document.createDocumentFragment();
const defaultPattern = {
title: '',
active: true,
pattern: '',
type: 1, // PATTERN_TYPE_WILDCARD,
protocols: 1 // PROTOCOL_ALL
};
const protocolSet = { // converting to meaningful terms
1: 'All',
2: 'HTTP',
4: 'HTTPS'
};
const patternTypeSet = {
1: 'wildcard',
2: 'Reg Exp'
}
// ----- check for Edit
const id = localStorage.getItem('id');
const sync = localStorage.getItem('sync') === 'true';
const storageArea = !sync ? chrome.storage.local : chrome.storage.sync;
if (id) { // This is an edit operation
storageArea.get(id, result => {
if (!Object.keys(result).length) {
/*
if (id === LASTRESORT) { // error prevention
proxy = DEFAULT_PROXY_SETTING;
processOptions();
return;
}*/
console.error('Unable to edit saved proxy (could not get existing settings)')
return;
}
proxy = result[id];
if (proxy.title) { header.textContent = chrome.i18n.getMessage('editPatternsFor', proxy.title); }
processOptions();
hideSpinner();
})
}
/*
else {
// Error, shouldn't ever get here
hideSpinner();
document.querySelector('#error').classList.remove('hide');
document.querySelector('.main').classList.add('hide');
console.error("2: Unable to read saved proxy proxy (could not get existing settings)");
}*/
// --- processing all buttons
document.querySelectorAll('button').forEach(item => item.addEventListener('click', process));
function process() {
switch (this.dataset.i18n) {
case 'back': // error
case 'cancel':
location.href = '/options.html';
break;
case 'exportPatterns': exportPatterns(); break;
case 'newWhite':
addNew(tbody[0], 'whitePatterns');
break;
case 'newBlack':
addNew(tbody[1], 'blackPatterns');
break;
case 'save':
checkOptions();
break;
case 'add':
if (typeof(this.dataset.black) !== 'undefined') {
proxy.blackPatterns.push(...blacklistSet);
processOptions();
}
else {
proxy.whitePatterns.push(PATTERN_ALL_WHITE);
processOptions();
}
break;
}
}
function processOptions() {
// clearing the content
tbody[0].textContent = '';
tbody[1].textContent = '';
proxy.whitePatterns.forEach((item, index) => docfrag.appendChild(makeRow(item, index, 'whitePatterns')));
docfrag.hasChildNodes() && tbody[0].appendChild(docfrag);
proxy.blackPatterns.forEach((item, index) => docfrag.appendChild(makeRow(item, index, 'blackPatterns')));
docfrag.hasChildNodes() && tbody[1].appendChild(docfrag);
}
function makeRow(pat, index, bw) {
const tr = template.cloneNode(true);
tr.classList.remove('template');
tr.classList.add(pat.active ? 'success' : 'secondary');
tr.dataset.idx = index;
tr.dataset.bw = bw; // black/white
const td = tr.children;
td[0].children[0].value = pat.title;
td[1].children[0].value = pat.pattern;
td[2].children[0].value = pat.type;
td[3].children[0].value = pat.protocols;
td[4].children[0].checked = pat.active;
td[4].children[0].id = bw + index;
td[4].children[1].setAttribute('for', td[4].children[0].id);
pat.importedPattern && td[5].children[0].classList.remove('hide');
// add Listeners();
[...td[5].children].forEach(item => item.addEventListener('click', processEdit));
return tr;
}
function addNew(parent, bw) {
const tr = makeRow(defaultPattern, parent.children.length, bw);
parent.appendChild(tr);
tr.children[1].children[0].focus();
}
function processEdit() {
const parent = this.parentNode.parentNode;
const idx = parent.dataset.idx *1;
const patternsArray = proxy[parent.dataset.bw]; // whitePatterns | blackPatterns
switch (this.dataset.i18n) {
case 'imported|title':
alert(chrome.i18n.getMessage('importedPattern') + ' \n\n' + patternsArray[idx].importedPattern);
break;
case 'patternTester|title':
const pat = patternsArray[idx];
if (pat) {
localStorage.setItem('pattern', pat.pattern);
localStorage.setItem('type', pat.type);
localStorage.setItem('protocols', pat.protocols);
}
chrome.tabs.create({url: '/pattern-tester.html'});
break;
case 'delete|title':
parent.style.opacity = 0;
setTimeout(() => { parent.remove(); }, 300); // remove row
break;
}
}
function checkOptions() {
const pxy = {
whitePatterns: [],
blackPatterns: []
};
// use for loop to be able to return early on error
for (const item of document.querySelectorAll('tr[data-idx]')) {
const td = item.children;
// --- trim text values
[td[0].children[0], td[1].children[0]].forEach(item => item.value = item.value.trim());
// test pattern
const regex = testPattern(td[1].children[0], td[2].children[0]);
if (!regex) { return; }
const bw = item.dataset.bw;
pxy[bw].push({
title: td[0].children[0].value,
pattern: td[1].children[0].value,
type: td[2].children[0].value *1,
protocols: td[3].children[0].value *1,
active: td[4].children[0].checked
});
}
// all patterns passed
proxy.whitePatterns = pxy.whitePatterns;
proxy.blackPatterns = pxy.blackPatterns;
storageArea.set({[id]: proxy}, () => location.href = '/options.html');
}
function testPattern(pattern, type) {
// --- reset
pattern.classList.remove('invalid');
result.classList.add('hide');
result.classList.remove('alert');
// --- pattern check
return checkPattern(pattern, type);
}
function exportPatterns() {
const tmpObject = {whitePatterns: proxy.whitePatterns, blackPatterns: proxy.blackPatterns};
const blob = new Blob([JSON.stringify(tmpObject, null, 2)], {type : 'text/plain'});
const filename = 'foxyproxy' + (proxy.title ? '-' + proxy.title : '') + '-patterns' + '_' + new Date().toISOString().substring(0, 10) + '.json';
chrome.downloads.download({
url: URL.createObjectURL(blob),
filename,
saveAs: true,
conflictAction: 'uniquify'
}, () => console.log('Export/download finished')); // wait for it to complete before returning
}
document.getElementById('file').addEventListener('change', processFileSelect);
function processFileSelect(e) {
const file = e.target.files[0];
Utils.importFile(file, ['application/json'], 1024*1024*5, 'json', imported => {
proxy.whitePatterns = imported.whitePatterns;
proxy.blackPatterns = imported.blackPatterns;
processOptions();
Utils.notify(chrome.i18n.getMessage('importBW', [proxy.whitePatterns.length, proxy.blackPatterns.length]));
});
}

112
src/scripts/popup.js Normal file
View file

@ -0,0 +1,112 @@
'use strict';
// ----------------- Internationalization ------------------
document.querySelectorAll('[data-i18n]').forEach(node => {
let [text, attr] = node.dataset.i18n.split('|');
text = chrome.i18n.getMessage(text);
attr ? node[attr] = text : node.appendChild(document.createTextNode(text));
});
// ----------------- /Internationalization -----------------
// ----------------- User Preference -----------------------
let storageArea;
chrome.storage.local.get(null, result => {
storageArea = result.sync ? chrome.storage.sync : chrome.storage.local;
result.sync ? chrome.storage.sync.get(null, processOptions) : processOptions(result);
});
// ----------------- /User Preference ----------------------
function processOptions(pref) {
// ----- templates & containers
const docfrag = document.createDocumentFragment();
const temp = document.querySelector('li.template');
// add default lastresort if not there
//pref[LASTRESORT] || (pref[LASTRESORT] = DEFAULT_PROXY_SETTING);
const prefKeys = Object.keys(pref).filter(item => !NON_PROXY_KEYS.includes(item)); // not for these
prefKeys.sort((a, b) => pref[a].index - pref[b].index); // sort by index
pref.mode = pref.mode || 'disabled'; // defaults to disabled
let hasProxySettings = false;
prefKeys.forEach(id => {
const item = pref[id];
if (!Utils.isUnsupportedType(item.type)) { // if supported
const li = temp.cloneNode(true);
li.classList.remove('template');
li.id = id;
li.style.color = item.color;
li.children[0].textContent = Utils.getProxyTitle(item);
li.children[1].textContent = '(' + chrome.i18n.getMessage('forAll') + ')';
docfrag.appendChild(li);
hasProxySettings = true;
}
});
docfrag.hasChildNodes() && temp.parentNode.appendChild(docfrag, temp.nextElementSibling);
if (FOXYPROXY_BASIC) {
temp.parentNode.children[0].classList.add('hide'); // hide by pattern option
pref.mode === 'patterns' && (pref.mode = 'disabled');
}
// hide the selections if there are no proxy settings defined
document.getElementById('scroll').style.display = hasProxySettings ? 'block' : 'none';
const node = document.getElementById(pref.mode); // querySelector error with selectors starting with number
node.classList.add('on');
// add Listeners
document.querySelectorAll('li, button').forEach(item => item.addEventListener('click', process));
}
function process() {
let tabs;
switch (this.dataset.i18n) {
case 'myIP':
chrome.tabs.create({url: 'https://getfoxyproxy.org/geoip/'}); // no need to wait for it
window.close();
break;
case 'log':
const url = chrome.runtime.getURL('log.html');
chrome.tabs.query({url}, tabs => { // find a log tab
tabs[0] ? chrome.tabs.update(tabs[0].id, {active: true}) : chrome.tabs.create({url}); // active existing tab OR open new tab
window.close();
});
break;
case 'options':
chrome.tabs.query({url: chrome.runtime.getURL('') + '*'}, tabs => {
if (!tabs[0]) {
chrome.runtime.openOptionsPage();
window.close();
return;
}
const tab = tabs.find(item => /(proxy|options|patterns)\.html/.test(item.url)); // find a option tab
tab ? chrome.tabs.update(tab.id, {active: true}) : chrome.tabs.update(tabs[0].id, {active: true, url: '/options.html'});
window.close();
});
break;
default:
// reset the old one
const old = document.querySelector('.on');
old && old.classList.remove('on');
this.classList.add('on');
storageArea.set({mode: this.id}); // keep it open for more action
// popup & options are the only place that can set mode
// sending message to option && bg, if it is open
chrome.runtime.sendMessage({mode: this.id});
}
}

228
src/scripts/proxy.js Normal file
View file

@ -0,0 +1,228 @@
'use strict';
// ----------------- Internationalization ------------------
document.querySelectorAll('[data-i18n]').forEach(node => {
let [text, attr] = node.dataset.i18n.split('|');
text = chrome.i18n.getMessage(text);
attr ? node[attr] = text : node.appendChild(document.createTextNode(text));
});
// ----------------- /Internationalization -----------------
document.addEventListener('keyup', evt => {
if (evt.keyCode === 27) {
close();
}
});
// ----- global
let proxy = {}, proxiesAdded = 0;
const color = new jscolor('colorChooser', {uppercase: false, hash: true});
color.fromString(DEFAULT_COLOR); // starting from default color
const header = document.querySelector('.header'); // dynamic header
setHeader();
// ----- check for Edit
let id = localStorage.getItem('id');
const sync = localStorage.getItem('sync') === 'true';
const storageArea = !sync ? chrome.storage.local : chrome.storage.sync;
if (id) { // This is an edit operation
storageArea.get(id, result => {
if (!Object.keys(result).length) {
/*
if (id === LASTRESORT) { // error prevention
proxy = DEFAULT_PROXY_SETTING;
processOptions();
return;
}*/
console.error('Unable to edit saved proxy (could not get existing settings)')
return;
}
proxy = result[id];
processOptions();
});
}
// --- show & hide element using CSS
const nav = [...document.querySelectorAll('input[name="nav"]')];
//nav[0].checked = true;
const proxyType = document.querySelector('#proxyType');
proxyType.addEventListener('change', function() { nav[this.value -1].checked = true; });
const proxyTitle = document.querySelector('#proxyTitle');
proxyTitle.focus();
const proxyAddress = document.querySelector('#proxyAddress');
const proxyPort = document.querySelector('#proxyPort');
const proxyUsername = document.querySelector('#proxyUsername');
const proxyPassword = document.querySelector('#proxyPassword');
const proxyActive = document.querySelector('#proxyActive');
const proxyDNS = document.querySelector('#proxyDNS');
const pacURL = document.querySelector('#pacURL');
// --- remove nodes completely for FP Basic
FOXYPROXY_BASIC && document.querySelectorAll('.notForBasic').forEach(item => item.remove());
// --- remove pattern shortcuts if this is an edit operation
id && document.querySelectorAll('.notForEdit').forEach(item => item.remove());
// --- add Listeners
document.querySelectorAll('button').forEach(item => item.addEventListener('click', process));
function process() {
switch (this.dataset.i18n) {
case 'cancel':
close();
break;
case 'saveAdd':
if (!validateInput()) { return; }
storageArea.set(makeProxy(), resetOptions);
break;
case 'saveEditPattern':
if (!validateInput()) { return; }
storageArea.set(makeProxy(), () => {
localStorage.setItem('id', id); // in case new proxy was added
proxyPassword.value = ''; // prevent Firefox's save password prompt
location.href = '/patterns.html';
});
break;
case 'save':
if (!validateInput()) { return; }
storageArea.set(makeProxy(), () => {
proxyPassword.value = ''; // prevent Firefox's save password promp
location.href = '/options.html'
});
break;
case 'togglePW|title':
const inp = this.nextElementSibling;
inp.type = inp.type === 'password' ? 'text' : 'password';
break;
}
}
function setHeader(proxy) {
if (proxy) {
document.title = 'FoxyProxy ' + chrome.i18n.getMessage('editProxy', '');
header.textContent = chrome.i18n.getMessage('editProxy', proxy.title || `${proxy.address}:${proxy.port}`);
return;
}
document.title = 'FoxyProxy ' + chrome.i18n.getMessage('addProxy');
header.textContent = chrome.i18n.getMessage('addProxy');
}
function processOptions() {
setHeader(proxy);
// select
proxyType.value = proxy.type;
nav[proxyType.value -1].checked = true;
// checkbox
proxyActive.checked = proxy.active;
proxyDNS.checked = proxy.proxyDNS || false;
// color
color.fromString(proxy.color || DEFAULT_COLOR);
// input
proxyTitle.value = proxy.title || '';
proxyAddress.value = proxy.address || '';
proxyPort.value = proxy.port || '';
proxyUsername.value = proxy.username || '';
proxyPassword.value = proxy.password || '';
pacURL.value = proxy.pacURL || '';
}
function makeProxy() {
proxy.type = proxyType.value *1;
proxy.color = document.querySelector('#colorChooser').value;
proxy.title = proxyTitle.value;
proxy.active = proxyActive.checked;
if (proxy.type !== PROXY_TYPE_NONE) {
proxy.address = proxyAddress.value;
proxy.port = proxyPort.value *1;
proxy.proxyDNS = proxy.type === PROXY_TYPE_SOCKS5 && proxyDNS.checked;
// already trimmed in validateInput()
proxy.username = proxyUsername.value; // if it had u/p and then deletd it, it must be reflected
proxy.password = proxyPassword.value;
}
if (FOXYPROXY_BASIC) {
proxy.whitePatterns = proxy.blackPatterns = [];
}
else {
proxy.whitePatterns = proxy.whitePatterns || (document.querySelector('#whiteAll').checked ? [PATTERN_ALL_WHITE] : []);
proxy.blackPatterns = proxy.blackPatterns || (document.querySelector('#blackAll').checked ? blacklistSet : []);
}
proxy.pacURL = proxy.pacURL || pacURL.value; // imported foxyproxy.xml
if (!id) { // global
// This is an add operation since id does not exist. If this is an edit op, then id is already set.
// Get the nextIndex given to us by options.js and subtract by the number of proxies we've added
// while this window has been open. This ensures this proxy setting is first in list of all proxy settings.
proxy.index = (localStorage.getItem('nextIndex')) - (++proxiesAdded);
id = Utils.getUniqueId();
}
// else proxy.index is already set for edit operations
return {[id]: proxy};
}
function validateInput() {
document.querySelectorAll('input[type="text"]').forEach(item => item.value = item.value.trim());
if (proxyType.value *1 === PROXY_TYPE_NONE) { return true; }
// let's handle here, #proxyPort will be checked later separately
// escape all inputs
[proxyTitle, proxyAddress].forEach(item => item.value = Utils.stripBadChars(item.value));
// checking proxyAddress
proxyAddress.classList.remove('invalid'); // reset
if (!proxyAddress.value) {
proxyAddress.classList.add('invalid');
return false;
}
// checking proxyPort
proxyPort.classList.remove('invalid'); // reset
if (!proxyPort.value *1) { // check to see if it is a digit and not 0
proxyPort.classList.add('invalid');
return false;
}
return true;
}
function resetOptions() {
localStorage.removeItem('id');
id = null;
// to help entering sets quickly, some fields are kept
[proxyTitle, proxyAddress].forEach(item => item.value = '');
color.fromString(DEFAULT_COLOR);
setHeader();
proxyTitle.focus();
}
function close() {
proxyPassword.value = ''; /* prevent Firefox's save password prompt */
location.href = '/options.html';
}

324
src/scripts/utils.js Normal file
View file

@ -0,0 +1,324 @@
'use strict';
// ----------------- Constants -----------------------------
const FOXYPROXY_BASIC = false;
// Bit-wise flags so we can add/remove these independently. We may add more later so PROTOCOL_ALL is future-proof.
const PROTOCOL_ALL = 1; // in case other protocols besides http and https are supported later
const PROTOCOL_HTTP = 2;
const PROTOCOL_HTTPS = 4;
// import | pac
const PROXY_TYPE_HTTP = 1;
const PROXY_TYPE_HTTPS = 2;
const PROXY_TYPE_SOCKS5 = 3;
const PROXY_TYPE_SOCKS4 = 4;
const PROXY_TYPE_NONE = 5; // DIRECT
const PROXY_TYPE_PAC = 6;
const PROXY_TYPE_WPAD = 7;
const PROXY_TYPE_SYSTEM = 8;
const PROXY_TYPE_PASS = 9;
const PATTERN_TYPE_WILDCARD = 1;
const PATTERN_TYPE_REGEXP = 2;
// Storage keys that are not proxy settings
const NON_PROXY_KEYS = ['mode', 'logging', 'sync', 'browserVersion', 'foxyProxyVersion', 'foxyProxyEdition', 'nextIndex'];
// bg | import | proxy | utils
const PATTERN_ALL_WHITE = {
title: 'all URLs',
active: true,
pattern: '*',
type: 1, // PATTERN_TYPE_WILDCARD,
protocols: 1 // PROTOCOL_ALL
};
const DEFAULT_COLOR = '#66cc66'; // default proxy color
// patterns | proxy
// the local-internal blacklist, always used as a set
const blacklistSet = [
{
title: "local hostnames (usually no dots in the name). Pattern exists because 'Do not use this proxy for localhost and intranet/private IP addresses' is checked.",
pattern: "^(?:[^:@/]+(?::[^@/]+)?@)?(?:localhost|127\\.\\d+\\.\\d+\\.\\d+)(?::\\d+)?(?:/.*)?$",
},
{
title: "local subnets (IANA reserved address space). Pattern exists because 'Do not use this proxy for localhost and intranet/private IP addresses' is checked.",
pattern: "^(?:[^:@/]+(?::[^@/]+)?@)?(?:192\\.168\\.\\d+\\.\\d+|10\\.\\d+\\.\\d+\\.\\d+|172\\.(?:1[6789]|2[0-9]|3[01])\\.\\d+\\.\\d+)(?::\\d+)?(?:/.*)?$",
},
{
title: "localhost - matches the local host optionally prefixed by a user:password authentication string and optionally suffixed by a port number. The entire local subnet (127.0.0.0/8) matches. Pattern exists because 'Do not use this proxy for localhost and intranet/private IP addresses' is checked.",
pattern: "^(?:[^:@/]+(?::[^@/]+)?@)?[\\w-]+(?::\\d+)?(?:/.*)?$"
}
].map (item => {
item.active = true;
item.type = 2; // PATTERN_TYPE_REGEXP,
item.protocols = 1; // PROTOCOL_ALL
return item;
});
// ----------------- Utils ---------------------------------
class Utils {
static notify(message, title = 'FoxyProxy') {
// the id is not used anywhere and can be omitted, it is only useful if you want to manually close the notification early
chrome.notifications.create('foxyproxy', {
type: 'basic',
iconUrl: '/images/icon.svg',
title,
message
});
}
// options | popup
static isUnsupportedType(type) {
//return type === PROXY_TYPE_PAC || type === PROXY_TYPE_WPAD || type === PROXY_TYPE_SYSTEM || type === PROXY_TYPE_PASS;
return [PROXY_TYPE_PAC, PROXY_TYPE_WPAD, PROXY_TYPE_SYSTEM, PROXY_TYPE_PASS].includes(type);
}
// bg | pattern-tester | validate-pattern
static wildcardToRegExp(pat) {
let start = 0, end = pat.length, matchOptionalSubdomains = false;
if (pat[0] === '.') { pat = '*' + pat; }
if (pat.startsWith('**')) {
// Strip asterisks from front and back
while (pat[start] === '*' && start < end) start++;
while (pat[end - 1] === '*' && start < end) end--;
// If there's only an asterisk left, match everything
if (end - start == 1 && pat[start] == '*') return '';
}
else if (pat.startsWith('*.')) { matchOptionalSubdomains = true; }
let regExpStr = pat.substring(start, end+1)
// $& replaces with the string found, but with that string escaped
.replace(/[$.+()^{}\]\[|]/g, '\\$&')
.replace(/\*/g, '.*')
.replace(/\?/g, '.');
if (matchOptionalSubdomains) {
// Non-capturing group that matches:
// any group of non-whitespace characters following by an optional . repeated zero or more times
regExpStr = '(?:\\S+\\.)*' + regExpStr.substring(4);
}
// Leading or ending double-asterisks mean exact starting and ending positions
if (start === 0) { regExpStr = '^' + regExpStr; }
if (end === pat.length) { regExpStr += '$'; }
return regExpStr;
}
// Prep the patternObject for matching: convert wildcards to regexp,
// store the originalPattern which the user entered so we can display if needed, etc.
// Return null if patternObject is inactive or there is an error.
static processPatternObject(patternObject) {
if (patternObject.active) {
// Store the original pattern so if this pattern matches something,
// we can display whatever the user entered ("original") in the log.
patternObject.originalPattern = patternObject.pattern;
if (patternObject.type === PATTERN_TYPE_WILDCARD) {
patternObject.pattern = Utils.wildcardToRegExp(patternObject.pattern);
}
try {
// Convert to real RegExp, not just a string. Validate. If invalid, notify user.
patternObject.pattern = new RegExp(patternObject.pattern, 'i');
return patternObject;
}
catch(e) {
console.error(`Error creating regexp for pattern: ${patternObject.pattern}`, e);
Utils.notify(`Error creating regular expression for pattern ${regExpStr}`);
}
}
return null;
}
// import | pattern
static importFile(file, mimeTypeArr, maxSizeBytes, jsonOrXml, callback) {
if (!file) {
alert('There was an error');
return;
}
// Check MIME type // Ch65 no filetype for JSON
if (!mimeTypeArr.includes(file.type)) {
alert('Unsupported file format');
return;
}
if (file.size > maxSizeBytes) {
alert('Filesize is too large');
return;
}
const reader = new FileReader();
reader.onloadend = () => {
if (reader.error) {
alert('Error reading file.');
return;
}
let settings;
try {
if (jsonOrXml === 'json') { settings = JSON.parse(reader.result); }
else if (jsonOrXml === 'xml') {
settings = new DOMParser().parseFromString(reader.result, 'text/xml');
if (settings.documentElement.nodeName === 'parsererror') { throw new Error(); }
}
}
catch(e) {
console.log(e);
alert("Error parsing file. Please remove sensitive data from the file, and then email it to support@getfoxyproxy.org so we can fix bugs in our parser.");
return;
}
if (settings && confirm('This will overwite existing proxy settings. Are you sure?')) { callback(settings); }
else { callback(); }
};
reader.onerror = () => { alert('Error reading file'); };
reader.readAsText(file);
}
// import | options
static exportFile() {
chrome.storage.local.get(null, result => {
browser.runtime.getBrowserInfo().then((bi) => {
!result.sync ? Utils.saveAs(result, bi.version) : chrome.storage.sync.get(null, result => {
Utils.saveAs(result, bi.version, true);
});
});
});
}
// exportFile helper
static saveAs(data, browserVersion, sync) {
const settings = data; //Utils.prepareForSettings(data);
// Browser version and extension version. These are used for debugging.
settings.browserVersion = browserVersion;
settings.foxyProxyVersion = chrome.runtime.getManifest().version;
settings.foxyProxyEdition = FOXYPROXY_BASIC ? 'basic' : 'standard';
settings.sync = sync;
const blob = new Blob([JSON.stringify(settings, null, 2)], {type : 'text/plain;charset=utf-8'});
const filename = chrome.i18n.getMessage('extensionName') + '_' + new Date().toISOString().substring(0, 10) + '.json';
chrome.downloads.download({
url: URL.createObjectURL(blob),
filename,
saveAs: true,
conflictAction: 'uniquify'
});
}
static updateIcon(iconPath, color, title, titleIsKey, badgeText, badgeTextIsKey) {
chrome.browserAction.setIcon({path: iconPath});
if (color) {
chrome.browserAction.setBadgeBackgroundColor({color: color});
}
else {
// TODO: confirm this is OK to do
chrome.browserAction.setBadgeBackgroundColor({color: null});
}
if (title) {
chrome.browserAction.setTitle({title: 'FoxyProxy: ' + (titleIsKey ? chrome.i18n.getMessage(title) : title)});
}
else {
chrome.browserAction.setTitle({title: ''});
}
if (badgeText) {
chrome.browserAction.setBadgeText({text: badgeTextIsKey ? chrome.i18n.getMessage(badgeText) : badgeText});
}
else {
chrome.browserAction.setBadgeText({text: ''});
}
}
static getProxyTitle(proxySetting) {
if (proxySetting.title) {
return proxySetting.title;
}
else if (proxySetting.type === PROXY_TYPE_NONE) {
return 'Direct (no proxy)';
}
else {
return `${proxySetting.address}:${proxySetting.port}`;
}
}
/*
// utils only used for export, will be removed as DB format export is adapted
static prepareForSettings(settings = {}) {
//if (settings && !settings.mode) { }// 5.0 settings
let lastResortFound = false;
const prefKeys = Object.keys(settings);
const def = {
id: LASTRESORT,
active: true,
title: 'Default',
notes: 'These are the settings that are used when no patterns match a URL.',
color: '#0055E5',
type: PROXY_TYPE_NONE,
whitePatterns: [PATTERN_ALL_WHITE],
blackPatterns: []
};
// base format
const ret = {
mode: 'disabled',
proxySettings: [],
logging: {
size: 500,
active: true
}
};
if (!prefKeys.length) { // settings is {}
ret.proxySettings = [def];
return ret;
}
prefKeys.forEach(key => {
switch (key) {
case 'mode':
case 'logging':
ret[key] = settings[key];
break;
case 'sync': break; // do nothing
default:
const temp = settings[key];
temp.id = key; // Copy the id into the object
temp.id === LASTRESORT && (lastResortFound = true);
ret.proxySettings.push(temp);
}
});
ret.proxySettings.sort((a, b) => a.index - b.index);
ret.proxySettings.forEach(item => delete item.index); // Re-calculated when/if this object is written to disk again (user may move proxySetting up/down)
!lastResortFound && ret.proxySettings.push(def); // add default lastresort
return ret;
}
*/
static getUniqueId() {
// We don't need cryptographically secure UUIDs, just something unique
return Math.random().toString(36).substring(7) + new Date().getTime();
}
static stripBadChars(str) {
return str ? str.replace(/[&<>"']+/g, '') : null;
}
}

629
src/styles/app.css Normal file
View file

@ -0,0 +1,629 @@
body {
background: #630;
color: #333;
font-family: "Helvetica Neue", Helvetica, Roboto, Arial, sans-serif;
margin: 0;
padding: 1em;
animation: fadein 0.3s ease-in-out;
}
body::after {
content: '';
background-image: url('/images/logo.svg');
background-repeat: no-repeat;
background-size: contain;
position: absolute;
bottom: 0.5em;
right: 0.5em;
display: inline-block;
width: 128px;
height: 128px;
opacity: 0.3;
z-index: -1;
}
@keyframes fadein {
from { opacity: 0; }
to { opacity: 1; }
}
* {
box-sizing: border-box;
}
.flex {
display: flex;
}
.flex > * {
flex: 1;
}
img {
vertical-align: text-bottom;
}
a {
color: #f90;
text-decoration: none;
transition: all 0.5s ease-in-out;
}
a:hover {
color: #c60;
}
h1, h2, h3, h4, h5, h6 {
color: #c60;
}
fieldset {
border-radius: 10px;
margin-bottom: 1em;
border: 1px solid #ccc;
}
legend {
color: #c60;
font-size: 1.1em;
}
table {
border-spacing: 0;
width: 100%;
}
th {
background-color: #eee;
padding: 0.4em;
text-align: left;
border-bottom: 1px solid #fff;
}
tr{
background-color: #f8f8f8;
}
tbody tr:nth-child(even) {
background-color: #f5fffa;
}
tbody tr:hover {
background-color: #cae1d3;
}
td {
padding: 0.2em;
}
.ellipsis {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
button, .button {
background: #f90;
border-radius: 3px;
border: 0;
color: #fff;
cursor: pointer;
display: inline-block;
font-size: 0.9em;
font-weight: bold;
margin: 0 0 0 0.5em;
min-width: 6em;
padding: 0.4em 1em;
text-align: center;
transition: all 0.3s ease-out;
vertical-align: middle;
-webkit-appearance: none;
-moz-appearance: none;
}
button:not(.plain):hover, .button:hover {
background: #e37f08;
box-shadow: 0px 1px 5px rgba(0,0,0,0.3);
}
button.small {
font-size: 0.8em;
padding: 0.3em 0.5em;
min-width: 2em;
}
button.alert {
background: #ec5840;
}
button.alert:hover {
background: #dc143c;
}
button.plain {
background: transparent;
padding: 0;
margin: 0;
min-width: 1em;
}
button[type="submit"] {
background-color: #4682b4;
}
button[type="submit"]:hover {
background-color: #05a;
}
label {
/* font-size: 0.9em;*/
}
input::placeholder {
font-style: italic;
}
input[type="file"] {
display: none;
}
[type="text"], [type="password"], [type="url"], textarea {
background-color: #fefefe;
border-radius: 5px;
border: 1px solid #ccc;
box-shadow: inset 0 1px 2px rgba(10, 10, 10, 0.1);
color: #999;
display: inline-block;
font-size: 1em;
margin: 0 0 1em;
padding: 0.5em;
transition: all 0.5s;
width: 100%;
}
[type="text"]:focus, [type="password"]:focus, [type="url"]:focus, textarea:focus {
border: 1px solid #999;
box-shadow: 0 0 5px #cacaca;
}
select {
background-color: #f8f8ff;
background-image: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" version="1.1" width="32" height="24" viewBox="0 0 32 24" fill="rgb(255, 153, 0)"><polygon points="0,0 32,0 16,24"></polygon></svg>');
background-position: right 0.5em center;
background-repeat: no-repeat;
background-size: 14px;
border-radius: 5px;
border: 1px solid #ccc;
color: #999;
font-size: 1em;
margin: 0 0 1em;
padding: 0.5em;
width: 100%;
-webkit-appearance: none;
-moz-appearance: none;
}
select:disabled {
background-color: #e6e6e6;
cursor: default;
}
select[multiple] {
height: auto;
}
/* ----- switch ----- */
input.switch {
display: none;
}
input.switch + label {
background: #ddd;
border-radius: 5px;
box-shadow: 0px 1px 3px rgba(0,0,0,0.5);
cursor: pointer;
display: inline-block;
height: 1.5em;
margin-right: 0.5em;
position: relative;
text-align: left;
transition: all 0.5s ease-in-out;
vertical-align: middle;
width: 3.5em;
font-size: 0.9em;
}
input.switch + label::before {
background: #ccc;
border-radius: 5px;
box-shadow:inset 0px 1px 3px rgba(0,0,0,0.5);
content: '';
display: block;
height: 1.1em;
left: 0.2em;
position: absolute;
top: 0.2em;
transition: all 0.5s ease-in-out;
width: 1.1em;
}
input.switch:checked + label {
background: #f90;
}
input.switch:checked + label::before {
left: 2.2em;
background: #fff;
}
input.switch + label::after {
display: inline-block;
content: 'Off';
color: #fff;
margin-left: 1.8em;
transition: all 0.5s ease-in-out;
font-weight: bold;
vertical-align: middle;
}
input.switch:checked + label::after {
content: 'On';
margin-left: 0.2em;
}
/* ----- /switch ----- */
.template {
display: none !important;
}
.invalid {
background-color: rgba(236, 88, 64, 0.1);
border-color: #ec5840;
}
.hide {
display: none;
}
.bold {
font-weight: bold;
}
.prime {
margin: 0 0 1em 0;
padding: 1em;
border-radius: 5px;
background-color: white;
}
.prime.alert {
background-color: #fce6e2;
border: 1px solid #ccc;
}
.prime.warning {
background-color: #fff3d9;
border: 1px solid #ccc;
}
.prime.small {
padding: 0.5em;
border: 1px solid #ccc;
}
.prime.tiny {
margin: 0;
padding: 0.1em;
font-size: 0.8em;
border: 1px solid #ccc;
}
.fp-orange, .orangehover:hover {
color: #f90;
}
.flag {
font-size: 1.5em;
cursor: help;
width: 1em;
display: inline-block;
margin-left: 0.5em;
}
.success {
background-color: #e1faea;
}
.success:hover {
background-color: #cae1d3;
}
.secondary {
background-color: #ebebeb;
}
.secondary:hover {
background: #d4d4d4;
}
.unsupported {
background-color: #fce6e2;
border: 1px solid #ccc;
}
.unsupported:hover {
background-color: #e1ceca;
color: #fff;
}
.header {
color: #c60;
font-size: 1.5em;
font-weight: bold;
padding: 0.5em;
margin: 0 0 0.5rem 0;
}
.header::before {
content: '';
background-image: url('/images/icon.svg');
background-repeat: no-repeat;
background-size: contain;
vertical-align: middle;
margin-right: 0.5em;
display: inline-block;
width: 48px;
height: 48px;
}
.header.browserPopup {
font-size: 1.4em;
padding: 0.4em;
}
.header.browserPopup::before {
width: 36px;
height: 36px;
}
.scroll {
max-height: 50vh;
overflow-y: auto;
scrollbar-color: #ddd #f5f5f5;
scrollbar-width: thin;
}
.spinner {
align-items: center;
background-color: rgba(255, 255, 255, 0.8);
color: #f90;
display: flex;
font-size: 14em;
height: 100%;
justify-content: center;
left: 0;
margin: 0;
opacity: 0;
position: fixed;
top: 0;
transition: all 0.5s ease-in-out;
width: 100%;
z-index: 10000;
}
.spinner.on {
opacity: 0.5;
}
/* ----- Popup ----- */
.popup {
display: none;
align-items: center;
justify-content: center;
background-color: rgba(255, 255, 255, 0.8);
margin: 0;
width: 100%;
height: 100%;
position: fixed;
top: 0;
left: 0;
opacity: 0;
z-index: 10000;
transition: all 0.5s ease-in-out;
}
.popup.on {
opacity: 1;
}
.popup.on div:first-child {
transform: scale(1);
}
.popup div:first-child {
display: inline-block;
background-color: #fff;
border-radius: 10px;
box-shadow: 0 10px 30px 0 rgba(0, 0, 0, 0.2), 0 10px 15px 0 rgba(0, 0, 0, 0.3);
transform: scale(0.8);
transition: all 0.5s ease-in-out;
width: 50vw;
}
.popup div div {
margin: 1em;
}
.popup h3 {
color: #fff;
background-color: #630;
margin: 0 0 1em;
padding: 0.5em;
border-radius: 10px 10px 0 0 ;
}
.popup h3::before {
content: '';
background-image: url('/images/icon.svg');
background-size: contain;
vertical-align: middle;
margin-right: 0.5em;
display: inline-block;
width: 36px;
height: 36px;
}
.popup h4 {
margin-bottom: 0;
}
.popup p {
margin: 0;
}
/* ----- /Popup ----- */
/* ----- fa ----- */
i.fa {
color: #f90;
display: inline-block;
text-align: center;
transition: all 0.5s ease-in-out;
}
i.fa:hover {
}
a i.fa {
color: inherit;
}
i.fa.fa-eye {
font-size: 1.2em;
}
input[type="password"] + button i.fa.fa-eye {
color: #f90;
}
input[type="text"] + button i.fa.fa-eye {
color: #ccc;
}
/* ----- tooltip ----- */
.tooltip {
position: relative;
cursor: help;
display: inline-block;
}
.tooltip .tooltiptext {
visibility: hidden;
width: 20em;
background-color: #630;
color: white;
text-align: center;
border-radius: 3px;
padding: .8em;
position: absolute;
z-index: 1;
bottom: 125%;
left: 10%;
margin-left: -2em;
opacity: 0;
transition: all 0.5s ease-in-out;
font-weight: normal;
box-shadow: 0px 1px 5px rgba(0,0,0,0.5);
font-size: 0.9rem;
}
.tooltip .tooltiptext::after {
content: '';
position: absolute;
top: 100%;
left: 1em;
border-width: 5px;
border-style: solid;
border-color: #555 transparent transparent transparent;
}
.tooltip:hover .tooltiptext {
visibility: visible;
opacity: 1;
}
.tooltiptext.center {
margin-left: -10em;
}
.tooltiptext.center::after {
left: 50%;
}
.tooltiptext.bottom {
top: 125%;
bottom: auto;
}
.tooltiptext.bottom::after {
bottom: 100%;
top: auto;
left: 75%;
border-color: transparent transparent #555 transparent;
}
.tooltip i.fa {
font-size: 1.2em;
color: black;
}
.tooltip i.fa:hover {
color: #f90;
}
.tooltiptable {
/* https://stackoverflow.com/questions/20626685/better-way-to-set-distance-between-flexbox-items */
display: flex;
flex-direction: row;
flex-wrap: wrap;
justify-content: space-between;
text-align: left;
}
.tooltiptable > div {
/*
1/ - 2 columns per row
.5em - spacing between rows
*/
box-sizing: border-box;
margin-bottom: .5em;
width: calc(1/2*100% - (1 - 1/2)*10px);
}
.tooltiptablefooter {
margin-top: 1em;
text-align: justify;
}
.monospace {
font-family: monospace;
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 179 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 264 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 260 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 114 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 121 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 387 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 259 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 314 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 314 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 384 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 332 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 123 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.3 KiB