diff --git a/src/Http/Controllers/FilesApiController.php b/src/Http/Controllers/FilesApiController.php index 9ad3b265..ff8c20ca 100644 --- a/src/Http/Controllers/FilesApiController.php +++ b/src/Http/Controllers/FilesApiController.php @@ -20,6 +20,9 @@ public function __construct(HeadlessH5PServiceContract $hh5pService) public function __invoke(FilesStoreRequest $request, String $nonce = null): JsonResponse { + if (!$request->hasValidSignature()) { + abort(401); + } try { $result = $this->hh5pService->uploadFile( $request->get('contentId'), @@ -28,9 +31,9 @@ public function __invoke(FilesStoreRequest $request, String $nonce = null): Json $nonce ); - return $this->sendResponse($result); + return response()->json($result); } catch (Exception $error) { - return $this->sendError($error->getMessage(), 422); + return response()->json(['error' => $error->getMessage()], 422); } } } diff --git a/src/Repositories/H5PContentRepository.php b/src/Repositories/H5PContentRepository.php index 020403eb..72b50e1f 100644 --- a/src/Repositories/H5PContentRepository.php +++ b/src/Repositories/H5PContentRepository.php @@ -16,6 +16,7 @@ use Illuminate\Pagination\LengthAwarePaginator; use Illuminate\Support\Collection; + class H5PContentRepository implements H5PContentRepositoryContract { use QueryExtendable; @@ -53,6 +54,7 @@ public function create(string $title, string $library, string $params, string $n 'library' => $library, 'parameters' => $params, 'nonce' => $nonce, + ]); $this->moveTmpFilesToContentFolders($nonce, $content); @@ -108,9 +110,9 @@ private function moveTmpFilesToContentFolders($nonce, $contentId): bool $files = H5PTempFile::where(['nonce' => $nonce])->get(); foreach ($files as $file) { - $old_path = $storage_path.$file->path; + $old_path = $storage_path . $file->path; if (strpos($file->path, '/editor') !== false) { - $new_path = $storage_path.str_replace('/editor', '/content/'.$contentId, $file->path); + $new_path = $storage_path . str_replace('/editor', '/content/' . $contentId, $file->path); $dir_path = dirname($new_path); if (!is_dir($dir_path)) { mkdir($dir_path, 0777, true); @@ -217,7 +219,7 @@ public function download($id): string $filename = $this->hh5pService->getRepository()->getDownloadFile($id); - return storage_path('app/h5p/exports/'.$filename); + return storage_path('app/h5p/exports/' . $filename); } public function getLibraryById(int $id): H5PLibrary diff --git a/src/Services/HeadlessH5PService.php b/src/Services/HeadlessH5PService.php index 03508edd..73f6fe16 100644 --- a/src/Services/HeadlessH5PService.php +++ b/src/Services/HeadlessH5PService.php @@ -18,6 +18,8 @@ //use EscolaLms\HeadlessH5P\Repositories\H5PFileStorageRepository; use Illuminate\Http\UploadedFile; use Illuminate\Support\Collection; +use Illuminate\Support\Facades\URL; +use Illuminate\Support\Facades\Auth; class HeadlessH5PService implements HeadlessH5PServiceContract { @@ -144,10 +146,10 @@ public function getConfig(): array if (!isset($this->config)) { $config = (array) config('hh5p'); $config['url'] = asset($config['url']); - $config['ajaxPath'] = route($config['ajaxPath']).'/'; - $config['libraryUrl'] = url($config['libraryUrl']).'/'; + $config['ajaxPath'] = route($config['ajaxPath']) . '/'; + $config['libraryUrl'] = url($config['libraryUrl']) . '/'; $config['get_laravelh5p_url'] = url($config['get_laravelh5p_url']); - $config['get_h5peditor_url'] = url($config['get_h5peditor_url']).'/'; + $config['get_h5peditor_url'] = url($config['get_h5peditor_url']) . '/'; $config['get_h5pcore_url'] = url($config['get_h5pcore_url']); $config['getCopyrightSemantics'] = $this->getContentValidator()->getCopyrightSemantics(); $config['getMetadataSemantics'] = $this->getContentValidator()->getMetadataSemantics(); @@ -205,14 +207,14 @@ public function getEditorSettings($content = null): array 'scripts' => [], ]; foreach (H5PCore::$styles as $style) { - $settings['core']['styles'][] = $config['get_h5pcore_url'].'/'.$style; + $settings['core']['styles'][] = $config['get_h5pcore_url'] . '/' . $style; } foreach (H5PCore::$scripts as $script) { - $settings['core']['scripts'][] = $config['get_h5pcore_url'].'/'.$script; + $settings['core']['scripts'][] = $config['get_h5pcore_url'] . '/' . $script; } - $settings['core']['scripts'][] = $config['get_h5peditor_url'].'/scripts/h5peditor-editor.js'; - $settings['core']['scripts'][] = $config['get_h5peditor_url'].'/scripts/h5peditor-init.js'; - $settings['core']['scripts'][] = $config['get_h5peditor_url'].'/language/en.js'; // TODO this lang should vary depending on config + $settings['core']['scripts'][] = $config['get_h5peditor_url'] . '/scripts/h5peditor-editor.js'; + $settings['core']['scripts'][] = $config['get_h5peditor_url'] . '/scripts/h5peditor-init.js'; + $settings['core']['scripts'][] = $config['get_h5peditor_url'] . '/language/en.js'; // TODO this lang should vary depending on config $settings['editor'] = [ 'filesPath' => isset($content) ? url("h5p/content/$content") : url('h5p/editor'), @@ -240,24 +242,30 @@ public function getEditorSettings($content = null): array $settings['nonce'] = bin2hex(random_bytes(4)); } + $settings['filesAjaxPath'] = URL::temporarySignedRoute( + 'hh5p.files.upload.nonce', + now()->addMinutes(30), + ['nonce' => $settings['nonce']] + ); + // load core assets $settings['editor']['assets']['css'] = $settings['core']['styles']; $settings['editor']['assets']['js'] = $settings['core']['scripts']; // add editor styles foreach (H5peditor::$styles as $style) { - $settings['editor']['assets']['css'][] = $config['get_h5peditor_url'].('/'.$style); + $settings['editor']['assets']['css'][] = $config['get_h5peditor_url'] . ('/' . $style); } // Add editor JavaScript foreach (H5peditor::$scripts as $script) { // We do not want the creator of the iframe inside the iframe if ($script !== 'scripts/h5peditor-editor.js') { - $settings['editor']['assets']['js'][] = $config['get_h5peditor_url'].('/'.$script); + $settings['editor']['assets']['js'][] = $config['get_h5peditor_url'] . ('/' . $script); } } - $language_script = '/language/'.$config['get_language'].'.js'; - $settings['editor']['assets']['js'][] = $config['get_h5peditor_url'].($language_script); + $language_script = '/language/' . $config['get_language'] . '.js'; + $settings['editor']['assets']['js'][] = $config['get_h5peditor_url'] . ($language_script); if ($content) { $preloaded_dependencies = $this->getCore()->loadContentDependencies($content, 'preloaded'); @@ -266,11 +274,11 @@ public function getEditorSettings($content = null): array $embed = H5PCore::determineEmbedType($cid['content']['embed_type'] ?? 'div', $cid['content']['library']['embedTypes']); $scripts = array_map(function ($value) use ($config) { - return $config['url'].($value->path.$value->version); + return $config['url'] . ($value->path . $value->version); }, $files['scripts']); $styles = array_map(function ($value) use ($config) { - return $config['url'].($value->path.$value->version); + return $config['url'] . ($value->path . $value->version); }, $files['styles']); // Error with scripts order @@ -333,10 +341,10 @@ public function getContentSettings($id): array 'scripts' => [], ]; foreach (H5PCore::$styles as $style) { - $settings['core']['styles'][] = $config['get_h5pcore_url'].'/'.$style; + $settings['core']['styles'][] = $config['get_h5pcore_url'] . '/' . $style; } foreach (H5PCore::$scripts as $script) { - $settings['core']['scripts'][] = $config['get_h5pcore_url'].'/'.$script; + $settings['core']['scripts'][] = $config['get_h5pcore_url'] . '/' . $script; } //$settings['core']['scripts'][] = $config['get_h5peditor_url'].'/language/en.js'; // TODO this lang should vary depending on config @@ -349,7 +357,7 @@ public function getContentSettings($id): array $library = $content['library']; - $uberName = $library['name'].' '.$library['majorVersion'].'.'.$library['minorVersion']; + $uberName = $library['name'] . ' ' . $library['majorVersion'] . '.' . $library['minorVersion']; $settings['contents']["cid-$id"] = [ 'library' => $uberName, @@ -374,7 +382,7 @@ public function getContentSettings($id): array $settings['nonce'] = $settings['contents']["cid-$id"]['nonce']; - $language_script = '/language/'.$config['get_language'].'.js'; + $language_script = '/language/' . $config['get_language'] . '.js'; $preloaded_dependencies = $this->getCore()->loadContentDependencies($id, 'preloaded'); $files = $this->getCore()->getDependenciesFiles($preloaded_dependencies); @@ -383,11 +391,11 @@ public function getContentSettings($id): array $embed = H5PCore::determineEmbedType($cid['content']['embed_type'] ?? 'div', $cid['content']['library']['embedTypes']); $scripts = array_map(function ($value) use ($config) { - return $config['url'].($value->path.$value->version); + return $config['url'] . ($value->path . $value->version); }, $files['scripts']); $styles = array_map(function ($value) use ($config) { - return $config['url'].($value->path.$value->version); + return $config['url'] . ($value->path . $value->version); }, $files['styles']); if ($embed === 'iframe') { @@ -432,7 +440,7 @@ public function getSettingsForContent($id) $library = $content['library']; - $uberName = $library['name'].' '.$library['majorVersion'].'.'.$library['minorVersion']; + $uberName = $library['name'] . ' ' . $library['majorVersion'] . '.' . $library['minorVersion']; $settings = [ 'library' => $uberName, @@ -479,7 +487,7 @@ public function uploadFile($contentId, $field, $token, $nonce = null) } $result = json_decode($file->getResult()); - $result->path = $file->getType().'s/'.$file->getName().'#tmp'; + $result->path = $file->getType() . 's/' . $file->getName() . '#tmp'; return $result; } diff --git a/src/routes.php b/src/routes.php index d80209ac..1179df9c 100644 --- a/src/routes.php +++ b/src/routes.php @@ -23,7 +23,6 @@ Route::get('content/{id}/export', [ContentApiController::class, 'download'])->name('hh5p.content.export'); Route::get('content/{id}', [ContentApiController::class, 'show'])->name('hh5p.content.show'); Route::post('files', FilesApiController::class)->name('hh5p.files.upload'); - Route::post('files/{nonce}', FilesApiController::class)->name('hh5p.files.upload.nonce'); }); Route::group(['prefix' => 'hh5p'], function () { @@ -38,4 +37,5 @@ Route::group(['prefix' => 'api/hh5p'], function () { Route::get('libraries', [LibraryApiController::class, 'libraries'])->name('hh5p.library.libraries'); Route::post('libraries', [LibraryApiController::class, 'libraries'])->name('hh5p.library.libraries'); + Route::post('files/{nonce}', FilesApiController::class)->name('hh5p.files.upload.nonce'); });