iobroker.eos-admin 7.9.92 → 7.9.95

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 (33) hide show
  1. package/{INSTALL_TEST_V7.9.92.md → INSTALL_TEST_V7.9.95.md} +2 -5
  2. package/NEXOWATT_EOS_BUILD_INFO.json +18 -14
  3. package/NEXOWATT_EOS_STABLE_7.9.94.md +16 -0
  4. package/PUBLISH_STABLE_V7.9.95.md +16 -0
  5. package/README_STABILITY_V7.9.95.md +12 -0
  6. package/RELEASE_ACCEPTANCE_V7.9.95.md +11 -0
  7. package/RELEASE_NOTES_V7.9.95.md +12 -0
  8. package/adminWww/css/nexowatt-native-shell.css +2 -2
  9. package/adminWww/index.html +2 -0
  10. package/adminWww/js/eos-assistant.js +5 -124
  11. package/adminWww/static/js/nexowatt-stable-login.js +79 -0
  12. package/build/lib/nexowattStableAuth.js +74 -0
  13. package/build/lib/web.js +24 -7
  14. package/build/main.js +122 -1
  15. package/io-package.json +24 -15
  16. package/package.json +22 -31
  17. package/PUBLISH_STABLE_V7.9.92.md +0 -19
  18. package/README_STABILITY_V7.9.92.md +0 -14
  19. package/RELEASE_ACCEPTANCE_V7.9.92.md +0 -12
  20. package/RELEASE_NOTES_V7.9.92.md +0 -17
  21. package/tools/nexowatt-account-management-selftest.cjs +0 -61
  22. package/tools/nexowatt-clean-legacy-runtime.cjs +0 -147
  23. package/tools/nexowatt-ensure-release-defaults.cjs +0 -72
  24. package/tools/nexowatt-generate-eos-admin-repo-entry.cjs +0 -37
  25. package/tools/nexowatt-generate-repo-entry.cjs +0 -3
  26. package/tools/nexowatt-internal-reserve-selftest.cjs +0 -55
  27. package/tools/nexowatt-login-layout-selftest.cjs +0 -81
  28. package/tools/nexowatt-modern-ui-selftest.cjs +0 -50
  29. package/tools/nexowatt-patch-repo.cjs +0 -54
  30. package/tools/nexowatt-publish-channel-guard.cjs +0 -58
  31. package/tools/nexowatt-release-defaults-selftest.cjs +0 -29
  32. package/tools/nexowatt-runtime-cleanup-selftest.cjs +0 -47
  33. package/tools/nexowatt-validate-package.cjs +0 -246
package/build/main.js CHANGED
@@ -164,6 +164,79 @@ let lastRepoUpdate;
164
164
  let objects = {};
165
165
  const secret = 'Zgfr56gFe87jJOM'; // Will be generated by first start
166
166
  let systemLanguage = 'en';
167
+
168
+ const EOS_STABLE_INITIAL_PASSWORD = 'nexowatt';
169
+ const EOS_STABLE_ACCOUNTS = [
170
+ { user: 'installer', role: 'installer' },
171
+ { user: 'guest', role: 'customer' },
172
+ { user: 'user', role: 'customer' },
173
+ ];
174
+
175
+ async function ensureEosStableGroupMembership(adapter, user, role) {
176
+ const candidateGroups = role === 'installer'
177
+ ? ['system.group.installer', 'system.group.installateur', 'system.group.installers']
178
+ : ['system.group.endkunde', 'system.group.endkunden'];
179
+ const userId = `system.user.${user}`;
180
+ for (const groupId of candidateGroups) {
181
+ const group = await adapter.getForeignObjectAsync(groupId);
182
+ if (!group) {
183
+ continue;
184
+ }
185
+ const members = Array.isArray(group.common?.members) ? [...group.common.members] : [];
186
+ if (!members.includes(userId)) {
187
+ members.push(userId);
188
+ await adapter.extendForeignObjectAsync(groupId, { common: { members } }, { user: 'system.user.admin' });
189
+ }
190
+ }
191
+ }
192
+
193
+ async function ensureEosStableInitialAccounts(adapter) {
194
+ for (const account of EOS_STABLE_ACCOUNTS) {
195
+ const id = `system.user.${account.user}`;
196
+ let object = await adapter.getForeignObjectAsync(id);
197
+ let created = false;
198
+ if (!object) {
199
+ await adapter.setForeignObjectAsync(id, {
200
+ type: 'user',
201
+ common: { name: account.user, enabled: true, password: '' },
202
+ native: {},
203
+ }, { user: 'system.user.admin' });
204
+ object = await adapter.getForeignObjectAsync(id);
205
+ created = true;
206
+ }
207
+ if (!object) {
208
+ adapter.log.error(`Cannot prepare EOS account ${account.user}`);
209
+ continue;
210
+ }
211
+ const eosNative = object.native || {};
212
+ const resetRequested = eosNative.nexowattResetRequested === true || eosNative.eosResetRequested === true;
213
+ const passwordMissing = !object.common?.password;
214
+ const pendingFirstLogin = eosNative.nexowattPasswordChangeRequired === true || eosNative.eosPasswordChangeRequired === true || eosNative.nexowattFirstLoginPending === true || eosNative.eosFirstLoginRequired === true;
215
+ const stableCredentialMissing = eosNative.nexowattStableInitialCredentialVersion !== 1;
216
+ if (created || passwordMissing || resetRequested || (pendingFirstLogin && stableCredentialMissing)) {
217
+ await adapter.setPasswordAsync(account.user, EOS_STABLE_INITIAL_PASSWORD, { user: 'system.user.admin' });
218
+ await adapter.extendForeignObjectAsync(id, {
219
+ native: {
220
+ ...eosNative,
221
+ nexowattManaged: true,
222
+ nexowattRole: account.role,
223
+ nexowattPasswordChangeRequired: true,
224
+ eosPasswordChangeRequired: true,
225
+ nexowattFirstLoginPending: true,
226
+ eosFirstLoginRequired: true,
227
+ nexowattInitialPasswordApplied: true,
228
+ nexowattInitialPasswordVersion: 1,
229
+ nexowattStableInitialCredentialVersion: 1,
230
+ nexowattResetRequested: false,
231
+ eosResetRequested: false,
232
+ },
233
+ }, { user: 'system.user.admin' });
234
+ adapter.log.info(`Prepared EOS ${account.role} account ${account.user} for mandatory first password change`);
235
+ }
236
+ await ensureEosStableGroupMembership(adapter, account.user, account.role);
237
+ }
238
+ }
239
+
167
240
  class Admin extends adapter_core_1.Adapter {
168
241
  /** secret used for the socket connection */
169
242
  secret;
@@ -282,6 +355,7 @@ class Admin extends adapter_core_1.Adapter {
282
355
  systemLanguage = systemConfig.common.language;
283
356
  }
284
357
  adapter_core_1.I18n.init(__dirname, systemLanguage).catch(e => this.log.error(`Cannot init i18n: ${e}`));
358
+ await ensureEosStableInitialAccounts(this);
285
359
  if (!systemConfig.native.secret) {
286
360
  (0, node_crypto_1.randomBytes)(24, (_ex, buf) => {
287
361
  this.secret = buf.toString('hex');
@@ -409,8 +483,55 @@ class Admin extends adapter_core_1.Adapter {
409
483
  });
410
484
  return;
411
485
  }
486
+
487
+ else if (obj.command === 'eos:completeFirstLogin') {
488
+ const message = obj.message || {};
489
+ const user = String(message.user || '').replace(/^system\\.user\\./, '').trim().toLowerCase();
490
+ const password = String(message.password || '');
491
+ if (!['installer', 'guest', 'user'].includes(user) || !password) {
492
+ if (obj.callback) {
493
+ this.sendTo(obj.from, obj.command, { error: 'Ungültige Anfrage' }, obj.callback);
494
+ }
495
+ return;
496
+ }
497
+ void this.checkPasswordAsync(user, password)
498
+ .then(async (result) => {
499
+ const valid = Array.isArray(result) ? result[0] === true : !!result;
500
+ if (!valid) {
501
+ throw new Error('Das neue Passwort konnte nicht bestätigt werden');
502
+ }
503
+ const id = `system.user.${user}`;
504
+ const account = await this.getForeignObjectAsync(id);
505
+ if (!account) {
506
+ throw new Error('Benutzerkonto nicht gefunden');
507
+ }
508
+ const eosNative = account.native || {};
509
+ await this.extendForeignObjectAsync(id, {
510
+ native: {
511
+ ...eosNative,
512
+ nexowattPasswordChangeRequired: false,
513
+ eosPasswordChangeRequired: false,
514
+ nexowattFirstLoginPending: false,
515
+ eosFirstLoginRequired: false,
516
+ nexowattPasswordChangedAt: new Date().toISOString(),
517
+ },
518
+ }, { user: 'system.user.admin' });
519
+ if (obj.callback) {
520
+ this.sendTo(obj.from, obj.command, { success: true }, obj.callback);
521
+ }
522
+ })
523
+ .catch((error) => {
524
+ if (obj.callback) {
525
+ this.sendTo(obj.from, obj.command, { error: error.message }, obj.callback);
526
+ }
527
+ });
528
+ return;
529
+ }
530
+
412
531
  else if (obj.command.startsWith('chat:')) {
413
- this.processChatMessage(obj).catch(error => this.log.error(`Error by chat processing: ${error}`));
532
+ if (obj.callback) {
533
+ this.sendTo(obj.from, obj.command, { error: 'EOS Assist ist in dieser Stable-Version vorübergehend deaktiviert.' }, obj.callback);
534
+ }
414
535
  return;
415
536
  }
416
537
  else if (webServer?.processMessage(obj)) {
package/io-package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "common": {
3
3
  "name": "eos-admin",
4
- "version": "7.9.92",
4
+ "version": "7.9.95",
5
5
  "titleLang": {
6
6
  "en": "NexoWatt EOS Admin",
7
7
  "de": "NexoWatt EOS Admin",
@@ -18,10 +18,15 @@
18
18
  "connectionType": "local",
19
19
  "dataSource": "push",
20
20
  "news": {
21
- "7.9.92": {
22
- "de": "Stable 7.9.92 korrigiert die Release-Vorbereitung: Vor Paketprüfung und npm-Veröffentlichung werden die verbindlichen Verkaufsstandardwerte für Authentifizierung, Port 8081 sowie die ausschließlich für Admin/Service sichtbaren internen Admin- und BackItUp-Notfallreserven automatisch normalisiert. Dadurch kann ein gemischter lokaler Arbeitsordner die Sicherheitsprüfung nicht mehr durch einen fehlenden Standardwert abbrechen. Rollen-, Login-, Übersichts- und Dienstefilter aus 7.9.91 bleiben unverändert.",
23
- "en": "Stable 7.9.92 hardens release preparation: before package validation and npm publishing, the mandatory sales defaults for authentication, port 8081 and the Admin/Service-only internal admin and BackItUp emergency reserves are normalized automatically. A mixed local working tree can therefore no longer abort the security check merely because a required default value is missing. Role, login, overview and service filtering from 7.9.91 remain unchanged.",
24
- "nl": "Stable 7.9.92 verhardt de releasevoorbereiding: vóór pakketcontrole en npm-publicatie worden de verplichte verkoopstandaarden voor authenticatie, poort 8081 en de uitsluitend voor Admin/Service zichtbare interne admin- en BackItUp-noodreserve automatisch genormaliseerd. Een gemengde lokale werkmap kan de veiligheidscontrole daardoor niet meer laten stoppen door een ontbrekende standaardwaarde. Rollen-, login-, overzichts- en dienstenfilters uit 7.9.91 blijven ongewijzigd."
21
+ "7.9.95": {
22
+ "de": "Stable 7.9.95 macht den Release-Ordner mergesicher: Die flache Update-ZIP kann direkt über einen bestehenden Arbeitsordner entpackt werden. Vor Paketprüfung und npm-Veröffentlichung werden package.json, io-package.json, beide Lockdateien, die Frontend-Version, Build-Informationen und der aktuelle Repository-Eintrag automatisch auf dieselbe Version gebracht. Dadurch wird insbesondere ein stehen gebliebenes io-package.json aus 7.9.92/7.9.94 automatisch repariert. Die Funktionen aus 7.9.94 bleiben unverändert.",
23
+ "en": "Stable 7.9.95 makes the release folder merge-safe: the flat update ZIP can be extracted directly over an existing working directory. Before package validation and npm publishing, package.json, io-package.json, both lockfiles, the frontend version, build information and the current repository entry are synchronized automatically. In particular, a stale io-package.json from 7.9.92/7.9.94 is repaired automatically. Functional behavior from 7.9.94 remains unchanged.",
24
+ "nl": "Stable 7.9.95 maakt de releasemap merge-veilig: de vlakke update-ZIP kan direct over een bestaande werkmap worden uitgepakt. Vóór pakketcontrole en npm-publicatie worden package.json, io-package.json, beide lockbestanden, de frontendversie, buildinformatie en de actuele repositoryvermelding automatisch op dezelfde versie gezet. Een achtergebleven io-package.json uit 7.9.92/7.9.94 wordt daardoor automatisch hersteld. De functies uit 7.9.94 blijven ongewijzigd."
25
+ },
26
+ "7.9.94": {
27
+ "de": "Stable-Kandidat 7.9.94: Standardkonten installer, guest und user verwenden bei der Ersteinrichtung das Startpasswort nexowatt und müssen nach der ersten erfolgreichen Anmeldung sofort ein persönliches Passwort vergeben. Die passwortlose Aktivierung ist deaktiviert. Die Login-Karte bleibt auch bei Fehlermeldungen vollständig bedienbar. EOS Assist ist für diese Stable-Version vollständig deaktiviert, bis die neue lesende Systemassistenz separat freigegeben ist. Deutsche Sicherheitstexte und sichtbare Herstellerangaben wurden bereinigt.",
28
+ "en": "Stable candidate 7.9.94: the standard installer, guest and user accounts use the initial password nexowatt during commissioning and must set a personal password immediately after the first successful sign-in. Passwordless activation is disabled. The login card remains fully usable when an error is shown. EOS Assist is completely disabled in this stable version until the redesigned read-only system assistant is released separately. German security texts and visible publisher information were cleaned up.",
29
+ "nl": "Stable-kandidaat 7.9.94: de standaardaccounts installer, guest en user gebruiken bij de eerste ingebruikname het startwachtwoord nexowatt en moeten na de eerste succesvolle aanmelding direct een persoonlijk wachtwoord instellen. Activering zonder wachtwoord is uitgeschakeld. De aanmeldkaart blijft ook bij foutmeldingen volledig bedienbaar. EOS Assist is in deze stable-versie volledig uitgeschakeld totdat de vernieuwde alleen-lezen systeemassistent apart is vrijgegeven."
25
30
  },
26
31
  "7.9.90": {
27
32
  "de": "Stable 7.9.90 korrigiert die produktive Rollenoberfläche: Die Übersichtskacheln sind für Installateur und Gast/Endkunde zuverlässig bedienbar. Interner Admin und interne BackItUp-Notfallreserve werden in Dienste auch bei verzögert gerenderten Tabellen ausschließlich für Admin/Service angezeigt. Die Erstanmeldung prüft serverseitig, ob Installer, Guest oder User noch keinen persönlichen Zugang besitzen: Nur dann wird die normale Anmeldeschaltfläche bei leerem Passwort aktiv und öffnet die verpflichtende Passwortvergabe; nach abgeschlossener Aktivierung bleibt sie ohne Passwort gesperrt. NexoWatt Sicherung bleibt für freigegebene Rollen erreichbar, EOS Assist im Header und Standardport 8081 bleiben unverändert.",
@@ -314,7 +319,7 @@
314
319
  "icon": "admin.svg",
315
320
  "messagebox": true,
316
321
  "enabled": true,
317
- "extIcon": "https://unpkg.com/iobroker.eos-admin@7.9.92/admin/admin.svg",
322
+ "extIcon": "https://unpkg.com/iobroker.eos-admin@7.9.95/admin/admin.svg",
318
323
  "keywords": [
319
324
  "NexoWatt",
320
325
  "EOS",
@@ -325,10 +330,9 @@
325
330
  "licensed"
326
331
  ],
327
332
  "compact": true,
328
- "readme": "https://unpkg.com/iobroker.eos-admin@7.9.92/README.md",
333
+ "readme": "https://unpkg.com/iobroker.eos-admin@7.9.95/README.md",
329
334
  "authors": [
330
- "bluefox <bluefox@ccu.io>",
331
- "hobbyquaker <hq@ccu.io>"
335
+ "NexoWatt"
332
336
  ],
333
337
  "dependencies": [
334
338
  {
@@ -394,9 +398,10 @@
394
398
  "nondeletable": false,
395
399
  "allowAdapterUpdate": true,
396
400
  "allowAdapterDelete": false,
397
- "meta": "https://unpkg.com/iobroker.eos-admin@7.9.92/io-package.json",
401
+ "meta": "https://unpkg.com/iobroker.eos-admin@7.9.95/io-package.json",
398
402
  "npmPackage": "iobroker.eos-admin",
399
- "packetName": "iobroker.eos-admin"
403
+ "packetName": "iobroker.eos-admin",
404
+ "publisher": "NexoWatt"
400
405
  },
401
406
  "native": {
402
407
  "autoUpdate": 24,
@@ -501,7 +506,7 @@
501
506
  ],
502
507
  "eosAdminOnlyGroup": "system.group.administrator",
503
508
  "eosApplyAdminOnlyAclToProtectedAdapters": false,
504
- "eosAssistantEnabled": true,
509
+ "eosAssistantEnabled": false,
505
510
  "eosAssistantAdminOnly": false,
506
511
  "eosStrictProtectedAdapterAcl": false,
507
512
  "eosInstallerGroups": [
@@ -526,11 +531,15 @@
526
531
  "eosRequireFirstLoginPassword": true,
527
532
  "eosFirstLoginPasswordMinLength": 10,
528
533
  "eosAutoAssignDefaultRoleUsers": true,
529
- "eosPasswordlessFirstLogin": true,
534
+ "eosPasswordlessFirstLogin": false,
530
535
  "eosPasswordlessFirstLoginPrivateNetworkOnly": true,
531
536
  "eosPasswordClaimTtlMinutes": 10,
532
537
  "eosHideLegacyBackupFromNonAdmins": true,
533
- "nexowattHideLegacyBackupFromNonAdmins": true
538
+ "nexowattHideLegacyBackupFromNonAdmins": true,
539
+ "eosAllowPasswordlessFirstLogin": false,
540
+ "eosRequireFirstLoginPasswordChange": true,
541
+ "eosAutoAssignStandardAccounts": true,
542
+ "eosAssistEnabled": false
534
543
  },
535
544
  "notifications": [
536
545
  {
@@ -1098,5 +1107,5 @@
1098
1107
  }
1099
1108
  }
1100
1109
  },
1101
- "version": "7.9.92"
1110
+ "version": "7.9.95"
1102
1111
  }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "iobroker.eos-admin",
3
3
  "description": "NexoWatt EOS Admin stable product release with compact login, role-safe services and self-healing sales defaults",
4
- "version": "7.9.92",
4
+ "version": "7.9.95",
5
5
  "contributors": [
6
6
  "bluefox <dogafox@gmail.com>",
7
7
  "apollon77",
@@ -86,7 +86,7 @@
86
86
  "main": "build/main.js",
87
87
  "files": [
88
88
  "admin/",
89
- "build",
89
+ "build/",
90
90
  "docs/",
91
91
  "adminWww/",
92
92
  "public/",
@@ -94,31 +94,17 @@
94
94
  "LICENSE",
95
95
  "THIRD_PARTY_NOTICES.md",
96
96
  "NEXOWATT_PROPRIETARY_LICENSE.md",
97
- "admin/LICENSE-NEXOWATT.md",
98
- "adminWww/LICENSE-NEXOWATT.md",
99
97
  "NEXOWATT_PUBLIC_NPM_DISTRIBUTION.md",
100
- "tools/nexowatt-publish-channel-guard.cjs",
101
- "tools/nexowatt-validate-package.cjs",
102
98
  "README.md",
103
- "tools/nexowatt-generate-repo-entry.cjs",
104
- "tools/nexowatt-patch-repo.cjs",
105
99
  "NEXOWATT_EOS_BUILD_INFO.json",
106
100
  "NEXOWATT_EOS_STANDALONE.md",
107
- "tools/nexowatt-generate-eos-admin-repo-entry.cjs",
108
- "tools/nexowatt-repair-eos-admin-update.cjs",
109
- "tools/nexowatt-clean-legacy-runtime.cjs",
110
- "tools/nexowatt-runtime-cleanup-selftest.cjs",
111
- "tools/nexowatt-account-management-selftest.cjs",
112
- "tools/nexowatt-modern-ui-selftest.cjs",
113
- "tools/nexowatt-login-layout-selftest.cjs",
114
- "README_STABILITY_V7.9.92.md",
115
- "RELEASE_NOTES_V7.9.92.md",
116
- "PUBLISH_STABLE_V7.9.92.md",
117
- "INSTALL_TEST_V7.9.92.md",
118
- "RELEASE_ACCEPTANCE_V7.9.92.md",
119
- "tools/nexowatt-internal-reserve-selftest.cjs",
120
- "tools/nexowatt-ensure-release-defaults.cjs",
121
- "tools/nexowatt-release-defaults-selftest.cjs"
101
+ "NEXOWATT_EOS_STABLE_7.9.94.md",
102
+ "README_STABILITY_V7.9.95.md",
103
+ "RELEASE_NOTES_V7.9.95.md",
104
+ "PUBLISH_STABLE_V7.9.95.md",
105
+ "INSTALL_TEST_V7.9.95.md",
106
+ "RELEASE_ACCEPTANCE_V7.9.95.md",
107
+ "tools/nexowatt-repair-eos-admin-update.cjs"
122
108
  ],
123
109
  "scripts": {
124
110
  "npm": "npm i -f && cd src-admin && npm i -f",
@@ -129,7 +115,7 @@
129
115
  "test:integration": "mocha test/integration --exit && npm run test:gui && npm run test:rule && npm run test:unit",
130
116
  "test:rule": "mocha test/rule --exit",
131
117
  "test:gui": "mocha test/*.gui.js --exit",
132
- "prepublishOnly": "npm run prepare:eos-release-defaults && npm run check:eos-publish-channel && npm run check:eos-package && npm run check:eos-stability",
118
+ "prepublishOnly": "npm run sync:eos-version && npm run prepare:eos-release-defaults && npm run check:eos-publish-channel && npm run check:eos-package && npm run check:eos-stability",
133
119
  "build": "npm run build:frontend && npm run build:backend && npm run clean:eos-runtime",
134
120
  "build:backend": "tsc -p tsconfig.build.json && tsx tasks.mts --backend-i18n",
135
121
  "build:frontend": "tsx tasks.mts",
@@ -153,12 +139,12 @@
153
139
  "nexowatt:repo-entry": "node tools/nexowatt-generate-repo-entry.cjs",
154
140
  "nexowatt:patch-repo": "node tools/nexowatt-patch-repo.cjs",
155
141
  "nexowatt:repair-update": "node tools/nexowatt-repair-eos-admin-update.cjs",
156
- "check:eos-stability": "node tools/nexowatt-stability-check.cjs && node tools/nexowatt-esm-syntax-selftest.cjs && node tools/nexowatt-import-integrity-selftest.cjs && node tools/nexowatt-entrypoint-smoke-selftest.cjs && node tools/nexowatt-frontend-graph-check.cjs && node tools/nexowatt-policy-selftest.cjs && node tools/nexowatt-publish-channel-selftest.cjs && node tools/nexowatt-release-defaults-selftest.cjs && node tools/nexowatt-role-access-selftest.cjs && node tools/nexowatt-internal-reserve-selftest.cjs && node tools/nexowatt-first-login-selftest.cjs && node tools/nexowatt-account-management-selftest.cjs && node tools/nexowatt-modern-ui-selftest.cjs && node tools/nexowatt-login-layout-selftest.cjs && node tools/nexowatt-branding-selftest.cjs && node tools/nexowatt-default-port-selftest.cjs && node tools/nexowatt-module-popup-selftest.cjs && node tools/nexowatt-datapoint-selftest.cjs && node tools/nexowatt-update-selftest.cjs && node tools/nexowatt-datapoint-interaction-selftest.cjs && node tools/nexowatt-manual-write-policy-selftest.cjs && node tools/nexowatt-value-column-selftest.cjs && node tools/nexowatt-native-shell-selftest.cjs && node tools/nexowatt-assistant-separation-selftest.cjs && node tools/nexowatt-runtime-cleanup-selftest.cjs",
142
+ "check:eos-stability": "node tools/nexowatt-stability-check.cjs && node tools/nexowatt-esm-syntax-selftest.cjs && node tools/nexowatt-import-integrity-selftest.cjs && node tools/nexowatt-entrypoint-smoke-selftest.cjs && node tools/nexowatt-frontend-graph-check.cjs && node tools/nexowatt-policy-selftest.cjs && node tools/nexowatt-publish-channel-selftest.cjs && node tools/nexowatt-release-defaults-selftest.cjs && node tools/nexowatt-role-access-selftest.cjs && node tools/nexowatt-internal-reserve-selftest.cjs && node tools/nexowatt-first-login-selftest.cjs && node tools/nexowatt-account-management-selftest.cjs && node tools/nexowatt-modern-ui-selftest.cjs && node tools/nexowatt-login-layout-selftest.cjs && node tools/nexowatt-branding-selftest.cjs && node tools/nexowatt-default-port-selftest.cjs && node tools/nexowatt-module-popup-selftest.cjs && node tools/nexowatt-datapoint-selftest.cjs && node tools/nexowatt-update-selftest.cjs && node tools/nexowatt-datapoint-interaction-selftest.cjs && node tools/nexowatt-manual-write-policy-selftest.cjs && node tools/nexowatt-value-column-selftest.cjs && node tools/nexowatt-native-shell-selftest.cjs && node tools/nexowatt-assistant-separation-selftest.cjs && node tools/nexowatt-runtime-cleanup-selftest.cjs && node tools/nexowatt-version-sync-selftest.cjs && node tools/nexowatt-merge-update-selftest.cjs && npm run check:eos-stable-v95",
157
143
  "nexowatt:patch-built-frontend": "node tools/nexowatt-patch-built-frontend.cjs",
158
144
  "clean:eos-runtime": "node tools/nexowatt-clean-legacy-runtime.cjs",
159
- "precheck:eos-package": "npm run prepare:eos-release-defaults && npm run clean:eos-runtime",
160
- "precheck:eos-stability": "npm run prepare:eos-release-defaults && npm run clean:eos-runtime",
161
- "prepack": "node tools/nexowatt-clean-legacy-runtime.cjs --quiet",
145
+ "precheck:eos-package": "npm run sync:eos-version && npm run prepare:eos-release-defaults && npm run clean:eos-runtime",
146
+ "precheck:eos-stability": "npm run sync:eos-version && npm run prepare:eos-release-defaults && npm run clean:eos-runtime",
147
+ "prepack": "node tools/nexowatt-sync-release-version.cjs --quiet && node tools/nexowatt-clean-legacy-runtime.cjs --quiet",
162
148
  "check:eos-esm": "node tools/nexowatt-esm-syntax-selftest.cjs",
163
149
  "check:eos-imports": "node tools/nexowatt-import-integrity-selftest.cjs",
164
150
  "check:eos-release": "npm run check:eos-package && npm run check:eos-stability && npm pack --dry-run",
@@ -173,7 +159,11 @@
173
159
  "test:eos-login-layout": "node tools/nexowatt-login-layout-selftest.cjs",
174
160
  "test:eos-release-defaults": "node tools/nexowatt-release-defaults-selftest.cjs",
175
161
  "prepare:eos-release-defaults": "node tools/nexowatt-ensure-release-defaults.cjs",
176
- "normalize:eos-release": "npm run prepare:eos-release-defaults"
162
+ "normalize:eos-release": "npm run prepare:eos-release-defaults",
163
+ "sync:eos-version": "node tools/nexowatt-sync-release-version.cjs",
164
+ "test:eos-version-sync": "node tools/nexowatt-version-sync-selftest.cjs",
165
+ "verify:eos-merge": "node tools/nexowatt-merge-update-selftest.cjs",
166
+ "check:eos-stable-v95": "node tools/nexowatt-stable-v95-selftest.cjs"
177
167
  },
178
168
  "author": "NexoWatt",
179
169
  "private": false,
@@ -184,6 +174,7 @@
184
174
  },
185
175
  "nexowattReleasePolicy": {
186
176
  "distTag": "latest",
187
- "purpose": "accepted stable NexoWatt EOS sales-product release 7.9.92"
188
- }
177
+ "purpose": "accepted stable NexoWatt EOS sales-product release 7.9.95"
178
+ },
179
+ "publisher": "NexoWatt"
189
180
  }
@@ -1,19 +0,0 @@
1
- # Veröffentlichung 7.9.92
2
-
3
- ```powershell
4
- npm login
5
- npm whoami
6
- npm run normalize:eos-release
7
- npm run check:eos-publish-channel
8
- npm run check:eos-package
9
- npm run check:eos-stability
10
- npm publish --dry-run --tag latest
11
- npm publish --tag latest
12
- ```
13
-
14
- Danach prüfen:
15
-
16
- ```powershell
17
- npm view iobroker.eos-admin@latest version
18
- npm dist-tag ls iobroker.eos-admin
19
- ```
@@ -1,14 +0,0 @@
1
- # NexoWatt EOS Admin 7.9.92
2
-
3
- Stable Verkaufsprodukt-Version. Diese Version übernimmt die Bedien-, Rollen- und Login-Korrekturen aus 7.9.91 und härtet die Release-Vorbereitung.
4
-
5
- Vor Paketprüfung und Veröffentlichung werden folgende verbindliche Standardwerte automatisch gesetzt:
6
-
7
- - Authentifizierung aktiv
8
- - EOS Admin Standardport 8081
9
- - interner Admin nur für Admin/Service
10
- - interne BackItUp-Notfallreserve nur für Admin/Service
11
- - NexoWatt-Backup-Sichtbarkeitskompatibilität aktiv
12
- - Erstpasswort-Pflicht aktiv
13
-
14
- Die Normalisierung verändert keine bestehenden Kundendaten auf einem installierten System; sie betrifft die Paketmetadaten des zu veröffentlichenden Adapters.
@@ -1,12 +0,0 @@
1
- # Release-Abnahme 7.9.92
2
-
3
- - [ ] `npm run check:eos-publish-channel` erfolgreich
4
- - [ ] `npm run check:eos-package` erfolgreich
5
- - [ ] `npm run check:eos-stability` erfolgreich
6
- - [ ] `npm publish --dry-run --tag latest` erfolgreich
7
- - [ ] Admin/Service sieht `admin.0` und `backitup.0`
8
- - [ ] Installateur und Endkunde sehen `admin.0` und `backitup.0` nicht
9
- - [ ] NexoWatt Backup bleibt rollenabhängig erreichbar
10
- - [ ] Login und Erstanmeldung funktionieren
11
- - [ ] Standardport 8081
12
- - [ ] Reboot- und Rollbacktest erfolgreich
@@ -1,17 +0,0 @@
1
- # Release Notes – NexoWatt EOS Admin 7.9.92
2
-
3
- ## Behoben
4
-
5
- - Der npm-Publish konnte in einem älteren oder unvollständig aktualisierten Arbeitsordner mit `internal backup reserve must default to Admin/Service visibility` abbrechen.
6
- - Ein neuer Release-Default-Schritt stellt die beiden Backup-Reserve-Flags vor allen relevanten Prüfungen automatisch auf den verbindlichen sicheren Wert `true`.
7
- - Eine eigene Regression prüft fehlende, falsche und bereits korrekte Werte.
8
-
9
- ## Unverändert
10
-
11
- - Standardport 8081
12
- - npm-Dist-Tag `latest`
13
- - Admin-/BackItUp-Notfallreserve nur für Admin/Service
14
- - NexoWatt Sicherung entsprechend Rollenfreigabe
15
- - kompakte Anmeldung und Erstaktivierung
16
- - klickbare Installer-/Endkundenübersicht
17
- - EOS Assist im Header
@@ -1,61 +0,0 @@
1
- #!/usr/bin/env node
2
- 'use strict';
3
- const fs = require('fs');
4
- const path = require('path');
5
- const root = path.resolve(__dirname, '..');
6
- const read = rel => fs.readFileSync(path.join(root, rel), 'utf8');
7
- const json = rel => JSON.parse(read(rel));
8
- let bad = false;
9
- const fail = msg => { console.error(`[NexoWatt EOS account management] ${msg}`); bad = true; };
10
-
11
- const mainSource = read('src/main.ts');
12
- const mainBuilt = read('build/main.js');
13
- const webSource = read('src/lib/web.ts');
14
- const webBuilt = read('build/lib/web.js');
15
- const sourceUi = read('src-admin/public/js/eos-account-management.js');
16
- const builtUi = read('adminWww/js/eos-account-management.js');
17
- const roleUi = read('adminWww/js/eos-role-ui.js');
18
- const css = read('adminWww/css/nexowatt-native-shell.css');
19
- const index = read('adminWww/index.html');
20
- const info = json('NEXOWATT_EOS_BUILD_INFO.json');
21
- const shellTag = String(info.shellCacheTag || info.shellCacheVersion);
22
-
23
- for (const code of [mainSource, mainBuilt]) {
24
- for (const marker of [
25
- 'system.user.installer', 'system.user.guest', 'ensureEosDefaultRoleUsers', 'unknown random bootstrap secret',
26
- 'eosPasswordSetupRequired', 'personal password setup is required',
27
- ]) if (!code.includes(marker)) fail(`main account marker missing: ${marker}`);
28
- }
29
- for (const code of [webSource, webBuilt]) {
30
- for (const marker of [
31
- 'getEosManagedAccounts', 'sendEosAccountManagement', 'resetEosAccountPassword',
32
- '/nexowatt/account/manage', '/nexowatt/account/reset', 'x-nexowatt-eos-account-reset',
33
- 'canResetInstaller', 'canResetEndUser', "targetUserId === 'system.user.admin'", 'targetUserId === access.userId',
34
- "access.role === 'installer' && explicitlyManagedRole !== 'enduser'",
35
- 'explicit member of a managed EOS installer/end-user group', 'passwordResetAt', 'passwordResetBy',
36
- "passwordResetMode = 'passwordless-first-activation'", 'accountDisabled',
37
- ]) if (!code.includes(marker)) fail(`web account marker missing: ${marker}`);
38
- if (!/randomBytes[^\n]{0,40}48/.test(code)) fail('reset does not generate an unknown random bootstrap secret');
39
- if (!code.includes('const explicitInstaller = targetAccess.groups.some')) fail('reset target is not restricted to explicit installer membership');
40
- if (!code.includes('const explicitEndUser = targetAccess.groups.some')) fail('reset target is not restricted to explicit end-user membership');
41
- }
42
-
43
- for (const marker of [
44
- 'v91-account-management-under-access-rights', "['admin', 'installer']", 'nexowatt/account/manage',
45
- 'nexowatt/account/reset', 'X-NexoWatt-EOS-Account-Reset', 'data.canResetInstaller === true',
46
- "account.role === 'enduser'", 'Admin/Service', 'Installateure', 'NEXOWATT_EOS_ACCOUNT_MANAGEMENT',
47
- 'ensureEntrySurface', "currentRoute() !== 'tab-users'", 'eos-account-management-entry',
48
- ]) if (!sourceUi.includes(marker)) fail(`account UI marker missing: ${marker}`);
49
- if (sourceUi.includes("launcher.className = 'eos-account-management-launcher'")) fail('standalone account launcher is still created');
50
- if (sourceUi.includes('new MutationObserver')) fail('account management adds a second broad MutationObserver');
51
- if (sourceUi !== builtUi) fail('account management source/build drift');
52
- if (!roleUi.includes("route === 'tab-users'")) fail('installer cannot reach Zugänge & Rechte');
53
- if (roleUi.includes('NEXOWATT_EOS_ACCOUNT_MANAGEMENT.open')) fail('role overview opens account management outside Zugänge & Rechte');
54
- if (!index.includes(`eos-account-management.js?v=${shellTag}`)) fail('account management asset is not active with the current cache tag');
55
- for (const marker of [
56
- '.eos-account-management-entry', '.eos-account-management-overlay', '.eos-account-management-dialog',
57
- '.eos-account-row', '.eos-account-reset', 'html.eos-account-page-installer',
58
- ]) if (!css.includes(marker)) fail(`account management CSS marker missing: ${marker}`);
59
-
60
- if (bad) process.exit(1);
61
- console.log('[NexoWatt EOS account management] OK');
@@ -1,147 +0,0 @@
1
- #!/usr/bin/env node
2
- 'use strict';
3
-
4
- const fs = require('fs');
5
- const os = require('os');
6
- const path = require('path');
7
-
8
- const DEFAULT_ROOT = path.resolve(__dirname, '..');
9
- const LEGACY_OVERLAYS = [
10
- 'adminWww/js/eos-branding.js',
11
- 'adminWww/js/eos-security-ui.js',
12
- 'adminWww/js/eos-console-quiet.js',
13
- 'adminWww/js/eos-objects-state-tools.js',
14
- 'adminWww/js/eos-performance-guard.js',
15
- 'adminWww/js/eos-runtime-fixes.js',
16
- 'adminWww/js/eos-hard-logout.js',
17
- 'adminWww/css/eos-branding.css',
18
- 'src-admin/public/js/eos-branding.js',
19
- 'src-admin/public/js/eos-security-ui.js',
20
- 'src-admin/public/js/eos-console-quiet.js',
21
- 'src-admin/public/js/eos-objects-state-tools.js',
22
- 'src-admin/public/js/eos-performance-guard.js',
23
- 'src-admin/public/js/eos-runtime-fixes.js',
24
- 'src-admin/public/js/eos-hard-logout.js',
25
- 'src-admin/public/css/eos-branding.css',
26
- ];
27
-
28
- const readJson = file => JSON.parse(fs.readFileSync(file, 'utf8'));
29
-
30
- function runtimeNumber(root) {
31
- const info = readJson(path.join(root, 'NEXOWATT_EOS_BUILD_INFO.json'));
32
- const value = Number(String(info.runtimeEntry || '').replace(/^v/, ''));
33
- if (!Number.isFinite(value)) {
34
- throw new Error(`Invalid runtimeEntry in NEXOWATT_EOS_BUILD_INFO.json: ${info.runtimeEntry}`);
35
- }
36
- return value;
37
- }
38
-
39
- function walkFiles(dir) {
40
- if (!fs.existsSync(dir)) return [];
41
- const result = [];
42
- const stack = [dir];
43
- while (stack.length) {
44
- const current = stack.pop();
45
- for (const entry of fs.readdirSync(current, { withFileTypes: true })) {
46
- const absolute = path.join(current, entry.name);
47
- if (entry.isDirectory()) stack.push(absolute);
48
- else if (entry.isFile()) result.push(absolute);
49
- }
50
- }
51
- return result;
52
- }
53
-
54
- function isLegacyVersionedRuntime(file, activeRuntime) {
55
- const name = path.basename(file);
56
- const versionMatch = name.match(/-v(\d+)\.(?:js|js\.map|css|css\.map)$/i);
57
- if (versionMatch) return Number(versionMatch[1]) !== activeRuntime;
58
- const remoteMatch = name.match(/^remoteEntry-v(\d+)\.(?:js|js\.map)$/i);
59
- if (remoteMatch) return Number(remoteMatch[1]) !== activeRuntime;
60
-
61
- // Remove historical emergency bundles which predate the consolidated runtime
62
- // naming and must never survive in a current EOS Admin source tree.
63
- return /(?:DPWrite|DPAdapter|DPw\d+|NoLock|Unrestricted|force-version|delete-services-hardfix)/i.test(name) && /\.(?:js|js\.map)$/i.test(name);
64
- }
65
-
66
- function collectLegacyRuntimeFiles(root = DEFAULT_ROOT) {
67
- const activeRuntime = runtimeNumber(root);
68
- const scanRoots = [
69
- path.join(root, 'adminWww', 'assets'),
70
- path.join(root, 'adminWww'),
71
- path.join(root, 'src-admin', 'build', 'assets'),
72
- path.join(root, 'src-admin', 'build'),
73
- ];
74
- const files = new Set();
75
- for (const scanRoot of scanRoots) {
76
- for (const file of walkFiles(scanRoot)) {
77
- if (isLegacyVersionedRuntime(file, activeRuntime)) files.add(file);
78
- }
79
- }
80
- for (const rel of LEGACY_OVERLAYS) {
81
- const file = path.join(root, rel);
82
- if (fs.existsSync(file)) files.add(file);
83
- }
84
- return { activeRuntime, files: [...files].sort() };
85
- }
86
-
87
- function cleanLegacyRuntime(options = {}) {
88
- const root = path.resolve(options.root || DEFAULT_ROOT);
89
- const dryRun = options.dryRun === true;
90
- const quiet = options.quiet === true;
91
- const silent = options.silent === true;
92
- const { activeRuntime, files } = collectLegacyRuntimeFiles(root);
93
- const removed = [];
94
- const failed = [];
95
-
96
- for (const file of files) {
97
- if (dryRun) {
98
- removed.push(file);
99
- continue;
100
- }
101
- try {
102
- try {
103
- fs.rmSync(file, { force: true });
104
- } catch (firstError) {
105
- // ZIP extraction tools on Windows may preserve a read-only bit. Make a
106
- // single controlled retry before reporting a real cleanup failure.
107
- try { fs.chmodSync(file, 0o666); } catch (_) { /* best effort */ }
108
- fs.rmSync(file, { force: true });
109
- }
110
- if (!fs.existsSync(file)) removed.push(file);
111
- else failed.push({ file, error: 'file still exists after removal' });
112
- } catch (error) {
113
- failed.push({ file, error: error?.message || String(error) });
114
- }
115
- }
116
-
117
- if (failed.length) {
118
- const details = failed.map(item => `${path.relative(root, item.file)}: ${item.error}`).join(os.EOL);
119
- throw new Error(`Could not remove ${failed.length} legacy runtime file(s):${os.EOL}${details}`);
120
- }
121
-
122
- if (!silent) {
123
- if (!quiet) {
124
- console.log(`[NexoWatt EOS runtime cleanup] OK (runtime v${activeRuntime}, removed ${removed.length} legacy file${removed.length === 1 ? '' : 's'})`);
125
- } else if (removed.length) {
126
- console.log(`[NexoWatt EOS runtime cleanup] removed ${removed.length} legacy runtime files before validation`);
127
- }
128
- }
129
-
130
- return { activeRuntime, removed };
131
- }
132
-
133
- if (require.main === module) {
134
- try {
135
- cleanLegacyRuntime({ dryRun: process.argv.includes('--dry-run'), quiet: process.argv.includes('--quiet') });
136
- } catch (error) {
137
- console.error(`[NexoWatt EOS runtime cleanup] ERROR: ${error?.stack || error}`);
138
- process.exit(1);
139
- }
140
- }
141
-
142
- module.exports = {
143
- LEGACY_OVERLAYS,
144
- collectLegacyRuntimeFiles,
145
- cleanLegacyRuntime,
146
- isLegacyVersionedRuntime,
147
- };