@@ -18,8 +18,6 @@ require_once("api/framework/APIResponse.inc");
1818
1919
2020class 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}
0 commit comments