diff --git a/.gitignore b/.gitignore index f02b897..3138173 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,2 @@ -cookie.txt -/vendor \ No newline at end of file +/vendor +!.gitignore diff --git a/LICENSE b/LICENSE deleted file mode 100644 index e5abfa3..0000000 --- a/LICENSE +++ /dev/null @@ -1,22 +0,0 @@ -This program is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program. If not, see . - -Это свободная программа: вы можете перераспространять ее и/или изменять -ее на условиях Стандартной общественной лицензии GNU в том виде, в каком -она была опубликована Фондом свободного программного обеспечения; либо -версии 3 лицензии, либо (по вашему выбору) любой более поздней версии. - -Эта программа распространяется в надежде, что она будет полезной, -но БЕЗО ВСЯКИХ ГАРАНТИЙ; даже без неявной гарантии ТОВАРНОГО ВИДА -или ПРИГОДНОСТИ ДЛЯ ОПРЕДЕЛЕННЫХ ЦЕЛЕЙ. Подробнее см. в Стандартной -общественной лицензии GNU . \ No newline at end of file diff --git a/README.md b/README.md index 2428105..edd3bd0 100644 --- a/README.md +++ b/README.md @@ -1,21 +1,7 @@ # Менеджер аккаунтов -Инициализирует аккаунты для их использования в колпачных фреймворках и библеотеках +Инициализирует аккаунты для использования в фреймворках ### Установка: ```sh -$ composer install hood/accounts +$ composer install mirzaev/accounts ``` - -### Пример использования: -```php -use hood\accounts\vk; - -// Подключение библеотек -require_once './vendor/autoload.php'; - -// Инициализация пользователя ВКонтакте -$account = (new vk($id))->auth('login', 'password')->key($project_id); - -// Вывести сгенерированный ключ -echo $account->key; -``` \ No newline at end of file diff --git a/composer.json b/composer.json index 8df9ce9..40219ff 100644 --- a/composer.json +++ b/composer.json @@ -3,8 +3,7 @@ "type": "library", "description": "Менеджер аккаунтов", "keywords": [ - "accounts", - "vk" + "accounts" ], "homepage": "https://git.hood.su/mirzaev/accounts", "license": "WTFPL", diff --git a/mirzaev/accounts/system/vk.php b/mirzaev/accounts/system/vk.php deleted file mode 100644 index 8e84844..0000000 --- a/mirzaev/accounts/system/vk.php +++ /dev/null @@ -1,396 +0,0 @@ -cookies - строка cookie, $this->root_path - корневая директория (которая сейчас $this->path), $this->cookies_path - путь до файла хранящего cookies - * 2. Сделать возможность авторизации без входного и пароля, указав место хранения файла cookies - * 4. Добавить возможность авторизации через сторонний браузер, который более походит на настоящий (низкий приоритет) - * 5. Создать debug-режим в котором будут сохранены обрабатываемые html страницы и действия будут записываться по PSR-7 в журнал (низкий приоритет) - */ -final class vk extends account implements basic -{ - /** - * @var int $id Идентификатор - */ - private int $id; - - /** - * @var string $login Входной [псевдоним] - */ - private string $login; - - /** - * @var string $password Пароль - */ - private string $password; - - /** - * @var string $key Ключ доступа - */ - private string $key; - - /** - * Конструктор - * - * @param int $id Идентификатор - * @param string|null $path Корневой каталог аккаунтов - * - * @return self - */ - public function __construct(int $id, string $path = null) - { - // Идентификатор - $this->id = $id; - - // Инициализация директории пользователя - if (isset($path)) { - // Если передан путь и он существует - $this->path = $path . DIRECTORY_SEPARATOR . $id; - } else { - // Иначе путь по умолчанию - $this->path = __DIR__ . DIRECTORY_SEPARATOR . 'accounts' . DIRECTORY_SEPARATOR . $id; - } - - // Проверка и создание директории - if (!file_exists($this->path)) { - mkdir($this->path, 0775, true); - } - - // Инициализация браузера - $this->browser(); - } - - /** - * Аутентификация - * - * @param string $login Входной - * @param string $password Пароль - * @param int $mode Режим - * - * @return self - * - * @todo - * 1. Добавить проверку требования двухэтапной аутентификации - * 2. Добавить проверку требования ввода капчи - * 3. Добавить проверку неудачного ввода пароля - * 4. Добавить аутентификацию через версию для ПК - * 5. Добавить идентификацию капчи, решение капчи и тесты с капчей - */ - public function auth(string $login, string $password, int $mode = 0): self - { - if (isset($this->login, $this->password)) { - throw new Exception('Повторная аутентификация запрещена'); - } - - // Инициализация свойств - $this->login = $login; - $this->password = $password; - - // Переход на страницу аутентификации и обработка формы - if ($mode === 0) { - // Если установлен режим мобильной версии (по умолчанию) - - // Запрос страницы с аутентификацией - $response = $this->browser->request('GET', 'https://m.vk.com'); - - // Проверка - $body = $this->check((string) $response->getBody()); - - if ($response->getStatusCode() === 200) { - // Инициализация DOM - $dom = new DOMDocument; - @$dom->loadHTML($body); - - // Ссылка для отправки формы (аутентификация) - $action = $dom->getElementsByTagName('form')[0]->getAttribute('action'); - } else { - throw new Exception('Не удалось получить страницу аутентификации: ' . $response->getReasonPhrase(), $response->getStatusCode()); - } - } else if ($mode === 1) { - // Иначе, если установлен режим аутентификации через обычную версию - // $this->browser->post('http://login.vk.com/?act=login'); - } - - // Аутентификация - $response = $this->browser->request( - 'POST', - $action, - [ - 'form_params' => [ - 'email' => $login, - 'pass' => $password - ] - ] - ); - - // Поиск уведомления с ошибкой - $warning = $this->xpath((string) $response->getBody(), "//div[contains(@class, 'service_msg_box')]/div[contains(@class, 'service_msg service_msg_warning')]/text()"); - - if (!empty($warning[0]->textContent)) { - // Если аутентификация не прошла и появилось окно с ошибкой - throw new Exception('ВКонтакте: "' . trim($warning[0]->textContent) . '"'); - } - - return $this; - } - - /** - * @todo Сделать - */ - public function deauth(): self - { - // Очистка cookie - if (file_exists($this->path . DIRECTORY_SEPARATOR . 'cookie.txt')) { - // Если сущестуют cookie, то удалить - unlink($this->path . DIRECTORY_SEPARATOR . 'cookie.txt'); - - // Ренициализация браузера - $this->browser(); - } - - return $this; - } - - - public function key(int $project_id = null, string ...$rights): string - { - if (!is_null($project_id)) { - // Если переданы параметры - - // Инициализация - $uri = ''; - - // Запрос и обработка страницы подтверждения генерации ключа - $response = $this->browser->request( - 'POST', - 'https://oauth.vk.com/authorize?client_id=' . $project_id . '&redirect_uri=https://oauth.vk.com/blank.html&display=mobile&scope=' . (empty($rights) ? 140488159 : implode(',', $rights)) . '&response_type=token', - [ - 'http_errors' => false, - 'on_stats' => function (TransferStats $stats) use (&$uri) { - $uri = $stats->getEffectiveUri(); - } - ] - ); - - // Проверка - $body = $this->check((string) $response->getBody()); - - if ($response->getStatusCode() === 200) { - // Поиск текста - $text = $this->xpath($body, "/html/body/text()|/html/body/b/text()"); - - // Инкрементация найденных строк в одну - for ($body = '', $i = 1; $i < count($text); $body .= $text[$i++]->textContent); - - // Обрезка переносов строки и пробелов - $body = trim($body); - - if ($body !== "Пожалуйста, не копируйте данные из адресной строки для сторонних сайтов. Таким образом Вы можете потерять доступ к Вашему аккаунту.") { - // Если показывает страницу подтверждения генерации токена (после генерации подтверждать не просит и сразу выдаёт токен) - - // Инициализация DOM - $dom = new DOMDocument; - @$dom->loadHTML((string) $response->getBody()); - - // Ссылка для отправки формы (подтверждение выдачи ключа) - $action = $dom->getElementsByTagName('form')[0]->getAttribute('action'); - - // Запрос ключа - $response = $this->browser->request( - 'POST', - $action, - [ - 'http_errors' => false, - 'on_stats' => function (TransferStats $stats) use (&$uri) { - $uri = $stats->getEffectiveUri(); - } - ] - ); - - // Проверка ответа на наличие json с ошибкой - $this->check((string) $response->getBody()); - } - - // Извлечение ключа из URI - $parts = parse_url((string) $uri); - parse_str($parts['fragment'], $fragments); - - // Запись ключа - $this->key = $fragments['access_token']; - } else { - throw new Exception('ВКонтакте: "' . json_decode((string) $response->getBody())->error_description . '"'); - } - } - - return $this->key; - } - - private function browser(): browser - { - return $this->browser = new browser([ - 'verify' => $this->ssl, - 'cookies' => (new FileCookieJar($this->path . DIRECTORY_SEPARATOR . 'cookie.txt')) - ]); - } - - private function xpath(string $html, string $query): ?object - { - // DOM - $dom = new DOMDocument; - @$dom->loadHTML($html); - - // XPATH 1.0 - $xpath = new DOMXPath($dom); - return $xpath->query($query); - } - - private function check(string $response): ?string - { - $json = json_decode($response); - - if (json_last_error() === JSON_ERROR_NONE) { - // Если это JSON - - if (isset($json->error)) { - // Если есть ошибки - throw new Exception('ВКонтакте: "' . ($json->error['error_msg'] ?? $json->error_description) . '"', $json->error['error_code'] ?? 0); - } - } - - return $response; - } - - /** - * Магический метод: установить свойство - * - * @param mixed $name Название - * @param mixed $value Значение - * - * @return void - */ - public function __set($name, $value): void - { - if ($name === 'id') { - throw new Exception('Запрещено инициализировать идентификатор'); - } else if ($name === 'login' || $name === 'name' || $name === 'email' || $name === 'phone' || $name === 'number' || $name === 'nick' || $name === 'nickname') { - throw new Exception('Запрещено инициализировать входной'); - } else if ($name === 'password' || $name === 'pswd' || $name === 'pass') { - throw new Exception('Запрещено инициализировать пароль'); - } else if ($name === 'key' || $name === 'token') { - $this->key = $value; - } else if ($name === 'browser') { - throw new Exception('Запрещено инициализировать браузер'); - } else if ($name === 'path') { - $this->path = $value. DIRECTORY_SEPARATOR . $this->id; - - // Проверка и создание директории - if (!file_exists($this->path)) { - mkdir($this->path, 0775, true); - } - - // Реинициализация браузера с новым значением - $this->browser(); - } else if ($name === 'ssl') { - $this->ssl = $value; - // Реинициализация браузера с новым значением - $this->browser(); - } - } - - /** - * Магический метод: получить свойство - * - * @param mixed $name Название - * - * @return mixed - */ - public function __get($name) - { - if ($name === 'id') { - return $this->id; - } else if ($name === 'login' || $name === 'name' || $name === 'email' || $name === 'phone' || $name === 'number' || $name === 'nick' || $name === 'nickname') { - return $this->login; - } else if ($name === 'password' || $name === 'pswd' || $name === 'pass') { - return $this->password; - } else if ($name === 'key') { - return $this->key; - } else if ($name === 'browser') { - return $this->browser; - } else if ($name === 'path') { - return $this->path; - } else if ($name === 'ssl') { - return $this->ssl ?? $this->ssl = true; - } - } - - /** - * Магический метод: проверка на инициализированность - * - * @param mixed $name Название - * - * @return mixed - */ - public function __isset($name) - { - if ($name === 'id') { - return isset($this->id); - } else if ($name === 'login' || $name === 'name' || $name === 'email' || $name === 'phone' || $name === 'number' || $name === 'nick' || $name === 'nickname') { - return isset($this->login); - } else if ($name === 'password' || $name === 'pswd' || $name === 'pass') { - return isset($this->password); - } else if ($name === 'key') { - return isset($this->key); - } else if ($name === 'browser') { - return isset($this->browser); - } else if ($name === 'path') { - return isset($this->path); - } else if ($name === 'ssl') { - return isset($this->ssl); - } - } - - - - /** - * Магический метод: удаление - * - * @param mixed $name Название - * - * @return mixed - */ - public function __unset($name) - { - if ($name === 'id') { - throw new Exception('Запрещено деинициализировать идентификатор'); - } else if ($name === 'login' || $name === 'name' || $name === 'email' || $name === 'phone' || $name === 'number' || $name === 'nick' || $name === 'nickname') { - throw new Exception('Запрещено деинициализировать входной'); - } else if ($name === 'password' || $name === 'pswd' || $name === 'pass') { - throw new Exception('Запрещено деинициализировать пароль'); - } else if ($name === 'key') { - unset($this->key); - } else if ($name === 'browser') { - unset($this->browser); - } else if ($name === 'path') { - unset($this->path); - } else if ($name === 'ssl') { - unset($this->ssl); - } - } -}