* @author Jim Jagielski (jimjag) * @author Andy Prevost (codeworxtech) * @author Brent R. Matzelle (original founder) * @copyright 2012 - 2020 Marcus Bointon * @copyright 2010 - 2012 Jim Jagielski * @copyright 2004 - 2009 Andy Prevost * @license https://www.gnu.org/licenses/old-licenses/lgpl-2.1.html GNU Lesser General Public License * @note This program is distributed in the hope that it will be useful - WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. */ namespace AcyMailerPhp; /** * OAuth - OAuth2 authentication wrapper class. * Uses the oauth2-client package from the League of Extraordinary Packages. * * @see https://oauth2-client.thephpleague.com * * @author Marcus Bointon (Synchro/coolbru) */ class OAuth implements OAuthTokenProvider { /** * The sending method used. */ protected string $sendingMethod; /** * The URL called to generate an access token from a refresh token. */ protected string $tokenGenerationUrl; /** * The current OAuth access token, prefixed with "Bearer ". */ protected string $oauthToken; /** * The user's email address, usually used as the login ID * and also the from address when sending email. */ protected string $oauthUserEmail; /** * The client secret, generated in the app definition of the service you're connecting to. */ protected string $oauthClientSecret; /** * The client ID, generated in the app definition of the service you're connecting to. */ protected string $oauthClientId; /** * The refresh token, used to obtain new AccessTokens. */ protected string $oauthRefreshToken; /** * The timestamp at which the current token expires. */ protected int $oauthTokenExpiration; public function __construct(array $options) { $this->sendingMethod = $options['sendingMethod'] ?? ''; $this->tokenGenerationUrl = $options['tokenGenerationUrl'] ?? ''; $this->oauthUserEmail = $options['userName'] ?? ''; $this->oauthClientId = $options['clientId'] ?? ''; $this->oauthClientSecret = $options['clientSecret'] ?? ''; $this->oauthRefreshToken = $options['refreshToken'] ?? ''; $this->oauthToken = $options['oauthToken'] ?? ''; $this->oauthTokenExpiration = $options['oauthTokenExpiration'] ? (int)$options['oauthTokenExpiration'] : 0; } /** * Generate a base64-encoded OAuth token. */ public function getOauth64(): string { $this->oauthToken = $this->getToken(); if (empty($this->oauthToken)) { return ''; } return base64_encode('user='.$this->oauthUserEmail."\001auth=Bearer ".$this->oauthToken."\001\001"); } /** * Custom method to avoid having a million vendors in the extension zip file. */ public function getToken(): string { // Get a new token only if it's not available or has expired if (!empty($this->oauthToken) && $this->oauthTokenExpiration > time()) { return $this->oauthToken; } $response = acym_makeCurlCall( $this->tokenGenerationUrl, [ 'data' => [ 'client_id' => $this->oauthClientId, 'client_secret' => $this->oauthClientSecret, 'refresh_token' => $this->oauthRefreshToken, 'grant_type' => 'refresh_token', ], 'method' => 'POST', ] ); if (!empty($response['token_type']) && !empty($response['access_token'])) { $config = acym_config(); $config->saveConfig( [ $this->sendingMethod.'_access_token' => $response['access_token'], $this->sendingMethod.'_access_token_expiration' => time() + (int)$response['expires_in'], ] ); } else { acym_logError('Response from OAuth refresh token call: '.json_encode($response), 'oauth', 100); $notification = [ 'name' => 'oauth_refresh_token_error', 'removable' => 1, ]; acym_enqueueMessage(acym_translationSprintf('ACYM_OAUTH_REFRESH_TOKEN_ERROR', $response['error'] ?? ''), 'error', true, [$notification]); } return $response['access_token'] ?? ''; } }