diff --git a/app/BlueprintFramework/Libraries/ExtensionLibrary/BlueprintBaseLibrary.php b/app/BlueprintFramework/Libraries/ExtensionLibrary/BlueprintBaseLibrary.php index f083ca4b..c2951d03 100644 --- a/app/BlueprintFramework/Libraries/ExtensionLibrary/BlueprintBaseLibrary.php +++ b/app/BlueprintFramework/Libraries/ExtensionLibrary/BlueprintBaseLibrary.php @@ -228,6 +228,27 @@ public function extension(string $identifier): bool return str_contains($this->fileRead(base_path('.blueprint/extensions/blueprint/private/db/installed_extensions')), $identifier); } + /** + * Returns the extension's configuration as an associative array. + * + * @param string $identifier Extension identifier + * @return array Extension configuration + * + * [BlueprintExtensionLibrary documentation](https://blueprint.zip/docs/?page=documentation/$blueprint) + */ + public function extensionConfig(string $identifier): array + { + if (!file_exists(base_path(".blueprint/extensions/$identifier/private/.store/conf.yml"))) + return []; + if (!is_readable(base_path(".blueprint/extensions/$identifier/private/.store/conf.yml"))) + return []; + + $conf = Yaml::parse($this->fileRead(base_path(".blueprint/extensions/$identifier/private/.store/conf.yml"))); + + return array_filter($conf['info'], fn ($k) => !!$k); + } + + /** * Returns an array containing all installed extensions's identifiers. * diff --git a/app/Http/Controllers/Admin/ImageProxy.php b/app/Http/Controllers/Admin/ImageProxy.php new file mode 100644 index 00000000..55c50823 --- /dev/null +++ b/app/Http/Controllers/Admin/ImageProxy.php @@ -0,0 +1,70 @@ +blueprint->extensionConfig($extension); + if ($ext === null || $ext === []) { + abort(404, 'Extension not found.'); + } + + if(!isset($ext['icon'])) { + + return response()->file(public_path('assets/extensions/' . $extension . '/icon.jpg'), [ + 'Content-Type' => 'image/jpeg', + 'Content-Disposition' => 'inline; filename="icon.jpg"' + ]); + } + + if (!\str_starts_with($ext['icon'], 'http')) { + return response()->file('public/assets/extensions/' . $extension . '/icon.' . pathinfo($ext['icon'], PATHINFO_EXTENSION), [ + 'Content-Type' => 'image/image', + 'Content-Disposition' => 'inline' + ]); + } + + $cache_key = 'blueprint_extension_icon_' . $extension; + if (!Cache::has($cache_key)) { + $iconContent = @file_get_contents($ext['icon']); + if ($iconContent === false) { + abort(404, 'Failed to fetch the icon from the provided URL.'); + } + Cache::put($cache_key, $iconContent, now()->addDays(1)); + } + $icon = Cache::get($cache_key); + if (empty($icon)) { + abort(404, 'Icon not found.'); + } + + $tempFile = tempnam(sys_get_temp_dir(), 'icon_') . '.jpg'; + file_put_contents($tempFile, $icon); + + return response()->file($tempFile, [ + 'Content-Type' => 'image/jpeg', + 'Content-Disposition' => 'inline; filename="icon.jpg"' + ])->deleteFileAfterSend(true); + } +} diff --git a/resources/views/admin/extensions.blade.php b/resources/views/admin/extensions.blade.php index a4e49aaf..bc62ad1f 100644 --- a/resources/views/admin/extensions.blade.php +++ b/resources/views/admin/extensions.blade.php @@ -112,9 +112,7 @@ 'EXTENSION_ID' => $extension['identifier'], 'EXTENSION_NAME' => $extension['name'], 'EXTENSION_VERSION' => $extension['version'], - 'EXTENSION_ICON' => !empty($extension['icon']) - ? '/assets/extensions/'.$extension['identifier'].'/icon.'.pathinfo($extension['icon'], PATHINFO_EXTENSION) - : '/assets/extensions/'.$extension['identifier'].'/icon.jpg' + 'EXTENSION_ICON' => '/admin/extensions/img/'.$extension['identifier'].'.jpg', ]) @endforeach diff --git a/routes/blueprint.php b/routes/blueprint.php index e516874b..5eb4ce77 100644 --- a/routes/blueprint.php +++ b/routes/blueprint.php @@ -16,6 +16,7 @@ */ Route::group(['prefix' => 'extensions'], function () { Route::get('/', [Admin\ExtensionsController::class, 'index'])->name('admin.extensions'); + Route::get('/img/{extension}.jpg', [Admin\ImageProxy::class, 'index'])->name('admin.extensions.img'); }); Route::group(['prefix' => 'extensions/blueprint'], function () { diff --git a/scripts/commands/extensions/install.sh b/scripts/commands/extensions/install.sh index e7c8fec1..2977a13e 100644 --- a/scripts/commands/extensions/install.sh +++ b/scripts/commands/extensions/install.sh @@ -113,7 +113,7 @@ InstallExtension() { ((PROGRESS_NOW++)) # "prevent" folder "escaping" - if [[ ( $icon == "/"* ) || ( $icon == *"/.."* ) || ( $icon == *"../"* ) || ( $icon == *"/../"* ) || ( $icon == *"~"* ) || ( $icon == *"\\"* ) ]] \ + if [[(( $icon == "/"* ) || ( $icon == *"/.."* ) || ( $icon == *"../"* ) || ( $icon == *"/../"* ) || ( $icon == *"~"* ) || ( $icon == *"\\"* ) ) && !( ${icon} =~ ^https?:// ) ]] \ || [[ ( $admin_view == "/"* ) || ( $admin_view == *"/.."* ) || ( $admin_view == *"../"* ) || ( $admin_view == *"/../"* ) || ( $admin_view == *"~"* ) || ( $admin_view == *"\\"* ) ]] \ || [[ ( $admin_controller == "/"* ) || ( $admin_controller == *"/.."* ) || ( $admin_controller == *"../"* ) || ( $admin_controller == *"/../"* ) || ( $admin_controller == *"~"* ) || ( $admin_controller == *"\\"* ) ]] \ || [[ ( $admin_css == "/"* ) || ( $admin_css == *"/.."* ) || ( $admin_css == *"../"* ) || ( $admin_css == *"/../"* ) || ( $admin_css == *"~"* ) || ( $admin_css == *"\\"* ) ]] \ @@ -410,7 +410,7 @@ InstallExtension() { # Validate paths to files and directories defined in conf.yml. if \ - [[ ( ! -f ".blueprint/tmp/$n/$icon" ) && ( ${icon} != "" ) ]] || # file: icon (optional) + [[ ( ! -f ".blueprint/tmp/$n/$icon" ) && ( ${icon} != "" ) && ! ( ${icon} =~ ^https?:// ) ]] || # file: icon (optional) [[ ( ! -f ".blueprint/tmp/$n/$admin_view" ) ]] || # file: admin_view [[ ( ! -f ".blueprint/tmp/$n/$admin_controller" ) && ( ${admin_controller} != "" ) ]] || # file: admin_controller (optional) [[ ( ! -f ".blueprint/tmp/$n/$admin_css" ) && ( ${admin_css} != "" ) ]] || # file: admin_css (optional) @@ -1129,9 +1129,22 @@ InstallExtension() { *.webp) local ICON_EXT="webp" ;; *) local ICON_EXT="jpg" ;; esac - cp ".blueprint/tmp/$n/$icon" ".blueprint/extensions/$identifier/assets/icon.$ICON_EXT" + if [[ $icon == "http"* ]]; then + if [[ $icon != *".svg" && $icon != *".png" && $icon != *".gif" && $icon != *".jpeg" && $icon != *".webp" ]]; then + PRINT WARNING "Icon URL does not end with a valid image extension, using default icon instead." + icnNUM=$(( 1 + RANDOM % 5 )) + cp ".blueprint/assets/Extensions/Defaults/$icnNUM.jpg" ".blueprint/extensions/$identifier/assets/icon.jpg" + else + # download icon from url + PRINT INFO "parsing icon.." + ICON_OVERRIDE=$icon + fi + fi fi; ICON="/assets/extensions/$identifier/icon.$ICON_EXT" + if [[ $ICON_OVERRIDE != "" ]]; then + ICON=$ICON_OVERRIDE + fi ((PROGRESS_NOW++))