iobroker.eos-admin 7.10.0 → 7.10.2

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 (65) hide show
  1. package/INSTALL_TEST_V7.10.2.md +22 -0
  2. package/MERGE_UPDATE_README_V7.10.2.md +11 -0
  3. package/NEXOWATT_EOS_BUILD_INFO.json +19 -21
  4. package/NEXOWATT_EOS_PREBUILT_MANIFEST.json +1410 -0
  5. package/PUBLISH_STABLE_V7.10.2.md +21 -0
  6. package/README.md +16 -6
  7. package/README_STABILITY_V7.10.2.md +20 -0
  8. package/RELEASE_ACCEPTANCE_V7.10.2.md +13 -0
  9. package/RELEASE_NOTES_V7.10.2.md +11 -0
  10. package/adminWww/assets/Intro-DkwRiz1n-v84.js +1 -1
  11. package/adminWww/assets/bootstrap-COulQZax-v84.js +2 -2
  12. package/adminWww/css/eos-ems-overview.css +5 -3
  13. package/adminWww/css/nexowatt-native-shell.css +85 -413
  14. package/adminWww/index.html +20 -21
  15. package/adminWww/js/eos-account-management.js +28 -19
  16. package/adminWww/js/eos-assistant.js +1 -1
  17. package/adminWww/js/eos-ems-overview.js +1 -1
  18. package/adminWww/js/eos-role-bootstrap.js +17 -80
  19. package/adminWww/js/eos-role-ui.js +28 -4
  20. package/adminWww/js/nexowatt-native-shell.js +1 -1
  21. package/adminWww/static/js/nexowatt-stable-login.js +43 -70
  22. package/adminWww/static/js/nexowatt-stable-v7101.js +27 -0
  23. package/build/lib/eosAutoUpdate.js +418 -20
  24. package/build/lib/eosAutoUpdate.js.map +1 -0
  25. package/build/lib/eosRequestSecurity.js +4 -1
  26. package/build/lib/eosRequestSecurity.js.map +1 -0
  27. package/build/lib/web.js +161 -254
  28. package/build/lib/web.js.map +1 -1
  29. package/build/main.js +39 -67
  30. package/io-package.json +72 -7
  31. package/package.json +24 -25
  32. package/tools/nexowatt-account-management-selftest.cjs +15 -19
  33. package/tools/nexowatt-account-password-flow-selftest.cjs +15 -0
  34. package/tools/nexowatt-apply-ems-overview.cjs +4 -2
  35. package/tools/nexowatt-auto-update-selftest.cjs +144 -32
  36. package/tools/nexowatt-backend-runtime-selftest.cjs +147 -0
  37. package/tools/nexowatt-clean-legacy-runtime.cjs +1 -1
  38. package/tools/nexowatt-ems-overview-selftest.cjs +1 -1
  39. package/tools/nexowatt-ensure-release-defaults.cjs +1 -1
  40. package/tools/nexowatt-login-layout-selftest.cjs +9 -13
  41. package/tools/nexowatt-merge-update-selftest.cjs +7 -1
  42. package/tools/nexowatt-modern-ui-selftest.cjs +10 -46
  43. package/tools/nexowatt-password-write-selftest.cjs +46 -16
  44. package/tools/nexowatt-prebuilt-release-selftest.cjs +292 -0
  45. package/tools/nexowatt-release-defaults-selftest.cjs +1 -1
  46. package/tools/nexowatt-runtime-cleanup-selftest.cjs +6 -8
  47. package/tools/nexowatt-stable-v7102-selftest.cjs +51 -0
  48. package/tools/nexowatt-sync-release-version.cjs +43 -5
  49. package/tools/nexowatt-ui-overview-runtime-selftest.cjs +2 -3
  50. package/tools/nexowatt-validate-package.cjs +54 -29
  51. package/tools/nexowatt-version-sync-selftest.cjs +18 -1
  52. package/INSTALL_TEST_V7.10.0.md +0 -11
  53. package/MERGE_UPDATE_README_V7.10.0.md +0 -5
  54. package/PUBLISH_STABLE_V7.10.0.md +0 -15
  55. package/README_STABILITY_V7.10.0.md +0 -3
  56. package/RELEASE_ACCEPTANCE_V7.10.0.md +0 -11
  57. package/RELEASE_NOTES_V7.10.0.md +0 -17
  58. package/adminWww/js/eos-release-watch.js +0 -77
  59. package/adminWww/static/js/nexowatt-stable-v7100.js +0 -111
  60. package/build/lib/eosPassword.js +0 -72
  61. package/build/lib/nexowattStableAuth.js +0 -74
  62. package/src/lib/eosAutoUpdate.ts +0 -320
  63. package/tools/nexowatt-cache-update-selftest.cjs +0 -12
  64. package/tools/nexowatt-request-security-selftest.cjs +0 -11
  65. package/tools/nexowatt-stable-v7100-selftest.cjs +0 -17
package/build/main.js CHANGED
@@ -20,7 +20,6 @@ const socket_classes_1 = require("@iobroker/socket-classes");
20
20
  const ws_server_1 = require("@iobroker/ws-server");
21
21
  const translations_1 = require("./lib/translations");
22
22
  const web_1 = require("./lib/web");
23
- const eosPassword_1 = require("./lib/eosPassword");
24
23
  const checkLinuxPass_1 = require("./lib/checkLinuxPass");
25
24
  const plugin_docker_1 = require("@iobroker/plugin-docker");
26
25
  const objectFixes_1 = require("./lib/objectFixes");
@@ -197,43 +196,27 @@ async function ensureEosStableInitialAccounts(adapter) {
197
196
  let object = await adapter.getForeignObjectAsync(id);
198
197
  let created = false;
199
198
  if (!object) {
200
- await adapter.setForeignObjectAsync(id, {
201
- type: 'user',
202
- common: { name: account.user, enabled: true, password: '' },
203
- native: {},
204
- }, { user: 'system.user.admin' });
199
+ await adapter.setForeignObjectAsync(id, { type: 'user', common: { name: account.user, enabled: true, password: '' }, native: {} }, { user: 'system.user.admin' });
205
200
  object = await adapter.getForeignObjectAsync(id);
206
201
  created = true;
207
202
  }
208
- if (!object) {
209
- adapter.log.error(`Cannot prepare EOS account ${account.user}`);
210
- continue;
211
- }
212
- const eosNative = object.native || {};
213
- const resetRequested = eosNative.nexowattResetRequested === true || eosNative.eosResetRequested === true;
214
- const passwordMissing = !object.common?.password;
215
- const pendingFirstLogin = eosNative.nexowattPasswordChangeRequired === true || eosNative.eosPasswordChangeRequired === true || eosNative.nexowattFirstLoginPending === true || eosNative.eosFirstLoginRequired === true;
216
- const stableCredentialMissing = eosNative.nexowattStableInitialCredentialVersion !== 1;
217
- if (created || passwordMissing || resetRequested || (pendingFirstLogin && stableCredentialMissing)) {
218
- await (0, eosPassword_1.setEosUserPasswordWithVerification)(adapter, id, EOS_STABLE_INITIAL_PASSWORD, 'system.user.admin');
219
- await adapter.extendForeignObjectAsync(id, {
220
- native: {
221
- ...eosNative,
222
- nexowattManaged: true,
223
- nexowattRole: account.role,
224
- nexowattPasswordChangeRequired: true,
225
- eosPasswordChangeRequired: true,
226
- nexowattFirstLoginPending: true,
227
- eosFirstLoginRequired: true,
228
- nexowattInitialPasswordApplied: true,
229
- nexowattInitialPasswordVersion: 1,
230
- nexowattStableInitialCredentialVersion: 1,
231
- nexowattResetRequested: false,
232
- eosResetRequested: false,
233
- },
234
- }, { user: 'system.user.admin' });
235
- adapter.log.info(`Prepared EOS ${account.role} account ${account.user} for mandatory first password change`);
203
+ if (!object) { adapter.log.error(`Cannot prepare EOS account ${account.user}`); continue; }
204
+ if (created || !String(object.common?.password || '').trim()) {
205
+ await adapter.setPasswordAsync(account.user, EOS_STABLE_INITIAL_PASSWORD, { user: 'system.user.admin' });
206
+ object = await adapter.getForeignObjectAsync(id);
236
207
  }
208
+ if (!object) continue;
209
+ const previous = object.native || {};
210
+ const previousAccount = previous.nexowattEosAccount || {};
211
+ await adapter.extendForeignObjectAsync(id, { native: {
212
+ ...previous, nexowattManaged: true, nexowattRole: account.role,
213
+ nexowattPasswordChangeRequired: false, eosPasswordChangeRequired: false,
214
+ nexowattFirstLoginPending: false, eosFirstLoginRequired: false,
215
+ nexowattResetRequested: false, eosResetRequested: false,
216
+ nexowattEosAccount: { ...previousAccount, passwordInitialized: true, passwordSetupVersion: 1,
217
+ passwordInitializationVersion: 1, forcePasswordChange: false,
218
+ passwordlessFirstLoginAllowed: false, standardPasswordMode: true },
219
+ } }, { user: 'system.user.admin' });
237
220
  await ensureEosStableGroupMembership(adapter, account.user, account.role);
238
221
  }
239
222
  }
@@ -964,7 +947,7 @@ class Admin extends adapter_core_1.Adapter {
964
947
  object: { ...full },
965
948
  state: { ...full },
966
949
  file: { ...full },
967
- users: { ...none },
950
+ users: { list: true, read: true, write: false, create: false, delete: false },
968
951
  other: { execute: false, http: true, sendto: true },
969
952
  };
970
953
  }
@@ -972,7 +955,7 @@ class Admin extends adapter_core_1.Adapter {
972
955
  object: { list: true, read: true, write: true, create: true, delete: true },
973
956
  state: { list: true, read: true, write: true, create: false, delete: false },
974
957
  file: { list: true, read: true, write: false, create: false, delete: false },
975
- users: { ...none },
958
+ users: { list: true, read: true, write: false, create: false, delete: false },
976
959
  other: { execute: false, http: true, sendto: true },
977
960
  };
978
961
  }
@@ -1119,10 +1102,10 @@ class Admin extends adapter_core_1.Adapter {
1119
1102
  },
1120
1103
  native: {
1121
1104
  nexowattEosAccount: {
1122
- passwordInitialized: false,
1123
- passwordSetupVersion: 0,
1124
- forcePasswordChange: true,
1125
- passwordlessFirstLoginAllowed: true,
1105
+ passwordInitialized: true,
1106
+ passwordSetupVersion: 1,
1107
+ forcePasswordChange: false,
1108
+ passwordlessFirstLoginAllowed: false,
1126
1109
  provisionedBy: 'NexoWatt EOS',
1127
1110
  provisionedAt: new Date().toISOString(),
1128
1111
  },
@@ -1153,7 +1136,7 @@ class Admin extends adapter_core_1.Adapter {
1153
1136
  }
1154
1137
  if (String(user.common.password || '') === '') {
1155
1138
  const bootstrapSecret = `${(0, node_crypto_1.randomBytes)(48).toString('base64url')}!aA1`;
1156
- await (0, eosPassword_1.setEosUserPasswordWithVerification)(this, userId, bootstrapSecret, ADMIN_OWNER_USER);
1139
+ await this.setPasswordAsync(userId.replace(/^system\.user\./, ''), bootstrapSecret, { user: ADMIN_OWNER_USER });
1157
1140
  user = (await this.getForeignObjectAsync(userId));
1158
1141
  if (!user) {
1159
1142
  return;
@@ -1198,11 +1181,9 @@ class Admin extends adapter_core_1.Adapter {
1198
1181
  const endUsers = ['system.user.guest', 'system.user.user', 'system.user.endkunde', 'system.user.kunde'];
1199
1182
  for (const userId of installerUsers) {
1200
1183
  await this.addUserToEosGroup(userId, installerGroup);
1201
- await this.prepareEosPasswordlessFirstLogin(userId);
1202
1184
  }
1203
1185
  for (const userId of endUsers) {
1204
1186
  await this.addUserToEosGroup(userId, endUserGroup);
1205
- await this.prepareEosPasswordlessFirstLogin(userId);
1206
1187
  }
1207
1188
  }
1208
1189
  async refreshEosRoleCache() {
@@ -1211,9 +1192,7 @@ class Admin extends adapter_core_1.Adapter {
1211
1192
  const priorities = { enduser: 1, installer: 2, admin: 3 };
1212
1193
  const assign = (userId, role) => {
1213
1194
  const current = next.get(userId);
1214
- if (!current || priorities[role] > priorities[current]) {
1215
- next.set(userId, role);
1216
- }
1195
+ if (!current || priorities[role] > priorities[current]) next.set(userId, role);
1217
1196
  };
1218
1197
  for (const [roleName, groupIds] of [
1219
1198
  ['admin', this.getEosRoleGroupIds('service')],
@@ -1222,29 +1201,15 @@ class Admin extends adapter_core_1.Adapter {
1222
1201
  ['admin', ['system.group.administrator']],
1223
1202
  ]) {
1224
1203
  for (const groupId of groupIds) {
1225
- const group = (await this.getForeignObjectAsync(groupId));
1226
- for (const member of group?.common?.members || []) {
1227
- assign(member, roleName);
1228
- }
1204
+ const group = await this.getForeignObjectAsync(groupId);
1205
+ for (const member of group?.common?.members || []) assign(member, roleName);
1229
1206
  }
1230
1207
  }
1231
1208
  this.eosRoleCache.clear();
1232
1209
  this.eosPasswordSetupRequired.clear();
1233
- for (const [userId, role] of next.entries()) {
1234
- this.eosRoleCache.set(userId, role);
1235
- if (role === 'admin') {
1236
- continue;
1237
- }
1238
- const user = (await this.getForeignObjectAsync(userId));
1239
- const native = (user?.native || {});
1240
- const account = (native.nexowattEosAccount || {});
1241
- const initialized = account.passwordInitialized === true
1242
- || Number(account.passwordSetupVersion || account.passwordInitializationVersion || 0) >= 1;
1243
- if (account.forcePasswordChange === true || !initialized) {
1244
- this.eosPasswordSetupRequired.add(userId);
1245
- }
1246
- }
1210
+ for (const [userId, role] of next.entries()) this.eosRoleCache.set(userId, role);
1247
1211
  }
1212
+
1248
1213
  getEosCachedRole(userId) {
1249
1214
  if (userId === 'system.user.admin') {
1250
1215
  return 'admin';
@@ -1279,9 +1244,6 @@ class Admin extends adapter_core_1.Adapter {
1279
1244
  if (role === 'admin') {
1280
1245
  return original(socketClient, command, callback, ...args);
1281
1246
  }
1282
- if (userId && this.eosPasswordSetupRequired.has(userId)) {
1283
- return deny(socketClient, command, callback, 'personal password setup is required');
1284
- }
1285
1247
  if (command === 'cmdExec') {
1286
1248
  if (role !== 'installer') {
1287
1249
  return deny(socketClient, command, callback, 'raw command execution is Service-only');
@@ -1304,6 +1266,16 @@ class Admin extends adapter_core_1.Adapter {
1304
1266
  if (role === 'enduser' && ['readLogs', 'sendToHost'].includes(command)) {
1305
1267
  return deny(socketClient, command, callback, 'technical diagnostics are installer/service-only');
1306
1268
  }
1269
+ if (command === 'changePassword') {
1270
+ const targetRaw = String(args[0] || '').trim();
1271
+ const targetUser = targetRaw.startsWith('system.user.') ? targetRaw : `system.user.${targetRaw}`;
1272
+ const selfUser = String(userId || '');
1273
+ const allowed = role === 'installer'
1274
+ ? new Set([selfUser, 'system.user.installer', 'system.user.user', 'system.user.guest']).has(targetUser)
1275
+ : targetUser === selfUser;
1276
+ if (!allowed) return deny(socketClient, command, callback, 'password target outside EOS role scope');
1277
+ return true;
1278
+ }
1307
1279
  if (['addUser', 'delUser', 'addGroup', 'delGroup'].includes(command)) {
1308
1280
  return deny(socketClient, command, callback, 'account administration is Service-only');
1309
1281
  }
package/io-package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "common": {
3
3
  "name": "eos-admin",
4
- "version": "7.10.0",
4
+ "version": "7.10.2",
5
5
  "titleLang": {
6
6
  "en": "NexoWatt EOS Admin",
7
7
  "de": "NexoWatt EOS Admin",
@@ -18,6 +18,21 @@
18
18
  "connectionType": "local",
19
19
  "dataSource": "push",
20
20
  "news": {
21
+ "7.10.2": {
22
+ "de": "Stable-Hotfix 7.10.2 beseitigt die EOS-Admin-Startschleife: Stable-Update-Status wird nicht mehr in die laufende Instanzkonfiguration geschrieben, der erste Abgleich startet verzögert und das Release prüft die vollständige Backend-Modulkette einschließlich eosRequestSecurity.",
23
+ "en": "Stable hotfix 7.10.2 removes the EOS Admin restart loop: stable-update status is no longer written to the running instance configuration, first reconciliation is delayed, and the release validates the complete backend module chain including eosRequestSecurity.",
24
+ "nl": "Stable-hotfix 7.10.2 verhelpt de EOS Admin-herstartlus: de status van stabiele updates wordt niet meer naar de configuratie van de actieve instantie geschreven, de eerste synchronisatie start vertraagd en de release controleert de volledige backendmoduleketen inclusief eosRequestSecurity."
25
+ },
26
+ "7.10.1": {
27
+ "de": "Stable-Kandidat 7.10.1 basiert wieder auf 7.9.98: native Passwortverwaltung ohne erzwungene Erstpasswortseite, dauerhafter Cockpit-Scrollbereich, Stift im unteren Kartenbereich und abschaltbare NexoWatt-Stable-Updates.",
28
+ "en": "Stable candidate 7.10.1 returns to the 7.9.98 baseline: native password management without forced first-password page, persistent cockpit scrolling, in-grid edit control and optional NexoWatt stable updates.",
29
+ "nl": "Stable-kandidaat 7.10.1 keert terug naar de 7.9.98-basis: native wachtwoordbeheer zonder verplichte eerste-wachtwoordpagina, blijvend cockpit-scrollen, bewerken in het onderste kaartgebied en uitschakelbare NexoWatt-stabiele updates."
30
+ },
31
+ "7.9.98": {
32
+ "de": "Stable-Kandidat 7.9.98 ergänzt den vertikalen Cockpit-Scrollbereich, bereinigt die Login-Felder und korrigiert Passwort-Reset sowie persönliche Erstpasswortvergabe über die echte ioBroker-Passwort-API.",
33
+ "en": "Stable candidate 7.9.98 adds vertical cockpit scrolling, cleans up login fields and fixes password reset plus first personal password setup through the real ioBroker password API.",
34
+ "nl": "Stable-kandidaat 7.9.98 voegt verticaal scrollen in het cockpit toe, herstelt de loginvelden en corrigeert wachtwoordreset en het eerste persoonlijke wachtwoord via de echte ioBroker-wachtwoord-API."
35
+ },
21
36
  "7.9.95": {
22
37
  "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
38
  "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.",
@@ -329,7 +344,7 @@
329
344
  "icon": "admin.svg",
330
345
  "messagebox": true,
331
346
  "enabled": true,
332
- "extIcon": "https://unpkg.com/iobroker.eos-admin@7.10.0/admin/admin.svg",
347
+ "extIcon": "https://unpkg.com/iobroker.eos-admin@7.10.2/admin/admin.svg",
333
348
  "keywords": [
334
349
  "NexoWatt",
335
350
  "EOS",
@@ -340,7 +355,7 @@
340
355
  "licensed"
341
356
  ],
342
357
  "compact": true,
343
- "readme": "https://unpkg.com/iobroker.eos-admin@7.10.0/README.md",
358
+ "readme": "https://unpkg.com/iobroker.eos-admin@7.10.2/README.md",
344
359
  "authors": [
345
360
  "NexoWatt"
346
361
  ],
@@ -408,7 +423,7 @@
408
423
  "nondeletable": false,
409
424
  "allowAdapterUpdate": true,
410
425
  "allowAdapterDelete": false,
411
- "meta": "https://unpkg.com/iobroker.eos-admin@7.10.0/io-package.json",
426
+ "meta": "https://unpkg.com/iobroker.eos-admin@7.10.2/io-package.json",
412
427
  "npmPackage": "iobroker.eos-admin",
413
428
  "packetName": "iobroker.eos-admin",
414
429
  "publisher": "NexoWatt"
@@ -538,7 +553,7 @@
538
553
  "enabled": true
539
554
  }
540
555
  ],
541
- "eosRequireFirstLoginPassword": true,
556
+ "eosRequireFirstLoginPassword": false,
542
557
  "eosFirstLoginPasswordMinLength": 10,
543
558
  "eosAutoAssignDefaultRoleUsers": true,
544
559
  "eosPasswordlessFirstLogin": false,
@@ -547,7 +562,7 @@
547
562
  "eosHideLegacyBackupFromNonAdmins": true,
548
563
  "nexowattHideLegacyBackupFromNonAdmins": true,
549
564
  "eosAllowPasswordlessFirstLogin": false,
550
- "eosRequireFirstLoginPasswordChange": true,
565
+ "eosRequireFirstLoginPasswordChange": false,
551
566
  "eosAutoAssignStandardAccounts": true,
552
567
  "eosAssistEnabled": false,
553
568
  "eosNexoWattAutoUpdate": true
@@ -838,6 +853,56 @@
838
853
  },
839
854
  "native": {}
840
855
  },
856
+ {
857
+ "_id": "info.nexowattStableUpdatesEnabled",
858
+ "type": "state",
859
+ "common": {
860
+ "name": {
861
+ "en": "NexoWatt stable automatic updates enabled",
862
+ "de": "Automatische NexoWatt-Stable-Updates aktiviert",
863
+ "ru": "Автоматические стабильные обновления NexoWatt включены",
864
+ "pt": "Atualizações estáveis automáticas da NexoWatt ativadas",
865
+ "nl": "Automatische stabiele NexoWatt-updates ingeschakeld",
866
+ "fr": "Mises à jour stables automatiques NexoWatt activées",
867
+ "it": "Aggiornamenti stabili automatici NexoWatt abilitati",
868
+ "es": "Actualizaciones estables automáticas de NexoWatt activadas",
869
+ "pl": "Automatyczne stabilne aktualizacje NexoWatt włączone",
870
+ "uk": "Автоматичні стабільні оновлення NexoWatt увімкнено",
871
+ "zh-cn": "已启用 NexoWatt 稳定版自动更新"
872
+ },
873
+ "role": "switch.enable",
874
+ "type": "boolean",
875
+ "read": true,
876
+ "write": false,
877
+ "def": true
878
+ },
879
+ "native": {}
880
+ },
881
+ {
882
+ "_id": "info.nexowattStableUpdatesState",
883
+ "type": "state",
884
+ "common": {
885
+ "name": {
886
+ "en": "NexoWatt stable automatic update runtime state",
887
+ "de": "Laufzeitstatus der automatischen NexoWatt-Stable-Updates",
888
+ "ru": "Состояние автоматических стабильных обновлений NexoWatt",
889
+ "pt": "Estado das atualizações estáveis automáticas da NexoWatt",
890
+ "nl": "Runtime-status van automatische stabiele NexoWatt-updates",
891
+ "fr": "État des mises à jour stables automatiques NexoWatt",
892
+ "it": "Stato degli aggiornamenti stabili automatici NexoWatt",
893
+ "es": "Estado de las actualizaciones estables automáticas de NexoWatt",
894
+ "pl": "Stan automatycznych stabilnych aktualizacji NexoWatt",
895
+ "uk": "Стан автоматичних стабільних оновлень NexoWatt",
896
+ "zh-cn": "NexoWatt 稳定版自动更新运行状态"
897
+ },
898
+ "role": "json",
899
+ "type": "json",
900
+ "read": true,
901
+ "write": false,
902
+ "def": "{}"
903
+ },
904
+ "native": {}
905
+ },
841
906
  {
842
907
  "_id": "info.newsFeed",
843
908
  "type": "state",
@@ -1118,5 +1183,5 @@
1118
1183
  }
1119
1184
  }
1120
1185
  },
1121
- "version": "7.10.0"
1186
+ "version": "7.10.2"
1122
1187
  }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "iobroker.eos-admin",
3
- "description": "NexoWatt EOS Admin – stable candidate with native NexoWatt auto updates, reliable account passwords, clean login and scrollable cockpit.",
4
- "version": "7.10.0",
3
+ "description": "NexoWatt EOS Admin – repaired stable baseline with restart-safe automatic updates, native account passwords and persistent cockpit scrolling.",
4
+ "version": "7.10.2",
5
5
  "contributors": [
6
6
  "bluefox <dogafox@gmail.com>",
7
7
  "apollon77",
@@ -118,27 +118,27 @@
118
118
  "tools/nexowatt-version-sync-selftest.cjs",
119
119
  "tools/nexowatt-merge-update-selftest.cjs",
120
120
  "tools/nexowatt-ems-overview-selftest.cjs",
121
- "README_STABILITY_V7.10.0.md",
122
- "RELEASE_NOTES_V7.10.0.md",
123
- "PUBLISH_STABLE_V7.10.0.md",
124
- "INSTALL_TEST_V7.10.0.md",
125
- "RELEASE_ACCEPTANCE_V7.10.0.md",
126
- "MERGE_UPDATE_README_V7.10.0.md",
127
121
  "README_EMS_OVERVIEW_MERGE.md",
128
122
  "RC73_EOS_ADMIN_MERGE_VALIDATION.md",
129
123
  "VALIDATION_EMS_OVERVIEW_MERGE.md",
130
124
  "NexoWatt_EOS_Admin_EMS_OVERVIEW_MERGE_VALIDATION.md",
131
125
  "tools/nexowatt-apply-ems-overview.cjs",
132
126
  "tools/nexowatt-ui-overview-runtime-selftest.cjs",
133
- "tools/nexowatt-stable-v7100-selftest.cjs",
134
127
  "tools/nexowatt-password-write-selftest.cjs",
135
- "tools/nexowatt-request-security-selftest.cjs",
136
- "tools/nexowatt-cache-update-selftest.cjs",
137
- "src/lib/eosAutoUpdate.ts",
138
- "build/lib/eosAutoUpdate.js",
139
- "adminWww/js/eos-auto-update.js",
128
+ "tools/nexowatt-account-password-flow-selftest.cjs",
129
+ "tools/nexowatt-auto-update-selftest.cjs",
140
130
  "adminWww/css/eos-auto-update.css",
141
- "tools/nexowatt-auto-update-selftest.cjs"
131
+ "adminWww/js/eos-auto-update.js",
132
+ "tools/nexowatt-backend-runtime-selftest.cjs",
133
+ "NEXOWATT_EOS_PREBUILT_MANIFEST.json",
134
+ "tools/nexowatt-prebuilt-release-selftest.cjs",
135
+ "tools/nexowatt-stable-v7102-selftest.cjs",
136
+ "README_STABILITY_V7.10.2.md",
137
+ "RELEASE_NOTES_V7.10.2.md",
138
+ "PUBLISH_STABLE_V7.10.2.md",
139
+ "INSTALL_TEST_V7.10.2.md",
140
+ "RELEASE_ACCEPTANCE_V7.10.2.md",
141
+ "MERGE_UPDATE_README_V7.10.2.md"
142
142
  ],
143
143
  "scripts": {
144
144
  "npm": "npm i -f && cd src-admin && npm i -f",
@@ -149,8 +149,8 @@
149
149
  "test:integration": "mocha test/integration --exit && npm run test:gui && npm run test:rule && npm run test:unit",
150
150
  "test:rule": "mocha test/rule --exit",
151
151
  "test:gui": "mocha test/*.gui.js --exit",
152
- "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",
153
- "build": "npm run build:frontend && npm run build:backend && npm run clean:eos-runtime",
152
+ "prepublishOnly": "npm run sync:eos-version && npm run prepare:eos-release-defaults && npm run clean:eos-runtime && npm run check:eos-publish-channel && npm run check:eos-package && npm run check:eos-stability",
153
+ "build": "npm run build:frontend && npm run build:backend && npm run clean:eos-runtime && npm run seal:eos-prebuilt-release",
154
154
  "build:backend": "tsc -p tsconfig.build.json && tsx tasks.mts --backend-i18n",
155
155
  "build:frontend": "tsx tasks.mts",
156
156
  "clean": "rimraf src-admin/build",
@@ -173,12 +173,12 @@
173
173
  "nexowatt:repo-entry": "node tools/nexowatt-generate-repo-entry.cjs",
174
174
  "nexowatt:patch-repo": "node tools/nexowatt-patch-repo.cjs",
175
175
  "nexowatt:repair-update": "node tools/nexowatt-repair-eos-admin-update.cjs",
176
- "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-cache-update-selftest.cjs && node tools/nexowatt-auto-update-selftest.cjs && node tools/nexowatt-request-security-selftest.cjs && node tools/nexowatt-password-write-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-v7100 && node tools/nexowatt-ems-overview-selftest.cjs && node tools/nexowatt-ui-overview-runtime-selftest.cjs",
176
+ "check:eos-stability": "node tools/nexowatt-stability-check.cjs && node tools/nexowatt-esm-syntax-selftest.cjs && node tools/nexowatt-backend-runtime-selftest.cjs && node tools/nexowatt-prebuilt-release-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-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 && node tools/nexowatt-password-write-selftest.cjs && node tools/nexowatt-account-password-flow-selftest.cjs && npm run check:eos-stable-v7102 && node tools/nexowatt-ems-overview-selftest.cjs && node tools/nexowatt-ui-overview-runtime-selftest.cjs && node tools/nexowatt-auto-update-selftest.cjs",
177
177
  "nexowatt:patch-built-frontend": "node tools/nexowatt-patch-built-frontend.cjs",
178
178
  "clean:eos-runtime": "node tools/nexowatt-clean-legacy-runtime.cjs",
179
179
  "precheck:eos-package": "npm run sync:eos-version && npm run prepare:eos-release-defaults && npm run clean:eos-runtime",
180
180
  "precheck:eos-stability": "npm run sync:eos-version && npm run prepare:eos-release-defaults && npm run clean:eos-runtime",
181
- "prepack": "node tools/nexowatt-sync-release-version.cjs --quiet && node tools/nexowatt-clean-legacy-runtime.cjs --quiet",
181
+ "prepack": "node tools/nexowatt-sync-release-version.cjs --quiet && node tools/nexowatt-ensure-release-defaults.cjs && node tools/nexowatt-clean-legacy-runtime.cjs --quiet && node tools/nexowatt-prebuilt-release-selftest.cjs",
182
182
  "check:eos-esm": "node tools/nexowatt-esm-syntax-selftest.cjs",
183
183
  "check:eos-imports": "node tools/nexowatt-import-integrity-selftest.cjs",
184
184
  "check:eos-release": "npm run check:eos-package && npm run check:eos-stability && npm pack --dry-run",
@@ -197,11 +197,10 @@
197
197
  "sync:eos-version": "node tools/nexowatt-sync-release-version.cjs",
198
198
  "test:eos-version-sync": "node tools/nexowatt-version-sync-selftest.cjs",
199
199
  "verify:eos-merge": "node tools/nexowatt-merge-update-selftest.cjs",
200
- "test:eos-password-write": "node tools/nexowatt-password-write-selftest.cjs",
201
- "test:eos-request-security": "node tools/nexowatt-request-security-selftest.cjs",
202
- "test:eos-cache-update": "node tools/nexowatt-cache-update-selftest.cjs",
203
- "check:eos-auto-update": "node tools/nexowatt-auto-update-selftest.cjs",
204
- "check:eos-stable-v7100": "node tools/nexowatt-stable-v7100-selftest.cjs"
200
+ "check:eos-backend-runtime": "node tools/nexowatt-backend-runtime-selftest.cjs",
201
+ "check:eos-stable-v7102": "node tools/nexowatt-stable-v7102-selftest.cjs",
202
+ "check:eos-prebuilt-release": "node tools/nexowatt-prebuilt-release-selftest.cjs",
203
+ "seal:eos-prebuilt-release": "node tools/nexowatt-prebuilt-release-selftest.cjs --write"
205
204
  },
206
205
  "author": "NexoWatt",
207
206
  "private": false,
@@ -212,7 +211,7 @@
212
211
  },
213
212
  "nexowattReleasePolicy": {
214
213
  "distTag": "latest",
215
- "purpose": "accepted stable NexoWatt EOS sales-product release 7.10.0"
214
+ "purpose": "accepted stable NexoWatt EOS sales-product candidate 7.10.2"
216
215
  },
217
216
  "publisher": "NexoWatt"
218
217
  }
@@ -1,23 +1,19 @@
1
1
  #!/usr/bin/env node
2
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 json=rel=>JSON.parse(read(rel));
4
- const fail=m=>{console.error(`[NexoWatt EOS account management] ${m}`);process.exit(1)};const must=(c,m)=>{if(!c)fail(m)};
5
- const mainSource=read('src/main.ts'),mainBuilt=read('build/main.js'),webSource=read('src/lib/web.ts'),webBuilt=read('build/lib/web.js'),passwordSource=read('src/lib/eosPassword.ts');
6
- const sourceUi=read('src-admin/public/js/eos-account-management.js'),builtUi=read('adminWww/js/eos-account-management.js'),roleUi=read('adminWww/js/eos-role-ui.js'),css=read('adminWww/css/nexowatt-native-shell.css'),index=read('adminWww/index.html'),info=json('NEXOWATT_EOS_BUILD_INFO.json'),shellTag=String(info.shellCacheTag||info.shellCacheVersion);
7
- for(const code of [mainSource,mainBuilt])for(const marker of ['system.user.installer','system.user.guest','ensureEosDefaultRoleUsers','unknown random bootstrap secret','personal password setup is required'])must(code.includes(marker),`main marker missing: ${marker}`);
3
+ const fs=require('fs');const path=require('path');const root=path.resolve(__dirname,'..');const read=rel=>fs.readFileSync(path.join(root,rel),'utf8');const json=rel=>JSON.parse(read(rel));let bad=false;const fail=msg=>{console.error(`[NexoWatt EOS account management] ${msg}`);bad=true;};
4
+ const mainSource=read('src/main.ts'),mainBuilt=read('build/main.js'),webSource=read('src/lib/web.ts'),webBuilt=read('build/lib/web.js'),sourceUi=read('src-admin/public/js/eos-account-management.js'),builtUi=read('adminWww/js/eos-account-management.js'),roleUi=read('adminWww/js/eos-role-ui.js'),css=read('adminWww/css/nexowatt-native-shell.css'),index=read('adminWww/index.html'),info=json('NEXOWATT_EOS_BUILD_INFO.json'),shellTag=String(info.shellCacheTag||info.shellCacheVersion);
5
+ for(const code of [mainSource,mainBuilt])for(const marker of ['system.user.installer','system.user.guest','ensureEosDefaultRoleUsers','unknown random bootstrap secret','eosPasswordSetupRequired','personal password setup is required'])if(!code.includes(marker))fail(`main marker missing: ${marker}`);
8
6
  for(const code of [webSource,webBuilt]){
9
- for(const marker of ['getEosManagedAccounts','sendEosAccountManagement','resetEosAccountPassword','/nexowatt/account/manage','/nexowatt/account/reset','x-nexowatt-eos-account-reset','canResetInstaller','canResetEndUser',"targetUserId === 'system.user.admin'",'targetUserId === access.userId','const managedAccounts = await this.getEosManagedAccounts(access.role)','const managedTarget = managedAccounts.find(account => account.id === targetUserId)',"managedTarget?.role === 'installer'","managedTarget?.role === 'enduser'",'passwordResetAt','passwordResetBy',"passwordResetMode = 'initial-password'","setEosUserPassword(targetUserId, 'nexowatt')",'passwordlessFirstLoginAllowed = false','initialPasswordRequired: true','accountDisabled','passwordMetadataNotPersisted']) must(code.includes(marker),`web marker missing: ${marker}`);
10
- must(!code.includes('const explicitInstaller = targetAccess.groups.some'),'obsolete explicit installer re-classifier remains');
11
- must(!code.includes('const explicitEndUser = targetAccess.groups.some'),'obsolete explicit end-user re-classifier remains');
12
- must(!code.includes('setForeignObjectAsync(targetUserId, user)'),'reset still writes stale full user object');
7
+ for(const marker of ['getEosManagedAccounts','sendEosAccountManagement','resetEosAccountPassword','/nexowatt/account/manage','/nexowatt/account/reset','x-nexowatt-eos-account-reset','canResetInstaller','canResetEndUser',"targetUserId === 'system.user.admin'",'targetUserId === access.userId',"access.role === 'installer' && explicitlyManagedRole !== 'enduser'",'passwordResetAt','passwordResetBy',"passwordResetMode = 'initial-password'","setEosUserPassword(targetUserId, 'nexowatt')",'passwordlessFirstLoginAllowed = false','initialPasswordRequired: true','accountDisabled','getEosPasswordUserName','setPasswordAsync(userName, password','checkPasswordAsync(userName, password','updateEosAccountMetadata','extendForeignObjectAsync','invalidRequestOrigin'])if(!code.includes(marker))fail(`web marker missing: ${marker}`);
8
+ if(!code.includes('const explicitInstaller = targetAccess.groups.some')||!code.includes('const explicitEndUser = targetAccess.groups.some'))fail('explicit managed-group guard missing');
9
+ const reset=code.slice(code.indexOf('resetEosAccountPassword'),code.indexOf('getEosHistoryInstances'));
10
+ if(reset.includes('setForeignObjectAsync(targetUserId'))fail('reset replaces the complete user object after password write');
13
11
  }
14
- for(const marker of ['apiTarget: normalized.userId','apiTarget: normalized.userName','verifyAfterWrite','passwordNotPersisted','passwordVerificationFailed'])must(passwordSource.includes(marker),`password helper marker missing: ${marker}`);
15
- for(const marker of ["VERSION = 'v7100-account-management-password-write'","['admin', 'installer']",'nexowatt/account/manage','nexowatt/account/reset','X-NexoWatt-EOS-Account-Reset','data.canResetInstaller === true',"account.role === 'enduser'",'Admin/Service','Installateure','NEXOWATT_EOS_ACCOUNT_MANAGEMENT','ensureEntrySurface',"currentRoute() !== 'tab-users'",'eos-account-management-entry','Startpasswort „nexowatt“','passwordVerificationFailed'])must(sourceUi.includes(marker),`UI marker missing: ${marker}`);
16
- must(sourceUi===builtUi,'account management source/build drift');
17
- must(!sourceUi.includes("launcher.className = 'eos-account-management-launcher'"),'standalone account launcher remains');
18
- must(!sourceUi.includes('new MutationObserver'),'account management adds a broad observer');
19
- must(roleUi.includes("route === 'tab-users'"),'installer cannot reach Zugänge & Rechte');
20
- must(!roleUi.includes('NEXOWATT_EOS_ACCOUNT_MANAGEMENT.open'),'overview opens account management outside Zugänge & Rechte');
21
- must(index.includes(`eos-account-management.js?v=${shellTag}`),'account management cache tag stale');
22
- for(const marker of ['.eos-account-management-entry','.eos-account-management-overlay','.eos-account-management-dialog','.eos-account-row','.eos-account-reset','html.eos-account-page-installer'])must(css.includes(marker),`CSS marker missing: ${marker}`);
23
- console.log('[NexoWatt EOS account management] OK (managed-list authorization and real password reset)');
12
+ for(const marker of ['v98-account-management-real-password-write',"['admin', 'installer']",'nexowatt/account/manage','nexowatt/account/reset','X-NexoWatt-EOS-Account-Reset','data.canResetInstaller === true',"account.role === 'enduser'",'Startpasswort „nexowatt“','accountErrorText','invalidRequestOrigin','credentials: \'include\'','NEXOWATT_EOS_ACCOUNT_MANAGEMENT','ensureEntrySurface',"currentRoute() !== 'tab-users'",'eos-account-management-entry'])if(!sourceUi.includes(marker))fail(`account UI marker missing: ${marker}`);
13
+ if(sourceUi.includes("launcher.className = 'eos-account-management-launcher'"))fail('standalone account launcher remains');
14
+ if(sourceUi.includes('new MutationObserver'))fail('account management adds a second broad MutationObserver');
15
+ if(sourceUi!==builtUi)fail('account UI source/build drift');
16
+ if(!roleUi.includes("route === 'tab-users'"))fail('installer cannot reach access page');
17
+ if(!index.includes(`eos-account-management.js?v=${shellTag}`))fail('account asset cache tag mismatch');
18
+ for(const marker of ['.eos-account-management-entry','.eos-account-management-overlay','.eos-account-management-dialog','.eos-account-row','.eos-account-reset'])if(!css.includes(marker))fail(`account CSS missing: ${marker}`);
19
+ if(bad)process.exit(1);console.log('[NexoWatt EOS account management] OK');
@@ -0,0 +1,15 @@
1
+ #!/usr/bin/env node
2
+ 'use strict';
3
+ const fs=require('node:fs'),path=require('node:path');const root=path.resolve(__dirname,'..');const read=r=>fs.readFileSync(path.join(root,r),'utf8');const fail=m=>{console.error('[NexoWatt EOS standard password flow] '+m);process.exit(1)};const must=(v,m)=>{if(!v)fail(m)};
4
+ const source=read('src/main.ts'),built=read('build/main.js'),boot=read('adminWww/js/eos-role-bootstrap.js'),role=read('adminWww/js/eos-role-ui.js'),index=read('adminWww/index.html'),io=JSON.parse(read('io-package.json'));
5
+ for(const code of [source,built]){
6
+ must(code.includes("EOS_STABLE_INITIAL_PASSWORD = 'nexowatt'"),'initial password constant missing');
7
+ must(code.includes("if (created || !String(object.common?.password || '').trim())")||code.includes("if (created || !String(object.common?.password || '').trim())"),'password is not limited to new/passwordless accounts');
8
+ for(const marker of ['nexowattPasswordChangeRequired: false','eosPasswordChangeRequired: false','nexowattFirstLoginPending: false','eosFirstLoginRequired: false','forcePasswordChange: false','standardPasswordMode: true']) must(code.includes(marker),`legacy first-login flag is not cleared: ${marker}`);
9
+ must(code.includes("command === 'changePassword'")&&code.includes('password target outside EOS role scope'),'native password command role guard missing');
10
+ }
11
+ must(io.native.eosRequireFirstLoginPassword===false&&io.native.eosRequireFirstLoginPasswordChange===false,'forced first-password defaults remain');
12
+ must(!boot.includes('installIntegratedFirstLogin(base);')&&!boot.includes('showFirstLoginPassword(resolved, base);'),'forced password surface remains active');
13
+ must(!index.includes('eos-account-management.js'),'custom reset runtime remains active');
14
+ must(role.includes('filterNativeUsersPage')&&role.includes("route === 'tab-users'"),'role-scoped native Users page missing');
15
+ console.log('[NexoWatt EOS standard password flow] OK (nexowatt only on creation, native password editor, no forced reset flow)');
@@ -52,7 +52,7 @@ if (!css.includes(cssMarker)) {
52
52
  overflow: hidden;
53
53
  }
54
54
  .eos-ems-overview-card * { box-sizing: border-box; }
55
- .eos-ems-overview-header { display:flex; align-items:flex-start; justify-content:flex-start; gap:20px; }
55
+ .eos-ems-overview-header { display:flex; align-items:flex-start; justify-content:space-between; gap:20px; }
56
56
  .eos-ems-overview-header h2 { margin:5px 0 6px; font-size:clamp(1.2rem,2vw,1.65rem); color:#f5fbff; }
57
57
  .eos-ems-overview-header p { margin:0; max-width:760px; color:#9eb2c2; line-height:1.45; }
58
58
  .eos-ems-overview-eyebrow { color:#49e39e; font-size:.72rem; font-weight:900; letter-spacing:.13em; text-transform:uppercase; }
@@ -83,7 +83,9 @@ if (!css.includes(cssMarker)) {
83
83
  .eos-ems-overview-event time { color:#6f8799; font-size:.68rem; font-variant-numeric:tabular-nums; }
84
84
  .eos-ems-overview-event div { display:grid; gap:2px; min-width:0; }
85
85
  .eos-ems-overview-empty { color:#718797; font-size:.76rem; }
86
- .eos-ems-overview-footer { display:flex; justify-content:flex-start; gap:12px; margin-top:12px; color:#60798a; font-size:.67rem; }
86
+ .eos-ems-overview-footer { display:flex; justify-content:space-between; gap:12px; margin-top:12px; color:#60798a; font-size:.67rem; }
87
+ .eos-ems-overview-footer a { color:#5ee0c2; font-weight:800; text-decoration:none; }
88
+ .eos-ems-overview-footer a:hover,.eos-ems-overview-footer a:focus-visible { color:#9af2dd; text-decoration:underline; }
87
89
  @media (max-width: 1100px) {
88
90
  .eos-ems-overview-card { flex-basis:100%; max-width:none; }
89
91
  }