c57de38724c03ce0f69ec0d60f3dd161f4772a81
[oweals/luci.git] / applications / luci-app-https-dns-proxy / luasrc / model / cbi / https-dns-proxy.lua
1 local sys = require "luci.sys"
2 local util = require "luci.util"
3 local fs = require "nixio.fs"
4 local dispatcher = require "luci.dispatcher"
5 local i18n = require "luci.i18n"
6 local uci = require("luci.model.uci").cursor()
7
8 local packageName = "https-dns-proxy"
9 local providers_dir = "/usr/lib/lua/luci/" .. packageName .. "/providers/"
10 local helperText = ""
11
12 function create_helper_text()
13         local initText = "<br />" .. translate("For more information on different options check") .. " "
14         for filename in fs.dir(providers_dir) do
15                 local p_func = loadfile(providers_dir .. filename)
16                 setfenv(p_func, { _ = i18n.translate })
17                 local p = p_func()
18                 if p.help_link then
19                         local url, domain
20                         url = p.help_link
21                         domain = p.help_link_text or url:match('^%w+://([^/]+)')
22                         if not helperText:find(domain) then
23                                 if helperText == "" then
24                                         helperText = initText
25                                 else
26                                         helperText = helperText .. ", "
27                                 end
28                                 helperText = helperText .. [[<a href="]] .. url .. [[">]] .. domain .. [[</a>]]
29                         end
30                 end
31         end
32         if helperText ~= "" then
33                 local a = helperText:gsub('(.*),%s.*$', '%1')
34                 helperText = a .. " " .. translate("and") .. helperText:sub(#a + 2) .. "."
35         end
36 end
37
38 function get_provider_name(value)
39         for filename in fs.dir(providers_dir) do
40                 local p_func = loadfile(providers_dir .. filename)
41                 setfenv(p_func, { _ = i18n.translate })
42                 local p = p_func()
43                 value = value:gsub('[%p%c%s]', '')
44                 p.url_match = p.resolver_url:gsub('[%p%c%s]', '')
45                 if value:match(p.url_match) then
46                         return p.label
47                 end
48         end
49         return translate("Unknown Provider")
50 end
51
52 local packageStatus, packageStatusCode
53 local ubusStatus = util.ubus("service", "list", { name = packageName })
54 local packageVersion = tostring(util.trim(sys.exec("opkg list-installed " .. packageName .. " | awk '{print $3}'"))) or ""
55
56 if packageVersion == "" then
57         packageStatusCode = -1
58         packageStatus = translatef("%s is not installed or not found", packageName)
59 else  
60         if not ubusStatus or not ubusStatus[packageName] then
61                 packageStatusCode = 0
62                 packageStatus = translate("Stopped")
63                 if not sys.init.enabled(packageName) then
64                         packageStatus = packageStatus .. " (" .. translate("disabled") .. ")"
65                 end
66         else
67                 packageStatusCode, packageStatus = 1, ""
68                 for n = 1,1000 do
69                         if ubusStatus and ubusStatus[packageName] and 
70                                  ubusStatus[packageName]["instances"] and 
71                                  ubusStatus[packageName]["instances"]["instance" .. n] and 
72                                  ubusStatus[packageName]["instances"]["instance" .. n]["running"] then
73                                 local value, k, v, url, url_flag, la, la_flag, lp, lp_flag
74                                 for k, v in pairs(ubusStatus[packageName]["instances"]["instance" .. n]["command"]) do
75                                         if la_flag then la, la_flag = v, false end
76                                         if lp_flag then lp, lp_flag = v, false end
77                                         if url_flag then url, url_flag = v, false end
78                                         if v == "-a" then la_flag = true end
79                                         if v == "-p" then lp_flag = true end
80                                         if v == "-r" then url_flag = true end
81                                 end
82                                 la = la or "127.0.0.1"
83                                 lp = lp or n + 5053
84                                 packageStatus = packageStatus .. translatef("Running: %s DoH at %s:%s", get_provider_name(url), la, lp) .. "\n"
85                         else
86                                 break
87                         end
88                 end
89         end
90 end
91
92 m = Map("https-dns-proxy", translate("DNS HTTPS Proxy Settings"))
93
94 h = m:section(TypedSection, "_dummy", translatef("Service Status [%s %s]", packageName, packageVersion))
95 h.template = "cbi/nullsection"
96 ss = h:option(DummyValue, "_dummy", translate("Service Status"))
97 if packageStatusCode == -1 then
98         ss.template = packageName .. "/status"
99         ss.value = packageStatus
100 else
101                 if packageStatusCode == 0 then
102                         ss.template = packageName .. "/status"
103                 else
104                         ss.template = packageName .. "/status-textarea"
105                 end
106         ss.value = packageStatus
107         buttons = h:option(DummyValue, "_dummy")
108         buttons.template = packageName .. "/buttons"
109 end
110
111 create_helper_text()
112 s3 = m:section(TypedSection, "https-dns-proxy", translate("Instances"), 
113         translatef("When you add/remove any instances below, they will be used to override the 'DNS forwardings' section of %sDHCP and DNS%s.", "<a href=\"" .. dispatcher.build_url("admin/network/dhcp") .. "\">", "</a>") .. helperText)
114 s3.template = "cbi/tblsection"
115 s3.sortable  = false
116 s3.anonymous = true
117 s3.addremove = true
118
119 prov = s3:option(ListValue, "resolver_url", translate("Resolver"))
120 for filename in fs.dir(providers_dir) do
121         local p_func = loadfile(providers_dir .. filename)
122         setfenv(p_func, { _ = i18n.translate })
123         local p = p_func()
124         prov:value(p.resolver_url, p.label)
125         if p.default then
126                 prov.default = p.resolver_url
127         end
128 end
129 prov.forcewrite = true
130 prov.write = function(self, section, value)
131         if not value then return end
132         for filename in fs.dir(providers_dir) do
133                 local p_func = loadfile(providers_dir .. filename)
134                 setfenv(p_func, { _ = i18n.translate })
135                 local p = p_func()
136                 value = value:gsub('[%p%c%s]', '')
137                 p.url_match = p.resolver_url:gsub('[%p%c%s]', '')
138                 if value:match(p.url_match) then
139                         uci:set(packageName, section, "bootstrap_dns", p.bootstrap_dns)
140                         uci:set(packageName, section, "resolver_url", p.resolver_url)
141                 end
142         end
143         uci:save(packageName)
144 end
145
146 la = s3:option(Value, "listen_addr", translate("Listen address"))
147 la.datatype    = "host"
148 la.placeholder = "127.0.0.1"
149 la.rmempty     = true
150
151 local n = 0
152 uci:foreach(packageName, packageName, function(s)
153                 if s[".name"] == section then
154                                 return false
155                 end
156                 n = n + 1
157 end)
158
159 lp = s3:option(Value, "listen_port", translate("Listen port"))
160 lp.datatype = "port"
161 lp.value    = n + 5053
162
163 sa = s3:option(Value, "edns_subnet", translate("EDNS client subnet"))
164 sa.rmempty  = true
165
166 ps = s3:option(Value, "proxy_server", translate("Proxy server"))
167 ps.rmempty  = true
168
169 return m