Skip to content

Commit

Permalink
Use a decodedRequestPacket variable for the doecded request, fix up f…
Browse files Browse the repository at this point in the history
…unction signatures
  • Loading branch information
klauste committed Sep 23, 2024
1 parent 5b7a641 commit 8f3206b
Showing 1 changed file with 74 additions and 84 deletions.
158 changes: 74 additions & 84 deletions src/Request/Init.php
Original file line number Diff line number Diff line change
Expand Up @@ -71,8 +71,15 @@ class Init
*/
private $requestPacket;

private $decodedRequestPacket;

/**
* Tracking if the request was passed as a string
* Tracking if the request was passed as a string. If the request is indeed passed as string,
* there is an attempt to not alter the string in any way by decoding and encoding. This will
* only work if telemetry is disabled. Otherwise the metadata has to be set in the request
* meaning that decoding is required. It also does not work for assess if it has questions
* api settings
*
* @var bool
*/
private $requestPassedAsString = false;
Expand Down Expand Up @@ -139,28 +146,19 @@ public function __construct(
$this->preHashStringFactory = new PreHashStringFactory();
}

// convert when it is an array for generateSignature
if (!self::$telemetryEnabled) {
if (isset($requestPacket) && is_array($requestPacket)) {
$requestPacket = json_encode($requestPacket);
}
}

$this->preHashStringGenerator = $this->preHashStringFactory->getPreHashStringGenerator($service);

// First validate the arguments passed
list ($requestPacket, $securityPacket) = $this->validate($service, $secret, $securityPacket, $requestPacket);

if (self::$telemetryEnabled) {
$requestPacket = $this->addMeta($requestPacket);
}

// Set instance variables based off the arguments passed
$this->service = $service;
$this->securityPacket = $securityPacket;
$this->secret = $secret;
$this->requestPacket = $requestPacket;
$this->action = $action;
$this->validate();

if (self::$telemetryEnabled) {
$this->addMeta();
}

// Set any service specific options
$this->setServiceOptions();
Expand All @@ -184,11 +182,8 @@ public function __construct(
* }
* }
*
* @param array $requestPacket
*
* @return array
*/
private function addMeta(array $requestPacket): array
private function addMeta()
{
$sdkMetricsMeta = [
'version' => $this->getSDKVersion(),
Expand All @@ -198,15 +193,14 @@ private function addMeta(array $requestPacket): array
'platform_version' => php_uname('r')
];

if (isset($requestPacket['meta'])) {
$requestPacket['meta']['sdk'] = $sdkMetricsMeta;
if (isset($this->decodedRequestPacket['meta'])) {
$this->decodedRequestPacket['meta']['sdk'] = $sdkMetricsMeta;
} else {
$requestPacket['meta'] = [
$this->decodedRequestPacket['meta'] = [
'sdk' => $sdkMetricsMeta
];
}

return $requestPacket;
$this->requestPacket = Json::encode($this->decodedRequestPacket);

Check notice on line 203 in src/Request/Init.php

View check run for this annotation

Codacy Production / Codacy Static Code Analysis

src/Request/Init.php#L203

Avoid using static access to class '\LearnositySdk\Utils\Json' in method 'addMeta'.
}

/**
Expand Down Expand Up @@ -237,7 +231,7 @@ public function generate(bool $encode = true)
// Add the security packet (with signature) to the output
$output['security'] = Json::encode($this->securityPacket);

$output['request'] = Json::encode($this->requestPacket);
$output['request'] = Json::encode($this->decodedRequestPacket);

Check notice on line 234 in src/Request/Init.php

View check run for this annotation

Codacy Production / Codacy Static Code Analysis

src/Request/Init.php#L234

Avoid using static access to class '\LearnositySdk\Utils\Json' in method 'generate'.

if (!empty($this->action)) {
$output['action'] = $this->action;
Expand All @@ -248,8 +242,8 @@ public function generate(bool $encode = true)
case 'assess':
// Stringify the request packet if necessary
$output = $this->requestPassedAsString ?
Json::encode($this->requestPacket) :
$this->requestPacket;
$this->requestPacket :
$this->decodedRequestPacket;
break;
case 'author':
case 'authoraide':
Expand All @@ -259,10 +253,9 @@ public function generate(bool $encode = true)
$output['security'] = $this->securityPacket;

// Stringify the request packet if necessary
/*$output['request'] = $this->requestPassedAsString ?
json_decode($this->requestPacket) :
$this->requestPacket;*/
$output['request'] = $this->requestPacket;
$output['request'] = $this->requestPassedAsString ?
$this->requestPacket :
$this->decodedRequestPacket;
break;
case 'questions':
// Add the security packet (with signature) to the root of output
Expand All @@ -271,14 +264,14 @@ public function generate(bool $encode = true)
// Remove the `domain` key from the security packet
unset($output['domain']);

if (!empty($this->requestPacket)) {
$output = array_merge($output, $this->requestPacket);
if (!empty($this->decodedRequestPacket)) {
$output = array_merge($output, $this->decodedRequestPacket);
}
break;
case 'events':
// Add the security packet (with signature) to the output
$output['security'] = $this->securityPacket;
$output['config'] = $this->requestPacket;
$output['config'] = $this->decodedRequestPacket;
break;
default:
// no default
Expand Down Expand Up @@ -320,26 +313,21 @@ public function generateSignature(): string
*/
private function setServiceOptions()
{
// Not sure - if this is required. Here, we are converting the string to array with the
if (self::$telemetryEnabled) {
$this->requestPacket = is_string($this->requestPacket) ? (array)json_decode($this->requestPacket) : $this->requestPacket;
}

switch ($this->service) {
case 'assess':
$this->signRequestData = false;
// The Assess API holds data for the Questions API that includes
// security information and a signature. Retrieve the security
// information from $this and generate a signature for the
// Questions API
if (array_key_exists('questionsApiActivity', $this->requestPacket)) {
if (array_key_exists('questionsApiActivity', $this->decodedRequestPacket)) {
// prepare signature parts
$signatureParts = [];
$signatureParts['consumer_key'] = $this->securityPacket['consumer_key'];
if (isset($this->securityPacket['domain'])) {
$signatureParts['domain'] = $this->securityPacket['domain'];
} elseif (isset($this->requestPacket['questionsApiActivity']['domain'])) {
$signatureParts['domain'] = $this->requestPacket['questionsApiActivity']['domain'];
} elseif (isset($this->decodedRequestPacket['questionsApiActivity']['domain'])) {
$signatureParts['domain'] = $this->decodedRequestPacket['questionsApiActivity']['domain'];
} else {
$signatureParts['domain'] = 'assess.learnosity.com';
}
Expand All @@ -351,7 +339,7 @@ private function setServiceOptions()
$signatureParts['secret'] = $this->secret;

// override security parameters in questionsApiActivity
$questionsApi = $this->requestPacket['questionsApiActivity'];
$questionsApi = $this->decodedRequestPacket['questionsApiActivity'];
$questionsApi['consumer_key'] = $signatureParts['consumer_key'];
unset($questionsApi['domain']);
$questionsApi['timestamp'] = $signatureParts['timestamp'];
Expand All @@ -364,7 +352,8 @@ private function setServiceOptions()
$this->securityPacket = $signatureParts;
$questionsApi['signature'] = $this->generateSignature();

$this->requestPacket['questionsApiActivity'] = $questionsApi;
$this->decodedRequestPacket['questionsApiActivity'] = $questionsApi;
$this->requestPacket = Json::encode($this->decodedRequestPacket);
}
break;
case 'questions':
Expand All @@ -375,15 +364,15 @@ private function setServiceOptions()
// The Events API requires a user_id, so we make sure it's a part
// of the security packet as we share the signature in some cases
if (
array_key_exists('user_id', $this->requestPacket)
&& !array_key_exists('user_id', $this->securityPacket)
array_key_exists('user_id', $this->decodedRequestPacket) &&
!array_key_exists('user_id', $this->securityPacket)
) {
$this->securityPacket['user_id'] = $this->requestPacket['user_id'];
$this->securityPacket['user_id'] = $this->decodedRequestPacket['user_id'];
}
break;
case 'events':
$this->signRequestData = false;
$users = $this->requestPacket['users'];
$users = $this->decodedRequestPacket['users'];
$hashedUsers = [];
if (!$this->isAssocArray($users)) {
throw new ValidationException('Passing an array of user IDs is deprecated,' .
Expand All @@ -398,7 +387,8 @@ private function setServiceOptions()
);
}
if (count($hashedUsers)) {
$this->requestPacket['users'] = $hashedUsers;
$this->decodedRequestPacket['users'] = $hashedUsers;
$this->requestPacket = Json::encode($this->decodedRequestPacket);
}
break;
default:
Expand All @@ -410,56 +400,56 @@ private function setServiceOptions()
/**
* Validate the arguments passed to the constructor
*
* @param string $service
* @param string $secret
* @param array|string $securityPacket
* @param array|string $requestPacket
* @return array
* @throws ValidationException
*/
public function validate(string $service, string $secret, $securityPacket, $requestPacket): array
public function validate()
{

if (self::$telemetryEnabled) {
// Not sure - if this is required. Here, we are converting the string to array with the - start
$requestPacket = is_string($requestPacket) ? (array)json_decode($requestPacket) : $requestPacket;
// --end
if (!empty($requestPacket) && !is_array($requestPacket)) {
throw new ValidationException('The request packet must be an array');
}

if (is_null($requestPacket) || empty($requestPacket)) {
$requestPacket = [];
}
} else {
if (is_string($requestPacket)) {
$this->requestPassedAsString = true;
}

if (is_null($requestPacket)) {
$requestPacket = '{}';
}
$this->validateAndSetRequestPacket();
// In case the user gave us a JSON securityPacket, convert to an array
if (is_string($this->securityPacket)) {
$this->securityPacket = json_decode($this->securityPacket, true);
}

if (empty($securityPacket) || !is_array($securityPacket)) {
if (empty($this->securityPacket) || !is_array($this->securityPacket)) {// In case the user gave us a JSON securityPacket, convert to an array
throw new ValidationException('The security packet must be an array or a valid JSON string');
}

// In case the user gave us a JSON securityPacket, convert to an array
if (!is_array($securityPacket) && is_string($securityPacket)) {
$securityPacket = json_decode($securityPacket, true);
if (empty($this->secret)) {
throw new ValidationException('The `secret` argument must be a valid string');
}

if (empty($secret)) {
throw new ValidationException('The `secret` argument must be a valid string');
$this->securityPacket = $this->preHashStringGenerator->validate($this->securityPacket);
}

private function validateAndSetRequestPacket()
{
$this->requestPassedAsString = $this->isRequestNonEmptyString();
if ($this->isRequestNonEmptyString()) {
$this->decodedRequestPacket = json_decode($this->requestPacket, true);
if (!is_array($this->decodedRequestPacket)) {
throw new ValidationException('The request packet must be an array or a valid JSON string');
}
return;
}

if (empty($this->requestPacket)) {
$this->requestPacket = [];
}

/*
if (!empty($requestPacket) && !is_string($requestPacket)) {
if (!empty($this->requestPacket) && !is_array($this->requestPacket)) {
throw new ValidationException('The request packet must be an array or a valid JSON string');
}*/
}
if (empty($this->requestPacket)) {
$this->requestPacket = [];
}
$this->decodedRequestPacket = $this->requestPacket;
$this->requestPacket = Json::encode($this->decodedRequestPacket);
}

return $this->preHashStringGenerator->validate($securityPacket, $requestPacket);
private function isRequestNonEmptyString(): bool
{
return is_string($this->requestPacket) && !empty($this->requestPacket);
}

/**
Expand Down

0 comments on commit 8f3206b

Please sign in to comment.