diff --git a/www/caddy/src/opnsense/mvc/app/controllers/OPNsense/Caddy/Api/DiagnosticsController.php b/www/caddy/src/opnsense/mvc/app/controllers/OPNsense/Caddy/Api/DiagnosticsController.php new file mode 100644 index 000000000..d0d711f60 --- /dev/null +++ b/www/caddy/src/opnsense/mvc/app/controllers/OPNsense/Caddy/Api/DiagnosticsController.php @@ -0,0 +1,92 @@ +configdRun('caddy config'); + + // 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']]; + } + + // Prepare the response array + $response = ['status' => 'success', 'content' => $responseArray]; + // Set the content type + $this->response->setContentType('application/json', 'UTF-8'); + // Encode and set the content + $this->response->setContent(json_encode($response, JSON_PRETTY_PRINT)); + + return $this->response; + } + + /** + * Fetch and display the contents of the Caddyfile as JSON. + */ + public function caddyfileAction() + { + $backend = new Backend(); + $response = $backend->configdRun('caddy caddyfile'); + + // Decode JSON to PHP array + $responseArray = json_decode($response, true); + + if (isset($responseArray['error'])) { + // Handle the error + return ["status" => "failed", "message" => $responseArray['message']]; + } + + // Assuming the response structure is like { "content": "actual Caddyfile content here" } + if (!isset($responseArray['content'])) { + return ["status" => "failed", "message" => "Caddyfile content not found"]; + } + + // Return the response as an array which gets automatically encoded to JSON + return ["status" => "success", "content" => $responseArray['content']]; + } +} diff --git a/www/caddy/src/opnsense/mvc/app/controllers/OPNsense/Caddy/DiagnosticsController.php b/www/caddy/src/opnsense/mvc/app/controllers/OPNsense/Caddy/DiagnosticsController.php new file mode 100644 index 000000000..55e7bbcc6 --- /dev/null +++ b/www/caddy/src/opnsense/mvc/app/controllers/OPNsense/Caddy/DiagnosticsController.php @@ -0,0 +1,41 @@ +view->pick('OPNsense/Caddy/diagnostics'); + } +} diff --git a/www/caddy/src/opnsense/mvc/app/models/OPNsense/Caddy/ACL/ACL.xml b/www/caddy/src/opnsense/mvc/app/models/OPNsense/Caddy/ACL/ACL.xml index c98f84a7e..cea3a9cc5 100644 --- a/www/caddy/src/opnsense/mvc/app/models/OPNsense/Caddy/ACL/ACL.xml +++ b/www/caddy/src/opnsense/mvc/app/models/OPNsense/Caddy/ACL/ACL.xml @@ -15,4 +15,12 @@ api/caddy/reverse_proxy/* + + Services: Caddy Web Server: Diagnostics + Allow access to Caddy Diagnostics + + ui/caddy/diagnostics/* + api/caddy/diagnostics/* + + diff --git a/www/caddy/src/opnsense/mvc/app/models/OPNsense/Caddy/Menu/Menu.xml b/www/caddy/src/opnsense/mvc/app/models/OPNsense/Caddy/Menu/Menu.xml index 60886d550..70d146ffe 100644 --- a/www/caddy/src/opnsense/mvc/app/models/OPNsense/Caddy/Menu/Menu.xml +++ b/www/caddy/src/opnsense/mvc/app/models/OPNsense/Caddy/Menu/Menu.xml @@ -3,7 +3,8 @@ - + + diff --git a/www/caddy/src/opnsense/mvc/app/views/OPNsense/Caddy/diagnostics.volt b/www/caddy/src/opnsense/mvc/app/views/OPNsense/Caddy/diagnostics.volt new file mode 100644 index 000000000..b42a37741 --- /dev/null +++ b/www/caddy/src/opnsense/mvc/app/views/OPNsense/Caddy/diagnostics.volt @@ -0,0 +1,194 @@ +{# + # Copyright (c) 2024 Cedrik Pischem + # All rights reserved. + # + # Redistribution and use in source and binary forms, with or without modification, + # are permitted provided that the following conditions are met: + # + # 1. Redistributions of source code must retain the above copyright notice, + # this list of conditions and the following disclaimer. + # + # 2. Redistributions in binary form must reproduce the above copyright notice, + # this list of conditions and the following disclaimer in the documentation + # and/or other materials provided with the distribution. + # + # THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, + # INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY + # AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + # AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, + # OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + # SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + # INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + # 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. + #} + + + + + + + + + +
+ +
+
+

+            

{{ lang._("This is the generated configuration located at %sCaddyfile%s. It's the main configuration file to get support with. The validation button triggers a manual check for any configuration errors, which is the same check that is triggered by the Apply buttons automatically.") | format('/usr/local/etc/caddy/', '') }}

+ + +

+
+
+ +
+
+

+            

{{ lang._("Shows the running Caddy configuration located in %sautosave.json%s. It is automatically adapted from the Caddyfile and also includes any custom imported configurations from %scaddy.d%s.") | format('/var/db/caddy/config/caddy/', '', '/usr/local/etc/caddy/', '') }}

+ +

+
+
+
diff --git a/www/caddy/src/opnsense/scripts/OPNsense/Caddy/caddy_diagnostics.py b/www/caddy/src/opnsense/scripts/OPNsense/Caddy/caddy_diagnostics.py new file mode 100755 index 000000000..ec1e2d13f --- /dev/null +++ b/www/caddy/src/opnsense/scripts/OPNsense/Caddy/caddy_diagnostics.py @@ -0,0 +1,86 @@ +#!/usr/local/bin/python3 + +# +# Copyright (c) 2024 Cedrik Pischem +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without modification, +# are permitted provided that the following conditions are met: +# +# 1. Redistributions of source code must retain the above copyright notice, +# this list of conditions and the following disclaimer. +# +# 2. Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, +# INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY +# AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +# AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, +# OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +# 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. +# + +import sys +import json + +# Function to show the Caddy configuration from a JSON file +def show_caddy_config(): + config_path = "/var/db/caddy/config/caddy/autosave.json" + + try: + # Open and read the JSON configuration file directly into a Python dictionary + with open(config_path, "r") as file: + config_data = json.load(file) # Load the JSON directly + + # Print the JSON to stdout using json.dumps to ensure it's a JSON string and nicely formatted + print(json.dumps(config_data)) # Output the JSON directly + # Output error details in JSON format so that the API can consume them + 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"})) + except Exception as e: + print(json.dumps({"error": "General Error", "message": str(e)})) + +def show_caddyfile(): + caddyfile_path = "/usr/local/etc/caddy/Caddyfile" + + try: + with open(caddyfile_path, "r") as file: + caddyfile_data = file.read() + # Output the Caddyfile data directly as a JSON object with a generic key like "content" + print(json.dumps({"content": caddyfile_data})) + except FileNotFoundError: + print(json.dumps({"error": "Caddyfile not found", "message": "Caddyfile not found"})) + except Exception as e: + print(json.dumps({"error": "General Error", "message": str(e)})) + +# Action handler +def perform_action(action): + actions = { + "config": show_caddy_config, + "caddyfile": show_caddyfile + # Additional actions can be added here in the same format. + } + + action_func = actions.get(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}"})) + +if __name__ == "__main__": + if len(sys.argv) > 1: + action = sys.argv[1] + perform_action(action) + else: + # Output error details in JSON format if no action is specified + print(json.dumps({"error": "No Action Specified", "message": "No action specified"})) + diff --git a/www/caddy/src/opnsense/service/conf/actions.d/actions_caddy.conf b/www/caddy/src/opnsense/service/conf/actions.d/actions_caddy.conf index cd5f1b2f6..0d768ce42 100644 --- a/www/caddy/src/opnsense/service/conf/actions.d/actions_caddy.conf +++ b/www/caddy/src/opnsense/service/conf/actions.d/actions_caddy.conf @@ -35,3 +35,15 @@ command:/usr/local/sbin/pluginctl -s caddy status parameters: type:script_output message:Request Caddy status + +[config] +command:/usr/local/opnsense/scripts/OPNsense/Caddy/caddy_diagnostics.py config +parameters: +type:script_output +message:Request Caddy JSON configuration + +[caddyfile] +command:/usr/local/opnsense/scripts/OPNsense/Caddy/caddy_diagnostics.py caddyfile +parameters: +type:script_output +message:Request Caddyfile