Beispiel #1
0
 /**
  * Get the default value of each field.
  *
  * @return array
  */
 public function getDefaults()
 {
     if ($this->spec instanceof Spec) {
         return $this->spec->getDefaults();
     }
     return [];
 }
 /**
  * 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;
     }
 }
Beispiel #3
0
 /**
  * Check that the spec matches and overlay help messaged.
  *
  * The resulting SpecResult instance should have more user-friendly
  * messages. This allows one to use Specs for validation on a website or
  * even an API.
  *
  * @param array $input
  *
  * @return SpecResult
  */
 public function check(array $input)
 {
     $result = $this->spec->check($input);
     return new SpecResult($result->getMissing(), Arr::walkCopy($result->getFailed(), function ($key, $value, &$array, $path) {
         $array[$key] = Std::coalesce(Std::firstBias(Arr::dotGet($this->messages, Std::nonempty($path, $key)) !== null, [Arr::dotGet($this->messages, Std::nonempty($path, $key))], null), Std::firstBias($value instanceof AbstractConstraint, function () use($value) {
             return $value->getDescription();
         }, null), Std::firstBias(is_array($value), function () use($value) {
             return array_map(function (AbstractConstraint $item) {
                 return $item->getDescription();
             }, $value);
         }, $value));
     }, true, '', false), $result->getStatus());
 }
 /**
  * Encode constraints into JSON schema types/constraints.
  *
  * @param Spec $spec
  * @param AbstractConstraint|AbstractConstraint[]|Spec $input
  * @param string $title
  *
  * @throws CoreException
  * @return array
  */
 public function encodeConstraints(Spec $spec, $input, $title)
 {
     if ($input instanceof AbstractConstraint) {
         $schema = ['description' => $input->getDescription()];
         if ($input instanceof PrimitiveTypeConstraint) {
             $schema['type'] = $input->toString();
         }
         return $schema;
     } elseif (is_array($input)) {
         $schema = [];
         $descriptions = [];
         foreach ($input as $constraint) {
             $descriptions[] = $constraint->getDescription();
             if ($constraint instanceof PrimitiveTypeConstraint) {
                 $schema['type'] = $constraint->toString();
             }
         }
         $schema['description'] = implode('. ', $descriptions);
         return $schema;
     } elseif ($input instanceof Spec) {
         return (new static())->encode($input, $title);
     }
     throw new CoreException('Unexpected constraint type.');
 }
Beispiel #5
0
 /**
  * Render the Node.
  *
  * @throws CoreException
  * @throws InvalidAttributesException
  * @return string
  */
 public function render()
 {
     $result = $this->spec->check($this->attributes);
     if ($result->failed()) {
         throw new InvalidAttributesException($result);
     }
     $attributes = $this->renderAttributes();
     if (strlen($attributes)) {
         $attributes = ' ' . $attributes;
     }
     if ($this->selfClosing) {
         return vsprintf('<%s%s/>', [$this->tagName, $attributes]);
     }
     return vsprintf('<%s%s>%s</%s>', [$this->tagName, $attributes, $this->renderContent(), $this->tagName]);
 }
Beispiel #6
0
 public function testComplexSpec()
 {
     $graph = new SpecGraph();
     $graph->add('input', [], Spec::define(['sleepy' => Boa::boolean(), 'tennis_balls' => Boa::integer(), 'message' => Boa::either(Boa::string(), Boa::integer())], [], ['message']));
     $graph->add('allowedMessage', ['input'], Spec::define(['message' => [Boa::in(['hi', 'how are you?', 'you dumb']), Boa::in(['hi', 'how are you?', 'you are smart'])]], [], ['message']));
     $graph->add('validBallCount', ['input'], Spec::define(['tennis_balls' => Boa::between(1, 10)]));
     $graph->add('additionalBallProps', ['validBallCount'], Spec::define(['ball_color' => [Boa::string(), Boa::in(['blue', 'red', 'yellow'])]], [], ['ball_color']));
     $result = $graph->check(['sleepy' => true, 'tennis_balls' => 3, 'message' => 'hi', 'ball_color' => 'blue']);
     $this->assertTrue($result->passed());
     $result2 = $graph->check(['sleepy' => 1, 'tennis_balls' => 3]);
     $this->assertEqualsMatrix([[true, $result2->failed()], [1, count($result2->getFailed())], [['message'], $result2->getMissing()]]);
     $result3 = $graph->check(['sleepy' => true, 'tennis_balls' => -30, 'message' => 'hello']);
     $this->assertEqualsMatrix([[true, $result3->failed()], [2, count($result3->getFailed())], [[], $result3->getMissing()]]);
     $result4 = $graph->check(['sleepy' => true, 'tennis_balls' => 3, 'message' => 'how are you?']);
     $this->assertEqualsMatrix([[true, $result4->failed()], [0, count($result4->getFailed())], [['ball_color'], $result4->getMissing()]]);
     $result5 = $graph->check(['sleepy' => true, 'tennis_balls' => 3, 'message' => 'how are you?', 'ball_color' => 'liquid_gold']);
     $this->assertEqualsMatrix([[true, $result5->failed()], [1, count($result5->getFailed())], [[], $result5->getMissing()]]);
 }
Beispiel #7
0
 /**
  * Get all the constraints for a field.
  *
  * @param string $fieldName
  *
  * @return Iterable
  */
 protected function getInternalFieldConstraints($fieldName)
 {
     return parent::getInternalFieldConstraints($fieldName)->append(ArrayList::of([$this->getFieldType($fieldName)]));
 }
Beispiel #8
0
 /**
  * The inverse operation of calling toResponse.
  *
  * This function will attempt to parse a Response object into an
  * ApiResponse object, which can be useful for introspection and testing.
  *
  * @param Response $response
  *
  * @throws CoreException
  * @return static
  */
 public static function fromResponse(Response $response)
 {
     $body = Std::jsonDecode($response->getContent());
     $result = Spec::define(['messages' => Boa::arrOf(Boa::string()), 'status' => Boa::in(static::getValidStatuses()), 'code' => Boa::integer()])->check($body);
     if ($result->failed()) {
         throw new CoreException('Unable to parse an ApiResponse out of the content of a' . ' Response object. Make sure that the Response object was' . ' actually generated by an ApiResponse or a compatible' . ' implementation.');
     }
     return new static(Arr::except($body, static::getReservedKeys()), $body['status'], $body['messages']);
 }
Beispiel #9
0
 /**
  * Get a RAML parameter definition from a Spec field.
  *
  * @param Spec $spec
  * @param string $field
  *
  * @return array
  */
 protected function specFieldToParameter(Spec $spec, $field)
 {
     $constraints = $spec->getConstraints();
     $defaults = $spec->getDefaults();
     $required = $spec->getRequired();
     $parameter = [];
     if (Arr::has($constraints, $field)) {
         $input = $constraints[$field];
         if (is_array($input) || $input instanceof Spec) {
             if ($input instanceof Spec) {
                 $input = [$input];
             }
             foreach ($input as $constraint) {
                 if ($constraint instanceof PrimitiveTypeConstraint) {
                     switch ($constraint->toString()) {
                         case ScalarTypes::SCALAR_STRING:
                             $parameter['type'] = 'string';
                             break;
                         case ScalarTypes::SCALAR_FLOAT:
                         case ScalarTypes::SCALAR_INTEGER:
                             $parameter['type'] = 'number';
                             break;
                         case ScalarTypes::SCALAR_BOOLEAN:
                             $parameter['type'] = 'boolean';
                             break;
                     }
                 }
             }
         }
     }
     if (Arr::has($defaults, $field)) {
         $parameter['default'] = $defaults[$field];
     }
     $parameter['required'] = in_array($field, $required);
     return $parameter;
 }
 /**
  * @inheritDoc
  */
 public function getSpec()
 {
     return Spec::define(['days' => Boa::integer(), 'repeat_in' => Boa::integer(), 'expire_after' => Boa::integer()], ['days' => 30, 'repeat_in' => -1, 'expire_after' => 1440]);
 }
 /**
  * @param Spec $spec
  * @param string $field
  *
  * @return TableRow
  */
 protected function renderConstraint(Spec $spec, $field)
 {
     $constraints = $spec->getConstraints();
     $defaults = $spec->getDefaults();
     $default = '';
     if (array_key_exists($field, $defaults)) {
         $default = $defaults[$field];
     }
     $constraint = $constraints[$field];
     if ($constraint instanceof AbstractConstraint) {
         return new TableRow([], [new TableCell([], $field), new TableCell([], $constraint->toString()), new TableCell([], (string) $default)]);
     }
     return new TableRow([], [new TableCell([], $field), new TableCell([], Std::map(function (AbstractConstraint $constraint) {
         return $constraint->toString() . ', ';
     }, $constraint)), new TableCell([], (string) $default)]);
 }
 public function testFireWithValidSpec()
 {
     $laravelJob = m::mock(LaravelJob::class);
     $laravelJob->shouldReceive('delete')->atLeast()->once();
     $job = new Job();
     $job->state = JobState::QUEUED;
     $job->data = json_encode(['omg' => false, 'why_not' => 'because']);
     $handler = $this->expectationsToMock(BaseTask::class, [$this->on('fire', [$job, m::type(JobSchedulerInterface::class)]), $this->on('getSpec', [], Spec::define(['omg' => Boa::boolean()], ['yes' => 'please'], ['why_not'])), $this->on('isSelfDeleting', [], false)]);
     $impersonator = new Impersonator();
     $impersonator->mock(JobRepositoryInterface::class, function (MockInterface $mock) use($job) {
         $mock->shouldReceive('find')->with(1337)->atLeast()->once()->andReturn($job);
         $mock->shouldReceive('started')->with($job, m::type('string'))->atLeast()->once();
         $mock->shouldReceive('complete')->with($job)->atLeast()->once();
     });
     $impersonator->mock(HandlerResolverInterface::class, function (MockInterface $mock) use($job, $handler) {
         $mock->shouldReceive('resolve')->with($job)->atLeast()->once()->andReturn($handler);
     });
     /** @var RunTaskCommand $command */
     $command = $impersonator->make(RunTaskCommand::class);
     $command->fire($laravelJob, ['job_id' => 1337]);
 }
Beispiel #13
0
 public function testAccessors()
 {
     $strings = Boa::string();
     $spec = new Spec(['name' => $strings], ['name' => 'Bobby'], ['name']);
     $this->assertEqualsMatrix([[['name' => $strings], $spec->getConstraints()], [['name' => 'Bobby'], $spec->getDefaults()], [['name'], $spec->getRequired()]]);
 }