From 1a977d47fd2cf7b563c96a3a4f7b25b887aed87f Mon Sep 17 00:00:00 2001 From: Jared Hendrickson Date: Wed, 4 May 2022 23:00:34 -0600 Subject: [PATCH 1/8] Add /api/v1/interface/available endpoint to read details about available interfaces. (#216) --- .../api/endpoints/APIInterfaceAvailable.inc | 26 ++++++++++++++++ .../api/models/APIInterfaceAvailableRead.inc | 31 +++++++++++++++++++ .../local/www/api/documentation/openapi.yml | 16 ++++++++++ tests/test_api_v1_interface_available.py | 21 +++++++++++++ 4 files changed, 94 insertions(+) create mode 100644 pfSense-pkg-API/files/etc/inc/api/endpoints/APIInterfaceAvailable.inc create mode 100644 pfSense-pkg-API/files/etc/inc/api/models/APIInterfaceAvailableRead.inc create mode 100644 tests/test_api_v1_interface_available.py diff --git a/pfSense-pkg-API/files/etc/inc/api/endpoints/APIInterfaceAvailable.inc b/pfSense-pkg-API/files/etc/inc/api/endpoints/APIInterfaceAvailable.inc new file mode 100644 index 000000000..9fdc34713 --- /dev/null +++ b/pfSense-pkg-API/files/etc/inc/api/endpoints/APIInterfaceAvailable.inc @@ -0,0 +1,26 @@ +url = "/api/v1/interface/available"; + } + + protected function get() { + return (new APIInterfaceAvailableRead())->call(); + } +} diff --git a/pfSense-pkg-API/files/etc/inc/api/models/APIInterfaceAvailableRead.inc b/pfSense-pkg-API/files/etc/inc/api/models/APIInterfaceAvailableRead.inc new file mode 100644 index 000000000..78c162b0e --- /dev/null +++ b/pfSense-pkg-API/files/etc/inc/api/models/APIInterfaceAvailableRead.inc @@ -0,0 +1,31 @@ +privileges = ["page-all", "page-interfaces-assignnetworkports"]; + + } + + public function action() { + return APIResponse\get(0, APITools\get_all_avail_interfaces()); + } +} diff --git a/pfSense-pkg-API/files/usr/local/www/api/documentation/openapi.yml b/pfSense-pkg-API/files/usr/local/www/api/documentation/openapi.yml index 6c3d37b8c..37dda338b 100644 --- a/pfSense-pkg-API/files/usr/local/www/api/documentation/openapi.yml +++ b/pfSense-pkg-API/files/usr/local/www/api/documentation/openapi.yml @@ -4628,6 +4628,21 @@ paths: summary: Update interface tags: - Interface + /api/v1/interface/available: + get: + description: 'Read all interfaces available on the system. This will provide details for all interfaces regardless + if they are currently configured on pfSense.

+ + + _Requires at least one of the following privileges:_ [`page-all`, `page-interfaces-assignnetworkports`]' + responses: + 200: + $ref: '#/components/responses/Success' + 401: + $ref: '#/components/responses/AuthenticationFailed' + summary: Read all available interfaces + tags: + - Interface > Available /api/v1/interface/apply: post: description: 'Apply pending interface changes.

@@ -9338,6 +9353,7 @@ tags: - name: User > Group - name: User > Group > Member - name: Interface + - name: Interface > Available - name: Interface > Bridge - name: Interface > VLAN - name: Interface > Apply diff --git a/tests/test_api_v1_interface_available.py b/tests/test_api_v1_interface_available.py new file mode 100644 index 000000000..7a0678ae5 --- /dev/null +++ b/tests/test_api_v1_interface_available.py @@ -0,0 +1,21 @@ +# Copyright 2022 Jared Hendrickson +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import e2e_test_framework + +class APIE2ETestInterfaceAvailable(e2e_test_framework.APIE2ETest): + uri = "/api/v1/interface/available" + get_tests = [{"name": "Read all available interface"}] + +APIE2ETestInterfaceAvailable() From 4efca2d681708b624de6aa668156b23e669726c7 Mon Sep 17 00:00:00 2001 From: Jared Hendrickson Date: Thu, 5 May 2022 20:04:12 -0600 Subject: [PATCH 2/8] Fixed issue that prevented the /api/v1/system/package endpoint from successfully correctly installing pfSense packages. --- .../etc/inc/api/framework/APIResponse.inc | 16 +- .../inc/api/models/APISystemPackageCreate.inc | 154 +++--------------- .../inc/api/models/APISystemPackageDelete.inc | 13 +- .../local/www/api/documentation/openapi.yml | 16 +- tests/test_api_v1_system_package.py | 77 +-------- 5 files changed, 28 insertions(+), 248 deletions(-) diff --git a/pfSense-pkg-API/files/etc/inc/api/framework/APIResponse.inc b/pfSense-pkg-API/files/etc/inc/api/framework/APIResponse.inc index 5f077b51a..98dc613a3 100644 --- a/pfSense-pkg-API/files/etc/inc/api/framework/APIResponse.inc +++ b/pfSense-pkg-API/files/etc/inc/api/framework/APIResponse.inc @@ -569,21 +569,9 @@ function get($id, $data=[], $all=false) { ], 1077 => [ "status" => "bad request", - "code" => 400, - "return" => $id, - "message" => "Remote URL does not contain a pfSense package" - ], - 1078 => [ - "status" => "bad request", - "code" => 504, - "return" => $id, - "message" => "System package installation exceeded timeout" - ], - 1079 => [ - "status" => "bad request", - "code" => 400, + "code" => 500, "return" => $id, - "message" => "System package installation timeout cannot be greater than 120 seconds" + "message" => "System package failed to install" ], 1080 => [ "status" => "bad request", diff --git a/pfSense-pkg-API/files/etc/inc/api/models/APISystemPackageCreate.inc b/pfSense-pkg-API/files/etc/inc/api/models/APISystemPackageCreate.inc index b1712516d..fac55cc2b 100644 --- a/pfSense-pkg-API/files/etc/inc/api/models/APISystemPackageCreate.inc +++ b/pfSense-pkg-API/files/etc/inc/api/models/APISystemPackageCreate.inc @@ -18,8 +18,6 @@ require_once("api/framework/APIResponse.inc"); class APISystemPackageCreate extends APIModel { - public $pkg_mode; - # Create our method constructor public function __construct() { parent::__construct(); @@ -28,32 +26,35 @@ class APISystemPackageCreate extends APIModel { } public function action() { - return APIResponse\get($this->install_pkg()); + # Force the action to be logged in the configuration history if our API response code is success + if (pkg_install($this->validated_data["name"])) { + return APIResponse\get(0); + } else { + return APIResponse\get(1077); + } } public function validate_payload(){ - $this->__validate_force(); // Must run before __validate_name $this->__validate_name(); - $this->__validate_timeout(); } - # Attempts to install the package specified in $this->validated_data["name"] - public function install_pkg() { - # Format and execute our pkg command. Enforce a timeout to prevent gateway timeouts. - $pkg_force = ($this->validated_data["force"]) ? " -f" : ""; - $pkg_y = ($this->pkg_mode === "install") ? " -y" : ""; - $pkg_cmd = "pkg ".$this->pkg_mode.$pkg_y.$pkg_force." ".$this->validated_data["name"]." 2>&1"; - exec("timeout ".$this->validated_data["timeout"]." ".$pkg_cmd, $pkg_out, $pkg_rc); - - # Check for known errors - $api_rc = $this->__check_pkg_install($pkg_out, $pkg_rc); - - # Force the action to be logged in the configuration history if our API response code is success - if ($api_rc === 0) { - $this->write_config(); + private function __validate_name() { + # Check for our required name input + if (isset($this->initial_data["name"])) { + # Ensure this package exists in pfSense's repos + if ($this->is_pkg_in_repo($this->initial_data["name"])) { + # Ensure package is not already installed + if (!is_pkg_installed($this->initial_data["name"])) { + $this->validated_data["name"] = $this->initial_data["name"]; + } else { + $this->errors[] = APIResponse\get(1076); + } + } else { + $this->errors[] = APIResponse\get(1075); + } + } else { + $this->errors[] = APIResponse\get(1073); } - - return $api_rc; } # Checks pfSense's upstream package repo for a package by name. Requires upstream internet connection. @@ -74,115 +75,4 @@ class APISystemPackageCreate extends APIModel { return false; } - - private function __validate_name() { - # Check for our required name input - if (isset($this->initial_data["name"])) { - # Check if this is a remote/third-party package to be installed by URL - if (filter_var($this->initial_data["name"], FILTER_VALIDATE_URL)) { - # Set pkg add to install package from URL - $this->pkg_mode = "add"; - $this->validated_data["name"] = filter_var($this->initial_data["name"], FILTER_VALIDATE_URL); - } - # Otherwise, we will assume this package exists in pfSense's package repos - else { - # Set pkg install to install the package from pfSense's repos - $this->pkg_mode = "install"; - - # Ensure this package exists in pfSense's repos - if ($this->is_pkg_in_repo($this->initial_data["name"])) { - # Ensure package is not already installed - if (!is_pkg_installed($this->initial_data["name"]) or $this->validated_data["force"]) { - $this->validated_data["name"] = $this->initial_data["name"]; - } else { - $this->errors[] = APIResponse\get(1076); - } - } else { - $this->errors[] = APIResponse\get(1075); - } - - } - } else { - $this->errors[] = APIResponse\get(1073); - } - } - - private function __validate_force() { - # Check for our optional force input - if ($this->initial_data["force"] === true) { - $this->validated_data["force"] = true; - } - } - - private function __validate_timeout() { - # Check for our optional timeout input - if (isset($this->initial_data["timeout"])) { - # Require timeout value to be 120 seconds or less - if (is_numeric($this->initial_data["timeout"]) and intval($this->initial_data["timeout"]) <= 120) { - # Force timeouts less than 5 to minimum of 5 seconds - if (intval($this->initial_data["timeout"]) < 5) { - $this->initial_data["timeout"] = 5; - } - - $this->validated_data["timeout"] = intval($this->initial_data["timeout"]); - } else { - $this->errors[] = APIResponse\get(1079); - } - } else { - $this->validated_data["timeout"] = 90; - } - } - - # This function is intended to take the output of our pkg add or install command and check for failures. - # Returns the corresponding API response ID. - # TODO: matching text based error messages is prone to breaking as the pkg cli tool changes. As of now, pkg does - # TODO: not return unique return codes for specific errors. Re-evaluate as time goes and refactor when a better way - # TODO: is made available. - private function __check_pkg_install($pkg_out, $pkg_rc) { - # Check if our package installation timed out - if ($pkg_rc === 124) { - return 1078; - } - - # Loop through each line of the pkg output and check for known error messages - foreach ($pkg_out as $pkg_line) { - # Check for 'pkg install' no matching package in repository error - if (APITools\str_starts_with("pkg: No packages available to install matching", $pkg_line)) { - return 1075; - } - # Check for 'pkg install' most recent version is already installed error - elseif (APITools\str_starts_with("The most recent versions of packages are already installed", $pkg_line)) { - return 1076; - } - # Check for 'pkg add' most recent version is already installed error - elseif (APITools\str_starts_with("the most recent version of", $pkg_line)) { - return 1076; - } - # Check for 'pkg add' no package file found at URL error - elseif (APITools\str_ends_with(": Not Found", $pkg_line)) { - return 1075; - } - # Check for 'pkg add' URL does not contain package file error - elseif (APITools\str_ends_with(": Unrecognized archive format", $pkg_line)) { - return 1077; - } - # Check for 'pkg add' DNS resolution error - elseif (APITools\str_ends_with(": No address record", $pkg_line)) { - return 13; - } - # Check for 'pkg add' URL unreachable error - elseif (APITools\str_ends_with(": Network is unreachable", $pkg_line)) { - return 13; - } - } - - # When no known error messages were matched, but the pkg command still failed, return unexpected error - if ($pkg_rc !== 0) { - return 1; - } - # Otherwise, our package installation appears to be successful - else { - return 0; - } - } } diff --git a/pfSense-pkg-API/files/etc/inc/api/models/APISystemPackageDelete.inc b/pfSense-pkg-API/files/etc/inc/api/models/APISystemPackageDelete.inc index 7ec48f9b0..f6e42d956 100644 --- a/pfSense-pkg-API/files/etc/inc/api/models/APISystemPackageDelete.inc +++ b/pfSense-pkg-API/files/etc/inc/api/models/APISystemPackageDelete.inc @@ -26,7 +26,8 @@ class APISystemPackageDelete extends APIModel { } public function action() { - $this->delete_pkg(); + uninstall_package($this->validated_data["name"]); + $this->write_config(); return APIResponse\get(0); } @@ -34,16 +35,6 @@ class APISystemPackageDelete extends APIModel { $this->__validate_name(); } - # Deletes the package specified in $this->validated_data["name"] - public function delete_pkg() { - # Remove the requested package and clean up dependencies afterwards - pkg_call("delete -y " . $this->validated_data["name"]); - pkg_call("autoremove -y"); - - # Force the action to be logged in the configuration history - $this->write_config(); - } - private function __validate_name() { # Check for our required name input if (isset($this->initial_data["name"])) { diff --git a/pfSense-pkg-API/files/usr/local/www/api/documentation/openapi.yml b/pfSense-pkg-API/files/usr/local/www/api/documentation/openapi.yml index 6c3d37b8c..f36b110c8 100644 --- a/pfSense-pkg-API/files/usr/local/www/api/documentation/openapi.yml +++ b/pfSense-pkg-API/files/usr/local/www/api/documentation/openapi.yml @@ -8470,24 +8470,10 @@ paths: application/json: schema: properties: - force: - default: false - description: Force the installation of the package. Forced installs - will always force the package to re-install and bypasses certain - warnings. Use extreme caution when using forced installs. - type: boolean name: description: Name of pfSense package to install. This must be the - pfSense package internal name including the `pfSense-pkg-` prefix - or a URL to an external package. + pfSense package internal name including the `pfSense-pkg-` prefix. type: string - timeout: - default: 90 - description: Amount of time (in seconds) to allow the package installation - to take before timing out. - maximum: 120 - minimum: 5 - type: integer required: - name type: object diff --git a/tests/test_api_v1_system_package.py b/tests/test_api_v1_system_package.py index 9218cf662..61c092f69 100644 --- a/tests/test_api_v1_system_package.py +++ b/tests/test_api_v1_system_package.py @@ -12,36 +12,13 @@ class APIE2ETestSystemPackage(e2e_test_framework.APIE2ETest): "name": "pfSense-pkg-nmap" } }, - { - "name": "Check install of package via URL", - "resp_time": 30, - "payload": { - "name": "https://github.com/jaredhendrickson13/pfsense-saml2-auth/releases/latest/download/pfSense-2.5-pkg-saml2-auth.txz" - } - }, - { - "name": "Check forced install of pfSense repo package", - "resp_time": 30, - "payload": { - "name": "pfSense-pkg-nmap", - "force": True - } - }, - { - "name": "Check forced install of package via URL", - "resp_time": 30, - "payload": { - "name": "https://github.com/jaredhendrickson13/pfsense-saml2-auth/releases/latest/download/pfSense-2.5-pkg-saml2-auth.txz", - "force": True - } - }, { "name": "Check package name required constraint", "status": 400, "return": 1073 }, { - "name": "Check inability to install already installed package when not forced", + "name": "Check inability to install already installed package", "status": 400, "return": 1076, "resp_time": 30, @@ -49,51 +26,6 @@ class APIE2ETestSystemPackage(e2e_test_framework.APIE2ETest): "name": "pfSense-pkg-nmap" } }, - { - "name": "Check inability to install already installed package via URL when not forced", - "status": 400, - "return": 1076, - "resp_time": 30, - "payload": { - "name": "https://github.com/jaredhendrickson13/pfsense-saml2-auth/releases/latest/download/pfSense-2.5-pkg-saml2-auth.txz" - } - }, - { - "name": "Check package install timeout enforcement", - "status": 504, - "return": 1078, - "resp_time": 8, - "payload": { - "name": "https://1.2.3.4/", - "timeout": 5 - } - }, - { - "name": "Check package install timeout maximum constraint", - "status": 400, - "return": 1079, - "payload": { - "name": "https://1.2.3.4/", - "timeout": 121 - } - }, - { - "name": "Check invalid package file at URL", - "status": 400, - "return": 1077, - "payload": { - "name": "https://example.com/index.html" - } - }, - { - "name": "Check package install via URL with unresolvable DNS name", - "status": 502, - "return": 13, - "resp_time": 5, - "payload": { - "name": "https://doesnotexist.jaredhendrickson.com" - } - }, { "name": "Check install package from pfSense repo that doesn't exist", "status": 400, @@ -113,13 +45,6 @@ class APIE2ETestSystemPackage(e2e_test_framework.APIE2ETest): "name": "pfSense-pkg-nmap" } }, - { - "name": "Test deletion of URL installed package", - "resp_time": 30, - "payload": { - "name": "pfSense-pkg-saml2-auth" - } - }, { "name": "Check package name required constraint", "status": 400, From 5f7f7c9f06d6535a9f5d3d456614e6b9513cab3c Mon Sep 17 00:00:00 2001 From: Jared Hendrickson Date: Thu, 5 May 2022 22:48:20 -0600 Subject: [PATCH 3/8] Added /api/v1/services/unbound/host_override/flush endpoint to delete all existing Unbound host overrides --- .../APIServicesUnboundHostOverrideFlush.inc | 26 +++++++++++++ ...ServicesUnboundHostOverrideFlushDelete.inc | 38 +++++++++++++++++++ .../local/www/api/documentation/openapi.yml | 17 +++++++++ ...v1_services_unbound_host_override_flush.py | 24 ++++++++++++ 4 files changed, 105 insertions(+) create mode 100644 pfSense-pkg-API/files/etc/inc/api/endpoints/APIServicesUnboundHostOverrideFlush.inc create mode 100644 pfSense-pkg-API/files/etc/inc/api/models/APIServicesUnboundHostOverrideFlushDelete.inc create mode 100644 tests/test_api_v1_services_unbound_host_override_flush.py diff --git a/pfSense-pkg-API/files/etc/inc/api/endpoints/APIServicesUnboundHostOverrideFlush.inc b/pfSense-pkg-API/files/etc/inc/api/endpoints/APIServicesUnboundHostOverrideFlush.inc new file mode 100644 index 000000000..f5c1b3e11 --- /dev/null +++ b/pfSense-pkg-API/files/etc/inc/api/endpoints/APIServicesUnboundHostOverrideFlush.inc @@ -0,0 +1,26 @@ +url = "/api/v1/services/unbound/host_override/flush"; + } + + protected function delete() { + return (new APIServicesUnboundHostOverrideFlushDelete())->call(); + } +} diff --git a/pfSense-pkg-API/files/etc/inc/api/models/APIServicesUnboundHostOverrideFlushDelete.inc b/pfSense-pkg-API/files/etc/inc/api/models/APIServicesUnboundHostOverrideFlushDelete.inc new file mode 100644 index 000000000..70f68db4a --- /dev/null +++ b/pfSense-pkg-API/files/etc/inc/api/models/APIServicesUnboundHostOverrideFlushDelete.inc @@ -0,0 +1,38 @@ +privileges = ["page-all", "page-services-dnsresolver-edithost"]; + $this->change_note = "Flushed DNS Resolver host overrides via API"; + } + + public function action() { + # Capture all host overrides, remove them from the config and save the changes. + $this->validated_data = $this->config["unbound"]["hosts"]; + unset($this->config["unbound"]["hosts"]); + $this->write_config(); + + # Mark the Unbound subsystem as changed, but do not allow clients to immediately apply the change. + mark_subsystem_dirty("unbound"); + + return APIResponse\get(0, $this->validated_data); + } +} diff --git a/pfSense-pkg-API/files/usr/local/www/api/documentation/openapi.yml b/pfSense-pkg-API/files/usr/local/www/api/documentation/openapi.yml index 6c3d37b8c..6b71d1e2f 100644 --- a/pfSense-pkg-API/files/usr/local/www/api/documentation/openapi.yml +++ b/pfSense-pkg-API/files/usr/local/www/api/documentation/openapi.yml @@ -7282,6 +7282,22 @@ paths: summary: Create DNS Resolver (Unbound) host override alias tags: - Services > Unbound > Host Override > Alias + /api/v1/services/unbound/host_override/flush: + delete: + description: 'Deletes all existing DNS Resolver (Unbound) host overrides. This is useful for scripts + that need to setup host overrides from scratch.

_Note: this endpoint + will not reload the DNS Resolver (Unbound) service automatically, you must make another API + call to the /api/v1/services/unbound/apply endpoint to do so._.

+ + _Requires at least one of the following privileges:_ [`page-all`, `page-firewall-rules-edit`]' + responses: + 200: + $ref: '#/components/responses/Success' + 401: + $ref: '#/components/responses/AuthenticationFailed' + summary: Delete all DNS Resolver (Unbound) host overrides + tags: + - Services > Unbound > Host Override > Flush /api/v1/services/unbound/restart: post: description: 'Restart the DNS Resolver (Unbound) service.

@@ -9395,6 +9411,7 @@ tags: - name: Services > Unbound > Access List > Row - name: Services > Unbound > Host Override - name: Services > Unbound > Host Override > Alias + - name: Services > Unbound > Host Override > Flush - name: Services > DNSMASQ - name: Services > DNSMASQ > Host Override - name: Services > DNSMASQ > Host Override > Alias diff --git a/tests/test_api_v1_services_unbound_host_override_flush.py b/tests/test_api_v1_services_unbound_host_override_flush.py new file mode 100644 index 000000000..84c22fba6 --- /dev/null +++ b/tests/test_api_v1_services_unbound_host_override_flush.py @@ -0,0 +1,24 @@ +# Copyright 2022 Jared Hendrickson +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import e2e_test_framework + +class APIE2ETestServicesUnboundHostOverrideFlush(e2e_test_framework.APIE2ETest): + uri = "/api/v1/services/unbound/host_override/flush" + + delete_tests = [ + {"name": "Flush all Unbound host overrides", "payload": {}}, + ] + +APIE2ETestServicesUnboundHostOverrideFlush() From db7995b697d663b6b86a8b2accc5dd1eae45f540 Mon Sep 17 00:00:00 2001 From: Jared Hendrickson Date: Thu, 5 May 2022 22:53:36 -0600 Subject: [PATCH 4/8] Changed Swagger UI favicon to pfSense favicon to be more cohesive --- .../local/www/api/documentation/favicon-16x16.png | Bin 665 -> 0 bytes .../local/www/api/documentation/favicon-32x32.png | Bin 628 -> 0 bytes .../usr/local/www/api/documentation/index.php | 9 +++++++-- 3 files changed, 7 insertions(+), 2 deletions(-) delete mode 100644 pfSense-pkg-API/files/usr/local/www/api/documentation/favicon-16x16.png delete mode 100644 pfSense-pkg-API/files/usr/local/www/api/documentation/favicon-32x32.png diff --git a/pfSense-pkg-API/files/usr/local/www/api/documentation/favicon-16x16.png b/pfSense-pkg-API/files/usr/local/www/api/documentation/favicon-16x16.png deleted file mode 100644 index 8b194e617af1c135e6b37939591d24ac3a5efa18..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 665 zcmV;K0%rY*P)}JKSduyL>)s!A4EhTMMEM%Q;aL6%l#xiZiF>S;#Y{N2Zz%pvTGHJduXuC6Lx-)0EGfRy*N{Tv4i8@4oJ41gw zKzThrcRe|7J~(YYIBq{SYCkn-KQm=N8$CrEK1CcqMI1dv9z#VRL_{D)L|`QmF8}}l zJ9JV`Q}p!p_4f7m_U`WQ@apR4;o;!mnU<7}iG_qr zF(e)x9~BG-3IzcG2M4an0002kNkl41`ZiN1i62V%{PM@Ry|IS_+Yc7{bb`MM~xm(7p4|kMHP&!VGuDW4kFixat zXw43VmgwEvB$hXt_u=vZ>+v4i7E}n~eG6;n4Z=zF1n?T*yg<;W6kOfxpC6nao>VR% z?fpr=asSJ&`L*wu^rLJ5Peq*PB0;alL#XazZCBxJLd&giTfw@!hW167F^`7kobi;( ze<<>qNlP|xy7S1zl@lZNIBR7#o9ybJsptO#%}P0hz~sBp00000NkvXXu0mjfUsDF? diff --git a/pfSense-pkg-API/files/usr/local/www/api/documentation/favicon-32x32.png b/pfSense-pkg-API/files/usr/local/www/api/documentation/favicon-32x32.png deleted file mode 100644 index 249737fe44558e679f0b67134e274461d988fa98..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 628 zcmV-)0*n2LP)Ma*GM0}OV<074bNCP7P7GVd{iMr*I6y~TMLss@FjvgL~HxU z%Vvj33AwpD(Z4*$Mfx=HaU16axM zt2xG_rloN<$iy9j9I5pfSense REST API Documentation - - + + + + + + + From 1914264ba4e87849029eceffe23604f904d8c5ab Mon Sep 17 00:00:00 2001 From: Jared Hendrickson Date: Thu, 5 May 2022 23:26:30 -0600 Subject: [PATCH 5/8] Fixed issue in APISystemPackageDelete.inc that prevented the package configuration from being removed after deletion. --- .../files/etc/inc/api/models/APISystemPackageDelete.inc | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/pfSense-pkg-API/files/etc/inc/api/models/APISystemPackageDelete.inc b/pfSense-pkg-API/files/etc/inc/api/models/APISystemPackageDelete.inc index f6e42d956..2e34fbd08 100644 --- a/pfSense-pkg-API/files/etc/inc/api/models/APISystemPackageDelete.inc +++ b/pfSense-pkg-API/files/etc/inc/api/models/APISystemPackageDelete.inc @@ -26,8 +26,7 @@ class APISystemPackageDelete extends APIModel { } public function action() { - uninstall_package($this->validated_data["name"]); - $this->write_config(); + pkg_delete($this->validated_data["name"]); return APIResponse\get(0); } From 1188a32620e6f03af52a23342f320e8632ad597c Mon Sep 17 00:00:00 2001 From: Jared Hendrickson Date: Thu, 5 May 2022 23:32:43 -0600 Subject: [PATCH 6/8] Corrected required permissions for /api/v1/services/unbound/host_override/flush --- .../files/usr/local/www/api/documentation/openapi.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pfSense-pkg-API/files/usr/local/www/api/documentation/openapi.yml b/pfSense-pkg-API/files/usr/local/www/api/documentation/openapi.yml index ee984a746..3f8a2f9c7 100644 --- a/pfSense-pkg-API/files/usr/local/www/api/documentation/openapi.yml +++ b/pfSense-pkg-API/files/usr/local/www/api/documentation/openapi.yml @@ -7304,7 +7304,7 @@ paths: will not reload the DNS Resolver (Unbound) service automatically, you must make another API call to the /api/v1/services/unbound/apply endpoint to do so._.

- _Requires at least one of the following privileges:_ [`page-all`, `page-firewall-rules-edit`]' + _Requires at least one of the following privileges:_ [`page-all`, `page-services-dnsresolver-edithost`]' responses: 200: $ref: '#/components/responses/Success' From 20b7ee260e68d966ca25ed64c4b83e03c279c0ec Mon Sep 17 00:00:00 2001 From: Jared Hendrickson Date: Thu, 5 May 2022 23:41:23 -0600 Subject: [PATCH 7/8] Default return data on /api/v1/services/unbound/host_overrides/flush to empty array --- .../models/APIServicesUnboundHostOverrideFlushDelete.inc | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/pfSense-pkg-API/files/etc/inc/api/models/APIServicesUnboundHostOverrideFlushDelete.inc b/pfSense-pkg-API/files/etc/inc/api/models/APIServicesUnboundHostOverrideFlushDelete.inc index 70f68db4a..081253536 100644 --- a/pfSense-pkg-API/files/etc/inc/api/models/APIServicesUnboundHostOverrideFlushDelete.inc +++ b/pfSense-pkg-API/files/etc/inc/api/models/APIServicesUnboundHostOverrideFlushDelete.inc @@ -25,8 +25,10 @@ class APIServicesUnboundHostOverrideFlushDelete extends APIModel { } public function action() { - # Capture all host overrides, remove them from the config and save the changes. - $this->validated_data = $this->config["unbound"]["hosts"]; + # Capture the host overrides being deleted, if empty, default to empty array + $this->validated_data = ($this->config["unbound"]["hosts"]) ?: []; + + # Remove the host overrides from the configuration unset($this->config["unbound"]["hosts"]); $this->write_config(); From 4e4e827f074ba2b63375c9f11b90aabc1dc34f25 Mon Sep 17 00:00:00 2001 From: Jared Hendrickson Date: Fri, 6 May 2022 00:38:06 -0600 Subject: [PATCH 8/8] Fixed issue that allowed certificates to be updated without specifying a refid, added test to check for this. Added refid as a required property in the openapi schema for certificate updates. --- .../api/models/APISystemCertificateUpdate.inc | 10 ++++----- .../local/www/api/documentation/openapi.yml | 22 +++++++++++-------- tests/test_api_v1_system_certificate.py | 12 ++++++++-- 3 files changed, 28 insertions(+), 16 deletions(-) diff --git a/pfSense-pkg-API/files/etc/inc/api/models/APISystemCertificateUpdate.inc b/pfSense-pkg-API/files/etc/inc/api/models/APISystemCertificateUpdate.inc index fb7b91008..2af7e8b99 100644 --- a/pfSense-pkg-API/files/etc/inc/api/models/APISystemCertificateUpdate.inc +++ b/pfSense-pkg-API/files/etc/inc/api/models/APISystemCertificateUpdate.inc @@ -43,11 +43,11 @@ class APISystemCertificateUpdate extends APIModel { break; } } - # If we did not find an ID in the loop, return a not found error - if (is_null($this->id)) { - $this->errors[] = APIResponse\get(1009); - } - } + } + # If we did not find an ID in the loop, return a not found error + if (is_null($this->id)) { + $this->errors[] = APIResponse\get(1009); + } } private function __validate_crt() { diff --git a/pfSense-pkg-API/files/usr/local/www/api/documentation/openapi.yml b/pfSense-pkg-API/files/usr/local/www/api/documentation/openapi.yml index 3f8a2f9c7..e648c6e38 100644 --- a/pfSense-pkg-API/files/usr/local/www/api/documentation/openapi.yml +++ b/pfSense-pkg-API/files/usr/local/www/api/documentation/openapi.yml @@ -7302,7 +7302,7 @@ paths: description: 'Deletes all existing DNS Resolver (Unbound) host overrides. This is useful for scripts that need to setup host overrides from scratch.

_Note: this endpoint will not reload the DNS Resolver (Unbound) service automatically, you must make another API - call to the /api/v1/services/unbound/apply endpoint to do so._.

+ call to the /api/v1/services/unbound/apply endpoint to do so._

_Requires at least one of the following privileges:_ [`page-all`, `page-services-dnsresolver-edithost`]' responses: @@ -8057,25 +8057,29 @@ paths: application/json: schema: properties: - active: - default: false - description: Set this certificate as the active certificate used - by the webConfigurator. - type: boolean + refid: + description: 'ID of the certificate to be updated.' + type: string crt: description: 'Base64 encoded PEM certificate to import. _Note: previous releases referred to the `crt` parameter as `cert`. Both `crt` and `cert` can be used interchangeably._' type: string - descr: - description: Descriptive name for the certificate. - type: string prv: description: 'Corresponding Base64 encoded certificate key. _Note: previous releases referred to the `prv` parameter as `key`. Both `prv` and `key` can be used interchangeably._' type: string + descr: + description: Descriptive name for the certificate. + type: string + active: + default: false + description: Set this certificate as the active certificate used + by the webConfigurator. + type: boolean required: + - refid - crt - prv type: object diff --git a/tests/test_api_v1_system_certificate.py b/tests/test_api_v1_system_certificate.py index 850f5cad8..a2e35725f 100644 --- a/tests/test_api_v1_system_certificate.py +++ b/tests/test_api_v1_system_certificate.py @@ -232,16 +232,21 @@ class APIE2ETestSystemCertificate(e2e_test_framework.APIE2ETest): } ] put_tests = [ + { + "name": "Check refid requirement", + "status": 400, + "return": 1009 + }, { "name": "Check updating a non-existing certificate", "status": 400, "return": 1009, - "payload": {"descr": "INVALID"} + "payload": {"refid": "INVALID"} }, { "name": "Update an existing certificate", "payload": { - "descr": "Unit Test", + "descr": "E2E Test", "crt": crt, "prv": key } @@ -297,6 +302,9 @@ def post_post(self): if "payload" in test.keys() and "no_caref" not in test.keys(): self.post_tests[counter]["payload"]["caref"] = self.post_responses[0]["data"]["refid"] counter = counter + 1 + # Add imported certifictes refid to the update certificate payload + elif len(self.post_responses) == 2: + self.put_tests[2]["payload"]["refid"] = self.post_responses[1]["data"]["refid"] APIE2ETestSystemCertificate()