Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7bc229de53 | ||
|
|
83e3d61634 | ||
|
|
b088c6caa7 | ||
|
|
658a1cce72 | ||
|
|
bac8ebeb55 | ||
|
|
76eaa48342 |
No files matched your search
@@ -894,6 +894,13 @@ côté du catalogue, 0644, atomique) et un historique ; audit `keyring.publish`
|
||||
des administrateurs expose désormais la clé publique des clés **actives** seulement (celle d'une clé en attente
|
||||
permettrait de calculer l'empreinte à dicter).
|
||||
|
||||
**Contenu en ligne** (page Signature, `GET v1/signing` : `SigningState`) : versions en ligne de chaque jeu, catalogue,
|
||||
puis **formulaires des demandes** (`FeedbackFormsSignatureState` : révision, condensé, signature, signataire ;
|
||||
révision 0 = formulaires d'origine intégrés au launcher, rien à signer ; fichier de référence illisible signalé).
|
||||
Chaque contenu est vérifié par le launcher avec le trousseau publié (accepté ou refusé par les joueurs, et pourquoi)
|
||||
et avec le trousseau proposé (« sa clé ne sera plus dans le trousseau proposé » ; l'export de la demande le rappelle).
|
||||
Un serveur antérieur à la 3.2.1 n'envoie pas les formulaires : la ligne n'apparaît pas.
|
||||
|
||||
**Signature du contenu** (`ContentSigning`) : propriété `signature` `{ keyId, signedAt, value }` dans le JSON
|
||||
(atomique avec le contenu, ignorée par les anciens launchers), sur le message `GameLauncher/Content/v1`
|
||||
(type, identifiant du jeu ou « catalog », date à la seconde, clé, condensé). Condensés canoniques, calculés par
|
||||
|
||||
@@ -2,6 +2,7 @@ using System.Text.Json;
|
||||
using GameLauncher.Contracts;
|
||||
using GameLauncher.Contracts.Catalog;
|
||||
using GameLauncher.Contracts.Dtos;
|
||||
using GameLauncher.Contracts.Feedback;
|
||||
using GameLauncher.Contracts.Security;
|
||||
using GameLauncher.Contracts.Signing;
|
||||
using GameLauncher.Server.Hosting;
|
||||
@@ -13,7 +14,7 @@ namespace GameLauncher.Server.Modules.Signing;
|
||||
|
||||
/// <summary>
|
||||
/// Signature du contenu servi aux joueurs (phase 7) :
|
||||
/// • GET v1/signing (admins.manage) : trousseau publié, signatures des manifests et du catalogue ;
|
||||
/// • GET v1/signing (admins.manage) : trousseau publié, signatures des manifests, du catalogue et des formulaires des demandes ;
|
||||
/// • PUT v1/keyring (admins.manage, requête signée) : publication d'un trousseau signé HORS LIGNE par la clé racine ;
|
||||
/// • GET / POST v1/games/{gameId}/signature (releases.publish) : signature de la version déjà en ligne.
|
||||
/// La signature des nouvelles versions et du catalogue se fait à leur publication (modules Publishing et Catalog).
|
||||
@@ -33,8 +34,8 @@ public sealed class SigningModule : IApiModule
|
||||
api.MapPost(ApiRoutes.ManifestSignaturePattern, SignManifest).RequirePermission(AdminPermissions.ReleasesPublish).RequireSignedRequest();
|
||||
}
|
||||
|
||||
private static IResult State(KeyringStore keyrings, CatalogStore catalogs, AdminStore admins, IOptions<LauncherApiOptions> options,
|
||||
ILogger<SigningModule> logger)
|
||||
private static IResult State(KeyringStore keyrings, CatalogStore catalogs, FeedbackFormsStore forms, AdminStore admins,
|
||||
IOptions<LauncherApiOptions> options, ILogger<SigningModule> logger)
|
||||
{
|
||||
var settings = options.Value;
|
||||
var db = admins.Read();
|
||||
@@ -78,6 +79,30 @@ public sealed class SigningModule : IApiModule
|
||||
};
|
||||
}
|
||||
|
||||
// Formulaires des demandes en vigueur (référence privée, recopiée à l'identique dans le fichier public).
|
||||
FeedbackFormsSignatureState? feedbackForms = null;
|
||||
if (forms.PublishingEnabled)
|
||||
{
|
||||
try
|
||||
{
|
||||
var current = forms.Current;
|
||||
feedbackForms = current.Revision == 0
|
||||
? new FeedbackFormsSignatureState()
|
||||
: new FeedbackFormsSignatureState
|
||||
{
|
||||
Revision = current.Revision,
|
||||
Digest = FeedbackFormRules.Digest(current),
|
||||
Signature = current.Signature,
|
||||
SignerName = ContentSignatures.SignerName(db, current.Signature)
|
||||
};
|
||||
}
|
||||
catch (Exception ex) when (ex is IOException or UnauthorizedAccessException or InvalidDataException or JsonException)
|
||||
{
|
||||
logger.LogWarning(ex, "Signature des formulaires des demandes");
|
||||
feedbackForms = new FeedbackFormsSignatureState { Unreadable = true };
|
||||
}
|
||||
}
|
||||
|
||||
KeyringDocument? keyring;
|
||||
try
|
||||
{
|
||||
@@ -97,7 +122,8 @@ public sealed class SigningModule : IApiModule
|
||||
KeyringPublicUrl = keyrings.PublishingEnabled ? settings.KeyringPublicUrl : null,
|
||||
RequireSignatures = settings.ContentSigning.Require,
|
||||
Manifests = manifests,
|
||||
Catalog = catalog
|
||||
Catalog = catalog,
|
||||
FeedbackForms = feedbackForms
|
||||
}, ApiJson.Options);
|
||||
}
|
||||
|
||||
|
||||
@@ -55,6 +55,9 @@ public sealed record SigningState
|
||||
|
||||
/// <summary>Catalogue publié (null : publication du catalogue non configurée).</summary>
|
||||
public CatalogSignatureState? Catalog { get; init; }
|
||||
|
||||
/// <summary>Formulaires des demandes (null : publication des formulaires non configurée, ou serveur antérieur à la 3.2.1).</summary>
|
||||
public FeedbackFormsSignatureState? FeedbackForms { get; init; }
|
||||
}
|
||||
|
||||
public sealed record CatalogSignatureState
|
||||
@@ -64,3 +67,19 @@ public sealed record CatalogSignatureState
|
||||
public ContentSignature? Signature { get; init; }
|
||||
public string? SignerName { get; init; }
|
||||
}
|
||||
|
||||
/// <summary>Signature des formulaires des demandes en vigueur (feedback-forms.json).</summary>
|
||||
public sealed record FeedbackFormsSignatureState
|
||||
{
|
||||
/// <summary>Révision en vigueur (0 : formulaires d'origine, intégrés au launcher, jamais publiés).</summary>
|
||||
public long Revision { get; init; }
|
||||
|
||||
/// <summary>Condensé du contenu signé (vide : formulaires d'origine, ou fichier illisible).</summary>
|
||||
public string Digest { get; init; } = "";
|
||||
|
||||
public ContentSignature? Signature { get; init; }
|
||||
public string? SignerName { get; init; }
|
||||
|
||||
/// <summary>Vrai : le fichier de référence des formulaires est illisible sur le serveur.</summary>
|
||||
public bool Unreadable { get; init; }
|
||||
}
|
||||
@@ -9,7 +9,8 @@ namespace GameLauncher.Modules.Admin.Signing;
|
||||
|
||||
/// <summary>
|
||||
/// Page « Signature » (propriétaires) : trousseau publié (vérifié avec la clé racine intégrée à l'exe), trousseau
|
||||
/// proposé d'après les appareils actifs autorisés à publier, état des signatures du contenu en ligne.
|
||||
/// proposé d'après les appareils actifs autorisés à publier, état des signatures du contenu en ligne (versions en
|
||||
/// ligne, catalogue, formulaires des demandes).
|
||||
/// La clé racine n'est JAMAIS ouverte par le launcher : la demande est exportée, signée hors ligne avec
|
||||
/// tools\sign-keyring.bat, puis le trousseau signé est publié ici.
|
||||
/// </summary>
|
||||
@@ -193,6 +194,16 @@ public sealed class SigningPanelViewModel : AdminPanelViewModel
|
||||
items.Add(new SignedContentItem($"Catalogue (révision {catalog.Revision})", ContentKinds.Catalog, ContentKinds.CatalogId,
|
||||
catalog.Digest, catalog.Signature, catalog.SignerName, state.Keyring, proposed,
|
||||
"Republiez-le depuis la page « Jeux » (il est signé à chaque publication)."));
|
||||
if (state.FeedbackForms is { } forms)
|
||||
items.Add(forms.Unreadable
|
||||
? SignedContentItem.Failed("Formulaires des demandes",
|
||||
"Fichier des formulaires illisible sur le serveur (voir ses journaux) : restaurez-le depuis feedback-forms-history/ " +
|
||||
"dans les données privées du serveur.")
|
||||
: new SignedContentItem(
|
||||
forms.Revision > 0 ? $"Formulaires des demandes (révision {forms.Revision})" : "Formulaires des demandes",
|
||||
ContentKinds.FeedbackForms, ContentKinds.FeedbackFormsId, forms.Digest, forms.Signature, forms.SignerName, state.Keyring, proposed,
|
||||
"Republiez-les depuis la page « Formulaires des demandes » (ils sont signés à chaque publication).",
|
||||
"Formulaires d'origine, intégrés au launcher : rien à signer tant que rien n'est publié."));
|
||||
return items;
|
||||
}
|
||||
|
||||
@@ -319,12 +330,12 @@ public sealed class KeyringKeyItem
|
||||
public sealed class SignedContentItem
|
||||
{
|
||||
internal SignedContentItem(string title, string kind, string id, string digest, ContentSignature? signature, string? signerName,
|
||||
KeyringDocument? published, KeyringDocument proposed, string howToSign)
|
||||
KeyringDocument? published, KeyringDocument proposed, string howToSign, string nothingPublished = "Rien n'est publié.")
|
||||
{
|
||||
Title = title;
|
||||
if (string.IsNullOrEmpty(digest))
|
||||
{
|
||||
Text = "Rien n'est publié.";
|
||||
Text = nothingPublished;
|
||||
IsValid = true;
|
||||
return;
|
||||
}
|
||||
@@ -342,6 +353,15 @@ public sealed class SignedContentItem
|
||||
Text += $" Attention : sa clé ne sera plus dans le trousseau proposé. {howToSign}";
|
||||
}
|
||||
|
||||
private SignedContentItem(string title, string text)
|
||||
{
|
||||
Title = title;
|
||||
Text = text;
|
||||
}
|
||||
|
||||
/// <summary>Contenu dont l'état ne peut pas être lu (refusé, à corriger sur le serveur).</summary>
|
||||
internal static SignedContentItem Failed(string title, string text) => new(title, text);
|
||||
|
||||
public string Title { get; }
|
||||
public string Text { get; }
|
||||
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
(1.0.0 → 1.0.1 → 1.1.0…). Les launchers des joueurs ne se mettent à jour que vers
|
||||
une version STRICTEMENT supérieure à la leur.
|
||||
-->
|
||||
<Version>3.2.0</Version>
|
||||
<Version>3.2.1</Version>
|
||||
<Authors>Lanisys</Authors>
|
||||
<Company>LanisysGames</Company>
|
||||
<Copyright>© LanisysGames</Copyright>
|
||||
|
||||
@@ -6,6 +6,7 @@ using GameLauncher.Modules.Admin;
|
||||
using GameLauncher.Modules.Admin.Publishing;
|
||||
using GameLauncher.Modules.Admin.Signing;
|
||||
using GameLauncher.Modules.Admin.ViewModels;
|
||||
using GameLauncher.Tests.Contracts;
|
||||
using GameLauncher.Tests.Infrastructure;
|
||||
using GameLauncher.Tests.Publishing;
|
||||
using GameLauncher.Tests.Server;
|
||||
@@ -91,6 +92,70 @@ public class SigningPanelTests
|
||||
Assert.Contains("déjà publié", page.ErrorMessage);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task The_feedback_forms_signature_is_shown_below_the_catalog()
|
||||
{
|
||||
var directory = Path.Combine(Path.GetTempPath(), "launcher-signing-tests", Guid.NewGuid().ToString("N"), "catalog");
|
||||
Directory.CreateDirectory(directory);
|
||||
await using var api = await TestApi.StartAsync(new Dictionary<string, string?>
|
||||
{
|
||||
["LauncherApi:Catalog:PublicFile"] = Path.Combine(directory, "catalog.json"),
|
||||
["LauncherApi:Games:EZR:ManifestFile"] = ChangelogModuleTests.PublishedManifest(),
|
||||
["LauncherApi:Feedback:Enabled"] = "true",
|
||||
["LauncherApi:Feedback:Games:0"] = "EZR"
|
||||
});
|
||||
using var folder = new TempFolder();
|
||||
var (_, signer) = AdminTestKit.CreateKeyFile(folder.Path);
|
||||
using var _ = signer;
|
||||
AdminTestKit.RegisterOwner(api, signer);
|
||||
using var root = SigningKit.NewKey();
|
||||
|
||||
// Trousseau n° 1 : la clé de Camille, sans l'autorisation « formulaires ».
|
||||
using var camilleKey = api.AddOwner("Camille");
|
||||
await using var camille = await api.LoginAsync(camilleKey);
|
||||
KeyringKey Entry(params string[] scopes) => new()
|
||||
{
|
||||
KeyId = camilleKey.KeyId, PublicKey = Convert.ToBase64String(camilleKey.PublicKey), Name = "Camille — PC", Scopes = scopes.ToList()
|
||||
};
|
||||
await camille.PublishKeyringAsync(SigningKit.Keyring(root, 1, Entry(SigningScopes.All.Where(s => s != SigningScopes.Forms).ToArray())));
|
||||
|
||||
await using var shell = new AdminShellViewModel(AdminTestKit.Environment(api, folder.Path, new FakeDialogs(), Modules,
|
||||
rootKeys: new[] { SigningKit.Root(root) }));
|
||||
await Assert.IsType<LoginViewModel>(shell.Screen).LoginAsync(AdminTestKit.Passphrase);
|
||||
var workspace = Assert.IsType<AdminWorkspaceViewModel>(shell.Screen);
|
||||
workspace.Navigate(SigningPanelViewModel.PanelId);
|
||||
await workspace.Activation;
|
||||
var page = Assert.IsType<SigningPanelViewModel>(workspace.SelectedPanel!.ViewModel);
|
||||
|
||||
// Formulaires d'origine : rien à signer ; affichés après les versions en ligne et le catalogue.
|
||||
Assert.False(page.HasError, page.ErrorMessage);
|
||||
Assert.StartsWith("Version en ligne de EZR", page.Contents[0].Title);
|
||||
Assert.StartsWith("Catalogue", page.Contents[^2].Title);
|
||||
var forms = page.Contents[^1];
|
||||
Assert.Equal("Formulaires des demandes", forms.Title);
|
||||
Assert.StartsWith("Formulaires d'origine", forms.Text);
|
||||
Assert.True(forms.IsValid);
|
||||
|
||||
// Publiés par Camille, dont la clé n'a pas l'autorisation « formulaires » dans le trousseau publié : refusés par
|
||||
// les launchers ; le trousseau proposé (propriétaire : autorisation « formulaires ») les rendra valides.
|
||||
await camille.PublishFeedbackFormsAsync(FeedbackFormsKit.Custom(), 0);
|
||||
await page.RefreshCommand.ExecuteAsync();
|
||||
forms = page.Contents[^1];
|
||||
Assert.Equal("Formulaires des demandes (révision 1)", forms.Title);
|
||||
Assert.False(forms.IsValid);
|
||||
Assert.False(forms.WillBreak);
|
||||
Assert.Contains("refusé par les launchers", forms.Text);
|
||||
Assert.Contains("« Formulaires des demandes »", forms.Text);
|
||||
|
||||
// Trousseau n° 2 avec l'autorisation « formulaires » : valides.
|
||||
await camille.PublishKeyringAsync(SigningKit.Keyring(root, 2, Entry(SigningScopes.All.ToArray())));
|
||||
await page.RefreshCommand.ExecuteAsync();
|
||||
forms = page.Contents[^1];
|
||||
Assert.True(forms.IsValid, forms.Text);
|
||||
Assert.Contains("Camille", forms.Text);
|
||||
Assert.Contains("valide pour les launchers", forms.Text);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Device_names_proposed_for_the_public_keyring_are_cleaned()
|
||||
{
|
||||
|
||||
@@ -709,6 +709,14 @@ internal sealed class SampleWorld
|
||||
Digest = SampleData.Digest("catalogue"),
|
||||
Signature = Signature(-3),
|
||||
SignerName = "Camille — PC-STUDIO"
|
||||
},
|
||||
// Formulaires des demandes de démonstration (révision 3, comme la page « Formulaires des demandes »).
|
||||
FeedbackForms = new FeedbackFormsSignatureState
|
||||
{
|
||||
Revision = 3,
|
||||
Digest = FeedbackFormRules.Digest(SampleData.SampleFeedbackForms()),
|
||||
Signature = Signature(-1),
|
||||
SignerName = $"{OwnerName} — PC-BUREAU"
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@@ -45,8 +45,9 @@ Les positions du rapport sont en unités WPF (multiplier par `--scale` pour les
|
||||
démonstration (ni fichier choisi, ni presse-papiers).
|
||||
* **Menu d'administration** (`admin-*`) : connexion (normale, refusée, verrouillée), « J'ai une
|
||||
invitation » (formulaire, empreinte), puis **chaque page déclarée par les modules** (`admin-page-<id>`,
|
||||
lues dans `App.CreateModules` : une page ajoutée plus tard est capturée sans modifier l'outil), une
|
||||
version prête à publier, la fiche d'une demande de joueur (`admin-page-feedback-requests-detail` :
|
||||
lues dans `App.CreateModules` : une page ajoutée plus tard est capturée sans modifier l'outil ; la page
|
||||
« Signature », `admin-page-signing`, montre les versions en ligne, le catalogue et les formulaires des
|
||||
demandes), une version prête à publier, la fiche d'une demande de joueur (`admin-page-feedback-requests-detail` :
|
||||
lien signalé, captures d'écran) et un formulaire des demandes en cours de modification
|
||||
(`admin-page-feedback-forms-edit` : champ ajouté et déplié, erreur « lien » et avertissement « donnée
|
||||
personnelle », aperçu tel que les joueurs le verront), puis un type de demande ajouté
|
||||
|
||||
+47
-109
@@ -1,140 +1,78 @@
|
||||
# Launcher 3.2.0
|
||||
# Launcher 3.2.1
|
||||
LAUNCHER - NOTES DE MISE À JOUR
|
||||
Formulaires des demandes modifiables - Mise à jour du 10 novembre 2026
|
||||
Signature des formulaires des demandes - Mise à jour du 10 novembre 2026
|
||||
==================================================================
|
||||
|
||||
Les formulaires du bouton « Aide » se gèrent désormais depuis le menu d'administration : de 1 à 8 types de demande (ajout, suppression, ordre d'affichage, icône, captures d'écran autorisées ou non) et leurs champs, avec un aperçu identique à la fenêtre des joueurs.
|
||||
La page « Signature » du menu d'administration affiche désormais l'état de signature des formulaires des demandes, sous les versions en ligne et le catalogue : formulaires d'origine, signés et valides, ou refusés par les launchers avec la raison et le remède.
|
||||
|
||||
Les formulaires sont communs à tous les jeux, signés et vérifiés par le launcher, et ne peuvent contenir aucun lien. Le serveur est à redéployer, avec deux blocs nginx à ajouter ; le trousseau est à re-signer une fois cette version diffusée.
|
||||
Le serveur est à redéployer ; aucun bloc nginx à ajouter.
|
||||
|
||||
|
||||
------------------------------------------------------------------
|
||||
EN BREF
|
||||
------------------------------------------------------------------
|
||||
- NOUVEAU : page « Formulaires des demandes » dans le menu :
|
||||
types de demande, champs, aperçu, contrôle en direct, publication
|
||||
signée.
|
||||
- NOUVEAU : 1 à 8 types de demande : ajout, suppression, ordre
|
||||
d'affichage, type masqué.
|
||||
- NOUVEAU : icône d'un type : l'une des quatre d'origine, ou un
|
||||
fichier .ico importé (image 64 × 64 obligatoire).
|
||||
- NOUVEAU : captures d'écran autorisées ou non par type de demande.
|
||||
- NOUVEAU : champs texte court, cases à cocher, case oui/non, notes
|
||||
de 3, 5 ou 10 étoiles.
|
||||
- AMÉLIORÉ : fenêtre « Aide » : formulaires publiés, saisie gardée
|
||||
si les formulaires changent pendant la saisie.
|
||||
- AMÉLIORÉ : chaque demande garde le formulaire de son envoi (nom,
|
||||
icône, libellés).
|
||||
- SÉCURITÉ : formulaires signés et revérifiés par le launcher ;
|
||||
aucun lien accepté dans les textes.
|
||||
- SERVEUR : à redéployer, avec deux blocs nginx ; trousseau à
|
||||
re-signer après la diffusion de la 3.2.0.
|
||||
- QUALITÉ : 13 nouveaux tests automatisés (355 au total).
|
||||
- AMÉLIORÉ : page « Signature » : ligne « Formulaires des demandes »
|
||||
dans « Contenu en ligne », sous les versions en ligne et le
|
||||
catalogue.
|
||||
- AMÉLIORÉ : vérification avec le trousseau publié (accepté ou refusé
|
||||
par les joueurs, et pourquoi) et avec le trousseau proposé.
|
||||
- SÉCURITÉ : export de la demande de trousseau : les formulaires qui
|
||||
deviendraient invalides sont rappelés.
|
||||
- SERVEUR : à redéployer ; aucun bloc nginx à ajouter.
|
||||
- QUALITÉ : 1 nouveau test automatisé (356 au total).
|
||||
|
||||
|
||||
------------------------------------------------------------------
|
||||
PAGE « FORMULAIRES DES DEMANDES » (ADMINISTRATION)
|
||||
PAGE « SIGNATURE »
|
||||
------------------------------------------------------------------
|
||||
- Permission « Formulaires des demandes » (feedback.forms).
|
||||
- Types de demande : ajouter (8 au plus), monter, descendre,
|
||||
supprimer (avec confirmation ; les demandes reçues restent
|
||||
consultables), masquer.
|
||||
- Réglages d'un type : nom, description, exemple de titre,
|
||||
informations techniques cochées par défaut, captures d'écran
|
||||
autorisées (3 au plus), icône.
|
||||
- Champs : ajouter, monter, descendre, retirer ; libellé, aide,
|
||||
obligatoire, aperçu dans la liste, longueur, nombre d'étoiles,
|
||||
choix (2 à 20).
|
||||
- Types de champs : zone de texte, texte court, liste déroulante,
|
||||
cases à cocher, case oui/non, étoiles (3, 5 ou 10).
|
||||
- Aperçu identique à la fenêtre « Aide » ; contrôle en direct, la
|
||||
publication reste bloquée tant qu'il reste une erreur.
|
||||
- Avertissement si un libellé semble demander une donnée
|
||||
personnelle (e-mail, mot de passe, téléphone…).
|
||||
- « Publier », « Annuler les modifications », « Revenir à
|
||||
l'origine », « Recharger » ; une publication d'un autre
|
||||
administrateur n'est jamais écrasée.
|
||||
|
||||
|
||||
------------------------------------------------------------------
|
||||
ICÔNES IMPORTÉES
|
||||
------------------------------------------------------------------
|
||||
- Fichier .ico seulement (1 Mo au plus), contenant une image de
|
||||
64 × 64 pixels ; les autres tailles du fichier sont ignorées.
|
||||
- PNG intégré ou bitmap 24/32 bits ; 256 couleurs et moins refusés.
|
||||
- Image réécrite en PNG neuf, sans métadonnées, intégrée aux
|
||||
formulaires et couverte par leur signature.
|
||||
- Un fichier refusé affiche un message qui explique pourquoi.
|
||||
|
||||
|
||||
------------------------------------------------------------------
|
||||
FENÊTRE « AIDE » ET DEMANDES DES JOUEURS
|
||||
------------------------------------------------------------------
|
||||
- Formulaires publiés lus à l'ouverture de la fenêtre, puis
|
||||
vérifiés (règles, signature, révision).
|
||||
- Types dans l'ordre choisi, avec leur icône ; types masqués
|
||||
absents ; section « Captures d'écran » masquée si le type ne les
|
||||
autorise pas.
|
||||
- Formulaires republiés pendant la saisie : formulaire reconstruit,
|
||||
saisie des champs inchangés gardée.
|
||||
- Hors ligne ou formulaires refusés : formulaires d'origine.
|
||||
- Menu : chaque demande s'affiche avec le formulaire de son envoi ;
|
||||
filtre par type publié, « (masqué) » ou « (supprimé) ».
|
||||
- Journal d'audit : « Formulaires des demandes publiés », avec le
|
||||
détail des changements par type.
|
||||
- Contenu en ligne, dans l'ordre : versions en ligne, catalogue,
|
||||
formulaires des demandes.
|
||||
- Formulaires d'origine : « rien à signer tant que rien n'est
|
||||
publié ».
|
||||
- Formulaires publiés : révision, signataire et date ; « valide pour
|
||||
les launchers », ou refus avec la raison (clé absente du trousseau,
|
||||
autorisation « formulaires » manquante…) et le remède (republier
|
||||
depuis la page « Formulaires des demandes »).
|
||||
- Avertissement si la clé qui les a signés ne sera plus dans le
|
||||
trousseau proposé ; rappel à l'export de la demande.
|
||||
- Fichier des formulaires illisible sur le serveur : signalé, avec
|
||||
la marche à suivre (historique feedback-forms-history/).
|
||||
- Serveur antérieur à la 3.2.1 : la ligne n'apparaît pas.
|
||||
|
||||
|
||||
------------------------------------------------------------------
|
||||
SÉCURITÉ
|
||||
------------------------------------------------------------------
|
||||
- Formulaires signés par une clé autorisée « formulaires » dans le
|
||||
trousseau ; vérifiés par chaque launcher, comme le catalogue.
|
||||
- Aucun lien dans les noms, descriptions, libellés, aides et choix :
|
||||
refusé par le menu, le serveur et le launcher.
|
||||
- Ancienne révision refusée par le launcher.
|
||||
- Publication par requête signée, avec la permission
|
||||
feedback.forms ; révision attendue (rien n'est écrasé).
|
||||
- Taille limitée : 256 Ko de formulaires, icônes comprises.
|
||||
- Le serveur refuse une demande avec captures pour un type qui ne
|
||||
les autorise pas, et une demande pour un type masqué ou supprimé.
|
||||
- Une autorisation inconnue du trousseau est désormais acceptée sans
|
||||
effet.
|
||||
- Accès inchangé : session et permission admins.manage.
|
||||
- Vérification faite par le launcher avec le trousseau publié et la
|
||||
clé racine intégrée, comme chez les joueurs.
|
||||
- Rien de secret renvoyé : révision, condensé, signature et
|
||||
signataire de formulaires publics.
|
||||
|
||||
|
||||
------------------------------------------------------------------
|
||||
SERVEUR
|
||||
------------------------------------------------------------------
|
||||
- À redéployer : server/deploy/LISEZMOI.md, étape 8, puis
|
||||
étape 3 nonies.
|
||||
- nginx : ajouter « location = /catalog/feedback-forms.json »
|
||||
(nginx-catalog.conf) et « location = /api/v1/feedback/forms »
|
||||
(nginx-api.conf, 300 Ko).
|
||||
- Publier ensuite le launcher 3.2.0, puis donner la permission
|
||||
feedback.forms et re-signer le trousseau.
|
||||
- Les launchers 3.0 / 3.1 envoient toujours leurs demandes avec les
|
||||
formulaires d'origine, acceptées sauf type masqué ou supprimé.
|
||||
- À redéployer : server/deploy/LISEZMOI.md, étape 8.
|
||||
- Aucun réglage ni bloc nginx à ajouter.
|
||||
- Ordre indifférent entre serveur et launcher.
|
||||
- Après la mise à jour, vérifier dans la page « Signature » que les
|
||||
formulaires publiés sont valides pour les launchers ; sinon,
|
||||
re-signer le trousseau avec l'autorisation « formulaires des
|
||||
demandes ».
|
||||
|
||||
|
||||
------------------------------------------------------------------
|
||||
DÉVELOPPEMENT
|
||||
------------------------------------------------------------------
|
||||
- Contrats : FeedbackFormsDocument (document signé et règles),
|
||||
FeedbackIcons (lecture des .ico, sans bibliothèque).
|
||||
- Signature : type de contenu feedback-forms, autorisation « forms »
|
||||
du trousseau.
|
||||
- Serveur : FeedbackFormsStore (référence privée, historique de 20
|
||||
publications, copie publique) ; route v1/feedback/forms.
|
||||
- Launcher : FeedbackFormsService (lecture et vérification),
|
||||
Themes/FeedbackForms.xaml (modèles partagés avec l'aperçu).
|
||||
- Menu : FeedbackFormsPanelViewModel, FeedbackFormEditors.
|
||||
- Outil ui-snapshot : scènes admin-page-feedback-forms-edit,
|
||||
admin-page-feedback-forms-new-type, feedback-custom-kinds et
|
||||
feedback-custom.
|
||||
- Tests : FeedbackFormsTests.cs, FeedbackFormsModuleTests.cs,
|
||||
FeedbackFormsPanelTests.cs (nouveaux), ContentSigningTests.cs,
|
||||
FeedbackPanelTests.cs.
|
||||
- Documentation : README.md, docs/ADMIN-ARCHITECTURE.md
|
||||
(§ 11 sexies) et server/deploy/LISEZMOI.md mis à jour.
|
||||
- Contrats : FeedbackFormsSignatureState, SigningState.FeedbackForms.
|
||||
- Serveur : GET v1/signing renvoie la signature des formulaires en
|
||||
vigueur (SigningModule).
|
||||
- Menu : SigningPanelViewModel (ligne « Formulaires des demandes »).
|
||||
- Outil ui-snapshot : formulaires de démonstration dans la scène
|
||||
admin-page-signing.
|
||||
- Tests : SigningPanelTests.cs.
|
||||
- Documentation : docs/ADMIN-ARCHITECTURE.md (§ 12) mis à jour.
|
||||
|
||||
|
||||
La sécurité des mises à jour du launcher ne change pas : la signature numérique et l'empreinte SHA-256 de chaque nouvelle version sont vérifiées avant toute installation.
|
||||
Reference in new issue
Block a user