summaryrefslogtreecommitdiffhomepage
path: root/applications/luci-app-ddns/htdocs
diff options
context:
space:
mode:
authorAnsuel Smith <ansuelsmth@gmail.com>2019-11-06 01:33:53 +0100
committerAnsuel Smith <ansuelsmth@gmail.com>2019-11-11 20:47:16 +0100
commit34fa5122f98af4ac635dfc26a64f6d2d3e4fafcb (patch)
tree39183ec3b008cd16a23e3fa0a6ab544602aa4408 /applications/luci-app-ddns/htdocs
parent0731f7e5e43f490c39e364e43988a59ee2be9576 (diff)
luci-app-ddns: convert to client side implementation
Signed-off-by: Ansuel Smith <ansuelsmth@gmail.com>
Diffstat (limited to 'applications/luci-app-ddns/htdocs')
-rw-r--r--applications/luci-app-ddns/htdocs/luci-static/resources/view/ddns/overview.js994
-rw-r--r--applications/luci-app-ddns/htdocs/luci-static/resources/view/status/include/70_ddns.js46
2 files changed, 1040 insertions, 0 deletions
diff --git a/applications/luci-app-ddns/htdocs/luci-static/resources/view/ddns/overview.js b/applications/luci-app-ddns/htdocs/luci-static/resources/view/ddns/overview.js
new file mode 100644
index 000000000..f19445366
--- /dev/null
+++ b/applications/luci-app-ddns/htdocs/luci-static/resources/view/ddns/overview.js
@@ -0,0 +1,994 @@
+'use strict';
+'require uci';
+'require rpc';
+'require fs';
+'require form';
+'require tools.widgets as widgets';
+
+var callGetLogServices, callInitAction, callDDnsGetStatus;
+
+var NextUpdateStrings = {};
+
+NextUpdateStrings = {
+ 'Verify' : _("Verify"),
+ 'Run once' : _("Run once"),
+ 'Disabled' : _("Disabled"),
+ 'Stopped' : _("Stopped")
+}
+
+var time_res = {};
+time_res['seconds'] = 1;
+time_res['minutes'] = 60;
+time_res['hours'] = 3600;
+
+callGetLogServices = rpc.declare({
+ object: 'luci.ddns',
+ method: 'get_services_log',
+ params: [ 'service_name' ],
+ expect: { },
+});
+
+callInitAction = rpc.declare({
+ object: 'luci',
+ method: 'setInitAction',
+ params: [ 'name', 'action' ],
+ expect: { result: false }
+});
+
+callDDnsGetStatus = rpc.declare({
+ object: 'luci.ddns',
+ method: 'get_ddns_state',
+ expect: { }
+});
+
+return L.view.extend({
+
+ callDDnsGetEnv: rpc.declare({
+ object: 'luci.ddns',
+ method: 'get_env',
+ expect: { }
+ }),
+
+ callDDnsGetServicesStatus: rpc.declare({
+ object: 'luci.ddns',
+ method: 'get_services_status',
+ expect: { }
+ }),
+
+ poll_status: function(map, data) {
+ var status = data[1] || [], service = data[0] || [], rows = map.querySelectorAll('.cbi-section-table-row[data-sid]'),
+ section_id, cfg_detail_ip, cfg_update, cfg_status, host, ip, last_update,
+ next_update, service_status, reload, cfg_enabled, stop,
+ ddns_enabled = map.querySelector('[data-name="_enabled"]').querySelector('.cbi-value-field'),
+ ddns_toggle = map.querySelector('[data-name="_toggle"]').querySelector('button');
+
+ ddns_toggle.innerHTML = status['_enabled'] ? _('Stop DDNS') : _('Start DDNS')
+
+ L.dom.content(ddns_enabled, function() {
+ return E([], [
+ E('div', {}, status['_enabled'] ? _('DDNS Autostart enabled') : [
+ _('DDNS Autostart disabled'),
+ E('div', { 'class' : 'cbi-value-description' },
+ _("Currently DDNS updates are not started at boot or on interface events.") + "<br>" +
+ _("This is the default if you run DDNS scripts by yourself (i.e. via cron with force_interval set to '0')"))
+ ]),]);
+ });
+
+ for (var i = 0; i < rows.length; i++) {
+ section_id = rows[i].getAttribute('data-sid');
+ cfg_detail_ip = rows[i].querySelector('[data-name="_cfg_detail_ip"]');
+ cfg_update = rows[i].querySelector('[data-name="_cfg_update"]');
+ cfg_status = rows[i].querySelector('[data-name="_cfg_status"]');
+ reload = rows[i].querySelector('.cbi-section-actions .reload');
+ stop = rows[i].querySelector('.cbi-section-actions .stop');
+ cfg_enabled = uci.get('ddns', section_id, 'enabled');
+
+ reload.disabled = (status['_enabled'] == 0 || cfg_enabled == 0);
+
+ host = uci.get('ddns', section_id, 'lookup_host') || _('Configuration Error');
+ ip = _('No Data');
+ last_update = _('Never');
+ next_update = _('Unknown');
+ service_status = '<b>' + _('Not Running') + '</b>';
+
+ if (service[section_id]) {
+ stop.disabled = (!service[section_id].pid || (service[section_id].pid && cfg_enabled == '1'));
+ if (service[section_id].ip)
+ ip = service[section_id].ip;
+ if (service[section_id].last_update)
+ last_update = service[section_id].last_update;
+ if (service[section_id].next_update)
+ next_update = NextUpdateStrings[service[section_id].next_update] || service[section_id].next_update;
+ if (service[section_id].pid)
+ service_status = '<b>' + _('Running') + '</b> : ' + service[section_id].pid;
+ }
+
+ cfg_detail_ip.innerHTML = host + '<br>' + ip;
+ cfg_update.innerHTML = last_update + '<br>' + next_update;
+ cfg_status.innerHTML = service_status;
+ }
+
+ return;
+ },
+
+ load: function() {
+ return Promise.all([
+ this.callDDnsGetServicesStatus(),
+ callDDnsGetStatus(),
+ this.callDDnsGetEnv(),
+ fs.lines('/etc/ddns/services'),
+ fs.lines('/etc/ddns/services_ipv6'),
+ uci.load('ddns')
+ ]);
+ },
+
+ render: function(data) {
+ var resolved = data[0] || [];
+ var status = data[1] || [];
+ var env = data[2] || [];
+ var logdir = uci.get('ddns', 'global', 'ddns_logdir') || "/var/log/ddns";
+
+ var services4 = [];
+ var services6 = [];
+
+ data[3].forEach(function(item) {
+ if (!item.startsWith("#")) {
+ services4.push(item.split('\t')[0].slice(1,-1));
+ }
+ });
+
+ data[4].forEach(function(item) {
+ if (!item.startsWith("#")) {
+ services6.push(item.split('\t')[0].slice(1,-1));
+ }
+ });
+
+ var m, s, o;
+
+ m = new form.Map('ddns', _('Dynamic DNS'),);
+
+ var is = m.section(form.NamedSection, 'global', 'ddns', _('Information'));
+
+ s = is;
+
+ o = s.option(form.DummyValue, '_version', _('Dynamic DNS Version'));
+ o.cfgvalue = function() {
+ return status[this.option];
+ };
+
+ o = s.option(form.DummyValue, '_enabled', _('State'));
+ o.cfgvalue = function() {
+ var res = status[this.option];
+ if (!res) {
+ this.description = _("Currently DDNS updates are not started at boot or on interface events.") + "<br>" +
+ _("This is the default if you run DDNS scripts by yourself (i.e. via cron with force_interval set to '0')")
+ }
+ return res ? _('DDNS Autostart enabled') : _('DDNS Autostart disabled')
+ };
+
+ o = s.option(form.DummyValue, '_toggle', '&nbsp');
+ o.cfgvalue = function() {
+ var action = status['_enabled'] ? 'stop' : 'start';
+ return E([], [
+ E('button', {
+ 'class': 'cbi-button cbi-button-apply',
+ 'click': L.ui.createHandlerFn(this, function() {
+ return callDDnsGetStatus().then(L.bind(function(data) {
+ return callInitAction('ddns', action == 'stop' ? 'disable' : 'enable').then(function() {
+ return callInitAction('ddns', action);
+ });
+ }, this)).then(L.bind(m.render, m));
+ })
+ }, _(action.toUpperCase() + ' DDns'))]);
+ };
+
+ o = s.option(form.DummyValue, '_restart', '&nbsp');
+ o.cfgvalue = function() {
+ return E([], [
+ E('button', {
+ 'class': 'cbi-button cbi-button-apply',
+ 'click': L.ui.createHandlerFn(this, function() {
+ return callInitAction('ddns', 'restart').then(L.bind(m.render, m));
+ })
+ }, _('Restart DDns'))]);
+ };
+
+ // DDns hints
+
+ if (!env['has_ipv6']) {
+ o = s.option(form.DummyValue, '_no_ipv6');
+ o.rawhtml = true;
+ o.title = '<b>' + _("IPv6 not supported") + '</b>';
+ o.cfgvalue = function() { return _("IPv6 is currently not (fully) supported by this system") + "<br>" +
+ _("Please follow the instructions on OpenWrt's homepage to enable IPv6 support") + "<br>" +
+ _("or update your system to the latest OpenWrt Release")};
+ }
+
+ if (!env['has_ssl']) {
+ o = s.option(form.DummyValue, '_no_https');
+ o.titleref = L.url("admin", "system", "opkg")
+ o.rawhtml = true;
+ o.title = '<b>' + _("HTTPS not supported") + '</b>';
+ o.cfgvalue = function() { return _("Neither GNU Wget with SSL nor cURL installed to support secure updates via HTTPS protocol.") +
+ "<br />- " +
+ _("You should install 'wget' or 'curl' or 'uclient-fetch' with 'libustream-*ssl' package.") +
+ "<br />- " +
+ _("In some versions cURL/libcurl in OpenWrt is compiled without proxy support.")};
+ }
+
+ if (!env['has_bindnet']) {
+ o = s.option(form.DummyValue, '_no_bind_network');
+ o.titleref = L.url("admin", "system", "opkg")
+ o.rawhtml = true;
+ o.title = '<b>' + _("Binding to a specific network not supported") + '</b>';
+ o.cfgvalue = function() { return _("Neither GNU Wget with SSL nor cURL installed to select a network to use for communication.") +
+ "<br />- " +
+ _("You should install 'wget' or 'curl' package.") +
+ "<br />- " +
+ _("GNU Wget will use the IP of given network, cURL will use the physical interface.") +
+ "<br />- " +
+ _("In some versions cURL/libcurl in OpenWrt is compiled without proxy support.")};
+ }
+
+ if (!env['has_proxy']) {
+ o = s.option(form.DummyValue, '_no_proxy');
+ o.titleref = L.url("admin", "system", "opkg")
+ o.rawhtml = true;
+ o.title = '<b>' + _("cURL without Proxy Support") + '</b>';
+ o.cfgvalue = function() { return _("cURL is installed, but libcurl was compiled without proxy support.") +
+ "<br />- " +
+ _("You should install 'wget' or 'uclient-fetch' package or replace libcurl.") +
+ "<br />- " +
+ _("In some versions cURL/libcurl in OpenWrt is compiled without proxy support.")};
+ }
+
+ if (!env['has_forceip']) {
+ o = s.option(form.DummyValue, '_no_force_ip');
+ o.titleref = L.url("admin", "system", "opkg")
+ o.rawhtml = true;
+ o.title = '<b>' + _("Force IP Version not supported") + '</b>';
+ o.cfgvalue = function() { return _("BusyBox's nslookup and Wget do not support to specify " +
+ "the IP version to use for communication with DDNS Provider!") +
+ "<br />- " + _("You should install 'wget' or 'curl' or 'uclient-fetch' package.")
+ };
+ }
+
+ if (!env['has_bindhost']) {
+ o = s.option(form.DummyValue, '_no_dnstcp');
+ o.titleref = L.url("admin", "system", "opkg")
+ o.rawhtml = true;
+ o.title = '<b>' + _("DNS requests via TCP not supported") + '</b>';
+ o.cfgvalue = function() { return _("BusyBox's nslookup and hostip do not support to specify to use TCP " +
+ "instead of default UDP when requesting DNS server!") +
+ "<br />- " +
+ _("You should install 'bind-host' or 'knot-host' or 'drill' package for DNS requests.")};
+ }
+
+ if (!env['has_dnsserver']) {
+ o = s.option(form.DummyValue, '_no_dnsserver');
+ o.titleref = L.url("admin", "system", "opkg")
+ o.rawhtml = true;
+ o.title = '<b>' + _("Using specific DNS Server not supported") + '</b>';
+ o.cfgvalue = function() { return _("BusyBox's nslookup in the current compiled version " +
+ "does not handle given DNS Servers correctly!") +
+ "<br />- " +
+ _("You should install 'bind-host' or 'knot-host' or 'drill' or 'hostip' package, " +
+ "if you need to specify a DNS server to detect your registered IP.")};
+ }
+
+ if (env['has_ssl'] && !env['has_cacerts']) {
+ o = s.option(form.DummyValue, '_no_certs');
+ o.titleref = L.url("admin", "system", "opkg")
+ o.rawhtml = true;
+ o.title = '<b>' + _("No certificates found") + '</b>';
+ o.cfgvalue = function() { return _("If using secure communication you should verify server certificates!") +
+ "<br />- " +
+ _("Install 'ca-certificates' package or needed certificates " +
+ "by hand into /etc/ssl/certs default directory")};
+ }
+
+ // DDns services
+ s = m.section(form.GridSection, 'service', _('Services'));
+ s.anonymous = true;
+ s.addremove = true;
+ s.addbtntitle = _('Add new services...');
+
+ s.anonymous = true;
+ s.addremove = true;
+ s.sortable = true;
+
+ s.handleAdd = function(ev) {
+ var m2 = new form.Map('ddns'),
+ s2 = m2.section(form.NamedSection, '_new_');
+
+ s2.render = function() {
+ return Promise.all([
+ {},
+ this.renderUCISection('_new_')
+ ]).then(this.renderContents.bind(this));
+ };
+
+ name = s2.option(form.Value, 'name', _('Name'));
+ name.rmempty = false;
+ name.datatype = 'uciname';
+ name.placeholder = _('New DDns Service…');
+ name.validate = function(section_id, value) {
+ if (uci.get('ddns', value) != null)
+ return _('The service name is already used');
+
+ return true;
+ };
+
+ m2.render().then(L.bind(function(nodes) {
+ L.ui.showModal(_('Add new services...'), [
+ nodes,
+ E('div', { 'class': 'right' }, [
+ E('button', {
+ 'class': 'btn',
+ 'click': L.ui.hideModal
+ }, _('Cancel')), ' ',
+ E('button', {
+ 'class': 'cbi-button cbi-button-positive important',
+ 'click': L.ui.createHandlerFn(this, function(ev) {
+ var nameval = name.isValid('_new_') ? name.formvalue('_new_') : null;
+
+ if (nameval == null || nameval == '')
+ return;
+
+ return m.save(function() {
+ uci.add('ddns', 'service', nameval);
+ }).then(L.bind(m.children[1].renderMoreOptionsModal, m.children[1], nameval));
+ })
+ }, _('Create service'))
+ ])
+ ], 'cbi-modal');
+
+ nodes.querySelector('[id="%s"] input[type="text"]'.format(name.cbid('_new_'))).focus();
+ }, this));
+ };
+
+ s.renderRowActions = function(section_id) {
+ var tdEl = this.super('renderRowActions', [ section_id, _('Edit') ]),
+ cfg_enabled = uci.get('ddns', section_id, 'enabled'),
+ reload_opt = {
+ 'class': 'cbi-button cbi-button-neutral reload',
+ 'click': L.ui.createHandlerFn(this, function() {
+ return fs.exec('/usr/lib/ddns/dynamic_dns_lucihelper.sh',
+ [ '-S', section_id, '--', 'start' ]).then(L.bind(m.render, m));
+ }),
+ 'title': _('Reload this service'),
+ },
+ stop_opt = {
+ 'class': 'cbi-button cbi-button-neutral stop',
+ 'click': L.ui.createHandlerFn(this, function() {
+ return fs.exec('/usr/lib/ddns/dynamic_dns_lucihelper.sh',
+ [ '-S', section_id, '--', 'start' ]).then(L.bind(m.render, m));
+ }),
+ 'title': _('Stop this service'),
+ };
+
+ if (status['_enabled'] == 0 || cfg_enabled == 0)
+ reload_opt['disabled'] = 'disabled';
+
+ if (!resolved[section_id] || !resolved[section_id].pid ||
+ (resolved[section_id].pid && cfg_enabled == '1'))
+ stop_opt['disabled'] = 'disabled';
+
+ L.dom.content(tdEl.lastChild, [
+ E('button', stop_opt, _('Stop')),
+ E('button', reload_opt, _('Reload')),
+ tdEl.lastChild.childNodes[0],
+ tdEl.lastChild.childNodes[1],
+ tdEl.lastChild.childNodes[2]
+ ]);
+
+ return tdEl;
+ };
+
+ o = s.option(form.DummyValue, '_cfg_name', _('Name'));
+ o.modalonly = false;
+ o.textvalue = function(section_id) {
+ return '<b>' + section_id + '</b>';
+ }
+
+ o = s.option(form.DummyValue, '_cfg_detail_ip', _('Lookup Hostname') + "<br>" + _('Registered IP'));
+ o.rawhtml = true;
+ o.modalonly = false;
+ o.textvalue = function(section_id) {
+ var host = uci.get('ddns', section_id, 'lookup_host') || _('Configuration Error'),
+ ip = _('No Data');
+ if (resolved[section_id] && resolved[section_id].ip)
+ ip = resolved[section_id].ip;
+
+ return host + '<br>' + ip;
+ };
+
+ o = s.option(form.Flag, 'enabled', _('Enabled'));
+ o.rmempty = false;
+ o.editable = true;
+ o.modalonly = false;
+
+ o = s.option(form.DummyValue, '_cfg_update', _('Last Update') + "<br>" + _('Next Update'));
+ o.rawhtml = true;
+ o.modalonly = false;
+ o.textvalue = function(section_id) {
+ var last_update = _('Never'), next_update = _('Unknown');
+ if (resolved[section_id]) {
+ if (resolved[section_id].last_update)
+ last_update = resolved[section_id].last_update;
+ if (resolved[section_id].next_update)
+ next_update = NextUpdateStrings[resolved[section_id].next_update] || resolved[section_id].next_update;
+ }
+
+ return last_update + '<br>' + next_update;
+ };
+
+ s.modaltitle = function(section_id) {
+ return _('DDns Service') + ' » ' + section_id;
+ };
+
+ o = s.option(form.DummyValue, '_cfg_status', _('Status'));
+ o.modalonly = false;
+ o.textvalue = function(section_id) {
+ var text = '<b>' + _('Not Running') + '</b>';
+
+ if (resolved[section_id] && resolved[section_id].pid)
+ text = '<b>' + _('Running') + '</b> : ' + resolved[section_id].pid;
+
+ return text;
+ }
+
+
+ s.tab('basic', _('Basic Settings'));
+ s.tab('advanced', _('Advanced Settings'));
+ s.tab('timer', _('Timer Settings'));
+ s.tab('logview', _('Log File Viewer'));
+
+ // TAB: BASIC
+
+ // enabled
+ o = s.taboption('basic', form.Flag, 'enabled', _('Enabled'),_("If this service section is disabled it could not be started." + "<br />" +
+ "Neither from LuCI interface nor from console"));
+ o.modalonly = true;
+ o.rmempty = false;
+ o.default = '1';
+
+ // lookup_host
+
+ o = s.taboption('basic', form.Value, 'lookup_host', _("Lookup Hostname"),
+ _("Hostname/FQDN to validate, if IP update happen or necessary") );
+ o.rmempty = false;
+ o.placeholder = "myhost.example.com";
+ o.datatype = 'and(minlength(3),hostname("strict"))';
+ o.modalonly = true;
+
+ // use_ipv6
+
+ o = s.taboption('basic', form.ListValue, 'use_ipv6', _("IP address version"),
+ _("Defines which IP address 'IPv4/IPv6' is send to the DDNS provider"));
+ o.default = '0';
+ o.modalonly = true;
+ o.rmempty = false;
+
+ o.value("0", _("IPv4-Address"))
+ if (env["has_ipv6"])
+ o.value("1", _("IPv6-Address"))
+
+ // service_name
+
+ o = s.taboption('basic', form.ListValue, 'ipv4_service_name', _("DDNS Service provider") + " [IPv4]");
+ o.depends("use_ipv6", "0")
+ o.modalonly = true;
+
+ for (var i = 0; i < services4.length; i++)
+ o.value(services4[i]);
+
+ o.value('-',"-- " + _("custom") + " --");
+
+ o.cfgvalue = function(section_id) {
+ return uci.get('ddns', section_id, 'service_name');
+ }
+
+ o.write = function(section_id, formvalue) {
+ if (formvalue != '-') {
+ uci.set('ddns', section_id, 'update_url', null);
+ uci.set('ddns', section_id, 'update_script', null);
+ return uci.set('ddns', section_id, 'service_name', formvalue);
+ }
+ return uci.set('ddns', section_id, 'service_name', null);
+ };
+
+ o = s.taboption('basic', form.ListValue, 'ipv6_service_name', _("DDNS Service provider") + " [IPv6]");
+ o.depends("use_ipv6", "1")
+ o.modalonly = true;
+
+ for (var i = 0; i < services6.length; i++)
+ o.value(services6[i]);
+
+ o.value('-',"-- " + _("custom") + " --");
+
+ o.cfgvalue = function(section_id) {
+ return uci.get('ddns', section_id, 'service_name');
+ }
+
+ o.write = function(section_id, formvalue) {
+ if (formvalue != '-') {
+ uci.set('ddns', section_id, 'update_url', null);
+ uci.set('ddns', section_id, 'update_script', null);
+ return uci.set('ddns', section_id, 'service_name', formvalue);
+ }
+ return uci.set('ddns', section_id, 'service_name', null);
+ };
+
+ // update_url
+
+ o = s.taboption('basic', form.Value, 'update_url', _("Custom update-URL"),
+ _("Update URL to be used for updating your DDNS Provider." + "<br />" +
+ "Follow instructions you will find on their WEB page."));
+ o.modalonly = true;
+ o.rmempty = false;
+ o.depends("ipv6_service_name","-");
+ o.depends("ipv4_service_name","-");
+
+ // update_script
+
+ o = s.taboption('basic', form.Value, 'update_script', _("Custom update-script"),
+ _("Custom update script to be used for updating your DDNS Provider."));
+ o.modalonly = true;
+ o.rmempty = false;
+ o.depends("ipv6_service_name","-");
+ o.depends("ipv4_service_name","-");
+
+ // domain
+
+ o = s.taboption('basic', form.Value, 'domain', _("Domain"),
+ _("Replaces [USERNAME] in Update-URL (URL-encoded)"));
+ o.modalonly = true;
+ o.rmempty = false;
+
+ // username
+
+ o = s.taboption('basic', form.Value, 'username', _("Username"),
+ _("Replaces [USERNAME] in Update-URL (URL-encoded)"));
+ o.modalonly = true;
+ o.rmempty = false;
+
+ // password
+
+
+ o = s.taboption('basic', form.Value, 'password', _("Password"),
+ _("Replaces [PASSWORD] in Update-URL (URL-encoded)"));
+ o.password = true;
+ o.modalonly = true;
+ o.rmempty = false;
+
+ // param_enc
+
+ o = s.taboption('basic', form.Value, 'param_enc', _("Optional Encoded Parameter"),
+ _("Optional: Replaces [PARAMENC] in Update-URL (URL-encoded)"));
+ o.optional = true;
+ o.modalonly = true;
+
+ // param_opt
+
+ o = s.taboption('basic', form.Value, 'param_opt', _("Optional Parameter"),
+ _("Optional: Replaces [PARAMOPT] in Update-URL (NOT URL-encoded)"));
+ o.optional = true;
+ o.modalonly = true;
+
+ // use_https
+
+ if (env['has_ssl']) {
+ o = s.taboption('basic', form.Flag, 'use_https', _("Use HTTP Secure"),
+ _("Enable secure communication with DDNS provider"));
+ o.optional = true;
+ o.modalonly = true;
+
+ o = s.taboption('basic', form.Value, 'cacert',
+ _("Path to CA-Certificate"),
+ _("directory or path/file") + "<br>" +
+ _("or") + '<b>' + " IGNORE " + '</b>' +
+ _("to run HTTPS without verification of server certificates (insecure)"));
+ o.modalonly = true;
+ o.depends("use_https", "1");
+ o.placeholder = "/etc/ssl/certs";
+ o.rmempty = false;
+ };
+
+ // TAB Advanced
+
+ // ip_source
+
+ o = s.taboption('advanced', form.ListValue, 'ip_source', _("IP address source"),
+ _("Defines the source to read systems IP-Address from, that will be send to the DDNS provider"));
+
+ o.modalonly = true;
+ o.default = "network";
+ o.value("network", _("Network"));
+ o.value("web", _("URL"));
+ o.value("interface", _("Interface"));
+ o.value("script", _("Script"));
+
+ o.write = function(section_id, formvalue) {
+ switch(formvalue) {
+ case 'network':
+ uci.set('ddns', section_id, "ip_url",null);
+ uci.set('ddns', section_id, "ip_interface",null);
+ uci.set('ddns', section_id, "ip_script",null);
+ break;
+ case 'web':
+ uci.set('ddns', section_id, "ip_network",null);
+ uci.set('ddns', section_id, "ip_interface",null);
+ uci.set('ddns', section_id, "ip_script",null);
+ break;
+ case 'interface':
+ uci.set('ddns', section_id, "ip_network",null);
+ uci.set('ddns', section_id, "ip_url",null);
+ uci.set('ddns', section_id, "ip_script",null);
+ break;
+ case 'script':
+ uci.set('ddns', section_id, "ip_network",null);
+ uci.set('ddns', section_id, "ip_url",null);
+ uci.set('ddns', section_id, "ip_interface",null);
+ break;
+ default:
+ break;
+ };
+
+ return uci.set('ddns', section_id, 'ip_source', formvalue )
+ };
+
+ // ip_network
+
+ o = s.taboption('advanced', widgets.ZoneSelect, 'ip_network', _("Network"),
+ _("Defines the network to read systems IP-Address from"));
+ o.depends('ip_source','network');
+ o.modalonly = true;
+ o.default = 'wan';
+ o.multiple = false;
+
+ // ip_url
+
+ o = s.taboption('advanced', form.Value, 'ip_url', _("URL to detect"),
+ _("Defines the Web page to read systems IP-Address from" + '<br>' +
+ _('Example for IPv4' + ': http://checkip.dyndns.com') + '<br>' +
+ _('Example for IPv6' + ': http://checkipv6.dyndns.com')));
+ o.depends("ip_source", "web")
+
+ o.modalonly = true;
+
+ // ip_interface
+
+ o = s.taboption('advanced', widgets.ZoneSelect, 'ip_interface', _("Interface"),
+ _("Defines the interface to read systems IP-Address from"));
+
+ o.modalonly = true;
+ o.depends("ip_source", "interface")
+ o.multiple = false;
+ o.default = 'wan';
+
+ // ip_script
+
+ o = s.taboption('advanced', form.Value, 'ip_script', _("Script"),
+ _("User defined script to read systems IP-Address"));
+
+ o.modalonly = true;
+ o.depends("ip_source", "script")
+ o.placeholder = "/path/to/script.sh"
+
+ // interface
+
+ o = s.taboption('advanced', widgets.ZoneSelect, 'interface', _("Event Network"),
+ _("Network on which the ddns-updater scripts will be started"));
+
+ o.modalonly = true;
+ o.multiple = false;
+ o.default = 'wan';
+ o.depends("ip_source", "web");
+ o.depends("ip_source", "script");
+
+ // interface_show
+
+ o = s.taboption('advanced', form.DummyValue, '_interface', _("Event Network"),
+ _("Network on which the ddns-updater scripts will be started"));
+ o.depends("ip_source", "interface");
+ o.depends("ip_source", "network");
+ o.forcewrite = true;
+ o.modalonly = true;
+ o.cfgvalue = function(section_id) {
+ return uci.get('ddns', section_id, 'interface') || _('This will be autoset to the selected interface');
+ };
+ o.write = function(section_id) {
+ var opt = this.section.children.filter(function(o) { return o.option == 'ip_source' })[0].formvalue(section_id);
+ var val = this.section.children.filter(function(o) { return o.option == 'ip_'+opt })[0].formvalue(section_id);
+ return uci.set('ddns', section_id, 'interface', val);
+ };
+
+ // bind_network
+
+ if (env['has_bindnet']) {
+ o = s.taboption('advanced', widgets.ZoneSelect, 'bind_network', _("Bind Network"),
+ _('OPTIONAL: Network to use for communication') + '<br>' +
+ _("Network on which the ddns-updater scripts will be started"));
+ o.depends("ip_source", "web");
+ o.optional = true;
+ o.rmempty = true;
+ o.modalonly = true;
+ }
+
+ // force_ipversion
+
+ if (env['has_forceip']) {
+ o = s.taboption('advanced', form.Flag, 'force_ipversion', _("Force IP Version"),
+ _('OPTIONAL: Force the usage of pure IPv4/IPv6 only communication.'));
+ o.optional = true;
+ o.rmempty = true;
+ o.modalonly = true;
+ }
+
+ // dns_server
+
+ if (env['has_dnsserver']) {
+ o = s.taboption("advanced", form.Value, "dns_server",
+ _("DNS-Server"),
+ _("OPTIONAL: Use non-default DNS-Server to detect 'Registered IP'.") + "<br />" +
+ _("Format: IP or FQDN"));
+ o.placeholder = "mydns.lan"
+ o.optional = true;
+ o.rmempty = true;
+ o.modalonly = true;
+ }
+
+ // force_dnstcp
+
+ if (env['has_bindhost']) {
+ o = s.taboption("advanced", form.Flag, "force_dnstcp",
+ _("Force TCP on DNS"),
+ _("OPTIONAL: Force the use of TCP instead of default UDP on DNS requests."));
+ o.optional = true;
+ o.rmempty = true;
+ o.modalonly = true;
+ }
+
+ // proxy
+
+ if (env['has_proxy']) {
+ o = s.taboption("advanced", form.Value, "proxy", _("PROXY-Server"),
+ _("OPTIONAL: Proxy-Server for detection and updates.") + "<br />" +
+ _("Format") + ": " + '<b>' + "[user:password@]proxyhost:port" + '</b>' + "<br />" +
+ _("IPv6 address must be given in square brackets") + ": " +
+ '<b>' + " [2001:db8::1]:8080" + '</b>');
+ o.optional = true;
+ o.rmempty = true;
+ o.modalonly = true;
+ }
+
+ // use_syslog
+
+ o = s.taboption("advanced", form.ListValue, "use_syslog", _("Log to syslog"),
+ _("Writes log messages to syslog. Critical Errors will always be written to syslog."));
+ o.modalonly = true;
+ o.placeholder = "2"
+ o.optional = true;
+ o.value("0", _("No logging"))
+ o.value("1", _("Info"))
+ o.value("2", _("Notice"))
+ o.value("3", _("Warning"))
+ o.value("4", _("Error"))
+
+ // use_logfile
+
+ o = s.taboption("advanced", form.Flag, "use_logfile", _("Log to file"));
+ o.default = '1';
+ o.optional = true;
+ o.modalonly = true;
+ o.cfgvalue = function(section_id) {
+ this.description = _("Writes detailed messages to log file. File will be truncated automatically.") + "<br>" +
+ _("File") + ': "' + logdir + '/' + section_id + '.log"';
+ return uci.get('ddns', section_id, 'use_logfile');
+ };
+
+ // TAB Timer
+
+ // check_interval
+ o = s.taboption("timer", form.Value, "check_interval", _("Check Interval"));
+ o.placeholder = "30";
+ o.modalonly = true;
+ o.datatype = 'uinteger';
+
+ o.validate = function(section_id, formvalue) {
+ var unit = this.section.children.filter(function(o) { return o.option == 'check_unit' })[0].formvalue(section_id),
+ time_to_sec = time_res[unit || 'minutes'] * formvalue;
+
+ if (formvalue && time_to_sec < 300)
+ return _('Values below 5 minutes == 300 seconds are not supported');
+
+ return true;
+
+ };
+
+ // check_interval
+ o = s.taboption("timer", form.ListValue, "check_unit",'Check Unit');
+ o.description = _("Interval unit to check for changed IP");
+ o.modalonly = true;
+ o.default = "minutes"
+ o.value("seconds", _("seconds"));
+ o.value("minutes", _("minutes"));
+ o.value("hours", _("hours"));
+
+ // force_interval
+
+ o = s.taboption("timer", form.Value, "force_interval", _("Force Interval"));
+ o.description = _("Interval to force updates send to DDNS Provider" + "<br />" +
+ "Setting this parameter to 0 will force the script to only run once");
+ o.placeholder = "72";
+ o.optional = true;
+ o.modalonly = true;
+ o.datatype = 'uinteger';
+
+ o.validate = function(section_id, formvalue) {
+
+ if (!formvalue)
+ return true;
+
+ var check_unit = this.section.children.filter(function(o) { return o.option == 'check_unit' })[0].formvalue(section_id),
+ check_val = this.section.children.filter(function(o) { return o.option == 'check_interval' })[0].formvalue(section_id),
+ force_unit = this.section.children.filter(function(o) { return o.option == 'force_unit' })[0].formvalue(section_id),
+ check_to_sec = time_res[check_unit || 'minutes'] * ( check_val || '30'),
+ force_to_sec = time_res[force_unit || 'minutes'] * formvalue;
+
+ if (force_to_sec != 0 && force_to_sec < check_to_sec)
+ return _("Values lower 'Check Interval' except '0' are not supported");
+
+ return true;
+ };
+
+ // force_unit
+
+ o = s.taboption("timer", form.ListValue, "force_unit",'Force Unit');
+ o.description = _("Interval unit to force updates send to DDNS Provider");
+ o.modalonly = true;
+ o.optional = true;
+ o.default = "minutes"
+ o.value("minutes", _("minutes"));
+ o.value("hours", _("hours"));
+ o.value("hours", _("days"));
+
+ // retry_count
+
+ o = s.taboption("timer", form.Value, "retry_count", _("Error Retry Counter"));
+ o.description = _("On Error the script will stop execution after given number of retrys")
+ + "<br />"
+ + _("The default setting of '0' will retry infinite.");
+ o.placeholder = "0";
+ o.optional = true;
+ o.modalonly = true;
+ o.datatype = 'uinteger';
+
+ // retry_interval
+
+ o = s.taboption("timer", form.Value, "retry_interval", _("Error Retry Interval"));
+ o.description = _("On Error the script will stop execution after given number of retrys")
+ + "<br />"
+ + _("The default setting of '0' will retry infinite.");
+ o.placeholder = "60";
+ o.optional = true;
+ o.modalonly = true;
+ o.datatype = 'uinteger';
+
+ // retry_unit
+
+ o = s.taboption("timer", form.ListValue, "retry_unit",'Retry Unit');
+ o.description = _("On Error the script will retry the failed action after given time");
+ o.modalonly = true;
+ o.optional = true;
+ o.default = "seconds"
+ o.value("seconds", _("seconds"));
+ o.value("minutes", _("minutes"));
+
+ // TAB logview
+
+ o = s.taboption("logview", form.DummyValue, '_read_log', '');
+ o.depends('use_logfile','1');
+ o.modalonly = true;
+ o.cfgvalue = function(section_id) {
+ return E([], [
+ E('button', {
+ 'class': 'cbi-button cbi-button-apply',
+ 'click': L.ui.createHandlerFn(this, function() {
+ var o = this.section.children.filter(function(o) { return o.option == '_logview' })[0];
+ return callGetLogServices(section_id).then(L.bind(o.update_log, o));
+ })
+ }, _('Read / Reread log file'))]);
+ };
+
+ o = s.taboption("logview", form.DummyValue, "_logview");
+ o.depends('use_logfile','1');
+ o.modalonly = true;
+
+ o.update_log = L.bind(function(view, log_data) {
+ return document.getElementById('log_area').innerHTML = log_data.result;
+ }, o, this)
+
+ o.render = L.bind(function() {
+ return E([
+ E('p', {}, _('This is the current content of the log file in ') + logdir + ' for this service.'),
+ E('p', {}, E('textarea', { 'style': 'width:100%', 'rows': 20, 'readonly' : 'readonly', 'id' : 'log_area' }, _('Please press [Read] button') ))
+ ]);
+ }, o, this)
+
+
+ // Advanced Configuration Section
+
+ s = m.section(form.NamedSection, 'global', 'ddns', _('Global Configuration'));
+ s.description = _('Configure here the details for all Dynamic DNS services including this LuCI application.')
+ + '<br /><strong>'
+ + _("It is NOT recommended for casual users to change settings on this page.")
+ + '</strong><br />'
+ + '<a href="https://openwrt.org/docs/guide-user/base-system/ddns#section_ddns" target="_blank">'
+ + _('For detailed information about parameter settings look here.')
+ + '</a>';
+ s.addremove = false;
+
+ o = s.option(form.Flag, 'upd_privateip', _("Allow non-public IP's"));
+ o.description = _("Non-public and by default blocked IP's") + ':'
+ + '<br /><strong>IPv4: </strong>'
+ + '0/8, 10/8, 100.64/10, 127/8, 169.254/16, 172.16/12, 192.168/16'
+ + '<br /><strong>IPv6: </strong>'
+ + '::/32, f000::/4"';
+ o.default = "0";
+ o.optional = true;
+
+ o = s.option(form.Value, 'ddns_dateformat', _('Date format'));
+ o.description = '<a href="http://www.cplusplus.com/reference/ctime/strftime/" target="_blank">'
+ + _("For supported codes look here")
+ + '</a><br>' +
+ _('Current setting: ') + '<b>' + status['_curr_dateformat'] + '</b>';
+ o.default = "%F %R"
+ o.optional = true;
+ o.rmempty = true;
+
+ o = s.option(form.Value, 'ddns_rundir', _('Status directory'));
+ o.description = _('Directory contains PID and other status information for each running section.');
+ o.default = "/var/run/ddns";
+ o.optional = true;
+ o.rmempty = true;
+
+ o = s.option(form.Value, 'ddns_logdir', _('Log directory'));
+ o.description = _('Directory contains Log files for each running section.');
+ o.default = "/var/log/ddns";
+ o.optional = true;
+ o.rmempty = true;
+ o.validate = function(section_id, formvalue) {
+ if (formvalue.indexOf('../') !== -1)
+ return _('"../" not allowed in path for Security Reason.')
+
+ return true;
+ }
+
+ o = s.option(form.Value, 'ddns_loglines', _('Log length'));
+ o.description = _('Number of last lines stored in log files');
+ o.datatype = 'min(1)';
+ o.default = '250';
+
+ if (env['has_wget'] && env['has_curl']) {
+
+ o = s.option(form.Flag, 'use_curl', _('Use cURL'));
+ o.description = _('If Wget and cURL package are installed, Wget is used for communication by default.');
+ o.default = "0";
+ o.optional = true;
+ o.rmempty = true;
+
+ }
+
+ return m.render().then(L.bind(function(m, nodes) {
+ L.Poll.add(L.bind(function() {
+ return Promise.all([
+ this.callDDnsGetServicesStatus(),
+ callDDnsGetStatus()
+ ]).then(L.bind(this.poll_status, this, nodes));
+ }, this), 5);
+ return nodes;
+ }, this, m));
+ }
+});
diff --git a/applications/luci-app-ddns/htdocs/luci-static/resources/view/status/include/70_ddns.js b/applications/luci-app-ddns/htdocs/luci-static/resources/view/status/include/70_ddns.js
new file mode 100644
index 000000000..698cf8d25
--- /dev/null
+++ b/applications/luci-app-ddns/htdocs/luci-static/resources/view/status/include/70_ddns.js
@@ -0,0 +1,46 @@
+'use strict';
+'require rpc';
+'require uci';
+
+return L.Class.extend({
+ title: _('Dynamic DNS'),
+
+ callDDnsGetServicesStatus: rpc.declare({
+ object: 'luci.ddns',
+ method: 'get_services_status',
+ expect: { }
+ }),
+
+ load: function() {
+ return Promise.all([
+ this.callDDnsGetServicesStatus(),
+ uci.load('ddns')
+ ]);
+ },
+
+ render: function(data) {
+ var services = data[0];
+
+ var table = E('div', { 'class': 'table' }, [
+ E('div', { 'class': 'tr table-titles' }, [
+ E('div', { 'class': 'th' }, _('Configuration')),
+ E('div', { 'class': 'th' }, _('Next Update')),
+ E('div', { 'class': 'th' }, _('Lookup Hostname')),
+ E('div', { 'class': 'th' }, _('Registered IP')),
+ E('div', { 'class': 'th' }, _('Network'))
+ ])
+ ]);
+
+ cbi_update_table(table, Object.keys(services).map(function(key, index) {
+ return [
+ key,
+ services[key].next_update ? _(services[key].next_update) : _('Unknown'),
+ uci.get('ddns',key,'lookup_host'),
+ services[key].ip ? services[key].ip : _('No Data'),
+ (uci.get('ddns',key,'use_ipv6') == '1' ? 'IPv6' : 'IPv4') + ' / ' + uci.get('ddns',key,'interface')
+ ];
+ }), E('em', _('There is no service configured.')));
+
+ return E([table]);
+ }
+});