| 
<?phpnamespace ParagonIE\Sapient\UnitTests;
 
 use GuzzleHttp\Psr7\Request;
 use GuzzleHttp\Psr7\Response;
 use ParagonIE\ConstantTime\Base64UrlSafe;
 use ParagonIE\Sapient\Adapter\Guzzle;
 use ParagonIE\Sapient\CryptographyKeys\{
 SealingPublicKey,
 SealingSecretKey
 };
 use ParagonIE\Sapient\Sapient;
 use PHPUnit\Framework\TestCase;
 
 /**
 * Class SapientTest
 * @package ParagonIE\Sapient\UnitTests
 */
 class SapientSealTest extends TestCase
 {
 /** @var Sapient */
 protected $sapient;
 
 /** @var SealingSecretKey */
 protected $clientSealSecret;
 
 /** @var SealingPublicKey */
 protected $clientSealPublic;
 
 /** @var SealingSecretKey */
 protected $serverSealSecret;
 
 /** @var SealingPublicKey */
 protected $serverSealPublic;
 
 /**
 * Setup the class properties
 */
 public function setUp()
 {
 $this->sapient = new Sapient(new Guzzle());
 
 $this->clientSealSecret = SealingSecretKey::generate();
 $this->clientSealPublic = $this->clientSealSecret->getPublickey();
 
 $this->serverSealSecret = SealingSecretKey::generate();
 $this->serverSealPublic = $this->serverSealSecret->getPublickey();
 }
 
 private function getSampleObjects(): array
 {
 return [
 [],
 ['test' => 'abcdefg'],
 ['random' => Base64UrlSafe::encode(
 \random_bytes(
 \random_int(1, 100)
 )
 )
 ],
 ['structued' => [
 'abc' => 'def',
 'o' => null,
 'ghi' => ['j', 'k', 'l'],
 'm' => 1234,
 'n' => 56.78,
 'p' => ['q' => ['r' => []]]
 ]]
 ];
 }
 
 /**
 * @covers Sapient::createSignedJsonRequest()
 * @covers Sapient::verifySignedRequest()
 */
 public function testSignedJsonRequest()
 {
 $sampleObjects = $this->getSampleObjects();
 
 foreach ($sampleObjects as $obj) {
 $guzzle = new Guzzle();
 $request = $guzzle->createSealedJsonRequest(
 'POST',
 '/',
 $obj,
 $this->clientSealPublic
 );
 $decoded = $this->sapient->unsealJsonRequest(
 $request,
 $this->clientSealSecret
 );
 $this->assertSame($obj, $decoded);
 
 /* We expect an exception: */
 try {
 $this->sapient->unsealJsonRequest(
 $request,
 $this->serverSealSecret
 );
 $this->fail('Bad message signature');
 } catch (\Throwable $ex) {
 }
 
 $invalid = $request->withBody(
 $this->sapient->stringToStream(
 Base64UrlSafe::encode('invalid message goes here for verifying the failure of crypto_box_seal')
 )
 );
 /* We expect an exception: */
 try {
 $this->sapient->unsealJsonRequest(
 $invalid,
 $this->clientSealSecret
 );
 $this->fail('Bad message accepted');
 } catch (\Throwable $ex) {
 }
 }
 }
 
 /**
 * @covers Sapient::createSignedRequest()
 * @covers Sapient::verifySignedRequest()
 */
 public function testSignedRequest()
 {
 $randomMessage = Base64UrlSafe::encode(
 \random_bytes(
 \random_int(101, 200)
 )
 );
 $request = $this->sapient->createSealedRequest(
 'POST',
 '/',
 $randomMessage,
 $this->clientSealPublic
 );
 $decoded = $this->sapient->unsealRequest(
 $request,
 $this->clientSealSecret
 );
 $this->assertInstanceOf(Request::class, $decoded);
 $this->assertSame($randomMessage, (string) $decoded->getBody());
 
 /* Test bad public key */
 try {
 $this->sapient->unsealRequest(
 $request,
 $this->serverSealSecret
 );
 $this->fail('Bad message signature');
 } catch (\Throwable $ex) {
 }
 
 $invalid = $request->withBody(
 $this->sapient->stringToStream(
 Base64UrlSafe::encode('invalid message goes here for verifying the failure of crypto_box_seal')
 )
 );
 
 /* Test bad message */
 try {
 $this->sapient->unsealRequest(
 $invalid,
 $this->serverSealSecret
 );
 $this->fail('Bad message accepted');
 } catch (\Throwable $ex) {
 }
 }
 /**
 * @covers Sapient::createSignedJsonResponse()
 * @covers Sapient::verifySignedResponse()
 */
 public function testSignedJsonResponse()
 {
 $sampleObjects = $this->getSampleObjects();
 
 foreach ($sampleObjects as $obj) {
 $guzzle = new Guzzle();
 $response = $guzzle->createSealedJsonResponse(
 200,
 $obj,
 $this->serverSealPublic
 );
 $responseRaw = $this->sapient->unsealResponse(
 $response,
 $this->serverSealSecret
 );
 $this->assertInstanceOf(Response::class, $responseRaw);
 
 $decoded = $this->sapient->unsealJsonResponse($response, $this->serverSealSecret);
 $this->assertSame($obj, $decoded);
 
 /* Test bad public key */
 try {
 $this->sapient->unsealResponse(
 $response,
 $this->clientSealSecret
 );
 $this->fail('Bad message accepted');
 } catch (\Throwable $ex) {
 }
 
 $invalid = $response->withBody(
 $this->sapient->stringToStream(
 Base64UrlSafe::encode('invalid message goes here for verifying the failure of crypto_box_seal')
 )
 );
 /* Test bad message */
 try {
 $this->sapient->unsealResponse(
 $invalid,
 $this->serverSealSecret
 );
 $this->fail('Bad message accepted');
 } catch (\Throwable $ex) {
 }
 }
 }
 
 /**
 * @covers Sapient::createSignedResponse()
 * @covers Sapient::verifySignedResponse()
 */
 public function testSealedResponse()
 {
 $randomMessage = Base64UrlSafe::encode(
 \random_bytes(
 \random_int(101, 200)
 )
 );
 $response = $this->sapient->createSealedResponse(
 200,
 $randomMessage,
 $this->serverSealPublic
 );
 $responseRaw = $this->sapient->unsealResponse(
 $response,
 $this->serverSealSecret
 );
 $this->assertInstanceOf(Response::class, $responseRaw);
 
 $decoded = $this->sapient->unsealResponse($response, $this->serverSealSecret);
 $this->assertSame($randomMessage, (string) $decoded->getBody());
 
 /* Test bad public key */
 try {
 $this->sapient->unsealResponse(
 $response,
 $this->clientSealSecret
 );
 $this->fail('Bad message accepted');
 } catch (\Throwable $ex) {
 }
 
 $invalid = $response->withBody(
 $this->sapient->stringToStream(
 Base64UrlSafe::encode('invalid message goes here for verifying the failure of crypto_box_seal')
 )
 );
 /* Test bad message */
 try {
 $this->sapient->unsealResponse(
 $invalid,
 $this->serverSealSecret
 );
 $this->fail('Bad message accepted');
 } catch (\Throwable $ex) {
 }
 }
 
 /**
 * @covers Sapient::signRequest()
 * @covers Sapient::signResponse()
 */
 public function testPsr7()
 {
 $randomMessage = Base64UrlSafe::encode(
 \random_bytes(
 \random_int(101, 200)
 )
 );
 
 $request = new Request('POST', '/test', [], $randomMessage);
 $signedRequest = $this->sapient->sealRequest($request, $this->clientSealPublic);
 try {
 $unsealed = $this->sapient->unsealRequest(
 $signedRequest,
 $this->clientSealSecret
 );
 $this->assertSame(
 $randomMessage,
 (string) $unsealed->getBody()
 );
 } catch (\Throwable $ex) {
 $this->fail('Error decrypting message');
 }
 
 $response = new Response(200, [], $randomMessage);
 $signedResponse = $this->sapient->sealResponse($response, $this->clientSealPublic);
 try {
 $unsealed = $this->sapient->unsealResponse(
 $signedResponse,
 $this->clientSealSecret
 );
 $this->assertSame(
 $randomMessage,
 (string) $unsealed->getBody()
 );
 } catch (\Throwable $ex) {
 $this->fail('Error decrypting message');
 }
 }
 }
 |