Pārlūkot izejas kodu

OAuth (part 4 draft)

Visman 2 gadi atpakaļ
vecāks
revīzija
76350bc12e

+ 5 - 0
app/Models/Pages/Admin/Update.php

@@ -499,6 +499,11 @@ class Update extends Admin
             '\\ForkBB\\Models\\Pages\\RegLog::class',
             'Register'
         );
+        $coreConfig->add(
+            'shared=>providerUser',
+            '\\ForkBB\\Models\\ProviderUser\\ProviderUser::class',
+            'providers'
+        );
 
         $coreConfig->save();
 

+ 30 - 2
app/Models/Pages/Auth.php

@@ -22,6 +22,11 @@ class Auth extends Page
 {
     use RegLogTrait;
 
+    /**
+     * Флаг входа c использованием html формы
+     */
+    protected bool $loginWithForm = true;
+
     /**
      * Выход пользователя
      */
@@ -59,6 +64,24 @@ class Auth extends Page
         $v = null;
 
         if ('POST' === $method) {
+            // вход без html формы
+            if (
+                isset($args['user'])
+                && $args['user'] instanceof User
+            ) {
+                $this->userAfterLogin = $args['user'];
+                $this->loginWithForm  = false;
+
+                $_POST = [
+                    'token'    => $this->c->Csrf->create('Login'),
+                    'redirect' => $this->c->Csrf->create('Index'),
+                    'username' => $this->userAfterLogin->username,
+                    'password' => $this->userAfterLogin->password,
+                    'save'     => '1',
+                    'login'    => 'Login User model',
+                ];
+            }
+
             $v = $this->c->Validator->reset()
                 ->addValidators([
                     'login_check' => [$this, 'vLoginCheck'],
@@ -188,7 +211,9 @@ class Auth extends Page
     public function vLoginCheck(Validator $v, #[SensitiveParameter] string $password ): string
     {
         if (empty($v->getErrors())) {
-            $this->userAfterLogin = $this->c->users->loadByName($v->username);
+            if ($this->loginWithForm) {
+                $this->userAfterLogin = $this->c->users->loadByName($v->username);
+            }
 
             if (
                 ! $this->userAfterLogin instanceof User
@@ -197,7 +222,10 @@ class Auth extends Page
                 $v->addError('Wrong user/pass');
             } elseif ($this->userAfterLogin->isUnverified) {
                 $v->addError('Account is not activated', 'w');
-            } elseif (! \password_verify($password, $this->userAfterLogin->password)) {
+            } elseif (
+                $this->loginWithForm
+                && ! \password_verify($password, $this->userAfterLogin->password)
+            ) {
                 $v->addError('Wrong user/pass');
             }
         }

+ 23 - 1
app/Models/Pages/RegLog.php

@@ -80,6 +80,28 @@ class RegLog extends Page
             }
         }
 
-        exit(var_dump($provider->userId, $provider->userName, $provider->userEmail));
+        // гость
+        if ($this->user->isGuest) {
+            $uid = $this->c->providerUser->findUser($provider);
+
+            // логин
+            if ($uid > 0) {
+                $args = [
+                    'user' => $this->c->users->load($uid),
+                ];
+
+                return $this->c->Auth->login($args, 'POST');
+
+            // регистрация
+            } else {
+
+            }
+
+        // пользователь
+        } else {
+
+        }
+
+        exit(var_dump($provider->userId, $provider->userName, $provider->userEmail, $this->c->NormEmail->normalize($provider->userEmail)));
     }
 }

+ 81 - 0
app/Models/ProviderUser/ProviderUser.php

@@ -0,0 +1,81 @@
+<?php
+/**
+ * This file is part of the ForkBB <https://github.com/forkbb>.
+ *
+ * @copyright (c) Visman <mio.visman@yandex.ru, https://github.com/MioVisman>
+ * @license   The MIT License (MIT)
+ */
+
+declare(strict_types=1);
+
+namespace ForkBB\Models\ProviderUser;
+
+use ForkBB\Core\Container;
+use ForkBB\Models\Model;
+use ForkBB\Models\Provider\Driver;
+use PDO;
+use RuntimeException;
+
+class ProviderUser extends Model
+{
+    /**
+     * Ключ модели для контейнера
+     */
+    protected string $cKey = 'ProvUser';
+
+    /**
+     * Возращает id локального пользователя по данным провайдера или 0
+     * Поиск идет по провайдеру и идентификатору пользователя
+     */
+    public function findUser(Driver $provider): int
+    {
+        if ('' == $provider->userId) {
+            throw new RuntimeException('The user ID is empty');
+        }
+
+        $vars = [
+            ':name' => $provider->name,
+            ':id'   => $provider->userId,
+        ];
+        $query = 'SELECT pu.uid
+            FROM ::providers_users AS pu
+            WHERE pu.pr_name=?s:name AND pu.pu_uid=?s:id';
+
+        $result = $this->c->DB->query($query, $vars)->fetchAll(PDO::FETCH_COLUMN);
+        $count  = \count($result);
+
+        if ($count > 1) {
+            throw new RuntimeException("Many entries for '{$provider->name}-{$provider->userId}'");
+        }
+
+        return $count ? \array_pop($result) : 0;
+    }
+
+    /**
+     * Возращает id локального пользователя по данным провайдера или 0
+     * Поиск идет по email
+     */
+    public function findEmail(Driver $provider): int
+    {
+        if ('' == $provider->userEmail) {
+            throw new RuntimeException('The user email is empty');
+        }
+
+        $vars = [
+            ':email' => $this->c->NormEmail->normalize($provider->userEmail),
+        ];
+        $query = 'SELECT pu.uid
+            FROM ::providers_users AS pu
+            WHERE pu.pu_email_normal=?s:email
+            GROUP BY pu.uid';
+
+        $result = $this->c->DB->query($query, $vars)->fetchAll(PDO::FETCH_COLUMN);
+        $count  = \count($result);
+
+        if ($count > 1) {
+            throw new RuntimeException("Many entries for '{$provider->userEmail}'");
+        }
+
+        return $count ? \array_pop($result) : 0;
+    }
+}

+ 1 - 0
app/config/main.dist.php

@@ -169,6 +169,7 @@ return [
                 'github' => \ForkBB\Models\Provider\Driver\GitHub::class,
             ],
         ],
+        'providerUser'  => \ForkBB\Models\ProviderUser\ProviderUser::class,
 
         'Csrf' => [
             'class'  => \ForkBB\Core\Csrf::class,