Skip to content

Commit

Permalink
Merge branch 'release/1.12.0'
Browse files Browse the repository at this point in the history
Release 1.12.0
  • Loading branch information
nickvandegroes committed Sep 10, 2019
2 parents be64573 + 147762d commit cfde75f
Show file tree
Hide file tree
Showing 130 changed files with 3,004 additions and 364 deletions.
20 changes: 20 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,25 @@
# Change Log

## [Unreleased](https://github.com/bunq/sdk_php/tree/HEAD)

[Full Changelog](https://github.com/bunq/sdk_php/compare/1.10.16...HEAD)

**Closed issues:**

- Fout! Use of undefined constant CURLOPT\_PINNEDPUBLICKEY - assumed 'CURLOPT\_PINNEDPUBLICKEY' \(this will throw an Error in a future version of PHP\) [\#178](https://github.com/bunq/sdk_php/issues/178)
- NotificationFilterUrlMonetaryAccount::create fails [\#177](https://github.com/bunq/sdk_php/issues/177)
- TransferwiseTransfer property on EventObject is not populated [\#176](https://github.com/bunq/sdk_php/issues/176)
- Bad schedule payment update response\(sdk\_php\) [\#173](https://github.com/bunq/sdk_php/issues/173)
- Allow access to `merchant\_category\_code` in the `counterparty\_alias` [\#171](https://github.com/bunq/sdk_php/issues/171)
- Not receive schedule payment status \(sdk\_php\) [\#170](https://github.com/bunq/sdk_php/issues/170)

**Merged pull requests:**

- Fix NotificationFilter, Model issues and implement PSD2 [\#179](https://github.com/bunq/sdk_php/pull/179) ([NickvandeGroes](https://github.com/NickvandeGroes))

## [1.10.16](https://github.com/bunq/sdk_php/tree/1.10.16) (2019-06-15)
[Full Changelog](https://github.com/bunq/sdk_php/compare/1.10.2...1.10.16)

## [1.10.2](https://github.com/bunq/sdk_php/tree/1.10.2) (2019-05-15)
[Full Changelog](https://github.com/bunq/sdk_php/compare/1.10.1...1.10.2)

Expand Down
36 changes: 36 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,30 @@ BunqContext::loadApiContext($apiContext);

**Tip:** both saving and restoring the context can be done without any arguments. In this case the context will be saved to/restored from the `bunq.conf` file in the same folder with your script.

##### PSD2
It is possible to create an ApiContext as PSD2 Service Provider. Although this might seem a complex task, we wrote some helper implementations to get you started.
You need to create a certificate and private key to get you started. Our sandbox environment currently accepts all certificates, if these criteria are met:
- Up to 64 characters
- PISP and/or AISP used in the end.

Make sure you have your unique eIDAS certificate number and certificates ready when you want to perform these tasks on our production environment.

Creating a PSD2 context is very easy:
```php
$apiContext = ApiContext::createForPsd2(
BunqEnumApiEnvironmentType::SANDBOX(), // Could be PRODUCTION as well.
SecurityUtil::getCertificateFromFile($pathToCertificate),
SecurityUtil::getPrivateKeyFromFile($pathToKey),
[
SecurityUtil::getCertificateFromFile($pathToCertificateInChain), // Could be one file containing chain, or multiple certificate files in array.
],
$description
)
```

This context can be saved the same way as a normal ApiContext. After creating this context, create an OAuth client to get your users to grant you access.
For a more detailed example, check the [tinker_php](https://github.com/bunq/tinker_php/) repository.

##### Proxy
You can use a proxy with the bunq PHP SDK. This option must be a string. This proxy will be used for all requests done with
the context for which it was provided. You will be prompted to provide a proxy URL when using the interactive installation script.
Expand Down Expand Up @@ -127,6 +151,18 @@ Payment::create(
##### Example
See [`tinker/BunqLib`](https://github.com/bunq/tinker_php/blob/05a38a2660e6f6db1f7efc9b915f0131c172c230/src/BunqLib.php#L240-L245)

##### NotificationFilters / Callbacks
**Note!** Due to an in internal change in the way we handle `NotificationFilters` (Callbacks), you should not use the default classes included in this SDK.
Please make sure you make use of the associated `Internal`-classes. For example when you need `NotificationFilterUrlUser`, make use of `NotificationFilterUrlUserInternal`.
You can use every method of these classes, except for the `create()` method. **Always use `createWithListResponse()` instead.**

##### Example
```
NotificationFilterPushUserInternal::createWithListResponse(...)
NotificationFilterUrlUserInternal::createWithListResponse(...)
NotificationFilterUrlMonetaryAccountInternal::createWithListResponse(...)
```

#### Reading objects
To use the read method you must pass the identifier of the object to read (ID or UUID) except for the endpoints `User`, `UserPerson`, `UserCompany` and `MonetaryAccount`. The SDK will use the default IDs when none are passed. For all other endpoints you must pass the identifier.

Expand Down
2 changes: 1 addition & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@
"phpstan/phpstan": "^0.8",
"phpunit/phpunit": "^6.0.13",
"sebastian/phpcpd": "^3.0",
"sensiolabs/security-checker": "^4.1"
"sensiolabs/security-checker": "^5.0"
},
"bin": [
"bin/bunq-install"
Expand Down
2 changes: 1 addition & 1 deletion grumphp.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ parameters:
ignore_unstaged_changes: false
process_async_limit: 10
process_async_wait: 1000
process_timeout: 120
process_timeout: 300
stop_on_failure: true
ascii:
failed: ~
Expand Down
2 changes: 0 additions & 2 deletions phpunit.xml
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,6 @@
<testsuite name="ParaTest Fixtures">
<directory>./tests/</directory>
</testsuite>
</testsuites>
<testsuites>
<testsuite name="Test Suite">
<directory>./tests</directory>
</testsuite>
Expand Down
74 changes: 73 additions & 1 deletion src/Context/ApiContext.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,18 @@
use bunq\Exception\BunqException;
use bunq\Model\Core\DeviceServerInternal;
use bunq\Model\Core\Installation;
use bunq\Model\Core\PaymentServiceProviderCredentialInternal;
use bunq\Model\Core\SandboxUserInternal;
use bunq\Model\Core\SessionServer;
use bunq\Model\Core\Token;
use bunq\Model\Generated\Endpoint\Session;
use bunq\Model\Generated\Object\Certificate;
use bunq\Security\KeyPair;
use bunq\Security\PrivateKey;
use bunq\Util\BunqEnumApiEnvironmentType;
use bunq\Util\FileUtil;
use bunq\Util\InstallationUtil;
use bunq\Util\SecurityUtil;
use GuzzleHttp\Psr7\Uri;

/**
Expand Down Expand Up @@ -117,6 +121,46 @@ public static function create(
return $apiContext;
}

/**
* @param BunqEnumApiEnvironmentType $environmentType
* @param Certificate $publicCertificate
* @param PrivateKey $privateKey
* @param Certificate[] $allChainCertificate
* @param string $description
* @param string[] $allPermittedIp
* @param string|null $proxyUrl
*
* @return ApiContext
*/
public static function createForPsd2(
BunqEnumApiEnvironmentType $environmentType,
Certificate $publicCertificate,
PrivateKey $privateKey,
array $allChainCertificate,
string $description,
array $allPermittedIp = [],
string $proxyUrl = null
): ApiContext {
InstallationUtil::assertDeviceDescriptionIsValid($description);
InstallationUtil::assertAllIpIsValid($allPermittedIp);

$apiContext = new static();
$apiContext->environmentType = $environmentType;
$apiContext->proxyUrl = $proxyUrl;

$apiContext->initializeInstallationContext();
$apiContext->initializePsd2Credential(
$publicCertificate,
$privateKey,
$allChainCertificate
);

$apiContext->registerDevice($description, $allPermittedIp);
$apiContext->initializeSessionContext();

return $apiContext;
}

/**
*/
private function createSandboxUser()
Expand Down Expand Up @@ -152,6 +196,34 @@ private function initializeInstallationContext()
);
}

/**
* @param Certificate $publicCertificate
* @param PrivateKey $privateKey
* @param Certificate[] $allChainCertificate
*/
private function initializePsd2Credential(
Certificate $publicCertificate,
PrivateKey $privateKey,
array $allChainCertificate
) {
$sessionToken = $this->installationContext->getInstallationToken();
$clientKeyPair = $this->installationContext->getKeyPairClient();

$stringToSign = SecurityUtil::getPublicKeyFormattedString(
$clientKeyPair->getPublicKey()
) . $sessionToken->getToken();

$keySignature = $privateKey->sign($stringToSign);
$paymentProviderResponse = PaymentServiceProviderCredentialInternal::createWithApiContext(
$publicCertificate->getCertificate(),
SecurityUtil::getCertificateChainString($allChainCertificate),
$keySignature,
$this
);

$this->apiKey = $paymentProviderResponse->getValue()->getTokenValue();
}

/**
* @param string $description
* @param string[] $permittedIps
Expand Down Expand Up @@ -183,7 +255,7 @@ private function initializeSessionContext()
*/
public static function restore(string $fileName = self::FILENAME_CONFIG_DEFAULT): ApiContext
{
$contextJsonString = self::getContextJsonString($fileName);
$contextJsonString = static::getContextJsonString($fileName);

return static::fromJson($contextJsonString);
}
Expand Down
2 changes: 2 additions & 0 deletions src/Context/BunqContext.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@

use bunq\Exception\BunqException;

/**
*/
class BunqContext
{
/**
Expand Down
15 changes: 14 additions & 1 deletion src/Context/UserContext.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,15 @@

use bunq\Exception\BunqException;
use bunq\Model\Core\BunqModel;
use bunq\Model\Core\SessionServer;
use bunq\Model\Generated\Endpoint\MonetaryAccountBank;
use bunq\Model\Generated\Endpoint\User;
use bunq\Model\Generated\Endpoint\UserApiKey;
use bunq\Model\Generated\Endpoint\UserCompany;
use bunq\Model\Generated\Endpoint\UserPaymentServiceProvider;
use bunq\Model\Generated\Endpoint\UserPerson;

/**
*/
class UserContext
{
/**
Expand Down Expand Up @@ -46,6 +48,11 @@ class UserContext
*/
protected $userApiKey;

/**
* @var UserPaymentServiceProvider
*/
protected $userPaymentServiceProvider;

/**
* @var MonetaryAccountBank
*/
Expand Down Expand Up @@ -85,6 +92,8 @@ private function setUser($user)
$this->userCompany = $user;
} elseif ($user instanceof UserApiKey) {
$this->userApiKey = $user;
} elseif ($user instanceof UserPaymentServiceProvider) {
$this->userPaymentServiceProvider = $user;
} else {
throw new BunqException(vsprintf(self::ERROR_UNEXPECTED_USER_INSTANCE, [get_class($user)]));
}
Expand All @@ -95,6 +104,10 @@ private function setUser($user)
*/
public function initMainMonetaryAccount()
{
if (!is_null($this->userPaymentServiceProvider)) {
return;
}

$allMonetaryAccount = MonetaryAccountBank::listing()->getValue();

foreach ($allMonetaryAccount as $account) {
Expand Down
1 change: 0 additions & 1 deletion src/Exception/BadRequestException.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,4 @@
*/
class BadRequestException extends ApiException
{

}
1 change: 0 additions & 1 deletion src/Exception/ForbiddenException.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,4 @@
*/
class ForbiddenException extends ApiException
{

}
1 change: 0 additions & 1 deletion src/Exception/MethodNotAllowedException.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,4 @@
*/
class MethodNotAllowedException extends ApiException
{

}
1 change: 0 additions & 1 deletion src/Exception/NotFoundException.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,4 @@
*/
class NotFoundException extends ApiException
{

}
1 change: 0 additions & 1 deletion src/Exception/PleaseContactBunqException.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,4 @@
*/
class PleaseContactBunqException extends ApiException
{

}
1 change: 0 additions & 1 deletion src/Exception/TooManyRequestsException.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,4 @@
*/
class TooManyRequestsException extends ApiException
{

}
1 change: 0 additions & 1 deletion src/Exception/UnauthorizedException.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,4 @@
*/
class UnauthorizedException extends ApiException
{

}
1 change: 0 additions & 1 deletion src/Exception/UnknownApiErrorException.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,4 @@
*/
class UnknownApiErrorException extends ApiException
{

}
25 changes: 24 additions & 1 deletion src/Http/ApiClient.php
Original file line number Diff line number Diff line change
Expand Up @@ -39,11 +39,13 @@ class ApiClient
self::DEVICE_SERVER_URL => true,
self::INSTALLATION_URL => true,
self::SESSION_SERVER_URL => true,
self::PAYMENT_SERVICE_PROVIDER_CREDENTIAL_URL => true,
];
const SANDBOX_USER_URL = 'sandbox-user';
const DEVICE_SERVER_URL = 'device-server';
const INSTALLATION_URL = 'installation';
const SESSION_SERVER_URL = 'session-server';
const PAYMENT_SERVICE_PROVIDER_CREDENTIAL_URL = 'payment-service-provider-credential';

/**
* Public key locations.
Expand Down Expand Up @@ -85,7 +87,7 @@ class ApiClient
/**
* User agent constants.
*/
const HEADER_USER_AGENT_BUNQ_SDK_DEFAULT = 'bunq-sdk-php/1.10.16';
const HEADER_USER_AGENT_BUNQ_SDK_DEFAULT = 'bunq-sdk-php/1.12.0';

/**
* Binary request constants.
Expand Down Expand Up @@ -145,6 +147,12 @@ class ApiClient
const REGEX_CURL_ERROR_CODE = '/(cURL error )(?P<errorCode>\d+)/';
const REGEX_NAMED_GOUP_ERROR_CODE = 'errorCode';

/**
* Curl option constants.
*/
const CURL_FIELD_KEY_PINNING = 'CURLOPT_PINNEDPUBLICKEY';
const CURL_VALUE_KEY_PINNING = 10230;

/**
* @var Client
*/
Expand Down Expand Up @@ -253,6 +261,7 @@ private function initialize(string $uri)
private function initializeHttpClient()
{
if (is_null($this->httpClient)) {
$this->initializeAllDefinitionIfNeeded();
$middleware = $this->determineMiddleware();

$this->httpClient = new Client(
Expand All @@ -272,6 +281,20 @@ private function initializeHttpClient()
}
}

/**
* Initialize definitions if needed.
*
* Defines CURLOPT_PINNEDPUBLICKEY for PHP <7.0.7.
*/
private function initializeAllDefinitionIfNeeded()
{
if (defined(self::CURL_FIELD_KEY_PINNING)) {
// Do nothing.
} else {
define(self::CURL_FIELD_KEY_PINNING, self::CURL_VALUE_KEY_PINNING);
}
}

/**
* @return HandlerStack
*/
Expand Down
1 change: 0 additions & 1 deletion src/Model/Core/AnchorObjectInterface.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,4 @@
*/
interface AnchorObjectInterface
{

}
Loading

0 comments on commit cfde75f

Please sign in to comment.