Phase 6: AIOS security plugin with conservative login lockdown config (10 attempts)
This commit is contained in:
Executable
+620
@@ -0,0 +1,620 @@
|
||||
/*!
|
||||
* jQuery blockUI plugin
|
||||
* Version 2.70.0-2014.11.23
|
||||
* Requires jQuery v1.7 or later
|
||||
*
|
||||
* Examples at: http://malsup.com/jquery/block/
|
||||
* Copyright (c) 2007-2013 M. Alsup
|
||||
* Dual licensed under the MIT and GPL licenses:
|
||||
* http://www.opensource.org/licenses/mit-license.php
|
||||
* http://www.gnu.org/licenses/gpl.html
|
||||
*
|
||||
* Thanks to Amir-Hossein Sobhi for some excellent contributions!
|
||||
*/
|
||||
|
||||
;(function() {
|
||||
/*jshint eqeqeq:false curly:false latedef:false */
|
||||
"use strict";
|
||||
|
||||
function setup($) {
|
||||
$.fn._fadeIn = $.fn.fadeIn;
|
||||
|
||||
var noOp = $.noop || function() {};
|
||||
|
||||
// this bit is to ensure we don't call setExpression when we shouldn't (with extra muscle to handle
|
||||
// confusing userAgent strings on Vista)
|
||||
var msie = /MSIE/.test(navigator.userAgent);
|
||||
var ie6 = /MSIE 6.0/.test(navigator.userAgent) && ! /MSIE 8.0/.test(navigator.userAgent);
|
||||
var mode = document.documentMode || 0;
|
||||
var setExpr = $.isFunction( document.createElement('div').style.setExpression );
|
||||
|
||||
// global $ methods for blocking/unblocking the entire page
|
||||
$.blockUI = function(opts) { install(window, opts); };
|
||||
$.unblockUI = function(opts) { remove(window, opts); };
|
||||
|
||||
// convenience method for quick growl-like notifications (http://www.google.com/search?q=growl)
|
||||
$.growlUI = function(title, message, timeout, onClose) {
|
||||
var $m = $('<div class="growlUI"></div>');
|
||||
if (title) $m.append('<h1>'+title+'</h1>');
|
||||
if (message) $m.append('<h2>'+message+'</h2>');
|
||||
if (timeout === undefined) timeout = 3000;
|
||||
|
||||
// Added by konapun: Set timeout to 30 seconds if this growl is moused over, like normal toast notifications
|
||||
var callBlock = function(opts) {
|
||||
opts = opts || {};
|
||||
|
||||
$.blockUI({
|
||||
message: $m,
|
||||
fadeIn : typeof opts.fadeIn !== 'undefined' ? opts.fadeIn : 700,
|
||||
fadeOut: typeof opts.fadeOut !== 'undefined' ? opts.fadeOut : 1000,
|
||||
timeout: typeof opts.timeout !== 'undefined' ? opts.timeout : timeout,
|
||||
centerY: false,
|
||||
showOverlay: false,
|
||||
onUnblock: onClose,
|
||||
css: $.blockUI.defaults.growlCSS
|
||||
});
|
||||
};
|
||||
|
||||
callBlock();
|
||||
var nonmousedOpacity = $m.css('opacity');
|
||||
$m.mouseover(function() {
|
||||
callBlock({
|
||||
fadeIn: 0,
|
||||
timeout: 30000
|
||||
});
|
||||
|
||||
var displayBlock = $('.blockMsg');
|
||||
displayBlock.stop(); // cancel fadeout if it has started
|
||||
displayBlock.fadeTo(300, 1); // make it easier to read the message by removing transparency
|
||||
}).mouseout(function() {
|
||||
$('.blockMsg').fadeOut(1000);
|
||||
});
|
||||
// End konapun additions
|
||||
};
|
||||
|
||||
// plugin method for blocking element content
|
||||
$.fn.block = function(opts) {
|
||||
if ( this[0] === window ) {
|
||||
$.blockUI( opts );
|
||||
return this;
|
||||
}
|
||||
var fullOpts = $.extend({}, $.blockUI.defaults, opts || {});
|
||||
this.each(function() {
|
||||
var $el = $(this);
|
||||
if (fullOpts.ignoreIfBlocked && $el.data('blockUI.isBlocked'))
|
||||
return;
|
||||
$el.unblock({ fadeOut: 0 });
|
||||
});
|
||||
|
||||
return this.each(function() {
|
||||
if ($.css(this,'position') == 'static') {
|
||||
this.style.position = 'relative';
|
||||
$(this).data('blockUI.static', true);
|
||||
}
|
||||
this.style.zoom = 1; // force 'hasLayout' in ie
|
||||
install(this, opts);
|
||||
});
|
||||
};
|
||||
|
||||
// plugin method for unblocking element content
|
||||
$.fn.unblock = function(opts) {
|
||||
if ( this[0] === window ) {
|
||||
$.unblockUI( opts );
|
||||
return this;
|
||||
}
|
||||
return this.each(function() {
|
||||
remove(this, opts);
|
||||
});
|
||||
};
|
||||
|
||||
$.blockUI.version = 2.70; // 2nd generation blocking at no extra cost!
|
||||
|
||||
// override these in your code to change the default behavior and style
|
||||
$.blockUI.defaults = {
|
||||
// message displayed when blocking (use null for no message)
|
||||
message: '<h1>Please wait...</h1>',
|
||||
|
||||
title: null, // title string; only used when theme == true
|
||||
draggable: true, // only used when theme == true (requires jquery-ui.js to be loaded)
|
||||
|
||||
theme: false, // set to true to use with jQuery UI themes
|
||||
|
||||
// styles for the message when blocking; if you wish to disable
|
||||
// these and use an external stylesheet then do this in your code:
|
||||
// $.blockUI.defaults.css = {};
|
||||
css: {
|
||||
padding: 0,
|
||||
margin: 0,
|
||||
width: '30%',
|
||||
top: '40%',
|
||||
left: '35%',
|
||||
textAlign: 'center',
|
||||
color: '#000',
|
||||
border: '3px solid #aaa',
|
||||
backgroundColor:'#fff',
|
||||
cursor: 'wait'
|
||||
},
|
||||
|
||||
// minimal style set used when themes are used
|
||||
themedCSS: {
|
||||
width: '30%',
|
||||
top: '40%',
|
||||
left: '35%'
|
||||
},
|
||||
|
||||
// styles for the overlay
|
||||
overlayCSS: {
|
||||
backgroundColor: '#000',
|
||||
opacity: 0.6,
|
||||
cursor: 'wait'
|
||||
},
|
||||
|
||||
// style to replace wait cursor before unblocking to correct issue
|
||||
// of lingering wait cursor
|
||||
cursorReset: 'default',
|
||||
|
||||
// styles applied when using $.growlUI
|
||||
growlCSS: {
|
||||
width: '350px',
|
||||
top: '10px',
|
||||
left: '',
|
||||
right: '10px',
|
||||
border: 'none',
|
||||
padding: '5px',
|
||||
opacity: 0.6,
|
||||
cursor: 'default',
|
||||
color: '#fff',
|
||||
backgroundColor: '#000',
|
||||
'-webkit-border-radius':'10px',
|
||||
'-moz-border-radius': '10px',
|
||||
'border-radius': '10px'
|
||||
},
|
||||
|
||||
// IE issues: 'about:blank' fails on HTTPS and javascript:false is s-l-o-w
|
||||
// (hat tip to Jorge H. N. de Vasconcelos)
|
||||
/*jshint scripturl:true */
|
||||
iframeSrc: /^https/i.test(window.location.href || '') ? 'javascript:false' : 'about:blank',
|
||||
|
||||
// force usage of iframe in non-IE browsers (handy for blocking applets)
|
||||
forceIframe: false,
|
||||
|
||||
// z-index for the blocking overlay
|
||||
baseZ: 1000,
|
||||
|
||||
// set these to true to have the message automatically centered
|
||||
centerX: true, // <-- only effects element blocking (page block controlled via css above)
|
||||
centerY: true,
|
||||
|
||||
// allow body element to be stetched in ie6; this makes blocking look better
|
||||
// on "short" pages. disable if you wish to prevent changes to the body height
|
||||
allowBodyStretch: true,
|
||||
|
||||
// enable if you want key and mouse events to be disabled for content that is blocked
|
||||
bindEvents: true,
|
||||
|
||||
// be default blockUI will supress tab navigation from leaving blocking content
|
||||
// (if bindEvents is true)
|
||||
constrainTabKey: true,
|
||||
|
||||
// fadeIn time in millis; set to 0 to disable fadeIn on block
|
||||
fadeIn: 200,
|
||||
|
||||
// fadeOut time in millis; set to 0 to disable fadeOut on unblock
|
||||
fadeOut: 400,
|
||||
|
||||
// time in millis to wait before auto-unblocking; set to 0 to disable auto-unblock
|
||||
timeout: 0,
|
||||
|
||||
// disable if you don't want to show the overlay
|
||||
showOverlay: true,
|
||||
|
||||
// if true, focus will be placed in the first available input field when
|
||||
// page blocking
|
||||
focusInput: true,
|
||||
|
||||
// elements that can receive focus
|
||||
focusableElements: ':input:enabled:visible',
|
||||
|
||||
// suppresses the use of overlay styles on FF/Linux (due to performance issues with opacity)
|
||||
// no longer needed in 2012
|
||||
// applyPlatformOpacityRules: true,
|
||||
|
||||
// callback method invoked when fadeIn has completed and blocking message is visible
|
||||
onBlock: null,
|
||||
|
||||
// callback method invoked when unblocking has completed; the callback is
|
||||
// passed the element that has been unblocked (which is the window object for page
|
||||
// blocks) and the options that were passed to the unblock call:
|
||||
// onUnblock(element, options)
|
||||
onUnblock: null,
|
||||
|
||||
// callback method invoked when the overlay area is clicked.
|
||||
// setting this will turn the cursor to a pointer, otherwise cursor defined in overlayCss will be used.
|
||||
onOverlayClick: null,
|
||||
|
||||
// don't ask; if you really must know: http://groups.google.com/group/jquery-en/browse_thread/thread/36640a8730503595/2f6a79a77a78e493#2f6a79a77a78e493
|
||||
quirksmodeOffsetHack: 4,
|
||||
|
||||
// class name of the message block
|
||||
blockMsgClass: 'blockMsg',
|
||||
|
||||
// if it is already blocked, then ignore it (don't unblock and reblock)
|
||||
ignoreIfBlocked: false
|
||||
};
|
||||
|
||||
// private data and functions follow...
|
||||
|
||||
var pageBlock = null;
|
||||
var pageBlockEls = [];
|
||||
|
||||
function install(el, opts) {
|
||||
var css, themedCSS;
|
||||
var full = (el == window);
|
||||
var msg = (opts && opts.message !== undefined ? opts.message : undefined);
|
||||
opts = $.extend({}, $.blockUI.defaults, opts || {});
|
||||
|
||||
if (opts.ignoreIfBlocked && $(el).data('blockUI.isBlocked'))
|
||||
return;
|
||||
|
||||
opts.overlayCSS = $.extend({}, $.blockUI.defaults.overlayCSS, opts.overlayCSS || {});
|
||||
css = $.extend({}, $.blockUI.defaults.css, opts.css || {});
|
||||
if (opts.onOverlayClick)
|
||||
opts.overlayCSS.cursor = 'pointer';
|
||||
|
||||
themedCSS = $.extend({}, $.blockUI.defaults.themedCSS, opts.themedCSS || {});
|
||||
msg = msg === undefined ? opts.message : msg;
|
||||
|
||||
// remove the current block (if there is one)
|
||||
if (full && pageBlock)
|
||||
remove(window, {fadeOut:0});
|
||||
|
||||
// if an existing element is being used as the blocking content then we capture
|
||||
// its current place in the DOM (and current display style) so we can restore
|
||||
// it when we unblock
|
||||
if (msg && typeof msg != 'string' && (msg.parentNode || msg.jquery)) {
|
||||
var node = msg.jquery ? msg[0] : msg;
|
||||
var data = {};
|
||||
$(el).data('blockUI.history', data);
|
||||
data.el = node;
|
||||
data.parent = node.parentNode;
|
||||
data.display = node.style.display;
|
||||
data.position = node.style.position;
|
||||
if (data.parent)
|
||||
data.parent.removeChild(node);
|
||||
}
|
||||
|
||||
$(el).data('blockUI.onUnblock', opts.onUnblock);
|
||||
var z = opts.baseZ;
|
||||
|
||||
// blockUI uses 3 layers for blocking, for simplicity they are all used on every platform;
|
||||
// layer1 is the iframe layer which is used to supress bleed through of underlying content
|
||||
// layer2 is the overlay layer which has opacity and a wait cursor (by default)
|
||||
// layer3 is the message content that is displayed while blocking
|
||||
var lyr1, lyr2, lyr3, s;
|
||||
if (msie || opts.forceIframe)
|
||||
lyr1 = $('<iframe class="blockUI" style="z-index:'+ (z++) +';display:none;border:none;margin:0;padding:0;position:absolute;width:100%;height:100%;top:0;left:0" src="'+opts.iframeSrc+'"></iframe>');
|
||||
else
|
||||
lyr1 = $('<div class="blockUI" style="display:none"></div>');
|
||||
|
||||
if (opts.theme)
|
||||
lyr2 = $('<div class="blockUI blockOverlay ui-widget-overlay" style="z-index:'+ (z++) +';display:none"></div>');
|
||||
else
|
||||
lyr2 = $('<div class="blockUI blockOverlay" style="z-index:'+ (z++) +';display:none;border:none;margin:0;padding:0;width:100%;height:100%;top:0;left:0"></div>');
|
||||
|
||||
if (opts.theme && full) {
|
||||
s = '<div class="blockUI ' + opts.blockMsgClass + ' blockPage ui-dialog ui-widget ui-corner-all" style="z-index:'+(z+10)+';display:none;position:fixed">';
|
||||
if ( opts.title ) {
|
||||
s += '<div class="ui-widget-header ui-dialog-titlebar ui-corner-all blockTitle">'+(opts.title || ' ')+'</div>';
|
||||
}
|
||||
s += '<div class="ui-widget-content ui-dialog-content"></div>';
|
||||
s += '</div>';
|
||||
}
|
||||
else if (opts.theme) {
|
||||
s = '<div class="blockUI ' + opts.blockMsgClass + ' blockElement ui-dialog ui-widget ui-corner-all" style="z-index:'+(z+10)+';display:none;position:absolute">';
|
||||
if ( opts.title ) {
|
||||
s += '<div class="ui-widget-header ui-dialog-titlebar ui-corner-all blockTitle">'+(opts.title || ' ')+'</div>';
|
||||
}
|
||||
s += '<div class="ui-widget-content ui-dialog-content"></div>';
|
||||
s += '</div>';
|
||||
}
|
||||
else if (full) {
|
||||
s = '<div class="blockUI ' + opts.blockMsgClass + ' blockPage" style="z-index:'+(z+10)+';display:none;position:fixed"></div>';
|
||||
}
|
||||
else {
|
||||
s = '<div class="blockUI ' + opts.blockMsgClass + ' blockElement" style="z-index:'+(z+10)+';display:none;position:absolute"></div>';
|
||||
}
|
||||
lyr3 = $(s);
|
||||
|
||||
// if we have a message, style it
|
||||
if (msg) {
|
||||
if (opts.theme) {
|
||||
lyr3.css(themedCSS);
|
||||
lyr3.addClass('ui-widget-content');
|
||||
}
|
||||
else
|
||||
lyr3.css(css);
|
||||
}
|
||||
|
||||
// style the overlay
|
||||
if (!opts.theme /*&& (!opts.applyPlatformOpacityRules)*/)
|
||||
lyr2.css(opts.overlayCSS);
|
||||
lyr2.css('position', full ? 'fixed' : 'absolute');
|
||||
|
||||
// make iframe layer transparent in IE
|
||||
if (msie || opts.forceIframe)
|
||||
lyr1.css('opacity',0.0);
|
||||
|
||||
//$([lyr1[0],lyr2[0],lyr3[0]]).appendTo(full ? 'body' : el);
|
||||
var layers = [lyr1,lyr2,lyr3], $par = full ? $('body') : $(el);
|
||||
$.each(layers, function() {
|
||||
this.appendTo($par);
|
||||
});
|
||||
|
||||
if (opts.theme && opts.draggable && $.fn.draggable) {
|
||||
lyr3.draggable({
|
||||
handle: '.ui-dialog-titlebar',
|
||||
cancel: 'li'
|
||||
});
|
||||
}
|
||||
|
||||
// ie7 must use absolute positioning in quirks mode and to account for activex issues (when scrolling)
|
||||
var expr = setExpr && (!$.support.boxModel || $('object,embed', full ? null : el).length > 0);
|
||||
if (ie6 || expr) {
|
||||
// give body 100% height
|
||||
if (full && opts.allowBodyStretch && $.support.boxModel)
|
||||
$('html,body').css('height','100%');
|
||||
|
||||
// fix ie6 issue when blocked element has a border width
|
||||
if ((ie6 || !$.support.boxModel) && !full) {
|
||||
var t = sz(el,'borderTopWidth'), l = sz(el,'borderLeftWidth');
|
||||
var fixT = t ? '(0 - '+t+')' : 0;
|
||||
var fixL = l ? '(0 - '+l+')' : 0;
|
||||
}
|
||||
|
||||
// simulate fixed position
|
||||
$.each(layers, function(i,o) {
|
||||
var s = o[0].style;
|
||||
s.position = 'absolute';
|
||||
if (i < 2) {
|
||||
if (full)
|
||||
s.setExpression('height','Math.max(document.body.scrollHeight, document.body.offsetHeight) - (jQuery.support.boxModel?0:'+opts.quirksmodeOffsetHack+') + "px"');
|
||||
else
|
||||
s.setExpression('height','this.parentNode.offsetHeight + "px"');
|
||||
if (full)
|
||||
s.setExpression('width','jQuery.support.boxModel && document.documentElement.clientWidth || document.body.clientWidth + "px"');
|
||||
else
|
||||
s.setExpression('width','this.parentNode.offsetWidth + "px"');
|
||||
if (fixL) s.setExpression('left', fixL);
|
||||
if (fixT) s.setExpression('top', fixT);
|
||||
}
|
||||
else if (opts.centerY) {
|
||||
if (full) s.setExpression('top','(document.documentElement.clientHeight || document.body.clientHeight) / 2 - (this.offsetHeight / 2) + (blah = document.documentElement.scrollTop ? document.documentElement.scrollTop : document.body.scrollTop) + "px"');
|
||||
s.marginTop = 0;
|
||||
}
|
||||
else if (!opts.centerY && full) {
|
||||
var top = (opts.css && opts.css.top) ? parseInt(opts.css.top, 10) : 0;
|
||||
var expression = '((document.documentElement.scrollTop ? document.documentElement.scrollTop : document.body.scrollTop) + '+top+') + "px"';
|
||||
s.setExpression('top',expression);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// show the message
|
||||
if (msg) {
|
||||
if (opts.theme)
|
||||
lyr3.find('.ui-widget-content').append(msg);
|
||||
else
|
||||
lyr3.append(msg);
|
||||
if (msg.jquery || msg.nodeType)
|
||||
$(msg).show();
|
||||
}
|
||||
|
||||
if ((msie || opts.forceIframe) && opts.showOverlay)
|
||||
lyr1.show(); // opacity is zero
|
||||
if (opts.fadeIn) {
|
||||
var cb = opts.onBlock ? opts.onBlock : noOp;
|
||||
var cb1 = (opts.showOverlay && !msg) ? cb : noOp;
|
||||
var cb2 = msg ? cb : noOp;
|
||||
if (opts.showOverlay)
|
||||
lyr2._fadeIn(opts.fadeIn, cb1);
|
||||
if (msg)
|
||||
lyr3._fadeIn(opts.fadeIn, cb2);
|
||||
}
|
||||
else {
|
||||
if (opts.showOverlay)
|
||||
lyr2.show();
|
||||
if (msg)
|
||||
lyr3.show();
|
||||
if (opts.onBlock)
|
||||
opts.onBlock.bind(lyr3)();
|
||||
}
|
||||
|
||||
// bind key and mouse events
|
||||
bind(1, el, opts);
|
||||
|
||||
if (full) {
|
||||
pageBlock = lyr3[0];
|
||||
pageBlockEls = $(opts.focusableElements,pageBlock);
|
||||
if (opts.focusInput)
|
||||
setTimeout(focus, 20);
|
||||
}
|
||||
else
|
||||
center(lyr3[0], opts.centerX, opts.centerY);
|
||||
|
||||
if (opts.timeout) {
|
||||
// auto-unblock
|
||||
var to = setTimeout(function() {
|
||||
if (full)
|
||||
$.unblockUI(opts);
|
||||
else
|
||||
$(el).unblock(opts);
|
||||
}, opts.timeout);
|
||||
$(el).data('blockUI.timeout', to);
|
||||
}
|
||||
}
|
||||
|
||||
// remove the block
|
||||
function remove(el, opts) {
|
||||
var count;
|
||||
var full = (el == window);
|
||||
var $el = $(el);
|
||||
var data = $el.data('blockUI.history');
|
||||
var to = $el.data('blockUI.timeout');
|
||||
if (to) {
|
||||
clearTimeout(to);
|
||||
$el.removeData('blockUI.timeout');
|
||||
}
|
||||
opts = $.extend({}, $.blockUI.defaults, opts || {});
|
||||
bind(0, el, opts); // unbind events
|
||||
|
||||
if (opts.onUnblock === null) {
|
||||
opts.onUnblock = $el.data('blockUI.onUnblock');
|
||||
$el.removeData('blockUI.onUnblock');
|
||||
}
|
||||
|
||||
var els;
|
||||
if (full) // crazy selector to handle odd field errors in ie6/7
|
||||
els = $('body').children().filter('.blockUI').add('body > .blockUI');
|
||||
else
|
||||
els = $el.find('>.blockUI');
|
||||
|
||||
// fix cursor issue
|
||||
if ( opts.cursorReset ) {
|
||||
if ( els.length > 1 )
|
||||
els[1].style.cursor = opts.cursorReset;
|
||||
if ( els.length > 2 )
|
||||
els[2].style.cursor = opts.cursorReset;
|
||||
}
|
||||
|
||||
if (full)
|
||||
pageBlock = pageBlockEls = null;
|
||||
|
||||
if (opts.fadeOut) {
|
||||
count = els.length;
|
||||
els.stop().fadeOut(opts.fadeOut, function() {
|
||||
if ( --count === 0)
|
||||
reset(els,data,opts,el);
|
||||
});
|
||||
}
|
||||
else
|
||||
reset(els, data, opts, el);
|
||||
}
|
||||
|
||||
// move blocking element back into the DOM where it started
|
||||
function reset(els,data,opts,el) {
|
||||
var $el = $(el);
|
||||
if ( $el.data('blockUI.isBlocked') )
|
||||
return;
|
||||
|
||||
els.each(function(i,o) {
|
||||
// remove via DOM calls so we don't lose event handlers
|
||||
if (this.parentNode)
|
||||
this.parentNode.removeChild(this);
|
||||
});
|
||||
|
||||
if (data && data.el) {
|
||||
data.el.style.display = data.display;
|
||||
data.el.style.position = data.position;
|
||||
data.el.style.cursor = 'default'; // #59
|
||||
if (data.parent)
|
||||
data.parent.appendChild(data.el);
|
||||
$el.removeData('blockUI.history');
|
||||
}
|
||||
|
||||
if ($el.data('blockUI.static')) {
|
||||
$el.css('position', 'static'); // #22
|
||||
}
|
||||
|
||||
if (typeof opts.onUnblock == 'function')
|
||||
opts.onUnblock(el,opts);
|
||||
|
||||
// fix issue in Safari 6 where block artifacts remain until reflow
|
||||
var body = $(document.body), w = body.width(), cssW = body[0].style.width;
|
||||
body.width(w-1).width(w);
|
||||
body[0].style.width = cssW;
|
||||
}
|
||||
|
||||
// bind/unbind the handler
|
||||
function bind(b, el, opts) {
|
||||
var full = el == window, $el = $(el);
|
||||
|
||||
// don't bother unbinding if there is nothing to unbind
|
||||
if (!b && (full && !pageBlock || !full && !$el.data('blockUI.isBlocked')))
|
||||
return;
|
||||
|
||||
$el.data('blockUI.isBlocked', b);
|
||||
|
||||
// don't bind events when overlay is not in use or if bindEvents is false
|
||||
if (!full || !opts.bindEvents || (b && !opts.showOverlay))
|
||||
return;
|
||||
|
||||
// bind anchors and inputs for mouse and key events
|
||||
var events = 'mousedown mouseup keydown keypress keyup touchstart touchend touchmove';
|
||||
if (b)
|
||||
$(document).bind(events, opts, handler);
|
||||
else
|
||||
$(document).unbind(events, handler);
|
||||
|
||||
// former impl...
|
||||
// var $e = $('a,:input');
|
||||
// b ? $e.bind(events, opts, handler) : $e.unbind(events, handler);
|
||||
}
|
||||
|
||||
// event handler to suppress keyboard/mouse events when blocking
|
||||
function handler(e) {
|
||||
// allow tab navigation (conditionally)
|
||||
if (e.type === 'keydown' && e.keyCode && e.keyCode == 9) {
|
||||
if (pageBlock && e.data.constrainTabKey) {
|
||||
var els = pageBlockEls;
|
||||
var fwd = !e.shiftKey && e.target === els[els.length-1];
|
||||
var back = e.shiftKey && e.target === els[0];
|
||||
if (fwd || back) {
|
||||
setTimeout(function(){focus(back);},10);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
var opts = e.data;
|
||||
var target = $(e.target);
|
||||
if (target.hasClass('blockOverlay') && opts.onOverlayClick)
|
||||
opts.onOverlayClick(e);
|
||||
|
||||
// allow events within the message content
|
||||
if (target.parents('div.' + opts.blockMsgClass).length > 0)
|
||||
return true;
|
||||
|
||||
// allow events for content that is not being blocked
|
||||
return target.parents().children().filter('div.blockUI').length === 0;
|
||||
}
|
||||
|
||||
function focus(back) {
|
||||
if (!pageBlockEls)
|
||||
return;
|
||||
var e = pageBlockEls[back===true ? pageBlockEls.length-1 : 0];
|
||||
if (e)
|
||||
e.focus();
|
||||
}
|
||||
|
||||
function center(el, x, y) {
|
||||
var p = el.parentNode, s = el.style;
|
||||
var l = ((p.offsetWidth - el.offsetWidth)/2) - sz(p,'borderLeftWidth');
|
||||
var t = ((p.offsetHeight - el.offsetHeight)/2) - sz(p,'borderTopWidth');
|
||||
if (x) s.left = l > 0 ? (l+'px') : '0';
|
||||
if (y) s.top = t > 0 ? (t+'px') : '0';
|
||||
}
|
||||
|
||||
function sz(el, p) {
|
||||
return parseInt($.css(el,p),10)||0;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
/*global define:true */
|
||||
if (typeof define === 'function' && define.amd && define.amd.jQuery) {
|
||||
define(['jquery'], setup);
|
||||
} else {
|
||||
setup(jQuery);
|
||||
}
|
||||
|
||||
})();
|
||||
Vendored
Executable
+7
File diff suppressed because one or more lines are too long
Vendored
Executable
+7
@@ -0,0 +1,7 @@
|
||||
/*!
|
||||
* chartjs-gauge.js v0.3.0
|
||||
* https://github.com/haiiaaa/chartjs-gauge/
|
||||
* (c) 2021 chartjs-gauge.js Contributors
|
||||
* Released under the MIT License
|
||||
*/
|
||||
!function(t,e){"object"==typeof exports&&"undefined"!=typeof module?module.exports=e(require("chart.js")):"function"==typeof define&&define.amd?define(["chart.js"],e):(t=t||self).Gauge=e(t.Chart)}(this,(function(t){"use strict";function e(t,e,r){return e in t?Object.defineProperty(t,e,{value:r,enumerable:!0,configurable:!0,writable:!0}):t[e]=r,t}function r(t,e){var r=Object.keys(t);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(t);e&&(a=a.filter((function(e){return Object.getOwnPropertyDescriptor(t,e).enumerable}))),r.push.apply(r,a)}return r}(t=t&&Object.prototype.hasOwnProperty.call(t,"default")?t.default:t).defaults._set("gauge",{needle:{radiusPercentage:2,widthPercentage:3.2,lengthPercentage:80,color:"rgba(0, 0, 0, 1)"},valueLabel:{display:!0,formatter:null,color:"rgba(255, 255, 255, 1)",backgroundColor:"rgba(0, 0, 0, 1)",borderRadius:5,padding:{top:5,right:5,bottom:5,left:5},bottomMarginPercentage:5},animation:{duration:1e3,animateRotate:!0,animateScale:!1},cutoutPercentage:50,rotation:-Math.PI,circumference:Math.PI,legend:{display:!1},tooltips:{enabled:!1}});var a=t.controllers.doughnut.extend({getValuePercent:function(t,e){var r=t.minValue,a=t.data,n=r||0;return(e-n)/((a[a.length-1]||1)-n)},getWidth:function(t){return t.chartArea.right-t.chartArea.left},getTranslation:function(t){var e=t.chartArea,r=t.offsetX,a=t.offsetY;return{dx:(e.left+e.right)/2+r,dy:(e.top+e.bottom)/2+a}},getAngle:function(t){var e=t.chart,r=t.valuePercent,a=e.options;return a.rotation+a.circumference*r},drawNeedle:function(t){this.chart.animating||(t=1);var e=this.chart,r=e.ctx,a=e.config,n=e.innerRadius,i=e.outerRadius,o=a.data.datasets[this.index],l=this.getMeta().previous,c=a.options.needle,s=c.radiusPercentage,u=c.widthPercentage,h=c.lengthPercentage,d=c.color,g=this.getWidth(this.chart),f=s/100*g,p=u/100*g,b=h/100*(i-n)+n,P=this.getTranslation(this.chart),v=P.dx,m=P.dy,y=this.getAngle({chart:this.chart,valuePercent:l.valuePercent}),x=y+(this.getAngle({chart:this.chart,valuePercent:this.getValuePercent(o,o.value)})-y)*t;r.save(),r.translate(v,m),r.rotate(x),r.fillStyle=d,r.beginPath(),r.ellipse(0,0,f,f,0,0,2*Math.PI),r.fill(),r.beginPath(),r.moveTo(0,p/2),r.lineTo(b,0),r.lineTo(0,-p/2),r.fill(),r.restore()},drawValueLabel:function(e){if(this.chart.config.options.valueLabel.display){var r=this.chart,a=r.ctx,n=r.config,i=n.options.defaultFontFamily,o=n.data.datasets[this.index],l=n.options.valueLabel,c=l.formatter,s=l.fontSize,u=l.color,h=l.backgroundColor,d=l.borderRadius,g=l.padding,f=l.bottomMarginPercentage/100*this.getWidth(this.chart),p=(c||function(t){return t})(o.value).toString();a.textBaseline="middle",a.textAlign="center",s&&(a.font="".concat(s,"px ").concat(i));var b=a.measureText(p).width,P=Math.max(a.measureText("m").width,a.measureText("W").width),v=-(g.left+b/2),m=-(g.top+P/2),y=g.left+b+g.right,x=g.top+P+g.bottom,w=this.getTranslation(this.chart),O=w.dx,j=w.dy,M=this.chart.options.rotation%(2*Math.PI);O+=f*Math.cos(M+Math.PI/2),j+=f*Math.sin(M+Math.PI/2),a.save(),a.translate(O,j),a.beginPath(),t.helpers.canvas.roundedRect(a,v,m,y,x,d),a.fillStyle=h,a.fill(),a.fillStyle=u||n.options.defaultFontColor;a.fillText(p,0,.075*P),a.restore()}},update:function(e){var r=this.chart.config.data.datasets[this.index];r.minValue=r.minValue||0;var a=this.getMeta(),n={valuePercent:0};e?(a.previous=null,a.current=n):(r.data.sort((function(t,e){return t-e})),a.previous=a.current||n,a.current={valuePercent:this.getValuePercent(r,r.value)}),t.controllers.doughnut.prototype.update.call(this,e)},updateElement:function(a,n,i){t.controllers.doughnut.prototype.updateElement.call(this,a,n,i);var o=this.getDataset(),l=o.data,c=0===n?o.minValue:l[n-1],s=l[n],u=this.getAngle({chart:this.chart,valuePercent:this.getValuePercent(o,c)}),h=this.getAngle({chart:this.chart,valuePercent:this.getValuePercent(o,s)}),d=h-u;a._model=function(t){for(var a=1;a<arguments.length;a++){var n=null!=arguments[a]?arguments[a]:{};a%2?r(Object(n),!0).forEach((function(r){e(t,r,n[r])})):Object.getOwnPropertyDescriptors?Object.defineProperties(t,Object.getOwnPropertyDescriptors(n)):r(Object(n)).forEach((function(e){Object.defineProperty(t,e,Object.getOwnPropertyDescriptor(n,e))}))}return t}({},a._model,{startAngle:u,endAngle:h,circumference:d})},draw:function(e){t.controllers.doughnut.prototype.draw.call(this,e),this.drawNeedle(e),this.drawValueLabel(e)}});return void 0===CanvasRenderingContext2D.prototype.ellipse&&(CanvasRenderingContext2D.prototype.ellipse=function(t,e,r,a,n,i,o,l){this.save(),this.translate(t,e),this.rotate(n),this.scale(r,a),this.arc(0,0,1,i,o,l),this.restore()}),t.controllers.gauge=a,t.Gauge=function(e,r){return r.type="gauge",new t(e,r)},t.Gauge}));
|
||||
+122
@@ -0,0 +1,122 @@
|
||||
var tfa_query_leaving = false;
|
||||
|
||||
// Prevent accidental leaving if there are unsaved settings
|
||||
window.onbeforeunload = function(e) {
|
||||
if (tfa_query_leaving) {
|
||||
e.returnValue = simba_tfa_frontend.ask;
|
||||
return simba_tfa_frontend.ask;
|
||||
}
|
||||
}
|
||||
|
||||
jQuery(function($) {
|
||||
|
||||
$(".tfa_settings_form input, .tfa_settings_form textarea, .tfa_settings_form select" ).on('change', function() {
|
||||
tfa_query_leaving = true;
|
||||
});
|
||||
|
||||
$(".simbatfa_settings_save").on('click', function() {
|
||||
|
||||
$.blockUI({ message: '<div style="margin: 8px;font-size:150%;">'+simba_tfa_frontend.saving+'</div>' });
|
||||
|
||||
// https://stackoverflow.com/questions/10147149/how-can-i-override-jquerys-serialize-to-include-unchecked-checkboxes
|
||||
var form_data = $('.tfa_settings_form input, .tfa_settings_form textarea, .tfa_settings_form select').serialize();
|
||||
|
||||
// Include unchecked checkboxes. Use filter to only include unchecked boxes.
|
||||
$.each($('.tfa_settings_form input[type=checkbox]')
|
||||
.filter(function(idx) {
|
||||
return $(this).prop('checked') === false
|
||||
}),
|
||||
function(idx, el){
|
||||
// attach matched element names to the form_data with a chosen value.
|
||||
var emptyVal = '0';
|
||||
form_data += '&' + $(el).attr('name') + '=' + emptyVal;
|
||||
}
|
||||
);
|
||||
|
||||
$.post(simba_tfa_frontend.ajax_url, {
|
||||
action: 'tfa_frontend',
|
||||
subaction: 'savesettings',
|
||||
settings: form_data,
|
||||
nonce: simba_tfa_frontend.nonce
|
||||
}, function(response) {
|
||||
var settings_saved = false;
|
||||
try {
|
||||
var resp = JSON.parse(response);
|
||||
if (resp.hasOwnProperty('result')) {
|
||||
settings_saved = true;
|
||||
tfa_query_leaving = false;
|
||||
// Allow user code to respond
|
||||
$(document).trigger('tfa_settings_saved', resp);
|
||||
}
|
||||
|
||||
if (resp.hasOwnProperty('message')) {
|
||||
alert(resp.message);
|
||||
}
|
||||
|
||||
if (resp.hasOwnProperty('qr')) {
|
||||
$('.simbaotp_qr_container').data('qrcode', resp['qr']).empty().qrcode({
|
||||
"render": "image",
|
||||
"text": resp['qr'],
|
||||
});
|
||||
}
|
||||
|
||||
if (resp.hasOwnProperty('al_type_disp')) {
|
||||
$("#al_type_name").html(resp['al_type_disp']['disp']);
|
||||
$("#al_type_desc").html(resp['al_type_disp']['desc']);
|
||||
}
|
||||
|
||||
} catch(err) {
|
||||
console.log(err);
|
||||
console.log(response);
|
||||
if ('' === simba_tfa_frontend.also_try) {
|
||||
alert(simba_tfa_frontend.response+response);
|
||||
}
|
||||
}
|
||||
if ('' != simba_tfa_frontend.also_try) {
|
||||
if (!settings_saved) {
|
||||
$.post(simba_tfa_frontend.also_try, {
|
||||
action: 'tfa_frontend',
|
||||
subaction: 'savesettings',
|
||||
settings: form_data,
|
||||
nonce: simba_tfa_frontend.nonce
|
||||
}, function(response) {
|
||||
|
||||
try {
|
||||
var resp = JSON.parse(response);
|
||||
if (resp.hasOwnProperty('result')) {
|
||||
settings_saved = true;
|
||||
tfa_query_leaving = false;
|
||||
// Allow user code to respond
|
||||
$(document).trigger('tfa_settings_saved', resp);
|
||||
}
|
||||
if (resp.hasOwnProperty('message')) {
|
||||
alert(resp.message);
|
||||
}
|
||||
if (resp.hasOwnProperty('qr')) {
|
||||
$('.simbaotp_qr_container').data('qrcode', resp['qr']).empty().qrcode({
|
||||
"render": "image",
|
||||
"text": resp['qr'],
|
||||
});
|
||||
}
|
||||
if (resp.hasOwnProperty('al_type_disp')) {
|
||||
$("#al_type_name").html(resp['al_type_disp']['disp']);
|
||||
$("#al_type_desc").html(resp['al_type_disp']['desc']);
|
||||
}
|
||||
|
||||
} catch(err) {
|
||||
console.log(err);
|
||||
console.log(response);
|
||||
alert(simba_tfa_frontend.response+response);
|
||||
}
|
||||
$.unblockUI();
|
||||
});
|
||||
} else {
|
||||
$.unblockUI();
|
||||
}
|
||||
} else {
|
||||
$.unblockUI();
|
||||
}
|
||||
});
|
||||
|
||||
});
|
||||
});
|
||||
+19
@@ -0,0 +1,19 @@
|
||||
var registerBlockType = wp.blocks.registerBlockType;
|
||||
var createElement = wp.element.createElement;
|
||||
var serverSideRender = wp.serverSideRender;
|
||||
|
||||
registerBlockType('twofactor/user-settings', {
|
||||
title: tfa_trans.block_title,
|
||||
icon: 'lock',
|
||||
category: 'widgets',
|
||||
edit: function (props) {
|
||||
return createElement(
|
||||
'div',
|
||||
null,
|
||||
createElement(serverSideRender, {
|
||||
block: 'twofactor/user-settings',
|
||||
attributes: props.attributes,
|
||||
} )
|
||||
);
|
||||
},
|
||||
} );
|
||||
+40
@@ -0,0 +1,40 @@
|
||||
# jQuery.qrcode
|
||||
|
||||
[![license][license-img]][github] [![web][web-img]][web] [![github][github-img]][github] [![bower][bower-img]][github]
|
||||
|
||||
jQuery plugin to dynamically generate QR codes. Uses [QR Code Generator][qrcode] (MIT).
|
||||
|
||||
|
||||
## License
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2016 Lars Jung (https://larsjung.de)
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
|
||||
|
||||
[web]: https://larsjung.de/qrcode/
|
||||
[github]: https://github.com/lrsjng/jquery-qrcode
|
||||
|
||||
[license-img]: https://img.shields.io/badge/license-MIT-a0a060.svg?style=flat-square
|
||||
[web-img]: https://img.shields.io/badge/web-larsjung.de/qrcode-a0a060.svg?style=flat-square
|
||||
[github-img]: https://img.shields.io/badge/github-lrsjng/jquery--qrcode-a0a060.svg?style=flat-square
|
||||
[bower-img]: https://img.shields.io/badge/bower-lrsjng/jquery--qrcode-a0a060.svg?style=flat-square
|
||||
|
||||
[qrcode]: https://github.com/kazuhikoarase/qrcode-generator
|
||||
Vendored
Executable
+2332
File diff suppressed because it is too large
Load Diff
Vendored
Executable
+2
File diff suppressed because one or more lines are too long
wp-content/plugins/all-in-one-wp-security-and-firewall/includes/simba-tfa/includes/jquery.blockUI.js
Executable
+619
@@ -0,0 +1,619 @@
|
||||
/*!
|
||||
* jQuery blockUI plugin
|
||||
* Version 2.70.0-2014.11.23
|
||||
* Requires jQuery v1.7 or later
|
||||
*
|
||||
* Examples at: http://malsup.com/jquery/block/
|
||||
* Copyright (c) 2007-2013 M. Alsup
|
||||
* Dual licensed under the MIT and GPL licenses:
|
||||
* http://www.opensource.org/licenses/mit-license.php
|
||||
* http://www.gnu.org/licenses/gpl.html
|
||||
*
|
||||
* Thanks to Amir-Hossein Sobhi for some excellent contributions!
|
||||
*/
|
||||
;(function() {
|
||||
/*jshint eqeqeq:false curly:false latedef:false */
|
||||
"use strict";
|
||||
|
||||
function setup($) {
|
||||
$.fn._fadeIn = $.fn.fadeIn;
|
||||
|
||||
var noOp = $.noop || function() {};
|
||||
|
||||
// this bit is to ensure we don't call setExpression when we shouldn't (with extra muscle to handle
|
||||
// confusing userAgent strings on Vista)
|
||||
var msie = /MSIE/.test(navigator.userAgent);
|
||||
var ie6 = /MSIE 6.0/.test(navigator.userAgent) && ! /MSIE 8.0/.test(navigator.userAgent);
|
||||
var mode = document.documentMode || 0;
|
||||
var setExpr = $.isFunction( document.createElement('div').style.setExpression );
|
||||
|
||||
// global $ methods for blocking/unblocking the entire page
|
||||
$.blockUI = function(opts) { install(window, opts); };
|
||||
$.unblockUI = function(opts) { remove(window, opts); };
|
||||
|
||||
// convenience method for quick growl-like notifications (http://www.google.com/search?q=growl)
|
||||
$.growlUI = function(title, message, timeout, onClose) {
|
||||
var $m = $('<div class="growlUI"></div>');
|
||||
if (title) $m.append('<h1>'+title+'</h1>');
|
||||
if (message) $m.append('<h2>'+message+'</h2>');
|
||||
if (timeout === undefined) timeout = 3000;
|
||||
|
||||
// Added by konapun: Set timeout to 30 seconds if this growl is moused over, like normal toast notifications
|
||||
var callBlock = function(opts) {
|
||||
opts = opts || {};
|
||||
|
||||
$.blockUI({
|
||||
message: $m,
|
||||
fadeIn : typeof opts.fadeIn !== 'undefined' ? opts.fadeIn : 700,
|
||||
fadeOut: typeof opts.fadeOut !== 'undefined' ? opts.fadeOut : 1000,
|
||||
timeout: typeof opts.timeout !== 'undefined' ? opts.timeout : timeout,
|
||||
centerY: false,
|
||||
showOverlay: false,
|
||||
onUnblock: onClose,
|
||||
css: $.blockUI.defaults.growlCSS
|
||||
});
|
||||
};
|
||||
|
||||
callBlock();
|
||||
var nonmousedOpacity = $m.css('opacity');
|
||||
$m.mouseover(function() {
|
||||
callBlock({
|
||||
fadeIn: 0,
|
||||
timeout: 30000
|
||||
});
|
||||
|
||||
var displayBlock = $('.blockMsg');
|
||||
displayBlock.stop(); // cancel fadeout if it has started
|
||||
displayBlock.fadeTo(300, 1); // make it easier to read the message by removing transparency
|
||||
}).mouseout(function() {
|
||||
$('.blockMsg').fadeOut(1000);
|
||||
});
|
||||
// End konapun additions
|
||||
};
|
||||
|
||||
// plugin method for blocking element content
|
||||
$.fn.block = function(opts) {
|
||||
if ( this[0] === window ) {
|
||||
$.blockUI( opts );
|
||||
return this;
|
||||
}
|
||||
var fullOpts = $.extend({}, $.blockUI.defaults, opts || {});
|
||||
this.each(function() {
|
||||
var $el = $(this);
|
||||
if (fullOpts.ignoreIfBlocked && $el.data('blockUI.isBlocked'))
|
||||
return;
|
||||
$el.unblock({ fadeOut: 0 });
|
||||
});
|
||||
|
||||
return this.each(function() {
|
||||
if ($.css(this,'position') == 'static') {
|
||||
this.style.position = 'relative';
|
||||
$(this).data('blockUI.static', true);
|
||||
}
|
||||
this.style.zoom = 1; // force 'hasLayout' in ie
|
||||
install(this, opts);
|
||||
});
|
||||
};
|
||||
|
||||
// plugin method for unblocking element content
|
||||
$.fn.unblock = function(opts) {
|
||||
if ( this[0] === window ) {
|
||||
$.unblockUI( opts );
|
||||
return this;
|
||||
}
|
||||
return this.each(function() {
|
||||
remove(this, opts);
|
||||
});
|
||||
};
|
||||
|
||||
$.blockUI.version = 2.70; // 2nd generation blocking at no extra cost!
|
||||
|
||||
// override these in your code to change the default behavior and style
|
||||
$.blockUI.defaults = {
|
||||
// message displayed when blocking (use null for no message)
|
||||
message: '<h1>Please wait...</h1>',
|
||||
|
||||
title: null, // title string; only used when theme == true
|
||||
draggable: true, // only used when theme == true (requires jquery-ui.js to be loaded)
|
||||
|
||||
theme: false, // set to true to use with jQuery UI themes
|
||||
|
||||
// styles for the message when blocking; if you wish to disable
|
||||
// these and use an external stylesheet then do this in your code:
|
||||
// $.blockUI.defaults.css = {};
|
||||
css: {
|
||||
padding: 0,
|
||||
margin: 0,
|
||||
width: '30%',
|
||||
top: '40%',
|
||||
left: '35%',
|
||||
textAlign: 'center',
|
||||
color: '#000',
|
||||
border: '3px solid #aaa',
|
||||
backgroundColor:'#fff',
|
||||
cursor: 'wait'
|
||||
},
|
||||
|
||||
// minimal style set used when themes are used
|
||||
themedCSS: {
|
||||
width: '30%',
|
||||
top: '40%',
|
||||
left: '35%'
|
||||
},
|
||||
|
||||
// styles for the overlay
|
||||
overlayCSS: {
|
||||
backgroundColor: '#000',
|
||||
opacity: 0.6,
|
||||
cursor: 'wait'
|
||||
},
|
||||
|
||||
// style to replace wait cursor before unblocking to correct issue
|
||||
// of lingering wait cursor
|
||||
cursorReset: 'default',
|
||||
|
||||
// styles applied when using $.growlUI
|
||||
growlCSS: {
|
||||
width: '350px',
|
||||
top: '10px',
|
||||
left: '',
|
||||
right: '10px',
|
||||
border: 'none',
|
||||
padding: '5px',
|
||||
opacity: 0.6,
|
||||
cursor: 'default',
|
||||
color: '#fff',
|
||||
backgroundColor: '#000',
|
||||
'-webkit-border-radius':'10px',
|
||||
'-moz-border-radius': '10px',
|
||||
'border-radius': '10px'
|
||||
},
|
||||
|
||||
// IE issues: 'about:blank' fails on HTTPS and javascript:false is s-l-o-w
|
||||
// (hat tip to Jorge H. N. de Vasconcelos)
|
||||
/*jshint scripturl:true */
|
||||
iframeSrc: /^https/i.test(window.location.href || '') ? 'javascript:false' : 'about:blank',
|
||||
|
||||
// force usage of iframe in non-IE browsers (handy for blocking applets)
|
||||
forceIframe: false,
|
||||
|
||||
// z-index for the blocking overlay
|
||||
baseZ: 1000,
|
||||
|
||||
// set these to true to have the message automatically centered
|
||||
centerX: true, // <-- only effects element blocking (page block controlled via css above)
|
||||
centerY: true,
|
||||
|
||||
// allow body element to be stetched in ie6; this makes blocking look better
|
||||
// on "short" pages. disable if you wish to prevent changes to the body height
|
||||
allowBodyStretch: true,
|
||||
|
||||
// enable if you want key and mouse events to be disabled for content that is blocked
|
||||
bindEvents: true,
|
||||
|
||||
// be default blockUI will suppress tab navigation from leaving blocking content
|
||||
// (if bindEvents is true)
|
||||
constrainTabKey: true,
|
||||
|
||||
// fadeIn time in millis; set to 0 to disable fadeIn on block
|
||||
fadeIn: 200,
|
||||
|
||||
// fadeOut time in millis; set to 0 to disable fadeOut on unblock
|
||||
fadeOut: 400,
|
||||
|
||||
// time in millis to wait before auto-unblocking; set to 0 to disable auto-unblock
|
||||
timeout: 0,
|
||||
|
||||
// disable if you don't want to show the overlay
|
||||
showOverlay: true,
|
||||
|
||||
// if true, focus will be placed in the first available input field when
|
||||
// page blocking
|
||||
focusInput: true,
|
||||
|
||||
// elements that can receive focus
|
||||
focusableElements: ':input:enabled:visible',
|
||||
|
||||
// suppresses the use of overlay styles on FF/Linux (due to performance issues with opacity)
|
||||
// no longer needed in 2012
|
||||
// applyPlatformOpacityRules: true,
|
||||
|
||||
// callback method invoked when fadeIn has completed and blocking message is visible
|
||||
onBlock: null,
|
||||
|
||||
// callback method invoked when unblocking has completed; the callback is
|
||||
// passed the element that has been unblocked (which is the window object for page
|
||||
// blocks) and the options that were passed to the unblock call:
|
||||
// onUnblock(element, options)
|
||||
onUnblock: null,
|
||||
|
||||
// callback method invoked when the overlay area is clicked.
|
||||
// setting this will turn the cursor to a pointer, otherwise cursor defined in overlayCss will be used.
|
||||
onOverlayClick: null,
|
||||
|
||||
// don't ask; if you really must know: http://groups.google.com/group/jquery-en/browse_thread/thread/36640a8730503595/2f6a79a77a78e493#2f6a79a77a78e493
|
||||
quirksmodeOffsetHack: 4,
|
||||
|
||||
// class name of the message block
|
||||
blockMsgClass: 'blockMsg',
|
||||
|
||||
// if it is already blocked, then ignore it (don't unblock and reblock)
|
||||
ignoreIfBlocked: false
|
||||
};
|
||||
|
||||
// private data and functions follow...
|
||||
|
||||
var pageBlock = null;
|
||||
var pageBlockEls = [];
|
||||
|
||||
function install(el, opts) {
|
||||
var css, themedCSS;
|
||||
var full = (el == window);
|
||||
var msg = (opts && opts.message !== undefined ? opts.message : undefined);
|
||||
opts = $.extend({}, $.blockUI.defaults, opts || {});
|
||||
|
||||
if (opts.ignoreIfBlocked && $(el).data('blockUI.isBlocked'))
|
||||
return;
|
||||
|
||||
opts.overlayCSS = $.extend({}, $.blockUI.defaults.overlayCSS, opts.overlayCSS || {});
|
||||
css = $.extend({}, $.blockUI.defaults.css, opts.css || {});
|
||||
if (opts.onOverlayClick)
|
||||
opts.overlayCSS.cursor = 'pointer';
|
||||
|
||||
themedCSS = $.extend({}, $.blockUI.defaults.themedCSS, opts.themedCSS || {});
|
||||
msg = msg === undefined ? opts.message : msg;
|
||||
|
||||
// remove the current block (if there is one)
|
||||
if (full && pageBlock)
|
||||
remove(window, {fadeOut:0});
|
||||
|
||||
// if an existing element is being used as the blocking content then we capture
|
||||
// its current place in the DOM (and current display style) so we can restore
|
||||
// it when we unblock
|
||||
if (msg && typeof msg != 'string' && (msg.parentNode || msg.jquery)) {
|
||||
var node = msg.jquery ? msg[0] : msg;
|
||||
var data = {};
|
||||
$(el).data('blockUI.history', data);
|
||||
data.el = node;
|
||||
data.parent = node.parentNode;
|
||||
data.display = node.style.display;
|
||||
data.position = node.style.position;
|
||||
if (data.parent)
|
||||
data.parent.removeChild(node);
|
||||
}
|
||||
|
||||
$(el).data('blockUI.onUnblock', opts.onUnblock);
|
||||
var z = opts.baseZ;
|
||||
|
||||
// blockUI uses 3 layers for blocking, for simplicity they are all used on every platform;
|
||||
// layer1 is the iframe layer which is used to suppress bleed through of underlying content
|
||||
// layer2 is the overlay layer which has opacity and a wait cursor (by default)
|
||||
// layer3 is the message content that is displayed while blocking
|
||||
var lyr1, lyr2, lyr3, s;
|
||||
if (msie || opts.forceIframe)
|
||||
lyr1 = $('<iframe class="blockUI" style="z-index:'+ (z++) +';display:none;border:none;margin:0;padding:0;position:absolute;width:100%;height:100%;top:0;left:0" src="'+opts.iframeSrc+'"></iframe>');
|
||||
else
|
||||
lyr1 = $('<div class="blockUI" style="display:none"></div>');
|
||||
|
||||
if (opts.theme)
|
||||
lyr2 = $('<div class="blockUI blockOverlay ui-widget-overlay" style="z-index:'+ (z++) +';display:none"></div>');
|
||||
else
|
||||
lyr2 = $('<div class="blockUI blockOverlay" style="z-index:'+ (z++) +';display:none;border:none;margin:0;padding:0;width:100%;height:100%;top:0;left:0"></div>');
|
||||
|
||||
if (opts.theme && full) {
|
||||
s = '<div class="blockUI ' + opts.blockMsgClass + ' blockPage ui-dialog ui-widget ui-corner-all" style="z-index:'+(z+10)+';display:none;position:fixed">';
|
||||
if ( opts.title ) {
|
||||
s += '<div class="ui-widget-header ui-dialog-titlebar ui-corner-all blockTitle">'+(opts.title || ' ')+'</div>';
|
||||
}
|
||||
s += '<div class="ui-widget-content ui-dialog-content"></div>';
|
||||
s += '</div>';
|
||||
}
|
||||
else if (opts.theme) {
|
||||
s = '<div class="blockUI ' + opts.blockMsgClass + ' blockElement ui-dialog ui-widget ui-corner-all" style="z-index:'+(z+10)+';display:none;position:absolute">';
|
||||
if ( opts.title ) {
|
||||
s += '<div class="ui-widget-header ui-dialog-titlebar ui-corner-all blockTitle">'+(opts.title || ' ')+'</div>';
|
||||
}
|
||||
s += '<div class="ui-widget-content ui-dialog-content"></div>';
|
||||
s += '</div>';
|
||||
}
|
||||
else if (full) {
|
||||
s = '<div class="blockUI ' + opts.blockMsgClass + ' blockPage" style="z-index:'+(z+10)+';display:none;position:fixed"></div>';
|
||||
}
|
||||
else {
|
||||
s = '<div class="blockUI ' + opts.blockMsgClass + ' blockElement" style="z-index:'+(z+10)+';display:none;position:absolute"></div>';
|
||||
}
|
||||
lyr3 = $(s);
|
||||
|
||||
// if we have a message, style it
|
||||
if (msg) {
|
||||
if (opts.theme) {
|
||||
lyr3.css(themedCSS);
|
||||
lyr3.addClass('ui-widget-content');
|
||||
}
|
||||
else
|
||||
lyr3.css(css);
|
||||
}
|
||||
|
||||
// style the overlay
|
||||
if (!opts.theme /*&& (!opts.applyPlatformOpacityRules)*/)
|
||||
lyr2.css(opts.overlayCSS);
|
||||
lyr2.css('position', full ? 'fixed' : 'absolute');
|
||||
|
||||
// make iframe layer transparent in IE
|
||||
if (msie || opts.forceIframe)
|
||||
lyr1.css('opacity',0.0);
|
||||
|
||||
//$([lyr1[0],lyr2[0],lyr3[0]]).appendTo(full ? 'body' : el);
|
||||
var layers = [lyr1,lyr2,lyr3], $par = full ? $('body') : $(el);
|
||||
$.each(layers, function() {
|
||||
this.appendTo($par);
|
||||
});
|
||||
|
||||
if (opts.theme && opts.draggable && $.fn.draggable) {
|
||||
lyr3.draggable({
|
||||
handle: '.ui-dialog-titlebar',
|
||||
cancel: 'li'
|
||||
});
|
||||
}
|
||||
|
||||
// ie7 must use absolute positioning in quirks mode and to account for activex issues (when scrolling)
|
||||
var expr = setExpr && (!$.support.boxModel || $('object,embed', full ? null : el).length > 0);
|
||||
if (ie6 || expr) {
|
||||
// give body 100% height
|
||||
if (full && opts.allowBodyStretch && $.support.boxModel)
|
||||
$('html,body').css('height','100%');
|
||||
|
||||
// fix ie6 issue when blocked element has a border width
|
||||
if ((ie6 || !$.support.boxModel) && !full) {
|
||||
var t = sz(el,'borderTopWidth'), l = sz(el,'borderLeftWidth');
|
||||
var fixT = t ? '(0 - '+t+')' : 0;
|
||||
var fixL = l ? '(0 - '+l+')' : 0;
|
||||
}
|
||||
|
||||
// simulate fixed position
|
||||
$.each(layers, function(i,o) {
|
||||
var s = o[0].style;
|
||||
s.position = 'absolute';
|
||||
if (i < 2) {
|
||||
if (full)
|
||||
s.setExpression('height','Math.max(document.body.scrollHeight, document.body.offsetHeight) - (jQuery.support.boxModel?0:'+opts.quirksmodeOffsetHack+') + "px"');
|
||||
else
|
||||
s.setExpression('height','this.parentNode.offsetHeight + "px"');
|
||||
if (full)
|
||||
s.setExpression('width','jQuery.support.boxModel && document.documentElement.clientWidth || document.body.clientWidth + "px"');
|
||||
else
|
||||
s.setExpression('width','this.parentNode.offsetWidth + "px"');
|
||||
if (fixL) s.setExpression('left', fixL);
|
||||
if (fixT) s.setExpression('top', fixT);
|
||||
}
|
||||
else if (opts.centerY) {
|
||||
if (full) s.setExpression('top','(document.documentElement.clientHeight || document.body.clientHeight) / 2 - (this.offsetHeight / 2) + (blah = document.documentElement.scrollTop ? document.documentElement.scrollTop : document.body.scrollTop) + "px"');
|
||||
s.marginTop = 0;
|
||||
}
|
||||
else if (!opts.centerY && full) {
|
||||
var top = (opts.css && opts.css.top) ? parseInt(opts.css.top, 10) : 0;
|
||||
var expression = '((document.documentElement.scrollTop ? document.documentElement.scrollTop : document.body.scrollTop) + '+top+') + "px"';
|
||||
s.setExpression('top',expression);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// show the message
|
||||
if (msg) {
|
||||
if (opts.theme)
|
||||
lyr3.find('.ui-widget-content').append(msg);
|
||||
else
|
||||
lyr3.append(msg);
|
||||
if (msg.jquery || msg.nodeType)
|
||||
$(msg).show();
|
||||
}
|
||||
|
||||
if ((msie || opts.forceIframe) && opts.showOverlay)
|
||||
lyr1.show(); // opacity is zero
|
||||
if (opts.fadeIn) {
|
||||
var cb = opts.onBlock ? opts.onBlock : noOp;
|
||||
var cb1 = (opts.showOverlay && !msg) ? cb : noOp;
|
||||
var cb2 = msg ? cb : noOp;
|
||||
if (opts.showOverlay)
|
||||
lyr2._fadeIn(opts.fadeIn, cb1);
|
||||
if (msg)
|
||||
lyr3._fadeIn(opts.fadeIn, cb2);
|
||||
}
|
||||
else {
|
||||
if (opts.showOverlay)
|
||||
lyr2.show();
|
||||
if (msg)
|
||||
lyr3.show();
|
||||
if (opts.onBlock)
|
||||
opts.onBlock.bind(lyr3)();
|
||||
}
|
||||
|
||||
// bind key and mouse events
|
||||
bind(1, el, opts);
|
||||
|
||||
if (full) {
|
||||
pageBlock = lyr3[0];
|
||||
pageBlockEls = $(opts.focusableElements,pageBlock);
|
||||
if (opts.focusInput)
|
||||
setTimeout(focus, 20);
|
||||
}
|
||||
else
|
||||
center(lyr3[0], opts.centerX, opts.centerY);
|
||||
|
||||
if (opts.timeout) {
|
||||
// auto-unblock
|
||||
var to = setTimeout(function() {
|
||||
if (full)
|
||||
$.unblockUI(opts);
|
||||
else
|
||||
$(el).unblock(opts);
|
||||
}, opts.timeout);
|
||||
$(el).data('blockUI.timeout', to);
|
||||
}
|
||||
}
|
||||
|
||||
// remove the block
|
||||
function remove(el, opts) {
|
||||
var count;
|
||||
var full = (el == window);
|
||||
var $el = $(el);
|
||||
var data = $el.data('blockUI.history');
|
||||
var to = $el.data('blockUI.timeout');
|
||||
if (to) {
|
||||
clearTimeout(to);
|
||||
$el.removeData('blockUI.timeout');
|
||||
}
|
||||
opts = $.extend({}, $.blockUI.defaults, opts || {});
|
||||
bind(0, el, opts); // unbind events
|
||||
|
||||
if (opts.onUnblock === null) {
|
||||
opts.onUnblock = $el.data('blockUI.onUnblock');
|
||||
$el.removeData('blockUI.onUnblock');
|
||||
}
|
||||
|
||||
var els;
|
||||
if (full) // crazy selector to handle odd field errors in ie6/7
|
||||
els = $('body').children().filter('.blockUI').add('body > .blockUI');
|
||||
else
|
||||
els = $el.find('>.blockUI');
|
||||
|
||||
// fix cursor issue
|
||||
if ( opts.cursorReset ) {
|
||||
if ( els.length > 1 )
|
||||
els[1].style.cursor = opts.cursorReset;
|
||||
if ( els.length > 2 )
|
||||
els[2].style.cursor = opts.cursorReset;
|
||||
}
|
||||
|
||||
if (full)
|
||||
pageBlock = pageBlockEls = null;
|
||||
|
||||
if (opts.fadeOut) {
|
||||
count = els.length;
|
||||
els.stop().fadeOut(opts.fadeOut, function() {
|
||||
if ( --count === 0)
|
||||
reset(els,data,opts,el);
|
||||
});
|
||||
}
|
||||
else
|
||||
reset(els, data, opts, el);
|
||||
}
|
||||
|
||||
// move blocking element back into the DOM where it started
|
||||
function reset(els,data,opts,el) {
|
||||
var $el = $(el);
|
||||
if ( $el.data('blockUI.isBlocked') )
|
||||
return;
|
||||
|
||||
els.each(function(i,o) {
|
||||
// remove via DOM calls so we don't lose event handlers
|
||||
if (this.parentNode)
|
||||
this.parentNode.removeChild(this);
|
||||
});
|
||||
|
||||
if (data && data.el) {
|
||||
data.el.style.display = data.display;
|
||||
data.el.style.position = data.position;
|
||||
data.el.style.cursor = 'default'; // #59
|
||||
if (data.parent)
|
||||
data.parent.appendChild(data.el);
|
||||
$el.removeData('blockUI.history');
|
||||
}
|
||||
|
||||
if ($el.data('blockUI.static')) {
|
||||
$el.css('position', 'static'); // #22
|
||||
}
|
||||
|
||||
if (typeof opts.onUnblock == 'function')
|
||||
opts.onUnblock(el,opts);
|
||||
|
||||
// fix issue in Safari 6 where block artifacts remain until reflow
|
||||
var body = $(document.body), w = body.width(), cssW = body[0].style.width;
|
||||
body.width(w-1).width(w);
|
||||
body[0].style.width = cssW;
|
||||
}
|
||||
|
||||
// bind/unbind the handler
|
||||
function bind(b, el, opts) {
|
||||
var full = el == window, $el = $(el);
|
||||
|
||||
// don't bother unbinding if there is nothing to unbind
|
||||
if (!b && (full && !pageBlock || !full && !$el.data('blockUI.isBlocked')))
|
||||
return;
|
||||
|
||||
$el.data('blockUI.isBlocked', b);
|
||||
|
||||
// don't bind events when overlay is not in use or if bindEvents is false
|
||||
if (!full || !opts.bindEvents || (b && !opts.showOverlay))
|
||||
return;
|
||||
|
||||
// bind anchors and inputs for mouse and key events
|
||||
var events = 'mousedown mouseup keydown keypress keyup touchstart touchend touchmove';
|
||||
if (b)
|
||||
$(document).bind(events, opts, handler);
|
||||
else
|
||||
$(document).unbind(events, handler);
|
||||
|
||||
// former impl...
|
||||
// var $e = $('a,:input');
|
||||
// b ? $e.bind(events, opts, handler) : $e.unbind(events, handler);
|
||||
}
|
||||
|
||||
// event handler to suppress keyboard/mouse events when blocking
|
||||
function handler(e) {
|
||||
// allow tab navigation (conditionally)
|
||||
if (e.type === 'keydown' && e.keyCode && e.keyCode == 9) {
|
||||
if (pageBlock && e.data.constrainTabKey) {
|
||||
var els = pageBlockEls;
|
||||
var fwd = !e.shiftKey && e.target === els[els.length-1];
|
||||
var back = e.shiftKey && e.target === els[0];
|
||||
if (fwd || back) {
|
||||
setTimeout(function(){focus(back);},10);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
var opts = e.data;
|
||||
var target = $(e.target);
|
||||
if (target.hasClass('blockOverlay') && opts.onOverlayClick)
|
||||
opts.onOverlayClick(e);
|
||||
|
||||
// allow events within the message content
|
||||
if (target.parents('div.' + opts.blockMsgClass).length > 0)
|
||||
return true;
|
||||
|
||||
// allow events for content that is not being blocked
|
||||
return target.parents().children().filter('div.blockUI').length === 0;
|
||||
}
|
||||
|
||||
function focus(back) {
|
||||
if (!pageBlockEls)
|
||||
return;
|
||||
var e = pageBlockEls[back===true ? pageBlockEls.length-1 : 0];
|
||||
if (e)
|
||||
e.focus();
|
||||
}
|
||||
|
||||
function center(el, x, y) {
|
||||
var p = el.parentNode, s = el.style;
|
||||
var l = ((p.offsetWidth - el.offsetWidth)/2) - sz(p,'borderLeftWidth');
|
||||
var t = ((p.offsetHeight - el.offsetHeight)/2) - sz(p,'borderTopWidth');
|
||||
if (x) s.left = l > 0 ? (l+'px') : '0';
|
||||
if (y) s.top = t > 0 ? (t+'px') : '0';
|
||||
}
|
||||
|
||||
function sz(el, p) {
|
||||
return parseInt($.css(el,p),10)||0;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
/*global define:true */
|
||||
if (typeof define === 'function' && define.amd && define.amd.jQuery) {
|
||||
define(['jquery'], setup);
|
||||
} else {
|
||||
setup(jQuery);
|
||||
}
|
||||
|
||||
})();
|
||||
Vendored
Executable
+14
File diff suppressed because one or more lines are too long
+146
@@ -0,0 +1,146 @@
|
||||
<?php
|
||||
|
||||
if (!defined('ABSPATH')) die('No direct access.');
|
||||
|
||||
/**
|
||||
* Purpose of this class: abstract out code handling integrations with login forms
|
||||
*/
|
||||
|
||||
class Simba_TFA_Login_Form_Integrations {
|
||||
|
||||
// Main class
|
||||
private $tfa;
|
||||
|
||||
/**
|
||||
* Plugin constructor
|
||||
*
|
||||
* @param Object $tfa
|
||||
*/
|
||||
public function __construct($tfa) {
|
||||
|
||||
$this->tfa = $tfa;
|
||||
|
||||
$enqueue_upon_actions = array(
|
||||
// This is needed for the login form on the dedicated payment page (e.g. /checkout/order-pay/123456/?pay_for_order=true&key=wc_order_blahblahblah)
|
||||
'woocommerce_login_form_start',
|
||||
'woocommerce_before_customer_login_form',
|
||||
// The login form on the checkout doesn't call the woocommerce_before_customer_login_form action
|
||||
'woocommerce_before_checkout_form',
|
||||
'affwp_login_fields_before',
|
||||
);
|
||||
|
||||
foreach ($enqueue_upon_actions as $action) {
|
||||
add_action($action, array($this->tfa, 'login_enqueue_scripts'));
|
||||
}
|
||||
|
||||
if (!defined('TWO_FACTOR_DISABLE') || !TWO_FACTOR_DISABLE) {
|
||||
add_action('affwp_process_login_form', array($this, 'affwp_process_login_form'));
|
||||
}
|
||||
|
||||
add_filter('tml_display', array($this, 'tml_display'));
|
||||
add_filter('wppb_login_form_bottom', array($this, 'pb_login_form'));
|
||||
|
||||
// We want to run first if possible, so that we're not aborted by JavaScript exceptions in other components (our code is critical to the login process for TFA users)
|
||||
// Unfortunately, though, people start enqueuing from init onwards (before that is buggy - https://core.trac.wordpress.org/ticket/11526), so, we try to detect the login page and go earlier there.
|
||||
if (isset($GLOBALS['pagenow']) && 'wp-login.php' === $GLOBALS['pagenow']) {
|
||||
add_action('init', array($this->tfa, 'login_enqueue_scripts'), -99999999999);
|
||||
} else {
|
||||
add_action('login_enqueue_scripts', array($this->tfa, 'login_enqueue_scripts'), -99999999999);
|
||||
}
|
||||
|
||||
add_filter('do_shortcode_tag', array($this, 'do_shortcode_tag'), 10, 2);
|
||||
|
||||
add_filter('simba_tfa_login_enqueue_localize', array($this, 'simba_tfa_login_enqueue_localize'), 9);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Catch TML login widgets (other TML login forms already trigger)
|
||||
*
|
||||
* @param Mixed $whatever
|
||||
*
|
||||
* @return Mixed
|
||||
*/
|
||||
public function tml_display($whatever) {
|
||||
$this->tfa->login_enqueue_scripts();
|
||||
return $whatever;
|
||||
}
|
||||
|
||||
/**
|
||||
* Catch Profile Builder login form
|
||||
*
|
||||
* @param Mixed $whatever
|
||||
*
|
||||
* @return Mixed
|
||||
*/
|
||||
public function pb_login_form($whatever) {
|
||||
$this->tfa->login_enqueue_scripts();
|
||||
return $whatever;
|
||||
}
|
||||
|
||||
/**
|
||||
* Runs upon the WP filter simba_tfa_login_enqueue_localize.
|
||||
*
|
||||
* @param Array $localize
|
||||
*
|
||||
* @return Array
|
||||
*/
|
||||
public function simba_tfa_login_enqueue_localize($localize) {
|
||||
// WP login form is #loginform
|
||||
// Ultimate Membership Pro - April 2018
|
||||
// Theme My Login 6.x - .tml-login form[name="loginform"]
|
||||
// Theme My Login 7.x - .tml-login form[name="login"] (July 2018)
|
||||
// WP Members - March 2018
|
||||
// bbPress - June 2021
|
||||
// WooCommerce - ported over from the separate wooextend.js code, June 2021
|
||||
// Affiliates WP - ported over from the separate wooextend.js code, June 2021
|
||||
$localize['login_form_selectors'] .= '.tml-login form[name="loginform"], .tml-login form[name="login"], #loginform, #wpmem_login form, form#ihc_login_form, .bbp-login-form, .woocommerce form.login, #affwp-login-form, #wppb-loginform';
|
||||
$localize['login_form_off_selectors'] .= '#ihc_login_form';
|
||||
return $localize;
|
||||
}
|
||||
|
||||
/**
|
||||
* Runs upon the WP action affwp_process_login_form
|
||||
*/
|
||||
public function affwp_process_login_form() {
|
||||
|
||||
if (!function_exists('affiliate_wp')) return;
|
||||
|
||||
$affiliate_wp = affiliate_wp();
|
||||
$login = $affiliate_wp->login;
|
||||
|
||||
$params = array(
|
||||
// phpcs:ignore WordPress.Security.NonceVerification -- No nonce.
|
||||
'log' => isset($_POST['affwp_user_login']) ? sanitize_user(wp_unslash($_POST['affwp_user_login'])): '',
|
||||
|
||||
$request_uri = isset($_SERVER['REQUEST_URI']) ? sanitize_text_field(wp_unslash($_SERVER['REQUEST_URI'])) : '',
|
||||
'caller'=> isset($_SERVER['PHP_SELF']) ? sanitize_text_field(wp_unslash($_SERVER['PHP_SELF'])) : $request_uri,
|
||||
// phpcs:ignore WordPress.Security.NonceVerification -- No nonce.
|
||||
'two_factor_code' => isset($_POST['two_factor_code']) ? sanitize_text_field(wp_unslash((string) $_POST['two_factor_code'])) : '',
|
||||
);
|
||||
$code_ok = $this->tfa->authorise_user_from_login($params, true);
|
||||
|
||||
$code_ok = apply_filters('simbatfa_affwp_process_login_form_auth_result', $code_ok, $params);
|
||||
|
||||
if (is_wp_error($code_ok)) {
|
||||
$login->add_error($code_ok->get_error_code(), $code_ok->get_error_message());
|
||||
} elseif (!$code_ok) {
|
||||
$login->add_error('authentication_failed', __('Error:', 'all-in-one-wp-security-and-firewall').' '.apply_filters('simba_tfa_message_code_incorrect', __('The one-time password (TFA code) you entered was incorrect.', 'all-in-one-wp-security-and-firewall')));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Ultimate Membership Pro support
|
||||
*
|
||||
* @param String $output
|
||||
* @param String $tag
|
||||
*
|
||||
* @return String
|
||||
*/
|
||||
public function do_shortcode_tag($output, $tag) {
|
||||
if ('ihc-login-form' == $tag) $this->tfa->login_enqueue_scripts();
|
||||
return $output;
|
||||
}
|
||||
|
||||
}
|
||||
Executable
+481
@@ -0,0 +1,481 @@
|
||||
.select2-container {
|
||||
box-sizing: border-box;
|
||||
display: inline-block;
|
||||
margin: 0;
|
||||
position: relative;
|
||||
vertical-align: middle; }
|
||||
.select2-container .select2-selection--single {
|
||||
box-sizing: border-box;
|
||||
cursor: pointer;
|
||||
display: block;
|
||||
height: 28px;
|
||||
user-select: none;
|
||||
-webkit-user-select: none; }
|
||||
.select2-container .select2-selection--single .select2-selection__rendered {
|
||||
display: block;
|
||||
padding-left: 8px;
|
||||
padding-right: 20px;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap; }
|
||||
.select2-container .select2-selection--single .select2-selection__clear {
|
||||
position: relative; }
|
||||
.select2-container[dir="rtl"] .select2-selection--single .select2-selection__rendered {
|
||||
padding-right: 8px;
|
||||
padding-left: 20px; }
|
||||
.select2-container .select2-selection--multiple {
|
||||
box-sizing: border-box;
|
||||
cursor: pointer;
|
||||
display: block;
|
||||
min-height: 32px;
|
||||
user-select: none;
|
||||
-webkit-user-select: none; }
|
||||
.select2-container .select2-selection--multiple .select2-selection__rendered {
|
||||
display: inline-block;
|
||||
overflow: hidden;
|
||||
padding-left: 8px;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap; }
|
||||
.select2-container .select2-search--inline {
|
||||
float: left; }
|
||||
.select2-container .select2-search--inline .select2-search__field {
|
||||
box-sizing: border-box;
|
||||
border: none;
|
||||
font-size: 100%;
|
||||
margin-top: 5px;
|
||||
padding: 0; }
|
||||
.select2-container .select2-search--inline .select2-search__field::-webkit-search-cancel-button {
|
||||
-webkit-appearance: none; }
|
||||
|
||||
.select2-dropdown {
|
||||
background-color: white;
|
||||
border: 1px solid #aaa;
|
||||
border-radius: 4px;
|
||||
box-sizing: border-box;
|
||||
display: block;
|
||||
position: absolute;
|
||||
left: -100000px;
|
||||
width: 100%;
|
||||
z-index: 1051; }
|
||||
|
||||
.select2-results {
|
||||
display: block; }
|
||||
|
||||
.select2-results__options {
|
||||
list-style: none;
|
||||
margin: 0;
|
||||
padding: 0; }
|
||||
|
||||
.select2-results__option {
|
||||
padding: 6px;
|
||||
user-select: none;
|
||||
-webkit-user-select: none; }
|
||||
.select2-results__option[aria-selected] {
|
||||
cursor: pointer; }
|
||||
|
||||
.select2-container--open .select2-dropdown {
|
||||
left: 0; }
|
||||
|
||||
.select2-container--open .select2-dropdown--above {
|
||||
border-bottom: none;
|
||||
border-bottom-left-radius: 0;
|
||||
border-bottom-right-radius: 0; }
|
||||
|
||||
.select2-container--open .select2-dropdown--below {
|
||||
border-top: none;
|
||||
border-top-left-radius: 0;
|
||||
border-top-right-radius: 0; }
|
||||
|
||||
.select2-search--dropdown {
|
||||
display: block;
|
||||
padding: 4px; }
|
||||
.select2-search--dropdown .select2-search__field {
|
||||
padding: 4px;
|
||||
width: 100%;
|
||||
box-sizing: border-box; }
|
||||
.select2-search--dropdown .select2-search__field::-webkit-search-cancel-button {
|
||||
-webkit-appearance: none; }
|
||||
.select2-search--dropdown.select2-search--hide {
|
||||
display: none; }
|
||||
|
||||
.select2-close-mask {
|
||||
border: 0;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
display: block;
|
||||
position: fixed;
|
||||
left: 0;
|
||||
top: 0;
|
||||
min-height: 100%;
|
||||
min-width: 100%;
|
||||
height: auto;
|
||||
width: auto;
|
||||
opacity: 0;
|
||||
z-index: 99;
|
||||
background-color: #fff;
|
||||
filter: alpha(opacity=0); }
|
||||
|
||||
.select2-hidden-accessible {
|
||||
border: 0 !important;
|
||||
clip: rect(0 0 0 0) !important;
|
||||
-webkit-clip-path: inset(50%) !important;
|
||||
clip-path: inset(50%) !important;
|
||||
height: 1px !important;
|
||||
overflow: hidden !important;
|
||||
padding: 0 !important;
|
||||
position: absolute !important;
|
||||
width: 1px !important;
|
||||
white-space: nowrap !important; }
|
||||
|
||||
.select2-container--default .select2-selection--single {
|
||||
background-color: #fff;
|
||||
border: 1px solid #aaa;
|
||||
border-radius: 4px; }
|
||||
.select2-container--default .select2-selection--single .select2-selection__rendered {
|
||||
color: #444;
|
||||
line-height: 28px; }
|
||||
.select2-container--default .select2-selection--single .select2-selection__clear {
|
||||
cursor: pointer;
|
||||
float: right;
|
||||
font-weight: bold; }
|
||||
.select2-container--default .select2-selection--single .select2-selection__placeholder {
|
||||
color: #999; }
|
||||
.select2-container--default .select2-selection--single .select2-selection__arrow {
|
||||
height: 26px;
|
||||
position: absolute;
|
||||
top: 1px;
|
||||
right: 1px;
|
||||
width: 20px; }
|
||||
.select2-container--default .select2-selection--single .select2-selection__arrow b {
|
||||
border-color: #888 transparent transparent transparent;
|
||||
border-style: solid;
|
||||
border-width: 5px 4px 0 4px;
|
||||
height: 0;
|
||||
left: 50%;
|
||||
margin-left: -4px;
|
||||
margin-top: -2px;
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
width: 0; }
|
||||
|
||||
.select2-container--default[dir="rtl"] .select2-selection--single .select2-selection__clear {
|
||||
float: left; }
|
||||
|
||||
.select2-container--default[dir="rtl"] .select2-selection--single .select2-selection__arrow {
|
||||
left: 1px;
|
||||
right: auto; }
|
||||
|
||||
.select2-container--default.select2-container--disabled .select2-selection--single {
|
||||
background-color: #eee;
|
||||
cursor: default; }
|
||||
.select2-container--default.select2-container--disabled .select2-selection--single .select2-selection__clear {
|
||||
display: none; }
|
||||
|
||||
.select2-container--default.select2-container--open .select2-selection--single .select2-selection__arrow b {
|
||||
border-color: transparent transparent #888 transparent;
|
||||
border-width: 0 4px 5px 4px; }
|
||||
|
||||
.select2-container--default .select2-selection--multiple {
|
||||
background-color: white;
|
||||
border: 1px solid #aaa;
|
||||
border-radius: 4px;
|
||||
cursor: text; }
|
||||
.select2-container--default .select2-selection--multiple .select2-selection__rendered {
|
||||
box-sizing: border-box;
|
||||
list-style: none;
|
||||
margin: 0;
|
||||
padding: 0 5px;
|
||||
width: 100%; }
|
||||
.select2-container--default .select2-selection--multiple .select2-selection__rendered li {
|
||||
list-style: none; }
|
||||
.select2-container--default .select2-selection--multiple .select2-selection__clear {
|
||||
cursor: pointer;
|
||||
float: right;
|
||||
font-weight: bold;
|
||||
margin-top: 5px;
|
||||
margin-right: 10px;
|
||||
padding: 1px; }
|
||||
.select2-container--default .select2-selection--multiple .select2-selection__choice {
|
||||
background-color: #e4e4e4;
|
||||
border: 1px solid #aaa;
|
||||
border-radius: 4px;
|
||||
cursor: default;
|
||||
float: left;
|
||||
margin-right: 5px;
|
||||
margin-top: 5px;
|
||||
padding: 0 5px; }
|
||||
.select2-container--default .select2-selection--multiple .select2-selection__choice__remove {
|
||||
color: #999;
|
||||
cursor: pointer;
|
||||
display: inline-block;
|
||||
font-weight: bold;
|
||||
margin-right: 2px; }
|
||||
.select2-container--default .select2-selection--multiple .select2-selection__choice__remove:hover {
|
||||
color: #333; }
|
||||
|
||||
.select2-container--default[dir="rtl"] .select2-selection--multiple .select2-selection__choice, .select2-container--default[dir="rtl"] .select2-selection--multiple .select2-search--inline {
|
||||
float: right; }
|
||||
|
||||
.select2-container--default[dir="rtl"] .select2-selection--multiple .select2-selection__choice {
|
||||
margin-left: 5px;
|
||||
margin-right: auto; }
|
||||
|
||||
.select2-container--default[dir="rtl"] .select2-selection--multiple .select2-selection__choice__remove {
|
||||
margin-left: 2px;
|
||||
margin-right: auto; }
|
||||
|
||||
.select2-container--default.select2-container--focus .select2-selection--multiple {
|
||||
border: solid black 1px;
|
||||
outline: 0; }
|
||||
|
||||
.select2-container--default.select2-container--disabled .select2-selection--multiple {
|
||||
background-color: #eee;
|
||||
cursor: default; }
|
||||
|
||||
.select2-container--default.select2-container--disabled .select2-selection__choice__remove {
|
||||
display: none; }
|
||||
|
||||
.select2-container--default.select2-container--open.select2-container--above .select2-selection--single, .select2-container--default.select2-container--open.select2-container--above .select2-selection--multiple {
|
||||
border-top-left-radius: 0;
|
||||
border-top-right-radius: 0; }
|
||||
|
||||
.select2-container--default.select2-container--open.select2-container--below .select2-selection--single, .select2-container--default.select2-container--open.select2-container--below .select2-selection--multiple {
|
||||
border-bottom-left-radius: 0;
|
||||
border-bottom-right-radius: 0; }
|
||||
|
||||
.select2-container--default .select2-search--dropdown .select2-search__field {
|
||||
border: 1px solid #aaa; }
|
||||
|
||||
.select2-container--default .select2-search--inline .select2-search__field {
|
||||
background: transparent;
|
||||
border: none;
|
||||
outline: 0;
|
||||
box-shadow: none;
|
||||
-webkit-appearance: textfield; }
|
||||
|
||||
.select2-container--default .select2-results > .select2-results__options {
|
||||
max-height: 200px;
|
||||
overflow-y: auto; }
|
||||
|
||||
.select2-container--default .select2-results__option[role=group] {
|
||||
padding: 0; }
|
||||
|
||||
.select2-container--default .select2-results__option[aria-disabled=true] {
|
||||
color: #999; }
|
||||
|
||||
.select2-container--default .select2-results__option[aria-selected=true] {
|
||||
background-color: #ddd; }
|
||||
|
||||
.select2-container--default .select2-results__option .select2-results__option {
|
||||
padding-left: 1em; }
|
||||
.select2-container--default .select2-results__option .select2-results__option .select2-results__group {
|
||||
padding-left: 0; }
|
||||
.select2-container--default .select2-results__option .select2-results__option .select2-results__option {
|
||||
margin-left: -1em;
|
||||
padding-left: 2em; }
|
||||
.select2-container--default .select2-results__option .select2-results__option .select2-results__option .select2-results__option {
|
||||
margin-left: -2em;
|
||||
padding-left: 3em; }
|
||||
.select2-container--default .select2-results__option .select2-results__option .select2-results__option .select2-results__option .select2-results__option {
|
||||
margin-left: -3em;
|
||||
padding-left: 4em; }
|
||||
.select2-container--default .select2-results__option .select2-results__option .select2-results__option .select2-results__option .select2-results__option .select2-results__option {
|
||||
margin-left: -4em;
|
||||
padding-left: 5em; }
|
||||
.select2-container--default .select2-results__option .select2-results__option .select2-results__option .select2-results__option .select2-results__option .select2-results__option .select2-results__option {
|
||||
margin-left: -5em;
|
||||
padding-left: 6em; }
|
||||
|
||||
.select2-container--default .select2-results__option--highlighted[aria-selected] {
|
||||
background-color: #5897fb;
|
||||
color: white; }
|
||||
|
||||
.select2-container--default .select2-results__group {
|
||||
cursor: default;
|
||||
display: block;
|
||||
padding: 6px; }
|
||||
|
||||
.select2-container--classic .select2-selection--single {
|
||||
background-color: #f7f7f7;
|
||||
border: 1px solid #aaa;
|
||||
border-radius: 4px;
|
||||
outline: 0;
|
||||
background-image: -webkit-linear-gradient(top, white 50%, #eeeeee 100%);
|
||||
background-image: -o-linear-gradient(top, white 50%, #eeeeee 100%);
|
||||
background-image: linear-gradient(to bottom, white 50%, #eeeeee 100%);
|
||||
background-repeat: repeat-x;
|
||||
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#FFFFFFFF', endColorstr='#FFEEEEEE', GradientType=0); }
|
||||
.select2-container--classic .select2-selection--single:focus {
|
||||
border: 1px solid #5897fb; }
|
||||
.select2-container--classic .select2-selection--single .select2-selection__rendered {
|
||||
color: #444;
|
||||
line-height: 28px; }
|
||||
.select2-container--classic .select2-selection--single .select2-selection__clear {
|
||||
cursor: pointer;
|
||||
float: right;
|
||||
font-weight: bold;
|
||||
margin-right: 10px; }
|
||||
.select2-container--classic .select2-selection--single .select2-selection__placeholder {
|
||||
color: #999; }
|
||||
.select2-container--classic .select2-selection--single .select2-selection__arrow {
|
||||
background-color: #ddd;
|
||||
border: none;
|
||||
border-left: 1px solid #aaa;
|
||||
border-top-right-radius: 4px;
|
||||
border-bottom-right-radius: 4px;
|
||||
height: 26px;
|
||||
position: absolute;
|
||||
top: 1px;
|
||||
right: 1px;
|
||||
width: 20px;
|
||||
background-image: -webkit-linear-gradient(top, #eeeeee 50%, #cccccc 100%);
|
||||
background-image: -o-linear-gradient(top, #eeeeee 50%, #cccccc 100%);
|
||||
background-image: linear-gradient(to bottom, #eeeeee 50%, #cccccc 100%);
|
||||
background-repeat: repeat-x;
|
||||
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#FFEEEEEE', endColorstr='#FFCCCCCC', GradientType=0); }
|
||||
.select2-container--classic .select2-selection--single .select2-selection__arrow b {
|
||||
border-color: #888 transparent transparent transparent;
|
||||
border-style: solid;
|
||||
border-width: 5px 4px 0 4px;
|
||||
height: 0;
|
||||
left: 50%;
|
||||
margin-left: -4px;
|
||||
margin-top: -2px;
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
width: 0; }
|
||||
|
||||
.select2-container--classic[dir="rtl"] .select2-selection--single .select2-selection__clear {
|
||||
float: left; }
|
||||
|
||||
.select2-container--classic[dir="rtl"] .select2-selection--single .select2-selection__arrow {
|
||||
border: none;
|
||||
border-right: 1px solid #aaa;
|
||||
border-radius: 0;
|
||||
border-top-left-radius: 4px;
|
||||
border-bottom-left-radius: 4px;
|
||||
left: 1px;
|
||||
right: auto; }
|
||||
|
||||
.select2-container--classic.select2-container--open .select2-selection--single {
|
||||
border: 1px solid #5897fb; }
|
||||
.select2-container--classic.select2-container--open .select2-selection--single .select2-selection__arrow {
|
||||
background: transparent;
|
||||
border: none; }
|
||||
.select2-container--classic.select2-container--open .select2-selection--single .select2-selection__arrow b {
|
||||
border-color: transparent transparent #888 transparent;
|
||||
border-width: 0 4px 5px 4px; }
|
||||
|
||||
.select2-container--classic.select2-container--open.select2-container--above .select2-selection--single {
|
||||
border-top: none;
|
||||
border-top-left-radius: 0;
|
||||
border-top-right-radius: 0;
|
||||
background-image: -webkit-linear-gradient(top, white 0%, #eeeeee 50%);
|
||||
background-image: -o-linear-gradient(top, white 0%, #eeeeee 50%);
|
||||
background-image: linear-gradient(to bottom, white 0%, #eeeeee 50%);
|
||||
background-repeat: repeat-x;
|
||||
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#FFFFFFFF', endColorstr='#FFEEEEEE', GradientType=0); }
|
||||
|
||||
.select2-container--classic.select2-container--open.select2-container--below .select2-selection--single {
|
||||
border-bottom: none;
|
||||
border-bottom-left-radius: 0;
|
||||
border-bottom-right-radius: 0;
|
||||
background-image: -webkit-linear-gradient(top, #eeeeee 50%, white 100%);
|
||||
background-image: -o-linear-gradient(top, #eeeeee 50%, white 100%);
|
||||
background-image: linear-gradient(to bottom, #eeeeee 50%, white 100%);
|
||||
background-repeat: repeat-x;
|
||||
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#FFEEEEEE', endColorstr='#FFFFFFFF', GradientType=0); }
|
||||
|
||||
.select2-container--classic .select2-selection--multiple {
|
||||
background-color: white;
|
||||
border: 1px solid #aaa;
|
||||
border-radius: 4px;
|
||||
cursor: text;
|
||||
outline: 0; }
|
||||
.select2-container--classic .select2-selection--multiple:focus {
|
||||
border: 1px solid #5897fb; }
|
||||
.select2-container--classic .select2-selection--multiple .select2-selection__rendered {
|
||||
list-style: none;
|
||||
margin: 0;
|
||||
padding: 0 5px; }
|
||||
.select2-container--classic .select2-selection--multiple .select2-selection__clear {
|
||||
display: none; }
|
||||
.select2-container--classic .select2-selection--multiple .select2-selection__choice {
|
||||
background-color: #e4e4e4;
|
||||
border: 1px solid #aaa;
|
||||
border-radius: 4px;
|
||||
cursor: default;
|
||||
float: left;
|
||||
margin-right: 5px;
|
||||
margin-top: 5px;
|
||||
padding: 0 5px; }
|
||||
.select2-container--classic .select2-selection--multiple .select2-selection__choice__remove {
|
||||
color: #888;
|
||||
cursor: pointer;
|
||||
display: inline-block;
|
||||
font-weight: bold;
|
||||
margin-right: 2px; }
|
||||
.select2-container--classic .select2-selection--multiple .select2-selection__choice__remove:hover {
|
||||
color: #555; }
|
||||
|
||||
.select2-container--classic[dir="rtl"] .select2-selection--multiple .select2-selection__choice {
|
||||
float: right;
|
||||
margin-left: 5px;
|
||||
margin-right: auto; }
|
||||
|
||||
.select2-container--classic[dir="rtl"] .select2-selection--multiple .select2-selection__choice__remove {
|
||||
margin-left: 2px;
|
||||
margin-right: auto; }
|
||||
|
||||
.select2-container--classic.select2-container--open .select2-selection--multiple {
|
||||
border: 1px solid #5897fb; }
|
||||
|
||||
.select2-container--classic.select2-container--open.select2-container--above .select2-selection--multiple {
|
||||
border-top: none;
|
||||
border-top-left-radius: 0;
|
||||
border-top-right-radius: 0; }
|
||||
|
||||
.select2-container--classic.select2-container--open.select2-container--below .select2-selection--multiple {
|
||||
border-bottom: none;
|
||||
border-bottom-left-radius: 0;
|
||||
border-bottom-right-radius: 0; }
|
||||
|
||||
.select2-container--classic .select2-search--dropdown .select2-search__field {
|
||||
border: 1px solid #aaa;
|
||||
outline: 0; }
|
||||
|
||||
.select2-container--classic .select2-search--inline .select2-search__field {
|
||||
outline: 0;
|
||||
box-shadow: none; }
|
||||
|
||||
.select2-container--classic .select2-dropdown {
|
||||
background-color: white;
|
||||
border: 1px solid transparent; }
|
||||
|
||||
.select2-container--classic .select2-dropdown--above {
|
||||
border-bottom: none; }
|
||||
|
||||
.select2-container--classic .select2-dropdown--below {
|
||||
border-top: none; }
|
||||
|
||||
.select2-container--classic .select2-results > .select2-results__options {
|
||||
max-height: 200px;
|
||||
overflow-y: auto; }
|
||||
|
||||
.select2-container--classic .select2-results__option[role=group] {
|
||||
padding: 0; }
|
||||
|
||||
.select2-container--classic .select2-results__option[aria-disabled=true] {
|
||||
color: grey; }
|
||||
|
||||
.select2-container--classic .select2-results__option--highlighted[aria-selected] {
|
||||
background-color: #3875d7;
|
||||
color: white; }
|
||||
|
||||
.select2-container--classic .select2-results__group {
|
||||
cursor: default;
|
||||
display: block;
|
||||
padding: 6px; }
|
||||
|
||||
.select2-container--classic.select2-container--open .select2-dropdown {
|
||||
border-color: #5897fb; }
|
||||
Executable
+6108
File diff suppressed because it is too large
Load Diff
Vendored
Executable
+2
File diff suppressed because one or more lines are too long
+113
@@ -0,0 +1,113 @@
|
||||
<?php
|
||||
|
||||
if (!defined('ABSPATH')) die('Access denied.');
|
||||
|
||||
class Simba_TFA_Encryption_Muplugin {
|
||||
|
||||
/**
|
||||
* The simba tfa object
|
||||
*
|
||||
* @var object
|
||||
*/
|
||||
private $simba_tfa;
|
||||
|
||||
/**
|
||||
* Full path to the file we're managing
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
private $file_path;
|
||||
|
||||
/**
|
||||
* The class constructor
|
||||
*
|
||||
* @param object $simba_tfa - the simba tfa object
|
||||
*/
|
||||
public function __construct($simba_tfa) {
|
||||
$this->simba_tfa = $simba_tfa;
|
||||
$this->file_path = path_join($this->get_mu_plugin_dir(), 'simba-tfa-encryption-key.php');
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns full path to mu-plugin directory
|
||||
*
|
||||
* @return string - the mu-plugin directory path
|
||||
*/
|
||||
public function get_mu_plugin_dir() {
|
||||
return WPMU_PLUGIN_DIR;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the full path to the mu-plugin file
|
||||
*
|
||||
* @return string - the mu-plugin path
|
||||
*/
|
||||
public function get_file_path() {
|
||||
return $this->file_path;
|
||||
}
|
||||
|
||||
/**
|
||||
* This function checks if our mu-plugin exists
|
||||
*
|
||||
* @return boolean - true if the file exists otherwise false
|
||||
*/
|
||||
public function muplugin_exists() {
|
||||
return file_exists($this->file_path);
|
||||
}
|
||||
|
||||
/**
|
||||
* Inserts our code into our mu-plugin.
|
||||
*
|
||||
* The mu-plugin and the mu-plugin directory will be created if they don't already exists
|
||||
*
|
||||
* @return boolean|WP_Error - true on success or WP_Error on failure
|
||||
*/
|
||||
public function insert_contents() {
|
||||
|
||||
$info = pathinfo($this->file_path);
|
||||
|
||||
if (!isset($info['dirname'])) {
|
||||
return new WP_Error(
|
||||
'file_no_directory',
|
||||
/* translators: %s: Multi user plugin directory */
|
||||
__('Encrypt secrets feature not enabled: no directory has been set.', 'all-in-one-wp-security-and-firewall') . ' ' . sprintf(__('Please check your %s constant is valid', 'all-in-one-wp-security-and-firewall'), 'WPMU_PLUGIN_DIR'),
|
||||
$this->file_path
|
||||
);
|
||||
}
|
||||
|
||||
if (false === wp_mkdir_p($info['dirname'])) {
|
||||
return new WP_Error(
|
||||
'file_no_directory_created',
|
||||
/* translators: %s: Multi user plugin directory */
|
||||
sprintf(__('The encrypt secrets feature was not enabled: your mu-plugins directory could not be automatically created; therefore, please use your web hosting file manager or FTP to manually create this folder and then try again: %s', 'all-in-one-wp-security-and-firewall'), $this->get_mu_plugin_dir()),
|
||||
$info['dirname']
|
||||
);
|
||||
}
|
||||
|
||||
if (false === @file_put_contents($this->file_path, $this->get_contents())) { // phpcs:ignore Generic.PHP.NoSilencedErrors.Discouraged -- ignore this as it is handled by the caller
|
||||
return new WP_Error(
|
||||
'file_no_contents',
|
||||
/* translators: %s: File path. */
|
||||
__('The encrypt secrets feature was not enabled: attempting to write the mu-plugin file contents failed; therefore, please create the file manually.', 'all-in-one-wp-security-and-firewall') . "<br><br>" . sprintf(__('Add the following code to the file %s', 'all-in-one-wp-security-and-firewall'), $this->get_file_path()) . "\n" . '<br><br><code>' . nl2br(esc_html($this->get_contents())) . '</code><br><br>' . __('Once you have added the above code then press the button to turn on encryption again', 'all-in-one-wp-security-and-firewall'),
|
||||
$info['dirname']
|
||||
);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* This function creates the contents for the mu-plugin
|
||||
*
|
||||
* @return string - the contents of the mu-plugin
|
||||
*/
|
||||
public function get_contents() {
|
||||
$encryption_key = base64_encode($this->simba_tfa->random_bytes(16));
|
||||
$code = "<?php\n";
|
||||
$code .= "// Simba TFA Database encryption key. Do not change this unless you wish all your existing encrypted keys to become unusable (e.g. if you intend to then replace them all).\n";
|
||||
$code .= "if (!defined('SIMBA_TFA_DB_ENCRYPTION_KEY')) define('SIMBA_TFA_DB_ENCRYPTION_KEY', '{$encryption_key}');";
|
||||
|
||||
return $code;
|
||||
}
|
||||
}
|
||||
|
||||
Executable
+361
@@ -0,0 +1,361 @@
|
||||
jQuery(function($) {
|
||||
|
||||
var username_requires_otp = [];
|
||||
|
||||
/**
|
||||
* Returns the jQuery identifiers for finding the username field. Abstracted here to avoid maintaining multiple lists.
|
||||
*
|
||||
* @return String
|
||||
*/
|
||||
function get_username_identifiers() {
|
||||
// 'username' is used by WooCommerce and RegistrationMagic
|
||||
return '[name="log"], [name="username"], #user_login, #affwp-login-user-login, #affwp-user-login, #gform_fields_login input[type="text"], .um-field-username input[type="text"]';
|
||||
}
|
||||
|
||||
/**
|
||||
* Process the results of a check for whether the user has TFA enabled or not
|
||||
*
|
||||
* @param Object form - jQuery form object
|
||||
* @param Object response - the response from the check; must have the property (boolean) "status" and potentially user_(boolean) "can_trust" and (boolean) user_can_trust.
|
||||
*/
|
||||
function process_user_tfa_enabled_check_results(form, response) {
|
||||
|
||||
if (true === response.status) {
|
||||
// Don't bother to remove the spinner if the form is being submitted.
|
||||
$('.simbaotp_spinner').remove();
|
||||
|
||||
var user_can_trust = (response.hasOwnProperty('user_can_trust') && response.user_can_trust) ? true : false;
|
||||
|
||||
var user_already_trusted = (response.hasOwnProperty('user_already_trusted') && response.user_can_trust) ? true : false;
|
||||
|
||||
console.log("Simba TFA: User has OTP enabled: showing OTP field (user_can_trust="+user_can_trust+")");
|
||||
|
||||
show_otp_field(form, user_can_trust, user_already_trusted);
|
||||
|
||||
return true;
|
||||
|
||||
} else {
|
||||
console.log("Simba TFA: User does not have OTP enabled: submitting form");
|
||||
// For some reason, .submit() stopped working with TML 7.x. N.B. Used to do this only for form_type == 2 ("TML shortcode or widget, WP Members, bbPress, Ultimate Membership Pro, WooCommerce or Elementor login form")
|
||||
// The un-disabling is for Ultimate Member, which for unknown reasons outputs the login button in a disabled state
|
||||
$(form).find('input[type="submit"], button[type="submit"]').first().prop('disabled', false).trigger('click');
|
||||
// $('#wp-submit').parents('form').first().trigger('submit');
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the user requires an OTP field and if so, display it
|
||||
*
|
||||
* @param String form - DOM selector string
|
||||
* @param Boolean only_cache_the_results - if true, then nothing more will be done that caching the results (in the variable username_requires_otp will be updated)
|
||||
*
|
||||
* @uses show_otp_field()
|
||||
*
|
||||
* @return Boolean - true if we got involved
|
||||
*/
|
||||
function check_and_possibly_show_otp_field(form, only_cache_the_results) {
|
||||
|
||||
// If this is a "lost password" form, then exit
|
||||
if ($(form).attr('id') === 'lostpasswordform' || $(form).attr('id') === 'resetpasswordform') return false;
|
||||
|
||||
var username = $(form).find(get_username_identifiers()).first().val();
|
||||
|
||||
if (!username.length) return false;
|
||||
|
||||
// Is the result already known?
|
||||
if ('object' === typeof username_requires_otp[username]) {
|
||||
if (!only_cache_the_results) {
|
||||
// Process the already-known result
|
||||
return process_user_tfa_enabled_check_results($(form), username_requires_otp[username]);
|
||||
}
|
||||
// No further processing
|
||||
return true;
|
||||
}
|
||||
|
||||
var $submit_button = $(form).find('input[name="wp-submit"], input[type="submit"], button[type="submit"]').first();
|
||||
|
||||
if (simba_tfasettings.hasOwnProperty('spinnerimg') && $('.simbaotp_spinner').length === 0) {
|
||||
var styling = 'float:right; margin:6px 12px; width: 20px; height: 20px;';
|
||||
if ($('#theme-my-login #wp-submit').length >0) {
|
||||
styling = 'margin-left: 4px; position: relative; top: 4px; width: 20px; height: 20px; border:0px; box-shadow:none;';
|
||||
}
|
||||
$submit_button.after('<img class="simbaotp_spinner" src="'+simba_tfasettings.spinnerimg+'" style="'+styling+'">');
|
||||
}
|
||||
|
||||
$.ajax({
|
||||
url: simba_tfasettings.ajaxurl,
|
||||
type: 'POST',
|
||||
data: {
|
||||
action: 'simbatfa-init-otp',
|
||||
user: username
|
||||
},
|
||||
dataType: 'text',
|
||||
success: function(resp) {
|
||||
try {
|
||||
var json_begins = resp.search('{"jsonstarter":"justhere"');
|
||||
if (json_begins > -1) {
|
||||
if (json_begins > 0) {
|
||||
console.log("Expected JSON marker found at position: "+json_begins);
|
||||
resp = resp.substring(json_begins);
|
||||
}
|
||||
} else {
|
||||
console.log("Expected JSON marker not found");
|
||||
console.log(resp);
|
||||
}
|
||||
|
||||
response = JSON.parse(resp);
|
||||
|
||||
if (response.hasOwnProperty('php_output')) {
|
||||
console.log("PHP output was returned (follows)");
|
||||
console.log(response.php_output);
|
||||
}
|
||||
|
||||
if (response.hasOwnProperty('extra_output')) {
|
||||
console.log("Extra output was returned (follows)");
|
||||
console.log(response.extra_output);
|
||||
}
|
||||
|
||||
if (only_cache_the_results) {
|
||||
// Save the result for later processing
|
||||
username_requires_otp[username] = response;
|
||||
$('.simbaotp_spinner').remove();
|
||||
} else {
|
||||
process_user_tfa_enabled_check_results($(form), response);
|
||||
}
|
||||
|
||||
} catch(err) {
|
||||
$('#login').html(resp);
|
||||
console.log("Simba TFA: Error when processing response");
|
||||
console.log(err);
|
||||
console.log(resp);
|
||||
}
|
||||
},
|
||||
error: function(jq_xhr, text_status, error_thrown) {
|
||||
console.log("Simba TFA: AJAX error: "+error_thrown+": "+text_status);
|
||||
console.log(jq_xhr);
|
||||
if (jq_xhr.hasOwnProperty('responseText')) {
|
||||
console.log(jq_xhr.responseText);
|
||||
$(form).append('<p class="error" style="clear:left;">'+simba_tfasettings.error+'</p>');
|
||||
}
|
||||
}
|
||||
});
|
||||
return true;
|
||||
}
|
||||
|
||||
// Parameters: see check_and_possibly_show_otp_field
|
||||
function show_otp_field(form, user_can_trust, user_already_trusted) {
|
||||
|
||||
var $submit_button;
|
||||
|
||||
user_can_trust = ('undefined' == typeof user_can_trust) ? false : user_can_trust;
|
||||
user_already_trusted = ('undefined' == typeof user_already_trusted) ? false : user_already_trusted;
|
||||
|
||||
if ('https:' != window.location.protocol && 'localhost' !== location.hostname && '127.0.0.1' !== location.hostname && /^\.localdomain$/.test(location.hostname)) {
|
||||
user_can_trust = false;
|
||||
}
|
||||
|
||||
if (!user_can_trust) { user_already_trusted = false; }
|
||||
|
||||
var form_is_gravity_forms = ('object' == typeof window['gform_gravityforms'] && 'undefined' !== typeof $(form).attr('id') && 'gform_' === $(form).attr('id').substring(0, 6));
|
||||
|
||||
// This is used just for applying similar styling (via adding structure/CSS classes)
|
||||
var form_is_ultimate_member = ($(form).find('.um-row').length > 0) ? true : false;
|
||||
|
||||
// This is used just for applying styling if .js-login-form class exists inside form
|
||||
var form_is_login_form = ($(form).find('.js-login-form').length > 0) ? true : false;
|
||||
|
||||
// Gravity Forms won't submit if the elements are hidden
|
||||
var form_retain_existing_elements = form_is_gravity_forms ? true : false;
|
||||
|
||||
// name="Submit" is WP-Members. 'submit' is Theme My Login starting from 7.x
|
||||
$submit_button = $(form).find('input[name="wp-submit"], input[name="Submit"], input[name="submit"]');
|
||||
// This hasn't been needed for anything yet (Jul 2018), but is a decent back-stop that would have prevented some breakage in the past that needed manual attention:
|
||||
if (0 == $submit_button.length) {
|
||||
$submit_button = $(form).find('input[type="submit"], button[type="submit"]').first();
|
||||
}
|
||||
|
||||
if (!form_retain_existing_elements) {
|
||||
// Hide all elements in a browser-safe way
|
||||
// .user-pass-wrap is the wrapper used (instead of a paragraph) on wp-login.php from WP 5.3
|
||||
// .um-row : Ultimate Member
|
||||
// .rmrow : RegistrationMagic
|
||||
$submit_button.parents('form').first().find('p, .impu-form-line-fr, .tml-field-wrap, .user-pass-wrap, .elementor-field-type-text, .elementor-field-type-submit, .elementor-remember-me, .bbp-username, .bbp-password, .bbp-submit-wrapper, .gform_body, .um-row, .um-button, .js-login-form, .rmrow').each(function(i) {
|
||||
$(this).css('visibility', 'hidden').css('position', 'absolute');
|
||||
// On the WooCommerce form, the 'required' asterisk in the child <span> still shows without this
|
||||
$(this).find('span').css('visibility', 'hidden').css('position', 'absolute');
|
||||
});
|
||||
|
||||
// WP-Members
|
||||
$submit_button.parents('#wpmem_login').find('fieldset').css('visibility', 'hidden').css('position', 'absolute');
|
||||
|
||||
}
|
||||
|
||||
// Add new field and controls
|
||||
var html = '';
|
||||
|
||||
if (form_is_ultimate_member) {
|
||||
html += '<div class="um-row">';
|
||||
}
|
||||
|
||||
if (user_already_trusted) {
|
||||
|
||||
html += '<br><span class="simbaotp_is_trusted">'+simba_tfasettings.is_trusted+'</span>';
|
||||
|
||||
} else {
|
||||
|
||||
if (form_is_ultimate_member) { html += '<div class="um-field um-field-text um-field-type_text"><div class="um-field-label">'; }
|
||||
|
||||
html += '<label ';
|
||||
|
||||
if (form_is_gravity_forms) {
|
||||
html += 'class="gfield_label"';
|
||||
}
|
||||
|
||||
html += 'for="simba_two_factor_auth">';
|
||||
|
||||
html += simba_tfasettings.otp + '</label><input type="text" name="two_factor_code" id="simba_two_factor_auth" autocomplete="off" data-lpignore="true"';
|
||||
|
||||
if ($(form).hasClass('woocommerce-form-login')) {
|
||||
// Retain compatibility with previous full-width layout
|
||||
html += ' style="width: 100%;"';
|
||||
}
|
||||
|
||||
html += '>';
|
||||
|
||||
if (form_is_ultimate_member) { html += '</div>'; }
|
||||
|
||||
html += '<p class="forgetmenot';
|
||||
if (form_is_gravity_forms) html += ' gfield';
|
||||
html += '" style="font-size:small;';
|
||||
if (!$(form).hasClass('woocommerce-form-login')) {
|
||||
// Retain compatibility with previous full-width layout
|
||||
html += ' max-width: 60%;';
|
||||
}
|
||||
html += '">';
|
||||
|
||||
if (form_is_ultimate_member) { html += '</div>'; }
|
||||
|
||||
// Would need further styling investigations to display this
|
||||
if (!form_is_gravity_forms) {
|
||||
html += '<span class="simba_tfa_otp_login_help">'+simba_tfasettings.otp_login_help+'</span>';
|
||||
}
|
||||
|
||||
if (form_is_ultimate_member) {
|
||||
html += '</div>';
|
||||
}
|
||||
|
||||
if (user_can_trust) {
|
||||
|
||||
html += '<input type="checkbox" name="simba_tfa_mark_as_trusted" id="simba_tfa_mark_as_trusted" value="1"><label for="simba_tfa_mark_as_trusted">'+ simba_tfasettings.mark_as_trusted+'</label>';
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
html += '</p>';
|
||||
|
||||
var submit_button_text;
|
||||
var submit_button_name;
|
||||
|
||||
// Gravity forms doesn't like its button being disabled
|
||||
if (!form_is_gravity_forms) {
|
||||
|
||||
if ('button' == $submit_button.prop('nodeName').toLowerCase()) {
|
||||
submit_button_text = $submit_button.text().trim();
|
||||
submit_button_name = $submit_button.attr('name');
|
||||
} else {
|
||||
submit_button_text = $submit_button.val();
|
||||
submit_button_name = $submit_button.attr('name');
|
||||
}
|
||||
|
||||
html += '<p class="submit';
|
||||
|
||||
if (form_is_ultimate_member) { html += ' um-center'; }
|
||||
|
||||
html += '"><input id="tfa_login_btn" class="button button-primary button-large';
|
||||
|
||||
if (form_is_ultimate_member) { html += ' um-button'; }
|
||||
|
||||
if (form_is_login_form) { html += ' c-btn-rg hover:bg-main focus:bg-main'; }
|
||||
|
||||
html += '" type="submit" ';
|
||||
if ('undefined' !== typeof submit_button_name && '' != submit_button_name) { html += 'name="'+submit_button_name+'" '; }
|
||||
html += 'value="' + submit_button_text + '"></p>';
|
||||
|
||||
$submit_button.prop('disabled', true).hide();
|
||||
|
||||
}
|
||||
|
||||
if (form_retain_existing_elements && form_is_gravity_forms) {
|
||||
// $submit_button.parents('form').first().append(html);
|
||||
//$('<div style="clear:both;">'+html+'</div>').insertBefore($submit_button);
|
||||
$(form).find('#gform_fields_login').append(html);
|
||||
} else {
|
||||
$submit_button.parents('form').first().prepend(html);
|
||||
}
|
||||
|
||||
$('#login_error').hide();
|
||||
|
||||
if (user_already_trusted) {
|
||||
if (form_retain_existing_elements) {
|
||||
$submit_button.trigger('click');
|
||||
} else {
|
||||
$('#tfa_login_btn').trigger('click');
|
||||
}
|
||||
} else {
|
||||
|
||||
$('#simba_two_factor_auth').trigger('focus');
|
||||
|
||||
// Hide extra boxes of third party plugins
|
||||
jQuery('.hide-when-displaying-tfa-input').hide();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* This function gets attached to a form submission handler and decides whether to add an OTP field or not.
|
||||
*
|
||||
* @param Object e - submission event
|
||||
*
|
||||
* @return Boolean - whether to proceed with the submission or not
|
||||
*/
|
||||
var form_submit_handler = function(e) {
|
||||
|
||||
console.log('Simba TFA: form submit request');
|
||||
|
||||
var form = e.target;
|
||||
|
||||
var form_is_gravity_forms = ('object' == typeof window['gform_gravityforms'] && 'undefined' !== typeof $(form).attr('id') && 'gform_' === $(form).attr('id').substring(0, 6));
|
||||
|
||||
// Turn off everything
|
||||
$(form).off();
|
||||
|
||||
if (0 == $(form).find('#simba_two_factor_auth').length && check_and_possibly_show_otp_field(form)) {
|
||||
|
||||
if (form_is_gravity_forms) {
|
||||
var form_id = $(form).attr('id').substring(6);
|
||||
// Gravity Forms won't allow the form to submit if this is already true
|
||||
window['gf_submitting_'+form_id] = false;
|
||||
}
|
||||
|
||||
e.preventDefault();
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
};
|
||||
|
||||
if (simba_tfasettings.login_form_off_selectors) {
|
||||
$(simba_tfasettings.login_form_off_selectors).off('submit');
|
||||
}
|
||||
|
||||
$(simba_tfasettings.login_form_selectors).on('submit', form_submit_handler);
|
||||
|
||||
$(simba_tfasettings.login_form_selectors).find(get_username_identifiers()).on('blur', function() {
|
||||
var $form = $(this).parents('form').first();
|
||||
check_and_possibly_show_otp_field($form, true);
|
||||
});
|
||||
|
||||
});
|
||||
BIN
Binary file not shown.
|
After Width: | Height: | Size: 3.7 KiB |
BIN
Binary file not shown.
|
After Width: | Height: | Size: 6.8 KiB |
Executable
+216
@@ -0,0 +1,216 @@
|
||||
<?php
|
||||
if (!defined('ABSPATH')) die('Access denied.');
|
||||
|
||||
class Simba_TFA_Frontend {
|
||||
|
||||
private $mother;
|
||||
|
||||
/**
|
||||
* Class constructor
|
||||
*
|
||||
* @param Object $mother
|
||||
*/
|
||||
public function __construct($mother) {
|
||||
|
||||
$this->mother = $mother;
|
||||
add_action('wp_ajax_tfa_frontend', array($this, 'ajax'));
|
||||
add_shortcode('twofactor_user_settings', array($this, 'tfa_user_settings_front'));
|
||||
|
||||
if (!WP_Block_Type_Registry::get_instance()->is_registered('twofactor/user-settings')) {
|
||||
register_block_type('twofactor/user-settings', array(
|
||||
'editor_script' => 'twofactor-gutenberg-blocks',
|
||||
'render_callback' => array($this, 'tfa_user_settings_front'),
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Runs upon the WP action wp_ajax_tfa_frontend
|
||||
*
|
||||
* @uses die()
|
||||
*/
|
||||
public function ajax() {
|
||||
$totp_controller = $this->mother->get_controller('totp');
|
||||
global $current_user;
|
||||
|
||||
$return_array = array();
|
||||
|
||||
if (empty($_POST) || empty($_POST['subaction']) || !isset($_POST['nonce']) || !is_user_logged_in() || !wp_verify_nonce($_POST['nonce'], 'tfa_frontend_nonce')) die('Security check');
|
||||
|
||||
if ('savesettings' == $_POST['subaction']) {
|
||||
if (empty($_POST['settings']) || !is_string($_POST['settings'])) die;
|
||||
|
||||
parse_str(stripslashes($_POST['settings']), $posted_settings);
|
||||
|
||||
if (isset($posted_settings['tfa_algorithm_type'])) {
|
||||
$old_algorithm = $totp_controller->get_user_otp_algorithm($current_user->ID);
|
||||
|
||||
if ($old_algorithm != $posted_settings['tfa_algorithm_type'])
|
||||
$totp_controller->changeUserAlgorithmTo($current_user->ID, $posted_settings['tfa_algorithm_type']);
|
||||
|
||||
//Re-fetch the algorithm type, url and private string
|
||||
$variables = $this->tfa_fetch_assort_vars();
|
||||
|
||||
$return_array['qr'] = $totp_controller->tfa_qr_code_url($variables['algorithm_type'], $variables['url'], $variables['tfa_priv_key']);
|
||||
$return_array['al_type_disp'] = $this->tfa_algorithm_info($variables['algorithm_type']);
|
||||
}
|
||||
|
||||
if (isset($posted_settings['tfa_enable_tfa'])) {
|
||||
|
||||
$allow_enable_or_disable = false;
|
||||
|
||||
if (empty($posted_settings['require_current']) || !$posted_settings['tfa_enable_tfa']) {
|
||||
$allow_enable_or_disable = true;
|
||||
} else {
|
||||
|
||||
if (!isset($posted_settings['tfa_enable_current']) || '' == $posted_settings['tfa_enable_current']) {
|
||||
$return_array['message'] = __('To enable TFA, you must enter the current code.', 'all-in-one-wp-security-and-firewall');
|
||||
$return_array['error'] = 'code_absent';
|
||||
} else {
|
||||
// Third parameter: don't allow emergency codes
|
||||
if ($totp_controller->check_code_for_user($current_user->ID, $posted_settings['tfa_enable_current'], false)) {
|
||||
$allow_enable_or_disable = true;
|
||||
} else {
|
||||
$return_array['error'] = 'code_wrong';
|
||||
$return_array['message'] = apply_filters('simba_tfa_message_code_incorrect', __('The TFA code you entered was incorrect.', 'all-in-one-wp-security-and-firewall'));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if ($allow_enable_or_disable) $this->mother->change_tfa_enabled_status($current_user->ID, $posted_settings['tfa_enable_tfa']);
|
||||
}
|
||||
|
||||
$return_array['result'] = 'saved';
|
||||
|
||||
echo json_encode($return_array);
|
||||
}
|
||||
|
||||
die;
|
||||
}
|
||||
|
||||
/**
|
||||
* Make the algorithm information string easier to update
|
||||
*
|
||||
* @param String $algorithm_type - totp|hotp
|
||||
*/
|
||||
public function tfa_algorithm_info($algorithm_type) {
|
||||
$al_type_disp = strtoupper($algorithm_type);
|
||||
$al_type_desc = ($algorithm_type == 'totp' ? __('a time based', 'all-in-one-wp-security-and-firewall') : __('an event based', 'all-in-one-wp-security-and-firewall'));
|
||||
|
||||
return array('disp' => $al_type_disp, 'desc' => $al_type_desc);
|
||||
}
|
||||
|
||||
/**
|
||||
* Make the assorted required variables more accessible for ajax
|
||||
*
|
||||
* Returns: Site URL, private key, emergency codes, algorithm type
|
||||
*
|
||||
* @return Array
|
||||
*/
|
||||
public function tfa_fetch_assort_vars() {
|
||||
global $current_user;
|
||||
$totp_controller = $this->mother->get_controller('totp');
|
||||
|
||||
$url = preg_replace('/^https?:\/\//i', '', site_url());
|
||||
|
||||
$tfa_priv_key_64 = get_user_meta($current_user->ID, 'tfa_priv_key_64', true);
|
||||
|
||||
if (!$tfa_priv_key_64) $tfa_priv_key_64 = $totp_controller->addPrivateKey($current_user->ID);
|
||||
|
||||
$tfa_priv_key = trim($totp_controller->getPrivateKeyPlain($tfa_priv_key_64, $current_user->ID));
|
||||
|
||||
$algorithm_type = $totp_controller->get_user_otp_algorithm($current_user->ID);
|
||||
|
||||
return apply_filters('simba_tfa_fetch_assort_vars', array(
|
||||
'url' => $url,
|
||||
'tfa_priv_key_64' => $tfa_priv_key_64,
|
||||
'tfa_priv_key' => $tfa_priv_key,
|
||||
'emergency_str' => '<em>'.__('No emergency codes left. Sorry.', 'all-in-one-wp-security-and-firewall').'</em>',
|
||||
'algorithm_type' => $algorithm_type
|
||||
), $totp_controller, $current_user);
|
||||
}
|
||||
|
||||
/**
|
||||
* Paints out the 'save settings' button
|
||||
*/
|
||||
public function save_settings_button() {
|
||||
echo '<button style="margin-left: 4px;margin-bottom: 10px" class="simbatfa_settings_save button button-primary">'.__('Save Settings', 'all-in-one-wp-security-and-firewall').'</button>';
|
||||
}
|
||||
|
||||
/**
|
||||
* Paint output for the TFA on/off radio
|
||||
*
|
||||
* @param String $style - valid values are 'show_current' and 'require_current'
|
||||
*/
|
||||
public function settings_enable_or_disable_output($style = 'show_current') {
|
||||
$this->save_settings_javascript_output();
|
||||
global $current_user;
|
||||
?>
|
||||
<div class="simbatfa_frontend_settings_box tfa_settings_form">
|
||||
<p><?php $this->mother->paint_enable_tfa_radios($current_user->ID, true, $style); ?></p>
|
||||
<button style="margin-left: 4px; margin-bottom: 10px;" class="button button-primary simbatfa_settings_save"><?php _e('Save Settings', 'all-in-one-wp-security-and-firewall'); ?></button>
|
||||
</div>
|
||||
<?php
|
||||
}
|
||||
|
||||
/**
|
||||
* Enqueue scripts
|
||||
*/
|
||||
public function save_settings_javascript_output() {
|
||||
|
||||
static $is_already_added = false;
|
||||
if ($is_already_added) return;
|
||||
$is_already_added = true;
|
||||
|
||||
$suffix = defined('SCRIPT_DEBUG') && SCRIPT_DEBUG ? '' : '.min';
|
||||
wp_register_script('jquery-blockui', $this->mother->includes_url().'/jquery.blockUI' . $suffix . '.js', array('jquery'), '2.60');
|
||||
|
||||
$script_ver = (defined('WP_DEBUG') && WP_DEBUG) ? time() : filemtime($this->mother->includes_dir().'/frontend-settings.js');
|
||||
|
||||
wp_enqueue_script('simba-tfa-frontend-settings', $this->mother->includes_url().'/frontend-settings.js', array('jquery-blockui'), $script_ver);
|
||||
|
||||
$ajax_url = admin_url('admin-ajax.php');
|
||||
// It's possible that FORCE_ADMIN_SSL will make that SSL, whilst the user is on the front-end having logged in over non-SSL - and as a result, their login cookies won't get sent, and they're not registered as logged in.
|
||||
if (!is_admin() && substr(strtolower($ajax_url), 0, 6) == 'https:' && !is_ssl()) {
|
||||
$also_try = 'http:'.substr($ajax_url, 6);
|
||||
} else {
|
||||
$also_try = '';
|
||||
}
|
||||
|
||||
$localize = array(
|
||||
'ask' => __('You have unsaved settings.', 'all-in-one-wp-security-and-firewall'),
|
||||
'saving' => __('Saving...', 'all-in-one-wp-security-and-firewall'),
|
||||
'ajax_url' => $ajax_url,
|
||||
'also_try' => $also_try,
|
||||
'nonce' => wp_create_nonce('tfa_frontend_nonce'),
|
||||
'response' => __('Response:', 'all-in-one-wp-security-and-firewall'),
|
||||
);
|
||||
|
||||
wp_localize_script('simba-tfa-frontend-settings', 'simba_tfa_frontend', $localize);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Shortcode function for twofactor_user_settings
|
||||
*
|
||||
* @param Array $atts - shortcode attributes
|
||||
*
|
||||
* @return String
|
||||
*/
|
||||
public function tfa_user_settings_front($atts = array()) {
|
||||
|
||||
if (!is_user_logged_in()) return '';
|
||||
|
||||
$atts = array_change_key_case((array)$atts, CASE_LOWER);
|
||||
|
||||
$atts = shortcode_atts(array('show_algorithm_selector' => 'no'), $atts);
|
||||
|
||||
$show_algorithm_selector = ('yes' === $atts['show_algorithm_selector']);
|
||||
|
||||
global $current_user;
|
||||
|
||||
return $this->mother->include_template('shortcode-tfa-user-settings.php', array('is_activated_for_user' => $current_user->ID, 'tfa_frontend' => $this, 'show_algorithm_selector' => $show_algorithm_selector), true);
|
||||
|
||||
}
|
||||
}
|
||||
Executable
+101
@@ -0,0 +1,101 @@
|
||||
jQuery(function($) {
|
||||
|
||||
// Render any QR codes on the page
|
||||
$('.simbaotp_qr_container').qrcode({
|
||||
'render': 'image',
|
||||
'text': $('.simbaotp_qr_container:first').data('qrcode'),
|
||||
});
|
||||
|
||||
function update_otp_code() {
|
||||
|
||||
$('.simba_current_otp').html('<em>'+simbatfa_totp.updating+'</em>');
|
||||
|
||||
var got_code = '';
|
||||
|
||||
$.post(simbatfa_totp.ajax_url, {
|
||||
action: 'simbatfa_shared_ajax',
|
||||
subaction: 'refreshotp',
|
||||
nonce: simbatfa_totp.tfa_shared_nonce
|
||||
}, function(response) {
|
||||
|
||||
try {
|
||||
var resp = JSON.parse(response);
|
||||
got_code = resp.code;
|
||||
} catch(err) {
|
||||
if ('' !== simbatfa_totp.also_try) {
|
||||
alert(simbatfa_totp.response+" "+response);
|
||||
}
|
||||
console.log(response);
|
||||
console.log(err);
|
||||
}
|
||||
|
||||
if ('' === got_code && '' !== simbatfa_totp.also_try) {
|
||||
$.post(simbatfa_totp.also_try, {
|
||||
action: 'simbatfa_shared_ajax',
|
||||
subaction: 'refreshotp',
|
||||
nonce: simbatfa_totp.tfa_shared_nonce
|
||||
}, function(response) {
|
||||
try {
|
||||
var resp = JSON.parse(response);
|
||||
if (resp.code) {
|
||||
$('.simba_current_otp').html(resp.code);
|
||||
} else {
|
||||
console.log(response);
|
||||
console.log("TFA: no code found");
|
||||
}
|
||||
} catch(err) {
|
||||
alert(simbatfa_totp.response+" "+response);
|
||||
console.log(response);
|
||||
console.log(err);
|
||||
}
|
||||
});
|
||||
} else if ('' != got_code) {
|
||||
$('.simba_current_otp').html(got_code);
|
||||
} else {
|
||||
console.log("TFA: no code found");
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
var min_refresh_after = 30;
|
||||
|
||||
if (0 == $('body.settings_page_two-factor-auth').length) {
|
||||
$('.simba_current_otp').each(function(ind, obj) {
|
||||
var refresh_after = $(obj).data('refresh_after');
|
||||
if (refresh_after > 0 && refresh_after < min_refresh_after) {
|
||||
min_refresh_after = refresh_after;
|
||||
}
|
||||
});
|
||||
|
||||
// Update after the given seconds, and then every 30 seconds
|
||||
setTimeout(function() {
|
||||
setInterval(update_otp_code, 30000)
|
||||
update_otp_code();
|
||||
}, min_refresh_after * 1000);
|
||||
}
|
||||
|
||||
// Handle clicks on the 'refresh' link
|
||||
$('.simbaotp_refresh').on('click', function(e) {
|
||||
e.preventDefault();
|
||||
update_otp_code();
|
||||
});
|
||||
|
||||
$('#tfa_trusted_devices_box').on('click', '.simbatfa-trust-remove', function(e) {
|
||||
e.preventDefault();
|
||||
var device_id = $(this).data('trusted-device-id');
|
||||
$(this).parents('.simbatfa_trusted_device').css('opacity', '0.5');
|
||||
if ('undefined' !== typeof device_id) {
|
||||
$.post(simbatfa_totp.ajax_url, {
|
||||
action: 'simbatfa_shared_ajax',
|
||||
subaction: 'untrust_device',
|
||||
nonce: simbatfa_totp.tfa_shared_nonce,
|
||||
device_id: device_id
|
||||
}, function(response) {
|
||||
var resp = JSON.parse(response);
|
||||
if (resp.hasOwnProperty('trusted_list')) {
|
||||
$('#tfa_trusted_devices_box_inner').html(resp.trusted_list);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
Executable
+13
@@ -0,0 +1,13 @@
|
||||
/* TFA users list column */
|
||||
th.column-tfa-status,
|
||||
td.column-tfa-status {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
td.column-tfa-status span.dashicons-no {
|
||||
color: red;
|
||||
}
|
||||
|
||||
td.column-tfa-status span.dashicons-yes {
|
||||
color: green;
|
||||
}
|
||||
+225
@@ -0,0 +1,225 @@
|
||||
<?php
|
||||
//namespace Base32;
|
||||
|
||||
/**
|
||||
* Base32 encoder and decoder
|
||||
*
|
||||
* Last update: 2012-06-20
|
||||
*
|
||||
* RFC 4648 compliant
|
||||
* @link http://www.ietf.org/rfc/rfc4648.txt
|
||||
*
|
||||
* Some groundwork based on this class
|
||||
* https://github.com/NTICompass/PHP-Base32
|
||||
*
|
||||
* @author Christian Riesen <chris.riesen@gmail.com>
|
||||
* @link http://christianriesen.com
|
||||
* @license MIT License see LICENSE file
|
||||
*/
|
||||
class Base32
|
||||
{
|
||||
/**
|
||||
* Table for encoding base32
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
private static $encode = array(
|
||||
0 => 'A',
|
||||
1 => 'B',
|
||||
2 => 'C',
|
||||
3 => 'D',
|
||||
4 => 'E',
|
||||
5 => 'F',
|
||||
6 => 'G',
|
||||
7 => 'H',
|
||||
8 => 'I',
|
||||
9 => 'J',
|
||||
10 => 'K',
|
||||
11 => 'L',
|
||||
12 => 'M',
|
||||
13 => 'N',
|
||||
14 => 'O',
|
||||
15 => 'P',
|
||||
16 => 'Q',
|
||||
17 => 'R',
|
||||
18 => 'S',
|
||||
19 => 'T',
|
||||
20 => 'U',
|
||||
21 => 'V',
|
||||
22 => 'W',
|
||||
23 => 'X',
|
||||
24 => 'Y',
|
||||
25 => 'Z',
|
||||
26 => 2,
|
||||
27 => 3,
|
||||
28 => 4,
|
||||
29 => 5,
|
||||
30 => 6,
|
||||
31 => 7,
|
||||
32 => '=',
|
||||
);
|
||||
|
||||
/**
|
||||
* Table for decoding base32
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
private static $decode = array(
|
||||
'A' => 0,
|
||||
'B' => 1,
|
||||
'C' => 2,
|
||||
'D' => 3,
|
||||
'E' => 4,
|
||||
'F' => 5,
|
||||
'G' => 6,
|
||||
'H' => 7,
|
||||
'I' => 8,
|
||||
'J' => 9,
|
||||
'K' => 10,
|
||||
'L' => 11,
|
||||
'M' => 12,
|
||||
'N' => 13,
|
||||
'O' => 14,
|
||||
'P' => 15,
|
||||
'Q' => 16,
|
||||
'R' => 17,
|
||||
'S' => 18,
|
||||
'T' => 19,
|
||||
'U' => 20,
|
||||
'V' => 21,
|
||||
'W' => 22,
|
||||
'X' => 23,
|
||||
'Y' => 24,
|
||||
'Z' => 25,
|
||||
2 => 26,
|
||||
3 => 27,
|
||||
4 => 28,
|
||||
5 => 29,
|
||||
6 => 30,
|
||||
7 => 31,
|
||||
'=' => 32,
|
||||
);
|
||||
|
||||
/**
|
||||
* Creates an array from a binary string into a given chunk size
|
||||
*
|
||||
* @param string $binaryString String to chunk
|
||||
* @param integer $bits Number of bits per chunk
|
||||
* @return array
|
||||
*/
|
||||
private static function chunk($binaryString, $bits)
|
||||
{
|
||||
$binaryString = chunk_split($binaryString, $bits, ' ');
|
||||
|
||||
if (substr($binaryString, (strlen($binaryString)) - 1) == ' ') {
|
||||
$binaryString = substr($binaryString, 0, strlen($binaryString)-1);
|
||||
}
|
||||
|
||||
return explode(' ', $binaryString);
|
||||
}
|
||||
|
||||
/**
|
||||
* Encodes into base32
|
||||
*
|
||||
* @param string $string Clear text string
|
||||
* @return string Base32 encoded string
|
||||
*/
|
||||
public static function encode($string)
|
||||
{
|
||||
if (strlen($string) == 0) {
|
||||
// Gives an empty string
|
||||
return '';
|
||||
}
|
||||
|
||||
// Convert string to binary
|
||||
$binaryString = '';
|
||||
|
||||
foreach (str_split($string) as $s) {
|
||||
// Return each character as an 8-bit binary string
|
||||
$s = decbin(ord($s));
|
||||
$binaryString .= str_pad($s, 8, 0, STR_PAD_LEFT);
|
||||
}
|
||||
|
||||
// Break into 5-bit chunks, then break that into an array
|
||||
$binaryArray = self::chunk($binaryString, 5);
|
||||
|
||||
// Pad array to be divisible by 8
|
||||
while (count($binaryArray) % 8 !== 0) {
|
||||
$binaryArray[] = null;
|
||||
}
|
||||
|
||||
$base32String = '';
|
||||
|
||||
// Encode in base32
|
||||
foreach ($binaryArray as $bin) {
|
||||
$char = 32;
|
||||
|
||||
if (!is_null($bin)) {
|
||||
// Pad the binary strings
|
||||
$bin = str_pad($bin, 5, 0, STR_PAD_RIGHT);
|
||||
$char = bindec($bin);
|
||||
}
|
||||
|
||||
// Base32 character
|
||||
$base32String .= self::$encode[$char];
|
||||
}
|
||||
|
||||
return $base32String;
|
||||
}
|
||||
|
||||
/**
|
||||
* Decodes base32
|
||||
*
|
||||
* @param string $base32String Base32 encoded string
|
||||
* @return string Clear text string
|
||||
*/
|
||||
public static function decode($base32String)
|
||||
{
|
||||
if (strlen($base32String) == 0) {
|
||||
// Gives an empty string
|
||||
return '';
|
||||
}
|
||||
|
||||
// Only work in upper cases
|
||||
$base32String = strtoupper($base32String);
|
||||
|
||||
// Remove anything that is not base32 alphabet
|
||||
$pattern = '/[^A-Z2-7]/';
|
||||
$replacement = '';
|
||||
|
||||
$base32String = preg_replace($pattern, '', $base32String);
|
||||
|
||||
$base32Array = str_split($base32String);
|
||||
|
||||
$binaryArray = array();
|
||||
$string = '';
|
||||
|
||||
foreach ($base32Array as $str) {
|
||||
$char = self::$decode[$str];
|
||||
|
||||
// Ignore the padding character
|
||||
if ($char !== 32) {
|
||||
$char = decbin($char);
|
||||
$string .= str_pad($char, 5, 0, STR_PAD_LEFT);
|
||||
}
|
||||
}
|
||||
|
||||
while (strlen($string) %8 !== 0) {
|
||||
$string = substr($string, 0, strlen($string)-1);
|
||||
}
|
||||
|
||||
$binaryArray = self::chunk($string, 8);
|
||||
|
||||
$realString = '';
|
||||
|
||||
foreach ($binaryArray as $bin) {
|
||||
// Pad each value to 8 bits
|
||||
$bin = str_pad($bin, 8, 0, STR_PAD_RIGHT);
|
||||
// Convert binary strings to ascii
|
||||
$realString .= chr(bindec($bin));
|
||||
}
|
||||
|
||||
return $realString;
|
||||
}
|
||||
}
|
||||
|
||||
+24
@@ -0,0 +1,24 @@
|
||||
Copyright (c) 2008, Jakob Heuser
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
* Neither the name of HOTP-PHP nor the
|
||||
names of its contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY Jakob Heuser ''AS IS'' AND ANY
|
||||
EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL <copyright holder> BE LIABLE FOR ANY
|
||||
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
+27
@@ -0,0 +1,27 @@
|
||||
HOTP - PHP Based HMAC One Time Passwords
|
||||
========================================
|
||||
|
||||
**What is HOTP**:
|
||||
HOTP is a class that simplifies One Time Password systems for PHP Authentication. The HOTP/TOTP Algorithms have been around for a bit, so this is a straightforward class to meet the test vector requirements.
|
||||
|
||||
**What works with HOTP/TOTP**:
|
||||
It's been tested to the test vectors, and I've verified the time-sync hashes against the following:
|
||||
|
||||
* Android: Mobile-OTP
|
||||
* iPhone: OATH Token
|
||||
|
||||
**Why would I use this**:
|
||||
Who wouldn't love a simple drop-in class for HMAC Based One Time Passwords? It's a great extra layer of security (creating two-factor auth) and it's pretty darn zippy.
|
||||
|
||||
**Okay you sold me. Give me some docs**:
|
||||
|
||||
* $result = HOTP::generateByCounter($key, $counter); // event based
|
||||
* $result = HOTP::generateByTime($key, $window); // time based within a "window" of time
|
||||
* $result = HOTP::generateByTimeWindow($key, $window, $min, $max); // same as generateByTime, but for $min windows before and $max windows after
|
||||
|
||||
with $result, you can do all sorts of neat things...
|
||||
|
||||
* $result->toString();
|
||||
* $result->toHex();
|
||||
* $result->doDec();
|
||||
* $result->toHotp($length); // how many digits in your OTP?
|
||||
+160
@@ -0,0 +1,160 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
HOTP Example File
|
||||
*/
|
||||
require_once 'hotp.php';
|
||||
|
||||
$key = '12345678901234567890';
|
||||
|
||||
$table = array(
|
||||
'HOTP' => array(
|
||||
0 => array(
|
||||
'HMAC' => 'cc93cf18508d94934c64b65d8ba7667fb7cde4b0',
|
||||
'hex' => '4c93cf18',
|
||||
'dec' => '1284755224',
|
||||
'hotp' => '755224',
|
||||
),
|
||||
1 => array(
|
||||
'HMAC' => '75a48a19d4cbe100644e8ac1397eea747a2d33ab',
|
||||
'hex' => '41397eea',
|
||||
'dec' => '1094287082',
|
||||
'hotp' => '287082',
|
||||
),
|
||||
2 => array(
|
||||
'HMAC' => '0bacb7fa082fef30782211938bc1c5e70416ff44',
|
||||
'hex' => '82fef30',
|
||||
'dec' => '137359152',
|
||||
'hotp' => '359152',
|
||||
),
|
||||
3 => array(
|
||||
'HMAC' => '66c28227d03a2d5529262ff016a1e6ef76557ece',
|
||||
'hex' => '66ef7655',
|
||||
'dec' => '1726969429',
|
||||
'hotp' => '969429',
|
||||
),
|
||||
4 => array(
|
||||
'HMAC' => 'a904c900a64b35909874b33e61c5938a8e15ed1c',
|
||||
'hex' => '61c5938a',
|
||||
'dec' => '1640338314',
|
||||
'hotp' => '338314',
|
||||
),
|
||||
5 => array(
|
||||
'HMAC' => 'a37e783d7b7233c083d4f62926c7a25f238d0316',
|
||||
'hex' => '33c083d4',
|
||||
'dec' => '868254676',
|
||||
'hotp' => '254676',
|
||||
),
|
||||
6 => array(
|
||||
'HMAC' => 'bc9cd28561042c83f219324d3c607256c03272ae',
|
||||
'hex' => '7256c032',
|
||||
'dec' => '1918287922',
|
||||
'hotp' => '287922',
|
||||
),
|
||||
7 => array(
|
||||
'HMAC' => 'a4fb960c0bc06e1eabb804e5b397cdc4b45596fa',
|
||||
'hex' => '4e5b397',
|
||||
'dec' => '82162583',
|
||||
'hotp' => '162583',
|
||||
),
|
||||
8 => array(
|
||||
'HMAC' => '1b3c89f65e6c9e883012052823443f048b4332db',
|
||||
'hex' => '2823443f',
|
||||
'dec' => '673399871',
|
||||
'hotp' => '399871',
|
||||
),
|
||||
9 => array(
|
||||
'HMAC' => '1637409809a679dc698207310c8c7fc07290d9e5',
|
||||
'hex' => '2679dc69',
|
||||
'dec' => '645520489',
|
||||
'hotp' => '520489',
|
||||
),
|
||||
),
|
||||
'TOTP' => array(
|
||||
'59' => array(
|
||||
'totp' => '94287082',
|
||||
),
|
||||
'1111111109' => array(
|
||||
'totp' => '07081804',
|
||||
),
|
||||
'1111111111' => array(
|
||||
'totp' => '14050471',
|
||||
),
|
||||
'1234567890' => array(
|
||||
'totp' => '89005924',
|
||||
),
|
||||
'2000000000' => array(
|
||||
'totp' => '69279037',
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
echo <<<DOCBLOCK
|
||||
<!DOCTYPE><html><head></head><body><pre>
|
||||
http://www.ietf.org/rfc/rfc4226.txt
|
||||
http://tools.ietf.org/html/draft-mraihi-totp-timebased-06
|
||||
|
||||
TEST VECTOR VERIFICATION
|
||||
|
||||
HOTP Tests:
|
||||
|
||||
DOCBLOCK;
|
||||
|
||||
echo "Count Method Value Pass/Fail\n";
|
||||
echo "----------------------------------------------------------------------\n";
|
||||
|
||||
// loop over all HOTP table results, and calculate the matching value
|
||||
foreach ($table['HOTP'] as $seed => $results) {
|
||||
$hotp = HOTP::generateByCounter($key, $seed);
|
||||
$first = true;
|
||||
foreach ($results as $type => $calc) {
|
||||
if ($first) {
|
||||
echo str_pad($seed, 4, ' ', STR_PAD_LEFT);
|
||||
$first = false;
|
||||
}
|
||||
else {
|
||||
echo ' ';
|
||||
}
|
||||
echo ' ';
|
||||
echo str_pad($type, 5, ' ', STR_PAD_RIGHT);
|
||||
echo ' ';
|
||||
echo str_pad($calc, 47, ' ', STR_PAD_RIGHT);
|
||||
echo ' ';
|
||||
$method = 'to'.(ucfirst(str_replace('HMAC', 'string', $type)));
|
||||
echo str_pad(($calc == $hotp->$method(6)) ? '[OK]' : '[FAIL]', 9, ' ', STR_PAD_LEFT);
|
||||
echo "\n";
|
||||
}
|
||||
}
|
||||
|
||||
echo <<<DOCBLOCK
|
||||
|
||||
TOTP Tests:
|
||||
|
||||
DOCBLOCK;
|
||||
|
||||
echo "Time (sec) Value Pass/Fail\n";
|
||||
echo "----------------------------------------------------------------------\n";
|
||||
|
||||
// now echo over the TOTP table
|
||||
foreach ($table['TOTP'] as $seed => $results) {
|
||||
$totp = HOTP::generateByTime($key, 30, $seed);
|
||||
$first = true;
|
||||
foreach ($results as $type => $calc) {
|
||||
if ($first) {
|
||||
echo str_pad($seed, 10, ' ', STR_PAD_LEFT);
|
||||
$first = false;
|
||||
}
|
||||
else {
|
||||
echo ' ';
|
||||
}
|
||||
echo ' ';
|
||||
echo str_pad($calc, 47, ' ', STR_PAD_RIGHT);
|
||||
echo ' ';
|
||||
$method = 'to'.(ucfirst(str_replace('totp', 'hotp', $type)));
|
||||
echo str_pad(($calc == $totp->$method(8)) ? '[OK]' : '[FAIL]', 9, ' ', STR_PAD_LEFT);
|
||||
echo "\n";
|
||||
}
|
||||
}
|
||||
|
||||
echo '</pre></body></html>';
|
||||
|
||||
+174
@@ -0,0 +1,174 @@
|
||||
<?php
|
||||
/**
|
||||
* HOTP Class
|
||||
* Based on the work of OAuth, and the sample implementation of HMAC OTP
|
||||
* http://tools.ietf.org/html/draft-mraihi-oath-hmac-otp-04#appendix-D
|
||||
* @author Jakob Heuser (firstname)@felocity.com
|
||||
* @copyright 2011
|
||||
* @license BSD
|
||||
* @version 1.0
|
||||
*/
|
||||
class HOTP {
|
||||
/**
|
||||
* Generate a HOTP key based on a counter value (event based HOTP)
|
||||
* @param string $key the key to use for hashing
|
||||
* @param int $counter the number of attempts represented in this hashing
|
||||
* @return HOTPResult a HOTP Result which can be truncated or output
|
||||
*/
|
||||
public static function generateByCounter($key, $counter) {
|
||||
// the counter value can be more than one byte long,
|
||||
// so we need to pack it down properly.
|
||||
$cur_counter = array(0, 0, 0, 0, 0, 0, 0, 0);
|
||||
for($i = 7; $i >= 0; $i--) {
|
||||
$cur_counter[$i] = pack ('C*', $counter);
|
||||
$counter = $counter >> 8;
|
||||
}
|
||||
|
||||
$bin_counter = implode($cur_counter);
|
||||
|
||||
// Pad to 8 chars
|
||||
if (strlen($bin_counter) < 8) {
|
||||
$bin_counter = str_repeat (chr(0), 8 - strlen ($bin_counter)) . $bin_counter;
|
||||
}
|
||||
|
||||
// HMAC
|
||||
$hash = hash_hmac('sha1', $bin_counter, $key);
|
||||
|
||||
return new HOTPResult($hash);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate a HOTP key based on a timestamp and window size
|
||||
* @param string $key the key to use for hashing
|
||||
* @param int $window the size of the window a key is valid for in seconds
|
||||
* @param int $timestamp a timestamp to calculate for, defaults to time()
|
||||
* @return HOTPResult a HOTP Result which can be truncated or output
|
||||
*/
|
||||
public static function generateByTime($key, $window, $timestamp = false) {
|
||||
if (!$timestamp && $timestamp !== 0) {
|
||||
$timestamp = HOTP::getTime();
|
||||
}
|
||||
|
||||
$counter = intval($timestamp / $window);
|
||||
|
||||
return HOTP::generateByCounter($key, $counter);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate a HOTP key collection based on a timestamp and window size
|
||||
* all keys that could exist between a start and end time will be included
|
||||
* in the returned array
|
||||
* @param string $key the key to use for hashing
|
||||
* @param int $window the size of the window a key is valid for in seconds
|
||||
* @param int $min the minimum window to accept before $timestamp
|
||||
* @param int $max the maximum window to accept after $timestamp
|
||||
* @param int $timestamp a timestamp to calculate for, defaults to time()
|
||||
* @return array of HOTPResult
|
||||
*/
|
||||
public static function generateByTimeWindow($key, $window, $min = -1, $max = 1, $timestamp = false) {
|
||||
if (!$timestamp && $timestamp !== 0) {
|
||||
$timestamp = HOTP::getTime();
|
||||
}
|
||||
|
||||
$counter = intval($timestamp / $window);
|
||||
$window = range($min, $max);
|
||||
|
||||
$out = array();
|
||||
for ($i = 0; $i < count($window); $i++) {
|
||||
$shift_counter = $window[$i];
|
||||
$out[$shift_counter] = HOTP::generateByCounter($key, $counter + $shift_counter);
|
||||
}
|
||||
|
||||
return $out;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the current time
|
||||
* Ensures we are operating in UTC for the entire framework
|
||||
* Restores the timezone on exit.
|
||||
* @return int the current time
|
||||
*/
|
||||
public static function getTime() {
|
||||
return time(); // PHP's time is always UTC
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The HOTPResult Class converts an HOTP item to various forms
|
||||
* Supported formats include hex, decimal, string, and HOTP
|
||||
* @author Jakob Heuser (firstname)@felocity.com
|
||||
*/
|
||||
class HOTPResult {
|
||||
protected $hash;
|
||||
protected $binary;
|
||||
protected $decimal;
|
||||
|
||||
/**
|
||||
* Build an HOTP Result
|
||||
* @param string $value the value to construct with
|
||||
*/
|
||||
public function __construct($value) {
|
||||
// store raw
|
||||
$this->hash = $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the string version of the HOTP
|
||||
* @return string
|
||||
*/
|
||||
public function toString() {
|
||||
return $this->hash;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the hex version of the HOTP
|
||||
* @return string
|
||||
*/
|
||||
public function toHex() {
|
||||
if( !$this->hex )
|
||||
{
|
||||
$this->hex = dechex($this->toDec());
|
||||
}
|
||||
return $this->hex;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the decimal version of the HOTP
|
||||
* @return int
|
||||
*/
|
||||
public function toDec() {
|
||||
if( !$this->decimal )
|
||||
{
|
||||
// store calculate decimal
|
||||
$hmac_result = array();
|
||||
|
||||
// Convert to decimal
|
||||
foreach(str_split($this->hash,2) as $hex)
|
||||
{
|
||||
$hmac_result[] = hexdec($hex);
|
||||
}
|
||||
|
||||
$offset = $hmac_result[19] & 0xf;
|
||||
|
||||
$this->decimal = (
|
||||
(($hmac_result[$offset+0] & 0x7f) << 24 ) |
|
||||
(($hmac_result[$offset+1] & 0xff) << 16 ) |
|
||||
(($hmac_result[$offset+2] & 0xff) << 8 ) |
|
||||
($hmac_result[$offset+3] & 0xff)
|
||||
);
|
||||
}
|
||||
return $this->decimal;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the truncated decimal form of the HOTP
|
||||
* @param int $length the length of the HOTP to return
|
||||
* @return string
|
||||
*/
|
||||
public function toHOTP($length) {
|
||||
$str = str_pad($this->toDec(), $length, "0", STR_PAD_LEFT);
|
||||
$str = substr($str, (-1 * $length));
|
||||
return $str;
|
||||
}
|
||||
|
||||
}
|
||||
Executable
+1034
File diff suppressed because it is too large
Load Diff
+1722
File diff suppressed because it is too large
Load Diff
+214
@@ -0,0 +1,214 @@
|
||||
<?php
|
||||
|
||||
if (!defined('ABSPATH')) die('Access denied.');
|
||||
|
||||
?><div id="simba-tfa-admin-wrapper" class="wrap">
|
||||
|
||||
<div>
|
||||
<h1><?php echo esc_html(empty($settings_page_heading) ? __('Two Factor Authentication - Admin Settings', 'all-in-one-wp-security-and-firewall') : $settings_page_heading); ?></h1>
|
||||
<?php
|
||||
if (!empty($admin_settings_links) && is_array($admin_settings_links)) {
|
||||
// phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- Escaping down in return value.
|
||||
echo implode(' | ', array_map(function($val) {
|
||||
return '<a href="'.esc_url($val['url']).'">' . esc_html($val['title']) . '</a>';
|
||||
}, $admin_settings_links));
|
||||
echo '<br>';
|
||||
}
|
||||
?>
|
||||
</div>
|
||||
|
||||
<?php $encryption_enabled = $simba_tfa->get_option('tfa_encrypt_secrets'); ?>
|
||||
|
||||
<?php if (defined('TWO_FACTOR_DISABLE') && TWO_FACTOR_DISABLE) { ?>
|
||||
<div class="error">
|
||||
<h3><?php esc_html_e('Two Factor Authentication currently disabled', 'all-in-one-wp-security-and-firewall');?></h3>
|
||||
<p>
|
||||
<?php esc_html_e('Two factor authentication is currently disabled via the TWO_FACTOR_DISABLE constant (which is mostly likely to be defined in your wp-config.php)', 'all-in-one-wp-security-and-firewall'); ?>
|
||||
</p>
|
||||
</div>
|
||||
<?php } ?>
|
||||
|
||||
<div style="max-width:800px;">
|
||||
|
||||
<?php
|
||||
if (is_multisite()) {
|
||||
if (is_super_admin()) {
|
||||
?>
|
||||
<p style="font-size: 120%; font-weight: bold;">
|
||||
<?php esc_html_e('N.B. These two-factor settings apply to your entire WordPress network. (i.e. They are not localised to one particular site).', 'all-in-one-wp-security-and-firewall');?>
|
||||
</p>
|
||||
<?php
|
||||
} else {
|
||||
// Should not be possible to reach this; but an extra check does not hurt.
|
||||
die('Security check');
|
||||
}
|
||||
}
|
||||
?>
|
||||
|
||||
<form method="post" action="options.php" style="margin-top: 12px">
|
||||
<?php settings_fields('tfa_user_roles_group'); ?>
|
||||
<h2><?php esc_html_e('Make two factor authentication available', 'all-in-one-wp-security-and-firewall'); ?></h2>
|
||||
<?php esc_html_e('Choose which user roles will have two factor authentication available.', 'all-in-one-wp-security-and-firewall'); ?>
|
||||
<p>
|
||||
<?php $simba_tfa->list_user_roles_checkboxes(); ?>
|
||||
</p>
|
||||
<?php submit_button(); ?>
|
||||
</form>
|
||||
|
||||
<hr>
|
||||
|
||||
<div class="tfa-premium">
|
||||
<h2><?php esc_html_e('Make two factor authentication compulsory', 'all-in-one-wp-security-and-firewall'); ?></h2>
|
||||
|
||||
<?php
|
||||
|
||||
$output = '<p><a href="' . esc_url($simba_tfa->get_premium_version_url()) . '">' . esc_html__('Requiring users to use two-factor authentication is a feature of the Premium version of this plugin.', 'all-in-one-wp-security-and-firewall').'</a><p>';
|
||||
echo apply_filters('simba_tfa_after_user_roles', $output); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- already escaped (and not suitable for kses since non-wordpress.org add-on adds HTML lists)
|
||||
|
||||
?>
|
||||
|
||||
<hr>
|
||||
<h2><?php esc_html_e('Trusted devices', 'all-in-one-wp-security-and-firewall'); ?></h2>
|
||||
|
||||
<form method="post" action="options.php" style="margin-top: 12px">
|
||||
<?php settings_fields('tfa_user_roles_trusted_group'); ?>
|
||||
<?php esc_html_e('Choose which user roles are permitted to mark devices they login on as trusted. This feature requires browser cookies and an https (i.e. SSL) connection to the website to work.', 'all-in-one-wp-security-and-firewall'); ?>
|
||||
|
||||
<?php
|
||||
$output = '<p><a href="' . esc_url($simba_tfa->get_premium_version_url()) . '">' . esc_html__('Allowing users to mark a device as trusted so that a two-factor code is only needed once in a specified number of days (instead of every login) is a feature of the Premium version of this plugin.', 'all-in-one-wp-security-and-firewall').'</a><p>';
|
||||
echo apply_filters('simba_tfa_trusted_devices_config', $output); //phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- Contains checkboxes, and content is already escaped during construction.
|
||||
|
||||
?>
|
||||
</form>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
<div>
|
||||
<hr>
|
||||
<form method="post" action="options.php" style="margin-top: 40px">
|
||||
<?php
|
||||
settings_fields('tfa_xmlrpc_status_group');
|
||||
?>
|
||||
<h2><?php esc_html_e('XMLRPC requests', 'all-in-one-wp-security-and-firewall'); ?></h2>
|
||||
<?php
|
||||
|
||||
echo '<p>';
|
||||
echo esc_html__("XMLRPC is a feature within WordPress allowing other computers to talk to your WordPress install. For example, it could be used by an app on your tablet that allows you to blog directly from the app (instead of needing the WordPress dashboard).", 'all-in-one-wp-security-and-firewall');
|
||||
echo '</p><p>';
|
||||
|
||||
echo esc_html__("Unfortunately, XMLRPC also provides a way for attackers to perform actions on your WordPress site, using only a password (i.e. without a two-factor password). More unfortunately, authors of legitimate programmes using XMLRPC have not yet added two-factor support to their code.", 'all-in-one-wp-security-and-firewall');
|
||||
echo '</p><p>';
|
||||
|
||||
echo esc_html__("i.e. XMLRPC requests coming in to WordPress (whether from a legitimate app, or from an attacker) can only be verified using the password - not with a two-factor code. As a result, there not be an ideal option to pick below. You may have to choose between the convenience of using your apps, or the security of two factor authentication.", 'all-in-one-wp-security-and-firewall');
|
||||
echo '</p>';
|
||||
|
||||
?>
|
||||
<p>
|
||||
<?php $simba_tfa->tfa_list_xmlrpc_status_radios(); ?>
|
||||
</p>
|
||||
<?php submit_button(); ?>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<div id="simba-tfa-admin-settings-algorithm">
|
||||
<hr>
|
||||
<form method="post" action="options.php" style="margin-top: 40px">
|
||||
<?php settings_fields('simba_tfa_default_hmac_group'); ?>
|
||||
<h2><?php esc_html_e('Default algorithm for codes generated by user devices', 'all-in-one-wp-security-and-firewall'); ?></h2>
|
||||
<?php esc_html_e('Your users can change this in their own settings if they want.', 'all-in-one-wp-security-and-firewall'); ?>
|
||||
<p>
|
||||
<?php
|
||||
$totp_controller->print_default_hmac_radios();
|
||||
?></p>
|
||||
<?php submit_button(); ?>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<div id="simba-tfa-admin-settings-encryption">
|
||||
<hr>
|
||||
<?php if ($encryption_enabled) { ?>
|
||||
<h2><?php esc_html_e('Encrypt keys in database', 'all-in-one-wp-security-and-firewall'); ?></h2>
|
||||
<p>
|
||||
<strong><?php echo esc_html__('Encryption of keys in the database has been enabled.', 'all-in-one-wp-security-and-firewall') . ' ' . esc_html__('This feature cannot be turned off.', 'all-in-one-wp-security-and-firewall'); ?></strong>
|
||||
</p>
|
||||
<?php } else { ?>
|
||||
<form method="post" action="options.php" style="margin-top: 40px">
|
||||
<?php settings_fields('simba_tfa_encrypt_secrets_group'); ?>
|
||||
<input type="hidden" name="tfa_encrypt_secrets" value="1">
|
||||
<h2><?php esc_html_e('Encrypt keys in database', 'all-in-one-wp-security-and-firewall'); ?></h2>
|
||||
<p>
|
||||
<b><?php esc_html_e('Once turned on, this feature cannot be turned off (but there is no technical reason why this should discourage you from using it).', 'all-in-one-wp-security-and-firewall'); ?></b>
|
||||
</p>
|
||||
<p>
|
||||
<?php esc_html_e('This feature will encrypt all two factor authentication secret keys stored in the database, using an encryption key that is stored on your disk.', 'all-in-one-wp-security-and-firewall'); ?>
|
||||
<?php esc_html_e("This means that in the event your database is compromised there's an additional layer of security (the attacker would need to compromise your on-disk data as well) protecting your two factor authentication secret keys.", 'all-in-one-wp-security-and-firewall'); ?>
|
||||
</p>
|
||||
<?php submit_button(__('Enable encryption of database keys', 'all-in-one-wp-security-and-firewall')); ?>
|
||||
</form>
|
||||
<?php } ?>
|
||||
</div>
|
||||
|
||||
<hr>
|
||||
|
||||
<?php
|
||||
if (function_exists('WC')) {
|
||||
|
||||
?>
|
||||
<br><br>
|
||||
<h2><?php esc_html_e("WooCommerce integration", 'all-in-one-wp-security-and-firewall'); ?></h2>
|
||||
<p>
|
||||
<?php echo apply_filters('simba_tfa_settings_woocommerce', '<a href="' . esc_url($simba_tfa->get_premium_version_url()) . '">' . esc_html__('The Premium version of this plugin allows you to add a configuration tab for users in the WooCommerce "My account" area, and anti-bot protection on the WooCommerce login form.', 'all-in-one-wp-security-and-firewall').'</a>'); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- already escaped, and contains checkboxes ?>
|
||||
</p>
|
||||
<hr>
|
||||
<?php } ?>
|
||||
|
||||
<br>
|
||||
|
||||
<div class="tfa-premium">
|
||||
<br>
|
||||
<h2><?php esc_html_e("Users' settings", 'all-in-one-wp-security-and-firewall'); ?></h2>
|
||||
<p>
|
||||
|
||||
<?php
|
||||
if (!class_exists('Simba_Two_Factor_Authentication_Premium')) { ?>
|
||||
|
||||
<a href="<?php echo esc_url($simba_tfa->get_premium_version_url()); ?>"><?php esc_html_e("The Premium version of this plugin allows you to see and reset the TFA settings of other users.", 'all-in-one-wp-security-and-firewall'); ?></a>
|
||||
|
||||
<a href="https://wordpress.org/plugins/user-switching/"><?php esc_html_e('Another way to do that is by using a user-switching plugin like this one.', 'all-in-one-wp-security-and-firewall'); ?></a>
|
||||
|
||||
<?php } ?>
|
||||
|
||||
<?php do_action('simba_tfa_users_settings'); ?>
|
||||
|
||||
<hr>
|
||||
<?php if (!class_exists('Simba_Two_Factor_Authentication_Premium')) { ?>
|
||||
<h2><?php esc_html_e('Premium version', 'all-in-one-wp-security-and-firewall'); ?></h2>
|
||||
<p>
|
||||
<a href="<?php echo esc_url($simba_tfa->get_premium_version_url()); ?>"><?php esc_html_e("If you want to say 'thank you' or help this plugin's development, or get extra features, then please take a look at the premium version of this plugin.", 'all-in-one-wp-security-and-firewall'); ?></a> <?php esc_html_e('It comes with these extra features:', 'all-in-one-wp-security-and-firewall');?><br>
|
||||
</p>
|
||||
<p>
|
||||
<ul style="list-style: disc inside;">
|
||||
<li><strong><?php esc_html_e('Emergency codes', 'all-in-one-wp-security-and-firewall');?></strong> - <?php esc_html_e('provide your users with one-time codes to use in case they lose their device.', 'all-in-one-wp-security-and-firewall');?></li>
|
||||
<li><strong><?php esc_html_e('Make TFA compulsory', 'all-in-one-wp-security-and-firewall');?></strong> - <?php esc_html_e('require your users to set up TFA to be able to log in, after an optional grace period.', 'all-in-one-wp-security-and-firewall');?></li>
|
||||
<li><strong><?php esc_html_e('Trusted devices', 'all-in-one-wp-security-and-firewall');?></strong> - <?php esc_html_e('allow privileged (or all) users to mark a device as trusted and thereby only needing to supply a TFA code upon login every so-many days (e.g. every 30 days) instead of on each login.', 'all-in-one-wp-security-and-firewall');?></li>
|
||||
<li><strong><?php esc_html_e('Manage all users centrally', 'all-in-one-wp-security-and-firewall');?></strong> - <?php esc_html_e('enable, disable or see TFA codes for all your users from one central location.', 'all-in-one-wp-security-and-firewall');?></li>
|
||||
<li><strong><?php esc_html_e('More shortcodes', 'all-in-one-wp-security-and-firewall');?></strong> - <?php esc_html_e('flexible shortcodes allowing you to design your front-end settings page for your users exactly as you wish.', 'all-in-one-wp-security-and-firewall');?></li>
|
||||
<li><strong><?php esc_html_e('More WooCommerce features', 'all-in-one-wp-security-and-firewall');?></strong> - <?php esc_html_e('automatically add TFA settings in the WooCommerce account settings, and WooCommerce login form bot protection.', 'all-in-one-wp-security-and-firewall');?></li>
|
||||
<li><strong><?php esc_html_e('Elementor support', 'all-in-one-wp-security-and-firewall');?></strong> - <?php esc_html_e('adds support for Elementor login forms.', 'all-in-one-wp-security-and-firewall');?></li>
|
||||
<li><strong><?php esc_html_e('Any-form support', 'all-in-one-wp-security-and-firewall');?></strong> - <?php esc_html_e('adds support for any login form from any plugin via appending your TFA code onto the end of your password.', 'all-in-one-wp-security-and-firewall');?></li>
|
||||
<li><strong><?php esc_html_e('Personal support', 'all-in-one-wp-security-and-firewall');?></strong> - <?php esc_html_e('access to our personal support desk for 12 months.', 'all-in-one-wp-security-and-firewall');?></li>
|
||||
</ul>
|
||||
</p>
|
||||
<hr>
|
||||
<?php } ?>
|
||||
</div>
|
||||
|
||||
<h2><?php esc_html_e('Translations', 'all-in-one-wp-security-and-firewall'); ?></h2>
|
||||
<p>
|
||||
<?php /* translators: %s: Plugin translation URL. */ ?>
|
||||
<?php echo sprintf(esc_html__("If you want to translate this plugin, please go to %s", 'all-in-one-wp-security-and-firewall'), '<a href="' . esc_url($simba_tfa->get_plugin_translate_url()) . '">' . esc_html__('the wordpress.org translation website.', 'all-in-one-wp-security-and-firewall').'</a>') . ' ' . esc_html__("Don't send us the translation file directly - plugin authors do not have access to the wordpress.org translation system (local language teams do).", 'all-in-one-wp-security-and-firewall'); ?>
|
||||
<br>
|
||||
</p>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
+30
@@ -0,0 +1,30 @@
|
||||
<p class="simba_tfa_personal_settings_notice simba_tfa_intro_notice">
|
||||
<?php
|
||||
|
||||
if (current_user_can($simba_tfa->get_management_capability())) {
|
||||
echo esc_html(apply_filters('simba_tfa_message_personal_settings', __('These are your personal settings.', 'all-in-one-wp-security-and-firewall') . ' ' . __('Nothing you change here will have any effect on other users.', 'all-in-one-wp-security-and-firewall')));
|
||||
}
|
||||
|
||||
if (is_multisite()) {
|
||||
if (is_super_admin()) {
|
||||
// Since WP 4.9
|
||||
$main_site_id = function_exists('get_main_site_id') ? get_main_site_id() : 1;
|
||||
$switched = switch_to_blog($main_site_id);
|
||||
echo ' <a href="' . esc_url($simba_tfa->get_site_wide_administration_url()) . '">' . esc_html__('The site-wide administration options are here.', 'all-in-one-wp-security-and-firewall').'</a>';
|
||||
if ($switched) restore_current_blog();
|
||||
}
|
||||
} elseif (current_user_can($simba_tfa->get_management_capability())) {
|
||||
echo ' <a href="' . esc_url($simba_tfa->get_site_wide_administration_url()) . '">' . esc_html__('The site-wide administration options are here.', 'all-in-one-wp-security-and-firewall').'</a>';
|
||||
}
|
||||
|
||||
?>
|
||||
</p>
|
||||
|
||||
<p class="simba_tfa_verify_tfa_notice simba_tfa_intro_notice"><strong>
|
||||
|
||||
<?php echo esc_html(apply_filters('simbatfa_message_you_should_verify', __('If you activate two-factor authentication, then verify that your two-factor application and this page show the same One-Time Password (within a minute of each other) before you log out.', 'all-in-one-wp-security-and-firewall'))); ?></strong>
|
||||
|
||||
<?php if (current_user_can($simba_tfa->get_management_capability())) { ?>
|
||||
<a href="<?php echo esc_url($simba_tfa->get_faq_url()); ?>"><?php esc_html_e('You should also bookmark the FAQs, which explain how to de-activate the plugin even if you cannot log in.', 'all-in-one-wp-security-and-firewall');?></a>
|
||||
<?php } ?>
|
||||
</p>
|
||||
+29
@@ -0,0 +1,29 @@
|
||||
<?php
|
||||
|
||||
if (!defined('ABSPATH')) die('No direct access.');
|
||||
|
||||
if (!$is_activated_for_user) {
|
||||
|
||||
global $current_user;
|
||||
echo empty($current_user->ID) ? '(' . esc_html__('Not logged in.', 'all-in-one-wp-security-and-firewall').')' : esc_html__('Two factor authentication is not available for your user.', 'all-in-one-wp-security-and-firewall');
|
||||
|
||||
} else {
|
||||
|
||||
?>
|
||||
|
||||
<div class="wrap" style="padding-bottom:10px">
|
||||
|
||||
<?php $simba_tfa->include_template('settings-intro-notices.php'); ?>
|
||||
|
||||
<?php $tfa_frontend->settings_enable_or_disable_output(); ?>
|
||||
|
||||
<?php $simba_tfa->get_controller('totp')->current_codes_box(); ?>
|
||||
|
||||
<?php if (!empty($show_algorithm_selector)) $simba_tfa->get_controller('totp')->advanced_settings_box(array($tfa_frontend, 'save_settings_button')); ?>
|
||||
|
||||
</div>
|
||||
|
||||
<?php $tfa_frontend->save_settings_javascript_output(); ?>
|
||||
|
||||
<?php
|
||||
}
|
||||
+29
@@ -0,0 +1,29 @@
|
||||
<?php if (!defined('ABSPATH')) die('No direct access.'); ?>
|
||||
|
||||
<div id="tfa_trusted_devices_box_inner">
|
||||
|
||||
<p><?php _e('Trusted devices are devices which have previously logged in with a second factor, belonging to users who have been permitted to mark devices as trusted, and for which the user checked the checkbox on the login form to trust the device.', 'all-in-one-wp-security-and-firewall'); ?></p>
|
||||
|
||||
<?php
|
||||
|
||||
global $current_user;
|
||||
|
||||
$trusted_devices = $this->user_get_trusted_devices($current_user->ID);
|
||||
|
||||
if (empty($trusted_devices)) {
|
||||
echo '<em>'.__('(none)', 'all-in-one-wp-security-and-firewall').'</em>';
|
||||
}
|
||||
|
||||
foreach ($trusted_devices as $device_id => $device) {
|
||||
|
||||
if (!isset($device['token']) || '' == $device['token']) continue;
|
||||
|
||||
$user_agent = empty($device['user_agent']) ? __('(unspecified)', 'all-in-one-wp-security-and-firewall'): $device['user_agent'];
|
||||
|
||||
echo '<span class="simbatfa_trusted_device">'.sprintf(__('User agent %s logged in from IP address %s and is trusted until %s', 'all-in-one-wp-security-and-firewall'), '<strong>'.htmlspecialchars($user_agent).'</strong>', '<strong><a target="_blank" href="https://ipinfo.io/'.$device['ip'].'">'.htmlspecialchars($device['ip']).'</a></strong>', '<strong>'.date_i18n(get_option('time_format').' '.get_option('date_format'), $device['until']).'</strong>').' - <a href="#" class="simbatfa-trust-remove" data-trusted-device-id="'.esc_attr($device_id).'">'.__('Remove trust', 'all-in-one-wp-security-and-firewall').'</a></span><br>';
|
||||
|
||||
}
|
||||
|
||||
?>
|
||||
|
||||
</div>
|
||||
+62
@@ -0,0 +1,62 @@
|
||||
<?php
|
||||
|
||||
if (!defined('ABSPATH')) die('Access denied.');
|
||||
|
||||
global $current_user;
|
||||
$totp_controller = $simba_tfa->get_controller('totp');
|
||||
|
||||
?>
|
||||
<style>
|
||||
#icon-tfa-plugin {
|
||||
background: transparent url('<?php print esc_url(plugin_dir_url(__FILE__)); ?>img/tfa_admin_icon_32x32.png' ) no-repeat;
|
||||
}
|
||||
.inside > h3, .normal {
|
||||
cursor: default;
|
||||
margin-top: 20px;
|
||||
}
|
||||
</style>
|
||||
<div class="wrap">
|
||||
|
||||
<h2><?php echo esc_html__('Two Factor Authentication', 'all-in-one-wp-security-and-firewall') . ' ' . esc_html__('Settings', 'all-in-one-wp-security-and-firewall'); ?></h2>
|
||||
|
||||
<?php
|
||||
|
||||
if (!empty($totp_controller->were_settings_saved())) {
|
||||
echo '<div class="updated notice is-dismissible">' . "<p><strong>" . esc_html__('Settings saved.', 'all-in-one-wp-security-and-firewall') . "</strong></p></div>";
|
||||
}
|
||||
|
||||
$simba_tfa->include_template('settings-intro-notices.php');
|
||||
|
||||
?>
|
||||
|
||||
<form method="post" action="<?php print esc_url(add_query_arg('settings-updated', 'true', isset($_SERVER['REQUEST_URI']) ? sanitize_url(wp_unslash($_SERVER['REQUEST_URI'])) : '')); ?>">
|
||||
|
||||
<?php wp_nonce_field('tfa_activate', '_tfa_activate_nonce', false, true); ?>
|
||||
|
||||
<h2><?php esc_html_e('Activate two factor authentication', 'all-in-one-wp-security-and-firewall'); ?></h2>
|
||||
<p>
|
||||
<?php
|
||||
$utc_date = gmdate('Y-m-d H:i:s');
|
||||
$date_now = get_date_from_gmt($utc_date, 'Y-m-d H:i:s');
|
||||
/* translators: 1. UTC date. 2. Now date. */
|
||||
echo sprintf(esc_html__('N.B. Getting your TFA app/device to generate the correct code depends upon a) you first setting it up by entering or scanning the code below into it, and b) upon your web-server and your TFA app/device agreeing upon the UTC time (within a minute or so). The current UTC time according to the server when this page loaded: %1$s, and in the time-zone you have configured in your WordPress settings: %2$s', 'all-in-one-wp-security-and-firewall'), esc_html($utc_date), esc_html($date_now));
|
||||
?>
|
||||
</p>
|
||||
<p>
|
||||
<?php
|
||||
$simba_tfa->paint_enable_tfa_radios($current_user->ID);
|
||||
?></p>
|
||||
<?php submit_button(); ?>
|
||||
</form>
|
||||
|
||||
<?php
|
||||
|
||||
$totp_controller->current_codes_box();
|
||||
|
||||
$totp_controller->advanced_settings_box();
|
||||
|
||||
do_action('simba_tfa_user_settings_after_advanced_settings');
|
||||
|
||||
?>
|
||||
|
||||
</div>
|
||||
Reference in New Issue
Block a user