2
0

privoxy.lua 36 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922
  1. -- Copyright 2014-2015 Christian Schoenebeck <christian dot schoenebeck at gmail dot com>
  2. -- Licensed under the Apache License, Version 2.0
  3. local NXFS = require "nixio.fs"
  4. local SYS = require "luci.sys"
  5. local UTIL = require "luci.util"
  6. local DISP = require "luci.dispatcher"
  7. local DTYP = require "luci.cbi.datatypes"
  8. local CTRL = require "luci.controller.privoxy" -- this application's controller
  9. local HELP = [[<a href="http://www.privoxy.org/user-manual/config.html#%s" target="_blank">%s</a>]]
  10. -- Error handling if wrong privoxy version installed -- ########################
  11. if not CTRL.service_ok() then
  12. local f = SimpleForm("_sf")
  13. f.title = CTRL.app_title_main()
  14. f.description = CTRL.app_description()
  15. f.embedded = true
  16. f.submit = false
  17. f.reset = false
  18. local s = f:section(SimpleSection)
  19. local v = s:option(DummyValue, "_dv")
  20. v.titleref = DISP.build_url("admin", "system", "packages")
  21. v.rawhtml = true
  22. v.value = CTRL.service_update()
  23. return f
  24. end
  25. -- #################################################################################################
  26. -- Error handling if no config, create an empty one -- #########################
  27. if not NXFS.access("/etc/config/privoxy") then
  28. NXFS.writefile("/etc/config/privoxy", "")
  29. end
  30. -- cbi-map -- ##################################################################
  31. local m = Map("privoxy")
  32. m.title = CTRL.app_title_main()
  33. m.description = CTRL.app_description()
  34. function m.commit_handler(self)
  35. if self.changed then -- changes ?
  36. os.execute("/etc/init.d/privoxy reload &") -- reload configuration
  37. end
  38. end
  39. -- cbi-section -- ##############################################################
  40. local ns = m:section( NamedSection, "privoxy", "privoxy")
  41. function ns.cfgvalue(self, section)
  42. if not self.map:get("system") then -- section might not exist
  43. self.map:set("system", nil, "system")
  44. end
  45. if not self.map:get(section) then -- section might not exist
  46. self.map:set(section, nil, self.sectiontype)
  47. end
  48. return self.map:get(section)
  49. end
  50. ns:tab("sys",
  51. translate("System"),
  52. nil )
  53. local function err_tab_sys(title, msg)
  54. return string.format(translate("System") .. " - %s: %s", title, msg )
  55. end
  56. ns:tab("doc",
  57. translate("Documentation"),
  58. translate("If you intend to operate Privoxy for more users than just yourself, "
  59. .. "it might be a good idea to let them know how to reach you, what you block "
  60. .. "and why you do that, your policies, etc.") )
  61. local function err_tab_doc(title, msg)
  62. return string.format(translate("Documentation") .. " - %s: %s", title, msg )
  63. end
  64. ns:tab("filter",
  65. translate("Files and Directories"),
  66. translate("Privoxy can (and normally does) use a number of other files "
  67. .. "for additional configuration, help and logging. This section of "
  68. .. "the configuration file tells Privoxy where to find those other files.") )
  69. local function err_tab_filter(title, msg)
  70. return string.format(translate("Files and Directories") .. " - %s: %s", title, msg )
  71. end
  72. ns:tab("access",
  73. translate("Access Control"),
  74. translate("This tab controls the security-relevant aspects of Privoxy's configuration.") )
  75. local function err_tab_access(title, msg)
  76. return string.format(translate("Access Control") .. " - %s: %s", title, msg )
  77. end
  78. ns:tab("forward",
  79. translate("Forwarding"),
  80. translate("Configure here the routing of HTTP requests through a chain of multiple proxies. "
  81. .. "Note that parent proxies can severely decrease your privacy level. "
  82. .. "Also specified here are SOCKS proxies.") )
  83. ns:tab("misc",
  84. translate("Miscellaneous"),
  85. nil)
  86. local function err_tab_misc(self, msg)
  87. return string.format(translate("Miscellaneous") .. " - %s: %s", self.title_base, msg )
  88. end
  89. ns:tab("debug",
  90. translate("Logging"),
  91. nil )
  92. ns:tab("logview",
  93. translate("Log File Viewer"),
  94. nil )
  95. -- tab: local -- ###############################################################
  96. -- start/stop button -----------------------------------------------------------
  97. local btn = ns:taboption("sys", Button, "_startstop")
  98. btn.title = translate("Start / Stop")
  99. btn.description = translate("Start/Stop Privoxy WEB Proxy")
  100. btn.template = "privoxy/detail_startstop"
  101. function btn.cfgvalue(self, section)
  102. local pid = CTRL.get_pid(true)
  103. if pid > 0 then
  104. btn.inputtitle = "PID: " .. pid
  105. btn.inputstyle = "reset"
  106. btn.disabled = false
  107. else
  108. btn.inputtitle = translate("Start")
  109. btn.inputstyle = "apply"
  110. btn.disabled = false
  111. end
  112. return true
  113. end
  114. -- enabled ---------------------------------------------------------------------
  115. local ena = ns:taboption("sys", Flag, "_enabled")
  116. ena.title = translate("Enabled")
  117. ena.description = translate("Enable/Disable autostart of Privoxy on system startup and interface events")
  118. ena.orientation = "horizontal" -- put description under the checkbox
  119. ena.rmempty = false
  120. function ena.cfgvalue(self, section)
  121. return (SYS.init.enabled("privoxy")) and "1" or "0"
  122. end
  123. function ena.write(self, section, value)
  124. if value == "1" then
  125. return SYS.init.enable("privoxy")
  126. else
  127. return SYS.init.disable("privoxy")
  128. end
  129. end
  130. -- boot_delay ------------------------------------------------------------------
  131. local bd = ns:taboption("sys", Value, "boot_delay")
  132. bd.title = translate("Boot delay")
  133. bd.description = translate("Delay (in seconds) during system boot before Privoxy start")
  134. .. [[<br />]]
  135. .. translate("During delay ifup-events are not monitored !")
  136. bd.default = "10"
  137. bd.rmempty = false
  138. -- value is in a separate section so we need to do by hand
  139. function bd.cfgvalue(self, section)
  140. local value = tonumber(self.map:get("system", "boot_delay") )
  141. if not value then return nil end
  142. return tostring(value)
  143. end
  144. function bd.validate(self, value)
  145. local val = tonumber(value)
  146. if not val then
  147. return nil, err_tab_sys(self.title, translate("Value is not a number") )
  148. elseif val < 0 or val > 300 then
  149. return nil, err_tab_sys(self.title, translate("Value not between 0 and 300") )
  150. end
  151. return value
  152. end
  153. function bd.write(self, section, value)
  154. local fvalue = self:formvalue(section)
  155. local cvalue = self:cfgvalue(section)
  156. if (fvalue ~= cvalue) then
  157. self.map:set("system", "boot_delay", value)
  158. end
  159. end
  160. -- hostname --------------------------------------------------------------------
  161. local hn = ns:taboption("doc", Value, "hostname")
  162. hn.title = string.format(HELP, "HOSTNAME", "Hostname" )
  163. hn.description = translate("The hostname shown on the CGI pages.")
  164. hn.placeholder = SYS.hostname()
  165. hn.optional = true
  166. hn.rmempty = true
  167. function hn.parse(self, section, novld)
  168. CTRL.value_parse(self, section, novld)
  169. end
  170. -- user-manual -----------------------------------------------------------------
  171. local um = ns:taboption("doc", Value, "user_manual")
  172. um.title = string.format(HELP, "USER-MANUAL", "User Manual" )
  173. um.description = translate("Location of the Privoxy User Manual.")
  174. um.placeholder = "http://www.privoxy.org/user-manual/"
  175. um.optional = true
  176. um.rmempty = true
  177. function um.parse(self, section, novld)
  178. CTRL.value_parse(self, section, novld)
  179. end
  180. -- admin-address ---------------------------------------------------------------
  181. local aa = ns:taboption("doc", Value, "admin_address")
  182. aa.title_base = "Admin Email"
  183. aa.title = string.format(HELP, "ADMIN-ADDRESS", aa.title_base )
  184. aa.description = translate("An email address to reach the Privoxy administrator.")
  185. aa.placeholder = "privoxy.admin@example.com"
  186. aa.optional = true
  187. aa.rmempty = true
  188. function aa.validate(self, value)
  189. if not value or #value == 0 then
  190. return ""
  191. end
  192. if not (value:match("[A-Za-z0-9%.%%%+%-]+@[A-Za-z0-9%.%%%+%-]+%.%w%w%w?%w?")) then
  193. return nil, err_tab_doc(self.title_base, translate("Invalid email address") )
  194. end
  195. return value
  196. end
  197. function aa.parse(self, section, novld)
  198. CTRL.value_parse(self, section, novld)
  199. end
  200. -- proxy-info-url --------------------------------------------------------------
  201. local piu = ns:taboption("doc", Value, "proxy_info_url")
  202. piu.title = string.format(HELP, "PROXY-INFO-URL", "Proxy Info URL" )
  203. piu.description = translate("A URL to documentation about the local Privoxy setup, configuration or policies.")
  204. piu.optional = true
  205. piu.rmempty = true
  206. function piu.parse(self, section, novld)
  207. CTRL.value_parse(self, section, novld)
  208. end
  209. -- trust-info-url --------------------------------------------------------------
  210. local tiu = ns:taboption("doc", Value, "trust_info_url")
  211. tiu.title = string.format(HELP, "TRUST-INFO-URL", "Trust Info URLs" )
  212. tiu.description = translate("A URL to be displayed in the error page that users will see if access to an untrusted page is denied.")
  213. .. [[<br /><strong>]]
  214. .. translate("The value of this option only matters if the experimental trust mechanism has been activated.")
  215. .. [[</strong>]]
  216. tiu.optional = true
  217. tiu.rmepty = true
  218. function tiu.parse(self, section, novld)
  219. CTRL.value_parse(self, section, novld)
  220. end
  221. -- tab: filter -- ##############################################################
  222. -- logdir ----------------------------------------------------------------------
  223. local ld = ns:taboption("filter", Value, "logdir")
  224. ld.title_base = "Log Directory"
  225. ld.title = string.format(HELP, "LOGDIR", ld.title_base )
  226. ld.description = translate("The directory where all logging takes place (i.e. where the logfile is located).")
  227. .. [[<br />]]
  228. .. translate("No trailing '/', please.")
  229. ld.default = "/var/log"
  230. ld.rmempty = false
  231. function ld.validate(self, value)
  232. if not value or #value == 0 then
  233. return nil, err_tab_filter(self.title_base, translate("Mandatory Input: No Directory given!") )
  234. elseif not NXFS.access(value) then
  235. return nil, err_tab_filter(self.title_base, translate("Directory does not exist!") )
  236. else
  237. return value
  238. end
  239. end
  240. function ld.parse(self, section, novld)
  241. CTRL.value_parse(self, section, novld)
  242. end
  243. -- logfile ---------------------------------------------------------------------
  244. local lf = ns:taboption("filter", Value, "logfile")
  245. lf.title_base = "Log File"
  246. lf.title = string.format(HELP, "LOGFILE", lf.title_base )
  247. lf.description = translate("The log file to use. File name, relative to log directory.")
  248. lf.default = "privoxy.log"
  249. lf.rmempty = false
  250. function lf.validate(self, value)
  251. if not value or #value == 0 then
  252. return nil, err_tab_filter(self.title_base, translate("Mandatory Input: No File given!") )
  253. else
  254. return value
  255. end
  256. end
  257. -- confdir ---------------------------------------------------------------------
  258. local cd = ns:taboption("filter", Value, "confdir")
  259. cd.title_base = "Configuration Directory"
  260. cd.title = string.format(HELP, "CONFDIR", cd.title_base )
  261. cd.description = translate("The directory where the other configuration files are located.")
  262. .. [[<br />]]
  263. .. translate("No trailing '/', please.")
  264. cd.default = "/etc/privoxy"
  265. cd.rmempty = false
  266. function cd.validate(self, value)
  267. if not value or #value == 0 then
  268. return nil, err_tab_filter(self.title_base, translate("Mandatory Input: No Directory given!") )
  269. elseif not NXFS.access(value) then
  270. return nil, err_tab_filter(self.title_base, translate("Directory does not exist!") )
  271. else
  272. return value
  273. end
  274. end
  275. -- templdir --------------------------------------------------------------------
  276. local tld = ns:taboption("filter", Value, "templdir")
  277. tld.title_base = "Template Directory"
  278. tld.title = string.format(HELP, "TEMPLDIR", tld.title_base )
  279. tld.description = translate("An alternative directory where the templates are loaded from.")
  280. .. [[<br />]]
  281. .. translate("No trailing '/', please.")
  282. tld.placeholder = "/etc/privoxy/templates"
  283. tld.rmempty = true
  284. function tld.validate(self, value)
  285. if not NXFS.access(value) then
  286. return nil, err_tab_filter(self.title_base, translate("Directory does not exist!") )
  287. else
  288. return value
  289. end
  290. end
  291. -- temporary-directory ---------------------------------------------------------
  292. local td = ns:taboption("filter", Value, "temporary_directory")
  293. td.title_base = "Temporary Directory"
  294. td.title = string.format(HELP, "TEMPORARY-DIRECTORY", td.title_base )
  295. td.description = translate("A directory where Privoxy can create temporary files.")
  296. .. [[<br /><strong>]]
  297. .. translate("Only when using 'external filters', Privoxy has to create temporary files.")
  298. .. [[</strong>]]
  299. td.rmempty = true
  300. -- actionsfile -----------------------------------------------------------------
  301. local af = ns:taboption("filter", DynamicList, "actionsfile")
  302. af.title_base = "Action Files"
  303. af.title = string.format(HELP, "ACTIONSFILE", af.title_base)
  304. af.description = translate("The actions file(s) to use. Multiple actionsfile lines are permitted, and are in fact recommended!")
  305. .. [[<br /><strong>match-all.action := </strong>]]
  306. .. translate("Actions that are applied to all sites and maybe overruled later on.")
  307. .. [[<br /><strong>default.action := </strong>]]
  308. .. translate("Main actions file")
  309. .. [[<br /><strong>user.action := </strong>]]
  310. .. translate("User customizations")
  311. af.rmempty = false
  312. function af.validate(self, value)
  313. if not value or #value == 0 then
  314. return nil, err_tab_access(self.title_base, translate("Mandatory Input: No files given!") )
  315. end
  316. local confdir = cd:formvalue(ns.section)
  317. local err = false
  318. local file = ""
  319. if type(value) == "table" then
  320. local x
  321. for _, x in ipairs(value) do
  322. if x and #x > 0 then
  323. if not NXFS.access(confdir .."/".. x) then
  324. err = true
  325. file = x
  326. break -- break/leave for on error
  327. end
  328. end
  329. end
  330. else
  331. if not NXFS.access(confdir .."/".. value) then
  332. err = true
  333. file = value
  334. end
  335. end
  336. if err then
  337. return nil, string.format(err_tab_filter(self.title_base, translate("File '%s' not found inside Configuration Directory") ), file)
  338. end
  339. return value
  340. end
  341. -- filterfile ------------------------------------------------------------------
  342. local ff = ns:taboption("filter", DynamicList, "filterfile")
  343. ff.title_base = "Filter files"
  344. ff.title = string.format(HELP, "FILTERFILE", ff.title_base )
  345. ff.description = translate("The filter files contain content modification rules that use regular expressions.")
  346. ff.rmempty = false
  347. function ff.validate(self, value)
  348. if not value or #value == 0 then
  349. return nil, err_tab_access(self.title_base, translate("Mandatory Input: No files given!") )
  350. end
  351. local confdir = cd:formvalue(ns.section)
  352. local err = false
  353. local file = ""
  354. if type(value) == "table" then
  355. local x
  356. for _, x in ipairs(value) do
  357. if x and #x > 0 then
  358. if not NXFS.access(confdir .."/".. x) then
  359. err = true
  360. file = x
  361. break -- break/leave for on error
  362. end
  363. end
  364. end
  365. else
  366. if not NXFS.access(confdir .."/".. value) then
  367. err = true
  368. file = value
  369. end
  370. end
  371. if err then
  372. return nil, string.format(err_tab_filter(self.title_base, translate("File '%s' not found inside Configuration Directory") ), file )
  373. end
  374. return value
  375. end
  376. -- trustfile -------------------------------------------------------------------
  377. local tf = ns:taboption("filter", Value, "trustfile")
  378. tf.title_base = "Trust file"
  379. tf.title = string.format(HELP, "TRUSTFILE", tf.title_base )
  380. tf.description = translate("The trust mechanism is an experimental feature for building white-lists "
  381. .."and should be used with care.")
  382. .. [[<br /><strong>]]
  383. .. translate("It is NOT recommended for the casual user.")
  384. .. [[</strong>]]
  385. tf.placeholder = "user.trust"
  386. tf.rmempty = true
  387. function tf.validate(self, value)
  388. local confdir = cd:formvalue(ns.section)
  389. local err = false
  390. local file = ""
  391. if type(value) == "table" then
  392. local x
  393. for _, x in ipairs(value) do
  394. if x and #x > 0 then
  395. if not NCFS.access(confdir .."/".. x) then
  396. err = true
  397. file = x
  398. break -- break/leave for on error
  399. end
  400. end
  401. end
  402. else
  403. if not NXFS.access(confdir .."/".. value) then
  404. err = true
  405. file = value
  406. end
  407. end
  408. if err then
  409. return nil, string.format(err_tab_filter(self.title_base, translate("File '%s' not found inside Configuration Directory") ), file )
  410. end
  411. return value
  412. end
  413. -- tab: access -- ##############################################################
  414. -- listen-address --------------------------------------------------------------
  415. local la = ns:taboption("access", DynamicList, "listen_address")
  416. la.title_base = "Listen addresses"
  417. la.title = string.format(HELP, "LISTEN-ADDRESS", la.title_base )
  418. la.description = translate("The address and TCP port on which Privoxy will listen for client requests.")
  419. .. [[<br />]]
  420. .. translate("Syntax: ")
  421. .. "IPv4:Port / [IPv6]:Port / Host:Port"
  422. la.default = "127.0.0.1:8118"
  423. la.rmempty = false
  424. function la.validate(self, value)
  425. if not value or #value == 0 then
  426. return nil, err_tab_access(self.title_base, translate("Mandatory Input: No Data given!") )
  427. end
  428. local function check_value(v)
  429. local _ret = UTIL.split(v, "]:")
  430. local _ip
  431. if _ret[2] then -- ip6 with port
  432. _ip = string.gsub(_ret[1], "%[", "") -- remove "[" at beginning
  433. if not DTYP.ip6addr(_ip) then
  434. return translate("Mandatory Input: No valid IPv6 address given!")
  435. elseif not DTYP.port(_ret[2]) then
  436. return translate("Mandatory Input: No valid Port given!")
  437. else
  438. return nil
  439. end
  440. end
  441. _ret = UTIL.split(v, ":")
  442. if not _ret[2] then
  443. return translate("Mandatory Input: No Port given!")
  444. end
  445. if #_ret[1] > 0 and not DTYP.host(_ret[1]) then -- :8118 is valid address
  446. return translate("Mandatory Input: No valid IPv4 address or host given!")
  447. elseif not DTYP.port(_ret[2]) then
  448. return translate("Mandatory Input: No valid Port given!")
  449. else
  450. return nil
  451. end
  452. end
  453. local err = ""
  454. local entry = ""
  455. if type(value) == "table" then
  456. local x
  457. for _, x in ipairs(value) do
  458. if x and #x > 0 then
  459. err = check_value(x)
  460. if err then
  461. entry = x
  462. break
  463. end
  464. end
  465. end
  466. else
  467. err = check_value(value)
  468. entry = value
  469. end
  470. if err then
  471. return nil, string.format(err_tab_access(self.title_base, err .. " - %s"), entry )
  472. end
  473. return value
  474. end
  475. -- permit-access ---------------------------------------------------------------
  476. local pa = ns:taboption("access", DynamicList, "permit_access")
  477. pa.title = string.format(HELP, "ACLS", "Permit access" )
  478. pa.description = translate("Who can access what.")
  479. .. [[<br /><strong>]]
  480. .. translate("Please read Privoxy manual for details!")
  481. .. [[</strong>]]
  482. pa.rmempty = true
  483. -- deny-access -----------------------------------------------------------------
  484. local da = ns:taboption("access", DynamicList, "deny_access")
  485. da.title = string.format(HELP, "ACLS", "Deny Access" )
  486. da.description = translate("Who can access what.")
  487. .. [[<br /><strong>]]
  488. .. translate("Please read Privoxy manual for details!")
  489. .. [[</strong>]]
  490. da.rmempty = true
  491. -- buffer-limit ----------------------------------------------------------------
  492. local bl = ns:taboption("access", Value, "buffer_limit")
  493. bl.title_base = "Buffer Limit"
  494. bl.title = string.format(HELP, "BUFFER-LIMIT", bl.title_base )
  495. bl.description = translate("Maximum size (in KB) of the buffer for content filtering.")
  496. .. [[<br />]]
  497. .. translate("Value range 1 to 4096, no entry defaults to 4096")
  498. bl.default = 4096
  499. bl.rmempty = true
  500. function bl.validate(self, value)
  501. local v = tonumber(value)
  502. if not v then
  503. return nil, err_tab_access(self.title_base, translate("Value is not a number") )
  504. elseif v < 1 or v > 4096 then
  505. return nil, err_tab_access(self.title_base, translate("Value not between 1 and 4096") )
  506. elseif v == self.default then
  507. return "" -- don't need to save default
  508. end
  509. return value
  510. end
  511. -- toggle ----------------------------------------------------------------------
  512. local tgl = ns:taboption("access", Flag, "toggle")
  513. tgl.title = string.format(HELP, "TOGGLE", "Toggle Status" )
  514. tgl.description = translate("Enable/Disable filtering when Privoxy starts.")
  515. .. [[<br />]]
  516. .. translate("Disabled == Transparent Proxy Mode")
  517. tgl.orientation = "horizontal"
  518. tgl.default = "1"
  519. tgl.rmempty = false
  520. -- enable-remote-toggle --------------------------------------------------------
  521. local ert = ns:taboption("access", Flag, "enable_remote_toggle")
  522. ert.title = string.format(HELP, "ENABLE-REMOTE-TOGGLE", "Enable remote toggle" )
  523. ert.description = translate("Whether or not the web-based toggle feature may be used.")
  524. ert.orientation = "horizontal"
  525. ert.rmempty = true
  526. -- enable-remote-http-toggle ---------------------------------------------------
  527. local eht = ns:taboption("access", Flag, "enable_remote_http_toggle")
  528. eht.title = string.format(HELP, "ENABLE-REMOTE-HTTP-TOGGLE", "Enable remote toggle via HTTP" )
  529. eht.description = translate("Whether or not Privoxy recognizes special HTTP headers to change toggle state.")
  530. .. [[<br /><strong>]]
  531. .. translate("This option will be removed in future releases as it has been obsoleted by the more general header taggers.")
  532. .. [[</strong>]]
  533. eht.orientation = "horizontal"
  534. eht.rmempty = true
  535. -- enable-edit-actions ---------------------------------------------------------
  536. local eea = ns:taboption("access", Flag, "enable_edit_actions")
  537. eea.title = string.format(HELP, "ENABLE-EDIT-ACTIONS", "Enable action file editor" )
  538. eea.description = translate("Whether or not the web-based actions file editor may be used.")
  539. eea.orientation = "horizontal"
  540. eea.rmempty = true
  541. -- enforce-blocks --------------------------------------------------------------
  542. local eb = ns:taboption("access", Flag, "enforce_blocks")
  543. eb.title = string.format(HELP, "ENFORCE-BLOCKS", "Enforce page blocking" )
  544. eb.description = translate("If enabled, Privoxy hides the 'go there anyway' link. "
  545. .. "The user obviously should not be able to bypass any blocks.")
  546. eb.orientation = "horizontal"
  547. eb.rmempty = true
  548. -- tab: forward -- #############################################################
  549. -- enable-proxy-authentication-forwarding --------------------------------------
  550. local paf = ns:taboption("forward", Flag, "enable_proxy_authentication_forwarding")
  551. paf.title = string.format(HELP, "ENABLE-PROXY-AUTHENTICATION-FORWARDING",
  552. translate("Enable proxy authentication forwarding") )
  553. paf.description = translate("Whether or not proxy authentication through Privoxy should work.")
  554. .. [[<br /><strong>]]
  555. .. translate("Enabling this option is NOT recommended if there is no parent proxy that requires authentication!")
  556. .. [[</strong>]]
  557. --paf.orientation = "horizontal"
  558. paf.rmempty = true
  559. -- forward ---------------------------------------------------------------------
  560. local fwd = ns:taboption("forward", DynamicList, "forward")
  561. fwd.title = string.format(HELP, "FORWARD", "Forward HTTP" )
  562. fwd.description = translate("To which parent HTTP proxy specific requests should be routed.")
  563. .. [[<br />]]
  564. .. translate("Syntax: target_pattern http_parent[:port]")
  565. fwd.rmempty = true
  566. -- forward-socks4 --------------------------------------------------------------
  567. local fs4 = ns:taboption("forward", DynamicList, "forward_socks4")
  568. fs4.title = string.format(HELP, "SOCKS", "Forward SOCKS 4" )
  569. fs4.description = translate("Through which SOCKS proxy (and optionally to which parent HTTP proxy) specific requests should be routed.")
  570. .. [[<br />]]
  571. .. translate("Syntax:")
  572. .. " target_pattern socks_proxy[:port] http_parent[:port]"
  573. fs4.rmempty = true
  574. -- forward-socks4a -------------------------------------------------------------
  575. local f4a = ns:taboption("forward", DynamicList, "forward_socks4a")
  576. f4a.title = string.format(HELP, "SOCKS", "Forward SOCKS 4A" )
  577. f4a.description = fs4.description
  578. f4a.rmempty = true
  579. -- forward-socks5 --------------------------------------------------------------
  580. local fs5 = ns:taboption("forward", DynamicList, "forward_socks5")
  581. fs5.title = string.format(HELP, "SOCKS", "Forward SOCKS 5" )
  582. fs5.description = translate("Through which SOCKS proxy (and optionally to which parent HTTP proxy) specific requests should be routed.")
  583. .. [[<br />]]
  584. .. translate("Syntax:")
  585. .. " target_pattern [user:pass@]socks_proxy[:port] http_parent[:port]"
  586. fs5.rmempty = true
  587. -- forward-socks5t -------------------------------------------------------------
  588. local f5t = ns:taboption("forward", DynamicList, "forward_socks5t")
  589. f5t.title = string.format(HELP, "SOCKS", "Forward SOCKS 5t" )
  590. f5t.description = fs5.description
  591. f5t.rmempty = true
  592. -- tab: misc -- ################################################################
  593. -- accept-intercepted-requests -------------------------------------------------
  594. local air = ns:taboption("misc", Flag, "accept_intercepted_requests")
  595. air.title = string.format(HELP, "ACCEPT-INTERCEPTED-REQUESTS", "Accept intercepted requests" )
  596. air.description = translate("Whether intercepted requests should be treated as valid.")
  597. air.orientation = "horizontal"
  598. air.rmempty = true
  599. -- allow-cgi-request-crunching -------------------------------------------------
  600. local crc = ns:taboption("misc", Flag, "allow_cgi_request_crunching")
  601. crc.title = string.format(HELP, "ALLOW-CGI-REQUEST-CRUNCHING", "Allow CGI request crunching" )
  602. crc.description = translate("Whether requests to Privoxy's CGI pages can be blocked or redirected.")
  603. crc.orientation = "horizontal"
  604. crc.rmempty = true
  605. -- split-large-forms -----------------------------------------------------------
  606. local slf = ns:taboption("misc", Flag, "split_large_forms")
  607. slf.title = string.format(HELP, "SPLIT-LARGE-FORMS", "Split large forms" )
  608. slf.description = translate("Whether the CGI interface should stay compatible with broken HTTP clients.")
  609. slf.orientation = "horizontal"
  610. slf.rmempty = true
  611. -- keep-alive-timeout ----------------------------------------------------------
  612. local kat = ns:taboption("misc", Value, "keep_alive_timeout")
  613. kat.title_base = "Keep-alive timeout"
  614. kat.title = string.format(HELP, "KEEP-ALIVE-TIMEOUT", kat.title_base)
  615. kat.description = translate("Number of seconds after which an open connection will no longer be reused.")
  616. kat.rmempty = true
  617. function kat.validate(self, value)
  618. local v = tonumber(value)
  619. if not v then
  620. return nil, err_tab_misc(self.title_base, translate("Value is not a number") )
  621. elseif v < 1 then
  622. return nil, err_tab_misc(self.title_base, translate("Value not greater 0 or empty") )
  623. end
  624. return value
  625. end
  626. -- tolerate-pipelining ---------------------------------------------------------
  627. local tp = ns:taboption("misc", Flag, "tolerate_pipelining")
  628. tp.title = string.format(HELP, "TOLERATE-PIPELINING", "Tolerate pipelining" )
  629. tp.description = translate("Whether or not pipelined requests should be served.")
  630. tp.orientation = "horizontal"
  631. tp.rmempty = true
  632. -- default-server-timeout ------------------------------------------------------
  633. local dst = ns:taboption("misc", Value, "default_server_timeout")
  634. dst.title_base = "Default server timeout"
  635. dst.title = string.format(HELP, "DEFAULT-SERVER-TIMEOUT", dst.title_base)
  636. dst.description = translate("Assumed server-side keep-alive timeout (in seconds) if not specified by the server.")
  637. dst.rmempty = true
  638. function dst.validate(self, value)
  639. local v = tonumber(value)
  640. if not v then
  641. return nil, err_tab_misc(self.title_base, translate("Value is not a number") )
  642. elseif v < 1 then
  643. return nil, err_tab_misc(self.title_base, translate("Value not greater 0 or empty") )
  644. end
  645. return value
  646. end
  647. -- connection-sharing ----------------------------------------------------------
  648. local cs = ns:taboption("misc", Flag, "connection_sharing")
  649. cs.title = string.format(HELP, "CONNECTION-SHARING", "Connection sharing" )
  650. cs.description = translate("Whether or not outgoing connections that have been kept alive should be shared between different incoming connections.")
  651. cs.orientation = "horizontal"
  652. cs.rmempty = true
  653. -- socket-timeout --------------------------------------------------------------
  654. local st = ns:taboption("misc", Value, "socket_timeout")
  655. st.title_base = "Socket timeout"
  656. st.title = string.format(HELP, "SOCKET-TIMEOUT", st.title_base )
  657. st.description = translate("Number of seconds after which a socket times out if no data is received.")
  658. st.default = 300
  659. st.rmempty = true
  660. function st.validate(self, value)
  661. local v = tonumber(value)
  662. if not v then
  663. return nil, err_tab_misc(self.title_base, translate("Value is not a number") )
  664. elseif v < 1 then
  665. return nil, err_tab_misc(self.title_base, translate("Value not greater 0 or empty") )
  666. elseif v == self.default then
  667. return "" -- don't need to save default
  668. end
  669. return value
  670. end
  671. -- max-client-connections ------------------------------------------------------
  672. local mcc = ns:taboption("misc", Value, "max_client_connections")
  673. mcc.title_base = "Max. client connections"
  674. mcc.title = string.format(HELP, "MAX-CLIENT-CONNECTIONS", mcc.title_base )
  675. mcc.description = translate("Maximum number of client connections that will be served.")
  676. mcc.default = 128
  677. mcc.rmempty = true
  678. function mcc.validate(self, value)
  679. local v = tonumber(value)
  680. if not v then
  681. return nil, err_tab_misc(self.title_base, translate("Value is not a number") )
  682. elseif v < 1 then
  683. return nil, err_tab_misc(self.title_base, translate("Value not greater 0 or empty") )
  684. elseif v == self.default then
  685. return "" -- don't need to save default
  686. end
  687. return value
  688. end
  689. -- handle-as-empty-doc-returns-ok ----------------------------------------------
  690. local her = ns:taboption("misc", Flag, "handle_as_empty_doc_returns_ok")
  691. her.title = string.format(HELP, "HANDLE-AS-EMPTY-DOC-RETURNS-OK", "Handle as empty doc returns ok" )
  692. her.description = translate("The status code Privoxy returns for pages blocked with +handle-as-empty-document.")
  693. her.orientation = "horizontal"
  694. her.rmempty = true
  695. -- enable-compression ----------------------------------------------------------
  696. local ec = ns:taboption("misc", Flag, "enable_compression")
  697. ec.title = string.format(HELP, "ENABLE-COMPRESSION", "Enable compression" )
  698. ec.description = translate("Whether or not buffered content is compressed before delivery.")
  699. ec.orientation = "horizontal"
  700. ec.rmempty = true
  701. -- compression-level -----------------------------------------------------------
  702. local cl = ns:taboption("misc", Value, "compression_level")
  703. cl.title_base = "Compression level"
  704. cl.title = string.format(HELP, "COMPRESSION-LEVEL", cl.title_base )
  705. cl.description = translate("The compression level that is passed to the zlib library when compressing buffered content.")
  706. cl.default = 1
  707. cl.rmempty = true
  708. function cl.validate(self, value)
  709. local v = tonumber(value)
  710. if not v then
  711. return nil, err_tab_misc(self.title_base, translate("Value is not a number") )
  712. elseif v < 0 or v > 9 then
  713. return nil, err_tab_misc(self.title_base, translate("Value not between 0 and 9") )
  714. elseif v == self.default then
  715. return "" -- don't need to save default
  716. end
  717. return value
  718. end
  719. -- client-header-order ---------------------------------------------------------
  720. local cho = ns:taboption("misc", Value, "client_header_order")
  721. cho.title = string.format(HELP, "CLIENT-HEADER-ORDER", "Client header order" )
  722. cho.description = translate("The order in which client headers are sorted before forwarding them.")
  723. .. [[<br />]]
  724. .. translate("Syntax: Client header names delimited by spaces.")
  725. cho.rmempty = true
  726. -- "debug"-tab definition -- ###################################################
  727. -- single-threaded -------------------------------------------------------------
  728. local st = ns:taboption("debug", Flag, "single_threaded")
  729. st.title = string.format(HELP, "SINGLE-THREADED", "Single Threaded" )
  730. st.description = translate("Whether to run only one server thread.")
  731. .. [[<br /><strong>]]
  732. .. translate("This option is only there for debugging purposes. It will drastically reduce performance.")
  733. .. [[</strong>]]
  734. st.rmempty = true
  735. -- debug 1 ---------------------------------------------------------------------
  736. local d0 = ns:taboption("debug", Flag, "debug_1")
  737. d0.title = string.format(HELP, "DEBUG", "Debug 1" )
  738. d0.description = translate("Log the destination for each request Privoxy let through. See also 'Debug 1024'.")
  739. d0.rmempty = true
  740. -- debug 2 ---------------------------------------------------------------------
  741. local d1 = ns:taboption("debug", Flag, "debug_2")
  742. d1.title = string.format(HELP, "DEBUG", "Debug 2" )
  743. d1.description = translate("Show each connection status")
  744. d1.rmempty = true
  745. -- debug 4 ---------------------------------------------------------------------
  746. local d2 = ns:taboption("debug", Flag, "debug_4")
  747. d2.title = string.format(HELP, "DEBUG", "Debug 4" )
  748. d2.description = translate("Show I/O status")
  749. d2.rmempty = true
  750. -- debug 8 ---------------------------------------------------------------------
  751. local d3 = ns:taboption("debug", Flag, "debug_8")
  752. d3.title = string.format(HELP, "DEBUG", "Debug 8" )
  753. d3.description = translate("Show header parsing")
  754. d3.rmempty = true
  755. -- debug 16 --------------------------------------------------------------------
  756. local d4 = ns:taboption("debug", Flag, "debug_16")
  757. d4.title = string.format(HELP, "DEBUG", "Debug 16" )
  758. d4.description = translate("Log all data written to the network")
  759. d4.rmempty = true
  760. -- debug 32 --------------------------------------------------------------------
  761. local d5 = ns:taboption("debug", Flag, "debug_32")
  762. d5.title = string.format(HELP, "DEBUG", "Debug 32" )
  763. d5.description = translate("Debug force feature")
  764. d5.rmempty = true
  765. -- debug 64 --------------------------------------------------------------------
  766. local d6 = ns:taboption("debug", Flag, "debug_64")
  767. d6.title = string.format(HELP, "DEBUG", "Debug 64" )
  768. d6.description = translate("Debug regular expression filters")
  769. d6.rmempty = true
  770. -- debug 128 -------------------------------------------------------------------
  771. local d7 = ns:taboption("debug", Flag, "debug_128")
  772. d7.title = string.format(HELP, "DEBUG", "Debug 128" )
  773. d7.description = translate("Debug redirects")
  774. d7.rmempty = true
  775. -- debug 256 -------------------------------------------------------------------
  776. local d8 = ns:taboption("debug", Flag, "debug_256")
  777. d8.title = string.format(HELP, "DEBUG", "Debug 256" )
  778. d8.description = translate("Debug GIF de-animation")
  779. d8.rmempty = true
  780. -- debug 512 -------------------------------------------------------------------
  781. local d9 = ns:taboption("debug", Flag, "debug_512")
  782. d9.title = string.format(HELP, "DEBUG", "Debug 512" )
  783. d9.description = translate("Common Log Format")
  784. d9.rmempty = true
  785. -- debug 1024 ------------------------------------------------------------------
  786. local d10 = ns:taboption("debug", Flag, "debug_1024")
  787. d10.title = string.format(HELP, "DEBUG", "Debug 1024" )
  788. d10.description = translate("Log the destination for requests Privoxy didn't let through, and the reason why.")
  789. d10.rmempty = true
  790. -- debug 2048 ------------------------------------------------------------------
  791. local d11 = ns:taboption("debug", Flag, "debug_2048")
  792. d11.title = string.format(HELP, "DEBUG", "Debug 2048" )
  793. d11.description = translate("CGI user interface")
  794. d11.rmempty = true
  795. -- debug 4096 ------------------------------------------------------------------
  796. local d12 = ns:taboption("debug", Flag, "debug_4096")
  797. d12.title = string.format(HELP, "DEBUG", "Debug 4096" )
  798. d12.description = translate("Startup banner and warnings.")
  799. d12.rmempty = true
  800. -- debug 8192 ------------------------------------------------------------------
  801. local d13 = ns:taboption("debug", Flag, "debug_8192")
  802. d13.title = string.format(HELP, "DEBUG", "Debug 8192" )
  803. d13.description = translate("Non-fatal errors - *we highly recommended enabling this*")
  804. d13.rmempty = true
  805. -- debug 16384 -----------------------------------------------------------------
  806. --[[ TODO ???
  807. local d14 = ns:taboption("debug", Flag, "debug_16384")
  808. d14.title = string.format(HELP, "DEBUG", "Debug 16384" )
  809. d14.description = translate("")
  810. d14.rmempty = true
  811. ]]--
  812. -- debug 32768 -----------------------------------------------------------------
  813. local d15 = ns:taboption("debug", Flag, "debug_32768")
  814. d15.title = string.format(HELP, "DEBUG", "Debug 32768" )
  815. d15.description = translate("Log all data read from the network")
  816. d15.rmempty = true
  817. -- debug 65536 -----------------------------------------------------------------
  818. local d16 = ns:taboption("debug", Flag, "debug_65536")
  819. d16.title = string.format(HELP, "DEBUG", "Debug 65536" )
  820. d16.description = translate("Log the applying actions")
  821. d16.rmempty = true
  822. -- tab: logview -- #############################################################
  823. local lv = ns:taboption("logview", DummyValue, "_logview")
  824. lv.template = "privoxy/detail_logview"
  825. lv.inputtitle = translate("Read / Reread log file")
  826. lv.rows = 50
  827. function lv.cfgvalue(self, section)
  828. local lfile=self.map:get(ns.section, "logdir") .. "/" .. self.map:get(ns.section, "logfile")
  829. if NXFS.access(lfile) then
  830. return lfile .. "\n" .. translate("Please press [Read] button")
  831. end
  832. return lfile .. "\n" .. translate("File not found or empty")
  833. end
  834. return m