AlkantarClanX12
Your IP : 216.73.217.24
<?php
/*
Copyright (C) 2015-26 CERBER TECH INC., https://wpcerber.com
Licensed under the GNU GPL.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
/*
*========================================================================*
| |
| ATTENTION! Do not change or edit this file! |
| |
*========================================================================*
*/
const CERBER_PIN_LENGTH = 4;
const CERBER_PIN_EXPIRES = 15;
final class CRB_2FA {
static $token = '';
static $user_set = null;
/**
* Enforce 2FA for a user based on the plugin settings
*
* @param string $login User login
* @param WP_User $user
*
* @return bool|WP_Error
*/
static function main_controller( $login, $user ) {
static $done = false;
if ( $done ) {
return 0;
}
$done = true;
if ( crb_acl_is_allowed() ) {
return 6;
}
if ( ( ! $user instanceof WP_User ) || empty( $user->ID ) ) {
return new WP_Error( 'no-user', 'Invalid user data' );
}
self::remove_expired_cookies( $user->ID );
$user_mode = self::get_user_meta_data( 'tfm', $user->ID );
if ( $user_mode === 2 ) {
return 7;
}
if ( ( $coo = self::get_user_meta_data( 'tf_remember', $user->ID ) )
&& self::get_user_days( $user->ID ) ) {
// Check for remembered devices
foreach ( $coo as $coo_name => $coo_data ) {
if ( $coo_data[1] > time()
&& cerber_get_cookie( $coo_name ) == $coo_data[0] ) {
return 8;
}
}
}
if ( $user_mode == 1 ) {
$go = true;
}
else {
$u_roles = null;
if ( ! empty( $user->roles ) ) {
$u_roles = $user->roles;
}
else { // a backup way
$data = get_userdata( $user->ID );
if ( ! empty( $data->roles ) ) {
$u_roles = $data->roles;
}
}
if ( empty( $u_roles ) ) {
return new WP_Error( 'no-roles', 'No roles found for the user #' . $user->ID );
}
if ( $go = self::check_role_policies( $user->ID, $u_roles ) ) {
CRB_Globals::set_ctrl_setting( $go );
}
}
if ( ! $go ) {
return 9;
}
// This user must complete 2FA
$login = (string) $login;
$ret = self::initiate_2fa( $user, $login );
if ( crb_is_wp_error( $ret ) ) {
return $ret;
}
crb_sessions_update( $user->ID, self::get_session_token_hash(), array( 'mfa_status' => 1 ) );
cerber_log( 400, $login, $user->ID );
$home = cerber_get_home_url();
if ( 2 < substr_count( $home, '/' ) ) {
// Home page URL includes a subfolder. Make sure it contains trailing slash as well. Improves web servers compatibility.
$home .= '/';
}
crb_safe_redirect( $home );
exit;
}
/**
* Check if 2FA must be enforced.
*
* @param int $user_id
* @param string[] $roles
*
* @return string|bool Non-empty string if the given user must complete 2FA, false otherwise
*/
private static function check_role_policies( $user_id, $roles ) {
foreach ( $roles as $role ) {
$policies = cerber_get_role_policies( $role );
if ( empty( $policies['2famode'] )
|| ( $policies['2famode'] == 2 && ! lab_lab() ) ) {
continue;
}
elseif ( $policies['2famode'] == 1 ) {
return '2famode';
}
if ( $history = self::get_user_meta_data( '2fa_history', $user_id ) ) {
if ( ( $logins = crb_array_get( $policies, '2falogins' ) )
&& ( $history[0] >= $logins ) ) {
return '2falogins';
}
if ( ( $days = crb_array_get( $policies, '2fadays' ) )
&& ( ( time() - $history[1] ) > $days * 24 * 3600 ) ) {
return '2fadays';
}
}
if ( $last_login = self::get_user_meta_data( 'last_login', $user_id ) ) {
if ( crb_array_get( $policies, '2fanewip' ) ) {
if ( $last_login['ip'] != cerber_get_remote_ip() ) {
return '2fanewip';
}
}
if ( crb_array_get( $policies, '2fanewnet4' ) ) {
if ( cerber_get_subnet_ipv4( $last_login['ip'] ) != cerber_get_subnet_ipv4( cerber_get_remote_ip() ) ) {
return '2fanewnet4';
}
}
if ( crb_array_get( $policies, '2fanewua' ) ) {
if ( $last_login['ua'] != sha1( crb_array_get( $_SERVER, 'HTTP_USER_AGENT', '' ) ) ) {
return '2fanewua';
}
}
}
if ( $limit = crb_array_get( $policies, '2fasessions' ) ) {
if ( $limit < crb_sessions_get_num( $user_id ) ) {
return '2fasessions';
}
}
if ( $last_login ) {
if ( crb_array_get( $policies, '2fanewcountry' ) ) {
if ( lab_get_country( $last_login['ip'], false ) != lab_get_country( cerber_get_remote_ip(), false ) ) {
return '2fanewcountry';
}
}
}
}
return false;
}
/**
* Return user's meta data handled by WP Cerber
*
* @param string $field
* @param integer $user_id
*
* @return false|mixed
*
* @since 9.6.1
*/
private static function get_user_meta_data( $field, $user_id ) {
static $pro = array( 'tfm', 'tf_remember', 'tfremember', '2fa_history', 'last_login' );
if ( in_array( $field, $pro )
&& ! lab_lab() ) {
return false;
}
if ( ! self::$user_set ) {
self::$user_set = cerber_get_set( CRB_USER_SET, $user_id );
}
return crb_array_get( self::$user_set, $field );
}
/**
* Initiate 2FA process
*
* @param $user
* @param string $login
*
* @return bool|string|WP_Error
*/
private static function initiate_2fa( $user, $login = '' ) {
if ( ! $pin = self::generate_pin( $user->ID ) ) {
return new WP_Error( '2fa-error', 'Unable to create PIN for the user #' . $user->ID );
}
$data = array(
'login' => $login,
'to' => cerber_2fa_get_redirect_to( $user ),
'ajax' => cerber_is_wp_ajax(),
'interim' => isset( $_REQUEST['interim-login'] ) ? 1 : 0,
);
self::update_2fa_data( $data, $user->ID );
return $pin;
}
/**
* Generates PIN and its expiration
*
* @param $user_id
*
* @return bool|string
*/
private static function generate_pin( $user_id ) {
$pin = substr( str_shuffle( '1234567890' ), 0, CERBER_PIN_LENGTH );
$data = array(
'pin' => $pin,
'expires' => time() + CERBER_PIN_EXPIRES * 60,
'attempts' => 0,
'ip' => cerber_get_remote_ip(),
'ua' => sha1( $_SERVER['HTTP_USER_AGENT'] ?? '' ),
'ua_raw' => substr( trim( $_SERVER['HTTP_USER_AGENT'] ?? '' ), 0, 200 ),
'2email' => self::get_user_email( $user_id )
);
if ( self::update_2fa_data( $data, $user_id ) ) {
self::send_user_pin( $user_id, $pin );
return $pin;
}
return false;
}
/**
* Pre-checks: make sure WordPress has properly identified the user.
*
* @param $user_id
*
* @return void
*/
static function check_for_errors( $user_id ) {
if ( ! cerber_get_post( 'the_2fa_nonce' )
|| ! cerber_get_post( 'cerber_verify_pin' ) ) {
return;
}
if ( ! $user_id ) {
self::send_ajax_response( 'Authentication error: WordPress user is not identified.' );
}
}
/**
* @param int $current_user_id Current user ID
*
*/
static function restrict_and_verify( $current_user_id = null ) {
static $done = false;
if ( $done ) {
return;
}
$done = true;
if ( ! $current_user_id
&& ! $current_user_id = get_current_user_id() ) {
return;
}
$twofactor = self::get_2fa_data( $current_user_id );
if ( empty( $twofactor['pin'] ) ) {
return;
}
if ( crb_acl_is_allowed() ) {
self::delete_2fa( $current_user_id );
return;
}
// Check user settings again: they can be changed by admin after the user was enforced to complete 2FA
$user_mode = self::get_user_meta_data( 'tfm', $current_user_id);
if ( $user_mode === 2 ) {
self::delete_2fa( $current_user_id, true );
return;
}
elseif ( ! $user_mode ) {
$user = wp_get_current_user();
if ( ! self::check_role_policies( $current_user_id, $user->roles ) ) {
self::delete_2fa( $current_user_id );
return;
}
}
// Check the browser and user context
if ( ( $sts = ( $twofactor['ip'] != cerber_get_remote_ip() ? 540 : 0 ) )
|| ( $sts = ( $twofactor['ua'] != sha1( crb_array_get( $_SERVER, 'HTTP_USER_AGENT', '' ) ) ? 541 : 0 ) )
|| ( $sts = ( cerber_is_ip_allowed() ? 0 : CRB_Globals::$act_status ) ) ) {
self::delete_2fa( $current_user_id );
crb_force_current_user_logout( $sts );
crb_redirect( get_home_url() );
exit;
}
// User wants to abort 2FA?
if ( $now = cerber_get_get( 'cerber_2fa_now' ) ) {
$go = null;
if ( $now == 'different' ) {
$go = wp_login_url( ( ! empty( $twofactor['to'] ) ) ? urldecode( $twofactor['to'] ) : '' );
}
if ( $now == 'cancel' ) {
$go = get_home_url();
}
if ( $go ) {
crb_force_current_user_logout( 28 );
crb_redirect( $go );
exit;
}
}
if ( $twofactor['attempts'] > 5 ) {
crb_apply_soft_ip_lockout( cerber_get_remote_ip(), 721 );
crb_force_current_user_logout( 542 );
crb_redirect( get_home_url() );
exit;
}
$pin_expired = false;
if ( $twofactor['expires'] < time() ) {
self::generate_pin( $current_user_id );
$pin_expired = true;
}
// The first step of verification, ajax
if ( cerber_is_http_post() ) {
self::process_ajax( $pin_expired );
}
// The second, final step of verification
if ( cerber_is_http_post()
&& ! empty( $twofactor['nonce'] )
&& $_POST['cerber_tag'] === $twofactor['nonce']
&& ( $pin = cerber_get_post( 'cerber_pin' ) )
&& self::verify_pin( trim( $pin ) ) ) {
self::delete_2fa( $current_user_id );
cerber_log( CRB_EV_LIN, $twofactor['login'], $current_user_id, 27 );
crb_update_login_history( $current_user_id, true );
cerber_2fa_checker( true );
self::save_remember_device( $current_user_id );
crb_sessions_update( $current_user_id, self::get_session_token_hash(), array( 'mfa_status' => 2 ) );
$url = ( ! empty( $twofactor['to'] ) ) ? $twofactor['to'] : get_home_url();
crb_safe_redirect( $url );
exit;
}
self::show_2fa_page();
exit;
}
/**
* Returns the number of days for which we will remember the user's device.
* Picks the smallest number if the user has multiple roles.
*
* @param int $user_id
*
* @return int
*
* @since 9.5.7
*/
private static function get_user_days( $user_id = null ) {
if ( ! $user_id ) {
$user = wp_get_current_user();
}
else {
$user = get_userdata( $user_id );
}
// User policies
if ( lab_lab() ) {
$cus = cerber_get_set( CRB_USER_SET, $user->ID );
if ( is_numeric( $cus['tfremember'] ?? false ) ) {
return $cus['tfremember'];
}
}
// Roles policies
if ( ! $user->roles ) {
return 0;
}
$list = array();
foreach ( $user->roles as $role ) {
$policies = cerber_get_role_policies( $role );
$list[] = (int) $policies['2faremember'] ?? 0;
}
return min( $list );
}
/**
* @param int $user_id
*
* @return void
*
* @since 9.5.7
*/
private static function save_remember_device( $user_id ) {
if ( cerber_get_post( 'cerber_trust_device' ) != 'yes'
|| ! $days = self::get_user_days( $user_id ) ) {
return;
}
$salt = crb_random_string( 8, 12 );
// Unique name for all users and websites on the domain
$name = 'crb_tf_' . sha1( $salt . cerber_get_site_url() . '|' . $user_id );
$val = '(' . rand( 0, 99 ) . ')'; // Can be any value
$until = time() + DAY_IN_SECONDS * $days; // expires
$expires = $until + DAY_IN_SECONDS * rand( 0, 3 ); // add some randomness to make it harder to find expiration time
if ( cerber_set_cookie( $name, $val, $expires, '', '', true ) ) {
$cus = cerber_get_set( CRB_USER_SET, $user_id );
$cook_list = ( isset( $cus['tf_remember'] ) && is_array( $cus['tf_remember'] ) ) ? $cus['tf_remember'] : array();
$cook_list[ $name ] = array( $val, $until );
$cus['tf_remember'] = $cook_list;
cerber_update_set( CRB_USER_SET, $cus, $user_id );
}
self::remove_expired_cookies( $user_id );
}
/**
* Removes stored but expired device cookies
*
* @param int $user_id
*
* @return void
*
* @since 9.5.7
*/
static function remove_expired_cookies( $user_id ) {
$cus = cerber_get_set( CRB_USER_SET, $user_id );
$cook_list = ( isset( $cus['tf_remember'] ) && is_array( $cus['tf_remember'] ) ) ? $cus['tf_remember'] : array();
if ( ! $cook_list ) {
return;
}
$update = false;
foreach ( $cook_list as $coo_name => $coo_data ) {
if ( $coo_data[1] < time() ) {
unset( $cook_list[ $coo_name ] );
$update = true;
}
}
if ( $update ) {
$cus['tf_remember'] = $cook_list;
cerber_update_set( CRB_USER_SET, $cus, $user_id );
}
}
static function process_ajax( $pin_expired = false ) {
if ( ( ! $nonce = cerber_get_post( 'the_2fa_nonce', '\w+' ) )
|| ( ! $pin = cerber_get_post( 'cerber_verify_pin' ) ) ) {
return;
}
$err = '';
if ( ! wp_verify_nonce( $nonce, 'crb-ajax-2fa' ) ) {
$err = 'Nonce error.';
}
elseif ( $pin_expired ) {
$err = __( 'This verification PIN code is expired. We have just sent a new one to your email.', 'wp-cerber' );
}
elseif ( ! self::verify_pin( trim( $pin ), $nonce ) ) {
$err = __( 'You have entered an incorrect verification PIN code', 'wp-cerber' );
}
self::send_ajax_response( $err );
}
/**
* @param string $err
*
* @return void
*/
private static function send_ajax_response( $err ) {
echo json_encode( array( 'error' => $err ) );
exit;
}
private static function verify_pin( $pin, $nonce = null ) {
$data = self::get_2fa_data();
if ( empty( $data['pin'] )
|| $data['expires'] < time() ) {
return false;
}
if ( (string) $pin === (string) $data['pin'] ) {
$ret = true;
if ( ! $nonce ) {
return $ret;
}
$data['nonce'] = $nonce;
}
else {
$data['attempts'] ++;
$ret = false;
}
self::update_2fa_data( $data );
return $ret;
}
static function show_2fa_page( $echo = true ) {
@ini_set( 'display_errors', 0 );
if ( ! defined( 'CONCATENATE_SCRIPTS' ) ) {
define( 'CONCATENATE_SCRIPTS', false );
define( 'CONCATENATE_SCRIPTS_BY_CRB', true );
}
// Workaround to avoid warning messages generated _wp_scripts_maybe_doing_it_wrong()
global $wp_actions;
$wp_actions['wp_enqueue_scripts'] = 1;
// --------------------------------------------------------------------
wp_enqueue_script( 'jquery' );
ob_start();
?>
<!DOCTYPE html>
<html style="height: 100%;">
<head>
<meta charset="UTF-8">
<title><?php _e( 'Please verify that it’s you', 'wp-cerber' ); ?></title>
<style>
body {
height: 90%;
text-align: center;
font-family: Arial, Helvetica, sans-serif;
color: #555;
}
#cerber_2fa_page {
display: flex;
align-items: center;
justify-content: center;
text-align: center;
height: 90%;
}
#cerber_2fa_wrap {
text-align: center;
background-color: #eee;
border-top: solid 4px #ddd;
padding: 1.5em 3em 1.5em 3em;
}
#cerber_2fa_inner {
width: 350px;
}
@media (-webkit-min-device-pixel-ratio: 2) and (max-width: 1000px),
(min-resolution: 192dpi) and (max-width: 1000px), {
#cerber_2fa_inner {
width: 100%;
}
}
@media screen and (max-width: 900px) {
#cerber_2fa_inner {
/*width: 100%;*/
}
}
#cerber_2fa_msg {
display: none;
position: fixed;
top: 0;
left: 0;
width: 100%;
/*height: 80px;*/
padding: 40px 0 40px 0;
background-color: #FF4633;
color: #fff;
opacity: 0.9;
}
#cerber_2fa_title {
color:#000;
}
#cerber_2fa_info{
color: #333;
}
#cerber_2fa_form {
margin-bottom: 3em;
}
#cerber_2fa_form input[type="text"] {
color: #000;
text-align: center;
font-size: 1.4em;
letter-spacing: 0.1em;
padding: 5px;
min-width: 140px;
border-radius: 4px;
}
#cerber_2fa_form input[type="submit"] {
color: white;
background: #0085ba;
/*background: #0073aa;*/
border: 0;
font-size: 1em;
font-weight: 600;
letter-spacing: 0.05em;
text-align: center;
cursor: pointer;
padding: 1em;
min-width: 150px;
border-radius: 4px;
}
#cerber_2fa_trust_device {
margin: 1.3em 0;
}
#cerber_2fa_trust_device > * {
vertical-align: middle;
cursor: pointer;
}
#cerber_2fa_trust_device > input {
width: 1.1em;
height: 1.1em;
margin-right: 0.5em;
}
</style>
<?php
// -------------------------------------------
// Because print_head_scripts() -> 'wp_print_scripts' hook -> wp_just_in_time_script_localization() -> AUTOSAVE_INTERVAL
if ( ! defined( 'AUTOSAVE_INTERVAL' ) ) {
define( 'AUTOSAVE_INTERVAL', MINUTE_IN_SECONDS );
}
print_head_scripts();
// -------------------------------------------
?>
<script>
var ajaxurl = "<?php echo admin_url( 'admin-ajax.php' ); ?>";
var nonce2fa = "<?php echo wp_create_nonce( 'crb-ajax-2fa' ); ?>";
</script>
</head>
<body>
<div id="cerber_2fa_page">
<?php
self::cerber_2fa_form();
?>
</div>
</body>
</html>
<?php
$html = ob_get_clean();
if ( $echo ) {
echo $html;
}
return $html;
}
static function send_user_pin( $user_id, $pin ) {
if ( ! $pin ) {
return false;
}
$subj = __( 'Please verify that it’s you', 'wp-cerber' );
$body = array();
//$body[] = 'We need to verify that it’s you because you are trying to sign-in from a different device or a different location or you have not signed in for a long time. If this wasn’t you, please reset your password immediately.';
$body[] = __( "You or someone else trying to log into the website. We have to verify that it's you. If this wasn't you, please immediately reset your password to safeguard your account.", 'wp-cerber' );
/* translators: %s is the number of minutes the PIN code is valid. */
$body[] = sprintf( __( 'Please use the following verification PIN code to verify your identity. The code is valid for %s minutes.', 'wp-cerber' ), CERBER_PIN_EXPIRES );
$body[] = '';
$body[] = $pin;
$user_data = get_userdata( $user_id );
$info_level = cerber_get_user_policy( '2faemailinfo', $user_data );
if ( $info_level ) {
$ds = array();
/* translators: %s is the user login name. */
$ds[] = sprintf( __( 'Login: %s', 'wp-cerber' ), $user_data->user_login );
if ( $info_level == 2 ) {
/* translators: %s is the IP address. */
$ds[] = sprintf( __( 'IP address: %s', 'wp-cerber' ), cerber_get_remote_ip() );
/* translators: %s is the hostname. */
$ds[] = sprintf( __( 'Hostname: %s', 'wp-cerber' ), @gethostbyaddr( cerber_get_remote_ip() ) );
if ( $c = lab_get_country( cerber_get_remote_ip(), false ) ) {
/* translators: %s is the location (country name and code). */
$ds[] = sprintf( __( 'Location: %s', 'wp-cerber' ), crb_get_country_name( $c ) . ' (' . $c . ')' );
}
}
/* translators: %s is the browser user agent string. */
$ds[] = sprintf( __( 'Browser: %s', 'wp-cerber' ), substr( strip_tags( crb_array_get( $_SERVER, 'HTTP_USER_AGENT', 'Not set' ) ), 0, 1000 ) );
/* translators: %s is the date. */
$ds[] = sprintf( __( 'Date: %s', 'wp-cerber' ), cerber_date( time(), false ) );
$body[] = '';
$body[] = __( 'Here are the details of the sign-in attempt', 'wp-cerber' );
$body[] = implode( "\n", $ds );
}
$body = implode( "\n\n", $body );
$email = self::get_user_email( $user_id );
$user_name = trim( $user_data->user_firstname . ' ' . $user_data->user_lastname );
$user_name = crb_sanitize_mail_display_name( $user_name );
$to = $user_name ? '"' . $user_name . '" <' . $email . '>' : $email;
$result = CRB_Messaging::send( '2fa', array(
'subj' => $subj,
'text' => $body
), array( 'email' => 1, 'pushbullet' => 0 ), true, array( 'email_recipients' => array( $to ) ) );
if ( $result && ( $user_data->user_email != $email ) ) {
// TODO Should we send a notification to the main user email?
}
return true;
}
static function get_user_email( $user_id = null ) {
if ( ! $user_id ) {
$user_id = get_current_user_id();
}
if ( lab_lab() ) {
$cus = cerber_get_set( CRB_USER_SET, $user_id );
if ( $cus
&& ( $email = crb_array_get( $cus, 'tfemail' ) )
&& is_email( $email ) ) {
return $email;
}
}
$data = get_userdata( $user_id );
return $data->user_email;
}
/**
* Return all valid user PINs
*
* @param $user_id
*
* @return string
*/
static function get_user_pin_info( $user_id ) {
if ( ! $cus = cerber_get_set( CRB_USER_SET, $user_id ) ) {
return '';
}
if ( ! $fa = crb_array_get( $cus, '2fa' ) ) {
return '';
}
$pins = '';
foreach ( $fa as $entry ) {
if ( empty( $entry['pin'] )
|| $entry['expires'] < time() ) {
continue;
}
if ( $ua = $entry['ua_raw'] ?? '' ) {
$ua_info = crb_escape_html( CRB_User_Agent_Parser::detect( $ua ) ) . ' (' . crb_escape_html( $ua ) . ')';
}
else {
$ua_info = '';
}
$pins .= '<tr><td><code style="font-size: 110%;">' . $entry['pin'] . '</code></td><td>' . cerber_ago_time( $entry['expires'] ) . '</td><td>' . ( $entry['2email'] ?? '' ) . '</td><td>' . $ua_info . '</td></tr>';
}
if ( ! $pins ) {
return '';
}
return '<div id="crb-admin-2fa-pins"><table><tr><td>PIN</td><td>Expires</td><td>Sent To</td><td>User Browser</td></tr>' . $pins . '</table></div>';
}
static function update_2fa_data( $data, $user_id = null ) {
if ( ! $user_id ) {
$user_id = get_current_user_id();
}
$cus = cerber_get_set( CRB_USER_SET, $user_id );
if ( ! is_array( $cus ) ) {
$cus = array();
}
if ( ! isset( $cus['2fa'] ) ) {
$cus['2fa'] = array();
}
$old = self::cerber_2fa_session_id();
$token = self::get_session_token_hash();
// Move existing data from the deprecated format
if ( $existing = $cus['2fa'][ $old ] ?? false ) {
unset( $cus['2fa'][ $old ] );
$cus['2fa'][ $token ] = $existing;
}
$cus['2fa'][ $token ] = array_merge( $cus['2fa'][ $token ] ?? [], $data );
return cerber_update_set( CRB_USER_SET, $cus, $user_id );
}
/**
* Returns 2FA data for the current user session
*
* @param int $current_user_id
*
* @return array
*/
static function get_2fa_data( $current_user_id = null ) {
if ( ! $current_user_id ) {
$current_user_id = get_current_user_id();
}
if ( ! $cus = cerber_get_set( CRB_USER_SET, $current_user_id ) ) {
return array();
}
if ( empty( $cus['2fa'] ) ) {
return array();
}
if ( $ret = $cus['2fa'][ self::get_session_token_hash() ] ?? false ) {
return $ret;
}
// Deprecated format
if ( $ret = $cus['2fa'][ self::cerber_2fa_session_id() ] ?? false ) {
return $ret;
}
return array();
}
/**
* Deletes all 2FA data for any given user, or the current session 2FA data of the current user
*
* @param int $uid If $all is false, may be only the current user ID
* @param bool $all If false, deletes current session 2FA data for the current user
*
* @return void
*/
static function delete_2fa( $uid, $all = false ) {
if ( ! $uid = absint( $uid ) ) {
return;
}
$cus = cerber_get_set( CRB_USER_SET, $uid );
if ( $cus && isset( $cus['2fa'] ) ) {
if ( $all ) {
unset( $cus['2fa'] );
}
else {
unset( $cus['2fa'][ self::get_session_token_hash() ] );
unset( $cus['2fa'][ self::cerber_2fa_session_id() ] );
}
cerber_update_set( CRB_USER_SET, $cus, $uid );
}
}
/**
* Return WordPress session token for the current user session
*
* @return string
*
* @deprecated since 9.6.3.2
*/
static function cerber_2fa_session_id() {
if ( self::$token ) {
return self::$token;
}
return crb_get_session_token();
}
/**
* Returns hashed WordPress session token for the current user session
* The hash can be stored in the DB safely
*
* @return string
*
* @since 9.6.3.2
*/
static function get_session_token_hash() {
$token = ( self::$token ) ?: crb_get_session_token();
return cerber_hash_token( $token );
}
static function cerber_2fa_form() {
$max = CERBER_PIN_LENGTH;
$atts = 'pattern="\d{' . $max . '}" maxlength="' . $max . '" size="' . $max . '" title="' . __( 'only digits are allowed', 'wp-cerber' ) . '"';
$email = self::get_user_email();
/* translators: %s is the masked email address. */
$text = sprintf( __( "We've sent a verification PIN code to your email %s", 'wp-cerber' ), cerber_mask_email( $email ) ) .
'<p>'. __( 'Enter the code from the email in the field below.', 'wp-cerber' ).'</p>';
//$change = '<a href="' . cerber_get_home_url() . '/?cerber_2fa_now=different">' . __( 'Sign in with a different account', 'wp-cerber' ) . '</a>';
$change = '<a href="' . cerber_get_home_url() . '/?cerber_2fa_now=different">' . __( 'Try again', 'wp-cerber' ) . '</a>';
$cancel = '<a href="' . cerber_get_home_url() . '/?cerber_2fa_now=cancel">' . __( 'Cancel', 'wp-cerber' ) . '</a>';
$links = '<p>' . __( 'Did not receive the email?', 'wp-cerber' ) . '</p>' .
/* translators: 1: "Try again" link, 2: "Cancel" link */
sprintf( __( '%1$s or %2$s', 'wp-cerber' ), $change, $cancel );
$trust = '';
if ( $days = self::get_user_days() ) {
/* translators: %d is the number of days the device will be remembered. */
$trust = '<p id="cerber_2fa_trust_device"><input name="cerber_trust_device" id="trust_this_device" type="checkbox" value="yes"><label for="trust_this_device">' . sprintf( __( 'Remember this device for %d days', 'wp-cerber' ), $days ) . '</label></p>';
}
?>
<div id="cerber_2fa_msg"></div>
<div id="cerber_2fa_box">
<div id="cerber_2fa_wrap">
<div id="cerber_2fa_inner">
<h1 id="cerber_2fa_title"><?php _e( "Verify it's you", 'wp-cerber' ); ?></h1>
<div id="cerber_2fa_info"><?php echo $text; ?></div>
<form id="cerber_2fa_form" method="post" data-verified="no">
<p><input required type="text" name="cerber_pin" <?php echo $atts; ?> ></p>
<p><input type="hidden" name="cerber_tag" value="2FA"></p>
<?php echo $trust; ?>
<p><input type="submit" value="<?php _e( 'Verify', 'wp-cerber' ); ?>"></p>
</form>
</div>
</div>
<?php echo $links; ?>
</div>
<script>
jQuery( function( $ ) {
let cform = $('#cerber_2fa_form');
let umsg = 'cerber_2fa_msg';
cform.submit(function (event) {
crb_hide_user_msg();
if (cform.data('verified') === 'yes') {
return;
}
event.preventDefault();
$.post(ajaxurl, {
the_2fa_nonce: nonce2fa,
cerber_verify_pin: $(this).find('input[type="text"]').val()
},
function (server_response, textStatus, jqXHR) {
let server_data = JSON.parse(server_response);
if (server_data.error.length === 0) {
cform.find('[name="cerber_tag"]').val(nonce2fa);
cform.data('verified', 'yes');
cform.submit();
}
else {
crb_display_user_msg(server_data['error']);
}
}
).fail(function (jqXHR, textStatus, errorThrown) {
let err = errorThrown + ' ' + jqXHR.status;
alert(err);
console.error('Server Error: ' + err);
});
});
function crb_display_user_msg(msg) {
$('#' + umsg).fadeIn(500).html(msg);
setTimeout(function (args) {
crb_hide_user_msg();
}, 5000);
}
function crb_hide_user_msg() {
document.getElementById(umsg).style.display = "none";
}
});
</script>
<?php
}
}
/**
* @param $user WP_User
*
* @return string
*/
function cerber_2fa_get_redirect_to( $user ) {
if ( isset( $_REQUEST['redirect_to'] ) ) {
$redirect_to = $_REQUEST['redirect_to'];
$requested_redirect_to = $redirect_to;
}
else {
$redirect_to = admin_url();
$requested_redirect_to = '';
}
$redirect_to = apply_filters( 'login_redirect', $redirect_to, $requested_redirect_to, $user );
return $redirect_to;
}
/**
* Verify that 2FA on the website works
* If it works, 2FA can be enabled for admins
*
*/
function cerber_2fa_checker( $save = false ) {
if ( $save ) {
cerber_update_set( 'cerber_2fa_is_ok', 1, null, false );
}
else {
if ( cerber_get_set( 'cerber_2fa_is_ok', null, false ) ) {
return true;
}
return false;
}
}
Home - Capital GMC Buick Regina
Skip to content
{{ $t(category) }}
Error
{{vehicle.modelData.year}} {{vehicle.modelData.make}} {{vehicle.modelData.model}}
Starting from {{vehicle.modelData.startingPrice | moneyFormat(lang)}}
Welcome to Capital GMC BUICK – REGINA
Thank you for choosing Capital GMC Buick | Regina, your premier certified Buick and GMC dealership proudly serving drivers in Regina and the surrounding communities. Whether you’re searching for a brand-new Buick or GMC vehicle or a meticulously inspected pre-owned model, we have a diverse selection to match your needs and lifestyle.
Beyond our impressive inventory, we offer a seamless and stress-free financing experience through our well-connected finance centre, where our team of experts is dedicated to securing the best loan or lease options for you, quickly, transparently, and hassle-free.
But our commitment to you doesn’t stop at the sale. Our state-of-the-art service centre is staffed with skilled Buick and GMC technicians who use the latest equipment and genuine OEM parts to keep your vehicle running at its best. From routine maintenance to complex repairs, we’ve got you covered.
Experience top-tier customer service, quality vehicles, and expert care, all in one place. Visit Capital GMC Buick | Regina today or call us at 306-205-8072 with any questions. We’re here to help!
Ask a Question
Capital GMC Buick – Regina
Contact Us
Have a question or need assistance? Fill out the form and we will reach out to you as soon as possible.
Notice: JavaScript is required for this content.
CLOSE
Schedule a Visit
Let us know when you are coming and how we can assist you. We can ensure someone will be on hand to help you out at the desired date and time.
Notice: JavaScript is required for this content.
CLOSE
Find a Career
Have a look at our list of available positions and apply online today to join our team!
×
Opportunities to Grow
The auto industry is constantly changing and we want to continue to grow. We offer growth, leadership & mentorship programs to allow our staff to grow with us.
×
Competitive Salary
We have a significant earning potential with incentive-based pay in most roles. We also offer an employee referral bonus with paid bonuses.
×
Health & Dental
We offer a comprehensive benefits package including extended health, dental, and vision care. We also include paramedical, life insurance, paid sick leave, short & long-term disability coverages.
×
Vacation
We value our employees and want everyone to take their vacation time. We offer a minimum of 2 weeks vacation each year.
×
Training & Development
We have many opportunities for paid education and training in-house as well as training from the Manufacturer.
×
$10,000 Cash Giveaway – Terms & Conditions
All October long, stop by Capital GMC Buick Cadillac, to enter for your chance to win $10,000 cash. No purchase is required, but entries must be made in-store.
The contest is open to residents of Saskatchewan who are 18+. Dealership employees and their households are not eligible. Entries will be accepted from October 1 to October 31, 2025. A random draw will take place on November 1, 2025.
The prize is one $10,000 award, paid by cheque, and must be accepted as awarded. Winner will be contacted by phone or email and must respond within 7 days or another entry may be drawn. Odds of winning depend on the number of entries received.By entering, you agree that Capital Automotive Group may use your name and photo for winner announcements. The contest is governed by the laws of Saskatchewan.
Notice: JavaScript is required for this content.
CLOSE