|
13 | 13 | // See the License for the specific language governing permissions and |
14 | 14 | // limitations under the License. |
15 | 15 |
|
16 | | -# Imports and inits |
17 | 16 | include_once("util.inc"); |
18 | 17 | include_once("guiconfig.inc"); |
19 | 18 | require_once("api/framework/APITools.inc"); |
20 | 19 |
|
| 20 | +# Initialize the pfSense UI page (note: $pgtitle must be defined before including head.inc) |
21 | 21 | $pgtitle = array(gettext('System'), gettext('API'), gettext('Settings')); |
22 | 22 | include('head.inc'); |
| 23 | +echo "<link rel='stylesheet' href='/css/api.css'/>"; |
| 24 | +echo "<script type='application/javascript' src='/js/api.js'></script>"; |
23 | 25 | $tab_array = [[gettext("Settings"), true, "/api/"], [gettext("Documentation"), false, "/api/documentation/"]]; |
24 | 26 | display_top_tabs($tab_array, true); # Ensure the tabs are written to the top of page |
25 | 27 |
|
26 | | - |
27 | 28 | # Variables |
28 | 29 | global $config; |
29 | 30 | $form = new Form(false); |
30 | 31 | $general_section = new Form_Section('General Settings'); |
31 | 32 | $token_section = new Form_Section('API Token Settings'); |
32 | 33 | $jwt_section = new Form_Section('JWT Settings'); |
33 | | -$advanced_section = new Form_Section('Advanced Settings'); |
| 34 | +$advanced_section = new Form_Section('Advanced Settings', 'api-advanced-settings'); |
34 | 35 | $pkg_index = APITools\get_api_config()[0]; |
35 | 36 | $pkg_config = APITools\get_api_config()[1]; |
36 | 37 |
|
37 | | -# UPON POST |
| 38 | +# Generate new API token if requested |
38 | 39 | if ($_POST["gen"] === "1") { |
39 | 40 | $new_key = APITools\generate_token($_SESSION["Username"]); |
40 | 41 | print_apply_result_box(0, "\nSave this API key somewhere safe, it cannot be viewed again: \n".$new_key); |
41 | 42 | } |
42 | | -# Rotate JWT server key requested |
| 43 | + |
| 44 | +# Rotate JWT server key if requested |
43 | 45 | if ($_POST["rotate_server_key"]) { |
44 | 46 | $config["installedpackages"]["package"][$pkg_index]["conf"]["keys"] = []; |
45 | 47 | APITools\create_jwt_server_key(true); |
|
54 | 56 | write_config(sprintf(gettext($change_note))); |
55 | 57 | print_apply_result_box(0); |
56 | 58 | } |
| 59 | + |
| 60 | +# Upon normal save, update changed values |
57 | 61 | if (isset($_POST["save"])) { |
58 | 62 | # Save enable value to config |
59 | 63 | if (isset($_POST["enable"])) { |
|
69 | 73 | if (isset($_POST["authmode"])) { |
70 | 74 | $pkg_config["authmode"] = $_POST["authmode"]; |
71 | 75 | } |
72 | | - # Save JWT expiration value to coonfig |
| 76 | + # Save JWT expiration value to config |
73 | 77 | if (isset($_POST["jwt_exp"])) { |
74 | 78 | $pkg_config["jwt_exp"] = $_POST["jwt_exp"]; |
75 | 79 | } |
|
94 | 98 | } else { |
95 | 99 | unset($pkg_config["readonly"]); |
96 | 100 | } |
97 | | - # Write and apply our changes, leave a session variable indicating save, then reload the page |
98 | | - $config["installedpackages"]["package"][$pkg_index]["conf"] = $pkg_config; |
99 | | - $change_note = " Updated API settings"; |
100 | | - write_config(sprintf(gettext($change_note))); |
101 | | - APITools\create_jwt_server_key(); |
102 | | - print_apply_result_box(0); |
| 101 | + # Save our allow OPTIONS value |
| 102 | + if (isset($_POST["allow_options"])) { |
| 103 | + $pkg_config["allow_options"] = ""; |
| 104 | + } else { |
| 105 | + unset($pkg_config["allow_options"]); |
| 106 | + } |
| 107 | + # Save any custom headers specified |
| 108 | + if (!empty($_POST["custom_headers"])) { |
| 109 | + # Decode the JSON string to ensure it is valid |
| 110 | + $headers = json_decode($_POST["custom_headers"], true); |
| 111 | + |
| 112 | + # Only save the new value if it was a successfully decoded JSON string |
| 113 | + if (is_array($headers)) { |
| 114 | + # Loop through each requested header and ensure types are valid |
| 115 | + foreach ($headers as $key=>$value) { |
| 116 | + if (!is_string($key) or !is_string($value)) { |
| 117 | + print_input_errors(["Custom headers key-value pairs must be string types."]); |
| 118 | + $has_errors = true; |
| 119 | + break; |
| 120 | + } |
| 121 | + } |
| 122 | + $pkg_config["custom_headers"] = $headers; |
| 123 | + } else { |
| 124 | + print_input_errors(["Custom headers must be a JSON string containing key-value pairs."]); |
| 125 | + $has_errors = true; |
| 126 | + } |
| 127 | + } else { |
| 128 | + unset($pkg_config["custom_headers"]); |
| 129 | + } |
| 130 | + |
| 131 | + # Only write changes if no errors occurred |
| 132 | + if (!$has_errors) { |
| 133 | + # Write and apply our changes, leave a session variable indicating save, then reload the page |
| 134 | + $config["installedpackages"]["package"][$pkg_index]["conf"] = $pkg_config; |
| 135 | + $change_note = " Updated API settings"; |
| 136 | + write_config(sprintf(gettext($change_note))); |
| 137 | + APITools\create_jwt_server_key(); |
| 138 | + print_apply_result_box(0); |
| 139 | + } |
103 | 140 | } |
104 | 141 |
|
105 | 142 | # Backup our configuration is persist is enabled and the request is a POST request |
106 | 143 | if(isset($pkg_config["persist"]) and $_SERVER["REQUEST_METHOD"] === "POST") { |
107 | 144 | shell_exec("/usr/local/share/pfSense-pkg-API/manage.php backup"); |
108 | 145 | } |
109 | 146 |
|
110 | | -# POPULATE THE GENERAL SECTION OF THE UI |
| 147 | +# Populate the GENERAL section of the UI form |
111 | 148 | $general_section->addInput(new Form_Checkbox( |
112 | 149 | 'enable', |
113 | 150 | 'Enable', |
|
142 | 179 | $pkg_config["allowed_interfaces"], |
143 | 180 | array_merge(["any" => "Any", "localhost" => "Link-local"], get_configured_interface_with_descr(true)), |
144 | 181 | true |
145 | | -)); |
| 182 | +))->setHelp( |
| 183 | + "Select interfaces that are allowed to respond to API requests." |
| 184 | +); |
146 | 185 |
|
147 | 186 | $general_section->addInput(new Form_Select( |
148 | 187 | 'authmode', |
149 | 188 | 'Authentication Mode', |
150 | 189 | $pkg_config["authmode"], |
151 | 190 | ["local" => "Local Database", "token" => "API Token", "jwt" => "JWT"] |
152 | | -)); |
| 191 | +))->setHelp( |
| 192 | + "Select the mode used to authenticate API requests See the <a href='/api/documentation/'>developer documentation</a> |
| 193 | + for more information on API authentication." |
| 194 | +); |
| 195 | + |
| 196 | +# Add toggle button to show/hide the advanced settings |
| 197 | +$show_adv_btn = new Form_Button('display_advanced', 'Display Advanced', null, 'fa-cog'); |
| 198 | +$show_adv_btn->setAttribute('type','button')->addClass('btn-info btn-sm')->setOnClick("toggle_advanced_settings()"); |
| 199 | +$general_section->addInput(new Form_StaticText('Advanced Settings', $show_adv_btn)); |
153 | 200 |
|
154 | | -# POPULATE THE API TOKEN SECTION OF THE UI |
| 201 | +### Populate the API TOKEN section of the UI form |
155 | 202 | $token_section->addInput(new Form_Select( |
156 | 203 | 'keyhash', |
157 | 204 | 'Token Hash Algorithm', |
|
160 | 207 | ))->setHelp( |
161 | 208 | "Hashing algorithm used when generating API tokens." |
162 | 209 | ); |
| 210 | + |
163 | 211 | $token_section->addInput(new Form_Select( |
164 | 212 | 'keybytes', |
165 | 213 | 'Token Bit Strength', |
|
169 | 217 | "Bit strength used when generating API tokens." |
170 | 218 | ); |
171 | 219 |
|
172 | | -# POPULATE THE JWT SECTION OF THE UI |
| 220 | +### Populate the JWT section of the UI form |
173 | 221 | $jwt_section->addInput(new Form_Input( |
174 | 222 | 'jwt_exp', |
175 | 223 | 'JWT Expiration', |
|
181 | 229 | 86400 seconds (1 day)." |
182 | 230 | ); |
183 | 231 |
|
184 | | -# POPULATE THE ADVANCED SECTION OF THE UI |
| 232 | +### Populate the ADVANCED section of the UI form |
| 233 | +$advanced_section->addClass("hide-api-advanced-settings"); |
185 | 234 | $advanced_section->addInput(new Form_Checkbox( |
186 | 235 | 'allow_options', |
187 | 236 | 'OPTIONS Method', |
188 | 237 | 'Allow OPTIONS Request Method', |
189 | | - $pkg_config["allow_options"] |
190 | | -))->setHelp("Allow API to answer OPTIONS requests. This is sometimes required for integration with frontend web applications."); |
| 238 | + isset($pkg_config["allow_options"]) |
| 239 | +))->setHelp( |
| 240 | + "Allow API to answer OPTIONS requests. This is sometimes required for integration with frontend web applications." |
| 241 | +); |
| 242 | + |
191 | 243 | $advanced_section->addInput(new Form_Textarea( |
192 | 244 | 'custom_headers', |
193 | | - 'Custom Response Headers', |
| 245 | + 'Custom Headers', |
194 | 246 | (is_array($pkg_config["custom_headers"])) ? json_encode($pkg_config["custom_headers"]) : "" |
195 | 247 | ))->setHelp( |
196 | 248 | 'Specify custom response headers to return with API responses. This must be JSON encoded string containing key-value |
197 | | - pairs (e.g. {"test-header-name": "test-header-value"}). This may be required by some HTTP clients and frameworks. |
| 249 | + pairs (e.g. <code>{"test-header-name": "test-header-value"}</code>). This may be required by some HTTP clients and frameworks. |
198 | 250 | For example, this can be used to set CORS policy headers required by frontend web applications.' |
199 | 251 | ); |
200 | 252 |
|
201 | | - |
202 | | -# POPULATE OUR COMPLETE FORM |
| 253 | +# Populate the entire form |
203 | 254 | $form->add($general_section); |
204 | 255 | $form->add($advanced_section); |
205 | | - |
206 | | -# Only display the Token or JWT sections if they are the selected auth mode |
207 | 256 | ($pkg_config["authmode"] === "token") ? $form->add($token_section) : null; |
208 | 257 | ($pkg_config["authmode"] === "jwt") ? $form->add($jwt_section) : null; |
| 258 | + |
| 259 | +# Add buttons below the form |
209 | 260 | $rotate_btn = new Form_Button('rotate_server_key', 'Rotate server key', null, 'fa-level-up'); |
210 | 261 | $rotate_btn->addClass('btn btn-sm btn-success'); |
211 | 262 | $rotate_btn->setOnclick("return confirm(\"Rotating the server key will void any existng API tokens and JWTs. Proceed?\");"); |
212 | | -$form->addGlobal($rotate_btn); |
213 | 263 | $form->addGlobal(new Form_Button('save', 'Save', null, 'fa-save'))->addClass('btn btn-sm btn-primary api-save-btn'); |
| 264 | +(in_array($pkg_config["authmode"], ["token", "jwt"])) ? $form->addGlobal($rotate_btn) : null; |
214 | 265 | $form->addGlobal(new Form_Button('report', 'Report an Issue', 'https://github.com/jaredhendrickson13/pfsense-api/issues/new', ''))->addClass('fa fa-question-circle api-report'); |
215 | 266 |
|
216 | | -# PRINT OUR FORM AND PFSENSE FOOTER |
| 267 | +# Display the populated configuration form |
217 | 268 | print $form; |
218 | | -//print "<a style=\"float: right;\" class=\"fa fa-question-circle\" href='https://github.com/jaredhendrickson13/pfsense-api/issues/new'> <span style=\"font-family: 'Helvetica'; font-size: 14px;\">Report an Issue</span></a>"; |
219 | 269 |
|
220 | | -# POPULATE TOKEN TABLE |
| 270 | +# POPULATE TOKEN TABLE IF TOKEN AUTH MODE IS SET |
221 | 271 | if ($pkg_config["authmode"] === "token") { |
222 | 272 | # Pull credentials if configured |
223 | 273 | $user_creds = APITools\get_existing_tokens($_SESSION["Username"]); |
|
0 commit comments