diff --git a/installer/PSLauncher.iss b/installer/PSLauncher.iss
index 794bee4..f7ae52d 100644
--- a/installer/PSLauncher.iss
+++ b/installer/PSLauncher.iss
@@ -11,7 +11,7 @@
#define MyAppName "PROSERVE Launcher"
#define MyAppShortName "PS_Launcher"
-#define MyAppVersion "0.27.4"
+#define MyAppVersion "0.28.10"
#define MyAppPublisher "ASTERION VR"
#define MyAppURL "https://asterionvr.com"
#define MyAppExeName "PS_Launcher.exe"
diff --git a/server/admin/launcher.php b/server/admin/launcher.php
index aaf2578..540963c 100644
--- a/server/admin/launcher.php
+++ b/server/admin/launcher.php
@@ -76,6 +76,7 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
$message = "Sortie du script (scope: launcher{$forceLabel}) :\n" . implode("\n", $result['log']);
if (!$result['ok']) $messageType = 'error';
}
+ // (Le settings lock est maintenant par-license, géré dans licenses.php — voir migration 003.)
} catch (Exception $e) {
$message = $e->getMessage();
$messageType = 'error';
diff --git a/server/admin/licenses.php b/server/admin/licenses.php
index 4af0fad..93a234a 100644
--- a/server/admin/licenses.php
+++ b/server/admin/licenses.php
@@ -145,6 +145,26 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
$db->prepare('UPDATE licenses SET max_machines = ? WHERE id = ?')->execute([$newMax, $id]);
$message = "License #{$id} : limite passée à {$newMax} machine(s).";
}
+ elseif ($action === 'set_settings_lock_password') {
+ $id = (int)($_POST['id'] ?? 0);
+ $pwd = (string)($_POST['settings_lock_password'] ?? '');
+ if ($id <= 0) {
+ throw new Exception('License id invalide.');
+ }
+ if ($pwd === '') {
+ // Vide = retire le verrouillage pour cette license
+ $db->prepare('UPDATE licenses SET settings_lock_password_hash = NULL WHERE id = ?')->execute([$id]);
+ $message = "License #{$id} : verrouillage des paramètres avancés retiré.";
+ } else {
+ if (strlen($pwd) < 4) {
+ throw new Exception('Mot de passe trop court (minimum 4 caractères).');
+ }
+ // SHA-256 hex lowercase, format compatible avec SettingsLockService côté launcher.
+ $hash = hash('sha256', $pwd);
+ $db->prepare('UPDATE licenses SET settings_lock_password_hash = ? WHERE id = ?')->execute([$hash, $id]);
+ $message = "License #{$id} : mot de passe des paramètres avancés mis à jour.";
+ }
+ }
elseif ($action === 'reset_machines') {
$id = (int)($_POST['id'] ?? 0);
$db->prepare('DELETE FROM license_machines WHERE license_id = ?')->execute([$id]);
@@ -363,6 +383,24 @@ Layout::header('Licenses', 'licenses');
+
+
+ = $hasLock ? '🔒 Lock' : 'Lock' ?>
+
+
+