updated plugin WP Mail SMTP
version 2.4.0
This commit is contained in:
@ -0,0 +1,203 @@
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright [yyyy] [name of copyright owner]
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
|
@ -0,0 +1,64 @@
|
||||
<?php
|
||||
|
||||
namespace WPMailSMTP\Vendor;
|
||||
|
||||
/*
|
||||
* Copyright 2008 Google Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
use WPMailSMTP\Vendor\Google\Auth\HttpHandler\HttpHandlerFactory;
|
||||
use WPMailSMTP\Vendor\GuzzleHttp\ClientInterface;
|
||||
use WPMailSMTP\Vendor\GuzzleHttp\Psr7;
|
||||
use WPMailSMTP\Vendor\GuzzleHttp\Psr7\Request;
|
||||
/**
|
||||
* Wrapper around Google Access Tokens which provides convenience functions
|
||||
*
|
||||
*/
|
||||
class Google_AccessToken_Revoke
|
||||
{
|
||||
/**
|
||||
* @var GuzzleHttp\ClientInterface The http client
|
||||
*/
|
||||
private $http;
|
||||
/**
|
||||
* Instantiates the class, but does not initiate the login flow, leaving it
|
||||
* to the discretion of the caller.
|
||||
*/
|
||||
public function __construct(\WPMailSMTP\Vendor\GuzzleHttp\ClientInterface $http = null)
|
||||
{
|
||||
$this->http = $http;
|
||||
}
|
||||
/**
|
||||
* Revoke an OAuth2 access token or refresh token. This method will revoke the current access
|
||||
* token, if a token isn't provided.
|
||||
*
|
||||
* @param string|array $token The token (access token or a refresh token) that should be revoked.
|
||||
* @return boolean Returns True if the revocation was successful, otherwise False.
|
||||
*/
|
||||
public function revokeToken($token)
|
||||
{
|
||||
if (\is_array($token)) {
|
||||
if (isset($token['refresh_token'])) {
|
||||
$token = $token['refresh_token'];
|
||||
} else {
|
||||
$token = $token['access_token'];
|
||||
}
|
||||
}
|
||||
$body = \WPMailSMTP\Vendor\GuzzleHttp\Psr7\stream_for(\http_build_query(array('token' => $token)));
|
||||
$request = new \WPMailSMTP\Vendor\GuzzleHttp\Psr7\Request('POST', \WPMailSMTP\Vendor\Google_Client::OAUTH2_REVOKE_URI, ['Cache-Control' => 'no-store', 'Content-Type' => 'application/x-www-form-urlencoded'], $body);
|
||||
$httpHandler = \WPMailSMTP\Vendor\Google\Auth\HttpHandler\HttpHandlerFactory::build($this->http);
|
||||
$response = $httpHandler($request);
|
||||
return $response->getStatusCode() == 200;
|
||||
}
|
||||
}
|
@ -0,0 +1,218 @@
|
||||
<?php
|
||||
|
||||
namespace WPMailSMTP\Vendor;
|
||||
|
||||
/*
|
||||
* Copyright 2008 Google Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
use WPMailSMTP\Vendor\Firebase\JWT\ExpiredException as ExpiredExceptionV3;
|
||||
use WPMailSMTP\Vendor\Firebase\JWT\SignatureInvalidException;
|
||||
use WPMailSMTP\Vendor\GuzzleHttp\Client;
|
||||
use WPMailSMTP\Vendor\GuzzleHttp\ClientInterface;
|
||||
use WPMailSMTP\Vendor\Psr\Cache\CacheItemPoolInterface;
|
||||
use WPMailSMTP\Vendor\Google\Auth\Cache\MemoryCacheItemPool;
|
||||
use WPMailSMTP\Vendor\Stash\Driver\FileSystem;
|
||||
use WPMailSMTP\Vendor\Stash\Pool;
|
||||
/**
|
||||
* Wrapper around Google Access Tokens which provides convenience functions
|
||||
*
|
||||
*/
|
||||
class Google_AccessToken_Verify
|
||||
{
|
||||
const FEDERATED_SIGNON_CERT_URL = 'https://www.googleapis.com/oauth2/v3/certs';
|
||||
const OAUTH2_ISSUER = 'accounts.google.com';
|
||||
const OAUTH2_ISSUER_HTTPS = 'https://accounts.google.com';
|
||||
/**
|
||||
* @var GuzzleHttp\ClientInterface The http client
|
||||
*/
|
||||
private $http;
|
||||
/**
|
||||
* @var Psr\Cache\CacheItemPoolInterface cache class
|
||||
*/
|
||||
private $cache;
|
||||
/**
|
||||
* Instantiates the class, but does not initiate the login flow, leaving it
|
||||
* to the discretion of the caller.
|
||||
*/
|
||||
public function __construct(\WPMailSMTP\Vendor\GuzzleHttp\ClientInterface $http = null, \WPMailSMTP\Vendor\Psr\Cache\CacheItemPoolInterface $cache = null, $jwt = null)
|
||||
{
|
||||
if (null === $http) {
|
||||
$http = new \WPMailSMTP\Vendor\GuzzleHttp\Client();
|
||||
}
|
||||
if (null === $cache) {
|
||||
$cache = new \WPMailSMTP\Vendor\Google\Auth\Cache\MemoryCacheItemPool();
|
||||
}
|
||||
$this->http = $http;
|
||||
$this->cache = $cache;
|
||||
$this->jwt = $jwt ?: $this->getJwtService();
|
||||
}
|
||||
/**
|
||||
* Verifies an id token and returns the authenticated apiLoginTicket.
|
||||
* Throws an exception if the id token is not valid.
|
||||
* The audience parameter can be used to control which id tokens are
|
||||
* accepted. By default, the id token must have been issued to this OAuth2 client.
|
||||
*
|
||||
* @param string $idToken the ID token in JWT format
|
||||
* @param string $audience Optional. The audience to verify against JWt "aud"
|
||||
* @return array the token payload, if successful
|
||||
*/
|
||||
public function verifyIdToken($idToken, $audience = null)
|
||||
{
|
||||
if (empty($idToken)) {
|
||||
throw new \LogicException('id_token cannot be null');
|
||||
}
|
||||
// set phpseclib constants if applicable
|
||||
$this->setPhpsecConstants();
|
||||
// Check signature
|
||||
$certs = $this->getFederatedSignOnCerts();
|
||||
foreach ($certs as $cert) {
|
||||
$bigIntClass = $this->getBigIntClass();
|
||||
$rsaClass = $this->getRsaClass();
|
||||
$modulus = new $bigIntClass($this->jwt->urlsafeB64Decode($cert['n']), 256);
|
||||
$exponent = new $bigIntClass($this->jwt->urlsafeB64Decode($cert['e']), 256);
|
||||
$rsa = new $rsaClass();
|
||||
$rsa->loadKey(array('n' => $modulus, 'e' => $exponent));
|
||||
try {
|
||||
$payload = $this->jwt->decode($idToken, $rsa->getPublicKey(), array('RS256'));
|
||||
if (\property_exists($payload, 'aud')) {
|
||||
if ($audience && $payload->aud != $audience) {
|
||||
return \false;
|
||||
}
|
||||
}
|
||||
// support HTTP and HTTPS issuers
|
||||
// @see https://developers.google.com/identity/sign-in/web/backend-auth
|
||||
$issuers = array(self::OAUTH2_ISSUER, self::OAUTH2_ISSUER_HTTPS);
|
||||
if (!isset($payload->iss) || !\in_array($payload->iss, $issuers)) {
|
||||
return \false;
|
||||
}
|
||||
return (array) $payload;
|
||||
} catch (\WPMailSMTP\Vendor\ExpiredException $e) {
|
||||
return \false;
|
||||
} catch (\WPMailSMTP\Vendor\Firebase\JWT\ExpiredException $e) {
|
||||
return \false;
|
||||
} catch (\WPMailSMTP\Vendor\Firebase\JWT\SignatureInvalidException $e) {
|
||||
// continue
|
||||
} catch (\DomainException $e) {
|
||||
// continue
|
||||
}
|
||||
}
|
||||
return \false;
|
||||
}
|
||||
private function getCache()
|
||||
{
|
||||
return $this->cache;
|
||||
}
|
||||
/**
|
||||
* Retrieve and cache a certificates file.
|
||||
*
|
||||
* @param $url string location
|
||||
* @throws Google_Exception
|
||||
* @return array certificates
|
||||
*/
|
||||
private function retrieveCertsFromLocation($url)
|
||||
{
|
||||
// If we're retrieving a local file, just grab it.
|
||||
if (0 !== \strpos($url, 'http')) {
|
||||
if (!($file = \file_get_contents($url))) {
|
||||
throw new \WPMailSMTP\Vendor\Google_Exception("Failed to retrieve verification certificates: '" . $url . "'.");
|
||||
}
|
||||
return \json_decode($file, \true);
|
||||
}
|
||||
$response = $this->http->get($url);
|
||||
if ($response->getStatusCode() == 200) {
|
||||
return \json_decode((string) $response->getBody(), \true);
|
||||
}
|
||||
throw new \WPMailSMTP\Vendor\Google_Exception(\sprintf('Failed to retrieve verification certificates: "%s".', $response->getBody()->getContents()), $response->getStatusCode());
|
||||
}
|
||||
// Gets federated sign-on certificates to use for verifying identity tokens.
|
||||
// Returns certs as array structure, where keys are key ids, and values
|
||||
// are PEM encoded certificates.
|
||||
private function getFederatedSignOnCerts()
|
||||
{
|
||||
$certs = null;
|
||||
if ($cache = $this->getCache()) {
|
||||
$cacheItem = $cache->getItem('federated_signon_certs_v3');
|
||||
$certs = $cacheItem->get();
|
||||
}
|
||||
if (!$certs) {
|
||||
$certs = $this->retrieveCertsFromLocation(self::FEDERATED_SIGNON_CERT_URL);
|
||||
if ($cache) {
|
||||
$cacheItem->expiresAt(new \DateTime('+1 hour'));
|
||||
$cacheItem->set($certs);
|
||||
$cache->save($cacheItem);
|
||||
}
|
||||
}
|
||||
if (!isset($certs['keys'])) {
|
||||
throw new \InvalidArgumentException('federated sign-on certs expects "keys" to be set');
|
||||
}
|
||||
return $certs['keys'];
|
||||
}
|
||||
private function getJwtService()
|
||||
{
|
||||
$jwtClass = 'JWT';
|
||||
if (\class_exists('WPMailSMTP\\Vendor\\Firebase\\JWT\\JWT')) {
|
||||
$jwtClass = 'WPMailSMTP\\Vendor\\Firebase\\JWT\\JWT';
|
||||
}
|
||||
if (\property_exists($jwtClass, 'leeway') && $jwtClass::$leeway < 1) {
|
||||
// Ensures JWT leeway is at least 1
|
||||
// @see https://github.com/google/google-api-php-client/issues/827
|
||||
$jwtClass::$leeway = 1;
|
||||
}
|
||||
return new $jwtClass();
|
||||
}
|
||||
private function getRsaClass()
|
||||
{
|
||||
if (\class_exists('WPMailSMTP\\Vendor\\phpseclib\\Crypt\\RSA')) {
|
||||
return 'WPMailSMTP\\Vendor\\phpseclib\\Crypt\\RSA';
|
||||
}
|
||||
return 'Crypt_RSA';
|
||||
}
|
||||
private function getBigIntClass()
|
||||
{
|
||||
if (\class_exists('WPMailSMTP\\Vendor\\phpseclib\\Math\\BigInteger')) {
|
||||
return 'WPMailSMTP\\Vendor\\phpseclib\\Math\\BigInteger';
|
||||
}
|
||||
return 'Math_BigInteger';
|
||||
}
|
||||
private function getOpenSslConstant()
|
||||
{
|
||||
if (\class_exists('WPMailSMTP\\Vendor\\phpseclib\\Crypt\\RSA')) {
|
||||
return 'WPMailSMTP\\Vendor\\phpseclib\\Crypt\\RSA::MODE_OPENSSL';
|
||||
}
|
||||
if (\class_exists('WPMailSMTP\\Vendor\\Crypt_RSA')) {
|
||||
return 'CRYPT_RSA_MODE_OPENSSL';
|
||||
}
|
||||
throw new \Exception('Cannot find RSA class');
|
||||
}
|
||||
/**
|
||||
* phpseclib calls "phpinfo" by default, which requires special
|
||||
* whitelisting in the AppEngine VM environment. This function
|
||||
* sets constants to bypass the need for phpseclib to check phpinfo
|
||||
*
|
||||
* @see phpseclib/Math/BigInteger
|
||||
* @see https://github.com/GoogleCloudPlatform/getting-started-php/issues/85
|
||||
*/
|
||||
private function setPhpsecConstants()
|
||||
{
|
||||
if (\filter_var(\getenv('GAE_VM'), \FILTER_VALIDATE_BOOLEAN)) {
|
||||
if (!\defined('WPMailSMTP\\Vendor\\MATH_BIGINTEGER_OPENSSL_ENABLED')) {
|
||||
\define('WPMailSMTP\\Vendor\\MATH_BIGINTEGER_OPENSSL_ENABLED', \true);
|
||||
}
|
||||
if (!\defined('WPMailSMTP\\Vendor\\CRYPT_RSA_MODE')) {
|
||||
\define('WPMailSMTP\\Vendor\\CRYPT_RSA_MODE', \constant($this->getOpenSslConstant()));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,49 @@
|
||||
<?php
|
||||
|
||||
namespace WPMailSMTP\Vendor;
|
||||
|
||||
/**
|
||||
* Copyright 2015 Google Inc. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
use WPMailSMTP\Vendor\GuzzleHttp\Client;
|
||||
use WPMailSMTP\Vendor\GuzzleHttp\ClientInterface;
|
||||
class Google_AuthHandler_AuthHandlerFactory
|
||||
{
|
||||
/**
|
||||
* Builds out a default http handler for the installed version of guzzle.
|
||||
*
|
||||
* @return Google_AuthHandler_Guzzle5AuthHandler|Google_AuthHandler_Guzzle6AuthHandler
|
||||
* @throws Exception
|
||||
*/
|
||||
public static function build($cache = null, array $cacheConfig = [])
|
||||
{
|
||||
$guzzleVersion = null;
|
||||
if (\defined('\\WPMailSMTP\\Vendor\\GuzzleHttp\\ClientInterface::MAJOR_VERSION')) {
|
||||
$guzzleVersion = \WPMailSMTP\Vendor\GuzzleHttp\ClientInterface::MAJOR_VERSION;
|
||||
} elseif (\defined('\\WPMailSMTP\\Vendor\\GuzzleHttp\\ClientInterface::VERSION')) {
|
||||
$guzzleVersion = (int) \substr(\WPMailSMTP\Vendor\GuzzleHttp\ClientInterface::VERSION, 0, 1);
|
||||
}
|
||||
switch ($guzzleVersion) {
|
||||
case 5:
|
||||
return new \WPMailSMTP\Vendor\Google_AuthHandler_Guzzle5AuthHandler($cache, $cacheConfig);
|
||||
case 6:
|
||||
return new \WPMailSMTP\Vendor\Google_AuthHandler_Guzzle6AuthHandler($cache, $cacheConfig);
|
||||
case 7:
|
||||
return new \WPMailSMTP\Vendor\Google_AuthHandler_Guzzle7AuthHandler($cache, $cacheConfig);
|
||||
default:
|
||||
throw new \Exception('Version not supported');
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,63 @@
|
||||
<?php
|
||||
|
||||
namespace WPMailSMTP\Vendor;
|
||||
|
||||
use WPMailSMTP\Vendor\Google\Auth\CredentialsLoader;
|
||||
use WPMailSMTP\Vendor\Google\Auth\HttpHandler\HttpHandlerFactory;
|
||||
use WPMailSMTP\Vendor\Google\Auth\FetchAuthTokenCache;
|
||||
use WPMailSMTP\Vendor\Google\Auth\Subscriber\AuthTokenSubscriber;
|
||||
use WPMailSMTP\Vendor\Google\Auth\Subscriber\ScopedAccessTokenSubscriber;
|
||||
use WPMailSMTP\Vendor\Google\Auth\Subscriber\SimpleSubscriber;
|
||||
use WPMailSMTP\Vendor\GuzzleHttp\Client;
|
||||
use WPMailSMTP\Vendor\GuzzleHttp\ClientInterface;
|
||||
use WPMailSMTP\Vendor\Psr\Cache\CacheItemPoolInterface;
|
||||
/**
|
||||
*
|
||||
*/
|
||||
class Google_AuthHandler_Guzzle5AuthHandler
|
||||
{
|
||||
protected $cache;
|
||||
protected $cacheConfig;
|
||||
public function __construct(\WPMailSMTP\Vendor\Psr\Cache\CacheItemPoolInterface $cache = null, array $cacheConfig = [])
|
||||
{
|
||||
$this->cache = $cache;
|
||||
$this->cacheConfig = $cacheConfig;
|
||||
}
|
||||
public function attachCredentials(\WPMailSMTP\Vendor\GuzzleHttp\ClientInterface $http, \WPMailSMTP\Vendor\Google\Auth\CredentialsLoader $credentials, callable $tokenCallback = null)
|
||||
{
|
||||
// use the provided cache
|
||||
if ($this->cache) {
|
||||
$credentials = new \WPMailSMTP\Vendor\Google\Auth\FetchAuthTokenCache($credentials, $this->cacheConfig, $this->cache);
|
||||
}
|
||||
// if we end up needing to make an HTTP request to retrieve credentials, we
|
||||
// can use our existing one, but we need to throw exceptions so the error
|
||||
// bubbles up.
|
||||
$authHttp = $this->createAuthHttp($http);
|
||||
$authHttpHandler = \WPMailSMTP\Vendor\Google\Auth\HttpHandler\HttpHandlerFactory::build($authHttp);
|
||||
$subscriber = new \WPMailSMTP\Vendor\Google\Auth\Subscriber\AuthTokenSubscriber($credentials, $authHttpHandler, $tokenCallback);
|
||||
$http->setDefaultOption('auth', 'google_auth');
|
||||
$http->getEmitter()->attach($subscriber);
|
||||
return $http;
|
||||
}
|
||||
public function attachToken(\WPMailSMTP\Vendor\GuzzleHttp\ClientInterface $http, array $token, array $scopes)
|
||||
{
|
||||
$tokenFunc = function ($scopes) use($token) {
|
||||
return $token['access_token'];
|
||||
};
|
||||
$subscriber = new \WPMailSMTP\Vendor\Google\Auth\Subscriber\ScopedAccessTokenSubscriber($tokenFunc, $scopes, $this->cacheConfig, $this->cache);
|
||||
$http->setDefaultOption('auth', 'scoped');
|
||||
$http->getEmitter()->attach($subscriber);
|
||||
return $http;
|
||||
}
|
||||
public function attachKey(\WPMailSMTP\Vendor\GuzzleHttp\ClientInterface $http, $key)
|
||||
{
|
||||
$subscriber = new \WPMailSMTP\Vendor\Google\Auth\Subscriber\SimpleSubscriber(['key' => $key]);
|
||||
$http->setDefaultOption('auth', 'simple');
|
||||
$http->getEmitter()->attach($subscriber);
|
||||
return $http;
|
||||
}
|
||||
private function createAuthHttp(\WPMailSMTP\Vendor\GuzzleHttp\ClientInterface $http)
|
||||
{
|
||||
return new \WPMailSMTP\Vendor\GuzzleHttp\Client(['base_url' => $http->getBaseUrl(), 'defaults' => ['exceptions' => \true, 'verify' => $http->getDefaultOption('verify'), 'proxy' => $http->getDefaultOption('proxy')]]);
|
||||
}
|
||||
}
|
@ -0,0 +1,72 @@
|
||||
<?php
|
||||
|
||||
namespace WPMailSMTP\Vendor;
|
||||
|
||||
use WPMailSMTP\Vendor\Google\Auth\CredentialsLoader;
|
||||
use WPMailSMTP\Vendor\Google\Auth\HttpHandler\HttpHandlerFactory;
|
||||
use WPMailSMTP\Vendor\Google\Auth\FetchAuthTokenCache;
|
||||
use WPMailSMTP\Vendor\Google\Auth\Middleware\AuthTokenMiddleware;
|
||||
use WPMailSMTP\Vendor\Google\Auth\Middleware\ScopedAccessTokenMiddleware;
|
||||
use WPMailSMTP\Vendor\Google\Auth\Middleware\SimpleMiddleware;
|
||||
use WPMailSMTP\Vendor\GuzzleHttp\Client;
|
||||
use WPMailSMTP\Vendor\GuzzleHttp\ClientInterface;
|
||||
use WPMailSMTP\Vendor\Psr\Cache\CacheItemPoolInterface;
|
||||
/**
|
||||
* This supports Guzzle 6
|
||||
*/
|
||||
class Google_AuthHandler_Guzzle6AuthHandler
|
||||
{
|
||||
protected $cache;
|
||||
protected $cacheConfig;
|
||||
public function __construct(\WPMailSMTP\Vendor\Psr\Cache\CacheItemPoolInterface $cache = null, array $cacheConfig = [])
|
||||
{
|
||||
$this->cache = $cache;
|
||||
$this->cacheConfig = $cacheConfig;
|
||||
}
|
||||
public function attachCredentials(\WPMailSMTP\Vendor\GuzzleHttp\ClientInterface $http, \WPMailSMTP\Vendor\Google\Auth\CredentialsLoader $credentials, callable $tokenCallback = null)
|
||||
{
|
||||
// use the provided cache
|
||||
if ($this->cache) {
|
||||
$credentials = new \WPMailSMTP\Vendor\Google\Auth\FetchAuthTokenCache($credentials, $this->cacheConfig, $this->cache);
|
||||
}
|
||||
// if we end up needing to make an HTTP request to retrieve credentials, we
|
||||
// can use our existing one, but we need to throw exceptions so the error
|
||||
// bubbles up.
|
||||
$authHttp = $this->createAuthHttp($http);
|
||||
$authHttpHandler = \WPMailSMTP\Vendor\Google\Auth\HttpHandler\HttpHandlerFactory::build($authHttp);
|
||||
$middleware = new \WPMailSMTP\Vendor\Google\Auth\Middleware\AuthTokenMiddleware($credentials, $authHttpHandler, $tokenCallback);
|
||||
$config = $http->getConfig();
|
||||
$config['handler']->remove('google_auth');
|
||||
$config['handler']->push($middleware, 'google_auth');
|
||||
$config['auth'] = 'google_auth';
|
||||
$http = new \WPMailSMTP\Vendor\GuzzleHttp\Client($config);
|
||||
return $http;
|
||||
}
|
||||
public function attachToken(\WPMailSMTP\Vendor\GuzzleHttp\ClientInterface $http, array $token, array $scopes)
|
||||
{
|
||||
$tokenFunc = function ($scopes) use($token) {
|
||||
return $token['access_token'];
|
||||
};
|
||||
$middleware = new \WPMailSMTP\Vendor\Google\Auth\Middleware\ScopedAccessTokenMiddleware($tokenFunc, $scopes, $this->cacheConfig, $this->cache);
|
||||
$config = $http->getConfig();
|
||||
$config['handler']->remove('google_auth');
|
||||
$config['handler']->push($middleware, 'google_auth');
|
||||
$config['auth'] = 'scoped';
|
||||
$http = new \WPMailSMTP\Vendor\GuzzleHttp\Client($config);
|
||||
return $http;
|
||||
}
|
||||
public function attachKey(\WPMailSMTP\Vendor\GuzzleHttp\ClientInterface $http, $key)
|
||||
{
|
||||
$middleware = new \WPMailSMTP\Vendor\Google\Auth\Middleware\SimpleMiddleware(['key' => $key]);
|
||||
$config = $http->getConfig();
|
||||
$config['handler']->remove('google_auth');
|
||||
$config['handler']->push($middleware, 'google_auth');
|
||||
$config['auth'] = 'simple';
|
||||
$http = new \WPMailSMTP\Vendor\GuzzleHttp\Client($config);
|
||||
return $http;
|
||||
}
|
||||
private function createAuthHttp(\WPMailSMTP\Vendor\GuzzleHttp\ClientInterface $http)
|
||||
{
|
||||
return new \WPMailSMTP\Vendor\GuzzleHttp\Client(['base_uri' => $http->getConfig('base_uri'), 'exceptions' => \true, 'verify' => $http->getConfig('verify'), 'proxy' => $http->getConfig('proxy')]);
|
||||
}
|
||||
}
|
@ -0,0 +1,25 @@
|
||||
<?php
|
||||
|
||||
namespace WPMailSMTP\Vendor;
|
||||
|
||||
/**
|
||||
* Copyright 2020 Google LLC
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
/**
|
||||
* This supports Guzzle 7
|
||||
*/
|
||||
class Google_AuthHandler_Guzzle7AuthHandler extends \WPMailSMTP\Vendor\Google_AuthHandler_Guzzle6AuthHandler
|
||||
{
|
||||
}
|
@ -0,0 +1,977 @@
|
||||
<?php
|
||||
|
||||
namespace WPMailSMTP\Vendor;
|
||||
|
||||
/*
|
||||
* Copyright 2010 Google Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
use WPMailSMTP\Vendor\Google\Auth\ApplicationDefaultCredentials;
|
||||
use WPMailSMTP\Vendor\Google\Auth\Cache\MemoryCacheItemPool;
|
||||
use WPMailSMTP\Vendor\Google\Auth\CredentialsLoader;
|
||||
use WPMailSMTP\Vendor\Google\Auth\HttpHandler\HttpHandlerFactory;
|
||||
use WPMailSMTP\Vendor\Google\Auth\OAuth2;
|
||||
use WPMailSMTP\Vendor\Google\Auth\Credentials\ServiceAccountCredentials;
|
||||
use WPMailSMTP\Vendor\Google\Auth\Credentials\UserRefreshCredentials;
|
||||
use WPMailSMTP\Vendor\GuzzleHttp\Client;
|
||||
use WPMailSMTP\Vendor\GuzzleHttp\ClientInterface;
|
||||
use WPMailSMTP\Vendor\GuzzleHttp\Ring\Client\StreamHandler;
|
||||
use WPMailSMTP\Vendor\Psr\Cache\CacheItemPoolInterface;
|
||||
use WPMailSMTP\Vendor\Psr\Http\Message\RequestInterface;
|
||||
use WPMailSMTP\Vendor\Psr\Log\LoggerInterface;
|
||||
use WPMailSMTP\Vendor\Monolog\Logger;
|
||||
use WPMailSMTP\Vendor\Monolog\Handler\StreamHandler as MonologStreamHandler;
|
||||
use WPMailSMTP\Vendor\Monolog\Handler\SyslogHandler as MonologSyslogHandler;
|
||||
/**
|
||||
* The Google API Client
|
||||
* https://github.com/google/google-api-php-client
|
||||
*/
|
||||
class Google_Client
|
||||
{
|
||||
const LIBVER = "2.7.0";
|
||||
const USER_AGENT_SUFFIX = "google-api-php-client/";
|
||||
const OAUTH2_REVOKE_URI = 'https://oauth2.googleapis.com/revoke';
|
||||
const OAUTH2_TOKEN_URI = 'https://oauth2.googleapis.com/token';
|
||||
const OAUTH2_AUTH_URL = 'https://accounts.google.com/o/oauth2/auth';
|
||||
const API_BASE_PATH = 'https://www.googleapis.com';
|
||||
/**
|
||||
* @var Google\Auth\OAuth2 $auth
|
||||
*/
|
||||
private $auth;
|
||||
/**
|
||||
* @var GuzzleHttp\ClientInterface $http
|
||||
*/
|
||||
private $http;
|
||||
/**
|
||||
* @var Psr\Cache\CacheItemPoolInterface $cache
|
||||
*/
|
||||
private $cache;
|
||||
/**
|
||||
* @var array access token
|
||||
*/
|
||||
private $token;
|
||||
/**
|
||||
* @var array $config
|
||||
*/
|
||||
private $config;
|
||||
/**
|
||||
* @var Psr\Log\LoggerInterface $logger
|
||||
*/
|
||||
private $logger;
|
||||
/**
|
||||
* @var boolean $deferExecution
|
||||
*/
|
||||
private $deferExecution = \false;
|
||||
/** @var array $scopes */
|
||||
// Scopes requested by the client
|
||||
protected $requestedScopes = [];
|
||||
/**
|
||||
* Construct the Google Client.
|
||||
*
|
||||
* @param array $config
|
||||
*/
|
||||
public function __construct(array $config = array())
|
||||
{
|
||||
$this->config = \array_merge([
|
||||
'application_name' => '',
|
||||
// Don't change these unless you're working against a special development
|
||||
// or testing environment.
|
||||
'base_path' => self::API_BASE_PATH,
|
||||
// https://developers.google.com/console
|
||||
'client_id' => '',
|
||||
'client_secret' => '',
|
||||
// Path to JSON credentials or an array representing those credentials
|
||||
// @see Google_Client::setAuthConfig
|
||||
'credentials' => null,
|
||||
// @see Google_Client::setScopes
|
||||
'scopes' => null,
|
||||
// Sets X-Goog-User-Project, which specifies a user project to bill
|
||||
// for access charges associated with the request
|
||||
'quota_project' => null,
|
||||
'redirect_uri' => null,
|
||||
'state' => null,
|
||||
// Simple API access key, also from the API console. Ensure you get
|
||||
// a Server key, and not a Browser key.
|
||||
'developer_key' => '',
|
||||
// For use with Google Cloud Platform
|
||||
// fetch the ApplicationDefaultCredentials, if applicable
|
||||
// @see https://developers.google.com/identity/protocols/application-default-credentials
|
||||
'use_application_default_credentials' => \false,
|
||||
'signing_key' => null,
|
||||
'signing_algorithm' => null,
|
||||
'subject' => null,
|
||||
// Other OAuth2 parameters.
|
||||
'hd' => '',
|
||||
'prompt' => '',
|
||||
'openid.realm' => '',
|
||||
'include_granted_scopes' => null,
|
||||
'login_hint' => '',
|
||||
'request_visible_actions' => '',
|
||||
'access_type' => 'online',
|
||||
'approval_prompt' => 'auto',
|
||||
// Task Runner retry configuration
|
||||
// @see Google_Task_Runner
|
||||
'retry' => array(),
|
||||
'retry_map' => null,
|
||||
// cache config for downstream auth caching
|
||||
'cache_config' => [],
|
||||
// function to be called when an access token is fetched
|
||||
// follows the signature function ($cacheKey, $accessToken)
|
||||
'token_callback' => null,
|
||||
// Service class used in Google_Client::verifyIdToken.
|
||||
// Explicitly pass this in to avoid setting JWT::$leeway
|
||||
'jwt' => null,
|
||||
// Setting api_format_v2 will return more detailed error messages
|
||||
// from certain APIs.
|
||||
'api_format_v2' => \false,
|
||||
], $config);
|
||||
if (!\is_null($this->config['credentials'])) {
|
||||
$this->setAuthConfig($this->config['credentials']);
|
||||
unset($this->config['credentials']);
|
||||
}
|
||||
if (!\is_null($this->config['scopes'])) {
|
||||
$this->setScopes($this->config['scopes']);
|
||||
unset($this->config['scopes']);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Get a string containing the version of the library.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getLibraryVersion()
|
||||
{
|
||||
return self::LIBVER;
|
||||
}
|
||||
/**
|
||||
* For backwards compatibility
|
||||
* alias for fetchAccessTokenWithAuthCode
|
||||
*
|
||||
* @param $code string code from accounts.google.com
|
||||
* @return array access token
|
||||
* @deprecated
|
||||
*/
|
||||
public function authenticate($code)
|
||||
{
|
||||
return $this->fetchAccessTokenWithAuthCode($code);
|
||||
}
|
||||
/**
|
||||
* Attempt to exchange a code for an valid authentication token.
|
||||
* Helper wrapped around the OAuth 2.0 implementation.
|
||||
*
|
||||
* @param $code string code from accounts.google.com
|
||||
* @return array access token
|
||||
*/
|
||||
public function fetchAccessTokenWithAuthCode($code)
|
||||
{
|
||||
if (\strlen($code) == 0) {
|
||||
throw new \InvalidArgumentException("Invalid code");
|
||||
}
|
||||
$auth = $this->getOAuth2Service();
|
||||
$auth->setCode($code);
|
||||
$auth->setRedirectUri($this->getRedirectUri());
|
||||
$httpHandler = \WPMailSMTP\Vendor\Google\Auth\HttpHandler\HttpHandlerFactory::build($this->getHttpClient());
|
||||
$creds = $auth->fetchAuthToken($httpHandler);
|
||||
if ($creds && isset($creds['access_token'])) {
|
||||
$creds['created'] = \time();
|
||||
$this->setAccessToken($creds);
|
||||
}
|
||||
return $creds;
|
||||
}
|
||||
/**
|
||||
* For backwards compatibility
|
||||
* alias for fetchAccessTokenWithAssertion
|
||||
*
|
||||
* @return array access token
|
||||
* @deprecated
|
||||
*/
|
||||
public function refreshTokenWithAssertion()
|
||||
{
|
||||
return $this->fetchAccessTokenWithAssertion();
|
||||
}
|
||||
/**
|
||||
* Fetches a fresh access token with a given assertion token.
|
||||
* @param ClientInterface $authHttp optional.
|
||||
* @return array access token
|
||||
*/
|
||||
public function fetchAccessTokenWithAssertion(\WPMailSMTP\Vendor\GuzzleHttp\ClientInterface $authHttp = null)
|
||||
{
|
||||
if (!$this->isUsingApplicationDefaultCredentials()) {
|
||||
throw new \DomainException('set the JSON service account credentials using' . ' Google_Client::setAuthConfig or set the path to your JSON file' . ' with the "GOOGLE_APPLICATION_CREDENTIALS" environment variable' . ' and call Google_Client::useApplicationDefaultCredentials to' . ' refresh a token with assertion.');
|
||||
}
|
||||
$this->getLogger()->log('info', 'OAuth2 access token refresh with Signed JWT assertion grants.');
|
||||
$credentials = $this->createApplicationDefaultCredentials();
|
||||
$httpHandler = \WPMailSMTP\Vendor\Google\Auth\HttpHandler\HttpHandlerFactory::build($authHttp);
|
||||
$creds = $credentials->fetchAuthToken($httpHandler);
|
||||
if ($creds && isset($creds['access_token'])) {
|
||||
$creds['created'] = \time();
|
||||
$this->setAccessToken($creds);
|
||||
}
|
||||
return $creds;
|
||||
}
|
||||
/**
|
||||
* For backwards compatibility
|
||||
* alias for fetchAccessTokenWithRefreshToken
|
||||
*
|
||||
* @param string $refreshToken
|
||||
* @return array access token
|
||||
*/
|
||||
public function refreshToken($refreshToken)
|
||||
{
|
||||
return $this->fetchAccessTokenWithRefreshToken($refreshToken);
|
||||
}
|
||||
/**
|
||||
* Fetches a fresh OAuth 2.0 access token with the given refresh token.
|
||||
* @param string $refreshToken
|
||||
* @return array access token
|
||||
*/
|
||||
public function fetchAccessTokenWithRefreshToken($refreshToken = null)
|
||||
{
|
||||
if (null === $refreshToken) {
|
||||
if (!isset($this->token['refresh_token'])) {
|
||||
throw new \LogicException('refresh token must be passed in or set as part of setAccessToken');
|
||||
}
|
||||
$refreshToken = $this->token['refresh_token'];
|
||||
}
|
||||
$this->getLogger()->info('OAuth2 access token refresh');
|
||||
$auth = $this->getOAuth2Service();
|
||||
$auth->setRefreshToken($refreshToken);
|
||||
$httpHandler = \WPMailSMTP\Vendor\Google\Auth\HttpHandler\HttpHandlerFactory::build($this->getHttpClient());
|
||||
$creds = $auth->fetchAuthToken($httpHandler);
|
||||
if ($creds && isset($creds['access_token'])) {
|
||||
$creds['created'] = \time();
|
||||
if (!isset($creds['refresh_token'])) {
|
||||
$creds['refresh_token'] = $refreshToken;
|
||||
}
|
||||
$this->setAccessToken($creds);
|
||||
}
|
||||
return $creds;
|
||||
}
|
||||
/**
|
||||
* Create a URL to obtain user authorization.
|
||||
* The authorization endpoint allows the user to first
|
||||
* authenticate, and then grant/deny the access request.
|
||||
* @param string|array $scope The scope is expressed as an array or list of space-delimited strings.
|
||||
* @return string
|
||||
*/
|
||||
public function createAuthUrl($scope = null)
|
||||
{
|
||||
if (empty($scope)) {
|
||||
$scope = $this->prepareScopes();
|
||||
}
|
||||
if (\is_array($scope)) {
|
||||
$scope = \implode(' ', $scope);
|
||||
}
|
||||
// only accept one of prompt or approval_prompt
|
||||
$approvalPrompt = $this->config['prompt'] ? null : $this->config['approval_prompt'];
|
||||
// include_granted_scopes should be string "true", string "false", or null
|
||||
$includeGrantedScopes = $this->config['include_granted_scopes'] === null ? null : \var_export($this->config['include_granted_scopes'], \true);
|
||||
$params = \array_filter(['access_type' => $this->config['access_type'], 'approval_prompt' => $approvalPrompt, 'hd' => $this->config['hd'], 'include_granted_scopes' => $includeGrantedScopes, 'login_hint' => $this->config['login_hint'], 'openid.realm' => $this->config['openid.realm'], 'prompt' => $this->config['prompt'], 'response_type' => 'code', 'scope' => $scope, 'state' => $this->config['state']]);
|
||||
// If the list of scopes contains plus.login, add request_visible_actions
|
||||
// to auth URL.
|
||||
$rva = $this->config['request_visible_actions'];
|
||||
if (\strlen($rva) > 0 && \false !== \strpos($scope, 'plus.login')) {
|
||||
$params['request_visible_actions'] = $rva;
|
||||
}
|
||||
$auth = $this->getOAuth2Service();
|
||||
return (string) $auth->buildFullAuthorizationUri($params);
|
||||
}
|
||||
/**
|
||||
* Adds auth listeners to the HTTP client based on the credentials
|
||||
* set in the Google API Client object
|
||||
*
|
||||
* @param GuzzleHttp\ClientInterface $http the http client object.
|
||||
* @return GuzzleHttp\ClientInterface the http client object
|
||||
*/
|
||||
public function authorize(\WPMailSMTP\Vendor\GuzzleHttp\ClientInterface $http = null)
|
||||
{
|
||||
$credentials = null;
|
||||
$token = null;
|
||||
$scopes = null;
|
||||
if (null === $http) {
|
||||
$http = $this->getHttpClient();
|
||||
}
|
||||
// These conditionals represent the decision tree for authentication
|
||||
// 1. Check for Application Default Credentials
|
||||
// 2. Check for API Key
|
||||
// 3a. Check for an Access Token
|
||||
// 3b. If access token exists but is expired, try to refresh it
|
||||
if ($this->isUsingApplicationDefaultCredentials()) {
|
||||
$credentials = $this->createApplicationDefaultCredentials();
|
||||
} elseif ($token = $this->getAccessToken()) {
|
||||
$scopes = $this->prepareScopes();
|
||||
// add refresh subscriber to request a new token
|
||||
if (isset($token['refresh_token']) && $this->isAccessTokenExpired()) {
|
||||
$credentials = $this->createUserRefreshCredentials($scopes, $token['refresh_token']);
|
||||
}
|
||||
}
|
||||
$authHandler = $this->getAuthHandler();
|
||||
if ($credentials) {
|
||||
$callback = $this->config['token_callback'];
|
||||
$http = $authHandler->attachCredentials($http, $credentials, $callback);
|
||||
} elseif ($token) {
|
||||
$http = $authHandler->attachToken($http, $token, (array) $scopes);
|
||||
} elseif ($key = $this->config['developer_key']) {
|
||||
$http = $authHandler->attachKey($http, $key);
|
||||
}
|
||||
return $http;
|
||||
}
|
||||
/**
|
||||
* Set the configuration to use application default credentials for
|
||||
* authentication
|
||||
*
|
||||
* @see https://developers.google.com/identity/protocols/application-default-credentials
|
||||
* @param boolean $useAppCreds
|
||||
*/
|
||||
public function useApplicationDefaultCredentials($useAppCreds = \true)
|
||||
{
|
||||
$this->config['use_application_default_credentials'] = $useAppCreds;
|
||||
}
|
||||
/**
|
||||
* To prevent useApplicationDefaultCredentials from inappropriately being
|
||||
* called in a conditional
|
||||
*
|
||||
* @see https://developers.google.com/identity/protocols/application-default-credentials
|
||||
*/
|
||||
public function isUsingApplicationDefaultCredentials()
|
||||
{
|
||||
return $this->config['use_application_default_credentials'];
|
||||
}
|
||||
/**
|
||||
* Set the access token used for requests.
|
||||
*
|
||||
* Note that at the time requests are sent, tokens are cached. A token will be
|
||||
* cached for each combination of service and authentication scopes. If a
|
||||
* cache pool is not provided, creating a new instance of the client will
|
||||
* allow modification of access tokens. If a persistent cache pool is
|
||||
* provided, in order to change the access token, you must clear the cached
|
||||
* token by calling `$client->getCache()->clear()`. (Use caution in this case,
|
||||
* as calling `clear()` will remove all cache items, including any items not
|
||||
* related to Google API PHP Client.)
|
||||
*
|
||||
* @param string|array $token
|
||||
* @throws InvalidArgumentException
|
||||
*/
|
||||
public function setAccessToken($token)
|
||||
{
|
||||
if (\is_string($token)) {
|
||||
if ($json = \json_decode($token, \true)) {
|
||||
$token = $json;
|
||||
} else {
|
||||
// assume $token is just the token string
|
||||
$token = array('access_token' => $token);
|
||||
}
|
||||
}
|
||||
if ($token == null) {
|
||||
throw new \InvalidArgumentException('invalid json token');
|
||||
}
|
||||
if (!isset($token['access_token'])) {
|
||||
throw new \InvalidArgumentException("Invalid token format");
|
||||
}
|
||||
$this->token = $token;
|
||||
}
|
||||
public function getAccessToken()
|
||||
{
|
||||
return $this->token;
|
||||
}
|
||||
/**
|
||||
* @return string|null
|
||||
*/
|
||||
public function getRefreshToken()
|
||||
{
|
||||
if (isset($this->token['refresh_token'])) {
|
||||
return $this->token['refresh_token'];
|
||||
}
|
||||
return null;
|
||||
}
|
||||
/**
|
||||
* Returns if the access_token is expired.
|
||||
* @return bool Returns True if the access_token is expired.
|
||||
*/
|
||||
public function isAccessTokenExpired()
|
||||
{
|
||||
if (!$this->token) {
|
||||
return \true;
|
||||
}
|
||||
$created = 0;
|
||||
if (isset($this->token['created'])) {
|
||||
$created = $this->token['created'];
|
||||
} elseif (isset($this->token['id_token'])) {
|
||||
// check the ID token for "iat"
|
||||
// signature verification is not required here, as we are just
|
||||
// using this for convenience to save a round trip request
|
||||
// to the Google API server
|
||||
$idToken = $this->token['id_token'];
|
||||
if (\substr_count($idToken, '.') == 2) {
|
||||
$parts = \explode('.', $idToken);
|
||||
$payload = \json_decode(\base64_decode($parts[1]), \true);
|
||||
if ($payload && isset($payload['iat'])) {
|
||||
$created = $payload['iat'];
|
||||
}
|
||||
}
|
||||
}
|
||||
// If the token is set to expire in the next 30 seconds.
|
||||
return $created + ($this->token['expires_in'] - 30) < \time();
|
||||
}
|
||||
/**
|
||||
* @deprecated See UPGRADING.md for more information
|
||||
*/
|
||||
public function getAuth()
|
||||
{
|
||||
throw new \BadMethodCallException('This function no longer exists. See UPGRADING.md for more information');
|
||||
}
|
||||
/**
|
||||
* @deprecated See UPGRADING.md for more information
|
||||
*/
|
||||
public function setAuth($auth)
|
||||
{
|
||||
throw new \BadMethodCallException('This function no longer exists. See UPGRADING.md for more information');
|
||||
}
|
||||
/**
|
||||
* Set the OAuth 2.0 Client ID.
|
||||
* @param string $clientId
|
||||
*/
|
||||
public function setClientId($clientId)
|
||||
{
|
||||
$this->config['client_id'] = $clientId;
|
||||
}
|
||||
public function getClientId()
|
||||
{
|
||||
return $this->config['client_id'];
|
||||
}
|
||||
/**
|
||||
* Set the OAuth 2.0 Client Secret.
|
||||
* @param string $clientSecret
|
||||
*/
|
||||
public function setClientSecret($clientSecret)
|
||||
{
|
||||
$this->config['client_secret'] = $clientSecret;
|
||||
}
|
||||
public function getClientSecret()
|
||||
{
|
||||
return $this->config['client_secret'];
|
||||
}
|
||||
/**
|
||||
* Set the OAuth 2.0 Redirect URI.
|
||||
* @param string $redirectUri
|
||||
*/
|
||||
public function setRedirectUri($redirectUri)
|
||||
{
|
||||
$this->config['redirect_uri'] = $redirectUri;
|
||||
}
|
||||
public function getRedirectUri()
|
||||
{
|
||||
return $this->config['redirect_uri'];
|
||||
}
|
||||
/**
|
||||
* Set OAuth 2.0 "state" parameter to achieve per-request customization.
|
||||
* @see http://tools.ietf.org/html/draft-ietf-oauth-v2-22#section-3.1.2.2
|
||||
* @param string $state
|
||||
*/
|
||||
public function setState($state)
|
||||
{
|
||||
$this->config['state'] = $state;
|
||||
}
|
||||
/**
|
||||
* @param string $accessType Possible values for access_type include:
|
||||
* {@code "offline"} to request offline access from the user.
|
||||
* {@code "online"} to request online access from the user.
|
||||
*/
|
||||
public function setAccessType($accessType)
|
||||
{
|
||||
$this->config['access_type'] = $accessType;
|
||||
}
|
||||
/**
|
||||
* @param string $approvalPrompt Possible values for approval_prompt include:
|
||||
* {@code "force"} to force the approval UI to appear.
|
||||
* {@code "auto"} to request auto-approval when possible. (This is the default value)
|
||||
*/
|
||||
public function setApprovalPrompt($approvalPrompt)
|
||||
{
|
||||
$this->config['approval_prompt'] = $approvalPrompt;
|
||||
}
|
||||
/**
|
||||
* Set the login hint, email address or sub id.
|
||||
* @param string $loginHint
|
||||
*/
|
||||
public function setLoginHint($loginHint)
|
||||
{
|
||||
$this->config['login_hint'] = $loginHint;
|
||||
}
|
||||
/**
|
||||
* Set the application name, this is included in the User-Agent HTTP header.
|
||||
* @param string $applicationName
|
||||
*/
|
||||
public function setApplicationName($applicationName)
|
||||
{
|
||||
$this->config['application_name'] = $applicationName;
|
||||
}
|
||||
/**
|
||||
* If 'plus.login' is included in the list of requested scopes, you can use
|
||||
* this method to define types of app activities that your app will write.
|
||||
* You can find a list of available types here:
|
||||
* @link https://developers.google.com/+/api/moment-types
|
||||
*
|
||||
* @param array $requestVisibleActions Array of app activity types
|
||||
*/
|
||||
public function setRequestVisibleActions($requestVisibleActions)
|
||||
{
|
||||
if (\is_array($requestVisibleActions)) {
|
||||
$requestVisibleActions = \implode(" ", $requestVisibleActions);
|
||||
}
|
||||
$this->config['request_visible_actions'] = $requestVisibleActions;
|
||||
}
|
||||
/**
|
||||
* Set the developer key to use, these are obtained through the API Console.
|
||||
* @see http://code.google.com/apis/console-help/#generatingdevkeys
|
||||
* @param string $developerKey
|
||||
*/
|
||||
public function setDeveloperKey($developerKey)
|
||||
{
|
||||
$this->config['developer_key'] = $developerKey;
|
||||
}
|
||||
/**
|
||||
* Set the hd (hosted domain) parameter streamlines the login process for
|
||||
* Google Apps hosted accounts. By including the domain of the user, you
|
||||
* restrict sign-in to accounts at that domain.
|
||||
* @param $hd string - the domain to use.
|
||||
*/
|
||||
public function setHostedDomain($hd)
|
||||
{
|
||||
$this->config['hd'] = $hd;
|
||||
}
|
||||
/**
|
||||
* Set the prompt hint. Valid values are none, consent and select_account.
|
||||
* If no value is specified and the user has not previously authorized
|
||||
* access, then the user is shown a consent screen.
|
||||
* @param $prompt string
|
||||
* {@code "none"} Do not display any authentication or consent screens. Must not be specified with other values.
|
||||
* {@code "consent"} Prompt the user for consent.
|
||||
* {@code "select_account"} Prompt the user to select an account.
|
||||
*/
|
||||
public function setPrompt($prompt)
|
||||
{
|
||||
$this->config['prompt'] = $prompt;
|
||||
}
|
||||
/**
|
||||
* openid.realm is a parameter from the OpenID 2.0 protocol, not from OAuth
|
||||
* 2.0. It is used in OpenID 2.0 requests to signify the URL-space for which
|
||||
* an authentication request is valid.
|
||||
* @param $realm string - the URL-space to use.
|
||||
*/
|
||||
public function setOpenidRealm($realm)
|
||||
{
|
||||
$this->config['openid.realm'] = $realm;
|
||||
}
|
||||
/**
|
||||
* If this is provided with the value true, and the authorization request is
|
||||
* granted, the authorization will include any previous authorizations
|
||||
* granted to this user/application combination for other scopes.
|
||||
* @param $include boolean - the URL-space to use.
|
||||
*/
|
||||
public function setIncludeGrantedScopes($include)
|
||||
{
|
||||
$this->config['include_granted_scopes'] = $include;
|
||||
}
|
||||
/**
|
||||
* sets function to be called when an access token is fetched
|
||||
* @param callable $tokenCallback - function ($cacheKey, $accessToken)
|
||||
*/
|
||||
public function setTokenCallback(callable $tokenCallback)
|
||||
{
|
||||
$this->config['token_callback'] = $tokenCallback;
|
||||
}
|
||||
/**
|
||||
* Revoke an OAuth2 access token or refresh token. This method will revoke the current access
|
||||
* token, if a token isn't provided.
|
||||
*
|
||||
* @param string|array|null $token The token (access token or a refresh token) that should be revoked.
|
||||
* @return boolean Returns True if the revocation was successful, otherwise False.
|
||||
*/
|
||||
public function revokeToken($token = null)
|
||||
{
|
||||
$tokenRevoker = new \WPMailSMTP\Vendor\Google_AccessToken_Revoke($this->getHttpClient());
|
||||
return $tokenRevoker->revokeToken($token ?: $this->getAccessToken());
|
||||
}
|
||||
/**
|
||||
* Verify an id_token. This method will verify the current id_token, if one
|
||||
* isn't provided.
|
||||
*
|
||||
* @throws LogicException If no token was provided and no token was set using `setAccessToken`.
|
||||
* @throws UnexpectedValueException If the token is not a valid JWT.
|
||||
* @param string|null $idToken The token (id_token) that should be verified.
|
||||
* @return array|false Returns the token payload as an array if the verification was
|
||||
* successful, false otherwise.
|
||||
*/
|
||||
public function verifyIdToken($idToken = null)
|
||||
{
|
||||
$tokenVerifier = new \WPMailSMTP\Vendor\Google_AccessToken_Verify($this->getHttpClient(), $this->getCache(), $this->config['jwt']);
|
||||
if (null === $idToken) {
|
||||
$token = $this->getAccessToken();
|
||||
if (!isset($token['id_token'])) {
|
||||
throw new \LogicException('id_token must be passed in or set as part of setAccessToken');
|
||||
}
|
||||
$idToken = $token['id_token'];
|
||||
}
|
||||
return $tokenVerifier->verifyIdToken($idToken, $this->getClientId());
|
||||
}
|
||||
/**
|
||||
* Set the scopes to be requested. Must be called before createAuthUrl().
|
||||
* Will remove any previously configured scopes.
|
||||
* @param string|array $scope_or_scopes, ie:
|
||||
* array(
|
||||
* 'https://www.googleapis.com/auth/plus.login',
|
||||
* 'https://www.googleapis.com/auth/moderator'
|
||||
* );
|
||||
*/
|
||||
public function setScopes($scope_or_scopes)
|
||||
{
|
||||
$this->requestedScopes = array();
|
||||
$this->addScope($scope_or_scopes);
|
||||
}
|
||||
/**
|
||||
* This functions adds a scope to be requested as part of the OAuth2.0 flow.
|
||||
* Will append any scopes not previously requested to the scope parameter.
|
||||
* A single string will be treated as a scope to request. An array of strings
|
||||
* will each be appended.
|
||||
* @param $scope_or_scopes string|array e.g. "profile"
|
||||
*/
|
||||
public function addScope($scope_or_scopes)
|
||||
{
|
||||
if (\is_string($scope_or_scopes) && !\in_array($scope_or_scopes, $this->requestedScopes)) {
|
||||
$this->requestedScopes[] = $scope_or_scopes;
|
||||
} else {
|
||||
if (\is_array($scope_or_scopes)) {
|
||||
foreach ($scope_or_scopes as $scope) {
|
||||
$this->addScope($scope);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Returns the list of scopes requested by the client
|
||||
* @return array the list of scopes
|
||||
*
|
||||
*/
|
||||
public function getScopes()
|
||||
{
|
||||
return $this->requestedScopes;
|
||||
}
|
||||
/**
|
||||
* @return string|null
|
||||
* @visible For Testing
|
||||
*/
|
||||
public function prepareScopes()
|
||||
{
|
||||
if (empty($this->requestedScopes)) {
|
||||
return null;
|
||||
}
|
||||
return \implode(' ', $this->requestedScopes);
|
||||
}
|
||||
/**
|
||||
* Helper method to execute deferred HTTP requests.
|
||||
*
|
||||
* @param $request Psr\Http\Message\RequestInterface|Google_Http_Batch
|
||||
* @param string $expectedClass
|
||||
* @throws Google_Exception
|
||||
* @return object of the type of the expected class or Psr\Http\Message\ResponseInterface.
|
||||
*/
|
||||
public function execute(\WPMailSMTP\Vendor\Psr\Http\Message\RequestInterface $request, $expectedClass = null)
|
||||
{
|
||||
$request = $request->withHeader('User-Agent', \sprintf('%s %s%s', $this->config['application_name'], self::USER_AGENT_SUFFIX, $this->getLibraryVersion()))->withHeader('x-goog-api-client', \sprintf('gl-php/%s gdcl/%s', \phpversion(), $this->getLibraryVersion()));
|
||||
if ($this->config['api_format_v2']) {
|
||||
$request = $request->withHeader('X-GOOG-API-FORMAT-VERSION', 2);
|
||||
}
|
||||
// call the authorize method
|
||||
// this is where most of the grunt work is done
|
||||
$http = $this->authorize();
|
||||
return \WPMailSMTP\Vendor\Google_Http_REST::execute($http, $request, $expectedClass, $this->config['retry'], $this->config['retry_map']);
|
||||
}
|
||||
/**
|
||||
* Declare whether batch calls should be used. This may increase throughput
|
||||
* by making multiple requests in one connection.
|
||||
*
|
||||
* @param boolean $useBatch True if the batch support should
|
||||
* be enabled. Defaults to False.
|
||||
*/
|
||||
public function setUseBatch($useBatch)
|
||||
{
|
||||
// This is actually an alias for setDefer.
|
||||
$this->setDefer($useBatch);
|
||||
}
|
||||
/**
|
||||
* Are we running in Google AppEngine?
|
||||
* return bool
|
||||
*/
|
||||
public function isAppEngine()
|
||||
{
|
||||
return isset($_SERVER['SERVER_SOFTWARE']) && \strpos($_SERVER['SERVER_SOFTWARE'], 'Google App Engine') !== \false;
|
||||
}
|
||||
public function setConfig($name, $value)
|
||||
{
|
||||
$this->config[$name] = $value;
|
||||
}
|
||||
public function getConfig($name, $default = null)
|
||||
{
|
||||
return isset($this->config[$name]) ? $this->config[$name] : $default;
|
||||
}
|
||||
/**
|
||||
* For backwards compatibility
|
||||
* alias for setAuthConfig
|
||||
*
|
||||
* @param string $file the configuration file
|
||||
* @throws Google_Exception
|
||||
* @deprecated
|
||||
*/
|
||||
public function setAuthConfigFile($file)
|
||||
{
|
||||
$this->setAuthConfig($file);
|
||||
}
|
||||
/**
|
||||
* Set the auth config from new or deprecated JSON config.
|
||||
* This structure should match the file downloaded from
|
||||
* the "Download JSON" button on in the Google Developer
|
||||
* Console.
|
||||
* @param string|array $config the configuration json
|
||||
* @throws Google_Exception
|
||||
*/
|
||||
public function setAuthConfig($config)
|
||||
{
|
||||
if (\is_string($config)) {
|
||||
if (!\file_exists($config)) {
|
||||
throw new \InvalidArgumentException(\sprintf('file "%s" does not exist', $config));
|
||||
}
|
||||
$json = \file_get_contents($config);
|
||||
if (!($config = \json_decode($json, \true))) {
|
||||
throw new \LogicException('invalid json for auth config');
|
||||
}
|
||||
}
|
||||
$key = isset($config['installed']) ? 'installed' : 'web';
|
||||
if (isset($config['type']) && $config['type'] == 'service_account') {
|
||||
// application default credentials
|
||||
$this->useApplicationDefaultCredentials();
|
||||
// set the information from the config
|
||||
$this->setClientId($config['client_id']);
|
||||
$this->config['client_email'] = $config['client_email'];
|
||||
$this->config['signing_key'] = $config['private_key'];
|
||||
$this->config['signing_algorithm'] = 'HS256';
|
||||
} elseif (isset($config[$key])) {
|
||||
// old-style
|
||||
$this->setClientId($config[$key]['client_id']);
|
||||
$this->setClientSecret($config[$key]['client_secret']);
|
||||
if (isset($config[$key]['redirect_uris'])) {
|
||||
$this->setRedirectUri($config[$key]['redirect_uris'][0]);
|
||||
}
|
||||
} else {
|
||||
// new-style
|
||||
$this->setClientId($config['client_id']);
|
||||
$this->setClientSecret($config['client_secret']);
|
||||
if (isset($config['redirect_uris'])) {
|
||||
$this->setRedirectUri($config['redirect_uris'][0]);
|
||||
}
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Use when the service account has been delegated domain wide access.
|
||||
*
|
||||
* @param string $subject an email address account to impersonate
|
||||
*/
|
||||
public function setSubject($subject)
|
||||
{
|
||||
$this->config['subject'] = $subject;
|
||||
}
|
||||
/**
|
||||
* Declare whether making API calls should make the call immediately, or
|
||||
* return a request which can be called with ->execute();
|
||||
*
|
||||
* @param boolean $defer True if calls should not be executed right away.
|
||||
*/
|
||||
public function setDefer($defer)
|
||||
{
|
||||
$this->deferExecution = $defer;
|
||||
}
|
||||
/**
|
||||
* Whether or not to return raw requests
|
||||
* @return boolean
|
||||
*/
|
||||
public function shouldDefer()
|
||||
{
|
||||
return $this->deferExecution;
|
||||
}
|
||||
/**
|
||||
* @return Google\Auth\OAuth2 implementation
|
||||
*/
|
||||
public function getOAuth2Service()
|
||||
{
|
||||
if (!isset($this->auth)) {
|
||||
$this->auth = $this->createOAuth2Service();
|
||||
}
|
||||
return $this->auth;
|
||||
}
|
||||
/**
|
||||
* create a default google auth object
|
||||
*/
|
||||
protected function createOAuth2Service()
|
||||
{
|
||||
$auth = new \WPMailSMTP\Vendor\Google\Auth\OAuth2(['clientId' => $this->getClientId(), 'clientSecret' => $this->getClientSecret(), 'authorizationUri' => self::OAUTH2_AUTH_URL, 'tokenCredentialUri' => self::OAUTH2_TOKEN_URI, 'redirectUri' => $this->getRedirectUri(), 'issuer' => $this->config['client_id'], 'signingKey' => $this->config['signing_key'], 'signingAlgorithm' => $this->config['signing_algorithm']]);
|
||||
return $auth;
|
||||
}
|
||||
/**
|
||||
* Set the Cache object
|
||||
* @param Psr\Cache\CacheItemPoolInterface $cache
|
||||
*/
|
||||
public function setCache(\WPMailSMTP\Vendor\Psr\Cache\CacheItemPoolInterface $cache)
|
||||
{
|
||||
$this->cache = $cache;
|
||||
}
|
||||
/**
|
||||
* @return Psr\Cache\CacheItemPoolInterface Cache implementation
|
||||
*/
|
||||
public function getCache()
|
||||
{
|
||||
if (!$this->cache) {
|
||||
$this->cache = $this->createDefaultCache();
|
||||
}
|
||||
return $this->cache;
|
||||
}
|
||||
/**
|
||||
* @param array $cacheConfig
|
||||
*/
|
||||
public function setCacheConfig(array $cacheConfig)
|
||||
{
|
||||
$this->config['cache_config'] = $cacheConfig;
|
||||
}
|
||||
/**
|
||||
* Set the Logger object
|
||||
* @param Psr\Log\LoggerInterface $logger
|
||||
*/
|
||||
public function setLogger(\WPMailSMTP\Vendor\Psr\Log\LoggerInterface $logger)
|
||||
{
|
||||
$this->logger = $logger;
|
||||
}
|
||||
/**
|
||||
* @return Psr\Log\LoggerInterface implementation
|
||||
*/
|
||||
public function getLogger()
|
||||
{
|
||||
if (!isset($this->logger)) {
|
||||
$this->logger = $this->createDefaultLogger();
|
||||
}
|
||||
return $this->logger;
|
||||
}
|
||||
protected function createDefaultLogger()
|
||||
{
|
||||
$logger = new \WPMailSMTP\Vendor\Monolog\Logger('google-api-php-client');
|
||||
if ($this->isAppEngine()) {
|
||||
$handler = new \WPMailSMTP\Vendor\Monolog\Handler\SyslogHandler('app', \LOG_USER, \WPMailSMTP\Vendor\Monolog\Logger::NOTICE);
|
||||
} else {
|
||||
$handler = new \WPMailSMTP\Vendor\Monolog\Handler\StreamHandler('php://stderr', \WPMailSMTP\Vendor\Monolog\Logger::NOTICE);
|
||||
}
|
||||
$logger->pushHandler($handler);
|
||||
return $logger;
|
||||
}
|
||||
protected function createDefaultCache()
|
||||
{
|
||||
return new \WPMailSMTP\Vendor\Google\Auth\Cache\MemoryCacheItemPool();
|
||||
}
|
||||
/**
|
||||
* Set the Http Client object
|
||||
* @param GuzzleHttp\ClientInterface $http
|
||||
*/
|
||||
public function setHttpClient(\WPMailSMTP\Vendor\GuzzleHttp\ClientInterface $http)
|
||||
{
|
||||
$this->http = $http;
|
||||
}
|
||||
/**
|
||||
* @return GuzzleHttp\ClientInterface implementation
|
||||
*/
|
||||
public function getHttpClient()
|
||||
{
|
||||
if (null === $this->http) {
|
||||
$this->http = $this->createDefaultHttpClient();
|
||||
}
|
||||
return $this->http;
|
||||
}
|
||||
/**
|
||||
* Set the API format version.
|
||||
*
|
||||
* `true` will use V2, which may return more useful error messages.
|
||||
*
|
||||
* @param bool $value
|
||||
*/
|
||||
public function setApiFormatV2($value)
|
||||
{
|
||||
$this->config['api_format_v2'] = (bool) $value;
|
||||
}
|
||||
protected function createDefaultHttpClient()
|
||||
{
|
||||
$guzzleVersion = null;
|
||||
if (\defined('\\WPMailSMTP\\Vendor\\GuzzleHttp\\ClientInterface::MAJOR_VERSION')) {
|
||||
$guzzleVersion = \WPMailSMTP\Vendor\GuzzleHttp\ClientInterface::MAJOR_VERSION;
|
||||
} elseif (\defined('\\WPMailSMTP\\Vendor\\GuzzleHttp\\ClientInterface::VERSION')) {
|
||||
$guzzleVersion = (int) \substr(\WPMailSMTP\Vendor\GuzzleHttp\ClientInterface::VERSION, 0, 1);
|
||||
}
|
||||
$options = ['exceptions' => \false];
|
||||
if (5 === $guzzleVersion) {
|
||||
$options = ['base_url' => $this->config['base_path'], 'defaults' => $options];
|
||||
if ($this->isAppEngine()) {
|
||||
// set StreamHandler on AppEngine by default
|
||||
$options['handler'] = new \WPMailSMTP\Vendor\GuzzleHttp\Ring\Client\StreamHandler();
|
||||
$options['defaults']['verify'] = '/etc/ca-certificates.crt';
|
||||
}
|
||||
} elseif (6 === $guzzleVersion || 7 === $guzzleVersion) {
|
||||
// guzzle 6 or 7
|
||||
$options['base_uri'] = $this->config['base_path'];
|
||||
} else {
|
||||
throw new \LogicException('Could not find supported version of Guzzle.');
|
||||
}
|
||||
return new \WPMailSMTP\Vendor\GuzzleHttp\Client($options);
|
||||
}
|
||||
private function createApplicationDefaultCredentials()
|
||||
{
|
||||
$scopes = $this->prepareScopes();
|
||||
$sub = $this->config['subject'];
|
||||
$signingKey = $this->config['signing_key'];
|
||||
// create credentials using values supplied in setAuthConfig
|
||||
if ($signingKey) {
|
||||
$serviceAccountCredentials = array('client_id' => $this->config['client_id'], 'client_email' => $this->config['client_email'], 'private_key' => $signingKey, 'type' => 'service_account', 'quota_project' => $this->config['quota_project']);
|
||||
$credentials = \WPMailSMTP\Vendor\Google\Auth\CredentialsLoader::makeCredentials($scopes, $serviceAccountCredentials);
|
||||
} else {
|
||||
$credentials = \WPMailSMTP\Vendor\Google\Auth\ApplicationDefaultCredentials::getCredentials($scopes, null, null, null, $this->config['quota_project']);
|
||||
}
|
||||
// for service account domain-wide authority (impersonating a user)
|
||||
// @see https://developers.google.com/identity/protocols/OAuth2ServiceAccount
|
||||
if ($sub) {
|
||||
if (!$credentials instanceof \WPMailSMTP\Vendor\Google\Auth\Credentials\ServiceAccountCredentials) {
|
||||
throw new \DomainException('domain-wide authority requires service account credentials');
|
||||
}
|
||||
$credentials->setSub($sub);
|
||||
}
|
||||
return $credentials;
|
||||
}
|
||||
protected function getAuthHandler()
|
||||
{
|
||||
// Be very careful using the cache, as the underlying auth library's cache
|
||||
// implementation is naive, and the cache keys do not account for user
|
||||
// sessions.
|
||||
//
|
||||
// @see https://github.com/google/google-api-php-client/issues/821
|
||||
return \WPMailSMTP\Vendor\Google_AuthHandler_AuthHandlerFactory::build($this->getCache(), $this->config['cache_config']);
|
||||
}
|
||||
private function createUserRefreshCredentials($scope, $refreshToken)
|
||||
{
|
||||
$creds = \array_filter(array('client_id' => $this->getClientId(), 'client_secret' => $this->getClientSecret(), 'refresh_token' => $refreshToken));
|
||||
return new \WPMailSMTP\Vendor\Google\Auth\Credentials\UserRefreshCredentials($scope, $creds);
|
||||
}
|
||||
}
|
@ -0,0 +1,87 @@
|
||||
<?php
|
||||
|
||||
namespace WPMailSMTP\Vendor;
|
||||
|
||||
if (!\class_exists('WPMailSMTP\\Vendor\\Google_Client')) {
|
||||
require_once __DIR__ . '/autoload.php';
|
||||
}
|
||||
/**
|
||||
* Extension to the regular Google_Model that automatically
|
||||
* exposes the items array for iteration, so you can just
|
||||
* iterate over the object rather than a reference inside.
|
||||
*/
|
||||
class Google_Collection extends \WPMailSMTP\Vendor\Google_Model implements \Iterator, \Countable
|
||||
{
|
||||
protected $collection_key = 'items';
|
||||
public function rewind()
|
||||
{
|
||||
if (isset($this->{$this->collection_key}) && \is_array($this->{$this->collection_key})) {
|
||||
\reset($this->{$this->collection_key});
|
||||
}
|
||||
}
|
||||
public function current()
|
||||
{
|
||||
$this->coerceType($this->key());
|
||||
if (\is_array($this->{$this->collection_key})) {
|
||||
return \current($this->{$this->collection_key});
|
||||
}
|
||||
}
|
||||
public function key()
|
||||
{
|
||||
if (isset($this->{$this->collection_key}) && \is_array($this->{$this->collection_key})) {
|
||||
return \key($this->{$this->collection_key});
|
||||
}
|
||||
}
|
||||
public function next()
|
||||
{
|
||||
return \next($this->{$this->collection_key});
|
||||
}
|
||||
public function valid()
|
||||
{
|
||||
$key = $this->key();
|
||||
return $key !== null && $key !== \false;
|
||||
}
|
||||
public function count()
|
||||
{
|
||||
if (!isset($this->{$this->collection_key})) {
|
||||
return 0;
|
||||
}
|
||||
return \count($this->{$this->collection_key});
|
||||
}
|
||||
public function offsetExists($offset)
|
||||
{
|
||||
if (!\is_numeric($offset)) {
|
||||
return parent::offsetExists($offset);
|
||||
}
|
||||
return isset($this->{$this->collection_key}[$offset]);
|
||||
}
|
||||
public function offsetGet($offset)
|
||||
{
|
||||
if (!\is_numeric($offset)) {
|
||||
return parent::offsetGet($offset);
|
||||
}
|
||||
$this->coerceType($offset);
|
||||
return $this->{$this->collection_key}[$offset];
|
||||
}
|
||||
public function offsetSet($offset, $value)
|
||||
{
|
||||
if (!\is_numeric($offset)) {
|
||||
return parent::offsetSet($offset, $value);
|
||||
}
|
||||
$this->{$this->collection_key}[$offset] = $value;
|
||||
}
|
||||
public function offsetUnset($offset)
|
||||
{
|
||||
if (!\is_numeric($offset)) {
|
||||
return parent::offsetUnset($offset);
|
||||
}
|
||||
unset($this->{$this->collection_key}[$offset]);
|
||||
}
|
||||
private function coerceType($offset)
|
||||
{
|
||||
$keyType = $this->keyType($this->collection_key);
|
||||
if ($keyType && !\is_object($this->{$this->collection_key}[$offset])) {
|
||||
$this->{$this->collection_key}[$offset] = new $keyType($this->{$this->collection_key}[$offset]);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,22 @@
|
||||
<?php
|
||||
|
||||
namespace WPMailSMTP\Vendor;
|
||||
|
||||
/*
|
||||
* Copyright 2013 Google Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
class Google_Exception extends \Exception
|
||||
{
|
||||
}
|
@ -0,0 +1,188 @@
|
||||
<?php
|
||||
|
||||
namespace WPMailSMTP\Vendor;
|
||||
|
||||
/*
|
||||
* Copyright 2012 Google Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
use WPMailSMTP\Vendor\GuzzleHttp\Psr7;
|
||||
use WPMailSMTP\Vendor\GuzzleHttp\Psr7\Request;
|
||||
use WPMailSMTP\Vendor\GuzzleHttp\Psr7\Response;
|
||||
use WPMailSMTP\Vendor\Psr\Http\Message\RequestInterface;
|
||||
use WPMailSMTP\Vendor\Psr\Http\Message\ResponseInterface;
|
||||
/**
|
||||
* Class to handle batched requests to the Google API service.
|
||||
*
|
||||
* Note that calls to `Google_Http_Batch::execute()` do not clear the queued
|
||||
* requests. To start a new batch, be sure to create a new instance of this
|
||||
* class.
|
||||
*/
|
||||
class Google_Http_Batch
|
||||
{
|
||||
const BATCH_PATH = 'batch';
|
||||
private static $CONNECTION_ESTABLISHED_HEADERS = array("HTTP/1.0 200 Connection established\r\n\r\n", "HTTP/1.1 200 Connection established\r\n\r\n");
|
||||
/** @var string Multipart Boundary. */
|
||||
private $boundary;
|
||||
/** @var array service requests to be executed. */
|
||||
private $requests = array();
|
||||
/** @var Google_Client */
|
||||
private $client;
|
||||
private $rootUrl;
|
||||
private $batchPath;
|
||||
public function __construct(\WPMailSMTP\Vendor\Google_Client $client, $boundary = \false, $rootUrl = null, $batchPath = null)
|
||||
{
|
||||
$this->client = $client;
|
||||
$this->boundary = $boundary ?: \mt_rand();
|
||||
$this->rootUrl = \rtrim($rootUrl ?: $this->client->getConfig('base_path'), '/');
|
||||
$this->batchPath = $batchPath ?: self::BATCH_PATH;
|
||||
}
|
||||
public function add(\WPMailSMTP\Vendor\Psr\Http\Message\RequestInterface $request, $key = \false)
|
||||
{
|
||||
if (\false == $key) {
|
||||
$key = \mt_rand();
|
||||
}
|
||||
$this->requests[$key] = $request;
|
||||
}
|
||||
public function execute()
|
||||
{
|
||||
$body = '';
|
||||
$classes = array();
|
||||
$batchHttpTemplate = <<<EOF
|
||||
--%s
|
||||
Content-Type: application/http
|
||||
Content-Transfer-Encoding: binary
|
||||
MIME-Version: 1.0
|
||||
Content-ID: %s
|
||||
|
||||
%s
|
||||
%s%s
|
||||
|
||||
|
||||
EOF;
|
||||
/** @var Google_Http_Request $req */
|
||||
foreach ($this->requests as $key => $request) {
|
||||
$firstLine = \sprintf('%s %s HTTP/%s', $request->getMethod(), $request->getRequestTarget(), $request->getProtocolVersion());
|
||||
$content = (string) $request->getBody();
|
||||
$headers = '';
|
||||
foreach ($request->getHeaders() as $name => $values) {
|
||||
$headers .= \sprintf("%s:%s\r\n", $name, \implode(', ', $values));
|
||||
}
|
||||
$body .= \sprintf($batchHttpTemplate, $this->boundary, $key, $firstLine, $headers, $content ? "\n" . $content : '');
|
||||
$classes['response-' . $key] = $request->getHeaderLine('X-Php-Expected-Class');
|
||||
}
|
||||
$body .= "--{$this->boundary}--";
|
||||
$body = \trim($body);
|
||||
$url = $this->rootUrl . '/' . $this->batchPath;
|
||||
$headers = array('Content-Type' => \sprintf('multipart/mixed; boundary=%s', $this->boundary), 'Content-Length' => \strlen($body));
|
||||
$request = new \WPMailSMTP\Vendor\GuzzleHttp\Psr7\Request('POST', $url, $headers, $body);
|
||||
$response = $this->client->execute($request);
|
||||
return $this->parseResponse($response, $classes);
|
||||
}
|
||||
public function parseResponse(\WPMailSMTP\Vendor\Psr\Http\Message\ResponseInterface $response, $classes = array())
|
||||
{
|
||||
$contentType = $response->getHeaderLine('content-type');
|
||||
$contentType = \explode(';', $contentType);
|
||||
$boundary = \false;
|
||||
foreach ($contentType as $part) {
|
||||
$part = \explode('=', $part, 2);
|
||||
if (isset($part[0]) && 'boundary' == \trim($part[0])) {
|
||||
$boundary = $part[1];
|
||||
}
|
||||
}
|
||||
$body = (string) $response->getBody();
|
||||
if (!empty($body)) {
|
||||
$body = \str_replace("--{$boundary}--", "--{$boundary}", $body);
|
||||
$parts = \explode("--{$boundary}", $body);
|
||||
$responses = array();
|
||||
$requests = \array_values($this->requests);
|
||||
foreach ($parts as $i => $part) {
|
||||
$part = \trim($part);
|
||||
if (!empty($part)) {
|
||||
list($rawHeaders, $part) = \explode("\r\n\r\n", $part, 2);
|
||||
$headers = $this->parseRawHeaders($rawHeaders);
|
||||
$status = \substr($part, 0, \strpos($part, "\n"));
|
||||
$status = \explode(" ", $status);
|
||||
$status = $status[1];
|
||||
list($partHeaders, $partBody) = $this->parseHttpResponse($part, \false);
|
||||
$response = new \WPMailSMTP\Vendor\GuzzleHttp\Psr7\Response($status, $partHeaders, \WPMailSMTP\Vendor\GuzzleHttp\Psr7\stream_for($partBody));
|
||||
// Need content id.
|
||||
$key = $headers['content-id'];
|
||||
try {
|
||||
$response = \WPMailSMTP\Vendor\Google_Http_REST::decodeHttpResponse($response, $requests[$i - 1]);
|
||||
} catch (\WPMailSMTP\Vendor\Google_Service_Exception $e) {
|
||||
// Store the exception as the response, so successful responses
|
||||
// can be processed.
|
||||
$response = $e;
|
||||
}
|
||||
$responses[$key] = $response;
|
||||
}
|
||||
}
|
||||
return $responses;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
private function parseRawHeaders($rawHeaders)
|
||||
{
|
||||
$headers = array();
|
||||
$responseHeaderLines = \explode("\r\n", $rawHeaders);
|
||||
foreach ($responseHeaderLines as $headerLine) {
|
||||
if ($headerLine && \strpos($headerLine, ':') !== \false) {
|
||||
list($header, $value) = \explode(': ', $headerLine, 2);
|
||||
$header = \strtolower($header);
|
||||
if (isset($headers[$header])) {
|
||||
$headers[$header] .= "\n" . $value;
|
||||
} else {
|
||||
$headers[$header] = $value;
|
||||
}
|
||||
}
|
||||
}
|
||||
return $headers;
|
||||
}
|
||||
/**
|
||||
* Used by the IO lib and also the batch processing.
|
||||
*
|
||||
* @param $respData
|
||||
* @param $headerSize
|
||||
* @return array
|
||||
*/
|
||||
private function parseHttpResponse($respData, $headerSize)
|
||||
{
|
||||
// check proxy header
|
||||
foreach (self::$CONNECTION_ESTABLISHED_HEADERS as $established_header) {
|
||||
if (\stripos($respData, $established_header) !== \false) {
|
||||
// existed, remove it
|
||||
$respData = \str_ireplace($established_header, '', $respData);
|
||||
// Subtract the proxy header size unless the cURL bug prior to 7.30.0
|
||||
// is present which prevented the proxy header size from being taken into
|
||||
// account.
|
||||
// @TODO look into this
|
||||
// if (!$this->needsQuirk()) {
|
||||
// $headerSize -= strlen($established_header);
|
||||
// }
|
||||
break;
|
||||
}
|
||||
}
|
||||
if ($headerSize) {
|
||||
$responseBody = \substr($respData, $headerSize);
|
||||
$responseHeaders = \substr($respData, 0, $headerSize);
|
||||
} else {
|
||||
$responseSegments = \explode("\r\n\r\n", $respData, 2);
|
||||
$responseHeaders = $responseSegments[0];
|
||||
$responseBody = isset($responseSegments[1]) ? $responseSegments[1] : null;
|
||||
}
|
||||
$responseHeaders = $this->parseRawHeaders($responseHeaders);
|
||||
return array($responseHeaders, $responseBody);
|
||||
}
|
||||
}
|
@ -0,0 +1,277 @@
|
||||
<?php
|
||||
|
||||
namespace WPMailSMTP\Vendor;
|
||||
|
||||
/**
|
||||
* Copyright 2012 Google Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
use WPMailSMTP\Vendor\GuzzleHttp\Psr7;
|
||||
use WPMailSMTP\Vendor\GuzzleHttp\Psr7\Request;
|
||||
use WPMailSMTP\Vendor\GuzzleHttp\Psr7\Uri;
|
||||
use WPMailSMTP\Vendor\Psr\Http\Message\RequestInterface;
|
||||
/**
|
||||
* Manage large file uploads, which may be media but can be any type
|
||||
* of sizable data.
|
||||
*/
|
||||
class Google_Http_MediaFileUpload
|
||||
{
|
||||
const UPLOAD_MEDIA_TYPE = 'media';
|
||||
const UPLOAD_MULTIPART_TYPE = 'multipart';
|
||||
const UPLOAD_RESUMABLE_TYPE = 'resumable';
|
||||
/** @var string $mimeType */
|
||||
private $mimeType;
|
||||
/** @var string $data */
|
||||
private $data;
|
||||
/** @var bool $resumable */
|
||||
private $resumable;
|
||||
/** @var int $chunkSize */
|
||||
private $chunkSize;
|
||||
/** @var int $size */
|
||||
private $size;
|
||||
/** @var string $resumeUri */
|
||||
private $resumeUri;
|
||||
/** @var int $progress */
|
||||
private $progress;
|
||||
/** @var Google_Client */
|
||||
private $client;
|
||||
/** @var Psr\Http\Message\RequestInterface */
|
||||
private $request;
|
||||
/** @var string */
|
||||
private $boundary;
|
||||
/**
|
||||
* Result code from last HTTP call
|
||||
* @var int
|
||||
*/
|
||||
private $httpResultCode;
|
||||
/**
|
||||
* @param Google_Client $client
|
||||
* @param RequestInterface $request
|
||||
* @param string $mimeType
|
||||
* @param string $data The bytes you want to upload.
|
||||
* @param bool $resumable
|
||||
* @param bool $chunkSize File will be uploaded in chunks of this many bytes.
|
||||
* only used if resumable=True
|
||||
*/
|
||||
public function __construct(\WPMailSMTP\Vendor\Google_Client $client, \WPMailSMTP\Vendor\Psr\Http\Message\RequestInterface $request, $mimeType, $data, $resumable = \false, $chunkSize = \false)
|
||||
{
|
||||
$this->client = $client;
|
||||
$this->request = $request;
|
||||
$this->mimeType = $mimeType;
|
||||
$this->data = $data;
|
||||
$this->resumable = $resumable;
|
||||
$this->chunkSize = $chunkSize;
|
||||
$this->progress = 0;
|
||||
$this->process();
|
||||
}
|
||||
/**
|
||||
* Set the size of the file that is being uploaded.
|
||||
* @param $size - int file size in bytes
|
||||
*/
|
||||
public function setFileSize($size)
|
||||
{
|
||||
$this->size = $size;
|
||||
}
|
||||
/**
|
||||
* Return the progress on the upload
|
||||
* @return int progress in bytes uploaded.
|
||||
*/
|
||||
public function getProgress()
|
||||
{
|
||||
return $this->progress;
|
||||
}
|
||||
/**
|
||||
* Send the next part of the file to upload.
|
||||
* @param string|bool $chunk Optional. The next set of bytes to send. If false will
|
||||
* use $data passed at construct time.
|
||||
*/
|
||||
public function nextChunk($chunk = \false)
|
||||
{
|
||||
$resumeUri = $this->getResumeUri();
|
||||
if (\false == $chunk) {
|
||||
$chunk = \substr($this->data, $this->progress, $this->chunkSize);
|
||||
}
|
||||
$lastBytePos = $this->progress + \strlen($chunk) - 1;
|
||||
$headers = array('content-range' => "bytes {$this->progress}-{$lastBytePos}/{$this->size}", 'content-length' => \strlen($chunk), 'expect' => '');
|
||||
$request = new \WPMailSMTP\Vendor\GuzzleHttp\Psr7\Request('PUT', $resumeUri, $headers, \WPMailSMTP\Vendor\GuzzleHttp\Psr7\stream_for($chunk));
|
||||
return $this->makePutRequest($request);
|
||||
}
|
||||
/**
|
||||
* Return the HTTP result code from the last call made.
|
||||
* @return int code
|
||||
*/
|
||||
public function getHttpResultCode()
|
||||
{
|
||||
return $this->httpResultCode;
|
||||
}
|
||||
/**
|
||||
* Sends a PUT-Request to google drive and parses the response,
|
||||
* setting the appropiate variables from the response()
|
||||
*
|
||||
* @param Google_Http_Request $httpRequest the Reuqest which will be send
|
||||
*
|
||||
* @return false|mixed false when the upload is unfinished or the decoded http response
|
||||
*
|
||||
*/
|
||||
private function makePutRequest(\WPMailSMTP\Vendor\Psr\Http\Message\RequestInterface $request)
|
||||
{
|
||||
$response = $this->client->execute($request);
|
||||
$this->httpResultCode = $response->getStatusCode();
|
||||
if (308 == $this->httpResultCode) {
|
||||
// Track the amount uploaded.
|
||||
$range = $response->getHeaderLine('range');
|
||||
if ($range) {
|
||||
$range_array = \explode('-', $range);
|
||||
$this->progress = $range_array[1] + 1;
|
||||
}
|
||||
// Allow for changing upload URLs.
|
||||
$location = $response->getHeaderLine('location');
|
||||
if ($location) {
|
||||
$this->resumeUri = $location;
|
||||
}
|
||||
// No problems, but upload not complete.
|
||||
return \false;
|
||||
}
|
||||
return \WPMailSMTP\Vendor\Google_Http_REST::decodeHttpResponse($response, $this->request);
|
||||
}
|
||||
/**
|
||||
* Resume a previously unfinished upload
|
||||
* @param $resumeUri the resume-URI of the unfinished, resumable upload.
|
||||
*/
|
||||
public function resume($resumeUri)
|
||||
{
|
||||
$this->resumeUri = $resumeUri;
|
||||
$headers = array('content-range' => "bytes */{$this->size}", 'content-length' => 0);
|
||||
$httpRequest = new \WPMailSMTP\Vendor\GuzzleHttp\Psr7\Request('PUT', $this->resumeUri, $headers);
|
||||
return $this->makePutRequest($httpRequest);
|
||||
}
|
||||
/**
|
||||
* @return Psr\Http\Message\RequestInterface $request
|
||||
* @visible for testing
|
||||
*/
|
||||
private function process()
|
||||
{
|
||||
$this->transformToUploadUrl();
|
||||
$request = $this->request;
|
||||
$postBody = '';
|
||||
$contentType = \false;
|
||||
$meta = (string) $request->getBody();
|
||||
$meta = \is_string($meta) ? \json_decode($meta, \true) : $meta;
|
||||
$uploadType = $this->getUploadType($meta);
|
||||
$request = $request->withUri(\WPMailSMTP\Vendor\GuzzleHttp\Psr7\Uri::withQueryValue($request->getUri(), 'uploadType', $uploadType));
|
||||
$mimeType = $this->mimeType ?: $request->getHeaderLine('content-type');
|
||||
if (self::UPLOAD_RESUMABLE_TYPE == $uploadType) {
|
||||
$contentType = $mimeType;
|
||||
$postBody = \is_string($meta) ? $meta : \json_encode($meta);
|
||||
} else {
|
||||
if (self::UPLOAD_MEDIA_TYPE == $uploadType) {
|
||||
$contentType = $mimeType;
|
||||
$postBody = $this->data;
|
||||
} else {
|
||||
if (self::UPLOAD_MULTIPART_TYPE == $uploadType) {
|
||||
// This is a multipart/related upload.
|
||||
$boundary = $this->boundary ?: \mt_rand();
|
||||
$boundary = \str_replace('"', '', $boundary);
|
||||
$contentType = 'multipart/related; boundary=' . $boundary;
|
||||
$related = "--{$boundary}\r\n";
|
||||
$related .= "Content-Type: application/json; charset=UTF-8\r\n";
|
||||
$related .= "\r\n" . \json_encode($meta) . "\r\n";
|
||||
$related .= "--{$boundary}\r\n";
|
||||
$related .= "Content-Type: {$mimeType}\r\n";
|
||||
$related .= "Content-Transfer-Encoding: base64\r\n";
|
||||
$related .= "\r\n" . \base64_encode($this->data) . "\r\n";
|
||||
$related .= "--{$boundary}--";
|
||||
$postBody = $related;
|
||||
}
|
||||
}
|
||||
}
|
||||
$request = $request->withBody(\WPMailSMTP\Vendor\GuzzleHttp\Psr7\stream_for($postBody));
|
||||
if (isset($contentType) && $contentType) {
|
||||
$request = $request->withHeader('content-type', $contentType);
|
||||
}
|
||||
return $this->request = $request;
|
||||
}
|
||||
/**
|
||||
* Valid upload types:
|
||||
* - resumable (UPLOAD_RESUMABLE_TYPE)
|
||||
* - media (UPLOAD_MEDIA_TYPE)
|
||||
* - multipart (UPLOAD_MULTIPART_TYPE)
|
||||
* @param $meta
|
||||
* @return string
|
||||
* @visible for testing
|
||||
*/
|
||||
public function getUploadType($meta)
|
||||
{
|
||||
if ($this->resumable) {
|
||||
return self::UPLOAD_RESUMABLE_TYPE;
|
||||
}
|
||||
if (\false == $meta && $this->data) {
|
||||
return self::UPLOAD_MEDIA_TYPE;
|
||||
}
|
||||
return self::UPLOAD_MULTIPART_TYPE;
|
||||
}
|
||||
public function getResumeUri()
|
||||
{
|
||||
if (null === $this->resumeUri) {
|
||||
$this->resumeUri = $this->fetchResumeUri();
|
||||
}
|
||||
return $this->resumeUri;
|
||||
}
|
||||
private function fetchResumeUri()
|
||||
{
|
||||
$body = $this->request->getBody();
|
||||
if ($body) {
|
||||
$headers = array('content-type' => 'application/json; charset=UTF-8', 'content-length' => $body->getSize(), 'x-upload-content-type' => $this->mimeType, 'x-upload-content-length' => $this->size, 'expect' => '');
|
||||
foreach ($headers as $key => $value) {
|
||||
$this->request = $this->request->withHeader($key, $value);
|
||||
}
|
||||
}
|
||||
$response = $this->client->execute($this->request, \false);
|
||||
$location = $response->getHeaderLine('location');
|
||||
$code = $response->getStatusCode();
|
||||
if (200 == $code && \true == $location) {
|
||||
return $location;
|
||||
}
|
||||
$message = $code;
|
||||
$body = \json_decode((string) $this->request->getBody(), \true);
|
||||
if (isset($body['error']['errors'])) {
|
||||
$message .= ': ';
|
||||
foreach ($body['error']['errors'] as $error) {
|
||||
$message .= "{$error['domain']}, {$error['message']};";
|
||||
}
|
||||
$message = \rtrim($message, ';');
|
||||
}
|
||||
$error = "Failed to start the resumable upload (HTTP {$message})";
|
||||
$this->client->getLogger()->error($error);
|
||||
throw new \WPMailSMTP\Vendor\Google_Exception($error);
|
||||
}
|
||||
private function transformToUploadUrl()
|
||||
{
|
||||
$parts = \parse_url((string) $this->request->getUri());
|
||||
if (!isset($parts['path'])) {
|
||||
$parts['path'] = '';
|
||||
}
|
||||
$parts['path'] = '/upload' . $parts['path'];
|
||||
$uri = \WPMailSMTP\Vendor\GuzzleHttp\Psr7\Uri::fromParts($parts);
|
||||
$this->request = $this->request->withUri($uri);
|
||||
}
|
||||
public function setChunkSize($chunkSize)
|
||||
{
|
||||
$this->chunkSize = $chunkSize;
|
||||
}
|
||||
public function getRequest()
|
||||
{
|
||||
return $this->request;
|
||||
}
|
||||
}
|
@ -0,0 +1,148 @@
|
||||
<?php
|
||||
|
||||
namespace WPMailSMTP\Vendor;
|
||||
|
||||
/*
|
||||
* Copyright 2010 Google Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
use WPMailSMTP\Vendor\Google\Auth\HttpHandler\HttpHandlerFactory;
|
||||
use WPMailSMTP\Vendor\GuzzleHttp\ClientInterface;
|
||||
use WPMailSMTP\Vendor\GuzzleHttp\Exception\RequestException;
|
||||
use WPMailSMTP\Vendor\GuzzleHttp\Psr7\Response;
|
||||
use WPMailSMTP\Vendor\Psr\Http\Message\RequestInterface;
|
||||
use WPMailSMTP\Vendor\Psr\Http\Message\ResponseInterface;
|
||||
/**
|
||||
* This class implements the RESTful transport of apiServiceRequest()'s
|
||||
*/
|
||||
class Google_Http_REST
|
||||
{
|
||||
/**
|
||||
* Executes a Psr\Http\Message\RequestInterface and (if applicable) automatically retries
|
||||
* when errors occur.
|
||||
*
|
||||
* @param Google_Client $client
|
||||
* @param Psr\Http\Message\RequestInterface $req
|
||||
* @param string $expectedClass
|
||||
* @param array $config
|
||||
* @param array $retryMap
|
||||
* @return array decoded result
|
||||
* @throws Google_Service_Exception on server side error (ie: not authenticated,
|
||||
* invalid or malformed post body, invalid url)
|
||||
*/
|
||||
public static function execute(\WPMailSMTP\Vendor\GuzzleHttp\ClientInterface $client, \WPMailSMTP\Vendor\Psr\Http\Message\RequestInterface $request, $expectedClass = null, $config = array(), $retryMap = null)
|
||||
{
|
||||
$runner = new \WPMailSMTP\Vendor\Google_Task_Runner($config, \sprintf('%s %s', $request->getMethod(), (string) $request->getUri()), array(\get_class(), 'doExecute'), array($client, $request, $expectedClass));
|
||||
if (null !== $retryMap) {
|
||||
$runner->setRetryMap($retryMap);
|
||||
}
|
||||
return $runner->run();
|
||||
}
|
||||
/**
|
||||
* Executes a Psr\Http\Message\RequestInterface
|
||||
*
|
||||
* @param Google_Client $client
|
||||
* @param Psr\Http\Message\RequestInterface $request
|
||||
* @param string $expectedClass
|
||||
* @return array decoded result
|
||||
* @throws Google_Service_Exception on server side error (ie: not authenticated,
|
||||
* invalid or malformed post body, invalid url)
|
||||
*/
|
||||
public static function doExecute(\WPMailSMTP\Vendor\GuzzleHttp\ClientInterface $client, \WPMailSMTP\Vendor\Psr\Http\Message\RequestInterface $request, $expectedClass = null)
|
||||
{
|
||||
try {
|
||||
$httpHandler = \WPMailSMTP\Vendor\Google\Auth\HttpHandler\HttpHandlerFactory::build($client);
|
||||
$response = $httpHandler($request);
|
||||
} catch (\WPMailSMTP\Vendor\GuzzleHttp\Exception\RequestException $e) {
|
||||
// if Guzzle throws an exception, catch it and handle the response
|
||||
if (!$e->hasResponse()) {
|
||||
throw $e;
|
||||
}
|
||||
$response = $e->getResponse();
|
||||
// specific checking for Guzzle 5: convert to PSR7 response
|
||||
if ($response instanceof \WPMailSMTP\Vendor\GuzzleHttp\Message\ResponseInterface) {
|
||||
$response = new \WPMailSMTP\Vendor\GuzzleHttp\Psr7\Response($response->getStatusCode(), $response->getHeaders() ?: [], $response->getBody(), $response->getProtocolVersion(), $response->getReasonPhrase());
|
||||
}
|
||||
}
|
||||
return self::decodeHttpResponse($response, $request, $expectedClass);
|
||||
}
|
||||
/**
|
||||
* Decode an HTTP Response.
|
||||
* @static
|
||||
* @throws Google_Service_Exception
|
||||
* @param Psr\Http\Message\RequestInterface $response The http response to be decoded.
|
||||
* @param Psr\Http\Message\ResponseInterface $response
|
||||
* @param string $expectedClass
|
||||
* @return mixed|null
|
||||
*/
|
||||
public static function decodeHttpResponse(\WPMailSMTP\Vendor\Psr\Http\Message\ResponseInterface $response, \WPMailSMTP\Vendor\Psr\Http\Message\RequestInterface $request = null, $expectedClass = null)
|
||||
{
|
||||
$code = $response->getStatusCode();
|
||||
// retry strategy
|
||||
if (\intVal($code) >= 400) {
|
||||
// if we errored out, it should be safe to grab the response body
|
||||
$body = (string) $response->getBody();
|
||||
// Check if we received errors, and add those to the Exception for convenience
|
||||
throw new \WPMailSMTP\Vendor\Google_Service_Exception($body, $code, null, self::getResponseErrors($body));
|
||||
}
|
||||
// Ensure we only pull the entire body into memory if the request is not
|
||||
// of media type
|
||||
$body = self::decodeBody($response, $request);
|
||||
if ($expectedClass = self::determineExpectedClass($expectedClass, $request)) {
|
||||
$json = \json_decode($body, \true);
|
||||
$expectedClass = 'WPMailSMTP\\Vendor\\' . $expectedClass;
|
||||
return new $expectedClass($json);
|
||||
}
|
||||
return $response;
|
||||
}
|
||||
private static function decodeBody(\WPMailSMTP\Vendor\Psr\Http\Message\ResponseInterface $response, \WPMailSMTP\Vendor\Psr\Http\Message\RequestInterface $request = null)
|
||||
{
|
||||
if (self::isAltMedia($request)) {
|
||||
// don't decode the body, it's probably a really long string
|
||||
return '';
|
||||
}
|
||||
return (string) $response->getBody();
|
||||
}
|
||||
private static function determineExpectedClass($expectedClass, \WPMailSMTP\Vendor\Psr\Http\Message\RequestInterface $request = null)
|
||||
{
|
||||
// "false" is used to explicitly prevent an expected class from being returned
|
||||
if (\false === $expectedClass) {
|
||||
return null;
|
||||
}
|
||||
// if we don't have a request, we just use what's passed in
|
||||
if (null === $request) {
|
||||
return $expectedClass;
|
||||
}
|
||||
// return what we have in the request header if one was not supplied
|
||||
return $expectedClass ?: $request->getHeaderLine('X-Php-Expected-Class');
|
||||
}
|
||||
private static function getResponseErrors($body)
|
||||
{
|
||||
$json = \json_decode($body, \true);
|
||||
if (isset($json['error']['errors'])) {
|
||||
return $json['error']['errors'];
|
||||
}
|
||||
return null;
|
||||
}
|
||||
private static function isAltMedia(\WPMailSMTP\Vendor\Psr\Http\Message\RequestInterface $request = null)
|
||||
{
|
||||
if ($request && ($qs = $request->getUri()->getQuery())) {
|
||||
\parse_str($qs, $query);
|
||||
if (isset($query['alt']) && $query['alt'] == 'media') {
|
||||
return \true;
|
||||
}
|
||||
}
|
||||
return \false;
|
||||
}
|
||||
}
|
@ -0,0 +1,292 @@
|
||||
<?php
|
||||
|
||||
namespace WPMailSMTP\Vendor;
|
||||
|
||||
/*
|
||||
* Copyright 2011 Google Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
/**
|
||||
* This class defines attributes, valid values, and usage which is generated
|
||||
* from a given json schema.
|
||||
* http://tools.ietf.org/html/draft-zyp-json-schema-03#section-5
|
||||
*
|
||||
*/
|
||||
class Google_Model implements \ArrayAccess
|
||||
{
|
||||
/**
|
||||
* If you need to specify a NULL JSON value, use Google_Model::NULL_VALUE
|
||||
* instead - it will be replaced when converting to JSON with a real null.
|
||||
*/
|
||||
const NULL_VALUE = "{}gapi-php-null";
|
||||
protected $internal_gapi_mappings = array();
|
||||
protected $modelData = array();
|
||||
protected $processed = array();
|
||||
/**
|
||||
* Polymorphic - accepts a variable number of arguments dependent
|
||||
* on the type of the model subclass.
|
||||
*/
|
||||
public final function __construct()
|
||||
{
|
||||
if (\func_num_args() == 1 && \is_array(\func_get_arg(0))) {
|
||||
// Initialize the model with the array's contents.
|
||||
$array = \func_get_arg(0);
|
||||
$this->mapTypes($array);
|
||||
}
|
||||
$this->gapiInit();
|
||||
}
|
||||
/**
|
||||
* Getter that handles passthrough access to the data array, and lazy object creation.
|
||||
* @param string $key Property name.
|
||||
* @return mixed The value if any, or null.
|
||||
*/
|
||||
public function __get($key)
|
||||
{
|
||||
$keyType = $this->keyType($key);
|
||||
$keyDataType = $this->dataType($key);
|
||||
if ($keyType && !isset($this->processed[$key])) {
|
||||
if (isset($this->modelData[$key])) {
|
||||
$val = $this->modelData[$key];
|
||||
} elseif ($keyDataType == 'array' || $keyDataType == 'map') {
|
||||
$val = array();
|
||||
} else {
|
||||
$val = null;
|
||||
}
|
||||
if ($this->isAssociativeArray($val)) {
|
||||
if ($keyDataType && 'map' == $keyDataType) {
|
||||
foreach ($val as $arrayKey => $arrayItem) {
|
||||
$this->modelData[$key][$arrayKey] = new $keyType($arrayItem);
|
||||
}
|
||||
} else {
|
||||
$this->modelData[$key] = new $keyType($val);
|
||||
}
|
||||
} else {
|
||||
if (\is_array($val)) {
|
||||
$arrayObject = array();
|
||||
foreach ($val as $arrayIndex => $arrayItem) {
|
||||
$arrayObject[$arrayIndex] = new $keyType($arrayItem);
|
||||
}
|
||||
$this->modelData[$key] = $arrayObject;
|
||||
}
|
||||
}
|
||||
$this->processed[$key] = \true;
|
||||
}
|
||||
return isset($this->modelData[$key]) ? $this->modelData[$key] : null;
|
||||
}
|
||||
/**
|
||||
* Initialize this object's properties from an array.
|
||||
*
|
||||
* @param array $array Used to seed this object's properties.
|
||||
* @return void
|
||||
*/
|
||||
protected function mapTypes($array)
|
||||
{
|
||||
// Hard initialise simple types, lazy load more complex ones.
|
||||
foreach ($array as $key => $val) {
|
||||
if ($keyType = $this->keyType($key)) {
|
||||
$dataType = $this->dataType($key);
|
||||
if ($dataType == 'array' || $dataType == 'map') {
|
||||
$this->{$key} = array();
|
||||
foreach ($val as $itemKey => $itemVal) {
|
||||
if ($itemVal instanceof $keyType) {
|
||||
$this->{$key}[$itemKey] = $itemVal;
|
||||
} else {
|
||||
$this->{$key}[$itemKey] = new $keyType($itemVal);
|
||||
}
|
||||
}
|
||||
} elseif ($val instanceof $keyType) {
|
||||
$this->{$key} = $val;
|
||||
} else {
|
||||
$this->{$key} = new $keyType($val);
|
||||
}
|
||||
unset($array[$key]);
|
||||
} elseif (\property_exists($this, $key)) {
|
||||
$this->{$key} = $val;
|
||||
unset($array[$key]);
|
||||
} elseif (\property_exists($this, $camelKey = $this->camelCase($key))) {
|
||||
// This checks if property exists as camelCase, leaving it in array as snake_case
|
||||
// in case of backwards compatibility issues.
|
||||
$this->{$camelKey} = $val;
|
||||
}
|
||||
}
|
||||
$this->modelData = $array;
|
||||
}
|
||||
/**
|
||||
* Blank initialiser to be used in subclasses to do post-construction initialisation - this
|
||||
* avoids the need for subclasses to have to implement the variadics handling in their
|
||||
* constructors.
|
||||
*/
|
||||
protected function gapiInit()
|
||||
{
|
||||
return;
|
||||
}
|
||||
/**
|
||||
* Create a simplified object suitable for straightforward
|
||||
* conversion to JSON. This is relatively expensive
|
||||
* due to the usage of reflection, but shouldn't be called
|
||||
* a whole lot, and is the most straightforward way to filter.
|
||||
*/
|
||||
public function toSimpleObject()
|
||||
{
|
||||
$object = new \stdClass();
|
||||
// Process all other data.
|
||||
foreach ($this->modelData as $key => $val) {
|
||||
$result = $this->getSimpleValue($val);
|
||||
if ($result !== null) {
|
||||
$object->{$key} = $this->nullPlaceholderCheck($result);
|
||||
}
|
||||
}
|
||||
// Process all public properties.
|
||||
$reflect = new \ReflectionObject($this);
|
||||
$props = $reflect->getProperties(\ReflectionProperty::IS_PUBLIC);
|
||||
foreach ($props as $member) {
|
||||
$name = $member->getName();
|
||||
$result = $this->getSimpleValue($this->{$name});
|
||||
if ($result !== null) {
|
||||
$name = $this->getMappedName($name);
|
||||
$object->{$name} = $this->nullPlaceholderCheck($result);
|
||||
}
|
||||
}
|
||||
return $object;
|
||||
}
|
||||
/**
|
||||
* Handle different types of values, primarily
|
||||
* other objects and map and array data types.
|
||||
*/
|
||||
private function getSimpleValue($value)
|
||||
{
|
||||
if ($value instanceof \WPMailSMTP\Vendor\Google_Model) {
|
||||
return $value->toSimpleObject();
|
||||
} else {
|
||||
if (\is_array($value)) {
|
||||
$return = array();
|
||||
foreach ($value as $key => $a_value) {
|
||||
$a_value = $this->getSimpleValue($a_value);
|
||||
if ($a_value !== null) {
|
||||
$key = $this->getMappedName($key);
|
||||
$return[$key] = $this->nullPlaceholderCheck($a_value);
|
||||
}
|
||||
}
|
||||
return $return;
|
||||
}
|
||||
}
|
||||
return $value;
|
||||
}
|
||||
/**
|
||||
* Check whether the value is the null placeholder and return true null.
|
||||
*/
|
||||
private function nullPlaceholderCheck($value)
|
||||
{
|
||||
if ($value === self::NULL_VALUE) {
|
||||
return null;
|
||||
}
|
||||
return $value;
|
||||
}
|
||||
/**
|
||||
* If there is an internal name mapping, use that.
|
||||
*/
|
||||
private function getMappedName($key)
|
||||
{
|
||||
if (isset($this->internal_gapi_mappings, $this->internal_gapi_mappings[$key])) {
|
||||
$key = $this->internal_gapi_mappings[$key];
|
||||
}
|
||||
return $key;
|
||||
}
|
||||
/**
|
||||
* Returns true only if the array is associative.
|
||||
* @param array $array
|
||||
* @return bool True if the array is associative.
|
||||
*/
|
||||
protected function isAssociativeArray($array)
|
||||
{
|
||||
if (!\is_array($array)) {
|
||||
return \false;
|
||||
}
|
||||
$keys = \array_keys($array);
|
||||
foreach ($keys as $key) {
|
||||
if (\is_string($key)) {
|
||||
return \true;
|
||||
}
|
||||
}
|
||||
return \false;
|
||||
}
|
||||
/**
|
||||
* Verify if $obj is an array.
|
||||
* @throws Google_Exception Thrown if $obj isn't an array.
|
||||
* @param array $obj Items that should be validated.
|
||||
* @param string $method Method expecting an array as an argument.
|
||||
*/
|
||||
public function assertIsArray($obj, $method)
|
||||
{
|
||||
if ($obj && !\is_array($obj)) {
|
||||
throw new \WPMailSMTP\Vendor\Google_Exception("Incorrect parameter type passed to {$method}(). Expected an array.");
|
||||
}
|
||||
}
|
||||
public function offsetExists($offset)
|
||||
{
|
||||
return isset($this->{$offset}) || isset($this->modelData[$offset]);
|
||||
}
|
||||
public function offsetGet($offset)
|
||||
{
|
||||
return isset($this->{$offset}) ? $this->{$offset} : $this->__get($offset);
|
||||
}
|
||||
public function offsetSet($offset, $value)
|
||||
{
|
||||
if (\property_exists($this, $offset)) {
|
||||
$this->{$offset} = $value;
|
||||
} else {
|
||||
$this->modelData[$offset] = $value;
|
||||
$this->processed[$offset] = \true;
|
||||
}
|
||||
}
|
||||
public function offsetUnset($offset)
|
||||
{
|
||||
unset($this->modelData[$offset]);
|
||||
}
|
||||
protected function keyType($key)
|
||||
{
|
||||
$keyType = $key . "Type";
|
||||
// ensure keyType is a valid class
|
||||
if (\property_exists($this, $keyType) && \class_exists($this->{$keyType})) {
|
||||
return $this->{$keyType};
|
||||
}
|
||||
}
|
||||
protected function dataType($key)
|
||||
{
|
||||
$dataType = $key . "DataType";
|
||||
if (\property_exists($this, $dataType)) {
|
||||
return $this->{$dataType};
|
||||
}
|
||||
}
|
||||
public function __isset($key)
|
||||
{
|
||||
return isset($this->modelData[$key]);
|
||||
}
|
||||
public function __unset($key)
|
||||
{
|
||||
unset($this->modelData[$key]);
|
||||
}
|
||||
/**
|
||||
* Convert a string to camelCase
|
||||
* @param string $value
|
||||
* @return string
|
||||
*/
|
||||
private function camelCase($value)
|
||||
{
|
||||
$value = \ucwords(\str_replace(array('-', '_'), ' ', $value));
|
||||
$value = \str_replace(' ', '', $value);
|
||||
$value[0] = \strtolower($value[0]);
|
||||
return $value;
|
||||
}
|
||||
}
|
@ -0,0 +1,50 @@
|
||||
<?php
|
||||
|
||||
namespace WPMailSMTP\Vendor;
|
||||
|
||||
/*
|
||||
* Copyright 2010 Google Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
class Google_Service
|
||||
{
|
||||
public $batchPath;
|
||||
public $rootUrl;
|
||||
public $version;
|
||||
public $servicePath;
|
||||
public $availableScopes;
|
||||
public $resource;
|
||||
private $client;
|
||||
public function __construct(\WPMailSMTP\Vendor\Google_Client $client)
|
||||
{
|
||||
$this->client = $client;
|
||||
}
|
||||
/**
|
||||
* Return the associated Google_Client class.
|
||||
* @return Google_Client
|
||||
*/
|
||||
public function getClient()
|
||||
{
|
||||
return $this->client;
|
||||
}
|
||||
/**
|
||||
* Create a new HTTP Batch handler for this service
|
||||
*
|
||||
* @return Google_Http_Batch
|
||||
*/
|
||||
public function createBatch()
|
||||
{
|
||||
return new \WPMailSMTP\Vendor\Google_Http_Batch($this->client, \false, $this->rootUrl, $this->batchPath);
|
||||
}
|
||||
}
|
@ -0,0 +1,62 @@
|
||||
<?php
|
||||
|
||||
namespace WPMailSMTP\Vendor;
|
||||
|
||||
/*
|
||||
* Copyright 2014 Google Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
class Google_Service_Exception extends \WPMailSMTP\Vendor\Google_Exception
|
||||
{
|
||||
/**
|
||||
* Optional list of errors returned in a JSON body of an HTTP error response.
|
||||
*/
|
||||
protected $errors = array();
|
||||
/**
|
||||
* Override default constructor to add the ability to set $errors and a retry
|
||||
* map.
|
||||
*
|
||||
* @param string $message
|
||||
* @param int $code
|
||||
* @param Exception|null $previous
|
||||
* @param [{string, string}] errors List of errors returned in an HTTP
|
||||
* response. Defaults to [].
|
||||
*/
|
||||
public function __construct($message, $code = 0, \Exception $previous = null, $errors = array())
|
||||
{
|
||||
if (\version_compare(\PHP_VERSION, '5.3.0') >= 0) {
|
||||
parent::__construct($message, $code, $previous);
|
||||
} else {
|
||||
parent::__construct($message, $code);
|
||||
}
|
||||
$this->errors = $errors;
|
||||
}
|
||||
/**
|
||||
* An example of the possible errors returned.
|
||||
*
|
||||
* {
|
||||
* "domain": "global",
|
||||
* "reason": "authError",
|
||||
* "message": "Invalid Credentials",
|
||||
* "locationType": "header",
|
||||
* "location": "Authorization",
|
||||
* }
|
||||
*
|
||||
* @return [{string, string}] List of errors return in an HTTP response or [].
|
||||
*/
|
||||
public function getErrors()
|
||||
{
|
||||
return $this->errors;
|
||||
}
|
||||
}
|
@ -0,0 +1,212 @@
|
||||
<?php
|
||||
|
||||
namespace WPMailSMTP\Vendor;
|
||||
|
||||
/**
|
||||
* Copyright 2010 Google Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
use WPMailSMTP\Vendor\GuzzleHttp\Psr7\Request;
|
||||
/**
|
||||
* Implements the actual methods/resources of the discovered Google API using magic function
|
||||
* calling overloading (__call()), which on call will see if the method name (plus.activities.list)
|
||||
* is available in this service, and if so construct an apiHttpRequest representing it.
|
||||
*
|
||||
*/
|
||||
class Google_Service_Resource
|
||||
{
|
||||
// Valid query parameters that work, but don't appear in discovery.
|
||||
private $stackParameters = array('alt' => array('type' => 'string', 'location' => 'query'), 'fields' => array('type' => 'string', 'location' => 'query'), 'trace' => array('type' => 'string', 'location' => 'query'), 'userIp' => array('type' => 'string', 'location' => 'query'), 'quotaUser' => array('type' => 'string', 'location' => 'query'), 'data' => array('type' => 'string', 'location' => 'body'), 'mimeType' => array('type' => 'string', 'location' => 'header'), 'uploadType' => array('type' => 'string', 'location' => 'query'), 'mediaUpload' => array('type' => 'complex', 'location' => 'query'), 'prettyPrint' => array('type' => 'string', 'location' => 'query'));
|
||||
/** @var string $rootUrl */
|
||||
private $rootUrl;
|
||||
/** @var Google_Client $client */
|
||||
private $client;
|
||||
/** @var string $serviceName */
|
||||
private $serviceName;
|
||||
/** @var string $servicePath */
|
||||
private $servicePath;
|
||||
/** @var string $resourceName */
|
||||
private $resourceName;
|
||||
/** @var array $methods */
|
||||
private $methods;
|
||||
public function __construct($service, $serviceName, $resourceName, $resource)
|
||||
{
|
||||
$this->rootUrl = $service->rootUrl;
|
||||
$this->client = $service->getClient();
|
||||
$this->servicePath = $service->servicePath;
|
||||
$this->serviceName = $serviceName;
|
||||
$this->resourceName = $resourceName;
|
||||
$this->methods = \is_array($resource) && isset($resource['methods']) ? $resource['methods'] : array($resourceName => $resource);
|
||||
}
|
||||
/**
|
||||
* TODO: This function needs simplifying.
|
||||
* @param $name
|
||||
* @param $arguments
|
||||
* @param $expectedClass - optional, the expected class name
|
||||
* @return Google_Http_Request|expectedClass
|
||||
* @throws Google_Exception
|
||||
*/
|
||||
public function call($name, $arguments, $expectedClass = null)
|
||||
{
|
||||
if (!isset($this->methods[$name])) {
|
||||
$this->client->getLogger()->error('Service method unknown', array('service' => $this->serviceName, 'resource' => $this->resourceName, 'method' => $name));
|
||||
throw new \WPMailSMTP\Vendor\Google_Exception("Unknown function: " . "{$this->serviceName}->{$this->resourceName}->{$name}()");
|
||||
}
|
||||
$method = $this->methods[$name];
|
||||
$parameters = $arguments[0];
|
||||
// postBody is a special case since it's not defined in the discovery
|
||||
// document as parameter, but we abuse the param entry for storing it.
|
||||
$postBody = null;
|
||||
if (isset($parameters['postBody'])) {
|
||||
if ($parameters['postBody'] instanceof \WPMailSMTP\Vendor\Google_Model) {
|
||||
// In the cases the post body is an existing object, we want
|
||||
// to use the smart method to create a simple object for
|
||||
// for JSONification.
|
||||
$parameters['postBody'] = $parameters['postBody']->toSimpleObject();
|
||||
} else {
|
||||
if (\is_object($parameters['postBody'])) {
|
||||
// If the post body is another kind of object, we will try and
|
||||
// wrangle it into a sensible format.
|
||||
$parameters['postBody'] = $this->convertToArrayAndStripNulls($parameters['postBody']);
|
||||
}
|
||||
}
|
||||
$postBody = (array) $parameters['postBody'];
|
||||
unset($parameters['postBody']);
|
||||
}
|
||||
// TODO: optParams here probably should have been
|
||||
// handled already - this may well be redundant code.
|
||||
if (isset($parameters['optParams'])) {
|
||||
$optParams = $parameters['optParams'];
|
||||
unset($parameters['optParams']);
|
||||
$parameters = \array_merge($parameters, $optParams);
|
||||
}
|
||||
if (!isset($method['parameters'])) {
|
||||
$method['parameters'] = array();
|
||||
}
|
||||
$method['parameters'] = \array_merge($this->stackParameters, $method['parameters']);
|
||||
foreach ($parameters as $key => $val) {
|
||||
if ($key != 'postBody' && !isset($method['parameters'][$key])) {
|
||||
$this->client->getLogger()->error('Service parameter unknown', array('service' => $this->serviceName, 'resource' => $this->resourceName, 'method' => $name, 'parameter' => $key));
|
||||
throw new \WPMailSMTP\Vendor\Google_Exception("({$name}) unknown parameter: '{$key}'");
|
||||
}
|
||||
}
|
||||
foreach ($method['parameters'] as $paramName => $paramSpec) {
|
||||
if (isset($paramSpec['required']) && $paramSpec['required'] && !isset($parameters[$paramName])) {
|
||||
$this->client->getLogger()->error('Service parameter missing', array('service' => $this->serviceName, 'resource' => $this->resourceName, 'method' => $name, 'parameter' => $paramName));
|
||||
throw new \WPMailSMTP\Vendor\Google_Exception("({$name}) missing required param: '{$paramName}'");
|
||||
}
|
||||
if (isset($parameters[$paramName])) {
|
||||
$value = $parameters[$paramName];
|
||||
$parameters[$paramName] = $paramSpec;
|
||||
$parameters[$paramName]['value'] = $value;
|
||||
unset($parameters[$paramName]['required']);
|
||||
} else {
|
||||
// Ensure we don't pass nulls.
|
||||
unset($parameters[$paramName]);
|
||||
}
|
||||
}
|
||||
$this->client->getLogger()->info('Service Call', array('service' => $this->serviceName, 'resource' => $this->resourceName, 'method' => $name, 'arguments' => $parameters));
|
||||
// build the service uri
|
||||
$url = $this->createRequestUri($method['path'], $parameters);
|
||||
// NOTE: because we're creating the request by hand,
|
||||
// and because the service has a rootUrl property
|
||||
// the "base_uri" of the Http Client is not accounted for
|
||||
$request = new \WPMailSMTP\Vendor\GuzzleHttp\Psr7\Request($method['httpMethod'], $url, ['content-type' => 'application/json'], $postBody ? \json_encode($postBody) : '');
|
||||
// support uploads
|
||||
if (isset($parameters['data'])) {
|
||||
$mimeType = isset($parameters['mimeType']) ? $parameters['mimeType']['value'] : 'application/octet-stream';
|
||||
$data = $parameters['data']['value'];
|
||||
$upload = new \WPMailSMTP\Vendor\Google_Http_MediaFileUpload($this->client, $request, $mimeType, $data);
|
||||
// pull down the modified request
|
||||
$request = $upload->getRequest();
|
||||
}
|
||||
// if this is a media type, we will return the raw response
|
||||
// rather than using an expected class
|
||||
if (isset($parameters['alt']) && $parameters['alt']['value'] == 'media') {
|
||||
$expectedClass = null;
|
||||
}
|
||||
// if the client is marked for deferring, rather than
|
||||
// execute the request, return the response
|
||||
if ($this->client->shouldDefer()) {
|
||||
// @TODO find a better way to do this
|
||||
$request = $request->withHeader('X-Php-Expected-Class', $expectedClass);
|
||||
return $request;
|
||||
}
|
||||
return $this->client->execute($request, $expectedClass);
|
||||
}
|
||||
protected function convertToArrayAndStripNulls($o)
|
||||
{
|
||||
$o = (array) $o;
|
||||
foreach ($o as $k => $v) {
|
||||
if ($v === null) {
|
||||
unset($o[$k]);
|
||||
} elseif (\is_object($v) || \is_array($v)) {
|
||||
$o[$k] = $this->convertToArrayAndStripNulls($o[$k]);
|
||||
}
|
||||
}
|
||||
return $o;
|
||||
}
|
||||
/**
|
||||
* Parse/expand request parameters and create a fully qualified
|
||||
* request uri.
|
||||
* @static
|
||||
* @param string $restPath
|
||||
* @param array $params
|
||||
* @return string $requestUrl
|
||||
*/
|
||||
public function createRequestUri($restPath, $params)
|
||||
{
|
||||
// Override the default servicePath address if the $restPath use a /
|
||||
if ('/' == \substr($restPath, 0, 1)) {
|
||||
$requestUrl = \substr($restPath, 1);
|
||||
} else {
|
||||
$requestUrl = $this->servicePath . $restPath;
|
||||
}
|
||||
// code for leading slash
|
||||
if ($this->rootUrl) {
|
||||
if ('/' !== \substr($this->rootUrl, -1) && '/' !== \substr($requestUrl, 0, 1)) {
|
||||
$requestUrl = '/' . $requestUrl;
|
||||
}
|
||||
$requestUrl = $this->rootUrl . $requestUrl;
|
||||
}
|
||||
$uriTemplateVars = array();
|
||||
$queryVars = array();
|
||||
foreach ($params as $paramName => $paramSpec) {
|
||||
if ($paramSpec['type'] == 'boolean') {
|
||||
$paramSpec['value'] = $paramSpec['value'] ? 'true' : 'false';
|
||||
}
|
||||
if ($paramSpec['location'] == 'path') {
|
||||
$uriTemplateVars[$paramName] = $paramSpec['value'];
|
||||
} else {
|
||||
if ($paramSpec['location'] == 'query') {
|
||||
if (\is_array($paramSpec['value'])) {
|
||||
foreach ($paramSpec['value'] as $value) {
|
||||
$queryVars[] = $paramName . '=' . \rawurlencode(\rawurldecode($value));
|
||||
}
|
||||
} else {
|
||||
$queryVars[] = $paramName . '=' . \rawurlencode(\rawurldecode($paramSpec['value']));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (\count($uriTemplateVars)) {
|
||||
$uriTemplateParser = new \WPMailSMTP\Vendor\Google_Utils_UriTemplate();
|
||||
$requestUrl = $uriTemplateParser->parse($requestUrl, $uriTemplateVars);
|
||||
}
|
||||
if (\count($queryVars)) {
|
||||
$requestUrl .= '?' . \implode('&', $queryVars);
|
||||
}
|
||||
return $requestUrl;
|
||||
}
|
||||
}
|
@ -0,0 +1,71 @@
|
||||
<?php
|
||||
|
||||
namespace WPMailSMTP\Vendor;
|
||||
|
||||
/*
|
||||
* Copyright 2020 Google LLC
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
|
||||
* use this file except in compliance with the License. You may obtain a copy of
|
||||
* the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations under
|
||||
* the License.
|
||||
*/
|
||||
use WPMailSMTP\Vendor\Composer\Script\Event;
|
||||
use WPMailSMTP\Vendor\Symfony\Component\Filesystem\Filesystem;
|
||||
use WPMailSMTP\Vendor\Symfony\Component\Finder\Finder;
|
||||
class Google_Task_Composer
|
||||
{
|
||||
/**
|
||||
* @param Event $event Composer event passed in for any script method
|
||||
* @param FilesystemInterface $filesystem Optional. Used for testing.
|
||||
*/
|
||||
public static function cleanup(\WPMailSMTP\Vendor\Composer\Script\Event $event, \WPMailSMTP\Vendor\Symfony\Component\Filesystem\Filesystem $filesystem = null)
|
||||
{
|
||||
$composer = $event->getComposer();
|
||||
$extra = $composer->getPackage()->getExtra();
|
||||
$servicesToKeep = isset($extra['google/apiclient-services']) ? $extra['google/apiclient-services'] : [];
|
||||
if ($servicesToKeep) {
|
||||
$serviceDir = \sprintf('%s/google/apiclient-services/src/Google/Service', $composer->getConfig()->get('vendor-dir'));
|
||||
self::verifyServicesToKeep($serviceDir, $servicesToKeep);
|
||||
$finder = self::getServicesToRemove($serviceDir, $servicesToKeep);
|
||||
$filesystem = $filesystem ?: new \WPMailSMTP\Vendor\Symfony\Component\Filesystem\Filesystem();
|
||||
if (0 !== ($count = \count($finder))) {
|
||||
$event->getIO()->write(\sprintf('Removing %s google services', $count));
|
||||
foreach ($finder as $file) {
|
||||
$realpath = $file->getRealPath();
|
||||
$filesystem->remove($realpath);
|
||||
$filesystem->remove($realpath . '.php');
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
/**
|
||||
* @throws InvalidArgumentException when the service doesn't exist
|
||||
*/
|
||||
private static function verifyServicesToKeep($serviceDir, array $servicesToKeep)
|
||||
{
|
||||
$finder = (new \WPMailSMTP\Vendor\Symfony\Component\Finder\Finder())->directories()->depth('== 0');
|
||||
foreach ($servicesToKeep as $service) {
|
||||
if (!\preg_match('/^[a-zA-Z0-9]*$/', $service)) {
|
||||
throw new \InvalidArgumentException(\sprintf('Invalid Google service name "%s"', $service));
|
||||
}
|
||||
try {
|
||||
$finder->in($serviceDir . '/' . $service);
|
||||
} catch (\InvalidArgumentException $e) {
|
||||
throw new \InvalidArgumentException(\sprintf('Google service "%s" does not exist or was removed previously', $service));
|
||||
}
|
||||
}
|
||||
}
|
||||
private static function getServicesToRemove($serviceDir, array $servicesToKeep)
|
||||
{
|
||||
// find all files in the current directory
|
||||
return (new \WPMailSMTP\Vendor\Symfony\Component\Finder\Finder())->directories()->depth('== 0')->in($serviceDir)->exclude($servicesToKeep);
|
||||
}
|
||||
}
|
@ -0,0 +1,22 @@
|
||||
<?php
|
||||
|
||||
namespace WPMailSMTP\Vendor;
|
||||
|
||||
/*
|
||||
* Copyright 2014 Google Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
class Google_Task_Exception extends \WPMailSMTP\Vendor\Google_Exception
|
||||
{
|
||||
}
|
@ -0,0 +1,26 @@
|
||||
<?php
|
||||
|
||||
namespace WPMailSMTP\Vendor;
|
||||
|
||||
/*
|
||||
* Copyright 2014 Google Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
/**
|
||||
* Interface for checking how many times a given task can be retried following
|
||||
* a failure.
|
||||
*/
|
||||
interface Google_Task_Retryable
|
||||
{
|
||||
}
|
@ -0,0 +1,230 @@
|
||||
<?php
|
||||
|
||||
namespace WPMailSMTP\Vendor;
|
||||
|
||||
/*
|
||||
* Copyright 2014 Google Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
/**
|
||||
* A task runner with exponential backoff support.
|
||||
*
|
||||
* @see https://developers.google.com/drive/web/handle-errors#implementing_exponential_backoff
|
||||
*/
|
||||
class Google_Task_Runner
|
||||
{
|
||||
const TASK_RETRY_NEVER = 0;
|
||||
const TASK_RETRY_ONCE = 1;
|
||||
const TASK_RETRY_ALWAYS = -1;
|
||||
/**
|
||||
* @var integer $maxDelay The max time (in seconds) to wait before a retry.
|
||||
*/
|
||||
private $maxDelay = 60;
|
||||
/**
|
||||
* @var integer $delay The previous delay from which the next is calculated.
|
||||
*/
|
||||
private $delay = 1;
|
||||
/**
|
||||
* @var integer $factor The base number for the exponential back off.
|
||||
*/
|
||||
private $factor = 2;
|
||||
/**
|
||||
* @var float $jitter A random number between -$jitter and $jitter will be
|
||||
* added to $factor on each iteration to allow for a better distribution of
|
||||
* retries.
|
||||
*/
|
||||
private $jitter = 0.5;
|
||||
/**
|
||||
* @var integer $attempts The number of attempts that have been tried so far.
|
||||
*/
|
||||
private $attempts = 0;
|
||||
/**
|
||||
* @var integer $maxAttempts The max number of attempts allowed.
|
||||
*/
|
||||
private $maxAttempts = 1;
|
||||
/**
|
||||
* @var callable $action The task to run and possibly retry.
|
||||
*/
|
||||
private $action;
|
||||
/**
|
||||
* @var array $arguments The task arguments.
|
||||
*/
|
||||
private $arguments;
|
||||
/**
|
||||
* @var array $retryMap Map of errors with retry counts.
|
||||
*/
|
||||
protected $retryMap = [
|
||||
'500' => self::TASK_RETRY_ALWAYS,
|
||||
'503' => self::TASK_RETRY_ALWAYS,
|
||||
'rateLimitExceeded' => self::TASK_RETRY_ALWAYS,
|
||||
'userRateLimitExceeded' => self::TASK_RETRY_ALWAYS,
|
||||
6 => self::TASK_RETRY_ALWAYS,
|
||||
// CURLE_COULDNT_RESOLVE_HOST
|
||||
7 => self::TASK_RETRY_ALWAYS,
|
||||
// CURLE_COULDNT_CONNECT
|
||||
28 => self::TASK_RETRY_ALWAYS,
|
||||
// CURLE_OPERATION_TIMEOUTED
|
||||
35 => self::TASK_RETRY_ALWAYS,
|
||||
// CURLE_SSL_CONNECT_ERROR
|
||||
52 => self::TASK_RETRY_ALWAYS,
|
||||
];
|
||||
/**
|
||||
* Creates a new task runner with exponential backoff support.
|
||||
*
|
||||
* @param array $config The task runner config
|
||||
* @param string $name The name of the current task (used for logging)
|
||||
* @param callable $action The task to run and possibly retry
|
||||
* @param array $arguments The task arguments
|
||||
* @throws Google_Task_Exception when misconfigured
|
||||
*/
|
||||
public function __construct($config, $name, $action, array $arguments = array())
|
||||
{
|
||||
if (isset($config['initial_delay'])) {
|
||||
if ($config['initial_delay'] < 0) {
|
||||
throw new \WPMailSMTP\Vendor\Google_Task_Exception('Task configuration `initial_delay` must not be negative.');
|
||||
}
|
||||
$this->delay = $config['initial_delay'];
|
||||
}
|
||||
if (isset($config['max_delay'])) {
|
||||
if ($config['max_delay'] <= 0) {
|
||||
throw new \WPMailSMTP\Vendor\Google_Task_Exception('Task configuration `max_delay` must be greater than 0.');
|
||||
}
|
||||
$this->maxDelay = $config['max_delay'];
|
||||
}
|
||||
if (isset($config['factor'])) {
|
||||
if ($config['factor'] <= 0) {
|
||||
throw new \WPMailSMTP\Vendor\Google_Task_Exception('Task configuration `factor` must be greater than 0.');
|
||||
}
|
||||
$this->factor = $config['factor'];
|
||||
}
|
||||
if (isset($config['jitter'])) {
|
||||
if ($config['jitter'] <= 0) {
|
||||
throw new \WPMailSMTP\Vendor\Google_Task_Exception('Task configuration `jitter` must be greater than 0.');
|
||||
}
|
||||
$this->jitter = $config['jitter'];
|
||||
}
|
||||
if (isset($config['retries'])) {
|
||||
if ($config['retries'] < 0) {
|
||||
throw new \WPMailSMTP\Vendor\Google_Task_Exception('Task configuration `retries` must not be negative.');
|
||||
}
|
||||
$this->maxAttempts += $config['retries'];
|
||||
}
|
||||
if (!\is_callable($action)) {
|
||||
throw new \WPMailSMTP\Vendor\Google_Task_Exception('Task argument `$action` must be a valid callable.');
|
||||
}
|
||||
$this->action = $action;
|
||||
$this->arguments = $arguments;
|
||||
}
|
||||
/**
|
||||
* Checks if a retry can be attempted.
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public function canAttempt()
|
||||
{
|
||||
return $this->attempts < $this->maxAttempts;
|
||||
}
|
||||
/**
|
||||
* Runs the task and (if applicable) automatically retries when errors occur.
|
||||
*
|
||||
* @return mixed
|
||||
* @throws Google_Task_Retryable on failure when no retries are available.
|
||||
*/
|
||||
public function run()
|
||||
{
|
||||
while ($this->attempt()) {
|
||||
try {
|
||||
return \call_user_func_array($this->action, $this->arguments);
|
||||
} catch (\WPMailSMTP\Vendor\Google_Service_Exception $exception) {
|
||||
$allowedRetries = $this->allowedRetries($exception->getCode(), $exception->getErrors());
|
||||
if (!$this->canAttempt() || !$allowedRetries) {
|
||||
throw $exception;
|
||||
}
|
||||
if ($allowedRetries > 0) {
|
||||
$this->maxAttempts = \min($this->maxAttempts, $this->attempts + $allowedRetries);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Runs a task once, if possible. This is useful for bypassing the `run()`
|
||||
* loop.
|
||||
*
|
||||
* NOTE: If this is not the first attempt, this function will sleep in
|
||||
* accordance to the backoff configurations before running the task.
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public function attempt()
|
||||
{
|
||||
if (!$this->canAttempt()) {
|
||||
return \false;
|
||||
}
|
||||
if ($this->attempts > 0) {
|
||||
$this->backOff();
|
||||
}
|
||||
$this->attempts++;
|
||||
return \true;
|
||||
}
|
||||
/**
|
||||
* Sleeps in accordance to the backoff configurations.
|
||||
*/
|
||||
private function backOff()
|
||||
{
|
||||
$delay = $this->getDelay();
|
||||
\usleep($delay * 1000000);
|
||||
}
|
||||
/**
|
||||
* Gets the delay (in seconds) for the current backoff period.
|
||||
*
|
||||
* @return float
|
||||
*/
|
||||
private function getDelay()
|
||||
{
|
||||
$jitter = $this->getJitter();
|
||||
$factor = $this->attempts > 1 ? $this->factor + $jitter : 1 + \abs($jitter);
|
||||
return $this->delay = \min($this->maxDelay, $this->delay * $factor);
|
||||
}
|
||||
/**
|
||||
* Gets the current jitter (random number between -$this->jitter and
|
||||
* $this->jitter).
|
||||
*
|
||||
* @return float
|
||||
*/
|
||||
private function getJitter()
|
||||
{
|
||||
return $this->jitter * 2 * \mt_rand() / \mt_getrandmax() - $this->jitter;
|
||||
}
|
||||
/**
|
||||
* Gets the number of times the associated task can be retried.
|
||||
*
|
||||
* NOTE: -1 is returned if the task can be retried indefinitely
|
||||
*
|
||||
* @return integer
|
||||
*/
|
||||
public function allowedRetries($code, $errors = array())
|
||||
{
|
||||
if (isset($this->retryMap[$code])) {
|
||||
return $this->retryMap[$code];
|
||||
}
|
||||
if (!empty($errors) && isset($errors[0]['reason'], $this->retryMap[$errors[0]['reason']])) {
|
||||
return $this->retryMap[$errors[0]['reason']];
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
public function setRetryMap($retryMap)
|
||||
{
|
||||
$this->retryMap = $retryMap;
|
||||
}
|
||||
}
|
@ -0,0 +1,266 @@
|
||||
<?php
|
||||
|
||||
namespace WPMailSMTP\Vendor;
|
||||
|
||||
/*
|
||||
* Copyright 2013 Google Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
/**
|
||||
* Implementation of levels 1-3 of the URI Template spec.
|
||||
* @see http://tools.ietf.org/html/rfc6570
|
||||
*/
|
||||
class Google_Utils_UriTemplate
|
||||
{
|
||||
const TYPE_MAP = "1";
|
||||
const TYPE_LIST = "2";
|
||||
const TYPE_SCALAR = "4";
|
||||
/**
|
||||
* @var $operators array
|
||||
* These are valid at the start of a template block to
|
||||
* modify the way in which the variables inside are
|
||||
* processed.
|
||||
*/
|
||||
private $operators = array("+" => "reserved", "/" => "segments", "." => "dotprefix", "#" => "fragment", ";" => "semicolon", "?" => "form", "&" => "continuation");
|
||||
/**
|
||||
* @var reserved array
|
||||
* These are the characters which should not be URL encoded in reserved
|
||||
* strings.
|
||||
*/
|
||||
private $reserved = array("=", ",", "!", "@", "|", ":", "/", "?", "#", "[", "]", '$', "&", "'", "(", ")", "*", "+", ";");
|
||||
private $reservedEncoded = array("%3D", "%2C", "%21", "%40", "%7C", "%3A", "%2F", "%3F", "%23", "%5B", "%5D", "%24", "%26", "%27", "%28", "%29", "%2A", "%2B", "%3B");
|
||||
public function parse($string, array $parameters)
|
||||
{
|
||||
return $this->resolveNextSection($string, $parameters);
|
||||
}
|
||||
/**
|
||||
* This function finds the first matching {...} block and
|
||||
* executes the replacement. It then calls itself to find
|
||||
* subsequent blocks, if any.
|
||||
*/
|
||||
private function resolveNextSection($string, $parameters)
|
||||
{
|
||||
$start = \strpos($string, "{");
|
||||
if ($start === \false) {
|
||||
return $string;
|
||||
}
|
||||
$end = \strpos($string, "}");
|
||||
if ($end === \false) {
|
||||
return $string;
|
||||
}
|
||||
$string = $this->replace($string, $start, $end, $parameters);
|
||||
return $this->resolveNextSection($string, $parameters);
|
||||
}
|
||||
private function replace($string, $start, $end, $parameters)
|
||||
{
|
||||
// We know a data block will have {} round it, so we can strip that.
|
||||
$data = \substr($string, $start + 1, $end - $start - 1);
|
||||
// If the first character is one of the reserved operators, it effects
|
||||
// the processing of the stream.
|
||||
if (isset($this->operators[$data[0]])) {
|
||||
$op = $this->operators[$data[0]];
|
||||
$data = \substr($data, 1);
|
||||
$prefix = "";
|
||||
$prefix_on_missing = \false;
|
||||
switch ($op) {
|
||||
case "reserved":
|
||||
// Reserved means certain characters should not be URL encoded
|
||||
$data = $this->replaceVars($data, $parameters, ",", null, \true);
|
||||
break;
|
||||
case "fragment":
|
||||
// Comma separated with fragment prefix. Bare values only.
|
||||
$prefix = "#";
|
||||
$prefix_on_missing = \true;
|
||||
$data = $this->replaceVars($data, $parameters, ",", null, \true);
|
||||
break;
|
||||
case "segments":
|
||||
// Slash separated data. Bare values only.
|
||||
$prefix = "/";
|
||||
$data = $this->replaceVars($data, $parameters, "/");
|
||||
break;
|
||||
case "dotprefix":
|
||||
// Dot separated data. Bare values only.
|
||||
$prefix = ".";
|
||||
$prefix_on_missing = \true;
|
||||
$data = $this->replaceVars($data, $parameters, ".");
|
||||
break;
|
||||
case "semicolon":
|
||||
// Semicolon prefixed and separated. Uses the key name
|
||||
$prefix = ";";
|
||||
$data = $this->replaceVars($data, $parameters, ";", "=", \false, \true, \false);
|
||||
break;
|
||||
case "form":
|
||||
// Standard URL format. Uses the key name
|
||||
$prefix = "?";
|
||||
$data = $this->replaceVars($data, $parameters, "&", "=");
|
||||
break;
|
||||
case "continuation":
|
||||
// Standard URL, but with leading ampersand. Uses key name.
|
||||
$prefix = "&";
|
||||
$data = $this->replaceVars($data, $parameters, "&", "=");
|
||||
break;
|
||||
}
|
||||
// Add the initial prefix character if data is valid.
|
||||
if ($data || $data !== \false && $prefix_on_missing) {
|
||||
$data = $prefix . $data;
|
||||
}
|
||||
} else {
|
||||
// If no operator we replace with the defaults.
|
||||
$data = $this->replaceVars($data, $parameters);
|
||||
}
|
||||
// This is chops out the {...} and replaces with the new section.
|
||||
return \substr($string, 0, $start) . $data . \substr($string, $end + 1);
|
||||
}
|
||||
private function replaceVars($section, $parameters, $sep = ",", $combine = null, $reserved = \false, $tag_empty = \false, $combine_on_empty = \true)
|
||||
{
|
||||
if (\strpos($section, ",") === \false) {
|
||||
// If we only have a single value, we can immediately process.
|
||||
return $this->combine($section, $parameters, $sep, $combine, $reserved, $tag_empty, $combine_on_empty);
|
||||
} else {
|
||||
// If we have multiple values, we need to split and loop over them.
|
||||
// Each is treated individually, then glued together with the
|
||||
// separator character.
|
||||
$vars = \explode(",", $section);
|
||||
return $this->combineList(
|
||||
$vars,
|
||||
$sep,
|
||||
$parameters,
|
||||
$combine,
|
||||
$reserved,
|
||||
\false,
|
||||
// Never emit empty strings in multi-param replacements
|
||||
$combine_on_empty
|
||||
);
|
||||
}
|
||||
}
|
||||
public function combine($key, $parameters, $sep, $combine, $reserved, $tag_empty, $combine_on_empty)
|
||||
{
|
||||
$length = \false;
|
||||
$explode = \false;
|
||||
$skip_final_combine = \false;
|
||||
$value = \false;
|
||||
// Check for length restriction.
|
||||
if (\strpos($key, ":") !== \false) {
|
||||
list($key, $length) = \explode(":", $key);
|
||||
}
|
||||
// Check for explode parameter.
|
||||
if ($key[\strlen($key) - 1] == "*") {
|
||||
$explode = \true;
|
||||
$key = \substr($key, 0, -1);
|
||||
$skip_final_combine = \true;
|
||||
}
|
||||
// Define the list separator.
|
||||
$list_sep = $explode ? $sep : ",";
|
||||
if (isset($parameters[$key])) {
|
||||
$data_type = $this->getDataType($parameters[$key]);
|
||||
switch ($data_type) {
|
||||
case self::TYPE_SCALAR:
|
||||
$value = $this->getValue($parameters[$key], $length);
|
||||
break;
|
||||
case self::TYPE_LIST:
|
||||
$values = array();
|
||||
foreach ($parameters[$key] as $pkey => $pvalue) {
|
||||
$pvalue = $this->getValue($pvalue, $length);
|
||||
if ($combine && $explode) {
|
||||
$values[$pkey] = $key . $combine . $pvalue;
|
||||
} else {
|
||||
$values[$pkey] = $pvalue;
|
||||
}
|
||||
}
|
||||
$value = \implode($list_sep, $values);
|
||||
if ($value == '') {
|
||||
return '';
|
||||
}
|
||||
break;
|
||||
case self::TYPE_MAP:
|
||||
$values = array();
|
||||
foreach ($parameters[$key] as $pkey => $pvalue) {
|
||||
$pvalue = $this->getValue($pvalue, $length);
|
||||
if ($explode) {
|
||||
$pkey = $this->getValue($pkey, $length);
|
||||
$values[] = $pkey . "=" . $pvalue;
|
||||
// Explode triggers = combine.
|
||||
} else {
|
||||
$values[] = $pkey;
|
||||
$values[] = $pvalue;
|
||||
}
|
||||
}
|
||||
$value = \implode($list_sep, $values);
|
||||
if ($value == '') {
|
||||
return \false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
if ($tag_empty) {
|
||||
// If we are just indicating empty values with their key name, return that.
|
||||
return $key;
|
||||
} else {
|
||||
// Otherwise we can skip this variable due to not being defined.
|
||||
return \false;
|
||||
}
|
||||
}
|
||||
if ($reserved) {
|
||||
$value = \str_replace($this->reservedEncoded, $this->reserved, $value);
|
||||
}
|
||||
// If we do not need to include the key name, we just return the raw
|
||||
// value.
|
||||
if (!$combine || $skip_final_combine) {
|
||||
return $value;
|
||||
}
|
||||
// Else we combine the key name: foo=bar, if value is not the empty string.
|
||||
return $key . ($value != '' || $combine_on_empty ? $combine . $value : '');
|
||||
}
|
||||
/**
|
||||
* Return the type of a passed in value
|
||||
*/
|
||||
private function getDataType($data)
|
||||
{
|
||||
if (\is_array($data)) {
|
||||
\reset($data);
|
||||
if (\key($data) !== 0) {
|
||||
return self::TYPE_MAP;
|
||||
}
|
||||
return self::TYPE_LIST;
|
||||
}
|
||||
return self::TYPE_SCALAR;
|
||||
}
|
||||
/**
|
||||
* Utility function that merges multiple combine calls
|
||||
* for multi-key templates.
|
||||
*/
|
||||
private function combineList($vars, $sep, $parameters, $combine, $reserved, $tag_empty, $combine_on_empty)
|
||||
{
|
||||
$ret = array();
|
||||
foreach ($vars as $var) {
|
||||
$response = $this->combine($var, $parameters, $sep, $combine, $reserved, $tag_empty, $combine_on_empty);
|
||||
if ($response === \false) {
|
||||
continue;
|
||||
}
|
||||
$ret[] = $response;
|
||||
}
|
||||
return \implode($sep, $ret);
|
||||
}
|
||||
/**
|
||||
* Utility function to encode and trim values
|
||||
*/
|
||||
private function getValue($value, $length)
|
||||
{
|
||||
if ($length) {
|
||||
$value = \substr($value, 0, $length);
|
||||
}
|
||||
$value = \rawurlencode($value);
|
||||
return $value;
|
||||
}
|
||||
}
|
@ -0,0 +1,19 @@
|
||||
<?php
|
||||
|
||||
namespace WPMailSMTP\Vendor;
|
||||
|
||||
/**
|
||||
* THIS FILE IS FOR BACKWARDS COMPATIBLITY ONLY
|
||||
*
|
||||
* If you were not already including this file in your project, please ignore it
|
||||
*/
|
||||
$file = __DIR__ . '/../../vendor/autoload.php';
|
||||
if (!\file_exists($file)) {
|
||||
$exception = 'This library must be installed via composer or by downloading the full package.';
|
||||
$exception .= ' See the instructions at https://github.com/google/google-api-php-client#installation.';
|
||||
throw new \Exception($exception);
|
||||
}
|
||||
$error = 'google-api-php-client\'s autoloader was moved to vendor/autoload.php in 2.0.0. This ';
|
||||
$error .= 'redirect will be removed in 2.1. Please adjust your code to use the new location.';
|
||||
\trigger_error($error, \E_USER_DEPRECATED);
|
||||
require_once $file;
|
Reference in New Issue
Block a user