mirror of
https://github.com/bitinflow/accounts.git
synced 2026-03-14 22:15:52 +00:00
Compare commits
84 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 2ac7a361fb | |||
|
1b8aef1f6f
|
|||
|
f17519743e
|
|||
|
aea65e0894
|
|||
| ce36527fe0 | |||
| c0dee13277 | |||
| 4fae63297c | |||
| f8439f81e9 | |||
| 95b8559b01 | |||
| 441900e1d3 | |||
|
|
f5e9b0e5e6 | ||
|
|
a2405875ad | ||
|
|
7ba3cdffb0 | ||
| 00f30e097d | |||
| 99a9331b6e | |||
| 5caef21b01 | |||
| 8e88d12d88 | |||
| d44400fcfa | |||
| e4378d67c1 | |||
| a205365bf5 | |||
| c7eadf30ee | |||
| 49bbefae64 | |||
| 6290f6a419 | |||
| ac734a04c4 | |||
| 32b7437239 | |||
| 120bd61ae5 | |||
| 78f570f404 | |||
| 7dad10bd47 | |||
| 87fc416b44 | |||
| d03a95b552 | |||
| 1476446765 | |||
| 76243f0883 | |||
| 91bdad593f | |||
| 4fdbe165bc | |||
| f929f32887 | |||
| eb30953d8e | |||
| c6c815523c | |||
| f86a547ea1 | |||
| ac7ffab887 | |||
| db5685d612 | |||
| 3c46197a61 | |||
| a11436fbfe | |||
| c1bd13b449 | |||
| fc54c8b542 | |||
| 6fb7f0b38a | |||
|
e902a3a5b8
|
|||
|
377dc53037
|
|||
|
|
76edd961b7 | ||
|
|
8816ade239 | ||
|
032c771e49
|
|||
| b5b4f9cf5e | |||
| 4f3fa6d571 | |||
|
|
2df4501eae | ||
| 55c4276d9b | |||
|
|
baa45edb8a | ||
| 8f962d1e06 | |||
|
|
3760e312cd | ||
|
|
76b0569b0f | ||
|
|
e60c5a5cd3 | ||
|
|
7af00cb7ab | ||
|
|
3ba4805e3f | ||
|
|
80a6491058 | ||
|
|
14bf9d5480 | ||
|
|
32990da8a0 | ||
|
|
7805933b10 | ||
|
|
e006cd64b5 | ||
|
|
7edff12765 | ||
|
|
94a6a91e84 | ||
|
|
da00b4a97c | ||
|
|
26543d806c | ||
|
|
2c82e61790 | ||
|
|
ca57ff1c65 | ||
|
|
9207f38f93 | ||
|
|
da904f31cb | ||
|
|
c182baab17 | ||
|
|
0e07c295e3 | ||
|
|
940617af2e | ||
|
|
f2d064caef | ||
|
|
29a46a9ef9 | ||
|
|
553167d108 | ||
|
|
918bcd4644 | ||
|
|
2bd19efb3c | ||
|
|
b5ad7786f2 | ||
|
|
203dc18766 |
1
.gitignore
vendored
1
.gitignore
vendored
@@ -1,3 +1,4 @@
|
|||||||
vendor
|
vendor
|
||||||
.phpunit.result.cache
|
.phpunit.result.cache
|
||||||
.idea
|
.idea
|
||||||
|
composer.lock
|
||||||
61
AUTH.md
Normal file
61
AUTH.md
Normal file
@@ -0,0 +1,61 @@
|
|||||||
|
# Implementing Auth
|
||||||
|
|
||||||
|
This method should typically be called in the `boot` method of your `AuthServiceProvider` class:
|
||||||
|
|
||||||
|
```php
|
||||||
|
use Bitinflow\Accounts\BitinflowAccounts;
|
||||||
|
use Bitinflow\Accounts\Providers\BitinflowAccountsSsoUserProvider;
|
||||||
|
use Illuminate\Http\Request;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Register any authentication / authorization services.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function boot()
|
||||||
|
{
|
||||||
|
Auth::provider('sso-users', function ($app, array $config) {
|
||||||
|
return new BitinflowAccountsSsoUserProvider(
|
||||||
|
$app->make(BitinflowAccounts::class),
|
||||||
|
$app->make(Request::class),
|
||||||
|
$config['model'],
|
||||||
|
$config['fields'] ?? [],
|
||||||
|
$config['access_token_field'] ?? null
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
reference the guard in the `guards` configuration of your `auth.php` configuration file:
|
||||||
|
|
||||||
|
```php
|
||||||
|
'guards' => [
|
||||||
|
'web' => [
|
||||||
|
'driver' => 'session',
|
||||||
|
'provider' => 'users',
|
||||||
|
],
|
||||||
|
|
||||||
|
'api' => [
|
||||||
|
'driver' => 'bitinflow-accounts',
|
||||||
|
'provider' => 'sso-users',
|
||||||
|
],
|
||||||
|
],
|
||||||
|
```
|
||||||
|
|
||||||
|
reference the provider in the `providers` configuration of your `auth.php` configuration file:
|
||||||
|
|
||||||
|
```php
|
||||||
|
'providers' => [
|
||||||
|
'users' => [
|
||||||
|
'driver' => 'eloquent',
|
||||||
|
'model' => App\Models\User::class,
|
||||||
|
],
|
||||||
|
|
||||||
|
'sso-users' => [
|
||||||
|
'driver' => 'sso-users',
|
||||||
|
'model' => App\Models\User::class,
|
||||||
|
'fields' => ['first_name', 'last_name', 'email'],
|
||||||
|
'access_token_field' => 'sso_access_token',
|
||||||
|
],
|
||||||
|
],
|
||||||
|
```
|
||||||
37
README.md
37
README.md
@@ -1,8 +1,9 @@
|
|||||||
# bitinflow Accounts
|
# bitinflow Accounts
|
||||||
|
|
||||||
[](https://packagist.org/packages/ghostzero/bitinflow-accounts)
|
<a href="https://packagist.org/packages/ghostzero/bitinflow-accounts"><img src="https://img.shields.io/packagist/dt/ghostzero/bitinflow-accounts" alt="Total Downloads"></a>
|
||||||
[](https://packagist.org/packages/ghostzero/bitinflow-accounts)
|
<a href="https://packagist.org/packages/ghostzero/bitinflow-accounts"><img src="https://img.shields.io/packagist/v/ghostzero/bitinflow-accounts" alt="Latest Stable Version"></a>
|
||||||
[](https://packagist.org/packages/ghostzero/bitinflow-accounts)
|
<a href="https://packagist.org/packages/ghostzero/bitinflow-accounts"><img src="https://img.shields.io/packagist/l/ghostzero/bitinflow-accounts" alt="License"></a>
|
||||||
|
<a href="https://ghostzero.dev/discord"><img src="https://discordapp.com/api/guilds/590942233126240261/embed.png?style=shield" alt="Discord"></a>
|
||||||
|
|
||||||
PHP bitinflow Accounts API Client for Laravel 5+
|
PHP bitinflow Accounts API Client for Laravel 5+
|
||||||
|
|
||||||
@@ -26,7 +27,7 @@ composer require ghostzero/bitinflow-accounts
|
|||||||
Add Service Provider to your `app.php` configuration file:
|
Add Service Provider to your `app.php` configuration file:
|
||||||
|
|
||||||
```php
|
```php
|
||||||
GhostZero\BitinflowAccounts\Providers\BitinflowAccountsServiceProvider::class,
|
Bitinflow\Accounts\Providers\BitinflowAccountsServiceProvider::class,
|
||||||
```
|
```
|
||||||
|
|
||||||
## Event Listener
|
## Event Listener
|
||||||
@@ -46,7 +47,7 @@ GhostZero\BitinflowAccounts\Providers\BitinflowAccountsServiceProvider::class,
|
|||||||
protected $listen = [
|
protected $listen = [
|
||||||
\SocialiteProviders\Manager\SocialiteWasCalled::class => [
|
\SocialiteProviders\Manager\SocialiteWasCalled::class => [
|
||||||
// add your listeners (aka providers) here
|
// add your listeners (aka providers) here
|
||||||
'GhostZero\\BitinflowAccounts\\Socialite\\BitinflowExtendSocialite@handle',
|
'Bitinflow\\Accounts\\Socialite\\BitinflowExtendSocialite@handle',
|
||||||
],
|
],
|
||||||
];
|
];
|
||||||
```
|
```
|
||||||
@@ -56,7 +57,7 @@ protected $listen = [
|
|||||||
Copy configuration to config folder:
|
Copy configuration to config folder:
|
||||||
|
|
||||||
```
|
```
|
||||||
$ php artisan vendor:publish --provider="GhostZero\BitinflowAccounts\Providers\BitinflowAccountsServiceProvider"
|
$ php artisan vendor:publish --provider="Bitinflow\Accounts\Providers\BitinflowAccountsServiceProvider"
|
||||||
```
|
```
|
||||||
|
|
||||||
Add environmental variables to your `.env`
|
Add environmental variables to your `.env`
|
||||||
@@ -84,7 +85,7 @@ You will need to add an entry to the services configuration file so that after c
|
|||||||
#### Basic
|
#### Basic
|
||||||
|
|
||||||
```php
|
```php
|
||||||
$bitinflowAccounts = new GhostZero\BitinflowAccounts\BitinflowAccounts();
|
$bitinflowAccounts = new Bitinflow\Accounts\BitinflowAccounts();
|
||||||
|
|
||||||
$bitinflowAccounts->setClientId('abc123');
|
$bitinflowAccounts->setClientId('abc123');
|
||||||
|
|
||||||
@@ -105,7 +106,7 @@ echo $sshKey->name;
|
|||||||
#### Setters
|
#### Setters
|
||||||
|
|
||||||
```php
|
```php
|
||||||
$bitinflowAccounts = new GhostZero\BitinflowAccounts\BitinflowAccounts();
|
$bitinflowAccounts = new Bitinflow\Accounts\BitinflowAccounts();
|
||||||
|
|
||||||
$bitinflowAccounts->setClientId('abc123');
|
$bitinflowAccounts->setClientId('abc123');
|
||||||
$bitinflowAccounts->setClientSecret('abc456');
|
$bitinflowAccounts->setClientSecret('abc456');
|
||||||
@@ -119,7 +120,7 @@ $bitinflowAccounts = $bitinflowAccounts->withToken('abcdef123456');
|
|||||||
#### OAuth Tokens
|
#### OAuth Tokens
|
||||||
|
|
||||||
```php
|
```php
|
||||||
$bitinflowAccounts = new GhostZero\BitinflowAccounts\BitinflowAccounts();
|
$bitinflowAccounts = new Bitinflow\Accounts\BitinflowAccounts();
|
||||||
|
|
||||||
$bitinflowAccounts->setClientId('abc123');
|
$bitinflowAccounts->setClientId('abc123');
|
||||||
$bitinflowAccounts->setToken('abcdef123456');
|
$bitinflowAccounts->setToken('abcdef123456');
|
||||||
@@ -142,27 +143,24 @@ $result = $bitinflowAccounts->withToken('uvwxyz456789')->getAuthedUser();
|
|||||||
#### Facade
|
#### Facade
|
||||||
|
|
||||||
```php
|
```php
|
||||||
use GhostZero\BitinflowAccounts\Facades\BitinflowAccounts;
|
use Bitinflow\Accounts\Facades\BitinflowAccounts;
|
||||||
|
|
||||||
BitinflowAccounts::withClientId('abc123')->withToken('abcdef123456')->getAuthedUser();
|
BitinflowAccounts::withClientId('abc123')->withToken('abcdef123456')->getAuthedUser();
|
||||||
```
|
```
|
||||||
|
|
||||||
## Documentation
|
## Documentation
|
||||||
|
|
||||||
### Charges
|
### Oauth
|
||||||
|
|
||||||
```php
|
```php
|
||||||
public function createCharge(array $parameters)
|
public function retrievingToken(string $grantType, array $attributes)
|
||||||
public function getCharge(string $id)
|
|
||||||
public function updateCharge(string $id, array $parameters)
|
|
||||||
public function captureCharge(string $id, array $parameters = [])
|
|
||||||
```
|
```
|
||||||
|
|
||||||
### CheckoutSessions
|
### PaymentIntents
|
||||||
|
|
||||||
```php
|
```php
|
||||||
public function getCheckoutSession(string $id)
|
public function getPaymentIntent(string $id)
|
||||||
public function createCheckoutSession(array $parameters)
|
public function createPaymentIntent(array $parameters)
|
||||||
```
|
```
|
||||||
|
|
||||||
### SshKeys
|
### SshKeys
|
||||||
@@ -177,6 +175,7 @@ public function deleteSshKey(int $id)
|
|||||||
|
|
||||||
```php
|
```php
|
||||||
public function getAuthedUser()
|
public function getAuthedUser()
|
||||||
|
public function createUser(array $parameters)
|
||||||
```
|
```
|
||||||
|
|
||||||
[**OAuth Scopes Enums**](https://github.com/ghostzero/bitinflow-accounts/blob/master/src/Enums/Scope.php)
|
[**OAuth Scopes Enums**](https://github.com/ghostzero/bitinflow-accounts/blob/master/src/Enums/Scope.php)
|
||||||
@@ -190,7 +189,7 @@ composer test
|
|||||||
```
|
```
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
CLIENT_ID=xxxx CLIENT_KEY=yyyy CLIENT_ACCESS_TOKEN=zzzz composer test
|
BASE_URL=xxxx CLIENT_ID=xxxx CLIENT_KEY=yyyy CLIENT_ACCESS_TOKEN=zzzz composer test
|
||||||
```
|
```
|
||||||
|
|
||||||
#### Generate Documentation
|
#### Generate Documentation
|
||||||
|
|||||||
23
README.stub
23
README.stub
@@ -9,9 +9,10 @@ PHP bitinflow Accounts API Client for Laravel 5+
|
|||||||
## Table of contents
|
## Table of contents
|
||||||
|
|
||||||
1. [Installation](#installation)
|
1. [Installation](#installation)
|
||||||
2. [Configuration](#configuration)
|
2. [Event Listener](#event-listener)
|
||||||
3. [Examples](#examples)
|
3. [Configuration](#configuration)
|
||||||
4. [Documentation](#documentation)
|
4. [Examples](#examples)
|
||||||
|
5. [Documentation](#documentation)
|
||||||
6. [Development](#Development)
|
6. [Development](#Development)
|
||||||
|
|
||||||
## Installation
|
## Installation
|
||||||
@@ -25,7 +26,7 @@ composer require ghostzero/bitinflow-accounts
|
|||||||
Add Service Provider to your `app.php` configuration file:
|
Add Service Provider to your `app.php` configuration file:
|
||||||
|
|
||||||
```php
|
```php
|
||||||
GhostZero\BitinflowAccounts\Providers\BitinflowAccountsServiceProvider::class,
|
Bitinflow\Accounts\Providers\BitinflowAccountsServiceProvider::class,
|
||||||
```
|
```
|
||||||
|
|
||||||
## Event Listener
|
## Event Listener
|
||||||
@@ -45,7 +46,7 @@ GhostZero\BitinflowAccounts\Providers\BitinflowAccountsServiceProvider::class,
|
|||||||
protected $listen = [
|
protected $listen = [
|
||||||
\SocialiteProviders\Manager\SocialiteWasCalled::class => [
|
\SocialiteProviders\Manager\SocialiteWasCalled::class => [
|
||||||
// add your listeners (aka providers) here
|
// add your listeners (aka providers) here
|
||||||
'GhostZero\\BitinflowAccounts\\Socialite\\BitinflowExtendSocialite@handle',
|
'Bitinflow\\Accounts\\Socialite\\BitinflowExtendSocialite@handle',
|
||||||
],
|
],
|
||||||
];
|
];
|
||||||
```
|
```
|
||||||
@@ -55,7 +56,7 @@ protected $listen = [
|
|||||||
Copy configuration to config folder:
|
Copy configuration to config folder:
|
||||||
|
|
||||||
```
|
```
|
||||||
$ php artisan vendor:publish --provider="GhostZero\BitinflowAccounts\Providers\BitinflowAccountsServiceProvider"
|
$ php artisan vendor:publish --provider="Bitinflow\Accounts\Providers\BitinflowAccountsServiceProvider"
|
||||||
```
|
```
|
||||||
|
|
||||||
Add environmental variables to your `.env`
|
Add environmental variables to your `.env`
|
||||||
@@ -83,7 +84,7 @@ You will need to add an entry to the services configuration file so that after c
|
|||||||
#### Basic
|
#### Basic
|
||||||
|
|
||||||
```php
|
```php
|
||||||
$bitinflowAccounts = new GhostZero\BitinflowAccounts\BitinflowAccounts();
|
$bitinflowAccounts = new Bitinflow\Accounts\BitinflowAccounts();
|
||||||
|
|
||||||
$bitinflowAccounts->setClientId('abc123');
|
$bitinflowAccounts->setClientId('abc123');
|
||||||
|
|
||||||
@@ -104,7 +105,7 @@ echo $sshKey->name;
|
|||||||
#### Setters
|
#### Setters
|
||||||
|
|
||||||
```php
|
```php
|
||||||
$bitinflowAccounts = new GhostZero\BitinflowAccounts\BitinflowAccounts();
|
$bitinflowAccounts = new Bitinflow\Accounts\BitinflowAccounts();
|
||||||
|
|
||||||
$bitinflowAccounts->setClientId('abc123');
|
$bitinflowAccounts->setClientId('abc123');
|
||||||
$bitinflowAccounts->setClientSecret('abc456');
|
$bitinflowAccounts->setClientSecret('abc456');
|
||||||
@@ -118,7 +119,7 @@ $bitinflowAccounts = $bitinflowAccounts->withToken('abcdef123456');
|
|||||||
#### OAuth Tokens
|
#### OAuth Tokens
|
||||||
|
|
||||||
```php
|
```php
|
||||||
$bitinflowAccounts = new GhostZero\BitinflowAccounts\BitinflowAccounts();
|
$bitinflowAccounts = new Bitinflow\Accounts\BitinflowAccounts();
|
||||||
|
|
||||||
$bitinflowAccounts->setClientId('abc123');
|
$bitinflowAccounts->setClientId('abc123');
|
||||||
$bitinflowAccounts->setToken('abcdef123456');
|
$bitinflowAccounts->setToken('abcdef123456');
|
||||||
@@ -141,7 +142,7 @@ $result = $bitinflowAccounts->withToken('uvwxyz456789')->getAuthedUser();
|
|||||||
#### Facade
|
#### Facade
|
||||||
|
|
||||||
```php
|
```php
|
||||||
use GhostZero\BitinflowAccounts\Facades\BitinflowAccounts;
|
use Bitinflow\Accounts\Facades\BitinflowAccounts;
|
||||||
|
|
||||||
BitinflowAccounts::withClientId('abc123')->withToken('abcdef123456')->getAuthedUser();
|
BitinflowAccounts::withClientId('abc123')->withToken('abcdef123456')->getAuthedUser();
|
||||||
```
|
```
|
||||||
@@ -161,7 +162,7 @@ composer test
|
|||||||
```
|
```
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
CLIENT_ID=xxxx CLIENT_KEY=yyyy CLIENT_ACCESS_TOKEN=zzzz composer test
|
BASE_URL=xxxx CLIENT_ID=xxxx CLIENT_KEY=yyyy CLIENT_ACCESS_TOKEN=zzzz composer test
|
||||||
```
|
```
|
||||||
|
|
||||||
#### Generate Documentation
|
#### Generate Documentation
|
||||||
|
|||||||
@@ -1,34 +1,42 @@
|
|||||||
{
|
{
|
||||||
"name": "ghostzero/bitinflow-accounts",
|
"name": "bitinflow/accounts",
|
||||||
"description": "PHP bitinflow Accounts API Client for Laravel 5+",
|
"description": "PHP bitinflow Accounts API Client for Laravel 5+",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"authors": [
|
"authors": [
|
||||||
{
|
{
|
||||||
"name": "René Preuß",
|
"name": "René Preuß",
|
||||||
"email": "rene@preuss.io"
|
"email": "rene@bitinflow.com"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Maurice Preuß",
|
||||||
|
"email": "maurice@bitinflow.com"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"require": {
|
"require": {
|
||||||
"php": ">=7.2",
|
"php": "^7.4|^8.0",
|
||||||
"ext-json": "*",
|
"ext-json": "*",
|
||||||
"illuminate/support": "^6.0",
|
"illuminate/support": "~5.4|~5.7.0|~5.8.0|^6.0|^7.0|^8.0|^9.0|^10.0",
|
||||||
"illuminate/console": "^6.0",
|
"illuminate/console": "~5.4|~5.7.0|~5.8.0|^6.0|^7.0|^8.0|^9.0|^10.0",
|
||||||
"guzzlehttp/guzzle": "^6.3",
|
"guzzlehttp/guzzle": "^6.3|^7.0",
|
||||||
"socialiteproviders/manager": "^3.4"
|
"socialiteproviders/manager": "^3.4|^4.0.1",
|
||||||
|
"firebase/php-jwt": "^6.0"
|
||||||
},
|
},
|
||||||
"require-dev": {
|
"require-dev": {
|
||||||
"phpunit/phpunit": "^8.0",
|
"phpunit/phpunit": "^8.0|^9.0",
|
||||||
"orchestra/testbench": "~4.0",
|
"orchestra/testbench": "^6.0",
|
||||||
"codedungeon/phpunit-result-printer": "^0.26.2"
|
"codedungeon/phpunit-result-printer": "^0.31"
|
||||||
},
|
},
|
||||||
"autoload": {
|
"autoload": {
|
||||||
"psr-4": {
|
"psr-4": {
|
||||||
"GhostZero\\BitinflowAccounts\\": "src/GhostZero/BitinflowAccounts"
|
"Bitinflow\\Accounts\\": "src/Accounts",
|
||||||
|
"Bitinflow\\Payments\\": "src/Payments",
|
||||||
|
"Bitinflow\\Support\\": "src/Support"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"autoload-dev": {
|
"autoload-dev": {
|
||||||
"psr-4": {
|
"psr-4": {
|
||||||
"GhostZero\\BitinflowAccounts\\Tests\\": "tests/GhostZero/BitinflowAccounts"
|
"Bitinflow\\Accounts\\Tests\\": "tests/Accounts",
|
||||||
|
"Bitinflow\\Payments\\Tests\\": "tests/Payments"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
@@ -38,10 +46,10 @@
|
|||||||
"extra": {
|
"extra": {
|
||||||
"laravel": {
|
"laravel": {
|
||||||
"providers": [
|
"providers": [
|
||||||
"GhostZero\\BitinflowAccounts\\Providers\\BitinflowAccountsServiceProvider"
|
"Bitinflow\\Accounts\\Providers\\BitinflowAccountsServiceProvider"
|
||||||
],
|
],
|
||||||
"aliases": {
|
"aliases": {
|
||||||
"BitinflowAccounts": "GhostZero\\BitinflowAccounts\\Facades\\BitinflowAccounts"
|
"BitinflowAccounts": "Bitinflow\\Accounts\\Facades\\BitinflowAccounts"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
5001
composer.lock
generated
5001
composer.lock
generated
File diff suppressed because it is too large
Load Diff
@@ -1,7 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
return [
|
|
||||||
'client_id' => env('BITINFLOW_ACCOUNTS_KEY', ''),
|
|
||||||
'client_secret' => env('BITINFLOW_ACCOUNTS_SECRET', ''),
|
|
||||||
'redirect_url' => env('BITINFLOW_ACCOUNTS_REDIRECT_URI', ''),
|
|
||||||
];
|
|
||||||
15
config/bitinflow-accounts.php
Normal file
15
config/bitinflow-accounts.php
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
return [
|
||||||
|
// Accounts
|
||||||
|
'client_id' => env('BITINFLOW_ACCOUNTS_KEY'),
|
||||||
|
'client_secret' => env('BITINFLOW_ACCOUNTS_SECRET'),
|
||||||
|
'redirect_url' => env('BITINFLOW_ACCOUNTS_REDIRECT_URI'),
|
||||||
|
'base_url' => env('BITINFLOW_ACCOUNTS_BASE_URL'),
|
||||||
|
|
||||||
|
// Payments
|
||||||
|
'payments' => [
|
||||||
|
'base_url' => env('BITINFLOW_PAYMENTS_BASE_URL', 'https://api.pay.bitinflow.com/v1/'),
|
||||||
|
'dashboard_url' => env('BITINFLOW_PAYMENTS_DASHBOARD_URL', 'https://pay.bitinflow.com/v1/'),
|
||||||
|
]
|
||||||
|
];
|
||||||
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
require __DIR__ . '/../vendor/autoload.php';
|
require __DIR__ . '/../vendor/autoload.php';
|
||||||
|
|
||||||
use GhostZero\BitinflowAccounts\BitinflowAccounts;
|
use Bitinflow\Accounts\BitinflowAccounts;
|
||||||
use Illuminate\Support\Arr;
|
use Illuminate\Support\Arr;
|
||||||
|
|
||||||
$markdown = collect(class_uses(BitinflowAccounts::class))
|
$markdown = collect(class_uses(BitinflowAccounts::class))
|
||||||
|
|||||||
14
oauth-public.key
Normal file
14
oauth-public.key
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
-----BEGIN PUBLIC KEY-----
|
||||||
|
MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA3gKvEGl/CdMihkhttsZX
|
||||||
|
gbnT9Rj+m3d1nI1UG5T2kpzUx5fjnXA70Bfw/wrPyUDucXgTfPro98mZczCvWzY+
|
||||||
|
8EUF3zOM8BUaMOBEPUJV1Kb7mmGX6JI79KgEj5xBnQMNyEg+D6ZiUT7vu/I4JYik
|
||||||
|
TfPHzOz2d6w9g5a02aOKC/PXDjs+G16I6YKxKWNC1vMj4K1/1XNlkN4iu7e0AThQ
|
||||||
|
CcyrAB2qGSgJdEMJTsSB7WmknRZuc69nIpXdWoX1ctdjBiXoEh/C23SmXREX6/oP
|
||||||
|
KeLoT4qy3TkD2Z2sD+ytTDXuhp2HLL01NtUap3QUkriG/GdtT9Xa/AYYrNLYUDQG
|
||||||
|
LpYZU3EG+YLe2AmauouPGKiuHwgHix1yZ5x3iHhAsS8r5ZvumdnaJMB05TgE6sXe
|
||||||
|
Q5dG9TOHsIT9lLduFHpZOg4MjOt0Oj3/IdeP1wXN/JxWbEebkW42vyfXEtD20kbx
|
||||||
|
J3TcKEEB2YSg9qZzk7vvRkdzJCKA2Dmj0sZcRsSK0rYAP0kL7gLWAH3At3sD57cx
|
||||||
|
7i+Hi2lFbK4xRu1hcqpAcu5SPBSBB6lbyaW1XY6u8chc/zVyYdsXzyWBHx9P/Dkh
|
||||||
|
m6kBNv8/HfSz0ZwRPH4Dav57DEnaZPIXaXOE4e4S5BooPL9i7Stz7DkStteZoM09
|
||||||
|
y8bcxEnkdxqOnHc0cYZvPlsCAwEAAQ==
|
||||||
|
-----END PUBLIC KEY-----
|
||||||
@@ -20,4 +20,11 @@
|
|||||||
<directory suffix=".php">src</directory>
|
<directory suffix=".php">src</directory>
|
||||||
</whitelist>
|
</whitelist>
|
||||||
</filter>
|
</filter>
|
||||||
|
<php>
|
||||||
|
<env name="BITINFLOW_ACCOUNTS_KEY" value="38"/>
|
||||||
|
<env name="BITINFLOW_ACCOUNTS_SECRET" value="2goNRF8x37HPVZVaa28ySZGVXJuksvxnxM7TcGzM"/>
|
||||||
|
<env name="BITINFLOW_PAYMENTS_BASE_URL" value="https://api.sandbox.pay.bitinflow.com/v1/"/>
|
||||||
|
<env name="BITINFLOW_PAYMENTS_DASHBOARD_URL" value="https://sandbox.pay.bitinflow.com/v1/"/>
|
||||||
|
<env name="CLIENT_ACCESS_TOKEN" value="eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJhdWQiOiIxNSIsImp0aSI6IjAxN2QxZDg0Y2MxNjAyZTYxOGZkNjYwZGViZWVjMDY4MTk2YmYzMDk1OGMzY2RiYzBjZmJkZWFjZjFhOTUxODQzZDU1YTk3OGY2YWIxY2YzIiwiaWF0IjoxNjY0NjIzMzA4LjQyODI4MSwibmJmIjoxNjY0NjIzMzA4LjQyODI4NCwiZXhwIjoxNjgwMzQ4MTA4LjQxNjc4MSwic3ViIjoiMzkiLCJzY29wZXMiOlsiYXBpIiwicmVhZF91c2VyIl0sImNsaWVudCI6eyJ0cnVzdGVkIjpmYWxzZX19.vxnzCaU4PpOrNVHa5AnGSS6gX_RCvxIERAnHFhjTrUzRafV9mr2Cvwd-BDVYoUr10wHvxa_TJSYfnAdDuhE-MEyDv13O3dL2XGTtJNa_Rg6L6CQ0JvC3wL-lWPvGPFax9pu-_lqbA3jm5B08hc3-7tq3f2nXcxjhtkqT6TTJv1-RCAppb2HCXiUDAqANzbhyInDjOH2WvFj1OGC_AI03J3W2KRWyeFLtUne8XKPFyr9XGcPuTrqogcuuXLeUt2kcf2bXbuIV1OlgIECrDiP1Ee0F2AzPs27ZVJ2z0R0JbT6AubKhGl5_Qi27cwjOH7hT2dmjcF1mLjzpN1uChLIdSnGSoStH8VzYHnHE2I8G-owW_aadG2UmGdnRY143q6g_28f3WIZNSucBSXkwFeS_t4fylsvpxhpjYJusf5qiEU_X3YbeawYMUCFUkSD2XTIypAqMJLNZQAeJ52eyL-9fln-Bv7n9v7K9G6ieR6Tm0tsJ1PRnaQi7rA1NTFwHoQmIOW9tfMycLzT7bgSoz3ra6Ez2J7ZNuWBZNKS0O-0YfSrAWyWK5U8YRfQuSVzP2VrIU63K6RGU2c284PfQGy11kgKUNQPykirb8p7MDQ8PwrxKaylBnD6hhDgjqEh2bfsr_43DfJA0R58L1HK3BmQnxgap0C77wK1e0yNlABpN28Q"/>
|
||||||
|
</php>
|
||||||
</phpunit>
|
</phpunit>
|
||||||
17
src/Accounts/ApiOperations/Delete.php
Normal file
17
src/Accounts/ApiOperations/Delete.php
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace Bitinflow\Accounts\ApiOperations;
|
||||||
|
|
||||||
|
use Bitinflow\Accounts\Helpers\Paginator;
|
||||||
|
use Bitinflow\Accounts\Result;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author René Preuß <rene@preuss.io>
|
||||||
|
*/
|
||||||
|
trait Delete
|
||||||
|
{
|
||||||
|
|
||||||
|
abstract public function delete(string $path = '', array $parameters = [], Paginator $paginator = null): Result;
|
||||||
|
}
|
||||||
17
src/Accounts/ApiOperations/Get.php
Normal file
17
src/Accounts/ApiOperations/Get.php
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace Bitinflow\Accounts\ApiOperations;
|
||||||
|
|
||||||
|
use Bitinflow\Accounts\Helpers\Paginator;
|
||||||
|
use Bitinflow\Accounts\Result;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author René Preuß <rene@preuss.io>
|
||||||
|
*/
|
||||||
|
trait Get
|
||||||
|
{
|
||||||
|
|
||||||
|
abstract public function get(string $path = '', array $parameters = [], Paginator $paginator = null): Result;
|
||||||
|
}
|
||||||
17
src/Accounts/ApiOperations/Post.php
Normal file
17
src/Accounts/ApiOperations/Post.php
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace Bitinflow\Accounts\ApiOperations;
|
||||||
|
|
||||||
|
use Bitinflow\Accounts\Helpers\Paginator;
|
||||||
|
use Bitinflow\Accounts\Result;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author René Preuß <rene@preuss.io>
|
||||||
|
*/
|
||||||
|
trait Post
|
||||||
|
{
|
||||||
|
|
||||||
|
abstract public function post(string $path = '', array $parameters = [], Paginator $paginator = null): Result;
|
||||||
|
}
|
||||||
17
src/Accounts/ApiOperations/Put.php
Normal file
17
src/Accounts/ApiOperations/Put.php
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace Bitinflow\Accounts\ApiOperations;
|
||||||
|
|
||||||
|
use Bitinflow\Accounts\Helpers\Paginator;
|
||||||
|
use Bitinflow\Accounts\Result;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author René Preuß <rene@preuss.io>
|
||||||
|
*/
|
||||||
|
trait Put
|
||||||
|
{
|
||||||
|
|
||||||
|
abstract public function put(string $path = '', array $parameters = [], Paginator $paginator = null): Result;
|
||||||
|
}
|
||||||
19
src/Accounts/ApiOperations/Validation.php
Normal file
19
src/Accounts/ApiOperations/Validation.php
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Bitinflow\Accounts\ApiOperations;
|
||||||
|
|
||||||
|
use Bitinflow\Accounts\Exceptions\RequestRequiresMissingParametersException;
|
||||||
|
use Illuminate\Support\Arr;
|
||||||
|
|
||||||
|
trait Validation
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @throws RequestRequiresMissingParametersException
|
||||||
|
*/
|
||||||
|
public function validateRequired(array $parameters, array $required)
|
||||||
|
{
|
||||||
|
if (!Arr::has($parameters, $required)) {
|
||||||
|
throw RequestRequiresMissingParametersException::fromValidateRequired($parameters, $required);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
82
src/Accounts/ApiTokenCookieFactory.php
Normal file
82
src/Accounts/ApiTokenCookieFactory.php
Normal file
@@ -0,0 +1,82 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Bitinflow\Accounts;
|
||||||
|
|
||||||
|
use Carbon\Carbon;
|
||||||
|
use Firebase\JWT\JWT;
|
||||||
|
use Illuminate\Contracts\Config\Repository as Config;
|
||||||
|
use Illuminate\Contracts\Encryption\Encrypter;
|
||||||
|
use Symfony\Component\HttpFoundation\Cookie;
|
||||||
|
|
||||||
|
class ApiTokenCookieFactory
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* The configuration repository implementation.
|
||||||
|
*
|
||||||
|
* @var Config
|
||||||
|
*/
|
||||||
|
protected $config;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The encrypter implementation.
|
||||||
|
*
|
||||||
|
* @var Encrypter
|
||||||
|
*/
|
||||||
|
protected $encrypter;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create an API token cookie factory instance.
|
||||||
|
*
|
||||||
|
* @param Config $config
|
||||||
|
* @param Encrypter $encrypter
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function __construct(Config $config, Encrypter $encrypter)
|
||||||
|
{
|
||||||
|
$this->config = $config;
|
||||||
|
$this->encrypter = $encrypter;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new API token cookie.
|
||||||
|
*
|
||||||
|
* @param mixed $userId
|
||||||
|
* @param string $csrfToken
|
||||||
|
* @return Cookie
|
||||||
|
*/
|
||||||
|
public function make($userId, string $csrfToken): Cookie
|
||||||
|
{
|
||||||
|
$config = $this->config->get('session');
|
||||||
|
|
||||||
|
$expiration = Carbon::now()->addMinutes($config['lifetime']);
|
||||||
|
|
||||||
|
return new Cookie(
|
||||||
|
BitinflowAccounts::cookie(),
|
||||||
|
$this->createToken($userId, $csrfToken, $expiration),
|
||||||
|
$expiration,
|
||||||
|
$config['path'],
|
||||||
|
$config['domain'],
|
||||||
|
$config['secure'],
|
||||||
|
true,
|
||||||
|
false,
|
||||||
|
$config['same_site'] ?? null
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new JWT token for the given user ID and CSRF token.
|
||||||
|
*
|
||||||
|
* @param mixed $userId
|
||||||
|
* @param string $csrfToken
|
||||||
|
* @param Carbon $expiration
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
protected function createToken($userId, string $csrfToken, Carbon $expiration): string
|
||||||
|
{
|
||||||
|
return JWT::encode([
|
||||||
|
'sub' => $userId,
|
||||||
|
'csrf' => $csrfToken,
|
||||||
|
'expiry' => $expiration->getTimestamp(),
|
||||||
|
], $this->encrypter->getKey(), 'HS256');
|
||||||
|
}
|
||||||
|
}
|
||||||
232
src/Accounts/Auth/TokenGuard.php
Normal file
232
src/Accounts/Auth/TokenGuard.php
Normal file
@@ -0,0 +1,232 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Bitinflow\Accounts\Auth;
|
||||||
|
|
||||||
|
use Bitinflow\Accounts\BitinflowAccounts;
|
||||||
|
use Bitinflow\Accounts\Helpers\JwtParser;
|
||||||
|
use Bitinflow\Accounts\Traits\HasBitinflowTokens;
|
||||||
|
use Exception;
|
||||||
|
use Firebase\JWT\JWT;
|
||||||
|
use Firebase\JWT\Key;
|
||||||
|
use Illuminate\Auth\AuthenticationException;
|
||||||
|
use Illuminate\Auth\GuardHelpers;
|
||||||
|
use Illuminate\Container\Container;
|
||||||
|
use Illuminate\Contracts\Container\BindingResolutionException;
|
||||||
|
use Illuminate\Contracts\Debug\ExceptionHandler;
|
||||||
|
use Illuminate\Contracts\Encryption\Encrypter;
|
||||||
|
use Illuminate\Cookie\CookieValuePrefix;
|
||||||
|
use Illuminate\Cookie\Middleware\EncryptCookies;
|
||||||
|
use Illuminate\Foundation\Auth\User as Authenticatable;
|
||||||
|
use Illuminate\Http\Request;
|
||||||
|
use stdClass;
|
||||||
|
use Throwable;
|
||||||
|
|
||||||
|
class TokenGuard
|
||||||
|
{
|
||||||
|
use GuardHelpers;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var Encrypter
|
||||||
|
*/
|
||||||
|
private $encrypter;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var JwtParser
|
||||||
|
*/
|
||||||
|
private $jwtParser;
|
||||||
|
|
||||||
|
public function __construct(UserProvider $provider, Encrypter $encrypter, JwtParser $jwtParser)
|
||||||
|
{
|
||||||
|
$this->provider = $provider;
|
||||||
|
$this->encrypter = $encrypter;
|
||||||
|
$this->jwtParser = $jwtParser;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the user for the incoming request.
|
||||||
|
*
|
||||||
|
* @param Request $request
|
||||||
|
* @return mixed
|
||||||
|
* @throws BindingResolutionException
|
||||||
|
* @throws Throwable
|
||||||
|
*/
|
||||||
|
public function user(Request $request): ?Authenticatable
|
||||||
|
{
|
||||||
|
if ($request->bearerToken()) {
|
||||||
|
return $this->authenticateViaBearerToken($request);
|
||||||
|
} elseif ($request->cookie(BitinflowAccounts::cookie())) {
|
||||||
|
return $this->authenticateViaCookie($request);
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Authenticate the incoming request via the Bearer token.
|
||||||
|
*
|
||||||
|
* @param Request $request
|
||||||
|
* @return Authenticatable
|
||||||
|
* @throws BindingResolutionException
|
||||||
|
* @throws Throwable
|
||||||
|
*/
|
||||||
|
protected function authenticateViaBearerToken(Request $request): ?Authenticatable
|
||||||
|
{
|
||||||
|
if (!$token = $this->validateRequestViaBearerToken($request)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If the access token is valid we will retrieve the user according to the user ID
|
||||||
|
// associated with the token. We will use the provider implementation which may
|
||||||
|
// be used to retrieve users from Eloquent. Next, we'll be ready to continue.
|
||||||
|
/** @var Authenticatable|HasBitinflowTokens $user */
|
||||||
|
$user = $this->provider->retrieveById(
|
||||||
|
$request->attributes->get('oauth_user_id') ?: null
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!$user) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $token ? $user->withBitinflowAccessToken($token) : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Authenticate and get the incoming request via the Bearer token.
|
||||||
|
*
|
||||||
|
* @param Request $request
|
||||||
|
* @return stdClass|null
|
||||||
|
* @throws BindingResolutionException
|
||||||
|
* @throws Throwable
|
||||||
|
*/
|
||||||
|
protected function validateRequestViaBearerToken(Request $request): ?stdClass
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
$decoded = $this->jwtParser->decode($request);
|
||||||
|
|
||||||
|
$request->attributes->set('oauth_access_token_id', $decoded->jti);
|
||||||
|
$request->attributes->set('oauth_client_id', $decoded->aud);
|
||||||
|
$request->attributes->set('oauth_client_trusted', $decoded->client->trusted);
|
||||||
|
$request->attributes->set('oauth_user_id', $decoded->sub);
|
||||||
|
$request->attributes->set('oauth_scopes', $decoded->scopes);
|
||||||
|
|
||||||
|
return $decoded;
|
||||||
|
} catch (AuthenticationException $e) {
|
||||||
|
$request->headers->set('Authorization', '', true);
|
||||||
|
|
||||||
|
Container::getInstance()->make(
|
||||||
|
ExceptionHandler::class
|
||||||
|
)->report($e);
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Authenticate the incoming request via the token cookie.
|
||||||
|
*
|
||||||
|
* @param Request $request
|
||||||
|
* @return mixed
|
||||||
|
*/
|
||||||
|
protected function authenticateViaCookie(Request $request)
|
||||||
|
{
|
||||||
|
if (!$token = $this->getTokenViaCookie($request)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If this user exists, we will return this user and attach a "transient" token to
|
||||||
|
// the user model. The transient token assumes it has all scopes since the user
|
||||||
|
// is physically logged into the application via the application's interface.
|
||||||
|
/** @var Authenticatable|HasBitinflowTokens $user */
|
||||||
|
if ($user = $this->provider->retrieveById($token['sub'])) {
|
||||||
|
return $user->withBitinflowAccessToken((object)['scopes' => ['*']]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the token cookie via the incoming request.
|
||||||
|
*
|
||||||
|
* @param Request $request
|
||||||
|
* @return array|null
|
||||||
|
*/
|
||||||
|
protected function getTokenViaCookie(Request $request): ?array
|
||||||
|
{
|
||||||
|
// If we need to retrieve the token from the cookie, it'll be encrypted so we must
|
||||||
|
// first decrypt the cookie and then attempt to find the token value within the
|
||||||
|
// database. If we can't decrypt the value we'll bail out with a null return.
|
||||||
|
try {
|
||||||
|
$token = $this->decodeJwtTokenCookie($request);
|
||||||
|
} catch (Exception $e) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// We will compare the CSRF token in the decoded API token against the CSRF header
|
||||||
|
// sent with the request. If they don't match then this request isn't sent from
|
||||||
|
// a valid source and we won't authenticate the request for further handling.
|
||||||
|
if (!BitinflowAccounts::$ignoreCsrfToken && (!$this->validCsrf($token, $request) ||
|
||||||
|
time() >= $token['expiry'])) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $token;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Decode and decrypt the JWT token cookie.
|
||||||
|
*
|
||||||
|
* @param Request $request
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
protected function decodeJwtTokenCookie(Request $request): array
|
||||||
|
{
|
||||||
|
return (array)JWT::decode(
|
||||||
|
CookieValuePrefix::remove($this->encrypter->decrypt($request->cookie(BitinflowAccounts::cookie()), BitinflowAccounts::$unserializesCookies)),
|
||||||
|
new Key(
|
||||||
|
$this->encrypter->getKey(),
|
||||||
|
'HS256'
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determine if the CSRF / header are valid and match.
|
||||||
|
*
|
||||||
|
* @param array $token
|
||||||
|
* @param Request $request
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
protected function validCsrf(array $token, Request $request): bool
|
||||||
|
{
|
||||||
|
return isset($token['csrf']) && hash_equals(
|
||||||
|
$token['csrf'], (string)$this->getTokenFromRequest($request)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the CSRF token from the request.
|
||||||
|
*
|
||||||
|
* @param Request $request
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
protected function getTokenFromRequest(Request $request): string
|
||||||
|
{
|
||||||
|
$token = $request->header('X-CSRF-TOKEN');
|
||||||
|
|
||||||
|
if (!$token && $header = $request->header('X-XSRF-TOKEN')) {
|
||||||
|
$token = CookieValuePrefix::remove($this->encrypter->decrypt($header, static::serialized()));
|
||||||
|
}
|
||||||
|
|
||||||
|
return $token;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determine if the cookie contents should be serialized.
|
||||||
|
*
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public static function serialized(): bool
|
||||||
|
{
|
||||||
|
return EncryptCookies::serialized('XSRF-TOKEN');
|
||||||
|
}
|
||||||
|
}
|
||||||
86
src/Accounts/Auth/UserProvider.php
Normal file
86
src/Accounts/Auth/UserProvider.php
Normal file
@@ -0,0 +1,86 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Bitinflow\Accounts\Auth;
|
||||||
|
|
||||||
|
use Illuminate\Contracts\Auth\Authenticatable;
|
||||||
|
use Illuminate\Contracts\Auth\UserProvider as Base;
|
||||||
|
|
||||||
|
class UserProvider implements Base
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* The user provider instance.
|
||||||
|
*
|
||||||
|
* @var Base
|
||||||
|
*/
|
||||||
|
protected $provider;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The user provider name.
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
protected $providerName;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new Bitinflow Accounts user provider.
|
||||||
|
*
|
||||||
|
* @param Base $provider
|
||||||
|
* @param string $providerName
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function __construct(Base $provider, $providerName)
|
||||||
|
{
|
||||||
|
$this->provider = $provider;
|
||||||
|
$this->providerName = $providerName;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
public function retrieveById($identifier)
|
||||||
|
{
|
||||||
|
return $this->provider->retrieveById($identifier);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
public function retrieveByToken($identifier, $token)
|
||||||
|
{
|
||||||
|
return $this->provider->retrieveByToken($identifier, $token);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
public function updateRememberToken(Authenticatable $user, $token)
|
||||||
|
{
|
||||||
|
$this->provider->updateRememberToken($user, $token);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
public function retrieveByCredentials(array $credentials)
|
||||||
|
{
|
||||||
|
return $this->provider->retrieveByCredentials($credentials);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
public function validateCredentials(Authenticatable $user, array $credentials)
|
||||||
|
{
|
||||||
|
return $this->provider->validateCredentials($user, $credentials);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the name of the user provider.
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function getProviderName()
|
||||||
|
{
|
||||||
|
return $this->providerName;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,109 +1,156 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
namespace GhostZero\BitinflowAccounts;
|
namespace Bitinflow\Accounts;
|
||||||
|
|
||||||
use GhostZero\BitinflowAccounts\Exceptions\RequestRequiresAuthenticationException;
|
use Bitinflow\Accounts\ApiOperations;
|
||||||
use GhostZero\BitinflowAccounts\Exceptions\RequestRequiresClientIdException;
|
use Bitinflow\Accounts\Exceptions\RequestRequiresAuthenticationException;
|
||||||
use GhostZero\BitinflowAccounts\Exceptions\RequestRequiresRedirectUriException;
|
use Bitinflow\Accounts\Exceptions\RequestRequiresClientIdException;
|
||||||
use GhostZero\BitinflowAccounts\Helpers\Paginator;
|
use Bitinflow\Accounts\Exceptions\RequestRequiresRedirectUriException;
|
||||||
use GhostZero\BitinflowAccounts\Traits;
|
use Bitinflow\Accounts\Helpers\Paginator;
|
||||||
|
use Bitinflow\Accounts\Traits;
|
||||||
|
use Bitinflow\Support\Query;
|
||||||
use GuzzleHttp\Client;
|
use GuzzleHttp\Client;
|
||||||
use GuzzleHttp\Exception\GuzzleException;
|
use GuzzleHttp\Exception\GuzzleException;
|
||||||
use GuzzleHttp\Exception\RequestException;
|
use GuzzleHttp\Exception\RequestException;
|
||||||
|
use Illuminate\Contracts\Auth\Authenticatable;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author René Preuß <rene@preuss.io>
|
* @author René Preuß <rene@preuss.io>
|
||||||
*/
|
*/
|
||||||
class BitinflowAccounts
|
class BitinflowAccounts
|
||||||
{
|
{
|
||||||
|
use Traits\OauthTrait;
|
||||||
use Traits\ChargesTrait;
|
|
||||||
use Traits\CheckoutSessionsTrait;
|
|
||||||
use Traits\SshKeysTrait;
|
use Traits\SshKeysTrait;
|
||||||
use Traits\UsersTrait;
|
use Traits\UsersTrait;
|
||||||
|
|
||||||
const BASE_URI = 'https://accounts.bitinflow.com/api/';
|
use ApiOperations\Delete;
|
||||||
const OAUTH_BASE_URI = 'https://accounts.bitinflow.com/api/';
|
use ApiOperations\Get;
|
||||||
|
use ApiOperations\Post;
|
||||||
|
use ApiOperations\Put;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The name for API token cookies.
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
public static string $cookie = 'bitinflow_token';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Indicates if Bitinflow Accounts should ignore incoming CSRF tokens.
|
||||||
|
*/
|
||||||
|
public static bool $ignoreCsrfToken = false;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Indicates if Bitinflow Accounts should unserializes cookies.
|
||||||
|
*/
|
||||||
|
public static bool $unserializesCookies = false;
|
||||||
|
|
||||||
|
private static string $baseUrl = 'https://accounts.bitinflow.com/api/';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Guzzle is used to make http requests.
|
* Guzzle is used to make http requests.
|
||||||
* @var \GuzzleHttp\Client
|
|
||||||
*/
|
*/
|
||||||
protected $client;
|
protected Client $client;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Paginator object.
|
* Paginator object.
|
||||||
* @var Paginator
|
|
||||||
*/
|
*/
|
||||||
protected $paginator;
|
protected Paginator $paginator;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* bitinflow Accounts OAuth token.
|
* bitinflow Accounts OAuth token.
|
||||||
* @var string|null
|
*
|
||||||
*/
|
*/
|
||||||
protected $token = null;
|
protected ?string $token = null;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* bitinflow Accounts client id.
|
* bitinflow Accounts client id.
|
||||||
* @var string|null
|
*
|
||||||
*/
|
*/
|
||||||
protected $clientId = null;
|
protected ?string $clientId = null;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* bitinflow Accounts client secret.
|
* bitinflow Accounts client secret.
|
||||||
* @var string|null
|
|
||||||
*/
|
*/
|
||||||
protected $clientSecret = null;
|
protected ?string $clientSecret = null;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* bitinflow Accounts OAuth redirect url.
|
* bitinflow Accounts OAuth redirect url.
|
||||||
* @var string|null
|
|
||||||
*/
|
*/
|
||||||
protected $redirectUri = null;
|
protected ?string $redirectUri = null;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor.
|
* Constructor.
|
||||||
*/
|
*/
|
||||||
public function __construct()
|
public function __construct()
|
||||||
{
|
{
|
||||||
if ($clientId = config('bitinflow-accounts-api.client_id')) {
|
if ($clientId = config('bitinflow-accounts.client_id')) {
|
||||||
$this->setClientId($clientId);
|
$this->setClientId($clientId);
|
||||||
}
|
}
|
||||||
if ($clientSecret = config('bitinflow-accounts-api.client_secret')) {
|
if ($clientSecret = config('bitinflow-accounts.client_secret')) {
|
||||||
$this->setClientSecret($clientSecret);
|
$this->setClientSecret($clientSecret);
|
||||||
}
|
}
|
||||||
if ($redirectUri = config('bitinflow-accounts-api.redirect_url')) {
|
if ($redirectUri = config('bitinflow-accounts.redirect_url')) {
|
||||||
$this->setRedirectUri($redirectUri);
|
$this->setRedirectUri($redirectUri);
|
||||||
}
|
}
|
||||||
|
if ($redirectUri = config('bitinflow-accounts.base_url')) {
|
||||||
|
self::setBaseUrl($redirectUri);
|
||||||
|
}
|
||||||
$this->client = new Client([
|
$this->client = new Client([
|
||||||
'base_uri' => self::BASE_URI,
|
'base_uri' => self::$baseUrl,
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get client id.
|
* @param string $baseUrl
|
||||||
* @return string
|
*
|
||||||
* @throws RequestRequiresClientIdException
|
* @internal only for internal and debug purposes.
|
||||||
*/
|
*/
|
||||||
public function getClientId(): string
|
public static function setBaseUrl(string $baseUrl): void
|
||||||
{
|
{
|
||||||
if (!$this->clientId) {
|
self::$baseUrl = $baseUrl;
|
||||||
throw new RequestRequiresClientIdException;
|
|
||||||
}
|
|
||||||
|
|
||||||
return $this->clientId;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set client id.
|
* Get or set the name for API token cookies.
|
||||||
*
|
*
|
||||||
* @param string $clientId bitinflow Accounts client id
|
* @param string|null $cookie
|
||||||
*
|
* @return string|static
|
||||||
* @return void
|
|
||||||
*/
|
*/
|
||||||
public function setClientId(string $clientId): void
|
public static function cookie(string $cookie = null)
|
||||||
{
|
{
|
||||||
$this->clientId = $clientId;
|
if (is_null($cookie)) {
|
||||||
|
return static::$cookie;
|
||||||
|
}
|
||||||
|
|
||||||
|
static::$cookie = $cookie;
|
||||||
|
|
||||||
|
return new static;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the current user for the application with the given scopes.
|
||||||
|
*
|
||||||
|
* @param Authenticatable|Traits\HasBitinflowTokens $user
|
||||||
|
* @param array $scopes
|
||||||
|
* @param string $guard
|
||||||
|
* @return Authenticatable
|
||||||
|
*/
|
||||||
|
public static function actingAs($user, $scopes = [], $guard = 'api')
|
||||||
|
{
|
||||||
|
$user->withBitinflowAccessToken((object)[
|
||||||
|
'scopes' => $scopes
|
||||||
|
]);
|
||||||
|
|
||||||
|
if (isset($user->wasRecentlyCreated) && $user->wasRecentlyCreated) {
|
||||||
|
$user->wasRecentlyCreated = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
app('auth')->guard($guard)->setUser($user);
|
||||||
|
|
||||||
|
app('auth')->shouldUse($guard);
|
||||||
|
|
||||||
|
return $user;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -122,6 +169,7 @@ class BitinflowAccounts
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Get client secret.
|
* Get client secret.
|
||||||
|
*
|
||||||
* @return string
|
* @return string
|
||||||
* @throws RequestRequiresClientIdException
|
* @throws RequestRequiresClientIdException
|
||||||
*/
|
*/
|
||||||
@@ -162,6 +210,7 @@ class BitinflowAccounts
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Get redirect url.
|
* Get redirect url.
|
||||||
|
*
|
||||||
* @return string
|
* @return string
|
||||||
* @throws RequestRequiresRedirectUriException
|
* @throws RequestRequiresRedirectUriException
|
||||||
*/
|
*/
|
||||||
@@ -202,11 +251,12 @@ class BitinflowAccounts
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Get OAuth token.
|
* Get OAuth token.
|
||||||
|
*
|
||||||
* @return string bitinflow Accounts token
|
* @return string bitinflow Accounts token
|
||||||
* @return string|null
|
* @return string|null
|
||||||
* @throws RequestRequiresAuthenticationException
|
* @throws RequestRequiresAuthenticationException
|
||||||
*/
|
*/
|
||||||
public function getToken()
|
public function getToken(): ?string
|
||||||
{
|
{
|
||||||
if (!$this->token) {
|
if (!$this->token) {
|
||||||
throw new RequestRequiresAuthenticationException;
|
throw new RequestRequiresAuthenticationException;
|
||||||
@@ -250,78 +300,18 @@ class BitinflowAccounts
|
|||||||
* @throws GuzzleException
|
* @throws GuzzleException
|
||||||
* @throws RequestRequiresClientIdException
|
* @throws RequestRequiresClientIdException
|
||||||
*/
|
*/
|
||||||
public function get(string $path = '', array $parameters = [], Paginator $paginator = null)
|
public function get(string $path = '', array $parameters = [], Paginator $paginator = null): Result
|
||||||
{
|
{
|
||||||
return $this->query('GET', $path, $parameters, $paginator);
|
return $this->query('GET', $path, $parameters, $paginator);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @param string $path
|
|
||||||
* @param array $parameters
|
|
||||||
* @param Paginator|null $paginator
|
|
||||||
*
|
|
||||||
* @return Result
|
|
||||||
* @throws GuzzleException
|
|
||||||
* @throws RequestRequiresClientIdException
|
|
||||||
*/
|
|
||||||
public function post(string $path = '', array $parameters = [], Paginator $paginator = null)
|
|
||||||
{
|
|
||||||
return $this->query('POST', $path, $parameters, $paginator);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param string $path
|
|
||||||
* @param array $parameters
|
|
||||||
* @param Paginator|null $paginator
|
|
||||||
*
|
|
||||||
* @return Result
|
|
||||||
* @throws GuzzleException
|
|
||||||
* @throws RequestRequiresClientIdException
|
|
||||||
*/
|
|
||||||
public function delete(string $path = '', array $parameters = [], Paginator $paginator = null)
|
|
||||||
{
|
|
||||||
return $this->query('DELETE', $path, $parameters, $paginator);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param string $path
|
|
||||||
* @param array $parameters
|
|
||||||
* @param Paginator|null $paginator
|
|
||||||
*
|
|
||||||
* @return Result
|
|
||||||
* @throws GuzzleException
|
|
||||||
* @throws RequestRequiresClientIdException
|
|
||||||
*/
|
|
||||||
public function put(string $path = '', array $parameters = [], Paginator $paginator = null)
|
|
||||||
{
|
|
||||||
return $this->query('PUT', $path, $parameters, $paginator);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param string $method
|
|
||||||
* @param string $path
|
|
||||||
* @param array|null $body
|
|
||||||
*
|
|
||||||
* @return Result
|
|
||||||
* @throws GuzzleException
|
|
||||||
* @throws RequestRequiresClientIdException
|
|
||||||
*/
|
|
||||||
public function json(string $method, string $path = '', array $body = null)
|
|
||||||
{
|
|
||||||
if ($body) {
|
|
||||||
$body = json_encode(['data' => $body]);
|
|
||||||
}
|
|
||||||
|
|
||||||
return $this->query($method, $path, [], null, $body);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Build query & execute.
|
* Build query & execute.
|
||||||
*
|
*
|
||||||
* @param string $method HTTP method
|
* @param string $method HTTP method
|
||||||
* @param string $path Query path
|
* @param string $path Query path
|
||||||
* @param array $parameters Query parameters
|
* @param array $parameters Query parameters
|
||||||
* @param Paginator $paginator Paginator object
|
* @param Paginator|null $paginator Paginator object
|
||||||
* @param mixed|null $jsonBody JSON data
|
* @param mixed|null $jsonBody JSON data
|
||||||
*
|
*
|
||||||
* @return Result Result object
|
* @return Result Result object
|
||||||
@@ -330,14 +320,15 @@ class BitinflowAccounts
|
|||||||
*/
|
*/
|
||||||
public function query(string $method = 'GET', string $path = '', array $parameters = [], Paginator $paginator = null, $jsonBody = null): Result
|
public function query(string $method = 'GET', string $path = '', array $parameters = [], Paginator $paginator = null, $jsonBody = null): Result
|
||||||
{
|
{
|
||||||
|
/** @noinspection DuplicatedCode */
|
||||||
if ($paginator !== null) {
|
if ($paginator !== null) {
|
||||||
$parameters[$paginator->action] = $paginator->cursor();
|
$parameters[$paginator->action] = $paginator->cursor();
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
$response = $this->client->request($method, $path, [
|
$response = $this->client->request($method, $path, [
|
||||||
'headers' => $this->buildHeaders($jsonBody ? true : false),
|
'headers' => $this->buildHeaders((bool)$jsonBody),
|
||||||
'query' => $this->buildQuery($parameters),
|
'query' => Query::build($parameters),
|
||||||
'json' => $jsonBody ? $jsonBody : null,
|
'json' => $jsonBody ?: null,
|
||||||
]);
|
]);
|
||||||
$result = new Result($response, null, $paginator);
|
$result = new Result($response, null, $paginator);
|
||||||
} catch (RequestException $exception) {
|
} catch (RequestException $exception) {
|
||||||
@@ -348,26 +339,6 @@ class BitinflowAccounts
|
|||||||
return $result;
|
return $result;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Build query with support for multiple smae first-dimension keys.
|
|
||||||
*
|
|
||||||
* @param array $query
|
|
||||||
*
|
|
||||||
* @return string
|
|
||||||
*/
|
|
||||||
public function buildQuery(array $query): string
|
|
||||||
{
|
|
||||||
$parts = [];
|
|
||||||
foreach ($query as $name => $value) {
|
|
||||||
$value = (array) $value;
|
|
||||||
array_walk_recursive($value, function ($value) use (&$parts, $name) {
|
|
||||||
$parts[] = urlencode($name) . '=' . urlencode($value);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
return implode('&', $parts);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Build headers for request.
|
* Build headers for request.
|
||||||
*
|
*
|
||||||
@@ -380,15 +351,102 @@ class BitinflowAccounts
|
|||||||
{
|
{
|
||||||
$headers = [
|
$headers = [
|
||||||
'Client-ID' => $this->getClientId(),
|
'Client-ID' => $this->getClientId(),
|
||||||
|
'Accept' => 'application/json',
|
||||||
];
|
];
|
||||||
if ($this->token) {
|
if ($this->token) {
|
||||||
$headers['Authorization'] = 'Bearer ' . $this->token;
|
$headers['Authorization'] = 'Bearer ' . $this->token;
|
||||||
}
|
}
|
||||||
if ($json) {
|
if ($json) {
|
||||||
$headers['Content-Type'] = 'application/json';
|
$headers['Content-Type'] = 'application/json';
|
||||||
$headers['Accept'] = 'application/json';
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return $headers;
|
return $headers;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get client id.
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
* @throws RequestRequiresClientIdException
|
||||||
|
*/
|
||||||
|
public function getClientId(): string
|
||||||
|
{
|
||||||
|
if (!$this->clientId) {
|
||||||
|
throw new RequestRequiresClientIdException;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->clientId;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set client id.
|
||||||
|
*
|
||||||
|
* @param string $clientId bitinflow Accounts client id
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function setClientId(string $clientId): void
|
||||||
|
{
|
||||||
|
$this->clientId = $clientId;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string $path
|
||||||
|
* @param array $parameters
|
||||||
|
* @param Paginator|null $paginator
|
||||||
|
*
|
||||||
|
* @return Result
|
||||||
|
* @throws GuzzleException
|
||||||
|
* @throws RequestRequiresClientIdException
|
||||||
|
*/
|
||||||
|
public function post(string $path = '', array $parameters = [], Paginator $paginator = null): Result
|
||||||
|
{
|
||||||
|
return $this->query('POST', $path, $parameters, $paginator);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string $path
|
||||||
|
* @param array $parameters
|
||||||
|
* @param Paginator|null $paginator
|
||||||
|
*
|
||||||
|
* @return Result
|
||||||
|
* @throws GuzzleException
|
||||||
|
* @throws RequestRequiresClientIdException
|
||||||
|
*/
|
||||||
|
public function delete(string $path = '', array $parameters = [], Paginator $paginator = null): Result
|
||||||
|
{
|
||||||
|
return $this->query('DELETE', $path, $parameters, $paginator);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string $path
|
||||||
|
* @param array $parameters
|
||||||
|
* @param Paginator|null $paginator
|
||||||
|
*
|
||||||
|
* @return Result
|
||||||
|
* @throws GuzzleException
|
||||||
|
* @throws RequestRequiresClientIdException
|
||||||
|
*/
|
||||||
|
public function put(string $path = '', array $parameters = [], Paginator $paginator = null): Result
|
||||||
|
{
|
||||||
|
return $this->query('PUT', $path, $parameters, $paginator);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string $method
|
||||||
|
* @param string $path
|
||||||
|
* @param array|null $body
|
||||||
|
*
|
||||||
|
* @return Result
|
||||||
|
* @throws GuzzleException
|
||||||
|
* @throws RequestRequiresClientIdException
|
||||||
|
*/
|
||||||
|
public function json(string $method, string $path = '', array $body = null): Result
|
||||||
|
{
|
||||||
|
if ($body) {
|
||||||
|
$body = json_encode(['data' => $body]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->query($method, $path, [], null, $body);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
15
src/Accounts/Contracts/AppTokenRepository.php
Normal file
15
src/Accounts/Contracts/AppTokenRepository.php
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Bitinflow\Accounts\Contracts;
|
||||||
|
|
||||||
|
use Bitinflow\Accounts\Exceptions\RequestFreshAccessTokenException;
|
||||||
|
|
||||||
|
interface AppTokenRepository
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @throws RequestFreshAccessTokenException
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function getAccessToken(): string;
|
||||||
|
}
|
||||||
89
src/Accounts/Enums/Scope.php
Normal file
89
src/Accounts/Enums/Scope.php
Normal file
@@ -0,0 +1,89 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace Bitinflow\Accounts\Enums;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author René Preuß <rene@preuss.io>
|
||||||
|
*/
|
||||||
|
class Scope
|
||||||
|
{
|
||||||
|
|
||||||
|
/*
|
||||||
|
* v3 API
|
||||||
|
*/
|
||||||
|
|
||||||
|
public const USER = 'user';
|
||||||
|
public const USER_READ = 'user:read';
|
||||||
|
|
||||||
|
public const USERS = 'users';
|
||||||
|
public const USERS_READ = 'users:read';
|
||||||
|
public const USERS_CREATE = 'users:create';
|
||||||
|
|
||||||
|
public const PAYMENTS = 'payments';
|
||||||
|
public const PAYMENTS_READ = 'payments:read';
|
||||||
|
public const PAYMENTS_CREATE = 'payments:create';
|
||||||
|
public const PAYMENTS_CHECKOUT = 'payments:checkout';
|
||||||
|
public const PAYMENTS_REVOKE = 'payments:revoke';
|
||||||
|
public const PAYMENTS_RESUME = 'payments:resume';
|
||||||
|
|
||||||
|
public const PAYMENT_ORDERS = 'payment.orders';
|
||||||
|
public const PAYMENT_ORDERS_READ = 'payment.orders:read';
|
||||||
|
public const PAYMENT_ORDERS_CREATE = 'payment.orders:create';
|
||||||
|
public const PAYMENT_ORDERS_CHECKOUT = 'payment.orders:checkout';
|
||||||
|
public const PAYMENT_ORDERS_REVOKE = 'payment.orders:revoke';
|
||||||
|
|
||||||
|
public const PAYMENT_INVOICES = 'payment.invoices';
|
||||||
|
public const PAYMENT_INVOICES_READ = 'payment.invoices:read';
|
||||||
|
|
||||||
|
public const PAYMENT_SUBSCRIPTIONS = 'payment.subscriptions';
|
||||||
|
public const PAYMENT_SUBSCRIPTIONS_READ = 'payment.subscriptions:read';
|
||||||
|
public const PAYMENT_SUBSCRIPTIONS_CREATE = 'payment.subscriptions:create';
|
||||||
|
public const PAYMENT_SUBSCRIPTIONS_CHECKOUT = 'payment.subscriptions:checkout';
|
||||||
|
public const PAYMENT_SUBSCRIPTIONS_REVOKE = 'payment.subscriptions:revoke';
|
||||||
|
public const PAYMENT_SUBSCRIPTIONS_RESUME = 'payment.subscriptions:resume';
|
||||||
|
|
||||||
|
public const PAYMENT_WALLETS = 'payment.wallets';
|
||||||
|
public const PAYMENT_WALLETS_READ = 'payment.wallets:read';
|
||||||
|
public const PAYMENT_WALLETS_CREATE = 'payment.wallets:create';
|
||||||
|
|
||||||
|
public const PAYMENT_CHECKOUT_SESSIONS = 'payment.checkout-sessions';
|
||||||
|
public const PAYMENT_CHECKOUT_SESSIONS_READ = 'payment.checkout-sessions:read';
|
||||||
|
public const PAYMENT_CHECKOUT_SESSIONS_CREATE = 'payment.checkout-sessions:create';
|
||||||
|
public const PAYMENT_CHECKOUT_SESSIONS_CHECKOUT = 'payment.checkout-sessions:checkout';
|
||||||
|
public const PAYMENT_CHECKOUT_SESSIONS_REVOKE = 'payment.checkout-sessions:revoke';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* v2 API
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* v1 API
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Read authorized user´s email address.
|
||||||
|
public const USERS_READ_EMAIL = 'users:read:email';
|
||||||
|
|
||||||
|
// Manage a authorized user object.
|
||||||
|
public const USERS_EDIT = 'users:edit';
|
||||||
|
|
||||||
|
// also available in v3
|
||||||
|
// public const USERS_CREATE = 'users:create';
|
||||||
|
|
||||||
|
// Read authorized user´s transactions.
|
||||||
|
public const TRANSACTIONS_READ = 'transactions:read';
|
||||||
|
|
||||||
|
// Create a new charge for the authorized user.
|
||||||
|
public const CHARGES_CREATE = 'charges:create';
|
||||||
|
|
||||||
|
/*
|
||||||
|
* v0 API
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Deprecated scope.
|
||||||
|
public const API = 'api';
|
||||||
|
|
||||||
|
// Read nonpublic user information, including email address.
|
||||||
|
public const READ_USER = 'read_user';
|
||||||
|
}
|
||||||
41
src/Accounts/Exceptions/MissingScopeException.php
Normal file
41
src/Accounts/Exceptions/MissingScopeException.php
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Bitinflow\Accounts\Exceptions;
|
||||||
|
|
||||||
|
use Illuminate\Auth\Access\AuthorizationException;
|
||||||
|
use Illuminate\Support\Arr;
|
||||||
|
|
||||||
|
class MissingScopeException extends AuthorizationException
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* The scopes that the user did not have.
|
||||||
|
*
|
||||||
|
* @var array
|
||||||
|
*/
|
||||||
|
protected $scopes;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new missing scope exception.
|
||||||
|
*
|
||||||
|
* @param array|string $scopes
|
||||||
|
* @param string $message
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function __construct($scopes = [], $message = 'Invalid scope(s) provided.')
|
||||||
|
{
|
||||||
|
parent::__construct($message);
|
||||||
|
|
||||||
|
$this->scopes = Arr::wrap($scopes);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the scopes that the user did not have.
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function scopes()
|
||||||
|
{
|
||||||
|
return $this->scopes;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
declare(strict_types=1);
|
declare(strict_types=1);
|
||||||
|
|
||||||
namespace GhostZero\BitinflowAccounts\Exceptions;
|
namespace Bitinflow\Accounts\Exceptions;
|
||||||
|
|
||||||
use Exception;
|
use Exception;
|
||||||
|
|
||||||
27
src/Accounts/Exceptions/RequestFreshAccessTokenException.php
Normal file
27
src/Accounts/Exceptions/RequestFreshAccessTokenException.php
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Bitinflow\Accounts\Exceptions;
|
||||||
|
|
||||||
|
use DomainException;
|
||||||
|
use Psr\Http\Message\ResponseInterface;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author René Preuß <rene@bitinflow.com>
|
||||||
|
*/
|
||||||
|
class RequestFreshAccessTokenException extends DomainException
|
||||||
|
{
|
||||||
|
private ResponseInterface $response;
|
||||||
|
|
||||||
|
public static function fromResponse(ResponseInterface $response): self
|
||||||
|
{
|
||||||
|
$instance = new self(sprintf('Refresh token request from bitinflow accounts failed. Status Code is %s.', $response->getStatusCode()));
|
||||||
|
$instance->response = $response;
|
||||||
|
|
||||||
|
return $instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getResponse(): ResponseInterface
|
||||||
|
{
|
||||||
|
return $this->response;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
declare(strict_types=1);
|
declare(strict_types=1);
|
||||||
|
|
||||||
namespace GhostZero\BitinflowAccounts\Exceptions;
|
namespace Bitinflow\Accounts\Exceptions;
|
||||||
|
|
||||||
use Exception;
|
use Exception;
|
||||||
|
|
||||||
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
declare(strict_types=1);
|
declare(strict_types=1);
|
||||||
|
|
||||||
namespace GhostZero\BitinflowAccounts\Exceptions;
|
namespace Bitinflow\Accounts\Exceptions;
|
||||||
|
|
||||||
use Exception;
|
use Exception;
|
||||||
|
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace Bitinflow\Accounts\Exceptions;
|
||||||
|
|
||||||
|
use Exception;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author René Preuß <rene@preuss.io>
|
||||||
|
*/
|
||||||
|
class RequestRequiresMissingParametersException extends Exception
|
||||||
|
{
|
||||||
|
public function __construct($message = 'Request requires missing parameters', $code = 0, Exception $previous = null)
|
||||||
|
{
|
||||||
|
parent::__construct($message, $code, $previous);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function fromValidateRequired(array $given, array $required): RequestRequiresMissingParametersException
|
||||||
|
{
|
||||||
|
return new self(sprintf(
|
||||||
|
'Request requires missing parameters. Required: %s. Given: %s',
|
||||||
|
implode(', ', $required),
|
||||||
|
implode(', ', $given)
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
declare(strict_types=1);
|
declare(strict_types=1);
|
||||||
|
|
||||||
namespace GhostZero\BitinflowAccounts\Exceptions;
|
namespace Bitinflow\Accounts\Exceptions;
|
||||||
|
|
||||||
use Exception;
|
use Exception;
|
||||||
|
|
||||||
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
declare(strict_types=1);
|
declare(strict_types=1);
|
||||||
|
|
||||||
namespace GhostZero\BitinflowAccounts\Exceptions;
|
namespace Bitinflow\Accounts\Exceptions;
|
||||||
|
|
||||||
use Exception;
|
use Exception;
|
||||||
|
|
||||||
23
src/Accounts/Facades/BitinflowAccounts.php
Normal file
23
src/Accounts/Facades/BitinflowAccounts.php
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace Bitinflow\Accounts\Facades;
|
||||||
|
|
||||||
|
use Bitinflow\Accounts\BitinflowAccounts as BitinflowAccountsService;
|
||||||
|
use Illuminate\Contracts\Auth\Authenticatable;
|
||||||
|
use Illuminate\Support\Facades\Facade;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @method static string|static cookie(string $cookie = null)
|
||||||
|
* @method static Authenticatable actingAs($user, $scopes = [], $guard = 'api')
|
||||||
|
* @method static static withClientId(string $clientId): self
|
||||||
|
* @method static string getClientSecret(): string
|
||||||
|
*/
|
||||||
|
class BitinflowAccounts extends Facade
|
||||||
|
{
|
||||||
|
protected static function getFacadeAccessor()
|
||||||
|
{
|
||||||
|
return BitinflowAccountsService::class;
|
||||||
|
}
|
||||||
|
}
|
||||||
39
src/Accounts/Helpers/JwtParser.php
Normal file
39
src/Accounts/Helpers/JwtParser.php
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
|
||||||
|
namespace Bitinflow\Accounts\Helpers;
|
||||||
|
|
||||||
|
|
||||||
|
use Firebase\JWT\JWT;
|
||||||
|
use Firebase\JWT\Key;
|
||||||
|
use Illuminate\Auth\AuthenticationException;
|
||||||
|
use Illuminate\Http\Request;
|
||||||
|
use stdClass;
|
||||||
|
use Throwable;
|
||||||
|
|
||||||
|
class JwtParser
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @param Request $request
|
||||||
|
* @return stdClass
|
||||||
|
* @throws AuthenticationException
|
||||||
|
*/
|
||||||
|
public function decode(Request $request): stdClass
|
||||||
|
{
|
||||||
|
JWT::$leeway = 60;
|
||||||
|
|
||||||
|
try {
|
||||||
|
return JWT::decode(
|
||||||
|
$request->bearerToken(),
|
||||||
|
new Key($this->getOauthPublicKey(), 'RS256')
|
||||||
|
);
|
||||||
|
} catch (Throwable $exception) {
|
||||||
|
throw (new AuthenticationException());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private function getOauthPublicKey()
|
||||||
|
{
|
||||||
|
return file_get_contents(dirname(__DIR__, 3) . '/oauth-public.key');
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -2,9 +2,9 @@
|
|||||||
|
|
||||||
declare(strict_types=1);
|
declare(strict_types=1);
|
||||||
|
|
||||||
namespace GhostZero\BitinflowAccounts\Helpers;
|
namespace Bitinflow\Accounts\Helpers;
|
||||||
|
|
||||||
use GhostZero\BitinflowAccounts\Result;
|
use Bitinflow\Accounts\Result;
|
||||||
use stdClass;
|
use stdClass;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -13,17 +13,18 @@ use stdClass;
|
|||||||
class Paginator
|
class Paginator
|
||||||
{
|
{
|
||||||
|
|
||||||
/**
|
|
||||||
* bitinflow Accounts response pagination cursor.
|
|
||||||
* @var null|stdClass
|
|
||||||
*/
|
|
||||||
private $pagination;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Next desired action (first, after, before).
|
* Next desired action (first, after, before).
|
||||||
|
*
|
||||||
* @var null|string
|
* @var null|string
|
||||||
*/
|
*/
|
||||||
public $action = null;
|
public $action = null;
|
||||||
|
/**
|
||||||
|
* bitinflow Accounts response pagination cursor.
|
||||||
|
*
|
||||||
|
* @var null|stdClass
|
||||||
|
*/
|
||||||
|
private $pagination;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor.
|
* Constructor.
|
||||||
@@ -49,6 +50,7 @@ class Paginator
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Return the current active cursor.
|
* Return the current active cursor.
|
||||||
|
*
|
||||||
* @return string bitinflow Accounts cursor
|
* @return string bitinflow Accounts cursor
|
||||||
*/
|
*/
|
||||||
public function cursor(): string
|
public function cursor(): string
|
||||||
@@ -58,6 +60,7 @@ class Paginator
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Set the Paginator to fetch the next set of results.
|
* Set the Paginator to fetch the next set of results.
|
||||||
|
*
|
||||||
* @return self
|
* @return self
|
||||||
*/
|
*/
|
||||||
public function first(): self
|
public function first(): self
|
||||||
@@ -69,6 +72,7 @@ class Paginator
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Set the Paginator to fetch the first set of results.
|
* Set the Paginator to fetch the first set of results.
|
||||||
|
*
|
||||||
* @return self
|
* @return self
|
||||||
*/
|
*/
|
||||||
public function next(): self
|
public function next(): self
|
||||||
@@ -80,6 +84,7 @@ class Paginator
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Set the Paginator to fetch the last set of results.
|
* Set the Paginator to fetch the last set of results.
|
||||||
|
*
|
||||||
* @return self
|
* @return self
|
||||||
*/
|
*/
|
||||||
public function back(): self
|
public function back(): self
|
||||||
32
src/Accounts/Http/Middleware/CheckClientCredentials.php
Normal file
32
src/Accounts/Http/Middleware/CheckClientCredentials.php
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Bitinflow\Accounts\Http\Middleware;
|
||||||
|
|
||||||
|
use Bitinflow\Accounts\Exceptions\MissingScopeException;
|
||||||
|
use stdClass;
|
||||||
|
|
||||||
|
class CheckClientCredentials extends CheckCredentials
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Validate token credentials.
|
||||||
|
*
|
||||||
|
* @param stdClass $token
|
||||||
|
* @param array $scopes
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
* @throws MissingScopeException
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
protected function validateScopes(stdClass $token, array $scopes)
|
||||||
|
{
|
||||||
|
if (in_array('*', $token->scopes)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach ($scopes as $scope) {
|
||||||
|
if (!in_array($scope, $token->scopes)) {
|
||||||
|
throw new MissingScopeException($scopes);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,34 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Bitinflow\Accounts\Http\Middleware;
|
||||||
|
|
||||||
|
use Bitinflow\Accounts\Exceptions\MissingScopeException;
|
||||||
|
use stdClass;
|
||||||
|
|
||||||
|
class CheckClientCredentialsForAnyScope extends CheckCredentials
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Validate token credentials.
|
||||||
|
*
|
||||||
|
* @param stdClass $token
|
||||||
|
* @param array $scopes
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
* @throws MissingScopeException
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
protected function validateScopes(stdClass $token, array $scopes)
|
||||||
|
{
|
||||||
|
if (in_array('*', $token->scopes)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach ($scopes as $scope) {
|
||||||
|
if (in_array($scope, $token->scopes)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new MissingScopeException($scopes);
|
||||||
|
}
|
||||||
|
}
|
||||||
46
src/Accounts/Http/Middleware/CheckCredentials.php
Normal file
46
src/Accounts/Http/Middleware/CheckCredentials.php
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Bitinflow\Accounts\Http\Middleware;
|
||||||
|
|
||||||
|
use Bitinflow\Accounts\Exceptions\MissingScopeException;
|
||||||
|
use Bitinflow\Accounts\Helpers\JwtParser;
|
||||||
|
use Closure;
|
||||||
|
use Illuminate\Auth\AuthenticationException;
|
||||||
|
use Illuminate\Http\Request;
|
||||||
|
use stdClass;
|
||||||
|
|
||||||
|
abstract class CheckCredentials
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Handle an incoming request.
|
||||||
|
*
|
||||||
|
* @param Request $request
|
||||||
|
* @param Closure $next
|
||||||
|
* @param mixed ...$scopes
|
||||||
|
*
|
||||||
|
* @return mixed
|
||||||
|
* @throws AuthenticationException|MissingScopeException
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public function handle($request, Closure $next, ...$scopes)
|
||||||
|
{
|
||||||
|
$decoded = $this->getJwtParser()->decode($request);
|
||||||
|
|
||||||
|
$request->attributes->set('oauth_access_token_id', $decoded->jti);
|
||||||
|
$request->attributes->set('oauth_client_id', $decoded->aud);
|
||||||
|
//$request->attributes->set('oauth_client_trusted', $decoded->client->trusted);
|
||||||
|
$request->attributes->set('oauth_user_id', $decoded->sub);
|
||||||
|
$request->attributes->set('oauth_scopes', $decoded->scopes);
|
||||||
|
|
||||||
|
$this->validateScopes($decoded, $scopes);
|
||||||
|
|
||||||
|
return $next($request);
|
||||||
|
}
|
||||||
|
|
||||||
|
private function getJwtParser(): JwtParser
|
||||||
|
{
|
||||||
|
return app(JwtParser::class);
|
||||||
|
}
|
||||||
|
|
||||||
|
abstract protected function validateScopes(stdClass $token, array $scopes);
|
||||||
|
}
|
||||||
39
src/Accounts/Http/Middleware/CheckForAnyScope.php
Normal file
39
src/Accounts/Http/Middleware/CheckForAnyScope.php
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
|
||||||
|
namespace Bitinflow\Accounts\Http\Middleware;
|
||||||
|
|
||||||
|
|
||||||
|
use Bitinflow\Accounts\Exceptions\MissingScopeException;
|
||||||
|
use Closure;
|
||||||
|
use Illuminate\Auth\AuthenticationException;
|
||||||
|
use Illuminate\Http\Request;
|
||||||
|
use Illuminate\Http\Response;
|
||||||
|
|
||||||
|
class CheckForAnyScope
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Handle the incoming request.
|
||||||
|
*
|
||||||
|
* @param Request $request
|
||||||
|
* @param Closure $next
|
||||||
|
* @param mixed ...$scopes
|
||||||
|
* @return Response
|
||||||
|
*
|
||||||
|
* @throws AuthenticationException|MissingScopeException
|
||||||
|
*/
|
||||||
|
public function handle($request, $next, ...$scopes)
|
||||||
|
{
|
||||||
|
if (!$request->user() || !$request->user()->bitinflowToken()) {
|
||||||
|
throw new AuthenticationException;
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach ($scopes as $scope) {
|
||||||
|
if ($request->user()->bitinflowTokenCan($scope)) {
|
||||||
|
return $next($request);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new MissingScopeException($scopes);
|
||||||
|
}
|
||||||
|
}
|
||||||
37
src/Accounts/Http/Middleware/CheckScopes.php
Normal file
37
src/Accounts/Http/Middleware/CheckScopes.php
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Bitinflow\Accounts\Http\Middleware;
|
||||||
|
|
||||||
|
use Bitinflow\Accounts\Exceptions\MissingScopeException;
|
||||||
|
use Closure;
|
||||||
|
use Illuminate\Auth\AuthenticationException;
|
||||||
|
use Illuminate\Http\Request;
|
||||||
|
use Illuminate\Http\Response;
|
||||||
|
|
||||||
|
class CheckScopes
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Handle the incoming request.
|
||||||
|
*
|
||||||
|
* @param Request $request
|
||||||
|
* @param Closure $next
|
||||||
|
* @param mixed ...$scopes
|
||||||
|
* @return Response
|
||||||
|
*
|
||||||
|
* @throws AuthenticationException|MissingScopeException
|
||||||
|
*/
|
||||||
|
public function handle($request, $next, ...$scopes)
|
||||||
|
{
|
||||||
|
if (!$request->user() || !$request->user()->bitinflowToken()) {
|
||||||
|
throw new AuthenticationException;
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach ($scopes as $scope) {
|
||||||
|
if (!$request->user()->bitinflowTokenCan($scope)) {
|
||||||
|
throw new MissingScopeException($scope);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $next($request);
|
||||||
|
}
|
||||||
|
}
|
||||||
117
src/Accounts/Http/Middleware/CreateFreshApiToken.php
Normal file
117
src/Accounts/Http/Middleware/CreateFreshApiToken.php
Normal file
@@ -0,0 +1,117 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Bitinflow\Accounts\Http\Middleware;
|
||||||
|
|
||||||
|
use Bitinflow\Accounts\ApiTokenCookieFactory;
|
||||||
|
use Bitinflow\Accounts\BitinflowAccounts;
|
||||||
|
use Closure;
|
||||||
|
use Illuminate\Http\JsonResponse;
|
||||||
|
use Illuminate\Http\Request;
|
||||||
|
use Illuminate\Http\Response;
|
||||||
|
|
||||||
|
class CreateFreshApiToken
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* The API token cookie factory instance.
|
||||||
|
*
|
||||||
|
* @var ApiTokenCookieFactory
|
||||||
|
*/
|
||||||
|
protected $cookieFactory;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The authentication guard.
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
protected $guard;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new middleware instance.
|
||||||
|
*
|
||||||
|
* @param ApiTokenCookieFactory $cookieFactory
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function __construct(ApiTokenCookieFactory $cookieFactory)
|
||||||
|
{
|
||||||
|
$this->cookieFactory = $cookieFactory;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handle an incoming request.
|
||||||
|
*
|
||||||
|
* @param Request $request
|
||||||
|
* @param Closure $next
|
||||||
|
* @param string|null $guard
|
||||||
|
* @return mixed
|
||||||
|
*/
|
||||||
|
public function handle($request, Closure $next, $guard = null)
|
||||||
|
{
|
||||||
|
$this->guard = $guard;
|
||||||
|
|
||||||
|
$response = $next($request);
|
||||||
|
|
||||||
|
if ($this->shouldReceiveFreshToken($request, $response)) {
|
||||||
|
$response->withCookie($this->cookieFactory->make(
|
||||||
|
$request->user($this->guard)->getAuthIdentifier(), $request->session()->token()
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
return $response;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determine if the given request should receive a fresh token.
|
||||||
|
*
|
||||||
|
* @param Request $request
|
||||||
|
* @param Response $response
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
protected function shouldReceiveFreshToken($request, $response): bool
|
||||||
|
{
|
||||||
|
return $this->requestShouldReceiveFreshToken($request) &&
|
||||||
|
$this->responseShouldReceiveFreshToken($response);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determine if the request should receive a fresh token.
|
||||||
|
*
|
||||||
|
* @param Request $request
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
protected function requestShouldReceiveFreshToken($request)
|
||||||
|
{
|
||||||
|
return $request->isMethod('GET') && $request->user($this->guard);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determine if the response should receive a fresh token.
|
||||||
|
*
|
||||||
|
* @param Response $response
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
protected function responseShouldReceiveFreshToken($response)
|
||||||
|
{
|
||||||
|
return ($response instanceof Response ||
|
||||||
|
$response instanceof JsonResponse) &&
|
||||||
|
!$this->alreadyContainsToken($response);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determine if the given response already contains an API token.
|
||||||
|
*
|
||||||
|
* This avoids us overwriting a just "refreshed" token.
|
||||||
|
*
|
||||||
|
* @param Response $response
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
protected function alreadyContainsToken($response): bool
|
||||||
|
{
|
||||||
|
foreach ($response->headers->getCookies() as $cookie) {
|
||||||
|
if ($cookie->getName() === BitinflowAccounts::cookie()) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
96
src/Accounts/Providers/BitinflowAccountsServiceProvider.php
Normal file
96
src/Accounts/Providers/BitinflowAccountsServiceProvider.php
Normal file
@@ -0,0 +1,96 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace Bitinflow\Accounts\Providers;
|
||||||
|
|
||||||
|
use Bitinflow\Accounts\Auth\TokenGuard;
|
||||||
|
use Bitinflow\Accounts\Auth\UserProvider;
|
||||||
|
use Bitinflow\Accounts\BitinflowAccounts;
|
||||||
|
use Bitinflow\Accounts\Helpers\JwtParser;
|
||||||
|
use Bitinflow\Accounts\Contracts;
|
||||||
|
use Bitinflow\Accounts\Repository;
|
||||||
|
use Bitinflow\Payments\BitinflowPayments;
|
||||||
|
use Illuminate\Auth\RequestGuard;
|
||||||
|
use Illuminate\Support\Facades\Auth;
|
||||||
|
use Illuminate\Support\ServiceProvider;
|
||||||
|
|
||||||
|
class BitinflowAccountsServiceProvider extends ServiceProvider
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Bootstrap the application services.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function boot()
|
||||||
|
{
|
||||||
|
$this->publishes([
|
||||||
|
dirname(__DIR__, 3) . '/config/bitinflow-accounts.php' => config_path('bitinflow-accounts.php'),
|
||||||
|
], 'config');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Register the application services.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function register()
|
||||||
|
{
|
||||||
|
$this->mergeConfigFrom(dirname(__DIR__, 3) . '/config/bitinflow-accounts.php', 'bitinflow-accounts');
|
||||||
|
$this->app->singleton(Contracts\AppTokenRepository::class, Repository\AppTokenRepository::class);
|
||||||
|
$this->app->singleton(BitinflowAccounts::class, function () {
|
||||||
|
return new BitinflowAccounts;
|
||||||
|
});
|
||||||
|
$this->app->singleton(BitinflowPayments::class, function () {
|
||||||
|
return new BitinflowPayments;
|
||||||
|
});
|
||||||
|
|
||||||
|
$this->registerGuard();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Register the token guard.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
protected function registerGuard()
|
||||||
|
{
|
||||||
|
Auth::resolved(function ($auth) {
|
||||||
|
$auth->extend('bitinflow-accounts', function ($app, $name, array $config) {
|
||||||
|
return tap($this->makeGuard($config), function ($guard) {
|
||||||
|
$this->app->refresh('request', $guard, 'setRequest');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Make an instance of the token guard.
|
||||||
|
*
|
||||||
|
* @param array $config
|
||||||
|
* @return RequestGuard
|
||||||
|
*/
|
||||||
|
protected function makeGuard(array $config): RequestGuard
|
||||||
|
{
|
||||||
|
return new RequestGuard(function ($request) use ($config) {
|
||||||
|
return (new TokenGuard(
|
||||||
|
new UserProvider(Auth::createUserProvider($config['provider']), $config['provider']),
|
||||||
|
$this->app->make('encrypter'),
|
||||||
|
$this->app->make(JwtParser::class)
|
||||||
|
))->user($request);
|
||||||
|
}, $this->app['request']);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the services provided by the provider.
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function provides()
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
BitinflowAccounts::class,
|
||||||
|
BitinflowPayments::class,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
126
src/Accounts/Providers/BitinflowAccountsSsoUserProvider.php
Normal file
126
src/Accounts/Providers/BitinflowAccountsSsoUserProvider.php
Normal file
@@ -0,0 +1,126 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace Bitinflow\Accounts\Providers;
|
||||||
|
|
||||||
|
use Bitinflow\Accounts\BitinflowAccounts;
|
||||||
|
use Illuminate\Contracts\Auth\Authenticatable;
|
||||||
|
use Illuminate\Contracts\Auth\UserProvider;
|
||||||
|
use Illuminate\Database\Eloquent\Builder;
|
||||||
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
use Illuminate\Http\Request;
|
||||||
|
use Illuminate\Support\Arr;
|
||||||
|
|
||||||
|
class BitinflowAccountsSsoUserProvider implements UserProvider
|
||||||
|
{
|
||||||
|
private $bitinflowAccounts;
|
||||||
|
private $accessTokenField = null;
|
||||||
|
private $fields;
|
||||||
|
private $model;
|
||||||
|
private $request;
|
||||||
|
|
||||||
|
public function __construct(
|
||||||
|
BitinflowAccounts $bitinflowAccounts,
|
||||||
|
Request $request,
|
||||||
|
string $model,
|
||||||
|
array $fields,
|
||||||
|
?string $accessTokenField = null
|
||||||
|
) {
|
||||||
|
$this->request = $request;
|
||||||
|
$this->model = $model;
|
||||||
|
$this->fields = $fields;
|
||||||
|
$this->accessTokenField = $accessTokenField;
|
||||||
|
$this->bitinflowAccounts = $bitinflowAccounts;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param mixed $identifier
|
||||||
|
* @return Builder|Model|object|null
|
||||||
|
*/
|
||||||
|
public function retrieveById($identifier)
|
||||||
|
{
|
||||||
|
$model = $this->createModel();
|
||||||
|
$token = $this->request->bearerToken();
|
||||||
|
|
||||||
|
$user = $this->newModelQuery($model)
|
||||||
|
->where($model->getAuthIdentifierName(), $identifier)
|
||||||
|
->first();
|
||||||
|
|
||||||
|
// Return user when found
|
||||||
|
if ($user) {
|
||||||
|
// Update access token when updated
|
||||||
|
if ($this->accessTokenField) {
|
||||||
|
$user[$this->accessTokenField] = $token;
|
||||||
|
|
||||||
|
if ($user->isDirty()) {
|
||||||
|
$user->save();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $user;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create new user
|
||||||
|
$this->bitinflowAccounts->setToken($token);
|
||||||
|
$result = $this->bitinflowAccounts->getAuthedUser();
|
||||||
|
|
||||||
|
if (!$result->success()) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
$attributes = Arr::only((array)$result->data(), $this->fields);
|
||||||
|
$attributes[$model->getAuthIdentifierName()] = $result->data->id;
|
||||||
|
|
||||||
|
if ($this->accessTokenField) {
|
||||||
|
$attributes[$this->accessTokenField] = $token;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->newModelQuery($model)->create($attributes);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new instance of the model.
|
||||||
|
*
|
||||||
|
* @return Model
|
||||||
|
*/
|
||||||
|
public function createModel(): Model
|
||||||
|
{
|
||||||
|
$class = '\\' . ltrim($this->model, '\\');
|
||||||
|
|
||||||
|
return new $class;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get a new query builder for the model instance.
|
||||||
|
*
|
||||||
|
* @param Model|null $model
|
||||||
|
* @return Builder
|
||||||
|
*/
|
||||||
|
protected function newModelQuery(Model $model = null): Builder
|
||||||
|
{
|
||||||
|
return is_null($model)
|
||||||
|
? $this->createModel()->newQuery()
|
||||||
|
: $model->newQuery();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function retrieveByToken($identifier, $token)
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function updateRememberToken(Authenticatable $user, $token)
|
||||||
|
{
|
||||||
|
// void
|
||||||
|
}
|
||||||
|
|
||||||
|
public function retrieveByCredentials(array $credentials)
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function validateCredentials(Authenticatable $user, array $credentials)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
61
src/Accounts/Repository/AppTokenRepository.php
Normal file
61
src/Accounts/Repository/AppTokenRepository.php
Normal file
@@ -0,0 +1,61 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Bitinflow\Accounts\Repository;
|
||||||
|
|
||||||
|
use Bitinflow\Accounts\BitinflowAccounts;
|
||||||
|
use Bitinflow\Accounts\Contracts\AppTokenRepository as Repository;
|
||||||
|
use Bitinflow\Accounts\Exceptions\RequestFreshAccessTokenException;
|
||||||
|
use Illuminate\Support\Facades\Cache;
|
||||||
|
|
||||||
|
class AppTokenRepository implements Repository
|
||||||
|
{
|
||||||
|
public const ACCESS_TOKEN_CACHE_KEY = 'bitinflow-accounts:access_token';
|
||||||
|
|
||||||
|
private BitinflowAccounts $client;
|
||||||
|
|
||||||
|
public function __construct()
|
||||||
|
{
|
||||||
|
$this->client = app(BitinflowAccounts::class);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*/
|
||||||
|
public function getAccessToken(): string
|
||||||
|
{
|
||||||
|
$accessToken = Cache::get(self::ACCESS_TOKEN_CACHE_KEY);
|
||||||
|
|
||||||
|
if ($accessToken) {
|
||||||
|
return $accessToken;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->requestFreshAccessToken('*');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string $scope
|
||||||
|
*
|
||||||
|
* @throws RequestFreshAccessTokenException
|
||||||
|
*
|
||||||
|
* @return mixed
|
||||||
|
*/
|
||||||
|
private function requestFreshAccessToken(string $scope)
|
||||||
|
{
|
||||||
|
$result = $this->getClient()->retrievingToken('client_credentials', [
|
||||||
|
'scope' => $scope,
|
||||||
|
]);
|
||||||
|
|
||||||
|
if ( ! $result->success()) {
|
||||||
|
throw RequestFreshAccessTokenException::fromResponse($result->response());
|
||||||
|
}
|
||||||
|
|
||||||
|
Cache::put(self::ACCESS_TOKEN_CACHE_KEY, $accessToken = $result->data()->access_token, now()->addWeek());
|
||||||
|
|
||||||
|
return $accessToken;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function getClient(): BitinflowAccounts
|
||||||
|
{
|
||||||
|
return $this->client;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -2,11 +2,11 @@
|
|||||||
|
|
||||||
declare(strict_types=1);
|
declare(strict_types=1);
|
||||||
|
|
||||||
namespace GhostZero\BitinflowAccounts;
|
namespace Bitinflow\Accounts;
|
||||||
|
|
||||||
|
use Bitinflow\Accounts\Helpers\Paginator;
|
||||||
use Exception;
|
use Exception;
|
||||||
use GhostZero\BitinflowAccounts\Helpers\Paginator;
|
use Psr\Http\Message\ResponseInterface;
|
||||||
use GuzzleHttp\Psr7\Response;
|
|
||||||
use stdClass;
|
use stdClass;
|
||||||
|
|
||||||
|
|
||||||
@@ -17,55 +17,64 @@ class Result
|
|||||||
{
|
{
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Query successfull.
|
* Query successful.
|
||||||
|
*
|
||||||
* @var boolean
|
* @var boolean
|
||||||
*/
|
*/
|
||||||
public $success = false;
|
public $success = false;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Guzzle exception, if present.
|
* Guzzle exception, if present.
|
||||||
|
*
|
||||||
* @var null|mixed
|
* @var null|mixed
|
||||||
*/
|
*/
|
||||||
public $exception = null;
|
public $exception = null;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Query result data.
|
* Query result data.
|
||||||
|
*
|
||||||
* @var array
|
* @var array
|
||||||
*/
|
*/
|
||||||
public $data = [];
|
public $data = [];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Total amount of result data.
|
* Total amount of result data.
|
||||||
|
*
|
||||||
* @var integer
|
* @var integer
|
||||||
*/
|
*/
|
||||||
public $total = 0;
|
public $total = 0;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Status Code.
|
* Status Code.
|
||||||
|
*
|
||||||
* @var integer
|
* @var integer
|
||||||
*/
|
*/
|
||||||
public $status = 0;
|
public $status = 0;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* bitinflow Accounts response pagination cursor.
|
* bitinflow Accounts response pagination cursor.
|
||||||
* @var null|\stdClass
|
*
|
||||||
|
* @var null|stdClass
|
||||||
*/
|
*/
|
||||||
public $pagination;
|
public $pagination;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Internal paginator.
|
* Internal paginator.
|
||||||
|
*
|
||||||
* @var null|Paginator
|
* @var null|Paginator
|
||||||
*/
|
*/
|
||||||
public $paginator;
|
public $paginator;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Original Guzzle HTTP Response.
|
* Original Guzzle HTTP Response.
|
||||||
* @var Response
|
*
|
||||||
|
* @var ResponseInterface|null
|
||||||
*/
|
*/
|
||||||
public $response;
|
public $response;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Original bitinflow Accounts instance.
|
* Original bitinflow Accounts instance.
|
||||||
|
*
|
||||||
* @var BitinflowAccounts
|
* @var BitinflowAccounts
|
||||||
*/
|
*/
|
||||||
public $bitinflow;
|
public $bitinflow;
|
||||||
@@ -73,17 +82,17 @@ class Result
|
|||||||
/**
|
/**
|
||||||
* Constructor,
|
* Constructor,
|
||||||
*
|
*
|
||||||
* @param Response $response HTTP response
|
* @param ResponseInterface|null $response HTTP response
|
||||||
* @param Exception|mixed $exception Exception, if present
|
* @param Exception|mixed $exception Exception, if present
|
||||||
* @param null|Paginator $paginator Paginator, if present
|
* @param null|Paginator $paginator Paginator, if present
|
||||||
*/
|
*/
|
||||||
public function __construct(Response $response, Exception $exception = null, Paginator $paginator = null)
|
public function __construct(?ResponseInterface $response, Exception $exception = null, Paginator $paginator = null)
|
||||||
{
|
{
|
||||||
$this->response = $response;
|
$this->response = $response;
|
||||||
$this->success = $exception === null;
|
$this->success = $exception === null;
|
||||||
$this->exception = $exception;
|
$this->exception = $exception;
|
||||||
$this->status = $response->getStatusCode();
|
$this->status = $response ? $response->getStatusCode() : 500;
|
||||||
$jsonResponse = @json_decode($response->getBody()->getContents());
|
$jsonResponse = $response ? @json_decode($response->getBody()->getContents(), false) : null;
|
||||||
if ($jsonResponse !== null) {
|
if ($jsonResponse !== null) {
|
||||||
$this->setProperty($jsonResponse, 'data');
|
$this->setProperty($jsonResponse, 'data');
|
||||||
$this->setProperty($jsonResponse, 'total');
|
$this->setProperty($jsonResponse, 'total');
|
||||||
@@ -99,10 +108,10 @@ class Result
|
|||||||
* @param string $responseProperty Response property name
|
* @param string $responseProperty Response property name
|
||||||
* @param string|null $attribute Class property name
|
* @param string|null $attribute Class property name
|
||||||
*/
|
*/
|
||||||
private function setProperty(stdClass $jsonResponse, string $responseProperty, string $attribute = null)
|
private function setProperty(stdClass $jsonResponse, string $responseProperty, string $attribute = null): void
|
||||||
{
|
{
|
||||||
$classAttribute = $attribute ?? $responseProperty;
|
$classAttribute = $attribute ?? $responseProperty;
|
||||||
if (!empty($jsonResponse) && property_exists($jsonResponse, $responseProperty)) {
|
if (property_exists($jsonResponse, $responseProperty)) {
|
||||||
$this->{$classAttribute} = $jsonResponse->{$responseProperty};
|
$this->{$classAttribute} = $jsonResponse->{$responseProperty};
|
||||||
} elseif ($responseProperty === 'data') {
|
} elseif ($responseProperty === 'data') {
|
||||||
$this->{$classAttribute} = $jsonResponse;
|
$this->{$classAttribute} = $jsonResponse;
|
||||||
@@ -110,7 +119,8 @@ class Result
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns wether the query was successfull.
|
* Returns whether the query was successfully.
|
||||||
|
*
|
||||||
* @return bool Success state
|
* @return bool Success state
|
||||||
*/
|
*/
|
||||||
public function success(): bool
|
public function success(): bool
|
||||||
@@ -120,6 +130,7 @@ class Result
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the response data, also available as public attribute.
|
* Get the response data, also available as public attribute.
|
||||||
|
*
|
||||||
* @return mixed
|
* @return mixed
|
||||||
*/
|
*/
|
||||||
public function data()
|
public function data()
|
||||||
@@ -129,6 +140,7 @@ class Result
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the last HTTP or API error.
|
* Returns the last HTTP or API error.
|
||||||
|
*
|
||||||
* @return string Error message
|
* @return string Error message
|
||||||
*/
|
*/
|
||||||
public function error(): string
|
public function error(): string
|
||||||
@@ -148,6 +160,7 @@ class Result
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Shifts the current result (Use for single user/video etc. query).
|
* Shifts the current result (Use for single user/video etc. query).
|
||||||
|
*
|
||||||
* @return mixed Shifted data
|
* @return mixed Shifted data
|
||||||
*/
|
*/
|
||||||
public function shift()
|
public function shift()
|
||||||
@@ -163,6 +176,7 @@ class Result
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Return the current count of items in dataset.
|
* Return the current count of items in dataset.
|
||||||
|
*
|
||||||
* @return int Count
|
* @return int Count
|
||||||
*/
|
*/
|
||||||
public function count(): int
|
public function count(): int
|
||||||
@@ -170,29 +184,18 @@ class Result
|
|||||||
return count((array)$this->data);
|
return count((array)$this->data);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Set the Paginator to fetch the first set of results.
|
|
||||||
* @return null|Paginator
|
|
||||||
*/
|
|
||||||
public function first()
|
|
||||||
{
|
|
||||||
return $this->paginator !== null ? $this->paginator->first() : null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set the Paginator to fetch the next set of results.
|
* Set the Paginator to fetch the next set of results.
|
||||||
* @return null|Paginator
|
|
||||||
*/
|
*/
|
||||||
public function next()
|
public function next(): ?Paginator
|
||||||
{
|
{
|
||||||
return $this->paginator !== null ? $this->paginator->next() : null;
|
return $this->paginator !== null ? $this->paginator->next() : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set the Paginator to fetch the last set of results.
|
* Set the Paginator to fetch the last set of results.
|
||||||
* @return null|Paginator
|
|
||||||
*/
|
*/
|
||||||
public function back()
|
public function back(): ?Paginator
|
||||||
{
|
{
|
||||||
return $this->paginator !== null ? $this->paginator->back() : null;
|
return $this->paginator !== null ? $this->paginator->back() : null;
|
||||||
}
|
}
|
||||||
@@ -226,8 +229,6 @@ class Result
|
|||||||
*
|
*
|
||||||
* @param string $identifierAttribute Attribute to identify the users
|
* @param string $identifierAttribute Attribute to identify the users
|
||||||
* @param string $insertTo Data index to insert user data
|
* @param string $insertTo Data index to insert user data
|
||||||
*
|
|
||||||
* @return self
|
|
||||||
*/
|
*/
|
||||||
public function insertUsers(string $identifierAttribute = 'user_id', string $insertTo = 'user'): self
|
public function insertUsers(string $identifierAttribute = 'user_id', string $insertTo = 'user'): self
|
||||||
{
|
{
|
||||||
@@ -235,7 +236,7 @@ class Result
|
|||||||
$userIds = collect($data)->map(function ($item) use ($identifierAttribute) {
|
$userIds = collect($data)->map(function ($item) use ($identifierAttribute) {
|
||||||
return $item->{$identifierAttribute};
|
return $item->{$identifierAttribute};
|
||||||
})->toArray();
|
})->toArray();
|
||||||
if (count($userIds) == 0) {
|
if (count($userIds) === 0) {
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
$users = collect($this->bitinflow->getUsersByIds($userIds)->data);
|
$users = collect($this->bitinflow->getUsersByIds($userIds)->data);
|
||||||
@@ -248,4 +249,22 @@ class Result
|
|||||||
|
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the Paginator to fetch the first set of results.
|
||||||
|
*/
|
||||||
|
public function first(): ?Paginator
|
||||||
|
{
|
||||||
|
return $this->paginator !== null ? $this->paginator->first() : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function response(): ?ResponseInterface
|
||||||
|
{
|
||||||
|
return $this->response;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function dump()
|
||||||
|
{
|
||||||
|
dump($this->data());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
namespace GhostZero\BitinflowAccounts\Socialite;
|
namespace Bitinflow\Accounts\Socialite;
|
||||||
|
|
||||||
use SocialiteProviders\Manager\SocialiteWasCalled;
|
use SocialiteProviders\Manager\SocialiteWasCalled;
|
||||||
|
|
||||||
@@ -1,8 +1,8 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
namespace GhostZero\BitinflowAccounts\Socialite;
|
namespace Bitinflow\Accounts\Socialite;
|
||||||
|
|
||||||
use GhostZero\BitinflowAccounts\Enums\Scope;
|
use Bitinflow\Accounts\Enums\Scope;
|
||||||
use Illuminate\Support\Arr;
|
use Illuminate\Support\Arr;
|
||||||
use Laravel\Socialite\Two\ProviderInterface;
|
use Laravel\Socialite\Two\ProviderInterface;
|
||||||
use SocialiteProviders\Manager\OAuth2\AbstractProvider;
|
use SocialiteProviders\Manager\OAuth2\AbstractProvider;
|
||||||
@@ -22,7 +22,7 @@ class Provider extends AbstractProvider implements ProviderInterface
|
|||||||
/**
|
/**
|
||||||
* {@inheritdoc}
|
* {@inheritdoc}
|
||||||
*/
|
*/
|
||||||
protected $scopes = [Scope::READ_USER];
|
protected $scopes = [Scope::USER_READ];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* {@inherticdoc}.
|
* {@inherticdoc}.
|
||||||
@@ -53,14 +53,14 @@ class Provider extends AbstractProvider implements ProviderInterface
|
|||||||
protected function getUserByToken($token)
|
protected function getUserByToken($token)
|
||||||
{
|
{
|
||||||
$response = $this->getHttpClient()->get(
|
$response = $this->getHttpClient()->get(
|
||||||
'https://accounts.bitinflow.com/api/user', [
|
'https://accounts.bitinflow.com/api/v3/user', [
|
||||||
'headers' => [
|
'headers' => [
|
||||||
'Accept' => 'application/json',
|
'Accept' => 'application/json',
|
||||||
'Authorization' => 'Bearer ' . $token,
|
'Authorization' => 'Bearer ' . $token,
|
||||||
],
|
],
|
||||||
]);
|
]);
|
||||||
|
|
||||||
return json_decode($response->getBody()->getContents(), true);
|
return json_decode($response->getBody()->getContents(), true)['data'];
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
51
src/Accounts/Traits/HasBitinflowTokens.php
Normal file
51
src/Accounts/Traits/HasBitinflowTokens.php
Normal file
@@ -0,0 +1,51 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Bitinflow\Accounts\Traits;
|
||||||
|
|
||||||
|
use stdClass;
|
||||||
|
|
||||||
|
trait HasBitinflowTokens
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* The current access token for the authentication user.
|
||||||
|
*
|
||||||
|
* @var stdClass
|
||||||
|
*/
|
||||||
|
protected $accessToken;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the current access token being used by the user.
|
||||||
|
*
|
||||||
|
* @return stdClass|null
|
||||||
|
*/
|
||||||
|
public function bitinflowToken(): ?stdClass
|
||||||
|
{
|
||||||
|
return $this->accessToken;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determine if the current API token has a given scope.
|
||||||
|
*
|
||||||
|
* @param string $scope
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function bitinflowTokenCan(string $scope): bool
|
||||||
|
{
|
||||||
|
$scopes = $this->accessToken ? $this->accessToken->scopes : [];
|
||||||
|
|
||||||
|
return in_array('*', $scopes) || in_array($scope, $this->accessToken->scopes);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the current access token for the user.
|
||||||
|
*
|
||||||
|
* @param stdClass $accessToken
|
||||||
|
* @return $this
|
||||||
|
*/
|
||||||
|
public function withBitinflowAccessToken(stdClass $accessToken): self
|
||||||
|
{
|
||||||
|
$this->accessToken = $accessToken;
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
}
|
||||||
44
src/Accounts/Traits/OauthTrait.php
Normal file
44
src/Accounts/Traits/OauthTrait.php
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace Bitinflow\Accounts\Traits;
|
||||||
|
|
||||||
|
use Bitinflow\Accounts\Result;
|
||||||
|
use GuzzleHttp\Exception\RequestException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author René Preuß <rene@preuss.io>
|
||||||
|
*/
|
||||||
|
trait OauthTrait
|
||||||
|
{
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieving a oauth token using a given grant type.
|
||||||
|
*
|
||||||
|
* @param string $grantType
|
||||||
|
* @param array $attributes
|
||||||
|
*
|
||||||
|
* @return Result
|
||||||
|
*/
|
||||||
|
public function retrievingToken(string $grantType, array $attributes): Result
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
$response = $this->client->request('POST', '/oauth/token', [
|
||||||
|
'form_params' => $attributes + [
|
||||||
|
'grant_type' => $grantType,
|
||||||
|
'client_id' => $this->getClientId(),
|
||||||
|
'client_secret' => $this->getClientSecret(),
|
||||||
|
],
|
||||||
|
]);
|
||||||
|
|
||||||
|
$result = new Result($response, null);
|
||||||
|
} catch (RequestException $exception) {
|
||||||
|
$result = new Result($exception->getResponse(), $exception);
|
||||||
|
}
|
||||||
|
|
||||||
|
$result->bitinflow = $this;
|
||||||
|
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -2,12 +2,12 @@
|
|||||||
|
|
||||||
declare(strict_types=1);
|
declare(strict_types=1);
|
||||||
|
|
||||||
namespace GhostZero\BitinflowAccounts\Traits;
|
namespace Bitinflow\Accounts\Traits;
|
||||||
|
|
||||||
use GhostZero\BitinflowAccounts\ApiOperations\Delete;
|
use Bitinflow\Accounts\ApiOperations\Delete;
|
||||||
use GhostZero\BitinflowAccounts\ApiOperations\Get;
|
use Bitinflow\Accounts\ApiOperations\Get;
|
||||||
use GhostZero\BitinflowAccounts\ApiOperations\Post;
|
use Bitinflow\Accounts\ApiOperations\Post;
|
||||||
use GhostZero\BitinflowAccounts\Result;
|
use Bitinflow\Accounts\Result;
|
||||||
|
|
||||||
trait SshKeysTrait
|
trait SshKeysTrait
|
||||||
{
|
{
|
||||||
@@ -27,7 +27,7 @@ trait SshKeysTrait
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get currently authed user with Bearer Token
|
* Creates ssh key for the currently authed user
|
||||||
*
|
*
|
||||||
* @param string $publicKey
|
* @param string $publicKey
|
||||||
* @param string|null $name
|
* @param string|null $name
|
||||||
@@ -43,7 +43,7 @@ trait SshKeysTrait
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get currently authed user with Bearer Token
|
* Deletes a given ssh key for the currently authed user
|
||||||
*
|
*
|
||||||
* @param int $id
|
* @param int $id
|
||||||
*
|
*
|
||||||
50
src/Accounts/Traits/UsersTrait.php
Normal file
50
src/Accounts/Traits/UsersTrait.php
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace Bitinflow\Accounts\Traits;
|
||||||
|
|
||||||
|
use Bitinflow\Accounts\ApiOperations\Get;
|
||||||
|
use Bitinflow\Accounts\Result;
|
||||||
|
|
||||||
|
trait UsersTrait
|
||||||
|
{
|
||||||
|
|
||||||
|
use Get;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get currently authed user with Bearer Token
|
||||||
|
*
|
||||||
|
* @return Result Result object
|
||||||
|
*/
|
||||||
|
public function getAuthedUser(): Result
|
||||||
|
{
|
||||||
|
return $this->get('v3/user');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new user on behalf of the current user.
|
||||||
|
*
|
||||||
|
* @param array $parameters
|
||||||
|
*
|
||||||
|
* @return Result
|
||||||
|
*/
|
||||||
|
public function createUser(array $parameters): Result
|
||||||
|
{
|
||||||
|
return $this->post('v3/users', $parameters);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if the given email exists.
|
||||||
|
*
|
||||||
|
* @param string $email
|
||||||
|
*
|
||||||
|
* @return Result
|
||||||
|
*/
|
||||||
|
public function isEmailExisting(string $email): Result
|
||||||
|
{
|
||||||
|
return $this->post('v3/users/check', [
|
||||||
|
'email' => $email,
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,16 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
declare(strict_types=1);
|
|
||||||
|
|
||||||
namespace GhostZero\BitinflowAccounts\ApiOperations;
|
|
||||||
|
|
||||||
use GhostZero\BitinflowAccounts\Helpers\Paginator;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author René Preuß <rene@preuss.io>
|
|
||||||
*/
|
|
||||||
trait Delete
|
|
||||||
{
|
|
||||||
|
|
||||||
abstract public function delete(string $path = '', array $parameters = [], Paginator $paginator = null);
|
|
||||||
}
|
|
||||||
@@ -1,16 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
declare(strict_types=1);
|
|
||||||
|
|
||||||
namespace GhostZero\BitinflowAccounts\ApiOperations;
|
|
||||||
|
|
||||||
use GhostZero\BitinflowAccounts\Helpers\Paginator;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author René Preuß <rene@preuss.io>
|
|
||||||
*/
|
|
||||||
trait Get
|
|
||||||
{
|
|
||||||
|
|
||||||
abstract public function get(string $path = '', array $parameters = [], Paginator $paginator = null);
|
|
||||||
}
|
|
||||||
@@ -1,16 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
declare(strict_types=1);
|
|
||||||
|
|
||||||
namespace GhostZero\BitinflowAccounts\ApiOperations;
|
|
||||||
|
|
||||||
use GhostZero\BitinflowAccounts\Helpers\Paginator;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author René Preuß <rene@preuss.io>
|
|
||||||
*/
|
|
||||||
trait Post
|
|
||||||
{
|
|
||||||
|
|
||||||
abstract public function post(string $path = '', array $parameters = [], Paginator $paginator = null);
|
|
||||||
}
|
|
||||||
@@ -1,16 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
declare(strict_types=1);
|
|
||||||
|
|
||||||
namespace GhostZero\BitinflowAccounts\ApiOperations;
|
|
||||||
|
|
||||||
use GhostZero\BitinflowAccounts\Helpers\Paginator;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author René Preuß <rene@preuss.io>
|
|
||||||
*/
|
|
||||||
trait Put
|
|
||||||
{
|
|
||||||
|
|
||||||
abstract public function put(string $path = '', array $parameters = [], Paginator $paginator = null);
|
|
||||||
}
|
|
||||||
@@ -1,38 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
declare(strict_types=1);
|
|
||||||
|
|
||||||
namespace GhostZero\BitinflowAccounts\Enums;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author René Preuß <rene@preuss.io>
|
|
||||||
*/
|
|
||||||
class Scope
|
|
||||||
{
|
|
||||||
|
|
||||||
/*
|
|
||||||
* v0 API
|
|
||||||
*/
|
|
||||||
|
|
||||||
// Deprecated scope.
|
|
||||||
const API = 'api';
|
|
||||||
|
|
||||||
// Read nonpublic user information, including email address.
|
|
||||||
const READ_USER = 'read_user';
|
|
||||||
|
|
||||||
/*
|
|
||||||
* v1 API
|
|
||||||
*/
|
|
||||||
|
|
||||||
// Read authorized user´s email address.
|
|
||||||
const USERS_READ_EMAIL = 'users:read:email';
|
|
||||||
|
|
||||||
// Manage a authorized user object.
|
|
||||||
const USERS_EDIT = 'users:edit';
|
|
||||||
|
|
||||||
// Read authorized user´s transactions.
|
|
||||||
const TRANSACTIONS_READ = 'transactions:read';
|
|
||||||
|
|
||||||
// Create a new charge for the authorized user.
|
|
||||||
const CHARGES_CREATE = 'charges:create';
|
|
||||||
}
|
|
||||||
@@ -1,20 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
declare(strict_types=1);
|
|
||||||
|
|
||||||
namespace GhostZero\BitinflowAccounts\Facades;
|
|
||||||
|
|
||||||
use GhostZero\BitinflowAccounts\BitinflowAccounts as BitinflowAccountsService;
|
|
||||||
use Illuminate\Support\Facades\Facade;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author René Preuß <rene@preuss.io>
|
|
||||||
*/
|
|
||||||
class BitinflowAccounts extends Facade
|
|
||||||
{
|
|
||||||
|
|
||||||
protected static function getFacadeAccessor()
|
|
||||||
{
|
|
||||||
return BitinflowAccountsService::class;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,46 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
declare(strict_types=1);
|
|
||||||
|
|
||||||
namespace GhostZero\BitinflowAccounts\Providers;
|
|
||||||
|
|
||||||
use GhostZero\BitinflowAccounts\BitinflowAccounts;
|
|
||||||
use Illuminate\Support\ServiceProvider;
|
|
||||||
|
|
||||||
class BitinflowAccountsServiceProvider extends ServiceProvider
|
|
||||||
{
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Bootstrap the application services.
|
|
||||||
* @return void
|
|
||||||
*/
|
|
||||||
public function boot()
|
|
||||||
{
|
|
||||||
$this->publishes([
|
|
||||||
dirname(__DIR__) . '/../../../config/bitinflow-accounts-api.php' => config_path('bitinflow-accounts-api.php'),
|
|
||||||
], 'config');
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Register the application services.
|
|
||||||
* @return void
|
|
||||||
*/
|
|
||||||
public function register()
|
|
||||||
{
|
|
||||||
$this->mergeConfigFrom(
|
|
||||||
dirname(__DIR__) . '/../../../config/bitinflow-accounts-api.php', 'bitinflow-accounts-api'
|
|
||||||
);
|
|
||||||
$this->app->singleton(BitinflowAccounts::class, function () {
|
|
||||||
return new BitinflowAccounts;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the services provided by the provider.
|
|
||||||
* @return array
|
|
||||||
*/
|
|
||||||
public function provides()
|
|
||||||
{
|
|
||||||
return [BitinflowAccounts::class];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,69 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
declare(strict_types=1);
|
|
||||||
|
|
||||||
namespace GhostZero\BitinflowAccounts\Traits;
|
|
||||||
|
|
||||||
use GhostZero\BitinflowAccounts\ApiOperations\Get;
|
|
||||||
use GhostZero\BitinflowAccounts\ApiOperations\Post;
|
|
||||||
use GhostZero\BitinflowAccounts\ApiOperations\Put;
|
|
||||||
use GhostZero\BitinflowAccounts\Result;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author René Preuß <rene@preuss.io>
|
|
||||||
*/
|
|
||||||
trait ChargesTrait
|
|
||||||
{
|
|
||||||
|
|
||||||
use Get, Post, Put;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create a Charge object
|
|
||||||
*
|
|
||||||
* @param array $parameters
|
|
||||||
*
|
|
||||||
* @return Result Result object
|
|
||||||
*/
|
|
||||||
public function createCharge(array $parameters): Result
|
|
||||||
{
|
|
||||||
return $this->post('charges', $parameters);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get a Charge object
|
|
||||||
*
|
|
||||||
* @param string $id
|
|
||||||
*
|
|
||||||
* @return Result Result object
|
|
||||||
*/
|
|
||||||
public function getCharge(string $id): Result
|
|
||||||
{
|
|
||||||
return $this->get("charges/$id");
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Update a Charge object
|
|
||||||
*
|
|
||||||
* @param string $id
|
|
||||||
* @param array $parameters
|
|
||||||
*
|
|
||||||
* @return Result Result object
|
|
||||||
*/
|
|
||||||
public function updateCharge(string $id, array $parameters): Result
|
|
||||||
{
|
|
||||||
return $this->put("charges/$id", $parameters);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Capture a Charge object
|
|
||||||
*
|
|
||||||
* @param string $id
|
|
||||||
* @param array $parameters
|
|
||||||
*
|
|
||||||
* @return Result Result object
|
|
||||||
*/
|
|
||||||
public function captureCharge(string $id, array $parameters = []): Result
|
|
||||||
{
|
|
||||||
return $this->post("charges/$id/capture", $parameters);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,42 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
declare(strict_types=1);
|
|
||||||
|
|
||||||
namespace GhostZero\BitinflowAccounts\Traits;
|
|
||||||
|
|
||||||
use GhostZero\BitinflowAccounts\ApiOperations\Get;
|
|
||||||
use GhostZero\BitinflowAccounts\ApiOperations\Post;
|
|
||||||
use GhostZero\BitinflowAccounts\Result;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author René Preuß <rene@preuss.io>
|
|
||||||
*/
|
|
||||||
trait CheckoutSessionsTrait
|
|
||||||
{
|
|
||||||
|
|
||||||
use Get, Post;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get a Session object
|
|
||||||
*
|
|
||||||
* @param string $id
|
|
||||||
*
|
|
||||||
* @return Result Result object
|
|
||||||
*/
|
|
||||||
public function getCheckoutSession(string $id): Result
|
|
||||||
{
|
|
||||||
return $this->get("checkout/sessions/$id");
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create a Session object
|
|
||||||
*
|
|
||||||
* @param array $parameters
|
|
||||||
*
|
|
||||||
* @return Result
|
|
||||||
*/
|
|
||||||
public function createCheckoutSession(array $parameters): Result
|
|
||||||
{
|
|
||||||
return $this->post('payments/sessions', $parameters);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,23 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
declare(strict_types=1);
|
|
||||||
|
|
||||||
namespace GhostZero\BitinflowAccounts\Traits;
|
|
||||||
|
|
||||||
use GhostZero\BitinflowAccounts\ApiOperations\Get;
|
|
||||||
use GhostZero\BitinflowAccounts\Result;
|
|
||||||
|
|
||||||
trait UsersTrait
|
|
||||||
{
|
|
||||||
|
|
||||||
use Get;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get currently authed user with Bearer Token
|
|
||||||
* @return Result Result object
|
|
||||||
*/
|
|
||||||
public function getAuthedUser(): Result
|
|
||||||
{
|
|
||||||
return $this->get('users/me', [], null);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
260
src/Payments/BitinflowPayments.php
Normal file
260
src/Payments/BitinflowPayments.php
Normal file
@@ -0,0 +1,260 @@
|
|||||||
|
<?php /** @noinspection DuplicatedCode */
|
||||||
|
|
||||||
|
namespace Bitinflow\Payments;
|
||||||
|
|
||||||
|
use Bitinflow\Accounts\Exceptions\RequestRequiresAuthenticationException;
|
||||||
|
use Bitinflow\Accounts\Exceptions\RequestRequiresClientIdException;
|
||||||
|
use Bitinflow\Accounts\Helpers\Paginator;
|
||||||
|
use Bitinflow\Payments\Result;
|
||||||
|
use Bitinflow\Accounts\ApiOperations;
|
||||||
|
use Bitinflow\Payments\Traits;
|
||||||
|
use Bitinflow\Support\Query;
|
||||||
|
use GuzzleHttp\Client;
|
||||||
|
use GuzzleHttp\Exception\GuzzleException;
|
||||||
|
use GuzzleHttp\Exception\RequestException;
|
||||||
|
|
||||||
|
class BitinflowPayments
|
||||||
|
{
|
||||||
|
use Traits\Balance;
|
||||||
|
use Traits\Wallets;
|
||||||
|
use Traits\Orders;
|
||||||
|
use Traits\Subscriptions;
|
||||||
|
use Traits\CheckoutSessions;
|
||||||
|
use Traits\Taxation;
|
||||||
|
|
||||||
|
use ApiOperations\Validation;
|
||||||
|
|
||||||
|
private static string $baseUrl = 'https://api.pay.bitinflow.com/v1/';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* bitinflow Payments OAuth token.
|
||||||
|
*/
|
||||||
|
protected ?string $token = null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* bitinflow Accounts client id.
|
||||||
|
*/
|
||||||
|
protected ?string $clientId = null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* bitinflow Accounts client secret.
|
||||||
|
*/
|
||||||
|
protected ?string $clientSecret = null;
|
||||||
|
|
||||||
|
private Client $client;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor.
|
||||||
|
*/
|
||||||
|
public function __construct()
|
||||||
|
{
|
||||||
|
if ($clientId = config('bitinflow-accounts.client_id')) {
|
||||||
|
$this->setClientId($clientId);
|
||||||
|
}
|
||||||
|
if ($clientSecret = config('bitinflow-accounts.client_secret')) {
|
||||||
|
$this->setClientSecret($clientSecret);
|
||||||
|
}
|
||||||
|
if ($redirectUri = config('bitinflow-accounts.payments.base_url')) {
|
||||||
|
self::setBaseUrl($redirectUri);
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->client = new Client([
|
||||||
|
'base_uri' => self::$baseUrl,
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string $baseUrl
|
||||||
|
*
|
||||||
|
* @internal only for internal and debug purposes.
|
||||||
|
*/
|
||||||
|
public static function setBaseUrl(string $baseUrl): void
|
||||||
|
{
|
||||||
|
self::$baseUrl = $baseUrl;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get OAuth token.
|
||||||
|
*
|
||||||
|
* @return string bitinflow Accounts token
|
||||||
|
* @return string|null
|
||||||
|
* @throws RequestRequiresAuthenticationException
|
||||||
|
*/
|
||||||
|
public function getToken(): ?string
|
||||||
|
{
|
||||||
|
if (!$this->token) {
|
||||||
|
throw new RequestRequiresAuthenticationException;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->token;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set OAuth token.
|
||||||
|
*
|
||||||
|
* @param string $token bitinflow Accounts OAuth token
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function setToken(string $token): void
|
||||||
|
{
|
||||||
|
$this->token = $token;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fluid OAuth token setter.
|
||||||
|
*
|
||||||
|
* @param string $token bitinflow Accounts OAuth token
|
||||||
|
*
|
||||||
|
* @return self
|
||||||
|
*/
|
||||||
|
public function withToken(string $token): self
|
||||||
|
{
|
||||||
|
$this->setToken($token);
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Build query & execute.
|
||||||
|
*
|
||||||
|
* @param string $method HTTP method
|
||||||
|
* @param string $path Query path
|
||||||
|
* @param array $parameters Query parameters
|
||||||
|
* @param Paginator|null $paginator Paginator object
|
||||||
|
* @param mixed|null $jsonBody JSON data
|
||||||
|
*
|
||||||
|
* @return Result Result object
|
||||||
|
* @throws GuzzleException
|
||||||
|
* @throws RequestRequiresClientIdException
|
||||||
|
*/
|
||||||
|
public function query(string $method = 'GET', string $path = '', array $parameters = [], Paginator $paginator = null, $jsonBody = null): Result
|
||||||
|
{
|
||||||
|
if ($paginator !== null) {
|
||||||
|
$parameters[$paginator->action] = $paginator->cursor();
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
$response = $this->client->request($method, $path, [
|
||||||
|
'headers' => $this->buildHeaders((bool)$jsonBody),
|
||||||
|
'query' => Query::build($parameters),
|
||||||
|
'json' => $jsonBody ?: null,
|
||||||
|
]);
|
||||||
|
$result = new Result($response, null, $paginator);
|
||||||
|
} catch (RequestException $exception) {
|
||||||
|
$result = new Result($exception->getResponse(), $exception, $paginator);
|
||||||
|
}
|
||||||
|
$result->bitinflow = $this;
|
||||||
|
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Build headers for request.
|
||||||
|
*
|
||||||
|
* @param bool $json Body is JSON
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
* @throws RequestRequiresClientIdException
|
||||||
|
*/
|
||||||
|
private function buildHeaders(bool $json = false): array
|
||||||
|
{
|
||||||
|
$headers = [
|
||||||
|
'Client-ID' => $this->getClientId(),
|
||||||
|
'Accept' => 'application/json',
|
||||||
|
];
|
||||||
|
if ($this->token) {
|
||||||
|
$headers['Authorization'] = 'Bearer ' . $this->token;
|
||||||
|
}
|
||||||
|
if ($json) {
|
||||||
|
$headers['Content-Type'] = 'application/json';
|
||||||
|
}
|
||||||
|
|
||||||
|
return $headers;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get client id.
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
* @throws RequestRequiresClientIdException
|
||||||
|
*/
|
||||||
|
public function getClientId(): string
|
||||||
|
{
|
||||||
|
if (!$this->clientId) {
|
||||||
|
throw new RequestRequiresClientIdException;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->clientId;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set client id.
|
||||||
|
*
|
||||||
|
* @param string $clientId bitinflow Accounts client id
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function setClientId(string $clientId): void
|
||||||
|
{
|
||||||
|
$this->clientId = $clientId;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fluid client id setter.
|
||||||
|
*
|
||||||
|
* @param string $clientId bitinflow Accounts client id.
|
||||||
|
*
|
||||||
|
* @return self
|
||||||
|
*/
|
||||||
|
public function withClientId(string $clientId): self
|
||||||
|
{
|
||||||
|
$this->setClientId($clientId);
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get client secret.
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
* @throws RequestRequiresClientIdException
|
||||||
|
*/
|
||||||
|
public function getClientSecret(): string
|
||||||
|
{
|
||||||
|
if (!$this->clientSecret) {
|
||||||
|
throw new RequestRequiresClientIdException;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->clientSecret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set client secret.
|
||||||
|
*
|
||||||
|
* @param string $clientSecret bitinflow Accounts client secret
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function setClientSecret(string $clientSecret): void
|
||||||
|
{
|
||||||
|
$this->clientSecret = $clientSecret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fluid client secret setter.
|
||||||
|
*
|
||||||
|
* @param string $clientSecret bitinflow Accounts client secret
|
||||||
|
*
|
||||||
|
* @return self
|
||||||
|
*/
|
||||||
|
public function withClientSecret(string $clientSecret): self
|
||||||
|
{
|
||||||
|
$this->setClientSecret($clientSecret);
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getBaseUrl()
|
||||||
|
{
|
||||||
|
return self::$baseUrl;
|
||||||
|
}
|
||||||
|
}
|
||||||
19
src/Payments/Facades/BitinflowPayments.php
Normal file
19
src/Payments/Facades/BitinflowPayments.php
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace Bitinflow\Payments\Facades;
|
||||||
|
|
||||||
|
use Bitinflow\Payments\BitinflowPayments as BitinflowPaymentsService;
|
||||||
|
use Illuminate\Support\Facades\Facade;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author René Preuß <rene@preuss.io>
|
||||||
|
*/
|
||||||
|
class BitinflowPayments extends Facade
|
||||||
|
{
|
||||||
|
protected static function getFacadeAccessor()
|
||||||
|
{
|
||||||
|
return BitinflowPaymentsService::class;
|
||||||
|
}
|
||||||
|
}
|
||||||
10
src/Payments/Result.php
Normal file
10
src/Payments/Result.php
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Bitinflow\Payments;
|
||||||
|
|
||||||
|
use Bitinflow\Accounts\Result as Base;
|
||||||
|
|
||||||
|
class Result extends Base
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
45
src/Payments/Traits/Balance.php
Normal file
45
src/Payments/Traits/Balance.php
Normal file
@@ -0,0 +1,45 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Bitinflow\Payments\Traits;
|
||||||
|
|
||||||
|
use Bitinflow\Payments\Result;
|
||||||
|
use GuzzleHttp\Exception\GuzzleException;
|
||||||
|
|
||||||
|
trait Balance
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Get balance from user.
|
||||||
|
*/
|
||||||
|
public function getUser(): Result
|
||||||
|
{
|
||||||
|
return $this->query('GET', 'user');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Deposit given amount from bank to account.
|
||||||
|
*/
|
||||||
|
public function deposit(float $amount, string $description): Result
|
||||||
|
{
|
||||||
|
return $this->query('PUT', 'wallet/deposit', [], null, [
|
||||||
|
'amount' => $amount,
|
||||||
|
'description' => $description,
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Charge given amount from account.
|
||||||
|
*
|
||||||
|
* @throws GuzzleException
|
||||||
|
*/
|
||||||
|
public function charge(float $amount, string $description): bool
|
||||||
|
{
|
||||||
|
$result = $this->createOrder([
|
||||||
|
'name' => $description,
|
||||||
|
'description' => 'one-time payment',
|
||||||
|
'amount' => 1,
|
||||||
|
'price' => $amount,
|
||||||
|
]);
|
||||||
|
|
||||||
|
return $this->checkoutOrder($result->data()->id);
|
||||||
|
}
|
||||||
|
}
|
||||||
46
src/Payments/Traits/CheckoutSessions.php
Normal file
46
src/Payments/Traits/CheckoutSessions.php
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Bitinflow\Payments\Traits;
|
||||||
|
|
||||||
|
use Bitinflow\Accounts\Exceptions\RequestRequiresClientIdException;
|
||||||
|
use Bitinflow\Payments\Result;
|
||||||
|
use GuzzleHttp\Exception\GuzzleException;
|
||||||
|
|
||||||
|
trait CheckoutSessions
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @throws GuzzleException
|
||||||
|
* @throws RequestRequiresClientIdException
|
||||||
|
*/
|
||||||
|
public function createCheckoutSession(array $parameters): Result
|
||||||
|
{
|
||||||
|
return $this->query('POST', 'checkout-sessions', [], null, $parameters);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @throws GuzzleException
|
||||||
|
* @throws RequestRequiresClientIdException
|
||||||
|
*/
|
||||||
|
public function getCheckoutSession(string $id): Result
|
||||||
|
{
|
||||||
|
return $this->query('GET', sprintf('checkout-sessions/%s', $id));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @throws GuzzleException
|
||||||
|
* @throws RequestRequiresClientIdException
|
||||||
|
*/
|
||||||
|
public function checkoutCheckoutSession(string $id): Result
|
||||||
|
{
|
||||||
|
return $this->query('PUT', sprintf('checkout-sessions/%s/checkout', $id));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @throws GuzzleException
|
||||||
|
* @throws RequestRequiresClientIdException
|
||||||
|
*/
|
||||||
|
public function revokeCheckoutSession(string $id): Result
|
||||||
|
{
|
||||||
|
return $this->query('PUT', sprintf('checkout-sessions/%s/revoke', $id));
|
||||||
|
}
|
||||||
|
}
|
||||||
58
src/Payments/Traits/Orders.php
Normal file
58
src/Payments/Traits/Orders.php
Normal file
@@ -0,0 +1,58 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Bitinflow\Payments\Traits;
|
||||||
|
|
||||||
|
use Bitinflow\Payments\Result;
|
||||||
|
use Bitinflow\Payments\BitinflowPayments;
|
||||||
|
use GuzzleHttp\Exception\GuzzleException;
|
||||||
|
|
||||||
|
trait Orders
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Get orders from user.
|
||||||
|
*
|
||||||
|
* @throws GuzzleException
|
||||||
|
*/
|
||||||
|
public function getOrders(): Result
|
||||||
|
{
|
||||||
|
return $this->query('GET', 'orders');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string $id
|
||||||
|
*/
|
||||||
|
public function getOrder(string $id): Result
|
||||||
|
{
|
||||||
|
return $this->query('GET', sprintf('orders/%s', $id));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new order.
|
||||||
|
*
|
||||||
|
* @throws GuzzleException
|
||||||
|
*/
|
||||||
|
public function createOrder(array $parameters = []): Result
|
||||||
|
{
|
||||||
|
return $this->query('POST', 'orders', [], null, $parameters);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checkout given subscription.
|
||||||
|
*
|
||||||
|
* @param string $id
|
||||||
|
*/
|
||||||
|
public function checkoutOrder(string $id):Result
|
||||||
|
{
|
||||||
|
return $this->query('PUT', sprintf('orders/%s/checkout', $id));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Revoke a running subscription.
|
||||||
|
*
|
||||||
|
* @param string $id
|
||||||
|
*/
|
||||||
|
public function revokeOrder(string $id):Result
|
||||||
|
{
|
||||||
|
return $this->query('PUT', sprintf('orders/%s/revoke', $id));
|
||||||
|
}
|
||||||
|
}
|
||||||
82
src/Payments/Traits/Subscriptions.php
Normal file
82
src/Payments/Traits/Subscriptions.php
Normal file
@@ -0,0 +1,82 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Bitinflow\Payments\Traits;
|
||||||
|
|
||||||
|
use Bitinflow\Accounts\Exceptions\RequestRequiresClientIdException;
|
||||||
|
use Bitinflow\Accounts\Exceptions\RequestRequiresMissingParametersException;
|
||||||
|
use Bitinflow\Accounts\Helpers\Paginator;
|
||||||
|
use Bitinflow\Payments\Result;
|
||||||
|
use GuzzleHttp\Exception\GuzzleException;
|
||||||
|
|
||||||
|
trait Subscriptions
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Get subscriptions from user.
|
||||||
|
*
|
||||||
|
* @return object|null
|
||||||
|
*/
|
||||||
|
public function getSubscriptions(array $parameters = [], Paginator $paginator = null): Result
|
||||||
|
{
|
||||||
|
return $this->query('GET', 'subscriptions', $parameters, $paginator);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string $id
|
||||||
|
*/
|
||||||
|
public function getSubscription(string $id): Result
|
||||||
|
{
|
||||||
|
return $this->query('GET', sprintf('subscriptions/%s', $id));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new subscription.
|
||||||
|
*
|
||||||
|
* @param array $parameters array which requires following attributes:
|
||||||
|
* name, description, period, price
|
||||||
|
* and following attributes are optional:
|
||||||
|
* vat, payload, ends_at, webhook_url, webhook_secret
|
||||||
|
* @return object|false the subscription object
|
||||||
|
* @throws GuzzleException
|
||||||
|
* @throws RequestRequiresClientIdException
|
||||||
|
* @throws RequestRequiresMissingParametersException
|
||||||
|
*/
|
||||||
|
public function createSubscription(array $parameters): Result
|
||||||
|
{
|
||||||
|
$this->validateRequired($parameters, ['name', 'description', 'period', 'price']);
|
||||||
|
|
||||||
|
return $this->query('POST', 'subscriptions', [], null, $parameters);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Force given subscription to check out (trusted apps only).
|
||||||
|
*
|
||||||
|
* @param string $id
|
||||||
|
* @return Result
|
||||||
|
* @throws RequestRequiresClientIdException
|
||||||
|
* @throws GuzzleException
|
||||||
|
*/
|
||||||
|
public function checkoutSubscription(string $id): Result
|
||||||
|
{
|
||||||
|
return $this->query('PUT', sprintf('subscriptions/%s/checkout', $id));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Revoke a running subscription.
|
||||||
|
*
|
||||||
|
* @param string $id
|
||||||
|
*/
|
||||||
|
public function revokeSubscription(string $id): Result
|
||||||
|
{
|
||||||
|
return $this->query('PUT', sprintf('subscriptions/%s/revoke', $id));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Resume a running subscription.
|
||||||
|
*
|
||||||
|
* @param string $id
|
||||||
|
*/
|
||||||
|
public function resumeSubscription(string $id): Result
|
||||||
|
{
|
||||||
|
return $this->query('PUT', sprintf('subscriptions/%s/resume', $id));
|
||||||
|
}
|
||||||
|
}
|
||||||
16
src/Payments/Traits/Taxation.php
Normal file
16
src/Payments/Traits/Taxation.php
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Bitinflow\Payments\Traits;
|
||||||
|
|
||||||
|
use Bitinflow\Payments\Result;
|
||||||
|
|
||||||
|
trait Taxation
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Get vat from user.
|
||||||
|
*/
|
||||||
|
public function getTaxation(): Result
|
||||||
|
{
|
||||||
|
return $this->query('GET', 'taxation');
|
||||||
|
}
|
||||||
|
}
|
||||||
34
src/Payments/Traits/Wallets.php
Normal file
34
src/Payments/Traits/Wallets.php
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Bitinflow\Payments\Traits;
|
||||||
|
|
||||||
|
use Bitinflow\Payments\Result;
|
||||||
|
use Bitinflow\Payments\BitinflowPayments;
|
||||||
|
|
||||||
|
trait Wallets
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Get all wallets that belong to the user.
|
||||||
|
*/
|
||||||
|
public function getWallets(): Result
|
||||||
|
{
|
||||||
|
return $this->query('GET', 'wallet');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set default wallet to given wallet token.
|
||||||
|
*
|
||||||
|
* @param string $token default payment method token
|
||||||
|
*/
|
||||||
|
public function setDefaultWallet(string $token): Result
|
||||||
|
{
|
||||||
|
return $this->query('PUT', 'wallet/default', [], null, [
|
||||||
|
'token' => $token
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getWalletSetupIntent(string $successUrl): string
|
||||||
|
{
|
||||||
|
return sprintf('%swallet/?continue_url=%s', config('bitinflow-accounts.payments.dashboard_url'), urlencode($successUrl));
|
||||||
|
}
|
||||||
|
}
|
||||||
26
src/Support/Query.php
Normal file
26
src/Support/Query.php
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Bitinflow\Support;
|
||||||
|
|
||||||
|
class Query
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Build query with support for multiple same first-dimension keys.
|
||||||
|
*
|
||||||
|
* @param array $query
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public static function build(array $query): string
|
||||||
|
{
|
||||||
|
$parts = [];
|
||||||
|
foreach ($query as $name => $value) {
|
||||||
|
$value = (array)$value;
|
||||||
|
array_walk_recursive($value, function ($value) use (&$parts, $name) {
|
||||||
|
$parts[] = urlencode($name) . '=' . urlencode($value);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return implode('&', $parts);
|
||||||
|
}
|
||||||
|
}
|
||||||
23
tests/Accounts/ApiOauthTest.php
Normal file
23
tests/Accounts/ApiOauthTest.php
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace Bitinflow\Accounts\Tests;
|
||||||
|
|
||||||
|
use Bitinflow\Accounts\Tests\TestCases\ApiTestCase;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author René Preuß <rene@preuss.io>
|
||||||
|
*/
|
||||||
|
class ApiOauthTest extends ApiTestCase
|
||||||
|
{
|
||||||
|
|
||||||
|
public function testGetOauthToken(): void
|
||||||
|
{
|
||||||
|
$this->registerResult($result = $this->getClient()->retrievingToken('client_credentials', [
|
||||||
|
'scope' => '',
|
||||||
|
]));
|
||||||
|
$this->assertTrue($result->success());
|
||||||
|
$this->assertNotEmpty($result->data()->access_token);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -2,10 +2,10 @@
|
|||||||
|
|
||||||
declare(strict_types=1);
|
declare(strict_types=1);
|
||||||
|
|
||||||
namespace GhostZero\BitinflowAccounts\Tests;
|
namespace Bitinflow\Accounts\Tests;
|
||||||
|
|
||||||
use GhostZero\BitinflowAccounts\Result;
|
use Bitinflow\Accounts\Result;
|
||||||
use GhostZero\BitinflowAccounts\Tests\TestCases\ApiTestCase;
|
use Bitinflow\Accounts\Tests\TestCases\ApiTestCase;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author René Preuß <rene@preuss.io>
|
* @author René Preuß <rene@preuss.io>
|
||||||
@@ -13,15 +13,14 @@ use GhostZero\BitinflowAccounts\Tests\TestCases\ApiTestCase;
|
|||||||
class ApiSshKeysTest extends ApiTestCase
|
class ApiSshKeysTest extends ApiTestCase
|
||||||
{
|
{
|
||||||
|
|
||||||
public function testGetSshKeyByUserId()
|
public function testGetSshKeyByUserId(): void
|
||||||
{
|
{
|
||||||
$this->registerResult($result = $this->getClient()->getSshKeysByUserId(38));
|
$this->registerResult($result = $this->getClient()->getSshKeysByUserId(38));
|
||||||
$this->assertInstanceOf(Result::class, $result);
|
|
||||||
$this->assertEquals('rene.preuss@check24.de', $result->shift()->name);
|
$this->assertEquals('rene.preuss@check24.de', $result->shift()->name);
|
||||||
$this->assertGreaterThanOrEqual(2, $result->count());
|
$this->assertGreaterThanOrEqual(2, $result->count());
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testSshKeyManagement()
|
public function testSshKeyManagement(): void
|
||||||
{
|
{
|
||||||
$customName = 'Hello World!';
|
$customName = 'Hello World!';
|
||||||
$publicKey = 'ssh-rsa AAAAB3NzaC1yc2EAAAABJQAAAQEA3H7sYVrVCwwYIuRm3on3S9n/BCd2mBJrgCk6xTerbNmt0RyUZ+RtGsK6UYkgnRR2WWq9/Pv2s3RXJXPxbsIEYmKCcTdLUvDk56x9385cIVUX4w016mpe/8lyu+mIdqWYKsJMoab0oReCDX8Y9qBcaffDh8AgmYVN+86gXgoP1ITe9BDYrFiR6U571VyLDVN3OYOYPMF3/L9f0knMfM0T4LrS8oi6faVBCxZHRoBGtGmsTBkE0KwplYQFN2aa4Mxab+rTUFmJr3LYEcJF0J8wNJ3eEDFNOR0254jrjbGGAXGsc+cxJoNzech+GBkRMKMpNU0lds6VxP0ZB25VfzjEmQ== René Preuß';
|
$publicKey = 'ssh-rsa AAAAB3NzaC1yc2EAAAABJQAAAQEA3H7sYVrVCwwYIuRm3on3S9n/BCd2mBJrgCk6xTerbNmt0RyUZ+RtGsK6UYkgnRR2WWq9/Pv2s3RXJXPxbsIEYmKCcTdLUvDk56x9385cIVUX4w016mpe/8lyu+mIdqWYKsJMoab0oReCDX8Y9qBcaffDh8AgmYVN+86gXgoP1ITe9BDYrFiR6U571VyLDVN3OYOYPMF3/L9f0knMfM0T4LrS8oi6faVBCxZHRoBGtGmsTBkE0KwplYQFN2aa4Mxab+rTUFmJr3LYEcJF0J8wNJ3eEDFNOR0254jrjbGGAXGsc+cxJoNzech+GBkRMKMpNU0lds6VxP0ZB25VfzjEmQ== René Preuß';
|
||||||
64
tests/Accounts/ApiUsersTest.php
Normal file
64
tests/Accounts/ApiUsersTest.php
Normal file
@@ -0,0 +1,64 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace Bitinflow\Accounts\Tests;
|
||||||
|
|
||||||
|
use Bitinflow\Accounts\Enums\Scope;
|
||||||
|
use Bitinflow\Accounts\Tests\TestCases\ApiTestCase;
|
||||||
|
use Illuminate\Support\Str;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author René Preuß <rene@preuss.io>
|
||||||
|
*/
|
||||||
|
class ApiUsersTest extends ApiTestCase
|
||||||
|
{
|
||||||
|
|
||||||
|
public function testGetAuthedUser(): void
|
||||||
|
{
|
||||||
|
$this->getClient()->withToken($this->getToken());
|
||||||
|
$this->registerResult($result = $this->getClient()->getAuthedUser());
|
||||||
|
$this->assertTrue($result->success());
|
||||||
|
$this->assertEquals('rene@preuss.io', $result->data()->email);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testEmailAvailabilityNonExisting(): void
|
||||||
|
{
|
||||||
|
$this->getClient()->withToken($this->getToken());
|
||||||
|
$this->registerResult($result = $this->getClient()->isEmailExisting('rene+non-existing@preuss.io'));
|
||||||
|
$this->assertTrue(!$result->success());
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testEmailAvailabilityExisting(): void
|
||||||
|
{
|
||||||
|
$this->getClient()->withToken($this->getToken());
|
||||||
|
$this->registerResult($result = $this->getClient()->isEmailExisting('rene@preuss.io'));
|
||||||
|
$this->assertTrue($result->success());
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testCreateUser(): void
|
||||||
|
{
|
||||||
|
$testEmailAddress = $this->createRandomEmail();
|
||||||
|
|
||||||
|
$this->registerResult($result = $this->getClient()->retrievingToken('client_credentials', [
|
||||||
|
'scope' => Scope::USERS_CREATE,
|
||||||
|
]));
|
||||||
|
|
||||||
|
$this->getClient()->withToken($result->data()->access_token);
|
||||||
|
$this->registerResult($result = $this->getClient()->createUser([
|
||||||
|
'first_name' => 'René',
|
||||||
|
'last_name' => 'Preuß',
|
||||||
|
'email' => $testEmailAddress,
|
||||||
|
'password' => 'Password1',
|
||||||
|
'password_confirmation' => 'Password1',
|
||||||
|
'terms_accepted' => true,
|
||||||
|
]));
|
||||||
|
$this->assertTrue($result->success(), $result->error());
|
||||||
|
$this->assertEquals($testEmailAddress, $result->data()->email);
|
||||||
|
}
|
||||||
|
|
||||||
|
private function createRandomEmail(): string
|
||||||
|
{
|
||||||
|
return sprintf('rene+unittest.%s@bitinflow.com', Str::random());
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -2,11 +2,11 @@
|
|||||||
|
|
||||||
declare(strict_types=1);
|
declare(strict_types=1);
|
||||||
|
|
||||||
namespace GhostZero\BitinflowAccounts\Tests;
|
namespace Bitinflow\Accounts\Tests;
|
||||||
|
|
||||||
use GhostZero\BitinflowAccounts\BitinflowAccounts;
|
use Bitinflow\Accounts\BitinflowAccounts;
|
||||||
use GhostZero\BitinflowAccounts\Facades\BitinflowAccounts as BitinflowAccountsFacade;
|
use Bitinflow\Accounts\Facades\BitinflowAccounts as BitinflowAccountsFacade;
|
||||||
use GhostZero\BitinflowAccounts\Tests\TestCases\TestCase;
|
use Bitinflow\Accounts\Tests\TestCases\TestCase;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author René Preuß <rene@preuss.io>
|
* @author René Preuß <rene@preuss.io>
|
||||||
@@ -14,12 +14,12 @@ use GhostZero\BitinflowAccounts\Tests\TestCases\TestCase;
|
|||||||
class ServiceInstantiationTest extends TestCase
|
class ServiceInstantiationTest extends TestCase
|
||||||
{
|
{
|
||||||
|
|
||||||
public function testInstance()
|
public function testInstance(): void
|
||||||
{
|
{
|
||||||
$this->assertInstanceOf(BitinflowAccounts::class, app(BitinflowAccounts::class));
|
$this->assertInstanceOf(BitinflowAccounts::class, app(BitinflowAccounts::class));
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testFacade()
|
public function testFacade(): void
|
||||||
{
|
{
|
||||||
$this->assertInstanceOf(BitinflowAccounts::class, BitinflowAccountsFacade::getFacadeRoot());
|
$this->assertInstanceOf(BitinflowAccounts::class, BitinflowAccountsFacade::getFacadeRoot());
|
||||||
}
|
}
|
||||||
@@ -2,10 +2,10 @@
|
|||||||
|
|
||||||
declare(strict_types=1);
|
declare(strict_types=1);
|
||||||
|
|
||||||
namespace GhostZero\BitinflowAccounts\Tests\TestCases;
|
namespace Bitinflow\Accounts\Tests\TestCases;
|
||||||
|
|
||||||
use GhostZero\BitinflowAccounts\BitinflowAccounts;
|
use Bitinflow\Accounts\BitinflowAccounts;
|
||||||
use GhostZero\BitinflowAccounts\Result;
|
use Bitinflow\Accounts\Result;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author René Preuß <rene@preuss.io>
|
* @author René Preuß <rene@preuss.io>
|
||||||
@@ -18,6 +18,11 @@ abstract class ApiTestCase extends TestCase
|
|||||||
protected function setUp(): void
|
protected function setUp(): void
|
||||||
{
|
{
|
||||||
parent::setUp();
|
parent::setUp();
|
||||||
|
|
||||||
|
if ($this->getBaseUrl()) {
|
||||||
|
BitinflowAccounts::setBaseUrl($this->getBaseUrl());
|
||||||
|
}
|
||||||
|
|
||||||
if (!$this->getClientId()) {
|
if (!$this->getClientId()) {
|
||||||
$this->markTestSkipped('No Client-ID given');
|
$this->markTestSkipped('No Client-ID given');
|
||||||
}
|
}
|
||||||
@@ -34,6 +39,11 @@ abstract class ApiTestCase extends TestCase
|
|||||||
return $result;
|
return $result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected function getBaseUrl()
|
||||||
|
{
|
||||||
|
return getenv('BASE_URL');
|
||||||
|
}
|
||||||
|
|
||||||
protected function getClientId()
|
protected function getClientId()
|
||||||
{
|
{
|
||||||
return getenv('CLIENT_ID');
|
return getenv('CLIENT_ID');
|
||||||
@@ -2,10 +2,10 @@
|
|||||||
|
|
||||||
declare(strict_types=1);
|
declare(strict_types=1);
|
||||||
|
|
||||||
namespace GhostZero\BitinflowAccounts\Tests\TestCases;
|
namespace Bitinflow\Accounts\Tests\TestCases;
|
||||||
|
|
||||||
use GhostZero\BitinflowAccounts\BitinflowAccounts;
|
use Bitinflow\Accounts\BitinflowAccounts;
|
||||||
use GhostZero\BitinflowAccounts\Providers\BitinflowAccountsServiceProvider;
|
use Bitinflow\Accounts\Providers\BitinflowAccountsServiceProvider;
|
||||||
use Orchestra\Testbench\TestCase as BaseTestCase;
|
use Orchestra\Testbench\TestCase as BaseTestCase;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -1,23 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
declare(strict_types=1);
|
|
||||||
|
|
||||||
namespace GhostZero\BitinflowAccounts\Tests;
|
|
||||||
|
|
||||||
use GhostZero\BitinflowAccounts\Result;
|
|
||||||
use GhostZero\BitinflowAccounts\Tests\TestCases\ApiTestCase;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author René Preuß <rene@preuss.io>
|
|
||||||
*/
|
|
||||||
class ApiUsersTest extends ApiTestCase
|
|
||||||
{
|
|
||||||
|
|
||||||
public function testGetAuthedUser()
|
|
||||||
{
|
|
||||||
$this->getClient()->withToken($this->getToken());
|
|
||||||
$this->registerResult($result = $this->getClient()->getAuthedUser());
|
|
||||||
$this->assertInstanceOf(Result::class, $result);
|
|
||||||
$this->assertEquals('rene@preuss.io', $result->data()->email);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
26
tests/Payments/ApiOauthTest.php
Normal file
26
tests/Payments/ApiOauthTest.php
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace Bitinflow\Payments\Tests;
|
||||||
|
|
||||||
|
use Bitinflow\Accounts\Contracts\AppTokenRepository;
|
||||||
|
use Bitinflow\Payments\Tests\TestCases\ApiTestCase;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author René Preuß <rene@preuss.io>
|
||||||
|
*/
|
||||||
|
class ApiOauthTest extends ApiTestCase
|
||||||
|
{
|
||||||
|
|
||||||
|
public function testGetOauthToken(): void
|
||||||
|
{
|
||||||
|
$token = app(AppTokenRepository::class)->getAccessToken();
|
||||||
|
|
||||||
|
$this->getPaymentsClient()->withToken($this->getToken());
|
||||||
|
$this->registerResult($result = $this->getPaymentsClient()->createSubscription([
|
||||||
|
|
||||||
|
]));
|
||||||
|
$result->dump();
|
||||||
|
}
|
||||||
|
}
|
||||||
80
tests/Payments/TestCases/ApiTestCase.php
Normal file
80
tests/Payments/TestCases/ApiTestCase.php
Normal file
@@ -0,0 +1,80 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace Bitinflow\Payments\Tests\TestCases;
|
||||||
|
|
||||||
|
use Bitinflow\Accounts\BitinflowAccounts;
|
||||||
|
use Bitinflow\Accounts\Result;
|
||||||
|
use Bitinflow\Payments\BitinflowPayments;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author René Preuß <rene@preuss.io>
|
||||||
|
*/
|
||||||
|
abstract class ApiTestCase extends TestCase
|
||||||
|
{
|
||||||
|
protected static $rateLimitRemaining = null;
|
||||||
|
|
||||||
|
protected function setUp(): void
|
||||||
|
{
|
||||||
|
parent::setUp();
|
||||||
|
|
||||||
|
if ($this->getAccountsBaseUrl()) {
|
||||||
|
BitinflowAccounts::setBaseUrl($this->getAccountsBaseUrl());
|
||||||
|
}
|
||||||
|
if ($this->getPaymentsBaseUrl()) {
|
||||||
|
BitinflowPayments::setBaseUrl($this->getPaymentsBaseUrl());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!$this->getClientId()) {
|
||||||
|
$this->markTestSkipped('No Client-ID given');
|
||||||
|
}
|
||||||
|
if (self::$rateLimitRemaining !== null && self::$rateLimitRemaining < 3) {
|
||||||
|
$this->markTestSkipped('Rate Limit exceeded (' . self::$rateLimitRemaining . ')');
|
||||||
|
}
|
||||||
|
$this->getAccountsClient()->setClientId($this->getClientId());
|
||||||
|
$this->getPaymentsClient()->setClientId($this->getClientId());
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function registerResult(Result $result): Result
|
||||||
|
{
|
||||||
|
self::$rateLimitRemaining = $result->rateLimit('remaining');
|
||||||
|
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function getAccountsBaseUrl()
|
||||||
|
{
|
||||||
|
return getenv('ACCOUNTS_BASE_URL');
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function getPaymentsBaseUrl()
|
||||||
|
{
|
||||||
|
return getenv('PAYMENTS_BASE_URL');
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function getClientId()
|
||||||
|
{
|
||||||
|
return getenv('CLIENT_ID');
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function getClientSecret()
|
||||||
|
{
|
||||||
|
return getenv('CLIENT_KEY');
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function getToken()
|
||||||
|
{
|
||||||
|
return getenv('CLIENT_ACCESS_TOKEN');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getPaymentsClient(): BitinflowPayments
|
||||||
|
{
|
||||||
|
return app(BitinflowPayments::class);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getAccountsClient(): BitinflowAccounts
|
||||||
|
{
|
||||||
|
return app(BitinflowAccounts::class);
|
||||||
|
}
|
||||||
|
}
|
||||||
30
tests/Payments/TestCases/TestCase.php
Normal file
30
tests/Payments/TestCases/TestCase.php
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace Bitinflow\Payments\Tests\TestCases;
|
||||||
|
|
||||||
|
use Bitinflow\Accounts\BitinflowAccounts;
|
||||||
|
use Bitinflow\Accounts\Providers\BitinflowAccountsServiceProvider;
|
||||||
|
use Orchestra\Testbench\TestCase as BaseTestCase;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author René Preuß <rene@preuss.io>
|
||||||
|
*/
|
||||||
|
abstract class TestCase extends BaseTestCase
|
||||||
|
{
|
||||||
|
|
||||||
|
protected function getPackageProviders($app)
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
BitinflowAccountsServiceProvider::class,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function getPackageAliases($app)
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
'BitinflowAccounts' => BitinflowAccounts::class,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user