mirror of
https://github.com/netbirdio/plugins.git
synced 2026-05-22 18:44:07 -07:00
www/nginx: Custom error pages (#2149)
* [www/nginx] Improvement of default error pages * Added custom error page for 403 error * Configured WAF Denied error page for 405 * Make default error pages mobile friendly * [www/nginx] Add ability to configure error pages via GUI * Custom error pages for 4xx and 5xx HTTP status codes can be configured via GUI. * Correct indenting * Push version * [www/nginx] Improved customized error pages * Form displays meaning of HTTP status code * Allow status code rewriting * [www/nginx] Incorporated code review findings * [www/nginx] Add HTML content of custom error page to config Added HTML content of custom error pages to model * [www/nginx] Added ability to redirect error pages to URL * Add option to redirect to new page instead of displaying a custom error page. * Incorporated code review findinds. * Fixed error_page syntax for status code change * [www/nginx] Added error page configuration to locations Custom error pages can be overwritten on a per location basis. * [www/nginx] Custom error pages for WAF violations
This commit is contained in:
@@ -32,6 +32,7 @@ Plugin Changelog
|
||||
|
||||
* User interface improvements of NAXSI configuration (contributed by 8191)
|
||||
* Fixed missing certificate validation of upstreams (contributed by 8191)
|
||||
* Add custom error pages on a per HTTP server basis (contributed by 8191)
|
||||
|
||||
1.19
|
||||
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -5,6 +5,7 @@
|
||||
<title>Not Found</title>
|
||||
<meta name="generator" content="OPNsense" />
|
||||
<meta name="language" content="en-US" />
|
||||
<meta name="viewport" content="width=device-width,initial-scale=1" />
|
||||
<style>
|
||||
body {
|
||||
background-color: black;
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
<title>Request Denied</title>
|
||||
<meta name="generator" content="OPNsense" />
|
||||
<meta name="language" content="en-US" />
|
||||
<meta name="viewport" content="width=device-width,initial-scale=1" />
|
||||
<style>
|
||||
body {
|
||||
background-color: black;
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
<title>Request Denied</title>
|
||||
<meta name="generator" content="OPNsense" />
|
||||
<meta name="language" content="en-US" />
|
||||
<meta name="viewport" content="width=device-width,initial-scale=1" />
|
||||
<style>
|
||||
body {
|
||||
background-color: black;
|
||||
|
||||
@@ -396,6 +396,42 @@ class SettingsController extends ApiMutableModelControllerBase
|
||||
return $this->setBase('limit_zone', 'limit_zone', $uuid);
|
||||
}
|
||||
|
||||
// Error pages
|
||||
public function searcherrorpageAction()
|
||||
{
|
||||
return $this->searchBase('errorpage', array('name', 'statuscodes', 'response'));
|
||||
}
|
||||
|
||||
public function geterrorpageAction($uuid = null)
|
||||
{
|
||||
$this->sessionClose();
|
||||
$data = $this->getBase('errorpage', 'errorpage', $uuid);
|
||||
// Decode base64 encoded page content
|
||||
$data['errorpage']['pagecontent'] = base64_decode($data['errorpage']['pagecontent']);
|
||||
return $data;
|
||||
}
|
||||
|
||||
public function adderrorpageAction()
|
||||
{
|
||||
return $this->addBase('errorpage', 'errorpage', array(
|
||||
// Encode page content with base64
|
||||
'pagecontent' => base64_encode($this->request->getPost('errorpage')['pagecontent'])
|
||||
));
|
||||
}
|
||||
|
||||
public function delerrorpageAction($uuid)
|
||||
{
|
||||
return $this->delBase('errorpage', $uuid);
|
||||
}
|
||||
|
||||
public function seterrorpageAction($uuid)
|
||||
{
|
||||
return $this->setBase('errorpage', 'errorpage', $uuid, array(
|
||||
// Encode page content with base64
|
||||
'pagecontent' => base64_encode($this->request->getPost('errorpage')['pagecontent'])
|
||||
));
|
||||
}
|
||||
|
||||
// TLS fingerprints for MITM detection
|
||||
public function searchtls_fingerprintAction()
|
||||
{
|
||||
|
||||
@@ -61,6 +61,7 @@ class IndexController extends \OPNsense\Base\IndexController
|
||||
$this->view->cache_path = $this->getForm("cache_path");
|
||||
$this->view->sni_hostname_map = $this->getForm("sni_hostname_map");
|
||||
$this->view->ipacl = $this->getForm("ipacl");
|
||||
$this->view->errorpage = $this->getForm("errorpage");
|
||||
$this->view->tls_fingerprint = $this->getForm("tls_fingerprint");
|
||||
$this->view->syslog_target = $this->getForm("syslog_target");
|
||||
$nginx = new Nginx();
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
<form>
|
||||
<field>
|
||||
<id>errorpage.name</id>
|
||||
<label>Name</label>
|
||||
<type>text</type>
|
||||
<help>Enter a name for your error page.</help>
|
||||
</field>
|
||||
<field>
|
||||
<id>errorpage.statuscodes</id>
|
||||
<label>Status Codes</label>
|
||||
<type>select_multiple</type>
|
||||
<style>selectpicker</style>
|
||||
<help>Enter the HTTP status codes for which the error page shall be shown.</help>
|
||||
</field>
|
||||
<field>
|
||||
<id>errorpage.pagecontent</id>
|
||||
<label>Page Content</label>
|
||||
<type>textbox</type>
|
||||
<help>The HTML page content to display.</help>
|
||||
</field>
|
||||
<field>
|
||||
<id>errorpage.redirect</id>
|
||||
<label>Redirect Target</label>
|
||||
<type>text</type>
|
||||
<help>Instead of displaying a static error page redirect to a URL.</help>
|
||||
<advanced>true</advanced>
|
||||
</field>
|
||||
<field>
|
||||
<id>errorpage.response</id>
|
||||
<label>Response Status Code</label>
|
||||
<type>dropdown</type>
|
||||
<style>selectpicker</style>
|
||||
<help>Optionally enter a HTTP status code to change the response to. This does not work in combination with a redirection target.</help>
|
||||
<advanced>true</advanced>
|
||||
</field>
|
||||
</form>
|
||||
@@ -237,4 +237,11 @@
|
||||
<style>selectpicker</style>
|
||||
<help>If you choose multiple limits, the strictest will be used.</help>
|
||||
</field>
|
||||
<field>
|
||||
<id>httpserver.errorpages</id>
|
||||
<label>Error Pages</label>
|
||||
<style>selectpicker</style>
|
||||
<type>select_multiple</type>
|
||||
<help>Select custom error pages to display instead of the default builtin error pages. If at least one error page is selected here, all default error pages will be disabled.</help>
|
||||
</field>
|
||||
</form>
|
||||
|
||||
@@ -35,6 +35,14 @@
|
||||
<type>checkbox</type>
|
||||
<help>Enable learning mode means nothing is blocked but logged.</help>
|
||||
</field>
|
||||
<field>
|
||||
<id>location.secrules_errorpage</id>
|
||||
<label>Violation Error Page</label>
|
||||
<style>selectpicker</style>
|
||||
<type>dropdown</type>
|
||||
<help>Select a custom error page to display instead of the default builtin error pages for security rule violations. Only the page content itself is used. Status code rewriting and redirection is not supported.</help>
|
||||
<advanced>true</advanced>
|
||||
</field>
|
||||
<field>
|
||||
<id>location.xss_block_score</id>
|
||||
<label>Block XSS Score</label>
|
||||
@@ -312,4 +320,11 @@
|
||||
<advanced>true</advanced>
|
||||
<help>If you enable this option, nginx will not terminate the connection to the backend server if the client connection is terminated.</help>
|
||||
</field>
|
||||
<field>
|
||||
<id>location.errorpages</id>
|
||||
<label>Error Pages</label>
|
||||
<style>selectpicker</style>
|
||||
<type>select_multiple</type>
|
||||
<help>Select custom error pages to display instead of the default builtin error pages. Selection will override error pages configured on HTTP server.</help>
|
||||
</field>
|
||||
</form>
|
||||
|
||||
@@ -204,6 +204,21 @@
|
||||
<default>0</default>
|
||||
<Required>Y</Required>
|
||||
</enable_learning_mode>
|
||||
<secrules_errorpage type="ModelRelationField">
|
||||
<Model>
|
||||
<template>
|
||||
<source>OPNsense.Nginx.Nginx</source>
|
||||
<items>errorpage</items>
|
||||
<display>name</display>
|
||||
<filters>
|
||||
<pagecontent>/.+/</pagecontent>
|
||||
</filters>
|
||||
</template>
|
||||
</Model>
|
||||
<ValidationMessage>Selected error page(s) not found</ValidationMessage>
|
||||
<Required>N</Required>
|
||||
<multiple>N</multiple>
|
||||
</secrules_errorpage>
|
||||
<xss_block_score type="IntegerField">
|
||||
<Required>N</Required>
|
||||
</xss_block_score>
|
||||
@@ -464,6 +479,18 @@
|
||||
<Required>Y</Required>
|
||||
<default>0</default>
|
||||
</proxy_ssl_server_name>
|
||||
<errorpages type="ModelRelationField">
|
||||
<Model>
|
||||
<template>
|
||||
<source>OPNsense.Nginx.Nginx</source>
|
||||
<items>errorpage</items>
|
||||
<display>name</display>
|
||||
</template>
|
||||
</Model>
|
||||
<ValidationMessage>Selected error page(s) not found</ValidationMessage>
|
||||
<Required>N</Required>
|
||||
<multiple>Y</multiple>
|
||||
</errorpages>
|
||||
</location>
|
||||
|
||||
<custom_policy type="ArrayField">
|
||||
@@ -852,6 +879,18 @@
|
||||
<Required>Y</Required>
|
||||
<default>0</default>
|
||||
</zero_rtt>
|
||||
<errorpages type="ModelRelationField">
|
||||
<Model>
|
||||
<template>
|
||||
<source>OPNsense.Nginx.Nginx</source>
|
||||
<items>errorpage</items>
|
||||
<display>name</display>
|
||||
</template>
|
||||
</Model>
|
||||
<ValidationMessage>Selected error page(s) not found</ValidationMessage>
|
||||
<Required>N</Required>
|
||||
<multiple>Y</multiple>
|
||||
</errorpages>
|
||||
</http_server>
|
||||
|
||||
<stream_server type="ArrayField">
|
||||
@@ -1442,6 +1481,71 @@
|
||||
</rate>
|
||||
</limit_zone>
|
||||
|
||||
<errorpage type="ArrayField">
|
||||
<name type="TextField">
|
||||
<Required>Y</Required>
|
||||
</name>
|
||||
<statuscodes type="OptionField">
|
||||
<multiple>Y</multiple>
|
||||
<OptionValues>
|
||||
<status_400 value="400">400 Bad Request</status_400>
|
||||
<status_401 value="401">401 Unauthorized</status_401>
|
||||
<status_403 value="403">403 Forbidden</status_403>
|
||||
<status_404 value="404">404 Not Found</status_404>
|
||||
<status_405 value="405">405 Method Not Allowed</status_405>
|
||||
<status_407 value="407">407 Proxy Authentication Required</status_407>
|
||||
<status_408 value="408">408 Request Timeout</status_408>
|
||||
<status_410 value="410">410 Gone</status_410>
|
||||
<status_415 value="415">415 Unsupported Media Type</status_415>
|
||||
<status_429 value="429">429 Too Many Requests</status_429>
|
||||
<status_431 value="431">431 Request Header Fields Too Large</status_431>
|
||||
<status_500 value="500">500 Internal Server Error</status_500>
|
||||
<status_501 value="501">501 Not Implemented</status_501>
|
||||
<status_502 value="502">502 Bad Gateway</status_502>
|
||||
<status_503 value="503">503 Service Unavailable</status_503>
|
||||
<status_504 value="504">504 Gateway Timeout</status_504>
|
||||
</OptionValues>
|
||||
<Required>Y</Required>
|
||||
</statuscodes>
|
||||
<pagecontent type="Base64Field">
|
||||
<default>PCFET0NUWVBFIGh0bWw+CjxodG1sPgo8aGVhZD4KICAgIDxtZXRhIGNoYXJzZXQ9IlVURi04Ij4KICAgIDxtZXRhIG5hbWU9InZpZXdwb3J0IiBjb250ZW50PSJ3aWR0aD1kZXZpY2Utd2lkdGgsaW5pdGlhbC1zY2FsZT0xIiAvPgogICAgPHRpdGxlPkVycm9yPC90aXRsZT4KPC9oZWFkPgo8Ym9keT4KICAgIDxoMT5FcnJvcjwvaDE+CiAgICA8cD5Tb3JyeSwgYnV0IHNvbWV0aGluZyB3ZW50IHdyb25nLjwvcD4KPC9ib2R5Pgo8L2h0bWw+</default>
|
||||
<Constraints>
|
||||
<check001>
|
||||
<type>SingleSelectConstraint</type>
|
||||
<ValidationMessage>Page content is required if redirect is not used and needs to be empty otherwise.</ValidationMessage>
|
||||
<addFields>
|
||||
<field1>redirect</field1>
|
||||
</addFields>
|
||||
<isRequired>Y</isRequired>
|
||||
</check001>
|
||||
</Constraints>
|
||||
</pagecontent>
|
||||
<redirect type="UrlField">
|
||||
<Required>N</Required>
|
||||
<Constraints>
|
||||
<check001>
|
||||
<reference>pagecontent.check001</reference>
|
||||
</check001>
|
||||
</Constraints>
|
||||
</redirect>
|
||||
<response type="OptionField">
|
||||
<multiple>N</multiple>
|
||||
<OptionValues>
|
||||
<status_200 value="200">200 OK</status_200>
|
||||
<status_300 value="300">300 Multiple Choice</status_300>
|
||||
<status_301 value="301">301 Moved Permanently</status_301>
|
||||
<status_302 value="302">302 Found</status_302>
|
||||
<status_401 value="401">401 Unauthorized</status_401>
|
||||
<status_403 value="403">403 Forbidden</status_403>
|
||||
<status_404 value="404">404 Not Found</status_404>
|
||||
<status_451 value="451">451 Unavailable For Legal Reasons</status_451>
|
||||
<status_500 value="500">500 Internal Server Error</status_500>
|
||||
<status_503 value="503">503 Service Unavailable</status_503>
|
||||
</OptionValues>
|
||||
<Required>N</Required>
|
||||
</response>
|
||||
</errorpage>
|
||||
|
||||
<tls_fingerprint type="ArrayField">
|
||||
<description type="TextField">
|
||||
<Required>Y</Required>
|
||||
|
||||
@@ -124,6 +124,9 @@
|
||||
<li>
|
||||
<a data-toggle="tab" id="subtab_item_nginx-http-cache_path" href="#subtab_nginx-http-cache_path">{{ lang._('Cache Path')}}</a>
|
||||
</li>
|
||||
<li>
|
||||
<a data-toggle="tab" id="subtab_item_nginx-http-errorpages" href="#subtab_nginx-http-errorpages">{{ lang._('Error Pages')}}</a>
|
||||
</li>
|
||||
<li>
|
||||
<a data-toggle="tab" id="subtab_item_nginx-http-tls-fingerprint" href="#subtab_nginx-http-tls-fingerprint">{{ lang._('TLS Fingerprint (Advanced)')}}</a>
|
||||
</li>
|
||||
@@ -606,6 +609,29 @@
|
||||
</tfoot>
|
||||
</table>
|
||||
</div>
|
||||
<div id="subtab_nginx-http-errorpages" class="tab-pane fade">
|
||||
<table id="grid-errorpage" class="table table-condensed table-hover table-striped table-responsive" data-editDialog="errorpage_dlg">
|
||||
<thead>
|
||||
<tr>
|
||||
<th data-column-id="name" data-width="15%" data-type="string" data-sortable="true" data-visible="true">{{ lang._('Name') }}</th>
|
||||
<th data-column-id="statuscodes" data-type="string" data-formatter="statuscodes" data-sortable="false" data-visible="true">{{ lang._('Status Codes') }}</th>
|
||||
<th data-column-id="response" data-width="13em" data-type="string" data-formatter="response" data-sortable="true">{{ lang._('Response') }}</th>
|
||||
<th data-column-id="commands" data-width="7em" data-formatter="commands" data-sortable="false">{{ lang._('Commands') }}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
</tbody>
|
||||
<tfoot>
|
||||
<tr>
|
||||
<td></td>
|
||||
<td>
|
||||
<button data-action="add" type="button" class="btn btn-xs btn-default"><span class="fa fa-plus"></span></button>
|
||||
<button type="button" class="btn btn-xs reload_btn btn-primary"><span class="fa fa-refresh reloadAct_progress"></span></button>
|
||||
</td>
|
||||
</tr>
|
||||
</tfoot>
|
||||
</table>
|
||||
</div>
|
||||
<div id="subtab_nginx-http-tls-fingerprint" class="tab-pane fade">
|
||||
<table id="grid-tls_fingerprint" class="table table-condensed table-hover table-striped table-responsive" data-editDialog="tls_fingerprint_dlg">
|
||||
<thead>
|
||||
@@ -670,5 +696,6 @@
|
||||
{{ partial("layout_partials/base_dialog",['fields': cache_path,'id':'cache_pathdlg', 'label':lang._('Edit Cache Path')]) }}
|
||||
{{ partial("layout_partials/base_dialog",['fields': sni_hostname_map,'id':'sni_hostname_mapdlg', 'label':lang._('Edit SNI Hostname Mapping')]) }}
|
||||
{{ partial("layout_partials/base_dialog",['fields': ipacl,'id':'ipacl_dlg', 'label':lang._('Edit IP ACL')]) }}
|
||||
{{ partial("layout_partials/base_dialog",['fields': errorpage,'id':'errorpage_dlg', 'label':lang._('Edit Error Page')]) }}
|
||||
{{ partial("layout_partials/base_dialog",['fields': tls_fingerprint,'id':'tls_fingerprint_dlg', 'label':lang._('Edit TLS Fingerprint')]) }}
|
||||
{{ partial("layout_partials/base_dialog",['fields': syslog_target,'id':'syslog_target_dlg', 'label':lang._('Edit SYSLOG Target')]) }}
|
||||
|
||||
@@ -239,11 +239,66 @@ foreach ($nginx->userlist->iterateItems() as $user_list) {
|
||||
unset($file);
|
||||
}
|
||||
}
|
||||
|
||||
// create directories for cache
|
||||
foreach ($nginx->cache_path->iterateItems() as $cache_path) {
|
||||
@mkdir((string)$cache_path->path, 0755, true);
|
||||
}
|
||||
|
||||
// create custom error pages
|
||||
const ERRORPAGE_DIR = '/usr/local/etc/nginx/views';
|
||||
@mkdir(ERRORPAGE_DIR, 0755, true);
|
||||
$used_errorpages = array();
|
||||
// search used error pages in http servers and locations
|
||||
foreach (array($nginx->http_server, $nginx->location) as $entity) {
|
||||
foreach ($entity->iterateItems() as $element) {
|
||||
$pages = explode(',', $element->errorpages);
|
||||
foreach ($pages as $page) {
|
||||
$page = str_replace('-', '', $page);
|
||||
if (!in_array($page, $used_errorpages)) {
|
||||
$used_errorpages[] = $page;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// search used WAF error pages
|
||||
foreach ($nginx->location->iterateItems() as $location) {
|
||||
if ($location->secrules_errorpage != '') {
|
||||
$page = str_replace('-', '', $location->secrules_errorpage);
|
||||
if (!in_array($page, $used_errorpages)) {
|
||||
$used_errorpages[] = $page;
|
||||
}
|
||||
}
|
||||
}
|
||||
// create/update error pages
|
||||
foreach ($nginx->errorpage->iterateItems() as $errorpage) {
|
||||
$uuid = str_replace('-', '', $errorpage->getAttributes()['uuid']);
|
||||
if (in_array($uuid, $used_errorpages)) {
|
||||
$filename = "error_$uuid.html";
|
||||
$content = base64_decode((string)$errorpage->pagecontent);
|
||||
// Does error page have a content?
|
||||
if (strlen($content) > 0) {
|
||||
$fs_hash = @hash_file("sha1", ERRORPAGE_DIR . "/$filename");
|
||||
if ($fs_hash !== hash("sha1", $content)) {
|
||||
@file_put_contents(ERRORPAGE_DIR . "/$filename", $content);
|
||||
}
|
||||
chmod(ERRORPAGE_DIR . "/$filename", 0644);
|
||||
}
|
||||
else {
|
||||
unset($used_errorpages[array_search($uuid, $used_errorpages)]);
|
||||
}
|
||||
}
|
||||
}
|
||||
// delete unused (old) error pages
|
||||
$dir = new \DirectoryIterator(ERRORPAGE_DIR);
|
||||
foreach ($dir as $file) {
|
||||
if ($file->isFile() && strpos($file->getFilename(), 'error_') === 0) {
|
||||
if (!in_array(substr($file->getFilename(), 6, 32), $used_errorpages)) {
|
||||
@unlink($file->getPathname());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// export TLS fingerprint database for MitM detection
|
||||
$tls_fingerprint_database = array();
|
||||
foreach ($nginx->tls_fingerprint->iterateItems() as $tls_fingerprint) {
|
||||
|
||||
@@ -171,8 +171,38 @@ server {
|
||||
satisfy {{ server.satisfy }};
|
||||
{% endif %}
|
||||
#include tls.conf;
|
||||
{% set used_errorpages = [] %}
|
||||
{% if server.errorpages is defined and server.errorpages != '' %}
|
||||
{% for errorpage_uuid in server.errorpages.split(',') %}
|
||||
{% do used_errorpages.append(errorpage_uuid) %}
|
||||
{% set errorpage = helpers.getUUID(errorpage_uuid) %}
|
||||
error_page {{ errorpage.statuscodes.replace(',', ' ') }} {% if errorpage.response is defined and errorpage.response != '' %}={{ errorpage.response }} {% endif %}{% if errorpage.redirect is defined and errorpage.redirect != '' %}{{ errorpage.redirect }}{% else %}/error_{{ errorpage_uuid.replace('-', '') }}.html{% endif %};
|
||||
{% if errorpage.redirect is not defined or errorpage.redirect == '' %}
|
||||
location = /error_{{ errorpage_uuid.replace('-', '') }}.html {
|
||||
internal;
|
||||
root /usr/local/etc/nginx/views;
|
||||
}
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
{% else %}
|
||||
error_page 403 /opnsense_error_403.html;
|
||||
error_page 404 /opnsense_error_404.html;
|
||||
error_page 405 /waf_denied.html;
|
||||
error_page 500 501 502 503 504 /opnsense_server_error.html;
|
||||
|
||||
location = /opnsense_error_403.html {
|
||||
internal;
|
||||
root /usr/local/etc/nginx/views;
|
||||
}
|
||||
location = /opnsense_error_404.html {
|
||||
internal;
|
||||
root /usr/local/etc/nginx/views;
|
||||
}
|
||||
location = /opnsense_server_error.html {
|
||||
internal;
|
||||
root /usr/local/etc/nginx/views;
|
||||
}
|
||||
{% endif %}
|
||||
{% if server.security_header is defined and server.security_header != '' %}
|
||||
{% set security_rule = helpers.getUUID(server.security_header) %}
|
||||
{% if security_rule is defined %}
|
||||
@@ -193,14 +223,6 @@ server {
|
||||
return 403 "You got banned permanently from this server.";
|
||||
}
|
||||
error_page 418 = @permanentban;
|
||||
location = /opnsense_server_error.html {
|
||||
internal;
|
||||
root /usr/local/etc/nginx/views;
|
||||
}
|
||||
location = /opnsense_error_404.html {
|
||||
internal;
|
||||
root /usr/local/etc/nginx/views;
|
||||
}
|
||||
location = /waf_denied.html {
|
||||
root /usr/local/etc/nginx/views;
|
||||
access_log /var/log/nginx/waf_denied.access.log main;
|
||||
@@ -292,11 +314,38 @@ server {
|
||||
{% endif %}
|
||||
|
||||
{% if server.locations is defined %}
|
||||
{% set location_errorpages = [] %}
|
||||
{% for location_uuid in server.locations.split(',') %}
|
||||
{% set location = helpers.getUUID(location_uuid) %}
|
||||
{% if location.urlpattern is defined %}
|
||||
{% include "OPNsense/Nginx/location.conf" ignore missing with context %}
|
||||
{% if location.urlpattern is defined %}
|
||||
{% include "OPNsense/Nginx/location.conf" ignore missing with context %}
|
||||
{# Find used error pages in secrules_errorpage #}
|
||||
{% if location.secrules_errorpage is defined and location.secrules_errorpage != '' %}
|
||||
{% if location.secrules_errorpage not in location_errorpages %}
|
||||
{% do location_errorpages.append(location.secrules_errorpage) %}
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
{# Find custom error pages used in locations #}
|
||||
{% if location.errorpages is defined and location.errorpages != '' %}
|
||||
{% for errorpage_uuid in location.errorpages.split(',') %}
|
||||
{% if errorpage_uuid not in location_errorpages %}
|
||||
{% do location_errorpages.append(errorpage_uuid) %}
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
{# Error pages used in locations #}
|
||||
{% for errorpage_uuid in location_errorpages %}
|
||||
{% if errorpage_uuid not in used_errorpages %}
|
||||
{% set errorpage = helpers.getUUID(errorpage_uuid) %}
|
||||
{% if errorpage.redirect is not defined or errorpage.redirect == '' %}
|
||||
location = /error_{{ errorpage_uuid.replace('-', '') }}.html {
|
||||
internal;
|
||||
root /usr/local/etc/nginx/views;
|
||||
}
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
|
||||
|
||||
@@ -36,7 +36,17 @@ location {{ location.matchtype }} {{ location.urlpattern }} {
|
||||
LibInjectionSql;
|
||||
CheckRule "$LIBINJECTION_SQL >= {{ location.sqli_block_score }}" BLOCK;
|
||||
{% endif %}
|
||||
{% if location.secrules_errorpage is defined and location.secrules_errorpage != '' %}
|
||||
DeniedUrl "/error_{{ location.secrules_errorpage.replace('-', '') }}.html";
|
||||
{% else %}
|
||||
DeniedUrl "/waf_denied.html";
|
||||
{% endif %}
|
||||
{% if location.errorpages is defined and location.errorpages != '' %}
|
||||
{% for errorpage_uuid in location.errorpages.split(',') %}
|
||||
{% set errorpage = helpers.getUUID(errorpage_uuid) %}
|
||||
error_page {{ errorpage.statuscodes.replace(',', ' ') }} {% if errorpage.response is defined and errorpage.response != '' %}={{ errorpage.response }} {% endif %}{% if errorpage.redirect is defined and errorpage.redirect != '' %}{{ errorpage.redirect }}{% else %}/error_{{ errorpage_uuid.replace('-', '') }}.html{% endif %};
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
{% if location.force_https is defined and location.force_https == '1' %}
|
||||
if ($scheme != "https") {
|
||||
return 302 https://$host$request_uri;
|
||||
@@ -210,3 +220,4 @@ location {{ location.matchtype }} {{ location.urlpattern }} {
|
||||
{% endif %}{# honeypot #}
|
||||
include {{ location['@uuid'] }}_post/*.conf;
|
||||
}
|
||||
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -68,6 +68,7 @@ function init_grids() {
|
||||
'cache_path',
|
||||
'limit_request_connection',
|
||||
'snifwd',
|
||||
'errorpage',
|
||||
'tls_fingerprint',
|
||||
'syslog_target',
|
||||
'naxsirule'].forEach(function (element) {
|
||||
@@ -78,7 +79,29 @@ function init_grids() {
|
||||
'set': '/api/nginx/settings/set' + element + '/',
|
||||
'add': '/api/nginx/settings/add' + element + '/',
|
||||
'del': '/api/nginx/settings/del' + element + '/',
|
||||
'options': {selection: false, multiSelect: false}
|
||||
'options': {
|
||||
selection: false,
|
||||
multiSelect: false,
|
||||
formatters: {
|
||||
"commands": function (column, row) {
|
||||
return "<button type=\"button\" class=\"btn btn-xs btn-default command-edit\" data-row-id=\"" + row.uuid + "\"><span class=\"fa fa-pencil\"></span></button> " +
|
||||
"<button type=\"button\" class=\"btn btn-xs btn-default command-copy\" data-row-id=\"" + row.uuid + "\"><span class=\"fa fa-clone\"></span></button>" +
|
||||
"<button type=\"button\" class=\"btn btn-xs btn-default command-delete\" data-row-id=\"" + row.uuid + "\"><span class=\"fa fa-trash-o\"></span></button>";
|
||||
},
|
||||
"response": function (column, row) {
|
||||
return ((row.response == "none") ? "unchanged" : row.response);
|
||||
},
|
||||
// Extract 3 digit HTTP status code from string with human readable text (302 Found -> 302)
|
||||
"statuscodes": function (column, row) {
|
||||
const result = [];
|
||||
const elems = row.statuscodes.split(",");
|
||||
for (let elem of elems) {
|
||||
result.push(elem.substr(0, 3));
|
||||
}
|
||||
return result.join(", ");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user