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 = [ |         $result = [ | ||||||
|             'job' => $manifest ?: null, |             'job' => $manifest ?: null, | ||||||
|             'progress' => $progress, |             'progress' => $progress, | ||||||
|  |             'context' => $this->buildStatusContext(), | ||||||
|         ]; |         ]; | ||||||
|  |  | ||||||
|         $this->clearJobContext(); |         $this->clearJobContext(); | ||||||
| @@ -417,6 +418,7 @@ class SafeUpgradeManager | |||||||
|             'log' => $logPath, |             'log' => $logPath, | ||||||
|             'progress' => $this->getProgress(), |             'progress' => $this->getProgress(), | ||||||
|             'job' => $this->readManifest(), |             'job' => $this->readManifest(), | ||||||
|  |             'context' => $this->buildStatusContext(), | ||||||
|         ]; |         ]; | ||||||
|     } |     } | ||||||
|  |  | ||||||
| @@ -553,6 +555,7 @@ class SafeUpgradeManager | |||||||
|                 'status' => 'noop', |                 'status' => 'noop', | ||||||
|                 'version' => $localVersion, |                 'version' => $localVersion, | ||||||
|                 'message' => 'Grav is already up to date.', |                 'message' => 'Grav is already up to date.', | ||||||
|  |                 'context' => $this->buildStatusContext(), | ||||||
|             ]; |             ]; | ||||||
|         } |         } | ||||||
|  |  | ||||||
| @@ -647,6 +650,7 @@ class SafeUpgradeManager | |||||||
|             'version' => $remoteVersion, |             'version' => $remoteVersion, | ||||||
|             'manifest' => $manifest, |             'manifest' => $manifest, | ||||||
|             'previous_version' => $localVersion, |             'previous_version' => $localVersion, | ||||||
|  |             'context' => $this->buildStatusContext(), | ||||||
|         ]; |         ]; | ||||||
|     } |     } | ||||||
|  |  | ||||||
| @@ -896,6 +900,7 @@ class SafeUpgradeManager | |||||||
|                 'status' => 'finalized', |                 'status' => 'finalized', | ||||||
|                 'version' => $localVersion, |                 'version' => $localVersion, | ||||||
|                 'message' => 'Post-install scripts completed.', |                 'message' => 'Post-install scripts completed.', | ||||||
|  |                 'context' => $this->buildStatusContext(), | ||||||
|             ]; |             ]; | ||||||
|         } |         } | ||||||
|  |  | ||||||
| @@ -1011,9 +1016,31 @@ class SafeUpgradeManager | |||||||
|         return [ |         return [ | ||||||
|             'status' => 'error', |             'status' => 'error', | ||||||
|             'message' => $message, |             'message' => $message, | ||||||
|  |             'context' => $this->buildStatusContext(), | ||||||
|         ] + $extra; |         ] + $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 |     protected function ensureExecutablePermissions(): void | ||||||
|     { |     { | ||||||
|         $executables = [ |         $executables = [ | ||||||
|   | |||||||
| @@ -33,11 +33,73 @@ $readJson = static function (string $path): ?array { | |||||||
|  |  | ||||||
| $progress = null; | $progress = null; | ||||||
| $manifest = 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 !== '') { | if ($jobId !== '') { | ||||||
|     $jobPath = $jobsDir . '/' . $jobId; |     $jobPath = $jobsDir . '/' . $jobId; | ||||||
|     $progress = $readJson($jobPath . '/progress.json'); |     $progressPath = $progressPath ?: ($jobPath . '/progress.json'); | ||||||
|     $manifest = $readJson($jobPath . '/manifest.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)) { |     if (!$progress && !$manifest && !is_dir($jobPath)) { | ||||||
|         $progress = $readJson($fallbackProgress) ?: [ |         $progress = $readJson($fallbackProgress) ?: [ | ||||||
| @@ -46,37 +108,45 @@ if ($jobId !== '') { | |||||||
|             'percent' => null, |             'percent' => null, | ||||||
|             'timestamp' => time(), |             'timestamp' => time(), | ||||||
|         ]; |         ]; | ||||||
|  |  | ||||||
|         echo json_encode([ |  | ||||||
|             'status' => 'success', |  | ||||||
|             'message' => 'Safe upgrade job not found.', |  | ||||||
|             'data' => [ |  | ||||||
|                 'job' => null, |  | ||||||
|                 'progress' => $progress, |  | ||||||
|             ], |  | ||||||
|         ]); |  | ||||||
|         exit; |  | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
| if ($progress === null) { | if ($progress === null) { | ||||||
|     $progress = $readJson($fallbackProgress) ?: [ |     if ($progressPath && is_file($progressPath)) { | ||||||
|         'stage' => 'idle', |         $progress = $readJson($progressPath); | ||||||
|         'message' => '', |     } | ||||||
|         'percent' => null, |  | ||||||
|         'timestamp' => time(), |     if ($progress === null) { | ||||||
|     ]; |         $progress = $readJson($fallbackProgress) ?: [ | ||||||
|  |             'stage' => 'idle', | ||||||
|  |             'message' => '', | ||||||
|  |             'percent' => null, | ||||||
|  |             'timestamp' => time(), | ||||||
|  |         ]; | ||||||
|  |         $progressPath = $fallbackProgress; | ||||||
|  |     } | ||||||
| } | } | ||||||
|  |  | ||||||
| if ($jobId !== '' && is_array($progress) && !isset($progress['job_id'])) { | if ($jobId !== '' && is_array($progress) && !isset($progress['job_id'])) { | ||||||
|     $progress['job_id'] = $jobId; |     $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([ | echo json_encode([ | ||||||
|     'status' => 'success', |     'status' => 'success', | ||||||
|     'data' => [ |     'data' => [ | ||||||
|         'job' => $manifest ?: null, |         'job' => $manifest ?: null, | ||||||
|         'progress' => $progress, |         'progress' => $progress, | ||||||
|  |         'context' => $contextToken, | ||||||
|     ], |     ], | ||||||
| ]); | ]); | ||||||
|  |  | ||||||
|   | |||||||
| @@ -54,6 +54,7 @@ export default class SafeUpgrade { | |||||||
|         this.active = false; |         this.active = false; | ||||||
|         this.jobId = null; |         this.jobId = null; | ||||||
|         this.statusFailures = 0; |         this.statusFailures = 0; | ||||||
|  |         this.statusContext = null; | ||||||
|         this.directStatusUrl = this.resolveDirectStatusUrl(); |         this.directStatusUrl = this.resolveDirectStatusUrl(); | ||||||
|         this.preferDirectStatus = !!this.directStatusUrl; |         this.preferDirectStatus = !!this.directStatusUrl; | ||||||
|  |  | ||||||
| @@ -120,6 +121,7 @@ export default class SafeUpgrade { | |||||||
|         this.decisions = {}; |         this.decisions = {}; | ||||||
|         this.statusFailures = 0; |         this.statusFailures = 0; | ||||||
|         this.preferDirectStatus = !!this.directStatusUrl; |         this.preferDirectStatus = !!this.directStatusUrl; | ||||||
|  |         this.statusContext = null; | ||||||
|         this.renderLoading(); |         this.renderLoading(); | ||||||
|         this.modal.open(); |         this.modal.open(); | ||||||
|         this.fetchPreflight(); |         this.fetchPreflight(); | ||||||
| @@ -412,6 +414,7 @@ export default class SafeUpgrade { | |||||||
|                 } |                 } | ||||||
|                 this.statusFailures = 0; |                 this.statusFailures = 0; | ||||||
|                 this.preferDirectStatus = !!this.directStatusUrl; |                 this.preferDirectStatus = !!this.directStatusUrl; | ||||||
|  |                 this.statusContext = data.context || null; | ||||||
|                 this.beginPolling(1200); |                 this.beginPolling(1200); | ||||||
|             } else { |             } else { | ||||||
|                 this.renderResult(data); |                 this.renderResult(data); | ||||||
| @@ -453,8 +456,18 @@ export default class SafeUpgrade { | |||||||
|     resolveStatusEndpoint() { |     resolveStatusEndpoint() { | ||||||
|         const useDirect = this.directStatusUrl && this.preferDirectStatus; |         const useDirect = this.directStatusUrl && this.preferDirectStatus; | ||||||
|         let url = useDirect ? this.directStatusUrl : this.urls.status; |         let url = useDirect ? this.directStatusUrl : this.urls.status; | ||||||
|  |         const params = []; | ||||||
|  |  | ||||||
|         if (this.jobId) { |         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 { |         return { | ||||||
| @@ -532,6 +545,9 @@ export default class SafeUpgrade { | |||||||
|             } |             } | ||||||
|  |  | ||||||
|             const payload = response.data || {}; |             const payload = response.data || {}; | ||||||
|  |             if (Object.prototype.hasOwnProperty.call(payload, 'context')) { | ||||||
|  |                 this.statusContext = payload.context || null; | ||||||
|  |             } | ||||||
|             const job = payload.job || {}; |             const job = payload.job || {}; | ||||||
|             const data = payload.progress || payload; |             const data = payload.progress || payload; | ||||||
|             nextStage = data.stage || null; |             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.active = false; | ||||||
|     this.jobId = null; |     this.jobId = null; | ||||||
|     this.statusFailures = 0; |     this.statusFailures = 0; | ||||||
|  |     this.statusContext = null; | ||||||
|     this.directStatusUrl = this.resolveDirectStatusUrl(); |     this.directStatusUrl = this.resolveDirectStatusUrl(); | ||||||
|     this.preferDirectStatus = !!this.directStatusUrl; |     this.preferDirectStatus = !!this.directStatusUrl; | ||||||
|     this.registerEvents(); |     this.registerEvents(); | ||||||
| @@ -4676,6 +4677,7 @@ var SafeUpgrade = /*#__PURE__*/function () { | |||||||
|       this.decisions = {}; |       this.decisions = {}; | ||||||
|       this.statusFailures = 0; |       this.statusFailures = 0; | ||||||
|       this.preferDirectStatus = !!this.directStatusUrl; |       this.preferDirectStatus = !!this.directStatusUrl; | ||||||
|  |       this.statusContext = null; | ||||||
|       this.renderLoading(); |       this.renderLoading(); | ||||||
|       this.modal.open(); |       this.modal.open(); | ||||||
|       this.fetchPreflight(); |       this.fetchPreflight(); | ||||||
| @@ -4882,6 +4884,7 @@ var SafeUpgrade = /*#__PURE__*/function () { | |||||||
|           } |           } | ||||||
|           _this4.statusFailures = 0; |           _this4.statusFailures = 0; | ||||||
|           _this4.preferDirectStatus = !!_this4.directStatusUrl; |           _this4.preferDirectStatus = !!_this4.directStatusUrl; | ||||||
|  |           _this4.statusContext = data.context || null; | ||||||
|           _this4.beginPolling(1200); |           _this4.beginPolling(1200); | ||||||
|         } else { |         } else { | ||||||
|           _this4.renderResult(data); |           _this4.renderResult(data); | ||||||
| @@ -4921,8 +4924,15 @@ var SafeUpgrade = /*#__PURE__*/function () { | |||||||
|     value: function resolveStatusEndpoint() { |     value: function resolveStatusEndpoint() { | ||||||
|       var useDirect = this.directStatusUrl && this.preferDirectStatus; |       var useDirect = this.directStatusUrl && this.preferDirectStatus; | ||||||
|       var url = useDirect ? this.directStatusUrl : this.urls.status; |       var url = useDirect ? this.directStatusUrl : this.urls.status; | ||||||
|  |       var params = []; | ||||||
|       if (this.jobId) { |       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 { |       return { | ||||||
|         url: url, |         url: url, | ||||||
| @@ -5002,6 +5012,9 @@ var SafeUpgrade = /*#__PURE__*/function () { | |||||||
|           return; |           return; | ||||||
|         } |         } | ||||||
|         var payload = response.data || {}; |         var payload = response.data || {}; | ||||||
|  |         if (Object.prototype.hasOwnProperty.call(payload, 'context')) { | ||||||
|  |           _this6.statusContext = payload.context || null; | ||||||
|  |         } | ||||||
|         var job = payload.job || {}; |         var job = payload.job || {}; | ||||||
|         var data = payload.progress || payload; |         var data = payload.progress || payload; | ||||||
|         nextStage = data.stage || null; |         nextStage = data.stage || null; | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user