diff options
author | Richard Yu <yurichard3839@gmail.com> | 2019-11-04 10:02:03 +0800 |
---|---|---|
committer | Yousong Zhou <yszhou4tech@gmail.com> | 2019-11-04 10:14:15 +0800 |
commit | b83374b3401d33f1f1bc40bbb367991cc34cc918 (patch) | |
tree | 0207830ab0118912fe8d2fa86c35641f4384c925 /applications/luci-app-shadowsocks-libev/htdocs/luci-static/resources/view | |
parent | 4e9f2d3f1ef21262e8c009579d235d355fbd467a (diff) |
luci-app-shadowsocks-libev: port to client side
Signed-off-by: Richard Yu <yurichard3839@gmail.com>
Diffstat (limited to 'applications/luci-app-shadowsocks-libev/htdocs/luci-static/resources/view')
3 files changed, 322 insertions, 0 deletions
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 new file mode 100644 index 0000000000..27a2b950c2 --- /dev/null +++ b/applications/luci-app-shadowsocks-libev/htdocs/luci-static/resources/view/shadowsocks-libev/instances.js @@ -0,0 +1,162 @@ +'use strict'; +'require form'; +'require uci'; +'require fs'; +'require network'; +'require rpc'; +'require shadowsocks-libev as ss'; + +var conf = 'shadowsocks-libev'; +var cfgtypes = ['ss_local', 'ss_redir', 'ss_server', 'ss_tunnel']; + +var callServiceList = rpc.declare({ + object: 'service', + method: 'list', + params: [ 'name' ], + expect: { '': {} } +}); + +return L.view.extend({ + render: function(stats) { + var m, s, o; + + m = new form.Map(conf, + _('Local Instances'), + _('Instances of shadowsocks-libev components, e.g. ss-local, \ + ss-redir, ss-tunnel, ss-server, etc. To enable an instance it \ + is required to enable both the instance itself and the remote \ + server it refers to.')); + + s = m.section(form.GridSection); + s.addremove = true; + s.cfgsections = function() { + return this.map.data.sections(this.map.config) + .filter(function(s) { return cfgtypes.indexOf(s['.type']) !== -1; }) + .map(function(s) { return s['.name']; }); + }; + s.sectiontitle = function(section_id) { + var s = uci.get(conf, section_id); + return (s ? s['.type'] + '.' : '') + section_id; + }; + s.renderSectionAdd = function(extra_class) { + var el = form.GridSection.prototype.renderSectionAdd.apply(this, arguments), + optionEl = [E('option', { value: '_dummy' }, [_('-- instance type --')])]; + cfgtypes.forEach(function(t) { + optionEl.push(E('option', { value: t }, [t.replace('_', '-')])); + }); + var selectEl = E('select', { + class: 'cbi-input-select', + change: function(ev) { + ev.target.parentElement.nextElementSibling.nextElementSibling + .toggleAttribute('disabled', ev.target.value === '_dummy'); + } + }, optionEl); + el.lastElementChild.setAttribute('disabled', ''); + el.prepend(E('div', {}, selectEl)); + return el; + }; + s.handleAdd = function(ev, name) { + var selectEl = ev.target.parentElement.firstElementChild.firstElementChild, + type = selectEl.value; + this.sectiontype = type; + var promise = form.GridSection.prototype.handleAdd.apply(this, arguments); + this.sectiontype = undefined; + return promise; + }; + s.addModalOptions = function(s, section_id, ev) { + var sdata = uci.get(conf, section_id), + stype = sdata ? sdata['.type'] : null; + if (stype) { + s.sectiontype = stype; + return Promise.all([ + L.resolveDefault(fs.stat('/usr/bin/' + stype.replace('_', '-')), null), + network.getDevices() + ]).then(L.bind(function(res) { + s.tab('general', _('General Settings')); + s.tab('advanced', _('Advanced Settings')); + s.taboption('general', form.Flag, 'disabled', _('Disable')); + if (!res[0]) { + ss.option_install_package(s, 'general'); + } + ss.options_common(s, 'advanced'); + + 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.datatype = 'ipaddr'; + o.placeholder = '0.0.0.0'; + ss.values_ipaddr(o, res[1]); + } else { + ss.options_client(s, 'general', res[1]); + if (stype === 'ss_tunnel') { + o = s.taboption('general', form.Value, 'tunnel_address', + _('Tunnel address'), + _('The address ss-tunnel will forward traffic to')); + o.datatype = 'hostport'; + } + } + }, this)); + } + }; + + o = s.option(form.DummyValue, 'overview', _('Overview')); + o.modalonly = false; + o.editable = true; + o.rawhtml = true; + o.renderWidget = function(section_id, option_index, cfgvalue) { + var sdata = uci.get(conf, section_id); + if (sdata) { + return form.DummyValue.prototype.renderWidget.call(this, section_id, option_index, ss.cfgvalue_overview(sdata)); + } + return null; + }; + + o = s.option(form.DummyValue, 'running', _('Running')); + o.modalonly = false; + o.editable = true; + o.default = ''; + + o = s.option(form.Button, 'disabled', _('Enable/Disable')); + o.modalonly = false; + o.editable = true; + o.inputtitle = function(section_id) { + var s = uci.get(conf, section_id); + if (ss.ucival_to_bool(s['disabled'])) { + this.inputstyle = 'reset'; + return _('Disabled'); + } + this.inputstyle = 'save'; + return _('Enabled'); + } + o.onclick = function(ev) { + var inputEl = ev.target.parentElement.nextElementSibling; + inputEl.value = ss.ucival_to_bool(inputEl.value) ? '0' : '1'; + return this.map.save(); + } + + return m.render().finally(function() { + L.Poll.add(function() { + return L.resolveDefault(callServiceList(conf), {}) + .then(function(res) { + var instances = null; + try { + instances = res[conf]['instances']; + } catch (e) {} + if (!instances) return; + uci.sections(conf) + .filter(function(s) { return cfgtypes.indexOf(s['.type']) !== -1; }) + .forEach(function(s) { + var el = document.getElementById('cbi-shadowsocks-libev-' + s['.name'] + '-running'); + if (el) { + var name = s['.type'] + '.' + s['.name'], + running = instances.hasOwnProperty(name)? instances[name].running : false; + el.innerText = running ? 'yes' : 'no'; + } + }); + }); + }); + }); + }, +}); 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 new file mode 100644 index 0000000000..798237adbd --- /dev/null +++ b/applications/luci-app-shadowsocks-libev/htdocs/luci-static/resources/view/shadowsocks-libev/rules.js @@ -0,0 +1,123 @@ +'use strict'; +'require uci'; +'require fs'; +'require form'; +'require tools.widgets as widgets'; +'require shadowsocks-libev as ss'; + +var conf = 'shadowsocks-libev'; + +function src_dst_option(s /*, ... */) { + var o = s.taboption.apply(s, L.varargs(arguments, 1)); + o.datatype = 'or(ipaddr,cidr)'; +} + +return L.view.extend({ + load: function() { + return Promise.all([ + L.resolveDefault(fs.stat('/usr/lib/iptables/libxt_recent.so'), {}), + L.resolveDefault(fs.stat('/usr/bin/ss-rules'), null), + uci.load(conf).then(function() { + if (!uci.get_first(conf, 'ss_rules')) { + uci.set(conf, uci.add(conf, 'ss_rules', 'ss_rules'), 'disabled', '1'); + } + }) + ]); + }, + render: function(stats) { + var m, s, o; + + m = new form.Map(conf, _('Redir Rules'), + _('On this page you can configure how traffics are to be \ + forwarded to ss-redir instances. \ + If enabled, packets will first have their src ip addresses checked \ + against <em>Src ip/net bypass</em>, <em>Src ip/net forward</em>, \ + <em>Src ip/net checkdst</em> and if none matches <em>Src default</em> \ + will give the default action to be taken. \ + If the prior check results in action <em>checkdst</em>, packets will continue \ + to have their dst addresses checked.')); + + s = m.section(form.NamedSection, 'ss_rules', 'ss_rules'); + s.tab('general', _('General Settings')); + s.tab('src', _('Source Settings')); + s.tab('dst', _('Destination Settings')); + + s.taboption('general', form.Flag, 'disabled', _('Disable')); + if (!stats[1]) { + ss.option_install_package(s, 'general'); + } + + o = s.taboption('general', form.ListValue, 'redir_tcp', + _('ss-redir for TCP')); + ss.values_redir(o, 'tcp'); + o = s.taboption('general', form.ListValue, 'redir_udp', + _('ss-redir for UDP')); + ss.values_redir(o, 'udp'); + + o = s.taboption('general', form.ListValue, 'local_default', + _('Local-out default'), + _('Default action for locally generated TCP packets')); + ss.values_actions(o); + o = s.taboption('general', widgets.DeviceSelect, 'ifnames', + _('Ingress interfaces'), + _('Only apply rules on packets from these network interfaces')); + o.multiple = true; + o.noaliases = true; + o.noinactive = true; + s.taboption('general', form.Value, 'ipt_args', + _('Extra arguments'), + _('Passes additional arguments to iptables. Use with care!')); + + src_dst_option(s, 'src', form.DynamicList, 'src_ips_bypass', + _('Src ip/net bypass'), + _('Bypass ss-redir for packets with src address in this list')); + src_dst_option(s, 'src', form.DynamicList, 'src_ips_forward', + _('Src ip/net forward'), + _('Forward through ss-redir for packets with src address in this list')); + src_dst_option(s, 'src', form.DynamicList, 'src_ips_checkdst', + _('Src ip/net checkdst'), + _('Continue to have dst address checked for packets with src address in this list')); + o = s.taboption('src', form.ListValue, 'src_default', + _('Src default'), + _('Default action for packets whose src address do not match any of the src ip/net list')); + ss.values_actions(o); + + src_dst_option(s, 'dst', form.DynamicList, 'dst_ips_bypass', + _('Dst ip/net bypass'), + _('Bypass ss-redir for packets with dst address in this list')); + src_dst_option(s, 'dst', form.DynamicList, 'dst_ips_forward', + _('Dst ip/net forward'), + _('Forward through ss-redir for packets with dst address in this list')); + + var dir = '/etc/shadowsocks-libev'; + o = s.taboption('dst', form.FileUpload, 'dst_ips_bypass_file', + _('Dst ip/net bypass file'), + _('File containing ip/net for the purposes as with <em>Dst ip/net bypass</em>')); + o.root_directory = dir; + o = s.taboption('dst', form.FileUpload, 'dst_ips_forward_file', + _('Dst ip/net forward file'), + _('File containing ip/net for the purposes as with <em>Dst ip/net forward</em>')); + o.root_directory = dir; + o = s.taboption('dst', form.ListValue, 'dst_default', + _('Dst default'), + _('Default action for packets whose dst address do not match any of the dst ip list')); + ss.values_actions(o); + + if (stats[0].type === 'file') { + o = s.taboption('dst', form.Flag, 'dst_forward_recentrst'); + } else { + uci.set(conf, 'ss_rules', 'dst_forward_recentrst', '0'); + o = s.taboption('dst', form.Button, '_install'); + o.inputtitle = _('Install package iptables-mod-conntrack-extra'); + o.inputstyle = 'apply'; + o.onclick = function() { + window.open(L.url('admin/system/opkg') + + '?query=iptables-mod-conntrack-extra', '_blank', 'noopener'); + } + } + o.title = _('Forward recentrst'); + o.description = _('Forward those packets whose dst have recently sent to us multiple tcp-rst'); + + return m.render(); + }, +}); 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 new file mode 100644 index 0000000000..d46bfb0aa7 --- /dev/null +++ b/applications/luci-app-shadowsocks-libev/htdocs/luci-static/resources/view/shadowsocks-libev/servers.js @@ -0,0 +1,37 @@ +'use strict'; +'require form'; +'require shadowsocks-libev as ss'; + +function startsWith(str, search) { + return str.substring(0, search.length) === search; +} + +return L.view.extend({ + render: function() { + var m, s, o; + + m = new form.Map('shadowsocks-libev', _('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; + + o = s.option(form.Flag, 'disabled', _('Disable')); + o.editable = true; + + ss.options_server(s); + + return m.render(); + }, + addFooter: function() { + var p = '#edit='; + if (startsWith(location.hash, p)) { + var section_id = location.hash.substring(p.length); + var editBtn = document.querySelector('#cbi-shadowsocks-libev-' + section_id + ' button.cbi-button-edit'); + if (editBtn) + editBtn.click(); + } + return this.super('addFooter', arguments); + } +}); |