From d0b39de9b71d665e9d846adac32782c7cc480a89 Mon Sep 17 00:00:00 2001 From: Eser DENIZ Date: Wed, 8 May 2024 14:20:23 +0200 Subject: [PATCH] New authentification workflow --- app/Commands/DomainWatchCommand.php | 12 ++-- app/Commands/LoginCommand.php | 66 +++++++++++++++++-- app/Commands/LogoutCommand.php | 12 +++- app/Helpers/Helpers.php | 25 ++++++- .../Integrations/Unolia/Requests/Login.php | 38 +++++++++++ .../Integrations/Unolia/Requests/Logout.php | 16 +++++ app/Http/Integrations/Unolia/Unolia.php | 5 +- app/Http/Integrations/Unolia/UnoliaAuth.php | 36 ++++++++++ config/settings.php | 1 + 9 files changed, 196 insertions(+), 15 deletions(-) create mode 100644 app/Http/Integrations/Unolia/Requests/Login.php create mode 100644 app/Http/Integrations/Unolia/Requests/Logout.php create mode 100644 app/Http/Integrations/Unolia/UnoliaAuth.php diff --git a/app/Commands/DomainWatchCommand.php b/app/Commands/DomainWatchCommand.php index 66651b9..edffe31 100644 --- a/app/Commands/DomainWatchCommand.php +++ b/app/Commands/DomainWatchCommand.php @@ -31,14 +31,15 @@ public function handle() $interval = intval($this->option('interval')) <= 0 ? 2 : intval($this->option('interval')); $record = $response->json('data'); - - $start = time(); - $this->line(''); // Blank line - $this->line(' Watching the following record: '.implode(' | ', [ + $record_string = implode(' | ', [ $record['name'], $record['type'], $record['value'], - ])); + ]); + + $start = time(); + $this->line(''); // Blank line + $this->line(' Watching the following record: '.$record_string); $this->line(''); // Blank line @@ -59,6 +60,7 @@ public function handle() if ($record['state'] === 'verified') { $this->info(' Record is active'); + $this->notify('Record is active!', $record_string); break; } diff --git a/app/Commands/LoginCommand.php b/app/Commands/LoginCommand.php index f1f3d49..71e6490 100644 --- a/app/Commands/LoginCommand.php +++ b/app/Commands/LoginCommand.php @@ -2,13 +2,17 @@ namespace Unolia\UnoliaCLI\Commands; +use Exception; use LaravelZero\Framework\Commands\Command; +use Saloon\Exceptions\Request\Statuses\UnprocessableEntityException; use Unolia\UnoliaCLI\Helpers\Config; use Unolia\UnoliaCLI\Helpers\Helpers; use Unolia\UnoliaCLI\Http\Integrations\Unolia\Requests\CurrentAuthenticated; use Unolia\UnoliaCLI\Http\Integrations\Unolia\Requests\CurrentToken; +use Unolia\UnoliaCLI\Http\Integrations\Unolia\Requests\Login; use function Laravel\Prompts\password; +use function Laravel\Prompts\text; class LoginCommand extends Command { @@ -19,18 +23,68 @@ class LoginCommand extends Command public function handle() { $token = Helpers::getApiToken(); + $connector = Helpers::getApiConnector($token ?: ''); if (! empty($token)) { - $this->line('You are already logged in.'); + try { + $verify = $connector->send(new CurrentToken()); + $verify->throw(); + + $this->line('You are already logged in.'); + } catch (Exception) { + } + + return; + } + + $token_name = 'Token for '.get_current_user().'@'.gethostname(); + + $email = text('Email'); + $password = password('Password'); + $connector_auth = Helpers::getAuthConnector(); + + try { + $login = $connector_auth->send(new Login( + email: $email, + password: $password, + token_name: $token_name, + )); + + $login->throw(); + + } catch (UnprocessableEntityException $e) { + + $two_fa_error = $e->getResponse()->json('errors.two_factor_code'); + + if (! empty($two_fa_error)) { + $two_factor_code = text('Two factor authentication code'); + + $login = $connector_auth->send(new Login( + email: $email, password: $password, + two_factor_code: $two_factor_code, + token_name: $token_name, + )); + + try { + $login->throw(); + } catch (Exception $e) { + $this->error($e->getMessage()); + + return; + } + } else { + $this->error($e->getMessage()); + + return; + } + + } catch (Exception $e) { + $this->error($e->getMessage()); return; } - $token = password( - label: 'API Token', - placeholder: '', - hint: 'You can find your API token in your unolia.com account settings', - ); + $token = $login->json('data.token'); $connector = Helpers::getApiConnector($token); try { diff --git a/app/Commands/LogoutCommand.php b/app/Commands/LogoutCommand.php index 9894772..82a0f9b 100644 --- a/app/Commands/LogoutCommand.php +++ b/app/Commands/LogoutCommand.php @@ -5,10 +5,11 @@ use LaravelZero\Framework\Commands\Command; use Unolia\UnoliaCLI\Helpers\Config; use Unolia\UnoliaCLI\Helpers\Helpers; +use Unolia\UnoliaCLI\Http\Integrations\Unolia\Requests\Logout; class LogoutCommand extends Command { - protected $signature = 'logout'; + protected $signature = 'logout {--force : Force the operation when the actual token is already deleted from your account}'; protected $description = 'Logout from unolia.com'; @@ -22,6 +23,15 @@ public function handle() return; } + $connector = Helpers::getAuthConnector(); + $logout = $connector->send(new Logout()); + + if ($logout->failed() && ! $this->option('force')) { + $this->error('Logout failed: '.$logout->json('message')); + + return; + } + Config::set('api.token', null); $this->info('You are now logged out.'); diff --git a/app/Helpers/Helpers.php b/app/Helpers/Helpers.php index 6093228..91dee54 100644 --- a/app/Helpers/Helpers.php +++ b/app/Helpers/Helpers.php @@ -3,20 +3,43 @@ namespace Unolia\UnoliaCLI\Helpers; use Unolia\UnoliaCLI\Http\Integrations\Unolia\Unolia; +use Unolia\UnoliaCLI\Http\Integrations\Unolia\UnoliaAuth; class Helpers { public static function getApiConnector($token = null): Unolia { return new Unolia( - token: $token ?: self::getApiToken(), + token: $token ?? self::getApiToken(), api_url: config('settings.api.url'), ); } + public static function getAuthConnector($token = null): UnoliaAuth + { + return new UnoliaAuth( + token: $token ?? self::getApiToken(), + api_url: config('settings.api.auth_url'), + ); + } + public static function getApiToken(): ?string { // Check environment variable, else use config file return config('settings.api.token') ?: Config::get('api.token'); } + + public static function getUserAgent() + { + $phpVersion = 'PHP '.PHP_MAJOR_VERSION.'.'.PHP_MINOR_VERSION.'.'.PHP_RELEASE_VERSION; + + return sprintf( + 'User-Agent: UnoliaCLI/%s (%s; %s; %s; %s)', + config('app.version'), + function_exists('php_uname') ? php_uname('s') : 'Unknown', + function_exists('php_uname') ? php_uname('m') : 'Unknown', + function_exists('php_uname') ? php_uname('r') : 'Unknown', + $phpVersion, + ); + } } diff --git a/app/Http/Integrations/Unolia/Requests/Login.php b/app/Http/Integrations/Unolia/Requests/Login.php new file mode 100644 index 0000000..704b828 --- /dev/null +++ b/app/Http/Integrations/Unolia/Requests/Login.php @@ -0,0 +1,38 @@ + $this->email, + 'password' => $this->password, + 'two_factor_code' => $this->two_factor_code, + 'token_name' => $this->token_name, + ]); + } + + public function resolveEndpoint(): string + { + return 'login'; + } +} diff --git a/app/Http/Integrations/Unolia/Requests/Logout.php b/app/Http/Integrations/Unolia/Requests/Logout.php new file mode 100644 index 0000000..368506d --- /dev/null +++ b/app/Http/Integrations/Unolia/Requests/Logout.php @@ -0,0 +1,16 @@ + 'IntelliJ HTTP Client/PhpStorm 2024.1.1', + 'User-Agent' => Helpers::getUserAgent(), ]; } public function resolveBaseUrl(): string { - return $this->api_url ?? 'https://api.unolia.com/v1/'; + return $this->api_url ?? 'https://app.unolia.com/api/v1/'; } public function paginate(Request $request): UnoliaPaginator diff --git a/app/Http/Integrations/Unolia/UnoliaAuth.php b/app/Http/Integrations/Unolia/UnoliaAuth.php new file mode 100644 index 0000000..81ab233 --- /dev/null +++ b/app/Http/Integrations/Unolia/UnoliaAuth.php @@ -0,0 +1,36 @@ +token ? new TokenAuthenticator($this->token) : null; + } + + protected function defaultHeaders(): array + { + return [ + 'User-Agent' => Helpers::getUserAgent(), + ]; + } + + public function resolveBaseUrl(): string + { + return $this->api_url ?? 'https://app.unolia.com/api/'; + } +} diff --git a/config/settings.php b/config/settings.php index 53e2f33..1b5efe2 100644 --- a/config/settings.php +++ b/config/settings.php @@ -25,5 +25,6 @@ | */ 'url' => env('UNOLIA_API_URL', 'https://app.unolia.com/api/v1/'), + 'auth_url' => env('UNOLIA_AUTH_URL', 'https://app.unolia.com/api/'), ], ];