Skip to content

Commit

Permalink
Fixed issue #18501: Answers with 0 as value was not saved if encrypted (
Browse files Browse the repository at this point in the history
#2738)

Dev: replace !empty by isset && !== ""
Dev: keep not set and null value just in case
  • Loading branch information
Shnoulle committed Feb 9, 2023
1 parent fd805ff commit 20ac8a1
Show file tree
Hide file tree
Showing 3 changed files with 145 additions and 6 deletions.
4 changes: 2 additions & 2 deletions application/core/LSSodium.php
Expand Up @@ -115,7 +115,7 @@ protected function getEncryptionSecretKey()
public function encrypt($sDataToEncrypt): string
{
if ($this->bLibraryExists === true) {
if ($sDataToEncrypt) {
if (isset($sDataToEncrypt) && $sDataToEncrypt !== "") {
$sEncrypted = base64_encode(ParagonIE_Sodium_Compat::crypto_secretbox((string) $sDataToEncrypt, $this->sEncryptionNonce, $this->sEncryptionSecretBoxKey));
return $sEncrypted;
}
Expand All @@ -127,7 +127,7 @@ public function encrypt($sDataToEncrypt): string
/**
*
* Decrypt encrypted string.
* @param string $sEncryptedString Encrypted string to decrypt
* @param string $sEncryptedString Encrypted string to decrypt, if it string 'null', didn't try to decode
* @param bool $bReturnFalseIfError false by default. If TRUE, return false in case of error (bad decryption). Else, return given $encryptedInput value
* @return string Return decrypted value (string or unsezialized object) if suceeded. Return FALSE if an error occurs (bad password/salt given) or inpyt encryptedString
* @throws SodiumException
Expand Down
5 changes: 2 additions & 3 deletions application/models/LSActiveRecord.php
Expand Up @@ -399,7 +399,7 @@ public static function decryptSingleOld($value = ''): string
$sodium = Yii::app()->sodiumOld;
}
// if $value is provided, it would decrypt
if ($value) {
if (isset($value) && $value !== '') {
try {
return $sodium->decrypt($value);
} catch (throwable $e) {
Expand All @@ -424,7 +424,7 @@ public static function decryptSingleOld($value = ''): string
public static function encryptSingle($value = '')
{
// if $value is provided, it would decrypt
if (!empty($value)) {
if (isset($value) && $value !== "") {
// load sodium library
$sodium = Yii::app()->sodium;
return $sodium->encrypt($value);
Expand Down Expand Up @@ -458,7 +458,6 @@ public function encryptSave($runValidation = false)

// encrypt attributes
$this->decryptEncryptAttributes('encrypt');

// call save() method without validation, validation is already done ( if needed )
return $this->save(false);
}
Expand Down
142 changes: 141 additions & 1 deletion tests/unit/models/EncryptAttributesTest.php
Expand Up @@ -20,7 +20,7 @@ public static function setupBeforeClass(): void
$surveyFile = self::$surveysFolder . '/survey_archive_265831.lsa';
self::importSurvey($surveyFile);
}

/**
* Test token without validation.
*/
Expand Down Expand Up @@ -52,6 +52,69 @@ public function testTokenWithoutValidation()
$this->assertNotEquals('last', $token->lastname);
}

/**
* Test token with 0 as value
* No validation
*/
public function testTokenCrypt0()
{
// Get our token.
$tokens = \TokenDynamic::model(self::$surveyId)->findAll();
$this->assertNotEmpty($tokens);
$this->assertCount(1, $tokens);
$token = $tokens[0];
$token->decrypt();

// Change attribute_1.
$token->attribute_1 = '0';
$token->encryptSave(false);

// Load token and decrypt.
$tokens = \TokenDynamic::model(self::$surveyId)->findAll();
$this->assertCount(1, $tokens);
$token = $tokens[0];
$token->decrypt();
$this->assertEquals('0', $token->attribute_1);

// Test the omitting decrypt() works.
$tokens = \TokenDynamic::model(self::$surveyId)->findAll();
$this->assertCount(1, $tokens);
$token = $tokens[0];
$this->assertNotEquals('0', $token->attribute_1);
}

/**
* Test token with "" as value
* No validation
*/
public function testTokenCryptEmptyString()
{
// Get our token.
$tokens = \TokenDynamic::model(self::$surveyId)->findAll();
$this->assertNotEmpty($tokens);
$this->assertCount(1, $tokens);
$token = $tokens[0];
$token->decrypt();

// Change attribute_1.
$token->attribute_1 = '';
$token->encryptSave(false);

// Load token and decrypt.
$tokens = \TokenDynamic::model(self::$surveyId)->findAll();
$this->assertCount(1, $tokens);
$token = $tokens[0];
$token->decrypt();
$this->assertEquals('', $token->attribute_1);

// Test the omitting decrypt works : "" is not cryted
$tokens = \TokenDynamic::model(self::$surveyId)->findAll();
$this->assertCount(1, $tokens);
$token = $tokens[0];
/* "" is not crypted */
$this->assertEquals('', $token->attribute_1);
}

/**
* Test token with validation.
*/
Expand Down Expand Up @@ -156,4 +219,81 @@ public function testResponseWithValidation()
$this->assertEquals('New answer.', $decryptedAnswer);
$this->assertNotEquals('New answer.', $answer);
}

/**
* Test response savec with 0
* With validation
*/
public function testResponseCrypt0()
{
$responses = \Response::model(self::$surveyId)->findAll();
$this->assertCount(1, $responses);
$response = $responses[0];
$response->decrypt();

// Get questions.
$survey = \Survey::model()->findByPk(self::$surveyId);
$questionObjects = $survey->groups[0]->questions;
$questions = [];
foreach ($questionObjects as $q) {
$questions[$q->title] = $q;
}

$sgqa = self::$surveyId . 'X' . $survey->groups[0]->gid . 'X' . $questions['Q00']->qid;

// Change answer
$response->$sgqa = "0";
$response->encryptSave(true);

// Load answer
$responses = \Response::model(self::$surveyId)->findAll();
$this->assertCount(1, $responses);
$response = $responses[0];

$answer = $response->$sgqa;
$response->decrypt();
$decryptedAnswer = $response->$sgqa;

$this->assertEquals('0', $decryptedAnswer);
$this->assertNotEquals('0', $answer);
}

/**
* Test response saved with ""
* With validation
*/
public function testResponseCryptEmptyString()
{
$responses = \Response::model(self::$surveyId)->findAll();
$this->assertCount(1, $responses);
$response = $responses[0];
$response->decrypt();

// Get questions.
$survey = \Survey::model()->findByPk(self::$surveyId);
$questionObjects = $survey->groups[0]->questions;
$questions = [];
foreach ($questionObjects as $q) {
$questions[$q->title] = $q;
}

$sgqa = self::$surveyId . 'X' . $survey->groups[0]->gid . 'X' . $questions['Q00']->qid;

// Change answer
$response->$sgqa = "";
$response->encryptSave(true);

// Load answer
$responses = \Response::model(self::$surveyId)->findAll();
$this->assertCount(1, $responses);
$response = $responses[0];

$answer = $response->$sgqa;
$response->decrypt();
$decryptedAnswer = $response->$sgqa;

$this->assertEquals('', $decryptedAnswer);
/* "" is not crypted */
$this->assertEquals('', $answer);
}
}

0 comments on commit 20ac8a1

Please sign in to comment.