XF 2.0 Two-step validation through PHP script

Nicholas Ward

Member
Licensed customer
I have everything else supported.. just can't figure out how to handle two-step for the life of me. I need to check if they have it active, then see if it's currently saved and if not, save it. Anybody have any ideas?

Code:
<?php
$ip = $_POST['ip'];
$name = $_POST['name'];
$pass = $_POST['pass'];
$email = $_POST['email'];
if (!isset($ip, $name, $pass)) {
       die();
}
/**
* Create the bridge to Xenforo
**/
$fileDir = '../../';
require($fileDir . '/src/XF.php');
XF::start($fileDir);

/**
* Check if the username is registered (login and prompt for e-mail to create account)
*/
$finder = \XF::finder('XF:User');
$user = $finder->where('username', $name)->fetchOne();
if(!$user) {
    /**
     * Validate the username before proceeding with registration
     */
    $validator = \XF::app()->validator('Username');
    $username = $validator->coerceValue($name);
    if (!$validator->isValid($username, $errorKey)) {
        if($errorKey == 'too_long') {
            die('Username too long.');
        } else if($errorKey == 'disallowed' || $errorKey == 'censored') {
            die('Username contained disallowed words.');
        } else if($errorKey == 'regex' || $errorKey == 'comma') {
            die('Username contains incorrect characters.');
        } else if($errorKey == 'duplicate') {
            die('Username must be unique.');
        }
    }

    /**
     * If the account isn't registered and POST doesn't include email.. request! :-)
     */
    if(empty($email)) {
        die('Email required.');
    }

    /**
     * Ensure email isn't in use
     */
    $emailInUse = \XF::finder('XF:User')->where('email', $email)->fetchOne();
    if ($emailInUse) {
        die('Email in use.');
    }

    /**
     * Validate email
     */
    $emailValidator = \XF::app()->validator('Email');
    $emailValidator->setOption('check_typos', true);

    if (!$emailValidator->isValid($email, $errorKey)) {
        if ($errorKey == 'banned') {
            die('Email banned.');
        } else if ($errorKey == 'typo') {
            die('Email type.');
        } else {
            die('Invalid email.');
        }
    }

    /**
     * Register the new user
     */
    $registration = XF::service('XF:User\Registration');
    $input['username'] = $name;
    $input['email'] = $email;
    $input['password'] = $pass;
    $registration->setFromInput($input);
    $user = $registration->save();

    /**
     * Set the user groups
     */
    $user-> user_group_id = 2;
    //$user->secondary_group_ids = [1, 2, 3];
    $user->save();

    /**
     * Log the user in
     */
    $columns = array("user_id", "username", "user_group_id", "secondary_group_ids");
    $data = array();
    foreach ($columns as $c) {
        $data[$c] = $user[$c];
    }
    die('d=' . json_encode($data));
}

/**
* Check if the user is banned
*/
if($user->is_banned) {
    die('Banned.');
}

/**
* Verify the account details
**/
$loginService = \XF::app()->service('XF:User\Login', $name, $ip);
$success = $loginService->validate($pass);
if(!$success) {
    die('Incorrect password. Please try again.');
}

/**
* Verify two-step authentication
**/


/**
* Successful login
**/
$columns = array("user_id", "username", "user_group_id", "secondary_group_ids");
$data = array();
foreach ($columns as $c) {
    $data[$c] = $user[$c];
}
die('d=' . json_encode($data));

Thanks guys!
 
Last edited:
Is it that you want to switch the thing off? Go to settings mate it's in user groups and permissions
 
Is it that you want to switch the thing off? Go to settings mate it's in user groups and permissions

Hey man! Thanks for the reply. Nah, not trying to disable it. Attempting to integrate the checks into the script so that I can validate through the game client through java.
 
Check the XF/ControllerPlugin/Login.php file. There is a function
Code:
runTfaCheck
That should help.
 
Check the XF/ControllerPlugin/Login.php file. There is a function
Code:
runTfaCheck
That should help.

Hey, thanks for the reply man. How do I reference the plugin, though?

XF::service('XF:User\Login'); is for the service... but I don't see anything referencing a plugin.
 
Not entire sure how I would get the Controller plugin, but when you need a controller plugin from within a controller, it can be retrieved by
Code:
$this->plugin('XF:Login');

And plugin method in Controller.php is
Code:
public function plugin($name)
{
   $class = \XF::stringToClass($name, '%s\ControllerPlugin\%s');
   $class = $this->app->extendClass($class);

   return new $class($this);
}
 
Not entire sure how I would get the Controller plugin, but when you need a controller plugin from within a controller, it can be retrieved by
Code:
$this->plugin('XF:Login');

And plugin method in Controller.php is
Code:
public function plugin($name)
{
   $class = \XF::stringToClass($name, '%s\ControllerPlugin\%s');
   $class = $this->app->extendClass($class);

   return new $class($this);
}

Thanks man. I'll look into this as soon as I'm home.
 
In case people were curious, I ended up getting this to work. Here's how I did it:

PHP:
$tfaEnabled = $user->Option->use_tfa;
if ($tfaEnabled) {
    $tfaRepository = $user->repository('XF:Tfa');
    if ($tfaRepository->userRequiresTfa($user)) {
        $tfaTrustValue = $_POST['key'];
        $milliseconds = round(microtime(true) * 1000);
        $tfaTrustRepo = $user->repository('XF:UserTfaTrusted');
        if (!$tfaTrustRepo->getTfaTrustRecord($user->user_id, $tfaTrustValue)) {
            $tfaCode = $_POST['code'];
            if ($tfaCode == 0) {
                die("Two-factor authentication required.");
            }

            $providerId = 'totp';
            $tfaService = $loginService->service('XF:User\Tfa', $user);

            $providers = $tfaService->getProviders();
            $provider = $providers[$providerId];
            $providerData = $provider->getUserProviderConfig($user->user_id);
            $handler = $provider->handler;
            if (!$handler->verify('login', $user, $providerData, \XF::app()->request())) {
                die("Two-factor authentication invalid!");
            } else {
                if ($_POST['trust'] === true) {
                    $db = \XF::db();
                    $db->insert('xf_user_tfa_trusted', [
                        'user_id' => $user->user_id,
                        'trusted_key' => $tfaTrustValue,
                        'trusted_until' => \XF::$time + 86400 * 30
                    ]);
                }
            }
        }
    }
}
 
Last edited:
Back
Top Bottom