/** * Inject the image blob from the image model into the shared imagick instance * * @param EventInterface $event The event instance */ public function readImageBlob(EventInterface $event) { if ($event->hasArgument('image')) { // The image has been specified as an argument to the event $image = $event->getArgument('image'); } else { if ($event->getName() === 'images.post') { // The image is found in the request $image = $event->getRequest()->getImage(); } else { // The image is found in the response $image = $event->getResponse()->getModel(); } } // Inject the image blob $this->imagick->readImageBlob($image->getBlob()); }
/** * Perform content negotiation by looking the the current URL and the Accept request header * * @param EventInterface $event The event instance */ public function negotiate(EventInterface $event) { $request = $event->getRequest(); $response = $event->getResponse(); $formatter = null; $extension = $request->getExtension(); $routeName = (string) $request->getRoute(); $config = $event->getConfig(); $contentNegotiateImages = $config['contentNegotiateImages']; $model = $response->getModel(); if (!$extension && !$contentNegotiateImages && $model instanceof Model\Image) { // Configuration is telling us not to use content negotiation for images, // instead we want to use the original format of the image $mime = $model->getMimeType(); $formatter = $this->supportedTypes[$mime]; } else { if ($extension && !($model instanceof Model\Error && $routeName === 'image')) { // The user agent wants a specific type. Skip content negotiation completely, but not // if the request is against the image resource, and ended up as an error, because then // Imbo would try to render the error as an image. $mime = $this->defaultMimeType; if (isset($this->extensionsToMimeType[$extension])) { $mime = $this->extensionsToMimeType[$extension]; } $formatter = $this->supportedTypes[$mime]; } else { // Set Vary to Accept since we are doing content negotiation based on Accept $response->setVary('Accept', false); // No extension have been provided $acceptableTypes = array(); foreach (AcceptHeader::fromString($request->headers->get('Accept', '*/*'))->all() as $item) { $acceptableTypes[$item->getValue()] = $item->getQuality(); } $match = false; $maxQ = 0; // Specify which types to check for since all models can't be formatted by all // formatters $modelClass = get_class($model); $modelType = strtolower(substr($modelClass, strrpos($modelClass, '\\') + 1)); $types = $this->defaultModelTypes; if (isset($this->modelTypes[$modelType])) { $types = $this->modelTypes[$modelType]; } // If we are dealing with images we want to make sure the original mime type of the // image is checked first. If the client does not really have any preference with // regards to the mime type (*/* or image/*) this results in the original mime type of // the image being sent. if ($model instanceof Model\Image) { $original = $model->getMimeType(); if ($types[0] !== $original) { $types = array_filter($types, function ($type) use($original) { return $type !== $original; }); array_unshift($types, $original); } } foreach ($types as $mime) { if (($q = $this->contentNegotiation->isAcceptable($mime, $acceptableTypes)) && $q > $maxQ) { $maxQ = $q; $match = true; $formatter = $this->supportedTypes[$mime]; } } if (!$match && !$event->hasArgument('noStrict')) { // No types matched with strict mode enabled. The client does not want any of Imbo's // supported types. Y U NO ACCEPT MY TYPES?! FFFFUUUUUUU! throw new Exception\RuntimeException('Not acceptable', 406); } else { if (!$match) { // There was no match but we don't want to be an ass about it. Send a response // anyway (allowed according to RFC2616, section 10.4.7) $formatter = $this->supportedTypes[$this->defaultMimeType]; } } } } $this->formatter = $formatter; }
/** * Load images * * @param EventInterface $event An event instance */ public function loadImages(EventInterface $event) { $query = $this->getImagesQuery(); $params = $event->getRequest()->query; $returnMetadata = false; if ($params->has('page')) { $query->page($params->get('page')); } if ($params->has('limit')) { $query->limit($params->get('limit')); } if ($params->has('metadata')) { $query->returnMetadata($params->get('metadata')); $returnMetadata = true; } if ($params->has('from')) { $query->from($params->get('from')); } if ($params->has('to')) { $query->to($params->get('to')); } if ($params->has('sort')) { $sort = $params->get('sort'); if (is_array($sort)) { $query->sort($sort); } } if ($params->has('ids')) { $ids = $params->get('ids'); if (is_array($ids)) { $query->imageIdentifiers($ids); } } if ($params->has('checksums')) { $checksums = $params->get('checksums'); if (is_array($checksums)) { $query->checksums($checksums); } } if ($params->has('originalChecksums')) { $checksums = $params->get('originalChecksums'); if (is_array($checksums)) { $query->originalChecksums($checksums); } } if ($event->hasArgument('users')) { $users = $event->getArgument('users'); } else { $users = $event->getRequest()->getUsers(); if (!is_array($users)) { $users = []; } } $response = $event->getResponse(); $database = $event->getDatabase(); // Create the model and set some pagination values $model = new Model\Images(); $model->setLimit($query->limit())->setPage($query->page()); $images = $database->getImages($users, $query, $model); $modelImages = []; foreach ($images as $image) { $entry = new Model\Image(); $entry->setFilesize($image['size'])->setWidth($image['width'])->setHeight($image['height'])->setUser($image['user'])->setImageIdentifier($image['imageIdentifier'])->setChecksum($image['checksum'])->setOriginalChecksum(isset($image['originalChecksum']) ? $image['originalChecksum'] : null)->setMimeType($image['mime'])->setExtension($image['extension'])->setAddedDate($image['added'])->setUpdatedDate($image['updated']); if ($returnMetadata) { $entry->setMetadata($image['metadata']); } $modelImages[] = $entry; } // Add images to the model $model->setImages($modelImages); if ($params->has('fields')) { $fields = $params->get('fields'); if (is_array($fields)) { $model->setFields($fields); } } $lastModified = $database->getLastModified($users); $response->setModel($model)->setLastModified($lastModified); }
/** * Check if the public key used has access to this resource for this user * * @param EventInterface $event * @throws RuntimeException If public key does not have access to the resource */ public function checkAccess(EventInterface $event) { if ($event->hasArgument('skipAccessControl') && $event->getArgument('skipAccessControl') === true) { return; } $request = $event->getRequest(); $aclAdapter = $event->getAccessControl(); $resource = $event->getName(); $publicKey = $request->getPublicKey(); $user = $request->getUser(); $hasAccess = $aclAdapter->hasAccess($publicKey, $resource, $user); if ($hasAccess) { return; } // If we're asking for info on a public key, and that public key happens to be the one // used to sign the request, accept this as a valid request and let the user have access // to the resource. Note that this requires the accessToken listener to be in place - // if disabled, any user can ask for the access rules for all public keys if (in_array($resource, $this->ownPublicKeyAllowedResources)) { $routePubKey = $request->getRoute()->get('publickey'); if ($routePubKey === $publicKey) { return; } } // If a public key has access to resources within a resource group, allow the // public key to access the group resource to see which resources it contains if (in_array($resource, $this->groupLookupResources)) { $routeGroup = $request->getRoute()->get('group'); $aclList = $aclAdapter->getAccessListForPublicKey($publicKey); foreach ($aclList as $aclRule) { if (isset($aclRule['groups']) && in_array($routeGroup, $aclRule['groups'])) { return; } } } throw new RuntimeException('Permission denied (public key)', 400); }