Merged in feature/280-dev-dev01 (pull request #21)
auto-patch 280-dev-dev01-2024-01-19T16_41_58 * auto-patch 280-dev-dev01-2024-01-19T16_41_58
This commit is contained in:
520
wp/wp-content/plugins/ip-geo-block/admin/js/authenticate.js
Normal file
520
wp/wp-content/plugins/ip-geo-block/admin/js/authenticate.js
Normal file
@@ -0,0 +1,520 @@
|
||||
/*jslint white: true */
|
||||
/*!
|
||||
* Project: WP-ZEP - Zero-day exploit Prevention for wp-admin
|
||||
* Copyright (c) 2013-2019 tokkonopapa (tokkonopapa@yahoo.com)
|
||||
* This software is released under the MIT License.
|
||||
*/
|
||||
(function ($, window, document) {
|
||||
// https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/RegExp#Description
|
||||
var auth = IP_GEO_BLOCK_AUTH, wpzep = {
|
||||
init: false,
|
||||
regexp: new RegExp(auth.key + '(?:=|%3D)\\w+')
|
||||
},
|
||||
|
||||
// regular expression to find target for is_admin()
|
||||
regexp = new RegExp(
|
||||
'^(?:' + (auth.home || '') + auth.admin
|
||||
+ '|' + (auth.home || '') + auth.plugins
|
||||
+ '|' + (auth.home || '') + auth.themes
|
||||
+ '|' + (auth.admin ) // when site url is different from home url
|
||||
+ ')(?:.*\\.php|.*\\/)?$'
|
||||
),
|
||||
|
||||
// `theme-install.php` eats the query and set it to `request[browse]` as a parameter
|
||||
theme_featured = function (data) {
|
||||
var i = data.length, q = 'request%5Bbrowse%5D=' + auth.key;
|
||||
while (i-- > 0) {
|
||||
if (data[i].indexOf(q) !== -1) {
|
||||
data[i] = 'request%5Bbrowse%5D=featured'; // correct the parameter
|
||||
break;
|
||||
}
|
||||
}
|
||||
return data;
|
||||
},
|
||||
|
||||
// `upload.php` eats the query and set it to `query[ip-geo-block-auth-nonce]` as a parameter
|
||||
media_library = function (data) {
|
||||
var i = data.length, q = 'query%5B' + auth.key + '%5D=';
|
||||
while (i-- > 0) {
|
||||
if (data[i].indexOf(q) !== -1) {
|
||||
delete data[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
return data;
|
||||
},
|
||||
|
||||
// list of excluded links
|
||||
ajax_links = {
|
||||
'upload.php': media_library,
|
||||
'theme-install.php': theme_featured,
|
||||
'network/theme-install.php': theme_featured
|
||||
};
|
||||
|
||||
// Check path that should be excluded
|
||||
function check_ajax(path) {
|
||||
path = path.replace(auth.home + auth.admin, '');
|
||||
return ajax_links.hasOwnProperty(path) ? ajax_links[path] : null;
|
||||
}
|
||||
|
||||
// Escape string for use in HTML.
|
||||
function escapeHTML(html) {
|
||||
var elem = document.createElement('div');
|
||||
elem.appendChild(document.createTextNode(html));
|
||||
html = elem.innerHTML.replace(/["']/g, function (match) {
|
||||
return {
|
||||
'"': '"',
|
||||
"'": ''' //"
|
||||
}[match];
|
||||
});
|
||||
elem = '';
|
||||
return html;
|
||||
}
|
||||
|
||||
// Parse a URL and return its components
|
||||
function parse_uri(uri) {
|
||||
// avoid malformed URI error when uri includes '%'
|
||||
uri = /*decodeURIComponent*/(uri ? uri.toString() : '');
|
||||
|
||||
var m = uri.match(
|
||||
// https://tools.ietf.org/html/rfc3986#appendix-B
|
||||
/^(?:([^:\/?#]+):)?(\/\/([^\/?#]*))?([^?#]*)(?:\?([^#]*))?(?:#(.*))?/
|
||||
);
|
||||
|
||||
// scheme :// authority path ? query # fragment
|
||||
return {
|
||||
scheme: m[1] || '',
|
||||
relative: m[2] || '',
|
||||
authority: m[3] || '',
|
||||
path: m[4] || '',
|
||||
query: m[5] || '',
|
||||
fragment: m[6] || ''
|
||||
};
|
||||
}
|
||||
|
||||
// Compose a URL from components
|
||||
function compose_uri(uri) {
|
||||
return (uri.scheme ? uri.scheme + ':' : '') +
|
||||
(uri.relative + uri.path) +
|
||||
(uri.query ? '?' + uri.query : '') +
|
||||
(uri.fragment ? '#' + uri.fragment : '');
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert relative url to absolute url using browser feature
|
||||
*
|
||||
* @param string target url
|
||||
* @param string base of absolute url (default window.locatoin.href)
|
||||
* @return component of url
|
||||
*/
|
||||
var absolute_uri = (function () {
|
||||
var doc = null;
|
||||
|
||||
try {
|
||||
new URL('/', 'http://example.com/'); // test if URL object is abailable
|
||||
} catch (e) {
|
||||
try {
|
||||
doc = (new DOMParser()).parseFromString('<html><head></head><body></body></html>', 'text/html'); // IE11
|
||||
} catch (f) {
|
||||
doc = document.implementation.createHTMLDocument(''); // IE10
|
||||
}
|
||||
}
|
||||
|
||||
return function (url, base) {
|
||||
var d = document, baseElm, aElm, result;
|
||||
url = typeof url !== 'undefined' ? url : window.location.href;
|
||||
if (null === doc) {
|
||||
if (typeof base === 'undefined') {
|
||||
base = window.location.href; // based on current url
|
||||
}
|
||||
try {
|
||||
result = new URL(url, base); // base must be valid
|
||||
} catch (e) {
|
||||
result = new URL(url, window.location.href);
|
||||
}
|
||||
} else {
|
||||
// use anchor element to resolve url
|
||||
if (typeof base !== 'undefined') {
|
||||
// assign base element to anchor to be independent of the current document
|
||||
d = doc;
|
||||
while (d.head.firstChild) {
|
||||
d.head.removeChild(d.head.firstChild);
|
||||
}
|
||||
baseElm = d.createElement('base');
|
||||
baseElm.setAttribute('href', base);
|
||||
d.head.appendChild(baseElm);
|
||||
}
|
||||
aElm = d.createElement('a');
|
||||
aElm.setAttribute('href', url);
|
||||
aElm.setAttribute('href', aElm.href);
|
||||
//d.appendChild(aElm);
|
||||
|
||||
result = {
|
||||
protocol: aElm.protocol,
|
||||
host: aElm.host,
|
||||
hostname: aElm.hostname,
|
||||
port: aElm.port,
|
||||
pathname: aElm.pathname,
|
||||
search: aElm.search,
|
||||
hash: aElm.hash,
|
||||
href: aElm.href,
|
||||
username: '',
|
||||
password: '',
|
||||
origin : aElm.origin || null
|
||||
};
|
||||
if ('http:' === result.protocol && '80' === result.port) {
|
||||
// remove port number `80` in case of `http` and defalut port
|
||||
result.port = '';
|
||||
result.host = result.host.replace(/:80$/, '');
|
||||
} else if ('https:' === result.protocol && '443' === result.port) {
|
||||
// remove port number `443` in case of `https` and defalut port
|
||||
result.port = '';
|
||||
result.host = result.host.replace(/:443$/, '');
|
||||
}
|
||||
if ('http:' === result.protocol || 'https:' === result.protocol) {
|
||||
if (result.pathname && result.pathname.charAt(0) !== '/') {
|
||||
// in case no `/` at the top
|
||||
result.pathname = '/' + result.pathname;
|
||||
}
|
||||
if (!result.origin) {
|
||||
result.origin = result.protocol + '//' + result.hostname + (result.port ? ':' + result.port : '');
|
||||
}
|
||||
}
|
||||
}
|
||||
if (result.username || result.password) {
|
||||
// throw an error if basic basic authentication is targeted
|
||||
throw new URIError(result.username + ':' + result.password);
|
||||
}
|
||||
return result;
|
||||
};
|
||||
}());
|
||||
/*
|
||||
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/encodeURIComponent
|
||||
function encodeURIComponentRFC3986(str) {
|
||||
return encodeURIComponent(str).replace(/[!'()*]/g, function (c) {
|
||||
return '%' + c.charCodeAt(0).toString(16);
|
||||
});
|
||||
}
|
||||
*/
|
||||
// Append the nonce as query strings to the uri
|
||||
function add_query_nonce(uri, nonce) {
|
||||
if (typeof uri !== 'object') { // `string` or `undefined`
|
||||
uri = parse_uri(uri || window.location.href);
|
||||
}
|
||||
|
||||
var data = uri.query ? uri.query.split('&') : [],
|
||||
i = data.length,
|
||||
q = auth.key + '=';
|
||||
|
||||
// remove an old nonce
|
||||
while (i-- > 0) {
|
||||
if (data[i].indexOf(q) === 0) { // or `wpzep.regexp.test(data[i])`
|
||||
data.splice(i, 1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
data.push(auth.key + '=' + encodeURIComponent(nonce)); //RFC3986
|
||||
uri.query = data.join('&');
|
||||
|
||||
return compose_uri(uri);
|
||||
}
|
||||
|
||||
// Check uri component if it is not empty or only fragment (`#...`)
|
||||
function check_uri(uri) {
|
||||
return (!uri.scheme || /^https?$/.test(uri.scheme)) && (uri.path || uri.query);
|
||||
}
|
||||
|
||||
// Check uri where the nonce is needed
|
||||
// Note: in case of url in the admin area of different site, it returns 0
|
||||
function is_admin(url) {
|
||||
// parse uri and get real path
|
||||
try {
|
||||
url = url || window.location.pathname || ''; // in case of empty `action` on the form tag
|
||||
} catch (e) {
|
||||
url = '';
|
||||
}
|
||||
|
||||
var uri = parse_uri(url.toLowerCase());
|
||||
|
||||
// possibly scheme is `javascript` and path is `void(0);`
|
||||
if (check_uri(uri)) {
|
||||
// get absolute path with flattening `./`, `../`, `//`
|
||||
uri = absolute_uri(url);
|
||||
|
||||
// external domain (`http://example` or `www.example`)
|
||||
// https://tools.ietf.org/html/rfc6454#section-4
|
||||
if (uri.origin !== window.location.origin) {
|
||||
return -1; // external
|
||||
}
|
||||
|
||||
// check if uri includes the target path of zep
|
||||
url = regexp.exec(uri.pathname);
|
||||
if (url) {
|
||||
if ((0 <= url[0].indexOf(auth.admin + 'admin-')) ||
|
||||
(0 <= url[0].indexOf(auth.admin )) ||
|
||||
(0 <= url[0].indexOf(auth.plugins )) ||
|
||||
(0 <= url[0].indexOf(auth.themes ))) {
|
||||
return 1; // internal for admin
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 0; // internal not admin
|
||||
}
|
||||
|
||||
// Check if current page is admin area and the target of wp-zep
|
||||
function is_backend() {
|
||||
return (is_admin(window.location.pathname) === 1 || wpzep.regexp(window.location.search));
|
||||
}
|
||||
|
||||
// Check if url belongs to multisite
|
||||
function is_multisite(url) {
|
||||
var i, j, n = auth.sites.length;
|
||||
|
||||
for (i = 0; i < n; ++i) {
|
||||
j = url.indexOf(auth.sites[i] + '/');
|
||||
if (0 <= j && j <= 6) { // from `//` to `https://`
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// check if the uri does not need a nonce
|
||||
function is_neutral(uri) {
|
||||
// return !uri.query; // without queries
|
||||
// return !uri.query || !$('body').hasClass('wp-core-ui'); // without queries or outside dashboard
|
||||
return /\/$/.test(uri.path); // `/wp-admin/`
|
||||
}
|
||||
|
||||
// check if the link has nofollow
|
||||
function has_nofollow($elem) {
|
||||
return -1 !== ($elem.attr('rel') || '').indexOf('nofollow');
|
||||
}
|
||||
/*
|
||||
$.ajaxSetup({
|
||||
beforeSend: function (xhr, settings) {
|
||||
// settings: {
|
||||
// url: '/wp-admin/admin-ajax.php'
|
||||
// method: 'POST' or 'GET'
|
||||
// contentType: 'application/x-www-form-urlencoded; charset=UTF-8'
|
||||
// data: 'action=...'
|
||||
// }
|
||||
}
|
||||
});
|
||||
|
||||
// plupload
|
||||
$(window).on('BeforeUpload', function (uploader, file) {
|
||||
console.log(uploader);
|
||||
});
|
||||
*/
|
||||
// Embed a nonce before an Ajax request is sent
|
||||
// $(document).ajaxSend(function (event, jqxhr, settings) {
|
||||
$.ajaxPrefilter(function (settings /*, original, jqxhr*/) {
|
||||
// POST to async-upload.php causes an error in https://wordpress.org/plugins/mammoth-docx-converter/
|
||||
if (is_admin(settings.url) === 1 && !settings.url.match(/async-upload\.php$/)) {
|
||||
// multipart/form-data (XMLHttpRequest Level 2)
|
||||
// IE10+, Firefox 4+, Safari 5+, Android 3+
|
||||
if (typeof window.FormData !== 'undefined' && settings.data instanceof FormData) {
|
||||
settings.data.append(auth.key, auth.nonce);
|
||||
}
|
||||
|
||||
// application/x-www-form-urlencoded
|
||||
else {
|
||||
// Behavior of jQuery Ajax
|
||||
// method url url+data data
|
||||
// GET query query data
|
||||
// POST query query data
|
||||
var data, callback, uri = parse_uri(settings.url);
|
||||
|
||||
if (typeof settings.data === 'undefined' || uri.query) {
|
||||
settings.url = add_query_nonce(uri, auth.nonce);
|
||||
} else {
|
||||
data = settings.data ? settings.data.split('&') : [];
|
||||
callback = check_ajax(window.location.pathname);
|
||||
if (callback) {
|
||||
data = callback(data);
|
||||
}
|
||||
data.push(auth.key + '=' + encodeURIComponent(auth.nonce)); //RFC3986
|
||||
settings.data = data.join('&');
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
/*
|
||||
* jQuery.bind-first library v0.2.3 (jquery >= 1.7)
|
||||
* Copyright (c) 2013 Vladimir Zhuravlev
|
||||
*
|
||||
* Released under MIT License
|
||||
* @license https://github.com/private-face/jquery.bind-first
|
||||
*
|
||||
* Date: Thu Feb 6 10:13:59 ICT 2014
|
||||
*/
|
||||
function moveHandlerToTop($el, eventName, isDelegated) {
|
||||
var data = $._data($el[0]).events,
|
||||
events = data[eventName],
|
||||
handler = isDelegated ? events.splice(events.delegateCount - 1, 1)[0] : events.pop();
|
||||
|
||||
events.splice(isDelegated ? 0 : (events.delegateCount || 0), 0, handler);
|
||||
}
|
||||
|
||||
function moveEventHandlers($elems, eventsString, isDelegate) {
|
||||
var events = eventsString.split(/\s+/);
|
||||
$elems.each(function(i) {
|
||||
for (i = 0; i < events.length; ++i) {
|
||||
var pureEventName = $.trim(events[i]).match(/[^\.]+/i)[0];
|
||||
moveHandlerToTop($(this), pureEventName, isDelegate);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
if (typeof $.fn.onFirst === 'undefined') {
|
||||
$.fn.onFirst = function(types, selector) {
|
||||
var type, $el = $(this), isDelegated = (typeof selector === 'string');
|
||||
|
||||
$.fn.on.apply($el, arguments);
|
||||
|
||||
// events map
|
||||
if (typeof types === 'object') {
|
||||
for (type in types) {
|
||||
if (types.hasOwnProperty(type)) {
|
||||
moveEventHandlers($el, type, isDelegated);
|
||||
}
|
||||
}
|
||||
} else if (typeof types === 'string') {
|
||||
moveEventHandlers($el, types, isDelegated);
|
||||
}
|
||||
|
||||
return $el;
|
||||
};
|
||||
}
|
||||
|
||||
/*--------------------------------
|
||||
* Attach event to the document
|
||||
*--------------------------------*/
|
||||
function attach_event() {
|
||||
// https://www.sitepoint.com/jquery-body-on-document-on/
|
||||
var elem = $(document); // `html` or `body` doesn't work with some browsers
|
||||
|
||||
elem.onFirst('click contextmenu', 'a', function (event) {
|
||||
var admin = 0, // default: do nothing if href is empty
|
||||
$this = $(this),
|
||||
href = $this.attr('href') || '', // returns 'string' or 'undefined'
|
||||
uri = parse_uri(href);
|
||||
|
||||
// check href has right scheme and path
|
||||
if (check_uri(uri)) {
|
||||
admin = is_admin(href);
|
||||
}
|
||||
|
||||
// console.log('href:' + href, uri, 'admin:' + admin, 'is_backend:' + is_backend(), 'is_multisite:' + is_multisite(href));
|
||||
|
||||
// if context menu then continue and should be checked in check_nonce()
|
||||
if ('click' !== event.type) {
|
||||
return;
|
||||
}
|
||||
|
||||
// if admin area (except a link with nofollow in the comment thread) then add a nonce
|
||||
else if (admin === 1) {
|
||||
$this.attr('href', is_neutral(uri) ? href :
|
||||
add_query_nonce( href, has_nofollow($this) ? 'nofollow' : auth.nonce )
|
||||
);
|
||||
}
|
||||
|
||||
// if external then redirect with no referrer not to leak out the nonce
|
||||
else if (admin === -1 && is_backend()) {
|
||||
// open within the same window
|
||||
if ('_self' === $this.attr('target') || is_multisite(href)) {
|
||||
$this.attr('href', is_neutral(uri) ? href :
|
||||
add_query_nonce( href, has_nofollow($this) ? 'nofollow' : auth.nonce )
|
||||
);
|
||||
}
|
||||
|
||||
// open a new window
|
||||
else if (!this.hasAttribute('onClick')) {
|
||||
// avoid `url=...;url=javascript:...`
|
||||
href = href.split(';', 2).shift();
|
||||
href = escapeHTML(decodeURIComponent(this.href)); // & => &
|
||||
|
||||
admin = window.open();
|
||||
admin.document.write(
|
||||
'<!DOCTYPE html><html><head>' +
|
||||
'<meta name="referrer" content="never" />' +
|
||||
'<meta name="referrer" content="no-referrer" />' +
|
||||
'<meta http-equiv="refresh" content="0; url=' + href + '" />' +
|
||||
($('body').hasClass('webview') ? '<script>window.location.replace("' + href + '")</script>' : '') +
|
||||
'</head></html>'
|
||||
);
|
||||
admin.document.close();
|
||||
|
||||
// stop event propagation and location transition
|
||||
event.stopImmediatePropagation();
|
||||
return false; // same as event.stopPropagation() and event.preventDefault()
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
elem.onFirst('submit', 'form', function (/*event*/) {
|
||||
var $this = $(this), action = $this.attr('action'); // possibly 'undefined'
|
||||
|
||||
// if admin area then add the nonce
|
||||
if (is_admin(action) === 1) {
|
||||
if ('post' === ($this.attr('method') || '').toLowerCase()) {
|
||||
$this.attr('action', add_query_nonce(action, auth.nonce));
|
||||
} else {
|
||||
// https://www.w3.org/TR/1999/REC-html401-19991224/types.html#type-name
|
||||
$this.append('<input type="hidden" name="' + auth.key + '" value="' + auth.nonce + '">');
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/*--------------------------------
|
||||
* Something after document ready
|
||||
*--------------------------------*/
|
||||
function attach_ready(/*stat*/) {
|
||||
if (!wpzep.init) {
|
||||
wpzep.init = true;
|
||||
|
||||
$('img').each(function (/*index*/) {
|
||||
var src = $(this).attr('src');
|
||||
|
||||
// if admin area
|
||||
if (is_admin(src) === 1) {
|
||||
$(this).attr('src', add_query_nonce(src, auth.nonce));
|
||||
}
|
||||
});
|
||||
|
||||
// Restore post revisions (wp-admin/revisions.php @since 2.6.0)
|
||||
if ('undefined' !== typeof window._wpRevisionsSettings) {
|
||||
var i, data = window._wpRevisionsSettings.revisionData, n = data.length;
|
||||
|
||||
for (i = 0; i < n; ++i) {
|
||||
if (!wpzep.regexp.test(data[i].restoreUrl)) {
|
||||
window._wpRevisionsSettings.revisionData[i].restoreUrl = add_query_nonce(data[i].restoreUrl, auth.nonce);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Hide the title of sub-menu.
|
||||
$('#toplevel_page_ip-geo-block li.wp-first-item').each(function (/*i, obj*/) {
|
||||
var $this = $(this);
|
||||
$this.css('display', 'IP Geo Block' === $this.children('a').text() ? 'none' : 'block');
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
$(window).on('error', function (/*event*/) { // event.originalEvent.message
|
||||
attach_ready(); // fallback on error
|
||||
});
|
||||
|
||||
$(function () {
|
||||
attach_ready();
|
||||
});
|
||||
|
||||
// Attach event to add nonce
|
||||
attach_event();
|
||||
}(jQuery, window, document));
|
||||
Reference in New Issue
Block a user