"},m.createImgTag=function(r,t){r=r||2,t="undefined"==typeof t?4*r:t;var e=m.getModuleCount()*r+2*t,n=t,o=e-t;return v(e,e,function(t,e){if(t>=n&&o>t&&e>=n&&o>e){var i=Math.floor((t-n)/r),a=Math.floor((e-n)/r);return m.isDark(a,i)?0:1}return 1})},m};t.stringToBytes=function(r){for(var t=new Array,e=0;ei)t.push(i);else{var a=e[r.charAt(o)];"number"==typeof a?(255&a)==a?t.push(a):(t.push(a>>>8),t.push(255&a)):t.push(n)}}return t}};var e={MODE_NUMBER:1,MODE_ALPHA_NUM:2,MODE_8BIT_BYTE:4,MODE_KANJI:8},n={L:1,M:0,Q:3,H:2},o={PATTERN000:0,PATTERN001:1,PATTERN010:2,PATTERN011:3,PATTERN100:4,PATTERN101:5,PATTERN110:6,PATTERN111:7},i=function(){var t=[[],[6,18],[6,22],[6,26],[6,30],[6,34],[6,22,38],[6,24,42],[6,26,46],[6,28,50],[6,30,54],[6,32,58],[6,34,62],[6,26,46,66],[6,26,48,70],[6,26,50,74],[6,30,54,78],[6,30,56,82],[6,30,58,86],[6,34,62,90],[6,28,50,72,94],[6,26,50,74,98],[6,30,54,78,102],[6,28,54,80,106],[6,32,58,84,110],[6,30,58,86,114],[6,34,62,90,118],[6,26,50,74,98,122],[6,30,54,78,102,126],[6,26,52,78,104,130],[6,30,56,82,108,134],[6,34,60,86,112,138],[6,30,58,86,114,142],[6,34,62,90,118,146],[6,30,54,78,102,126,150],[6,24,50,76,102,128,154],[6,28,54,80,106,132,158],[6,32,58,84,110,136,162],[6,26,54,82,110,138,166],[6,30,58,86,114,142,170]],n=1335,i=7973,u=21522,f={},c=function(r){for(var t=0;0!=r;)t+=1,r>>>=1;return t};return f.getBCHTypeInfo=function(r){for(var t=r<<10;c(t)-c(n)>=0;)t^=n<=0;)t^=i<n;n+=1)e=e.multiply(r([1,a.gexp(n)],0));return e},f.getLengthInBits=function(r,t){if(t>=1&&10>t)switch(r){case e.MODE_NUMBER:return 10;case e.MODE_ALPHA_NUM:return 9;case e.MODE_8BIT_BYTE:return 8;case e.MODE_KANJI:return 8;default:throw new Error("mode:"+r)}else if(27>t)switch(r){case e.MODE_NUMBER:return 12;case e.MODE_ALPHA_NUM:return 11;case e.MODE_8BIT_BYTE:return 16;case e.MODE_KANJI:return 10;default:throw new Error("mode:"+r)}else{if(!(41>t))throw new Error("type:"+t);switch(r){case e.MODE_NUMBER:return 14;case e.MODE_ALPHA_NUM:return 13;case e.MODE_8BIT_BYTE:return 16;case e.MODE_KANJI:return 12;default:throw new Error("mode:"+r)}}},f.getLostPoint=function(r){for(var t=r.getModuleCount(),e=0,n=0;t>n;n+=1)for(var o=0;t>o;o+=1){for(var i=0,a=r.isDark(n,o),u=-1;1>=u;u+=1)if(!(0>n+u||n+u>=t))for(var f=-1;1>=f;f+=1)0>o+f||o+f>=t||(0!=u||0!=f)&&a==r.isDark(n+u,o+f)&&(i+=1);i>5&&(e+=3+i-5)}for(var n=0;t-1>n;n+=1)for(var o=0;t-1>o;o+=1){var c=0;r.isDark(n,o)&&(c+=1),r.isDark(n+1,o)&&(c+=1),r.isDark(n,o+1)&&(c+=1),r.isDark(n+1,o+1)&&(c+=1),(0==c||4==c)&&(e+=3)}for(var n=0;t>n;n+=1)for(var o=0;t-6>o;o+=1)r.isDark(n,o)&&!r.isDark(n,o+1)&&r.isDark(n,o+2)&&r.isDark(n,o+3)&&r.isDark(n,o+4)&&!r.isDark(n,o+5)&&r.isDark(n,o+6)&&(e+=40);for(var o=0;t>o;o+=1)for(var n=0;t-6>n;n+=1)r.isDark(n,o)&&!r.isDark(n+1,o)&&r.isDark(n+2,o)&&r.isDark(n+3,o)&&r.isDark(n+4,o)&&!r.isDark(n+5,o)&&r.isDark(n+6,o)&&(e+=40);for(var l=0,o=0;t>o;o+=1)for(var n=0;t>n;n+=1)r.isDark(n,o)&&(l+=1);var g=Math.abs(100*l/t/t-50)/5;return e+=10*g},f}(),a=function(){for(var r=new Array(256),t=new Array(256),e=0;8>e;e+=1)r[e]=1<e;e+=1)r[e]=r[e-4]^r[e-5]^r[e-6]^r[e-8];for(var e=0;255>e;e+=1)t[r[e]]=e;var n={};return n.glog=function(r){if(1>r)throw new Error("glog("+r+")");return t[r]},n.gexp=function(t){for(;0>t;)t+=255;for(;t>=256;)t-=255;return r[t]},n}(),u=function(){var r=[[1,26,19],[1,26,16],[1,26,13],[1,26,9],[1,44,34],[1,44,28],[1,44,22],[1,44,16],[1,70,55],[1,70,44],[2,35,17],[2,35,13],[1,100,80],[2,50,32],[2,50,24],[4,25,9],[1,134,108],[2,67,43],[2,33,15,2,34,16],[2,33,11,2,34,12],[2,86,68],[4,43,27],[4,43,19],[4,43,15],[2,98,78],[4,49,31],[2,32,14,4,33,15],[4,39,13,1,40,14],[2,121,97],[2,60,38,2,61,39],[4,40,18,2,41,19],[4,40,14,2,41,15],[2,146,116],[3,58,36,2,59,37],[4,36,16,4,37,17],[4,36,12,4,37,13],[2,86,68,2,87,69],[4,69,43,1,70,44],[6,43,19,2,44,20],[6,43,15,2,44,16],[4,101,81],[1,80,50,4,81,51],[4,50,22,4,51,23],[3,36,12,8,37,13],[2,116,92,2,117,93],[6,58,36,2,59,37],[4,46,20,6,47,21],[7,42,14,4,43,15],[4,133,107],[8,59,37,1,60,38],[8,44,20,4,45,21],[12,33,11,4,34,12],[3,145,115,1,146,116],[4,64,40,5,65,41],[11,36,16,5,37,17],[11,36,12,5,37,13],[5,109,87,1,110,88],[5,65,41,5,66,42],[5,54,24,7,55,25],[11,36,12,7,37,13],[5,122,98,1,123,99],[7,73,45,3,74,46],[15,43,19,2,44,20],[3,45,15,13,46,16],[1,135,107,5,136,108],[10,74,46,1,75,47],[1,50,22,15,51,23],[2,42,14,17,43,15],[5,150,120,1,151,121],[9,69,43,4,70,44],[17,50,22,1,51,23],[2,42,14,19,43,15],[3,141,113,4,142,114],[3,70,44,11,71,45],[17,47,21,4,48,22],[9,39,13,16,40,14],[3,135,107,5,136,108],[3,67,41,13,68,42],[15,54,24,5,55,25],[15,43,15,10,44,16],[4,144,116,4,145,117],[17,68,42],[17,50,22,6,51,23],[19,46,16,6,47,17],[2,139,111,7,140,112],[17,74,46],[7,54,24,16,55,25],[34,37,13],[4,151,121,5,152,122],[4,75,47,14,76,48],[11,54,24,14,55,25],[16,45,15,14,46,16],[6,147,117,4,148,118],[6,73,45,14,74,46],[11,54,24,16,55,25],[30,46,16,2,47,17],[8,132,106,4,133,107],[8,75,47,13,76,48],[7,54,24,22,55,25],[22,45,15,13,46,16],[10,142,114,2,143,115],[19,74,46,4,75,47],[28,50,22,6,51,23],[33,46,16,4,47,17],[8,152,122,4,153,123],[22,73,45,3,74,46],[8,53,23,26,54,24],[12,45,15,28,46,16],[3,147,117,10,148,118],[3,73,45,23,74,46],[4,54,24,31,55,25],[11,45,15,31,46,16],[7,146,116,7,147,117],[21,73,45,7,74,46],[1,53,23,37,54,24],[19,45,15,26,46,16],[5,145,115,10,146,116],[19,75,47,10,76,48],[15,54,24,25,55,25],[23,45,15,25,46,16],[13,145,115,3,146,116],[2,74,46,29,75,47],[42,54,24,1,55,25],[23,45,15,28,46,16],[17,145,115],[10,74,46,23,75,47],[10,54,24,35,55,25],[19,45,15,35,46,16],[17,145,115,1,146,116],[14,74,46,21,75,47],[29,54,24,19,55,25],[11,45,15,46,46,16],[13,145,115,6,146,116],[14,74,46,23,75,47],[44,54,24,7,55,25],[59,46,16,1,47,17],[12,151,121,7,152,122],[12,75,47,26,76,48],[39,54,24,14,55,25],[22,45,15,41,46,16],[6,151,121,14,152,122],[6,75,47,34,76,48],[46,54,24,10,55,25],[2,45,15,64,46,16],[17,152,122,4,153,123],[29,74,46,14,75,47],[49,54,24,10,55,25],[24,45,15,46,46,16],[4,152,122,18,153,123],[13,74,46,32,75,47],[48,54,24,14,55,25],[42,45,15,32,46,16],[20,147,117,4,148,118],[40,75,47,7,76,48],[43,54,24,22,55,25],[10,45,15,67,46,16],[19,148,118,6,149,119],[18,75,47,31,76,48],[34,54,24,34,55,25],[20,45,15,61,46,16]],t=function(r,t){var e={};return e.totalCount=r,e.dataCount=t,e},e={},o=function(t,e){switch(e){case n.L:return r[4*(t-1)+0];case n.M:return r[4*(t-1)+1];case n.Q:return r[4*(t-1)+2];case n.H:return r[4*(t-1)+3];default:return void 0}};return e.getRSBlocks=function(r,e){var n=o(r,e);if("undefined"==typeof n)throw new Error("bad rs block @ typeNumber:"+r+"/errorCorrectLevel:"+e);for(var i=n.length/3,a=new Array,u=0;i>u;u+=1)for(var f=n[3*u+0],c=n[3*u+1],l=n[3*u+2],g=0;f>g;g+=1)a.push(t(c,l));return a},e}(),f=function(){var r=new Array,t=0,e={};return e.getBuffer=function(){return r},e.getAt=function(t){var e=Math.floor(t/8);return 1==(r[e]>>>7-t%8&1)},e.put=function(r,t){for(var n=0;t>n;n+=1)e.putBit(1==(r>>>t-n-1&1))},e.getLengthInBits=function(){return t},e.putBit=function(e){var n=Math.floor(t/8);r.length<=n&&r.push(0),e&&(r[n]|=128>>>t%8),t+=1},e},c=function(r){var n=e.MODE_8BIT_BYTE,o=t.stringToBytes(r),i={};return i.getMode=function(){return n},i.getLength=function(r){return o.length},i.write=function(r){for(var t=0;t>>8)},t.writeBytes=function(r,e,n){e=e||0,n=n||r.length;for(var o=0;n>o;o+=1)t.writeByte(r[o+e])},t.writeString=function(r){for(var e=0;e0&&(t+=","),t+=r[e];return t+="]"},t},g=function(){var r=0,t=0,e=0,n="",o={},i=function(r){n+=String.fromCharCode(a(63&r))},a=function(r){if(0>r);else{if(26>r)return 65+r;if(52>r)return 97+(r-26);if(62>r)return 48+(r-52);if(62==r)return 43;if(63==r)return 47}throw new Error("n:"+r)};return o.writeByte=function(n){for(r=r<<8|255&n,t+=8,e+=1;t>=6;)i(r>>>t-6),t-=6},o.flush=function(){if(t>0&&(i(r<<6-t),r=0,t=0),e%3!=0)for(var o=3-e%3,a=0;o>a;a+=1)n+="="},o.toString=function(){return n},o},s=function(r){var t=r,e=0,n=0,o=0,i={};i.read=function(){for(;8>o;){if(e>=t.length){if(0==o)return-1;throw new Error("unexpected end of file./"+o)}var r=t.charAt(e);if(e+=1,"="==r)return o=0,-1;r.match(/^\s$/)||(n=n<<6|a(r.charCodeAt(0)),o+=6)}var i=n>>>o-8&255;return o-=8,i};var a=function(r){if(r>=65&&90>=r)return r-65;if(r>=97&&122>=r)return r-97+26;if(r>=48&&57>=r)return r-48+52;if(43==r)return 62;if(47==r)return 63;throw new Error("c:"+r)};return i},h=function(r,t){var e=r,n=t,o=new Array(r*t),i={};i.setPixel=function(r,t,n){o[t*e+r]=n},i.write=function(r){r.writeString("GIF87a"),r.writeShort(e),r.writeShort(n),r.writeByte(128),r.writeByte(0),r.writeByte(0),r.writeByte(0),r.writeByte(0),r.writeByte(0),r.writeByte(255),r.writeByte(255),r.writeByte(255),r.writeString(","),r.writeShort(0),r.writeShort(0),r.writeShort(e),r.writeShort(n),r.writeByte(0);var t=2,o=u(t);r.writeByte(t);for(var i=0;o.length-i>255;)r.writeByte(255),r.writeBytes(o,i,255),i+=255;r.writeByte(o.length-i),r.writeBytes(o,i,o.length-i),r.writeByte(0),r.writeString(";")};var a=function(r){var t=r,e=0,n=0,o={};return o.write=function(r,o){if(r>>>o!=0)throw new Error("length over");for(;e+o>=8;)t.writeByte(255&(r<>>=8-e,n=0,e=0;n=r<0&&t.writeByte(n)},o},u=function(r){for(var t=1<u;u+=1)i.add(String.fromCharCode(u));i.add(String.fromCharCode(t)),i.add(String.fromCharCode(e));var c=l(),g=a(c);g.write(t,n);var s=0,h=String.fromCharCode(o[s]);for(s+=1;si;i+=1)for(var a=0;r>a;a+=1)o.setPixel(a,i,e(a,i));var u=l();o.write(u);for(var f=g(),c=u.toByteArray(),s=0;s"};return t}();return function(r){"function"==typeof define&&define.amd?define([],r):"object"==typeof exports&&(module.exports=r())}(function(){return r}),!function(r){r.stringToBytes=function(r){function t(r){for(var t=[],e=0;en?t.push(n):2048>n?t.push(192|n>>6,128|63&n):55296>n||n>=57344?t.push(224|n>>12,128|n>>6&63,128|63&n):(e++,n=65536+((1023&n)<<10|1023&r.charCodeAt(e)),t.push(240|n>>18,128|n>>12&63,128|n>>6&63,128|63&n))}return t}return t(r)}}(r),r}()); assets/js/multi-recaptcha.js 0000644 00000003152 14757772106 0012123 0 ustar 00 ;;;
// WooCommerce Registration form
jQuery(document).ready(function(){
show_lz_multi_cap();
});
function captcha_v2_invisible_process(el){
grecaptcha.ready(function() {
var cap_div_id = grecaptcha.render(el,{
'sitekey': lz_cap_sitekey, 'size': 'invisible',
'callback' : function (recaptchaToken) { },
'expired-callback' : function(){grecaptcha.reset(cap_div_id);}
});
grecaptcha.execute(cap_div_id);
});
}
function show_lz_multi_cap(){
if(typeof grecaptcha == 'undefined'){
setTimeout(function(){show_lz_multi_cap()}, 1000);
return;
}
// reCAPTCHA v2 tick box
jQuery('.lz-recaptcha').each(function(index, el) {
// Get the sitekey
var lz_cap_key = jQuery(this).attr('data-sitekey');
//alert(lz_cap_key);
// Render it
try{
grecaptcha.render(el, {'sitekey' : lz_cap_key});
}catch(e){}
});
// reCAPTCHA v2 invisible
if(typeof lz_cap_invisible !== 'undefined' && lz_cap_invisible == 1 && typeof lz_cap_ver !== 'undefined' && lz_cap_ver == 2){
for (var i = 0; i < document.forms.length; ++i) {
var form = document.forms[i];
var cap_div = form.querySelector("."+lz_cap_div_class);
if (null === cap_div) continue;
cap_div.innerHTML = '';
captcha_v2_invisible_process(cap_div);
}
}
// reCAPTCHA v3
if(typeof lz_cap_ver !== 'undefined' && lz_cap_ver == 3){
grecaptcha.ready(function() {
grecaptcha.execute(lz_cap_sitekey, {action: lz_cap_page_type}).then(function(token) {
// pass the token to the backend script for verification
jQuery(".lz-v3-input").each(function() {
jQuery(this).val(token);
});
});
});
}
} lib/hybridauth/Provider/TwitchTV.php 0000644 00000003742 14757772106 0013522 0 ustar 00 apiRequestHeaders['Client-ID'] = $this->clientId;
}
/**
* {@inheritdoc}
*/
public function getUserProfile()
{
$response = $this->apiRequest('users');
$data = new Data\Collection($response);
if (!$data->exists('data')) {
throw new UnexpectedApiResponseException('Provider API returned an unexpected response.');
}
$users = $data->filter('data')->values();
$user = new Data\Collection($users[0]);
$userProfile = new User\Profile();
$userProfile->identifier = $user->get('id');
$userProfile->displayName = $user->get('display_name');
$userProfile->photoURL = $user->get('profile_image_url');
$userProfile->email = $user->get('email');
$userProfile->description = strip_tags($user->get('description'));
$userProfile->profileURL = "https://www.twitch.tv/{$userProfile->displayName}";
return $userProfile;
}
}
lib/hybridauth/Provider/Twitter.php 0000644 00000017147 14757772106 0013454 0 ustar 00 Hybridauth\HttpClient\Util::getCurrentUrl(),
* 'keys' => ['key' => '', 'secret' => ''], // OAuth1 uses 'key' not 'id'
* 'authorize' => true // Needed to perform actions on behalf of users (see below link)
* // https://developer.twitter.com/en/docs/authentication/oauth-1-0a/obtaining-user-access-tokens
* ];
*
* $adapter = new Hybridauth\Provider\Twitter($config);
*
* try {
* $adapter->authenticate();
*
* $userProfile = $adapter->getUserProfile();
* $tokens = $adapter->getAccessToken();
* $contacts = $adapter->getUserContacts(['screen_name' =>'andypiper']); // get those of @andypiper
* $activity = $adapter->getUserActivity('me');
* } catch (\Exception $e) {
* echo $e->getMessage() ;
* }
*/
class Twitter extends OAuth1
{
/**
* {@inheritdoc}
*/
protected $apiBaseUrl = 'https://api.twitter.com/1.1/';
/**
* {@inheritdoc}
*/
protected $authorizeUrl = 'https://api.twitter.com/oauth/authenticate';
/**
* {@inheritdoc}
*/
protected $requestTokenUrl = 'https://api.twitter.com/oauth/request_token';
/**
* {@inheritdoc}
*/
protected $accessTokenUrl = 'https://api.twitter.com/oauth/access_token';
/**
* {@inheritdoc}
*/
protected $apiDocumentation = 'https://dev.twitter.com/web/sign-in/implementing';
/**
* {@inheritdoc}
*/
protected function getAuthorizeUrl($parameters = [])
{
if ($this->config->get('authorize') === true) {
$this->authorizeUrl = 'https://api.twitter.com/oauth/authorize';
}
return parent::getAuthorizeUrl($parameters);
}
/**
* {@inheritdoc}
*/
public function getUserProfile()
{
$response = $this->apiRequest('account/verify_credentials.json', 'GET', [
'include_email' => $this->config->get('include_email') === false ? 'false' : 'true',
]);
$data = new Data\Collection($response);
if (!$data->exists('id_str')) {
throw new UnexpectedApiResponseException('Provider API returned an unexpected response.');
}
$userProfile = new User\Profile();
$userProfile->identifier = $data->get('id_str');
$userProfile->displayName = $data->get('screen_name');
$userProfile->description = $data->get('description');
$userProfile->firstName = $data->get('name');
$userProfile->email = $data->get('email');
$userProfile->emailVerified = $data->get('email');
$userProfile->webSiteURL = $data->get('url');
$userProfile->region = $data->get('location');
$userProfile->profileURL = $data->exists('screen_name')
? ('https://twitter.com/' . $data->get('screen_name'))
: '';
$photoSize = $this->config->get('photo_size') ?: 'original';
$photoSize = $photoSize === 'original' ? '' : "_{$photoSize}";
$userProfile->photoURL = $data->exists('profile_image_url_https')
? str_replace('_normal', $photoSize, $data->get('profile_image_url_https'))
: '';
$userProfile->data = [
'followed_by' => $data->get('followers_count'),
'follows' => $data->get('friends_count'),
];
return $userProfile;
}
/**
* {@inheritdoc}
*/
public function getUserContacts($parameters = [])
{
$parameters = ['cursor' => '-1'] + $parameters;
$response = $this->apiRequest('friends/ids.json', 'GET', $parameters);
$data = new Data\Collection($response);
if (!$data->exists('ids')) {
throw new UnexpectedApiResponseException('Provider API returned an unexpected response.');
}
if ($data->filter('ids')->isEmpty()) {
return [];
}
$contacts = [];
// 75 id per time should be okey
$contactsIds = array_chunk((array)$data->get('ids'), 75);
foreach ($contactsIds as $chunk) {
$parameters = ['user_id' => implode(',', $chunk)];
try {
$response = $this->apiRequest('users/lookup.json', 'GET', $parameters);
if ($response && count($response)) {
foreach ($response as $item) {
$contacts[] = $this->fetchUserContact($item);
}
}
} catch (\Exception $e) {
continue;
}
}
return $contacts;
}
/**
* @param $item
*
* @return User\Contact
*/
protected function fetchUserContact($item)
{
$item = new Data\Collection($item);
$userContact = new User\Contact();
$userContact->identifier = $item->get('id_str');
$userContact->displayName = $item->get('name');
$userContact->photoURL = $item->get('profile_image_url');
$userContact->description = $item->get('description');
$userContact->profileURL = $item->exists('screen_name')
? ('https://twitter.com/' . $item->get('screen_name'))
: '';
return $userContact;
}
/**
* {@inheritdoc}
*/
public function setUserStatus($status)
{
if (is_string($status)) {
$status = ['status' => $status];
}
// Prepare request parameters.
$params = [];
if (isset($status['status'])) {
$params['status'] = $status['status'];
}
if (isset($status['picture'])) {
$media = $this->apiRequest('https://upload.twitter.com/1.1/media/upload.json', 'POST', [
'media' => base64_encode(file_get_contents($status['picture'])),
]);
$params['media_ids'] = $media->media_id;
}
$response = $this->apiRequest('statuses/update.json', 'POST', $params);
return $response;
}
/**
* {@inheritdoc}
*/
public function getUserActivity($stream = 'me')
{
$apiUrl = ($stream == 'me')
? 'statuses/user_timeline.json'
: 'statuses/home_timeline.json';
$response = $this->apiRequest($apiUrl);
if (!$response) {
return [];
}
$activities = [];
foreach ($response as $item) {
$activities[] = $this->fetchUserActivity($item);
}
return $activities;
}
/**
* @param $item
* @return User\Activity
*/
protected function fetchUserActivity($item)
{
$item = new Data\Collection($item);
$userActivity = new User\Activity();
$userActivity->id = $item->get('id_str');
$userActivity->date = $item->get('created_at');
$userActivity->text = $item->get('text');
$userActivity->user->identifier = $item->filter('user')->get('id_str');
$userActivity->user->displayName = $item->filter('user')->get('name');
$userActivity->user->photoURL = $item->filter('user')->get('profile_image_url');
$userActivity->user->profileURL = $item->filter('user')->get('screen_name')
? ('https://twitter.com/' . $item->filter('user')->get('screen_name'))
: '';
return $userActivity;
}
}
lib/hybridauth/Provider/Google.php 0000644 00000013247 14757772106 0013223 0 ustar 00 Hybridauth\HttpClient\Util::getCurrentUrl(),
* 'keys' => ['id' => '', 'secret' => ''],
* 'scope' => 'https://www.googleapis.com/auth/userinfo.profile',
*
* // google's custom auth url params
* 'authorize_url_parameters' => [
* 'approval_prompt' => 'force', // to pass only when you need to acquire a new refresh token.
* 'access_type' => .., // is set to 'offline' by default
* 'hd' => ..,
* 'state' => ..,
* // etc.
* ]
* ];
*
* $adapter = new Hybridauth\Provider\Google($config);
*
* try {
* $adapter->authenticate();
*
* $userProfile = $adapter->getUserProfile();
* $tokens = $adapter->getAccessToken();
* $contacts = $adapter->getUserContacts(['max-results' => 75]);
* } catch (\Exception $e) {
* echo $e->getMessage() ;
* }
*/
class Google extends OAuth2
{
/**
* {@inheritdoc}
*/
// phpcs:ignore
protected $scope = 'https://www.googleapis.com/auth/userinfo.profile https://www.googleapis.com/auth/userinfo.email';
/**
* {@inheritdoc}
*/
protected $apiBaseUrl = 'https://www.googleapis.com/';
/**
* {@inheritdoc}
*/
protected $authorizeUrl = 'https://accounts.google.com/o/oauth2/v2/auth';
/**
* {@inheritdoc}
*/
protected $accessTokenUrl = 'https://oauth2.googleapis.com/token';
/**
* {@inheritdoc}
*/
protected $apiDocumentation = 'https://developers.google.com/identity/protocols/OAuth2';
/**
* {@inheritdoc}
*/
protected function initialize()
{
parent::initialize();
$this->AuthorizeUrlParameters += [
'access_type' => 'offline'
];
if ($this->isRefreshTokenAvailable()) {
$this->tokenRefreshParameters += [
'client_id' => $this->clientId,
'client_secret' => $this->clientSecret
];
}
}
/**
* {@inheritdoc}
*
* See: https://developers.google.com/identity/protocols/OpenIDConnect#obtainuserinfo
*/
public function getUserProfile()
{
$response = $this->apiRequest('oauth2/v3/userinfo');
$data = new Data\Collection($response);
if (!$data->exists('sub')) {
throw new UnexpectedApiResponseException('Provider API returned an unexpected response.');
}
$userProfile = new User\Profile();
$userProfile->identifier = $data->get('sub');
$userProfile->firstName = $data->get('given_name');
$userProfile->lastName = $data->get('family_name');
$userProfile->displayName = $data->get('name');
$userProfile->photoURL = $data->get('picture');
$userProfile->profileURL = $data->get('profile');
$userProfile->gender = $data->get('gender');
$userProfile->language = $data->get('locale');
$userProfile->email = $data->get('email');
$userProfile->emailVerified = $data->get('email_verified') ? $userProfile->email : '';
if ($this->config->get('photo_size')) {
$userProfile->photoURL .= '?sz=' . $this->config->get('photo_size');
}
return $userProfile;
}
/**
* {@inheritdoc}
*/
public function getUserContacts($parameters = [])
{
$parameters = ['max-results' => 500] + $parameters;
// Google Gmail and Android contacts
if (false !== strpos($this->scope, '/m8/feeds/') || false !== strpos($this->scope, '/auth/contacts.readonly')) {
return $this->getGmailContacts($parameters);
}
return [];
}
/**
* Retrieve Gmail contacts
*
* @param array $parameters
*
* @return array
*
* @throws \Exception
*/
protected function getGmailContacts($parameters = [])
{
$url = 'https://www.google.com/m8/feeds/contacts/default/full?'
. http_build_query(array_replace(['alt' => 'json', 'v' => '3.0'], (array)$parameters));
$response = $this->apiRequest($url);
if (!$response) {
return [];
}
$contacts = [];
if (isset($response->feed->entry)) {
foreach ($response->feed->entry as $idx => $entry) {
$uc = new User\Contact();
$uc->email = isset($entry->{'gd$email'}[0]->address)
? (string)$entry->{'gd$email'}[0]->address
: '';
$uc->displayName = isset($entry->title->{'$t'}) ? (string)$entry->title->{'$t'} : '';
$uc->identifier = ($uc->email != '') ? $uc->email : '';
$uc->description = '';
if (property_exists($response, 'website')) {
if (is_array($response->website)) {
foreach ($response->website as $w) {
if ($w->primary == true) {
$uc->webSiteURL = $w->value;
}
}
} else {
$uc->webSiteURL = $response->website->value;
}
} else {
$uc->webSiteURL = '';
}
$contacts[] = $uc;
}
}
return $contacts;
}
}
lib/hybridauth/Provider/WordPress.php 0000644 00000003445 14757772106 0013736 0 ustar 00 apiRequest('me/');
$data = new Data\Collection($response);
if (!$data->exists('ID')) {
throw new UnexpectedApiResponseException('Provider API returned an unexpected response.');
}
$userProfile = new User\Profile();
$userProfile->identifier = $data->get('ID');
$userProfile->displayName = $data->get('display_name');
$userProfile->photoURL = $data->get('avatar_URL');
$userProfile->profileURL = $data->get('profile_URL');
$userProfile->email = $data->get('email');
$userProfile->language = $data->get('language');
$userProfile->displayName = $userProfile->displayName ?: $data->get('username');
$userProfile->emailVerified = $data->get('email_verified') ? $data->get('email') : '';
return $userProfile;
}
}
lib/hybridauth/Provider/Facebook.php 0000644 00000032157 14757772106 0013521 0 ustar 00 Hybridauth\HttpClient\Util::getCurrentUrl(),
* 'keys' => ['id' => '', 'secret' => ''],
* 'scope' => 'email, user_status, user_posts',
* 'exchange_by_expiry_days' => 45, // null for no token exchange
* ];
*
* $adapter = new Hybridauth\Provider\Facebook($config);
*
* try {
* $adapter->authenticate();
*
* $userProfile = $adapter->getUserProfile();
* $tokens = $adapter->getAccessToken();
* $response = $adapter->setUserStatus("Hybridauth test message..");
* } catch (\Exception $e) {
* echo $e->getMessage() ;
* }
*/
class Facebook extends OAuth2
{
/**
* {@inheritdoc}
*/
protected $scope = 'email, public_profile';
/**
* {@inheritdoc}
*/
protected $apiBaseUrl = 'https://graph.facebook.com/v8.0/';
/**
* {@inheritdoc}
*/
protected $authorizeUrl = 'https://www.facebook.com/dialog/oauth';
/**
* {@inheritdoc}
*/
protected $accessTokenUrl = 'https://graph.facebook.com/oauth/access_token';
/**
* {@inheritdoc}
*/
protected $apiDocumentation = 'https://developers.facebook.com/docs/facebook-login/overview';
/**
* @var string Profile URL template as the fallback when no `link` returned from the API.
*/
protected $profileUrlTemplate = 'https://www.facebook.com/%s';
/**
* {@inheritdoc}
*/
protected function initialize()
{
parent::initialize();
// Require proof on all Facebook api calls
// https://developers.facebook.com/docs/graph-api/securing-requests#appsecret_proof
if ($accessToken = $this->getStoredData('access_token')) {
$this->apiRequestParameters['appsecret_proof'] = hash_hmac('sha256', $accessToken, $this->clientSecret);
}
}
/**
* {@inheritdoc}
*/
public function maintainToken()
{
if (!$this->isConnected()) {
return;
}
// Handle token exchange prior to the standard handler for an API request
$exchange_by_expiry_days = $this->config->get('exchange_by_expiry_days') ?: 45;
if ($exchange_by_expiry_days !== null) {
$projected_timestamp = time() + 60 * 60 * 24 * $exchange_by_expiry_days;
if (!$this->hasAccessTokenExpired() && $this->hasAccessTokenExpired($projected_timestamp)) {
$this->exchangeAccessToken();
}
}
}
/**
* Exchange the Access Token with one that expires further in the future.
*
* @return string Raw Provider API response
* @throws \Hybridauth\Exception\HttpClientFailureException
* @throws \Hybridauth\Exception\HttpRequestFailedException
* @throws \Hybridauth\Exception\InvalidAccessTokenException
*/
public function exchangeAccessToken()
{
$exchangeTokenParameters = [
'grant_type' => 'fb_exchange_token',
'client_id' => $this->clientId,
'client_secret' => $this->clientSecret,
'fb_exchange_token' => $this->getStoredData('access_token'),
];
$response = $this->httpClient->request(
$this->accessTokenUrl,
'GET',
$exchangeTokenParameters
);
$this->validateApiResponse('Unable to exchange the access token');
$this->validateAccessTokenExchange($response);
return $response;
}
/**
* {@inheritdoc}
*/
public function getUserProfile()
{
$fields = [
'id',
'name',
'first_name',
'last_name',
'website',
'locale',
'about',
'email',
'hometown',
'birthday',
];
if (strpos($this->scope, 'user_link') !== false) {
$fields[] = 'link';
}
if (strpos($this->scope, 'user_gender') !== false) {
$fields[] = 'gender';
}
// Note that en_US is needed for gender fields to match convention.
$locale = $this->config->get('locale') ?: 'en_US';
$response = $this->apiRequest('me', 'GET', [
'fields' => implode(',', $fields),
'locale' => $locale,
]);
$data = new Data\Collection($response);
if (!$data->exists('id')) {
throw new UnexpectedApiResponseException('Provider API returned an unexpected response.');
}
$userProfile = new User\Profile();
$userProfile->identifier = $data->get('id');
$userProfile->displayName = $data->get('name');
$userProfile->firstName = $data->get('first_name');
$userProfile->lastName = $data->get('last_name');
$userProfile->profileURL = $data->get('link');
$userProfile->webSiteURL = $data->get('website');
$userProfile->gender = $data->get('gender');
$userProfile->language = $data->get('locale');
$userProfile->description = $data->get('about');
$userProfile->email = $data->get('email');
// Fallback for profile URL in case Facebook does not provide "pretty" link with username (if user set it).
if (empty($userProfile->profileURL)) {
$userProfile->profileURL = $this->getProfileUrl($userProfile->identifier);
}
$userProfile->region = $data->filter('hometown')->get('name');
$photoSize = $this->config->get('photo_size') ?: '150';
$userProfile->photoURL = $this->apiBaseUrl . $userProfile->identifier;
$userProfile->photoURL .= '/picture?width=' . $photoSize . '&height=' . $photoSize;
$userProfile->emailVerified = $userProfile->email;
$userProfile = $this->fetchUserRegion($userProfile);
$userProfile = $this->fetchBirthday($userProfile, $data->get('birthday'));
return $userProfile;
}
/**
* Retrieve the user region.
*
* @param User\Profile $userProfile
*
* @return \Hybridauth\User\Profile
*/
protected function fetchUserRegion(User\Profile $userProfile)
{
if (!empty($userProfile->region)) {
$regionArr = explode(',', $userProfile->region);
if (count($regionArr) > 1) {
$userProfile->city = trim($regionArr[0]);
$userProfile->country = trim($regionArr[1]);
}
}
return $userProfile;
}
/**
* Retrieve the user birthday.
*
* @param User\Profile $userProfile
* @param string $birthday
*
* @return \Hybridauth\User\Profile
*/
protected function fetchBirthday(User\Profile $userProfile, $birthday)
{
$result = (new Data\Parser())->parseBirthday($birthday);
$userProfile->birthYear = (int)$result[0];
$userProfile->birthMonth = (int)$result[1];
$userProfile->birthDay = (int)$result[2];
return $userProfile;
}
/**
* /v2.0/me/friends only returns the user's friends who also use the app.
* In the cases where you want to let people tag their friends in stories published by your app,
* you can use the Taggable Friends API.
*
* https://developers.facebook.com/docs/apps/faq#unable_full_friend_list
*/
public function getUserContacts()
{
$contacts = [];
$apiUrl = 'me/friends?fields=link,name';
do {
$response = $this->apiRequest($apiUrl);
$data = new Data\Collection($response);
if (!$data->exists('data')) {
throw new UnexpectedApiResponseException('Provider API returned an unexpected response.');
}
if (!$data->filter('data')->isEmpty()) {
foreach ($data->filter('data')->toArray() as $item) {
$contacts[] = $this->fetchUserContact($item);
}
}
if ($data->filter('paging')->exists('next')) {
$apiUrl = $data->filter('paging')->get('next');
$pagedList = true;
} else {
$pagedList = false;
}
} while ($pagedList);
return $contacts;
}
/**
* Parse the user contact.
*
* @param array $item
*
* @return \Hybridauth\User\Contact
*/
protected function fetchUserContact($item)
{
$userContact = new User\Contact();
$item = new Data\Collection($item);
$userContact->identifier = $item->get('id');
$userContact->displayName = $item->get('name');
$userContact->profileURL = $item->exists('link')
?: $this->getProfileUrl($userContact->identifier);
$userContact->photoURL = $this->apiBaseUrl . $userContact->identifier . '/picture?width=150&height=150';
return $userContact;
}
/**
* {@inheritdoc}
*/
public function setPageStatus($status, $pageId)
{
$status = is_string($status) ? ['message' => $status] : $status;
// Post on user wall.
if ($pageId === 'me') {
return $this->setUserStatus($status);
}
// Retrieve writable user pages and filter by given one.
$pages = $this->getUserPages(true);
$pages = array_filter($pages, function ($page) use ($pageId) {
return $page->id == $pageId;
});
if (!$pages) {
throw new InvalidArgumentException('Could not find a page with given id.');
}
$page = reset($pages);
// Use page access token instead of user access token.
$headers = [
'Authorization' => 'Bearer ' . $page->access_token,
];
// Refresh proof for API call.
$parameters = $status + [
'appsecret_proof' => hash_hmac('sha256', $page->access_token, $this->clientSecret),
];
$response = $this->apiRequest("{$pageId}/feed", 'POST', $parameters, $headers);
return $response;
}
/**
* {@inheritdoc}
*/
public function getUserPages($writable = false)
{
$pages = $this->apiRequest('me/accounts');
if (!$writable) {
return $pages->data;
}
// Filter user pages by CREATE_CONTENT permission.
return array_filter($pages->data, function ($page) {
return in_array('CREATE_CONTENT', $page->tasks);
});
}
/**
* {@inheritdoc}
*/
public function getUserActivity($stream = 'me')
{
$apiUrl = $stream == 'me' ? 'me/feed' : 'me/home';
$response = $this->apiRequest($apiUrl);
$data = new Data\Collection($response);
if (!$data->exists('data')) {
throw new UnexpectedApiResponseException('Provider API returned an unexpected response.');
}
$activities = [];
foreach ($data->filter('data')->toArray() as $item) {
$activities[] = $this->fetchUserActivity($item);
}
return $activities;
}
/**
* @param $item
*
* @return User\Activity
*/
protected function fetchUserActivity($item)
{
$userActivity = new User\Activity();
$item = new Data\Collection($item);
$userActivity->id = $item->get('id');
$userActivity->date = $item->get('created_time');
if ('video' == $item->get('type') || 'link' == $item->get('type')) {
$userActivity->text = $item->get('link');
}
if (empty($userActivity->text) && $item->exists('story')) {
$userActivity->text = $item->get('link');
}
if (empty($userActivity->text) && $item->exists('message')) {
$userActivity->text = $item->get('message');
}
if (!empty($userActivity->text) && $item->exists('from')) {
$userActivity->user->identifier = $item->filter('from')->get('id');
$userActivity->user->displayName = $item->filter('from')->get('name');
$userActivity->user->profileURL = $this->getProfileUrl($userActivity->user->identifier);
$userActivity->user->photoURL = $this->apiBaseUrl . $userActivity->user->identifier;
$userActivity->user->photoURL .= '/picture?width=150&height=150';
}
return $userActivity;
}
/**
* Get profile URL.
*
* @param int $identity User ID.
* @return string|null NULL when identity is not provided.
*/
protected function getProfileUrl($identity)
{
if (!is_numeric($identity)) {
return null;
}
return sprintf($this->profileUrlTemplate, $identity);
}
}
lib/hybridauth/Provider/GitHub.php 0000644 00000005556 14757772106 0013175 0 ustar 00 apiRequest('user');
$data = new Data\Collection($response);
if (!$data->exists('id')) {
throw new UnexpectedApiResponseException('Provider API returned an unexpected response.');
}
$userProfile = new User\Profile();
$userProfile->identifier = $data->get('id');
$userProfile->displayName = $data->get('name');
$userProfile->description = $data->get('bio');
$userProfile->photoURL = $data->get('avatar_url');
$userProfile->profileURL = $data->get('html_url');
$userProfile->email = $data->get('email');
$userProfile->webSiteURL = $data->get('blog');
$userProfile->region = $data->get('location');
$userProfile->displayName = $userProfile->displayName ?: $data->get('login');
if (empty($userProfile->email) && strpos($this->scope, 'user:email') !== false) {
try {
// user email is not mandatory so keep it quite.
$userProfile = $this->requestUserEmail($userProfile);
} catch (\Exception $e) {
}
}
return $userProfile;
}
/**
* Request connected user email
*
* https://developer.github.com/v3/users/emails/
* @param User\Profile $userProfile
*
* @return User\Profile
*
* @throws \Exception
*/
protected function requestUserEmail(User\Profile $userProfile)
{
$response = $this->apiRequest('user/emails');
foreach ($response as $idx => $item) {
if (!empty($item->primary) && $item->primary == 1) {
$userProfile->email = $item->email;
if (!empty($item->verified) && $item->verified == 1) {
$userProfile->emailVerified = $userProfile->email;
}
break;
}
}
return $userProfile;
}
}
lib/hybridauth/Provider/Discord.php 0000644 00000004561 14757772106 0013375 0 ustar 00 isRefreshTokenAvailable()) {
$this->tokenRefreshParameters += [
'client_id' => $this->clientId,
'client_secret' => $this->clientSecret,
];
}
}
/**
* {@inheritdoc}
*/
public function getUserProfile()
{
$response = $this->apiRequest('users/@me');
$data = new Data\Collection($response);
if (!$data->exists('id')) {
throw new UnexpectedApiResponseException('Provider API returned an unexpected response.');
}
// Makes display name more unique.
$displayName = $data->get('username') ?: $data->get('login');
if ($discriminator = $data->get('discriminator')) {
$displayName .= "#{$discriminator}";
}
$userProfile = new User\Profile();
$userProfile->identifier = $data->get('id');
$userProfile->displayName = $displayName;
$userProfile->email = $data->get('email');
if ($data->get('verified')) {
$userProfile->emailVerified = $data->get('email');
}
if ($data->get('avatar')) {
$userProfile->photoURL = 'https://cdn.discordapp.com/avatars/';
$userProfile->photoURL .= $data->get('id') . '/' . $data->get('avatar') . '.png';
}
return $userProfile;
}
}
lib/hotp.php 0000644 00000012555 14757772106 0007025 0 ustar 00 = 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 \Loginizer\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 = \Loginizer\HOTP::getTime();
}
$counter = intval($timestamp / $window);
return \Loginizer\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 = \Loginizer\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] = \Loginizer\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;
}
}
lib/Base32.php 0000644 00000010705 14757772106 0007065 0 ustar 00
* @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;
}
}
main/settings/social_login.php 0000644 00000041135 14757772106 0012527 0 ustar 00
'.__('Create Google APP', 'loginizer').'
'.__('Last Updated','loginizer').': 24th June 2024
'.__('To allow your users to be able to login through their Google Account, you first need to create a Google App. For that follow the App creation steps below.', 'loginizer').'
'.__('If you are not logged in then login, and create a project if you don\'t have that already', 'loginizer').'
'.__('Once you have a project in the Console make sure you are on API and services page and then go to OAuth consent screen in the left navigation', 'loginizer').'
'.__('Under the "Authorized domains" section press the "Add Domain" button and enter your domain name, without subdomains!', 'loginizer').'
'.__('At the "Developer contact information" section, enter an email address that Google can use to notify you about any changes to your project.').'
'.__('Press "Save and Continue" then press it again on the "Scopes", "Test users" pages, too!', 'loginizer').'
'.__('After that you will need to create the credentials. For that in the same left navigation click on Credentials.', 'loginizer').'
'.__('On the credentials page, click on Create Credentials and then choose OAuth client ID', 'loginizer').'
'.__('A select field which is Application Type will appear, in that select web appilication and then other fields will show up', 'loginizer').'
'.__('Now set it\'s name to anything you like.', 'loginizer').'
'.__('After that in Authorize redirect URIs Add URI', 'loginizer').'
'.__('The URI you need to add is', 'loginizer').''.esc_url(wp_login_url()).'?lz_social_provider=Google
'.__('Now click on create and you will get your Client ID and secret key', 'loginizer').'
'.__('Copy those keys in the required field and save settings.', 'loginizer').'
';
}
function loginizer_how_to_facebook(){
// NOTE: update the date of last updated of this doc if you make any change.
echo '
'.__('Create Facebook App', 'loginizer').'
'.__('Last Updated','loginizer').': 24th June 2024
'.__('To allow your users to be able to login through their facebook account, you first need to create a Facebook App. For that follow the App creation steps below.', 'loginizer').'
'.__('If you are not logged in then login, and click on Create App button and choose "Others" as use case and click Next', 'loginizer').'
'.__('After selecting Others you will be asked to select App type there select Consumer and click next button', 'loginizer').'
'.__('A form will appear which will ask for your Apps name fill it and other details on the form and then Create App', 'loginizer').'
'.__('Your app will be created now on next page, you will get multiple options of Products you can add to your App, there setup Facebook Login', 'loginizer').'
'.__('After clicking on Setup Facebook login, you will be asked which platform you want to use it on there select Web', 'loginizer').'
'.__('Now you will need to fill up some details, first you will be asked about URL of the website after adding that in the field save and click on Continue', 'loginizer').'
'.__('Thats all you need to do in this form, for other steps you can just click on next.', 'loginizer').'
'.__('Once you are done with the steps in the Left Navigation go to Facebook Login then Settings.', 'loginizer').'
'.__('The settings releated to OAuth will open there you will need to fill the Valid OAuth Redirect URIs field with this URL.', 'loginizer').''.esc_url(wp_login_url()).'?lz_social_provider=Facebook
'.__('After adding the URL save changes and now from the Left Navigation go to App Settings the Basic.', 'loginizer').'
'.__('On the Baisc page of App Settings you will find App ID and App Secret copy that as we need that to setup Facebook Login through Loginizer.', 'loginizer').'
'.__('Now go to your WordPress admin then Loginizer then Social Login and then Facebook Settings', 'loginizer').'
'.__('In the Facebook settings page add the App ID to client ID and App Secret to App Secret', 'loginizer').'
'.__('Enable Facebook and save the settings, now a test info will show in there click on the Test button to verify that the setup went as expected.', 'loginizer').'
';
}
function loginizer_how_to_github(){
// NOTE: update the date of last updated of this doc if you make any change.
echo '
'.__('Create Github App', 'loginizer').'
'.__('Last Updated','loginizer').': 24th June 2024
'.__('To allow your users to be able to login through their Github Account, you first need to create a Github App. For that follow the App creation steps below.', 'loginizer').'
'.__('Make sure you are already logged in, if you are not then please login', 'loginizer').'
'.__('Now you will be in Developer Settings page and make sure you are on the OAuth App tab.', 'loginizer').'
'.__('There you will find a button to Register a New Application, Click on that button.', 'loginizer').'
'.__('A form will appear, fill that form with the required details, and in Authorization Callback URL field enter this URL', 'loginizer').''.esc_url(wp_login_url()).'?lz_social_provider=GitHub
'.__('Now save the details, and your client ID will be generated', 'loginizer').'
'.__('Now in the Client Secret section, look for Generate a new client secret button and click it and it will generate the secret key', 'loginizer').'
'.__('You have both keys with you now, so go to WordPress admin --> Loginizer --> Social Login --> in Provider tab go to Github and enter these keys in the respective fields and save it.', 'loginizer').'
';
}
function loginizer_how_to_wordpress(){
// NOTE: update the date of last updated of this doc if you make any change.
echo '
'.__('Create WordPress App', 'loginizer').'
'.__('Last Updated','loginizer').': 24th June 2024
'.__('To allow your users to be able to login through their WordPress.com Account, you first need to create a WordPress.com Application. For that follow the Application creation steps below.', 'loginizer').'
'.__('Make sure you are already logged in, if you are not then please login', 'loginizer').'
'.__('Now you will be in WordPress.com Developer My Application page.', 'loginizer').'
'.__('There you will find a link to Create new Application a New Application, Click on that link.', 'loginizer').'
'.__('A form will appear, fill that form with the required details, and in Redirect URLS field enter this URL', 'loginizer').''.esc_url(wp_login_url()).'?lz_social_provider=WordPress
'.__('Now click on Create button and the App will be created.', 'loginizer').'
'.__('You will need to go back to the My Application page, and find the app you just created and click on it', 'loginizer').'
'.__('On the app page, in the bottom you will find OAuth information, Copy the client ID and client secret.', 'loginizer').'
'.__('You have both keys with you now, so go to WordPress admin --> Loginizer --> Social Login --> in Provider tab go to WordPress and enter these keys in the respective fields and save it.', 'loginizer').'
';
}
function loginizer_how_to_discord(){
// NOTE: update the date of last updated of this doc if you make any change.
echo '
'.__('Create Discord App', 'loginizer').'
'.__('Last Updated','loginizer').': 24th June 2024
'.__('To allow your users to be able to login through their Discord Account, you first need to create a Discord Application. For that follow the Application creation steps below.', 'loginizer').'
'.__('Make sure you are already logged in, if you are not then please login', 'loginizer').'
'.__('Now you will be in Discord Developer Portal on Applications page.', 'loginizer').'
'.__('There you will find a button which says New Application on the top right, click on that button.', 'loginizer').'
'.__('A poup will appear, fill the Application name and check the terms and condition checkbox, and then click create.', 'loginizer').'
'.__('A form will appear with optional fields fill those as per your wish and save them.', 'loginizer').'
'.__('Now in the left navigation click on OAuth, and you will find client ID and an option to generate Client Secret', 'loginizer').'
'.__('And add the Redirect URL as without that Login won\'t work, the URL is ', 'loginizer').''.esc_url(wp_login_url()).'?lz_social_provider=Discord
'.__('Copy both Client ID and Client Secret and go to WordPress Admin, Loginizer, Social Login, Discord and enter the copied keys in the respective field and save it.', 'loginizer').'
';
}
function loginizer_how_to_twitchtv(){
// NOTE: update the date of last updated of this doc if you make any change.
echo '
'.__('Create Twitch App', 'loginizer').'
'.__('Last Updated','loginizer').': 24th June 2024
'.__('To allow your users to be able to login through their Twitch Account, you first need to create a Twitch Application. For that follow the Application creation steps below.', 'loginizer').'
'.__('There is a pre-requisite in Twitch that the account you are using to create the keys should have 2FA enabled on it. You can do it from this page','loginizer').' Security and Privacy
'.__('Now from the left navigation go to Applications.', 'loginizer').'
'.__('On the applications page click on Register your application button.', 'loginizer').'
'.__('A form will appear, fill the Application name, in Category select Website integration and client type as Confidential.', 'loginizer').'
'.__('Now the last field we need to fill is OAuth Redirect URLs in there add this URL.', 'loginizer').''.esc_url(wp_login_url()).'?lz_social_provider=TwitchTV
'.__('After all the fields are filled click on save and a App will be created and you will be redirected to the Application page with your App listed there, now click on the manage button of the listed app.', 'loginizer').'
'.__('You will get the Client ID and Client Secret here so copy them as we need to use them in Loginizer', 'loginizer').'
'.__('Now go to WordPress Admin, Loginizer, Social Login, Twitch and enter the copied keys in the respective field and save it.', 'loginizer').'
';
}
function loginizer_how_to_twitter(){
// NOTE: update the date of last updated of this doc if you make any change.
echo '
'.__('Create X App(Formly Twitter)', 'loginizer').'
'.__('Last Updated','loginizer').': 24th June 2024
'.__('To allow your users to be able to login through their X Account, you first need to create a X Project. For that follow the Project creation steps below.', 'loginizer').'
'.__('If you don\'t have a developer account then apply for it by filling required details. It is mandatory to fill this form to get access to the developer account.', 'loginizer').'
'.__('Once you have the developer account and you are on the Project and App page click on Add Project.','loginizer').'
'.__('You will have to fill a form with Project name, use case, project desccription and then App name.', 'loginizer').'
'.__('Once you do that it will show the API Key and API secret, copy that and come to your WordPress dashboard.', 'loginizer').'
'.__('On your WordPress admin go to Loginizer, Social Login and then X(formly Twitter) there place the API key in Client ID and API Secret in Client Secret and enable it and save it.', 'loginizer').'
'.__('The setup is not done yet, Loginzer will show a notice to test your Integration, but dont do it now, as few more steps are yet to be done, go back to Twitter Developer Accound and go to Project and APP from the Left Navigation then Your Project and then your APP.', 'loginizer').'
'.__('On the page of your APP there will be a section named User authentication settings in that section click on Set up button.', 'loginizer').'
'.__('Set up setting will appear in that set App Permission to Read and enable Request email from user.', 'loginizer').'
'.__('Next in the Type of App select Web App and then in the App Info section in the Callback URI/Redirect URL set this URL', 'loginizer').''.esc_url(wp_login_url()).'?lz_social_provider=Twitter
'.__('Next fill your Websites URL in Website URL field, then Twitter requires you to give it a Privacy Policy and Terms and Conditions page because we are requesting for user email. Fill those details and hit save', 'loginizer').'
'.__('Now you can test Twitter Login on Loginizer so it can start showing on the Login page.', 'loginizer').'
'.esc_html__('You are using an older version of Loginizer Security. We recommend updating to the latest version to ensure seamless and uninterrupted use of the application.', 'loginizer').'
'.esc_html__('You are using an older version of Loginizer. We recommend updating to the latest free version to ensure smooth and uninterrupted use of the application.', 'loginizer').'
';
}
if(!empty($showing_error)){
wp_register_script('loginizer-pro-version-notice', '', array('jquery'), LOGINIZER_PRO_VERSION, true );
wp_enqueue_script('loginizer-pro-version-notice');
wp_add_inline_script('loginizer-pro-version-notice', '
function loginizer_pro_dismiss_notice(e){
e.preventDefault();
let target = jQuery(e.target);
if(!target.hasClass("notice-dismiss")){
return;
}
let jEle = target.closest("#loginizer-pro-version-notice"),
type = jEle.data("type");
jEle.slideUp();
jQuery.post("'.admin_url('admin-ajax.php').'", {
security : "'.wp_create_nonce('loginizer_version_notice').'",
action: "loginizer_pro_version_notice",
type: type
}, function(res){
if(!res["success"]){
alert(res["data"]);
}
}).fail(function(data){
alert("There seems to be some issue dismissing this alert");
});
}');
}
} main/social-login.php 0000644 00000011004 14757772106 0010575 0 ustar 00 'icon',
'divider' => 'above',
'shape' => 'square'
], $atts);
$errors = loginizer_social_login_error_handler();
if(!empty($errors) || is_wp_error($errors)){
$error = '
';
$args = [
'type' => 'error',
];
// Add the number of retires left as well
if(count($errors->get_error_codes()) > 0 && isset($loginizer['retries_left'])){
$errors->add('retries_left', loginizer_retries_left());
}
$messages = $errors->get_error_messages();
$notice = '';
if(count($messages) == 1){
$notice .= '
';
}
updater/plugin-update-checker.php 0000644 00000152147 14757772106 0013133 0 ustar 00 metadataUrl = $metadataUrl;
$this->pluginAbsolutePath = $pluginFile;
$this->pluginFile = plugin_basename($this->pluginAbsolutePath);
$this->muPluginFile = $muPluginFile;
$this->slug = $slug;
$this->optionName = $optionName;
$this->debugMode = (bool)(constant('WP_DEBUG'));
//If no slug is specified, use the name of the main plugin file as the slug.
//For example, 'my-cool-plugin/cool-plugin.php' becomes 'cool-plugin'.
if ( empty($this->slug) ){
$this->slug = basename($this->pluginFile, '.php');
}
//Plugin slugs must be unique.
$slugCheckFilter = 'puc_is_slug_in_use-' . $this->slug;
$slugUsedBy = apply_filters($slugCheckFilter, false);
if ( $slugUsedBy ) {
$this->triggerError(sprintf(
'Plugin slug "%s" is already in use by %s. Slugs must be unique.',
htmlentities($this->slug),
htmlentities($slugUsedBy)
), E_USER_ERROR);
}
add_filter($slugCheckFilter, array($this, 'getAbsolutePath'));
if ( empty($this->optionName) ){
$this->optionName = 'external_updates-' . $this->slug;
}
//Backwards compatibility: If the plugin is a mu-plugin but no $muPluginFile is specified, assume
//it's the same as $pluginFile given that it's not in a subdirectory (WP only looks in the base dir).
if ( (strpbrk($this->pluginFile, '/\\') === false) && $this->isUnknownMuPlugin() ) {
$this->muPluginFile = $this->pluginFile;
}
$this->scheduler = $this->createScheduler($checkPeriod);
$this->upgraderStatus = new Loginizer_PucUpgraderStatus_3_2();
$this->installHooks();
}
/**
* Create an instance of the scheduler.
*
* This is implemented as a method to make it possible for plugins to subclass the update checker
* and substitute their own scheduler.
*
* @param int $checkPeriod
* @return Loginizer_PucScheduler_3_2
*/
protected function createScheduler($checkPeriod) {
return new Loginizer_PucScheduler_3_2($this, $checkPeriod);
}
/**
* Install the hooks required to run periodic update checks and inject update info
* into WP data structures.
*
* @return void
*/
protected function installHooks(){
//Override requests for plugin information
add_filter('plugins_api', array($this, 'injectInfo'), 20, 3);
//Insert our update info into the update array maintained by WP.
add_filter('site_transient_update_plugins', array($this,'injectUpdate')); //WP 3.0+
add_filter('transient_update_plugins', array($this,'injectUpdate')); //WP 2.8+
add_filter('site_transient_update_plugins', array($this, 'injectTranslationUpdates'));
add_filter('plugin_row_meta', array($this, 'addCheckForUpdatesLink'), 10, 2);
add_action('admin_init', array($this, 'handleManualCheck'));
add_action('all_admin_notices', array($this, 'displayManualCheckResult'));
//Clear the version number cache when something - anything - is upgraded or WP clears the update cache.
add_filter('upgrader_post_install', array($this, 'clearCachedVersion'));
add_action('delete_site_transient_update_plugins', array($this, 'clearCachedVersion'));
//Clear translation updates when WP clears the update cache.
//This needs to be done directly because the library doesn't actually remove obsolete plugin updates,
//it just hides them (see getUpdate()). We can't do that with translations - too much disk I/O.
add_action('delete_site_transient_update_plugins', array($this, 'clearCachedTranslationUpdates'));
if ( did_action('plugins_loaded') ) {
$this->initDebugBarPanel();
} else {
add_action('plugins_loaded', array($this, 'initDebugBarPanel'));
}
//Rename the update directory to be the same as the existing directory.
add_filter('upgrader_source_selection', array($this, 'fixDirectoryName'), 10, 3);
//Enable language support (i18n).
load_plugin_textdomain('plugin-update-checker', false, plugin_basename(dirname(__FILE__)) . '/languages');
//Allow HTTP requests to the metadata URL even if it's on a local host.
$this->metadataHost = @parse_url($this->metadataUrl, PHP_URL_HOST);
add_filter('http_request_host_is_external', array($this, 'allowMetadataHost'), 10, 2);
}
/**
* Explicitly allow HTTP requests to the metadata URL.
*
* WordPress has a security feature where the HTTP API will reject all requests that are sent to
* another site hosted on the same server as the current site (IP match), a local host, or a local
* IP, unless the host exactly matches the current site.
*
* This feature is opt-in (at least in WP 4.4). Apparently some people enable it.
*
* That can be a problem when you're developing your plugin and you decide to host the update information
* on the same server as your test site. Update requests will mysteriously fail.
*
* We fix that by adding an exception for the metadata host.
*
* @param bool $allow
* @param string $host
* @return bool
*/
public function allowMetadataHost($allow, $host) {
if ( strtolower($host) === strtolower($this->metadataHost) ) {
return true;
}
return $allow;
}
/**
* Retrieve plugin info from the configured API endpoint.
*
* @uses wp_remote_get()
*
* @param array $queryArgs Additional query arguments to append to the request. Optional.
* @return LoginizerInfo_3_2
*/
public function requestInfo($queryArgs = array()){
//Query args to append to the URL. Plugins can add their own by using a filter callback (see addQueryArgFilter()).
$installedVersion = $this->getInstalledVersion();
$queryArgs['installed_version'] = ($installedVersion !== null) ? $installedVersion : '';
$queryArgs = apply_filters('puc_request_info_query_args-'.$this->slug, $queryArgs);
//Various options for the wp_remote_get() call. Plugins can filter these, too.
$options = array(
'timeout' => 10, //seconds
'headers' => array(
'Accept' => 'application/json'
),
);
$options = apply_filters('puc_request_info_options-'.$this->slug, $options);
//The plugin info should be at 'http://your-api.com/url/here/$slug/info.json'
$url = $this->metadataUrl;
if ( !empty($queryArgs) ){
$url = add_query_arg($queryArgs, $url);
}
$result = wp_remote_get(
$url,
$options
);
//Try to parse the response
$status = $this->validateApiResponse($result);
$pluginInfo = null;
if ( !is_wp_error($status) ){
$pluginInfo = LoginizerInfo_3_2::fromJson($result['body']);
if ( $pluginInfo !== null ) {
$pluginInfo->filename = $this->pluginFile;
$pluginInfo->slug = $this->slug;
}
} else {
$this->triggerError(
sprintf('The URL %s does not point to a valid plugin metadata file. ', $url)
. $status->get_error_message(),
E_USER_WARNING
);
}
$pluginInfo = apply_filters('puc_request_info_result-'.$this->slug, $pluginInfo, $result);
return $pluginInfo;
}
/**
* Check if $result is a successful update API response.
*
* @param array|WP_Error $result
* @return true|WP_Error
*/
private function validateApiResponse($result) {
if ( is_wp_error($result) ) { /** @var WP_Error $result */
return new WP_Error($result->get_error_code(), 'WP HTTP Error: ' . $result->get_error_message());
}
if ( !isset($result['response']['code']) ) {
return new WP_Error('puc_no_response_code', 'wp_remote_get() returned an unexpected result.');
}
if ( $result['response']['code'] !== 200 ) {
return new WP_Error(
'puc_unexpected_response_code',
'HTTP response code is ' . $result['response']['code'] . ' (expected: 200)'
);
}
if ( empty($result['body']) ) {
return new WP_Error('puc_empty_response', 'The metadata file appears to be empty.');
}
return true;
}
/**
* Retrieve the latest update (if any) from the configured API endpoint.
*
* @uses LoginizerUpdateChecker::requestInfo()
*
* @return LoginizerUpdate_3_2 An instance of LoginizerUpdate, or NULL when no updates are available.
*/
public function requestUpdate(){
//For the sake of simplicity, this function just calls requestInfo()
//and transforms the result accordingly.
$pluginInfo = $this->requestInfo(array('checking_for_updates' => '1'));
if ( $pluginInfo == null ){
return null;
}
$update = LoginizerUpdate_3_2::fromLoginizerInfo($pluginInfo);
//Keep only those translation updates that apply to this site.
$update->translations = $this->filterApplicableTranslations($update->translations);
return $update;
}
/**
* Filter a list of translation updates and return a new list that contains only updates
* that apply to the current site.
*
* @param array $translations
* @return array
*/
private function filterApplicableTranslations($translations) {
$languages = array_flip(array_values(get_available_languages()));
$installedTranslations = wp_get_installed_translations('plugins');
if ( isset($installedTranslations[$this->slug]) ) {
$installedTranslations = $installedTranslations[$this->slug];
} else {
$installedTranslations = array();
}
$applicableTranslations = array();
foreach($translations as $translation) {
//Does it match one of the available core languages?
$isApplicable = array_key_exists($translation->language, $languages);
//Is it more recent than an already-installed translation?
if ( isset($installedTranslations[$translation->language]) ) {
$updateTimestamp = strtotime($translation->updated);
$installedTimestamp = strtotime($installedTranslations[$translation->language]['PO-Revision-Date']);
$isApplicable = $updateTimestamp > $installedTimestamp;
}
if ( $isApplicable ) {
$applicableTranslations[] = $translation;
}
}
return $applicableTranslations;
}
/**
* Get the currently installed version of the plugin.
*
* @return string Version number.
*/
public function getInstalledVersion(){
if ( isset($this->cachedInstalledVersion) ) {
return $this->cachedInstalledVersion;
}
$pluginHeader = $this->getPluginHeader();
if ( isset($pluginHeader['Version']) ) {
$this->cachedInstalledVersion = $pluginHeader['Version'];
return $pluginHeader['Version'];
} else {
//This can happen if the filename points to something that is not a plugin.
$this->triggerError(
sprintf(
"Can't to read the Version header for '%s'. The filename is incorrect or is not a plugin.",
$this->pluginFile
),
E_USER_WARNING
);
return null;
}
}
/**
* Get plugin's metadata from its file header.
*
* @return array
*/
protected function getPluginHeader() {
if ( !is_file($this->pluginAbsolutePath) ) {
//This can happen if the plugin filename is wrong.
$this->triggerError(
sprintf(
"Can't to read the plugin header for '%s'. The file does not exist.",
$this->pluginFile
),
E_USER_WARNING
);
return array();
}
if ( !function_exists('get_plugin_data') ){
/** @noinspection PhpIncludeInspection */
require_once( ABSPATH . '/wp-admin/includes/plugin.php' );
}
return get_plugin_data($this->pluginAbsolutePath, false, false);
}
/**
* Check for plugin updates.
* The results are stored in the DB option specified in $optionName.
*
* @return LoginizerUpdate_3_2|null
*/
public function checkForUpdates(){
$installedVersion = $this->getInstalledVersion();
//Fail silently if we can't find the plugin or read its header.
if ( $installedVersion === null ) {
$this->triggerError(
sprintf('Skipping update check for %s - installed version unknown.', $this->pluginFile),
E_USER_WARNING
);
return null;
}
$state = $this->getUpdateState();
if ( empty($state) ){
$state = new stdClass;
$state->lastCheck = 0;
$state->checkedVersion = '';
$state->update = null;
}
$state->lastCheck = time();
$state->checkedVersion = $installedVersion;
$this->setUpdateState($state); //Save before checking in case something goes wrong
$state->update = $this->requestUpdate();
$this->setUpdateState($state);
return $this->getUpdate();
}
/**
* Load the update checker state from the DB.
*
* @return stdClass|null
*/
public function getUpdateState() {
$state = get_site_option($this->optionName, null);
if ( empty($state) || !is_object($state)) {
$state = null;
}
if ( isset($state, $state->update) && is_object($state->update) ) {
$state->update = LoginizerUpdate_3_2::fromObject($state->update);
}
return $state;
}
/**
* Persist the update checker state to the DB.
*
* @param StdClass $state
* @return void
*/
private function setUpdateState($state) {
if ( isset($state->update) && is_object($state->update) && method_exists($state->update, 'toStdClass') ) {
$update = $state->update; /** @var LoginizerUpdate_3_2 $update */
$state->update = $update->toStdClass();
}
update_site_option($this->optionName, $state);
}
/**
* Reset update checker state - i.e. last check time, cached update data and so on.
*
* Call this when your plugin is being uninstalled, or if you want to
* clear the update cache.
*/
public function resetUpdateState() {
delete_site_option($this->optionName);
}
/**
* Intercept plugins_api() calls that request information about our plugin and
* use the configured API endpoint to satisfy them.
*
* @see plugins_api()
*
* @param mixed $result
* @param string $action
* @param array|object $args
* @return mixed
*/
public function injectInfo($result, $action = null, $args = null){
$relevant = ($action == 'plugin_information') && isset($args->slug) && (
($args->slug == $this->slug) || ($args->slug == dirname($this->pluginFile))
);
if ( !$relevant ) {
return $result;
}
$pluginInfo = $this->requestInfo();
$pluginInfo = apply_filters('puc_pre_inject_info-' . $this->slug, $pluginInfo);
if ( $pluginInfo ) {
return $pluginInfo->toWpFormat();
}
return $result;
}
/**
* Insert the latest update (if any) into the update list maintained by WP.
*
* @param StdClass $updates Update list.
* @return StdClass Modified update list.
*/
public function injectUpdate($updates){
//Is there an update to insert?
$update = $this->getUpdate();
//No update notifications for mu-plugins unless explicitly enabled. The MU plugin file
//is usually different from the main plugin file so the update wouldn't show up properly anyway.
if ( $this->isUnknownMuPlugin() ) {
$update = null;
}
if ( !empty($update) ) {
//Let plugins filter the update info before it's passed on to WordPress.
$update = apply_filters('puc_pre_inject_update-' . $this->slug, $update);
$updates = $this->addUpdateToList($updates, $update);
} else {
//Clean up any stale update info.
$updates = $this->removeUpdateFromList($updates);
}
return $updates;
}
/**
* @param StdClass|null $updates
* @param LoginizerUpdate_3_2 $updateToAdd
* @return StdClass
*/
private function addUpdateToList($updates, $updateToAdd) {
if ( !is_object($updates) ) {
$updates = new stdClass();
$updates->response = array();
}
$wpUpdate = $updateToAdd->toWpFormat();
$pluginFile = $this->pluginFile;
if ( $this->isMuPlugin() ) {
//WP does not support automatic update installation for mu-plugins, but we can still display a notice.
$wpUpdate->package = null;
$pluginFile = $this->muPluginFile;
}
$updates->response[$pluginFile] = $wpUpdate;
return $updates;
}
/**
* @param stdClass|null $updates
* @return stdClass|null
*/
private function removeUpdateFromList($updates) {
if ( isset($updates, $updates->response) ) {
unset($updates->response[$this->pluginFile]);
if ( !empty($this->muPluginFile) ) {
unset($updates->response[$this->muPluginFile]);
}
}
return $updates;
}
/**
* Insert translation updates into the list maintained by WordPress.
*
* @param stdClass $updates
* @return stdClass
*/
public function injectTranslationUpdates($updates) {
$translationUpdates = $this->getTranslationUpdates();
if ( empty($translationUpdates) ) {
return $updates;
}
//Being defensive.
if ( !is_object($updates) ) {
$updates = new stdClass();
}
if ( !isset($updates->translations) ) {
$updates->translations = array();
}
//In case there's a name collision with a plugin hosted on wordpress.org,
//remove any preexisting updates that match our plugin.
$translationType = 'plugin';
$filteredTranslations = array();
foreach($updates->translations as $translation) {
if ( ($translation['type'] === $translationType) && ($translation['slug'] === $this->slug) ) {
continue;
}
$filteredTranslations[] = $translation;
}
$updates->translations = $filteredTranslations;
//Add our updates to the list.
foreach($translationUpdates as $update) {
$convertedUpdate = array_merge(
array(
'type' => $translationType,
'slug' => $this->slug,
'autoupdate' => 0,
//AFAICT, WordPress doesn't actually use the "version" field for anything.
//But lets make sure it's there, just in case.
'version' => isset($update->version) ? $update->version : ('1.' . strtotime($update->updated)),
),
(array)$update
);
$updates->translations[] = $convertedUpdate;
}
return $updates;
}
/**
* Rename the update directory to match the existing plugin directory.
*
* When WordPress installs a plugin or theme update, it assumes that the ZIP file will contain
* exactly one directory, and that the directory name will be the same as the directory where
* the plugin/theme is currently installed.
*
* GitHub and other repositories provide ZIP downloads, but they often use directory names like
* "project-branch" or "project-tag-hash". We need to change the name to the actual plugin folder.
*
* This is a hook callback. Don't call it from a plugin.
*
* @param string $source The directory to copy to /wp-content/plugins. Usually a subdirectory of $remoteSource.
* @param string $remoteSource WordPress has extracted the update to this directory.
* @param WP_Upgrader $upgrader
* @return string|WP_Error
*/
public function fixDirectoryName($source, $remoteSource, $upgrader) {
global $wp_filesystem; /** @var WP_Filesystem_Base $wp_filesystem */
//Basic sanity checks.
if ( !isset($source, $remoteSource, $upgrader, $upgrader->skin, $wp_filesystem) ) {
return $source;
}
//If WordPress is upgrading anything other than our plugin, leave the directory name unchanged.
if ( !$this->isPluginBeingUpgraded($upgrader) ) {
return $source;
}
//Rename the source to match the existing plugin directory.
$pluginDirectoryName = dirname($this->pluginFile);
if ( $pluginDirectoryName === '.' ) {
return $source;
}
$correctedSource = trailingslashit($remoteSource) . $pluginDirectoryName . '/';
if ( $source !== $correctedSource ) {
//The update archive should contain a single directory that contains the rest of plugin files. Otherwise,
//WordPress will try to copy the entire working directory ($source == $remoteSource). We can't rename
//$remoteSource because that would break WordPress code that cleans up temporary files after update.
if ( $this->isBadDirectoryStructure($remoteSource) ) {
return new WP_Error(
'puc-incorrect-directory-structure',
sprintf(
'The directory structure of the update is incorrect. All plugin files should be inside ' .
'a directory named %s, not at the root of the ZIP file.',
htmlentities($this->slug)
)
);
}
/** @var WP_Upgrader_Skin $upgrader->skin */
$upgrader->skin->feedback(sprintf(
'Renaming %s to %s…',
'' . basename($source) . '',
'' . $pluginDirectoryName . ''
));
if ( $wp_filesystem->move($source, $correctedSource, true) ) {
$upgrader->skin->feedback('Plugin directory successfully renamed.');
return $correctedSource;
} else {
return new WP_Error(
'puc-rename-failed',
'Unable to rename the update to match the existing plugin directory.'
);
}
}
return $source;
}
/**
* Check for incorrect update directory structure. An update must contain a single directory,
* all other files should be inside that directory.
*
* @param string $remoteSource Directory path.
* @return bool
*/
private function isBadDirectoryStructure($remoteSource) {
global $wp_filesystem; /** @var WP_Filesystem_Base $wp_filesystem */
$sourceFiles = $wp_filesystem->dirlist($remoteSource);
if ( is_array($sourceFiles) ) {
$sourceFiles = array_keys($sourceFiles);
$firstFilePath = trailingslashit($remoteSource) . $sourceFiles[0];
return (count($sourceFiles) > 1) || (!$wp_filesystem->is_dir($firstFilePath));
}
//Assume it's fine.
return false;
}
/**
* Is there and update being installed RIGHT NOW, for this specific plugin?
*
* @param WP_Upgrader|null $upgrader The upgrader that's performing the current update.
* @return bool
*/
public function isPluginBeingUpgraded($upgrader = null) {
return $this->upgraderStatus->isPluginBeingUpgraded($this->pluginFile, $upgrader);
}
/**
* Get the details of the currently available update, if any.
*
* If no updates are available, or if the last known update version is below or equal
* to the currently installed version, this method will return NULL.
*
* Uses cached update data. To retrieve update information straight from
* the metadata URL, call requestUpdate() instead.
*
* @return LoginizerUpdate_3_2|null
*/
public function getUpdate() {
$state = $this->getUpdateState(); /** @var StdClass $state */
//Is there an update available?
if ( isset($state, $state->update) ) {
$update = $state->update;
//Check if the update is actually newer than the currently installed version.
$installedVersion = $this->getInstalledVersion();
if ( ($installedVersion !== null) && version_compare($update->version, $installedVersion, '>') ){
$update->filename = $this->pluginFile;
return $update;
}
}
return null;
}
/**
* Get a list of available translation updates.
*
* This method will return an empty array if there are no updates.
* Uses cached update data.
*
* @return array
*/
public function getTranslationUpdates() {
$state = $this->getUpdateState();
if ( isset($state, $state->update, $state->update->translations) ) {
return $state->update->translations;
}
return array();
}
/**
* Remove all cached translation updates.
*
* @see wp_clean_update_cache
*/
public function clearCachedTranslationUpdates() {
$state = $this->getUpdateState();
if ( isset($state, $state->update, $state->update->translations) ) {
$state->update->translations = array();
$this->setUpdateState($state);
}
}
/**
* Add a "Check for updates" link to the plugin row in the "Plugins" page. By default,
* the new link will appear after the "Visit plugin site" link.
*
* You can change the link text by using the "puc_manual_check_link-$slug" filter.
* Returning an empty string from the filter will disable the link.
*
* @param array $pluginMeta Array of meta links.
* @param string $pluginFile
* @return array
*/
public function addCheckForUpdatesLink($pluginMeta, $pluginFile) {
$isRelevant = ($pluginFile == $this->pluginFile)
|| (!empty($this->muPluginFile) && $pluginFile == $this->muPluginFile);
if ( $isRelevant && current_user_can('update_plugins') ) {
$linkUrl = wp_nonce_url(
add_query_arg(
array(
'puc_check_for_updates' => 1,
'puc_slug' => $this->slug,
),
self_admin_url('plugins.php')
),
'puc_check_for_updates'
);
$linkText = apply_filters('puc_manual_check_link-' . $this->slug, __('Check for updates', 'plugin-update-checker'));
if ( !empty($linkText) ) {
$final_link = sprintf('%s', esc_attr($linkUrl), $linkText);
$pluginMeta[] = apply_filters('puc_manual_final_check_link-' . $this->slug, $final_link);
}
}
return $pluginMeta;
}
/**
* Check for updates when the user clicks the "Check for updates" link.
* @see self::addCheckForUpdatesLink()
*
* @return void
*/
public function handleManualCheck() {
$shouldCheck =
isset($_GET['puc_check_for_updates'], $_GET['puc_slug'])
&& $_GET['puc_slug'] == $this->slug
&& current_user_can('update_plugins')
&& check_admin_referer('puc_check_for_updates');
if ( $shouldCheck ) {
$update = $this->checkForUpdates();
$status = ($update === null) ? 'no_update' : 'update_available';
wp_redirect(add_query_arg(
array(
'puc_update_check_result' => $status,
'puc_slug' => $this->slug,
),
self_admin_url('plugins.php')
));
}
}
/**
* Display the results of a manual update check.
* @see self::handleManualCheck()
*
* You can change the result message by using the "puc_manual_check_message-$slug" filter.
*/
public function displayManualCheckResult() {
if ( isset($_GET['puc_update_check_result'], $_GET['puc_slug']) && ($_GET['puc_slug'] == $this->slug) ) {
$status = strval($_GET['puc_update_check_result']);
if ( $status == 'no_update' ) {
$message = __('This plugin is up to date.', 'plugin-update-checker');
} else if ( $status == 'update_available' ) {
$message = __('A new version of this plugin is available.', 'plugin-update-checker');
} else {
$message = sprintf(__('Unknown update checker status "%s"', 'plugin-update-checker'), htmlentities($status));
}
printf(
'
%s
',
apply_filters('puc_manual_check_message-' . $this->slug, $message, $status)
);
}
}
/**
* Check if the plugin file is inside the mu-plugins directory.
*
* @return bool
*/
protected function isMuPlugin() {
static $cachedResult = null;
if ( $cachedResult === null ) {
if ( !defined('WPMU_PLUGIN_DIR') || !is_string(WPMU_PLUGIN_DIR) ) {
$cachedResult = false;
return $cachedResult;
}
//Convert both paths to the canonical form before comparison.
$muPluginDir = realpath(WPMU_PLUGIN_DIR);
$pluginPath = realpath($this->pluginAbsolutePath);
if ( empty($muPluginDir) ) {
$cachedResult = false;
return $cachedResult;
}
$cachedResult = (strpos($pluginPath, $muPluginDir) === 0);
}
return $cachedResult;
}
/**
* MU plugins are partially supported, but only when we know which file in mu-plugins
* corresponds to this plugin.
*
* @return bool
*/
protected function isUnknownMuPlugin() {
return empty($this->muPluginFile) && $this->isMuPlugin();
}
/**
* Clear the cached plugin version. This method can be set up as a filter (hook) and will
* return the filter argument unmodified.
*
* @param mixed $filterArgument
* @return mixed
*/
public function clearCachedVersion($filterArgument = null) {
$this->cachedInstalledVersion = null;
return $filterArgument;
}
/**
* Get absolute path to the main plugin file.
*
* @return string
*/
public function getAbsolutePath() {
return $this->pluginAbsolutePath;
}
/**
* Register a callback for filtering query arguments.
*
* The callback function should take one argument - an associative array of query arguments.
* It should return a modified array of query arguments.
*
* @uses add_filter() This method is a convenience wrapper for add_filter().
*
* @param callable $callback
* @return void
*/
public function addQueryArgFilter($callback){
add_filter('puc_request_info_query_args-'.$this->slug, $callback);
}
/**
* Register a callback for filtering arguments passed to wp_remote_get().
*
* The callback function should take one argument - an associative array of arguments -
* and return a modified array or arguments. See the WP documentation on wp_remote_get()
* for details on what arguments are available and how they work.
*
* @uses add_filter() This method is a convenience wrapper for add_filter().
*
* @param callable $callback
* @return void
*/
public function addHttpRequestArgFilter($callback){
add_filter('puc_request_info_options-'.$this->slug, $callback);
}
/**
* Register a callback for filtering the plugin info retrieved from the external API.
*
* The callback function should take two arguments. If the plugin info was retrieved
* successfully, the first argument passed will be an instance of LoginizerInfo. Otherwise,
* it will be NULL. The second argument will be the corresponding return value of
* wp_remote_get (see WP docs for details).
*
* The callback function should return a new or modified instance of LoginizerInfo or NULL.
*
* @uses add_filter() This method is a convenience wrapper for add_filter().
*
* @param callable $callback
* @return void
*/
public function addResultFilter($callback){
add_filter('puc_request_info_result-'.$this->slug, $callback, 10, 2);
}
/**
* Register a callback for one of the update checker filters.
*
* Identical to add_filter(), except it automatically adds the "puc_" prefix
* and the "-$plugin_slug" suffix to the filter name. For example, "request_info_result"
* becomes "puc_request_info_result-your_plugin_slug".
*
* @param string $tag
* @param callable $callback
* @param int $priority
* @param int $acceptedArgs
*/
public function addFilter($tag, $callback, $priority = 10, $acceptedArgs = 1) {
add_filter('puc_' . $tag . '-' . $this->slug, $callback, $priority, $acceptedArgs);
}
/**
* Initialize the update checker Debug Bar plugin/add-on thingy.
*/
public function initDebugBarPanel() {
$debugBarPlugin = dirname(__FILE__) . '/debug-bar-plugin.php';
if ( class_exists('Debug_Bar', false) && file_exists($debugBarPlugin) ) {
/** @noinspection PhpIncludeInspection */
require_once $debugBarPlugin;
$this->debugBarPlugin = new Loginizer_PucDebugBarPlugin_3_2($this);
}
}
/**
* Trigger a PHP error, but only when $debugMode is enabled.
*
* @param string $message
* @param int $errorType
*/
protected function triggerError($message, $errorType) {
if ( $this->debugMode ) {
trigger_error($message, $errorType);
}
}
}
endif;
if ( !class_exists('LoginizerInfo_3_2', false) ):
/**
* A container class for holding and transforming various plugin metadata.
*
* @author Janis Elsts
* @copyright 2016
* @version 3.2
* @access public
*/
#[\AllowDynamicProperties]
class LoginizerInfo_3_2 {
//Most fields map directly to the contents of the plugin's info.json file.
//See the relevant docs for a description of their meaning.
public $name;
public $slug;
public $version;
public $homepage;
public $sections = array();
public $banners;
public $translations = array();
public $download_url;
public $author;
public $author_homepage;
public $requires;
public $tested;
public $upgrade_notice;
public $rating;
public $num_ratings;
public $downloaded;
public $active_installs;
public $last_updated;
public $id = 0; //The native WP.org API returns numeric plugin IDs, but they're not used for anything.
public $filename; //Plugin filename relative to the plugins directory.
/**
* Create a new instance of LoginizerInfo from JSON-encoded plugin info
* returned by an external update API.
*
* @param string $json Valid JSON string representing plugin info.
* @return LoginizerInfo_3_2|null New instance of LoginizerInfo, or NULL on error.
*/
public static function fromJson($json){
/** @var StdClass $apiResponse */
$apiResponse = json_decode($json);
if ( empty($apiResponse) || !is_object($apiResponse) ){
trigger_error(
"Failed to parse plugin metadata. Try validating your .json file with http://jsonlint.com/",
E_USER_NOTICE
);
return null;
}
$valid = self::validateMetadata($apiResponse);
if ( is_wp_error($valid) ){
trigger_error($valid->get_error_message(), E_USER_NOTICE);
return null;
}
$info = new self();
foreach(get_object_vars($apiResponse) as $key => $value){
$info->$key = $value;
}
//json_decode decodes assoc. arrays as objects. We want it as an array.
$info->sections = (array)$info->sections;
return $info;
}
/**
* Very, very basic validation.
*
* @param StdClass $apiResponse
* @return bool|WP_Error
*/
protected static function validateMetadata($apiResponse) {
if (
!isset($apiResponse->name, $apiResponse->version)
|| empty($apiResponse->name)
|| empty($apiResponse->version)
) {
return new WP_Error(
'puc-invalid-metadata',
"The plugin metadata file does not contain the required 'name' and/or 'version' keys."
);
}
return true;
}
/**
* Transform plugin info into the format used by the native WordPress.org API
*
* @return object
*/
public function toWpFormat(){
$info = new stdClass;
//The custom update API is built so that many fields have the same name and format
//as those returned by the native WordPress.org API. These can be assigned directly.
$sameFormat = array(
'name', 'slug', 'version', 'requires', 'tested', 'rating', 'upgrade_notice',
'num_ratings', 'downloaded', 'active_installs', 'homepage', 'last_updated',
);
foreach($sameFormat as $field){
if ( isset($this->$field) ) {
$info->$field = $this->$field;
} else {
$info->$field = null;
}
}
//Other fields need to be renamed and/or transformed.
$info->download_link = $this->download_url;
$info->author = $this->getFormattedAuthor();
$info->sections = array_merge(array('description' => ''), $this->sections);
if ( !empty($this->banners) ) {
//WP expects an array with two keys: "high" and "low". Both are optional.
//Docs: https://wordpress.org/plugins/about/faq/#banners
$info->banners = is_object($this->banners) ? get_object_vars($this->banners) : $this->banners;
$info->banners = array_intersect_key($info->banners, array('high' => true, 'low' => true));
}
return $info;
}
protected function getFormattedAuthor() {
if ( !empty($this->author_homepage) ){
return sprintf('%s', $this->author_homepage, $this->author);
}
return $this->author;
}
}
endif;
if ( !class_exists('LoginizerUpdate_3_2', false) ):
/**
* A simple container class for holding information about an available update.
*
* @author Janis Elsts
* @copyright 2016
* @version 3.2
* @access public
*/
#[\AllowDynamicProperties]
class LoginizerUpdate_3_2 {
public $id = 0;
public $slug;
public $version;
public $homepage;
public $download_url;
public $upgrade_notice;
public $tested;
public $translations = array();
public $filename; //Plugin filename relative to the plugins directory.
private static $fields = array(
'id', 'slug', 'version', 'homepage', 'tested',
'download_url', 'upgrade_notice', 'filename',
'translations', 'icons', 'banners'
);
/**
* Create a new instance of LoginizerUpdate from its JSON-encoded representation.
*
* @param string $json
* @return LoginizerUpdate_3_2|null
*/
public static function fromJson($json){
//Since update-related information is simply a subset of the full plugin info,
//we can parse the update JSON as if it was a plugin info string, then copy over
//the parts that we care about.
$pluginInfo = LoginizerInfo_3_2::fromJson($json);
if ( $pluginInfo != null ) {
return self::fromLoginizerInfo($pluginInfo);
} else {
return null;
}
}
/**
* Create a new instance of LoginizerUpdate based on an instance of LoginizerInfo.
* Basically, this just copies a subset of fields from one object to another.
*
* @param LoginizerInfo_3_2 $info
* @return LoginizerUpdate_3_2
*/
public static function fromLoginizerInfo($info){
return self::fromObject($info);
}
/**
* Create a new instance of LoginizerUpdate by copying the necessary fields from
* another object.
*
* @param StdClass|LoginizerInfo_3_2|LoginizerUpdate_3_2 $object The source object.
* @return LoginizerUpdate_3_2 The new copy.
*/
public static function fromObject($object) {
$update = new self();
$fields = self::$fields;
if ( !empty($object->slug) ) {
$fields = apply_filters('puc_retain_fields-' . $object->slug, $fields);
}
foreach($fields as $field){
if (property_exists($object, $field)) {
if(in_array($field, array('icons', 'banners'))){
$update->$field = (array) $object->$field;
}else{
$update->$field = $object->$field;
}
}
}
return $update;
}
/**
* Create an instance of StdClass that can later be converted back to
* a LoginizerUpdate. Useful for serialization and caching, as it avoids
* the "incomplete object" problem if the cached value is loaded before
* this class.
*
* @return StdClass
*/
public function toStdClass() {
$object = new stdClass();
$fields = self::$fields;
if ( !empty($this->slug) ) {
$fields = apply_filters('puc_retain_fields-' . $this->slug, $fields);
}
foreach($fields as $field){
if (property_exists($this, $field)) {
$object->$field = $this->$field;
}
}
return $object;
}
/**
* Transform the update into the format used by WordPress native plugin API.
*
* @return object
*/
public function toWpFormat(){
$update = new stdClass;
$update->id = $this->id;
$update->slug = $this->slug;
$update->new_version = $this->version;
$update->url = $this->homepage;
$update->package = $this->download_url;
$update->tested = $this->tested;
$update->plugin = $this->filename;
$update->icons = $this->icons;
$update->banners = $this->banners;
if ( !empty($this->upgrade_notice) ){
$update->upgrade_notice = $this->upgrade_notice;
}
return $update;
}
}
endif;
if ( !class_exists('Loginizer_PucScheduler_3_2', false) ):
/**
* The scheduler decides when and how often to check for updates.
* It calls @see LoginizerUpdateChecker::checkForUpdates() to perform the actual checks.
*
* @version 3.2
*/
class Loginizer_PucScheduler_3_2 {
public $checkPeriod = 12; //How often to check for updates (in hours).
public $throttleRedundantChecks = false; //Check less often if we already know that an update is available.
public $throttledCheckPeriod = 72;
/**
* @var LoginizerUpdateChecker_3_2
*/
protected $updateChecker;
private $cronHook = null;
/**
* Scheduler constructor.
*
* @param LoginizerUpdateChecker_3_2 $updateChecker
* @param int $checkPeriod How often to check for updates (in hours).
*/
public function __construct($updateChecker, $checkPeriod) {
$this->updateChecker = $updateChecker;
$this->checkPeriod = $checkPeriod;
//Set up the periodic update checks
$this->cronHook = 'check_plugin_updates-' . $this->updateChecker->slug;
if ( $this->checkPeriod > 0 ){
//Trigger the check via Cron.
//Try to use one of the default schedules if possible as it's less likely to conflict
//with other plugins and their custom schedules.
$defaultSchedules = array(
1 => 'hourly',
12 => 'twicedaily',
24 => 'daily',
);
if ( array_key_exists($this->checkPeriod, $defaultSchedules) ) {
$scheduleName = $defaultSchedules[$this->checkPeriod];
} else {
//Use a custom cron schedule.
$scheduleName = 'every' . $this->checkPeriod . 'hours';
add_filter('cron_schedules', array($this, '_addCustomSchedule'));
}
if ( !wp_next_scheduled($this->cronHook) && !defined('WP_INSTALLING') ) {
wp_schedule_event(time(), $scheduleName, $this->cronHook);
}
add_action($this->cronHook, array($this, 'maybeCheckForUpdates'));
register_deactivation_hook($this->updateChecker->pluginFile, array($this, '_removeUpdaterCron'));
//In case Cron is disabled or unreliable, we also manually trigger
//the periodic checks while the user is browsing the Dashboard.
add_action( 'admin_init', array($this, 'maybeCheckForUpdates') );
//Like WordPress itself, we check more often on certain pages.
/** @see wp_update_plugins */
add_action('load-update-core.php', array($this, 'maybeCheckForUpdates'));
add_action('load-plugins.php', array($this, 'maybeCheckForUpdates'));
add_action('load-update.php', array($this, 'maybeCheckForUpdates'));
//This hook fires after a bulk update is complete.
add_action('upgrader_process_complete', array($this, 'maybeCheckForUpdates'), 11, 0);
} else {
//Periodic checks are disabled.
wp_clear_scheduled_hook($this->cronHook);
}
}
/**
* Check for updates if the configured check interval has already elapsed.
* Will use a shorter check interval on certain admin pages like "Dashboard -> Updates" or when doing cron.
*
* You can override the default behaviour by using the "puc_check_now-$slug" filter.
* The filter callback will be passed three parameters:
* - Current decision. TRUE = check updates now, FALSE = don't check now.
* - Last check time as a Unix timestamp.
* - Configured check period in hours.
* Return TRUE to check for updates immediately, or FALSE to cancel.
*
* This method is declared public because it's a hook callback. Calling it directly is not recommended.
*/
public function maybeCheckForUpdates(){
if ( empty($this->checkPeriod) ){
return;
}
$state = $this->updateChecker->getUpdateState();
$shouldCheck =
empty($state) ||
!isset($state->lastCheck) ||
( (time() - $state->lastCheck) >= $this->getEffectiveCheckPeriod() );
//Let plugin authors substitute their own algorithm.
$shouldCheck = apply_filters(
'puc_check_now-' . $this->updateChecker->slug,
$shouldCheck,
(!empty($state) && isset($state->lastCheck)) ? $state->lastCheck : 0,
$this->checkPeriod
);
if ( $shouldCheck ) {
$this->updateChecker->checkForUpdates();
}
}
/**
* Calculate the actual check period based on the current status and environment.
*
* @return int Check period in seconds.
*/
protected function getEffectiveCheckPeriod() {
$currentFilter = current_filter();
if ( in_array($currentFilter, array('load-update-core.php', 'upgrader_process_complete')) ) {
//Check more often when the user visits "Dashboard -> Updates" or does a bulk update.
$period = 60;
} else if ( in_array($currentFilter, array('load-plugins.php', 'load-update.php')) ) {
//Also check more often on the "Plugins" page and /wp-admin/update.php.
$period = 3600;
} else if ( $this->throttleRedundantChecks && ($this->updateChecker->getUpdate() !== null) ) {
//Check less frequently if it's already known that an update is available.
$period = $this->throttledCheckPeriod * 3600;
} else if ( defined('DOING_CRON') && constant('DOING_CRON') ) {
//WordPress cron schedules are not exact, so lets do an update check even
//if slightly less than $checkPeriod hours have elapsed since the last check.
$cronFuzziness = 20 * 60;
$period = $this->checkPeriod * 3600 - $cronFuzziness;
} else {
$period = $this->checkPeriod * 3600;
}
return $period;
}
/**
* Add our custom schedule to the array of Cron schedules used by WP.
*
* @param array $schedules
* @return array
*/
public function _addCustomSchedule($schedules){
if ( $this->checkPeriod && ($this->checkPeriod > 0) ){
$scheduleName = 'every' . $this->checkPeriod . 'hours';
$schedules[$scheduleName] = array(
'interval' => $this->checkPeriod * 3600,
'display' => sprintf('Every %d hours', $this->checkPeriod),
);
}
return $schedules;
}
/**
* Remove the scheduled cron event that the library uses to check for updates.
*
* @return void
*/
public function _removeUpdaterCron(){
wp_clear_scheduled_hook($this->cronHook);
}
/**
* Get the name of the update checker's WP-cron hook. Mostly useful for debugging.
*
* @return string
*/
public function getCronHookName() {
return $this->cronHook;
}
}
endif;
if ( !class_exists('Loginizer_PucUpgraderStatus_3_2', false) ):
/**
* A utility class that helps figure out which plugin WordPress is upgrading.
*
* It may seem strange to have an separate class just for that, but the task is surprisingly complicated.
* Core classes like Plugin_Upgrader don't expose the plugin file name during an in-progress update (AFAICT).
* This class uses a few workarounds and heuristics to get the file name.
*/
class Loginizer_PucUpgraderStatus_3_2 {
private $upgradedPluginFile = null; //The plugin that is currently being upgraded by WordPress.
public function __construct() {
//Keep track of which plugin WordPress is currently upgrading.
add_filter('upgrader_pre_install', array($this, 'setUpgradedPlugin'), 10, 2);
add_filter('upgrader_package_options', array($this, 'setUpgradedPluginFromOptions'), 10, 1);
add_filter('upgrader_post_install', array($this, 'clearUpgradedPlugin'), 10, 1);
add_action('upgrader_process_complete', array($this, 'clearUpgradedPlugin'), 10, 1);
}
/**
* Is there and update being installed RIGHT NOW, for a specific plugin?
*
* Caution: This method is unreliable. WordPress doesn't make it easy to figure out what it is upgrading,
* and upgrader implementations are liable to change without notice.
*
* @param string $pluginFile The plugin to check.
* @param WP_Upgrader|null $upgrader The upgrader that's performing the current update.
* @return bool True if the plugin identified by $pluginFile is being upgraded.
*/
public function isPluginBeingUpgraded($pluginFile, $upgrader = null) {
if ( isset($upgrader) ) {
$upgradedPluginFile = $this->getPluginBeingUpgradedBy($upgrader);
if ( !empty($upgradedPluginFile) ) {
$this->upgradedPluginFile = $upgradedPluginFile;
}
}
return ( !empty($this->upgradedPluginFile) && ($this->upgradedPluginFile === $pluginFile) );
}
/**
* Get the file name of the plugin that's currently being upgraded.
*
* @param Plugin_Upgrader|WP_Upgrader $upgrader
* @return string|null
*/
private function getPluginBeingUpgradedBy($upgrader) {
if ( !isset($upgrader, $upgrader->skin) ) {
return null;
}
//Figure out which plugin is being upgraded.
$pluginFile = null;
$skin = $upgrader->skin;
if ( $skin instanceof Plugin_Upgrader_Skin ) {
if ( isset($skin->plugin) && is_string($skin->plugin) && ($skin->plugin !== '') ) {
$pluginFile = $skin->plugin;
}
} elseif ( isset($skin->plugin_info) && is_array($skin->plugin_info) ) {
//This case is tricky because Bulk_Plugin_Upgrader_Skin (etc) doesn't actually store the plugin
//filename anywhere. Instead, it has the plugin headers in $plugin_info. So the best we can
//do is compare those headers to the headers of installed plugins.
$pluginFile = $this->identifyPluginByHeaders($skin->plugin_info);
}
return $pluginFile;
}
/**
* Identify an installed plugin based on its headers.
*
* @param array $searchHeaders The plugin file header to look for.
* @return string|null Plugin basename ("foo/bar.php"), or NULL if we can't identify the plugin.
*/
private function identifyPluginByHeaders($searchHeaders) {
if ( !function_exists('get_plugins') ){
/** @noinspection PhpIncludeInspection */
require_once( ABSPATH . '/wp-admin/includes/plugin.php' );
}
$installedPlugins = get_plugins();
$matches = array();
foreach($installedPlugins as $pluginBasename => $headers) {
$diff1 = array_diff_assoc($headers, $searchHeaders);
$diff2 = array_diff_assoc($searchHeaders, $headers);
if ( empty($diff1) && empty($diff2) ) {
$matches[] = $pluginBasename;
}
}
//It's possible (though very unlikely) that there could be two plugins with identical
//headers. In that case, we can't unambiguously identify the plugin that's being upgraded.
if ( count($matches) !== 1 ) {
return null;
}
return reset($matches);
}
/**
* @access private
*
* @param mixed $input
* @param array $hookExtra
* @return mixed Returns $input unaltered.
*/
public function setUpgradedPlugin($input, $hookExtra) {
if (!empty($hookExtra['plugin']) && is_string($hookExtra['plugin'])) {
$this->upgradedPluginFile = $hookExtra['plugin'];
} else {
$this->upgradedPluginFile = null;
}
return $input;
}
/**
* @access private
*
* @param array $options
* @return array
*/
public function setUpgradedPluginFromOptions($options) {
if (isset($options['hook_extra']['plugin']) && is_string($options['hook_extra']['plugin'])) {
$this->upgradedPluginFile = $options['hook_extra']['plugin'];
} else {
$this->upgradedPluginFile = null;
}
return $options;
}
/**
* @access private
*
* @param mixed $input
* @return mixed Returns $input unaltered.
*/
public function clearUpgradedPlugin($input = null) {
$this->upgradedPluginFile = null;
return $input;
}
}
endif;
if ( !class_exists('Loginizer_PucFactory', false) ):
/**
* A factory that builds instances of other classes from this library.
*
* When multiple versions of the same class have been loaded (e.g. LoginizerUpdateChecker 1.2
* and 1.3), this factory will always use the latest available version. Register class
* versions by calling {@link Loginizer_PucFactory::addVersion()}.
*
* At the moment it can only build instances of the LoginizerUpdateChecker class. Other classes
* are intended mainly for internal use and refer directly to specific implementations. If you
* want to instantiate one of them anyway, you can use {@link Loginizer_PucFactory::getLatestClassVersion()}
* to get the class name and then create it with new $class(...).
*/
class Loginizer_PucFactory {
protected static $classVersions = array();
protected static $sorted = false;
/**
* Create a new instance of LoginizerUpdateChecker.
*
* @see LoginizerUpdateChecker::__construct()
*
* @param $metadataUrl
* @param $pluginFile
* @param string $slug
* @param int $checkPeriod
* @param string $optionName
* @param string $muPluginFile
* @return LoginizerUpdateChecker_3_2
*/
public static function buildUpdateChecker($metadataUrl, $pluginFile, $slug = '', $checkPeriod = 12, $optionName = '', $muPluginFile = '') {
$class = self::getLatestClassVersion('LoginizerUpdateChecker');
return new $class($metadataUrl, $pluginFile, $slug, $checkPeriod, $optionName, $muPluginFile);
}
/**
* Get the specific class name for the latest available version of a class.
*
* @param string $class
* @return string|null
*/
public static function getLatestClassVersion($class) {
if ( !self::$sorted ) {
self::sortVersions();
}
if ( isset(self::$classVersions[$class]) ) {
return reset(self::$classVersions[$class]);
} else {
return null;
}
}
/**
* Sort available class versions in descending order (i.e. newest first).
*/
protected static function sortVersions() {
foreach ( self::$classVersions as $class => $versions ) {
uksort($versions, array(__CLASS__, 'compareVersions'));
self::$classVersions[$class] = $versions;
}
self::$sorted = true;
}
protected static function compareVersions($a, $b) {
return -version_compare($a, $b);
}
/**
* Register a version of a class.
*
* @access private This method is only for internal use by the library.
*
* @param string $generalClass Class name without version numbers, e.g. 'LoginizerUpdateChecker'.
* @param string $versionedClass Actual class name, e.g. 'LoginizerUpdateChecker_1_2'.
* @param string $version Version number, e.g. '1.2'.
*/
public static function addVersion($generalClass, $versionedClass, $version) {
if ( !isset(self::$classVersions[$generalClass]) ) {
self::$classVersions[$generalClass] = array();
}
self::$classVersions[$generalClass][$version] = $versionedClass;
self::$sorted = false;
}
}
endif;
//Register classes defined in this file with the factory.
Loginizer_PucFactory::addVersion('LoginizerUpdateChecker', 'LoginizerUpdateChecker_3_2', '3.2');
Loginizer_PucFactory::addVersion('LoginizerUpdate', 'LoginizerUpdate_3_2', '3.2');
Loginizer_PucFactory::addVersion('LoginizerInfo', 'LoginizerInfo_3_2', '3.2');
Loginizer_PucFactory::addVersion('Loginizer_PucGitHubChecker', 'Loginizer_PucGitHubChecker_3_2', '3.2');
updater/license.txt 0000644 00000002037 14757772106 0010415 0 ustar 00 Copyright (c) 2014 Jānis Elsts
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. functions.php 0000644 00000016470 14757772106 0007315 0 ustar 00 response) || !isset($transient->response[$plugin])){
return $transient;
}
$free_version = loginizer_pro_get_free_version_num();
// Update the Loginizer version to the equivalent of Pro version
if(version_compare($free_version, LOGINIZER_PRO_VERSION, '<')){
$transient->response[$plugin]->package = 'https://downloads.wordpress.org/plugin/loginizer.'.LOGINIZER_PRO_VERSION.'.zip';
}else{
unset($transient->response[$plugin]);
}
return $transient;
}
// Auto update free version after update pro version
function loginizer_pro_update_free_after_pro($upgrader_object, $options) {
// Check if the action is an update for the plugins
if($options['action'] != 'update' || $options['type'] != 'plugin'){
return;
}
// Define the slugs for the free and pro plugins
$free_slug = 'loginizer/loginizer.php';
$pro_slug = 'loginizer-security/loginizer-security.php';
// Check if the pro plugin is in the list of updated plugins
if(
(isset($options['plugins']) && in_array($pro_slug, $options['plugins'])) ||
(isset($options['plugin']) && $pro_slug == $options['plugin'])
){
// Trigger the update for the free plugin
$current_version = loginizer_pro_get_free_version_num();
if(empty($current_version)){
return;
}
// Check for updates for the free plugin
include_once(ABSPATH . 'wp-admin/includes/plugin.php');
$update_plugins = get_site_transient('update_plugins');
if(isset($update_plugins->response[$free_slug])){
$free_plugin_update = $update_plugins->response[$free_slug];
// If there's an update available, proceed to update the free plugin
if(version_compare($free_plugin_update->new_version, $current_version, '>')){
require_once(ABSPATH . 'wp-admin/includes/class-wp-upgrader.php');
$upgrader = new Plugin_Upgrader();
$upgrader->upgrade($free_slug);
}
}
}
}
function loginizer_pro_update_checker(){
$current_version = get_option('loginizer_pro_version', '0.0');
$version = (int) str_replace('.', '', $current_version);
// No update required
if($current_version == LOGINIZER_PRO_VERSION){
return true;
}
$is_network_wide = loginizer_pro_is_network_active('loginizer-security');
if($is_network_wide){
$free_ins = get_site_option('loginizer_free_installed');
}else{
$free_ins = get_option('loginizer_free_installed');
}
// If plugin reached here it means Loginizer free installed
if(empty($free_ins)){
if($is_network_wide){
update_site_option('loginizer_free_installed', time());
}else{
update_option('loginizer_free_installed', time());
}
}
update_option('loginizer_version_pro_nag', time());
update_option('loginizer_version_free_nag', time());
update_option('loginizer_pro_version', LOGINIZER_PRO_VERSION);
}
// Add our license key if ANY
function loginizer_updater_filter_args($queryArgs) {
global $loginizer;
if ( !empty($loginizer['license']['license']) ) {
$queryArgs['license'] = $loginizer['license']['license'];
}
$queryArgs['url'] = rawurlencode(site_url());
return $queryArgs;
}
// Handle the Check for update link and ask to install license key
function loginizer_updater_check_link($final_link){
global $loginizer;
if(empty($loginizer['license']['license'])){
return 'Install License Key to Update';
}
return $final_link;
}
function loginizer_pro_load_license($parent = 0){
global $loginizer;
// Load license
if(!empty($parent)){
$license_field = 'softaculous_pro_license';
$license_api_url = 'https://a.softaculous.com/softwp/';
$prods = apply_filters('softaculous_pro_products', []);
}else{
$license_field = 'loginizer_license';
$license_api_url = LOGINIZER_API;
$prods = [];
}
$loginizer['license'] = get_option($license_field, []);
// Update license details as well
if(!empty($loginizer['license']) && !empty($loginizer['license']['license']) && (time() - @$loginizer['license']['last_update']) >= 86400){
$resp = wp_remote_get($license_api_url.'license.php?license='.$loginizer['license']['license'].'&prods='.implode(',', $prods).'&url='.rawurlencode(site_url()));
// Did we get a response ?
if(is_array($resp)){
$tosave = json_decode($resp['body'], true);
// Is it the license ?
if(!empty($tosave['license'])){
$tosave['last_update'] = time();
update_option($license_field, $tosave);
}
}
}
// If the license is Free or Expired check for Softaculous Pro license
if(empty($loginizer['license']) || empty($loginizer['license']['active'])){
if(function_exists('softaculous_pro_load_license')){
$softaculous_license = softaculous_pro_load_license();
if(!empty($softaculous_license['license']) &&
(!empty($softaculous_license['active']) || empty($loginizer['license']))
){
$loginizer['license'] = $softaculous_license;
}
}elseif(empty($parent)){
$loginizer['license'] = get_option('softaculous_pro_license', []);
if(!empty($loginizer['license'])){
loginizer_pro_load_license(1);
}
}
}
}
add_filter('softaculous_pro_products', 'loginizer_softaculous_pro_products', 10, 1);
function loginizer_softaculous_pro_products($r = []){
$r['loginizer'] = 'loginizer';
return $r;
}
function loginizer_pro_api_url($main_server = 0, $suffix = 'loginizer'){
global $loginizer;
$r = array(
'https://s0.softaculous.com/a/softwp/',
'https://s1.softaculous.com/a/softwp/',
'https://s2.softaculous.com/a/softwp/',
'https://s3.softaculous.com/a/softwp/',
'https://s4.softaculous.com/a/softwp/',
'https://s5.softaculous.com/a/softwp/',
'https://s7.softaculous.com/a/softwp/',
'https://s8.softaculous.com/a/softwp/'
);
$mirror = $r[array_rand($r)];
// If the license is newly issued, we need to fetch from API only
if(!empty($main_server) || empty($loginizer['license']['last_edit']) ||
(!empty($loginizer['license']['last_edit']) && (time() - 3600) < $loginizer['license']['last_edit'])
){
$mirror = LOGINIZER_API;
}
if(!empty($suffix)){
$mirror = str_replace('/softwp', '/'.$suffix, $mirror);
}
return $mirror;
} index.php 0000644 00000000032 14757772106 0006377 0 ustar 00 30));
if(is_array($resp)){
$json = json_decode($resp['body'], true);
//print_r($json);
}
// Save the License
if(!empty($json['license'])){
update_option('loginizer_license', $json);
}
}
unlink(__DIR__.'/license.key');
}
// Load license
loginizer_pro_load_license();
// Check for updates
include_once('updater/plugin-update-checker.php');
$loginizer_updater = Loginizer_PucFactory::buildUpdateChecker(loginizer_pro_api_url().'/updates.php?version='.LOGINIZER_PRO_VERSION, LOGINIZER_PRO_FILE);
// Add the license key to query arguments
$loginizer_updater->addQueryArgFilter('loginizer_updater_filter_args');
// Show the text to install the license key
add_filter('puc_manual_final_check_link-loginizer-security', 'loginizer_updater_check_link', 10, 1);
add_filter('plugin_row_meta', 'loginizer_plugin_row_links', 10, 2);
}
// Checking For SSO
if(!empty($_GET['ssotoken'])){
add_filter('authenticate', 'loginizer_sso_authenticate', 10003, 3);
add_action('wp_login_errors', 'loginizer_error_handler', 10001, 2);
add_action('wp_login', 'loginizer_login_success', 10, 2);
}
// CSRF Session URL
if(!empty($loginizer['enable_csrf_protection']) && loginizer_is_csrf_prot_mod_set()){
add_action('init', 'loginizer_csrf_sess_init');
add_filter('login_redirect', 'loginizer_login_csrf_redirect', 200, 3);
add_action('admin_bar_menu', 'loginizer_csrf_admin_bar_shortcut', 70);
add_filter('admin_url', 'loginizer_csrf_admin_redirects', 100005, 3);
add_filter('wp_redirect', 'loginizer_csrf_wp_redirects');
add_action('set_auth_cookie', 'loginizer_admin_url_cookie'); // Creates session key and handles cookies
add_action('wp_logout', 'loginizer_destroy_csrf_session', 10, 1);
}
// Handles Concurrent Sessions
if(!empty($loginizer['limit_session']) && !empty($loginizer['limit_session']['enable'])){
add_filter('wp_authenticate_user', 'loginizer_limit_sessions');
add_filter('check_password', 'loginizer_limit_destroy_sessions_handler', 10, 4);
}
// MasterStudy Login filter
add_filter('stm_lms_login', 'loginizer_handle_stm_lms_login');
add_filter('loginizer_system_information', 'loginizer_premium_system_info', 10);
add_filter('loginizer_pre_page_dashboard', 'loginizer_premium_page_dashboard', 10);
// A way to remove the settings
if(file_exists(LOGINIZER_PRO_DIR.'/reset_admin.txt')){
update_option('loginizer_wp_admin', array());
}
// Are we to ban user emails ?
if(!empty($loginizer['domains_blacklist']) && count($loginizer['domains_blacklist']) > 0){
add_filter('registration_errors', 'loginizer_domains_blacklist', 10, 3);
add_filter('woocommerce_registration_errors', 'loginizer_domains_blacklist', 10, 3);
}
// Is email password less login enabled ?
if(!empty($loginizer['email_pass_less']) && !defined('XMLRPC_REQUEST')){
// Add a handler for the GUI Login
add_filter('authenticate', 'loginizer_epl_wp_authenticate', 10002, 3);
// Dont show password error
add_filter('wp_login_errors', 'loginizer_epl_error_handler', 10000, 2);
// Hide the password field
add_action('login_enqueue_scripts', 'loginizer_epl_hide_pass');
add_action('wp_enqueue_scripts', 'loginizer_epl_hide_woocommerce_pass');
}
// Are we to rename the login ?
if(!empty($loginizer['login_slug'])){
//$loginizer['login_slug'] = 'login';
// Add the filters / actions
add_filter('site_url', 'loginizer_rl_site_url', 10, 2);
add_filter('network_site_url', 'loginizer_rl_site_url', 10, 2);
add_filter('wp_redirect', 'loginizer_rl_wp_redirect', 10, 2);
add_filter('register', 'loginizer_rl_register');
add_action('wp_loaded', 'loginizer_rl_wp_loaded');
}
// Rename the WP-ADMIN folder
if(!defined('SITEPAD') && !empty($loginizer['admin_slug'])){
add_filter('admin_url', 'loginizer_admin_url', 10001, 3);
add_action('set_auth_cookie', 'loginizer_admin_url_cookie');
// For multisite
if(lz_is_multisite()){
add_filter('network_admin_url', 'loginizer_network_admin_url', 10001, 2);
}
if(!empty($loginizer['restrict_wp_admin']) && preg_match('/\/wp-admin/is', $_SERVER['REQUEST_URI'])){
die(empty($loginizer['wp_admin_msg']) ? $loginizer['wp_admin_d_msg'] : $loginizer['wp_admin_msg']);
}
}
// Are we to rename the xmlrpc ?
if(!defined('SITEPAD') && !empty($loginizer['xmlrpc_slug']) && empty($loginizer['xmlrpc_disable'])){
// Add the filters / actions
add_action('wp_loaded', 'loginizer_xml_rename_wp_loaded');
}
// Are we to DISABLE the xmlrpc ?
if(!empty($loginizer['xmlrpc_disable'])){
// Add the filters / actions
add_filter('xmlrpc_enabled', 'loginizer_xmlrpc_null');
add_filter('bloginfo_url', 'loginizer_xmlrpc_remove_pingback_url', 10000, 2);
add_action('wp_loaded', 'loginizer_xmlrpc_disable');
}
// Are we to disable pingbacks ?
if(!empty($loginizer['pingbacks_disable'])){
// Add the filters / actions
add_filter('xmlrpc_methods', 'loginizer_pingbacks_disable');
}
//-----------------------------------
// Add the captcha filters / actions
//-----------------------------------
if(!empty($loginizer['social_settings']) && !loginizer_is_blacklisted()){
// Shortcode has options shape|divider|type
add_shortcode('loginizer_social', 'loginizer_social_shortcode');
if(!empty($_COOKIE['lz_social_error'])){
add_action('woocommerce_before_customer_login_form', 'loginizer_social_wc_error');
}
if(!empty($loginizer['social_settings']['general']['save_avatar'])){
add_filter('get_avatar', 'loginizer_social_update_avatar', 1, 5);
}
if(!empty($loginizer['social_settings']['login']['registration_form'])){
add_action('register_form', 'loginizer_social_btn_login', 100);
}
if(in_array('woocommerce/woocommerce.php', apply_filters('active_plugins', get_option('active_plugins')))){
if(!empty($loginizer['social_settings']['woocommerce']['login_form'])){
add_action('woocommerce_login_form', 'loginizer_social_btn_woocommerce', 100);
}
if(!empty($loginizer['social_settings']['woocommerce']['registration_form'])){
add_action('woocommerce_register_form', 'loginizer_social_btn_woocommerce');
}
}
if(!empty($loginizer['social_settings']['comment']['enable_buttons'])){
add_action('comment_form_must_log_in_after', 'loginizer_social_btn_comment');
}
}
if(!empty($loginizer['captcha_key']) || !empty($loginizer['captcha_no_google']) || !empty($loginizer['captcha_status'])){
add_action('login_init', 'loginizer_cap_session_key');
// Is reCaptcha on for login ?
if(!empty($loginizer['captcha_login']) && !defined('XMLRPC_REQUEST')){
add_filter('authenticate', 'loginizer_cap_login_verify', 10000);
add_action('login_form', 'loginizer_cap_form_login', 100);
add_action('woocommerce_login_form', 'loginizer_cap_form_login', 100);
// Need to make more room for login form
if(empty($loginizer['captcha_remove_css'])){
add_action('login_enqueue_scripts', 'loginizer_cap_login_form');
}
}
// Is reCaptcha on for Lost Password utility ?
if(!empty($loginizer['captcha_lostpass'])){
add_action('allow_password_reset', 'loginizer_cap_lostpass_verify', 10, 2);
add_action('lostpassword_form', 'loginizer_cap_form_login', 100);
add_filter('woocommerce_lostpassword_form', 'loginizer_cap_form_login');
}
// Is reCaptcha on for Reset Password utility ?
if(!empty($loginizer['captcha_resetpass'])){
add_filter('validate_password_reset', 'loginizer_cap_resetpass_verify', 10, 2);
add_action('resetpass_form', 'loginizer_cap_reset_form', 99);
add_filter('woocommerce_resetpassword_form', 'loginizer_cap_form_login');
}
// Is reCaptcha on for registration ?
if(!empty($loginizer['captcha_register'])){
add_filter('registration_errors', 'loginizer_cap_register_verify', 10, 3);
add_action('register_form', 'loginizer_cap_form_login', 100);
// For BuddyPress
add_filter('bp_signup_validate', 'loginizer_cap_register_verify_buddypress', 10, 3);
add_action('bp_after_signup_profile_fields', 'loginizer_cap_form_login', 100);
add_filter('woocommerce_before_checkout_process', 'loginizer_wc_before_checkout_process', 10);
add_filter('woocommerce_register_form', 'loginizer_cap_form_login');
add_filter('woocommerce_registration_errors', 'loginizer_cap_register_verify', 10, 3);
if(!empty($loginizer['captcha_wc_checkout'])){
add_action('woocommerce_checkout_order_review', 'loginizer_cap_form_ecommerce');
}
}
// Are we to show Captcha for guests only ?
if((is_user_logged_in() && empty($loginizer['captcha_user_hide'])) || !is_user_logged_in()){
// Is reCaptcha on for comment utility ?
if(!empty($loginizer['captcha_comment'])){
add_filter('preprocess_comment', 'loginizer_cap_comment_verify');
add_action('comment_form', 'loginizer_cap_comment_form');
}
// Is reCaptcha on for WooCommerce Logout utility ?
if(!empty($loginizer['captcha_wc_checkout'])){
add_action('woocommerce_after_checkout_validation', 'loginizer_wc_checkout_verify');
add_action('woocommerce_checkout_order_review', 'loginizer_cap_form_ecommerce');
}
}
}
//-----------------
// Two Factor Auth
//-----------------
if(!defined('SITEPAD') && loginizer_is_2fa_enabled() && !defined('XMLRPC_REQUEST')){
// After username and password check has been verified, are we to redirect ?
add_filter('authenticate', 'loginizer_user_redirect', 10003, 3);
$user_id = get_current_user_id();
$lz_2fa_state = get_transient('loginizer_2fa_'. $user_id);
// To redirect after login
if(!empty($_COOKIE['loginizer_2fa_' . $user_id]) && !empty($lz_2fa_state) && $lz_2fa_state != '2fa'){
loginizer_2fa_ajax_redirect();
}
$login_slug = 'wp-login.php';
if($loginizer['login_slug']){
$login_slug = $loginizer['login_slug'];
}
if(loginizer_cur_page() !== $login_slug && !empty($lz_2fa_state) && $lz_2fa_state == '2fa'){
wp_logout();
wp_safe_redirect(admin_url());
exit;
}
// Shows the Question / 2fa field
add_action('login_form_loginizer_security', 'loginizer_user_security');
$cur_user = wp_get_current_user();
//Add the Loginizer Security Settings Page for WooCommerce
if(class_exists('WooCommerce') && loginizer_is_2fa_applicable($cur_user)){
add_action( 'init', 'loginizer_add_premium_security_endpoint' );
add_filter( 'query_vars', 'loginizer_premium_security_query_vars', 0 );
add_filter( 'woocommerce_account_menu_items', 'loginizer_add_premium_security_link_my_account' );
add_action( 'woocommerce_account_loginizer-security_endpoint', 'loginizer_user_page' );
}
// Is the user logged in ?
if(is_user_logged_in()){
// Load user settings
loginizer_load_user_settings($tfa_uid, $tfa_user, $tfa_settings, $tfa_current_pref);
// If 2FA applicable as per role
if(loginizer_is_2fa_applicable($tfa_user)){
// Add to Settings menu on sites
add_action('admin_menu', 'loginizer_user_menu');
// Show the user the notification to set a 2FA
$loginizer['loginizer_2fa_notice'] = get_user_meta($tfa_uid, 'loginizer_2fa_notice');
// Are we to show the loginizer notification to set a 2FA
if(empty($loginizer['loginizer_2fa_notice']) && (empty($_COOKIE['loginizer_2fa_notice_'.$tfa_uid]) || $_COOKIE['loginizer_2fa_notice_'.$tfa_uid] != md5(wp_get_session_token())) &&
(empty($tfa_current_pref) || $tfa_current_pref == 'none') &&
lz_optget('page') != 'loginizer_user'
){
add_action('admin_notices', 'loginizer_2fa_notice');
}
// Are we to disable the notice forever ?
if(isset($_GET['loginizer_2fa_notice']) && (int)$_GET['loginizer_2fa_notice'] == 0){
update_user_meta($tfa_uid, 'loginizer_2fa_notice', time());
die('DONE');
}
// Are we to disable the notice temporarily ?
if(isset($_GET['loginizer_2fa_notice']) && (int)$_GET['loginizer_2fa_notice'] == 1){
@setcookie('loginizer_2fa_notice_'.$tfa_uid, md5(wp_get_session_token()), time() + (3 * DAY_IN_SECONDS), COOKIEPATH, COOKIE_DOMAIN, is_ssl());
}
}
add_filter('manage_users_columns', 'loginizer_2fa_columns_users');
add_filter('manage_users_custom_column', 'loginizer_2fa_column_data', 10, 3);
}
}
// Checksum is enabled right i.e. its not disabled ?
if(!defined('SITEPAD') && empty($loginizer['disable_checksum'])){
// Create an action always
add_action('loginizer_do_checksum', 'loginizer_checksums');
// Difference in seconds since last time
$diff = (time() - $loginizer['checksums_last_run']);
// Has it crossed the time ?
if(($diff / 86400) >= $loginizer['checksum_frequency']){
//loginizer_checksums();
wp_schedule_single_event(time(), 'loginizer_do_checksum');
}
}
if(wp_doing_ajax()){
include_once LOGINIZER_PRO_DIR . 'main/ajax.php';
return;
}
if(is_admin()){
include_once LOGINIZER_PRO_DIR . 'main/admin.php';
}
}
function loginizer_social_wc_error(){
// Showing woocommerce error
if(!function_exists('wc_add_wp_error_notices')){
return;
}
$errors = loginizer_social_login_error_handler();
if(empty($errors) || !is_wp_error($errors)){
return;
}
wc_add_wp_error_notices($errors);
loginizer_woocommerce_error_handler();
woocommerce_output_all_notices();
}
function loginizer_premium_system_info(){
global $loginizer;
echo '
';
}
function loginizer_premium_page_dashboard(){
global $loginizer, $lz_error;
// Is there a license key ?
if(isset($_POST['save_lz'])){
$license = lz_optpost('lz_license');
// Check if its a valid license
if(empty($license)){
$lz_error['lic_invalid'] = __('The license key was not submitted', 'loginizer');
return loginizer_page_dashboard_T();
}
$resp = wp_remote_get(LOGINIZER_API.'license.php?license='.$license.'&url='.rawurlencode(site_url()), array('timeout' => 30));
if(is_array($resp)){
$json = json_decode($resp['body'], true);
//print_r($json);
}else{
$lz_error['resp_invalid'] = __('The response was malformed '.var_export($resp, true), 'loginizer');
return loginizer_page_dashboard_T();
}
// Save the License
if(empty($json['license'])){
$lz_error['lic_invalid'] = __('The license key is invalid', 'loginizer');
return loginizer_page_dashboard_T();
}else{
update_option('loginizer_license', $json);
// Mark as saved
$GLOBALS['lz_saved'] = true;
$loginizer['license'] = get_option('loginizer_license');
}
}
}
// Change the Admin URL
function loginizer_admin_url($url, $path, $blog_id){
global $loginizer;
//echo $url."\n";echo $path."\n";
$new = str_replace('wp-admin', $loginizer['admin_slug'], $url);
//echo $new.' ';
return $new;
}
function loginizer_network_admin_url($url, $path){
global $loginizer;
//echo $url.' ';echo $path.' ';
$new = str_replace('wp-admin', $loginizer['admin_slug'], $url);
//echo $new.' ';
return $new;
}
// Required to be able to Login
function loginizer_admin_url_cookie($auth_cookie, $expire = 0, $expiration = '', $user_id = '', $scheme = ''){
global $loginizer;
if($scheme == 'secure_auth' || is_ssl()){
$auth_cookie_name = SECURE_AUTH_COOKIE;
$secure = true;
}else {
$auth_cookie_name = AUTH_COOKIE;
$secure = false;
}
$admin_slug = $loginizer['admin_slug'];
// Auth cookie has the user's username in it as the first word before pipe | so we get the user name through that
if(!empty($loginizer['enable_csrf_protection']) && !empty($auth_cookie)){
$u_login = explode('|', $auth_cookie);
$u_login = $u_login[0];
$user = get_user_by('login', $u_login);
$session = get_user_meta($user->ID, 'loginizer_csrf_session', true);
if(empty($session)){
loginizer_csrf_create_session($user->ID);
}
$session = get_user_meta($user->ID, 'loginizer_csrf_session', true);
$admin_slug = 'wp-admin-' . $session;
if(!empty($loginizer['admin_slug'])){
$admin_slug = $loginizer['admin_slug'] . '-' . $session;
}
}
@setcookie($auth_cookie_name, $auth_cookie, $expire, SITECOOKIEPATH . $admin_slug, COOKIE_DOMAIN, $secure, true);
}
// Verifies if the token is valid and creates the user session
function loginizer_epl_verify(){
global $loginizer;
if(empty($_GET['uid']) || empty($_GET['lepltoken'])){
return false;
}
$uid = (int) sanitize_key($_GET['uid']);
$token = sanitize_key($_GET['lepltoken']);
$action = 'loginizer_epl_'.$uid;
$hash = get_user_meta($uid, $action, true);
$expires = get_user_meta($uid, $action.'_expires', true);
include_once(ABSPATH.'/'.$loginizer['wp-includes'].'/class-phpass.php');
$wp_hasher = new PasswordHash(8, TRUE);
$time = time();
if(!$wp_hasher->CheckPassword($expires.$token, $hash) || $expires < $time){
$token_error_msg = __('The token is invalid or has expired. Please request a new email', 'loginizer');
// Throw an error
return new WP_Error('token_invalid', $token_error_msg, 'loginizer_epl');
}else{
if(!empty($loginizer['limit_session']) && !empty($loginizer['limit_session']['enable'])){
$limit_session = loginizer_limit_destroy_sessions($uid);
if(empty($limit_session)){
return new WP_Error('loginizer_session_limit', __('User ID not found so can not proceed', 'loginizer'), 'loginizer_epl');
}
}
// Login the User
wp_set_auth_cookie($uid);
// Delete the meta
delete_user_meta($uid, $action);
delete_user_meta($uid, $action.'_expires');
$user = get_user_by('id', $uid);
$redirect = !empty($_REQUEST['redirect_to']) ? esc_url_raw($_REQUEST['redirect_to']) : '';
if(!empty($loginizer['passwordless_redirect']) && !empty($user) && !empty($user->roles)){
$roles = $user->roles;
if(!is_array($user->roles)) {
$roles = [$user->roles];
}
// To check if we need a custom redirect for the role this user has
foreach($roles as $r){
if(!empty($loginizer['passwordless_redirect_for']) && in_array($r, $loginizer['passwordless_redirect_for'])){
$redirect = $loginizer['passwordless_redirect'];
break;
}
}
}
$redirect_to = !empty($redirect) ? $redirect : admin_url();
$redirect_to = loginizer_csrf_change_url($redirect_to, $uid);
loginizer_update_attempt_stats(1);
// Redirect and exit
wp_safe_redirect($redirect_to);
exit;
}
return false;
}
// Hides the password field for the password less email login
function loginizer_epl_hide_pass() {
?>
errors);echo ' ';
// Remove the empty password error
if(is_wp_error($errors)){
$errors->remove('empty_password');
}
return $errors;
}
// Handles the verification of the username or email
function loginizer_epl_wp_authenticate($user, $username, $password){
global $loginizer;
//echo 'loginizer_epl_wp_authenticate : '; print_r($user).' ';
if(is_wp_error($user)){
// Ignore certain codes
$ignore_codes = array('empty_username', 'empty_password');
if(is_wp_error($user) && !in_array($user->get_error_code(), $ignore_codes)) {
return $user;
}
}
// Is it a login attempt
$verified = loginizer_epl_verify();
if(is_wp_error($verified)){
return $verified;
}
if(empty($username) && empty($_POST)){
return $user;
}
$email = NULL;
// Is it an email address ?
if(is_email($username) && email_exists($username)){
$email = $username;
}
// Maybe its a username
if(!is_email($username) && username_exists($username)){
$user = get_user_by('login', $username);
if($user){
$email = $user->data->user_email;
}
}
// Did you get any valid email ?
if(empty($email)){
$account_error_msg = __('The username or email you provided does not exist !', 'loginizer');
return new WP_Error('invalid_account', $account_error_msg, 'loginizer_epl');
}
if(!empty($loginizer['limit_session']) && !empty($loginizer['limit_session']['enable'])){
$user = get_user_by('email', $email);
$session_limit = loginizer_limit_sessions($user);
if(is_wp_error($session_limit)){
return $session_limit;
}
}
// Send the email
$site_name = get_bloginfo('name');
$login_url = loginizer_epl_login_url($email);
$vars = array('email' => $email,
'site_name' => $site_name,
'site_url' => get_site_url(),
'login_url' => $login_url);
$subject = lz_lang_vars_name($loginizer['passwordless_sub'], $vars);
$message = lz_lang_vars_name($loginizer['passwordless_msg'], $vars);
//echo $subject.'
';echo $message;
$headers = array();
// Do we need to send the email as HTML ?
if(!empty($loginizer['passwordless_html'])){
$headers[] = 'Content-Type: text/html; charset=UTF-8';
if(!empty($loginizer['passwordless_msg_is_custom'])){
$message = html_entity_decode($message);
}else{
$message = preg_replace("/\ /i", " ", $message);
$message = preg_replace('/(?)\n/i', " \n", $message);
}
}
$sent = wp_mail($email, $subject, $message, $headers);
//echo $login_url;
if(empty($sent)){
$email_not_sent = __('There was a problem sending your email. Please try again or contact an admin.', 'loginizer');
return new WP_Error('email_not_sent', $email_not_sent, 'loginizer_epl');
}else{
$loginizer['no_loginizer_logs'] = 1;
$email_sent_msg = __('An email has been sent with the Login URL', 'loginizer');
return new WP_Error('email_sent', $email_sent_msg, 'message');
}
}
// Generate the URL for the
function loginizer_epl_login_url($email){
// Get the User ID
$user = get_user_by('email', $email);
$token = loginizer_epl_token($user->ID);
// The current URL
$redirect_url = '';
if(!empty($_REQUEST['redirect_to'])){
$redirect_url = $_REQUEST['redirect_to'];
} elseif (!empty($_REQUEST['redirect'])){
$redirect_url = $_REQUEST['redirect'];
} elseif(!empty(wp_validate_redirect($_SERVER['HTTP_REFERER']))){
$redirect_url = wp_validate_redirect($_SERVER['HTTP_REFERER']);
}
$redirect_param = (!empty($redirect_url) ? '&redirect_to='.urlencode($redirect_url) : '');
$url = wp_login_url().'?uid='.$user->ID.'&lepltoken='.$token.$redirect_param;
return $url;
}
// Creates a one time token
function loginizer_epl_token($uid = 0){
global $loginizer;
// Variables
$time = time();
$expires = ($time + 600);
$action = 'loginizer_epl_'.$uid;
include_once( ABSPATH . '/'.$loginizer['wp-includes'].'/class-phpass.php');
$wp_hasher = new PasswordHash(8, TRUE);
// Create the token with a random salt and the time
$token = wp_hash(wp_generate_password(20, false).$action.$time);
// Create a hash of the token
$stored_hash = $wp_hasher->HashPassword($expires.$token);
// Store the hash and when it expires
update_user_meta($uid, $action, $stored_hash);
update_user_meta($uid, $action.'_expires', $expires);
return $token;
}
// Send a 404
function loginizer_set_404(){
global $wp_query;
status_header(404);
$wp_query->set_404();
if( (($template = get_404_template()) || ($template = get_index_template()))
&& ($template = apply_filters('template_include', $template))
){
include($template);
}
die();
}
// Find the page being accessed
function loginizer_cur_page(){
$blog_url = trailingslashit(get_bloginfo('url'));
$server_host = isset($_SERVER['HTTP_HOST']) ? $_SERVER['HTTP_HOST'] : '';
$server_uri = isset($_SERVER['REQUEST_URI']) ? $_SERVER['REQUEST_URI'] : '';
// Build the Current URL
$url = (is_ssl() ? 'https://' : 'http://') . $server_host . $server_uri;
if(is_ssl() && preg_match('/^http\:/is', $blog_url)){
$blog_url = substr_replace($blog_url, 's', 4, 0);
}
// The relative URL to the Blog URL
$req = str_replace($blog_url, '', $url);
$req = str_replace('index.php/', '', $req);
// We dont need the args
$parts = explode('?', $req, 2);
$relative = basename($parts[0]);
// Remove trailing slash
$relative = rtrim($relative, '/');
$tmp = explode('/', $relative, 2);
$page = end($tmp);
//echo 'Page : '.$page.' ';
return $page;
}
// Converts the URL as per the one stored
function loginizer_rl_convert_url($link){
global $loginizer;
$dbt = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 7);
// If the login page is to be kept secret
if(!empty($loginizer['rename_login_secret']) && loginizer_cur_page() !== $loginizer['login_slug'] && !is_user_logged_in() && (empty($dbt[6]) || $dbt[6]['function'] != 'get_the_password_form')){
return $link;
}
$result = $link;
if(!empty($loginizer['login_slug']) && strpos($link, $loginizer['login_basename']) !== false){
$result = str_replace($loginizer['login_basename'], $loginizer['login_slug'], $link);
}
if(!empty($loginizer['xmlrpc_slug']) && strpos($link, 'xmlrpc.php') !== false){
$result = str_replace($loginizer['login_basename'], $loginizer['login_slug'], $link);
}
return $result;
}
function loginizer_rl_site_url($link){
$result = loginizer_rl_convert_url($link);
return $result;
}
function loginizer_rl_wp_redirect($link){
$result = loginizer_rl_convert_url($link);
return $result;
}
function loginizer_rl_register($link){
$result = loginizer_rl_convert_url($link);
return $result;
}
// Shows the Login correctly
function loginizer_rl_wp_loaded(){
global $loginizer, $interim_login;
$page = loginizer_cur_page();
// Is it wp-login.php ?
if ($page === $loginizer['login_basename']) {
loginizer_set_404();
}
// Is it our SLUG ? If not then return
if($page !== rtrim($loginizer['login_slug'], '/')){
return false;
}
// We dont want a WP plugin caching this page
@define('NO_CACHE', true);
@define('WTC_IN_MINIFY', true);
@define('WP_CACHE', false);
$user_login = '';
$error = '';
// Prevent errors from defining constants again
error_reporting(E_ERROR | E_CORE_ERROR | E_COMPILE_ERROR);
include ABSPATH.'/'.$loginizer['login_basename'];
exit();
}
// Renames the XML-RPC functionality
function loginizer_xml_rename_wp_loaded(){
global $loginizer;
$page = loginizer_cur_page();
// Is it xmlrpc.php ?
if ($page === 'xmlrpc.php') {
loginizer_set_404();
}
// Is it our SLUG ? If not then return
if($page !== $loginizer['xmlrpc_slug']){
return false;
}
// We dont want a WP plugin caching this page
@define('NO_CACHE', true);
@define('WTC_IN_MINIFY', true);
@define('WP_CACHE', false);
// Prevent errors from defining constants again
error_reporting(E_ERROR | E_CORE_ERROR | E_COMPILE_ERROR);
include ABSPATH.'/xmlrpc.php';
exit();
}
// Disables the XML-RPC functionality
function loginizer_xmlrpc_null(){
return null;
}
// Disables the XML-RPC functionality
function loginizer_xmlrpc_disable(){
global $loginizer;
$page = loginizer_cur_page();
// Is it xmlrpc.php ?
if ($page === 'xmlrpc.php'){
echo 'XML-RPC is disabled';
exit();
}
}
// Disables the XML-RPC functionality
function loginizer_xmlrpc_remove_pingback_url($output, $show) {
if($show == 'pingback_url'){
$output = '';
}
return $output;
}
// Disable Pingbacks
function loginizer_pingbacks_disable($methods) {
if(isset($methods['pingback.ping'])){
unset($methods['pingback.ping']);
}
if(isset($methods['pingback.extensions.getPingbacks'])){
unset($methods['pingback.extensions.getPingbacks']);
}
return $methods;
}
//========================
// Captcha Codes
//========================
// Adjusts the login form
function loginizer_cap_login_form(){
?>
add('loginizer_resetpass_cap_error', $captcha_fail_msg, 'loginizer_cap');
}
}
// Verify the register captcha is valid ?
function loginizer_cap_register_verify($errors, $username = '', $email = ''){
if(!loginizer_cap_verify()){
$captcha_fail_msg = __('The CAPTCHA verification failed. Please try again.', 'loginizer');
$errors->add('loginizer_cap_register_error', $captcha_fail_msg, 'loginizer_cap');
}
return $errors;
}
// Verify the register captcha is valid ?
function loginizer_cap_register_verify_buddypress($errors, $username = '', $email = ''){
global $bp;
// $bp is for BuddyPress Registration it does not pass $errors
if(!loginizer_cap_verify()){
$captcha_fail_msg = __('The CAPTCHA verification failed. Please try again.', 'loginizer');
// $bp is for BuddyPress
$bp->signup->errors['signup_username'] = $captcha_fail_msg;
}
return $errors;
}
// Verify the register captcha is valid ?
function loginizer_cap_comment_verify($comment){
if(!loginizer_cap_verify()){
wp_die('The CAPTCHA verification failed. Please try again.', 200);
}
return $comment;
}
// Verify WooCommerce Checkout Orders
function loginizer_wc_checkout_verify(){
global $loginizer;
// Is the registration function verifying it ?
if(!is_user_logged_in()
&& get_option('woocommerce_enable_signup_and_login_from_checkout', 'yes') == 'yes'
&& !empty($loginizer['captcha_register'])){
// So, no need of any more verification
// Lets verify
}elseif(!loginizer_cap_verify()){
$captcha_fail_msg = __('The CAPTCHA verification failed. Please try again.', 'loginizer');
wc_add_notice($captcha_fail_msg, 'error');
}
}
// Reset password form passes $user, hence we need to manually write echo
function loginizer_cap_reset_form($user = false){
loginizer_cap_form_login(false);
}
// For comment form pass false to echo the form
function loginizer_cap_comment_form($post_id = 0){
echo ' ';loginizer_cap_form_social(false);
}
// Converts numbers to words
function loginizer_cap_num_to_words( $number ) {
$words = array(
1 => __( 'one', 'loginizer' ),
2 => __( 'two', 'loginizer' ),
3 => __( 'three', 'loginizer' ),
4 => __( 'four', 'loginizer' ),
5 => __( 'five', 'loginizer' ),
6 => __( 'six', 'loginizer' ),
7 => __( 'seven', 'loginizer' ),
8 => __( 'eight', 'loginizer' ),
9 => __( 'nine', 'loginizer' ),
10 => __( 'ten', 'loginizer' ),
11 => __( 'eleven', 'loginizer' ),
12 => __( 'twelve', 'loginizer' ),
13 => __( 'thirteen', 'loginizer' ),
14 => __( 'fourteen', 'loginizer' ),
15 => __( 'fifteen', 'loginizer' ),
16 => __( 'sixteen', 'loginizer' ),
17 => __( 'seventeen', 'loginizer' ),
18 => __( 'eighteen', 'loginizer' ),
19 => __( 'nineteen', 'loginizer' ),
20 => __( 'twenty', 'loginizer' ),
30 => __( 'thirty', 'loginizer' ),
40 => __( 'forty', 'loginizer' ),
50 => __( 'fifty', 'loginizer' ),
60 => __( 'sixty', 'loginizer' ),
70 => __( 'seventy', 'loginizer' ),
80 => __( 'eighty', 'loginizer' ),
90 => __( 'ninety', 'loginizer' )
);
if ( isset( $words[$number] ) )
return $words[$number];
else {
$reverse = false;
switch ( get_bloginfo( 'language' ) ) {
case 'de-DE':
$spacer = 'und';
$reverse = true;
break;
case 'nl-NL':
$spacer = 'en';
$reverse = true;
break;
case 'ru-RU':
case 'pl-PL':
case 'en-EN':
default:
$spacer = ' ';
}
$first = (int) (substr( $number, 0, 1 ) * 10);
$second = (int) substr( $number, -1 );
return ($reverse === false ? $words[$first] . $spacer . $words[$second] : $words[$second] . $spacer . $words[$first]);
}
}
// Encode the operation
function loginizer_cap_encode_op($string){
return $string;
}
// Get the session key. If not there create one
function loginizer_cap_session_key(){
if(isset($_COOKIE['lz_math_sess']) && preg_match('/[a-z0-9]/is', $_COOKIE['lz_math_sess']) && strlen($_COOKIE['lz_math_sess']) == 40){
return $_COOKIE['lz_math_sess'];
}
// Generate the key
$new_session_key = lz_RandomString(40);
// Set the cookie
if(@setcookie('lz_math_sess', $new_session_key, time() + (30 * DAY_IN_SECONDS), COOKIEPATH, COOKIE_DOMAIN, is_ssl())){
// Set this to use first time
$_COOKIE['lz_math_sess'] = $new_session_key;
}
return $new_session_key;
}
// Generate the Captcha field if its a Math Captcha
function loginizer_cap_phrase($form = 'default'){
global $loginizer;
$ops = array('add' => '+',
'subtract' => '−',
'multiply' => '×',
'divide' => '÷',
);
$input = '';
if(empty($loginizer['captcha_add'])){
unset($ops['add']);
}
if(empty($loginizer['captcha_subtract'])){
unset($ops['subtract']);
}
if(empty($loginizer['captcha_multiply'])){
unset($ops['multiply']);
}
if(empty($loginizer['captcha_divide'])){
unset($ops['divide']);
}
// Randomly select an operation
$rnd_op = array_rand($ops, 1);
$number[3] = $ops[$rnd_op];
// Select where to place empty input
$rnd_input = mt_rand(0, 2);
// Generate the numbers
switch ($rnd_op){
case 'add':
if($rnd_input === 0){
$number[0] = mt_rand(1, 10);
$number[1] = mt_rand(1, 89);
}elseif($rnd_input === 1) {
$number[0] = mt_rand(1, 89);
$number[1] = mt_rand(1, 10);
}elseif($rnd_input === 2){
$number[0] = mt_rand(1, 9);
$number[1] = mt_rand(1, 10 - $number[0]);
}
$number[2] = $number[0] + $number[1];
break;
case 'subtract':
if($rnd_input === 0){
$number[0] = mt_rand(2, 10);
$number[1] = mt_rand(1, $number[0] - 1);
}elseif($rnd_input === 1){
$number[0] = mt_rand(11, 99);
$number[1] = mt_rand(1, 10);
}elseif($rnd_input === 2){
$number[0] = mt_rand(11, 99);
$number[1] = mt_rand($number[0] - 10, $number[0] - 1);
}
$number[2] = $number[0] - $number[1];
break;
case 'multiply':
if($rnd_input === 0){
$number[0] = mt_rand(1, 10);
$number[1] = mt_rand(1, 9);
}elseif($rnd_input === 1){
$number[0] = mt_rand(1, 9);
$number[1] = mt_rand(1, 10);
}elseif($rnd_input === 2){
$number[0] = mt_rand(1, 10);
$number[1] = ($number[0] > 5 ? 1 : ($number[0] === 4 && $number[0] === 5 ? mt_rand(1, 2 ) : ($number[0] === 3 ? mt_rand(1, 3 ) : ($number[0] === 2 ? mt_rand(1, 5 ) : mt_rand(1, 10 )))));
}
$number[2] = $number[0] * $number[1];
break;
case 'divide':
$divide = array( 1 => 99, 2 => 49, 3 => 33, 4 => 24, 5 => 19, 6 => 16, 7 => 14, 8 => 12, 9 => 11, 10 => 9 );
if($rnd_input === 0){
$divide = array( 2 => array( 1, 2 ), 3 => array( 1, 3 ), 4 => array( 1, 2, 4 ), 5 => array( 1, 5 ), 6 => array( 1, 2, 3, 6 ), 7 => array( 1, 7 ), 8 => array( 1, 2, 4, 8 ), 9 => array( 1, 3, 9 ), 10 => array( 1, 2, 5, 10 ) );
$number[0] = mt_rand(2, 10);
$number[1] = $divide[$number[0]][mt_rand(0, count( $divide[$number[0]] ) - 1 )];
}elseif($rnd_input === 1){
$number[1] = mt_rand(1, 10);
$number[0] = $number[1] * mt_rand(1, $divide[$number[1]]);
}elseif($rnd_input === 2){
$number[2] = mt_rand(1, 10 );
$number[0] = $number[2] * mt_rand(1, $divide[$number[2]]);
$number[1] = (int) ($number[0] / $number[2]);
}
if(! isset( $number[2] ) )
$number[2] = (int) ($number[0] / $number[1]);
break;
}
// Are we to display in words ?
if(!empty($loginizer['captcha_words'])){
if($rnd_input === 0){
$number[1] = loginizer_cap_num_to_words( $number[1] );
$number[2] = loginizer_cap_num_to_words( $number[2] );
}elseif($rnd_input === 1){
$number[0] = loginizer_cap_num_to_words( $number[0] );
$number[2] = loginizer_cap_num_to_words( $number[2] );
}elseif($rnd_input === 2){
$number[0] = loginizer_cap_num_to_words( $number[0] );
$number[1] = loginizer_cap_num_to_words( $number[1] );
}
}
// Finally make the input field
if(in_array( $form, array( 'default' ) ) ){
// As per the position of the empty input
if($rnd_input === 0 ){
$return = $input . ' ' . $number[3] . ' ' . loginizer_cap_encode_op( $number[1] ) . ' = ' . loginizer_cap_encode_op( $number[2] );
}elseif($rnd_input === 1 ){
$return = loginizer_cap_encode_op( $number[0] ) . ' ' . $number[3] . ' ' . $input . ' = ' . loginizer_cap_encode_op( $number[2] );
}elseif($rnd_input === 2 ){
$return = loginizer_cap_encode_op( $number[0] ) . ' ' . $number[3] . ' ' . loginizer_cap_encode_op( $number[1] ) . ' = ' . $input;
}
}
// Get the session ID
$session_id = loginizer_cap_session_key();
// Save the time
set_transient('lz_math_cap_'.$session_id, sha1(AUTH_KEY . $number[$rnd_input] . $session_id, false), $loginizer['captcha_time']);
// Save the value in the users cookie
//loginizer_cap_cookie_set(sha1(AUTH_KEY . $number[$rnd_input] . $session_id, false));
// In some themes the input field does not look fine if it is not in a div it used to take full page height for the input text tag
$return = '
'.$return.'
';
return $return;
}
// Captcha form for ecommerce
function loginizer_cap_form_ecommerce($return = false, $id = ''){
return loginizer_cap_form($return, $id, 'ecommerce');
}
// Captcha form for login
function loginizer_cap_form_login($return = false, $id = ''){
return loginizer_cap_form($return, $id, 'login');
}
// Captcha form for comments/social
function loginizer_cap_form_social($return = false, $id = ''){
return loginizer_cap_form($return, $id, 'social');
}
// Shows the captcha
function loginizer_cap_form($return = false, $id = '', $page_type = 'login'){
global $loginizer;
// Math Captcha
if(!empty($loginizer['captcha_no_google'])){
// We generate it only once
if(empty($GLOBALS['lz_captcha_no_google'])){
$GLOBALS['lz_captcha_no_google'] = $loginizer['captcha_text'].' '.loginizer_cap_phrase().'
';
}
// Store this value
$field = $GLOBALS['lz_captcha_no_google'];
// hcaptcha
}else if(!empty($loginizer['captcha_status']) && $loginizer['captcha_status'] === 3){
if (!wp_script_is('loginizer_hcaptcha_script', 'registered')) {
wp_register_script('loginizer_hcaptcha_script', 'https://js.hcaptcha.com/1/api.js', ['jquery'], 1, ['strategy' => 'defer']);
}
wp_enqueue_script('loginizer_hcaptcha_script');
$field = '';
// Cloudflare Turnstile
} elseif(!empty($loginizer['captcha_status']) && $loginizer['captcha_status'] === 4){
$do_multiple = false;
if(!wp_script_is('loginizer_turnstil_script', 'registered')){
wp_register_script('loginizer_turnstil_script', 'https://challenges.cloudflare.com/turnstile/v0/api.js', ['jquery'], 0, ['strategy' => 'defer']);
}
wp_enqueue_script('loginizer_turnstil_script');
$field = '';
// Google reCaptcha
} else {
$field = '';
$query_string = array();
$captcha_type = (!empty($loginizer['captcha_type']) ? $loginizer['captcha_type'] : '');
$site_key = $loginizer['captcha_key'];
$theme = $loginizer['captcha_theme'];
$size = $loginizer['captcha_size'];
$no_js = $loginizer['captcha_no_js'];
$captcha_ver = 2;
$captcha_js_ver = '2.0';
$invisible = 0;
if($captcha_type == 'v3'){
$invisible = 1;
$captcha_ver = 3;
$captcha_js_ver = '3.0';
$do_multiple = 1;
$lz_cap_div_class = 'lz-recaptcha-invisible-v3';
if(!empty($site_key)){
$query_string['render'] = $site_key;
}
}
// For v2 invisible
if($captcha_type == 'v2_invisible'){
$invisible = 1;
$do_multiple = 1;
$size = 'invisible';
$lz_cap_div_class = 'lz-recaptcha-invisible-v2';
$query_string['render'] = 'explicit';
}
// Is this a first call ?
if(!wp_script_is('loginizer_cap_script', 'registered')){
$language = $loginizer['captcha_lang'];
if(!empty($language)){
$query_string['hl'] = $language;
}
// We need these variables in JS
if(!empty($invisible)){
$field .= '';
}
wp_register_script('loginizer_cap_script', "https://".$loginizer['captcha_domain']."/recaptcha/api.js?".http_build_query($query_string), array('jquery'), $captcha_js_ver, true);
// We need to load multiple times
}else{
$do_multiple = 1;
}
if(!empty($do_multiple)){
if(!wp_script_is('loginizer_multi_cap_script', 'registered')){
wp_register_script('loginizer_multi_cap_script', LOGINIZER_PRO_DIR_URL.'/assets/js/multi-recaptcha.js', array('jquery'), $captcha_js_ver, true);
}
wp_enqueue_script('loginizer_multi_cap_script');
}
wp_enqueue_script('loginizer_cap_script');
// For v3 everything is done in javascript
if(empty($invisible)){
$field .= "";
if($no_js == 1){
$field .= "
";
}
$field .= ' ';
}else{
$field .= '';
if($captcha_ver == 3){
$field .= '';
}
}
}
// Are we to return the code ?
if($return){
return $field;
// Lets echo it
}else{
echo $field;
}
}
// Verifies the Google Captcha and is called by individual for verifiers
function loginizer_cap_verify(){
global $loginizer;
// WooCommerce is calling this function as well. Hence Captcha fails
if(isset($GLOBALS['called_loginizer_cap_verify'])){
return $GLOBALS['called_loginizer_cap_verify'];
}
// Is the post set ?
if(count($_POST) < 1){
return true;
}
// Some plugin allows to login via Google account does not post the captcha details but does add ONLY rememberme to POST causing the captcha validation to trigger
if(count($_POST) == 1 && isset($_POST['rememberme'])){
return true;
}
$GLOBALS['called_loginizer_cap_verify'] = true;
// Math Captcha
if(!empty($loginizer['captcha_no_google'])){
$response = (int) (!empty($_POST['loginizer_cap_math']) ? $_POST['loginizer_cap_math'] : '');
// Is the response valid ?
if(!is_numeric($response) || empty($response)){
$GLOBALS['called_loginizer_cap_verify'] = false;
return false;
}
// Get the session ID
$session_id = loginizer_cap_session_key();
// Is the response valid ?
if(empty($session_id)){
$GLOBALS['called_loginizer_cap_verify'] = false;
return false;
}
// Get the Value stored
$captcha_value = get_transient('lz_math_cap_'.$session_id);
// Do we have a stored value ?
if(empty($captcha_value) || strlen($captcha_value) != 40){
$GLOBALS['called_loginizer_cap_verify'] = false;
return false;
}
// Is the value matching
if($captcha_value != sha1(AUTH_KEY . $response . $session_id, false)){
$GLOBALS['called_loginizer_cap_verify'] = false;
return false;
}
return true;
// hcaptcha
}else if(!empty($loginizer['hcaptcha_sitekey']) && !empty($loginizer['captcha_status']) && $loginizer['captcha_status'] == 3){
if(empty($loginizer['hcaptcha_sitekey'])){
return true;
}
$hresponse = (!empty($_POST['h-captcha-response']) ? $_POST['h-captcha-response'] : '');
$ip = lz_getip();
// Is the IP or response not there ?
if(empty($hresponse) || empty($ip)){
$GLOBALS['called_loginizer_cap_verify'] = false;
return false;
}
$url = 'https://hcaptcha.com/siteverify';
// Verify the post
$req = wp_remote_post($url, [
'timeout' => 10,
'body' => [
'secret' => $loginizer['hcaptcha_secretkey'],
'response' => $hresponse,
'remoteip' => $ip,
]
]
);
// Was there an error posting ?
if(is_wp_error($req)){
$GLOBALS['called_loginizer_cap_verify'] = false;
return false;
}
// Process the post response
$resp = wp_remote_retrieve_body($req);
// Is the body valid
if(empty($resp)){
$GLOBALS['called_loginizer_cap_verify'] = false;
return false;
}
$json = json_decode($resp, true);
if(!empty($json['success'])){
return true;
}
// Google Captcha
} elseif(!empty($loginizer['turn_captcha_secret']) && !empty($loginizer['captcha_status']) && $loginizer['captcha_status'] == 4){
$response = (!empty($_POST['cf-turnstile-response']) ? $_POST['cf-turnstile-response'] : '');
$ip = lz_getip();
// Is the IP or response not there ?
if(empty($response) || empty($ip)){
$GLOBALS['called_loginizer_cap_verify'] = false;
return false;
}
$url = 'https://challenges.cloudflare.com/turnstile/v0/siteverify';
$req = wp_remote_post($url, [
'timeout' => 10,
'body' => [
'response' => $response,
'secret' => $loginizer['turn_captcha_secret'],
'remoteip' => $ip
]
]);
if(is_wp_error($req)){
$GLOBALS['called_loginizer_cap_verify'] = false;
return false;
}
// Process the post response
$resp = wp_remote_retrieve_body($req);
// Is the body valid
if(empty($resp)){
$GLOBALS['called_loginizer_cap_verify'] = false;
return false;
}
$json = json_decode($resp, true);
if(!empty($json['success'])){
return true;
}
}else{
// If secret key is not there, return
if(empty($loginizer['captcha_secret'])){
return true;
}
$response = (!empty($_POST['g-recaptcha-response']) ? $_POST['g-recaptcha-response'] : '');
$ip = lz_getip();
// Is the IP or response not there ?
if(empty($response) || empty($ip)){
$GLOBALS['called_loginizer_cap_verify'] = false;
return false;
}
$url = 'https://'.$loginizer['captcha_domain'].'/recaptcha/api/siteverify';
// Verify the post
$req = wp_remote_post($url, [
'timeout' => 10,
'body' => [
'secret' => $loginizer['captcha_secret'],
'response' => $response,
'remoteip' => $ip
]
]
);
// Was there an error posting ?
if(is_wp_error($req)){
$GLOBALS['called_loginizer_cap_verify'] = false;
return false;
}
// Process the post response
$resp = wp_remote_retrieve_body($req);
// Is the body valid
if(empty($resp)){
$GLOBALS['called_loginizer_cap_verify'] = false;
return false;
}
$json = json_decode($resp, true);
if(!empty($json['success'])){
return true;
}
}
// Couldnt verify
$GLOBALS['called_loginizer_cap_verify'] = false;
return false;
}
function loginizer_wc_before_checkout_process(){
global $loginizer;
// This is checkout page. If admin has disabled captcha on checkout
// and the user is registering during checkout we have not displayed the captcha form so we should not verify the same
if(empty($loginizer['captcha_wc_checkout'])){
remove_filter('woocommerce_registration_errors', 'loginizer_cap_register_verify');
}
}
//=========================================
// Registration Domain Blacklist
//=========================================
function loginizer_domains_blacklist($errors, $username, $email){
global $wpdb, $loginizer, $lz_error;
$domains = $loginizer['domains_blacklist'];
$domains = is_array($domains) ? $domains : array();
// Are you blacklisted ?
foreach($domains as $domain_to_match){
$domain_to_match = str_replace('*', '(.*?)', $domain_to_match);
if(preg_match('/'.$domain_to_match.'$/is', $email)){
$match_found = 1;
}
}
// Did we get a match ?
if(!empty($match_found)){
$errors->add('loginizer_domains_blacklist_error', 'The domain of your email is banned from registering on this website', 'loginizer_domains_blacklist');
}
return $errors;
}
//=========================================
// 2 Factor Auth / Question based security
//=========================================
// Handle the users secondary login i.e. 2fa / question, etc.
function loginizer_user_redirect($user, $username, $password){
global $loginizer;
// Is the post set ?
if(count($_POST) < 1){
return $user;
}
//print_r($user);die();
// Is it a valid user ?
if(!is_a($user, 'WP_User')){
return $user;
}
// The user has given correct details
// Now does the user have any of our features enabled ?
$settings = get_user_meta($user->ID, 'loginizer_user_settings', true);
//print_r($settings);die();
// Is it applicable as per role
if(!loginizer_is_2fa_applicable($user)){
return $user;
}
if(loginizer_is_whitelisted_2fa()){
return $user;
}
// Set the default return to the user only
$ret = $user;
// Is it a secondary question ?
if(!empty($settings['pref']) && $settings['pref'] == 'question'){
// Is there a question and answer
if(!empty($settings['question']) && !empty($settings['answer'])){
$save = 1;
}
}
// Is it a 2fa via App ?
if(!empty($settings['pref']) && $settings['pref'] == '2fa_app'){
if(!empty($settings['app_enable'])){
$save = 1;
}
}
// Is it a 2fa via email ?
if((!empty($settings['pref']) && $settings['pref'] == '2fa_email')
|| ((empty($settings['pref']) || @$settings['pref'] == 'none') && !empty($loginizer['2fa_email_force']))
){
// Generate a 6 digit code
$otp = wp_rand(100000, 999999);
$r['code'] = base64_encode($otp);
// Email them
$site_name = get_bloginfo('name');
$first_name = get_user_meta($user->ID, 'first_name', true);
$last_name = get_user_meta($user->ID, 'last_name', true);
if(empty($first_name)){
$first_name = $user->data->display_name;
}
$vars = array('email' => $user->data->user_email,
'otp' => $otp,
'site_name' => $site_name,
'site_url' => get_site_url(),
'display_name' => $user->data->display_name,
'user_login' => $user->data->user_login,
'first_name' => $first_name,
'last_name' => $last_name);
$subject = lz_lang_vars_name($loginizer['2fa_email_sub'], $vars);
$message = lz_lang_vars_name($loginizer['2fa_email_msg'], $vars);
//echo $user->data->user_email.' '.$message;die();
$sent = wp_mail($user->data->user_email, $subject, $message);
if(empty($sent)){
// For plugins that login using AJAX
if(!empty(get_transient('loginizer_2fa_'. $user->ID))){
return array('message' => esc_html__('There was a problem sending your email with the OTP. Please try again or contact an admin.', 'loginizer'));
}
return new WP_Error('email_not_sent', 'There was a problem sending your email with the OTP. Please try again or contact an admin.', 'loginizer_2fa_email');
}else{
$save = 1;
}
}
// Are we to create and save a token ?
if(!empty($save)){
// Are we to be remembered ?
$r['rememberme'] = lz_optreq('rememberme');
// Create a token
$token = loginizer_user_token($user->ID, $r);
// For custom redirect on Login when 2FA is enabled
$custom_redirects = get_option('loginizer_2fa_custom_redirect');
if(!empty($custom_redirects) && !empty($user->roles)){
foreach($user->roles as $role){
if(!empty($custom_redirects[$role]) && wp_validate_redirect($custom_redirects[$role])){
$_REQUEST['redirect_to'] = wp_validate_redirect($custom_redirects[$role]);
break;
}
}
}
$redirect_to = '';
if(!empty($_REQUEST['redirect_to'])){
$redirect_to = '&redirect_to='.urlencode($_REQUEST['redirect_to']);
} elseif(!empty($_REQUEST['redirect'])){
$redirect_to = '&redirect_to='.urlencode($_REQUEST['redirect']);
} elseif(!empty(wp_validate_redirect($_SERVER['HTTP_REFERER']))){
$redirect_to = '&redirect_to='.urlencode(wp_validate_redirect($_SERVER['HTTP_REFERER']));
}
// Form the URL
$url = wp_login_url().'?action=loginizer_security&uid='.$user->ID.'&lutoken='.$token.$redirect_to.(isset( $_REQUEST['interim-login'] ) ? '&interim-login=1' : '').(!empty($_SERVER['IS_WPE']) ? '&wpe-login=true' : '');
// For plugins that login using AJAX
if(!empty(get_transient('loginizer_2fa_'. $user->ID))){
return $url;
}
loginizer_update_attempt_stats(1);
// Lets redirect
wp_safe_redirect($url);
die();
}
return $ret;
}
// Creates a one time token
function loginizer_user_token($uid = 0, $r = array()){
global $loginizer;
// Variables
$time = time();
$expires = ($time + 600);
$action = 'loginizer_user_token';
include_once( ABSPATH.'/'.$loginizer['wp-includes'].'/class-phpass.php');
$wp_hasher = new PasswordHash(8, TRUE);
// Create the token with a random salt and the time
$token = wp_hash(wp_generate_password(20, false).$action.$time);
// Create a hash of the token
$r['stored_hash'] = $wp_hasher->HashPassword($expires.$token);
$r['expires'] = $expires;
// Store the hash and when it expires
update_user_meta($uid, $action, $r);
return $token;
}
// Process the secondary form i.e. question / 2fa, etc.
function loginizer_user_security(){
global $loginizer, $lz, $lz_error, $interim_login;
if(empty($_GET['uid']) || empty($_GET['lutoken'])){
return false;
}
$uid = (int) sanitize_key($_GET['uid']);
$token = sanitize_key($_GET['lutoken']);
$action = 'loginizer_user_token';
$meta = get_user_meta($uid, $action, true);
$hash = !empty($meta['stored_hash']) ? $meta['stored_hash'] : '';
$expires = !empty($meta['expires']) ? $meta['expires'] : '';
include_once(ABSPATH.'/'.$loginizer['wp-includes'].'/class-phpass.php');
$wp_hasher = new PasswordHash(8, TRUE);
$time = time();
if(!$wp_hasher->CheckPassword($expires.$token, $hash) || $expires < $time){
// Throw an error
$lz['error'] = sprintf(__('The token is invalid or has expired. Please provide your user details by clicking here', 'loginizer'), wp_login_url());
loginizer_user_security_form();
}
// Get the username
$userdata = get_userdata($uid);
$username = $userdata->data->user_login;
// Load the settings
$lz['settings'] = get_user_meta($uid, 'loginizer_user_settings', true);
// If the user was just created and the settings is empty
if(empty($lz['settings'])){
$lz['settings'] = array();
}
if((empty($lz['settings']['pref']) || $lz['settings']['pref'] == 'none') && !empty($loginizer['2fa_email_force'])){
$lz['settings']['pref'] = '2fa_email';
}
/* Make sure post was from this page */
if(count($_POST) > 0 && !check_admin_referer('loginizer-enduser')){
$lz['error'] = __('The form security was compromised !', 'loginizer');
loginizer_user_security_form();
}
// Has the user reached max attempts ?
if(!loginizer_can_login()){
$lz['error'] = $lz_error;
loginizer_user_security_form();
}
$interim_login = isset( $_REQUEST['interim-login'] );
// Process the post
if(!empty($_POST['lus_submit'])){
if(@$lz['settings']['pref'] == 'question'){
// Is there an answer ?
$answer = lz_optpost('lus_value');
// Is the answer correct ?
if($answer != @base64_decode($lz['settings']['answer'])){
loginizer_login_failed($username.' | 2FA-Answer', 1);
$lz['error'][] = __('The answer is wrong !', 'loginizer');
$lz['error'][] = loginizer_retries_left();
loginizer_user_security_form();
// Login the user
}else{
$do_login = 1;
}
}
if(@$lz['settings']['pref'] == '2fa_email'){
// Is there an OTP ?
$otp = lz_optpost('lus_value');
// Is the answer correct ?
if($otp != @base64_decode($meta['code'])){
loginizer_login_failed($username.' | 2FA-Email', 1);
$lz['error'][] = __('The OTP is wrong !', 'loginizer');
$lz['error'][] = loginizer_retries_left();
loginizer_user_security_form();
// Login the user
}else{
$do_login = 1;
}
}
// App based login
if(@$lz['settings']['pref'] == '2fa_app'){
// Is there an OTP ?
$otp = lz_optpost('lus_value');
$app2fa = loginizer_2fa_app($uid);
// Is the answer correct ?
if($otp != $app2fa['2fa_otp']){
// Maybe its an Emergency OTP
if(empty($lz['settings']['2fa_emergency']) || !@in_array($otp, $lz['settings']['2fa_emergency'])){
loginizer_login_failed($username.' | 2FA-APP', 1);
$lz['error'][] = __('The OTP is wrong !', 'loginizer');
$lz['error'][] = loginizer_retries_left();
loginizer_user_security_form();
}else{
// Remove the Emergency used and save the rest
unset($lz['settings']['2fa_emergency'][$otp]);
// Save it
update_user_meta($uid, 'loginizer_user_settings', $lz['settings']);
$do_login = 1;
}
// Login the user
}else{
$do_login = 1;
}
}
// Are we to login ?
if(!empty($do_login)){
$remember_me = !empty($meta['rememberme']) ? true : false;
// Login the User
wp_set_auth_cookie($uid, $remember_me);
// Delete the meta
delete_user_meta($uid, $action);
delete_transient('loginizer_2fa_' . $uid); // it is generated when the user logins through some ajax form
$redirect_to = !empty($_REQUEST['redirect_to']) ? $_REQUEST['redirect_to'] : admin_url();
// Redirect and exit
// Interim Login is used when session times out due to inactivity and login form is opened in a popup iframe
if ( $interim_login ) {
$message = '
' . __( 'You have logged in successfully.', 'loginizer' ) . '