diff --git a/server/admin/launcher.php b/server/admin/launcher.php new file mode 100644 index 0000000..e3e9f85 --- /dev/null +++ b/server/admin/launcher.php @@ -0,0 +1,189 @@ + 1, 'versions' => []]; + return json_decode(file_get_contents($path), true) ?? []; +} + +function saveManifest(string $path, array $manifest): void +{ + usort($manifest['versions'] ?? [], fn($a, $b) => version_compare($b['version'], $a['version'])); + file_put_contents( + $path, + json_encode($manifest, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES) . "\n" + ); +} + +if ($_SERVER['REQUEST_METHOD'] === 'POST') { + Auth::checkCsrf(); + $action = $_POST['action'] ?? ''; + $manifest = loadManifest($manifestPath); + + try { + if ($action === 'set_launcher') { + $lver = trim($_POST['launcher_version'] ?? ''); + $lmin = trim($_POST['launcher_min_required'] ?? ''); + if (!preg_match('/^\d+\.\d+\.\d+$/', $lver)) { + throw new Exception('Numéro de version launcher invalide (X.Y.Z attendu).'); + } + if ($lmin !== '' && !preg_match('/^\d+\.\d+\.\d+$/', $lmin)) { + throw new Exception('Numéro de version "minRequired" invalide.'); + } + $base = $config['base_url'] ?? 'https://asterionvr.com/PS_Launcher'; + $manifest['launcher'] = [ + 'version' => $lver, + 'minRequired' => $lmin !== '' ? $lmin : '0.5.0', + 'download' => [ + 'url' => "{$base}/builds/launcher/PSLauncher-{$lver}.exe", + 'sizeBytes' => 0, + 'sha256' => 'REPLACE_AFTER_BUILD', + ], + 'releaseNotesUrl' => null, + ]; + saveManifest($manifestPath, $manifest); + $message = "Section launcher mise à jour (v{$lver}). Upload PSLauncher-{$lver}.exe dans builds/launcher/ puis clique « Hasher le launcher + signer »."; + } + elseif ($action === 'remove_launcher') { + unset($manifest['launcher']); + saveManifest($manifestPath, $manifest); + $message = "Section launcher retirée du manifest (auto-update désactivé)."; + } + elseif ($action === 'sync_launcher') { + require_once "$root/tools/SignManifest.php"; + $signer = new \PSLauncher\Tools\SignManifest($root); + $result = $signer->run('launcher'); + $message = "Sortie du script (scope: launcher) :\n" . implode("\n", $result['log']); + if (!$result['ok']) $messageType = 'error'; + } + } catch (Exception $e) { + $message = $e->getMessage(); + $messageType = 'error'; + } +} + +$manifest = loadManifest($manifestPath); +$launcher = $manifest['launcher'] ?? null; +$launcherFiles = is_dir("$buildsDir/launcher") + ? array_map('basename', glob("$buildsDir/launcher/*.exe") ?: []) + : []; + +$launcherZipPresent = false; +$launcherHashed = false; +if ($launcher) { + $expectedFile = basename(parse_url($launcher['download']['url'] ?? '', PHP_URL_PATH) ?? ''); + $launcherZipPresent = in_array($expectedFile, $launcherFiles, true); + $launcherHashed = !empty($launcher['download']['sha256']) + && !str_starts_with($launcher['download']['sha256'], 'REPLACE'); +} + +Layout::header('Launcher', 'launcher'); +?> +

Launcher — auto-update

+ + + +
+

État actuel

+ +

+ Version annoncée : v + • minRequired : + • Exe : présent" + : "absent" ?> + • Hash : OK" + : "à calculer" ?> + • Signature manifest : NON SIGNÉ" + : "SIGNÉ Ed25519" ?> +

+

URL attendue de l'exe :

+ +

Aucune version du launcher déclarée — l'auto-update est désactivé. Configure-la ci-dessous pour l'activer.

+ +
+ +
+

Workflow d'une nouvelle version du launcher

+
    +
  1. Remplis le formulaire Définir / mettre à jour ci-dessous (ex : 0.6.0).
  2. +
  3. Sur ton poste : dotnet publish src\PSLauncher.App -c Release et dotnet publish src\PSLauncher.Updater -c Release (les exes sont copiés à la racine du repo).
  4. +
  5. Renomme la copie : PSLauncher.exe → PSLauncher-X.Y.Z.exe.
  6. +
  7. Upload via SFTP dans www/PS_Launcher/builds/launcher/.
  8. +
  9. Clique 🔁 Hasher le launcher + signer.
  10. +
  11. Les launchers déjà déployés détecteront la nouvelle version au prochain « Vérifier les MAJ ».
  12. +
+
+ +
+

Définir / mettre à jour

+
+ + +
+
+ + +
+
+ + +
+
+ +
+ +
+ + + +
+ + +
+ + + +
+ +
+ +
+

Exes présents dans builds/launcher/

+ +

Aucun exe pour l'instant. Upload les binaires via SFTP dans www/PS_Launcher/builds/launcher/.

+ + + + + + + + + + + +
FichierTaille
+ +
+ ['index.php', 'Dashboard'], 'licenses' => ['licenses.php', 'Licenses'], 'versions' => ['versions.php', 'Versions'], + 'launcher' => ['launcher.php', 'Launcher'], 'audit' => ['audit.php', 'Audit'], ]; $links = ''; diff --git a/server/admin/versions.php b/server/admin/versions.php index bf44fed..af3e3b0 100644 --- a/server/admin/versions.php +++ b/server/admin/versions.php @@ -132,41 +132,13 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') { saveManifest($manifestPath, $manifest); $message = "v{$version} retirée du manifest. Le ZIP reste dans builds/ (à supprimer en SFTP si voulu)."; } - elseif ($action === 'set_launcher') { - $lver = trim($_POST['launcher_version'] ?? ''); - $lmin = trim($_POST['launcher_min_required'] ?? ''); - if (!preg_match('/^\d+\.\d+\.\d+$/', $lver)) { - throw new Exception('Numéro de version launcher invalide (X.Y.Z attendu).'); - } - if ($lmin !== '' && !preg_match('/^\d+\.\d+\.\d+$/', $lmin)) { - throw new Exception('Numéro de version "minRequired" invalide.'); - } - $base = $config['base_url'] ?? 'https://asterionvr.com/PS_Launcher'; - $manifest['launcher'] = [ - 'version' => $lver, - 'minRequired' => $lmin !== '' ? $lmin : '0.5.0', - 'download' => [ - 'url' => "{$base}/builds/launcher/PSLauncher-{$lver}.exe", - 'sizeBytes' => 0, - 'sha256' => 'REPLACE_AFTER_BUILD', - ], - 'releaseNotesUrl' => null, - ]; - saveManifest($manifestPath, $manifest); - $message = "Section launcher mise à jour (v{$lver}). Upload PSLauncher-{$lver}.exe dans builds/launcher/ puis clique « Sync »."; - } - elseif ($action === 'remove_launcher') { - unset($manifest['launcher']); - saveManifest($manifestPath, $manifest); - $message = "Section launcher retirée du manifest (auto-update désactivé)."; - } - elseif ($action === 'sync') { - // Appel direct à la classe — pas d'exec(), fonctionne même quand la fonction - // est désactivée par le mutualisé OVH. + elseif ($action === 'sync' || $action === 'sync_versions') { require_once "$root/tools/SignManifest.php"; $signer = new \PSLauncher\Tools\SignManifest($root); - $result = $signer->run(); - $message = "Sortie du script :\n" . implode("\n", $result['log']); + $scope = $action === 'sync_versions' ? 'versions' : 'all'; + $result = $signer->run($scope); + $label = $scope === 'versions' ? 'versions Proserve' : 'manifest complet'; + $message = "Sortie du script (scope: {$label}) :\n" . implode("\n", $result['log']); if (!$result['ok']) $messageType = 'error'; } } catch (Exception $e) { @@ -233,81 +205,6 @@ Layout::header('Versions', 'versions'); - -
-

Auto-update du launcher

- - -

- Version annoncée : v - • minRequired : - • Exe : présent" - : "absent" ?> - • Hash : OK" - : "à calculer" ?> -

-

URL attendue de l'exe :

- -

Section launcher absente du manifest — l'auto-update est désactivé. Configure-la ci-dessous pour l'activer.

- - -

Définir / mettre à jour

-
- - -
-
- - -
-
- - -
-
- -
- - -
- - - -
- - -

Workflow

-
    -
  1. Définis la version ci-dessus (ex : 0.6.0).
  2. -
  3. Upload PSLauncher-X.Y.Z.exe via SFTP dans www/PS_Launcher/builds/launcher/.
  4. -
  5. Clique 🔁 Sync (sign-manifest) dans le tableau du manifest ci-dessous — il hashera la section launcher en plus des versions Proserve.
  6. -
- - -

Exes présents dans builds/launcher/

- - -
-

Manifest actuel

@@ -322,8 +219,8 @@ Layout::header('Versions', 'versions');
- - + +
diff --git a/server/tools/SignManifest.php b/server/tools/SignManifest.php index ba88726..2bb7e92 100644 --- a/server/tools/SignManifest.php +++ b/server/tools/SignManifest.php @@ -26,13 +26,12 @@ final class SignManifest private function out(string $line): void { $this->log[] = $line; } /** - * Recompute sizes / sha256 for every version that has its ZIP uploaded, - * bump 'latest' to the highest signed version, then sign the manifest - * with the Ed25519 private key from config.php (if available). + * Recompute sizes / sha256 selon le scope, puis re-signe le manifest avec Ed25519. * + * @param string $scope 'all' (défaut) | 'versions' (ne touche que les Proserve) | 'launcher' * @return array{ok:bool, log:string[]} */ - public function run(): array + public function run(string $scope = 'all'): array { if (!is_file($this->manifestPath)) { $this->out("Manifest introuvable : {$this->manifestPath}"); @@ -45,8 +44,11 @@ final class SignManifest return ['ok' => false, 'log' => $this->log]; } + $doVersions = ($scope === 'all' || $scope === 'versions'); + $doLauncher = ($scope === 'all' || $scope === 'launcher'); + $hashedVersions = []; - foreach ($manifest['versions'] as &$v) { + if ($doVersions) foreach ($manifest['versions'] as &$v) { $version = $v['version'] ?? '?'; $url = $v['download']['url'] ?? ''; if ($url === '') { @@ -84,7 +86,7 @@ final class SignManifest // Section launcher : si présente, on tente de hasher le PSLauncher-{ver}.exe // dans builds/launcher/. On ignore proprement si l'exe n'est pas là. - if (isset($manifest['launcher']) && is_array($manifest['launcher'])) { + if ($doLauncher && isset($manifest['launcher']) && is_array($manifest['launcher'])) { $launcher = &$manifest['launcher']; $lver = $launcher['version'] ?? ''; $lurl = $launcher['download']['url'] ?? ''; @@ -110,7 +112,8 @@ final class SignManifest } // Bump auto de `latest` sur la plus haute version effectivement uploadée - if (!empty($hashedVersions)) { + // (uniquement si on a touché aux versions) + if ($doVersions && !empty($hashedVersions)) { usort($hashedVersions, 'version_compare'); $newLatest = end($hashedVersions); if (($manifest['latest'] ?? null) !== $newLatest) {