'use strict';
'require uci';
'require form';
'require rpc';
'require tools.widgets as widgets';
'require fs';
'require view';
const callRcInit = rpc.declare({
object: 'rc',
method: 'init',
params: [ 'name', 'action' ],
expect: { result: false }
});
return view.extend({
handleSaveApply: function(ev, mode) {
var Fn = L.bind(function() {
callRcInit('privoxy', 'reload');
document.removeEventListener('uci-applied', Fn);
});
document.addEventListener('uci-applied', Fn);
this.super('handleSaveApply', [ev, mode]);
},
render: function(data) {
const m = new form.Map('privoxy', _('Privoxy'),
_('Configure the Privoxy proxy daemon settings.'));
const s = m.section(form.NamedSection, 'privoxy', 'privoxy', _('Privoxy Settings'));
// Tab: System
s.tab('sys', _('System'));
s.taboption('sys', form.Flag, '_enabled', _('Enabled'), _('Enable/Disable autostart of Privoxy'))
let bootDelay = s.taboption('sys', form.Value, 'boot_delay', _('Boot delay'),
_('Delay (in seconds) during system boot before Privoxy starts.'));
bootDelay.datatype = 'uinteger';
bootDelay.placeholder = '10';
bootDelay.default = '10';
// Tab: Documentation
s.tab('doc', _('Documentation'), _("If you intend to operate Privoxy for more users than just yourself, "
+ "it might be a good idea to let them know how to reach you, what you block "
+ "and why you do that, your policies, etc."));
s.taboption('doc', form.Value, 'hostname', _('Hostname'),
_('The hostname shown on the CGI pages.'))
//.placeholder = sys.hostname();
s.taboption('doc', form.Value, 'user_manual', _('User Manual'),
_('Location of the Privoxy User Manual.')).placeholder = 'http://www.privoxy.org/user-manual/';
let adminEmail = s.taboption('doc', form.Value, 'admin_address', _('Admin Email'),
_('Email address for the Privoxy administrator.'));
adminEmail.datatype = 'email';
adminEmail.placeholder = 'privoxy.admin@example.com';
s.taboption('doc', form.Value, 'proxy_info_url', _('Proxy Info URL'),
_('URL to documentation about the local Privoxy setup.'));
s.taboption('doc', form.Value, 'trust_info_url', _('Trust Info URL'),
_('URL shown if access to an untrusted page is denied. Only applies if trust mechanism is enabled.'));
// Tab: Filter
s.tab('filtering', _('Files and Directories'), _("Privoxy can (and normally does) use a number of other files "
+ "for additional configuration, help and logging. This section of "
+ "the configuration file tells Privoxy where to find those other files."));
// LOGDIR
let logdir = s.taboption('filtering', form.Value, 'logdir', _('Log Directory'),
_('The directory where all logging takes place (i.e. where the logfile is located).
No trailing "/", please.'));
logdir.default = '/var/log';
logdir.rmempty = false;
// LOGFILE
let logfile = s.taboption('filtering', form.Value, 'logfile', _('Log File'),
_('The log file to use. File name, relative to log directory.'));
logfile.default = 'privoxy.log';
logfile.rmempty = false;
logfile.validate = function(section_id, value) {
if (!value || value.trim() === '')
return _('Mandatory Input: No File given!');
return true;
};
// CONFDIR
let confdir = s.taboption('filtering', form.Value, 'confdir', _('Configuration Directory'),
_('The directory where the other configuration files are located.'));
confdir.default = '/etc/privoxy';
confdir.rmempty = false;
// TEMPLDIR
let templdir = s.taboption('filtering', form.Value, 'templdir', _('Template Directory'),
_('An alternative directory where the templates are loaded from.
No trailing "/", please.'));
templdir.placeholder = '/etc/privoxy/templates';
templdir.rmempty = true;
// TEMPORARY DIRECTORY
let tmpdir = s.taboption('filtering', form.Value, 'temporary_directory', _('Temporary Directory'),
_("A directory where Privoxy can create temporary files.
Only when using 'external filters', Privoxy has to create temporary files."));
tmpdir.rmempty = true;
tmpdir.placeholder = '/tmp';
tmpdir.default = '/tmp';
// ACTIONSFILE
let actionsfile = s.taboption('filtering', form.DynamicList, 'actionsfile', _('Action Files'),
_('The actions file(s) to use. Multiple actionsfile lines are permitted, and are in fact recommended!') +
'
match-all.action := ' + _('Actions that are applied to all sites and maybe overruled later on.') +
'
default.action := ' + _('Main actions file') +
'
user.action := ' + _('User customizations'));
actionsfile.rmempty = true;
// FILTERFILE
let filterfile = s.taboption('filtering', form.DynamicList, 'filterfile', _('Filter files'),
_('The filter files contain content modification rules that use regular expressions.'));
filterfile.rmempty = true;
// TRUSTFILE
let trustfile = s.taboption('filtering', form.Value, 'trustfile', _('Trust file'),
_('The trust mechanism is an experimental feature for building white-lists and should be used with care.') +
'
' + _('It is NOT recommended for the casual user.') + '');
trustfile.placeholder = 'user.trust';
trustfile.rmempty = true;
// Tab: Access
s.tab('access', _('Access Control'), _("This tab controls the security-relevant aspects of Privoxy's configuration."));
// LISTEN ADDRESS
let listen = s.taboption('access', form.DynamicList, 'listen_address', _('Listen addresses'),
_('The address and TCP port on which Privoxy will listen for client requests.') + '
' +
_('Syntax: ') + 'IPv4:Port / [IPv6]:Port / Host:Port');
listen.default = '127.0.0.1:8118';
listen.rmempty = false;
listen.datatype = 'or(hostport,ipaddrport(1))';
// PERMIT ACCESS
let permit = s.taboption('access', form.DynamicList, 'permit_access', _('Permit access'),
_('Who can access what.') + '
' + _('Please read Privoxy manual for details!') + '');
permit.rmempty = true;
permit.datatype = 'ipmask';
// DENY ACCESS
let deny = s.taboption('access', form.DynamicList, 'deny_access', _('Deny access'),
_('Who can access what.') + '
' + _('Please read Privoxy manual for details!') + '');
deny.rmempty = true;
deny.datatype = 'ipmask';
// BUFFER LIMIT
let buffer = s.taboption('access', form.Value, 'buffer_limit', _('Buffer Limit'),
_('Maximum size (in KB) of the buffer for content filtering.') + '
' +
_('Value range 1 to 4096, no entry defaults to 4096'));
buffer.default = 4096;
buffer.rmempty = true;
buffer.datatype = 'and(uinteger,min(1),max(4096))';
// TOGGLE
let toggle = s.taboption('access', form.Flag, 'toggle', _('Toggle Status'),
_('Enable/Disable filtering when Privoxy starts.') + '
' +
_('Disabled == Transparent Proxy Mode'));
toggle.default = '1';
toggle.rmempty = false;
// ENABLE REMOTE TOGGLE
let remoteToggle = s.taboption('access', form.Flag, 'enable_remote_toggle', _('Enable remote toggle'),
_('Whether or not the web-based toggle feature may be used.'));
remoteToggle.rmempty = true;
// ENABLE REMOTE HTTP TOGGLE
let httpToggle = s.taboption('access', form.Flag, 'enable_remote_http_toggle', _('Enable remote toggle via HTTP'),
_('Whether or not Privoxy recognizes special HTTP headers to change toggle state.') + '
' +
_('This option will be removed in future releases as it has been obsoleted by the more general header taggers.') + '');
httpToggle.rmempty = true;
// ENABLE EDIT ACTIONS
let editActions = s.taboption('access', form.Flag, 'enable_edit_actions', _('Enable action file editor'),
_('Whether or not the web-based actions file editor may be used.'));
editActions.rmempty = true;
// ENFORCE BLOCKS
let enforce = s.taboption('access', form.Flag, 'enforce_blocks', _('Enforce page blocking'),
_('If enabled, Privoxy hides the "go there anyway" link. The user obviously should not be able to bypass any blocks.'));
enforce.rmempty = true;
// Tab: Forward
s.tab('forward', _('Forwarding'), ("Configure here the routing of HTTP requests through a chain of multiple proxies. "
+ "Note that parent proxies can severely decrease your privacy level. "
+ "Also specified here are SOCKS proxies."));
let o = s.taboption("forward", form.Flag, "enable_proxy_authentication_forwarding", _("Enable proxy authentication forwarding"));
o.description = _("Whether or not proxy authentication through Privoxy should work.") +
"
" + _("Enabling this option is NOT recommended if there is no parent proxy that requires authentication!") + "";
o = s.taboption("forward", form.DynamicList, "forward", _("Forward HTTP"));
o.description = _("To which parent HTTP proxy specific requests should be routed.") +
"
" + _("Syntax: target_pattern http_parent[:port]");
o = s.taboption("forward", form.DynamicList, "forward_socks4", _("Forward SOCKS 4"));
o.description = _("Through which SOCKS proxy (and optionally to which parent HTTP proxy) specific requests should be routed.") +
"
" + _("Syntax: target_pattern socks_proxy[:port] http_parent[:port]");
o = s.taboption("forward", form.DynamicList, "forward_socks4a", _("Forward SOCKS 4A"));
o.description = _("Through which SOCKS proxy (and optionally to which parent HTTP proxy) specific requests should be routed.") +
"
" + _("Syntax: target_pattern socks_proxy[:port] http_parent[:port]");
o = s.taboption("forward", form.DynamicList, "forward_socks5", _("Forward SOCKS 5"));
o.description = _("Through which SOCKS proxy (and optionally to which parent HTTP proxy) specific requests should be routed.") +
"
" + _("Syntax: target_pattern [user:pass@]socks_proxy[:port] http_parent[:port]");
o = s.taboption("forward", form.DynamicList, "forward_socks5t", _("Forward SOCKS 5t"));
o.description = _("Through which SOCKS proxy (and optionally to which parent HTTP proxy) specific requests should be routed.") +
"
" + _("Syntax: target_pattern [user:pass@]socks_proxy[:port] http_parent[:port]");
// Tab: HTTPS Inspection (Section 7.7)
s.tab('https', _('HTTPS Inspection'), _("Privoxy can intercept HTTPS connections and generate on-the-fly SSL certificates. "
+ "This allows inspection and filtering of HTTPS traffic. A CA certificate must be installed on clients to trust."));
o = s.taboption("https", form.Flag, "enable_ssl_bumping", _("Enable HTTPS Inspection"),
_("Enable on-the-fly certificate generation for HTTPS connections.") +
"
" + _("Warning: ") + "" + _("Clients must trust the Privoxy CA certificate to avoid SSL errors."));
o.orientation = "horizontal";
let certdir = s.taboption("https", form.Value, "certdir", _("Certificate Directory"),
_("Directory for the CA certificate and generated certificates.") +
"
" + _("Required for HTTPS inspection to work.") + "");
certdir.default = '/etc/privoxy/ssl';
certdir.rmempty = false;
let caName = s.taboption("https", form.Value, "ca_common_name", _("CA Common Name"),
_("Common name (CN) for the Privoxy Certificate Authority.") +
"
" + _("This name will appear in the certificate details presented to clients."));
caName.default = 'Privoxy CA';
let caDays = s.taboption("https", form.Value, "ca_validity_days", _("CA Certificate Validity (days)"),
_("Validity period in days for the Certificate Authority certificate.") +
"
" + _("A longer validity period reduces the frequency of CA certificate regeneration."));
caDays.default = '3650';
caDays.datatype = 'and(uinteger,min(1),max(8250))';
let certDays = s.taboption("https", form.Value, "cert_validity_days", _("Certificate Validity (days)"),
_("Default validity period in days for generated server certificates."));
certDays.default = '365';
certDays.datatype = 'and(uinteger,min(1),max(8250))';
let certKeySize = s.taboption("https", form.Value, "cert_key_size", _("Certificate Key Size (bits)"),
_("RSA key size in bits 1024/2048/4096") +
"
" + _("Larger keys provide more security but take longer to generate."));
certKeySize.default = '2048';
certKeySize.datatype = 'uinteger';
// CA Certificate status display
let caCertPath = s.taboption("https", form.DummyValue, '_ca_cert_path', _('CA Certificate Path'),
_('Path to the CA certificate file. Install this in your browser/trusted CA store on each client.'));
caCertPath.rawhtml = true;
caCertPath.cfgvalue = function(section_id) {
var dir = uci.get(this.map.config, section_id, 'certdir') || '/etc/privoxy/ssl';
return dir + '/ca-cert.pem';
};
// Download button
let downloadBtn = s.taboption("https", form.Button, '_download_ca_cert', _('Download CA Certificate'),
_('Click to download the Privoxy CA certificate for installation on clients.'));
downloadBtn.inputstyle = 'primary';
downloadBtn.inputtitle = _('Download CA Certificate');
downloadBtn.onclick = L.bind(function() {
var dir = certdir.formvalue('privoxy') || '/etc/privoxy/ssl';
var certPath = dir + '/ca-cert.pem';
fs.read_direct(certPath, 'blob').then(function(blob) {
if (!(blob instanceof Blob)) {
throw new Error(_('Response is not a Blob'));
}
var url = URL.createObjectURL(blob);
var a = document.createElement('a');
a.href = url;
a.download = 'ca-cert.pem';
document.body.appendChild(a);
a.click();
a.remove();
URL.revokeObjectURL(url);
}).catch(function(err) {
L.ui.addNotification(null, E('p', {}, _('Failed to read certificate file: ') + err.message), 'error');
});
}, this);
// Regenerate button
let regenBtn = s.taboption("https", form.Button, '_regenerate_ca', _('Regenerate CA Certificate'),
_('Click to delete and regenerate the CA certificate (will cause SSL warnings on clients until new cert is installed).'));
regenBtn.inputstyle = 'negative';
regenBtn.inputtitle = _('Regenerate CA Certificate');
regenBtn.onclick = L.bind(function() {
if (confirm(_('Are you sure you want to regenerate the CA certificate? This will cause SSL warnings on all clients until the new certificate is installed.'))) {
// Create marker file to trigger certificate regeneration
return fs.write('/etc/privoxy/regenerate_ca', '1').then(function() {
return callRcInit('privoxy', 'reload');
}).then(function() {
L.ui.addNotification(null, E('p', {}, _('CA certificate has been regenerated.')), 'info');
}).catch(function(err) {
L.ui.addNotification(null, E('p', {}, _('Failed to regenerate CA certificate: ') + err.message), 'error');
});
}
}, this);
// Instructions section
let instructions = s.taboption("https", form.DummyValue, '_https_instructions', _('Installation Instructions'));
instructions.rawhtml = true;
instructions.default = '
' + _('1. Enable HTTPS Inspection above') + '
' + '2. ' + _('Configure the certificate directory and CA settings') + '
' + '3. ' + _('Save & Apply to generate the CA certificate') + '
' + '4. ' + _('Download the CA certificate using the button above') + '
' + '5. ' + _('Install the CA certificate in your browser/trusted store on each client device') + '
' + '6. ' + _('Configure clients to use this Privoxy proxy for HTTPS traffic') + '
' + '