Skip to content

Commit 04947b1

Browse files
Merge pull request #225 from jaredhendrickson13/v141
v1.4.1 Fixes & Features
2 parents cf2aaa6 + 4e4e827 commit 04947b1

16 files changed

Lines changed: 262 additions & 265 deletions
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
<?php
2+
// Copyright 2022 Jared Hendrickson
3+
//
4+
// Licensed under the Apache License, Version 2.0 (the "License");
5+
// you may not use this file except in compliance with the License.
6+
// You may obtain a copy of the License at
7+
//
8+
// http://www.apache.org/licenses/LICENSE-2.0
9+
//
10+
// Unless required by applicable law or agreed to in writing, software
11+
// distributed under the License is distributed on an "AS IS" BASIS,
12+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
// See the License for the specific language governing permissions and
14+
// limitations under the License.
15+
16+
require_once("api/framework/APIEndpoint.inc");
17+
18+
class APIInterfaceAvailable extends APIEndpoint {
19+
public function __construct() {
20+
$this->url = "/api/v1/interface/available";
21+
}
22+
23+
protected function get() {
24+
return (new APIInterfaceAvailableRead())->call();
25+
}
26+
}
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
<?php
2+
// Copyright 2022 Jared Hendrickson
3+
//
4+
// Licensed under the Apache License, Version 2.0 (the "License");
5+
// you may not use this file except in compliance with the License.
6+
// You may obtain a copy of the License at
7+
//
8+
// http://www.apache.org/licenses/LICENSE-2.0
9+
//
10+
// Unless required by applicable law or agreed to in writing, software
11+
// distributed under the License is distributed on an "AS IS" BASIS,
12+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
// See the License for the specific language governing permissions and
14+
// limitations under the License.
15+
16+
require_once("api/framework/APIEndpoint.inc");
17+
18+
class APIServicesUnboundHostOverrideFlush extends APIEndpoint {
19+
public function __construct() {
20+
$this->url = "/api/v1/services/unbound/host_override/flush";
21+
}
22+
23+
protected function delete() {
24+
return (new APIServicesUnboundHostOverrideFlushDelete())->call();
25+
}
26+
}

pfSense-pkg-API/files/etc/inc/api/framework/APIResponse.inc

Lines changed: 2 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -569,21 +569,9 @@ function get($id, $data=[], $all=false) {
569569
],
570570
1077 => [
571571
"status" => "bad request",
572-
"code" => 400,
573-
"return" => $id,
574-
"message" => "Remote URL does not contain a pfSense package"
575-
],
576-
1078 => [
577-
"status" => "bad request",
578-
"code" => 504,
579-
"return" => $id,
580-
"message" => "System package installation exceeded timeout"
581-
],
582-
1079 => [
583-
"status" => "bad request",
584-
"code" => 400,
572+
"code" => 500,
585573
"return" => $id,
586-
"message" => "System package installation timeout cannot be greater than 120 seconds"
574+
"message" => "System package failed to install"
587575
],
588576
1080 => [
589577
"status" => "bad request",
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
<?php
2+
// Copyright 2022 Jared Hendrickson
3+
//
4+
// Licensed under the Apache License, Version 2.0 (the "License");
5+
// you may not use this file except in compliance with the License.
6+
// You may obtain a copy of the License at
7+
//
8+
// http://www.apache.org/licenses/LICENSE-2.0
9+
//
10+
// Unless required by applicable law or agreed to in writing, software
11+
// distributed under the License is distributed on an "AS IS" BASIS,
12+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
// See the License for the specific language governing permissions and
14+
// limitations under the License.
15+
16+
require_once("api/framework/APIModel.inc");
17+
require_once("api/framework/APIResponse.inc");
18+
19+
20+
class APIInterfaceAvailableRead extends APIModel {
21+
# Create our method constructor
22+
public function __construct() {
23+
parent::__construct();
24+
$this->privileges = ["page-all", "page-interfaces-assignnetworkports"];
25+
26+
}
27+
28+
public function action() {
29+
return APIResponse\get(0, APITools\get_all_avail_interfaces());
30+
}
31+
}
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
<?php
2+
// Copyright 2022 Jared Hendrickson
3+
//
4+
// Licensed under the Apache License, Version 2.0 (the "License");
5+
// you may not use this file except in compliance with the License.
6+
// You may obtain a copy of the License at
7+
//
8+
// http://www.apache.org/licenses/LICENSE-2.0
9+
//
10+
// Unless required by applicable law or agreed to in writing, software
11+
// distributed under the License is distributed on an "AS IS" BASIS,
12+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
// See the License for the specific language governing permissions and
14+
// limitations under the License.
15+
16+
require_once("api/framework/APIModel.inc");
17+
require_once("api/framework/APIResponse.inc");
18+
19+
class APIServicesUnboundHostOverrideFlushDelete extends APIModel {
20+
# Create our method constructor
21+
public function __construct() {
22+
parent::__construct();
23+
$this->privileges = ["page-all", "page-services-dnsresolver-edithost"];
24+
$this->change_note = "Flushed DNS Resolver host overrides via API";
25+
}
26+
27+
public function action() {
28+
# Capture the host overrides being deleted, if empty, default to empty array
29+
$this->validated_data = ($this->config["unbound"]["hosts"]) ?: [];
30+
31+
# Remove the host overrides from the configuration
32+
unset($this->config["unbound"]["hosts"]);
33+
$this->write_config();
34+
35+
# Mark the Unbound subsystem as changed, but do not allow clients to immediately apply the change.
36+
mark_subsystem_dirty("unbound");
37+
38+
return APIResponse\get(0, $this->validated_data);
39+
}
40+
}

pfSense-pkg-API/files/etc/inc/api/models/APISystemCertificateUpdate.inc

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -43,11 +43,11 @@ class APISystemCertificateUpdate extends APIModel {
4343
break;
4444
}
4545
}
46-
# If we did not find an ID in the loop, return a not found error
47-
if (is_null($this->id)) {
48-
$this->errors[] = APIResponse\get(1009);
49-
}
50-
}
46+
}
47+
# If we did not find an ID in the loop, return a not found error
48+
if (is_null($this->id)) {
49+
$this->errors[] = APIResponse\get(1009);
50+
}
5151
}
5252

5353
private function __validate_crt() {

pfSense-pkg-API/files/etc/inc/api/models/APISystemPackageCreate.inc

Lines changed: 22 additions & 132 deletions
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,6 @@ require_once("api/framework/APIResponse.inc");
1818

1919

2020
class APISystemPackageCreate extends APIModel {
21-
public $pkg_mode;
22-
2321
# Create our method constructor
2422
public function __construct() {
2523
parent::__construct();
@@ -28,32 +26,35 @@ class APISystemPackageCreate extends APIModel {
2826
}
2927

3028
public function action() {
31-
return APIResponse\get($this->install_pkg());
29+
# Force the action to be logged in the configuration history if our API response code is success
30+
if (pkg_install($this->validated_data["name"])) {
31+
return APIResponse\get(0);
32+
} else {
33+
return APIResponse\get(1077);
34+
}
3235
}
3336

3437
public function validate_payload(){
35-
$this->__validate_force(); // Must run before __validate_name
3638
$this->__validate_name();
37-
$this->__validate_timeout();
3839
}
3940

40-
# Attempts to install the package specified in $this->validated_data["name"]
41-
public function install_pkg() {
42-
# Format and execute our pkg command. Enforce a timeout to prevent gateway timeouts.
43-
$pkg_force = ($this->validated_data["force"]) ? " -f" : "";
44-
$pkg_y = ($this->pkg_mode === "install") ? " -y" : "";
45-
$pkg_cmd = "pkg ".$this->pkg_mode.$pkg_y.$pkg_force." ".$this->validated_data["name"]." 2>&1";
46-
exec("timeout ".$this->validated_data["timeout"]." ".$pkg_cmd, $pkg_out, $pkg_rc);
47-
48-
# Check for known errors
49-
$api_rc = $this->__check_pkg_install($pkg_out, $pkg_rc);
50-
51-
# Force the action to be logged in the configuration history if our API response code is success
52-
if ($api_rc === 0) {
53-
$this->write_config();
41+
private function __validate_name() {
42+
# Check for our required name input
43+
if (isset($this->initial_data["name"])) {
44+
# Ensure this package exists in pfSense's repos
45+
if ($this->is_pkg_in_repo($this->initial_data["name"])) {
46+
# Ensure package is not already installed
47+
if (!is_pkg_installed($this->initial_data["name"])) {
48+
$this->validated_data["name"] = $this->initial_data["name"];
49+
} else {
50+
$this->errors[] = APIResponse\get(1076);
51+
}
52+
} else {
53+
$this->errors[] = APIResponse\get(1075);
54+
}
55+
} else {
56+
$this->errors[] = APIResponse\get(1073);
5457
}
55-
56-
return $api_rc;
5758
}
5859

5960
# Checks pfSense's upstream package repo for a package by name. Requires upstream internet connection.
@@ -74,115 +75,4 @@ class APISystemPackageCreate extends APIModel {
7475

7576
return false;
7677
}
77-
78-
private function __validate_name() {
79-
# Check for our required name input
80-
if (isset($this->initial_data["name"])) {
81-
# Check if this is a remote/third-party package to be installed by URL
82-
if (filter_var($this->initial_data["name"], FILTER_VALIDATE_URL)) {
83-
# Set pkg add to install package from URL
84-
$this->pkg_mode = "add";
85-
$this->validated_data["name"] = filter_var($this->initial_data["name"], FILTER_VALIDATE_URL);
86-
}
87-
# Otherwise, we will assume this package exists in pfSense's package repos
88-
else {
89-
# Set pkg install to install the package from pfSense's repos
90-
$this->pkg_mode = "install";
91-
92-
# Ensure this package exists in pfSense's repos
93-
if ($this->is_pkg_in_repo($this->initial_data["name"])) {
94-
# Ensure package is not already installed
95-
if (!is_pkg_installed($this->initial_data["name"]) or $this->validated_data["force"]) {
96-
$this->validated_data["name"] = $this->initial_data["name"];
97-
} else {
98-
$this->errors[] = APIResponse\get(1076);
99-
}
100-
} else {
101-
$this->errors[] = APIResponse\get(1075);
102-
}
103-
104-
}
105-
} else {
106-
$this->errors[] = APIResponse\get(1073);
107-
}
108-
}
109-
110-
private function __validate_force() {
111-
# Check for our optional force input
112-
if ($this->initial_data["force"] === true) {
113-
$this->validated_data["force"] = true;
114-
}
115-
}
116-
117-
private function __validate_timeout() {
118-
# Check for our optional timeout input
119-
if (isset($this->initial_data["timeout"])) {
120-
# Require timeout value to be 120 seconds or less
121-
if (is_numeric($this->initial_data["timeout"]) and intval($this->initial_data["timeout"]) <= 120) {
122-
# Force timeouts less than 5 to minimum of 5 seconds
123-
if (intval($this->initial_data["timeout"]) < 5) {
124-
$this->initial_data["timeout"] = 5;
125-
}
126-
127-
$this->validated_data["timeout"] = intval($this->initial_data["timeout"]);
128-
} else {
129-
$this->errors[] = APIResponse\get(1079);
130-
}
131-
} else {
132-
$this->validated_data["timeout"] = 90;
133-
}
134-
}
135-
136-
# This function is intended to take the output of our pkg add or install command and check for failures.
137-
# Returns the corresponding API response ID.
138-
# TODO: matching text based error messages is prone to breaking as the pkg cli tool changes. As of now, pkg does
139-
# TODO: not return unique return codes for specific errors. Re-evaluate as time goes and refactor when a better way
140-
# TODO: is made available.
141-
private function __check_pkg_install($pkg_out, $pkg_rc) {
142-
# Check if our package installation timed out
143-
if ($pkg_rc === 124) {
144-
return 1078;
145-
}
146-
147-
# Loop through each line of the pkg output and check for known error messages
148-
foreach ($pkg_out as $pkg_line) {
149-
# Check for 'pkg install' no matching package in repository error
150-
if (APITools\str_starts_with("pkg: No packages available to install matching", $pkg_line)) {
151-
return 1075;
152-
}
153-
# Check for 'pkg install' most recent version is already installed error
154-
elseif (APITools\str_starts_with("The most recent versions of packages are already installed", $pkg_line)) {
155-
return 1076;
156-
}
157-
# Check for 'pkg add' most recent version is already installed error
158-
elseif (APITools\str_starts_with("the most recent version of", $pkg_line)) {
159-
return 1076;
160-
}
161-
# Check for 'pkg add' no package file found at URL error
162-
elseif (APITools\str_ends_with(": Not Found", $pkg_line)) {
163-
return 1075;
164-
}
165-
# Check for 'pkg add' URL does not contain package file error
166-
elseif (APITools\str_ends_with(": Unrecognized archive format", $pkg_line)) {
167-
return 1077;
168-
}
169-
# Check for 'pkg add' DNS resolution error
170-
elseif (APITools\str_ends_with(": No address record", $pkg_line)) {
171-
return 13;
172-
}
173-
# Check for 'pkg add' URL unreachable error
174-
elseif (APITools\str_ends_with(": Network is unreachable", $pkg_line)) {
175-
return 13;
176-
}
177-
}
178-
179-
# When no known error messages were matched, but the pkg command still failed, return unexpected error
180-
if ($pkg_rc !== 0) {
181-
return 1;
182-
}
183-
# Otherwise, our package installation appears to be successful
184-
else {
185-
return 0;
186-
}
187-
}
18878
}

pfSense-pkg-API/files/etc/inc/api/models/APISystemPackageDelete.inc

Lines changed: 1 addition & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -26,24 +26,14 @@ class APISystemPackageDelete extends APIModel {
2626
}
2727

2828
public function action() {
29-
$this->delete_pkg();
29+
pkg_delete($this->validated_data["name"]);
3030
return APIResponse\get(0);
3131
}
3232

3333
public function validate_payload(){
3434
$this->__validate_name();
3535
}
3636

37-
# Deletes the package specified in $this->validated_data["name"]
38-
public function delete_pkg() {
39-
# Remove the requested package and clean up dependencies afterwards
40-
pkg_call("delete -y " . $this->validated_data["name"]);
41-
pkg_call("autoremove -y");
42-
43-
# Force the action to be logged in the configuration history
44-
$this->write_config();
45-
}
46-
4737
private function __validate_name() {
4838
# Check for our required name input
4939
if (isset($this->initial_data["name"])) {
Binary file not shown.
Binary file not shown.

0 commit comments

Comments
 (0)