iobroker.eos-admin 7.9.98 → 7.9.99

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (52) hide show
  1. package/INSTALL_TEST_V7.9.99.md +11 -0
  2. package/MERGE_UPDATE_README_V7.9.99.md +5 -0
  3. package/NEXOWATT_EOS_BUILD_INFO.json +21 -20
  4. package/PUBLISH_STABLE_V7.9.99.md +15 -0
  5. package/README.md +6 -16
  6. package/README_STABILITY_V7.9.99.md +18 -0
  7. package/RELEASE_ACCEPTANCE_V7.9.99.md +11 -0
  8. package/RELEASE_NOTES_V7.9.99.md +9 -0
  9. package/adminWww/assets/Intro-DkwRiz1n-v84.js +2 -2
  10. package/adminWww/assets/bootstrap-COulQZax-v84.js +2 -2
  11. package/adminWww/css/eos-ems-overview.css +3 -5
  12. package/adminWww/css/nexowatt-native-shell.css +26 -112
  13. package/adminWww/index.html +19 -18
  14. package/adminWww/js/eos-account-management.js +19 -28
  15. package/adminWww/js/eos-assistant.js +1 -1
  16. package/adminWww/js/eos-ems-overview.js +2 -3
  17. package/adminWww/js/eos-release-watch.js +77 -0
  18. package/adminWww/js/eos-role-bootstrap.js +11 -8
  19. package/adminWww/js/eos-role-ui.js +2 -2
  20. package/adminWww/js/nexowatt-native-shell.js +1 -1
  21. package/adminWww/static/js/nexowatt-stable-login.js +3 -3
  22. package/adminWww/static/js/{nexowatt-stable-v98.js → nexowatt-stable-v99.js} +2 -2
  23. package/build/lib/eosPassword.js +62 -0
  24. package/build/lib/eosRequestSecurity.js +31 -0
  25. package/build/lib/web.js +149 -154
  26. package/build/main.js +2 -1
  27. package/io-package.json +5 -10
  28. package/package.json +17 -13
  29. package/tools/nexowatt-account-management-selftest.cjs +19 -15
  30. package/tools/nexowatt-apply-ems-overview.cjs +2 -4
  31. package/tools/nexowatt-cache-update-selftest.cjs +11 -0
  32. package/tools/nexowatt-clean-legacy-runtime.cjs +1 -1
  33. package/tools/nexowatt-ems-overview-selftest.cjs +1 -1
  34. package/tools/nexowatt-login-layout-selftest.cjs +11 -11
  35. package/tools/nexowatt-merge-update-selftest.cjs +1 -1
  36. package/tools/nexowatt-modern-ui-selftest.cjs +2 -2
  37. package/tools/nexowatt-password-write-selftest.cjs +42 -44
  38. package/tools/nexowatt-request-security-selftest.cjs +11 -0
  39. package/tools/nexowatt-runtime-cleanup-selftest.cjs +6 -6
  40. package/tools/nexowatt-stable-v99-selftest.cjs +25 -0
  41. package/tools/nexowatt-sync-release-version.cjs +1 -42
  42. package/tools/nexowatt-ui-overview-runtime-selftest.cjs +3 -1
  43. package/tools/nexowatt-validate-package.cjs +23 -23
  44. package/tools/nexowatt-version-sync-selftest.cjs +1 -18
  45. package/INSTALL_TEST_V7.9.98.md +0 -39
  46. package/MERGE_UPDATE_README_V7.9.98.md +0 -29
  47. package/PUBLISH_STABLE_V7.9.98.md +0 -33
  48. package/README_STABILITY_V7.9.98.md +0 -22
  49. package/RELEASE_ACCEPTANCE_V7.9.98.md +0 -48
  50. package/RELEASE_NOTES_V7.9.98.md +0 -32
  51. package/tools/nexowatt-account-password-flow-selftest.cjs +0 -186
  52. package/tools/nexowatt-stable-v98-selftest.cjs +0 -14
@@ -41,23 +41,20 @@ if (pkg.scripts['test:eos-version-sync'] !== 'node tools/nexowatt-version-sync-s
41
41
  if (pkg.scripts['verify:eos-merge'] !== 'node tools/nexowatt-merge-update-selftest.cjs') fail('merge update selftest script is missing or incorrect');
42
42
  if (!pkg.scripts['check:eos-stability']?.includes('nexowatt-version-sync-selftest.cjs')) fail('version sync selftest is not part of check:eos-stability');
43
43
  if (!pkg.scripts['check:eos-stability']?.includes('nexowatt-merge-update-selftest.cjs')) fail('merge update selftest is not part of check:eos-stability');
44
- if (pkg.scripts['check:eos-stable-v98'] !== 'node tools/nexowatt-stable-v98-selftest.cjs') fail('stable v98 selftest script is missing or incorrect');
44
+ if (pkg.scripts['check:eos-stable-v99'] !== 'node tools/nexowatt-stable-v99-selftest.cjs') fail('stable v99 selftest script is missing or incorrect');
45
+ if (pkg.scripts['test:eos-password-write'] !== 'node tools/nexowatt-password-write-selftest.cjs') fail('password write selftest script is missing');
46
+ if (pkg.scripts['test:eos-request-security'] !== 'node tools/nexowatt-request-security-selftest.cjs') fail('request security selftest script is missing');
47
+ if (pkg.scripts['test:eos-cache-update'] !== 'node tools/nexowatt-cache-update-selftest.cjs') fail('cache update selftest script is missing');
48
+ for (const marker of ['nexowatt-password-write-selftest.cjs','nexowatt-request-security-selftest.cjs','nexowatt-cache-update-selftest.cjs']) if (!pkg.scripts['check:eos-stability']?.includes(marker)) fail(`stability check must execute ${marker}`);
45
49
  if (!pkg.scripts.prepublishOnly?.startsWith('npm run sync:eos-version && npm run prepare:eos-release-defaults && npm run check:eos-publish-channel')) fail('prepublishOnly must synchronize versions and normalize release defaults before the publish channel guard');
46
50
  if (pkg.scripts['precheck:eos-package'] !== 'npm run sync:eos-version && npm run prepare:eos-release-defaults && npm run clean:eos-runtime') fail('precheck:eos-package must synchronize versions, normalize release defaults and clean stale runtime files');
47
51
  if (pkg.scripts['precheck:eos-stability'] !== 'npm run sync:eos-version && npm run prepare:eos-release-defaults && npm run clean:eos-runtime') fail('precheck:eos-stability must synchronize versions, normalize release defaults and clean stale runtime files');
48
52
  if (pkg.scripts['test:eos-publish-channel'] !== 'node tools/nexowatt-publish-channel-selftest.cjs') fail('publish channel selftest script is missing');
49
53
  if (!pkg.scripts['check:eos-stability']?.includes('nexowatt-publish-channel-selftest.cjs')) fail('stability check must execute the publish channel selftest');
50
54
  if (!pkg.scripts['check:eos-stability']?.includes('nexowatt-release-defaults-selftest.cjs')) fail('stability check must execute the release-default selftest');
51
- if (!pkg.scripts['check:eos-stability']?.includes('nexowatt-password-write-selftest.cjs')) fail('password-write selftest is not part of check:eos-stability');
52
- if (!pkg.scripts['check:eos-stability']?.includes('nexowatt-account-password-flow-selftest.cjs')) fail('account-password flow selftest is not part of check:eos-stability');
53
55
  if (io.native?.auth !== true) fail('fresh sales installations must default to authenticated access');
54
56
  if (io.native?.eosHideLegacyBackupFromNonAdmins !== true) fail('internal BackItUp reserve must default to Admin/Service visibility');
55
57
  if (io.native?.nexowattHideLegacyBackupFromNonAdmins !== true) fail('NexoWatt backup visibility compatibility flag must default to true');
56
- for (const key of ['description', 'files', 'scripts', 'nexowattReleasePolicy']) {
57
- if (JSON.stringify(pkgLock.packages?.['']?.[key]) !== JSON.stringify(pkg[key])) {
58
- fail(`package-lock root ${key} must match package.json`);
59
- }
60
- }
61
58
  for (const [label, value] of [
62
59
  ['io-package common.version', io.common?.version],
63
60
  ['io-package top-level version', io.version],
@@ -107,6 +104,7 @@ for (const file of [
107
104
  'adminWww/js/eos-basic-settings.js',
108
105
  'adminWww/js/eos-role-ui.js',
109
106
  'adminWww/js/eos-account-management.js',
107
+ 'adminWww/js/eos-release-watch.js',
110
108
  'adminWww/js/eos-assistant.js',
111
109
  'adminWww/css/nexowatt-native-shell.css',
112
110
  'adminWww/img/eos/nexowatt-192.png',
@@ -117,14 +115,14 @@ for (const file of [
117
115
  'LICENSE',
118
116
  'NEXOWATT_PROPRIETARY_LICENSE.md',
119
117
  'THIRD_PARTY_NOTICES.md',
120
- 'README_STABILITY_V7.9.98.md',
121
- 'RELEASE_NOTES_V7.9.98.md',
122
- 'PUBLISH_STABLE_V7.9.98.md',
123
- 'INSTALL_TEST_V7.9.98.md',
124
- 'RELEASE_ACCEPTANCE_V7.9.98.md',
118
+ 'README_STABILITY_V7.9.99.md',
119
+ 'RELEASE_NOTES_V7.9.99.md',
120
+ 'PUBLISH_STABLE_V7.9.99.md',
121
+ 'INSTALL_TEST_V7.9.99.md',
122
+ 'RELEASE_ACCEPTANCE_V7.9.99.md',
125
123
  'MERGE_UPDATE.ps1',
126
124
  'MERGE_UPDATE.cmd',
127
- 'MERGE_UPDATE_README_V7.9.98.md',
125
+ 'MERGE_UPDATE_README_V7.9.99.md',
128
126
  'tools/nexowatt-patch-built-frontend.cjs',
129
127
  'tools/nexowatt-native-shell-selftest.cjs',
130
128
  'tools/nexowatt-clean-legacy-runtime.cjs',
@@ -135,6 +133,9 @@ for (const file of [
135
133
  'tools/nexowatt-role-access-selftest.cjs',
136
134
  'tools/nexowatt-first-login-selftest.cjs',
137
135
  'tools/nexowatt-account-management-selftest.cjs',
136
+ 'tools/nexowatt-password-write-selftest.cjs',
137
+ 'tools/nexowatt-request-security-selftest.cjs',
138
+ 'tools/nexowatt-cache-update-selftest.cjs',
138
139
  'tools/nexowatt-modern-ui-selftest.cjs',
139
140
  'tools/nexowatt-login-layout-selftest.cjs',
140
141
  'tools/nexowatt-internal-reserve-selftest.cjs',
@@ -142,14 +143,12 @@ for (const file of [
142
143
  'tools/nexowatt-sync-release-version.cjs',
143
144
  'tools/nexowatt-version-sync-selftest.cjs',
144
145
  'tools/nexowatt-merge-update-selftest.cjs',
145
- 'tools/nexowatt-stable-v98-selftest.cjs',
146
- 'tools/nexowatt-password-write-selftest.cjs',
147
- 'tools/nexowatt-account-password-flow-selftest.cjs',
146
+ 'tools/nexowatt-stable-v99-selftest.cjs',
148
147
  'tools/nexowatt-ems-overview-selftest.cjs',
149
148
  'tools/nexowatt-ui-overview-runtime-selftest.cjs',
150
149
  'adminWww/js/eos-ems-overview.js',
151
150
  'adminWww/css/eos-ems-overview.css',
152
- 'adminWww/static/js/nexowatt-stable-v98.js',
151
+ 'adminWww/static/js/nexowatt-stable-v99.js',
153
152
  'src-admin/src/components/Intro/NexoWattEmsOverview.tsx',
154
153
  'tools/nexowatt-publish-channel-guard.cjs',
155
154
  'tools/nexowatt-publish-channel-selftest.cjs',
@@ -177,8 +176,8 @@ const shellTag = String(buildInfo.shellCacheTag || shellCache);
177
176
  if (!runtime || !Number.isFinite(runtimeNumber)) fail(`invalid runtimeEntry ${runtime}`);
178
177
  if (!Number.isFinite(shellCache)) fail(`invalid shellCacheVersion ${buildInfo.shellCacheVersion}`);
179
178
  for (const marker of [
180
- `hostInit-${runtime}.js?v=${runtimeNumber}`,
181
- `index-CQZugZ1z-${runtime}.js?v=${runtimeNumber}`,
179
+ `hostInit-${runtime}.js?v=${shellTag}`,
180
+ `index-CQZugZ1z-${runtime}.js?v=${shellTag}`,
182
181
  `eos-manual-write-policy.js?v=${shellTag}`,
183
182
  `nexowatt-native-shell.css?v=${shellTag}`,
184
183
  `nexowatt-native-shell.js?v=${shellTag}`,
@@ -192,8 +191,9 @@ if (!index.includes(`eos-account-management.js?v=${shellTag}`)) fail('account ma
192
191
  if (!index.includes(`eos-assistant.js?v=${shellTag}`)) fail('EOS Assist cache key mismatch');
193
192
  if (!index.includes(`eos-ems-overview.js?v=${shellTag}`)) fail('EMS overview cache key mismatch');
194
193
  if (!index.includes(`eos-ems-overview.css?v=${shellTag}`)) fail('EMS overview CSS cache key mismatch');
195
- if (!index.includes(`nexowatt-stable-v98.js?v=${shellTag}`)) fail('stable v98 cache key mismatch');
196
- if (index.indexOf(`eos-manual-write-policy.js?v=${shellTag}`) > index.indexOf(`hostInit-${runtime}.js?v=${runtimeNumber}`)) fail('manual-write policy must load before the React runtime');
194
+ if (!index.includes(`nexowatt-stable-v99.js?v=${shellTag}`)) fail('stable v99 cache key mismatch');
195
+ if (!index.includes(`eos-release-watch.js?v=${shellTag}`)) fail('release watcher cache key mismatch');
196
+ if (index.indexOf(`eos-manual-write-policy.js?v=${shellTag}`) > index.indexOf(`hostInit-${runtime}.js?v=${shellTag}`)) fail('manual-write policy must load before the React runtime');
197
197
  if (!index.includes('class="eos-native-shell"')) fail('native NexoWatt shell class missing');
198
198
  for (const legacy of ['eos-branding.js', 'eos-security-ui.js', 'eos-console-quiet.js', 'eos-objects-state-tools.js']) {
199
199
  if (index.includes(legacy)) fail(`legacy browser overlay still loaded: ${legacy}`);
@@ -241,7 +241,7 @@ if (accountManagement.includes("launcher.className = 'eos-account-management-lau
241
241
  if (accountManagement.includes('new MutationObserver')) fail('account-management runtime adds a second broad DOM observer');
242
242
  if (read('src-admin/public/js/eos-account-management.js') !== accountManagement) fail('account-management source/build drift');
243
243
  const roleBootstrap = read('adminWww/js/eos-role-bootstrap.js');
244
- if (!roleBootstrap.includes('installIntegratedFirstLogin') || !roleBootstrap.includes('v98 compact normal-login first activation')) fail('compact integrated first-login is incomplete');
244
+ if (!roleBootstrap.includes('installIntegratedFirstLogin') || !roleBootstrap.includes('v99 normal-login first activation')) fail('compact integrated first-login is incomplete');
245
245
  if (/data-eos-account=|selector\.innerHTML/.test(roleBootstrap)) fail('login role buttons must not enlarge the normal login card');
246
246
  if (!roleBootstrap.includes('nexowatt/account/passwordless-status') || !roleBootstrap.includes('eligibility.allowed')) fail('server-checked first-login eligibility is incomplete');
247
247
  if (roleBootstrap.includes('installPasswordlessFirstLoginLauncher')) fail('old first-login launcher remains active');
@@ -24,19 +24,7 @@ try {
24
24
  const currentPkg = JSON.parse(fs.readFileSync(path.join(root, 'package.json'), 'utf8'));
25
25
  const version = currentPkg.version;
26
26
  writeJson('package.json', currentPkg);
27
- writeJson('package-lock.json', {
28
- name: currentPkg.name,
29
- version: '7.9.92',
30
- packages: {
31
- '': {
32
- version: '7.9.92',
33
- description: 'stale description',
34
- files: ['README_STABILITY_V7.9.92.md'],
35
- scripts: { 'check:eos-stable-v92': 'node stale.js' },
36
- nexowattReleasePolicy: { distTag: 'latest', purpose: 'stale 7.9.92 policy' },
37
- },
38
- },
39
- });
27
+ writeJson('package-lock.json', { name: currentPkg.name, version: '7.9.92', packages: { '': { version: '7.9.92' } } });
40
28
  writeJson('io-package.json', {
41
29
  version: '7.9.92',
42
30
  common: {
@@ -87,11 +75,6 @@ try {
87
75
  ]) {
88
76
  if (actual !== version) fail(`${label} was not synchronized: ${actual}`);
89
77
  }
90
- for (const key of ['description', 'files', 'scripts', 'nexowattReleasePolicy']) {
91
- if (JSON.stringify(lock.packages[''][key]) !== JSON.stringify(currentPkg[key])) {
92
- fail(`package-lock root ${key} was not synchronized`);
93
- }
94
- }
95
78
  if (io.common.meta !== `${expectedBase}/io-package.json`) fail('io-package URL was not synchronized');
96
79
  if (entry.meta !== `${expectedBase}/io-package.json`) fail('repository entry URL was not synchronized');
97
80
  if (!fs.existsSync(path.join(temp, build.repositoryEntry))) fail('current repository entry was not created');
@@ -1,39 +0,0 @@
1
- # Installationstest – NexoWatt EOS Admin 7.9.98
2
-
3
- ## Installation nach der npm-Veröffentlichung
4
-
5
- ```bash
6
- cd /opt/iobroker
7
- iobroker stop eos-admin.0
8
- npm install --no-save --omit=dev iobroker.eos-admin@7.9.98
9
- iobroker upload eos-admin
10
- iobroker restart eos-admin.0
11
- iobroker restart nexowatt-ui.0
12
- ```
13
-
14
- Version prüfen:
15
-
16
- ```bash
17
- node -p "require('/opt/iobroker/node_modules/iobroker.eos-admin/package.json').version"
18
- ```
19
-
20
- Erwartet:
21
-
22
- ```text
23
- 7.9.98
24
- ```
25
-
26
- Danach im Browser eine vollständige Aktualisierung mit `Strg + F5` durchführen.
27
-
28
- ## Installation des geprüften TGZ ohne Registry
29
-
30
- ```bash
31
- cd /opt/iobroker
32
- iobroker stop eos-admin.0
33
- npm install --no-save --omit=dev /PFAD/iobroker.eos-admin-7.9.98.tgz
34
- iobroker upload eos-admin
35
- iobroker restart eos-admin.0
36
- iobroker restart nexowatt-ui.0
37
- ```
38
-
39
- Anschließend die vollständige Abnahme aus `RELEASE_ACCEPTANCE_V7.9.98.md` durchführen.
@@ -1,29 +0,0 @@
1
- # NexoWatt EOS Admin 7.9.98 – Merge-Update
2
-
3
- Die Datei `NexoWatt_EOS_Admin_7.9.98_STABLE_MERGE_FLAT.zip` ist absichtlich flach aufgebaut. `package.json`, `io-package.json`, `src-admin`, `adminWww`, `build` und alle übrigen Repository-Dateien liegen direkt auf der ersten ZIP-Ebene.
4
-
5
- ## Anwendung auf einem vorhandenen Windows-Arbeitsordner
6
-
7
- 1. Den bestehenden Repository-Ordner sichern oder committen.
8
- 2. Die flache Merge-ZIP direkt in den vorhandenen Ordner entpacken.
9
- 3. Bei der Windows-Abfrage **„Dateien im Ziel ersetzen“** wählen.
10
- 4. Anschließend im Repository ausführen:
11
-
12
- ```powershell
13
- .\MERGE_UPDATE.cmd
14
- ```
15
-
16
- Alternativ:
17
-
18
- ```powershell
19
- .\MERGE_UPDATE.ps1
20
- ```
21
-
22
- Das Merge-Skript:
23
-
24
- - synchronisiert alle Release-Versionen auf `7.9.98`;
25
- - entfernt alte Stable-Laufzeitdateien wie v97;
26
- - prüft Paketstruktur, Stabilität, Rollen, Login, Passwortablauf und EMS-Übersicht;
27
- - führt abschließend einen npm-Pack-Dry-Run aus.
28
-
29
- Erst nach der grünen Abschlussmeldung veröffentlichen. `.git`, lokale Commit-Historie und `node_modules` werden vom Merge-Skript nicht gelöscht.
@@ -1,33 +0,0 @@
1
- # NexoWatt EOS Admin 7.9.98 veröffentlichen
2
-
3
- ## Empfohlener Weg: geprüftes TGZ veröffentlichen
4
-
5
- Dadurch können keine alten oder lokal zusätzlich vorhandenen Dateien in das npm-Paket gelangen.
6
-
7
- ```powershell
8
- npm login
9
- npm whoami
10
- npm publish .\iobroker.eos-admin-7.9.98.tgz --dry-run --tag latest
11
- npm publish .\iobroker.eos-admin-7.9.98.tgz --tag latest
12
- ```
13
-
14
- Der Dry-Run muss mit folgendem Paket enden:
15
-
16
- ```text
17
- + iobroker.eos-admin@7.9.98
18
- ```
19
-
20
- ## Veröffentlichung direkt aus dem Repository
21
-
22
- Nur aus einem sauberen Arbeitsordner ausführen:
23
-
24
- ```powershell
25
- npm login
26
- npm whoami
27
- npm run sync:eos-version
28
- npm run check:eos-release
29
- npm publish --dry-run --tag latest
30
- npm publish --tag latest
31
- ```
32
-
33
- Bei einem Fehler nicht veröffentlichen. Insbesondere müssen `package.json`, `package-lock.json`, `io-package.json`, `src-admin/package.json` und `src-admin/src/version.json` dieselbe Version enthalten.
@@ -1,22 +0,0 @@
1
- # NexoWatt EOS Admin 7.9.98 – Stable-Verkaufskandidat
2
-
3
- Version 7.9.98 beseitigt die vier zuletzt auf dem realen EOS-Testsystem festgestellten Verkaufsblocker, ohne die funktionierende EMS-Live-Diagnose oder die bestehenden Rollenrechte zu erweitern.
4
-
5
- ## Korrigierte Bereiche
6
-
7
- - **Cockpit vollständig bedienbar:** Der Kopf- und Navigationsbereich bleibt stehen; ausschließlich der Inhaltsbereich der Übersicht erhält einen vertikalen Scrollbereich. Dadurch sind auch lange EMS-Ereignislisten und die unteren Adapterkarten erreichbar.
8
- - **Saubere Anmeldung:** Loginname und Passwort verwenden feste Platzhalter statt kollidierender Floating Labels. Die Karte ist moderat größer, wächst bei Fehlermeldungen automatisch und besitzt keine innere horizontale oder vertikale Scrollleiste.
9
- - **Reales Kontopasswort beim Reset:** Ein zulässiger Reset schreibt das Startpasswort `nexowatt` mit der ioBroker-Passwortschnittstelle in das tatsächliche Benutzerkonto. Die EOS-Erstanmeldungsmerkmale werden getrennt davon aktualisiert, damit der neue Passwort-Hash nicht wieder überschrieben wird.
10
- - **Persönliches Passwort nach der ersten Anmeldung:** Das neue Kennwort wird serverseitig validiert, in das reale Benutzerkonto geschrieben, anschließend geprüft und erst danach wird der Erstanmeldungsstatus beendet.
11
- - **Saubere Rollenbegrenzung:** Admin/Service darf verwaltete Installateur- und Endkundenkonten zurücksetzen. Installateure dürfen ausschließlich ausdrücklich zugeordnete Endkundenkonten zurücksetzen. Admin-, Eigen-, deaktivierte und nicht verwaltete Konten bleiben geschützt.
12
-
13
- ## Unveränderte Produktregeln
14
-
15
- - Die EMS-Live-Kachel ist ausschließlich lesend und verändert keine Regelung, Geräte- oder Sollwerte.
16
- - Der NexoWatt UI Adapter stellt die Diagnosewerte weiterhin unter `nexowatt-ui.*.info.adminOverview.*` bereit.
17
- - EOS Assist bleibt bis zur vollständigen Neuimplementierung deaktiviert.
18
- - Standardport des EOS Admin bleibt `8081`.
19
-
20
- ## Freigabestatus
21
-
22
- Alle paketinternen Prüfungen, die isolierte Browser-Geometrieprüfung, der simulierte Passwortablauf und der npm-Publish-Dry-Run müssen erfolgreich sein. Vor dem Verkauf ist zusätzlich die Checkliste in `RELEASE_ACCEPTANCE_V7.9.98.md` einmal auf einem realen EOS-Testcontroller abzuarbeiten.
@@ -1,48 +0,0 @@
1
- # Release-Abnahme – NexoWatt EOS Admin 7.9.98
2
-
3
- Diese Checkliste ist vor der Verkaufsfreigabe einmal vollständig auf einem realen EOS-Testcontroller abzuarbeiten.
4
-
5
- ## Installation und Versionsstand
6
-
7
- - [ ] `iobroker.eos-admin` zeigt Version `7.9.98`.
8
- - [ ] `eos-admin.0` startet ohne Fehler und ist auf Port `8081` erreichbar.
9
- - [ ] Nach `Strg + F5` werden ausschließlich die v98-Laufzeitdateien geladen.
10
- - [ ] Ein kompletter Neustart des EOS-Controllers führt wieder zu einer erreichbaren Oberfläche.
11
-
12
- ## Anmeldung
13
-
14
- - [ ] Loginname und Passwort überlappen weder Rahmen noch Beschriftungen.
15
- - [ ] Die Anmeldekarte besitzt keine innere horizontale oder vertikale Scrollleiste.
16
- - [ ] Eine absichtlich falsche Anmeldung zeigt die vollständige Fehlermeldung innerhalb der Karte.
17
- - [ ] Die Karte bleibt bei 1920 × 1080 und 1366 × 768 vollständig bedienbar.
18
-
19
- ## Übersicht und EMS
20
-
21
- - [ ] Header und Navigation bleiben stehen.
22
- - [ ] Der Cockpit-Inhalt lässt sich bis zur letzten Karte vertikal scrollen.
23
- - [ ] EMS-Budget, Ladeleistung, Speicher, Regelentscheidungen und Ereignisse werden angezeigt.
24
- - [ ] Die Kachel aktualisiert sich mit realen Werten aus `nexowatt-ui.*.info.adminOverview.*`.
25
- - [ ] Die EMS-Kachel besitzt keine Schreibfunktion und verändert keine Sollwerte.
26
-
27
- ## Rollen und Passwort-Reset
28
-
29
- - [ ] Admin/Service kann `guest`, `user` und `installer` zurücksetzen, sofern diese Konten ausdrücklich einer verwalteten EOS-Rolle zugeordnet sind.
30
- - [ ] Installateur kann ausschließlich ausdrücklich zugeordnete Endkundenkonten zurücksetzen.
31
- - [ ] Admin-Konto, eigenes Konto, deaktivierte und nicht verwaltete Konten werden abgewiesen.
32
- - [ ] Nach dem Reset funktioniert die Anmeldung mit dem Startpasswort `nexowatt`.
33
- - [ ] Das bisherige persönliche Kennwort ist nach dem Reset nicht mehr gültig.
34
-
35
- ## Persönliches Passwort
36
-
37
- - [ ] Die Anmeldung mit `nexowatt` öffnet unmittelbar die Seite „Persönliches Passwort festlegen“.
38
- - [ ] Zu kurze, nicht übereinstimmende oder zu einfache Kennwörter werden verständlich abgewiesen.
39
- - [ ] Ein gültiges neues Kennwort wird gespeichert.
40
- - [ ] Nach erfolgreichem Speichern wird die alte Sitzung beendet.
41
- - [ ] Die erneute Anmeldung funktioniert ausschließlich mit dem neu vergebenen Kennwort.
42
- - [ ] Im nativen Benutzereditor ist weiterhin ein Passwort-Hash für das richtige Benutzerkonto vorhanden.
43
-
44
- ## Abschluss
45
-
46
- - [ ] EOS Assist bleibt ausgeblendet.
47
- - [ ] Sicherung, Dienste, Module, Datenpunkte und Systemlogs bleiben erreichbar.
48
- - [ ] Es treten während der Abnahme keine neuen Fehler im EOS-Admin-Log auf.
@@ -1,32 +0,0 @@
1
- # Release Notes – NexoWatt EOS Admin 7.9.98
2
-
3
- ## Übersicht und Bedienung
4
-
5
- - Der Cockpit-Inhalt kann jetzt bis zum letzten Element vertikal gescrollt werden.
6
- - Header und Hauptnavigation bleiben währenddessen stehen.
7
- - Die EMS-Live-Diagnose, aktuelle Regelentscheidungen, Ereignisse und nachfolgende Adapterkarten werden nicht mehr am unteren Fensterrand abgeschnitten.
8
-
9
- ## Anmeldung
10
-
11
- - Überlappende MUI-Feldbeschriftungen wurden entfernt.
12
- - Loginname und Passwort verwenden klar erkennbare Platzhalter.
13
- - Die Anmeldekarte wurde nur moderat vergrößert und wächst bei einer Fehlermeldung automatisch.
14
- - Innere horizontale und vertikale Scrollleisten bleiben ausgeschlossen.
15
-
16
- ## Konten und Kennwörter
17
-
18
- - Ein Kontoreset schreibt das reale ioBroker-Kontopasswort auf `nexowatt`.
19
- - Der Passwortschreibvorgang wird mit der Controller-Passwortprüfung verifiziert, bevor Erfolg gemeldet wird.
20
- - Die EOS-Erstanmeldungsmerkmale werden ausschließlich als Metadaten erweitert; der zuvor geschriebene Passwort-Hash wird nicht durch ein altes Benutzerobjekt überschrieben.
21
- - Admin/Service darf verwaltete Installateur- und Endkundenkonten zurücksetzen.
22
- - Installateure dürfen ausschließlich ausdrücklich zugeordnete Endkundenkonten zurücksetzen.
23
- - Admin-, Eigen-, deaktivierte und nicht verwaltete Konten werden weiterhin abgewiesen.
24
- - Die persönliche Passwortvergabe nach der Anmeldung mit `nexowatt` schreibt und prüft ebenfalls das reale Benutzerkennwort.
25
- - Nach erfolgreicher Passwortvergabe werden vorhandene Anmeldesitzungen beendet und der Erstanmeldungsstatus entfernt.
26
-
27
- ## Stabilität und Aktualisierung
28
-
29
- - Paket-, Lockfile-, io-package-, Frontend- und Repository-Versionen werden vor der Veröffentlichung auf `7.9.98` synchronisiert.
30
- - Alte Stable-Laufzeitdateien wie v97 werden beim Merge-Update automatisch entfernt.
31
- - Die EMS-Live-Diagnose bleibt read-only.
32
- - EOS Assist bleibt deaktiviert.
@@ -1,186 +0,0 @@
1
- #!/usr/bin/env node
2
- 'use strict';
3
-
4
- const assert = require('node:assert/strict');
5
- const fs = require('node:fs');
6
- const path = require('node:path');
7
- const vm = require('node:vm');
8
-
9
- const root = path.resolve(__dirname, '..');
10
- const built = fs.readFileSync(path.join(root, 'build/lib/web.js'), 'utf8');
11
- const accountUi = fs.readFileSync(path.join(root, 'adminWww/js/eos-account-management.js'), 'utf8');
12
- const firstLoginUi = fs.readFileSync(path.join(root, 'adminWww/js/eos-role-bootstrap.js'), 'utf8');
13
-
14
- function methodSlice(startMarker, endMarker) {
15
- const start = built.indexOf(startMarker);
16
- const end = built.indexOf(endMarker, start + startMarker.length);
17
- assert(start >= 0 && end > start, `method block not found: ${startMarker}`);
18
- return built.slice(start, end);
19
- }
20
-
21
- const methods = [
22
- methodSlice(' normalizeEosUserId(value) {', ' normalizeEosAdapterName(value) {'),
23
- methodSlice(' async readEosCurrentUser(req) {', ' getEosConfiguredRoleGroups(...keys) {'),
24
- methodSlice(' async getEosRequestAccess(req) {', ' getEosRoleCapabilities(role) {'),
25
- methodSlice(' validateEosFirstLoginPassword(password, passwordRepeat, userId) {', ' getEosPasswordUserName(userId) {'),
26
- methodSlice(' getEosPasswordUserName(userId) {', ' async destroyEosRequestSessions(req) {'),
27
- methodSlice(' async saveEosFirstLoginPassword(req, res) {', ' isEosPasswordlessFirstLoginEnabled() {'),
28
- methodSlice(' async resetEosAccountPassword(req, res) {', ' async getEosHistoryInstances() {'),
29
- methodSlice(' isEosSameOriginWrite(req) {', ' async saveEosBasicSettings(req, res) {'),
30
- ].join('\n');
31
-
32
- const sandbox = { module: { exports: null }, URL, Set, console, EOS_PASSWORD_SERVICE_USER: 'system.user.admin' };
33
- vm.runInNewContext(`module.exports = class Harness {\n${methods}\n}`, sandbox);
34
- const Harness = sandbox.module.exports;
35
-
36
- function responseMock() {
37
- return {
38
- statusCode: 200,
39
- payload: null,
40
- headers: {},
41
- clearedCookies: [],
42
- setHeader(name, value) { this.headers[String(name).toLowerCase()] = value; },
43
- status(code) { this.statusCode = code; return this; },
44
- json(value) { this.payload = value; return this; },
45
- clearCookie(name) { this.clearedCookies.push(name); },
46
- };
47
- }
48
-
49
- function requestMock(body = {}, headers = {}) {
50
- return {
51
- body,
52
- headers: {
53
- host: '192.168.10.124:8081',
54
- origin: 'http://192.168.10.124:8081',
55
- 'sec-fetch-site': 'same-origin',
56
- ...headers,
57
- },
58
- query: {},
59
- socket: { remoteAddress: '192.168.10.50' },
60
- };
61
- }
62
-
63
- async function resetScenario(requesterRole, targetRole, targetGroups) {
64
- const harness = new Harness();
65
- const writes = [];
66
- const metadata = {};
67
- harness.getEosRequestAccess = async () => ({ userId: requesterRole === 'admin' ? 'system.user.admin' : 'system.user.installer', role: requesterRole });
68
- harness.normalizeEosUserId = value => String(value || '').startsWith('system.user.') ? String(value) : `system.user.${value}`;
69
- harness.getEosAccessForUserId = async () => ({ role: targetRole, groups: targetGroups });
70
- harness.getEosInstallerGroups = () => ['system.group.installer', 'system.group.installateur'];
71
- harness.getEosEndUserGroups = () => ['system.group.endkunde', 'system.group.user'];
72
- harness.adapter = {
73
- setPasswordAsync: async (user, password) => writes.push([`system.user.${user}`, password]),
74
- checkPasswordAsync: async (user, password) => [password === 'nexowatt', `system.user.${user}`],
75
- getForeignObjectAsync: async id => ({ _id: id, common: { enabled: true, password: '$hash' }, native: { keep: true, nexowattEosAccount: {} } }),
76
- extendForeignObjectAsync: async (id, patch) => {
77
- metadata.id = id;
78
- metadata.native = patch.native;
79
- },
80
- log: { warn: () => undefined, info: () => undefined },
81
- };
82
- harness.invalidateEosPasswordClaimsForUser = () => undefined;
83
- const res = responseMock();
84
- await harness.resetEosAccountPassword(
85
- requestMock({ user: targetRole === 'installer' ? 'system.user.installer-target' : 'system.user.user' }, { 'x-nexowatt-eos-account-reset': '1' }),
86
- res,
87
- );
88
- return { res, writes, metadata };
89
- }
90
-
91
- (async () => {
92
- // Authenticated request identities are normalized to the real ioBroker user object id.
93
- const accessHarness = new Harness();
94
- accessHarness.getEosAccessForUserId = async userId => ({ userId, role: userId === 'system.user.admin' ? 'admin' : 'enduser' });
95
- const directAdmin = await accessHarness.getEosRequestAccess({ user: 'admin' });
96
- assert.equal(directAdmin.userId, 'system.user.admin');
97
- assert.equal(directAdmin.role, 'admin');
98
- const objectAdmin = await accessHarness.getEosRequestAccess({ user: { id: 'system.user.admin' } });
99
- assert.equal(objectAdmin.userId, 'system.user.admin');
100
- assert.equal(objectAdmin.role, 'admin');
101
-
102
- // Admin/Service can reset an explicitly managed End User and Installer account.
103
- const adminEndUser = await resetScenario('admin', 'enduser', ['system.group.endkunde']);
104
- assert.equal(adminEndUser.res.statusCode, 200);
105
- assert.deepEqual(adminEndUser.writes, [['system.user.user', 'nexowatt']]);
106
- assert.equal(adminEndUser.metadata.native.nexowattEosAccount.forcePasswordChange, true);
107
- assert.equal(adminEndUser.metadata.native.nexowattEosAccount.passwordResetMode, 'initial-password');
108
- assert.equal(adminEndUser.metadata.native.nexowattPasswordChangeRequired, true);
109
-
110
- const adminInstaller = await resetScenario('admin', 'installer', ['system.group.installer']);
111
- assert.equal(adminInstaller.res.statusCode, 200);
112
- assert.deepEqual(adminInstaller.writes, [['system.user.installer-target', 'nexowatt']]);
113
-
114
- // Installer may never reset another installer account.
115
- const installerDenied = await resetScenario('installer', 'installer', ['system.group.installer']);
116
- assert.equal(installerDenied.res.statusCode, 403);
117
- assert.equal(installerDenied.res.payload.error, 'permissionError');
118
- assert.equal(installerDenied.writes.length, 0);
119
-
120
- // First-login password save must write the real account and clear every force-change flag.
121
- const harness = new Harness();
122
- const passwordWrites = [];
123
- let metadata;
124
- let sessionsDestroyed = false;
125
- harness.getEosRequestAccess = async () => ({ userId: 'system.user.user', role: 'enduser' });
126
- harness.getEosFirstLoginPasswordState = async () => ({ required: true, initialized: false, minLength: 10, version: 1 });
127
- harness.getEosFirstLoginPasswordMinLength = () => 10;
128
- harness.destroyEosRequestSessions = async () => { sessionsDestroyed = true; };
129
- harness.adapter = {
130
- setPasswordAsync: async (user, password) => passwordWrites.push([`system.user.${user}`, password]),
131
- checkPasswordAsync: async (user, password) => [password === 'NexoWatt2025!', `system.user.${user}`],
132
- getForeignObjectAsync: async id => ({ _id: id, common: { enabled: true, password: '$hash' }, native: { nexowattEosAccount: {} } }),
133
- extendForeignObjectAsync: async (id, patch) => { metadata = { id, native: patch.native }; },
134
- log: { info: () => undefined },
135
- };
136
- const acceptedPassword = harness.validateEosFirstLoginPassword(
137
- 'NexoWatt2025!',
138
- 'NexoWatt2025!',
139
- 'system.user.user',
140
- );
141
- assert.equal(acceptedPassword.valid, true);
142
- assert.equal(acceptedPassword.password, 'NexoWatt2025!');
143
- const saveRes = responseMock();
144
- await harness.saveEosFirstLoginPassword(
145
- requestMock(
146
- { password: 'NexoWatt2025!', passwordRepeat: 'NexoWatt2025!' },
147
- { 'x-nexowatt-eos-first-login': '1' },
148
- ),
149
- saveRes,
150
- );
151
- assert.equal(saveRes.statusCode, 200);
152
- assert.equal(saveRes.payload.success, true);
153
- assert.equal(saveRes.payload.logoutRequired, true);
154
- assert.deepEqual(passwordWrites, [['system.user.user', 'NexoWatt2025!']]);
155
- assert.equal(metadata.native.nexowattEosAccount.passwordInitialized, true);
156
- assert.equal(metadata.native.nexowattEosAccount.forcePasswordChange, false);
157
- assert.equal(metadata.native.nexowattPasswordChangeRequired, false);
158
- assert.equal(metadata.native.eosFirstLoginRequired, false);
159
- assert.equal(sessionsDestroyed, true);
160
- assert.deepEqual(saveRes.clearedCookies.sort(), ['access_token', 'connect.sid', 'refresh_token'].sort());
161
-
162
- // Same-origin logic must support direct access and a reverse proxy without accepting cross-site writes.
163
- const originHarness = new Harness();
164
- assert.equal(originHarness.isEosSameOriginWrite(requestMock()), true);
165
- assert.equal(originHarness.isEosSameOriginWrite(requestMock({}, {
166
- host: '127.0.0.1:8081',
167
- origin: 'https://eos.example.test',
168
- 'x-forwarded-host': 'eos.example.test',
169
- 'sec-fetch-site': 'same-origin',
170
- })), true);
171
- assert.equal(originHarness.isEosSameOriginWrite(requestMock({}, {
172
- origin: 'https://attacker.example',
173
- 'sec-fetch-site': 'cross-site',
174
- })), false);
175
-
176
- // Browser writes must preserve the authenticated session cookie.
177
- assert.match(accountUi, /nexowatt\/account\/reset/);
178
- assert.match(accountUi, /method:\s*'POST',\s*credentials:\s*'include'/);
179
- assert.match(firstLoginUi, /nexowatt\/account\/first-password/);
180
- assert.match(firstLoginUi, /method:\s*'POST',\s*credentials:\s*'include'/);
181
-
182
- console.log('[NexoWatt EOS account password flow] OK: Admin/Installer permissions, initial password reset, personal password save, session and origin checks verified.');
183
- })().catch(error => {
184
- console.error(error && error.stack ? error.stack : error);
185
- process.exit(1);
186
- });
@@ -1,14 +0,0 @@
1
- #!/usr/bin/env node
2
- 'use strict';
3
- const fs=require('node:fs');const path=require('node:path');const root=path.resolve(__dirname,'..');const read=rel=>fs.readFileSync(path.join(root,rel),'utf8');const must=(ok,msg)=>{if(!ok){console.error(`[NexoWatt EOS stable v98] ${msg}`);process.exit(1)}};
4
- const pkg=JSON.parse(read('package.json')),io=JSON.parse(read('io-package.json')),info=JSON.parse(read('NEXOWATT_EOS_BUILD_INFO.json')),css=read('adminWww/css/nexowatt-native-shell.css'),stable=read('adminWww/static/js/nexowatt-stable-v98.js'),login=read('adminWww/static/js/nexowatt-stable-login.js'),index=read('adminWww/index.html'),web=read('src/lib/web.ts'),built=read('build/lib/web.js'),account=read('adminWww/js/eos-account-management.js'),bootstrap=read('adminWww/assets/bootstrap-COulQZax-v84.js'),ems=read('adminWww/js/eos-ems-overview.js');
5
- must(pkg.version==='7.9.98'&&io.version==='7.9.98'&&io.common.version==='7.9.98'&&info.version==='7.9.98','version drift');
6
- must(info.shellCacheVersion===98&&info.shellCacheTag==='98','shell cache not v98');
7
- must(css.includes('overflow-y: auto !important')&&css.includes('scrollbar-color: rgba(0, 229, 138'),'cockpit vertical scrollbar missing');
8
- must(css.includes('.MuiInputLabel-root { display: none !important; }')&&bootstrap.includes('I18n.t("enterLogin")+" *"'),'clean login field contract missing');
9
- must(stable.includes("VERSION = 'v98-scroll-login-password-write'")&&!login.includes('data-nw-login-card'),'stable runtime incorrect');
10
- must(index.includes('nexowatt-stable-v98.js?v=98')&&index.includes('nexowatt-native-shell.css?v=98'),'v98 assets not loaded');
11
- for(const code of [web,built])for(const marker of ['getEosPasswordUserName','setPasswordAsync(userName, password','checkPasswordAsync(userName, password','passwordVerificationFailed','updateEosAccountMetadata','extendForeignObjectAsync'])must(code.includes(marker),`password marker missing: ${marker}`);
12
- must(account.includes('Startpasswort „nexowatt“')&&account.includes('credentials: \'include\''),'reset UI does not describe/use stable initial password flow');
13
- must(ems.includes("REQUIRED_UI_VERSION = '0.8.198'")&&ems.includes('readUiAdapterInfo'),'working EMS diagnosis was lost');
14
- console.log('[NexoWatt EOS stable v98] OK');