├── LICENSE
├── README.md
├── css
└── main.css
├── favicon.ico
├── index.html
├── js
├── app.js
├── functions.js
└── lib
│ └── underscore-min.js
└── run.py
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2015 libre-net-society
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
23 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # i2pd-webui
2 | Fancy i2pd web user interface
3 |
4 | # Usage:
5 |
6 | Git clone repo to your computer.
7 |
8 | Run i2pd with i2pcontrol port listening at 7650, for example:
9 |
10 | ./i2p --i2pcontrolport=7650
11 |
12 | Then run web ui:
13 |
14 | python3 run.py
15 |
16 | Visit http://127.0.0.1:8082/ and enjoy fancy i2pd webui! ;)
17 |
--------------------------------------------------------------------------------
/css/main.css:
--------------------------------------------------------------------------------
1 | /*!
2 | Pure v0.6.0
3 | Copyright 2014 Yahoo! Inc. All rights reserved.
4 | Licensed under the BSD License.
5 | https://github.com/yahoo/pure/blob/master/LICENSE.md
6 | */
7 | /*!
8 | normalize.css v^3.0 | MIT License | git.io/normalize
9 | Copyright (c) Nicolas Gallagher and Jonathan Neal
10 | */
11 | /*! normalize.css v3.0.2 | MIT License | git.io/normalize */html{font-family:sans-serif;-ms-text-size-adjust:100%;-webkit-text-size-adjust:100%}body{margin:0}article,aside,details,figcaption,figure,footer,header,hgroup,main,menu,nav,section,summary{display:block}audio,canvas,progress,video{display:inline-block;vertical-align:baseline}audio:not([controls]){display:none;height:0}[hidden],template{display:none}a{background-color:transparent}a:active,a:hover{outline:0}abbr[title]{border-bottom:1px dotted}b,strong{font-weight:700}dfn{font-style:italic}h1{font-size:2em;margin:.67em 0}mark{background:#ff0;color:#000}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sup{top:-.5em}sub{bottom:-.25em}img{border:0}svg:not(:root){overflow:hidden}figure{margin:1em 40px}hr{-moz-box-sizing:content-box;box-sizing:content-box;height:0}pre{overflow:auto}code,kbd,pre,samp{font-family:monospace,monospace;font-size:1em}button,input,optgroup,select,textarea{color:inherit;font:inherit;margin:0}button{overflow:visible}button,select{text-transform:none}button,html input[type=button],input[type=reset],input[type=submit]{-webkit-appearance:button;cursor:pointer}button[disabled],html input[disabled]{cursor:default}button::-moz-focus-inner,input::-moz-focus-inner{border:0;padding:0}input{line-height:normal}input[type=checkbox],input[type=radio]{box-sizing:border-box;padding:0}input[type=number]::-webkit-inner-spin-button,input[type=number]::-webkit-outer-spin-button{height:auto}input[type=search]{-webkit-appearance:textfield;-moz-box-sizing:content-box;-webkit-box-sizing:content-box;box-sizing:content-box}input[type=search]::-webkit-search-cancel-button,input[type=search]::-webkit-search-decoration{-webkit-appearance:none}fieldset{border:1px solid silver;margin:0 2px;padding:.35em .625em .75em}legend{border:0;padding:0}textarea{overflow:auto}optgroup{font-weight:700}table{border-collapse:collapse;border-spacing:0}td,th{padding:0}.hidden,[hidden]{display:none!important}.pure-img{max-width:100%;height:auto;display:block}.pure-g{letter-spacing:-.31em;*letter-spacing:normal;*word-spacing:-.43em;text-rendering:optimizespeed;font-family:FreeSans,Arimo,"Droid Sans",Helvetica,Arial,sans-serif;display:-webkit-flex;-webkit-flex-flow:row wrap;display:-ms-flexbox;-ms-flex-flow:row wrap;-ms-align-content:flex-start;-webkit-align-content:flex-start;align-content:flex-start}.opera-only :-o-prefocus,.pure-g{word-spacing:-.43em}.pure-u{display:inline-block;*display:inline;zoom:1;letter-spacing:normal;word-spacing:normal;vertical-align:top;text-rendering:auto}.pure-g [class *="pure-u"]{font-family:sans-serif}.pure-u-1,.pure-u-1-1,.pure-u-1-2,.pure-u-1-3,.pure-u-2-3,.pure-u-1-4,.pure-u-3-4,.pure-u-1-5,.pure-u-2-5,.pure-u-3-5,.pure-u-4-5,.pure-u-5-5,.pure-u-1-6,.pure-u-5-6,.pure-u-1-8,.pure-u-3-8,.pure-u-5-8,.pure-u-7-8,.pure-u-1-12,.pure-u-5-12,.pure-u-7-12,.pure-u-11-12,.pure-u-1-24,.pure-u-2-24,.pure-u-3-24,.pure-u-4-24,.pure-u-5-24,.pure-u-6-24,.pure-u-7-24,.pure-u-8-24,.pure-u-9-24,.pure-u-10-24,.pure-u-11-24,.pure-u-12-24,.pure-u-13-24,.pure-u-14-24,.pure-u-15-24,.pure-u-16-24,.pure-u-17-24,.pure-u-18-24,.pure-u-19-24,.pure-u-20-24,.pure-u-21-24,.pure-u-22-24,.pure-u-23-24,.pure-u-24-24{display:inline-block;*display:inline;zoom:1;letter-spacing:normal;word-spacing:normal;vertical-align:top;text-rendering:auto}.pure-u-1-24{width:4.1667%;*width:4.1357%}.pure-u-1-12,.pure-u-2-24{width:8.3333%;*width:8.3023%}.pure-u-1-8,.pure-u-3-24{width:12.5%;*width:12.469%}.pure-u-1-6,.pure-u-4-24{width:16.6667%;*width:16.6357%}.pure-u-1-5{width:20%;*width:19.969%}.pure-u-5-24{width:20.8333%;*width:20.8023%}.pure-u-1-4,.pure-u-6-24{width:25%;*width:24.969%}.pure-u-7-24{width:29.1667%;*width:29.1357%}.pure-u-1-3,.pure-u-8-24{width:33.3333%;*width:33.3023%}.pure-u-3-8,.pure-u-9-24{width:37.5%;*width:37.469%}.pure-u-2-5{width:40%;*width:39.969%}.pure-u-5-12,.pure-u-10-24{width:41.6667%;*width:41.6357%}.pure-u-11-24{width:45.8333%;*width:45.8023%}.pure-u-1-2,.pure-u-12-24{width:50%;*width:49.969%}.pure-u-13-24{width:54.1667%;*width:54.1357%}.pure-u-7-12,.pure-u-14-24{width:58.3333%;*width:58.3023%}.pure-u-3-5{width:60%;*width:59.969%}.pure-u-5-8,.pure-u-15-24{width:62.5%;*width:62.469%}.pure-u-2-3,.pure-u-16-24{width:66.6667%;*width:66.6357%}.pure-u-17-24{width:70.8333%;*width:70.8023%}.pure-u-3-4,.pure-u-18-24{width:75%;*width:74.969%}.pure-u-19-24{width:79.1667%;*width:79.1357%}.pure-u-4-5{width:80%;*width:79.969%}.pure-u-5-6,.pure-u-20-24{width:83.3333%;*width:83.3023%}.pure-u-7-8,.pure-u-21-24{width:87.5%;*width:87.469%}.pure-u-11-12,.pure-u-22-24{width:91.6667%;*width:91.6357%}.pure-u-23-24{width:95.8333%;*width:95.8023%}.pure-u-1,.pure-u-1-1,.pure-u-5-5,.pure-u-24-24{width:100%}.pure-button{display:inline-block;zoom:1;line-height:normal;white-space:nowrap;vertical-align:middle;text-align:center;cursor:pointer;-webkit-user-drag:none;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}.pure-button::-moz-focus-inner{padding:0;border:0}.pure-button{font-family:inherit;font-size:100%;padding:.5em 1em;color:#444;color:rgba(0,0,0,.8);border:1px solid #999;border:0 rgba(0,0,0,0);background-color:#E6E6E6;text-decoration:none;border-radius:2px}.pure-button-hover,.pure-button:hover,.pure-button:focus{filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#00000000', endColorstr='#1a000000', GradientType=0);background-image:-webkit-gradient(linear,0 0,0 100%,from(transparent),color-stop(40%,rgba(0,0,0,.05)),to(rgba(0,0,0,.1)));background-image:-webkit-linear-gradient(transparent,rgba(0,0,0,.05) 40%,rgba(0,0,0,.1));background-image:-moz-linear-gradient(top,rgba(0,0,0,.05) 0,rgba(0,0,0,.1));background-image:-o-linear-gradient(transparent,rgba(0,0,0,.05) 40%,rgba(0,0,0,.1));background-image:linear-gradient(transparent,rgba(0,0,0,.05) 40%,rgba(0,0,0,.1))}.pure-button:focus{outline:0}.pure-button-active,.pure-button:active{box-shadow:0 0 0 1px rgba(0,0,0,.15) inset,0 0 6px rgba(0,0,0,.2) inset;border-color:#000\9}.pure-button[disabled],.pure-button-disabled,.pure-button-disabled:hover,.pure-button-disabled:focus,.pure-button-disabled:active{border:0;background-image:none;filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);filter:alpha(opacity=40);-khtml-opacity:.4;-moz-opacity:.4;opacity:.4;cursor:not-allowed;box-shadow:none}.pure-button-hidden{display:none}.pure-button::-moz-focus-inner{padding:0;border:0}.pure-button-primary,.pure-button-selected,a.pure-button-primary,a.pure-button-selected{background-color:#0078e7;color:#fff}.pure-form input[type=text],.pure-form input[type=password],.pure-form input[type=email],.pure-form input[type=url],.pure-form input[type=date],.pure-form input[type=month],.pure-form input[type=time],.pure-form input[type=datetime],.pure-form input[type=datetime-local],.pure-form input[type=week],.pure-form input[type=number],.pure-form input[type=search],.pure-form input[type=tel],.pure-form input[type=color],.pure-form select,.pure-form textarea{padding:.5em .6em;display:inline-block;border:1px solid #ccc;box-shadow:inset 0 1px 3px #ddd;border-radius:4px;vertical-align:middle;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}.pure-form input:not([type]){padding:.5em .6em;display:inline-block;border:1px solid #ccc;box-shadow:inset 0 1px 3px #ddd;border-radius:4px;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}.pure-form input[type=color]{padding:.2em .5em}.pure-form input[type=text]:focus,.pure-form input[type=password]:focus,.pure-form input[type=email]:focus,.pure-form input[type=url]:focus,.pure-form input[type=date]:focus,.pure-form input[type=month]:focus,.pure-form input[type=time]:focus,.pure-form input[type=datetime]:focus,.pure-form input[type=datetime-local]:focus,.pure-form input[type=week]:focus,.pure-form input[type=number]:focus,.pure-form input[type=search]:focus,.pure-form input[type=tel]:focus,.pure-form input[type=color]:focus,.pure-form select:focus,.pure-form textarea:focus{outline:0;border-color:#129FEA}.pure-form input:not([type]):focus{outline:0;border-color:#129FEA}.pure-form input[type=file]:focus,.pure-form input[type=radio]:focus,.pure-form input[type=checkbox]:focus{outline:thin solid #129FEA;outline:1px auto #129FEA}.pure-form .pure-checkbox,.pure-form .pure-radio{margin:.5em 0;display:block}.pure-form input[type=text][disabled],.pure-form input[type=password][disabled],.pure-form input[type=email][disabled],.pure-form input[type=url][disabled],.pure-form input[type=date][disabled],.pure-form input[type=month][disabled],.pure-form input[type=time][disabled],.pure-form input[type=datetime][disabled],.pure-form input[type=datetime-local][disabled],.pure-form input[type=week][disabled],.pure-form input[type=number][disabled],.pure-form input[type=search][disabled],.pure-form input[type=tel][disabled],.pure-form input[type=color][disabled],.pure-form select[disabled],.pure-form textarea[disabled]{cursor:not-allowed;background-color:#eaeded;color:#cad2d3}.pure-form input:not([type])[disabled]{cursor:not-allowed;background-color:#eaeded;color:#cad2d3}.pure-form input[readonly],.pure-form select[readonly],.pure-form textarea[readonly]{background-color:#eee;color:#777;border-color:#ccc}.pure-form input:focus:invalid,.pure-form textarea:focus:invalid,.pure-form select:focus:invalid{color:#b94a48;border-color:#e9322d}.pure-form input[type=file]:focus:invalid:focus,.pure-form input[type=radio]:focus:invalid:focus,.pure-form input[type=checkbox]:focus:invalid:focus{outline-color:#e9322d}.pure-form select{height:2.25em;border:1px solid #ccc;background-color:#fff}.pure-form select[multiple]{height:auto}.pure-form label{margin:.5em 0 .2em}.pure-form fieldset{margin:0;padding:.35em 0 .75em;border:0}.pure-form legend{display:block;width:100%;padding:.3em 0;margin-bottom:.3em;color:#333;border-bottom:1px solid #e5e5e5}.pure-form-stacked input[type=text],.pure-form-stacked input[type=password],.pure-form-stacked input[type=email],.pure-form-stacked input[type=url],.pure-form-stacked input[type=date],.pure-form-stacked input[type=month],.pure-form-stacked input[type=time],.pure-form-stacked input[type=datetime],.pure-form-stacked input[type=datetime-local],.pure-form-stacked input[type=week],.pure-form-stacked input[type=number],.pure-form-stacked input[type=search],.pure-form-stacked input[type=tel],.pure-form-stacked input[type=color],.pure-form-stacked input[type=file],.pure-form-stacked select,.pure-form-stacked label,.pure-form-stacked textarea{display:block;margin:.25em 0}.pure-form-stacked input:not([type]){display:block;margin:.25em 0}.pure-form-aligned input,.pure-form-aligned textarea,.pure-form-aligned select,.pure-form-aligned .pure-help-inline,.pure-form-message-inline{display:inline-block;*display:inline;*zoom:1;vertical-align:middle}.pure-form-aligned textarea{vertical-align:top}.pure-form-aligned .pure-control-group{margin-bottom:.5em}.pure-form-aligned .pure-control-group label{text-align:right;display:inline-block;vertical-align:middle;width:10em;margin:0 1em 0 0}.pure-form-aligned .pure-controls{margin:1.5em 0 0 11em}.pure-form input.pure-input-rounded,.pure-form .pure-input-rounded{border-radius:2em;padding:.5em 1em}.pure-form .pure-group fieldset{margin-bottom:10px}.pure-form .pure-group input,.pure-form .pure-group textarea{display:block;padding:10px;margin:0 0 -1px;border-radius:0;position:relative;top:-1px}.pure-form .pure-group input:focus,.pure-form .pure-group textarea:focus{z-index:3}.pure-form .pure-group input:first-child,.pure-form .pure-group textarea:first-child{top:1px;border-radius:4px 4px 0 0;margin:0}.pure-form .pure-group input:first-child:last-child,.pure-form .pure-group textarea:first-child:last-child{top:1px;border-radius:4px;margin:0}.pure-form .pure-group input:last-child,.pure-form .pure-group textarea:last-child{top:-2px;border-radius:0 0 4px 4px;margin:0}.pure-form .pure-group button{margin:.35em 0}.pure-form .pure-input-1{width:100%}.pure-form .pure-input-2-3{width:66%}.pure-form .pure-input-1-2{width:50%}.pure-form .pure-input-1-3{width:33%}.pure-form .pure-input-1-4{width:25%}.pure-form .pure-help-inline,.pure-form-message-inline{display:inline-block;padding-left:.3em;color:#666;vertical-align:middle;font-size:.875em}.pure-form-message{display:block;color:#666;font-size:.875em}@media only screen and (max-width :480px){.pure-form button[type=submit]{margin:.7em 0 0}.pure-form input:not([type]),.pure-form input[type=text],.pure-form input[type=password],.pure-form input[type=email],.pure-form input[type=url],.pure-form input[type=date],.pure-form input[type=month],.pure-form input[type=time],.pure-form input[type=datetime],.pure-form input[type=datetime-local],.pure-form input[type=week],.pure-form input[type=number],.pure-form input[type=search],.pure-form input[type=tel],.pure-form input[type=color],.pure-form label{margin-bottom:.3em;display:block}.pure-group input:not([type]),.pure-group input[type=text],.pure-group input[type=password],.pure-group input[type=email],.pure-group input[type=url],.pure-group input[type=date],.pure-group input[type=month],.pure-group input[type=time],.pure-group input[type=datetime],.pure-group input[type=datetime-local],.pure-group input[type=week],.pure-group input[type=number],.pure-group input[type=search],.pure-group input[type=tel],.pure-group input[type=color]{margin-bottom:0}.pure-form-aligned .pure-control-group label{margin-bottom:.3em;text-align:left;display:block;width:100%}.pure-form-aligned .pure-controls{margin:1.5em 0 0}.pure-form .pure-help-inline,.pure-form-message-inline,.pure-form-message{display:block;font-size:.75em;padding:.2em 0 .8em}}.pure-menu{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}.pure-menu-fixed{position:fixed;left:0;top:0;z-index:3}.pure-menu-list,.pure-menu-item{position:relative}.pure-menu-list{list-style:none;margin:0;padding:0}.pure-menu-item{padding:0;margin:0;height:100%}.pure-menu-link,.pure-menu-heading{display:block;text-decoration:none;white-space:nowrap}.pure-menu-horizontal{width:100%;white-space:nowrap}.pure-menu-horizontal .pure-menu-list{display:inline-block}.pure-menu-horizontal .pure-menu-item,.pure-menu-horizontal .pure-menu-heading,.pure-menu-horizontal .pure-menu-separator{display:inline-block;*display:inline;zoom:1;vertical-align:middle}.pure-menu-item .pure-menu-item{display:block}.pure-menu-children{display:none;position:absolute;left:100%;top:0;margin:0;padding:0;z-index:3}.pure-menu-horizontal .pure-menu-children{left:0;top:auto;width:inherit}.pure-menu-allow-hover:hover>.pure-menu-children,.pure-menu-active>.pure-menu-children{display:block;position:absolute}.pure-menu-has-children>.pure-menu-link:after{padding-left:.5em;content:"\25B8";font-size:small}.pure-menu-horizontal .pure-menu-has-children>.pure-menu-link:after{content:"\25BE"}.pure-menu-scrollable{overflow-y:scroll;overflow-x:hidden}.pure-menu-scrollable .pure-menu-list{display:block}.pure-menu-horizontal.pure-menu-scrollable .pure-menu-list{display:inline-block}.pure-menu-horizontal.pure-menu-scrollable{white-space:nowrap;overflow-y:hidden;overflow-x:auto;-ms-overflow-style:none;-webkit-overflow-scrolling:touch;padding:.5em 0}.pure-menu-horizontal.pure-menu-scrollable::-webkit-scrollbar{display:none}.pure-menu-separator{background-color:#ccc;height:1px;margin:.3em 0}.pure-menu-horizontal .pure-menu-separator{width:1px;height:1.3em;margin:0 .3em}.pure-menu-heading{text-transform:uppercase;color:#565d64}.pure-menu-link{color:#777}.pure-menu-children{background-color:#fff}.pure-menu-link,.pure-menu-disabled,.pure-menu-heading{padding:.5em 1em}.pure-menu-disabled{opacity:.5}.pure-menu-disabled .pure-menu-link:hover{background-color:transparent}.pure-menu-active>.pure-menu-link,.pure-menu-link:hover,.pure-menu-link:focus{background-color:#eee}.pure-menu-selected .pure-menu-link,.pure-menu-selected .pure-menu-link:visited{color:#000}.pure-table{border-collapse:collapse;border-spacing:0;empty-cells:show;border:1px solid #cbcbcb}.pure-table caption{color:#000;font:italic 85%/1 arial,sans-serif;padding:1em 0;text-align:center}.pure-table td,.pure-table th{border-left:1px solid #cbcbcb;border-width:0 0 0 1px;font-size:inherit;margin:0;overflow:visible;padding:.5em 1em}.pure-table td:first-child,.pure-table th:first-child{border-left-width:0}.pure-table thead{background-color:#e0e0e0;color:#000;text-align:left;vertical-align:bottom}.pure-table td{background-color:transparent}.pure-table-odd td{background-color:#f2f2f2}.pure-table-striped tr:nth-child(2n-1) td{background-color:#f2f2f2}.pure-table-bordered td{border-bottom:1px solid #cbcbcb}.pure-table-bordered tbody>tr:last-child>td{border-bottom-width:0}.pure-table-horizontal td,.pure-table-horizontal th{border-width:0 0 1px;border-bottom:1px solid #cbcbcb}.pure-table-horizontal tbody>tr:last-child>td{border-bottom-width:0}body {
12 | color: #777;
13 | }
14 |
15 | .pure-img-responsive {
16 | max-width: 100%;
17 | height: auto;
18 | }
19 |
20 | /*
21 | Add transition to containers so they can push in and out.
22 | */
23 | #layout,
24 | #menu,
25 | .menu-link {
26 | -webkit-transition: all 0.2s ease-out;
27 | -moz-transition: all 0.2s ease-out;
28 | -ms-transition: all 0.2s ease-out;
29 | -o-transition: all 0.2s ease-out;
30 | transition: all 0.2s ease-out;
31 | }
32 |
33 | /*
34 | This is the parent `
` that contains the menu and the content area.
35 | */
36 | #layout {
37 | position: relative;
38 | padding-left: 0;
39 | }
40 | #layout.active #menu {
41 | left: 150px;
42 | width: 150px;
43 | }
44 |
45 | #layout.active .menu-link {
46 | left: 150px;
47 | }
48 | /*
49 | The content `
` is where all your content goes.
50 | */
51 | .content {
52 | margin: 0 auto;
53 | padding: 0 2em;
54 | max-width: 800px;
55 | margin-bottom: 50px;
56 | line-height: 1.6em;
57 | }
58 |
59 | .header {
60 | margin: 0;
61 | color: #333;
62 | text-align: center;
63 | padding: 2.5em 2em 0;
64 | border-bottom: 1px solid #eee;
65 | }
66 | .header h1 {
67 | margin: 0.2em 0;
68 | font-size: 3em;
69 | font-weight: 300;
70 | }
71 | .header h2 {
72 | font-weight: 300;
73 | color: #ccc;
74 | padding: 0;
75 | margin-top: 0;
76 | }
77 |
78 | .content-subhead {
79 | margin: 50px 0 20px 0;
80 | font-weight: 300;
81 | color: #888;
82 | }
83 |
84 |
85 |
86 | /*
87 | The `#menu` `
` is the parent `
` that contains the `.pure-menu` that
88 | appears on the left side of the page.
89 | */
90 |
91 | #menu {
92 | margin-left: -150px; /* "#menu" width */
93 | width: 150px;
94 | position: fixed;
95 | top: 0;
96 | left: 0;
97 | bottom: 0;
98 | z-index: 1000; /* so the menu or its navicon stays above all content */
99 | background: #191818;
100 | overflow-y: auto;
101 | -webkit-overflow-scrolling: touch;
102 | }
103 | /*
104 | All anchors inside the menu should be styled like this.
105 | */
106 | #menu a {
107 | color: #999;
108 | border: none;
109 | padding: 0.6em 0 0.6em 0.6em;
110 | }
111 |
112 | /*
113 | Remove all background/borders, since we are applying them to #menu.
114 | */
115 | #menu .pure-menu,
116 | #menu .pure-menu ul {
117 | border: none;
118 | background: transparent;
119 | }
120 |
121 | /*
122 | Add that light border to separate items into groups.
123 | */
124 | #menu .pure-menu ul,
125 | #menu .pure-menu .menu-item-divided {
126 | border-top: 1px solid #333;
127 | }
128 | /*
129 | Change color of the anchor links on hover/focus.
130 | */
131 | #menu .pure-menu li a:hover,
132 | #menu .pure-menu li a:focus {
133 | background: #333;
134 | }
135 |
136 | /*
137 | This styles the selected menu item `
`.
138 | */
139 | #menu .pure-menu-selected,
140 | #menu .pure-menu-heading {
141 | background: #1f8dd6;
142 | }
143 | /*
144 | This styles a link within a selected menu item ``.
145 | */
146 | #menu .pure-menu-selected a {
147 | color: #fff;
148 | }
149 |
150 | /*
151 | This styles the menu heading.
152 | */
153 | #menu .pure-menu-heading {
154 | font-size: 110%;
155 | color: #fff;
156 | margin: 0;
157 | }
158 |
159 | /* -- Dynamic Button For Responsive Menu -------------------------------------*/
160 |
161 | /*
162 | The button to open/close the Menu is custom-made and not part of Pure. Here's
163 | how it works:
164 | */
165 |
166 | /*
167 | `.menu-link` represents the responsive menu toggle that shows/hides on
168 | small screens.
169 | */
170 | .menu-link {
171 | position: fixed;
172 | display: block; /* show this only on small screens */
173 | top: 0;
174 | left: 0; /* "#menu width" */
175 | background: #000;
176 | background: rgba(0,0,0,0.7);
177 | font-size: 10px; /* change this value to increase/decrease button size */
178 | z-index: 10;
179 | width: 2em;
180 | height: auto;
181 | padding: 2.1em 1.6em;
182 | }
183 |
184 | .menu-link:hover,
185 | .menu-link:focus {
186 | background: #000;
187 | }
188 |
189 | .menu-link span {
190 | position: relative;
191 | display: block;
192 | }
193 |
194 | .menu-link span,
195 | .menu-link span:before,
196 | .menu-link span:after {
197 | background-color: #fff;
198 | width: 100%;
199 | height: 0.2em;
200 | }
201 |
202 | .menu-link span:before,
203 | .menu-link span:after {
204 | position: absolute;
205 | margin-top: -0.6em;
206 | content: " ";
207 | }
208 |
209 | .menu-link span:after {
210 | margin-top: 0.6em;
211 | }
212 |
213 |
214 | /* -- Responsive Styles (Media Queries) ------------------------------------- */
215 |
216 | /*
217 | Hides the menu at `48em`, but modify this based on your app's needs.
218 | */
219 | @media (min-width: 48em) {
220 |
221 | .header,
222 | .content {
223 | padding-left: 2em;
224 | padding-right: 2em;
225 | }
226 |
227 | #layout {
228 | padding-left: 150px; /* left col width "#menu" */
229 | left: 0;
230 | }
231 | #menu {
232 | left: 150px;
233 | }
234 |
235 | .menu-link {
236 | position: fixed;
237 | left: 150px;
238 | display: none;
239 | }
240 |
241 | #layout.active .menu-link {
242 | left: 150px;
243 | }
244 | }
245 |
246 | @media (max-width: 48em) {
247 | /* Only apply this when the window is small. Otherwise, the following
248 | case results in extra padding on the left:
249 | * Make the window small.
250 | * Tap the menu to trigger the active state.
251 | * Make the window large again.
252 | */
253 | #layout.active {
254 | position: relative;
255 | left: 150px;
256 | }
257 | }
258 |
259 |
--------------------------------------------------------------------------------
/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/l-n-s/i2pd-webui/33bc65d1fe0530e85d3248423be06025b5b3fab0/favicon.ico
--------------------------------------------------------------------------------
/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | I2Pd webUI 0.1a (demo)
6 |
7 |
8 |
9 |
10 |
50 |
51 |
68 |
69 |
80 |
81 |
82 |
83 |
84 |
87 |
88 |
99 |
100 |
101 |
104 |
105 |
106 |
107 |
108 |
109 |
119 |
120 |
121 |
122 |
--------------------------------------------------------------------------------
/js/app.js:
--------------------------------------------------------------------------------
1 | /*
2 | * Quick and dirty demo control panel for PurpleI2P
3 | *
4 | */
5 |
6 | var ready = new Event('ready');
7 |
8 | var app = {
9 | 'getToken': function() {
10 | doAjax(function() {
11 | if (this.readyState == 4) {
12 | if (this.status == "200" && this.responseText != "") {
13 | window.token = JSON.parse(this.responseText).result.Token;
14 | document.dispatchEvent(ready);
15 | } else {
16 | document.open(); document.write(this.responseText); document.close();
17 | throw new Error("Something is not working");
18 | }
19 | }
20 | }, _jrc("Authenticate", { "API": 1, "Password": app.password }));
21 | },
22 |
23 | 'init': function() {
24 | app.getToken();
25 | document.addEventListener('ready', router, false);
26 | },
27 |
28 | 'password': "itoopie",
29 | };
30 |
31 | route("/", function(){
32 | basicRender("home", _jrc("RouterInfo", {
33 | "i2p.router.version": "",
34 | "i2p.router.net.status": "",
35 | "Token": window.token
36 | }), frontPageEvents);
37 |
38 | fetchStats();
39 | window.refresh = setInterval(fetchStats, 10000);
40 | });
41 |
42 | route("/config", function(){
43 | var jsonData = _jrc("NetworkSetting", {
44 | "i2p.router.net.bw.in": null,
45 | "i2p.router.net.bw.out": null,
46 | //"i2p.router.net.bw.share": null,
47 | "Token": window.token
48 | });
49 | basicRender("config", jsonData, configPageEvents);
50 | });
51 |
52 | route("/help", function(){
53 | basicRender("help");
54 | });
55 |
56 |
57 |
--------------------------------------------------------------------------------
/js/functions.js:
--------------------------------------------------------------------------------
1 | // PureCSS menu toggle
2 | (function (window, document) {
3 |
4 | var layout = document.getElementById('layout'),
5 | menu = document.getElementById('menu'),
6 | menuLink = document.getElementById('menuLink');
7 |
8 | function toggleClass(element, className) {
9 | var classes = element.className.split(/\s+/),
10 | length = classes.length,
11 | i = 0;
12 |
13 | for(; i < length; i++) {
14 | if (classes[i] === className) {
15 | classes.splice(i, 1);
16 | break;
17 | }
18 | }
19 | // The className is not found
20 | if (length === classes.length) {
21 | classes.push(className);
22 | }
23 |
24 | element.className = classes.join(' ');
25 | }
26 |
27 | menuLink.onclick = function (e) {
28 | var active = 'active';
29 |
30 | e.preventDefault();
31 | toggleClass(layout, active);
32 | toggleClass(menu, active);
33 | toggleClass(menuLink, active);
34 | };
35 |
36 | }(this, this.document));
37 |
38 | function msToString(mseconds) {
39 | // ms to string for uptime
40 | var seconds = mseconds / 1000;
41 | var numdays = Math.floor(seconds / 86400);
42 | var numhours = Math.floor((seconds % 86400) / 3600);
43 | var numminutes = Math.floor(((seconds % 86400) % 3600) / 60);
44 | var numseconds = ((seconds % 86400) % 3600) % 60;
45 |
46 | return numdays + "d " + numhours + "h " + numminutes + "m " + numseconds + "s";
47 | }
48 |
49 | function doAjax(responseHandler, data) {
50 | responseHandler = responseHandler || null;
51 | data = data || null;
52 | var xmlHttpRequst = new XMLHttpRequest();
53 |
54 | xmlHttpRequst.open("POST", "", true);
55 | xmlHttpRequst.setRequestHeader('Content-Type', 'application/json');
56 | xmlHttpRequst.onreadystatechange = responseHandler;
57 | xmlHttpRequst.send(data);
58 | }
59 |
60 | function _id(id) {
61 | return document.getElementById(id);
62 | }
63 |
64 | function _inHTML(id, value) {
65 | _id(id).innerHTML = value;
66 | return true;
67 | }
68 |
69 | function renderPage(templateId, args) {
70 | // write template to main div
71 | args = args || {};
72 | var template = _.template(_id(templateId).innerHTML)(args);
73 | _inHTML("main", template);
74 | }
75 |
76 | function basicRender(templateId, jsonData, onReady) {
77 | jsonData = jsonData || null;
78 | onReady = onReady || null;
79 |
80 | if (jsonData) {
81 | doAjax(function(){
82 | if (this.readyState == 4 && this.status == "200" && this.responseText != "") {
83 | //console.log(this.responseText);
84 | var result = JSON.parse(this.responseText).result;
85 | renderPage(templateId, {"r": result});
86 | if (onReady) onReady();
87 | }
88 | }, jsonData);
89 | } else {
90 | renderPage(templateId);
91 | if (onReady) onReady();
92 | }
93 | };
94 |
95 | function _jrc(method, params) {
96 | // JsonRpcConverter
97 | var obj = {
98 | "id": 1,
99 | "method": method,
100 | "params": params,
101 | "jsonrpc": "2.0"
102 | }
103 | return JSON.stringify(obj);
104 | }
105 |
106 | function fetchStats() {
107 | var jsonData = _jrc("RouterInfo", {
108 | "i2p.router.uptime": "",
109 | "i2p.router.net.tunnels.participating": "",
110 | "i2p.router.netdb.activepeers": "",
111 | "i2p.router.netdb.knownpeers": "",
112 | "i2p.router.net.bw.inbound.1s": "",
113 | "i2p.router.net.bw.outbound.1s": "",
114 | "Token": window.token
115 | });
116 |
117 | doAjax(function(){
118 | if (this.readyState == 4 && this.status == "200" && this.responseText != "") {
119 | //console.log(this.responseText);
120 | var result = JSON.parse(this.responseText).result;
121 | _inHTML("uptime", msToString(result["i2p.router.uptime"]));
122 | _inHTML("tunnels-participating", result["i2p.router.net.tunnels.participating"]);
123 | _inHTML("activepeers", result["i2p.router.netdb.activepeers"]);
124 | _inHTML("knownpeers", result["i2p.router.netdb.knownpeers"]);
125 | _inHTML("bw-in", result["i2p.router.net.bw.inbound.1s"]);
126 | _inHTML("bw-out", result["i2p.router.net.bw.outbound.1s"]);
127 | }
128 | }, jsonData);
129 | };
130 |
131 | /* Routing */
132 | var routes = {};
133 | function route(path, controller) {
134 | routes[path] = {controller: controller};
135 | }
136 |
137 | var el = null;
138 | function router() {
139 | el = el || _id("main");
140 | var url = location.hash.slice(1) || '/';
141 | var route = routes[url];
142 |
143 | if (el && route.controller) {
144 | if (window.refresh) clearInterval(window.refresh);
145 | route.controller();
146 | }
147 | }
148 |
149 | /*
150 | * Do RouterManager request and reload on success
151 | */
152 | function dumbRequest(data) {
153 | doAjax(function() {
154 | if (this.readyState == 4 && this.status == "200")
155 | window.location.reload();
156 | }, _jrc("RouterManager", data));
157 | }
158 |
159 | function frontPageEvents() {
160 | _id("restart").addEventListener('click', function() {
161 | dumbRequest({"Restart": null, "Token": window.token});
162 | });
163 | _id("reseed").addEventListener('click', function(){
164 | dumbRequest({"Reseed": null, "Token": window.token});
165 | });
166 | _id("shutdown").addEventListener('click', function(){
167 | dumbRequest({"Shutdown": null, "Token": window.token});
168 | });
169 | }
170 |
171 | function configPageEvents() {
172 | _id("config-form").addEventListener('submit', function(evt) {
173 | evt.preventDefault();
174 | var form = _id("config-form");
175 | doAjax(function() {
176 | if (this.readyState == 4 && this.status == "200") {
177 | var result = JSON.parse(this.responseText).result;
178 | if (result["SettingsSaved"] == true)
179 | alert("Network settings changed!");
180 | }
181 | }, _jrc("NetworkSetting", {
182 | "i2p.router.net.bw.in": form.bwin.value,
183 | "i2p.router.net.bw.out": form.bwout.value,
184 | //"i2p.router.net.bw.share": form.bwshare.value,
185 | "Token": window.token,
186 | }));
187 | return false;
188 | });
189 | }
190 |
--------------------------------------------------------------------------------
/js/lib/underscore-min.js:
--------------------------------------------------------------------------------
1 | // Underscore.js 1.8.3
2 | // http://underscorejs.org
3 | // (c) 2009-2015 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors
4 | // Underscore may be freely distributed under the MIT license.
5 | (function(){function n(n){function t(t,r,e,u,i,o){for(;i>=0&&o>i;i+=n){var a=u?u[i]:i;e=r(e,t[a],a,t)}return e}return function(r,e,u,i){e=b(e,i,4);var o=!k(r)&&m.keys(r),a=(o||r).length,c=n>0?0:a-1;return arguments.length<3&&(u=r[o?o[c]:c],c+=n),t(r,e,u,o,c,a)}}function t(n){return function(t,r,e){r=x(r,e);for(var u=O(t),i=n>0?0:u-1;i>=0&&u>i;i+=n)if(r(t[i],i,t))return i;return-1}}function r(n,t,r){return function(e,u,i){var o=0,a=O(e);if("number"==typeof i)n>0?o=i>=0?i:Math.max(i+a,o):a=i>=0?Math.min(i+1,a):i+a+1;else if(r&&i&&a)return i=r(e,u),e[i]===u?i:-1;if(u!==u)return i=t(l.call(e,o,a),m.isNaN),i>=0?i+o:-1;for(i=n>0?o:a-1;i>=0&&a>i;i+=n)if(e[i]===u)return i;return-1}}function e(n,t){var r=I.length,e=n.constructor,u=m.isFunction(e)&&e.prototype||a,i="constructor";for(m.has(n,i)&&!m.contains(t,i)&&t.push(i);r--;)i=I[r],i in n&&n[i]!==u[i]&&!m.contains(t,i)&&t.push(i)}var u=this,i=u._,o=Array.prototype,a=Object.prototype,c=Function.prototype,f=o.push,l=o.slice,s=a.toString,p=a.hasOwnProperty,h=Array.isArray,v=Object.keys,g=c.bind,y=Object.create,d=function(){},m=function(n){return n instanceof m?n:this instanceof m?void(this._wrapped=n):new m(n)};"undefined"!=typeof exports?("undefined"!=typeof module&&module.exports&&(exports=module.exports=m),exports._=m):u._=m,m.VERSION="1.8.3";var b=function(n,t,r){if(t===void 0)return n;switch(null==r?3:r){case 1:return function(r){return n.call(t,r)};case 2:return function(r,e){return n.call(t,r,e)};case 3:return function(r,e,u){return n.call(t,r,e,u)};case 4:return function(r,e,u,i){return n.call(t,r,e,u,i)}}return function(){return n.apply(t,arguments)}},x=function(n,t,r){return null==n?m.identity:m.isFunction(n)?b(n,t,r):m.isObject(n)?m.matcher(n):m.property(n)};m.iteratee=function(n,t){return x(n,t,1/0)};var _=function(n,t){return function(r){var e=arguments.length;if(2>e||null==r)return r;for(var u=1;e>u;u++)for(var i=arguments[u],o=n(i),a=o.length,c=0;a>c;c++){var f=o[c];t&&r[f]!==void 0||(r[f]=i[f])}return r}},j=function(n){if(!m.isObject(n))return{};if(y)return y(n);d.prototype=n;var t=new d;return d.prototype=null,t},w=function(n){return function(t){return null==t?void 0:t[n]}},A=Math.pow(2,53)-1,O=w("length"),k=function(n){var t=O(n);return"number"==typeof t&&t>=0&&A>=t};m.each=m.forEach=function(n,t,r){t=b(t,r);var e,u;if(k(n))for(e=0,u=n.length;u>e;e++)t(n[e],e,n);else{var i=m.keys(n);for(e=0,u=i.length;u>e;e++)t(n[i[e]],i[e],n)}return n},m.map=m.collect=function(n,t,r){t=x(t,r);for(var e=!k(n)&&m.keys(n),u=(e||n).length,i=Array(u),o=0;u>o;o++){var a=e?e[o]:o;i[o]=t(n[a],a,n)}return i},m.reduce=m.foldl=m.inject=n(1),m.reduceRight=m.foldr=n(-1),m.find=m.detect=function(n,t,r){var e;return e=k(n)?m.findIndex(n,t,r):m.findKey(n,t,r),e!==void 0&&e!==-1?n[e]:void 0},m.filter=m.select=function(n,t,r){var e=[];return t=x(t,r),m.each(n,function(n,r,u){t(n,r,u)&&e.push(n)}),e},m.reject=function(n,t,r){return m.filter(n,m.negate(x(t)),r)},m.every=m.all=function(n,t,r){t=x(t,r);for(var e=!k(n)&&m.keys(n),u=(e||n).length,i=0;u>i;i++){var o=e?e[i]:i;if(!t(n[o],o,n))return!1}return!0},m.some=m.any=function(n,t,r){t=x(t,r);for(var e=!k(n)&&m.keys(n),u=(e||n).length,i=0;u>i;i++){var o=e?e[i]:i;if(t(n[o],o,n))return!0}return!1},m.contains=m.includes=m.include=function(n,t,r,e){return k(n)||(n=m.values(n)),("number"!=typeof r||e)&&(r=0),m.indexOf(n,t,r)>=0},m.invoke=function(n,t){var r=l.call(arguments,2),e=m.isFunction(t);return m.map(n,function(n){var u=e?t:n[t];return null==u?u:u.apply(n,r)})},m.pluck=function(n,t){return m.map(n,m.property(t))},m.where=function(n,t){return m.filter(n,m.matcher(t))},m.findWhere=function(n,t){return m.find(n,m.matcher(t))},m.max=function(n,t,r){var e,u,i=-1/0,o=-1/0;if(null==t&&null!=n){n=k(n)?n:m.values(n);for(var a=0,c=n.length;c>a;a++)e=n[a],e>i&&(i=e)}else t=x(t,r),m.each(n,function(n,r,e){u=t(n,r,e),(u>o||u===-1/0&&i===-1/0)&&(i=n,o=u)});return i},m.min=function(n,t,r){var e,u,i=1/0,o=1/0;if(null==t&&null!=n){n=k(n)?n:m.values(n);for(var a=0,c=n.length;c>a;a++)e=n[a],i>e&&(i=e)}else t=x(t,r),m.each(n,function(n,r,e){u=t(n,r,e),(o>u||1/0===u&&1/0===i)&&(i=n,o=u)});return i},m.shuffle=function(n){for(var t,r=k(n)?n:m.values(n),e=r.length,u=Array(e),i=0;e>i;i++)t=m.random(0,i),t!==i&&(u[i]=u[t]),u[t]=r[i];return u},m.sample=function(n,t,r){return null==t||r?(k(n)||(n=m.values(n)),n[m.random(n.length-1)]):m.shuffle(n).slice(0,Math.max(0,t))},m.sortBy=function(n,t,r){return t=x(t,r),m.pluck(m.map(n,function(n,r,e){return{value:n,index:r,criteria:t(n,r,e)}}).sort(function(n,t){var r=n.criteria,e=t.criteria;if(r!==e){if(r>e||r===void 0)return 1;if(e>r||e===void 0)return-1}return n.index-t.index}),"value")};var F=function(n){return function(t,r,e){var u={};return r=x(r,e),m.each(t,function(e,i){var o=r(e,i,t);n(u,e,o)}),u}};m.groupBy=F(function(n,t,r){m.has(n,r)?n[r].push(t):n[r]=[t]}),m.indexBy=F(function(n,t,r){n[r]=t}),m.countBy=F(function(n,t,r){m.has(n,r)?n[r]++:n[r]=1}),m.toArray=function(n){return n?m.isArray(n)?l.call(n):k(n)?m.map(n,m.identity):m.values(n):[]},m.size=function(n){return null==n?0:k(n)?n.length:m.keys(n).length},m.partition=function(n,t,r){t=x(t,r);var e=[],u=[];return m.each(n,function(n,r,i){(t(n,r,i)?e:u).push(n)}),[e,u]},m.first=m.head=m.take=function(n,t,r){return null==n?void 0:null==t||r?n[0]:m.initial(n,n.length-t)},m.initial=function(n,t,r){return l.call(n,0,Math.max(0,n.length-(null==t||r?1:t)))},m.last=function(n,t,r){return null==n?void 0:null==t||r?n[n.length-1]:m.rest(n,Math.max(0,n.length-t))},m.rest=m.tail=m.drop=function(n,t,r){return l.call(n,null==t||r?1:t)},m.compact=function(n){return m.filter(n,m.identity)};var S=function(n,t,r,e){for(var u=[],i=0,o=e||0,a=O(n);a>o;o++){var c=n[o];if(k(c)&&(m.isArray(c)||m.isArguments(c))){t||(c=S(c,t,r));var f=0,l=c.length;for(u.length+=l;l>f;)u[i++]=c[f++]}else r||(u[i++]=c)}return u};m.flatten=function(n,t){return S(n,t,!1)},m.without=function(n){return m.difference(n,l.call(arguments,1))},m.uniq=m.unique=function(n,t,r,e){m.isBoolean(t)||(e=r,r=t,t=!1),null!=r&&(r=x(r,e));for(var u=[],i=[],o=0,a=O(n);a>o;o++){var c=n[o],f=r?r(c,o,n):c;t?(o&&i===f||u.push(c),i=f):r?m.contains(i,f)||(i.push(f),u.push(c)):m.contains(u,c)||u.push(c)}return u},m.union=function(){return m.uniq(S(arguments,!0,!0))},m.intersection=function(n){for(var t=[],r=arguments.length,e=0,u=O(n);u>e;e++){var i=n[e];if(!m.contains(t,i)){for(var o=1;r>o&&m.contains(arguments[o],i);o++);o===r&&t.push(i)}}return t},m.difference=function(n){var t=S(arguments,!0,!0,1);return m.filter(n,function(n){return!m.contains(t,n)})},m.zip=function(){return m.unzip(arguments)},m.unzip=function(n){for(var t=n&&m.max(n,O).length||0,r=Array(t),e=0;t>e;e++)r[e]=m.pluck(n,e);return r},m.object=function(n,t){for(var r={},e=0,u=O(n);u>e;e++)t?r[n[e]]=t[e]:r[n[e][0]]=n[e][1];return r},m.findIndex=t(1),m.findLastIndex=t(-1),m.sortedIndex=function(n,t,r,e){r=x(r,e,1);for(var u=r(t),i=0,o=O(n);o>i;){var a=Math.floor((i+o)/2);r(n[a])i;i++,n+=r)u[i]=n;return u};var E=function(n,t,r,e,u){if(!(e instanceof t))return n.apply(r,u);var i=j(n.prototype),o=n.apply(i,u);return m.isObject(o)?o:i};m.bind=function(n,t){if(g&&n.bind===g)return g.apply(n,l.call(arguments,1));if(!m.isFunction(n))throw new TypeError("Bind must be called on a function");var r=l.call(arguments,2),e=function(){return E(n,e,t,this,r.concat(l.call(arguments)))};return e},m.partial=function(n){var t=l.call(arguments,1),r=function(){for(var e=0,u=t.length,i=Array(u),o=0;u>o;o++)i[o]=t[o]===m?arguments[e++]:t[o];for(;e=e)throw new Error("bindAll must be passed function names");for(t=1;e>t;t++)r=arguments[t],n[r]=m.bind(n[r],n);return n},m.memoize=function(n,t){var r=function(e){var u=r.cache,i=""+(t?t.apply(this,arguments):e);return m.has(u,i)||(u[i]=n.apply(this,arguments)),u[i]};return r.cache={},r},m.delay=function(n,t){var r=l.call(arguments,2);return setTimeout(function(){return n.apply(null,r)},t)},m.defer=m.partial(m.delay,m,1),m.throttle=function(n,t,r){var e,u,i,o=null,a=0;r||(r={});var c=function(){a=r.leading===!1?0:m.now(),o=null,i=n.apply(e,u),o||(e=u=null)};return function(){var f=m.now();a||r.leading!==!1||(a=f);var l=t-(f-a);return e=this,u=arguments,0>=l||l>t?(o&&(clearTimeout(o),o=null),a=f,i=n.apply(e,u),o||(e=u=null)):o||r.trailing===!1||(o=setTimeout(c,l)),i}},m.debounce=function(n,t,r){var e,u,i,o,a,c=function(){var f=m.now()-o;t>f&&f>=0?e=setTimeout(c,t-f):(e=null,r||(a=n.apply(i,u),e||(i=u=null)))};return function(){i=this,u=arguments,o=m.now();var f=r&&!e;return e||(e=setTimeout(c,t)),f&&(a=n.apply(i,u),i=u=null),a}},m.wrap=function(n,t){return m.partial(t,n)},m.negate=function(n){return function(){return!n.apply(this,arguments)}},m.compose=function(){var n=arguments,t=n.length-1;return function(){for(var r=t,e=n[t].apply(this,arguments);r--;)e=n[r].call(this,e);return e}},m.after=function(n,t){return function(){return--n<1?t.apply(this,arguments):void 0}},m.before=function(n,t){var r;return function(){return--n>0&&(r=t.apply(this,arguments)),1>=n&&(t=null),r}},m.once=m.partial(m.before,2);var M=!{toString:null}.propertyIsEnumerable("toString"),I=["valueOf","isPrototypeOf","toString","propertyIsEnumerable","hasOwnProperty","toLocaleString"];m.keys=function(n){if(!m.isObject(n))return[];if(v)return v(n);var t=[];for(var r in n)m.has(n,r)&&t.push(r);return M&&e(n,t),t},m.allKeys=function(n){if(!m.isObject(n))return[];var t=[];for(var r in n)t.push(r);return M&&e(n,t),t},m.values=function(n){for(var t=m.keys(n),r=t.length,e=Array(r),u=0;r>u;u++)e[u]=n[t[u]];return e},m.mapObject=function(n,t,r){t=x(t,r);for(var e,u=m.keys(n),i=u.length,o={},a=0;i>a;a++)e=u[a],o[e]=t(n[e],e,n);return o},m.pairs=function(n){for(var t=m.keys(n),r=t.length,e=Array(r),u=0;r>u;u++)e[u]=[t[u],n[t[u]]];return e},m.invert=function(n){for(var t={},r=m.keys(n),e=0,u=r.length;u>e;e++)t[n[r[e]]]=r[e];return t},m.functions=m.methods=function(n){var t=[];for(var r in n)m.isFunction(n[r])&&t.push(r);return t.sort()},m.extend=_(m.allKeys),m.extendOwn=m.assign=_(m.keys),m.findKey=function(n,t,r){t=x(t,r);for(var e,u=m.keys(n),i=0,o=u.length;o>i;i++)if(e=u[i],t(n[e],e,n))return e},m.pick=function(n,t,r){var e,u,i={},o=n;if(null==o)return i;m.isFunction(t)?(u=m.allKeys(o),e=b(t,r)):(u=S(arguments,!1,!1,1),e=function(n,t,r){return t in r},o=Object(o));for(var a=0,c=u.length;c>a;a++){var f=u[a],l=o[f];e(l,f,o)&&(i[f]=l)}return i},m.omit=function(n,t,r){if(m.isFunction(t))t=m.negate(t);else{var e=m.map(S(arguments,!1,!1,1),String);t=function(n,t){return!m.contains(e,t)}}return m.pick(n,t,r)},m.defaults=_(m.allKeys,!0),m.create=function(n,t){var r=j(n);return t&&m.extendOwn(r,t),r},m.clone=function(n){return m.isObject(n)?m.isArray(n)?n.slice():m.extend({},n):n},m.tap=function(n,t){return t(n),n},m.isMatch=function(n,t){var r=m.keys(t),e=r.length;if(null==n)return!e;for(var u=Object(n),i=0;e>i;i++){var o=r[i];if(t[o]!==u[o]||!(o in u))return!1}return!0};var N=function(n,t,r,e){if(n===t)return 0!==n||1/n===1/t;if(null==n||null==t)return n===t;n instanceof m&&(n=n._wrapped),t instanceof m&&(t=t._wrapped);var u=s.call(n);if(u!==s.call(t))return!1;switch(u){case"[object RegExp]":case"[object String]":return""+n==""+t;case"[object Number]":return+n!==+n?+t!==+t:0===+n?1/+n===1/t:+n===+t;case"[object Date]":case"[object Boolean]":return+n===+t}var i="[object Array]"===u;if(!i){if("object"!=typeof n||"object"!=typeof t)return!1;var o=n.constructor,a=t.constructor;if(o!==a&&!(m.isFunction(o)&&o instanceof o&&m.isFunction(a)&&a instanceof a)&&"constructor"in n&&"constructor"in t)return!1}r=r||[],e=e||[];for(var c=r.length;c--;)if(r[c]===n)return e[c]===t;if(r.push(n),e.push(t),i){if(c=n.length,c!==t.length)return!1;for(;c--;)if(!N(n[c],t[c],r,e))return!1}else{var f,l=m.keys(n);if(c=l.length,m.keys(t).length!==c)return!1;for(;c--;)if(f=l[c],!m.has(t,f)||!N(n[f],t[f],r,e))return!1}return r.pop(),e.pop(),!0};m.isEqual=function(n,t){return N(n,t)},m.isEmpty=function(n){return null==n?!0:k(n)&&(m.isArray(n)||m.isString(n)||m.isArguments(n))?0===n.length:0===m.keys(n).length},m.isElement=function(n){return!(!n||1!==n.nodeType)},m.isArray=h||function(n){return"[object Array]"===s.call(n)},m.isObject=function(n){var t=typeof n;return"function"===t||"object"===t&&!!n},m.each(["Arguments","Function","String","Number","Date","RegExp","Error"],function(n){m["is"+n]=function(t){return s.call(t)==="[object "+n+"]"}}),m.isArguments(arguments)||(m.isArguments=function(n){return m.has(n,"callee")}),"function"!=typeof/./&&"object"!=typeof Int8Array&&(m.isFunction=function(n){return"function"==typeof n||!1}),m.isFinite=function(n){return isFinite(n)&&!isNaN(parseFloat(n))},m.isNaN=function(n){return m.isNumber(n)&&n!==+n},m.isBoolean=function(n){return n===!0||n===!1||"[object Boolean]"===s.call(n)},m.isNull=function(n){return null===n},m.isUndefined=function(n){return n===void 0},m.has=function(n,t){return null!=n&&p.call(n,t)},m.noConflict=function(){return u._=i,this},m.identity=function(n){return n},m.constant=function(n){return function(){return n}},m.noop=function(){},m.property=w,m.propertyOf=function(n){return null==n?function(){}:function(t){return n[t]}},m.matcher=m.matches=function(n){return n=m.extendOwn({},n),function(t){return m.isMatch(t,n)}},m.times=function(n,t,r){var e=Array(Math.max(0,n));t=b(t,r,1);for(var u=0;n>u;u++)e[u]=t(u);return e},m.random=function(n,t){return null==t&&(t=n,n=0),n+Math.floor(Math.random()*(t-n+1))},m.now=Date.now||function(){return(new Date).getTime()};var B={"&":"&","<":"<",">":">",'"':""","'":"'","`":"`"},T=m.invert(B),R=function(n){var t=function(t){return n[t]},r="(?:"+m.keys(n).join("|")+")",e=RegExp(r),u=RegExp(r,"g");return function(n){return n=null==n?"":""+n,e.test(n)?n.replace(u,t):n}};m.escape=R(B),m.unescape=R(T),m.result=function(n,t,r){var e=null==n?void 0:n[t];return e===void 0&&(e=r),m.isFunction(e)?e.call(n):e};var q=0;m.uniqueId=function(n){var t=++q+"";return n?n+t:t},m.templateSettings={evaluate:/<%([\s\S]+?)%>/g,interpolate:/<%=([\s\S]+?)%>/g,escape:/<%-([\s\S]+?)%>/g};var K=/(.)^/,z={"'":"'","\\":"\\","\r":"r","\n":"n","\u2028":"u2028","\u2029":"u2029"},D=/\\|'|\r|\n|\u2028|\u2029/g,L=function(n){return"\\"+z[n]};m.template=function(n,t,r){!t&&r&&(t=r),t=m.defaults({},t,m.templateSettings);var e=RegExp([(t.escape||K).source,(t.interpolate||K).source,(t.evaluate||K).source].join("|")+"|$","g"),u=0,i="__p+='";n.replace(e,function(t,r,e,o,a){return i+=n.slice(u,a).replace(D,L),u=a+t.length,r?i+="'+\n((__t=("+r+"))==null?'':_.escape(__t))+\n'":e?i+="'+\n((__t=("+e+"))==null?'':__t)+\n'":o&&(i+="';\n"+o+"\n__p+='"),t}),i+="';\n",t.variable||(i="with(obj||{}){\n"+i+"}\n"),i="var __t,__p='',__j=Array.prototype.join,"+"print=function(){__p+=__j.call(arguments,'');};\n"+i+"return __p;\n";try{var o=new Function(t.variable||"obj","_",i)}catch(a){throw a.source=i,a}var c=function(n){return o.call(this,n,m)},f=t.variable||"obj";return c.source="function("+f+"){\n"+i+"}",c},m.chain=function(n){var t=m(n);return t._chain=!0,t};var P=function(n,t){return n._chain?m(t).chain():t};m.mixin=function(n){m.each(m.functions(n),function(t){var r=m[t]=n[t];m.prototype[t]=function(){var n=[this._wrapped];return f.apply(n,arguments),P(this,r.apply(m,n))}})},m.mixin(m),m.each(["pop","push","reverse","shift","sort","splice","unshift"],function(n){var t=o[n];m.prototype[n]=function(){var r=this._wrapped;return t.apply(r,arguments),"shift"!==n&&"splice"!==n||0!==r.length||delete r[0],P(this,r)}}),m.each(["concat","join","slice"],function(n){var t=o[n];m.prototype[n]=function(){return P(this,t.apply(this._wrapped,arguments))}}),m.prototype.value=function(){return this._wrapped},m.prototype.valueOf=m.prototype.toJSON=m.prototype.value,m.prototype.toString=function(){return""+this._wrapped},"function"==typeof define&&define.amd&&define("underscore",[],function(){return m})}).call(this);
6 | //# sourceMappingURL=underscore-min.map
--------------------------------------------------------------------------------
/run.py:
--------------------------------------------------------------------------------
1 | #! /usr/bin/python3
2 | import http.server
3 | import urllib.request, urllib.error, urllib.parse
4 | import os
5 | from os import sep
6 | import ssl
7 |
8 | #For localhost without certificates properly set up
9 | #SSL: CERTIFICATE_VERIFY_FAILED urllib.request.urlopen
10 | #https://www.python.org/dev/peps/pep-0476/
11 | try:
12 | _create_unverified_https_context = ssl._create_unverified_context
13 | except AttributeError:
14 | # Legacy Python that doesn't verify HTTPS certificates by default
15 | pass
16 | else:
17 | # Handle target environment that doesn't support HTTPS verification
18 | ssl._create_default_https_context = _create_unverified_https_context
19 |
20 | #WebUI Settings
21 | listen_port = 8082
22 | server_address = "127.0.0.1"
23 |
24 | #i2pd I2PControl port. https is mandatory by i2pcontrol
25 | i2pcontrol_url = "https://127.0.0.1:7650/"
26 |
27 | #Alternate solution SSL: CERTIFICATE_VERIFY_FAILED
28 | #gcontext = ssl._create_unverified_context()
29 | gcontext = ssl.SSLContext(ssl.PROTOCOL_TLSv1)
30 | urllib.request.HTTPSHandler(context=gcontext)
31 |
32 | __location__ = os.path.realpath(
33 | os.path.join(os.getcwd(), os.path.dirname(__file__)))
34 |
35 | #Fix Chrome can not load page at all
36 | #Fix ERR_INVALID_HTTP_RESPONSE when load css,js,ico files
37 | #Fix css was ignored due to mime type mismatch
38 | def get_header_type(file_path):
39 | file_types_pairs = [(".js","application/javascript"),(".css","text/css"),
40 | (".ico","image/x-icon")]
41 | file_dict = dict(file_types_pairs)
42 | filename, file_extension = os.path.splitext(file_path)
43 | #print(file_extension)
44 | if file_extension in file_dict:
45 | return file_dict[file_extension]
46 | return "text/html"
47 |
48 | def resp_html(s):
49 | """Response to GET requests with actual documents"""
50 | legal_files = ["/js/lib/underscore-min.js", "/js/app.js", "/js/functions.js",
51 | "/css/main.css","/favicon.ico"]
52 |
53 | if s.path == "/":
54 | s.send_response(200)
55 | s.send_header("Content-Type", "text/html")
56 | s.end_headers()
57 | with open(os.path.join(__location__, "index.html"), 'rb') as f:
58 | s.wfile.write(f.read())
59 | elif s.path in legal_files:
60 | file_path = s.path[1:].replace("/", sep)
61 | with open(os.path.join(__location__, file_path), 'rb') as f:
62 | s.send_response(200)
63 | s.send_header("Content-Type", get_header_type(file_path))
64 | s.end_headers()
65 | s.wfile.write(f.read())
66 | else:
67 | s.send_error(404, "Not Found")
68 | print("404 Not Found")
69 |
70 | def proxy_request(data, s):
71 | """Send data to i2pcontrol port and return response"""
72 |
73 | req = urllib.request.Request(i2pcontrol_url, data)
74 | print(("--> sending to i2pcontrol", data))
75 | try:
76 | response = urllib.request.urlopen(req)
77 | s.send_response(200)
78 | s.send_header("Content-Type", "application/json")
79 | s.end_headers()
80 | resp = response.read()
81 | print(("<-- recieved from i2pcontrol", resp))
82 | s.wfile.write(resp)
83 | except urllib.error.URLError as e:
84 | print(e)
85 | s.send_error(500, "Cannot connect to I2PControl port" + e)
86 |
87 | class MyHandler(http.server.BaseHTTPRequestHandler):
88 | def do_GET(s):
89 | resp_html(s)
90 |
91 | def do_POST(s):
92 | content_length = int(s.headers['Content-Length'])
93 | post_data = s.rfile.read(content_length)
94 | proxy_request(post_data, s)
95 |
96 | if __name__ == "__main__":
97 | httpd = http.server.HTTPServer((server_address, listen_port), MyHandler)
98 | try:
99 | print(("WebUI is listening at http://"+ server_address +":" + str(listen_port)))
100 | httpd.serve_forever()
101 | except KeyboardInterrupt:
102 | pass
103 |
104 | httpd.server_close()
105 |
--------------------------------------------------------------------------------