多🌹444收拾收拾计算机视觉手机手机手机手机4大尺寸惆怅长岑长
??????????????????????????С??????????????P??????????????????????????????????????????????????????^??????????
????j??????????
? PNG ?%k25u25%fgd5n!? PNG ?%k25u25%fgd5n!? PNG ?%k25u25%fgd5n!? PNG ?%k25u25%fgd5n!magicai-updater/phpunit.xml.dist 0000644 00000001602 15266557156 0012774 0 ustar 00
](https://spatie.be/github-ad-click/magicai-updater)
We invest a lot of resources into creating [best in class open source packages](https://spatie.be/open-source). You can support us by [buying one of our paid products](https://spatie.be/open-source/support-us).
We highly appreciate you sending us a postcard from your hometown, mentioning which of our package(s) you are using. You'll find our address on [our contact page](https://spatie.be/about-us). We publish all received postcards on [our virtual postcard wall](https://spatie.be/open-source/postcards).
## Installation
You can install the package via composer:
```bash
composer require magicai/magicai-updater
```
You can publish and run the migrations with:
```bash
php artisan vendor:publish --tag="magicai-updater-migrations"
php artisan migrate
```
You can publish the config file with:
```bash
php artisan vendor:publish --tag="magicai-updater-config"
```
This is the contents of the published config file:
```php
return [
];
```
Optionally, you can publish the views using
```bash
php artisan vendor:publish --tag="magicai-updater-views"
```
## Usage
```php
$updater = new MagicAI\Updater();
echo $updater->echoPhrase('Hello, MagicAI!');
```
## Testing
```bash
composer test
```
## Changelog
Please see [CHANGELOG](CHANGELOG.md) for more information on what has changed recently.
## Contributing
Please see [CONTRIBUTING](CONTRIBUTING.md) for details.
## Security Vulnerabilities
Please review [our security policy](../../security/policy) on how to report security vulnerabilities.
## Credits
- [Rauf Abbaszade](https://github.com/rafoabbas)
- [All Contributors](../../contributors)
## License
The MIT License (MIT). Please see [License File](LICENSE.md) for more information.
magicai-updater/.editorconfig 0000644 00000000334 15266557156 0012277 0 ustar 00 root = true
[*]
charset = utf-8
end_of_line = lf
indent_size = 4
indent_style = space
insert_final_newline = true
trim_trailing_whitespace = true
[*.md]
trim_trailing_whitespace = false
[*.{yml,yaml}]
indent_size = 2
magicai-updater/phpstan-baseline.neon 0000644 00000000000 15266557156 0013726 0 ustar 00 magicai-updater/src/Controllers/UpdaterController.php 0000644 00000012357 15266557156 0017110 0 ustar 00 true,
'data' => Updater::checker(),
'user' => $request->user(),
]);
}
public function check(): array
{
return Updater::checker();
}
public function update(Request $request): RedirectResponse
{
Updater::downloadNewUpdater();
return back()->with([
'message' => trans('The updater has been successfully downloaded.'),
'type' => 'success',
]);
}
public function backup(Request $request): \Illuminate\Contracts\View\Factory|\Illuminate\Foundation\Application|View|\Illuminate\View\View|RedirectResponse|\Illuminate\Contracts\Foundation\Application
{
$data = Updater::backupView();
if ($data['updated']) {
return redirect()->route('updater.index')->with([
'message' => 'MagicAI is already up to date.',
'type' => 'success',
]);
}
if ($request->isMethod('get') && ! Updater::isLastBackupRecent()) {
return redirect()->route('updater.index')->with([
'message' => trans('The backup file could not be found. Please try again.'),
'type' => 'success',
]);
}
if ($request->isMethod('post') && ! Updater::isLastBackupRecent()) {
Updater::backup();
}
return view('magicai-updater::index', [
'permission' => true,
'data' => Updater::backupView(),
'fileName' => Updater::findLastBackup(),
]);
}
public function upgrade(Request $request): \Illuminate\Foundation\Application|\Illuminate\Http\Response|\Illuminate\Contracts\Foundation\Application|\Illuminate\Contracts\Routing\ResponseFactory
{
$backupFileName = Updater::findLastBackup();
if (file_exists(base_path($backupFileName))) {
Updater::updateNewVersion($backupFileName);
return response([
'message' => trans('Upgrade completed successfully.'),
'type' => 'success',
], 200);
}
return response([
'message' => 'The backup file could not be found. Please try again.',
'type' => 'success',
], 422);
}
public function downloadStep(): \Illuminate\Contracts\View\Factory|\Illuminate\Foundation\Application|View|\Illuminate\View\View|RedirectResponse|\Illuminate\Contracts\Foundation\Application
{
$data = Updater::downloadView();
$backupFileName = Updater::findLastBackup();
if (! file_exists(base_path($backupFileName))) {
return redirect()->route('updater.index')->with([
'message' => 'The backup file could not be found. Please try again.',
'type' => 'error',
]);
}
if ($data['updated']) {
return redirect()->route('updater.index')->with([
'message' => 'MagicAI is already up to date.',
'type' => 'success',
]);
}
if (! $data['isDownload']) {
Updater::downloadNewVersion();
}
return view('magicai-updater::index', [
'permission' => true,
'data' => $data,
'fileName' => 'new-version' . Updater::getDownloadVersion() . '.zip',
]);
}
public function download(Request $request): RedirectResponse
{
$backupFileName = Updater::findLastBackup();
if (file_exists(base_path($backupFileName))) {
Updater::downloadNewVersion();
return to_route('updater.download-step')->with([
'type' => 'success',
'message' => 'The download file has been successfully downloaded.',
]);
}
throw ValidationException::withMessages([
'message' => 'The backup file could not be found. Please try again.',
]);
}
public function versionCheck(): JsonResponse
{
$versionCheck = Updater::versionCheck();
if ($versionCheck) {
try {
Artisan::call('migrate', ['--force' => true]);
InstallationHelper::runInstallation();
Artisan::call('optimize:clear');
} catch (Exception $e) {
return response()->json([
'message' => $e->getMessage(),
'updated' => $versionCheck,
]);
}
}
return response()->json([
'message' => $versionCheck ? 'MagicAI is already up to date.' : 'MagicAI don\'t updated.',
'updated' => $versionCheck,
]);
}
public function forPanel(): JsonResponse
{
return response()->json(Updater::forPanel());
}
}
magicai-updater/src/Facades/Updater.php 0000644 00000001136 15266557156 0014055 0 ustar 00 blacklist();
if ($blackList) {
throw ValidationException::withMessages([
'message' => 'Please try again later!',
]);
}
$version = $this->nextVersion;
$downloadUrl = config('magicai-updater.base_url') . $this->versionZipFile;
try {
$downloadFile = $this->download($downloadUrl, 'new-version' . $version . '.zip');
cache()->remember($this->downloadFileCacheKey, now()->addMinutes(30), function () use ($downloadFile, $version) {
return [
'file' => $downloadFile,
'version' => $version,
];
});
} catch (Exception $exception) {
Log::error($exception->getMessage());
throw ValidationException::withMessages([
'message' => $exception->getMessage(),
]);
}
}
public function getDownloadVersion(): ?string
{
$array = cache($this->downloadFileCacheKey) ?: [];
return data_get($array, 'version');
}
public function updateNewVersion(string $backupFileName): bool
{
set_time_limit(0); // unlimited max execution time
ini_set('memory_limit', '-1'); // increase memory_limit to 1GB
$blackList = app(ExtensionRepositoryInterface::class)->blacklist();
if ($blackList) {
throw ValidationException::withMessages([
'message' => 'Please try again later!',
]);
}
$version = $this->nextVersion;
$downloadFile = data_get(cache($this->downloadFileCacheKey), 'file');
if (! $downloadFile || ! file_exists($downloadFile)) {
throw ValidationException::withMessages([
'message' => 'The download file could not be found. Please try again.',
]);
}
try {
if (File::exists(base_path('bootstrap/cache/packages.php'))) {
File::delete(base_path('bootstrap/cache/packages.php'));
}
if (File::exists(base_path('bootstrap/cache/services.php'))) {
File::delete(base_path('bootstrap/cache/services.php'));
}
Artisan::call('optimize:clear');
DB::beginTransaction();
Artisan::call('down');
$this->unzip($downloadFile);
$this->migrate();
$this->updateVersion($version);
InstallationHelper::runInstallation();
Artisan::call('up');
DB::commit();
} catch (InvalidURLException|ZipException|RuntimeException $e) {
Log::error($e->getMessage());
DB::rollBack();
$this->rollbackBackup($backupFileName);
Artisan::call('up');
throw ValidationException::withMessages([
'message' => $e->getMessage(),
]);
}
return true;
}
private function rollbackBackup(string $backupFileName): void
{
if (! File::exists(base_path($backupFileName))) {
return;
}
$this->unzip(base_path($backupFileName));
}
private function updateVersion(string $version): void
{
$setting = Setting::getCache();
$setting->script_version = $version;
$setting->save();
File::put(base_path('version.txt'), $version);
}
private function migrate(): void
{
Artisan::call('migrate', ['--force' => true]);
}
}
magicai-updater/src/Traits/HasBackup.php 0000644 00000011311 15266557156 0014226 0 ustar 00 backupFileNameCacheKey;
// }
public function backup(): bool
{
$this->configurePhp();
Artisan::call('optimize:clear');
$fileName = $this->backupFileName();
$zipName = $this->backupFilePath($fileName);
$zip = new ZipArchive;
try {
if ($zip->open($zipName, ZipArchive::CREATE) === true) {
$this->addFolderToZip(base_path(), $zip);
$zip->close();
}
} catch (Exception $e) {
\Illuminate\Support\Facades\Log::error('Backup failed: ', [
'message' => $e->getMessage(),
]);
Cache::forget($this->backupFileNameCacheKey);
throw ValidationException::withMessages([
'message' => __('Server Error:') . ' ' . $e->getMessage(),
]);
}
return $fileName;
}
public function exceptFolder(string $folder): bool
{
$exceptArray = array_map(static function ($item) {
return base_path($item);
}, $this->excepts);
if (in_array($folder, $exceptArray, true)) {
return true;
}
return false;
}
private function exceptFile(string $file): bool
{
if ($file === '.' || $file === '..') {
return true;
}
// except .zip files
if (pathinfo($file, PATHINFO_EXTENSION) === 'zip') {
return true;
}
return false;
}
private function addFolderToZip($folder, ZipArchive $zip, $parentFolder = ''): void
{
if ($this->exceptFolder($folder)) {
return;
}
$files = scandir($folder);
foreach ($files as $file) {
if ($this->exceptFile($file)) {
continue;
}
$filePath = $folder . DIRECTORY_SEPARATOR . $file;
$relativePath = $parentFolder ? $parentFolder . DIRECTORY_SEPARATOR . $file : $file;
if (is_dir($filePath)) {
$zip->addEmptyDir($relativePath);
$this->addFolderToZip($filePath, $zip, $relativePath);
} else {
if (is_file($filePath)) {
$zip->addFile($filePath, $relativePath);
}
}
}
}
private function backupFilePath(string $fileName): string
{
return base_path($fileName);
}
private function backupFileName(): string
{
return 'backup-' . date('Y-m-d_H-i') . '.zip';
}
public function isLastBackupRecent(int $minutes = 30): bool
{
$lastBackup = $this->findLastBackup();
if ($lastBackup === null) {
return false;
}
// backup-2025-05-28_09-17.zip → 2025-05-28 09:17
if (preg_match('/backup-(\d{4}-\d{2}-\d{2})_(\d{2}-\d{2})\.zip/', $lastBackup, $matches)) {
$backupDateTime = Carbon::createFromFormat('Y-m-d H-i', "{$matches[1]} {$matches[2]}");
return $backupDateTime->greaterThanOrEqualTo(now()->subMinutes($minutes));
}
return false;
}
public function findLastBackup(): ?string
{
$backupFiles = glob(base_path('/backup-*.zip'));
if (! empty($backupFiles)) {
usort($backupFiles, function ($a, $b) {
return strcmp(basename($b), basename($a));
});
$latestBackup = $backupFiles[0];
return basename($latestBackup);
}
return null;
}
// public function backupFileNameGetFromCache()
// {
// return Cache::get($this->backupFileNameCacheKey);
// }
private function configurePhp(): void
{
// unlimited max execution time
set_time_limit(0);
// increase memory_limit to 1GB
ini_set('memory_limit', '-1');
// increase max_execution_time to 1 hour
ini_set('max_execution_time', 3600);
}
}
magicai-updater/src/Traits/HasUpdater.php 0000644 00000003034 15266557156 0014430 0 ustar 00 blacklist();
if ($blackList) {
throw ValidationException::withMessages([
'message' => 'Please try again later!',
]);
}
$updaterDownloadUrl = config('magicai-updater.updater_download_url');
try {
$this->download($updaterDownloadUrl, 'updater.php.zip');
$this->unzip($this->path);
} catch (InvalidURLException $e) {
throw ValidationException::withMessages([
'message' => __($e->getMessage()),
]);
} catch (ZipException $e) {
throw ValidationException::withMessages([
'message' => __('Something went wrong!'),
]);
}
}
public function currentUpdater(): array
{
$data = [];
if (file_exists(base_path('updater.php'))) {
$data = require base_path('updater.php');
}
return [
'version' => $data['version'] ?? '0.0.0',
'list' => $data['list'] ?? null,
];
}
public function newUpdaterVersion(): ?string
{
return $this->json('updater_version');
}
}
magicai-updater/src/Traits/HasVersionPrepare.php 0000644 00000005552 15266557156 0015777 0 ustar 00 versionRequest()->json() ?: [];
$currentMagicAIVersion = floatval($this->currentMagicAIVersion());
$description = $lastVersion['description'] ?? [];
$versions = $this->versions($description);
$this->nextVersion = $this->setNextVersion($versions, $currentMagicAIVersion);
$this->latestVersion = $this->setLatestVersion($versions, $currentMagicAIVersion);
$this->setZipFile();
if (VersionComparator::compareVersion($this->nextVersion, $currentMagicAIVersion, '>')) {
$lastVersion['update'] = 'yes'; // Trigger the new version available.
$lastVersion['version'] = $this->nextVersion;
$lastVersion['latest_version'] = format_double($this->latestVersion);
$lastVersion['version_format'] = format_double($this->nextVersion);
$lastVersion['archive'] = $this->versionZipFile;
$lastVersion['current_version'] = format_double($currentMagicAIVersion);
}
return $lastVersion;
}
public function setZipFile(): string
{
$this->versionZipFile = 'magicai_' . $this->nextVersion . '.zip';
return $this->versionZipFile;
}
public function setNextVersion(array $versions, string $currentMagicAIVersion): string
{
$versions = array_reverse($versions); // 5.3, 5.31, 5.4, 5.41
foreach ($versions as $version) {
if ($version > $currentMagicAIVersion) {
return number_format($version, 2, '.');
}
}
return '';
}
public function setLatestVersion(array $versions, string $currentMagicAIVersion): string
{
$versions = array_reverse($versions); // 5.3, 5.31, 5.4, 5.41
$latestVersion = end($versions);
if ($latestVersion > $currentMagicAIVersion) {
return number_format($latestVersion, 2, '.');
}
return '';
}
public function versions(array $array = []): array
{
$versionList = array_map(function ($key) {
return trim(explode('-', $key)[0]);
}, array_keys($array));
$formatted = array_map(function ($version) {
$parts = explode('.', $version);
if (count($parts) === 3) {
return (float) ($parts[0] . '.' . $parts[1] . $parts[2]);
}
if (count($parts) === 2) {
return (float) ($parts[0] . '.' . $parts[1]);
}
return (float) ($parts[0]);
}, $versionList);
return $formatted;
}
}
magicai-updater/src/Traits/HasZipper.php 0000644 00000000761 15266557156 0014301 0 ustar 00 open($zipFile) === true) {
$zip->extractTo($destination);
$zip->close();
} else {
throw new ZipException('Invalid zip file');
}
}
}
magicai-updater/src/Traits/HasDownloader.php 0000644 00000003026 15266557156 0015123 0 ustar 00 path = base_path($filename);
try {
// Download the file from the URL
$response = Http::timeout(1800)
->withOptions([
'sink' => $this->path,
])
->throw(function ($request, $exception) {
throw new RuntimeException('Failed to download the zip file');
})
->get($url);
// If the request is unsuccessful, throw an exception
if (! $response->successful()) {
throw new RuntimeException('Failed to download the zip file');
}
} catch (Exception|RuntimeException $exception) {
throw new RuntimeException('Failed to download the zip file');
}
// Save the file content to the base_path() directory
return $this->path;
}
}
magicai-updater/src/Commands/UpdaterCommand.php 0000644 00000000475 15266557156 0015574 0 ustar 00 comment('All done');
return self::SUCCESS;
}
}
magicai-updater/src/UpdaterServiceProvider.php 0000644 00000003625 15266557156 0015570 0 ustar 00 name('magicai-updater')
->hasConfigFile()
->hasViews()
->hasViewComponents('updater', Permission::class, Li::class, Button::class)
->hasCommand(UpdaterCommand::class);
}
public function packageRegistered(): void
{
Route::prefix('updater')
->as('updater.')
->middleware(['web', 'auth', 'admin'])
->group(function (Router $router) {
$router->get('', [UpdaterController::class, 'index'])->name('index');
$router->get('check', [UpdaterController::class, 'check'])->name('check');
$router->post('update', [UpdaterController::class, 'update'])->name('update');
$router->any('backup', [UpdaterController::class, 'backup'])->name('backup');
$router->any('download-step', [UpdaterController::class, 'downloadStep'])->name('download-step');
$router->any('download', [UpdaterController::class, 'download'])->name('download');
$router->any('upgrade', [UpdaterController::class, 'upgrade'])->name('upgrade');
$router->get('for-panel', [UpdaterController::class, 'forPanel'])->name('for.panel');
$router->get('version-check', [UpdaterController::class, 'versionCheck'])->name('version-check');
});
}
}
magicai-updater/src/Updater.php 0000644 00000011102 15266557156 0012521 0 ustar 00 prepareVersion();
}
public function versionCheck(): bool|int
{
$magicAIVersion = cache()->remember('magicai_next_version_cache', 60 * 10, function () {
return $this->nextVersion;
});
if (! $magicAIVersion) {
$versions = $this->prepareVersion();
$magicAIVersion = $versions['version'];
}
$currentMagicAIVersion = $this->currentMagicAIVersion();
return VersionComparator::compareVersion($magicAIVersion, $currentMagicAIVersion, '=');
}
public function backupView(): array
{
$magicAIVersion = $this->nextVersion;
$currentMagicAIVersion = $this->currentMagicAIVersion();
if (VersionComparator::compareVersion($magicAIVersion, $currentMagicAIVersion, '=')) {
return [
'updated' => true,
];
}
return [
'updated' => false,
'title' => trans('MagicAI installed successfully'),
'version' => $this->nextVersion,
'view' => 'magicai-updater::particles.backup',
'step' => 4,
];
}
public function downloadView(): array
{
$magicAIVersion = $this->nextVersion;
$currentMagicAIVersion = $this->currentMagicAIVersion();
if (VersionComparator::compareVersion($magicAIVersion, $currentMagicAIVersion, '=')) {
return [
'updated' => true,
];
}
return [
'updated' => false,
'title' => trans('MagicAI installed successfully'),
'version' => $magicAIVersion,
'isDownload' => $magicAIVersion === $this->getDownloadVersion(),
'view' => 'magicai-updater::particles.download',
'step' => 4,
];
}
public function checker(): array
{
$updaterVersion = $this->newUpdaterVersion();
$currentUpdater = $this->currentUpdater();
$magicAIVersion = $this->nextVersion;
$currentMagicAIVersion = $this->currentMagicAIVersion();
if (VersionComparator::compareVersion($magicAIVersion, $currentMagicAIVersion, '=')) {
cache()->forget('magicai_next_version_cache');
return [
'title' => trans('MagicAI installed successfully'),
'version' => $magicAIVersion,
'view' => 'magicai-updater::particles.updated',
];
}
if ($updaterVersion && VersionComparator::compareVersion($updaterVersion, $currentUpdater['version'], '=')) {
cache()->forget('magicai_next_version_cache');
return [
'title' => trans('MagicAI is ready to update'),
'updater' => $this->currentUpdater(),
'version' => $magicAIVersion,
'updater_version' => $this->json('updater_version'),
'view' => 'magicai-updater::particles.update',
'step' => 2,
];
}
return [
'title' => trans('MagicAI is ready to download check for updates'),
'version' => $magicAIVersion,
'updater_version' => $this->json('updater_version'),
'view' => 'magicai-updater::particles.updater',
'step' => 1,
];
}
public function forPanel(): array
{
return $this->prepareVersion();
}
public function currentMagicAIVersion(): false|string
{
$this->currentMagicAIVersion = trim(File::get(base_path('version.txt')));
return $this->currentMagicAIVersion;
}
public function json(string $key): null|string|array
{
return $this->versionRequest()->json($key);
}
public function versionRequest(): Response
{
return once(static function () {
return Http::get(config('magicai-updater.version_url'));
});
}
}
magicai-updater/src/View/Components/Button.php 0000644 00000001034 15266557156 0015432 0 ustar 00 $this->permission,
'text' => $this->text,
'id' => $this->id,
]);
}
}
magicai-updater/src/View/Components/Permission.php 0000644 00000000605 15266557156 0016312 0 ustar 00 $this->permission,
]);
}
}
magicai-updater/src/View/Components/Li.php 0000644 00000000562 15266557156 0014530 0 ustar 00 $this->item,
]);
}
}
magicai-updater/phpstan.neon.dist 0000644 00000000331 15266557156 0013117 0 ustar 00 includes:
- phpstan-baseline.neon
parameters:
level: 5
paths:
- src
- config
- database
tmpDir: build/phpstan
checkOctaneCompatibility: true
checkModelProperties: true
magicai-updater/CHANGELOG.md 0000644 00000000127 15266557156 0011433 0 ustar 00 # Changelog
All notable changes to `magicai-updater` will be documented in this file.
magicai-updater/composer.json 0000644 00000004773 15266557156 0012357 0 ustar 00 {
"name": "magicai/magicai-updater",
"description": "Magic ai updater",
"keywords": [
"MagicAI",
"laravel",
"magicai-updater"
],
"homepage": "https://github.com/magicai/magicai-updater",
"license": "MIT",
"authors": [
{
"name": "MagicAI Team",
"email": "info@liquid-themes.com",
"role": "Developer"
}
],
"require": {
"php": "^8.2",
"ext-zip": "*",
"illuminate/contracts": "^10.0||^11.0",
"ryangjchandler/blade-tabler-icons": "^2.2",
"spatie/laravel-package-tools": "^1.16"
},
"require-dev": {
"laravel/pint": "^1.14",
"nunomaduro/collision": "^8.1.1||^7.10.0",
"larastan/larastan": "^2.9",
"orchestra/testbench": "^9.0.0||^8.22.0",
"pestphp/pest": "^2.34",
"pestphp/pest-plugin-arch": "^2.7",
"pestphp/pest-plugin-laravel": "^2.3",
"phpstan/extension-installer": "^1.3",
"phpstan/phpstan-deprecation-rules": "^1.1",
"phpstan/phpstan-phpunit": "^1.3",
"spatie/laravel-ray": "^1.35"
},
"autoload": {
"psr-4": {
"MagicAI\\Updater\\": "src/",
"MagicAI\\Updater\\Database\\Factories\\": "database/factories/"
}
},
"autoload-dev": {
"psr-4": {
"MagicAI\\Updater\\Tests\\": "tests/"
}
},
"scripts": {
"post-autoload-dump": "@composer run prepare",
"clear": "@php vendor/bin/testbench package:purge-magicai-updater --ansi",
"prepare": "@php vendor/bin/testbench package:discover --ansi",
"build": [
"@composer run prepare"
],
"start": [
"Composer\\Config::disableProcessTimeout",
"@composer run build",
"@php vendor/bin/testbench serve"
],
"analyse": "vendor/bin/phpstan analyse",
"test": "vendor/bin/pest",
"test-coverage": "vendor/bin/pest --coverage",
"format": "vendor/bin/pint"
},
"config": {
"sort-packages": true,
"allow-plugins": {
"pestphp/pest-plugin": true,
"phpstan/extension-installer": true
}
},
"extra": {
"laravel": {
"providers": [
"MagicAI\\Updater\\UpdaterServiceProvider"
],
"aliases": {
"Updater": "MagicAI\\Updater\\Facades\\Updater"
}
}
},
"minimum-stability": "dev",
"prefer-stable": true
}
magicai-updater/.gitignore 0000644 00000000520 15266557156 0011607 0 ustar 00 # Composer Related
composer.lock
/vendor
# Frontend Assets
/node_modules
# Logs
npm-debug.log
yarn-error.log
# Caches
.phpunit.cache
.phpunit.result.cache
/build
# IDE Helper
_ide_helper.php
_ide_helper_models.php
.phpstorm.meta.php
# Editors
/.idea
/.fleet
/.vscode
# Misc
phpunit.xml
phpstan.neon
testbench.yaml
/docs
/coverage
magicai-updater/.gitattributes 0000644 00000001301 15266557156 0012510 0 ustar 00 # Path-based git attributes
# https://www.kernel.org/pub/software/scm/git/docs/gitattributes.html
# Ignore all test and documentation with "export-ignore".
/.github export-ignore
/.gitattributes export-ignore
/.gitignore export-ignore
/phpunit.xml.dist export-ignore
/art export-ignore
/docs export-ignore
/tests export-ignore
/workbench export-ignore
/.editorconfig export-ignore
/.php_cs.dist.php export-ignore
/psalm.xml export-ignore
/psalm.xml.dist export-ignore
/testbench.yaml export-ignore
/UPGRADING.md export-ignore
/phpstan.neon.dist export-ignore
/phpstan-baseline.neon export-ignore
magicai-updater/resources/views/particles/updated.blade.php 0000644 00000001004 15266557156 0020157 0 ustar 00
Great! Your system is up to date.
@lang("The PHP ZIP extension is not enabled on your server. You need to enable it to use the updater.")
@lang("To update your system, you first need to download the update checker. This checker is necessary to analyze the system requirements and minimize errors. You can download it by clicking the button below.")
Great! Your system is backed up successfully.
{{ $fileName }}@lang('Welcome, ') {{ $user->name }}
@lang('You are not using the latest version of the system. You can upgrade to the latest version by clicking the button below.')@lang("You must have the necessary hardware to perform the update.")
Great! Update version downloaded successfully.
{{ $fileName }}
](https://spatie.be/github-ad-click/magicai-updater)
We invest a lot of resources into creating [best in class open source packages](https://spatie.be/open-source). You can support us by [buying one of our paid products](https://spatie.be/open-source/support-us).
We highly appreciate you sending us a postcard from your hometown, mentioning which of our package(s) you are using. You'll find our address on [our contact page](https://spatie.be/about-us). We publish all received postcards on [our virtual postcard wall](https://spatie.be/open-source/postcards).
## Installation
You can install the package via composer:
```bash
composer require magicai/magicai-updater
```
You can publish and run the migrations with:
```bash
php artisan vendor:publish --tag="magicai-updater-migrations"
php artisan migrate
```
You can publish the config file with:
```bash
php artisan vendor:publish --tag="magicai-updater-config"
```
This is the contents of the published config file:
```php
return [
];
```
Optionally, you can publish the views using
```bash
php artisan vendor:publish --tag="magicai-updater-views"
```
## Usage
```php
$updater = new MagicAI\Updater();
echo $updater->echoPhrase('Hello, MagicAI!');
```
## Testing
```bash
composer test
```
## Changelog
Please see [CHANGELOG](CHANGELOG.md) for more information on what has changed recently.
## Contributing
Please see [CONTRIBUTING](CONTRIBUTING.md) for details.
## Security Vulnerabilities
Please review [our security policy](../../security/policy) on how to report security vulnerabilities.
## Credits
- [Rauf Abbaszade](https://github.com/rafoabbas)
- [All Contributors](../../contributors)
## License
The MIT License (MIT). Please see [License File](LICENSE.md) for more information.
magicai-healthy/.editorconfig 0000644 00000000334 15266557156 0012271 0 ustar 00 root = true
[*]
charset = utf-8
end_of_line = lf
indent_size = 4
indent_style = space
insert_final_newline = true
trim_trailing_whitespace = true
[*.md]
trim_trailing_whitespace = false
[*.{yml,yaml}]
indent_size = 2
magicai-healthy/phpstan-baseline.neon 0000644 00000000000 15266557156 0013720 0 ustar 00 magicai-healthy/src/Services/ExtensionReportService.php 0000644 00000003774 15266557156 0017403 0 ustar 00 extensionRepository->checkSelectedExtensions($extensions);
$report = [
'total_extensions' => count($checkResults),
'valid_licenses' => 0,
'invalid_licenses' => 0,
'errors' => 0,
'extensions' => $checkResults,
'generated_at' => time(),
];
foreach ($checkResults as $result) {
switch ($result['status']) {
case 'valid':
$report['valid_licenses']++;
break;
case 'invalid':
$report['invalid_licenses']++;
break;
case 'error':
$report['errors']++;
break;
}
}
return $report;
}
public function generateLicenseReport(): array
{
$checkResults = $this->extensionRepository->checkAllRegisteredExtensions();
$report = [
'total_extensions' => count($checkResults),
'valid_licenses' => 0,
'invalid_licenses' => 0,
'errors' => 0,
'extensions' => $checkResults,
'generated_at' => time(),
];
foreach ($checkResults as $result) {
switch ($result['status']) {
case 'valid':
$report['valid_licenses']++;
break;
case 'invalid':
$report['invalid_licenses']++;
break;
case 'error':
$report['errors']++;
break;
}
}
return $report;
}
}
magicai-healthy/src/Services/ExtensionCacheService.php 0000644 00000002664 15266557156 0017130 0 ustar 00 getCacheKey($registerKey);
return Cache::get($cacheKey);
}
public function put(string $registerKey, bool $value): void
{
$cacheKey = $this->getCacheKey($registerKey);
Cache::put($cacheKey, $value, $this->cacheInterval);
}
public function forget(string $registerKey): void
{
$cacheKey = $this->getCacheKey($registerKey);
Cache::forget($cacheKey);
}
public function clearAll(string $registerKey): void
{
$cacheKey = $this->getCacheKey($registerKey);
$lastCheckKey = $this->getLastCheckCacheKey($registerKey);
Cache::forget($cacheKey);
Cache::forget($lastCheckKey);
}
private function getCacheKey(string $registerKey): string
{
return $this->cachePrefix . $this->obfuscationHelper->obfuscateKey($registerKey);
}
private function getLastCheckCacheKey(string $registerKey): string
{
return $this->cachePrefix . 'last_check_' . $this->obfuscationHelper->obfuscateKey($registerKey);
}
}
magicai-healthy/src/Services/ExtensionCleanupService.php 0000644 00000011426 15266557156 0017510 0 ustar 00 extensionRepository->checkAllRegisteredExtensions();
$uninstalledExtensions = [];
foreach ($checkResults as $result) {
if ($result['status'] === 'invalid') {
try {
// Extension'ı uninstall et
app(ExtensionUninstallService::class)->uninstall($result['slug']);
// Lisans dosyasını sil
$this->removeSecurityFile($result['slug']);
// Cache'i temizle
$this->cacheService->clearAll($result['slug']);
$uninstalledExtensions[] = $result['slug'];
Log::info('Extension removed due to security violation', [
'extension' => $result['slug'],
]);
} catch (Exception $e) {
Log::error('Failed to remove invalid extension', [
'extension' => $result['slug'],
'error' => $e->getMessage(),
]);
}
}
}
return $uninstalledExtensions;
}
public function removeSecurityFile(string $extensionSlug): bool
{
try {
$hashedKey = $this->obfuscationHelper->obfuscateKey($extensionSlug);
$securityFile = "{$this->managerFolder}/{$hashedKey}.lic";
if (Storage::disk('local')->exists($securityFile)) {
Storage::disk('local')->delete($securityFile);
Log::info('Security file removed', [
'extension' => $extensionSlug,
]);
return true;
}
return false;
} catch (Exception $e) {
Log::error('Failed to remove security file', [
'extension' => $extensionSlug,
'error' => $e->getMessage(),
]);
return false;
}
}
public function fullCleanup(string $extensionSlug): bool
{
try {
// 1. Extension'ı uninstall et
app(ExtensionUninstallService::class)->uninstall($extensionSlug);
// 2. Security dosyasını sil
$this->removeSecurityFile($extensionSlug);
// 3. Cache'i temizle
$this->cacheService->clearAll($extensionSlug);
Log::info('Full cleanup completed', [
'extension' => $extensionSlug,
]);
return true;
} catch (Exception $e) {
Log::error('Full cleanup failed', [
'extension' => $extensionSlug,
'error' => $e->getMessage(),
]);
return false;
}
}
public function cleanupOrphanedFiles(): array
{
$cleanedFiles = [];
try {
$registeredExtensions = $this->extensionRepository->getRegisteredExtensions();
$allSecurityFiles = Storage::disk('local')->files($this->managerFolder);
foreach ($allSecurityFiles as $file) {
if (! str_ends_with($file, '.lic')) {
continue;
}
$fileName = basename($file, '.lic');
$isOrphaned = true;
// Kayıtlı extension'larla karşılaştır
foreach (array_keys($registeredExtensions) as $extensionSlug) {
$hashedKey = $this->obfuscationHelper->obfuscateKey($extensionSlug);
if ($fileName === $hashedKey) {
$isOrphaned = false;
break;
}
}
if ($isOrphaned) {
Storage::disk('local')->delete($file);
$cleanedFiles[] = $file;
Log::info('Orphaned security file removed', [
'file' => $file,
]);
}
}
} catch (Exception $e) {
Log::error('Failed to cleanup orphaned files', [
'error' => $e->getMessage(),
]);
}
return $cleanedFiles;
}
}
magicai-healthy/src/Services/ExtensionValidationService.php 0000644 00000001401 15266557156 0020203 0 ustar 00 $extensionSlug,
'status' => 'valid',
'source' => 'bypass',
'message' => 'License validation bypassed (always valid)',
];
}
public function performValidation(string $registerKey): bool
{
return true; // Always valid
}
public function removeSecurityFile(string $extensionSlug): bool
{
// No-op (do nothing)
Log::info("Bypassed security removal for extension: {$extensionSlug}");
return true;
}
}
magicai-healthy/src/Helpers/ObfuscationHelper.php 0000644 00000001527 15266557156 0016137 0 ustar 00 'x7k9m2n5',
'salt2' => 'p3q8r1t6',
'salt3' => 'z4w7j0v9',
];
public function obfuscateKey(string $key): string
{
$combined = $key . $this->obfuscationKeys['salt3'];
return hash('sha256', $combined);
}
public function getCacheKey(string $registerKey): string
{
return $this->cachePrefix . $this->obfuscateKey($registerKey);
}
public function getLastCheckCacheKey(string $registerKey): string
{
return $this->cachePrefix . 'last_check_' . $this->obfuscateKey($registerKey);
}
public function getSalt(string $key): string
{
return $this->obfuscationKeys[$key] ?? '';
}
}
magicai-healthy/src/Helpers/LicenseHelper.php 0000644 00000004555 15266557156 0015251 0 ustar 00 get("{$this->managerFolder}/{$hashedKey}.lic")
);
return unserialize($content);
}
public function validateLicenseContent(array $content): bool
{
$requiredFields = ['domain', 'domain_key', 'extension'];
foreach ($requiredFields as $field) {
if (! isset($content[$field])) {
return false;
}
}
if (! isset($content['checksum'])) {
return false;
}
$expectedChecksum = $this->generateChecksum($content);
return hash_equals($content['checksum'], $expectedChecksum);
}
public function generateChecksum(array $content): string
{
$data = $content['domain'] . $content['domain_key'] . $content['extension'] . $this->obfuscationHelper->getSalt('salt1');
return hash_hmac('sha256', $data, $this->obfuscationHelper->getSalt('salt2'));
}
public function getCurrentDomain(): string
{
return request()->getHost();
}
public function getCurrentDomainKey(): string
{
return app(ExtensionRepositoryInterface::class)->domainKey();
}
public function saveLicenseData(string $registerKey, array $data): void
{
$data['checksum'] = $this->generateChecksum($data);
$encrypt = $this->encrypt($data);
$hashedKey = $this->obfuscationHelper->obfuscateKey($registerKey);
$this->save($hashedKey, $encrypt);
}
public function makeRemoteRequest(string $registerKey)
{
return app(ExtensionRepositoryInterface::class)->request(
'post',
"extension/{$registerKey}/license",
);
}
private function encrypt(array $content): string
{
return encrypt(serialize($content));
}
private function save(string $hashedKey, string $content): void
{
Storage::disk('local')->put("{$this->managerFolder}/{$hashedKey}.lic", $content);
}
}
magicai-healthy/src/Exceptions/InvalidLicenseException.php 0000644 00000000171 15266557156 0020004 0 ustar 00 getRegisteredExtensions();
$results = [];
foreach ($extensions as $slug) {
if (Helper::appIsDemo()) {
$results[$slug] = [
'status' => 'success',
'message' => 'Demo mode: License validation is not applicable.',
];
continue;
}
if (array_key_exists($slug, $regExtensions)) {
$results[$slug] = $this->validationService->validateSingle($slug);
} else {
$results[$slug] = [
'status' => 'error',
'message' => "Extension '$slug' is not registered.",
];
}
}
return $results;
}
public function checkAllRegisteredExtensions(): array
{
$registeredExtensions = $this->getRegisteredExtensions();
$results = [];
foreach ($registeredExtensions as $slug => $providerClass) {
if (Helper::appIsDemo()) {
$results[$slug] = [
'status' => 'success',
'message' => 'Demo mode: License validation is not applicable.',
];
continue;
}
$results[$slug] = $this->validationService->validateSingle($slug);
}
return $results;
}
public function getRegisteredExtensions(): array
{
$providers = MarketplaceServiceProvider::getExtensionProviders();
$loadedProviders = app()->getLoadedProviders();
return array_filter($providers, function ($provider) use ($loadedProviders) {
return array_key_exists($provider, $loadedProviders);
});
}
}
magicai-healthy/src/Commands/HealthyCommand.php 0000644 00000000475 15266557156 0015560 0 ustar 00 comment('All done');
return self::SUCCESS;
}
}
magicai-healthy/src/Http/Controllers/HealthyController.php 0000644 00000001543 15266557156 0020006 0 ustar 00 get('extensions')) {
$extensions = explode(',', $request->get('extensions'));
} else {
return response()->json(['error' => 'No extensions provided'], 400);
}
return response()->json($this->service->generateLicenseReportSelected($extensions));
}
public function checkAll(): JsonResponse
{
return response()->json($this->service->generateLicenseReport());
}
}
magicai-healthy/src/Http/Middleware/HealthyMiddleware.php 0000644 00000003205 15266557156 0017504 0 ustar 00 verify($k);
return $n($r);
} catch (InvalidLicenseException $e) {
Log::warning('Access violation', [
'id' => $this->s3->obfuscateKey($k),
'msg' => $e->getMessage(),
'addr' => $r->ip(),
'agent' => $r->userAgent(),
]);
$this->s2->clearAll($k);
abort(403);
}
}
private function verify(string $k): void
{
$c = $this->s2->get($k);
if ($c !== null) {
if (! $c) {
throw new InvalidLicenseException('Verification failed from cache.');
}
return;
}
$v = $this->s1->performValidation($k);
$this->s2->put($k, $v);
if (! $v) {
throw new InvalidLicenseException('Access denied.');
}
}
}
magicai-healthy/src/HealthyServiceProvider.php 0000644 00000003007 15266557156 0015546 0 ustar 00 name('magicai-healthy')
->hasConfigFile()
->hasViews()
->hasViewComponents('healthy', Permission::class, Li::class, Button::class)
->hasCommand(HealthyCommand::class);
}
public function bootingPackage()
{
$this->app->make(Router::class)->aliasMiddleware(
'healthy',
HealthyMiddleware::class
);
}
public function packageRegistered(): void
{
Route::prefix('healthy')
->as('healthy.')
->middleware(['api'])
->group(function (Router $router) {
$router->get('check/selected', [\MagicAI\Healthy\Http\Controllers\HealthyController::class, 'checkSelected'])
->name('check.selected');
$router->get('check/all', [\MagicAI\Healthy\Http\Controllers\HealthyController::class, 'checkAll'])
->name('check.all');
});
}
}
magicai-healthy/phpstan.neon.dist 0000644 00000000331 15266557156 0013111 0 ustar 00 includes:
- phpstan-baseline.neon
parameters:
level: 5
paths:
- src
- config
- database
tmpDir: build/phpstan
checkOctaneCompatibility: true
checkModelProperties: true
magicai-healthy/CHANGELOG.md 0000644 00000000127 15266557156 0011425 0 ustar 00 # Changelog
All notable changes to `magicai-updater` will be documented in this file.
magicai-healthy/composer.json 0000644 00000004606 15266557156 0012344 0 ustar 00 {
"name": "magicai/magicai-healthy",
"description": "Magic ai healthy",
"keywords": [
"MagicAI",
"laravel",
"magicai-healthy"
],
"homepage": "https://github.com/magicai/magicai-healthy",
"license": "MIT",
"authors": [
{
"name": "MagicAI Team",
"email": "info@liquid-themes.com",
"role": "Developer"
}
],
"require": {
"php": "^8.2",
"ext-zip": "*",
"illuminate/contracts": "^10.0||^11.0",
"spatie/laravel-package-tools": "^1.16"
},
"require-dev": {
"laravel/pint": "^1.14",
"nunomaduro/collision": "^8.1.1||^7.10.0",
"larastan/larastan": "^2.9",
"orchestra/testbench": "^9.0.0||^8.22.0",
"pestphp/pest": "^2.34",
"pestphp/pest-plugin-arch": "^2.7",
"pestphp/pest-plugin-laravel": "^2.3",
"phpstan/extension-installer": "^1.3",
"phpstan/phpstan-deprecation-rules": "^1.1",
"phpstan/phpstan-phpunit": "^1.3",
"spatie/laravel-ray": "^1.35"
},
"autoload": {
"psr-4": {
"MagicAI\\Healthy\\": "src/",
"MagicAI\\Healthy\\Database\\Factories\\": "database/factories/"
}
},
"autoload-dev": {
"psr-4": {
"MagicAI\\Healthy\\Tests\\": "tests/"
}
},
"scripts": {
"post-autoload-dump": "@composer run prepare",
"clear": "@php vendor/bin/testbench package:purge-magicai-updater --ansi",
"prepare": "@php vendor/bin/testbench package:discover --ansi",
"build": [
"@composer run prepare"
],
"start": [
"Composer\\Config::disableProcessTimeout",
"@composer run build",
"@php vendor/bin/testbench serve"
],
"analyse": "vendor/bin/phpstan analyse",
"test": "vendor/bin/pest",
"test-coverage": "vendor/bin/pest --coverage",
"format": "vendor/bin/pint"
},
"config": {
"sort-packages": true,
"allow-plugins": {
"pestphp/pest-plugin": true,
"phpstan/extension-installer": true
}
},
"extra": {
"laravel": {
"providers": [
"MagicAI\\Healthy\\HealthyServiceProvider"
],
"aliases": {
}
}
},
"minimum-stability": "dev",
"prefer-stable": true
}
magicai-healthy/.gitignore 0000644 00000000520 15266557156 0011601 0 ustar 00 # Composer Related
composer.lock
/vendor
# Frontend Assets
/node_modules
# Logs
npm-debug.log
yarn-error.log
# Caches
.phpunit.cache
.phpunit.result.cache
/build
# IDE Helper
_ide_helper.php
_ide_helper_models.php
.phpstorm.meta.php
# Editors
/.idea
/.fleet
/.vscode
# Misc
phpunit.xml
phpstan.neon
testbench.yaml
/docs
/coverage
magicai-healthy/.gitattributes 0000644 00000001301 15266557156 0012502 0 ustar 00 # Path-based git attributes
# https://www.kernel.org/pub/software/scm/git/docs/gitattributes.html
# Ignore all test and documentation with "export-ignore".
/.github export-ignore
/.gitattributes export-ignore
/.gitignore export-ignore
/phpunit.xml.dist export-ignore
/art export-ignore
/docs export-ignore
/tests export-ignore
/workbench export-ignore
/.editorconfig export-ignore
/.php_cs.dist.php export-ignore
/psalm.xml export-ignore
/psalm.xml.dist export-ignore
/testbench.yaml export-ignore
/UPGRADING.md export-ignore
/phpstan.neon.dist export-ignore
/phpstan-baseline.neon export-ignore
magicai-healthy/config/magicai-checker.php 0000644 00000000604 15266557156 0014566 0 ustar 00 'https://api.liquid-themes.com/magicai/' . $path,
'updater_download_url' => 'https://api.liquid-themes.com/magicai/' . $path . 'updater.php.zip',
'version_url' => 'https://api.liquid-themes.com/magicai/' . $path . 'magicaiupdater.json',
];