Skip to content
SOFe edited this page Sep 18, 2016 · 12 revisions

Developer documentation

Add extra registration fields

  1. Create a class that implements the HereAuth\User\Registration\RegistrationStep interface.
  2. Create a constructor that accepts a HereAuth\User\User as argument and stores it in a class property.
  3. Implement the getMessage() method, which returns a string containing the message to send to the player when the player:
  4. Implement the onSubmit() method. It accepts a string argument that is exactly what the player inputted, and returns a boolean (true/false) to indicate whether the value is accepted by you. If false is returned, the player will have to type the value again. If you return null (or if you return nothing), it will be casted to boolean to become false. Therefore, always return a value, true or false. You can know which player this is about using the User you stored in the constructor.
  5. Create an event handler for HereAuth\Event\HereAuthRegistrationCreationEvent.
  6. In the event, use the $event->getRegistration()->addStep() method to add a new instance of the class you just created above. Developers SHOULD use a different instance for every time the event is triggered. You can get the User required from the $event->getUser() function.

Example:

use pocketmine\event\Listener;

use HereAuth\Event\HereAuthRegistrationCreationEvent;
use HereAuth\User\User;
use HereAuth\User\Registration\RegistrationStep;

class MyRegStep implements RegistrationStep{
    private $user;

    public function __construct(User $user){
        $this->user = $user;
    }

    public function getMessage(){
        return "Please enter your email.";
    }

    public function onSubmit($addr){
        if(!preg_match('/^[A-z0-9_\-]+[@][A-z0-9_\-]+([.][A-z0-9_\-]+)+[A-z.]{2,4}$/', $addr)){
            $this->user->getPlayer()->sendMessage("Invalid email!");
            return false;
        }
        mail($addr, "You have been registered!", "Hello " . $this->user->getPlayer->getName() . ",\r\n" .
                "You have been registered with HereAuth on the following server:\r\n" .
                Utils::getIP() . ":" . $this->user->getMain()->getServer()->getPort() . "\r\nHave fun!");
        return true;
    }
}

class MyEventListener implements Listener{
    public function onRegistrationCreate(HereAuthRegistrationCreationEvent $event){
        $event->getRegistration()->addStep(new MyRegStep($event->getUser()));
    }
}

You can adjust the order of this field from other plugins, through adjusting the event handler priority in the documentation comment before the event handler (PocketMine built-in feature):

class MyEventListener implements Listener{
    /**
     * @priority LOW
     */
    public function onRegistrationCreate(HereAuthRegistrationCreationEvent $event){

As you might already know, there are 6 event priorities, being dispatched in this subsequent order: LOWEST -> LOW -> NORMAL -> HIGH -> HIGHEST -> MONITOR. However, you SHOULD NOT handle it at the MONITOR level so that event handlers after your one can see the step you added! As the PocketMine documentation says:

Event is listened to purely for monitoring the outcome of an event.

No modifications to the event should be made under this priority

Another point to note is that password input (and password confirm) as well as the custom registration steps defined in config.yml must come before steps added in events.

Change multi-factor authentication (MFA) behaviour

HereAuthMultiFactorAuthEvent when MFA takes place for a player.

Add a new type of MFA

Plugins can carry out MFA when HereAuthMultiFactorAuthEvent is fired. Use the HereAuthMultiFactorAuthEvent::addFailureEntry method if the custom MFA failed.

Example:

class MyEventListener implements Listener{
    /**
     * @param HereAuthMultiFactorAuthEvent $event
     *
     * @ignoreCancelled true
     */
    public function handleMFA(HereAuthMultiFactorAuthEvent $event){
        $user = $event->getUser();
        $player = $event->getPlayer();
        if($this->myOwnMFAFailsFor($player, $data)){
            $event->addFailureEntry("my-mfa-type-name", "Invalid MyMFA check", $data);
        }
    }
    public function myOwnMFAFailsFor(Player $player, &$data){
        $data = SOME_PRINTABLE_STRING;
        return A_BOOLEAN_VALUE;
    }
}

Disable a certain type of MFA

A certain type of MFA can be cancelled using the HereAuthMultiFactorAuthEvent::removeFailure method.

For example, to cancel skin MFA, an event handler of HereAuthMultiFactorAuthEvent can run $event->removeFailure("skin");. This returns true if skin MFA actually failed for that user, or false if skin MFA didn't run or the user passed it.

There are infinite types of MFA, as other plugins can add new types anytime. However, these are the current types by HereAuth:

  • skin - skin MFA
  • ip - IP MFA

Cancelling MFA

If a HereAuthMultiFactorAuthEvent is cancelled, whether MFA fails or not, the user would automatically pass the MFA checking.

HereAuthMultiFactorAuthEvent is cancelled when it is fired if the user has MFA timeout expired.

Handle events

Event name (**** in HereAuth\Event\ HereAuth****Event) Description Can be cancelled?
Authentication When a player auto-authed, registered or logged in with password, or when the player joined without registering (only for servers where ForceRegister is false)
RegistrationCreation When a user starts registering, this event is triggered so that other plugins can add registration steps to it
Login When a user had registered before and AutoAuth or password auth matched
Registration When a user has registered
MultiFactorAuth When a user undergoes MFA
Unregister Before a player is unregistered
Logout When a user is logged out

Imported hash algorithms

In order to support database importing, "imported hash" will be implemented in a "register-and-get" style.

While importing a specific database, the importer would identify the passwords in the database as encoded by a specific algorithm, then store it in the multiHash property of the account info with a type of the algorithm. It will be deleted and converted into normal hash when player logins.

This is also used by account renaming. When an account is renamed, the hash no longer works as the salt has been changed, and the player has to type the password again. In the meantime, the hash will be stored in the multiHash property, with the type being "rename".

Apart from the type of algorithm (multiHash type), extra data may be stored per account, for example, the salt. To store the data, the type row is appended with a ; then a suffix.

It is very simple to register a new type of imported hash: HereAuth::addImportedHash. The following example registers an imported hash using the whirlpool hash and a salt from the suffix:

class WhirlpoolHashPlugin extends PluginBase{
    public function onEnable(){
        // this plugin should have HereAuth as dependency
        $plugin = $this->getServer()->getPluginManager()->getPlugin("HereAuth");
        $plugin->addImportedHash(new WhirlpoolHash);
    }
    // in the future, HereAuth should have a method to remove imported hashes. Plugins should remove hashes they registered in onDisable().
}

class WhirlpoolHash implements ImportedHash{
    public function getName(){
        return "whirlpool";
    }

    public function hash($password, $salt, $suffix){
        // the $salt argument is the salt used by HereAuth hashes, which is strtolower($playerName).
        // it is generally useless for imported hashes. (it should actually be removed, but it was too late already)
        return hash("whirlpool", $suffix . $password . $suffix); // suffix is our salt
    }
}
Clone this wiki locally