Skip to content

Commit 5b7349d

Browse files
Added endpoint to add and delete firewall schedule time ranges, added unit tests to to test /api/v1/firewall/schedule/time_range, added support to delete firewall schedules and updated unit tests to test deletions
1 parent 5330b56 commit 5b7349d

10 files changed

Lines changed: 1285 additions & 0 deletions
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
<?php
2+
// Copyright 2021 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 APIFirewallSchedule extends APIEndpoint {
19+
public function __construct() {
20+
$this->url = "/api/v1/firewall/schedule";
21+
}
22+
23+
protected function get() {
24+
return (new APIFirewallScheduleRead())->call();
25+
}
26+
27+
protected function post() {
28+
return (new APIFirewallScheduleCreate())->call();
29+
}
30+
31+
protected function delete() {
32+
return (new APIFirewallScheduleDelete())->call();
33+
}
34+
}
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
<?php
2+
// Copyright 2021 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 APIFirewallScheduleTimeRange extends APIEndpoint {
19+
public function __construct() {
20+
$this->url = "/api/v1/firewall/schedule/time_range";
21+
}
22+
23+
protected function post() {
24+
return (new APIFirewallScheduleTimeRangeCreate())->call();
25+
}
26+
27+
protected function delete() {
28+
return (new APIFirewallScheduleTimeRangeDelete())->call();
29+
}
30+
}

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

Lines changed: 126 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1856,6 +1856,132 @@ function get($id, $data=[], $all=false) {
18561856
"return" => $id,
18571857
"message" => "Firewall traffic shaper queue name does not exist"
18581858
],
1859+
4146 => [
1860+
"status" => "bad request",
1861+
"code" => 400,
1862+
"return" => $id,
1863+
"message" => "Firewall schedule name is required"
1864+
],
1865+
4147 => [
1866+
"status" => "bad request",
1867+
"code" => 400,
1868+
"return" => $id,
1869+
"message" => "Firewall schedule name can only contain alphanumerics, underscores and hyphens"
1870+
],
1871+
4148 => [
1872+
"status" => "bad request",
1873+
"code" => 400,
1874+
"return" => $id,
1875+
"message" => "Firewall schedule name must 32 characters or less"
1876+
],
1877+
4149 => [
1878+
"status" => "bad request",
1879+
"code" => 400,
1880+
"return" => $id,
1881+
"message" => "Firewall schedule name already in use"
1882+
],
1883+
4150 => [
1884+
"status" => "bad request",
1885+
"code" => 400,
1886+
"return" => $id,
1887+
"message" => "Firewall schedule name does not exist"
1888+
],
1889+
4151 => [
1890+
"status" => "bad request",
1891+
"code" => 400,
1892+
"return" => $id,
1893+
"message" => "Firewall schedule time range month is required"
1894+
],
1895+
4152 => [
1896+
"status" => "bad request",
1897+
"code" => 400,
1898+
"return" => $id,
1899+
"message" => "Firewall schedule time range months must be between 1 and 12"
1900+
],
1901+
4153 => [
1902+
"status" => "bad request",
1903+
"code" => 400,
1904+
"return" => $id,
1905+
"message" => "Firewall schedule time range day is required"
1906+
],
1907+
4154 => [
1908+
"status" => "bad request",
1909+
"code" => 400,
1910+
"return" => $id,
1911+
"message" => "Firewall schedule time range number of days must match number of months"
1912+
],
1913+
4155 => [
1914+
"status" => "bad request",
1915+
"code" => 400,
1916+
"return" => $id,
1917+
"message" => "Firewall schedule time range days out of range for month"
1918+
],
1919+
4156 => [
1920+
"status" => "bad request",
1921+
"code" => 400,
1922+
"return" => $id,
1923+
"message" => "Firewall schedule time range hour is required"
1924+
],
1925+
4157 => [
1926+
"status" => "bad request",
1927+
"code" => 400,
1928+
"return" => $id,
1929+
"message" => "Firewall schedule time range starting hour is invalid"
1930+
],
1931+
4158 => [
1932+
"status" => "bad request",
1933+
"code" => 400,
1934+
"return" => $id,
1935+
"message" => "Firewall schedule time range ending hour is invalid"
1936+
],
1937+
4159 => [
1938+
"status" => "bad request",
1939+
"code" => 400,
1940+
"return" => $id,
1941+
"message" => "Firewall schedule time range starting hour cannot be greater than the ending hour"
1942+
],
1943+
4160 => [
1944+
"status" => "bad request",
1945+
"code" => 400,
1946+
"return" => $id,
1947+
"message" => "Firewall schedule time range positions must be between 1 and 7"
1948+
],
1949+
4161 => [
1950+
"status" => "bad request",
1951+
"code" => 400,
1952+
"return" => $id,
1953+
"message" => "Firewall schedule time range is required"
1954+
],
1955+
4162 => [
1956+
"status" => "bad request",
1957+
"code" => 400,
1958+
"return" => $id,
1959+
"message" => "At least one firewall schedule time range is required"
1960+
],
1961+
4163 => [
1962+
"status" => "bad request",
1963+
"code" => 400,
1964+
"return" => $id,
1965+
"message" => "Firewall schedule time range ID is required"
1966+
],
1967+
4164 => [
1968+
"status" => "bad request",
1969+
"code" => 400,
1970+
"return" => $id,
1971+
"message" => "Firewall schedule time range ID does not exist"
1972+
],
1973+
4165 => [
1974+
"status" => "bad request",
1975+
"code" => 400,
1976+
"return" => $id,
1977+
"message" => "Cannot delete the last remaining firewall schedule time range"
1978+
],
1979+
4166 => [
1980+
"status" => "bad request",
1981+
"code" => 400,
1982+
"return" => $id,
1983+
"message" => "Cannot delete firewall schedule while it is in use"
1984+
],
18591985

18601986
//5000-5999 reserved for /users API calls
18611987
5000 => [
Lines changed: 141 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,141 @@
1+
<?php
2+
// Copyright 2021 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 APIFirewallScheduleCreate extends APIModel {
21+
# Create our method constructor
22+
public function __construct() {
23+
parent::__construct();
24+
$this->privileges = ["page-all", "page-firewall-schedules-edit"];
25+
$this->change_note = "Added firewall schedule via API";
26+
}
27+
28+
public function action() {
29+
# Write this schedule to the config and reload the firewall filter
30+
$this->__init_config();
31+
$this->config["schedules"]["schedule"][] = $this->validated_data;
32+
$this->__sort_schedules();
33+
$this->write_config();
34+
filter_configure();
35+
36+
return APIResponse\get(0, $this->validated_data);
37+
}
38+
39+
public function validate_payload() {
40+
# Add static values
41+
$this->validated_data["schedlabel"] = uniqid();
42+
43+
# Validate fields
44+
$this->__validate_name();
45+
$this->__validate_timerange();
46+
$this->__validate_descr();
47+
}
48+
49+
private function __validate_name() {
50+
# Check for our required `name` payload value
51+
if (isset($this->initial_data["name"])) {
52+
# Ensure the name only contains alphanumeric, underscores, and hyphens
53+
if (preg_match('/^[\w-]+$/', $this->initial_data["name"])) {
54+
# Ensure the name is greater than 1 character and less than equal to 15 characters
55+
if (strlen($this->initial_data["name"]) >= 1 and strlen($this->initial_data["name"]) <= 32) {
56+
# Ensure the name is not already in use
57+
if (!$this->is_schedule_name_in_use($this->initial_data["name"])) {
58+
$this->validated_data["name"] = $this->initial_data["name"];
59+
} else {
60+
$this->errors[] = APIResponse\get(4149);
61+
}
62+
} else {
63+
$this->errors[] = APIResponse\get(4148);
64+
}
65+
} else {
66+
$this->errors[] = APIResponse\get(4147);
67+
}
68+
} else {
69+
$this->errors[] = APIResponse\get(4146);
70+
}
71+
}
72+
73+
private function __validate_timerange() {
74+
# Check for the optional `timerange` payload value
75+
if (isset($this->initial_data["timerange"])) {
76+
# Initialize the array to store validated time ranges
77+
$this->validated_data["timerange"];
78+
79+
# Require at least 1 time range to be configured
80+
if (is_array($this->initial_data["timerange"]) and count($this->initial_data["timerange"]) >= 1) {
81+
# Loop through each requested time range to validate
82+
foreach ($this->initial_data["timerange"] as $tr_data) {
83+
# Validate the time range using the APIFirewallScheduleTimeRangeCreate model
84+
$time_range = new APIFirewallScheduleTimeRangeCreate();
85+
$time_range->initial_data = $tr_data;
86+
$time_range->validate_payload(true);
87+
88+
# Add the validated time range if no errors were found
89+
if (empty($time_range->errors)) {
90+
$this->validated_data["timerange"][] = $time_range->validated_data;
91+
} else {
92+
$this->errors = $this->errors + $time_range->errors;
93+
}
94+
}
95+
} else {
96+
$this->errors[] = APIResponse\get(4162);
97+
}
98+
} else {
99+
$this->errors[] = APIResponse\get(4161);
100+
}
101+
}
102+
103+
private function __validate_descr() {
104+
# Check for the optional `descr` payload value
105+
if (isset($this->initial_data["descr"])) {
106+
$this->validated_data["descr"] = strval($this->initial_data["descr"]);
107+
}
108+
}
109+
110+
public function is_schedule_name_in_use($name) {
111+
# Loop through each schedule configured and check it's name
112+
foreach ($this->config["schedules"]["schedule"] as $schedule) {
113+
# Check if this $schedule's name matches our requested name
114+
if ($name === $schedule["name"] or $name == "wan" or $name == "lan") {
115+
return true;
116+
}
117+
}
118+
return false;
119+
}
120+
121+
private function __init_config() {
122+
# Check if there is no schedules array in the config
123+
if (empty($this->config["schedules"])) {
124+
$this->config["schedules"] = [];
125+
}
126+
# Check if there is no schedule array in the config
127+
if (empty($this->config["schedules"]["schedule"])) {
128+
$this->config["schedules"]["schedule"] = [];
129+
}
130+
}
131+
132+
private static function __compare_schedules($a, $b) {
133+
return strcmp($a['name'], $b['name']);
134+
}
135+
136+
private function __sort_schedules() {
137+
if (is_array($this->config['schedules']['schedule'])) {
138+
usort($this->config['schedules']['schedule'], ["APIFirewallScheduleCreate", "__compare_schedules"]);
139+
}
140+
}
141+
}

0 commit comments

Comments
 (0)