PluginProbe
HTTP Headers / 1.14.2
HTTP Headers v1.14.2
1.19.5 trunk 1.0.0 1.1.0 1.1.1 1.1.2 1.10.0 1.10.1 1.10.2 1.10.3 1.10.4 1.10.5 1.11.0 1.12.0 1.12.1 1.12.2 1.13.0 1.13.1 1.13.2 1.13.3 1.13.4 1.14.0 1.14.1 1.14.2 1.15.0 All 60 releases
http-headers / http-headers.php

http-headers.php in HTTP Headers 1.14.2, at http-headers.php

1,456 lines 52.5 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /*
3 Plugin Name: HTTP Headers
4 Plugin URI: https://zinoui.com/blog/http-headers-for-wordpress
5 Description: A plugin for HTTP headers management including security, access-control (CORS), caching, compression, and authentication.
6 Version: 1.14.2
7 Author: Dimitar Ivanov
8 Author URI: https://zinoui.com
9 License: GPLv2 or later
10 Text Domain: http-headers
11 */
12
13 /*
14 This program is free software; you can redistribute it and/or
15 modify it under the terms of the GNU General Public License
16 as published by the Free Software Foundation; either version 2
17 of the License, or (at your option) any later version.
18
19 This program is distributed in the hope that it will be useful,
20 but WITHOUT ANY WARRANTY; without even the implied warranty of
21 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 GNU General Public License for more details.
23
24 You should have received a copy of the GNU General Public License
25 along with this program. If not, see <http://www.gnu.org/copyleft/gpl.html>.
26
27 Copyright (c) 2017-2019 Zino UI
28 */
29
30 if (!defined('ABSPATH')) {
31 exit;
32 }
33
34 $options = include dirname(__FILE__) . '/views/includes/options.inc.php';
35 foreach ($options as $option) {
36 if (get_option($option[0]) === false) {
37 add_option($option[0], $option[1], null, 'yes');
38 }
39 }
40
41 function build_csp_value($value) {
42 $csp = array();
43 foreach ($value as $key => $val)
44 {
45 if (is_array($val))
46 {
47 $source = NULL;
48 if (isset($val['source']))
49 {
50 $source = $val['source'];
51 unset($val['source']);
52 }
53 if (!empty($val))
54 {
55 $val = join(" ", array_keys($val));
56 if ($source)
57 {
58 $val .= " " . $source;
59 }
60 $csp[] = sprintf("%s %s", $key, $val);
61 } elseif ($source) {
62 $csp[] = sprintf("%s %s", $key, $source);
63 }
64 } else {
65 if (in_array($key, array('block-all-mixed-content', 'upgrade-insecure-requests')))
66 {
67 $csp[] = $key;
68 }
69 if (in_array($key, array('plugin-types', 'report-to')) && !empty($val))
70 {
71 $csp[] = sprintf("%s %s", $key, $val);
72 }
73 }
74 }
75
76 if (!$csp)
77 {
78 return NULL;
79 }
80
81 return join('; ', $csp);
82 }
83
84 function get_http_headers() {
85 $statuses = array();
86 $unset = array();
87 $headers = array();
88 $append = array();
89 if (get_option('hh_x_frame_options') == 1) {
90 $x_frame_options_value = strtoupper(get_option('hh_x_frame_options_value'));
91 if ($x_frame_options_value == 'ALLOW-FROM') {
92 $x_frame_options_value .= ' ' . get_option('hh_x_frame_options_domain');
93 }
94 $headers['X-Frame-Options'] = $x_frame_options_value;
95 }
96 if (get_option('hh_x_powered_by') == 1) {
97 if (get_option('hh_x_powered_by_option') == 'set') {
98 $headers['X-Powered-By'] = get_option('hh_x_powered_by_value');
99 } else {
100 $unset[] = 'X-Powered-By';
101 }
102 }
103 if (get_option('hh_x_xxs_protection') == 1) {
104 $headers['X-XSS-Protection'] = get_option('hh_x_xxs_protection_value');
105 if ($headers['X-XSS-Protection'] == '1; report=') {
106 $headers['X-XSS-Protection'] .= get_option('hh_x_xxs_protection_uri');
107 }
108 }
109 if (get_option('hh_x_content_type_options') == 1) {
110 $headers['X-Content-Type-Options'] = get_option('hh_x_content_type_options_value');
111 }
112 if (get_option('hh_x_download_options') == 1) {
113 $headers['X-Download-Options'] = get_option('hh_x_download_options_value');
114 }
115 if (get_option('hh_x_permitted_cross_domain_policies') == 1) {
116 $headers['X-Permitted-Cross-Domain-Policies'] = get_option('hh_x_permitted_cross_domain_policies_value');
117 }
118 if (get_option('hh_x_dns_prefetch_control') == 1) {
119 $headers['X-DNS-Prefetch-Control'] = get_option('hh_x_dns_prefetch_control_value');
120 }
121 if (get_option('hh_connection') == 1) {
122 $headers['Connection'] = get_option('hh_connection_value');
123 }
124 if (get_option('hh_pragma') == 1) {
125 $headers['Pragma'] = get_option('hh_pragma_value');
126 }
127 if (get_option('hh_age') == 1) {
128 $headers['Age'] = sprintf("%u", get_option('hh_age_value'));
129 }
130 if (get_option('hh_cache_control') == 1) {
131 $hh_cache_control_value = get_option('hh_cache_control_value', array());
132 $tmp = array();
133 foreach ($hh_cache_control_value as $k => $v) {
134 if (in_array($k, array('max-age', 's-maxage', 'stale-while-revalidate', 'stale-if-error'))) {
135 if (strlen($v) > 0) {
136 $tmp[] = sprintf("%s=%u", $k, $v);
137 }
138 } else {
139 $tmp[] = $k;
140 }
141 }
142 $hh_cache_control_value = join(', ', $tmp);
143 $headers['Cache-Control'] = $hh_cache_control_value;
144 }
145 if (get_option('hh_strict_transport_security') == 1) {
146 $hh_strict_transport_security = array();
147
148 $hh_strict_transport_security_max_age = get_option('hh_strict_transport_security_max_age');
149 if ($hh_strict_transport_security_max_age !== false)
150 {
151 $hh_strict_transport_security[] = sprintf('max-age=%u', get_option('hh_strict_transport_security_max_age'));
152 if (get_option('hh_strict_transport_security_sub_domains'))
153 {
154 $hh_strict_transport_security[] = 'includeSubDomains';
155 }
156 if (get_option('hh_strict_transport_security_preload'))
157 {
158 $hh_strict_transport_security[] = 'preload';
159 }
160 } else {
161 $hh_strict_transport_security = array(get_option('hh_strict_transport_security_value'));
162 }
163 $headers['Strict-Transport-Security'] = join('; ', $hh_strict_transport_security);
164 }
165 if (get_option('hh_x_ua_compatible') == 1) {
166 $headers['X-UA-Compatible'] = get_option('hh_x_ua_compatible_value');
167 }
168 if (get_option('hh_public_key_pins') == 1) {
169 $public_key_pins_sha256_1 = get_option('hh_public_key_pins_sha256_1');
170 $public_key_pins_sha256_2 = get_option('hh_public_key_pins_sha256_2');
171 $public_key_pins_max_age = get_option('hh_public_key_pins_max_age');
172 $public_key_pins_sub_domains = get_option('hh_public_key_pins_sub_domains');
173 $public_key_pins_report_uri = get_option('hh_public_key_pins_report_uri');
174 $public_key_pins_report_only = get_option('hh_public_key_pins_report_only');
175 if (!empty($public_key_pins_sha256_1) && !empty($public_key_pins_sha256_2) && !empty($public_key_pins_max_age)) {
176
177 $public_key_pins = array();
178 $public_key_pins[] = sprintf('pin-sha256="%s"', $public_key_pins_sha256_1);
179 $public_key_pins[] = sprintf('pin-sha256="%s"', $public_key_pins_sha256_2);
180 $public_key_pins[] = sprintf("max-age=%u", $public_key_pins_max_age);
181 if ($public_key_pins_sub_domains) {
182 $public_key_pins[] = "includeSubDomains";
183 }
184 if (!empty($public_key_pins_report_uri)) {
185 $public_key_pins[] = sprintf('report-uri="%s"', $public_key_pins_report_uri);
186 }
187 $headers['Public-Key-Pins'.($public_key_pins_report_only ? '-Report-Only' : NULL)] = join('; ', $public_key_pins);
188 }
189 }
190
191 if (get_option('hh_content_security_policy') == 1)
192 {
193 $value = get_option('hh_content_security_policy_value');
194 $csp = build_csp_value($value);
195 if ($csp)
196 {
197 $csp_report_only = get_option('hh_content_security_policy_report_only');
198 $headers['Content-Security-Policy'.($csp_report_only ? '-Report-Only' : NULL)] = $csp;
199 }
200 }
201
202 if (get_option('hh_access_control_allow_origin') == 1)
203 {
204 $value = get_option('hh_access_control_allow_origin_value');
205 switch ($value)
206 {
207 case 'origin':
208 $value = get_option('hh_access_control_allow_origin_url', array());
209 if (is_scalar($value))
210 {
211 $value = array($value);
212 }
213 break;
214 }
215 if (!empty($value))
216 {
217 $headers['Access-Control-Allow-Origin'] = $value;
218 }
219 }
220 if (get_option('hh_access_control_allow_credentials') == 1)
221 {
222 $headers['Access-Control-Allow-Credentials'] = get_option('hh_access_control_allow_credentials_value');
223 }
224 if (get_option('hh_access_control_max_age') == 1)
225 {
226 $value = get_option('hh_access_control_max_age_value');
227 if (!empty($value))
228 {
229 $headers['Access-Control-Max-Age'] = intval($value);
230 }
231 }
232 if (get_option('hh_access_control_allow_methods') == 1)
233 {
234 $value = get_option('hh_access_control_allow_methods_value');
235 if (!empty($value))
236 {
237 $headers['Access-Control-Allow-Methods'] = join(', ', array_keys($value));
238 }
239 }
240 if (get_option('hh_access_control_allow_headers') == 1)
241 {
242 $tmp = array();
243 $value = get_option('hh_access_control_allow_headers_value');
244 if (!empty($value))
245 {
246 $tmp = array_merge($tmp, array_keys($value));
247 }
248 $custom = get_option('hh_access_control_allow_headers_custom');
249 if (!empty($custom))
250 {
251 $tmp = array_merge($tmp, $custom);
252 }
253 if ($tmp)
254 {
255 $tmp = array_filter($tmp, 'trim');
256 $tmp = array_unique($tmp);
257 $headers['Access-Control-Allow-Headers'] = join(', ', $tmp);
258 }
259 }
260 if (get_option('hh_access_control_expose_headers') == 1)
261 {
262 $tmp = array();
263 $value = get_option('hh_access_control_expose_headers_value');
264 if (!empty($value))
265 {
266 $tmp = array_merge($tmp, array_keys($value));
267 }
268 $custom = get_option('hh_access_control_expose_headers_custom');
269 if (!empty($custom))
270 {
271 $tmp = array_merge($tmp, $custom);
272 }
273 if ($tmp)
274 {
275 $tmp = array_filter($tmp, 'trim');
276 $tmp = array_unique($tmp);
277 $headers['Access-Control-Expose-Headers'] = join(', ', $tmp);
278 }
279 }
280 if (get_option('hh_p3p') == 1)
281 {
282 $value = get_option('hh_p3p_value');
283 if (!empty($value))
284 {
285 $headers['P3P'] = 'CP="' . join(' ', array_keys($value)) . '"';
286 }
287 }
288 if (get_option('hh_referrer_policy') == 1) {
289 $headers['Referrer-Policy'] = get_option('hh_referrer_policy_value');
290 }
291 if (get_option('hh_www_authenticate') == 1) {
292
293 switch (get_option('hh_www_authenticate_type')) {
294 case 'Basic':
295 if (!(isset($_SERVER['PHP_AUTH_USER'], $_SERVER['PHP_AUTH_PW'])
296 && $_SERVER['PHP_AUTH_USER'] == get_option('hh_www_authenticate_user')
297 && $_SERVER['PHP_AUTH_PW'] == get_option('hh_www_authenticate_pswd'))) {
298 $headers['WWW-Authenticate'] = sprintf("Basic realm='%s'", get_option('hh_www_authenticate_realm'));
299 $statuses['HTTP/1.1'] = '401 Unauthorized';
300 }
301 break;
302 case 'Digest':
303 if (empty($_SERVER['PHP_AUTH_DIGEST'])) {
304 $realm = get_option('hh_www_authenticate_realm');
305 $headers['WWW-Authenticate'] = sprintf("Digest realm='%s',qop='auth',nonce='%s',opaque='%s'",
306 $realm, uniqid(), md5($realm));
307 $statuses['HTTP/1.1'] = '401 Unauthorized';
308 }
309 break;
310 }
311 }
312 if (get_option('hh_vary') == 1)
313 {
314 $value = get_option('hh_vary_value');
315 if (!empty($value))
316 {
317 $append['Vary'] = join(', ', array_keys($value));
318 }
319 }
320
321 if (get_option('hh_expect_ct') == 1) {
322 $expect_ct_max_age = get_option('hh_expect_ct_max_age');
323 $expect_ct_report_uri = get_option('hh_expect_ct_report_uri');
324 if (!empty($expect_ct_report_uri) && !empty($expect_ct_max_age)) {
325
326 $expect_ct = array();
327 $expect_ct[] = sprintf("max-age=%u", $expect_ct_max_age);
328 if (get_option('hh_expect_ct_enforce') == 1) {
329 $expect_ct[] = "enforce";
330 }
331 $expect_ct[] = sprintf('report-uri="%s"', $expect_ct_report_uri);
332 $headers['Expect-CT'] = join(', ', $expect_ct);
333 }
334 }
335 if (get_option('hh_custom_headers') == 1) {
336 $custom_headers = get_option('hh_custom_headers_value');
337 if (isset($custom_headers['name'], $custom_headers['value']) && !empty($custom_headers['name'])) {
338 foreach ($custom_headers['name'] as $key => $name) {
339 $name = trim($name);
340 $value = trim($custom_headers['value'][$key]);
341 if (empty($name) || empty($value)) {
342 continue;
343 }
344 $headers[$name] = $value;
345 }
346 }
347 }
348 if (get_option('hh_report_to') == 1) {
349 $report_to = get_option('hh_report_to_value');
350 $tmp = array();
351 foreach ($report_to as $item)
352 {
353 $tmp[] = sprintf('{"url": "%s", "group": "%s", "max-age": %u%s}',
354 $item['url'], $item['group'], $item['max-age'], isset($item['includeSubDomains']) ? ', includeSubDomains' : NULL);
355 }
356 if ($tmp)
357 {
358 $headers['Report-To'] = join(', ', $tmp);
359 }
360 }
361 if (get_option('hh_feature_policy') == 1) {
362 $feature_policy_feature = get_option('hh_feature_policy_feature');
363 $feature_policy_value = get_option('hh_feature_policy_value');
364 $feature_policy_origin = get_option('hh_feature_policy_origin');
365 $tmp = array();
366 $feature_policy_feature = is_array($feature_policy_feature) ? $feature_policy_feature : array();
367 foreach (array_keys($feature_policy_feature) as $feature)
368 {
369 $value = NULL;
370 switch ($feature_policy_value[$feature])
371 {
372 case '*':
373 case "'none'":
374 $value = $feature_policy_value[$feature];
375 break;
376 case "'self'":
377 $value = $feature_policy_value[$feature];
378 if (!empty($feature_policy_origin[$feature]))
379 {
380 $value .= " " . $feature_policy_origin[$feature];
381 }
382 break;
383 case 'origin(s)':
384 $value = $feature_policy_origin[$feature];
385 break;
386 }
387
388 $tmp[] = sprintf("%s %s", $feature, $value);
389 }
390 if ($tmp)
391 {
392 $headers['Feature-Policy'] = join('; ', $tmp);
393 }
394 }
395
396 return array($headers, $statuses, $unset, $append);
397 }
398
399 function http_digest_parse($txt) {
400 $txt = stripslashes($txt);
401
402 $needed_parts = array('nonce'=>1, 'nc'=>1, 'cnonce'=>1, 'qop'=>1, 'username'=>1, 'uri'=>1, 'response'=>1);
403 $data = array();
404 $keys = implode('|', array_keys($needed_parts));
405
406 preg_match_all('@(' . $keys . ')=(?:([\'"])([^\2]+?)\2|([^\s,]+))@', $txt, $matches, PREG_SET_ORDER);
407
408 foreach ($matches as $m) {
409 $data[$m[1]] = $m[3] ? $m[3] : $m[4];
410 unset($needed_parts[$m[1]]);
411 }
412
413 return $needed_parts ? false : $data;
414 }
415
416 function php_auth_digest() {
417 if (!($data = http_digest_parse($_SERVER['PHP_AUTH_DIGEST'])) || get_option('hh_www_authenticate_user') != $data['username']) {
418 die('Wrong Credentials!');
419 }
420
421 $A1 = md5($data['username'] . ':' . get_option('hh_www_authenticate_realm') . ':' . get_option('hh_www_authenticate_pswd'));
422 $A2 = md5($_SERVER['REQUEST_METHOD'].':'.$data['uri']);
423 $valid_response = md5($A1.':'.$data['nonce'].':'.$data['nc'].':'.$data['cnonce'].':'.$data['qop'].':'.$A2);
424 if ($data['response'] != $valid_response) {
425 die('Wrong Credentials!');
426 }
427 }
428
429 function php_content_encoding() {
430 if (substr_count($_SERVER['HTTP_ACCEPT_ENCODING'], 'gzip')) {
431 ob_start('ob_gzhandler');
432 } else {
433 ob_start();
434 }
435 }
436
437 function php_cookie_security_directives() {
438 $lines = array();
439 if (get_option('hh_cookie_security') == 1) {
440 $value = get_option('hh_cookie_security_value', array());
441 if (isset($value['HttpOnly'])) {
442 $lines[] = 'session.cookie_httponly = on';
443 }
444 if (isset($value['Secure'])) {
445 $lines[] = 'session.cookie_secure = on';
446 }
447 if (isset($value['SameSite']) && in_array($value['SameSite'], array('None', 'Lax', 'Strict'))) {
448 $lines[] = sprintf('session.cookie_samesite = "%s"', $value['SameSite']);
449 }
450 }
451
452 return $lines;
453 }
454
455 function http_headers() {
456 if (get_option('hh_method') !== 'php') {
457 return;
458 }
459 // PHP method below
460 list($headers, $statuses, $unset, $append) = get_http_headers();
461 $isCors = false;
462 foreach ($headers as $key => $value) {
463 if ($key == 'Access-Control-Allow-Origin') {
464 if (isset($_SERVER['HTTP_ORIGIN'])) {
465 if (in_array($value, array('*', 'null'))) {
466 $isCors = true;
467 header(sprintf("%s: *", $key));
468 }
469
470 if (is_array($value) && in_array($_SERVER['HTTP_ORIGIN'], $value)) {
471 $isCors = true;
472 header(sprintf("%s: %s", $key, $_SERVER['HTTP_ORIGIN']));
473 header("Vary: Origin", false);
474 }
475 }
476 continue;
477 }
478 if (in_array($key, array('Access-Control-Allow-Headers', 'Access-Control-Allow-Methods', 'Access-Control-Allow-Credentials', 'Access-Control-Max-Age', 'Access-Control-Expose-Headers'))) {
479 if ($isCors) {
480 header(sprintf("%s: %s", $key, $value));
481 }
482 continue;
483 }
484 header(sprintf("%s: %s", $key, $value));
485 }
486 foreach ($append as $key => $value) {
487 header(sprintf("%s: %s", $key, $value), false);
488 }
489 foreach ($unset as $header) {
490 if (function_exists('header_remove')) {
491 header_remove($header);
492 } else {
493 header("$header:");
494 }
495 }
496 foreach ($statuses as $key => $value) {
497 header(sprintf("%s %s", $key, $value));
498 exit;
499 }
500
501 if (get_option('hh_www_authenticate') == 1) {
502 php_auth_digest();
503 }
504
505 if (get_option('hh_content_encoding') == 1) {
506 php_content_encoding();
507 }
508 }
509
510 function http_headers_admin_add_page() {
511 add_options_page('HTTP Headers', 'HTTP Headers', 'manage_options', 'http-headers', 'http_headers_admin_page');
512 }
513
514 function http_headers_admin() {
515 register_setting('http-headers-mtd', 'hh_method');
516 register_setting('http-headers-xfo', 'hh_x_frame_options');
517 register_setting('http-headers-xfo', 'hh_x_frame_options_value');
518 register_setting('http-headers-xfo', 'hh_x_frame_options_domain');
519 register_setting('http-headers-xss', 'hh_x_xxs_protection');
520 register_setting('http-headers-xss', 'hh_x_xxs_protection_value');
521 register_setting('http-headers-xss', 'hh_x_xxs_protection_uri');
522 register_setting('http-headers-cto', 'hh_x_content_type_options');
523 register_setting('http-headers-cto', 'hh_x_content_type_options_value');
524 register_setting('http-headers-sts', 'hh_strict_transport_security');
525 register_setting('http-headers-sts', 'hh_strict_transport_security_value'); //obsolete
526 register_setting('http-headers-sts', 'hh_strict_transport_security_max_age');
527 register_setting('http-headers-sts', 'hh_strict_transport_security_sub_domains');
528 register_setting('http-headers-sts', 'hh_strict_transport_security_preload');
529 register_setting('http-headers-pkp', 'hh_public_key_pins');
530 register_setting('http-headers-pkp', 'hh_public_key_pins_sha256_1');
531 register_setting('http-headers-pkp', 'hh_public_key_pins_sha256_2');
532 register_setting('http-headers-pkp', 'hh_public_key_pins_max_age');
533 register_setting('http-headers-pkp', 'hh_public_key_pins_sub_domains');
534 register_setting('http-headers-pkp', 'hh_public_key_pins_report_uri');
535 register_setting('http-headers-pkp', 'hh_public_key_pins_report_only');
536 register_setting('http-headers-uac', 'hh_x_ua_compatible');
537 register_setting('http-headers-uac', 'hh_x_ua_compatible_value');
538 register_setting('http-headers-p3p', 'hh_p3p');
539 register_setting('http-headers-p3p', 'hh_p3p_value');
540 register_setting('http-headers-rp', 'hh_referrer_policy');
541 register_setting('http-headers-rp', 'hh_referrer_policy_value');
542 register_setting('http-headers-csp', 'hh_content_security_policy');
543 register_setting('http-headers-csp', 'hh_content_security_policy_value');
544 register_setting('http-headers-csp', 'hh_content_security_policy_report_only');
545 register_setting('http-headers-acao', 'hh_access_control_allow_origin');
546 register_setting('http-headers-acao', 'hh_access_control_allow_origin_value');
547 register_setting('http-headers-acao', 'hh_access_control_allow_origin_url');
548 register_setting('http-headers-acac', 'hh_access_control_allow_credentials');
549 register_setting('http-headers-acac', 'hh_access_control_allow_credentials_value');
550 register_setting('http-headers-acam', 'hh_access_control_allow_methods');
551 register_setting('http-headers-acam', 'hh_access_control_allow_methods_value');
552 register_setting('http-headers-acah', 'hh_access_control_allow_headers');
553 register_setting('http-headers-acah', 'hh_access_control_allow_headers_value');
554 register_setting('http-headers-acah', 'hh_access_control_allow_headers_custom');
555 register_setting('http-headers-aceh', 'hh_access_control_expose_headers');
556 register_setting('http-headers-aceh', 'hh_access_control_expose_headers_value');
557 register_setting('http-headers-aceh', 'hh_access_control_expose_headers_custom');
558 register_setting('http-headers-acma', 'hh_access_control_max_age');
559 register_setting('http-headers-acma', 'hh_access_control_max_age_value');
560 register_setting('http-headers-ce', 'hh_content_encoding');
561 register_setting('http-headers-ce', 'hh_content_encoding_module');
562 register_setting('http-headers-ce', 'hh_content_encoding_value');
563 register_setting('http-headers-ce', 'hh_content_encoding_ext');
564 register_setting('http-headers-vary', 'hh_vary');
565 register_setting('http-headers-vary', 'hh_vary_value');
566 register_setting('http-headers-xpb', 'hh_x_powered_by');
567 register_setting('http-headers-xpb', 'hh_x_powered_by_option');
568 register_setting('http-headers-xpb', 'hh_x_powered_by_value');
569 register_setting('http-headers-wwa', 'hh_www_authenticate');
570 register_setting('http-headers-wwa', 'hh_www_authenticate_type');
571 register_setting('http-headers-wwa', 'hh_www_authenticate_realm');
572 register_setting('http-headers-wwa', 'hh_www_authenticate_user');
573 register_setting('http-headers-wwa', 'hh_www_authenticate_pswd');
574 register_setting('http-headers-cc', 'hh_cache_control');
575 register_setting('http-headers-cc', 'hh_cache_control_value');
576 register_setting('http-headers-age', 'hh_age');
577 register_setting('http-headers-age', 'hh_age_value');
578 register_setting('http-headers-pra', 'hh_pragma');
579 register_setting('http-headers-pra', 'hh_pragma_value');
580 register_setting('http-headers-exp', 'hh_expires');
581 register_setting('http-headers-exp', 'hh_expires_value');
582 register_setting('http-headers-exp', 'hh_expires_type');
583 register_setting('http-headers-con', 'hh_connection');
584 register_setting('http-headers-con', 'hh_connection_value');
585 register_setting('http-headers-cose', 'hh_cookie_security');
586 register_setting('http-headers-cose', 'hh_cookie_security_value');
587 register_setting('http-headers-ect', 'hh_expect_ct');
588 register_setting('http-headers-ect', 'hh_expect_ct_max_age');
589 register_setting('http-headers-ect', 'hh_expect_ct_report_uri');
590 register_setting('http-headers-ect', 'hh_expect_ct_enforce');
591 register_setting('http-headers-tao', 'hh_timing_allow_origin');
592 register_setting('http-headers-tao', 'hh_timing_allow_origin_value');
593 register_setting('http-headers-tao', 'hh_timing_allow_origin_url');
594 register_setting('http-headers-che', 'hh_custom_headers');
595 register_setting('http-headers-che', 'hh_custom_headers_value');
596 register_setting('http-headers-xdo', 'hh_x_download_options');
597 register_setting('http-headers-xdo', 'hh_x_download_options_value');
598 register_setting('http-headers-xpcd', 'hh_x_permitted_cross_domain_policies');
599 register_setting('http-headers-xpcd', 'hh_x_permitted_cross_domain_policies_value');
600 register_setting('http-headers-xdpc', 'hh_x_dns_prefetch_control');
601 register_setting('http-headers-xdpc', 'hh_x_dns_prefetch_control_value');
602 register_setting('http-headers-rt', 'hh_report_to');
603 register_setting('http-headers-rt', 'hh_report_to_value');
604 register_setting('http-headers-fp', 'hh_feature_policy');
605 register_setting('http-headers-fp', 'hh_feature_policy_value');
606 register_setting('http-headers-fp', 'hh_feature_policy_feature');
607 register_setting('http-headers-fp', 'hh_feature_policy_origin');
608 register_setting('http-headers-csd', 'hh_clear_site_data');
609 register_setting('http-headers-csd', 'hh_clear_site_data_value');
610 register_setting('http-headers-cty', 'hh_content_type');
611 register_setting('http-headers-cty', 'hh_content_type_value');
612 }
613
614 function http_headers_option($option) {
615
616 include_once ABSPATH . 'wp-admin/includes/admin.php';
617
618 if (isset($_POST['hh_method']))
619 {
620 check_admin_referer('http-headers-mtd-options');
621 # When method is changed
622 http_headers_activate();
623
624 } elseif (get_option('hh_method') == 'htaccess') {
625 # When particular header is changed
626 switch (true) {
627 case array_key_exists('hh_www_authenticate', $_POST):
628 check_admin_referer('http-headers-wwa-options');
629 update_auth_credentials();
630 update_auth_directives();
631 break;
632 case array_key_exists('hh_content_encoding', $_POST):
633 check_admin_referer('http-headers-ce-options');
634 update_content_encoding_directives();
635 break;
636 case array_key_exists('hh_content_type', $_POST):
637 check_admin_referer('http-headers-cty-options');
638 update_content_type_directives();
639 break;
640 case array_key_exists('hh_expires', $_POST):
641 check_admin_referer('http-headers-exp-options');
642 update_expires_directives();
643 break;
644 case array_key_exists('hh_cookie_security', $_POST):
645 check_admin_referer('http-headers-cose-options');
646 update_cookie_security_directives();
647 break;
648 case array_key_exists('hh_timing_allow_origin', $_POST):
649 check_admin_referer('http-headers-tao-options');
650 update_timing_directives();
651 break;
652 case array_key_exists('option_page', $_POST) && strpos($_POST['option_page'], 'http-headers-') === 0:
653 check_admin_referer($_POST['option_page'].'-options');
654 update_headers_directives();
655 break;
656 }
657 }
658 }
659
660 function nginx_headers_directives() {
661 $lines = array();
662 list($headers, $statuses, $unset, $append) = get_http_headers();
663
664 foreach ($unset as $header) {
665 $lines[] = sprintf(' more_clear_headers "%s";', $header);
666 }
667 $cors = $cors_header = $cors_inner = $cors_footer = array();
668 $all = array();
669 foreach ($headers as $key => $value) {
670 if (in_array($key, array('WWW-Authenticate'))) {
671 continue;
672 }
673 if (in_array($key, array('X-Content-Type-Options'))) {
674 $all[] = sprintf('add_header %s %s always;', $key, sprintf('%1$s%2$s%1$s', strpos($value, '"') === false ? '"' : "'", $value));
675 continue;
676 }
677 if ($key == 'Access-Control-Allow-Origin' && is_array($value)) {
678 $cors_header[] = sprintf('if ($http_origin ~* ^(%s)$) {', str_replace('.', '\.', join('|', $value)));
679 $cors_footer[] = '}';
680 $cors_inner[] = ' add_header Access-Control-Allow-Origin "$http_origin";';
681 if (!in_array('*', $value))
682 {
683 $cors_inner[] = ' add_header Vary "Origin";';
684 }
685 continue;
686 }
687 if (in_array($key, array('Access-Control-Allow-Headers', 'Access-Control-Allow-Methods', 'Access-Control-Allow-Credentials', 'Access-Control-Max-Age', 'Access-Control-Expose-Headers'))) {
688 $cors_inner[] = sprintf(' add_header %s %s;', $key, sprintf('%1$s%2$s%1$s', strpos($value, '"') === false ? '"' : "'", $value));
689 continue;
690 }
691 $lines[] = sprintf(' add_header %s %s;', $key, sprintf('%1$s%2$s%1$s', strpos($value, '"') === false ? '"' : "'", $value));
692 }
693 foreach ($append as $key => $value) {
694 $lines[] = sprintf(' add_header %s %s;', $key, sprintf('%1$s%2$s%1$s', strpos($value, '"') === false ? '"' : "'", $value));
695 }
696 if (!empty($cors_inner))
697 {
698 $cors = array_merge(
699 $cors_header,
700 $cors_inner,
701 $cors_footer
702 );
703 }
704 if (!empty($lines)) {
705 $lines = array_merge(
706 $all,
707 $cors,
708 array('location ~* \.(php|html)$ {'),
709 $lines,
710 array('}')
711 );
712 }
713 return $lines;
714 }
715
716 function nginx_content_encoding_directives() {
717 $lines = array();
718 if (get_option('hh_content_encoding') == 1) {
719
720 $lines[] = 'gzip on;';
721
722 $content_encoding_value = get_option('hh_content_encoding_value');
723 if (!$content_encoding_value) {
724 $content_encoding_value = array();
725 }
726
727 $content_encoding_ext = get_option('hh_content_encoding_ext');
728 if (!$content_encoding_ext) {
729 $content_encoding_ext = array();
730 }
731 if (!empty($content_encoding_ext)) {
732 //$lines[] = sprintf('<FilesMatch "\.(%s)$">', join('|', array_keys($content_encoding_ext)));
733 }
734 if (!empty($content_encoding_value)) {
735 $lines[] = sprintf('gzip_types %s;', join(' ', array_keys($content_encoding_value)));
736 }
737 }
738 return $lines;
739 }
740
741 function nginx_content_type_directives() {
742 $lines = array();
743 if (get_option('hh_content_type') == 1) {
744 $values = get_option('hh_content_type_value', array());
745 foreach ($values as $ext => $media_type) {
746 $lines[] = sprintf("%s %s;", $media_type, $ext);
747 }
748 }
749
750 return $lines;
751 }
752
753 function nginx_expires_directives() {
754 $lines = array();
755 if (get_option('hh_expires') == 1) {
756
757 $types = get_option('hh_expires_type', array());
758 $values = get_option('hh_expires_value', array());
759
760 $lines[] = 'map $sent_http_content_type $expires {';
761 foreach ($types as $type => $whatever) {
762 list($base, $period, $suffix) = explode('_', $values[$type]);
763 if (in_array($base, array('access', 'modification'))) {
764 $lines[] = $type != 'default'
765 ? sprintf(' %s %u%s;', $type, $period, $suffix[0])
766 : sprintf(' default %u%s;', $period, $suffix[0]);
767 } elseif ($base == 'invalid') {
768 $lines[] = $type != 'default'
769 ? sprintf(' %s 0;', $type)
770 : sprintf(' default 0;');
771 }
772 }
773 $lines[] = '}';
774
775 $lines[] = 'expires $expires;';
776 }
777 return $lines;
778 }
779
780 function nginx_timing_directives() {
781 $lines = array();
782 if (get_option('hh_timing_allow_origin') == 1) {
783 $value = get_option('hh_timing_allow_origin_value');
784 switch ($value)
785 {
786 case 'origin':
787 $value = get_option('hh_timing_allow_origin_url');
788 break;
789 }
790 if (!empty($value))
791 {
792 $lines[] = 'location ~* \.(js|css|jpe?g|png|gif|eot|otf|svg|ttf|woff2?)$ {';
793 $lines[] = sprintf(' add_header Timing-Allow-Origin "%s";', $value);
794 $lines[] = '}';
795 }
796 }
797 return $lines;
798 }
799
800 function nginx_auth_directives() {
801 $lines = array();
802 if (get_option('hh_www_authenticate') == 1) {
803
804 $type = get_option('hh_www_authenticate_type');
805
806 $file = $type == 'Basic' ? '.hh-htpasswd' : '.hh-htdigest';
807
808 $lines[] = 'location ~ ^\.hh-ht(digest|passwd)$ {';
809 $lines[] = ' deny all;';
810 $lines[] = '}';
811
812 $lines[] = sprintf('location %s {', get_home_path());
813 if ($type == 'Basic') {
814 $lines[] = sprintf(' auth_basic "%s";', get_option('hh_www_authenticate_realm'));
815 $lines[] = sprintf(' auth_basic_user_file %s%s;', get_home_path(), $file);
816 } else {
817 $lines[] = sprintf(' auth_digest "%s";', get_option('hh_www_authenticate_realm'));
818 $lines[] = sprintf(' auth_digest_user_file %s%s;', get_home_path(), $file);
819 }
820 $lines[] = '}';
821 }
822 return $lines;
823 }
824
825 function nginx_auth_credentials() {
826 return apache_auth_credentials();
827 }
828
829 function nginx_cookie_security_directives() {
830 $lines = array();
831
832 //TODO
833
834 return $lines;
835 }
836
837 function nginx_check_requirements() {
838 //TODO scheduled for v2.0.0
839 return true;
840 }
841
842 function iis_headers_directives() {
843 //TODO scheduled for v2.0.0
844 }
845
846 function iis_content_encoding_directives() {
847 //TODO scheduled for v2.0.0
848 }
849
850 function iis_content_type_directives() {
851 //TODO scheduled for v2.0.0
852 }
853
854 function iis_expires_directives() {
855 //TODO scheduled for v2.0.0
856 }
857
858 function iis_timing_directives() {
859 //TODO scheduled for v2.0.0
860 }
861
862 function iis_auth_directives() {
863 //TODO scheduled for v2.0.0
864 }
865
866 function iis_auth_credentials() {
867 //TODO scheduled for v2.0.0
868 }
869
870 function iis_cookie_security_directives() {
871 //TODO scheduled for v2.0.0
872 }
873
874 function iis_check_requirements() {
875 //TODO scheduled for v2.0.0
876 return true;
877 }
878
879 function apache_headers_directives() {
880 $lines = array();
881 list($headers, $statuses, $unset, $append) = get_http_headers();
882
883 foreach ($unset as $header) {
884 $lines[] = sprintf(' Header always unset %s', $header);
885 $lines[] = sprintf(' Header unset %s', $header);
886 }
887 $all = array();
888 foreach ($headers as $key => $value) {
889 if (in_array($key, array('WWW-Authenticate'))) {
890 continue;
891 }
892 if (in_array($key, array('X-Content-Type-Options'))) {
893 $all[] = sprintf(' Header always set %s %s', $key, sprintf('%1$s%2$s%1$s', strpos($value, '"') === false ? '"' : "'", $value));
894 continue;
895 }
896 if ($key == 'Strict-Transport-Security') {
897 $lines[] = sprintf(' Header set %s %s env=HTTPS', $key, sprintf('%1$s%2$s%1$s', strpos($value, '"') === false ? '"' : "'", $value));
898 continue;
899 }
900 if ($key == 'Access-Control-Allow-Origin') {
901 $all[] = ' <IfModule mod_setenvif.c>';
902 if (!is_array($value)) {
903 if ($value) {
904 $value = array($value);
905 } else {
906 $value = array();
907 }
908 }
909 //$value[] = 'null';
910 if (is_array($value))
911 {
912 $all[] = sprintf(' SetEnvIf Origin "^(%s)$" CORS=$0', str_replace(array('.', '*'), array('\.', '\*'), join('|', $value)));
913 } else {
914 $all[] = ' SetEnvIf Origin "^(.+)$" CORS=$0';
915 }
916 $all[] = ' </IfModule>';
917 $all[] = ' Header set Access-Control-Allow-Origin %{CORS}e env=CORS';
918 if (!in_array('*', $value))
919 {
920 $all[] = ' Header append Vary "Origin" env=CORS';
921 }
922 continue;
923 }
924 if (in_array($key, array('Access-Control-Allow-Headers', 'Access-Control-Allow-Methods', 'Access-Control-Allow-Credentials', 'Access-Control-Max-Age', 'Access-Control-Expose-Headers'))) {
925 $all[] = sprintf(' Header set %s %s env=CORS', $key, sprintf('%1$s%2$s%1$s', strpos($value, '"') === false ? '"' : "'", $value));
926 continue;
927 }
928 $lines[] = sprintf(' Header set %s %s', $key, sprintf('%1$s%2$s%1$s', strpos($value, '"') === false ? '"' : "'", $value));
929 }
930 foreach ($append as $key => $value) {
931 $lines[] = sprintf(' Header append %s %s', $key, sprintf('%1$s%2$s%1$s', strpos($value, '"') === false ? '"' : "'", $value));
932 }
933 if (!empty($lines) || !empty($all)) {
934 $lines = array_merge(
935 array('<IfModule mod_headers.c>'),
936 $all,
937 array(' <FilesMatch "\.(php|html)$">'),
938 $lines,
939 array(' </FilesMatch>', '</IfModule>')
940 );
941 }
942 return $lines;
943 }
944
945 function apache_content_encoding_directives() {
946 $lines = array();
947 if (get_option('hh_content_encoding') == 1) {
948
949 $content_encoding_module = get_option('hh_content_encoding_module');
950
951 $module = 'mod_deflate.c';
952 $filter = 'DEFLATE';
953 $accept_encoding = 'gzip';
954
955 if ($content_encoding_module == 'brotli') {
956 $module = 'mod_brotli.c';
957 $filter = 'BROTLI_COMPRESS';
958 $accept_encoding = 'br';
959 }
960
961 $content_encoding_value = get_option('hh_content_encoding_value');
962 if (!$content_encoding_value) {
963 $content_encoding_value = array();
964 }
965
966 $content_encoding_ext = get_option('hh_content_encoding_ext');
967 if (!$content_encoding_ext) {
968 $content_encoding_ext = array();
969 }
970
971 $type = join('|', array_keys($content_encoding_value));
972 $ext = join('|', array_keys($content_encoding_ext));
973
974 if (!empty($type) && !empty($ext)) {
975 $expression = sprintf('(%%{CONTENT_TYPE} =~ m#^(%1$s)# || %%{REQUEST_FILENAME} =~ /.(%2$s)$/)', $type, $ext);
976 } elseif (!empty($type)) {
977 $expression = sprintf('%%{CONTENT_TYPE} =~ m#^(%1$s)#', $type);
978 } elseif (!empty($ext)) {
979 $expression = sprintf('%%{REQUEST_FILENAME} =~ /.(%1$s)$/', $ext);
980 }
981
982 if (isset($expression)) {
983 $lines[] = '<IfModule mod_filter.c>';
984 $lines[] = ' FilterDeclare HttpHeaders';
985 if (in_array($content_encoding_module, array('brotli', 'deflate'))) {
986 $lines[] = sprintf('<IfModule %s>', $module);
987 $lines[] = sprintf(' FilterProvider HttpHeaders %1$s "%%{HTTP:Accept-Encoding} =~ /%2$s/ && %3$s"', $filter, $accept_encoding, $expression);
988 $lines[] = ' </IfModule>';
989 } else {
990 $lines[] = ' <IfModule mod_deflate.c>';
991 $lines[] = ' <IfModule !mod_brotli.c>';
992 $lines[] = sprintf(' FilterProvider HttpHeaders DEFLATE "%%{HTTP:Accept-Encoding} =~ /gzip/ && %1$s"', $expression);
993 $lines[] = ' </IfModule>';
994 $lines[] = ' </IfModule>';
995 $lines[] = ' <IfModule mod_brotli.c>';
996 $lines[] = sprintf(' FilterProvider HttpHeaders BROTLI_COMPRESS "%%{HTTP:Accept-Encoding} =~ /br/ && %1$s"', $expression);
997 $lines[] = ' </IfModule>';
998 }
999 $lines[] = ' FilterChain HttpHeaders';
1000 $lines[] = '</IfModule>';
1001 }
1002 }
1003
1004 return $lines;
1005 }
1006
1007 function apache_expires_directives() {
1008 $lines = array();
1009 if (get_option('hh_expires') == 1) {
1010
1011 $types = get_option('hh_expires_type', array());
1012 $values = get_option('hh_expires_value', array());
1013
1014 $lines[] = '<IfModule mod_expires.c>';
1015 $lines[] = ' ExpiresActive On';
1016 foreach ($types as $type => $whatever) {
1017 list($base, $period, $suffix) = explode('_', $values[$type]);
1018 if (in_array($base, array('access', 'modification'))) {
1019 $lines[] = $type != 'default'
1020 ? sprintf(' ExpiresByType %s "%s plus %u %s"', $type, $base, $period, $suffix)
1021 : sprintf(' ExpiresDefault "%s plus %u %s"', $base, $period, $suffix);
1022 } elseif ($base == 'invalid') {
1023 $lines[] = $type != 'default'
1024 ? sprintf(' ExpiresByType %s A0', $type)
1025 : sprintf(' ExpiresDefault A0');
1026 }
1027 }
1028 $lines[] = '</IfModule>';
1029 }
1030
1031 return $lines;
1032 }
1033
1034 function apache_content_type_directives() {
1035 $lines = array();
1036 if (get_option('hh_content_type') == 1) {
1037 $values = get_option('hh_content_type_value', array());
1038 $lines[] = '<IfModule mod_mime.c>';
1039 foreach ($values as $ext => $media_type) {
1040 $lines[] = sprintf(" AddType %s .%s", $media_type, $ext);
1041 }
1042 $lines[] = '</IfModule>';
1043 }
1044
1045 return $lines;
1046 }
1047
1048 function apache_timing_directives() {
1049 $lines = array();
1050 if (get_option('hh_timing_allow_origin') == 1) {
1051 $value = get_option('hh_timing_allow_origin_value');
1052 switch ($value)
1053 {
1054 case 'origin':
1055 $value = get_option('hh_timing_allow_origin_url');
1056 break;
1057 }
1058 if (!empty($value))
1059 {
1060 $lines[] = '<IfModule mod_headers.c>';
1061 $lines[] = ' <FilesMatch "\\.(js|css|jpe?g|png|gif|eot|otf|svg|ttf|woff2?)$">';
1062 $lines[] = sprintf(' Header set Timing-Allow-Origin "%s"', $value);
1063 $lines[] = ' </FilesMatch>';
1064 $lines[] = '</IfModule>';
1065 }
1066 }
1067
1068 return $lines;
1069 }
1070
1071 function apache_auth_directives() {
1072 $lines = array();
1073 if (get_option('hh_www_authenticate') == 1) {
1074
1075 $type = get_option('hh_www_authenticate_type');
1076
1077 $file = $type == 'Basic' ? '.hh-htpasswd' : '.hh-htdigest';
1078
1079 $lines[] = '<FilesMatch "^\.hh-ht(digest|passwd)$">';
1080 $lines[] = ' <IfModule mod_authz_core.c>';
1081 $lines[] = ' Require all denied';
1082 $lines[] = ' </IfModule>';
1083 $lines[] = ' <IfModule !mod_authz_core.c>';
1084 $lines[] = ' Order deny,allow';
1085 $lines[] = ' Deny from all';
1086 $lines[] = ' </IfModule>';
1087 $lines[] = '</FilesMatch>';
1088 // no empty AuthName
1089 $realm = get_option('hh_www_authenticate_realm'); // AuthName
1090 $realm = ($realm == '') ? 'restricted area':$realm; // Empty => give fixed value
1091
1092 $lines[] = sprintf('<IfModule mod_auth_%s.c>', strtolower($type));
1093 $lines[] = sprintf(' AuthType %s', get_option('hh_www_authenticate_type'));
1094 $lines[] = sprintf(' AuthName "%s"', $realm);
1095 $lines[] = sprintf(' AuthUserFile "%s%s"', get_home_path(), $file);
1096 $lines[] = ' Require valid-user';
1097 $lines[] = '</IfModule>';
1098 }
1099
1100 return $lines;
1101 }
1102
1103 function apache_auth_credentials() {
1104 if (get_option('hh_www_authenticate') == 1) {
1105 $type = get_option('hh_www_authenticate_type');
1106 $usernames = get_option('hh_www_authenticate_user', array());
1107 $passwords = get_option('hh_www_authenticate_pswd', array());
1108 if (!is_array($usernames)) {
1109 $usernames = array($usernames);
1110 }
1111 if (!is_array($passwords)) {
1112 $passwords = array($passwords);
1113 }
1114 $realm = get_option('hh_www_authenticate_realm');
1115 $auth = array();
1116 switch ($type) {
1117 case 'Basic':
1118 $ht_file = get_home_path().'.hh-htpasswd';
1119 foreach ($usernames as $k => $user) {
1120 $auth[] = sprintf('%s:{SHA}%s', $user, base64_encode(sha1($passwords[$k], true)));
1121 }
1122 break;
1123 case 'Digest':
1124 $ht_file = get_home_path().'.hh-htdigest';
1125 foreach ($usernames as $k => $user) {
1126 $auth[] = sprintf('%s:%s:%s', $user, $realm, md5($user.':'.$realm.':'.$passwords[$k]));
1127 }
1128 break;
1129 }
1130 $auth = join("\n", $auth);
1131
1132 return compact('ht_file', 'auth');
1133 }
1134 return false;
1135 }
1136
1137 function apache_cookie_security_directives() {
1138 $lines = array();
1139 if (get_option('hh_cookie_security') == 1) {
1140 $value = get_option('hh_cookie_security_value', array());
1141 if (isset($value['HttpOnly'])) {
1142 $lines[] = 'php_flag session.cookie_httponly on';
1143 }
1144 if (isset($value['Secure'])) {
1145 $lines[] = 'php_flag session.cookie_secure on';
1146 }
1147 if (isset($value['SameSite']) && in_array($value['SameSite'], array('None', 'Lax', 'Strict'))) {
1148 $lines[] = sprintf('php_value session.cookie_samesite "%s"', $value['SameSite']);
1149 }
1150 }
1151
1152 return $lines;
1153 }
1154
1155 function apache_check_requirements() {
1156 return check_filename(get_home_path().'.htaccess');
1157 }
1158
1159 function update_headers_directives() {
1160 $lines = array();
1161 if (get_option('hh_method') == 'htaccess') {
1162 $lines = apache_headers_directives();
1163 }
1164
1165 return insert_with_markers(get_home_path().'.htaccess', "HttpHeaders", $lines);
1166 }
1167
1168 function update_content_encoding_directives() {
1169 $lines = array();
1170 if (get_option('hh_method') == 'htaccess') {
1171 $lines = apache_content_encoding_directives();
1172 }
1173
1174 return insert_with_markers(get_home_path().'.htaccess', "HttpHeadersCompression", $lines);
1175 }
1176
1177 function update_expires_directives() {
1178 $lines = array();
1179 if (get_option('hh_method') == 'htaccess') {
1180 $lines = apache_expires_directives();
1181 }
1182
1183 return insert_with_markers(get_home_path().'.htaccess', "HttpHeadersExpires", $lines);
1184 }
1185
1186 function update_content_type_directives() {
1187 $lines = array();
1188 if (get_option('hh_method') == 'htaccess') {
1189 $lines = apache_content_type_directives();
1190 }
1191
1192 return insert_with_markers(get_home_path().'.htaccess', "HttpHeadersContentType", $lines);
1193 }
1194
1195 function update_timing_directives() {
1196 $lines = array();
1197 if (get_option('hh_method') == 'htaccess') {
1198 $lines = apache_timing_directives();
1199 }
1200
1201 return insert_with_markers(get_home_path().'.htaccess', "HttpHeadersTiming", $lines);
1202 }
1203
1204 function update_auth_directives() {
1205 $lines = array();
1206 if (get_option('hh_method') == 'htaccess') {
1207 $lines = apache_auth_directives();
1208 }
1209
1210 return insert_with_markers(get_home_path().'.htaccess', "HttpHeadersAuth", $lines);
1211 }
1212
1213 function update_auth_credentials() {
1214 if (get_option('hh_method') == 'htaccess') {
1215 $credentials = apache_auth_credentials();
1216
1217 return @file_put_contents($credentials['ht_file'], $credentials['auth']);
1218 }
1219
1220 return false;
1221 }
1222
1223 function update_cookie_security_directives() {
1224 $lines = array();
1225 $is_apache = get_option('hh_method') == 'htaccess';
1226 $htaccess = get_home_path().'.htaccess';
1227 if (strpos(PHP_SAPI, 'cgi') !== false) {
1228 $filename = get_home_path().ini_get('user_ini.filename');
1229 $lines = php_cookie_security_directives();
1230 } elseif ($is_apache) {
1231 $filename = $htaccess;
1232 $lines = apache_cookie_security_directives();
1233 }
1234
1235 if (!$is_apache) {
1236 insert_with_markers($htaccess, "HttpHeadersCookieSecurity", array());
1237 }
1238
1239 return insert_with_markers($filename, "HttpHeadersCookieSecurity", $lines);
1240 }
1241
1242 function is_samesite_supported() {
1243 return version_compare(PHP_VERSION, '7.3.0', '>=');
1244 }
1245
1246 function http_headers_text_domain() {
1247 load_plugin_textdomain('http-headers', false, basename( dirname( __FILE__ ) ) . '/languages/');
1248 }
1249
1250 function http_headers_settings_link( $links ) {
1251 $url = get_admin_url() . 'options-general.php?page=http-headers';
1252 $settings_link = '<a href="' . $url . '">' . __('Settings', 'http-headers') . '</a>';
1253 array_unshift( $links, $settings_link );
1254 return $links;
1255 }
1256
1257 function http_headers_after_setup_theme() {
1258 add_filter('plugin_action_links_' . plugin_basename(__FILE__), 'http_headers_settings_link');
1259 }
1260
1261 function http_headers_enqueue($hook) {
1262 if ( 'http-headers.php' != $hook ) {
1263 # FIXME
1264 //return;
1265 }
1266
1267 wp_enqueue_script('http_headers_admin_scripts', plugin_dir_url( __FILE__ ) . 'assets/scripts.js', array(), '1.14.0', true);
1268 wp_localize_script('http_headers_admin_scripts', 'hh', array(
1269 'lbl_delete' => __('Delete', 'http-headers'),
1270 'lbl_value' => __('Value', 'http-headers'),
1271 ));
1272 wp_enqueue_style('http_headers_admin_styles', plugin_dir_url( __FILE__ ) . 'assets/styles.css');
1273 }
1274
1275 function http_headers_ajax_inspect() {
1276 check_ajax_referer('inspect');
1277 if (current_user_can('manage_options')) {
1278 include 'views/ajax-inspect.php';
1279 }
1280 wp_die();
1281 }
1282
1283 function http_headers_post_import() {
1284 check_admin_referer('import');
1285 global $wpdb;
1286 if (!(isset($_FILES['file']['tmp_name'])
1287 && is_uploaded_file($_FILES['file']['tmp_name'])
1288 && $_FILES['file']['error'] == UPLOAD_ERR_OK
1289 )) {
1290 wp_redirect(sprintf("%soptions-general.php?page=http-headers&tab=advanced&status=ERR&code=100", get_admin_url()));
1291 exit;
1292 }
1293
1294 $string = @file_get_contents($_FILES['file']['tmp_name']);
1295 if ($string === false) {
1296 wp_redirect(sprintf("%soptions-general.php?page=http-headers&tab=advanced&status=ERR&code=101", get_admin_url()));
1297 exit;
1298 }
1299
1300 $arr = preg_split('/;(\s+)?\n/', $string);
1301 foreach ($arr as $statement) {
1302 $statement = preg_replace("/(INSERT\s*INTO\s*)[\w\_]+options/", '${1}'.$wpdb->options, $statement);
1303 $wpdb->query($statement);
1304 }
1305
1306 wp_redirect(sprintf("%soptions-general.php?page=http-headers&tab=advanced&status=OK", get_admin_url()));
1307 exit;
1308 }
1309
1310 function http_headers_post_export() {
1311 check_admin_referer('export');
1312 global $wpdb;
1313 $options = include dirname(__FILE__) . '/views/includes/options.inc.php';
1314 $opts = array();
1315 foreach ($options as $option)
1316 {
1317 $opts[] = $option[0];
1318 }
1319 $statement = sprintf("SELECT * FROM %s WHERE option_name IN ('%s');", $wpdb->options, join("','", $opts));
1320 $results = $wpdb->get_results($statement, ARRAY_A);
1321 $sql = array();
1322
1323 $indexes = array();
1324 foreach ($options as $option)
1325 {
1326 foreach ($results as $item)
1327 {
1328 if ($item['option_name'] == $option[0])
1329 {
1330 $indexes[$option[0]] = 1;
1331
1332 $value = str_replace("'", "''", $item['option_value']);
1333 $query = array();
1334 $query[] = sprintf("INSERT INTO %s (option_id, option_name, option_value, autoload)", $wpdb->options);
1335 $query[] = sprintf("VALUES (NULL, '%s', '%s', '%s')", $item['option_name'], $value, $item['autoload']);
1336 $query[] = sprintf("ON DUPLICATE KEY UPDATE option_value = '%s', autoload = '%s';", $value, $item['autoload']);
1337 $sql[] = join("\n", $query);
1338 break;
1339 }
1340 }
1341
1342 if (!isset($indexes[$option[0]]))
1343 {
1344 $query = array();
1345 $query[] = sprintf("INSERT INTO %s (option_id, option_name, option_value, autoload)", $wpdb->options);
1346 $query[] = sprintf("VALUES (NULL, '%s', '%s', 'yes')", $option[0], $option[1]);
1347 $query[] = sprintf("ON DUPLICATE KEY UPDATE option_value = '%s', autoload = 'yes';", $option[1]);
1348 $sql[] = join("\n", $query);
1349 }
1350 }
1351
1352 $sql = join("\n\n", $sql);
1353 $length = function_exists('mb_strlen') ? mb_strlen($sql) : strlen($sql);
1354 $name = sprintf('WP-HTTP-Headers-%u.sql', time());
1355
1356 # Send headers
1357 header('Pragma: public');
1358 header('Expires: 0');
1359 header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
1360 header('Cache-Control: private', false);
1361 header('Content-Transfer-Encoding: binary');
1362 header('Content-Disposition: attachment; filename="'.$name.'";');
1363 header('Content-Type: application/sql');
1364 header('Content-Length: ' . $length);
1365
1366 echo $sql;
1367 exit;
1368 }
1369
1370 function check_filename($filename) {
1371 if (!is_file($filename)) {
1372 return -1;
1373 }
1374
1375 clearstatcache();
1376 if (!is_writable($filename)) {
1377 return -2;
1378 }
1379
1380 return true;
1381 }
1382
1383 function check_webserver_requirements() {
1384 $method = get_option('hh_method');
1385 if ($method == 'htaccess') {
1386 return apache_check_requirements();
1387 }
1388
1389 return true;
1390 }
1391
1392 function check_php_requirements() {
1393 if (strpos(PHP_SAPI, 'cgi') !== false) {
1394 // cgi, cgi-fcgi, fpm-fcgi
1395 return check_filename(get_home_path().ini_get('user_ini.filename'));
1396 }
1397
1398 return true;
1399 }
1400
1401 function http_headers_logout() {
1402 if (get_option('hh_clear_site_data') == 1) {
1403 $values = get_option('hh_clear_site_data_value', array());
1404 $tmp = array_keys($values);
1405 if ($tmp) {
1406 header(sprintf('Clear-Site-Data: "%s"', join('", "', $tmp)));
1407 }
1408 }
1409 }
1410
1411 function http_headers_activate() {
1412 update_headers_directives();
1413 update_auth_credentials();
1414 update_auth_directives();
1415 update_content_encoding_directives();
1416 update_content_type_directives();
1417 update_expires_directives();
1418 update_cookie_security_directives();
1419 update_timing_directives();
1420 }
1421
1422 function http_headers_deactivate() {
1423 $filename = get_home_path().'.htaccess';
1424
1425 insert_with_markers($filename, "HttpHeaders", array());
1426 insert_with_markers($filename, "HttpHeadersCompression", array());
1427 insert_with_markers($filename, "HttpHeadersContentType", array());
1428 insert_with_markers($filename, "HttpHeadersExpires", array());
1429 insert_with_markers($filename, "HttpHeadersTiming", array());
1430 insert_with_markers($filename, "HttpHeadersAuth", array());
1431 insert_with_markers($filename, "HttpHeadersCookieSecurity", array());
1432 }
1433
1434 register_activation_hook(__FILE__, 'http_headers_activate');
1435 register_deactivation_hook(__FILE__, 'http_headers_deactivate');
1436 add_action('wp_logout', 'http_headers_logout');
1437
1438 if ( is_admin() ){ // admin actions
1439 add_action('admin_menu', 'http_headers_admin_add_page');
1440 add_action('admin_init', 'http_headers_admin');
1441 add_action("added_option", 'http_headers_option');
1442 add_action("updated_option", 'http_headers_option');
1443 add_action('admin_enqueue_scripts', 'http_headers_enqueue');
1444 add_action('after_setup_theme', 'http_headers_after_setup_theme');
1445 add_action('plugins_loaded', 'http_headers_text_domain');
1446 add_action('wp_ajax_inspect', 'http_headers_ajax_inspect');
1447 add_action('admin_post_import', 'http_headers_post_import');
1448 add_action('admin_post_export', 'http_headers_post_export');
1449 } else {
1450 // non-admin enqueues, actions, and filters
1451 add_action('send_headers', 'http_headers');
1452 }
1453
1454 function http_headers_admin_page() {
1455 include 'views/index.php';
1456 }