uhttpd.lua 9.1 KB

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