waffensachkunde

Waffensachkunde – Lernsoftware für die Sachkundeprüfung nach § 7 WaffG. Barrierefrei, offline, EUPL-1.2.

/ app e2e store-paket.spec.ts

6,3 KB Rohdatei
app/e2e/store-paket.spec.ts — 142 Zeilen
1 /**
2 * Rauchtest gegen das **Store-Paket** (AppX/MSIX).
3 *
4 * ## Warum es diesen Test neben `gepackt.spec.ts` gibt
5 *
6 * `gepackt.spec.ts` misst den NSIS-Bau unter `release/win-unpacked/`. Das
7 * Store-Paket ist ein anderes Erzeugnis mit einer anderen Umgebung: eigene
8 * Paketidentität, eigener AppContainer, eigene Registrierungssicht. Ein Test,
9 * der den einen Bau misst, sagt über den anderen nichts.
10 *
11 * ## Was hier geprüft wird – und warum gerade das
12 *
13 * Der Punkt, an dem sich die beiden Wege am ehesten unterscheiden, ist der
14 * **Ablageort der Nutzerdaten**. Windows kann den Anwendungsdatenordner eines
15 * Paketes umlenken, üblicherweise nach `%LOCALAPPDATA%\Packages\…`. Genau
16 * davon ging dieses Projekt lange aus: `docs/datenschutz.md` 4.6 und 7.4
17 * sagten es dem Leser zu, und `docs/stand.md` führte es als „am gepackten
18 * Store-Paket zu messen“.
19 *
20 * **Gemessen am 28.08.2026: Es wird nicht umgelenkt.** Das Paket lief unter
21 * seiner echten Store-Identität, und `lernstand.db-wal` und `-shm` – die
22 * Begleitdateien, die SQLite nur führt, solange die Datenbank offen ist –
23 * lagen unter `%APPDATA%\Waffensachkunde Lernsoftware\`. Im paketeigenen
24 * Bereich lag ausschließlich, was Windows selbst dort anlegt.
25 *
26 * Dieser Test hält dieses Ergebnis fest. Er behauptet nichts über Windows,
27 * sondern misst, was diese Anwendung in dieser Verpackung tut – und schlägt
28 * an, wenn eine künftige Windows- oder electron-builder-Fassung es ändert.
29 * Dann sind 4.6 und 7.4 der Datenschutzerklärung nachzuführen, nicht der
30 * Test.
31 *
32 * ## Eine Falle für den, der das nachprüfen will
33 *
34 * Eine Suche nach `lernstand.db` über das Benutzerprofil findet einen Treffer
35 * unter `%LOCALAPPDATA%\Packages\Claude_…\LocalCache\Roaming\` und legt den
36 * Schluss nahe, es werde eben doch umgelenkt. Wird es nicht: Am 28.08.2026
37 * mit `fsutil file queryfileid` gegengeprüft – dieser Pfad und
38 * `%APPDATA%\Waffensachkunde Lernsoftware\` tragen **dieselbe NTFS-Datei-ID**
39 * und denselben SHA-256. Es ist eine Datei, gesehen durch die Umlenkung eines
40 * **fremden** Paketbehälters, nicht durch die dieser Anwendung. Wer das
41 * nachmisst, prüfe die Datei-ID, nicht den Pfad.
42 *
43 * ## Warum er sich überspringt statt fehlzuschlagen
44 *
45 * Er braucht ein registriertes Paket, und das entsteht nicht beim Bauen,
46 * sondern durch einen bewussten Schritt am Rechner (`npm run dist:store`,
47 * auspacken, `Add-AppxPackage -Register`). Ein harter Abbruch machte jeden
48 * gewöhnlichen Lauf rot, ohne dass etwas falsch wäre. Übersprungen **mit
49 * Grund** ist die ehrliche Form: Der Gate-Bericht sagt dann, was er nicht
50 * geprüft hat.
51 */
52 import { execFileSync } from 'node:child_process';
53 import { existsSync } from 'node:fs';
54 import { join } from 'node:path';
55
56 import { expect, test } from './konsolenwache';
57
58 /** Die Paketfamilie aus dem Partner Center – Produktverwaltung, Product Identity. */
59 const PAKETFAMILIE = 'O-W.Waffensachkunde-Lernsoftware-OW_c9rr4ryw66n3y';
60
61 /* Zugriff über den Index und nicht über die Punktschreibweise: `process.env`
62 ist eine Indexsignatur, und `noPropertyAccessFromIndexSignature` besteht
63 zu Recht darauf — bei `process.env.APPDATA` fiele ein Tippfehler erst zur
64 Laufzeit auf, und zwar als leerer Pfad statt als Fehler. */
65
66 /** Der Ordner, den die Anwendung ohne Umlenkung benutzt. */
67 const KLASSISCH = join(process.env['APPDATA'] ?? '', 'Waffensachkunde Lernsoftware');
68
69 /** Der paketeigene Bereich, in den Windows umlenken **könnte**. */
70 const PAKETABLAGE = join(process.env['LOCALAPPDATA'] ?? '', 'Packages', PAKETFAMILIE);
71
72 /** Ist das Paket auf diesem Rechner registriert? `null`, wenn nicht messbar. */
73 function paketRegistriert(): boolean | null {
74 if (process.platform !== 'win32') {
75 return null;
76 }
77 try {
78 const ausgabe = execFileSync(
79 'powershell',
80 [
81 '-NoProfile',
82 '-Command',
83 `(Get-AppxPackage -Name 'O-W.Waffensachkunde-Lernsoftware-OW').PackageFullName`,
84 ],
85 { encoding: 'utf8', stdio: ['ignore', 'pipe', 'ignore'] },
86 ).trim();
87 return ausgabe.length > 0;
88 } catch {
89 /* Kein PowerShell, keine Berechtigung, kein Windows – nicht messbar. */
90 return null;
91 }
92 }
93
94 test.describe('Store-Paket – Ablageort der Nutzerdaten', () => {
95 test.beforeAll(() => {
96 const registriert = paketRegistriert();
97 test.skip(
98 registriert !== true,
99 'Kein registriertes Store-Paket auf diesem Rechner. Erzeugen mit ' +
100 '`npm run dist:store`, auspacken (die Namen im AppX sind ' +
101 'prozentkodiert!) und `Add-AppxPackage -Register …\\AppxManifest.xml`.',
102 );
103 });
104
105 test('legt den Lernstand am klassischen Ort ab, nicht in der Paketablage', () => {
106 /*
107 Die eine Aussage, auf die sich die Datenschutzerklärung stützt. Geprüft
108 wird die Datenbank selbst und nicht ein Ordner: Ein Ordner entsteht auch
109 leer, eine `lernstand.db` nur, wenn die Anwendung dort wirklich
110 geschrieben hat.
111 */
112 expect(
113 existsSync(join(KLASSISCH, 'lernstand.db')),
114 `Unter ${KLASSISCH} liegt keine lernstand.db. Entweder hat die ` +
115 'Anwendung dort noch nie geschrieben, oder der Ablageort hat sich ' +
116 'geändert — dann sind docs/datenschutz.md 4.6 und 7.4 nachzuführen.',
117 ).toBe(true);
118 });
119
120 test('legt keine zweite Datenbank in der Paketablage an', () => {
121 /*
122 Die Gegenrichtung, und der eigentliche Wächter: Sobald Windows oder
123 electron-builder die Umlenkung doch einschalten, entsteht hier eine
124 zweite lernstand.db — und dann stimmt die Zusage in der
125 Datenschutzerklärung nicht mehr, dass beide Fassungen sich denselben
126 Lernstand teilen.
127 */
128 const umgelenkt = [
129 join(PAKETABLAGE, 'LocalCache', 'Roaming', 'Waffensachkunde Lernsoftware', 'lernstand.db'),
130 join(PAKETABLAGE, 'RoamingState', 'Waffensachkunde Lernsoftware', 'lernstand.db'),
131 join(PAKETABLAGE, 'LocalState', 'Waffensachkunde Lernsoftware', 'lernstand.db'),
132 ];
133 const gefunden = umgelenkt.filter((pfad) => existsSync(pfad));
134 expect(
135 gefunden,
136 'In der Paketablage liegt ein Lernstand. Windows lenkt den ' +
137 'Anwendungsdatenordner jetzt also doch um. Das ist kein Fehler dieser ' +
138 'Anwendung, aber docs/datenschutz.md 4.6 und 7.4 behaupten dann das ' +
139 'Gegenteil und sind vor der nächsten Veröffentlichung nachzuführen.',
140 ).toEqual([]);
141 });
142 });