Ticket #10237: csp-wip-v1.patch
File csp-wip-v1.patch, 35.3 KB (added by , 15 years ago) |
---|
-
wp-includes/functions.php
function get_status_header_desc( $code ) { 1587 1587 } 1588 1588 1589 1589 /** 1590 * Gets the Content Security Policy if specified by the admin. 1591 * If CSP is not enabled, then the return value will be false. 1592 * 1593 * @return string Content Security Policy header value 1594 */ 1595 function get_csp() { 1596 if (!get_option("csp_enabled")) 1597 return false; 1598 $policy = get_option("csp_value"); 1599 // use default policy "allow 'self'" if user has not configured a policy 1600 if ( !strlen(trim($policy)) ) 1601 return "allow 'self'"; 1602 else 1603 return $policy; 1604 } 1605 1606 /** 1590 1607 * Set HTTP status header. 1591 1608 * 1592 1609 * @since 2.0.0 -
wp-includes/classes.php
class WP { 317 317 */ 318 318 function send_headers() { 319 319 $headers = array('X-Pingback' => get_bloginfo('pingback_url')); 320 // Content Security Policy header 321 $csp = get_csp(); 322 if ($csp) 323 $headers["X-Content-Security-Policy"] = $csp; 324 320 325 $status = null; 321 326 $exit_required = false; 322 327 -
wp-includes/script-loader.php
function wp_default_styles( &$styles ) { 473 473 $styles->add( 'jcrop', '/wp-includes/js/jcrop/jquery.Jcrop.css', array(), '0.9.8' ); 474 474 $styles->add( 'imgareaselect', '/wp-includes/js/imgareaselect/imgareaselect.css', array(), '0.9.1' ); 475 475 $styles->add( 'nav-menu', "/wp-admin/css/nav-menu$suffix.css", array(), '20100322' ); 476 $styles->add( 'security', "/wp-admin/css/security.css", array(), '20100412' ); 476 477 477 478 foreach ( $rtl_styles as $rtl_style ) { 478 479 $styles->add_data( $rtl_style, 'rtl', true ); -
wp-admin/menu.php.rej
1 *************** $menu[80] = array( __('Settings'), 'manage_options 2 *** 158,166 **** 3 $submenu['options-general.php'][25] = array(__('Discussion'), 'manage_options', 'options-discussion.php'); 4 $submenu['options-general.php'][30] = array(__('Media'), 'manage_options', 'options-media.php'); 5 $submenu['options-general.php'][35] = array(__('Privacy'), 'manage_options', 'options-privacy.php'); 6 - $submenu['options-general.php'][40] = array(__('Permalinks'), 'manage_options', 'options-permalink.php'); 7 if ( is_super_admin() ) 8 - $submenu['options-general.php'][45] = array(__('Miscellaneous'), 'manage_options', 'options-misc.php'); 9 10 $_wp_last_utility_menu = 80; // The index of the last top-level menu in the utility menu group 11 12 --- 158,167 ---- 13 $submenu['options-general.php'][25] = array(__('Discussion'), 'manage_options', 'options-discussion.php'); 14 $submenu['options-general.php'][30] = array(__('Media'), 'manage_options', 'options-media.php'); 15 $submenu['options-general.php'][35] = array(__('Privacy'), 'manage_options', 'options-privacy.php'); 16 + $submenu['options-general.php'][40] = array(__('Security'), 'manage_options', 'options-security.php'); 17 + $submenu['options-general.php'][45] = array(__('Permalinks'), 'manage_options', 'options-permalink.php'); 18 if ( is_super_admin() ) 19 + $submenu['options-general.php'][50] = array(__('Miscellaneous'), 'manage_options', 'options-misc.php'); 20 21 $_wp_last_utility_menu = 80; // The index of the last top-level menu in the utility menu group 22 -
wp-admin/js/options-security.dev.js
1 /* 2 * Script for Content Security Policy admin page 3 * Brandon Sterne <bsterne@mozilla.com> 4 * 5 * Uses Mark Perkins' jQuery URL Parser plugin documented here 6 * http://projects.allmarkedup.com/jquery_url_parser/ 7 */ 8 9 // keep a list of hosts for each type of content served on this blog 10 var sources = { 11 'images': {}, 'media': {}, 'script': {}, 'object': {}, 12 'frame': {}, 'font': {}, 'style': {} 13 }; 14 15 // store mappings between content-types and CSP directive names 16 var directives = { 17 'images': 'img-src', 'media': 'media-src', 'script': 'script-src', 18 'object': 'object-src', 'frame': 'frame-src', 'font': 'font-src', 19 'style': 'style-src' 20 }; 21 // allows us to look up directive mappings in either direction 22 directives.invert = function() { 23 var inverted = {}; 24 for (var prop in this) { 25 if (prop != "invert") inverted[this[prop]] = prop; 26 } 27 return inverted; 28 } 29 30 // Douglas Crockford's trim() implementation 31 String.prototype.trim = function () { 32 return this.replace(/^\s+|\s+$/g, ""); 33 }; 34 35 // return a word with the first letter capitalized 36 function capWord(w) { 37 return w.charAt(0).toUpperCase() + w.slice(1); 38 } 39 40 // return whether or not an object has no properties 41 function objIsEmpty(obj) { 42 for (var prop in obj) { 43 if (obj.hasOwnProperty(prop)) 44 return false; 45 } 46 return true; 47 } 48 49 // show debugging info 50 var DEBUG = false; 51 52 // for debugging: return a pretty-printed version of the content sources 53 function display(sources) { 54 var s = "{\n"; 55 for (type in sources) { 56 s += " "+type+": ["; 57 for (host in sources[type]) { 58 s += host+", "; 59 } 60 s += "],\n"; 61 } 62 s += "}"; 63 return s; 64 } 65 66 // page loaded 67 jQuery(document).ready(function($) { 68 // if there is an existing policy saved we will display it visually 69 var policy = $("#csp_value").val(); 70 // CSP is enabled, but not customized. The default policy is to allow content 71 // only from this site 72 if (policy == "allow 'self';") { 73 var myHost = jQuery.url.setUrl($(this).attr("src")).attr("host"); 74 // show non-editable policy representation. we don't want them to be able 75 // to remove "allow 'self'" (at least through the visual policy editor). 76 showVisualPolicy({"allowing":{"'self'":null}}, "csp_display", false); 77 } 78 // policy has been customized by the user 79 else if (policy.length) { 80 // parse the CSP syntax into our JS object format 81 var myDirs = policy.split(";"); // current CSP directives 82 // directive-to-readable-name mappings 83 var invDirectives = directives.invert(); 84 for (var i = 0 ; i < myDirs.length ; i++) { 85 var dirParts = myDirs[i].trim().split(/[\s]+/); 86 // only process directives we know about 87 if (dirParts[0] in invDirectives) { 88 // add hosts allowed for this directive 89 for (var j = 1 ; j < dirParts.length ; j++) 90 sources[ invDirectives[dirParts[0]] ][dirParts[j]] = null; 91 } 92 } 93 if (DEBUG) $("#log").text(display(sources)); 94 // show editable list of policy sources 95 showVisualPolicy(sources, "csp_display", true); 96 } 97 // no CSP set 98 else { 99 $("#csp_display").html("<p> </p>"); 100 } 101 102 // discard changes to the policy settings by reloading the page 103 $("#csp_discard").click( function() { 104 window.location.reload(true); 105 }); 106 107 // show/hide the advanced panel for manual editing 108 $("#csp_toggle_advanced").click( function() { 109 if ($(this).text() == "Show Advanced") { 110 $("#csp_advanced").show(); 111 $(this).text("Hide Advanced"); 112 } 113 else { 114 $("#csp_advanced").hide(); 115 $(this).text("Show Advanced"); 116 } 117 }); 118 119 // fetch the front page of the blog to analyze for Content Security 120 // Policy suggestion 121 $("#suggestpolicy").click( function() { 122 $("#analyze").attr("src", location.href.replace(/\/[^\/]+\/[^\/]+$/,"")); 123 // show throbber while analyzing 124 $("#content-loading").css("visibility", "visible"); 125 return false; 126 }); 127 128 // when "Enable CSP" preference is toggeld, enable "Discard Changes" button 129 $("#csp_enabled").click( function() { 130 $("#csp_discard").show(); 131 // if CSP is enabled, ensure that the source list contains at least 132 // the site itself, since "allow 'self'" is the default policy 133 if ($(this).attr("checked")) { 134 var sourcesIsEmpty = true; 135 for (type in sources) { 136 if (!objIsEmpty(sources[type])) { 137 sourcesIsEmpty = false; 138 break; 139 } 140 } 141 // show non-editable policy representation. we don't want them to be able 142 // to remove "allow 'self'" (at least through the visual policy editor). 143 if (sourcesIsEmpty) 144 showVisualPolicy({"allowing":{"'self'":null}}, "csp_display", false); 145 } 146 }); 147 148 // once the front page has loaded, examine its content for policy suggestions 149 $("#analyze").load(function() { 150 // don't examine until we've loaded a page in the frame 151 if (!$(this).attr("src")) 152 return false; 153 154 // use 'self' for content from this host 155 var myHost = jQuery.url.setUrl($(this).attr("src")).attr("host"); 156 157 /* images */ 158 // XXX bsterne - nearly every blog I've looked at sources images from 159 // all over the place. It's potentially confusing to users to show a list 160 // containing every site they get images from. For now, will allow 161 // images from anywhere. 162 sources.images["*"] = null; 163 /* 164 $.each($(this).contents().find("img"), function() { 165 var host = jQuery.url.setUrl($(this).attr("src")).attr("host"); 166 // relative URL, use 'self' 167 if (host == null) { 168 if (!(host in sources.images)) 169 sources.images["'self'"] = null; 170 } 171 // absolute URL, store the hostname 172 else { 173 if (!(host in sources.images)) 174 sources.images[host] = null; 175 } 176 }); 177 */ 178 179 /* media: <video> and <audio> */ 180 $.each($(this).contents().find("video,audio"), function() { 181 var host = jQuery.url.setUrl($(this).attr("src")).attr("host"); 182 // relative URL, use 'self' 183 if (host == null) { 184 if (!(host in sources.media)) 185 sources.media["'self'"] = null; 186 } 187 // absolute URL, store the hostname 188 else { 189 if (host == myHost) 190 host = "'self'"; 191 if (!(host in sources.media)) 192 sources.media[host] = null; 193 } 194 }); 195 196 /* external script resources */ 197 $.each($(this).contents().find("script"), function() { 198 var host = jQuery.url.setUrl($(this).attr("src")).attr("host"); 199 // relative URL, use 'self' 200 if (host == null) { 201 if (!(host in sources.script)) 202 sources.script["'self'"] = null; 203 } 204 // absolute URL, store the hostname 205 else { 206 if (host == myHost) 207 host = "'self'"; 208 if (!(host in sources.script)) 209 sources.script[host] = null; 210 } 211 }); 212 213 /* <object>, <applet>, <embed> */ 214 // object, applet 215 // http://www.w3.org/TR/1999/REC-html401-19991224/struct/objects.html#h-13.3 216 $.each($(this).contents().find("object,applet"), function() { 217 // codebase: base URI for classid, data, archive attrs 218 var codebase = $(this).attr("codebase"); 219 var host = jQuery.url.setUrl(codebase).attr("host"); 220 // relative URL, use 'self' 221 if (host == null) { 222 if (!(host in sources.object)) 223 sources.object["'self'"] = null; 224 } 225 // absolute URL, store the hostname 226 else { 227 if (host == myHost) 228 host = "'self'"; 229 if (!(host in sources.object)) 230 sources.object[host] = null; 231 } 232 233 // classid: location of an object's implementation. 234 // XXX bsterne - spec says this is a URI, but in the wild this usually 235 // references a COM registry ID. For now, skipping this URL for any 236 // non-data-returning protocols, e.g. clsid:. 237 var classid = $(this).attr("classid"); // applet won't have this 238 var protocol = jQuery.url.setUrl(classid).attr("protocol"); 239 if (jQuery.inArray(protocol, ["http", "https", "ftp", null]) != -1) { 240 host = jQuery.url.setUrl(classid).attr("host"); 241 // relative URL, use 'self' 242 if (host == null) { 243 if (!(host in sources.object)) 244 sources.object["'self'"] = null; 245 } 246 // absolute URL, store the hostname 247 else { 248 if (host == myHost) 249 host = "'self'"; 250 if (!(host in sources.object)) 251 sources.object[host] = null; 252 } 253 } 254 255 // data: object's or applet's location 256 var data = $(this).attr("data"); // applet won't have this 257 host = jQuery.url.setUrl(data).attr("host"); 258 // relative URL, use 'self' 259 if (host == null) { 260 if (!(host in sources.object)) 261 sources.object["'self'"] = null; 262 } 263 // absolute URL, store the hostname 264 else { 265 if (host == myHost) 266 host = "'self'"; 267 if (!(host in sources.object)) 268 sources.object[host] = null; 269 } 270 271 // archive: space-separated list of URIs of relevant resources 272 var archive = $(this).attr("archive"); 273 var hosts = archive.split(" "); 274 $.each(hosts, function() { 275 host = jQuery.url.setUrl(this).attr("host"); 276 // relative URL, use 'self' 277 if (host == null) { 278 if (!(host in sources.object)) 279 sources.object["'self'"] = null; 280 } 281 // absolute URL, store the hostname 282 else { 283 if (host == myHost) 284 host = "'self'"; 285 if (!(host in sources.object)) 286 sources.object[host] = null; 287 } 288 }); 289 }); 290 291 // embed 292 $.each($(this).contents().find("embed"), function() { 293 var host = jQuery.url.setUrl($(this).attr("src")).attr("host"); 294 // relative URL, use 'self' 295 if (host == null) { 296 if (!(host in sources.object)) 297 sources.object["'self'"] = null; 298 } 299 // absolute URL, store the hostname 300 else { 301 if (host == myHost) 302 host = "'self'"; 303 if (!(host in sources.object)) 304 sources.object[host] = null; 305 } 306 }); 307 308 // frame, iframe 309 $.each($(this).contents().find("frame,iframe"), function() { 310 var host = jQuery.url.setUrl($(this).attr("src")).attr("host"); 311 // relative URL, use 'self' 312 if (host == null) { 313 if (!(host in sources.frame)) 314 sources.frame["'self'"] = null; 315 } 316 // absolute URL, store the hostname 317 else { 318 if (host == myHost) 319 host = "'self'"; 320 if (!(host in sources.frame)) 321 sources.frame[host] = null; 322 } 323 }); 324 325 // @font-face (downloadable fonts) 326 var stylesheets = {}; 327 try { 328 var stylesheets = this.contentDocument.styleSheets; 329 } 330 // XXX bsterne - parsing style rules in IE is hard :-( 331 // see http://www.quirksmode.org/dom/w3c_css.html 332 catch (e) {} 333 334 for (var i = 0 ; i < stylesheets.length ; i++) { 335 // XXX bsterne - apparently, cross-site stylesheets' rules are subject to 336 // same-origin. We'll only be able to make font policy reccommendations 337 // based on same-site stylesheets. 338 var rules = {}; 339 try { 340 // Firefox, Chrome, Safari, etc. 341 rules = stylesheets[i].cssRules; 342 // Internet Explorer would use .rules if we can add support 343 // rules = stylesheets[i].rules; 344 } 345 catch (e) { // probably a cross-site stylesheet which we can't read 346 continue; 347 } 348 // XXX bsterne - Chrome can return null for cssRules but not throw 349 if (!rules) { 350 continue; 351 } 352 // search stylesheet rules for @font-face 353 for (var j = 0 ; j < rules.length ; j++) { 354 if (rules[j].type == rules[j].FONT_FACE_RULE) { 355 var src = rules[j].style.getPropertyValue("src"); 356 if (src) { 357 // remove url() wrapper from font-face src 358 // FIXME - get rid of slashes (working around js-mode indent bug) 359 var url = src.replace(/^url[\'"]*/, "").replace(/[\'"]*\)$/, ""); 360 var host = jQuery.url.setUrl(url).attr("host"); 361 // relative URL, use 'self' 362 if (host == null) { 363 if (!(host in sources.font)) 364 sources.font["'self'"] = null; 365 } 366 // absolute URL, store the hostname 367 else { 368 if (host == myHost) 369 host = "'self'"; 370 if (!(host in sources.font)) 371 sources.font[host] = null; 372 } 373 } 374 } 375 } 376 } 377 378 // external stylesheets 379 $.each($(this).contents().find("link[rel='stylesheet']"), function() { 380 var host = jQuery.url.setUrl($(this).attr("href")).attr("host"); 381 // relative URL, use 'self' 382 if (host == null) { 383 if (!(host in sources.style)) 384 sources.style["'self'"] = null; 385 } 386 // absolute URL, store the hostname 387 else { 388 if (host == myHost) 389 host = "'self'"; 390 if (!(host in sources.style)) 391 sources.style[host] = null; 392 } 393 }); 394 395 // turn off throbber 396 $("#content-loading").css("visibility", "hidden"); 397 398 // display a reccommended policy that the user can edit, then accept or reject 399 showVisualPolicy(sources, "csp_display", true); 400 // changes were made, enable "Discard Changes" button and change 401 // border of "Trusted Sites" panel 402 $("#csp_discard").show(); 403 $("#csp_display").css("border-style", "dashed").css("border-width","2px"); 404 }); 405 406 // display a visual representation of the policy defined in a source list 407 // inside the specified DOM element. If |editable| is passed in as true, 408 // the printed list will be interactive 409 function showVisualPolicy(sourceList, elementID, editable) { 410 if(DEBUG) $("#log").text(display(sourceList)) 411 $("#"+elementID).empty(); 412 var myHost = jQuery.url.setUrl($(this).attr("src")).attr("host"); 413 for (type in sourceList) { 414 var div = document.createElement("div"); 415 // skip content types which have no sources 416 if (objIsEmpty(sourceList[type])) 417 continue; 418 $(div).addClass("feature-name").text(capWord(type)); 419 $("#"+elementID).append(div); 420 var ol = document.createElement("ol"); 421 $(ol).addClass("feature-group"); 422 for (host in sourceList[type]) { 423 var li = document.createElement("li"); 424 $(li).attr("host", host); 425 $(li).attr("ctype", type); // content type 426 // if list is editable, permit the user to remove a source from the 427 // suggested source list or add it back in 428 if (editable) { 429 $(li).click(function() { 430 // changes were made, enable "Discard Changes" button and change 431 // border of "Trusted Sites" panel 432 $("#csp_discard").show(); 433 $("#csp_display").css("border-style", "dashed").css("border-width", 434 "2px"); 435 // re-enable a previously removed source 436 if ($(this).css("text-decoration") == "line-through") { 437 $(this).css("text-decoration", "none"); 438 //sourceList[this.type][this.host] = null; 439 sourceList[$(this).attr("ctype")][$(this).attr("host")] = null; 440 } 441 // remove a source from the list of suggestions 442 else { 443 $(this).css("text-decoration", "line-through"); 444 //delete sourceList[this.type][this.host]; 445 delete sourceList[$(this).attr("ctype")][$(this).attr("host")]; 446 } 447 if (DEBUG) $("#log").text(display(sourceList)); 448 }); 449 } 450 if (host == "*") { 451 var displayName = "Everyone"; 452 var faviconUrl = "images/everyone.gif"; 453 } 454 else if (host == "'self'") { 455 var displayName = myHost; 456 var faviconUrl = "http://" + myHost + "/favicon.ico"; 457 } 458 else { 459 var displayName = host; 460 var faviconUrl = "http://" + host + "/favicon.ico"; 461 } 462 $(li).html("<img src=\"" + faviconUrl + "\" class=\" csp-trusted\"" + 463 " onerror=\"this.parentNode.removeChild(this)\">"); 464 if (editable) 465 $(li).append("<label>" + displayName + "</label>"); 466 else 467 $(li).append(displayName); 468 $(ol).append(li); 469 } 470 $("#"+elementID).append(ol).append("<br class=\"clear\">"); 471 } 472 // show a message describing how to treat the list of sources 473 $("#csp_verify_text").show(); 474 } 475 476 // turn a list of sources into proper CSP syntax 477 function generatePolicyFromSources(sourceList) { 478 var policy = "allow 'self'; "; 479 for (type in sourceList) { 480 // skip types which have no sources specified 481 if (objIsEmpty(sourceList[type])) 482 continue; 483 policy += directives[type] + " "; 484 for (host in sourceList[type]) { 485 policy += host+" "; 486 } 487 policy += "; "; 488 } 489 return policy; 490 } 491 492 // once the user has verified the list of sources they want to allow, turn the 493 // list of hosts-per-content-type into proper CSP syntax 494 $("#csp_save").click( function() { 495 // if the advanced view is hidden, then generate policy from the visual 496 // editor and place in the form field 497 if ($("#csp_toggle_advanced").text() == "Show Advanced") { 498 $("#csp_value").val( generatePolicyFromSources(sources) ); 499 } 500 // otherwise the user wants to edit the policy directly, so we'll use what's 501 // in the form field 502 $("form").submit(); 503 }); 504 505 }); -
wp-admin/js/jquery.url.js
1 /* =========================================================================== 2 * 3 * JQuery URL Parser 4 * Version 1.0 5 * Parses URLs and provides easy access to information within them. 6 * 7 * Author: Mark Perkins 8 * Author email: mark@allmarkedup.com 9 * 10 * For full documentation and more go to http://projects.allmarkedup.com/jquery_url_parser/ 11 * 12 * --------------------------------------------------------------------------- 13 * 14 * CREDITS: 15 * 16 * Parser based on the Regex-based URI parser by Stephen Levithian. 17 * For more information (including a detailed explaination of the differences 18 * between the 'loose' and 'strict' pasing modes) visit http://blog.stevenlevithan.com/archives/parseuri 19 * 20 * --------------------------------------------------------------------------- 21 * 22 * LICENCE: 23 * 24 * Released under a MIT Licence. See licence.txt that should have been supplied with this file, 25 * or visit http://projects.allmarkedup.com/jquery_url_parser/licence.txt 26 * 27 * --------------------------------------------------------------------------- 28 * 29 * EXAMPLES OF USE: 30 * 31 * Get the domain name (host) from the current page URL 32 * jQuery.url.attr("host") 33 * 34 * Get the query string value for 'item' for the current page 35 * jQuery.url.param("item") // null if it doesn't exist 36 * 37 * Get the second segment of the URI of the current page 38 * jQuery.url.segment(2) // null if it doesn't exist 39 * 40 * Get the protocol of a manually passed in URL 41 * jQuery.url.setUrl("http://allmarkedup.com/").attr("protocol") // returns 'http' 42 * 43 */ 44 45 jQuery.url = function() 46 { 47 var segments = {}; 48 49 var parsed = {}; 50 51 /** 52 * Options object. Only the URI and strictMode values can be changed via the setters below. 53 */ 54 var options = { 55 56 url : window.location, // default URI is the page in which the script is running 57 58 strictMode: false, // 'loose' parsing by default 59 60 key: ["source","protocol","authority","userInfo","user","password","host","port","relative","path","directory","file","query","anchor"], // keys available to query 61 62 q: { 63 name: "queryKey", 64 parser: /(?:^|&)([^&=]*)=?([^&]*)/g 65 }, 66 67 parser: { 68 strict: /^(?:([^:\/?#]+):)?(?:\/\/((?:(([^:@]*):?([^:@]*))?@)?([^:\/?#]*)(?::(\d*))?))?((((?:[^?#\/]*\/)*)([^?#]*))(?:\?([^#]*))?(?:#(.*))?)/, // more intuitive, fails on relative paths and deviates from specs 69 loose: /^(?:(?![^:@]+:[^:@\/]*@)([^:\/?#.]+):)?(?:\/\/)?((?:(([^:@]*):?([^:@]*))?@)?([^:\/?#]*)(?::(\d*))?)(((\/(?:[^?#](?![^?#\/]*\.[^?#\/.]+(?:[?#]|$)))*\/?)?([^?#\/]*))(?:\?([^#]*))?(?:#(.*))?)/ //less intuitive, more accurate to the specs 70 } 71 72 }; 73 74 /** 75 * Deals with the parsing of the URI according to the regex above. 76 * Written by Steven Levithan - see credits at top. 77 */ 78 var parseUri = function() 79 { 80 str = decodeURI( options.url ); 81 82 var m = options.parser[ options.strictMode ? "strict" : "loose" ].exec( str ); 83 var uri = {}; 84 var i = 14; 85 86 while ( i-- ) { 87 uri[ options.key[i] ] = m[i] || ""; 88 } 89 90 uri[ options.q.name ] = {}; 91 uri[ options.key[12] ].replace( options.q.parser, function ( $0, $1, $2 ) { 92 if ($1) { 93 uri[options.q.name][$1] = $2; 94 } 95 }); 96 97 return uri; 98 }; 99 100 /** 101 * Returns the value of the passed in key from the parsed URI. 102 * 103 * @param string key The key whose value is required 104 */ 105 var key = function( key ) 106 { 107 if ( ! parsed.length ) 108 { 109 setUp(); // if the URI has not been parsed yet then do this first... 110 } 111 if ( key == "base" ) 112 { 113 if ( parsed.port !== null && parsed.port !== "" ) 114 { 115 return parsed.protocol+"://"+parsed.host+":"+parsed.port+"/"; 116 } 117 else 118 { 119 return parsed.protocol+"://"+parsed.host+"/"; 120 } 121 } 122 123 return ( parsed[key] === "" ) ? null : parsed[key]; 124 }; 125 126 /** 127 * Returns the value of the required query string parameter. 128 * 129 * @param string item The parameter whose value is required 130 */ 131 var param = function( item ) 132 { 133 if ( ! parsed.length ) 134 { 135 setUp(); // if the URI has not been parsed yet then do this first... 136 } 137 return ( parsed.queryKey[item] === null ) ? null : parsed.queryKey[item]; 138 }; 139 140 /** 141 * 'Constructor' (not really!) function. 142 * Called whenever the URI changes to kick off re-parsing of the URI and splitting it up into segments. 143 */ 144 var setUp = function() 145 { 146 parsed = parseUri(); 147 148 getSegments(); 149 }; 150 151 /** 152 * Splits up the body of the URI into segments (i.e. sections delimited by '/') 153 */ 154 var getSegments = function() 155 { 156 var p = parsed.path; 157 segments = []; // clear out segments array 158 segments = parsed.path.length == 1 ? {} : ( p.charAt( p.length - 1 ) == "/" ? p.substring( 1, p.length - 1 ) : path = p.substring( 1 ) ).split("/"); 159 }; 160 161 return { 162 163 /** 164 * Sets the parsing mode - either strict or loose. Set to loose by default. 165 * 166 * @param string mode The mode to set the parser to. Anything apart from a value of 'strict' will set it to loose! 167 */ 168 setMode : function( mode ) 169 { 170 strictMode = mode == "strict" ? true : false; 171 return this; 172 }, 173 174 /** 175 * Sets URI to parse if you don't want to to parse the current page's URI. 176 * Calling the function with no value for newUri resets it to the current page's URI. 177 * 178 * @param string newUri The URI to parse. 179 */ 180 setUrl : function( newUri ) 181 { 182 options.url = newUri === undefined ? window.location : newUri; 183 setUp(); 184 return this; 185 }, 186 187 /** 188 * Returns the value of the specified URI segment. Segments are numbered from 1 to the number of segments. 189 * For example the URI http://test.com/about/company/ segment(1) would return 'about'. 190 * 191 * If no integer is passed into the function it returns the number of segments in the URI. 192 * 193 * @param int pos The position of the segment to return. Can be empty. 194 */ 195 segment : function( pos ) 196 { 197 if ( ! parsed.length ) 198 { 199 setUp(); // if the URI has not been parsed yet then do this first... 200 } 201 if ( pos === undefined ) 202 { 203 return segments.length; 204 } 205 return ( segments[pos] === "" || segments[pos] === undefined ) ? null : segments[pos]; 206 }, 207 208 attr : key, // provides public access to private 'key' function - see above 209 210 param : param // provides public access to private 'param' function - see above 211 212 }; 213 214 }(); -
wp-admin/options-security.php
1 <?php 2 /** 3 * Security Settings Administration Panel. 4 * 5 * @package WordPress 6 * @subpackage Administration 7 */ 8 9 /** Load WordPress Administration Bootstrap */ 10 require_once('./admin.php'); 11 12 if ( ! current_user_can('manage_options') ) 13 wp_die(__('You do not have sufficient permissions to manage options for this blog.')); 14 15 $title = __('Security Settings'); 16 $parent_file = 'options-general.php'; 17 wp_enqueue_style( 'theme-install' ); 18 wp_enqueue_style( 'security' ); 19 include('./admin-header.php'); 20 ?> 21 22 <div class="wrap"> 23 <?php screen_icon(); ?> 24 <h2><?php echo esc_html( $title ); ?></h2> 25 26 <form method="post" action="options.php"> 27 <?php settings_fields('security'); ?> 28 29 <h3><?php _e('Content Security Policy'); ?></h3> 30 <p><a href="https://wiki.mozilla.org/Security/CSP">Content Security Policy</a> is a mechanism that prevents <a href="http://en.wikipedia.org/wiki/Cross-site_scripting">cross-site scripting</a> and other content-injection attacks. It works by informing the browser regarding which websites you trust to serve content in your pages, and what specific types of content are expected. To provide protection in this way, CSP fundamentally changes the way JavaScript can be embedded in web pages, so be aware that <b>WordPress plugins may experience broken functionality</b> when CSP is enabled.</p> 31 <table class="form-table" id="csp-form"> 32 <tr valign="top"> 33 <th><label for="csp_enabled"><?php _e('Enable CSP') ?></label></th> 34 <td><input id="csp_enabled" type="checkbox" name="csp_enabled" value="1" <?php checked('1', get_option('csp_enabled')); ?> /></td> 35 <th>Trusted Sites:</th> 36 <td width="80%"> 37 <div class="feature-filter" id="csp_display"></div> 38 </td> 39 <tr valign="middle"> 40 <td colspan="3"></td> 41 <td><span id="csp_verify_text">Verify that you trust the sites in the list above to serve content in your site. Remove any sites that you do not trust by clicking them. Your changes will not be saved until you click <b>Save Changes</b> below.</span></td> 42 </tr> 43 </tr> 44 <tr valign="top"> 45 <td colspan="3"></td> 46 <td> 47 <div class="tablenav" style="vertical-align:bottom"> 48 <div class="alignleft actions"><input type="button" name="suggestpolicy" id="suggestpolicy" class="button-secondary" value="<?php esc_attr_e('Suggest Policy') ?>" /><img id="content-loading" alt="" src="images/wpspin_light.gif"><input type="button" class="button-secondary" id="csp_discard" value="<?php esc_attr_e('Discard Changes') ?>" /><input type="button" class="button-primary" id="csp_save" value="<?php esc_attr_e('Save Changes') ?>" /></div> 49 </div> 50 </td> 51 </tr> 52 <tr> 53 <th><label id="csp_toggle_advanced">Show Advanced</label></th> 54 <td colspan="3"> 55 <div class="feature-filter" id="csp_advanced"> 56 <p>Do not edit the policy directly unless you really know what you are doing.</p> 57 <input type="text" name="csp_value" id="csp_value" value="<?php form_option('csp_value'); ?>" /> 58 </div> 59 </td> 60 </tr> 61 <?php do_settings_fields('security', 'default'); ?> 62 </table> 63 64 <?php do_settings_sections('security'); ?> 65 66 </form> 67 68 </div> 69 70 <iframe id="analyze"></iframe> 71 <pre id="log"></pre> 72 <script type="text/javascript" src="js/options-security.dev.js"></script> 73 <script type="text/javascript" src="js/jquery.url.js"></script> 74 <?php include('./admin-footer.php') ?> -
wp-admin/menu.php
$menu[80] = array( __('Settings'), 'manage_options 198 198 $submenu['options-general.php'][25] = array(__('Discussion'), 'manage_options', 'options-discussion.php'); 199 199 $submenu['options-general.php'][30] = array(__('Media'), 'manage_options', 'options-media.php'); 200 200 $submenu['options-general.php'][35] = array(__('Privacy'), 'manage_options', 'options-privacy.php'); 201 $submenu['options-general.php'][40] = array(__('Permalinks'), 'manage_options', 'options-permalink.php'); 201 $submenu['options-general.php'][40] = array(__('Security'), 'manage_options', 'options-security.php'); 202 $submenu['options-general.php'][45] = array(__('Permalinks'), 'manage_options', 'options-permalink.php'); 202 203 203 204 $_wp_last_utility_menu = 80; // The index of the last top-level menu in the utility menu group 204 205 -
wp-admin/admin-header.php
6 6 * @subpackage Administration 7 7 */ 8 8 9 // Content Security Policy header 10 $csp = get_csp(); 11 if ($csp) 12 @header("X-Content-Security-Policy: " . $csp); 9 13 @header('Content-Type: ' . get_option('html_type') . '; charset=' . get_option('blog_charset')); 10 14 if (!isset($_GET["page"])) require_once('admin.php'); 11 15 -
wp-admin/options.php
Cannot display: file marked as a binary type. svn:mime-type = application/octet-stream Property changes on: wp-admin/images/everyone.gif ___________________________________________________________________ Added: svn:mime-type + application/octet-stream
$whitelist_options = array( 38 38 'discussion' => array( 'default_pingback_flag', 'default_ping_status', 'default_comment_status', 'comments_notify', 'moderation_notify', 'comment_moderation', 'require_name_email', 'comment_whitelist', 'comment_max_links', 'moderation_keys', 'blacklist_keys', 'show_avatars', 'avatar_rating', 'avatar_default', 'close_comments_for_old_posts', 'close_comments_days_old', 'thread_comments', 'thread_comments_depth', 'page_comments', 'comments_per_page', 'default_comments_page', 'comment_order', 'comment_registration' ), 39 39 'media' => array( 'thumbnail_size_w', 'thumbnail_size_h', 'thumbnail_crop', 'medium_size_w', 'medium_size_h', 'large_size_w', 'large_size_h', 'image_default_size', 'image_default_align', 'image_default_link_type', 'embed_autourls', 'embed_size_w', 'embed_size_h', 'uploads_use_yearmonth_folders', 'upload_path', 'upload_url_path' ), 40 40 'privacy' => array( 'blog_public' ), 41 'security' => array( 'csp_enabled', 'csp_value' ), 41 42 'reading' => array( 'posts_per_page', 'posts_per_rss', 'rss_use_excerpt', 'blog_charset', 'show_on_front', 'page_on_front', 'page_for_posts' ), 42 43 'writing' => array( 'default_post_edit_rows', 'use_smilies', 'default_category', 'default_email_category', 'use_balanceTags', 'default_link_category', 'enable_app', 'enable_xmlrpc' ), 43 44 'options' => array( '' ) ); -
wp-admin/css/security.css
1 #suggestion, #analyze, #csp_discard, #csp_verify_text, #csp_advanced { display: none } 2 img.csp-trusted { vertical-align:middle; margin: 0 1em } 3 #content-loading { visibility:hidden; vertical-align:middle; margin:0 .5em } 4 #csp_value { width: 75%; margin: 1em }