Skip to content

Commit

Permalink
Initial Commit
Browse files Browse the repository at this point in the history
  • Loading branch information
ngoerlitz committed Jun 21, 2024
0 parents commit 20975a5
Show file tree
Hide file tree
Showing 49 changed files with 1,486 additions and 0 deletions.
Binary file added .gitignore
Binary file not shown.
Binary file added README.md
Binary file not shown.
13 changes: 13 additions & 0 deletions VATGER/OAuth/Listener.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<?php

namespace VATGER\OAuth;

use XF\Mvc\Entity\Entity;

class Listener {
public static function userEntityStructure(\XF\Mvc\Entity\Manager $em, \XF\Mvc\Entity\Structure &$structure): void {
$structure->columns[Setup::$OAUTH_DB_AUTH_COLUMN] = ['type' => Entity::STR, 'default' => null];
$structure->columns[Setup::$OAUTH_DB_REFRESH_COLUMN] = ['type' => Entity::STR, 'default' => null];
$structure->columns['vatsim_id'] = ['type' => Entity::INT, 'default' => null];
}
}
146 changes: 146 additions & 0 deletions VATGER/OAuth/Pub/Controller/ConnectController.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,146 @@
<?php

namespace VATGER\OAuth\Pub\Controller;

use VATGER\OAuth\Service\Vatsim\Connect;
use VATGER\OAuth\Setup;
use XF\Db\Exception;
use XF\Mvc\Reply\Error;
use XF\Mvc\Reply\Redirect;
use XF\PrintableException;
use XF\Pub\Controller\AbstractController;
use XF\Repository\User;

class ConnectController extends AbstractController
{
protected static string $GENERIC_ERROR_MESSAGE = "An internal error occurred. Please try again later or contact an administrator.";

public function actionIndex(): Redirect
{
if (!$this->_allowLogin()) {
return $this->redirect($this->_getHomeViewRedirect());
}

/** @var Connect $connectService */
$connectService = $this->service('VATGER\OAuth:Vatsim\Connect', $this->options());

return $this->redirect($connectService->getRedirectURI());
}

/**
* @throws PrintableException
*/
public function actionCallback(): Redirect|Error
{
if (!$this->_allowLogin()) {
return $this->redirect($this->_getHomeViewRedirect());
}

/** @var Connect $connectService */
$connectService = $this->service('VATGER\OAuth:Vatsim\Connect', $this->options());

$requestParams = $this->request->getRequestQueryParams();

if (!key_exists('code', $requestParams)) {
return $this->error("Code not found in request. Please try again later or contact an administrator.", 400);
}

$tokens = $connectService->getAuthToken($requestParams['code']);
if ($tokens == null) {
return $this->error(self::$GENERIC_ERROR_MESSAGE, 400);
}

$apiUser = $connectService->getUserDetails($tokens['access_token']);
if ($apiUser == null) {
return $this->error(self::$GENERIC_ERROR_MESSAGE, 400);
}

$cid = $this->_getValueFromJsonPath($apiUser, $this->options()["cid_mapping"]);
$email = $this->_getValueFromJsonPath($apiUser, $this->options()["email_mapping"]);
$fullName = $this->_getValueFromJsonPath($apiUser, $this->options()["full_name_mapping"]);

/** @var \XF\Entity\User $databaseUser */
$databaseUser = \XF::finder('XF:User')->where('vatsim_id', $cid)->fetchOne();
if (!$databaseUser) {
/** @var User $userRepository */
$userRepository = $this->repository('XF:User');
$baseUser = $userRepository->setupBaseUser();

if ($baseUser == null) {
return $this->error(self::$GENERIC_ERROR_MESSAGE, 400);
}

$baseUser["vatsim_id"] = $cid;
$baseUser["email"] = $email;
$baseUser["username"] = $fullName;
$baseUser[Setup::$OAUTH_DB_AUTH_COLUMN] = $tokens['access_token'];
$baseUser[Setup::$OAUTH_DB_REFRESH_COLUMN] = $tokens['refresh_token'];

$baseUser->custom_title = $cid;
$baseUser->Auth->setNoPassword();
$baseUser->Profile->password_date = \XF::$time;

$baseUser->save();
$databaseUser = $baseUser;

// Inform the homepage of this new user.
try {
\XF::app()->http()->client()->post($this->options()['homepage_callback'], [
'json' => [
'cid' => $cid,
'forum_id' => $baseUser['user_id']
]
]);
} catch (\Exception $exception) {
$baseUser->delete();
return $this->error(self::$GENERIC_ERROR_MESSAGE, $exception->getMessage());
}
}

$databaseUser[Setup::$OAUTH_DB_AUTH_COLUMN] = $tokens['access_token'];
$databaseUser[Setup::$OAUTH_DB_REFRESH_COLUMN] = $tokens['refresh_token'];
$databaseUser->save();

/** @var \XF\ControllerPlugin\Login $loginPlugin */
$loginPlugin = $this->plugin('XF:Login');

$loginPlugin->completeLogin($databaseUser, true);

return $this->redirect($this->_getHomeViewRedirect());
}

private function _getHomeViewRedirect()
{
return $this->getDynamicRedirectIfNot($this->buildLink('home'));
}

private function _allowLogin(): bool
{
// Potentially add some more cases in the future :)
if ($this->session()->exists())
{
return false;
}

return true;
}

private function _getValueFromJsonPath(mixed $obj, string $path): mixed
{
$keys = explode('.', $path);
$value = $obj;

foreach ($keys as $key)
{
if (isset($value[$key]))
{
$value = $value[$key];
} else
{
return null;
}
}

return $value;
}
}
74 changes: 74 additions & 0 deletions VATGER/OAuth/Service/Vatsim/Connect.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
<?php

namespace VATGER\OAuth\Service\Vatsim;

use ArrayObject;
use GuzzleHttp\Client;
use GuzzleHttp\Exception\RequestException;
use XF\Service\AbstractService;

class Connect extends AbstractService {
protected Client $client;
protected array $connectOptions;

public function __construct(\XF\App $app, ArrayObject $options)
{
parent::__construct($app);

$this->client = \XF::app()->http()->client();

$this->connectOptions = [
'base_url' => $options->base_url,
'client_id' => $options->client_id,
'client_secret' => $options->client_secret,
'redirect_url' => $options->redirect_url,
'scopes' => $options->scopes
];
}

public function getRedirectURI(): string
{
$base_url = $this->connectOptions["base_url"] . "/oauth/authorize";

$scopes = urlencode($this->connectOptions["scopes"]);
$redirect_url = $this->connectOptions['redirect_url'];

return $base_url . '?response_type=code&client_id=830&scope=' . $scopes . '&redirect_uri=' . $redirect_url;
}

public function getAuthToken(string $code): mixed
{
try {
$tokenResponse = $this->client->post($this->connectOptions['base_url'] . '/oauth/token', [
'json' => [
'grant_type' => 'authorization_code',
'code' => $code,
'client_id' => $this->connectOptions["client_id"],
'client_secret' => $this->connectOptions["client_secret"],
'redirect_uri' => $this->connectOptions["redirect_url"],
]
]);

return \GuzzleHttp\json_decode($tokenResponse->getBody(), true);
} catch (RequestException $e) {
\XF::logException($e);
return null;
}
}

public function getUserDetails(string $accessToken): mixed
{
try {
$userResponse = $this->client->get($this->connectOptions['base_url'] . '/api/user', [
'headers' => [
'Authorization' => 'Bearer ' . $accessToken,
]
]);

return \GuzzleHttp\json_decode($userResponse->getBody(), true);
} catch (RequestException $e) {
\XF::logException($e);
return null;
}
}
}
37 changes: 37 additions & 0 deletions VATGER/OAuth/Setup.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
<?php

namespace VATGER\OAuth;

use XF\AddOn\AbstractSetup;
use XF\AddOn\StepRunnerInstallTrait;
use XF\AddOn\StepRunnerUninstallTrait;
use XF\AddOn\StepRunnerUpgradeTrait;

class Setup extends AbstractSetup
{
public static string $OAUTH_DB_AUTH_COLUMN = "oauth_auth_token";
public static string $OAUTH_DB_REFRESH_COLUMN = "oauth_remember_token";

public function install(array $stepParams = []): void
{
$this->schemaManager()->alterTable('xf_user', function (\XF\Db\Schema\Alter $table) {
$table->addColumn(self::$OAUTH_DB_AUTH_COLUMN, 'text', 255)->nullable();
$table->addColumn(self::$OAUTH_DB_REFRESH_COLUMN, 'text', 255)->nullable();
$table->addColumn('vatsim_id', 'bigint')->nullable();
});
}

public function uninstall(array $stepParams = []): void
{
$this->schemaManager()->alterTable('xf_user', function (\XF\Db\Schema\Alter $table) {
$table->dropColumns(self::$OAUTH_DB_AUTH_COLUMN);
$table->dropColumns(self::$OAUTH_DB_REFRESH_COLUMN);
$table->dropColumns('vatsim_id');
});
}

public function upgrade(array $stepParams = []): void
{
// Currently, nothing to upgrade!
}
}
5 changes: 5 additions & 0 deletions VATGER/OAuth/_output/code_event_listeners/_metadata.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"entity_structure_660f1c943a695478e745c1b1cea66cba.json": {
"hash": "27a291062c38fce6ab50b43cae7ebfb3"
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{
"event_id": "entity_structure",
"execute_order": 10,
"callback_class": "VATGER\\OAuth\\Listener",
"callback_method": "userEntityStructure",
"active": true,
"hint": "XF\\Entity\\User",
"description": ""
}
5 changes: 5 additions & 0 deletions VATGER/OAuth/_output/extension_hint.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
<?php

/** @noinspection PhpIllegalPsrClassPathInspection */
// ################## THIS IS A GENERATED FILE ##################
// DO NOT EDIT DIRECTLY. EDIT THE CLASS EXTENSIONS IN THE CONTROL PANEL.
5 changes: 5 additions & 0 deletions VATGER/OAuth/_output/option_groups/_metadata.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"vatgerOAuth.json": {
"hash": "c00a7ada9801536853b4fc507fcce3bb"
}
}
6 changes: 6 additions & 0 deletions VATGER/OAuth/_output/option_groups/vatgerOAuth.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"icon": "",
"display_order": 1,
"advanced": false,
"debug_only": false
}
29 changes: 29 additions & 0 deletions VATGER/OAuth/_output/options/_metadata.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
{
"base_url.json": {
"hash": "7a5e0d8e19b8c567492c496ff70f2af9"
},
"cid_mapping.json": {
"hash": "02dad6e4d8a5e3345dcc851471eaaa1d"
},
"client_id.json": {
"hash": "381073712ddd097534626eaa2ebc7f37"
},
"client_secret.json": {
"hash": "381073712ddd097534626eaa2ebc7f37"
},
"email_mapping.json": {
"hash": "02dad6e4d8a5e3345dcc851471eaaa1d"
},
"full_name_mapping.json": {
"hash": "02dad6e4d8a5e3345dcc851471eaaa1d"
},
"homepage_callback.json": {
"hash": "5a25f3a6bfbfa5568c28b5832501b7d7"
},
"redirect_url.json": {
"hash": "381073712ddd097534626eaa2ebc7f37"
},
"scopes.json": {
"hash": "eb97b8745f63f905d5ea18a52ba09aa7"
}
}
13 changes: 13 additions & 0 deletions VATGER/OAuth/_output/options/base_url.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
{
"edit_format": "textbox",
"edit_format_params": "",
"data_type": "string",
"sub_options": [],
"validation_class": "",
"validation_method": "",
"advanced": false,
"default_value": "https://auth.vatsim-germany.org",
"relations": {
"vatgerOAuth": 1
}
}
13 changes: 13 additions & 0 deletions VATGER/OAuth/_output/options/cid_mapping.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
{
"edit_format": "textbox",
"edit_format_params": "",
"data_type": "string",
"sub_options": [],
"validation_class": "",
"validation_method": "",
"advanced": false,
"default_value": "",
"relations": {
"vatgerOAuth": 3
}
}
13 changes: 13 additions & 0 deletions VATGER/OAuth/_output/options/client_id.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
{
"edit_format": "textbox",
"edit_format_params": "",
"data_type": "string",
"sub_options": [],
"validation_class": "",
"validation_method": "",
"advanced": false,
"default_value": "",
"relations": {
"vatgerOAuth": 1
}
}
Loading

0 comments on commit 20975a5

Please sign in to comment.