summaryrefslogtreecommitdiffhomepage
path: root/applications/luci-app-shadowsocks-libev/htdocs/luci-static
diff options
context:
space:
mode:
Diffstat (limited to 'applications/luci-app-shadowsocks-libev/htdocs/luci-static')
-rw-r--r--applications/luci-app-shadowsocks-libev/htdocs/luci-static/resources/shadowsocks-libev.js86
-rw-r--r--applications/luci-app-shadowsocks-libev/htdocs/luci-static/resources/view/shadowsocks-libev/instances.js23
-rw-r--r--applications/luci-app-shadowsocks-libev/htdocs/luci-static/resources/view/shadowsocks-libev/rules.js3
-rw-r--r--applications/luci-app-shadowsocks-libev/htdocs/luci-static/resources/view/shadowsocks-libev/servers.js57
4 files changed, 153 insertions, 16 deletions
diff --git a/applications/luci-app-shadowsocks-libev/htdocs/luci-static/resources/shadowsocks-libev.js b/applications/luci-app-shadowsocks-libev/htdocs/luci-static/resources/shadowsocks-libev.js
index 3aaaa50121..c0f1ced553 100644
--- a/applications/luci-app-shadowsocks-libev/htdocs/luci-static/resources/shadowsocks-libev.js
+++ b/applications/luci-app-shadowsocks-libev/htdocs/luci-static/resources/shadowsocks-libev.js
@@ -1,4 +1,5 @@
'use strict';
+'require baseclass';
'require uci';
'require form';
'require network';
@@ -20,6 +21,7 @@ var names_options_client = [
];
var names_options_common = [
+ 'local_address',
'verbose',
'ipv6_first',
'fast_open',
@@ -67,7 +69,7 @@ function ucival_to_bool(val) {
return val === 'true' || val === '1' || val === 'yes' || val === 'on';
}
-return L.Class.extend({
+return baseclass.extend({
values_actions: function(o) {
o.value('bypass');
o.value('forward');
@@ -99,7 +101,7 @@ return L.Class.extend({
}
});
},
- values_ipaddr: function(o, netDevs) {
+ values_ip4addr: function(o, netDevs) {
netDevs.forEach(function(v) {
v.getIPAddrs().forEach(function(a) {
var host = a.split('/')[0];
@@ -107,6 +109,18 @@ return L.Class.extend({
});
});
},
+ values_ip6addr: function(o, netDevs) {
+ netDevs.forEach(function(v) {
+ v.getIP6Addrs().forEach(function(a) {
+ var host = a.split('/')[0];
+ o.value(host, '%s (%s)'.format(host, v.getShortName()));
+ });
+ });
+ },
+ values_ipaddr: function(o, netDevs) {
+ this.values_ip4addr(o, netDevs)
+ this.values_ip6addr(o, netDevs)
+ },
options_client: function(s, tab, netDevs) {
var o = s.taboption(tab, form.ListValue, 'server', _('Remote server'));
this.values_serverlist(o);
@@ -190,7 +204,7 @@ return L.Class.extend({
if (stype === 'ss_server') {
this.cfgvalue_overview_(sdata, lines, names_options_server);
this.cfgvalue_overview_(sdata, lines, names_options_common);
- this.cfgvalue_overview_(sdata, lines, ['bind_address']);
+ this.cfgvalue_overview_(sdata, lines, ['local_ipv4_address', 'local_ipv6_address']);
} else if (stype === 'ss_local' || stype === 'ss_redir' || stype === 'ss_tunnel') {
this.cfgvalue_overview_(sdata, lines, names_options_client);
if (stype === 'ss_tunnel') {
@@ -238,5 +252,71 @@ return L.Class.extend({
window.open(L.url('admin/system/opkg') +
'?query=' + opkg_package, '_blank', 'noopener');
};
+ },
+ parse_uri: function(uri) {
+ var scheme = 'ss://';
+ if (uri && uri.indexOf(scheme) === 0) {
+ var atPos = uri.indexOf('@'), hashPos = uri.lastIndexOf('#'), tag;
+ if (hashPos === -1) {
+ hashPos = undefined;
+ } else {
+ tag = uri.slice(hashPos + 1);
+ }
+
+ if (atPos !== -1) { // SIP002 format https://shadowsocks.org/en/spec/SIP002-URI-Scheme.html
+ var colonPos = uri.indexOf(':', atPos + 1), slashPos = uri.indexOf('/', colonPos + 1);
+ if (colonPos === -1) return null;
+ if (slashPos === -1) slashPos = undefined;
+
+ var userinfo = atob(uri.slice(scheme.length, atPos)
+ .replace(/-/g, '+').replace(/_/g, '/')),
+ i = userinfo.indexOf(':');
+ if (i === -1) return null;
+
+ var config = {
+ server: uri.slice(atPos + 1, colonPos),
+ server_port: uri.slice(colonPos + 1, slashPos ? slashPos : hashPos),
+ password: userinfo.slice(i + 1),
+ method: userinfo.slice(0, i)
+ };
+
+ if (slashPos) {
+ var search = uri.slice(slashPos + 1, hashPos);
+ if (search[0] === '?') search = search.slice(1);
+ search.split('&').forEach(function(s) {
+ var j = s.indexOf('=');
+ if (j !== -1) {
+ var k = s.slice(0, j), v = s.slice(j + 1);
+ if (k === 'plugin') {
+ v = decodeURIComponent(v);
+ var k = v.indexOf(';');
+ if (k !== -1) {
+ config['plugin'] = v.slice(0, k);
+ config['plugin_opts'] = v.slice(k + 1);
+ }
+ }
+ }
+ });
+ }
+ return [config, tag];
+ } else { // Legacy format https://shadowsocks.org/en/config/quick-guide.html
+ var plain = atob(uri.slice(scheme.length, hashPos)),
+ firstColonPos = plain.indexOf(':'),
+ lastColonPos = plain.lastIndexOf(':'),
+ atPos = plain.lastIndexOf('@', lastColonPos);
+ if (firstColonPos === -1 ||
+ lastColonPos === -1 ||
+ atPos === -1) return null;
+
+ var config = {
+ server: plain.slice(atPos + 1, lastColonPos),
+ server_port: plain.slice(lastColonPos + 1),
+ password: plain.slice(firstColonPos + 1, atPos),
+ method: plain.slice(0, firstColonPos)
+ };
+ return [config, tag];
+ }
+ }
+ return null;
}
});
diff --git a/applications/luci-app-shadowsocks-libev/htdocs/luci-static/resources/view/shadowsocks-libev/instances.js b/applications/luci-app-shadowsocks-libev/htdocs/luci-static/resources/view/shadowsocks-libev/instances.js
index 27a2b950c2..671f17a9e4 100644
--- a/applications/luci-app-shadowsocks-libev/htdocs/luci-static/resources/view/shadowsocks-libev/instances.js
+++ b/applications/luci-app-shadowsocks-libev/htdocs/luci-static/resources/view/shadowsocks-libev/instances.js
@@ -1,4 +1,6 @@
'use strict';
+'require view';
+'require poll';
'require form';
'require uci';
'require fs';
@@ -16,7 +18,7 @@ var callServiceList = rpc.declare({
expect: { '': {} }
});
-return L.view.extend({
+return view.extend({
render: function(stats) {
var m, s, o;
@@ -82,12 +84,21 @@ return L.view.extend({
if (stype === 'ss_server') {
ss.options_server(s, { tab: 'general' });
- o = s.taboption('general', form.Value, 'bind_address',
- _('Bind address'),
- _('The address ss-server will initiate connection from'));
+ o = s.taboption('advanced', form.Value, 'local_address',
+ _('Local address'),
+ _('The address ss-server will initiate connections from'));
o.datatype = 'ipaddr';
- o.placeholder = '0.0.0.0';
ss.values_ipaddr(o, res[1]);
+ o = s.taboption('advanced', form.Value, 'local_ipv4_address',
+ _('Local IPv4 address'),
+ _('The IPv4 address ss-server will initiate IPv4 connections from'));
+ o.datatype = 'ip4addr';
+ ss.values_ip4addr(o, res[1]);
+ o = s.taboption('advanced', form.Value, 'local_ipv6_address',
+ _('Local IPv6 address'),
+ _('The IPv6 address ss-server will initiate IPv6 connections from'));
+ o.datatype = 'ip6addr';
+ ss.values_ip6addr(o, res[1]);
} else {
ss.options_client(s, 'general', res[1]);
if (stype === 'ss_tunnel') {
@@ -137,7 +148,7 @@ return L.view.extend({
}
return m.render().finally(function() {
- L.Poll.add(function() {
+ poll.add(function() {
return L.resolveDefault(callServiceList(conf), {})
.then(function(res) {
var instances = null;
diff --git a/applications/luci-app-shadowsocks-libev/htdocs/luci-static/resources/view/shadowsocks-libev/rules.js b/applications/luci-app-shadowsocks-libev/htdocs/luci-static/resources/view/shadowsocks-libev/rules.js
index 798237adbd..4cb653e57e 100644
--- a/applications/luci-app-shadowsocks-libev/htdocs/luci-static/resources/view/shadowsocks-libev/rules.js
+++ b/applications/luci-app-shadowsocks-libev/htdocs/luci-static/resources/view/shadowsocks-libev/rules.js
@@ -1,4 +1,5 @@
'use strict';
+'require view';
'require uci';
'require fs';
'require form';
@@ -12,7 +13,7 @@ function src_dst_option(s /*, ... */) {
o.datatype = 'or(ipaddr,cidr)';
}
-return L.view.extend({
+return view.extend({
load: function() {
return Promise.all([
L.resolveDefault(fs.stat('/usr/lib/iptables/libxt_recent.so'), {}),
diff --git a/applications/luci-app-shadowsocks-libev/htdocs/luci-static/resources/view/shadowsocks-libev/servers.js b/applications/luci-app-shadowsocks-libev/htdocs/luci-static/resources/view/shadowsocks-libev/servers.js
index d46bfb0aa7..57756b83e6 100644
--- a/applications/luci-app-shadowsocks-libev/htdocs/luci-static/resources/view/shadowsocks-libev/servers.js
+++ b/applications/luci-app-shadowsocks-libev/htdocs/luci-static/resources/view/shadowsocks-libev/servers.js
@@ -1,21 +1,66 @@
'use strict';
+'require view';
'require form';
+'require uci';
+'require ui';
'require shadowsocks-libev as ss';
-function startsWith(str, search) {
- return str.substring(0, search.length) === search;
-}
+var conf = 'shadowsocks-libev';
-return L.view.extend({
+return view.extend({
render: function() {
var m, s, o;
- m = new form.Map('shadowsocks-libev', _('Remote Servers'),
+ m = new form.Map(conf, _('Remote Servers'),
_('Definition of remote shadowsocks servers. \
Disable any of them will also disable instances referring to it.'));
s = m.section(form.GridSection, 'server');
s.addremove = true;
+ s.handleLinkImport = function() {
+ var textarea = new ui.Textarea();
+ ui.showModal(_('Import Links'), [
+ textarea.render(),
+ E('div', { class: 'right' }, [
+ E('button', {
+ class: 'btn',
+ click: ui.hideModal
+ }, [ _('Cancel') ]),
+ ' ',
+ E('button', {
+ class: 'btn cbi-button-action',
+ click: ui.createHandlerFn(this, function() {
+ textarea.getValue().split('\n').forEach(function(s) {
+ var config = ss.parse_uri(s);
+ if (config) {
+ var tag = config[1];
+ if (tag && !tag.match(/^[a-zA-Z0-9_]+$/)) tag = null;
+ var sid = uci.add(conf, 'server', tag);
+ config = config[0];
+ Object.keys(config).forEach(function(k) {
+ uci.set(conf, sid, k, config[k]);
+ });
+ }
+ });
+ return uci.save()
+ .then(L.bind(this.map.load, this.map))
+ .then(L.bind(this.map.reset, this.map))
+ .then(L.ui.hideModal)
+ .catch(function() {});
+ })
+ }, [ _('Import') ])
+ ])
+ ]);
+ };
+ s.renderSectionAdd = function(extra_class) {
+ var el = form.GridSection.prototype.renderSectionAdd.apply(this, arguments);
+ el.appendChild(E('button', {
+ 'class': 'cbi-button cbi-button-add',
+ 'title': _('Import Links'),
+ 'click': ui.createHandlerFn(this, 'handleLinkImport')
+ }, [ _('Import Links') ]));
+ return el;
+ };
o = s.option(form.Flag, 'disabled', _('Disable'));
o.editable = true;
@@ -26,7 +71,7 @@ return L.view.extend({
},
addFooter: function() {
var p = '#edit=';
- if (startsWith(location.hash, p)) {
+ if (location.hash.indexOf(p) === 0) {
var section_id = location.hash.substring(p.length);
var editBtn = document.querySelector('#cbi-shadowsocks-libev-' + section_id + ' button.cbi-button-edit');
if (editBtn)