Skip to content

Commit

Permalink
Merge pull request #12 from superbrave/query-string
Browse files Browse the repository at this point in the history
Query string
  • Loading branch information
krijn-sb authored Mar 3, 2020
2 parents 61e5a6f + d049c98 commit e6cb614
Show file tree
Hide file tree
Showing 2 changed files with 122 additions and 7 deletions.
26 changes: 19 additions & 7 deletions src/Message/AbstractRequest.php
Original file line number Diff line number Diff line change
Expand Up @@ -76,19 +76,31 @@ protected function getResponseBody(): array
/**
* Safety hash from icepay, to be generated after putting in all the data.
*
* @param string $requestMethod
* @param string $urlPath
* @param array $data
* @param string $requestMethod
* @param string $urlPath
* @param array|\stdClass $data
* @param bool $urlIsFullUrl = false. True to have $urlPath be the absolute (full) url
*
* @return string
*/
private function getSecurityHash(string $requestMethod, string $urlPath, array $data): string
{
$string = $this->getBaseUrl().$urlPath.$requestMethod.$this->getContractProfileId().json_encode($data);
protected function getSecurityHash(
string $requestMethod,
string $urlPath,
$data,
bool $urlIsFullUrl = false
): string {
$contractProfileId = $this->getContractProfileId();

$fullUrl = $this->getBaseUrl().$urlPath;
if ($urlIsFullUrl) {
$fullUrl = $urlPath;
}

$toBeHashed = $fullUrl.$requestMethod.$contractProfileId.json_encode($data);

$hash = hash_hmac(
'sha256',
$string,
$toBeHashed,
base64_decode($this->getSecretKey()),
true
);
Expand Down
103 changes: 103 additions & 0 deletions src/Message/TransactionStatusRequest.php
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,12 @@ public function getData(): array
*/
public function sendData($data): ResponseInterface
{
$transactionStatusResponse = $this->getTransactionStatusFromPostBack();

if ($transactionStatusResponse !== null) {
return $transactionStatusResponse;
}

$this->sendRequest(
Request::METHOD_POST,
sprintf(
Expand All @@ -42,4 +48,101 @@ public function sendData($data): ResponseInterface
$this->getResponse()->getStatusCode()
);
}

/**
* Use the data sent by Icepay in the post back to check the status.
* This is necessary because Icepay has a delay in their backend if you request the status immediately after the signal.
*
* @see http://docs2.icepay.com/payment-process/handling-the-postback/postback-sample/
*
* @return TransactionStatusResponse|null - Null when the data is is not sent or not correct
*/
private function getTransactionStatusFromPostBack(): ?TransactionStatusResponse
{
if (stripos($this->httpRequest->getContentType(), 'json') === false) {
return null;
}

try {
$content = $this->httpRequest->getContent();
$contentAsArray = json_decode($content, true);
$contentAsStdObj = json_decode($content);
} catch (\LogicException $exception) {
return null;
}

if (is_array($contentAsArray) === false || isset($contentAsArray['StatusCode']) === false) {
return null;
}

$this->setContractProfileId($contentAsStdObj->ContractProfileId);

if ($this->validateSecurityHashMatch($this->httpRequest, $contentAsStdObj) === false) {
return null;
}

$camelCasedKeysContent = array_combine(
array_map('lcfirst', array_keys($contentAsArray)),
array_values($contentAsArray)
);

return new TransactionStatusResponse(
$this,
$camelCasedKeysContent,
200
);
}

/**
* Get the security hash from the request and match it against a generated hash from the sent values.
* Needs the POSTed JSON as stdClass.
*
* @param Request $request
* @param \stdClass $contentAsStdObj
*
* @return bool
*/
private function validateSecurityHashMatch(Request $request, \stdClass $contentAsStdObj): bool
{
$sentSecurityHash = $request->headers->get('checksum');

$possibleHashes = $this->getPossibleValidHashes($request, $contentAsStdObj);

foreach ($possibleHashes as $generatedHash) {
if ($generatedHash === $sentSecurityHash) {
return true;
}
}

return false;
}

/**
* They way Icepay generates the hash is by using our notification url.
* Though, they might add a trailing slash. Unsure of this at this point, so check both.
*
* @param Request $request
* @param \stdClass $contentAsStdObj
*
* @return array
*/
private function getPossibleValidHashes(Request $request, $contentAsStdObj): array
{
$notifyUrls = [
$request->getSchemeAndHttpHost().$request->getRequestUri(),
$request->getSchemeAndHttpHost().$request->getRequestUri().'/',
];

$hashes = [];
foreach ($notifyUrls as $notifyUrl) {
$hashes[] = $this->getSecurityHash(
$request->getMethod(),
$notifyUrl,
$contentAsStdObj,
true
);
}

return $hashes;
}
}

0 comments on commit e6cb614

Please sign in to comment.