Merge pull request #563 from cshore/pull-request-app-uhttpd
[project/luci.git] / applications / luci-app-uhttpd / luasrc / model / cbi / uhttpd / uhttpd.lua
1 -- Copyright 2015 Daniel Dickinson <openwrt@daniel.thecshore.com>
2 -- Licensed to the public under the Apache License 2.0.
3
4 local fs = require("nixio.fs")
5
6 local m = Map("uhttpd", translate("uHTTPd"),
7               translate("A lightweight single-threaded HTTP(S) server"))
8
9 local ucs = m:section(TypedSection, "uhttpd", "")
10 ucs.addremove = true
11 ucs.anonymous = false
12
13 local lhttp = nil
14 local lhttps = nil
15 local cert_file = nil
16 local key_file = nil
17
18 ucs:tab("general", translate("General Settings"))
19 ucs:tab("server", translate("Full Web Server Settings"), translate("For settings primarily geared to serving more than the web UI"))
20 ucs:tab("advanced", translate("Advanced Settings"), translate("Settings which are either rarely needed or which affect serving the WebUI"))
21
22 lhttp = ucs:taboption("general", DynamicList, "listen_http", translate("HTTP listeners (address:port)"), translate("Bind to specific interface:port (by specifying interface address"))
23 lhttp.datatype = "list(ipaddrport(1))"
24
25 function lhttp.validate(self, value, section)
26         local have_https_listener = false
27         local have_http_listener = false
28         if lhttp and lhttp:formvalue(section) and (#(lhttp:formvalue(section)) > 0) then
29                 for k, v in pairs(lhttp:formvalue(section)) do
30                         if v and (v ~= "") then
31                                 have_http_listener = true
32                                 break
33                         end
34                 end
35         end
36         if lhttps and lhttps:formvalue(section) and (#(lhttps:formvalue(section)) > 0) then
37                 for k, v in pairs(lhttps:formvalue(section)) do
38                         if v and (v ~= "") then
39                                 have_https_listener = true
40                                 break
41                         end
42                 end
43         end
44         if not (have_http_listener or have_https_listener) then
45                 return nil, "must listen on at list one address:port"
46         end
47         return DynamicList.validate(self, value, section)
48 end
49
50 lhttps = ucs:taboption("general", DynamicList, "listen_https", translate("HTTPS listener (address:port)"), translate("Bind to specific interface:port (by specifying interface address"))
51 lhttps.datatype = "list(ipaddrport(1))"
52 lhttps:depends("cert")
53 lhttps:depends("key")
54
55 function lhttps.validate(self, value, section)
56         local have_https_listener = false
57         local have_http_listener = false
58         if lhttps and lhttps:formvalue(section) and (#(lhttps:formvalue(section)) > 0) then
59                 for k, v in pairs(lhttps:formvalue(section)) do
60                         if v and (v ~= "") then
61                                 have_https_listener = true
62                                 break
63                         end
64                 end
65                 if have_https_listener and ((not cert_file) or (not cert_file:formvalue(section)) or (cert_file:formvalue(section) == ""))  then
66                         return nil, "must have certificate when using https"
67                 end
68                 if have_https_listener and ((not key_file) or (not key_file:formvalue(section)) or (key_file:formvalue(section) == "")) then
69                         return nil, "must have key when using https"
70                 end
71         end
72         if lhttp and (lhttp:formvalue(section)) and (#lhttp:formvalue(section) > 0) then
73                 for k, v in pairs(lhttp:formvalue(section)) do
74                         if v and (v ~= "") then
75                                 have_http_listener = true
76                                 break
77                         end
78                 end
79         end
80         if not (have_http_listener or have_https_listener) then
81                 return nil, "must listen on at list one address:port"
82         end
83         return DynamicList.validate(self, value, section)
84 end
85
86 o = ucs:taboption("general", Flag, "redirect_https", translate("Redirect all HTTP to HTTPS"))
87 o.default = o.enabled
88 o.rmempty = false
89
90 o = ucs:taboption("general", Flag, "rfc1918_filter", translate("Ignore private IPs on public interface"), translate("Prevent access from private (RFC1918) IPs on an interface if it has an public IP address"))
91 o.default = o.enabled
92 o.rmempty = false
93
94 cert_file = ucs:taboption("general", FileUpload, "cert", translate("HTTPS Certificate (DER Encoded)"))
95
96 key_file = ucs:taboption("general", FileUpload, "key", translate("HTTPS Private Key (DER Encoded)"))
97
98 o = ucs:taboption("general", Button, "remove_old", translate("Remove old certificate and key"),
99                   translate("uHTTPd will generate a new self-signed certificate using the configuration shown below."))
100 o.inputstyle = "remove"
101
102 function o.write(self, section)
103         if cert_file:cfgvalue(section) and fs.access(cert_file:cfgvalue(section)) then fs.unlink(cert_file:cfgvalue(section)) end
104         if key_file:cfgvalue(section) and fs.access(key_file:cfgvalue(section)) then fs.unlink(key_file:cfgvalue(section)) end
105         luci.sys.call("/etc/init.d/uhttpd restart")
106         luci.http.redirect(luci.dispatcher.build_url("admin", "services", "uhttpd"))
107 end
108
109 o = ucs:taboption("general", Button, "remove_conf", translate("Remove configuration for certificate and key"),
110         translate("This permanently deletes the cert, key, and configuration to use same."))
111 o.inputstyle = "remove"
112
113 function o.write(self, section)
114         if cert_file:cfgvalue(section) and fs.access(cert_file:cfgvalue(section)) then fs.unlink(cert_file:cfgvalue(section)) end
115         if key_file:cfgvalue(section) and fs.access(key_file:cfgvalue(section)) then fs.unlink(key_file:cfgvalue(section)) end
116         self.map:del(section, "cert")
117         self.map:del(section, "key")
118         self.map:del(section, "listen_https")
119         luci.http.redirect(luci.dispatcher.build_url("admin", "services", "uhttpd"))
120 end
121
122 o = ucs:taboption("server", DynamicList, "index_page", translate("Index page(s)"), translate("E.g specify with index.html and index.php when using PHP"))
123 o.optional = true
124 o.placeholder = "index.html"
125
126 o = ucs:taboption("server", DynamicList, "interpreter", translate("CGI filetype handler"), translate("Interpreter to associate with file endings ('suffix=handler', e.g. '.php=/usr/bin/php-cgi')"))
127 o.optional = true
128
129 o = ucs:taboption("server", Flag, "no_symlinks", translate("Do not follow symlinks outside document root"))
130 o.optional = true
131
132 o = ucs:taboption("server", Flag, "no_dirlists", translate("Do not generate directory listings."))
133 o.default = o.disabled
134
135 o = ucs:taboption("server", DynamicList, "alias", translate("Aliases"), translate("(/old/path=/new/path) or (just /old/path which becomes /cgi-prefix/old/path)"))
136 o.optional = true
137
138 o = ucs:taboption("server", Value, "realm", translate("Realm for Basic Auth"))
139 o.optional = true
140 o.placeholder = luci.sys.hostname() or "OpenWrt"
141
142 local httpconfig = ucs:taboption("server", Value, "config", translate("Config file (e.g. for credentials for Basic Auth)"), translate("Will not use HTTP authentication if not present"))
143 httpconfig.optional = true
144
145 o = ucs:taboption("server", Value, "error_page", translate("404 Error"), translate("Virtual URL or CGI script to display on status '404 Not Found'.  Must begin with '/'"))
146 o.optional = true
147
148 o = ucs:taboption("advanced", Value, "home", translate("Document root"),
149                   translate("Base directory for files to be served"))
150 o.default = "/www"
151 o.datatype = "directory"
152
153 o = ucs:taboption("advanced", Value, "cgi_prefix", translate("Path prefix for CGI scripts"), translate("CGI is disabled if not present."))
154 o.optional = true
155
156 o = ucs:taboption("advanced", Value, "lua_prefix", translate("Virtual path prefix for Lua scripts"))
157 o.placeholder = "/lua"
158 o.optional = true
159
160 o = ucs:taboption("advanced", Value, "lua_handler", translate("Full real path to handler for Lua scripts"), translate("Embedded Lua interpreter is disabled if not present."))
161 o.optional = true
162
163 o = ucs:taboption("advanced", Value, "ubus_prefix", translate("Virtual path prefix for ubus via JSON-RPC integration"), translate("ubus integration is disabled if not present"))
164 o.optional = true
165
166 o = ucs:taboption("advanced", Value, "ubus_socket", translate("Override path for ubus socket"))
167 o.optional = true
168
169 o = ucs:taboption("advanced", Flag, "ubus_cors", translate("Enable JSON-RPC Cross-Origin Resource Support"))
170 o.default = o.disabled
171 o.optional = true
172
173 o = ucs:taboption("advanced", Flag, "no_ubusauth", translate("Disable JSON-RPC authorization via ubus session API"))
174 o.optional= true
175 o.default = o.disabled
176
177 o = ucs:taboption("advanced", Value, "script_timeout", translate("Maximum wait time for Lua, CGI, or ubus execution"))
178 o.placeholder = 60
179 o.datatype = "uinteger"
180 o.optional = true
181
182 o = ucs:taboption("advanced", Value, "network_timeout", translate("Maximum wait time for network activity"))
183 o.placeholder = 30
184 o.datatype = "uinteger"
185 o.optional = true
186
187 o = ucs:taboption("advanced", Value, "http_keepalive", translate("Connection reuse"))
188 o.placeholder = 20
189 o.datatype = "uinteger"
190 o.optional = true
191
192 o = ucs:taboption("advanced", Value, "tcp_keepalive", translate("TCP Keepalive"))
193 o.optional = true
194 o.datatype = "uinteger"
195 o.default = 1
196
197 o = ucs:taboption("advanced", Value, "max_connections", translate("Maximum number of connections"))
198 o.optional = true
199 o.datatype = "uinteger"
200
201 o = ucs:taboption("advanced", Value, "max_requests", translate("Maximum number of script requests"))
202 o.optional = true
203 o.datatype = "uinteger"
204
205 local s = m:section(NamedSection, "px5g", "cert", translate("uHTTPd Self-signed Certificate Parameters"))
206
207 o = s:option(Value, "days", translate("Valid for # of Days"))
208 o.default = 730
209 o.datatype = "uinteger"
210
211 o = s:option(Value, "bits", translate("Length of key in bits"))
212 o.default = 1024
213 o.datatype = "min(1024)"
214
215 o = s:option(Value, "commonname", translate("Server Hostname"), translate("a.k.a CommonName"))
216 o.default = luci.sys.hostname()
217
218 o = s:option(Value, "country", translate("Country"))
219 o.default = "ZZ"
220
221 o = s:option(Value, "state", translate("State"))
222 o.default = "Unknown"
223
224 o = s:option(Value, "location", translate("Location"))
225 o.default = "Somewhere"
226
227 return m