mirror of
https://github.com/netbirdio/plugins.git
synced 2026-05-22 18:44:07 -07:00
www/caddy: Cleanup model, php (PSR-12), python (PEP 8) and jinja2 files (#4060)
* www/caddy: Remove unsused code in validation. * www/caddy: Cleanup Caddyfile template for better readability with improved indentation. * www/caddy: Cleanup rc.conf.d/caddy * www/caddy: Cleanup model. * www/caddy: Cleanup Caddyfile template some more. * www/caddy: Roll back changes to Caddyfile structure, don't fix what ain't broken. * www/caddy: Fix caddy_certs.php style warning. A file should declare new symbols (classes, functions, constants, etc.) and cause no other side effects, or it should execute logic with side effects, but should not do both. * www/caddy: Ignore php style warnings for migration scripts, since the class names have to ignore PascalCase. * www/caddy: Correct style of php files so that no lines exceed 120 characters. * www/caddy: Refactor caddy_diagnostics.py and caddy_control.py for Python PEP 8. Fix: Shadows name 'action' from outer scope * www/caddy: Changelog add code cleanup. * www/caddy: Fix minor regression in refactored caddy_control.py script. * www/caddy: Fix indentation of Caddyfile template for better code readability. The template gets edited and read a lot so this fix really helps with maintainability. * www/caddy: Add changelog. * www/caddy: Fix caddy_certs.php style issue by removing the declared function and execute logic with side effects directly. * www/caddy: Re-add ValidationMessage to IntegerField because there are custom constraints that are not displayed by the default validation message. * www/caddy: Add error handling to caddy_control.py when action is empty. Make use of service_action and cmd_action clearer. * www/caddy: Remove unnecessary variable in caddy_diagnostics.py * www/caddy: Add validation message since there is a no IP constraint. Add same constraint to subdomains. * www/caddy: Re-add validation message to ToDomain field since multiple are allowed * www/caddy: Re-add validation message to clientIps field since multiple are allowed
This commit is contained in:
+5
-1
@@ -28,7 +28,11 @@ Plugin Changelog
|
||||
1.6.0
|
||||
|
||||
* Add: New Dashboard widgets for 24.7, showing domain status and certificate validity status.
|
||||
* Fix: Caddyfile template fixed for IPv6 addresses and custom port.
|
||||
* Cleanup: PHP files refactored for PSR-12, Python files refactored for PEP-8.
|
||||
* Cleanup: Templates Caddyfile and rc.conf.d/caddy refactored for maintainability.
|
||||
* Cleanup: Spurious keys removed from Caddy.xml model.
|
||||
* Cleanup: Unused code removed from Caddy.php.
|
||||
* Fix: Caddyfile template fixed when IPv6 addresses and ports are used in Upstream. IPv6 address wraps into brackets now.
|
||||
* Add: forward_auth directive with Authelia as Authz Provider.
|
||||
* Add: Default HTTP and HTTPS ports can be changed in general settings.
|
||||
* Add: Introduce HTTP version to handler. HTTP/1.1, HTTP/2 and HTTP/3 can be chosen.
|
||||
|
||||
+1
-3
@@ -50,7 +50,7 @@ class DiagnosticsController extends ApiMutableModelControllerBase
|
||||
// Decode JSON to PHP array
|
||||
$responseArray = json_decode($response, true);
|
||||
|
||||
// Since errors are handled by the caddy_diagnostics script and returned as json, check for an error key in the response
|
||||
// Errors are handled by the caddy_diagnostics script and returned, check for an error key in the response
|
||||
if (isset($responseArray['error'])) {
|
||||
return ["status" => "failed", "message" => $responseArray['message']];
|
||||
}
|
||||
@@ -74,7 +74,6 @@ class DiagnosticsController extends ApiMutableModelControllerBase
|
||||
// Decode JSON to PHP array
|
||||
$responseArray = json_decode($response, true);
|
||||
|
||||
// Since errors are handled by the caddy_diagnostics script and returned as json, check for an error key in the response
|
||||
if (isset($responseArray['error'])) {
|
||||
return ["status" => "failed", "message" => $responseArray['message']];
|
||||
}
|
||||
@@ -94,7 +93,6 @@ class DiagnosticsController extends ApiMutableModelControllerBase
|
||||
// Decode JSON to PHP array
|
||||
$responseArray = json_decode($response, true);
|
||||
|
||||
// Since errors are handled by the caddy_diagnostics script and returned as json, check for an error key in the response
|
||||
if (isset($responseArray['error'])) {
|
||||
return ["status" => "failed", "message" => $responseArray['message']];
|
||||
}
|
||||
|
||||
+19
-11
@@ -26,7 +26,6 @@
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
*/
|
||||
|
||||
namespace OPNsense\Caddy\Api;
|
||||
@@ -70,14 +69,15 @@ class ReverseProxyController extends ApiMutableModelControllerBase
|
||||
}
|
||||
|
||||
/**
|
||||
* Centralized and generalized helper function for searching across different sections of the reverse proxy setup.
|
||||
* Generalized helper function for searching across different sections of the reverse proxy setup.
|
||||
* This function mostly helps when model relation fields are used.
|
||||
* It filters entries based on UUIDs provided as an argument. The section or key used for the UUID
|
||||
* can be specified, allowing for direct or indirect UUID referencing.
|
||||
*
|
||||
* @param string $modelPath The data model path identifier, pointing to the section of the model being searched.
|
||||
* @param string $uuidSearchBase The request parameter name for the comma-separated list of UUIDs to filter the search results.
|
||||
* @param string|null $uuidReferenceKey The specific attribute key used to fetch the UUID for filtering. If null, defaults to the item's own UUID.
|
||||
* @param string $modelPath The data model path identifier, pointing to section of model being searched.
|
||||
* @param string $uuidSearchBase The request parameter name for the comma-separated list of UUIDs.
|
||||
* @param string|null $uuidReferenceKey Attribute key used to fetch the UUID for filtering.
|
||||
* If null, uses item's own UUID.
|
||||
* @return array Filtered search results.
|
||||
*/
|
||||
private function searchActionHelper($modelPath, $uuidSearchBase, $uuidReferenceKey = null)
|
||||
@@ -89,8 +89,12 @@ class ReverseProxyController extends ApiMutableModelControllerBase
|
||||
|
||||
// Define a filter function to determine which items to include based on the UUID.
|
||||
$filterFunction = function ($modelItem) use ($uuidArray, $uuidReferenceKey) {
|
||||
// Extract UUID from the item, using the specified UUID key if provided, otherwise default to direct UUID access.
|
||||
$modelUUID = ($uuidReferenceKey !== null) ? (string)$modelItem->$uuidReferenceKey : (string)$modelItem->getAttributes()['uuid'];
|
||||
// Extract UUID from the item, using the specified UUID key if provided, else default to direct UUID access.
|
||||
if ($uuidReferenceKey !== null) {
|
||||
$modelUUID = (string)$modelItem->$uuidReferenceKey;
|
||||
} else {
|
||||
$modelUUID = (string)$modelItem->getAttributes()['uuid'];
|
||||
}
|
||||
// Include the item if the UUID array is empty or if the item's UUID is in the array.
|
||||
return empty($uuidArray) || in_array($modelUUID, $uuidArray, true);
|
||||
};
|
||||
@@ -245,8 +249,10 @@ class ReverseProxyController extends ApiMutableModelControllerBase
|
||||
{
|
||||
if ($this->request->isPost()) {
|
||||
$postData = $this->request->getPost();
|
||||
|
||||
if (isset($postData['basicauth']['basicauthpass']) && !empty(trim($postData['basicauth']['basicauthpass']))) {
|
||||
if (
|
||||
isset($postData['basicauth']['basicauthpass'])
|
||||
&& !empty(trim($postData['basicauth']['basicauthpass']))
|
||||
) {
|
||||
$plainPassword = $postData['basicauth']['basicauthpass'];
|
||||
$hashedPassword = password_hash($plainPassword, PASSWORD_BCRYPT);
|
||||
$_POST['basicauth']['basicauthpass'] = $hashedPassword;
|
||||
@@ -260,8 +266,10 @@ class ReverseProxyController extends ApiMutableModelControllerBase
|
||||
{
|
||||
if ($this->request->isPost()) {
|
||||
$postData = $this->request->getPost();
|
||||
|
||||
if (isset($postData['basicauth']['basicauthpass']) && !empty(trim($postData['basicauth']['basicauthpass']))) {
|
||||
if (
|
||||
isset($postData['basicauth']['basicauthpass'])
|
||||
&& !empty(trim($postData['basicauth']['basicauthpass']))
|
||||
) {
|
||||
$plainPassword = $postData['basicauth']['basicauthpass'];
|
||||
$hashedPassword = password_hash($plainPassword, PASSWORD_BCRYPT);
|
||||
$_POST['basicauth']['basicauthpass'] = $hashedPassword;
|
||||
|
||||
@@ -59,9 +59,15 @@ class Caddy extends BaseModel
|
||||
if (isset($combos[$comboKey])) {
|
||||
// Use dynamic $key for message referencing
|
||||
$messages->appendMessage(new Message(
|
||||
sprintf(gettext("Duplicate entry: The combination of '%s' and port '%s' is already used. Each combination of domain and port must be unique."), $fromDomain, $port),
|
||||
$key . ".FromDomain", // Adjusted to use dynamic key
|
||||
"DuplicateDomainPort"
|
||||
sprintf(
|
||||
gettext(
|
||||
'Duplicate entry: The combination of %s and port %s is already used. ' .
|
||||
'Each combination of domain and port must be unique.'
|
||||
),
|
||||
$fromDomain,
|
||||
$port
|
||||
),
|
||||
$key . ".FromDomain"
|
||||
));
|
||||
} else {
|
||||
$combos[$comboKey] = true;
|
||||
@@ -98,9 +104,14 @@ class Caddy extends BaseModel
|
||||
if (!$isValid) {
|
||||
$key = $subdomain->__reference; // Dynamic key based on subdomain reference
|
||||
$messages->appendMessage(new Message(
|
||||
sprintf(gettext("Invalid subdomain configuration: '%s' does not fall under any configured wildcard domain."), $subdomainName),
|
||||
$key . ".FromDomain", // Use dynamic key for message referencing
|
||||
"InvalidSubdomain"
|
||||
sprintf(
|
||||
gettext(
|
||||
'Invalid subdomain configuration: %s does not fall ' .
|
||||
'under any configured wildcard domain.'
|
||||
),
|
||||
$subdomainName
|
||||
),
|
||||
$key . ".FromDomain"
|
||||
));
|
||||
}
|
||||
}
|
||||
@@ -140,7 +151,18 @@ class Caddy extends BaseModel
|
||||
if (!empty($overlap) && $tlsAutoHttpsSetting !== 'off') {
|
||||
$portOverlap = implode(', ', $overlap);
|
||||
$messages->appendMessage(new Message(
|
||||
sprintf(gettext('To use "Auto HTTPS", resolve these conflicting ports (%s) that are currently configured for the OPNsense WebGUI. Go to "System - Settings - Administration". To release port 80, enable "Disable web GUI redirect rule". To release port %s, change "TCP port" to a non-standard port, e.g., 8443.'), $portOverlap, $httpsPort),
|
||||
sprintf(
|
||||
gettext(
|
||||
'To use "Auto HTTPS", resolve these conflicting ports %s ' .
|
||||
'that are currently configured for the OPNsense WebGUI. ' .
|
||||
'Go to "System - Settings - Administration". ' .
|
||||
'To release port 80, enable "Disable web GUI redirect rule". ' .
|
||||
'To release port %s, change "TCP port" to a non-standard port, ' .
|
||||
'e.g., 8443.'
|
||||
),
|
||||
$portOverlap,
|
||||
$httpsPort
|
||||
),
|
||||
"general.TlsAutoHttps"
|
||||
));
|
||||
}
|
||||
@@ -193,12 +215,23 @@ class Caddy extends BaseModel
|
||||
public function performValidation($validateFullModel = false)
|
||||
{
|
||||
$messages = parent::performValidation($validateFullModel);
|
||||
|
||||
// 1. Check domain-port combinations
|
||||
$this->checkForUniquePortCombos($this->reverseproxy->reverse->iterateItems(), $messages);
|
||||
$this->checkForUniquePortCombos(
|
||||
$this->reverseproxy->reverse->iterateItems(),
|
||||
$messages
|
||||
);
|
||||
|
||||
// 2. Check that subdomains are under a wildcard or exact domain
|
||||
$this->checkSubdomainsAgainstDomains($this->reverseproxy->subdomain->iterateItems(), $this->reverseproxy->reverse->iterateItems(), $messages);
|
||||
$this->checkSubdomainsAgainstDomains(
|
||||
$this->reverseproxy->subdomain->iterateItems(),
|
||||
$this->reverseproxy->reverse->iterateItems(),
|
||||
$messages
|
||||
);
|
||||
|
||||
// 3. Check WebGUI conflicts
|
||||
$this->checkWebGuiSettings($messages);
|
||||
|
||||
// 4. Check for ACME Email requirement
|
||||
$this->checkAcmeEmailAutoHttps($messages);
|
||||
// 5. Check for TLS conflicts in Domain
|
||||
|
||||
@@ -10,9 +10,7 @@
|
||||
</enabled>
|
||||
<HttpPort type="PortField"/>
|
||||
<HttpsPort type="PortField"/>
|
||||
<TlsEmail type="EmailField">
|
||||
<ValidationMessage>Please enter a valid email address.</ValidationMessage>
|
||||
</TlsEmail>
|
||||
<TlsEmail type="EmailField"/>
|
||||
<TlsAutoHttps type="OptionField">
|
||||
<BlankDesc>On (default)</BlankDesc>
|
||||
<OptionValues>
|
||||
@@ -106,9 +104,7 @@
|
||||
<FATAL>FATAL</FATAL>
|
||||
</OptionValues>
|
||||
</LogLevel>
|
||||
<DynDnsSimpleHttp type="UrlField">
|
||||
<ValidationMessage>Please enter a valid URL, starting with http or https.</ValidationMessage>
|
||||
</DynDnsSimpleHttp>
|
||||
<DynDnsSimpleHttp type="UrlField"/>
|
||||
<DynDnsInterface type="InterfaceField"/>
|
||||
<DynDnsInterval type="IntegerField">
|
||||
<MinimumValue>1</MinimumValue>
|
||||
@@ -150,17 +146,11 @@
|
||||
</enabled>
|
||||
<FromDomain type="HostnameField">
|
||||
<Required>Y</Required>
|
||||
<ValidationMessage>Please enter a valid 'from' domain.</ValidationMessage>
|
||||
<IpAllowed>N</IpAllowed>
|
||||
<HostWildcardAllowed>Y</HostWildcardAllowed>
|
||||
<FqdnWildcardAllowed>Y</FqdnWildcardAllowed>
|
||||
<ZoneRootAllowed>N</ZoneRootAllowed>
|
||||
<ValidationMessage>Please enter a valid domain name.</ValidationMessage>
|
||||
</FromDomain>
|
||||
<FromPort type="PortField">
|
||||
<ValidationMessage>Please enter a valid 'from' port number.</ValidationMessage>
|
||||
<EnableWellKnown>Y</EnableWellKnown>
|
||||
<EnableRanges>N</EnableRanges>
|
||||
</FromPort>
|
||||
<FromPort type="PortField"/>
|
||||
<accesslist type="ModelRelationField">
|
||||
<Model>
|
||||
<reverseproxy>
|
||||
@@ -189,10 +179,7 @@
|
||||
<CustomCertificate type="CertificateField"/>
|
||||
<AccessLog type="BooleanField"/>
|
||||
<DynDns type="BooleanField"/>
|
||||
<AcmePassthrough type="HostnameField">
|
||||
<ValidationMessage>Please enter a valid 'to' domain or IP address.</ValidationMessage>
|
||||
<IpAllowed>Y</IpAllowed>
|
||||
</AcmePassthrough>
|
||||
<AcmePassthrough type="HostnameField"/>
|
||||
<DisableTls type="BooleanField"/>
|
||||
</reverse>
|
||||
<subdomain type="ArrayField">
|
||||
@@ -213,8 +200,8 @@
|
||||
</reverse>
|
||||
<FromDomain type="HostnameField">
|
||||
<Required>Y</Required>
|
||||
<ValidationMessage>Please enter a valid 'from' Subdomain that is based upon the wildcard domain.</ValidationMessage>
|
||||
<ZoneRootAllowed>N</ZoneRootAllowed>
|
||||
<IpAllowed>N</IpAllowed>
|
||||
<ValidationMessage>Please enter a valid domain name.</ValidationMessage>
|
||||
</FromDomain>
|
||||
<accesslist type="ModelRelationField">
|
||||
<Model>
|
||||
@@ -241,10 +228,7 @@
|
||||
<Required>Y</Required>
|
||||
</description>
|
||||
<DynDns type="BooleanField"/>
|
||||
<AcmePassthrough type="HostnameField">
|
||||
<ValidationMessage>Please enter a valid 'to' domain or IP address.</ValidationMessage>
|
||||
<IpAllowed>Y</IpAllowed>
|
||||
</AcmePassthrough>
|
||||
<AcmePassthrough type="HostnameField"/>
|
||||
</subdomain>
|
||||
<handle type="ArrayField">
|
||||
<enabled type="BooleanField">
|
||||
@@ -282,7 +266,7 @@
|
||||
</HandleType>
|
||||
<HandlePath type="TextField">
|
||||
<Mask>/^(\/.*)?$/u</Mask>
|
||||
<ValidationMessage>Please enter a valid 'Handle Path' that starts with '/'.</ValidationMessage>
|
||||
<ValidationMessage>Please enter a valid Path that starts with '/'.</ValidationMessage>
|
||||
</HandlePath>
|
||||
<header type="ModelRelationField">
|
||||
<Model>
|
||||
@@ -297,19 +281,14 @@
|
||||
</header>
|
||||
<ToDomain type="HostnameField">
|
||||
<Required>Y</Required>
|
||||
<ValidationMessage>Please enter a valid 'to' domain or IP address.</ValidationMessage>
|
||||
<IpAllowed>Y</IpAllowed>
|
||||
<FieldSeparator>,</FieldSeparator>
|
||||
<AsList>Y</AsList>
|
||||
<ValidationMessage>Please enter one or multiple valid IP addresses, hostnames or FQDNs.</ValidationMessage>
|
||||
</ToDomain>
|
||||
<ToPort type="PortField">
|
||||
<ValidationMessage>Please enter a valid 'to' port number.</ValidationMessage>
|
||||
<EnableWellKnown>Y</EnableWellKnown>
|
||||
<EnableRanges>N</EnableRanges>
|
||||
</ToPort>
|
||||
<ToPort type="PortField"/>
|
||||
<ToPath type="TextField">
|
||||
<Mask>/^(\/.*)?$/u</Mask>
|
||||
<ValidationMessage>Please enter a valid 'Backend Path' that starts with '/'.</ValidationMessage>
|
||||
<ValidationMessage>Please enter a valid Path that starts with '/'.</ValidationMessage>
|
||||
</ToPath>
|
||||
<PassiveHealthFailDuration type="IntegerField">
|
||||
<MinimumValue>1</MinimumValue>
|
||||
@@ -351,30 +330,21 @@
|
||||
<HttpTlsTrustedCaCerts type="CertificateField">
|
||||
<Type>ca</Type>
|
||||
</HttpTlsTrustedCaCerts>
|
||||
<HttpTlsServerName type="HostnameField">
|
||||
<ValidationMessage>Please enter a valid hostname or IP address.</ValidationMessage>
|
||||
<IpAllowed>Y</IpAllowed>
|
||||
<HostWildcardAllowed>Y</HostWildcardAllowed>
|
||||
<FqdnWildcardAllowed>Y</FqdnWildcardAllowed>
|
||||
<ZoneRootAllowed>N</ZoneRootAllowed>
|
||||
</HttpTlsServerName>
|
||||
<HttpTlsServerName type="HostnameField"/>
|
||||
<description type="DescriptionField">
|
||||
<Required>Y</Required>
|
||||
</description>
|
||||
</handle>
|
||||
<accesslist type="ArrayField">
|
||||
<accesslistName type="TextField">
|
||||
<accesslistName type="DescriptionField">
|
||||
<Required>Y</Required>
|
||||
<Mask>/^([\t\n\v\f\r 0-9a-zA-Z.,_*-\x{00A0}-\x{FFFF}]){1,255}$/u</Mask>
|
||||
<ValidationMessage>Please provide a valid Access List Name.</ValidationMessage>
|
||||
</accesslistName>
|
||||
<clientIps type="NetworkField">
|
||||
<Required>Y</Required>
|
||||
<NetMaskAllowed>Y</NetMaskAllowed>
|
||||
<FieldSeparator>,</FieldSeparator>
|
||||
<AsList>Y</AsList>
|
||||
<Strict>Y</Strict>
|
||||
<ValidationMessage>Please enter valid IP address(es) or network(s), separated by commas.</ValidationMessage>
|
||||
<ValidationMessage>Please enter one or multiple valid IP addresses or networks.</ValidationMessage>
|
||||
</clientIps>
|
||||
<accesslistInvert type="BooleanField"/>
|
||||
<HttpResponseCode type="IntegerField">
|
||||
|
||||
@@ -31,7 +31,9 @@ namespace OPNsense\Caddy\Migrations;
|
||||
use OPNsense\Base\BaseModelMigration;
|
||||
use OPNsense\Core\Config;
|
||||
|
||||
// @codingStandardsIgnoreStart
|
||||
class M1_1_3 extends BaseModelMigration
|
||||
// @codingStandardsIgnoreEnd
|
||||
{
|
||||
public function run($model)
|
||||
{
|
||||
|
||||
@@ -31,7 +31,9 @@ namespace OPNsense\Caddy\Migrations;
|
||||
use OPNsense\Base\BaseModelMigration;
|
||||
use OPNsense\Core\Config;
|
||||
|
||||
// @codingStandardsIgnoreStart
|
||||
class M1_1_8 extends BaseModelMigration
|
||||
// @codingStandardsIgnoreEnd
|
||||
{
|
||||
public function run($model)
|
||||
{
|
||||
|
||||
@@ -2,8 +2,7 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* Copyright (C) 2023-2024 Cedrik Pischem
|
||||
* Copyright (C) 2015 Deciso B.V.
|
||||
* Copyright (C) 2024 Cedrik Pischem
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
@@ -28,55 +27,50 @@
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
require_once("config.inc");
|
||||
require_once "config.inc";
|
||||
|
||||
use OPNsense\Core\Config;
|
||||
|
||||
$configObj = Config::getInstance()->object();
|
||||
$temp_dir = '/var/db/caddy/data/caddy/certificates/temp/';
|
||||
|
||||
function extract_and_save_certificates($configObj, $temp_dir)
|
||||
{
|
||||
// Traverse through certificates
|
||||
foreach ($configObj->cert as $cert) {
|
||||
$cert_refid = (string)$cert->refid;
|
||||
$cert_content = base64_decode((string)$cert->crt);
|
||||
$key_content = base64_decode((string)$cert->prv);
|
||||
$cert_chain = $cert_content;
|
||||
// Traverse through certificates
|
||||
foreach ($configObj->cert as $cert) {
|
||||
$cert_refid = (string) $cert->refid;
|
||||
$cert_content = base64_decode((string) $cert->crt);
|
||||
$key_content = base64_decode((string) $cert->prv);
|
||||
$cert_chain = $cert_content;
|
||||
|
||||
// Handle CA and possible intermediate CA to create a certificate bundle
|
||||
if (!empty($cert->caref)) {
|
||||
foreach ($configObj->ca as $ca) {
|
||||
if ((string)$cert->caref == (string)$ca->refid) {
|
||||
$ca_content = base64_decode((string)$ca->crt);
|
||||
$cert_chain .= "\n" . $ca_content;
|
||||
// Handle CA and possible intermediate CA to create a certificate bundle
|
||||
if (!empty($cert->caref)) {
|
||||
foreach ($configObj->ca as $ca) {
|
||||
if ((string) $cert->caref === (string) $ca->refid) {
|
||||
$ca_content = base64_decode((string) $ca->crt);
|
||||
$cert_chain .= "\n" . $ca_content;
|
||||
|
||||
if (!empty($ca->caref)) {
|
||||
foreach ($configObj->ca as $parent_ca) {
|
||||
if ((string)$ca->caref == (string)$parent_ca->refid) {
|
||||
$parent_ca_content = base64_decode((string)$parent_ca->crt);
|
||||
$cert_chain .= "\n" . $parent_ca_content;
|
||||
break;
|
||||
}
|
||||
if (!empty($ca->caref)) {
|
||||
foreach ($configObj->ca as $parent_ca) {
|
||||
if ((string) $ca->caref === (string) $parent_ca->refid) {
|
||||
$parent_ca_content = base64_decode((string) $parent_ca->crt);
|
||||
$cert_chain .= "\n" . $parent_ca_content;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Save the certificate chain and private key
|
||||
file_put_contents($temp_dir . $cert_refid . '.pem', $cert_chain);
|
||||
file_put_contents($temp_dir . $cert_refid . '.key', $key_content);
|
||||
}
|
||||
|
||||
// Traverse through CA certificates and save them
|
||||
foreach ($configObj->ca as $ca) {
|
||||
$ca_refid = (string)$ca->refid;
|
||||
$ca_content = base64_decode((string)$ca->crt);
|
||||
|
||||
// Save the CA certificate
|
||||
file_put_contents($temp_dir . $ca_refid . '.pem', $ca_content);
|
||||
}
|
||||
// Save the certificate chain and private key
|
||||
file_put_contents($temp_dir . $cert_refid . '.pem', $cert_chain);
|
||||
file_put_contents($temp_dir . $cert_refid . '.key', $key_content);
|
||||
}
|
||||
|
||||
extract_and_save_certificates($configObj, $temp_dir);
|
||||
// Traverse through CA certificates and save them
|
||||
foreach ($configObj->ca as $ca) {
|
||||
$ca_refid = (string) $ca->refid;
|
||||
$ca_content = base64_decode((string) $ca->crt);
|
||||
|
||||
// Save the CA certificate
|
||||
file_put_contents($temp_dir . $ca_refid . '.pem', $ca_content);
|
||||
}
|
||||
|
||||
@@ -30,19 +30,23 @@ import subprocess
|
||||
import json
|
||||
import sys
|
||||
|
||||
def run_service_command(action, action_message):
|
||||
|
||||
def run_service_command(service_action, action_message):
|
||||
result = {"message": action_message}
|
||||
|
||||
if action == "validate":
|
||||
if service_action == "validate":
|
||||
try:
|
||||
# Validate the Caddyfile with explicit --config flag, capturing both stdout and stderr
|
||||
validation_output = subprocess.check_output(["caddy", "validate", "--config", "/usr/local/etc/caddy/Caddyfile"], stderr=subprocess.STDOUT, text=True)
|
||||
validation_output = subprocess.check_output(
|
||||
["caddy", "validate", "--config", "/usr/local/etc/caddy/Caddyfile"], stderr=subprocess.STDOUT,
|
||||
text=True)
|
||||
if "Valid configuration" in validation_output:
|
||||
result["status"] = "ok"
|
||||
result["message"] = "Caddy configuration is valid."
|
||||
else:
|
||||
# Search for the specific error message
|
||||
error_msg = next((line for line in validation_output.split('\n') if line.startswith("Error:")), "Caddy configuration is not valid.")
|
||||
error_msg = next((line for line in validation_output.split('\n') if line.startswith("Error:")),
|
||||
"Caddy configuration is not valid.")
|
||||
result["status"] = "failed"
|
||||
result["message"] = error_msg
|
||||
except subprocess.CalledProcessError as e:
|
||||
@@ -52,7 +56,7 @@ def run_service_command(action, action_message):
|
||||
result["message"] = error_msg
|
||||
else:
|
||||
try:
|
||||
subprocess.run(["service", "caddy", action], check=True)
|
||||
subprocess.run(["service", "caddy", service_action], check=True)
|
||||
result["status"] = "ok"
|
||||
except subprocess.CalledProcessError as e:
|
||||
result["status"] = "failed"
|
||||
@@ -60,29 +64,36 @@ def run_service_command(action, action_message):
|
||||
|
||||
return json.dumps(result)
|
||||
|
||||
# Updated actions dictionary
|
||||
|
||||
# "cmd_action": "service_action"
|
||||
actions = {
|
||||
"start": "start",
|
||||
"stop": "stop",
|
||||
"restart": "restart",
|
||||
"reload": "reloadssl", # Forces the reload even if the config in the Caddyfile is unchanged, using an extra command of the rc.d script, forcing certificates in the filesystem to reload.
|
||||
"reload": "reloadssl",
|
||||
# Reloadssl reloads even if the config in the Caddyfile is unchanged, using an extra command of the rc.d script,
|
||||
# forcing certificates in the filesystem to be reloaded.
|
||||
"validate": "validate" # Validate action
|
||||
}
|
||||
|
||||
if __name__ == "__main__":
|
||||
action = sys.argv[1] # Get the action from the command-line argument
|
||||
if action in actions:
|
||||
service_action = actions[action]
|
||||
message = f"{action.capitalize()}ing Caddy service" if action != "validate" else "Validating Caddy configuration"
|
||||
if len(sys.argv) > 1:
|
||||
action = sys.argv[1] # Get the action from the command-line argument
|
||||
if action in actions:
|
||||
cmd_action = action
|
||||
service_action = actions[action]
|
||||
message = f"{cmd_action.capitalize()} Caddy service"
|
||||
|
||||
# Call setup script for 'validate' and 'reloadssl' actions
|
||||
# This is needed because the setup script triggers the caddy_certs.php script, which exports all certificates into the filesystem.
|
||||
# Caddy reloads certificates when reloadssl is used. Because it is a non standard command, the caddy_setup script will not be triggered in /etc/rc.conf.d/caddy.
|
||||
# The validate command needs it to make sure all certificates are in the filesystem, because otherwise the validation fails.
|
||||
if service_action in ["validate", "reloadssl"]:
|
||||
subprocess.run(["/usr/local/opnsense/scripts/OPNsense/Caddy/setup.sh"], check=True)
|
||||
# Call setup script for 'validate' and 'reloadssl' actions. This is needed because the setup script triggers
|
||||
# the caddy_certs.php script, which exports all certificates into the filesystem. Caddy reloads certificates
|
||||
# when reloadssl is used. Because it is a non standard command, the caddy_setup script will not be triggered
|
||||
# in /etc/rc.conf.d/caddy. The validate command needs it to make sure all certificates are in the filesystem,
|
||||
# because otherwise the validation fails.
|
||||
if service_action in ["validate", "reloadssl"]:
|
||||
subprocess.run(["/usr/local/opnsense/scripts/OPNsense/Caddy/setup.sh"], check=True)
|
||||
|
||||
# Continue with the service action
|
||||
print(run_service_command(service_action, message))
|
||||
print(run_service_command(service_action, message))
|
||||
else:
|
||||
print(json.dumps({"status": "failed", "message": f"Unknown action: {action}"}))
|
||||
else:
|
||||
print(json.dumps({"status": "failed", "message": f"Unknown action: {action}"}))
|
||||
print(json.dumps({"status": "failed", "message": "No action provided"}))
|
||||
|
||||
@@ -33,6 +33,7 @@ import subprocess
|
||||
import asyncio
|
||||
from datetime import datetime
|
||||
|
||||
|
||||
# Function to show the Caddy configuration from a JSON file
|
||||
def show_caddy_config():
|
||||
config_path = "/var/db/caddy/config/caddy/autosave.json"
|
||||
@@ -48,10 +49,12 @@ def show_caddy_config():
|
||||
except FileNotFoundError:
|
||||
print(json.dumps({"error": "File not found", "message": "Caddy autosave.json configuration file not found"}))
|
||||
except json.JSONDecodeError:
|
||||
print(json.dumps({"error": "Invalid JSON", "message": "Error decoding the Caddy autosave.json, the file is not valid JSON"}))
|
||||
print(json.dumps(
|
||||
{"error": "Invalid JSON", "message": "Error decoding the Caddy autosave.json, the file is not valid JSON"}))
|
||||
except Exception as e:
|
||||
print(json.dumps({"error": "General Error", "message": str(e)}))
|
||||
|
||||
|
||||
def show_caddyfile():
|
||||
caddyfile_path = "/usr/local/etc/caddy/Caddyfile"
|
||||
|
||||
@@ -65,6 +68,7 @@ def show_caddyfile():
|
||||
except Exception as e:
|
||||
print(json.dumps({"error": "General Error", "message": str(e)}))
|
||||
|
||||
|
||||
# Function to extract certificate information using openssl command
|
||||
async def extract_certificate_info(cert_path):
|
||||
try:
|
||||
@@ -105,6 +109,7 @@ async def extract_certificate_info(cert_path):
|
||||
except Exception as e:
|
||||
raise RuntimeError(f"Error extracting certificate info for {cert_path}: {str(e)}")
|
||||
|
||||
|
||||
# Function to find certificates and create tasks to extract info
|
||||
async def find_certificates(base_dir):
|
||||
tasks = []
|
||||
@@ -123,6 +128,7 @@ async def find_certificates(base_dir):
|
||||
results = await asyncio.gather(*tasks, return_exceptions=True)
|
||||
return [result for result in results if not isinstance(result, Exception)]
|
||||
|
||||
|
||||
# Function to show certificates, processing all found in the given directory
|
||||
async def show_certificates():
|
||||
# Function to show certificates, processing all found in the given directory
|
||||
@@ -136,25 +142,26 @@ async def show_certificates():
|
||||
except Exception as e:
|
||||
print(json.dumps({"error": "General Error", "message": str(e)}))
|
||||
|
||||
|
||||
# Action handler
|
||||
def perform_action(action):
|
||||
def perform_action(cmd_action):
|
||||
actions = {
|
||||
"config": show_caddy_config,
|
||||
"caddyfile": show_caddyfile,
|
||||
"certificate": lambda: asyncio.run(show_certificates())
|
||||
}
|
||||
|
||||
action_func = actions.get(action)
|
||||
action_func = actions.get(cmd_action)
|
||||
if action_func:
|
||||
action_func()
|
||||
else:
|
||||
# Output error details in JSON format if action is unknown
|
||||
print(json.dumps({"error": "Unknown Action", "message": f"Unknown action: {action}"}))
|
||||
print(json.dumps({"error": "Unknown Action", "message": f"Unknown action: {cmd_action}"}))
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
if len(sys.argv) > 1:
|
||||
action = sys.argv[1]
|
||||
perform_action(action)
|
||||
perform_action(sys.argv[1])
|
||||
else:
|
||||
# Output error details in JSON format if no action is specified
|
||||
print(json.dumps({"error": "No Action Specified", "message": "No action specified"}))
|
||||
|
||||
@@ -37,11 +37,11 @@
|
||||
#}
|
||||
log {
|
||||
{% if generalSettings.LogAccessPlain|default("0") == "0" %}
|
||||
{% for reverse in helpers.toList('Pischem.caddy.reverseproxy.reverse') %}
|
||||
{% if reverse.enabled|default("0") == "1" and reverse.AccessLog|default("0") == "1" %}
|
||||
include http.log.access.{{ reverse['@uuid'] }}
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
{% for reverse in helpers.toList('Pischem.caddy.reverseproxy.reverse') %}
|
||||
{% if reverse.enabled|default("0") == "1" and reverse.AccessLog|default("0") == "1" %}
|
||||
include http.log.access.{{ reverse['@uuid'] }}
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
output net unixgram//var/caddy/var/run/log {
|
||||
}
|
||||
@@ -49,7 +49,7 @@
|
||||
time_format rfc3339
|
||||
}
|
||||
{% if generalSettings.LogLevel %}
|
||||
level {{ generalSettings.LogLevel }}
|
||||
level {{ generalSettings.LogLevel }}
|
||||
{% endif %}
|
||||
}
|
||||
|
||||
@@ -89,10 +89,10 @@
|
||||
{% if hasAccessList or hasLogCredentials %}
|
||||
servers {
|
||||
{% if hasAccessList %}
|
||||
trusted_proxies static {{ accessList.clientIps.split(',') | join(' ') }}
|
||||
trusted_proxies static {{ accessList.clientIps.split(',') | join(' ') }}
|
||||
{% endif %}
|
||||
{% if hasLogCredentials %}
|
||||
log_credentials
|
||||
log_credentials
|
||||
{% endif %}
|
||||
}
|
||||
{% endif %}
|
||||
@@ -175,11 +175,11 @@
|
||||
{% endif %}
|
||||
domains {
|
||||
{% for domain in dynDnsDomains %}
|
||||
{{ domain }}
|
||||
{{ domain }}
|
||||
{% endfor %}
|
||||
}
|
||||
{% if dynDnsSimpleHttp %}
|
||||
ip_source simple_http {{ dynDnsSimpleHttp }}
|
||||
ip_source simple_http {{ dynDnsSimpleHttp }}
|
||||
{% endif %}
|
||||
{% if dynDnsInterface %}
|
||||
{% set physicalInterfaceNames = [] %}
|
||||
@@ -189,16 +189,16 @@
|
||||
ip_source interface {{ physicalInterfaceNames | join(',') }}
|
||||
{% endif %}
|
||||
{% if dynDnsCheckInterval %}
|
||||
check_interval {{ dynDnsCheckInterval }}s
|
||||
check_interval {{ dynDnsCheckInterval }}s
|
||||
{% endif %}
|
||||
{% if dynDnsIpVersions %}
|
||||
versions {{ dynDnsIpVersions }}
|
||||
versions {{ dynDnsIpVersions }}
|
||||
{% endif %}
|
||||
{% if dynDnsTtl %}
|
||||
ttl {{ dynDnsTtl }}s
|
||||
ttl {{ dynDnsTtl }}s
|
||||
{% endif %}
|
||||
{% if dynDnsUpdateOnly|default("0") == "1" %}
|
||||
update_only
|
||||
update_only
|
||||
{% endif %}
|
||||
}
|
||||
{% endif %}
|
||||
@@ -211,11 +211,11 @@
|
||||
#}
|
||||
{% set emailValue = helpers.toList('Pischem.caddy.general.TlsEmail') | first %}
|
||||
{% if emailValue %}
|
||||
email {{ emailValue }}
|
||||
email {{ emailValue }}
|
||||
{% endif %}
|
||||
{% set autoHttpsValue = helpers.toList('Pischem.caddy.general.TlsAutoHttps') | first %}
|
||||
{% if autoHttpsValue %}
|
||||
auto_https {{ autoHttpsValue }}
|
||||
auto_https {{ autoHttpsValue }}
|
||||
{% endif %}
|
||||
{#
|
||||
# Important: Grace Period influences how fast the server can finish reloads with open connections, by forcing termination.
|
||||
@@ -299,8 +299,8 @@
|
||||
# It uses a 'handle' object that specifies which headers to manipulate based on their @UUIDs.
|
||||
# Each handle can have multiple of these HTTP headers assigned.
|
||||
# Parameters:
|
||||
# @param handle (@object):
|
||||
# - @uuid (@string)
|
||||
# @param handle (object):
|
||||
# - @uuid (string)
|
||||
# - HeaderUpDown (string): Determines the direction of the header.
|
||||
# - HeaderType (string): Specifies the name of the header.
|
||||
# - HeaderValue (string, optional): The new value to set for the header, if any.
|
||||
@@ -341,15 +341,15 @@
|
||||
# Purpose: Sets up the handle with the reverse proxy configurations. The TLS Settings are generated here for the Upstream.
|
||||
# Integrated Macros: header_manipulation
|
||||
# Parameters:
|
||||
# @param handle (@object):
|
||||
# - @uuid (@string)
|
||||
# @param handle (object):
|
||||
# - @uuid (string)
|
||||
# - HandleType (string): Specifies the handling strategy.
|
||||
# - HandlePath (string, optional): The path the handle should match on.
|
||||
# - ToDomain (string): Target domain for the reverse proxy.
|
||||
# - ToPort (string, optional): Target port on the ToDomain.
|
||||
# - ToPath (string, optional): Destination path on the ToDomain.
|
||||
# - HttpTls (boolean, optional): Enable TLS for the connection.
|
||||
# - HttpNtlm (boolean, optional): Enable NTLM authentication for the connection.
|
||||
# - HttpNtlm (boolean, optional): Enable NTLM authentication for the connection. Not all HTTP options apply to NTLM.
|
||||
# - HttpTlsInsecureSkipVerify (boolean, optional): If true, the server's SSL certificate is not verified.
|
||||
# - HttpTlsTrustedCaCerts (string, optional): The config extracted name of a CA certificate.
|
||||
# - HttpTlsServerName (string, optional): Specifies the server name for the TLS handshake.
|
||||
@@ -363,7 +363,7 @@
|
||||
{% include "OPNsense/Caddy/includeAuthProvider" %}
|
||||
{% endif %}
|
||||
{% if handle.ToPath|default("") != "" %}
|
||||
rewrite * {{ handle.ToPath }}{uri}
|
||||
rewrite * {{ handle.ToPath }}{uri}
|
||||
{% endif %}
|
||||
reverse_proxy {% for domain in handle.ToDomain.split(',') %}
|
||||
{# Check if the domain is IPv6 and wrap in square brackets if necessary #}
|
||||
@@ -373,22 +373,22 @@
|
||||
{% endfor %} {
|
||||
{{ header_manipulation(handle) }}
|
||||
{% if handle.PassiveHealthFailDuration|default("") %}
|
||||
fail_duration {{ handle.PassiveHealthFailDuration }}s
|
||||
fail_duration {{ handle.PassiveHealthFailDuration }}s
|
||||
{% endif %}
|
||||
{% if handle.HttpTls|default("0") == "1" or handle.HttpTlsInsecureSkipVerify|default("0") == "1" or handle.HttpTlsTrustedCaCerts or handle.HttpTlsServerName or handle.HttpVersion or handle.HttpKeepalive %}
|
||||
{% if handle.HttpNtlm|default("0") == "1" %}
|
||||
transport http_ntlm {
|
||||
{% if handle.HttpTls|default("0") == "1" %}
|
||||
tls
|
||||
tls
|
||||
{% endif %}
|
||||
{% if handle.HttpTlsInsecureSkipVerify|default("0") == "1" %}
|
||||
tls_insecure_skip_verify
|
||||
tls_insecure_skip_verify
|
||||
{% endif %}
|
||||
{% if handle.HttpTlsTrustedCaCerts %}
|
||||
tls_trust_pool file /var/db/caddy/data/caddy/certificates/temp/{{ handle.HttpTlsTrustedCaCerts }}.pem
|
||||
tls_trust_pool file /var/db/caddy/data/caddy/certificates/temp/{{ handle.HttpTlsTrustedCaCerts }}.pem
|
||||
{% endif %}
|
||||
{% if handle.HttpTlsServerName %}
|
||||
tls_server_name {{ handle.HttpTlsServerName }}
|
||||
tls_server_name {{ handle.HttpTlsServerName }}
|
||||
{% endif %}
|
||||
}
|
||||
{% else %}
|
||||
@@ -406,16 +406,16 @@
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
{% if handle.HttpTls|default("0") == "1" %}
|
||||
tls
|
||||
tls
|
||||
{% endif %}
|
||||
{% if handle.HttpTlsInsecureSkipVerify|default("0") == "1" %}
|
||||
tls_insecure_skip_verify
|
||||
tls_insecure_skip_verify
|
||||
{% endif %}
|
||||
{% if handle.HttpTlsTrustedCaCerts %}
|
||||
tls_trust_pool file /var/db/caddy/data/caddy/certificates/temp/{{ handle.HttpTlsTrustedCaCerts }}.pem
|
||||
tls_trust_pool file /var/db/caddy/data/caddy/certificates/temp/{{ handle.HttpTlsTrustedCaCerts }}.pem
|
||||
{% endif %}
|
||||
{% if handle.HttpTlsServerName %}
|
||||
tls_server_name {{ handle.HttpTlsServerName }}
|
||||
tls_server_name {{ handle.HttpTlsServerName }}
|
||||
{% endif %}
|
||||
}
|
||||
{% endif %}
|
||||
@@ -431,10 +431,10 @@
|
||||
# only get to the reverse proxy, when the access list matches. Invert is also possible, to explicitely deny IPs.
|
||||
# The assembly is handled by the "Section: Reverse Proxy Configurations".
|
||||
# Parameters:
|
||||
# @param accesslist (@object):
|
||||
# - @uuid (@string)
|
||||
# - clientIps (@string): A comma-separated list of client IP addresses
|
||||
# - invert (@boolean): A flag that inverts the logic of the access list
|
||||
# @param accesslist (object):
|
||||
# - uuid (string)
|
||||
# - clientIps (string): A comma-separated list of client IP addresses
|
||||
# - invert (boolean): A flag that inverts the logic of the access list
|
||||
#}
|
||||
{% macro access_list_configuration(accesslist, invert) %}
|
||||
{% set client_ips = accesslist.clientIps.split(',') %}
|
||||
@@ -448,11 +448,11 @@
|
||||
# Macro: basicauth_configuration
|
||||
# Purpose: Implements basic authentication with a username and password for access.
|
||||
# Parameters:
|
||||
# @param basicauth_uuids (@string): A comma-separated list of UUIDs, each UUID corresponding to
|
||||
# @param basicauth_uuids (string): A comma-separated list of UUIDs, each UUID corresponding to
|
||||
# a specific user credentials (username and password).
|
||||
# - @uuid (@string)
|
||||
# - basicauthuser (@string): The username required for authentication.
|
||||
# - basicauthpass (@string): The password associated with the username.
|
||||
# - @uuid (string)
|
||||
# - basicauthuser (string): The username required for authentication.
|
||||
# - basicauthpass (string): The password associated with the username.
|
||||
#}
|
||||
{% macro basicauth_configuration(basicauth_uuids) %}
|
||||
{% if basicauth_uuids %}
|
||||
@@ -482,139 +482,139 @@
|
||||
# - Order of Wildcard Domains and Subdomains: Handles for wildcard domains come after all subdomains.
|
||||
#}
|
||||
{% for reverse in helpers.toList('Pischem.caddy.reverseproxy.reverse') %}
|
||||
{% if reverse.enabled|default("0") == "1" %}
|
||||
# Reverse Proxy Domain: "{{ reverse['@uuid'] }}"
|
||||
{# The default are encrypted connections, uncencrypted connections have to render http:// #}
|
||||
{% if reverse.DisableTls|default("0") == "1" %}http://{% endif %}{{ reverse.FromDomain|default("") }}{% if reverse.FromPort %}:{{ reverse.FromPort }}{% endif %} {
|
||||
{% if reverse.AccessLog|default("0") == "1" %}
|
||||
{% if generalSettings.LogAccessPlain|default("0") == "0" %}
|
||||
log {{ reverse['@uuid'] }}
|
||||
{% else %}
|
||||
log {
|
||||
output file /var/log/caddy/access/{{ reverse['@uuid'] }}.log {
|
||||
roll_keep_for {{ generalSettings.LogAccessPlainKeep|default("10") }}d
|
||||
}
|
||||
}
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
{% set customCert = reverse.CustomCertificate|default("") %}
|
||||
{% set dnsChallenge = reverse.DnsChallenge|default("0") %}
|
||||
{{ tls_configuration(dnsProvider, dnsApiKey, customCert, dnsChallenge, dnsSecretApiKey, TlsDnsOptionalField1, TlsDnsOptionalField2, TlsDnsOptionalField3, TlsDnsOptionalField4) }}
|
||||
|
||||
{% if not reverse.accesslist %}
|
||||
{% set basicauth_uuids = reverse.basicauth %}
|
||||
{{ basicauth_configuration(basicauth_uuids) }}
|
||||
{% endif %}
|
||||
|
||||
{% for subdomain in helpers.toList('Pischem.caddy.reverseproxy.subdomain') %}
|
||||
{% if subdomain.enabled|default("0") == "1" and subdomain.reverse == reverse['@uuid'] %}
|
||||
@{{ subdomain['@uuid'] }} {
|
||||
host {{ subdomain.FromDomain }}
|
||||
}
|
||||
handle @{{ subdomain['@uuid'] }} {
|
||||
|
||||
{% if not subdomain.accesslist %}
|
||||
{% set subdomain_basicauth_uuids = subdomain.basicauth %}
|
||||
{{ basicauth_configuration(subdomain_basicauth_uuids) }}
|
||||
{% endif %}
|
||||
|
||||
{% if subdomain.accesslist %}
|
||||
{% set accesslist = helpers.toList('Pischem.caddy.reverseproxy.accesslist') | selectattr('@uuid', 'equalto', subdomain.accesslist) | first %}
|
||||
{{ access_list_configuration(accesslist, accesslist.accesslistInvert|default("0") == "1") }}
|
||||
handle @{{ accesslist['@uuid'] }} {
|
||||
|
||||
{% set subdomain_basicauth_uuids = subdomain.basicauth %}
|
||||
{{ basicauth_configuration(subdomain_basicauth_uuids) }}
|
||||
|
||||
{% set subdomain_handles = helpers.toList('Pischem.caddy.reverseproxy.handle') | selectattr('subdomain', 'equalto', subdomain['@uuid']) | list %}
|
||||
{% for handle in subdomain_handles %}
|
||||
{% if handle.enabled|default("0") == "1" and handle.HandlePath %}
|
||||
{{ reverse_proxy_configuration(handle) }}
|
||||
{% if reverse.enabled|default("0") == "1" %}
|
||||
# Reverse Proxy Domain: "{{ reverse['@uuid'] }}"
|
||||
{# The default are encrypted connections, uncencrypted connections have to render http:// #}
|
||||
{% if reverse.DisableTls|default("0") == "1" %}http://{% endif %}{{ reverse.FromDomain|default("") }}{% if reverse.FromPort %}:{{ reverse.FromPort }}{% endif %} {
|
||||
{% if reverse.AccessLog|default("0") == "1" %}
|
||||
{% if generalSettings.LogAccessPlain|default("0") == "0" %}
|
||||
log {{ reverse['@uuid'] }}
|
||||
{% else %}
|
||||
log {
|
||||
output file /var/log/caddy/access/{{ reverse['@uuid'] }}.log {
|
||||
roll_keep_for {{ generalSettings.LogAccessPlainKeep|default("10") }}d
|
||||
}
|
||||
}
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
{% set customCert = reverse.CustomCertificate|default("") %}
|
||||
{% set dnsChallenge = reverse.DnsChallenge|default("0") %}
|
||||
{{ tls_configuration(dnsProvider, dnsApiKey, customCert, dnsChallenge, dnsSecretApiKey, TlsDnsOptionalField1, TlsDnsOptionalField2, TlsDnsOptionalField3, TlsDnsOptionalField4) }}
|
||||
|
||||
{% if not reverse.accesslist %}
|
||||
{% set basicauth_uuids = reverse.basicauth %}
|
||||
{{ basicauth_configuration(basicauth_uuids) }}
|
||||
{% endif %}
|
||||
|
||||
{% for subdomain in helpers.toList('Pischem.caddy.reverseproxy.subdomain') %}
|
||||
{% if subdomain.enabled|default("0") == "1" and subdomain.reverse == reverse['@uuid'] %}
|
||||
@{{ subdomain['@uuid'] }} {
|
||||
host {{ subdomain.FromDomain }}
|
||||
}
|
||||
handle @{{ subdomain['@uuid'] }} {
|
||||
|
||||
{% if not subdomain.accesslist %}
|
||||
{% set subdomain_basicauth_uuids = subdomain.basicauth %}
|
||||
{{ basicauth_configuration(subdomain_basicauth_uuids) }}
|
||||
{% endif %}
|
||||
|
||||
{% if subdomain.accesslist %}
|
||||
{% set accesslist = helpers.toList('Pischem.caddy.reverseproxy.accesslist') | selectattr('@uuid', 'equalto', subdomain.accesslist) | first %}
|
||||
{{ access_list_configuration(accesslist, accesslist.accesslistInvert|default("0") == "1") }}
|
||||
handle @{{ accesslist['@uuid'] }} {
|
||||
|
||||
{% set subdomain_basicauth_uuids = subdomain.basicauth %}
|
||||
{{ basicauth_configuration(subdomain_basicauth_uuids) }}
|
||||
|
||||
{% set subdomain_handles = helpers.toList('Pischem.caddy.reverseproxy.handle') | selectattr('subdomain', 'equalto', subdomain['@uuid']) | list %}
|
||||
{% for handle in subdomain_handles %}
|
||||
{% if handle.enabled|default("0") == "1" and handle.HandlePath %}
|
||||
{{ reverse_proxy_configuration(handle) }}
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
{% for handle in subdomain_handles %}
|
||||
{% if handle.enabled|default("0") == "1" and not handle.HandlePath %}
|
||||
{{ reverse_proxy_configuration(handle) }}
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
}
|
||||
{% else %}
|
||||
{% set subdomain_handles = helpers.toList('Pischem.caddy.reverseproxy.handle') | selectattr('subdomain', 'equalto', subdomain['@uuid']) | list %}
|
||||
{% for handle in subdomain_handles %}
|
||||
{% if handle.enabled|default("0") == "1" and handle.HandlePath %}
|
||||
{{ reverse_proxy_configuration(handle) }}
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
{% for handle in subdomain_handles %}
|
||||
{% if handle.enabled|default("0") == "1" and not handle.HandlePath %}
|
||||
{{ reverse_proxy_configuration(handle) }}
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
|
||||
{% if subdomain.accesslist %}
|
||||
{% if accesslist.HttpResponseCode or accesslist.HttpResponseMessage %}
|
||||
respond {{ '"' + accesslist.HttpResponseMessage|default('') + '"' if accesslist.HttpResponseMessage else '' }} {{ accesslist.HttpResponseCode|default(403) }}
|
||||
{% elif Pischem.caddy.general.abort|default("0") == "1" %}
|
||||
abort
|
||||
{% endif %}
|
||||
{% else %}
|
||||
{% if Pischem.caddy.general.abort|default("0") == "1" %}
|
||||
abort
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
}
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
{% for handle in subdomain_handles %}
|
||||
{% if handle.enabled|default("0") == "1" and not handle.HandlePath %}
|
||||
{{ reverse_proxy_configuration(handle) }}
|
||||
|
||||
{% if reverse.accesslist %}
|
||||
{% set accesslist = helpers.toList('Pischem.caddy.reverseproxy.accesslist') | selectattr('@uuid', 'equalto', reverse.accesslist) | first %}
|
||||
{{ access_list_configuration(accesslist, accesslist.accesslistInvert|default("0") == "1") }}
|
||||
handle @{{ accesslist['@uuid'] }} {
|
||||
|
||||
{% set basicauth_uuids = reverse.basicauth %}
|
||||
{{ basicauth_configuration(basicauth_uuids) }}
|
||||
|
||||
{% set wildcard_handles = helpers.toList('Pischem.caddy.reverseproxy.handle') | selectattr('reverse', 'equalto', reverse['@uuid']) | selectattr('subdomain', 'undefined') | list %}
|
||||
{% for handle in wildcard_handles %}
|
||||
{% if handle.enabled|default("0") == "1" and handle.HandlePath %}
|
||||
{{ reverse_proxy_configuration(handle) }}
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
{% for handle in wildcard_handles %}
|
||||
{% if handle.enabled|default("0") == "1" and not handle.HandlePath %}
|
||||
{{ reverse_proxy_configuration(handle) }}
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
}
|
||||
{% else %}
|
||||
{% set wildcard_handles = helpers.toList('Pischem.caddy.reverseproxy.handle') | selectattr('reverse', 'equalto', reverse['@uuid']) | selectattr('subdomain', 'undefined') | list %}
|
||||
{% for handle in wildcard_handles %}
|
||||
{% if handle.enabled|default("0") == "1" and handle.HandlePath %}
|
||||
{{ reverse_proxy_configuration(handle) }}
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
{% for handle in wildcard_handles %}
|
||||
{% if handle.enabled|default("0") == "1" and not handle.HandlePath %}
|
||||
{{ reverse_proxy_configuration(handle) }}
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
|
||||
{% set accesslist = helpers.toList('Pischem.caddy.reverseproxy.accesslist') | selectattr('@uuid', 'equalto', reverse.accesslist) | first %}
|
||||
{% if accesslist %}
|
||||
{% if accesslist.HttpResponseCode or accesslist.HttpResponseMessage %}
|
||||
respond {{ '"' + accesslist.HttpResponseMessage|default('') + '"' if accesslist.HttpResponseMessage else '' }} {{ accesslist.HttpResponseCode|default(403) }}
|
||||
{% elif Pischem.caddy.general.abort|default("0") == "1" %}
|
||||
abort
|
||||
{% endif %}
|
||||
{% else %}
|
||||
{% if Pischem.caddy.general.abort|default("0") == "1" %}
|
||||
abort
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
}
|
||||
{% else %}
|
||||
{% set subdomain_handles = helpers.toList('Pischem.caddy.reverseproxy.handle') | selectattr('subdomain', 'equalto', subdomain['@uuid']) | list %}
|
||||
{% for handle in subdomain_handles %}
|
||||
{% if handle.enabled|default("0") == "1" and handle.HandlePath %}
|
||||
{{ reverse_proxy_configuration(handle) }}
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
{% for handle in subdomain_handles %}
|
||||
{% if handle.enabled|default("0") == "1" and not handle.HandlePath %}
|
||||
{{ reverse_proxy_configuration(handle) }}
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
|
||||
{% if subdomain.accesslist %}
|
||||
{% if accesslist.HttpResponseCode or accesslist.HttpResponseMessage %}
|
||||
respond {{ '"' + accesslist.HttpResponseMessage|default('') + '"' if accesslist.HttpResponseMessage else '' }} {{ accesslist.HttpResponseCode|default(403) }}
|
||||
{% elif Pischem.caddy.general.abort|default("0") == "1" %}
|
||||
abort
|
||||
{% endif %}
|
||||
{% else %}
|
||||
{% if Pischem.caddy.general.abort|default("0") == "1" %}
|
||||
abort
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
}
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
|
||||
{% if reverse.accesslist %}
|
||||
{% set accesslist = helpers.toList('Pischem.caddy.reverseproxy.accesslist') | selectattr('@uuid', 'equalto', reverse.accesslist) | first %}
|
||||
{{ access_list_configuration(accesslist, accesslist.accesslistInvert|default("0") == "1") }}
|
||||
handle @{{ accesslist['@uuid'] }} {
|
||||
|
||||
{% set basicauth_uuids = reverse.basicauth %}
|
||||
{{ basicauth_configuration(basicauth_uuids) }}
|
||||
|
||||
{% set wildcard_handles = helpers.toList('Pischem.caddy.reverseproxy.handle') | selectattr('reverse', 'equalto', reverse['@uuid']) | selectattr('subdomain', 'undefined') | list %}
|
||||
{% for handle in wildcard_handles %}
|
||||
{% if handle.enabled|default("0") == "1" and handle.HandlePath %}
|
||||
{{ reverse_proxy_configuration(handle) }}
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
{% for handle in wildcard_handles %}
|
||||
{% if handle.enabled|default("0") == "1" and not handle.HandlePath %}
|
||||
{{ reverse_proxy_configuration(handle) }}
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
}
|
||||
{% else %}
|
||||
{% set wildcard_handles = helpers.toList('Pischem.caddy.reverseproxy.handle') | selectattr('reverse', 'equalto', reverse['@uuid']) | selectattr('subdomain', 'undefined') | list %}
|
||||
{% for handle in wildcard_handles %}
|
||||
{% if handle.enabled|default("0") == "1" and handle.HandlePath %}
|
||||
{{ reverse_proxy_configuration(handle) }}
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
{% for handle in wildcard_handles %}
|
||||
{% if handle.enabled|default("0") == "1" and not handle.HandlePath %}
|
||||
{{ reverse_proxy_configuration(handle) }}
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
|
||||
{% set accesslist = helpers.toList('Pischem.caddy.reverseproxy.accesslist') | selectattr('@uuid', 'equalto', reverse.accesslist) | first %}
|
||||
{% if accesslist %}
|
||||
{% if accesslist.HttpResponseCode or accesslist.HttpResponseMessage %}
|
||||
respond {{ '"' + accesslist.HttpResponseMessage|default('') + '"' if accesslist.HttpResponseMessage else '' }} {{ accesslist.HttpResponseCode|default(403) }}
|
||||
{% elif Pischem.caddy.general.abort|default("0") == "1" %}
|
||||
abort
|
||||
{% endif %}
|
||||
{% else %}
|
||||
{% if Pischem.caddy.general.abort|default("0") == "1" %}
|
||||
abort
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
}
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
|
||||
import /usr/local/etc/caddy/caddy.d/*.conf
|
||||
|
||||
@@ -1,13 +1,8 @@
|
||||
# DO NOT EDIT THIS FILE -- OPNsense auto-generated file
|
||||
{% if helpers.exists('Pischem.caddy.general.enabled') %}
|
||||
{%- set general_enabled = helpers.toList('Pischem.caddy.general.enabled') | first %}
|
||||
{%- if general_enabled == '1' %}
|
||||
{% set generalSettings = helpers.getNodeByTag('Pischem.caddy.general') %}
|
||||
{% if generalSettings.enabled|default("0") == "1" %}
|
||||
caddy_enable="YES"
|
||||
# Path to the Caddy setup script
|
||||
caddy_setup="/usr/local/opnsense/scripts/OPNsense/Caddy/setup.sh"
|
||||
{%- else %}
|
||||
caddy_enable="NO"
|
||||
{%- endif %}
|
||||
{%- else %}
|
||||
{% else %}
|
||||
caddy_enable="NO"
|
||||
{% endif %}
|
||||
|
||||
Reference in New Issue
Block a user