/**
  * Handle an incoming request.
  *
  * @param Request $request
  * @param Closure $next
  *
  * @return mixed
  */
 public function handle($request, Closure $next)
 {
     $validationResult = Spec::define(['content-hash' => PrimitiveTypeConstraint::forType(ScalarTypes::SCALAR_STRING), 'authorization' => PrimitiveTypeConstraint::forType(ScalarTypes::SCALAR_STRING)], [], ['content-hash', 'authorization'])->check(array_map(function ($entry) {
         return $entry[0];
     }, $request->headers->all()));
     if ($validationResult->failed()) {
         return ApiResponse::makeFromSpec($validationResult)->toResponse();
     }
     $authorization = str_replace('Hash ', '', $request->headers->get('Authorization'));
     $content = $request->getContent();
     try {
         $pair = $this->finder->byPublicId($authorization, KeyPairTypes::TYPE_HMAC);
         $hasher = new HmacHasher();
         $verificationResult = $hasher->verify($request->headers->get('Content-Hash'), $content . Carbon::now()->format($this->format), $pair->getSecretKey());
         if ($verificationResult) {
             $request->attributes->set(static::ATTRIBUTE_KEYPAIR, $pair);
             return $next($request);
         }
         return ApiResponse::create([], ApiResponse::STATUS_INVALID, ['HMAC content hash does not match the expected hash.'])->toResponse();
     } catch (ModelNotFoundException $ex) {
         if ($ex->getModel() === KeyPair::class) {
             return ApiResponse::create([], ApiResponse::STATUS_INVALID, ['Unable to locate public ID. Check your credentials'])->toResponse();
         }
         throw $ex;
     }
 }
 public function testVerify()
 {
     $hasher = new HmacHasher();
     $private = Str::random(256);
     $private2 = Str::random(256);
     $hash1 = $hasher->hash('this is a test', $private);
     $hash2 = $hasher->hash('another test', $private2);
     $this->assertEqualsMatrix([[true, $hasher->verify($hash1, 'this is a test', $private)], [false, $hasher->verify($hash1, 'this is a test', $private2)], [false, $hasher->verify($hash2, 'this is a test', $private)], [false, $hasher->verify($hash1, 'th1s 1s 4 t3st', $private)], [false, $hasher->verify($hash2, 'another test', $private)], [true, $hasher->verify($hash2, 'another test', $private2)]]);
 }
 /**
  * Generate the content hash using the content string and the current date.
  *
  * @param $content
  *
  * @return string
  */
 public function hash($content)
 {
     return $this->hasher->hash($content . Carbon::now()->format('Y-m-d H:i'), $this->keyPair->secret_key);
 }
 public function testHandleWithMissingAuthorization()
 {
     $generator = new KeyPairGenerator();
     $hasher = new HmacHasher();
     $pair = $generator->generateHmac();
     $content = json_encode(['doge' => 'much secret']);
     $brokenRequest = Request::create('/auth/something/important/dont/hax/pls', 'POST', [], [], [], [], $content);
     $brokenRequest->headers->set('Content-Hash', $hasher->hash($content, $pair->getSecretKey()));
     $finder = m::mock(KeyPairFinderInterface::class);
     $finder->shouldReceive('byPublicId')->with($pair->getPublicId(), KeyPairTypes::TYPE_HMAC)->once()->andReturn($pair);
     $instance = new HmacMiddleware($finder);
     $response = $instance->handle($brokenRequest, function () {
         //
     });
     $body = Std::jsonDecode($response->getContent());
     $this->assertEqualsMatrix([['One or more fields are invalid. Please check your input.', $body['messages'][0]], [['authorization'], $body['missing']]]);
 }