392cf239b786a94aba119f194e027c7f24a27c0f
[project/luci.git] / applications / luci-app-ddns / htdocs / luci-static / resources / view / ddns / overview.js
1 'use strict';
2 'require uci';
3 'require rpc';
4 'require fs';
5 'require form';
6 'require tools.widgets as widgets';
7
8 var callGetLogServices, callInitAction, callDDnsGetStatus;
9
10 var NextUpdateStrings = {};
11
12 NextUpdateStrings = {
13 'Verify' : _("Verify"),
14 'Run once' : _("Run once"),
15 'Disabled' : _("Disabled"),
16 'Stopped' : _("Stopped")
17 }
18
19 var time_res = {};
20 time_res['seconds'] = 1;
21 time_res['minutes'] = 60;
22 time_res['hours'] = 3600;
23
24 callGetLogServices = rpc.declare({
25 object: 'luci.ddns',
26 method: 'get_services_log',
27 params: [ 'service_name' ],
28 expect: { },
29 });
30
31 callInitAction = rpc.declare({
32 object: 'luci',
33 method: 'setInitAction',
34 params: [ 'name', 'action' ],
35 expect: { result: false }
36 });
37
38 callDDnsGetStatus = rpc.declare({
39 object: 'luci.ddns',
40 method: 'get_ddns_state',
41 expect: { }
42 });
43
44 return L.view.extend({
45
46 callDDnsGetEnv: rpc.declare({
47 object: 'luci.ddns',
48 method: 'get_env',
49 expect: { }
50 }),
51
52 callDDnsGetServicesStatus: rpc.declare({
53 object: 'luci.ddns',
54 method: 'get_services_status',
55 expect: { }
56 }),
57
58 poll_status: function(map, data) {
59 var status = data[1] || [], service = data[0] || [], rows = map.querySelectorAll('.cbi-section-table-row[data-sid]'),
60 section_id, cfg_detail_ip, cfg_update, cfg_status, host, ip, last_update,
61 next_update, service_status, reload, cfg_enabled, stop,
62 ddns_enabled = map.querySelector('[data-name="_enabled"]').querySelector('.cbi-value-field'),
63 ddns_toggle = map.querySelector('[data-name="_toggle"]').querySelector('button');
64
65 ddns_toggle.innerHTML = status['_enabled'] ? _('Stop DDNS') : _('Start DDNS')
66
67 L.dom.content(ddns_enabled, function() {
68 return E([], [
69 E('div', {}, status['_enabled'] ? _('DDNS Autostart enabled') : [
70 _('DDNS Autostart disabled'),
71 E('div', { 'class' : 'cbi-value-description' },
72 _("Currently DDNS updates are not started at boot or on interface events.") + "<br />" +
73 _("This is the default if you run DDNS scripts by yourself (i.e. via cron with force_interval set to '0')"))
74 ]),]);
75 });
76
77 for (var i = 0; i < rows.length; i++) {
78 section_id = rows[i].getAttribute('data-sid');
79 cfg_detail_ip = rows[i].querySelector('[data-name="_cfg_detail_ip"]');
80 cfg_update = rows[i].querySelector('[data-name="_cfg_update"]');
81 cfg_status = rows[i].querySelector('[data-name="_cfg_status"]');
82 reload = rows[i].querySelector('.cbi-section-actions .reload');
83 stop = rows[i].querySelector('.cbi-section-actions .stop');
84 cfg_enabled = uci.get('ddns', section_id, 'enabled');
85
86 reload.disabled = (status['_enabled'] == 0 || cfg_enabled == 0);
87
88 host = uci.get('ddns', section_id, 'lookup_host') || _('Configuration Error');
89 ip = _('No Data');
90 last_update = _('Never');
91 next_update = _('Unknown');
92 service_status = '<b>' + _('Not Running') + '</b>';
93
94 if (service[section_id]) {
95 stop.disabled = (!service[section_id].pid || (service[section_id].pid && cfg_enabled == '1'));
96 if (service[section_id].ip)
97 ip = service[section_id].ip;
98 if (service[section_id].last_update)
99 last_update = service[section_id].last_update;
100 if (service[section_id].next_update)
101 next_update = NextUpdateStrings[service[section_id].next_update] || service[section_id].next_update;
102 if (service[section_id].pid)
103 service_status = '<b>' + _('Running') + '</b> : ' + service[section_id].pid;
104 }
105
106 cfg_detail_ip.innerHTML = host + '<br />' + ip;
107 cfg_update.innerHTML = last_update + '<br />' + next_update;
108 cfg_status.innerHTML = service_status;
109 }
110
111 return;
112 },
113
114 load: function() {
115 return Promise.all([
116 this.callDDnsGetServicesStatus(),
117 callDDnsGetStatus(),
118 this.callDDnsGetEnv(),
119 fs.lines('/etc/ddns/services'),
120 fs.lines('/etc/ddns/services_ipv6'),
121 uci.load('ddns')
122 ]);
123 },
124
125 render: function(data) {
126 var resolved = data[0] || [];
127 var status = data[1] || [];
128 var env = data[2] || [];
129 var logdir = uci.get('ddns', 'global', 'ddns_logdir') || "/var/log/ddns";
130
131 var services4 = [];
132 var services6 = [];
133
134 data[3].forEach(function(item) {
135 if (!item.startsWith("#")) {
136 services4.push(item.split('\t')[0].slice(1,-1));
137 }
138 });
139
140 data[4].forEach(function(item) {
141 if (!item.startsWith("#")) {
142 services6.push(item.split('\t')[0].slice(1,-1));
143 }
144 });
145
146 var m, s, o;
147
148 m = new form.Map('ddns', _('Dynamic DNS'));
149
150 var is = m.section(form.NamedSection, 'global', 'ddns', _('Information'));
151
152 s = is;
153
154 o = s.option(form.DummyValue, '_version', _('Dynamic DNS Version'));
155 o.cfgvalue = function() {
156 return status[this.option];
157 };
158
159 o = s.option(form.DummyValue, '_enabled', _('State'));
160 o.cfgvalue = function() {
161 var res = status[this.option];
162 if (!res) {
163 this.description = _("Currently DDNS updates are not started at boot or on interface events.") + "<br />" +
164 _("This is the default if you run DDNS scripts by yourself (i.e. via cron with force_interval set to '0')")
165 }
166 return res ? _('DDNS Autostart enabled') : _('DDNS Autostart disabled')
167 };
168
169 o = s.option(form.DummyValue, '_toggle', '&#160;');
170 o.cfgvalue = function() {
171 var action = status['_enabled'] ? 'stop' : 'start';
172 return E([], [
173 E('button', {
174 'class': 'cbi-button cbi-button-apply',
175 'click': L.ui.createHandlerFn(this, function() {
176 return callDDnsGetStatus().then(L.bind(function(data) {
177 return callInitAction('ddns', action == 'stop' ? 'disable' : 'enable').then(function() {
178 return callInitAction('ddns', action);
179 });
180 }, this)).then(L.bind(m.render, m));
181 })
182 }, _(action.toUpperCase() + ' DDns'))]);
183 };
184
185 o = s.option(form.DummyValue, '_restart', '&#160;');
186 o.cfgvalue = function() {
187 return E([], [
188 E('button', {
189 'class': 'cbi-button cbi-button-apply',
190 'click': L.ui.createHandlerFn(this, function() {
191 return callInitAction('ddns', 'restart').then(L.bind(m.render, m));
192 })
193 }, _('Restart DDns'))]);
194 };
195
196 // DDns hints
197
198 if (!env['has_ipv6']) {
199 o = s.option(form.DummyValue, '_no_ipv6');
200 o.rawhtml = true;
201 o.title = '<b>' + _("IPv6 not supported") + '</b>';
202 o.cfgvalue = function() { return _("IPv6 is currently not (fully) supported by this system") + "<br />" +
203 _("Please follow the instructions on OpenWrt's homepage to enable IPv6 support") + "<br />" +
204 _("or update your system to the latest OpenWrt Release")};
205 }
206
207 if (!env['has_ssl']) {
208 o = s.option(form.DummyValue, '_no_https');
209 o.titleref = L.url("admin", "system", "opkg")
210 o.rawhtml = true;
211 o.title = '<b>' + _("HTTPS not supported") + '</b>';
212 o.cfgvalue = function() { return _("Neither GNU Wget with SSL nor cURL installed to support secure updates via HTTPS protocol.") +
213 "<br />- " +
214 _("You should install 'wget' or 'curl' or 'uclient-fetch' with 'libustream-*ssl' package.") +
215 "<br />- " +
216 _("In some versions cURL/libcurl in OpenWrt is compiled without proxy support.")};
217 }
218
219 if (!env['has_bindnet']) {
220 o = s.option(form.DummyValue, '_no_bind_network');
221 o.titleref = L.url("admin", "system", "opkg")
222 o.rawhtml = true;
223 o.title = '<b>' + _("Binding to a specific network not supported") + '</b>';
224 o.cfgvalue = function() { return _("Neither GNU Wget with SSL nor cURL installed to select a network to use for communication.") +
225 "<br />- " +
226 _("You should install 'wget' or 'curl' package.") +
227 "<br />- " +
228 _("GNU Wget will use the IP of given network, cURL will use the physical interface.") +
229 "<br />- " +
230 _("In some versions cURL/libcurl in OpenWrt is compiled without proxy support.")};
231 }
232
233 if (!env['has_proxy']) {
234 o = s.option(form.DummyValue, '_no_proxy');
235 o.titleref = L.url("admin", "system", "opkg")
236 o.rawhtml = true;
237 o.title = '<b>' + _("cURL without Proxy Support") + '</b>';
238 o.cfgvalue = function() { return _("cURL is installed, but libcurl was compiled without proxy support.") +
239 "<br />- " +
240 _("You should install 'wget' or 'uclient-fetch' package or replace libcurl.") +
241 "<br />- " +
242 _("In some versions cURL/libcurl in OpenWrt is compiled without proxy support.")};
243 }
244
245 if (!env['has_forceip']) {
246 o = s.option(form.DummyValue, '_no_force_ip');
247 o.titleref = L.url("admin", "system", "opkg")
248 o.rawhtml = true;
249 o.title = '<b>' + _("Force IP Version not supported") + '</b>';
250 o.cfgvalue = function() { return _("BusyBox's nslookup and Wget do not support to specify " +
251 "the IP version to use for communication with DDNS Provider!") +
252 "<br />- " + _("You should install 'wget' or 'curl' or 'uclient-fetch' package.")
253 };
254 }
255
256 if (!env['has_bindhost']) {
257 o = s.option(form.DummyValue, '_no_dnstcp');
258 o.titleref = L.url("admin", "system", "opkg")
259 o.rawhtml = true;
260 o.title = '<b>' + _("DNS requests via TCP not supported") + '</b>';
261 o.cfgvalue = function() { return _("BusyBox's nslookup and hostip do not support to specify to use TCP " +
262 "instead of default UDP when requesting DNS server!") +
263 "<br />- " +
264 _("You should install 'bind-host' or 'knot-host' or 'drill' package for DNS requests.")};
265 }
266
267 if (!env['has_dnsserver']) {
268 o = s.option(form.DummyValue, '_no_dnsserver');
269 o.titleref = L.url("admin", "system", "opkg")
270 o.rawhtml = true;
271 o.title = '<b>' + _("Using specific DNS Server not supported") + '</b>';
272 o.cfgvalue = function() { return _("BusyBox's nslookup in the current compiled version " +
273 "does not handle given DNS Servers correctly!") +
274 "<br />- " +
275 _("You should install 'bind-host' or 'knot-host' or 'drill' or 'hostip' package, " +
276 "if you need to specify a DNS server to detect your registered IP.")};
277 }
278
279 if (env['has_ssl'] && !env['has_cacerts']) {
280 o = s.option(form.DummyValue, '_no_certs');
281 o.titleref = L.url("admin", "system", "opkg")
282 o.rawhtml = true;
283 o.title = '<b>' + _("No certificates found") + '</b>';
284 o.cfgvalue = function() { return _("If using secure communication you should verify server certificates!") +
285 "<br />- " +
286 _("Install 'ca-certificates' package or needed certificates " +
287 "by hand into /etc/ssl/certs default directory")};
288 }
289
290 // DDns services
291 s = m.section(form.GridSection, 'service', _('Services'));
292 s.anonymous = true;
293 s.addremove = true;
294 s.addbtntitle = _('Add new services...');
295
296 s.anonymous = true;
297 s.addremove = true;
298 s.sortable = true;
299
300 s.handleAdd = function(ev) {
301 var m2 = new form.Map('ddns'),
302 s2 = m2.section(form.NamedSection, '_new_');
303
304 s2.render = function() {
305 return Promise.all([
306 {},
307 this.renderUCISection('_new_')
308 ]).then(this.renderContents.bind(this));
309 };
310
311 name = s2.option(form.Value, 'name', _('Name'));
312 name.rmempty = false;
313 name.datatype = 'uciname';
314 name.placeholder = _('New DDns Service…');
315 name.validate = function(section_id, value) {
316 if (uci.get('ddns', value) != null)
317 return _('The service name is already used');
318
319 return true;
320 };
321
322 m2.render().then(L.bind(function(nodes) {
323 L.ui.showModal(_('Add new services...'), [
324 nodes,
325 E('div', { 'class': 'right' }, [
326 E('button', {
327 'class': 'btn',
328 'click': L.ui.hideModal
329 }, _('Cancel')), ' ',
330 E('button', {
331 'class': 'cbi-button cbi-button-positive important',
332 'click': L.ui.createHandlerFn(this, function(ev) {
333 var nameval = name.isValid('_new_') ? name.formvalue('_new_') : null;
334
335 if (nameval == null || nameval == '')
336 return;
337
338 return m.save(function() {
339 uci.add('ddns', 'service', nameval);
340 }).then(L.bind(m.children[1].renderMoreOptionsModal, m.children[1], nameval));
341 })
342 }, _('Create service'))
343 ])
344 ], 'cbi-modal');
345
346 nodes.querySelector('[id="%s"] input[type="text"]'.format(name.cbid('_new_'))).focus();
347 }, this));
348 };
349
350 s.renderRowActions = function(section_id) {
351 var tdEl = this.super('renderRowActions', [ section_id, _('Edit') ]),
352 cfg_enabled = uci.get('ddns', section_id, 'enabled'),
353 reload_opt = {
354 'class': 'cbi-button cbi-button-neutral reload',
355 'click': L.ui.createHandlerFn(this, function() {
356 return fs.exec('/usr/lib/ddns/dynamic_dns_lucihelper.sh',
357 [ '-S', section_id, '--', 'start' ]).then(L.bind(m.render, m));
358 }),
359 'title': _('Reload this service'),
360 },
361 stop_opt = {
362 'class': 'cbi-button cbi-button-neutral stop',
363 'click': L.ui.createHandlerFn(this, function() {
364 return fs.exec('/usr/lib/ddns/dynamic_dns_lucihelper.sh',
365 [ '-S', section_id, '--', 'start' ]).then(L.bind(m.render, m));
366 }),
367 'title': _('Stop this service'),
368 };
369
370 if (status['_enabled'] == 0 || cfg_enabled == 0)
371 reload_opt['disabled'] = 'disabled';
372
373 if (!resolved[section_id] || !resolved[section_id].pid ||
374 (resolved[section_id].pid && cfg_enabled == '1'))
375 stop_opt['disabled'] = 'disabled';
376
377 L.dom.content(tdEl.lastChild, [
378 E('button', stop_opt, _('Stop')),
379 E('button', reload_opt, _('Reload')),
380 tdEl.lastChild.childNodes[0],
381 tdEl.lastChild.childNodes[1],
382 tdEl.lastChild.childNodes[2]
383 ]);
384
385 return tdEl;
386 };
387
388 o = s.option(form.DummyValue, '_cfg_name', _('Name'));
389 o.modalonly = false;
390 o.textvalue = function(section_id) {
391 return '<b>' + section_id + '</b>';
392 }
393
394 o = s.option(form.DummyValue, '_cfg_detail_ip', _('Lookup Hostname') + "<br />" + _('Registered IP'));
395 o.rawhtml = true;
396 o.modalonly = false;
397 o.textvalue = function(section_id) {
398 var host = uci.get('ddns', section_id, 'lookup_host') || _('Configuration Error'),
399 ip = _('No Data');
400 if (resolved[section_id] && resolved[section_id].ip)
401 ip = resolved[section_id].ip;
402
403 return host + '<br />' + ip;
404 };
405
406 o = s.option(form.Flag, 'enabled', _('Enabled'));
407 o.rmempty = false;
408 o.editable = true;
409 o.modalonly = false;
410
411 o = s.option(form.DummyValue, '_cfg_update', _('Last Update') + "<br />" + _('Next Update'));
412 o.rawhtml = true;
413 o.modalonly = false;
414 o.textvalue = function(section_id) {
415 var last_update = _('Never'), next_update = _('Unknown');
416 if (resolved[section_id]) {
417 if (resolved[section_id].last_update)
418 last_update = resolved[section_id].last_update;
419 if (resolved[section_id].next_update)
420 next_update = NextUpdateStrings[resolved[section_id].next_update] || resolved[section_id].next_update;
421 }
422
423 return last_update + '<br />' + next_update;
424 };
425
426 s.modaltitle = function(section_id) {
427 return _('DDns Service') + ' » ' + section_id;
428 };
429
430 o = s.option(form.DummyValue, '_cfg_status', _('Status'));
431 o.modalonly = false;
432 o.textvalue = function(section_id) {
433 var text = '<b>' + _('Not Running') + '</b>';
434
435 if (resolved[section_id] && resolved[section_id].pid)
436 text = '<b>' + _('Running') + '</b> : ' + resolved[section_id].pid;
437
438 return text;
439 }
440
441
442 s.tab('basic', _('Basic Settings'));
443 s.tab('advanced', _('Advanced Settings'));
444 s.tab('timer', _('Timer Settings'));
445 s.tab('logview', _('Log File Viewer'));
446
447 // TAB: BASIC
448
449 // enabled
450 o = s.taboption('basic', form.Flag, 'enabled', _('Enabled'),_("If this service section is disabled it could not be started." + "<br />" +
451 "Neither from LuCI interface nor from console"));
452 o.modalonly = true;
453 o.rmempty = false;
454 o.default = '1';
455
456 // lookup_host
457
458 o = s.taboption('basic', form.Value, 'lookup_host', _("Lookup Hostname"),
459 _("Hostname/FQDN to validate, if IP update happen or necessary") );
460 o.rmempty = false;
461 o.placeholder = "myhost.example.com";
462 o.datatype = 'and(minlength(3),hostname("strict"))';
463 o.modalonly = true;
464
465 // use_ipv6
466
467 o = s.taboption('basic', form.ListValue, 'use_ipv6', _("IP address version"),
468 _("Defines which IP address 'IPv4/IPv6' is send to the DDNS provider"));
469 o.default = '0';
470 o.modalonly = true;
471 o.rmempty = false;
472
473 o.value("0", _("IPv4-Address"))
474 if (env["has_ipv6"])
475 o.value("1", _("IPv6-Address"))
476
477 // service_name
478
479 o = s.taboption('basic', form.ListValue, 'ipv4_service_name', _("DDNS Service provider") + " [IPv4]");
480 o.depends("use_ipv6", "0")
481 o.modalonly = true;
482
483 for (var i = 0; i < services4.length; i++)
484 o.value(services4[i]);
485
486 o.value('-',"-- " + _("custom") + " --");
487
488 o.cfgvalue = function(section_id) {
489 return uci.get('ddns', section_id, 'service_name');
490 }
491
492 o.write = function(section_id, formvalue) {
493 if (formvalue != '-') {
494 uci.set('ddns', section_id, 'update_url', null);
495 uci.set('ddns', section_id, 'update_script', null);
496 return uci.set('ddns', section_id, 'service_name', formvalue);
497 }
498 return uci.set('ddns', section_id, 'service_name', null);
499 };
500
501 o = s.taboption('basic', form.ListValue, 'ipv6_service_name', _("DDNS Service provider") + " [IPv6]");
502 o.depends("use_ipv6", "1")
503 o.modalonly = true;
504
505 for (var i = 0; i < services6.length; i++)
506 o.value(services6[i]);
507
508 o.value('-',"-- " + _("custom") + " --");
509
510 o.cfgvalue = function(section_id) {
511 return uci.get('ddns', section_id, 'service_name');
512 }
513
514 o.write = function(section_id, formvalue) {
515 if (formvalue != '-') {
516 uci.set('ddns', section_id, 'update_url', null);
517 uci.set('ddns', section_id, 'update_script', null);
518 return uci.set('ddns', section_id, 'service_name', formvalue);
519 }
520 return uci.set('ddns', section_id, 'service_name', null);
521 };
522
523 // update_url
524
525 o = s.taboption('basic', form.Value, 'update_url', _("Custom update-URL"),
526 _("Update URL to be used for updating your DDNS Provider." + "<br />" +
527 "Follow instructions you will find on their WEB page."));
528 o.modalonly = true;
529 o.rmempty = false;
530 o.depends("ipv6_service_name","-");
531 o.depends("ipv4_service_name","-");
532
533 // update_script
534
535 o = s.taboption('basic', form.Value, 'update_script', _("Custom update-script"),
536 _("Custom update script to be used for updating your DDNS Provider."));
537 o.modalonly = true;
538 o.rmempty = false;
539 o.depends("ipv6_service_name","-");
540 o.depends("ipv4_service_name","-");
541
542 // domain
543
544 o = s.taboption('basic', form.Value, 'domain', _("Domain"),
545 _("Replaces [USERNAME] in Update-URL (URL-encoded)"));
546 o.modalonly = true;
547 o.rmempty = false;
548
549 // username
550
551 o = s.taboption('basic', form.Value, 'username', _("Username"),
552 _("Replaces [USERNAME] in Update-URL (URL-encoded)"));
553 o.modalonly = true;
554 o.rmempty = false;
555
556 // password
557
558
559 o = s.taboption('basic', form.Value, 'password', _("Password"),
560 _("Replaces [PASSWORD] in Update-URL (URL-encoded)"));
561 o.password = true;
562 o.modalonly = true;
563 o.rmempty = false;
564
565 // param_enc
566
567 o = s.taboption('basic', form.Value, 'param_enc', _("Optional Encoded Parameter"),
568 _("Optional: Replaces [PARAMENC] in Update-URL (URL-encoded)"));
569 o.optional = true;
570 o.modalonly = true;
571
572 // param_opt
573
574 o = s.taboption('basic', form.Value, 'param_opt', _("Optional Parameter"),
575 _("Optional: Replaces [PARAMOPT] in Update-URL (NOT URL-encoded)"));
576 o.optional = true;
577 o.modalonly = true;
578
579 // use_https
580
581 if (env['has_ssl']) {
582 o = s.taboption('basic', form.Flag, 'use_https', _("Use HTTP Secure"),
583 _("Enable secure communication with DDNS provider"));
584 o.optional = true;
585 o.modalonly = true;
586
587 o = s.taboption('basic', form.Value, 'cacert',
588 _("Path to CA-Certificate"),
589 _("directory or path/file") + "<br />" +
590 _("or") + '<b>' + " IGNORE " + '</b>' +
591 _("to run HTTPS without verification of server certificates (insecure)"));
592 o.modalonly = true;
593 o.depends("use_https", "1");
594 o.placeholder = "/etc/ssl/certs";
595 o.rmempty = false;
596 };
597
598 // TAB Advanced
599
600 // ip_source
601
602 o = s.taboption('advanced', form.ListValue, 'ip_source', _("IP address source"),
603 _("Defines the source to read systems IP-Address from, that will be send to the DDNS provider"));
604
605 o.modalonly = true;
606 o.default = "network";
607 o.value("network", _("Network"));
608 o.value("web", _("URL"));
609 o.value("interface", _("Interface"));
610 o.value("script", _("Script"));
611
612 o.write = function(section_id, formvalue) {
613 switch(formvalue) {
614 case 'network':
615 uci.set('ddns', section_id, "ip_url",null);
616 uci.set('ddns', section_id, "ip_interface",null);
617 uci.set('ddns', section_id, "ip_script",null);
618 break;
619 case 'web':
620 uci.set('ddns', section_id, "ip_network",null);
621 uci.set('ddns', section_id, "ip_interface",null);
622 uci.set('ddns', section_id, "ip_script",null);
623 break;
624 case 'interface':
625 uci.set('ddns', section_id, "ip_network",null);
626 uci.set('ddns', section_id, "ip_url",null);
627 uci.set('ddns', section_id, "ip_script",null);
628 break;
629 case 'script':
630 uci.set('ddns', section_id, "ip_network",null);
631 uci.set('ddns', section_id, "ip_url",null);
632 uci.set('ddns', section_id, "ip_interface",null);
633 break;
634 default:
635 break;
636 };
637
638 return uci.set('ddns', section_id, 'ip_source', formvalue )
639 };
640
641 // ip_network
642
643 o = s.taboption('advanced', widgets.NetworkSelect, 'ip_network', _("Network"),
644 _("Defines the network to read systems IP-Address from"));
645 o.depends('ip_source','network');
646 o.modalonly = true;
647 o.default = 'wan';
648 o.multiple = false;
649
650 // ip_url
651
652 o = s.taboption('advanced', form.Value, 'ip_url', _("URL to detect"),
653 _("Defines the Web page to read systems IP-Address from" + '<br />' +
654 _('Example for IPv4' + ': http://checkip.dyndns.com') + '<br />' +
655 _('Example for IPv6' + ': http://checkipv6.dyndns.com')));
656 o.depends("ip_source", "web")
657
658 o.modalonly = true;
659
660 // ip_interface
661
662 o = s.taboption('advanced', widgets.DeviceSelect, 'ip_interface', _("Interface"),
663 _("Defines the interface to read systems IP-Address from"));
664
665 o.modalonly = true;
666 o.depends("ip_source", "interface")
667 o.multiple = false;
668 o.default = 'wan';
669
670 // ip_script
671
672 o = s.taboption('advanced', form.Value, 'ip_script', _("Script"),
673 _("User defined script to read systems IP-Address"));
674
675 o.modalonly = true;
676 o.depends("ip_source", "script")
677 o.placeholder = "/path/to/script.sh"
678
679 // interface
680
681 o = s.taboption('advanced', widgets.DeviceSelect, 'interface', _("Event Network"),
682 _("Network on which the ddns-updater scripts will be started"));
683
684 o.modalonly = true;
685 o.multiple = false;
686 o.default = 'wan';
687 o.depends("ip_source", "web");
688 o.depends("ip_source", "script");
689
690 // interface_show
691
692 o = s.taboption('advanced', form.DummyValue, '_interface', _("Event Network"),
693 _("Network on which the ddns-updater scripts will be started"));
694 o.depends("ip_source", "interface");
695 o.depends("ip_source", "network");
696 o.forcewrite = true;
697 o.modalonly = true;
698 o.cfgvalue = function(section_id) {
699 return uci.get('ddns', section_id, 'interface') || _('This will be autoset to the selected interface');
700 };
701 o.write = function(section_id) {
702 var opt = this.section.children.filter(function(o) { return o.option == 'ip_source' })[0].formvalue(section_id);
703 var val = this.section.children.filter(function(o) { return o.option == 'ip_'+opt })[0].formvalue(section_id);
704 return uci.set('ddns', section_id, 'interface', val);
705 };
706
707 // bind_network
708
709 if (env['has_bindnet']) {
710 o = s.taboption('advanced', widgets.ZoneSelect, 'bind_network', _("Bind Network"),
711 _('OPTIONAL: Network to use for communication') + '<br />' +
712 _("Network on which the ddns-updater scripts will be started"));
713 o.depends("ip_source", "web");
714 o.optional = true;
715 o.rmempty = true;
716 o.modalonly = true;
717 }
718
719 // force_ipversion
720
721 if (env['has_forceip']) {
722 o = s.taboption('advanced', form.Flag, 'force_ipversion', _("Force IP Version"),
723 _('OPTIONAL: Force the usage of pure IPv4/IPv6 only communication.'));
724 o.optional = true;
725 o.rmempty = true;
726 o.modalonly = true;
727 }
728
729 // dns_server
730
731 if (env['has_dnsserver']) {
732 o = s.taboption("advanced", form.Value, "dns_server",
733 _("DNS-Server"),
734 _("OPTIONAL: Use non-default DNS-Server to detect 'Registered IP'.") + "<br />" +
735 _("Format: IP or FQDN"));
736 o.placeholder = "mydns.lan"
737 o.optional = true;
738 o.rmempty = true;
739 o.modalonly = true;
740 }
741
742 // force_dnstcp
743
744 if (env['has_bindhost']) {
745 o = s.taboption("advanced", form.Flag, "force_dnstcp",
746 _("Force TCP on DNS"),
747 _("OPTIONAL: Force the use of TCP instead of default UDP on DNS requests."));
748 o.optional = true;
749 o.rmempty = true;
750 o.modalonly = true;
751 }
752
753 // proxy
754
755 if (env['has_proxy']) {
756 o = s.taboption("advanced", form.Value, "proxy", _("PROXY-Server"),
757 _("OPTIONAL: Proxy-Server for detection and updates.") + "<br />" +
758 _("Format") + ": " + '<b>' + "[user:password@]proxyhost:port" + '</b>' + "<br />" +
759 _("IPv6 address must be given in square brackets") + ": " +
760 '<b>' + " [2001:db8::1]:8080" + '</b>');
761 o.optional = true;
762 o.rmempty = true;
763 o.modalonly = true;
764 }
765
766 // use_syslog
767
768 o = s.taboption("advanced", form.ListValue, "use_syslog", _("Log to syslog"),
769 _("Writes log messages to syslog. Critical Errors will always be written to syslog."));
770 o.modalonly = true;
771 o.placeholder = "2"
772 o.optional = true;
773 o.value("0", _("No logging"))
774 o.value("1", _("Info"))
775 o.value("2", _("Notice"))
776 o.value("3", _("Warning"))
777 o.value("4", _("Error"))
778
779 // use_logfile
780
781 o = s.taboption("advanced", form.Flag, "use_logfile", _("Log to file"));
782 o.default = '1';
783 o.optional = true;
784 o.modalonly = true;
785 o.cfgvalue = function(section_id) {
786 this.description = _("Writes detailed messages to log file. File will be truncated automatically.") + "<br />" +
787 _("File") + ': "' + logdir + '/' + section_id + '.log"';
788 return uci.get('ddns', section_id, 'use_logfile');
789 };
790
791 // TAB Timer
792
793 // check_interval
794 o = s.taboption("timer", form.Value, "check_interval", _("Check Interval"));
795 o.placeholder = "30";
796 o.modalonly = true;
797 o.datatype = 'uinteger';
798
799 o.validate = function(section_id, formvalue) {
800 var unit = this.section.children.filter(function(o) { return o.option == 'check_unit' })[0].formvalue(section_id),
801 time_to_sec = time_res[unit || 'minutes'] * formvalue;
802
803 if (formvalue && time_to_sec < 300)
804 return _('Values below 5 minutes == 300 seconds are not supported');
805
806 return true;
807
808 };
809
810 // check_interval
811 o = s.taboption("timer", form.ListValue, "check_unit",'Check Unit');
812 o.description = _("Interval unit to check for changed IP");
813 o.modalonly = true;
814 o.default = "minutes"
815 o.value("seconds", _("seconds"));
816 o.value("minutes", _("minutes"));
817 o.value("hours", _("hours"));
818
819 // force_interval
820
821 o = s.taboption("timer", form.Value, "force_interval", _("Force Interval"));
822 o.description = _("Interval to force updates send to DDNS Provider" + "<br />" +
823 "Setting this parameter to 0 will force the script to only run once");
824 o.placeholder = "72";
825 o.optional = true;
826 o.modalonly = true;
827 o.datatype = 'uinteger';
828
829 o.validate = function(section_id, formvalue) {
830
831 if (!formvalue)
832 return true;
833
834 var check_unit = this.section.children.filter(function(o) { return o.option == 'check_unit' })[0].formvalue(section_id),
835 check_val = this.section.children.filter(function(o) { return o.option == 'check_interval' })[0].formvalue(section_id),
836 force_unit = this.section.children.filter(function(o) { return o.option == 'force_unit' })[0].formvalue(section_id),
837 check_to_sec = time_res[check_unit || 'minutes'] * ( check_val || '30'),
838 force_to_sec = time_res[force_unit || 'minutes'] * formvalue;
839
840 if (force_to_sec != 0 && force_to_sec < check_to_sec)
841 return _("Values lower 'Check Interval' except '0' are not supported");
842
843 return true;
844 };
845
846 // force_unit
847
848 o = s.taboption("timer", form.ListValue, "force_unit",'Force Unit');
849 o.description = _("Interval unit to force updates send to DDNS Provider");
850 o.modalonly = true;
851 o.optional = true;
852 o.default = "minutes"
853 o.value("minutes", _("minutes"));
854 o.value("hours", _("hours"));
855 o.value("days", _("days"));
856
857 // retry_count
858
859 o = s.taboption("timer", form.Value, "retry_count", _("Error Retry Counter"));
860 o.description = _("On Error the script will stop execution after given number of retrys")
861 + "<br />"
862 + _("The default setting of '0' will retry infinite.");
863 o.placeholder = "0";
864 o.optional = true;
865 o.modalonly = true;
866 o.datatype = 'uinteger';
867
868 // retry_interval
869
870 o = s.taboption("timer", form.Value, "retry_interval", _("Error Retry Interval"));
871 o.description = _("On Error the script will stop execution after given number of retrys")
872 + "<br />"
873 + _("The default setting of '0' will retry infinite.");
874 o.placeholder = "60";
875 o.optional = true;
876 o.modalonly = true;
877 o.datatype = 'uinteger';
878
879 // retry_unit
880
881 o = s.taboption("timer", form.ListValue, "retry_unit",'Retry Unit');
882 o.description = _("On Error the script will retry the failed action after given time");
883 o.modalonly = true;
884 o.optional = true;
885 o.default = "seconds"
886 o.value("seconds", _("seconds"));
887 o.value("minutes", _("minutes"));
888
889 // TAB logview
890
891 o = s.taboption("logview", form.DummyValue, '_read_log', '');
892 o.depends('use_logfile','1');
893 o.modalonly = true;
894 o.cfgvalue = function(section_id) {
895 return E([], [
896 E('button', {
897 'class': 'cbi-button cbi-button-apply',
898 'click': L.ui.createHandlerFn(this, function() {
899 var o = this.section.children.filter(function(o) { return o.option == '_logview' })[0];
900 return callGetLogServices(section_id).then(L.bind(o.update_log, o));
901 })
902 }, _('Read / Reread log file'))]);
903 };
904
905 o = s.taboption("logview", form.DummyValue, "_logview");
906 o.depends('use_logfile','1');
907 o.modalonly = true;
908
909 o.update_log = L.bind(function(view, log_data) {
910 return document.getElementById('log_area').textContent = log_data.result;
911 }, o, this)
912
913 o.render = L.bind(function() {
914 return E([
915 E('p', {}, _('This is the current content of the log file in ') + logdir + ' for this service.'),
916 E('p', {}, E('textarea', { 'style': 'width:100%', 'rows': 20, 'readonly' : 'readonly', 'id' : 'log_area' }, _('Please press [Read] button') ))
917 ]);
918 }, o, this)
919
920
921 // Advanced Configuration Section
922
923 s = m.section(form.NamedSection, 'global', 'ddns', _('Global Configuration'));
924 s.description = _('Configure here the details for all Dynamic DNS services including this LuCI application.')
925 + '<br /><strong>'
926 + _("It is NOT recommended for casual users to change settings on this page.")
927 + '</strong><br />'
928 + '<a href="https://openwrt.org/docs/guide-user/base-system/ddns#section_ddns" target="_blank">'
929 + _('For detailed information about parameter settings look here.')
930 + '</a>';
931 s.addremove = false;
932
933 o = s.option(form.Flag, 'upd_privateip', _("Allow non-public IP's"));
934 o.description = _("Non-public and by default blocked IP's") + ':'
935 + '<br /><strong>IPv4: </strong>'
936 + '0/8, 10/8, 100.64/10, 127/8, 169.254/16, 172.16/12, 192.168/16'
937 + '<br /><strong>IPv6: </strong>'
938 + '::/32, f000::/4"';
939 o.default = "0";
940 o.optional = true;
941
942 o = s.option(form.Value, 'ddns_dateformat', _('Date format'));
943 o.description = '<a href="http://www.cplusplus.com/reference/ctime/strftime/" target="_blank">'
944 + _("For supported codes look here")
945 + '</a><br />' +
946 _('Current setting: ') + '<b>' + status['_curr_dateformat'] + '</b>';
947 o.default = "%F %R"
948 o.optional = true;
949 o.rmempty = true;
950
951 o = s.option(form.Value, 'ddns_rundir', _('Status directory'));
952 o.description = _('Directory contains PID and other status information for each running section.');
953 o.default = "/var/run/ddns";
954 o.optional = true;
955 o.rmempty = true;
956
957 o = s.option(form.Value, 'ddns_logdir', _('Log directory'));
958 o.description = _('Directory contains Log files for each running section.');
959 o.default = "/var/log/ddns";
960 o.optional = true;
961 o.rmempty = true;
962 o.validate = function(section_id, formvalue) {
963 if (formvalue.indexOf('../') !== -1)
964 return _('"../" not allowed in path for Security Reason.')
965
966 return true;
967 }
968
969 o = s.option(form.Value, 'ddns_loglines', _('Log length'));
970 o.description = _('Number of last lines stored in log files');
971 o.datatype = 'min(1)';
972 o.default = '250';
973
974 if (env['has_wget'] && env['has_curl']) {
975
976 o = s.option(form.Flag, 'use_curl', _('Use cURL'));
977 o.description = _('If Wget and cURL package are installed, Wget is used for communication by default.');
978 o.default = "0";
979 o.optional = true;
980 o.rmempty = true;
981
982 }
983
984 return m.render().then(L.bind(function(m, nodes) {
985 L.Poll.add(L.bind(function() {
986 return Promise.all([
987 this.callDDnsGetServicesStatus(),
988 callDDnsGetStatus()
989 ]).then(L.bind(this.poll_status, this, nodes));
990 }, this), 5);
991 return nodes;
992 }, this, m));
993 }
994 });