ソースを参照

OAuth (part 5 draft)

Visman 2 年 前
コミット
9107637d4e

+ 89 - 9
app/Models/Pages/RegLog.php

@@ -13,6 +13,7 @@ namespace ForkBB\Models\Pages;
 use ForkBB\Core\Validator;
 use ForkBB\Core\Exceptions\MailException;
 use ForkBB\Models\Page;
+use ForkBB\Models\Provider\Driver;
 use ForkBB\Models\User\User;
 use function \ForkBB\__;
 
@@ -84,19 +85,60 @@ class RegLog extends Page
         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 {
+            if (empty($uid)) {
+                // на форуме есть пользователь с таким email
+                if ($this->c->providerUser->findEmail($provider) > 0) {
+                    $auth         = $this->c->Auth;
+                    $auth->fIswev = ['i', ['Email message', __($provider->name)]];
+
+                    return $auth->forget([], 'GET', $provider->userEmail);
+                }
+
+                if (1 !== $this->c->config->b_regs_allow) {
+                    return $this->c->Message->message('No new regs');
+                }
+
+                $user = $this->c->users->create();
+
+                $user->username        = $this->nameGenerator($provider);
+                $user->password        = \password_hash($this->c->Secury->randomPass(72), \PASSWORD_DEFAULT);
+                $user->group_id        = $this->c->config->i_default_user_group;
+                $user->email           = $provider->userEmail;
+                $user->email_confirmed = $provider->userEmailVerifed ? 1 : 0;
+                $user->activate_string = '';
+                $user->u_mark_all_read = \time();
+                $user->email_setting   = $this->c->config->i_default_email_setting;
+                $user->timezone        = $this->c->config->o_default_timezone;
+                $user->language        = $this->user->language;
+                $user->style           = $this->user->style;
+                $user->registered      = \time();
+                $user->registration_ip = $this->user->ip;
+                $user->ip_check_type   = 0;
+                $user->signature       = '';
+                $user->location        = $provider->userLocation;
+                $user->url             = $provider->userURL;
+
+                $newUserId = $this->c->users->insert($user);
+
+                if (true !== $this->c->providerUser->registration($user, $provider)) {
+                    throw new RuntimeException('Failed to insert data'); // ??????????????????????????????????????????
+                }
+
+                $this->c->Log->info('OAuth Reg: ok', [
+                    'user'     => $user->fLog(),
+                    'provider' => $provider->name,
+                    'userInfo' => $provider->userInfo,
+                    'headers'  => true,
+                ]);
 
+            } else {
+                $user = $this->c->users->load($uid);
             }
 
+            // вход
+            return $this->c->Auth->login(['user' => $user], 'POST');
+
         // пользователь
         } else {
 
@@ -104,4 +146,42 @@ class RegLog extends Page
 
         exit(var_dump($provider->userId, $provider->userName, $provider->userEmail, $this->c->NormEmail->normalize($provider->userEmail)));
     }
+
+    /**
+     * Подбирает уникальное имя для регистрации пользователя
+     */
+    protected function nameGenerator(Driver $provider): string
+    {
+        $names = [];
+
+        if ('' != $provider->userName) {
+            $names[] = $provider->userName;
+        }
+
+        if ('' != $provider->userLogin) {
+            $names[] = $provider->userLogin;
+        }
+
+        if ('' != ($tmp = (string) \strstr($provider->userEmail, '@', true))) {
+            $names[] = $tmp;
+        }
+
+        $names[] = 'user' . \time();
+        $v       = $this->c->Validator->reset()->addRules(['name' => 'required|string:trim|username|noURL:1']);
+        $end     = '';
+        $i       = 0;
+
+        while ($i < 100) {
+            foreach ($names as $name) {
+                if ($v->validation(['name' => $name . $end])) {
+                    return $v->name;
+                }
+            }
+
+            $end = '_' . $this->c->Secury->randomHash(4);
+            ++$i;
+        }
+
+        throw new RuntimeException('Failed to generate unique username');
+    }
 }

+ 5 - 0
app/Models/Provider/Driver.php

@@ -210,6 +210,11 @@ abstract class Driver extends Model
      */
     abstract protected function getuserId(): string;
 
+    /**
+     * Возвращает логин пользователя (от провайдера)
+     */
+    abstract protected function getuserLogin(): string;
+
     /**
      * Возвращает имя пользователя (от провайдера)
      */

+ 11 - 3
app/Models/Provider/Driver/GitHub.php

@@ -71,7 +71,7 @@ class GitHub extends Driver
             return false;
         }
 
-        $this->userInfo = $userInfo;
+        $this->userInfo = $this->c->Secury->replInvalidChars($userInfo);
 
         return true;
     }
@@ -84,12 +84,20 @@ class GitHub extends Driver
         return (string) ($this->userInfo['id'] ?? '');
     }
 
+    /**
+     * Возвращает логин пользователя (от провайдера)
+     */
+    protected function getuserLogin(): string
+    {
+        return (string) ($this->userInfo['login'] ?? '');
+    }
+
     /**
      * Возвращает имя пользователя (от провайдера)
      */
     protected function getuserName(): string
     {
-        return (string) ($this->userInfo['name'] ?? ($this->userInfo['login'] ?? ''));
+        return (string) ($this->userInfo['name'] ?? '');
     }
 
     /**
@@ -129,7 +137,7 @@ class GitHub extends Driver
      */
     protected function getuserLocation(): string
     {
-        return (string) ($this->userInfo['location'] ?? '');
+        return \mb_substr((string) ($this->userInfo['location'] ?? ''),  0, 30, 'UTF-8');
     }
 
     /**

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

@@ -13,6 +13,7 @@ namespace ForkBB\Models\ProviderUser;
 use ForkBB\Core\Container;
 use ForkBB\Models\Model;
 use ForkBB\Models\Provider\Driver;
+use ForkBB\Models\User\User;
 use PDO;
 use RuntimeException;
 
@@ -78,4 +79,35 @@ class ProviderUser extends Model
 
         return $count ? \array_pop($result) : 0;
     }
+
+    /**
+     * Создает новую связь между пользователем и провайдером
+     */
+    public function registration(User $user, Driver $provider): bool
+    {
+        if ($user->isGuest) {
+            throw new RuntimeException('User expected, not guest');
+        }
+
+        if ('' == $provider->userId) {
+            throw new RuntimeException('The user ID is empty');
+        }
+
+        if ('' == $provider->userEmail) {
+            throw new RuntimeException('The user email is empty');
+        }
+
+        $vars = [
+            ':uid'    => $user->id,
+            ':name'   => $provider->name,
+            ':userid' => $provider->userId,
+            ':email'  => $provider->userEmail,
+            ':normal' => $this->c->NormEmail->normalize($provider->userEmail),
+            ':verif'  => $provider->userEmailVerifed ? 1 : 0,
+        ];
+        $query = 'INSERT INTO ::providers_users (uid, pr_name, pu_uid, pu_email, pu_email_normal, pu_email_verified)
+            VALUES (?i:uid, ?s:name, ?s:userid, ?s:email, ?s:normal, ?i:verif)';
+
+        return false !== $this->c->DB->exec($query, $vars);
+    }
 }

+ 6 - 0
app/lang/en/admin_providers.po

@@ -77,3 +77,9 @@ msgstr "cURL error."
 
 msgid "User error"
 msgstr "User data request failed."
+
+msgid "No new regs"
+msgstr "This board is not accepting new registrations."
+
+msgid "Email message"
+msgstr "This email received from %s belongs to a registered user.<br>Perhaps you used another provider to sign in or username + passphrase?"

+ 6 - 0
app/lang/ru/admin_providers.po

@@ -77,3 +77,9 @@ msgstr "Ошибка cURL."
 
 msgid "User error"
 msgstr "Ошибка запроса данных пользователя."
+
+msgid "No new regs"
+msgstr "Форум закрыт для новых регистраций."
+
+msgid "Email message"
+msgstr "Данный электронный адрес, полученный от %s, принадлежит зарегистрированному пользователю.<br>Возможно, вы использовали другого провайдера для входа или имя + кодовую фразу?"