uhttpd.js 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258
  1. 'use strict';
  2. 'require view';
  3. 'require form';
  4. 'require fs';
  5. 'require uci';
  6. return view.extend({
  7. load: function () {
  8. return Promise.all([uci.load('uhttpd')]);
  9. },
  10. render: function () {
  11. var lhttp = null;
  12. var lhttps = null;
  13. var cert_file = null;
  14. var key_file = null;
  15. var ucs = null;
  16. var uhttpdMap = new form.Map('uhttpd', _('uHTTPd'), _('A lightweight single-threaded HTTP(S) server'));
  17. ucs = uhttpdMap.section(form.TypedSection, 'uhttpd');
  18. ucs.addremove = true;
  19. ucs.anonymous = false;
  20. ucs.tab('general', _('General Settings'));
  21. ucs.tab('server', _('Full Web Server Settings'), _('For settings primarily geared to serving more than the web UI'));
  22. ucs.tab('advanced', _('Advanced Settings'), _('Settings which are either rarely needed or which affect serving the WebUI'));
  23. lhttp = ucs.taboption('general', form.DynamicList, 'listen_http', _('HTTP listeners (address:port)'), _('Bind to specific interface:port (by specifying interface address)'));
  24. lhttp.datatype = 'list(ipaddrport(1))';
  25. lhttp.validate = function (section_id, value) {
  26. var have_https_listener = false;
  27. var have_http_listener = false;
  28. if (lhttp && lhttp.formvalue(section_id) && lhttp.formvalue(section_id).length > 0) {
  29. lhttp.formvalue(section_id).forEach(function (v) {
  30. if (v && v !== '') {
  31. have_http_listener = true;
  32. return false;
  33. }
  34. });
  35. }
  36. if (lhttps && lhttps.formvalue(section_id) && lhttps.formvalue(section_id).length > 0) {
  37. lhttps.formvalue(section_id).forEach(function (v) {
  38. if (v && v !== '') {
  39. have_https_listener = true;
  40. return false;
  41. }
  42. });
  43. }
  44. if (!(have_http_listener || have_https_listener)) {
  45. return [null, 'must listen on at least one address:port'];
  46. }
  47. return true;
  48. };
  49. lhttps = ucs.taboption('general', form.DynamicList, 'listen_https', _('HTTPS listener (address:port)'), _('Bind to specific interface:port (by specifying interface address)'));
  50. lhttps.datatype = 'list(ipaddrport(1))';
  51. var cert = uci.get('uhttpd', 'main', 'cert');
  52. var key = uci.get('uhttpd', 'main', 'key');
  53. lhttps.validate = function (section_id, value) {
  54. let have_https_listener = false;
  55. let have_http_listener = false;
  56. if (lhttps && lhttps.formvalue(section_id) && lhttps.formvalue(section_id).length > 0) {
  57. lhttps.formvalue(section_id).forEach(function (v) {
  58. if (v && v !== '') {
  59. have_https_listener = true;
  60. return false;
  61. }
  62. });
  63. if (have_https_listener && (!cert_file || !cert_file.formvalue(section_id) || cert_file.formvalue(section_id) === '')) {
  64. return [null, 'must have certificate when using https'];
  65. }
  66. if (have_https_listener && (!key_file || !key_file.formvalue(section_id) || key_file.formvalue(section_id) === '')) {
  67. return [null, 'must have key when using https'];
  68. }
  69. }
  70. if (lhttp && lhttp.formvalue(section_id) && lhttp.formvalue(section_id).length > 0) {
  71. lhttp.formvalue(section_id).forEach(function (v) {
  72. if (v && v !== '') {
  73. have_http_listener = true;
  74. return false;
  75. }
  76. });
  77. }
  78. if (!(have_http_listener || have_https_listener)) {
  79. return [null, 'must listen on at least one address:port'];
  80. }
  81. return true;
  82. };
  83. lhttps.depends({ cert, key });
  84. var httptoHttps = ucs.taboption('general', form.Flag, 'redirect_https', _('Redirect all HTTP to HTTPS'));
  85. httptoHttps.default = httptoHttps.enabled;
  86. httptoHttps.rmempty = false;
  87. var rfc1918Filter = ucs.taboption('general', form.Flag, 'rfc1918_filter', _('Ignore private IPs on public interface'), _('Prevent access from private (RFC1918) IPs on an interface if it has an public IP address'));
  88. rfc1918Filter.default = rfc1918Filter.enabled;
  89. rfc1918Filter.rmempty = false;
  90. cert_file = ucs.taboption('general', form.FileUpload, 'cert', _('HTTPS Certificate (DER or PEM format)'), _('Files can only be uploaded and saved to the /etc/luci-uploads directory.'));
  91. cert_file.root_directory = '/';
  92. cert_file.enable_remove = false;
  93. key_file = ucs.taboption('general', form.FileUpload, 'key', _('HTTPS Private Key (DER or PEM format)'), _('Files can only be uploaded and saved to the /etc/luci-uploads directory.'));
  94. key_file.root_directory = '/';
  95. key_file.enable_remove = false;
  96. var removeOld = ucs.taboption('general', form.Button, 'remove_old', _('Remove old certificate and key'), _('uHTTPd will generate a new self-signed certificate using the configuration shown below.'));
  97. removeOld.inputstyle = 'remove';
  98. removeOld.onclick = function (section_id) {
  99. fs.remove(`${uci.get('uhttpd', 'main', 'cert')}`)
  100. .then(() => fs.remove(`${uci.get('uhttpd', 'main', 'key')}`))
  101. .then(() => {
  102. return fs.exec('/etc/init.d/uhttpd', ['restart']);
  103. })
  104. .finally(() => {
  105. window.location.reload();
  106. });
  107. };
  108. var removeConf = ucs.taboption('general', form.Button, 'remove_conf', _('Remove configuration for certificate and key'), _('This permanently deletes the cert, key, and configuration to use same.'));
  109. removeConf.inputstyle = 'remove';
  110. removeConf.onclick = function (section_id) {
  111. fs.remove(`${uci.get('uhttpd', 'main', 'cert')}`)
  112. .then(() => fs.remove(`${uci.get('uhttpd', 'main', 'key')}`))
  113. .then(() => {
  114. uci.unset('uhttpd', 'main', 'cert');
  115. uci.unset('uhttpd', 'main', 'key');
  116. uci.unset('uhttpd', 'main', 'listen_https');
  117. return uci.save();
  118. })
  119. .then(() => {
  120. return fs.exec('/etc/init.d/uhttpd', ['restart']);
  121. })
  122. .finally(() => {
  123. window.location.reload();
  124. });
  125. };
  126. var indexPage = ucs.taboption('server', form.DynamicList, 'index_page', _('Index page(s)'), _('E.g specify with index.html and index.php when using PHP'));
  127. indexPage.optional = true;
  128. indexPage.placeholder = 'index.html';
  129. var interpreter = ucs.taboption('server', form.DynamicList, 'interpreter', _('CGI filetype handler'), _("Interpreter to associate with file endings ('suffix=handler', e.g. '.php=/usr/bin/php-cgi')"));
  130. interpreter.optional = true;
  131. var noSymlinks = ucs.taboption('server', form.Flag, 'no_symlinks', _('Do not follow symlinks outside document root'));
  132. noSymlinks.optional = true;
  133. var noDirlists = ucs.taboption('server', form.Flag, 'no_dirlists', _('Do not generate directory listings.'));
  134. noDirlists.default = noDirlists.disabled;
  135. var alias = ucs.taboption('server', form.DynamicList, 'alias', _('Aliases'), _('(/old/path=/new/path) or (just /old/path which becomes /cgi-prefix/old/path)'));
  136. alias.optional = true;
  137. var realm = ucs.taboption('server', form.Value, 'realm', _('Realm for Basic Auth'));
  138. realm.optional = true;
  139. realm.placeholder = window.location.hostname || 'OpenWrt';
  140. var httpconfig = ucs.taboption('server', form.Value, 'config', _('Config file (e.g. for credentials for Basic Auth)'), _('Will not use HTTP authentication if not present'));
  141. httpconfig.optional = true;
  142. var errorPage = ucs.taboption('server', form.Value, 'error_page', _('404 Error'), _("Virtual URL or CGI script to display on status '404 Not Found'. Must begin with '/'"));
  143. errorPage.optional = true;
  144. var docRoot = ucs.taboption('advanced', form.Value, 'home', _('Document root'), _('Base directory for files to be served'));
  145. docRoot.default = '/www';
  146. docRoot.datatype = 'directory';
  147. var cgiPrefix = ucs.taboption('advanced', form.Value, 'cgi_prefix', _('Path prefix for CGI scripts'), _('CGI is disabled if not present.'));
  148. cgiPrefix.optional = true;
  149. var luaPrefix = ucs.taboption('advanced', form.Value, 'lua_prefix', _('Virtual path prefix for Lua scripts'));
  150. luaPrefix.placeholder = '/lua';
  151. luaPrefix.optional = true;
  152. var luaHandler = ucs.taboption('advanced', form.Value, 'lua_handler', _('Full real path to handler for Lua scripts'), _('Embedded Lua interpreter is disabled if not present.'));
  153. luaHandler.optional = true;
  154. var ubusPrefix = ucs.taboption('advanced', form.Value, 'ubus_prefix', _('Virtual path prefix for ubus via JSON-RPC integration'), _('ubus integration is disabled if not present'));
  155. ubusPrefix.optional = true;
  156. var ubusSocket = ucs.taboption('advanced', form.Value, 'ubus_socket', _('Override path for ubus socket'));
  157. ubusSocket.optional = true;
  158. var ubusCors = ucs.taboption('advanced', form.Flag, 'ubus_cors', _('Enable JSON-RPC Cross-Origin Resource Support'));
  159. ubusCors.default = ubusCors.disabled;
  160. ubusCors.optional = true;
  161. var noUbusauth = ucs.taboption('advanced', form.Flag, 'no_ubusauth', _('Disable JSON-RPC authorization via ubus session API'));
  162. noUbusauth.optional = true;
  163. noUbusauth.default = noUbusauth.disabled;
  164. var scriptTimeout = ucs.taboption('advanced', form.Value, 'script_timeout', _('Maximum wait time for Lua, CGI, or ubus execution'));
  165. scriptTimeout.placeholder = 60;
  166. scriptTimeout.datatype = 'uinteger';
  167. scriptTimeout.optional = true;
  168. var networkTimeout = ucs.taboption('advanced', form.Value, 'network_timeout', _('Maximum wait time for network activity'));
  169. networkTimeout.placeholder = 30;
  170. networkTimeout.datatype = 'uinteger';
  171. networkTimeout.optional = true;
  172. var httpKeepalive = ucs.taboption('advanced', form.Value, 'http_keepalive', _('Connection reuse'));
  173. httpKeepalive.placeholder = 20;
  174. httpKeepalive.datatype = 'uinteger';
  175. httpKeepalive.optional = true;
  176. var tcpKeepalive = ucs.taboption('advanced', form.Value, 'tcp_keepalive', _('TCP Keepalive'));
  177. tcpKeepalive.optional = true;
  178. tcpKeepalive.datatype = 'uinteger';
  179. tcpKeepalive.default = 1;
  180. var maxConnections = ucs.taboption('advanced', form.Value, 'max_connections', _('Maximum number of connections'));
  181. maxConnections.optional = true;
  182. maxConnections.datatype = 'uinteger';
  183. var maxRequests = ucs.taboption('advanced', form.Value, 'max_requests', _('Maximum number of script requests'));
  184. maxRequests.optional = true;
  185. maxRequests.datatype = 'uinteger';
  186. var certParam = uhttpdMap.section(form.TypedSection, 'cert', _('uHTTPd Self-signed Certificate Parameters'));
  187. certParam.template = 'cbi/tsection';
  188. certParam.anonymous = true;
  189. var days = certParam.option(form.Value, 'days', _('Valid for # of Days'));
  190. days.default = 730;
  191. days.datatype = 'uinteger';
  192. var bits = certParam.option(form.Value, 'bits', _('Length of key in bits'));
  193. bits.default = 2048;
  194. bits.datatype = 'min(1024)';
  195. var commonname = certParam.option(form.Value, 'commonname', _('Server Hostname'), _('a.k.a CommonName'));
  196. commonname.default = window.location.hostname || 'OpenWrt';
  197. var organization = certParam.option(form.Value, 'organization', _('Organization'), _('If empty, a random/unique value is used in cert generation'));
  198. var location = certParam.option(form.Value, 'location', _('Location'));
  199. location.default = 'Unknown';
  200. var state = certParam.option(form.Value, 'state', _('State'));
  201. state.default = 'Unknown';
  202. var country = certParam.option(form.Value, 'country', _('Country'));
  203. country.default = 'ZZ';
  204. return uhttpdMap.render();
  205. },
  206. });