diff --git a/application/core/LSSodium.php b/application/core/LSSodium.php index 48342188c54..f09d2480300 100644 --- a/application/core/LSSodium.php +++ b/application/core/LSSodium.php @@ -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; } @@ -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 diff --git a/application/models/LSActiveRecord.php b/application/models/LSActiveRecord.php index d27e7196029..e58a57a9cff 100644 --- a/application/models/LSActiveRecord.php +++ b/application/models/LSActiveRecord.php @@ -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) { @@ -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); @@ -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); } diff --git a/tests/unit/models/EncryptAttributesTest.php b/tests/unit/models/EncryptAttributesTest.php index 3de704e84d3..624fb58b870 100644 --- a/tests/unit/models/EncryptAttributesTest.php +++ b/tests/unit/models/EncryptAttributesTest.php @@ -20,7 +20,7 @@ public static function setupBeforeClass(): void $surveyFile = self::$surveysFolder . '/survey_archive_265831.lsa'; self::importSurvey($surveyFile); } - + /** * Test token without validation. */ @@ -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. */ @@ -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); + } }