tinyproxy.js 9.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346
  1. 'use strict';
  2. 'require view';
  3. 'require form';
  4. 'require fs';
  5. 'require uci';
  6. 'require poll';
  7. 'require ui';
  8. var status = '';
  9. var url = 'http://127.0.0.1:%d/';
  10. var port = 8888;
  11. var isenabled = true;
  12. var TinyproxyStatus = form.DummyValue.extend({
  13. load: function() {
  14. this.default=E('div', { 'id': 'tinyproxystatusid' },'');
  15. }
  16. });
  17. var Tinyproxybuttons = form.DummyValue.extend({
  18. load: function() {
  19. var buttons = E([]);
  20. var restartButton = E('button', {
  21. 'id': 'restartbutton',
  22. 'class': 'cbi-button cbi-button-neutral',
  23. }, _('Restart tinyproxy')
  24. );
  25. restartButton.addEventListener('click', function() {
  26. fs.exec('/etc/init.d/tinyproxy', ['restart']);
  27. });
  28. var reloadButton = E('button', {
  29. 'id': 'reloadbutton',
  30. 'class': 'cbi-button cbi-button-neutral',
  31. }, _('Reload settings into tinyproxy')
  32. );
  33. reloadButton.addEventListener('click', function() {
  34. fs.exec('/etc/init.d/tinyproxy', ['reload']);
  35. });
  36. buttons.appendChild(E('div', { }, [restartButton, reloadButton ]));
  37. this.default= E('div', {}, [restartButton,reloadButton]);
  38. }
  39. });
  40. return view.extend({
  41. poll_status: function(nodes, data) {
  42. const element = document.getElementById('tinyproxystatusid');
  43. if (element) {
  44. element.innerHTML = '';
  45. let tempDiv = document.createElement('div');
  46. if ((data == null) || (data == '')) {
  47. if (isenabled == 1) {
  48. tempDiv.innerHTML = _('Waiting for data from url:') + ' ' + url.format(port);
  49. } else {
  50. tempDiv.innerHTML = _('Tinyproxy is disabled');
  51. }
  52. } else {
  53. tempDiv.innerHTML = data;
  54. }
  55. let styles = tempDiv.querySelectorAll('style');
  56. styles.forEach(style => style.remove());
  57. let elements = tempDiv.querySelectorAll('*');
  58. elements.forEach(el => el.removeAttribute('style'));
  59. element.appendChild(tempDiv);
  60. }
  61. },
  62. load: function() {
  63. },
  64. render: function () {
  65. var m, s, o, t, ta, v;
  66. m = new form.Map('tinyproxy', _('Tinyproxy'),_('Tinyproxy is a small and fast non-caching HTTP(S)-Proxy'));
  67. s = m.section(form.TypedSection);
  68. s.title = _('Status');
  69. s.anonymous = true;
  70. o = s.option(TinyproxyStatus);
  71. o = s.option(Tinyproxybuttons);
  72. s = m.section(form.TypedSection, 'tinyproxy', _('Server Settings'));
  73. s.anonymous = true;
  74. s.tab('general', _('General settings'));
  75. s.tab('privacy', _('Privacy settings'));
  76. s.tab('filteracl', _('Filtering and ACLs'));
  77. s.tab('limits', _('Server limits'));
  78. o = s.taboption('general', form.Flag, 'enabled', _('Enable Tinyproxy server'))
  79. o.rmempty = false;
  80. o = s.taboption('general', form.Value, 'Port', _('Listen port'),
  81. _('Specifies the HTTP port Tinyproxy is listening on for requests'));
  82. o.optional = true;
  83. o.datatype = 'port';
  84. o.placeholder = 8888;
  85. o = s.taboption('general', form.Value, 'Listen', _('Listen address'),
  86. _('Specifies the addresses Tinyproxy is listening on for requests'));
  87. o.optional = true;
  88. o.datatype = 'ipaddr';
  89. o.placeholder = '0.0.0.0';
  90. o = s.taboption('general', form.Value, 'Bind', _('Bind address'),
  91. _('Specifies the address Tinyproxy binds to for outbound forwarded requests'));
  92. o.optional = true;
  93. o.datatype = 'ipaddr';
  94. o.placeholder = '0.0.0.0';
  95. o = s.taboption('general', form.Value, 'DefaultErrorFile', _('Error page'),
  96. _('HTML template file to serve when HTTP errors occur'));
  97. o.optional = true;
  98. o.default = '/usr/share/tinyproxy/default.html';
  99. o = s.taboption('general', form.Value, 'StatFile', _('Statistics page'),
  100. _('HTML template file to serve for stat host requests'));
  101. o.optional = true;
  102. o.default = '/usr/share/tinyproxy/stats.html';
  103. o = s.taboption('general', form.Flag, 'Syslog', _('Use syslog'),
  104. _('Writes log messages to syslog instead of a log file'));
  105. o = s.taboption('general', form.Value, 'LogFile', _('Log file'),
  106. _('Log file to use for dumping messages'));
  107. o.default = '/var/log/tinyproxy.log';
  108. o.depends('Syslog', '');
  109. o = s.taboption('general', form.ListValue, 'LogLevel', _('Log level'),
  110. _('Logging verbosity of the Tinyproxy process'));
  111. o.value('Critical');
  112. o.value('Error');
  113. o.value('Warning');
  114. o.value('Notice');
  115. o.value('Connect');
  116. o.value('Info');
  117. o = s.taboption('general', form.Value, 'User', _('User'),
  118. _('Specifies the user name the Tinyproxy process is running as'));
  119. o.default = 'nobody';
  120. o = s.taboption('general', form.Value, 'Group', _('Group'),
  121. _('Specifies the group name the Tinyproxy process is running as'));
  122. o.default = 'nogroup';
  123. //
  124. // Privacy
  125. //
  126. o = s.taboption('privacy', form.Flag, 'XTinyproxy', _('X-Tinyproxy header'),
  127. _('Adds an \'X-Tinyproxy\' HTTP header with the client IP address to forwarded requests'));
  128. o = s.taboption('privacy', form.Value, 'ViaProxyName', _('Via hostname'),
  129. _('Specifies the Tinyproxy hostname to use in the Via HTTP header'));
  130. o.placeholder = 'tinyproxy';
  131. o.datatype = 'hostname';
  132. s.taboption('privacy', form.DynamicList, 'Anonymous', _('Header whitelist'),
  133. _('Specifies HTTP header names which are allowed to pass-through, all others are discarded. Leave empty to disable header filtering'));
  134. //
  135. // Filter
  136. //
  137. o = s.taboption('filteracl', form.DynamicList, 'Allow', _('Allowed clients'),
  138. _('List of IP addresses or ranges which are allowed to use the proxy server'));
  139. o.placeholder = '0.0.0.0';
  140. o.datatype = 'ipaddr';
  141. o = s.taboption('filteracl', form.DynamicList, 'ConnectPort', _('Allowed connect ports'),
  142. _('List of allowed ports for the CONNECT method. A single value \'0\' disables CONNECT completely, an empty list allows all ports'));
  143. o.placeholder = 0;
  144. o.datatype = 'port';
  145. s.taboption('filteracl', form.FileUpload, 'Filter', _('Filter file'),
  146. _('Plaintext file with URLs or domains to filter. One entry per line'));
  147. s.taboption('filteracl', form.Flag, 'FilterURLs', _('Filter by URLs'),
  148. _('By default, filtering is done based on domain names. Enable this to match against URLs instead'));
  149. s.taboption('filteracl', form.Flag, 'FilterExtended', _('Filter by RegExp'),
  150. _('By default, basic POSIX expressions are used for filtering. Enable this to activate extended regular expressions'));
  151. s.taboption('filteracl', form.Flag, 'FilterCaseSensitive', _('Filter case-sensitive'),
  152. _('By default, filter strings are treated as case-insensitive. Enable this to make the matching case-sensitive'));
  153. s.taboption('filteracl', form.Flag, 'FilterDefaultDeny', _('Default deny'),
  154. _('By default, the filter rules act as blacklist. Enable this option to only allow matched URLs or domain names'));
  155. //
  156. // Limits
  157. //
  158. o = s.taboption('limits', form.Value, 'Timeout', _('Connection timeout'),
  159. _('Maximum number of seconds an inactive connection is held open'));
  160. o.optional = true;
  161. o.datatype = 'uinteger';
  162. o.default = 600;
  163. o = s.taboption('limits', form.Value, 'MaxClients', _('Max. clients'),
  164. _('Maximum allowed number of concurrently connected clients'));
  165. o.datatype = 'uinteger';
  166. o.default = 10;
  167. o = s.taboption('limits', form.Value, 'MinSpareServers', _('Min. spare servers'),
  168. _('Minimum number of prepared idle processes'));
  169. o.datatype = 'uinteger';
  170. o.default = 5;
  171. o = s.taboption('limits', form.Value, 'MaxSpareServers', _('Max. spare servers'),
  172. _('Maximum number of prepared idle processes'));
  173. o.datatype = 'uinteger';
  174. o.default = 10;
  175. o = s.taboption('limits', form.Value, 'StartServers', _('Start spare servers'),
  176. _('Number of idle processes to start when launching Tinyproxy'));
  177. o.datatype = 'uinteger';
  178. o.default = 5;
  179. o = s.taboption('limits', form.Value, 'MaxRequestsPerChild', _('Max. requests per server'),
  180. _('Maximum allowed number of requests per process. If it is exeeded, the process is restarted. Zero means unlimited.'));
  181. o.datatype = 'uinteger';
  182. o.default = 0;
  183. //
  184. // Upstream
  185. //
  186. s = m.section(form.TypedSection, 'upstream', _('Upstream Proxies'),
  187. _('Upstream proxy rules define proxy servers to use when accessing certain IP addresses or domains.'));
  188. s.anonymous = true;
  189. s.addremove = true;
  190. t = s.option(form.ListValue, 'type', _('Policy'),
  191. _('<em>Via proxy</em> routes requests to the given target via the specified upstream proxy, <em>Reject access</em> disables any upstream proxy for the target'));
  192. t.value('proxy', _('Via proxy'));
  193. t.value('reject', _('Reject access'));
  194. ta = s.option(form.Value, 'target', _('Target host'),
  195. _('Can be either an IP address or range, a domain name or \'.\' for any host without domain'));
  196. ta.rmempty = true;
  197. ta.placeholder = '0.0.0.0/0';
  198. ta.datatype = 'host(1)';
  199. v = s.option(form.Value, 'via', _('Via proxy'),
  200. _('Specifies the upstream proxy to use for accessing the target host. Format is <code>address:port</code> or <code>socks5 address:port</code>'));
  201. v.depends({type: 'proxy'});
  202. v.placeholder = '10.0.0.1:8080';
  203. v.write = function(section_id, value) {
  204. if (value.match(/^\d+\.\d+\.\d+\.\d+:\d+/) ||
  205. value.match(/^socks5 \d+\.\d+\.\d+\.\d+:\d+/)) {
  206. return form.Value.prototype.write.apply(this, [section_id, value]);;
  207. } else {
  208. return
  209. }
  210. };
  211. return m.render().then(L.bind(function(m, nodes) {
  212. poll.add(L.bind(function() {
  213. return uci.load('tinyproxy').then(function() {
  214. port = uci.get_first('tinyproxy', 'tinyproxy', 'Port');
  215. isenabled = uci.get_first('tinyproxy', 'tinyproxy', 'enabled');
  216. if (isNaN(port) || port < 0 || port > 65535)
  217. port = 8888;
  218. return L.resolveDefault(fs.exec_direct('/usr/bin/wget', [ '-q', url.format(port), '-O', '-' ]), null);
  219. }).then(L.bind(this.poll_status, this, nodes));
  220. }, this), 5);
  221. return nodes;
  222. }, this, m));
  223. },
  224. handleSaveApply: function (ev, mode) {
  225. var Fn = L.bind(function() {
  226. fs.exec('/etc/init.d/tinyproxy', ['reload']);
  227. document.removeEventListener('uci-applied',Fn);
  228. });
  229. document.addEventListener('uci-applied', Fn);
  230. this.super('handleSaveApply', [ev, mode]);
  231. }
  232. });