Skip to content

Commit

Permalink
Add password provider
Browse files Browse the repository at this point in the history
  • Loading branch information
HasanAlyazidi committed Aug 22, 2024
1 parent a35932e commit 5f18021
Show file tree
Hide file tree
Showing 4 changed files with 151 additions and 0 deletions.
11 changes: 11 additions & 0 deletions config/sendables.php
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
<?php

use App\Models\User;
use HasanAlyazidi\Sendables\Models\Otp;
use HasanAlyazidi\Sendables\OTP\Providers\TesterOtpProvider;
use HasanAlyazidi\Sendables\OTP\Providers\FirebaseOtpProvider;
use HasanAlyazidi\Sendables\OTP\Providers\PasswordProvider;
use HasanAlyazidi\Sendables\SMS\Providers\OurSMSV2Provider;

return [
Expand Down Expand Up @@ -38,6 +40,15 @@
*/
'default' => FirebaseOtpProvider::class,

/**
* Password
*/
'password' => [
'model' => User::class,
'column' => 'password',
'provider' => PasswordProvider::class,
],

/**
* Tester
*/
Expand Down
21 changes: 21 additions & 0 deletions src/OTP/OtpVerifier.php
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,27 @@ private function setProvider() : void
return;
}

$passwordProvider = config('sendables.otp.providers.password');

$passwordProviderModel = $passwordProvider['model'];
$passwordProviderColumn = $passwordProvider['column'];

$mobileAccounts = $passwordProviderModel::where('mobile', $this->mobile)->get();

$countPasswordUsed = $mobileAccounts->whereNotNull($passwordProviderColumn)->count();
$isPasswordUsed = $countPasswordUsed >= 1;

if ($isPasswordUsed) {
$doAllAccountsHavePasswords = $mobileAccounts->count() == $countPasswordUsed;

if ($doAllAccountsHavePasswords) {
$this->selectedProvider = new $passwordProvider['provider']($this->mobile);
return;
}

// TODO: Multi providers used
}

$customProviders = config('sendables.otp.customProviders');

foreach ($customProviders as $code => $customProvider) {
Expand Down
103 changes: 103 additions & 0 deletions src/OTP/Providers/PasswordProvider.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
<?php

namespace HasanAlyazidi\Sendables\OTP\Providers;

use Illuminate\Support\Facades\Crypt;
use Illuminate\Support\Facades\Hash;
use SendablesHelpers;
use Throwable;

class PasswordProvider extends OtpProvider
{
protected $mobile;

public function __construct(string $mobile) {
$this->mobile = SendablesHelpers::removeLeadingPlus($mobile);
}

public function getClientType() : string
{
return 'password';
}

public function getCodeDigitsCount() : int
{
return 6;
}

public function send() : bool
{
return true;
}

public function confirm(string $password) : bool
{
$userModel = SendablesHelpers::getPasswordModel();

$users = $userModel::where('mobile', $this->mobile)->get();

$user = $users->first();

if ($user === null || $users->count() > 1) {
$this->setError(self::ERROR_CONFIRM_UNSENT);
return false;
}

$isCorrectPassword = Hash::check($password, $user->password);

if ($isCorrectPassword) {
$userToken = $user->generateAccessToken();

$encryptedOtpUserId = Crypt::encryptString($user->id);
$encryptedOtpUserToken = Crypt::encryptString($userToken);

$this->setOtpAuthenticationParams($encryptedOtpUserId, $encryptedOtpUserToken);

return true;
}

$this->setError(self::ERROR_WRONG_CODE);

return false;
}

public function isAuthenticated(string $otpUserId, string $otpUserToken) : bool
{
try {
$decryptedOtpUserId = Crypt::decryptString($otpUserId);
$decryptedOtpUserToken = Crypt::decryptString($otpUserToken);

$userModel = SendablesHelpers::getPasswordModel();

$user = $userModel::where('id', $decryptedOtpUserId)
->where('mobile', $this->mobile)
->first();

if ($user === null) {
return false;
}

$accessTokenId = $this->extractAccessTokenIdFromBearerToken($decryptedOtpUserToken);

$isValidToken = $user->tokens()->firstWhere('id', $accessTokenId) !== null;

return $isValidToken;
} catch (Throwable $e) {
return false;
}
}

public function extractAccessTokenIdFromBearerToken(string $bearerToken): string
{
$authHeader = explode(' ', $bearerToken);
$authHeaderTokenPart = $authHeader[0];

$tokenParts = explode('.', $authHeaderTokenPart);
$tokenHeader = $tokenParts[1];

$tokenHeaderJson = json_decode(base64_decode($tokenHeader), true);
$accessTokenId = $tokenHeaderJson['jti'];

return $accessTokenId;
}
}
16 changes: 16 additions & 0 deletions src/helpers.php
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,22 @@ public static function getOtpTableName()
return $tableName;
}

/**
* Get password model
*
* @return string
*/
public static function getPasswordModel()
{
$modelClass = config('sendables.otp.providers.password.model');

if (is_null($modelClass)) {
throw new Exception('Please include password `model` in `otp` inside config/sendables.php');
}

return $modelClass;
}

/**
* Add plus (+) in the beginning
*
Expand Down

0 comments on commit 5f18021

Please sign in to comment.