mirror of
				https://github.com/getgrav/grav-plugin-admin.git
				synced 2025-10-31 18:35:57 +01:00 
			
		
		
		
	more improvements to safe upgrade
This commit is contained in:
		| @@ -290,6 +290,7 @@ class SafeUpgradeManager | ||||
|         $result = [ | ||||
|             'job' => $manifest ?: null, | ||||
|             'progress' => $progress, | ||||
|             'context' => $this->buildStatusContext(), | ||||
|         ]; | ||||
|  | ||||
|         $this->clearJobContext(); | ||||
| @@ -417,6 +418,7 @@ class SafeUpgradeManager | ||||
|             'log' => $logPath, | ||||
|             'progress' => $this->getProgress(), | ||||
|             'job' => $this->readManifest(), | ||||
|             'context' => $this->buildStatusContext(), | ||||
|         ]; | ||||
|     } | ||||
|  | ||||
| @@ -553,6 +555,7 @@ class SafeUpgradeManager | ||||
|                 'status' => 'noop', | ||||
|                 'version' => $localVersion, | ||||
|                 'message' => 'Grav is already up to date.', | ||||
|                 'context' => $this->buildStatusContext(), | ||||
|             ]; | ||||
|         } | ||||
|  | ||||
| @@ -647,6 +650,7 @@ class SafeUpgradeManager | ||||
|             'version' => $remoteVersion, | ||||
|             'manifest' => $manifest, | ||||
|             'previous_version' => $localVersion, | ||||
|             'context' => $this->buildStatusContext(), | ||||
|         ]; | ||||
|     } | ||||
|  | ||||
| @@ -896,6 +900,7 @@ class SafeUpgradeManager | ||||
|                 'status' => 'finalized', | ||||
|                 'version' => $localVersion, | ||||
|                 'message' => 'Post-install scripts completed.', | ||||
|                 'context' => $this->buildStatusContext(), | ||||
|             ]; | ||||
|         } | ||||
|  | ||||
| @@ -1011,9 +1016,31 @@ class SafeUpgradeManager | ||||
|         return [ | ||||
|             'status' => 'error', | ||||
|             'message' => $message, | ||||
|             'context' => $this->buildStatusContext(), | ||||
|         ] + $extra; | ||||
|     } | ||||
|  | ||||
|     protected function buildStatusContext(): ?string | ||||
|     { | ||||
|         $context = []; | ||||
|  | ||||
|         if ($this->jobManifestPath) { | ||||
|             $context['manifest'] = $this->jobManifestPath; | ||||
|         } | ||||
|  | ||||
|         if ($this->progressPath) { | ||||
|             $context['progress'] = $this->progressPath; | ||||
|         } | ||||
|  | ||||
|         if (!$context) { | ||||
|             return null; | ||||
|         } | ||||
|  | ||||
|         $encoded = json_encode($context); | ||||
|  | ||||
|         return $encoded === false ? null : base64_encode($encoded); | ||||
|     } | ||||
|  | ||||
|     protected function ensureExecutablePermissions(): void | ||||
|     { | ||||
|         $executables = [ | ||||
|   | ||||
| @@ -33,11 +33,73 @@ $readJson = static function (string $path): ?array { | ||||
|  | ||||
| $progress = null; | ||||
| $manifest = null; | ||||
| $manifestPath = null; | ||||
| $progressPath = null; | ||||
|  | ||||
| $normalizeDir = static function (string $path): string { | ||||
|     $normalized = str_replace('\\', '/', $path); | ||||
|  | ||||
|     return rtrim($normalized, '/'); | ||||
| }; | ||||
|  | ||||
| $jobsDirNormalized = $normalizeDir($jobsDir); | ||||
| $userDataDirNormalized = $normalizeDir(dirname($jobsDir)); | ||||
|  | ||||
| $contextParam = $_GET['context'] ?? ''; | ||||
| if ($contextParam !== '') { | ||||
|     $decodedRaw = base64_decode(strtr($contextParam, ' ', '+'), true); | ||||
|     if ($decodedRaw !== false) { | ||||
|         $decoded = json_decode($decodedRaw, true); | ||||
|         if (is_array($decoded)) { | ||||
|             $validatePath = static function (string $candidate) use ($normalizeDir, $jobsDirNormalized, $userDataDirNormalized) { | ||||
|                 $candidate = str_replace('\\', '/', $candidate); | ||||
|                 $directory = dirname($candidate); | ||||
|                 $real = realpath($directory); | ||||
|                 if ($real === false) { | ||||
|                     return null; | ||||
|                 } | ||||
|  | ||||
|                 $real = $normalizeDir($real); | ||||
|                 if (strpos($real, $jobsDirNormalized) !== 0 && strpos($real, $userDataDirNormalized) !== 0) { | ||||
|                     return null; | ||||
|                 } | ||||
|  | ||||
|                 return $candidate; | ||||
|             }; | ||||
|  | ||||
|             if (!empty($decoded['manifest'])) { | ||||
|                 $candidate = $validatePath((string)$decoded['manifest']); | ||||
|                 if ($candidate) { | ||||
|                     $manifestPath = $candidate; | ||||
|                     if (is_file($candidate)) { | ||||
|                         $manifest = $readJson($candidate); | ||||
|                     } | ||||
|                 } | ||||
|             } | ||||
|  | ||||
|             if (!empty($decoded['progress'])) { | ||||
|                 $candidate = $validatePath((string)$decoded['progress']); | ||||
|                 if ($candidate) { | ||||
|                     $progressPath = $candidate; | ||||
|                     if (is_file($candidate)) { | ||||
|                         $progress = $readJson($candidate); | ||||
|                     } | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
| if ($jobId !== '') { | ||||
|     $jobPath = $jobsDir . '/' . $jobId; | ||||
|     $progress = $readJson($jobPath . '/progress.json'); | ||||
|     $manifest = $readJson($jobPath . '/manifest.json'); | ||||
|     $progressPath = $progressPath ?: ($jobPath . '/progress.json'); | ||||
|     $manifestPath = $manifestPath ?: ($jobPath . '/manifest.json'); | ||||
|     if (is_file($progressPath)) { | ||||
|         $progress = $readJson($progressPath); | ||||
|     } | ||||
|     if (is_file($manifestPath)) { | ||||
|         $manifest = $readJson($manifestPath); | ||||
|     } | ||||
|  | ||||
|     if (!$progress && !$manifest && !is_dir($jobPath)) { | ||||
|         $progress = $readJson($fallbackProgress) ?: [ | ||||
| @@ -46,37 +108,45 @@ if ($jobId !== '') { | ||||
|             'percent' => null, | ||||
|             'timestamp' => time(), | ||||
|         ]; | ||||
|  | ||||
|         echo json_encode([ | ||||
|             'status' => 'success', | ||||
|             'message' => 'Safe upgrade job not found.', | ||||
|             'data' => [ | ||||
|                 'job' => null, | ||||
|                 'progress' => $progress, | ||||
|             ], | ||||
|         ]); | ||||
|         exit; | ||||
|     } | ||||
| } | ||||
|  | ||||
| if ($progress === null) { | ||||
|     $progress = $readJson($fallbackProgress) ?: [ | ||||
|         'stage' => 'idle', | ||||
|         'message' => '', | ||||
|         'percent' => null, | ||||
|         'timestamp' => time(), | ||||
|     ]; | ||||
|     if ($progressPath && is_file($progressPath)) { | ||||
|         $progress = $readJson($progressPath); | ||||
|     } | ||||
|  | ||||
|     if ($progress === null) { | ||||
|         $progress = $readJson($fallbackProgress) ?: [ | ||||
|             'stage' => 'idle', | ||||
|             'message' => '', | ||||
|             'percent' => null, | ||||
|             'timestamp' => time(), | ||||
|         ]; | ||||
|         $progressPath = $fallbackProgress; | ||||
|     } | ||||
| } | ||||
|  | ||||
| if ($jobId !== '' && is_array($progress) && !isset($progress['job_id'])) { | ||||
|     $progress['job_id'] = $jobId; | ||||
| } | ||||
|  | ||||
| $contextPayload = []; | ||||
| if ($manifestPath) { | ||||
|     $contextPayload['manifest'] = $manifestPath; | ||||
| } | ||||
| if ($progressPath) { | ||||
|     $contextPayload['progress'] = $progressPath; | ||||
| } | ||||
|  | ||||
| $contextToken = $contextPayload ? base64_encode(json_encode($contextPayload)) : null; | ||||
|  | ||||
| echo json_encode([ | ||||
|     'status' => 'success', | ||||
|     'data' => [ | ||||
|         'job' => $manifest ?: null, | ||||
|         'progress' => $progress, | ||||
|         'context' => $contextToken, | ||||
|     ], | ||||
| ]); | ||||
|  | ||||
|   | ||||
| @@ -54,6 +54,7 @@ export default class SafeUpgrade { | ||||
|         this.active = false; | ||||
|         this.jobId = null; | ||||
|         this.statusFailures = 0; | ||||
|         this.statusContext = null; | ||||
|         this.directStatusUrl = this.resolveDirectStatusUrl(); | ||||
|         this.preferDirectStatus = !!this.directStatusUrl; | ||||
|  | ||||
| @@ -120,6 +121,7 @@ export default class SafeUpgrade { | ||||
|         this.decisions = {}; | ||||
|         this.statusFailures = 0; | ||||
|         this.preferDirectStatus = !!this.directStatusUrl; | ||||
|         this.statusContext = null; | ||||
|         this.renderLoading(); | ||||
|         this.modal.open(); | ||||
|         this.fetchPreflight(); | ||||
| @@ -412,6 +414,7 @@ export default class SafeUpgrade { | ||||
|                 } | ||||
|                 this.statusFailures = 0; | ||||
|                 this.preferDirectStatus = !!this.directStatusUrl; | ||||
|                 this.statusContext = data.context || null; | ||||
|                 this.beginPolling(1200); | ||||
|             } else { | ||||
|                 this.renderResult(data); | ||||
| @@ -453,8 +456,18 @@ export default class SafeUpgrade { | ||||
|     resolveStatusEndpoint() { | ||||
|         const useDirect = this.directStatusUrl && this.preferDirectStatus; | ||||
|         let url = useDirect ? this.directStatusUrl : this.urls.status; | ||||
|         const params = []; | ||||
|  | ||||
|         if (this.jobId) { | ||||
|             url += (url.includes('?') ? '&' : '?') + `job=${encodeURIComponent(this.jobId)}`; | ||||
|             params.push(`job=${encodeURIComponent(this.jobId)}`); | ||||
|         } | ||||
|  | ||||
|         if (this.statusContext) { | ||||
|             params.push(`context=${encodeURIComponent(this.statusContext)}`); | ||||
|         } | ||||
|  | ||||
|         if (params.length) { | ||||
|             url += (url.includes('?') ? '&' : '?') + params.join('&'); | ||||
|         } | ||||
|  | ||||
|         return { | ||||
| @@ -532,6 +545,9 @@ export default class SafeUpgrade { | ||||
|             } | ||||
|  | ||||
|             const payload = response.data || {}; | ||||
|             if (Object.prototype.hasOwnProperty.call(payload, 'context')) { | ||||
|                 this.statusContext = payload.context || null; | ||||
|             } | ||||
|             const job = payload.job || {}; | ||||
|             const data = payload.progress || payload; | ||||
|             nextStage = data.stage || null; | ||||
|   | ||||
							
								
								
									
										15
									
								
								themes/grav/js/admin.min.js
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										15
									
								
								themes/grav/js/admin.min.js
									
									
									
									
										vendored
									
									
								
							| @@ -4610,6 +4610,7 @@ var SafeUpgrade = /*#__PURE__*/function () { | ||||
|     this.active = false; | ||||
|     this.jobId = null; | ||||
|     this.statusFailures = 0; | ||||
|     this.statusContext = null; | ||||
|     this.directStatusUrl = this.resolveDirectStatusUrl(); | ||||
|     this.preferDirectStatus = !!this.directStatusUrl; | ||||
|     this.registerEvents(); | ||||
| @@ -4676,6 +4677,7 @@ var SafeUpgrade = /*#__PURE__*/function () { | ||||
|       this.decisions = {}; | ||||
|       this.statusFailures = 0; | ||||
|       this.preferDirectStatus = !!this.directStatusUrl; | ||||
|       this.statusContext = null; | ||||
|       this.renderLoading(); | ||||
|       this.modal.open(); | ||||
|       this.fetchPreflight(); | ||||
| @@ -4882,6 +4884,7 @@ var SafeUpgrade = /*#__PURE__*/function () { | ||||
|           } | ||||
|           _this4.statusFailures = 0; | ||||
|           _this4.preferDirectStatus = !!_this4.directStatusUrl; | ||||
|           _this4.statusContext = data.context || null; | ||||
|           _this4.beginPolling(1200); | ||||
|         } else { | ||||
|           _this4.renderResult(data); | ||||
| @@ -4921,8 +4924,15 @@ var SafeUpgrade = /*#__PURE__*/function () { | ||||
|     value: function resolveStatusEndpoint() { | ||||
|       var useDirect = this.directStatusUrl && this.preferDirectStatus; | ||||
|       var url = useDirect ? this.directStatusUrl : this.urls.status; | ||||
|       var params = []; | ||||
|       if (this.jobId) { | ||||
|         url += (url.indexOf('?') !== -1 ? '&' : '?') + "job=".concat(encodeURIComponent(this.jobId)); | ||||
|         params.push("job=".concat(encodeURIComponent(this.jobId))); | ||||
|       } | ||||
|       if (this.statusContext) { | ||||
|         params.push("context=".concat(encodeURIComponent(this.statusContext))); | ||||
|       } | ||||
|       if (params.length) { | ||||
|         url += (url.indexOf('?') !== -1 ? '&' : '?') + params.join('&'); | ||||
|       } | ||||
|       return { | ||||
|         url: url, | ||||
| @@ -5002,6 +5012,9 @@ var SafeUpgrade = /*#__PURE__*/function () { | ||||
|           return; | ||||
|         } | ||||
|         var payload = response.data || {}; | ||||
|         if (Object.prototype.hasOwnProperty.call(payload, 'context')) { | ||||
|           _this6.statusContext = payload.context || null; | ||||
|         } | ||||
|         var job = payload.job || {}; | ||||
|         var data = payload.progress || payload; | ||||
|         nextStage = data.stage || null; | ||||
|   | ||||
		Reference in New Issue
	
	Block a user