diff --git a/app/Services/Bunq/Id/BunqId.php b/app/Services/Bunq/Id/BunqId.php new file mode 100644 index 0000000000..9752d71ba3 --- /dev/null +++ b/app/Services/Bunq/Id/BunqId.php @@ -0,0 +1,43 @@ +id; + } + + /** + * @param int $id + */ + public function setId(int $id) + { + $this->id = $id; + } + + +} \ No newline at end of file diff --git a/app/Services/Bunq/Id/DeviceServerId.php b/app/Services/Bunq/Id/DeviceServerId.php new file mode 100644 index 0000000000..b8b845fd7e --- /dev/null +++ b/app/Services/Bunq/Id/DeviceServerId.php @@ -0,0 +1,25 @@ +publicKey = $response['server_public_key']; + } + + /** + * @param string $publicKey + */ + public function setPublicKey(string $publicKey) + { + $this->publicKey = $publicKey; + } + + /** + * @return string + */ + public function getPublicKey(): string + { + return $this->publicKey; + } + + +} \ No newline at end of file diff --git a/app/Services/Bunq/Object/UserPerson.php b/app/Services/Bunq/Object/UserPerson.php new file mode 100644 index 0000000000..963357ab51 --- /dev/null +++ b/app/Services/Bunq/Object/UserPerson.php @@ -0,0 +1,134 @@ +id = intval($data['id']); + $this->created = Carbon::createFromFormat('Y-m-d H:i:s.u', $data['created']); + $this->updated = Carbon::createFromFormat('Y-m-d H:i:s.u', $data['updated']); + $this->status = $data['status']; + $this->subStatus = $data['sub_status']; + $this->publicUuid = $data['public_uuid']; + $this->displayName = $data['display_name']; + $this->publicNickName = $data['public_nick_name']; + $this->language = $data['language']; + $this->region = $data['region']; + $this->sessionTimeout = intval($data['session_timeout']); + $this->firstName = $data['first_name']; + $this->middleName = $data['middle_name']; + $this->lastName = $data['last_name']; + $this->legalName = $data['legal_name']; + $this->taxResident = $data['tax_resident']; + $this->dateOfBirth = Carbon::createFromFormat('Y-m-d', $data['date_of_birth']); + $this->placeOfBirth = $data['place_of_birth']; + $this->countryOfBirth = $data['country_of_birth']; + $this->nationality = $data['nationality']; + $this->gender = $data['gender']; + $this->versionTos = intval($data['version_terms_of_service']); + $this->documentNumber = $data['document_number']; + $this->documentType = $data['document_type']; + $this->documentCountry = $data['document_country_of_issuance']; + + // create aliases + // create avatar + // create daily limit + // create notification filters + // create address main, postal + // document front, back attachment + // customer, customer_limit + // billing contracts + + // echo '
'; + // print_r($data); + // var_dump($this); + // echo ''; + } + +} \ No newline at end of file diff --git a/app/Services/Bunq/Request/BunqRequest.php b/app/Services/Bunq/Request/BunqRequest.php new file mode 100644 index 0000000000..4226204f0e --- /dev/null +++ b/app/Services/Bunq/Request/BunqRequest.php @@ -0,0 +1,374 @@ + 'X-Bunq-Client-Response-Id', + 'x-bunq-client-request-id' => 'X-Bunq-Client-Request-Id', + ]; + + public function __construct() + { + + + // create a log channel + $this->logger = new Logger('bunq-request'); + $this->logger->pushHandler(new StreamHandler('logs/bunq.log', Logger::DEBUG)); + $this->logger->debug('Hallo dan'); + } + + /** + * + */ + abstract public function call(): void; + + /** + * @return string + */ + public function getServer(): string + { + return $this->server; + } + + /** + * @param string $server + */ + public function setServer(string $server) + { + $this->server = $server; + } + + /** + * @param bool $fake + */ + public function setFake(bool $fake) + { + $this->fake = $fake; + } + + /** + * @param string $privateKey + */ + public function setPrivateKey(string $privateKey) + { + $this->privateKey = $privateKey; + } + + /** + * @param string $secret + */ + public function setSecret(string $secret) + { + $this->secret = $secret; + } + + /** + * @param ServerPublicKey $serverPublicKey + */ + public function setServerPublicKey(ServerPublicKey $serverPublicKey) + { + $this->serverPublicKey = $serverPublicKey; + } + + /** + * @param string $method + * @param string $uri + * @param array $headers + * @param string $data + * + * @return string + */ + protected function generateSignature(string $method, string $uri, array $headers, string $data): string + { + if (strlen($this->privateKey) === 0) { + throw new Exception('No private key present.'); + } + if (strtolower($method) === 'get') { + $data = ''; + } + + $uri = str_replace(['https://api.bunq.com', 'https://sandbox.public.api.bunq.com'], '', $uri); + $toSign = strtoupper($method) . ' ' . $uri . "\n"; + $headersToSign = ['Cache-Control', 'User-Agent']; + ksort($headers); + foreach ($headers as $name => $value) { + if (in_array($name, $headersToSign) || substr($name, 0, 7) === 'X-Bunq-') { + $toSign .= $name . ': ' . $value . "\n"; + } + } + $toSign .= "\n" . $data; + $signature = ''; + + openssl_sign($toSign, $signature, $this->privateKey, OPENSSL_ALGO_SHA256); + $signature = base64_encode($signature); + + return $signature; + } + + protected function getDefaultHeaders(): array + { + return [ + 'X-Bunq-Client-Request-Id' => uniqid('sander'), + 'Cache-Control' => 'no-cache', + 'User-Agent' => 'pre-Firefly III test thing', + 'X-Bunq-Language' => 'en_US', + 'X-Bunq-Region' => 'nl_NL', + 'X-Bunq-Geolocation' => '0 0 0 0 NL', + ]; + } + + /** + * @param string $key + * @param array $response + * + * @return array + */ + protected function getKeyFromResponse(string $key, array $response): array + { + if (isset($response['Response'])) { + foreach ($response['Response'] as $entry) { + $currentKey = key($entry); + $data = current($entry); + if ($currentKey === $key) { + return $data; + } + } + } + + return []; + } + + /** + * @param string $uri + * @param array $data + * @param array $headers + * + * @return array + * @throws Exception + */ + protected function sendSignedBunqGet(string $uri, array $data, array $headers): array + { + if (strlen($this->server) === 0) { + throw new Exception('No bunq server defined'); + } + + $body = json_encode($data); + $fullUri = $this->server . $uri; + $signature = $this->generateSignature('get', $uri, $headers, $body); + $headers['X-Bunq-Client-Signature'] = $signature; + try { + $response = Requests::get($fullUri, $headers); + } catch (Requests_Exception $e) { + return ['Error' => [0 => ['error_description' => $e->getMessage(), 'error_description_translated' => $e->getMessage()],]]; + } + + $body = $response->body; + $array = json_decode($body, true); + if ($this->isErrorResponse($array)) { + $this->throwResponseError($array); + } + $responseHeaders = $response->headers->getAll(); + $statusCode = $response->status_code; + if (!$this->verifyServerSignature($body, $responseHeaders, $statusCode)) { + throw new Exception(sprintf('Could not verify signature for request to "%s"', $uri)); + } + $array['ResponseHeaders'] = $responseHeaders; + + return $array; + } + + /** + * @param string $uri + * @param array $data + * @param array $headers + * + * @return array + * @throws Exception + */ + protected function sendSignedBunqPost(string $uri, array $data, array $headers): array + { + $body = json_encode($data); + $fullUri = $this->server . $uri; + $signature = $this->generateSignature('post', $uri, $headers, $body); + $headers['X-Bunq-Client-Signature'] = $signature; + try { + $response = Requests::post($fullUri, $headers, $body); + } catch (Requests_Exception $e) { + return ['Error' => [0 => ['error_description' => $e->getMessage(), 'error_description_translated' => $e->getMessage()],]]; + } + + $body = $response->body; + $array = json_decode($body, true); + if ($this->isErrorResponse($array)) { + $this->throwResponseError($array); + } + $responseHeaders = $response->headers->getAll(); + $statusCode = $response->status_code; + if (!$this->verifyServerSignature($body, $responseHeaders, $statusCode)) { + throw new Exception(sprintf('Could not verify signature for request to "%s"', $uri)); + } + $array['ResponseHeaders'] = $responseHeaders; + + return $array; + } + + /** + * @param string $uri + * @param array $data + * @param array $headers + * + * @return array + */ + protected function sendUnsignedBunqPost(string $uri, array $data, array $headers): array + { + $body = json_encode($data); + $fullUri = $this->server . $uri; + try { + $response = Requests::post($fullUri, $headers, $body); + } catch (Requests_Exception $e) { + return ['Error' => [0 => ['error_description' => $e->getMessage(), 'error_description_translated' => $e->getMessage()],]]; + } + $body = $response->body; + $responseHeaders = $response->headers->getAll(); + $array = json_decode($body, true); + if ($this->isErrorResponse($array)) { + $this->throwResponseError($array); + } + $array['ResponseHeaders'] = $responseHeaders; + + return $array; + } + + /** + * @param array $response + * + * @return bool + */ + private function isErrorResponse(array $response): bool + { + $key = key($response); + if ($key === 'Error') { + return true; + } + + return false; + } + + /** + * @param array $response + * + * @throws Exception + */ + private function throwResponseError(array $response) + { + echo '
' . print_r($response, true) . '
' . json_encode($response) . '