Skip to content

Commit

Permalink
Merge pull request #225 from jaredhendrickson13/v141
Browse files Browse the repository at this point in the history
v1.4.1 Fixes & Features
  • Loading branch information
jaredhendrickson13 authored May 6, 2022
2 parents cf2aaa6 + 4e4e827 commit 04947b1
Show file tree
Hide file tree
Showing 16 changed files with 262 additions and 265 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
<?php
// 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.

require_once("api/framework/APIEndpoint.inc");

class APIInterfaceAvailable extends APIEndpoint {
public function __construct() {
$this->url = "/api/v1/interface/available";
}

protected function get() {
return (new APIInterfaceAvailableRead())->call();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
<?php
// 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.

require_once("api/framework/APIEndpoint.inc");

class APIServicesUnboundHostOverrideFlush extends APIEndpoint {
public function __construct() {
$this->url = "/api/v1/services/unbound/host_override/flush";
}

protected function delete() {
return (new APIServicesUnboundHostOverrideFlushDelete())->call();
}
}
16 changes: 2 additions & 14 deletions pfSense-pkg-API/files/etc/inc/api/framework/APIResponse.inc
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
<?php
// 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.

require_once("api/framework/APIModel.inc");
require_once("api/framework/APIResponse.inc");


class APIInterfaceAvailableRead extends APIModel {
# Create our method constructor
public function __construct() {
parent::__construct();
$this->privileges = ["page-all", "page-interfaces-assignnetworkports"];

}

public function action() {
return APIResponse\get(0, APITools\get_all_avail_interfaces());
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
<?php
// 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.

require_once("api/framework/APIModel.inc");
require_once("api/framework/APIResponse.inc");

class APIServicesUnboundHostOverrideFlushDelete extends APIModel {
# Create our method constructor
public function __construct() {
parent::__construct();
$this->privileges = ["page-all", "page-services-dnsresolver-edithost"];
$this->change_note = "Flushed DNS Resolver host overrides via API";
}

public function action() {
# 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();

# 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);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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() {
Expand Down
154 changes: 22 additions & 132 deletions pfSense-pkg-API/files/etc/inc/api/models/APISystemPackageCreate.inc
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand All @@ -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.
Expand All @@ -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;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -26,24 +26,14 @@ class APISystemPackageDelete extends APIModel {
}

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

public function validate_payload(){
$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"])) {
Expand Down
Binary file not shown.
Binary file not shown.
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,13 @@
<title>pfSense REST API Documentation</title>
<link rel="stylesheet" type="text/css" href="./swagger-ui.css" />
<link rel="stylesheet" type="text/css" href="index.css" />
<link rel="icon" type="image/png" href="./favicon-32x32.png" sizes="32x32" />
<link rel="icon" type="image/png" href="./favicon-16x16.png" sizes="16x16" />
<link rel="apple-touch-icon-precomposed" href="/apple-touch/apple-touch-icon-iphone-60x60-precomposed.png">
<link rel="apple-touch-icon-precomposed" sizes="60x60" href="/apple-touch/apple-touch-icon-ipad-76x76-precomposed.png">
<link rel="apple-touch-icon-precomposed" sizes="114x114" href="/apple-touch/apple-touch-icon-iphone-retina-120x120-precomposed.png">
<link rel="apple-touch-icon-precomposed" sizes="144x144" href="/apple-touch/apple-touch-icon-ipad-retina-152x152-precomposed.png">
<link rel="icon" type="image/png" sizes="32x32" href="/favicon-32x32.png">
<link rel="icon" type="image/png" sizes="16x16" href="/favicon-16x16.png">
<link rel="mask-icon" href="/safari-pinned-tab.svg" color="#5bbad5">
</head>

<body>
Expand Down
Loading

0 comments on commit 04947b1

Please sign in to comment.