iobroker.eos-admin 7.10.5 → 7.10.7

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.
@@ -0,0 +1,9 @@
1
+ # Installation test 7.10.7
2
+
3
+ - Install/update EOS Admin 7.10.7 and verify port 8081 remains reachable.
4
+ - Sign in as Admin: all previous functions, datapoint writes, expert mode, Admin and XTerm remain available.
5
+ - Sign in as Installer: **EMS Apps öffnen** is visible and opens the EMS App-Center.
6
+ - Installer: Simulation and License remain hidden/blocked; expert head, ioBroker Admin, XTerm and Users/Rights remain unavailable.
7
+ - Sign in as End User: EMS App-Center, Simulation and License remain hidden/blocked; datapoints remain read-only.
8
+ - Confirm an End User cannot inherit an existing UI/Admin session on port 8188.
9
+ - Confirm navigation editing and backup visibility behavior remain restart-safe.
@@ -0,0 +1,7 @@
1
+ # Merge/update note 7.10.7
2
+
3
+ Always replace the previous repository with the complete 7.10.7 repository. Do not merge old `adminWww` role runtime files back into this release.
4
+
5
+ The authoritative role policy in 7.10.7 allows the Installer to use the EMS App-Center, while Simulation and License remain Admin-only and the End User remains blocked.
6
+
7
+ After a merge, run package validation, stability checks, role-security checks and `npm publish --dry-run` before publishing.
@@ -1,32 +1,28 @@
1
1
  {
2
- "version": "7.10.5",
2
+ "version": "7.10.7",
3
3
  "channel": "stable-latest",
4
- "baseFrontend": "validated v84 runtime with authoritative RBAC, restored administrator rights and restart-safe navigation layout",
4
+ "baseFrontend": "validated v84 runtime with authoritative RBAC, End User read-only UI and Installer EMS App-Center access",
5
5
  "runtimeEntry": "v84",
6
- "releaseType": "stable-admin-rights-rbac-navigation",
7
- "release": "stable-admin-rights-rbac-navigation",
8
- "label": "v7-10-5",
6
+ "releaseType": "stable-installer-ems-appcenter",
7
+ "release": "stable-installer-ems-appcenter",
8
+ "label": "v7-10-7",
9
9
  "notes": [
10
- "Administrator authority is derived only from the authenticated backend security context; DOM text is never used to classify a role.",
11
- "Admin keeps full datapoint write access, all overview cards and reversible expert mode.",
12
- "Installer and End User do not see ioBroker Admin, XTerm, App Center, License, Simulation or account administration.",
13
- "End User can open Datapoints in read-only mode; backend socket writes are denied independently of the browser.",
14
- "Navigation visibility/order is stored in eos-admin.0.info.uiTabsVisible and no longer modifies system.config or restarts the adapter.",
15
- "Backup navigation is shown only while a supported backup instance is enabled."
10
+ "Administrator authority and all Admin controls remain unchanged.",
11
+ "Installer may open and use the EMS App-Center.",
12
+ "Simulation and License remain Administrator-only.",
13
+ "End User App-Center blocking, read-only datapoints and port 8188 session scrubbing remain active."
16
14
  ],
17
15
  "changes": [
18
- "Removed the legacy DOM-text role heuristic that could downgrade system.user.admin to End User.",
19
- "Added explicit Admin bypass regression guards in source, backend runtime and frontend bundles.",
20
- "Added End User-only ObjectBrowser read-only wiring while retaining Admin/Installer native write controls.",
21
- "Moved menu layout persistence away from system.config into a dedicated adapter state.",
22
- "Hid Admin/XTerm cards only for restricted roles and forced them visible for Admin.",
23
- "Protected App Center, License and Simulation in the authenticated role layer and cleared inherited UI-admin sessions for non-admin roles."
16
+ "Split privileged UI actions into EMS, Simulation and License categories.",
17
+ "Allowed EMS App-Center actions for Admin and Installer only.",
18
+ "Kept Simulation and License actions Administrator-only.",
19
+ "Raised the release and browser cache identity to 7.10.7 / 7107."
24
20
  ],
25
- "brandingCacheVersion": 7105,
26
- "shellCacheVersion": 7105,
27
- "nativeShellVersion": 7105,
28
- "shellCacheTag": "7105",
29
- "repositoryEntry": "nexowatt-eos-admin-repository-entry-v7-10-5.json",
21
+ "brandingCacheVersion": 7107,
22
+ "shellCacheVersion": 7107,
23
+ "nativeShellVersion": 7107,
24
+ "shellCacheTag": "7107",
25
+ "repositoryEntry": "nexowatt-eos-admin-repository-entry-v7-10-7.json",
30
26
  "autoUpdateCacheVersion": 7103,
31
27
  "autoUpdateCacheTag": "7103"
32
28
  }
@@ -1,9 +1,9 @@
1
1
  {
2
2
  "format": 1,
3
3
  "package": "iobroker.eos-admin",
4
- "version": "7.10.5",
4
+ "version": "7.10.7",
5
5
  "algorithm": "sha256",
6
- "fileCount": 1389,
6
+ "fileCount": 1391,
7
7
  "trackedRoots": [
8
8
  "src",
9
9
  "build",
@@ -552,7 +552,7 @@
552
552
  "adminWww/img/le.png": "ef5ebb7112926f646e781a326b639f56888fafe0891b9b000178091b4f8ed9dd",
553
553
  "adminWww/img/logo.svg": "1167118074ff84d8cef82ad80c38609719dacfde9417126e46966c1ec986534b",
554
554
  "adminWww/img/no-image.svg": "25fc382f4ad3a36f8a637cd966b9107368e1f11906d706102ad5f37db6f57f34",
555
- "adminWww/index.html": "9358ac35e93087ed79e3c00ec54899fde92938c438eb86231328d5f08d3ea965",
555
+ "adminWww/index.html": "4ab35f356321beb1b578ceb42c0c441569822c05c50a94cf09896b77ece9cfd9",
556
556
  "adminWww/js/adapter-settings.js": "fb2e538a3385899f7fd47275ec588051c735d8f778a44b89f40f5eb820a31dbc",
557
557
  "adminWww/js/eos-account-management.js": "dbba398605b2391ac1a7ec97cf7eb84da7f929ea16bfb6761750cd700a687fbe",
558
558
  "adminWww/js/eos-assistant.js": "be43f49fd5310d2962365035556c37109d4868856e874e1f964c4b2f05bb6beb",
@@ -563,11 +563,11 @@
563
563
  "adminWww/js/eos-manual-write-policy.js": "3c93487146b4fd5f681aa45a6bb137d9a91c3fa145ebfa94ec5ccb6b15498e8b",
564
564
  "adminWww/js/eos-native-security.js": "33098b98164623fc133314658bca2f622d19971795dd8bd3c90aca68598aab90",
565
565
  "adminWww/js/eos-policy-client.js": "5ffd32270307137fbec69a9b9bea57ca1d2e27ede987ce1eb37ff1df6677d8d2",
566
- "adminWww/js/eos-role-bootstrap.js": "f7f6f4c816cbf694f8e24d812a2aa8e7c84a42af6ad2274f44bf24debcfec63f",
567
- "adminWww/js/eos-role-ui.js": "93424c5959159dd44421365a277b26c2c941f7d418eac4eae36547364cc10afb",
566
+ "adminWww/js/eos-role-bootstrap.js": "74dbc9246cbfd977d95be5af959686a71e439ac016ab70a9f5c62384792c2833",
567
+ "adminWww/js/eos-role-ui.js": "b4aa21c0664efd4b7ecd2a439f24547317162b4985abdd17f13df0d8d1c6c82d",
568
568
  "adminWww/js/license.js": "13798e577c82d7a5549b07a244b8b8453ef43e53fc7789f565c35b56e6654007",
569
569
  "adminWww/js/listHeader.js": "ed336a68a64e16a062d1af2269428fd20a08a4b695f17635f55a18bc1ef693a4",
570
- "adminWww/js/nexowatt-native-shell.js": "c0d327669ba12ba3b8e6fc4d1a17eb7092e59a0b23a2852161714c2b214dde15",
570
+ "adminWww/js/nexowatt-native-shell.js": "9fe37b190543d070f99d838a0833e1428ff430deafab371208aec697eceaddb4",
571
571
  "adminWww/js/tableEditor.js": "5508044619fec70071895d0ae3ab6ff75dd03bd936e7b133f98d098d4245ec20",
572
572
  "adminWww/js/translate.js": "264442c0f42a10148057125532bf55b7672c4cc051c28e7cbb922984a558f8d3",
573
573
  "adminWww/js/treeTable.js": "8abde0b7880a89f6f927a87bb041945dea1502f51bc9870d8ba0be9d3dd9eed8",
@@ -747,7 +747,7 @@
747
747
  "adminWww/static/js/html.js": "159b7192459d73d92761dab8c4d48e138e94e4d8e7bf99004bac257e403a0c3b",
748
748
  "adminWww/static/js/javascript.js": "6287a6b820c8707a0cd7b9e4545bcb023a8b9228569cfd21be6635d1409aabf4",
749
749
  "adminWww/static/js/nexowatt-stable-login.js": "ff0c6d4dc2086f3ab4be8ef455e5891a2ccb5f534bddfacbef2f5cd6ce65489e",
750
- "adminWww/static/js/nexowatt-stable-v7105.js": "35d329e37a698a71d2825fe1bcbcee4e1073249a59aa56a3c645cf9623461600",
750
+ "adminWww/static/js/nexowatt-stable-v7107.js": "3ba5e1587b3e0129afe054fbbdd321b80cbde050ce1b75d0e42889fd2ffede19",
751
751
  "adminWww/static/js/worker-css.js": "83c767cacd6b190e2f083b139cb3f124d1b560afbd7a6dbb74bf5539aa4cadee",
752
752
  "adminWww/static/js/worker-html.js": "661d2448443c0089fba31d2829d77761a5fc042035c38433eff0e20707f17457",
753
753
  "adminWww/static/js/worker-javascript.js": "73fcf007e2d19eacba8f365719ee92d14345505b03f9cf66e6338aef02fccd21",
@@ -793,7 +793,7 @@
793
793
  "build/lib/translations.js.map": "c74bcf48d2dd6ec58c48d48a7fb39c59a84fd58c25095bc0cb5bb46c88cfe24f",
794
794
  "build/lib/utils.js": "b013a5df06f95ed5bfcb851bb87c0617f61f70e6fe7f1fbf2402fd4d0aadec9b",
795
795
  "build/lib/utils.js.map": "74238d0d82cc28d41c4f627b73793f6cda26b338ef1bd97916b6417783949e29",
796
- "build/lib/web.js": "8de94dffdd7c70be6b537c111691c831116338b311f7569739de57f9a32e071f",
796
+ "build/lib/web.js": "f7d0adebfe5b7890f09d3b5eff986cd564724cc7a8497048dc670b43d69b1d90",
797
797
  "build/lib/web.js.map": "5fb9f337f3a27c04bb4303cb61ffa5f0da857299a7d2890609eb5f55f24f1789",
798
798
  "build/main.js": "7578ee14ea840950ad5164b0063c091c983528ebc32689dec5dc499062fbc92e",
799
799
  "build/main.js.map": "1cd3887da9b3d4061c59b6ad497c536c6c9a79938b10bbddf7128a1e7930dfbd",
@@ -850,11 +850,11 @@
850
850
  "src-admin/public/js/eos-manual-write-policy.js": "3c93487146b4fd5f681aa45a6bb137d9a91c3fa145ebfa94ec5ccb6b15498e8b",
851
851
  "src-admin/public/js/eos-native-security.js": "33098b98164623fc133314658bca2f622d19971795dd8bd3c90aca68598aab90",
852
852
  "src-admin/public/js/eos-policy-client.js": "5ffd32270307137fbec69a9b9bea57ca1d2e27ede987ce1eb37ff1df6677d8d2",
853
- "src-admin/public/js/eos-role-bootstrap.js": "f7f6f4c816cbf694f8e24d812a2aa8e7c84a42af6ad2274f44bf24debcfec63f",
854
- "src-admin/public/js/eos-role-ui.js": "93424c5959159dd44421365a277b26c2c941f7d418eac4eae36547364cc10afb",
853
+ "src-admin/public/js/eos-role-bootstrap.js": "74dbc9246cbfd977d95be5af959686a71e439ac016ab70a9f5c62384792c2833",
854
+ "src-admin/public/js/eos-role-ui.js": "b4aa21c0664efd4b7ecd2a439f24547317162b4985abdd17f13df0d8d1c6c82d",
855
855
  "src-admin/public/js/license.js": "13798e577c82d7a5549b07a244b8b8453ef43e53fc7789f565c35b56e6654007",
856
856
  "src-admin/public/js/listHeader.js": "ed336a68a64e16a062d1af2269428fd20a08a4b695f17635f55a18bc1ef693a4",
857
- "src-admin/public/js/nexowatt-native-shell.js": "c0d327669ba12ba3b8e6fc4d1a17eb7092e59a0b23a2852161714c2b214dde15",
857
+ "src-admin/public/js/nexowatt-native-shell.js": "9fe37b190543d070f99d838a0833e1428ff430deafab371208aec697eceaddb4",
858
858
  "src-admin/public/js/tableEditor.js": "5508044619fec70071895d0ae3ab6ff75dd03bd936e7b133f98d098d4245ec20",
859
859
  "src-admin/public/js/translate.js": "264442c0f42a10148057125532bf55b7672c4cc051c28e7cbb922984a558f8d3",
860
860
  "src-admin/public/js/treeTable.js": "8abde0b7880a89f6f927a87bb041945dea1502f51bc9870d8ba0be9d3dd9eed8",
@@ -975,7 +975,7 @@
975
975
  "src-admin/public/manifest.json": "15244d5d50f08420fc5d4793e5699e99c7b900b6908cfbc00a7182f4d4db55bd",
976
976
  "src-admin/public/robots.txt": "90d24bc3bf698ac1e173739502298ccca72adf1f564fab05f484b8c48d1cadd2",
977
977
  "src-admin/public/static/js/nexowatt-stable-login.js": "ff0c6d4dc2086f3ab4be8ef455e5891a2ccb5f534bddfacbef2f5cd6ce65489e",
978
- "src-admin/public/static/js/nexowatt-stable-v7105.js": "35d329e37a698a71d2825fe1bcbcee4e1073249a59aa56a3c645cf9623461600",
978
+ "src-admin/public/static/js/nexowatt-stable-v7107.js": "3ba5e1587b3e0129afe054fbbdd321b80cbde050ce1b75d0e42889fd2ffede19",
979
979
  "src-admin/src/App.tsx": "8ab367389c604d5face72cc71da49b08021ffa2e566db4d32df9ad98f9fe762a",
980
980
  "src-admin/src/Workers/AdaptersWorker.tsx": "3a2cdeb8010598c901df0e3cffcdae913e62e7ac7c84fcadf15cb7f961dc6ed9",
981
981
  "src-admin/src/Workers/GenericWorker.tsx": "3b3c6e7856602477c54d1dc085aa23b5cfcac7784cc73710b00622ac04ed5a97",
@@ -1323,7 +1323,7 @@
1323
1323
  "src-admin/src/tabs/Objects.tsx": "2b87a8a7e771e10e1cce49019c4be62578f10096eee5abd17d2685f5f41cc67c",
1324
1324
  "src-admin/src/tabs/Users.tsx": "45ed37e57b66f7e23eb465aef9ad9db55613b40bf44530ab81d6206806de102d",
1325
1325
  "src-admin/src/types.d.ts": "3cfac48af5f8416b55b89c0daca78499dbbd402c0b44cc661112b76953ba3344",
1326
- "src-admin/src/version.json": "13b5e66c3cd1fe6ee1f5f2cf0c4f921660dea2013644d05822ded200018dd14a",
1326
+ "src-admin/src/version.json": "b2da994816631b24508b9ecde47e77ea9d9463a8ff1afdeda0500219343f75fa",
1327
1327
  "src/i18n/de.json": "85d4ecfedf15d78984922b05377063b808ae8c5a75944af323e72a2c3a483d50",
1328
1328
  "src/i18n/en.json": "6a0156a1b026903821d395ef2ceef845e90531f323a218f97f5abefaabb46a23",
1329
1329
  "src/i18n/es.json": "54369f8044dfa222779849d2f158eb100188a43816d6c42a64575122cb528a30",
@@ -1350,7 +1350,7 @@
1350
1350
  "src/lib/testPassword.ts": "c627432e64b6ed40081e2828af207238bc9e9e1f8b823eaf20c7d3e059c5e938",
1351
1351
  "src/lib/translations.ts": "8fdb51d81c3f98e17e0231f6773381886eb1c68068a3f53dd5e32bf6b58f9d16",
1352
1352
  "src/lib/utils.ts": "5398da6c6a660c4300e2679aa5e001e05297d684cc39bdfab091375768169f30",
1353
- "src/lib/web.ts": "8eae6cc8dc6eb42bc7be5498f91e4064f35564355d7538cfa4d791e7b323ca5e",
1353
+ "src/lib/web.ts": "c4683adc8e32e23280bf6fead41cc7c67ff41982d33e388119b18a7ac9997fb7",
1354
1354
  "src/main.ts": "e9eb8013a229d9616be923850075e8cb5475bde32c882008721225ed37a85a8c",
1355
1355
  "src/types.d.ts": "12117a644a45cb0b551555184126563e80bf909726aa378c7d72327a30c61054",
1356
1356
  "tasks.mts": "84a396f8581e7e3ca499a1c4ce01d22ea29f81700520f804b48a95fb54d72408",
@@ -1375,10 +1375,11 @@
1375
1375
  "tools/nexowatt-generate-eos-admin-repo-entry.cjs": "a8b55d6001b0ed6d97221448b194748945f2e8382cdaf0b11ea91c63fb517139",
1376
1376
  "tools/nexowatt-generate-repo-entry.cjs": "4e98acc7db74546bd942cfa36d57015673c6f1514758494753e7339068f7eb68",
1377
1377
  "tools/nexowatt-import-integrity-selftest.cjs": "f46951126a237a6010c3c0949c25e2415ebe9af568d29411d10691951cb3ed87",
1378
+ "tools/nexowatt-installer-ems-selftest.cjs": "65bbc30d60b4a7e24a7aa599eda256b4361f66c1dd9437c989d549185c43bc79",
1378
1379
  "tools/nexowatt-internal-reserve-selftest.cjs": "f027a2272a4277d65167d68d4ca4428cd0c28a6c6c2b610eda575abd3f2bc90a",
1379
1380
  "tools/nexowatt-login-layout-selftest.cjs": "7d4baae82f1d53fc14446b8ef80aaffa39b0b3529821599f4a6e2c27fbc7a7f2",
1380
1381
  "tools/nexowatt-manual-write-policy-selftest.cjs": "a41057610972d681120bf35e0321029facc08b098c79da9b131980f80bd3fdce",
1381
- "tools/nexowatt-merge-update-selftest.cjs": "66d250def2c372cceb0fda42b0dc756557d8cdcf268f73a2ff7c68de4522e36a",
1382
+ "tools/nexowatt-merge-update-selftest.cjs": "f8abe1505e4dd8ade64577825e8c67ae3828892493c613a566ea353b668bfaaf",
1382
1383
  "tools/nexowatt-modern-ui-selftest.cjs": "0145adc4b7d84e996f227dee02c09f767ab9a29bb2151041a50b88bb27a5b93a",
1383
1384
  "tools/nexowatt-module-popup-selftest.cjs": "31f02e8cf0bfd61d7769e1095c93887a34cfbbd76a9805ef4931cea6dff53ddf",
1384
1385
  "tools/nexowatt-native-shell-selftest.cjs": "13aabd3a19f0c0422bbc1c676718685b77c88a526167a7b511fa6c9ab2ac860c",
@@ -1391,20 +1392,21 @@
1391
1392
  "tools/nexowatt-publish-channel-selftest.cjs": "c4efd1104ebe471ce1dc63195f322cffe760af295bf60f13b9766491acd0280e",
1392
1393
  "tools/nexowatt-release-defaults-selftest.cjs": "3e3c96ca774200461978c546d1a937cbae18d7f11497ed84dda639c2358f6e16",
1393
1394
  "tools/nexowatt-repair-eos-admin-update.cjs": "f28c1999b0f75139e582770ad649d17d11f9e909ac49d13c31be5fa5b36253e3",
1394
- "tools/nexowatt-role-access-selftest.cjs": "b855b69cb74a5124c9a5a22b811a5209f70f32979a776401897f7fe910f794e9",
1395
- "tools/nexowatt-role-security-selftest.cjs": "b5b21f3c80f69b03f9c95fb26e11b2706aac86534048ac7251a5275dfcbde6e2",
1395
+ "tools/nexowatt-role-access-selftest.cjs": "50e972f331b2c54640964b5dcf0eb0becc51439cf78d24fd76be45cf5a7db3be",
1396
+ "tools/nexowatt-role-security-selftest.cjs": "9dc69a6154b86f2fd3b7d28f4f7ae3b97bcb50e652d97fb6c7d090ba82ea2e84",
1396
1397
  "tools/nexowatt-runtime-cleanup-selftest.cjs": "f317b09aa0c51ffe7e1b5eaf10c52c886804ec6e8084967cd88e4ebece6ecfb5",
1397
- "tools/nexowatt-stability-check.cjs": "087c74c3f050ebfe3b092cc74a4b99b6e66813d57b0d2065f92fbddcb9e2ed9e",
1398
+ "tools/nexowatt-stability-check.cjs": "f9b79766c54f6b47a2ef475206180d9895045a4adb794d8eeab1e1de49113d51",
1398
1399
  "tools/nexowatt-stable-v7101-selftest.cjs": "817d09861ef29c52a67f64ec5b8f4ad4654ce7e6486eded786bb16f3c773eaf8",
1399
1400
  "tools/nexowatt-stable-v7102-selftest.cjs": "75baab5f8069569ad4896e5018f3c5ccbbda2c2297aca5c5146bce94f9cf795d",
1400
- "tools/nexowatt-stable-v7103-selftest.cjs": "80491789e636375c21e22335de08c8b4892c056e3fb703f1d5368e81105074b0",
1401
+ "tools/nexowatt-stable-v7103-selftest.cjs": "c2ba0387363fcc6de164b28df1d6c0d1eabc4636b6e6a734ed3a76a0fff1d78c",
1401
1402
  "tools/nexowatt-stable-v94-selftest.cjs": "5226881b3ad8918c67921ffb37716490f053ec88e7c0f24827a5eda7c75d4019",
1402
1403
  "tools/nexowatt-stable-v95-selftest.cjs": "0b15fcd329eb2994e64c407ab04eaafab7c38c4688136c197bf9601e1c35ee07",
1403
1404
  "tools/nexowatt-stable-v97-selftest.cjs": "4f50ad6e53b8de7eb045d56657cccd846883eacd8a877d51240d78153ba53d80",
1404
1405
  "tools/nexowatt-sync-release-version.cjs": "2478d714533ece21a275071ef6e5467f73c2fa33d0a63d76f408dc048a86c6f6",
1405
1406
  "tools/nexowatt-ui-overview-runtime-selftest.cjs": "83255e5d3c9a548013f6e9a74706644d15d98450d0bfa2eb3da83c740d8618ea",
1406
1407
  "tools/nexowatt-update-selftest.cjs": "c38c454135f98de683de8fa15fc4b9032063823f0f55fcfc8b675f551fd342f5",
1407
- "tools/nexowatt-validate-package.cjs": "4995d6db92d59ba4cdb1ed6481304deae348f644064e86fbf81384405e36b851",
1408
+ "tools/nexowatt-user-area-selftest.cjs": "0936141466414f020a7d4df60d81ee1d1cfc9bd3a8d4aa9bb361a71b7bdf5b45",
1409
+ "tools/nexowatt-validate-package.cjs": "956ed5a7b00a8d908c12d396b28eee879560dcb6155fde8540d7fc502416fb2f",
1408
1410
  "tools/nexowatt-value-column-selftest.cjs": "29d0a9bbea05a87dcf8ee09c86cc81acb6c59e1e34801890768f5e342083871a",
1409
1411
  "tools/nexowatt-version-sync-selftest.cjs": "65d7c8634b6d5581f337365e13a1a9432c7d47dbf5aebc237886730c32ba5e94",
1410
1412
  "tsconfig.build.json": "d3a31263975a13de77b97af9ff246d89931f3abb594047be2739cf11378b97f5",
@@ -0,0 +1,9 @@
1
+ # NPM publication 7.10.7
2
+
3
+ 1. Use a freshly extracted repository ZIP.
4
+ 2. Run `npm publish --dry-run`.
5
+ 3. Confirm version `7.10.7`, complete `build/` runtime and all active `adminWww` runtime files.
6
+ 4. Verify the Installer EMS self-test and role-security self-test are successful.
7
+ 5. Publish with `npm publish` only after the dry run succeeds.
8
+
9
+ No `npm install`, `npm ci`, `tsc` or `tsx` is required for the sealed prebuilt release.
@@ -0,0 +1,7 @@
1
+ # NexoWatt EOS Admin 7.10.7 – stability and RBAC baseline
2
+
3
+ This release retains the validated crash, package, update-placement, Admin-rights and End User read-only fixes from 7.10.2–7.10.6.
4
+
5
+ Role decisions continue to come exclusively from the authenticated `/nexowatt/security/context` response. Administrator remains the unconditional full-rights path. End User datapoints remain read-only in frontend and backend. Installer receives EMS App-Center access, while Simulation, License, expert mode, ioBroker Admin, XTerm and account administration remain restricted.
6
+
7
+ Menu edits continue to use the adapter state and must never write `system.config`.
@@ -0,0 +1,12 @@
1
+ # Release Acceptance 7.10.7
2
+
3
+ - [ ] Admin retains unrestricted access and all existing controls.
4
+ - [ ] Installer can open and use the EMS App-Center.
5
+ - [ ] Installer cannot open Simulation or License.
6
+ - [ ] Installer does not see expert mode, ioBroker Admin, XTerm or Users/Rights.
7
+ - [ ] End User cannot open EMS App-Center, Simulation or License.
8
+ - [ ] End User datapoints remain read-only and action icons remain hidden.
9
+ - [ ] End User session scrubbing on port 8188 remains active.
10
+ - [ ] Pencil navigation edits do not restart EOS Admin.
11
+ - [ ] Backup navigation follows the enabled state of the backup instance.
12
+ - [ ] `npm publish --dry-run` succeeds from a fresh extraction.
@@ -0,0 +1,19 @@
1
+ # NexoWatt EOS Admin 7.10.7
2
+
3
+ ## Installateurbereich
4
+
5
+ - Der Installateur kann **EMS Apps öffnen** und das EMS App-Center wie der Administrator verwenden.
6
+ - Die Freigabe gilt ausschließlich für das EMS App-Center.
7
+ - Simulation und Lizenzverwaltung bleiben ausschließlich für Administratoren verfügbar.
8
+ - Der Installateur erhält weiterhin keinen Expertenmodus, keinen ioBroker-Admin-Zugang, kein XTerm und keine Benutzer-/Rechteverwaltung.
9
+
10
+ ## Bestehende Rollen bleiben unverändert
11
+
12
+ - Administrator: vollständige Rechte und alle bisherigen Funktionen.
13
+ - Endkunde: Datenpunkte nur lesend; App-Center, Simulation und Lizenz bleiben vollständig gesperrt.
14
+ - Der Endkunden-Sitzungsschutz auf Port 8188 bleibt aktiv; nur der Installateur wird davon für die EMS-Nutzung ausgenommen.
15
+
16
+ ## Veröffentlichung
17
+
18
+ - Neue npm-Version 7.10.7, da 7.10.6 bereits veröffentlicht ist.
19
+ - Release-Dateien, Browser-Cache-Tags, Repository-Eintrag und Prebuilt-Manifest sind auf 7.10.7 synchronisiert.
@@ -1,12 +1,14 @@
1
- # NexoWatt EOS role matrix 7.10.5
1
+ # NexoWatt EOS role matrix 7.10.7
2
2
 
3
3
  | Capability | Admin | Installer | End User |
4
4
  |---|---:|---:|---:|
5
5
  | Datapoints read | Yes | Yes | Yes |
6
6
  | Datapoints write/edit | Yes | Yes | No |
7
+ | EMS App-Center | Yes | Yes | No |
8
+ | Simulation | Yes | No | No |
9
+ | License administration | Yes | No | No |
7
10
  | Expert mode | Yes | No | No |
8
11
  | ioBroker Admin / XTerm | Yes | No | No |
9
- | App Center / License / Simulation | Yes | No | No |
10
12
  | Users, groups, passwords | Yes | No | No |
11
13
  | Smart Home structure | Yes | Yes | Yes |
12
14
  | Navigation layout editing | Yes | No | No |
@@ -8,7 +8,7 @@
8
8
  <meta http-equiv="Cache-Control" content="no-store, no-cache, must-revalidate" />
9
9
  <meta http-equiv="Pragma" content="no-cache" />
10
10
  <meta http-equiv="Expires" content="0" />
11
- <script src="./js/eos-manual-write-policy.js?v=7105"></script>
11
+ <script src="./js/eos-manual-write-policy.js?v=7107"></script>
12
12
  <script type="module" src="./assets/hostInit-v84.js?v=84"></script>
13
13
 
14
14
  <meta charset="utf-8" />
@@ -36,8 +36,8 @@
36
36
  rel="stylesheet"
37
37
  href="css/leaflet.css"
38
38
  />
39
- <link rel="stylesheet" href="./css/nexowatt-native-shell.css?v=7105" />
40
- <link rel="stylesheet" href="./css/eos-ems-overview.css?v=7105" />
39
+ <link rel="stylesheet" href="./css/nexowatt-native-shell.css?v=7107" />
40
+ <link rel="stylesheet" href="./css/eos-ems-overview.css?v=7107" />
41
41
  <link rel="stylesheet" href="./css/eos-auto-update.css?v=7103" />
42
42
  <link
43
43
  rel="manifest"
@@ -160,22 +160,22 @@
160
160
  </script>
161
161
  <link rel="modulepreload" crossorigin href="./assets/preload-helper-BDBacUwf.js">
162
162
  <link rel="modulepreload" crossorigin href="./assets/iobroker_admin__mf_v__runtimeInit__mf_v__-g2X2zhAf.js">
163
- <script defer src="./js/eos-role-bootstrap.js?v=7105" data-eos-entry="./assets/index-CQZugZ1z-v84.js?v=84"></script>
164
- <script defer src="./js/eos-policy-client.js?v=7105"></script>
165
- <script defer src="./js/eos-branding-sanitizer.js?v=7105"></script>
166
- <script defer src="./js/nexowatt-native-shell.js?v=7105"></script>
167
- <script defer src="./js/eos-native-security.js?v=7105"></script>
168
- <script defer src="./js/eos-basic-settings.js?v=7105"></script>
169
- <script defer src="./js/eos-role-ui.js?v=7105"></script>
170
- <script defer src="./js/eos-ems-overview.js?v=7105"></script>
163
+ <script defer src="./js/eos-role-bootstrap.js?v=7107" data-eos-entry="./assets/index-CQZugZ1z-v84.js?v=84"></script>
164
+ <script defer src="./js/eos-policy-client.js?v=7107"></script>
165
+ <script defer src="./js/eos-branding-sanitizer.js?v=7107"></script>
166
+ <script defer src="./js/nexowatt-native-shell.js?v=7107"></script>
167
+ <script defer src="./js/eos-native-security.js?v=7107"></script>
168
+ <script defer src="./js/eos-basic-settings.js?v=7107"></script>
169
+ <script defer src="./js/eos-role-ui.js?v=7107"></script>
170
+ <script defer src="./js/eos-ems-overview.js?v=7107"></script>
171
171
 
172
172
  <script defer src="./js/eos-auto-update.js?v=7103"></script>
173
- <script defer src="./js/eos-assistant.js?v=7105"></script>
173
+ <script defer src="./js/eos-assistant.js?v=7107"></script>
174
174
  </head>
175
175
  <body>
176
176
  <noscript>Für NexoWatt EOS muss JavaScript aktiviert sein.</noscript>
177
177
  <div id="root"></div>
178
- <script defer src="static/js/nexowatt-stable-login.js?v=7105"></script>
179
- <script defer src="static/js/nexowatt-stable-v7105.js?v=7105"></script>
178
+ <script defer src="static/js/nexowatt-stable-login.js?v=7107"></script>
179
+ <script defer src="static/js/nexowatt-stable-v7107.js?v=7107"></script>
180
180
  </body>
181
181
  </html>
@@ -1,7 +1,7 @@
1
1
  (() => {
2
2
  'use strict';
3
3
 
4
- const VERSION = 'v7105-admin-authoritative-rbac';
4
+ const VERSION = 'v7107-admin-authoritative-rbac';
5
5
  const script = document.currentScript || document.querySelector('script[src*="eos-role-bootstrap.js"]');
6
6
  const entry = script?.dataset?.eosEntry || '';
7
7
  let launched = false;
@@ -1,7 +1,7 @@
1
1
  (() => {
2
2
  'use strict';
3
3
 
4
- const VERSION = 'v7105-admin-authoritative-rbac';
4
+ const VERSION = 'v7107-installer-ems-rbac';
5
5
  window.NEXOWATT_EOS_ROLE_UI_VERSION = VERSION;
6
6
 
7
7
  const state = {
@@ -15,10 +15,13 @@
15
15
  reserveObserver: null,
16
16
  reservePaper: null,
17
17
  reserveScheduled: false,
18
+ readonlySystemInfo: null,
19
+ readonlySystemInfoPromise: null,
18
20
  };
19
21
  const abort = new AbortController();
20
22
 
21
23
  const safe = fn => { try { return fn(); } catch (_) { return undefined; } };
24
+ const escapeHtml = value => String(value ?? '').replace(/[&<>"']/g, match => ({ '&': '&amp;', '<': '&lt;', '>': '&gt;', '"': '&quot;', "'": '&#39;' }[match] || match));
22
25
  const normalize = value => String(value || '')
23
26
  .toLowerCase().normalize('NFD').replace(/[\u0300-\u036f]/g, '').replace(/ß/g, 'ss')
24
27
  .replace(/[^a-z0-9#/_:.-]+/g, ' ').trim();
@@ -268,6 +271,55 @@
268
271
  role.setAttribute('data-nexowatt-overview-role', state.role);
269
272
  }
270
273
  };
274
+
275
+ const fetchReadonlySystemInfo = () => {
276
+ if (state.readonlySystemInfo) return Promise.resolve(state.readonlySystemInfo);
277
+ if (state.readonlySystemInfoPromise) return state.readonlySystemInfoPromise;
278
+ state.readonlySystemInfoPromise = fetch('/nexowatt/readonly/system-info', {
279
+ credentials: 'same-origin',
280
+ cache: 'no-store',
281
+ headers: { Accept: 'application/json' },
282
+ })
283
+ .then(response => (response.ok ? response.json() : null))
284
+ .then(data => {
285
+ state.readonlySystemInfo = data && typeof data === 'object' ? data : null;
286
+ return state.readonlySystemInfo;
287
+ })
288
+ .catch(() => null)
289
+ .finally(() => {
290
+ state.readonlySystemInfoPromise = null;
291
+ scheduleApply();
292
+ });
293
+ return state.readonlySystemInfoPromise;
294
+ };
295
+ const applyReadonlySystemInfoCard = () => safe(() => {
296
+ if (state.role !== 'enduser' || currentRoute() !== 'tab-intro') return;
297
+ const paper = appPaper();
298
+ if (!paper) return;
299
+ const title = Array.from(paper.querySelectorAll('h1,h2,h3,h4,h5,h6')).find(node => normalize(node.textContent || '') === 'nexowatt');
300
+ const card = title?.closest?.('.MuiCard-root');
301
+ if (!card || !/platform|ram|node\.js|npm/i.test(String(card.textContent || ''))) return;
302
+ Array.from(card.querySelectorAll('button')).forEach(button => {
303
+ if (/info/i.test(textOf(button))) {
304
+ button.classList.add('eos-role-hidden');
305
+ button.setAttribute('aria-hidden', 'true');
306
+ button.disabled = true;
307
+ }
308
+ });
309
+ if (!state.readonlySystemInfo && !state.readonlySystemInfoPromise) {
310
+ void fetchReadonlySystemInfo();
311
+ return;
312
+ }
313
+ const data = state.readonlySystemInfo;
314
+ const list = card.querySelector('ul');
315
+ if (!data || !list) return;
316
+ list.innerHTML = `
317
+ <li><span><span style="font-weight:600">Platform: </span>${escapeHtml(data.platform || '--')}</span></li>
318
+ <li><span><span style="font-weight:600">RAM: </span>${escapeHtml(Number.isFinite(Number(data.ramMb)) ? `${Math.round(Number(data.ramMb))} MB` : '--')}</span></li>
319
+ <li><span><span style="font-weight:600">Node.js: </span>${escapeHtml(data.nodejs || '--')}</span></li>
320
+ <li><span><span style="font-weight:600">NPM: </span>${escapeHtml(data.npm || '--')}</span></li>`;
321
+ });
322
+
271
323
  const hideIntroEditControls = () => {
272
324
  const paper = appPaper();
273
325
  if (!paper) return;
@@ -431,12 +483,26 @@
431
483
 
432
484
 
433
485
  const privilegedFrameObservers = new WeakMap();
434
- const privilegedActionPattern = /^(?:ems apps?(?: offnen| öffnen)?|app center|app-center|appcenter|simulation|simulator|lizenz|license)$/;
435
- const isPrivilegedAction = element => {
486
+ const privilegedActionKind = element => {
436
487
  const signature = normalize(textOf(element));
437
488
  const href = normalize(element?.getAttribute?.('href') || element?.href || element?.getAttribute?.('data-href') || '');
438
- return privilegedActionPattern.test(signature)
439
- || /(?:^|[\/#?&_.-])(?:appcenter|app-center|simulation|simulator|license|lizenz)(?:$|[\/#?&=_.-])/.test(href);
489
+ if (/^(?:ems apps?(?: offnen| öffnen)?|app center|app-center|appcenter)$/.test(signature)
490
+ || /(?:^|[\/#?&_.-])(?:appcenter|app-center)(?:$|[\/#?&=_.-])/.test(href)) return 'ems';
491
+ if (/^(?:simulation|simulator)$/.test(signature)
492
+ || /(?:^|[\/#?&_.-])(?:simulation|simulator)(?:$|[\/#?&=_.-])/.test(href)) return 'simulation';
493
+ if (/^(?:lizenz|license)$/.test(signature)
494
+ || /(?:^|[\/#?&_.-])(?:license|lizenz)(?:$|[\/#?&=_.-])/.test(href)) return 'license';
495
+ return '';
496
+ };
497
+ const isPrivilegedAction = element => !!privilegedActionKind(element);
498
+ const canUsePrivilegedAction = element => {
499
+ const action = privilegedActionKind(element);
500
+ if (!action) return true;
501
+ if (action === 'ems') {
502
+ return state.role === 'admin'
503
+ || (state.role === 'installer' && state.policy?.capabilities?.emsAppCenter !== false);
504
+ }
505
+ return state.role === 'admin';
440
506
  };
441
507
  const setPrivilegedActionHidden = (element, hidden) => {
442
508
  if (!element) return;
@@ -455,19 +521,18 @@
455
521
  };
456
522
  const applyPrivilegedActionsInDocument = doc => safe(() => {
457
523
  if (!doc?.documentElement) return;
458
- const admin = state.role === 'admin';
459
524
  doc.querySelectorAll('[data-eos-privileged-action-hidden="1"]').forEach(element => {
460
- if (admin || !isPrivilegedAction(element)) setPrivilegedActionHidden(element, false);
525
+ if (!isPrivilegedAction(element) || canUsePrivilegedAction(element)) setPrivilegedActionHidden(element, false);
461
526
  });
462
527
  for (const element of doc.querySelectorAll('a,button,[role="button"],[role="tab"],.MuiButtonBase-root')) {
463
- if (isPrivilegedAction(element)) setPrivilegedActionHidden(element, !admin);
528
+ if (isPrivilegedAction(element)) setPrivilegedActionHidden(element, !canUsePrivilegedAction(element));
464
529
  }
465
530
  if (!doc.documentElement.dataset.eosPrivilegedClickGuard) {
466
531
  doc.documentElement.dataset.eosPrivilegedClickGuard = '1';
467
532
  doc.addEventListener('click', event => {
468
- if (state.role === 'admin' || state.role === 'unknown') return;
533
+ if (state.role === 'unknown') return;
469
534
  const target = event.target?.closest?.('a,button,[role="button"],[role="tab"],.MuiButtonBase-root');
470
- if (!target || !isPrivilegedAction(target)) return;
535
+ if (!target || !isPrivilegedAction(target) || canUsePrivilegedAction(target)) return;
471
536
  event.preventDefault();
472
537
  event.stopImmediatePropagation();
473
538
  }, true);
@@ -492,9 +557,9 @@
492
557
  });
493
558
  });
494
559
  const scrubInheritedUiAdminSession = () => safe(() => {
495
- if (state.role === 'admin' || state.role === 'unknown') return;
560
+ if (state.role !== 'enduser') return;
496
561
  const user = String(state.policy?.user || state.policy?.userId || '').replace(/^system\.user\./, '') || state.role;
497
- const key = `eosUiAdminSessionScrubbed:v7105:${user}:${state.role}`;
562
+ const key = `eosUiAdminSessionScrubbed:v7107:${user}:${state.role}`;
498
563
  if (sessionStorage.getItem(key) === '1') return;
499
564
  sessionStorage.setItem(key, '1');
500
565
  const frame = document.createElement('iframe');
@@ -511,11 +576,38 @@
511
576
  if (!paper) return;
512
577
  const readonly = state.role === 'enduser' && currentRoute() === 'tab-objects';
513
578
  paper.toggleAttribute('data-eos-datapoints-readonly', readonly);
579
+ const clearControl = control => {
580
+ if (!control) return;
581
+ control.removeAttribute('aria-disabled');
582
+ control.removeAttribute('data-eos-enduser-write-blocked');
583
+ control.removeAttribute('data-eos-enduser-action-hidden');
584
+ control.classList.remove('eos-role-hidden');
585
+ control.removeAttribute('aria-hidden');
586
+ if ('disabled' in control) control.disabled = false;
587
+ };
588
+ paper.querySelectorAll('[data-eos-enduser-write-blocked="1"],[data-eos-enduser-action-hidden="1"]').forEach(clearControl);
514
589
  if (!readonly) return;
515
- paper.querySelectorAll('[data-eos-object-writable="1"],button[title*="edit" i],button[title*="delete" i],button[aria-label*="edit" i],button[aria-label*="delete" i]').forEach(control => {
590
+ const blockControl = control => {
591
+ if (!control) return;
516
592
  control.setAttribute('aria-disabled', 'true');
517
593
  control.setAttribute('data-eos-enduser-write-blocked', '1');
518
- });
594
+ };
595
+ const hideControl = control => {
596
+ if (!control) return;
597
+ control.setAttribute('aria-disabled', 'true');
598
+ control.setAttribute('data-eos-enduser-action-hidden', '1');
599
+ control.classList.add('eos-role-hidden');
600
+ control.setAttribute('aria-hidden', 'true');
601
+ if ('disabled' in control) control.disabled = true;
602
+ };
603
+ paper.querySelectorAll('[data-eos-object-writable="1"]').forEach(blockControl);
604
+ paper.querySelectorAll([
605
+ 'button[title*="edit" i]','button[title*="delete" i]','button[title*="remove" i]','button[title*="setting" i]','button[title*="einstell" i]',
606
+ 'button[aria-label*="edit" i]','button[aria-label*="delete" i]','button[aria-label*="remove" i]','button[aria-label*="setting" i]','button[aria-label*="einstell" i]',
607
+ '[role="button"][title*="edit" i]','[role="button"][title*="delete" i]','[role="button"][title*="setting" i]',
608
+ '[role="button"][aria-label*="edit" i]','[role="button"][aria-label*="delete" i]','[role="button"][aria-label*="setting" i]'
609
+ ].join(',')).forEach(hideControl);
610
+ paper.querySelectorAll('svg[data-testid*="Edit"],svg[data-testid*="Delete"],svg[data-testid*="Settings"],svg[data-testid*="Tune"],svg[data-testid*="Build"]').forEach(icon => hideControl(icon.closest('button,[role="button"]')));
519
611
  });
520
612
  const clearLegacyHeuristicRestrictionsForAdmin = () => safe(() => {
521
613
  if (state.role !== 'admin') return;
@@ -524,9 +616,10 @@
524
616
  element.removeAttribute('aria-hidden');
525
617
  element.style.removeProperty('display');
526
618
  });
527
- document.querySelectorAll('[data-eos-readonly],[data-eos-enduser-write-blocked]').forEach(element => {
619
+ document.querySelectorAll('[data-eos-readonly],[data-eos-enduser-write-blocked],[data-eos-enduser-action-hidden]').forEach(element => {
528
620
  element.removeAttribute('data-eos-readonly');
529
621
  element.removeAttribute('data-eos-enduser-write-blocked');
622
+ element.removeAttribute('data-eos-enduser-action-hidden');
530
623
  element.removeAttribute('aria-disabled');
531
624
  element.style.removeProperty('pointer-events');
532
625
  element.style.removeProperty('opacity');
@@ -544,6 +637,7 @@
544
637
  clearLegacyHeuristicRestrictionsForAdmin();
545
638
  redirectIfNeeded();
546
639
  ensureSafeOverview();
640
+ applyReadonlySystemInfoCard();
547
641
  filterNativeUsersPage();
548
642
  hideOfficialReserveSurfaces();
549
643
  applyEndUserDatapointPolicy();
@@ -1,7 +1,7 @@
1
1
  (() => {
2
2
  'use strict';
3
3
 
4
- const VERSION = 'v7105-nexowatt-native-shell-native-overview';
4
+ const VERSION = 'v7107-nexowatt-native-shell-native-overview';
5
5
  const previous = window.NEXOWATT_NATIVE_SHELL;
6
6
  if (previous?.version === VERSION) return;
7
7
  previous?.destroy?.();
@@ -1,6 +1,6 @@
1
1
  (() => {
2
2
  'use strict';
3
- const VERSION = 'v7105-scroll-standard-password';
3
+ const VERSION = 'v7107-scroll-standard-password';
4
4
  const ensureScroll = () => {
5
5
  const root = document.documentElement;
6
6
  const paper = document.getElementById('app-paper');
@@ -23,5 +23,5 @@
23
23
  const schedule=()=>{if(scheduled)return;scheduled=true;requestAnimationFrame(()=>{scheduled=false;apply();});};
24
24
  const start=()=>{apply();new MutationObserver(schedule).observe(document.documentElement,{subtree:true,childList:true});window.addEventListener('hashchange',schedule);window.addEventListener('resize',schedule,{passive:true});};
25
25
  document.readyState==='loading'?document.addEventListener('DOMContentLoaded',start,{once:true}):start();
26
- window.NEXOWATT_EOS_STABLE_V7101=Object.freeze({version:VERSION,refresh:apply,ensureScroll});
26
+ window.NEXOWATT_EOS_STABLE_V7107=Object.freeze({version:VERSION,refresh:apply,ensureScroll});
27
27
  })();
package/build/lib/web.js CHANGED
@@ -8,6 +8,7 @@ const node_util_1 = require("node:util");
8
8
  const node_path_1 = require("node:path");
9
9
  const node_os_1 = require("node:os");
10
10
  const node_stream_1 = require("node:stream");
11
+ const node_child_process_1 = require("node:child_process");
11
12
  const compression = require("compression");
12
13
  const mime_1 = require("mime");
13
14
  const node_zlib_1 = require("node:zlib");
@@ -649,6 +650,9 @@ class Web {
649
650
  objectDiagnostics: technical,
650
651
  logDiagnostics: technical,
651
652
  basicSystemSettings: technical,
653
+ emsAppCenter: technical,
654
+ simulation: role === 'admin',
655
+ licenseAdministration: role === 'admin',
652
656
  fullSystemSettings: role === 'admin',
653
657
  expertMode: role === 'admin',
654
658
  userManagement: role === 'admin',
@@ -1371,6 +1375,35 @@ class Web {
1371
1375
  this.adapter.log.info(`EOS installer basic settings updated by ${access.userId || 'unknown user'}`);
1372
1376
  await this.sendEosBasicSettings(req, res);
1373
1377
  }
1378
+
1379
+ getEosReadonlySystemInfo() {
1380
+ let npm = '--';
1381
+ try {
1382
+ const binary = process.platform === 'win32' ? 'npm.cmd' : 'npm';
1383
+ npm = (0, node_child_process_1.execFileSync)(binary, ['-v'], { encoding: 'utf8', timeout: 1500 }).trim() || '--';
1384
+ }
1385
+ catch {
1386
+ // ignore
1387
+ }
1388
+ return {
1389
+ platform: process.platform || '--',
1390
+ ramMb: Math.round((0, node_os_1.totalmem)() / 1024 / 1024),
1391
+ nodejs: process.version || '--',
1392
+ npm,
1393
+ active: true,
1394
+ };
1395
+ }
1396
+ async sendEosReadonlySystemInfo(req, res) {
1397
+ const access = await this.getEosRequestAccess(req);
1398
+ const authenticated = !this.settings.auth || !!access.userId;
1399
+ if (!authenticated) {
1400
+ res.status(401).json({ error: 'authenticationRequired' });
1401
+ return;
1402
+ }
1403
+ res.setHeader('Cache-Control', 'no-store, no-cache, must-revalidate, proxy-revalidate');
1404
+ res.setHeader('Content-Type', 'application/json; charset=utf-8');
1405
+ res.status(200).json(this.getEosReadonlySystemInfo());
1406
+ }
1374
1407
  async sendEosSecuritySession(req, res) {
1375
1408
  res.setHeader('Cache-Control', 'no-store, no-cache, must-revalidate, proxy-revalidate');
1376
1409
  res.setHeader('Content-Type', 'application/json; charset=utf-8');
@@ -1806,6 +1839,10 @@ class Web {
1806
1839
  this.server.app.get('/eos/security/status', sendSecuritySession);
1807
1840
  this.server.app.get('/nexowatt/security/session', sendSecuritySession);
1808
1841
  this.server.app.get('/nexowatt/security/context', sendSecuritySession);
1842
+ this.server.app.get('/nexowatt/readonly/system-info', (req, res) => { void this.sendEosReadonlySystemInfo(req, res).catch(e => {
1843
+ this.adapter.log.warn(`Cannot read EOS readonly system info: ${e instanceof Error ? e.message : e}`);
1844
+ res.status(500).json({ error: 'readonlySystemInfoFailed' });
1845
+ }); });
1809
1846
  this.server.app.get('/nexowatt/role-settings/basic', (req, res) => {
1810
1847
  void this.sendEosBasicSettings(req, res).catch(e => {
1811
1848
  this.adapter.log.warn(`Cannot read EOS basic settings: ${e instanceof Error ? e.message : e}`);
package/io-package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "common": {
3
3
  "name": "eos-admin",
4
- "version": "7.10.5",
4
+ "version": "7.10.7",
5
5
  "titleLang": {
6
6
  "en": "NexoWatt EOS Admin",
7
7
  "de": "NexoWatt EOS Admin",
@@ -18,6 +18,16 @@
18
18
  "connectionType": "local",
19
19
  "dataSource": "push",
20
20
  "news": {
21
+ "7.10.7": {
22
+ "de": "Stable 7.10.7 gibt dem Installateur den Zugriff auf „EMS Apps öffnen“ und das EMS App-Center frei. Simulation und Lizenzverwaltung bleiben ausschließlich dem Administrator vorbehalten. Endkundenbereich, Nur-Lese-Datenpunkte und Adminrechte bleiben unverändert.",
23
+ "en": "Stable 7.10.7 grants the Installer access to “Open EMS Apps” and the EMS App-Center. Simulation and license administration remain Administrator-only. End User read-only datapoints and all Administrator rights remain unchanged.",
24
+ "nl": "Stable 7.10.7 geeft de installateur toegang tot “EMS Apps openen” en het EMS App-Center. Simulatie en licentiebeheer blijven uitsluitend voor beheerders. Alleen-lezen datapunten voor eindgebruikers en alle beheerdersrechten blijven ongewijzigd."
25
+ },
26
+ "7.10.6": {
27
+ "de": "Stable 7.10.6 bereinigt ausschließlich den Endkundenbereich: Datenpunkte bleiben sichtbar und nur lesbar, Bearbeiten-/Löschen-/Einstellungsaktionen werden ausgeblendet, und die Systeminfokarte erhält Plattform, RAM, Node.js und NPM über einen authentifizierten Nur-Lese-Endpunkt. Die Administratoroberfläche und sämtliche Adminrechte bleiben unverändert.",
28
+ "en": "Stable 7.10.6 cleans up the End User area only: datapoints stay visible and read-only, edit/delete/settings actions are hidden, and the system information card receives platform, RAM, Node.js and NPM through an authenticated read-only endpoint. The administrator UI and all Admin rights remain unchanged.",
29
+ "nl": "Stable 7.10.6 ruimt uitsluitend het eindgebruikersgedeelte op: datapunten blijven zichtbaar en alleen-lezen, bewerk-/verwijder-/instellingsacties worden verborgen en de systeeminformatiekaart ontvangt platform, RAM, Node.js en NPM via een geauthenticeerd alleen-lezen eindpunt. De beheerdersinterface en alle beheerdersrechten blijven ongewijzigd."
30
+ },
21
31
  "7.10.5": {
22
32
  "de": "Stable 7.10.5 stellt die vollständigen Administratorrechte wieder her und trennt die Rollen verbindlich über den authentifizierten Backend-Kontext. Admin darf Datenpunkte schreiben, den Expertenmodus in beide Richtungen schalten und sieht Admin-/XTerm-Kacheln. Endkunden sehen Datenpunkte ausschließlich lesend; App-Center, Lizenz, Simulation, Benutzerverwaltung, ioBroker Admin, XTerm und Expertenmodus bleiben für Installateur und Endkunde gesperrt. Navigationsänderungen werden neustartsicher im Adapter-State gespeichert; Sicherung erscheint nur bei aktiver Backup-Instanz.",
23
33
  "en": "Stable 7.10.5 restores full administrator authority and binds roles exclusively to the authenticated backend context. Admin can write datapoints, toggle expert mode in both directions and sees the Admin/XTerm cards. End users can view datapoints read-only; App Center, License, Simulation, account management, ioBroker Admin, XTerm and expert mode remain blocked for Installer and End User. Navigation changes are stored restart-safely in an adapter state, and Backup is shown only for an enabled backup instance.",
@@ -354,7 +364,7 @@
354
364
  "icon": "admin.svg",
355
365
  "messagebox": true,
356
366
  "enabled": true,
357
- "extIcon": "https://unpkg.com/iobroker.eos-admin@7.10.5/admin/admin.svg",
367
+ "extIcon": "https://unpkg.com/iobroker.eos-admin@7.10.7/admin/admin.svg",
358
368
  "keywords": [
359
369
  "NexoWatt",
360
370
  "EOS",
@@ -365,7 +375,7 @@
365
375
  "licensed"
366
376
  ],
367
377
  "compact": true,
368
- "readme": "https://unpkg.com/iobroker.eos-admin@7.10.5/README.md",
378
+ "readme": "https://unpkg.com/iobroker.eos-admin@7.10.7/README.md",
369
379
  "authors": [
370
380
  "NexoWatt"
371
381
  ],
@@ -433,7 +443,7 @@
433
443
  "nondeletable": false,
434
444
  "allowAdapterUpdate": true,
435
445
  "allowAdapterDelete": false,
436
- "meta": "https://unpkg.com/iobroker.eos-admin@7.10.5/io-package.json",
446
+ "meta": "https://unpkg.com/iobroker.eos-admin@7.10.7/io-package.json",
437
447
  "npmPackage": "iobroker.eos-admin",
438
448
  "packetName": "iobroker.eos-admin",
439
449
  "publisher": "NexoWatt"
@@ -1210,5 +1220,5 @@
1210
1220
  }
1211
1221
  }
1212
1222
  },
1213
- "version": "7.10.5"
1223
+ "version": "7.10.7"
1214
1224
  }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "iobroker.eos-admin",
3
3
  "description": "NexoWatt EOS Admin – repaired stable baseline with restart-safe automatic updates, native account passwords and persistent cockpit scrolling.",
4
- "version": "7.10.5",
4
+ "version": "7.10.7",
5
5
  "contributors": [
6
6
  "bluefox <dogafox@gmail.com>",
7
7
  "apollon77",
@@ -133,15 +133,17 @@
133
133
  "NEXOWATT_EOS_PREBUILT_MANIFEST.json",
134
134
  "tools/nexowatt-prebuilt-release-selftest.cjs",
135
135
  "tools/nexowatt-stable-v7103-selftest.cjs",
136
- "README_STABILITY_V7.10.5.md",
137
- "RELEASE_NOTES_V7.10.5.md",
138
- "PUBLISH_STABLE_V7.10.5.md",
139
- "INSTALL_TEST_V7.10.5.md",
140
- "RELEASE_ACCEPTANCE_V7.10.5.md",
141
- "MERGE_UPDATE_README_V7.10.5.md",
136
+ "README_STABILITY_V7.10.7.md",
137
+ "RELEASE_NOTES_V7.10.7.md",
138
+ "PUBLISH_STABLE_V7.10.7.md",
139
+ "INSTALL_TEST_V7.10.7.md",
140
+ "RELEASE_ACCEPTANCE_V7.10.7.md",
141
+ "MERGE_UPDATE_README_V7.10.7.md",
142
142
  "tools/nexowatt-auto-update-placement-selftest.cjs",
143
143
  "tools/nexowatt-role-security-selftest.cjs",
144
- "SECURITY_ROLE_MATRIX_V7.10.5.md"
144
+ "SECURITY_ROLE_MATRIX_V7.10.7.md",
145
+ "tools/nexowatt-user-area-selftest.cjs",
146
+ "tools/nexowatt-installer-ems-selftest.cjs"
145
147
  ],
146
148
  "scripts": {
147
149
  "npm": "npm i -f && cd src-admin && npm i -f",
@@ -176,7 +178,7 @@
176
178
  "nexowatt:repo-entry": "node tools/nexowatt-generate-repo-entry.cjs",
177
179
  "nexowatt:patch-repo": "node tools/nexowatt-patch-repo.cjs",
178
180
  "nexowatt:repair-update": "node tools/nexowatt-repair-eos-admin-update.cjs",
179
- "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-v7103 && node tools/nexowatt-ems-overview-selftest.cjs && node tools/nexowatt-ui-overview-runtime-selftest.cjs && node tools/nexowatt-auto-update-selftest.cjs && node tools/nexowatt-auto-update-placement-selftest.cjs && node tools/nexowatt-role-security-selftest.cjs",
181
+ "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-v7103 && node tools/nexowatt-ems-overview-selftest.cjs && node tools/nexowatt-ui-overview-runtime-selftest.cjs && node tools/nexowatt-auto-update-selftest.cjs && node tools/nexowatt-auto-update-placement-selftest.cjs && node tools/nexowatt-role-security-selftest.cjs && node tools/nexowatt-user-area-selftest.cjs && node tools/nexowatt-installer-ems-selftest.cjs",
180
182
  "nexowatt:patch-built-frontend": "node tools/nexowatt-patch-built-frontend.cjs",
181
183
  "clean:eos-runtime": "node tools/nexowatt-clean-legacy-runtime.cjs",
182
184
  "precheck:eos-package": "npm run sync:eos-version && npm run prepare:eos-release-defaults && npm run clean:eos-runtime",
@@ -205,7 +207,8 @@
205
207
  "seal:eos-prebuilt-release": "node tools/nexowatt-prebuilt-release-selftest.cjs --write",
206
208
  "check:eos-stable-v7103": "node tools/nexowatt-stable-v7103-selftest.cjs",
207
209
  "test:eos-auto-update-placement": "node tools/nexowatt-auto-update-placement-selftest.cjs",
208
- "check:eos-role-security": "node tools/nexowatt-role-security-selftest.cjs"
210
+ "check:eos-role-security": "node tools/nexowatt-role-security-selftest.cjs",
211
+ "test:eos-installer-ems": "node tools/nexowatt-installer-ems-selftest.cjs"
209
212
  },
210
213
  "author": "NexoWatt",
211
214
  "private": false,
@@ -216,7 +219,7 @@
216
219
  },
217
220
  "nexowattReleasePolicy": {
218
221
  "distTag": "latest",
219
- "purpose": "accepted stable NexoWatt EOS admin-rights and RBAC correction 7.10.5"
222
+ "purpose": "accepted stable NexoWatt EOS Installer EMS App-Center access correction 7.10.7"
220
223
  },
221
224
  "publisher": "NexoWatt"
222
225
  }
@@ -0,0 +1,44 @@
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
+
8
+ const root = path.resolve(__dirname, '..');
9
+ const read = file => fs.readFileSync(path.join(root, file), 'utf8');
10
+ const json = file => JSON.parse(read(file));
11
+
12
+ const pkg = json('package.json');
13
+ const sourceRole = read('src-admin/public/js/eos-role-ui.js');
14
+ const runtimeRole = read('adminWww/js/eos-role-ui.js');
15
+ const sourceWeb = read('src/lib/web.ts');
16
+ const runtimeWeb = read('build/lib/web.js');
17
+
18
+ assert.equal(pkg.version, '7.10.7', 'Installer EMS release must use npm version 7.10.7');
19
+ assert.equal(runtimeRole, sourceRole, 'built and source role runtimes must be identical');
20
+
21
+ for (const code of [sourceRole, runtimeRole]) {
22
+ assert.match(code, /const privilegedActionKind = element =>/, 'privileged action classifier missing');
23
+ assert.match(code, /return 'ems';/, 'EMS action classification missing');
24
+ assert.match(code, /return 'simulation';/, 'Simulation action classification missing');
25
+ assert.match(code, /return 'license';/, 'License action classification missing');
26
+ assert.match(code, /action === 'ems'/, 'EMS-specific access branch missing');
27
+ assert.match(
28
+ code,
29
+ /state\.role === 'installer' && state\.policy\?\.capabilities\?\.emsAppCenter !== false/,
30
+ 'Installer is not allowed to open EMS App-Center',
31
+ );
32
+ assert.match(code, /return state\.role === 'admin';/, 'Simulation and License must remain Admin-only');
33
+ assert.match(code, /!canUsePrivilegedAction\(element\)/, 'UI visibility does not use the role-aware action permission');
34
+ assert.match(code, /\|\| canUsePrivilegedAction\(target\)\) return;/, 'click guard does not use the role-aware action permission');
35
+ assert.match(code, /if \(state\.role !== 'enduser'\) return;/, 'port 8188 session scrubbing must apply only to End User');
36
+ }
37
+
38
+ for (const code of [sourceWeb, runtimeWeb]) {
39
+ assert.match(code, /emsAppCenter: technical/, 'backend capability must grant EMS App-Center to Admin and Installer');
40
+ assert.match(code, /simulation: role === 'admin'/, 'Simulation capability must remain Admin-only');
41
+ assert.match(code, /licenseAdministration: role === 'admin'/, 'License capability must remain Admin-only');
42
+ }
43
+
44
+ console.log('[NexoWatt EOS installer EMS] OK (Installer may use EMS App-Center; Simulation/License remain Admin-only; End User remains blocked)');
@@ -16,7 +16,7 @@ for (const file of [
16
16
  'MERGE_UPDATE.ps1',
17
17
  'MERGE_UPDATE.cmd',
18
18
  'MERGE_UPDATE.sh',
19
- 'MERGE_UPDATE_README_V7.10.5.md',
19
+ 'MERGE_UPDATE_README_V7.10.7.md',
20
20
  'tools/nexowatt-apply-ems-overview.cjs',
21
21
  'tools/nexowatt-sync-release-version.cjs',
22
22
  'tools/nexowatt-version-sync-selftest.cjs',
@@ -16,6 +16,8 @@ const roleUi = read('adminWww/js/eos-role-ui.js');
16
16
  const sourceRoleUi = read('src-admin/public/js/eos-role-ui.js');
17
17
  const sourceMain = read('src/main.ts');
18
18
  const builtMain = read('build/main.js');
19
+ const webSource = read('src/lib/web.ts');
20
+ const webBuilt = read('build/lib/web.js');
19
21
  const appSource = read('src-admin/src/App.tsx');
20
22
  const objectsSource = read('src-admin/src/tabs/Objects.tsx');
21
23
  const introSource = read('src-admin/src/tabs/Intro.tsx');
@@ -30,9 +32,9 @@ const cleanupSource = read('tools/nexowatt-clean-legacy-runtime.cjs');
30
32
  // visible header happened to contain "user". Only authenticated backend policy may define the role.
31
33
  for (const html of [index, sourceIndex]) {
32
34
  assert.doesNotMatch(html, /nexowatt-role-security\.js/i, 'legacy heuristic role guard is still loaded');
33
- assert.match(html, /eos-role-bootstrap\.js\?v=7105/, 'authoritative role bootstrap cache tag is missing');
34
- assert.match(html, /eos-policy-client\.js\?v=7105/, 'authoritative policy client cache tag is missing');
35
- assert.match(html, /eos-role-ui\.js\?v=7105/, 'authoritative role UI cache tag is missing');
35
+ assert.match(html, /eos-role-bootstrap\.js\?v=7107/, 'authoritative role bootstrap cache tag is missing');
36
+ assert.match(html, /eos-policy-client\.js\?v=7107/, 'authoritative policy client cache tag is missing');
37
+ assert.match(html, /eos-role-ui\.js\?v=7107/, 'authoritative role UI cache tag is missing');
36
38
  }
37
39
  assert.equal(fs.existsSync(path.join(root, 'adminWww/nexowatt-role-security.js')), false, 'legacy runtime still exists');
38
40
  assert.equal(fs.existsSync(path.join(root, 'build/lib/eosRoleSecurity.js')), false, 'legacy backend heuristic still exists');
@@ -98,10 +100,23 @@ assert.match(introBundle, /_forceAdmin=_eosAdmin/);
98
100
  assert.doesNotMatch(introSource, /NEXOWATT_EOS_ACCESS_ROLE \|\| 'admin'/, 'Intro source must fail closed while role is unresolved');
99
101
  assert.doesNotMatch(introBundle, /NEXOWATT_EOS_ACCESS_ROLE\|\|"admin"/, 'Intro runtime must fail closed while role is unresolved');
100
102
 
101
- // App Center, License, Simulation and normal account administration are not available to Installer/End User.
103
+ // Installer receives EMS App-Center access only. Simulation and License remain Admin-only;
104
+ // End User remains blocked from all three actions and from inherited port-8188 sessions.
102
105
  for (const token of ['app center', 'app-center', 'appcenter', 'simulation', 'simulator', 'lizenz', 'license']) {
103
106
  assert.ok(roleUi.toLowerCase().includes(token), `role UI is missing protected action ${token}`);
104
107
  }
108
+ for (const code of [roleUi, sourceRoleUi]) {
109
+ assert.match(code, /const privilegedActionKind = element =>/, 'privileged actions are not separated by capability');
110
+ assert.match(code, /if \(action === 'ems'\)/, 'EMS action branch is missing');
111
+ assert.match(code, /state\.role === 'installer' && state\.policy\?\.capabilities\?\.emsAppCenter !== false/, 'Installer EMS App-Center allowance is missing');
112
+ assert.match(code, /return state\.role === 'admin';/, 'Simulation and License must remain Admin-only');
113
+ assert.match(code, /if \(state\.role !== 'enduser'\) return;/, 'port 8188 session scrubbing must be End User-only');
114
+ }
115
+ for (const code of [webSource, webBuilt]) {
116
+ assert.match(code, /emsAppCenter: technical/, 'backend role capabilities do not grant Installer EMS access');
117
+ assert.match(code, /simulation: role === 'admin'/, 'Simulation capability must remain Admin-only');
118
+ assert.match(code, /licenseAdministration: role === 'admin'/, 'License capability must remain Admin-only');
119
+ }
105
120
  assert.match(roleUi, /applyPrivilegedIframePolicy/);
106
121
  assert.match(roleUi, /:8188\/logout\?/);
107
122
  assert.match(roleUi, /route !== 'tab-users'/);
@@ -128,4 +143,20 @@ assert.ok((io.instanceObjects || []).some(object => object?._id === 'info.uiTabs
128
143
  assert.match(drawerSource, /backupAdapters\.has\(adapterName\) && instance\.enabled !== true/);
129
144
  assert.match(builtDrawer, /o\.has\(A\)&&d\.enabled!==!0/);
130
145
 
131
- console.log('[NexoWatt EOS role security] OK (authoritative Admin rights, End User read-only datapoints, protected tools, restart-safe menu storage)');
146
+ // 7.10.7 End User cleanup: system information is read-only and object actions disappear only for End User.
147
+ for (const code of [webSource, webBuilt]) {
148
+ assert.match(code, /nexowatt\/readonly\/system-info/, 'authenticated read-only system-info route is missing');
149
+ assert.match(code, /authenticationRequired/, 'read-only system-info route must require an authenticated session');
150
+ assert.match(code, /ramMb/, 'read-only system-info payload is incomplete');
151
+ }
152
+ for (const code of [roleUi, sourceRoleUi]) {
153
+ assert.match(code, /state\.role !== 'enduser' \|\| currentRoute\(\) !== 'tab-intro'/, 'system-info hydration is not End User-only');
154
+ assert.match(code, /data-eos-enduser-action-hidden/, 'End User object action hiding marker is missing');
155
+ assert.match(code, /svg\[data-testid\*="Edit"\]/, 'Edit icon fallback selector is missing');
156
+ assert.match(code, /svg\[data-testid\*="Settings"\]/, 'Settings icon fallback selector is missing');
157
+ assert.match(code, /svg\[data-testid\*="Delete"\]/, 'Delete icon fallback selector is missing');
158
+ assert.match(code, /state\.role !== 'admin'/, 'Admin restriction guard is missing');
159
+ }
160
+ assert.match(sourceMain, /role === 'enduser' && \['readLogs', 'sendToHost'\]\.includes\(command\)/, 'End User technical diagnostics must remain denied');
161
+
162
+ console.log('[NexoWatt EOS role security] OK (Admin full rights, Installer EMS App-Center access, End User read-only datapoints, protected Admin tools)');
@@ -31,7 +31,7 @@ const autoUi = read('adminWww/js/eos-auto-update.js');
31
31
  const autoCss = read('adminWww/css/eos-auto-update.css');
32
32
  const autoTag = String(info.autoUpdateCacheTag || info.autoUpdateCacheVersion || info.shellCacheTag || info.shellCacheVersion);
33
33
 
34
- must(pkg.version === '7.10.5' && io.version === '7.10.5' && io.common.version === '7.10.5' && info.version === '7.10.5', 'version drift');
34
+ must(pkg.version === '7.10.7' && io.version === '7.10.7' && io.common.version === '7.10.7' && info.version === '7.10.7', 'version drift');
35
35
  must(io.native.eosRequireFirstLoginPassword === false && io.native.eosRequireFirstLoginPasswordChange === false, 'forced first password still enabled');
36
36
  must(!index.includes('eos-account-management.js'), 'custom reset UI still loaded');
37
37
  must(!boot.includes('installIntegratedFirstLogin(base);') && !boot.includes('showFirstLoginPassword(resolved, base);'), 'forced first-login UI still active');
@@ -49,7 +49,7 @@ must(!autoBackend.includes('extendForeignObjectAsync(this.instanceId'), 'runtime
49
49
  must(web.includes('this.nexowattStableUpdateManager?.stop();'), 'auto-update manager is not stopped with the web server');
50
50
  must(fs.existsSync(path.join(root, 'build/lib/eosRequestSecurity.js')), 'eosRequestSecurity runtime module missing');
51
51
 
52
- // 7.10.4 placement acceptance remains mandatory in 7.10.5: System Settings only.
52
+ // 7.10.4 placement acceptance remains mandatory in 7.10.7: System Settings only.
53
53
  must(index.includes(`eos-auto-update.js?v=${autoTag}`), 'auto-update JavaScript cache key missing');
54
54
  must(index.includes(`eos-auto-update.css?v=${autoTag}`), 'auto-update CSS cache key missing');
55
55
  must(autoUi.includes('[role="dialog"][aria-labelledby="system-settings-dialog-title"]'), 'System Settings selector missing');
@@ -0,0 +1,36 @@
1
+ #!/usr/bin/env node
2
+ 'use strict';
3
+ const assert = require('node:assert/strict');
4
+ const fs = require('node:fs');
5
+ const path = require('node:path');
6
+ const root = path.resolve(__dirname, '..');
7
+ const read = file => fs.readFileSync(path.join(root, file), 'utf8');
8
+ const pkg = JSON.parse(read('package.json'));
9
+ const sourceWeb = read('src/lib/web.ts');
10
+ const builtWeb = read('build/lib/web.js');
11
+ const sourceRole = read('src-admin/public/js/eos-role-ui.js');
12
+ const runtimeRole = read('adminWww/js/eos-role-ui.js');
13
+ const sourceMain = read('src/main.ts');
14
+ const builtMain = read('build/main.js');
15
+
16
+ assert.equal(pkg.version, '7.10.7', 'release must use a new npm version');
17
+ for (const web of [sourceWeb, builtWeb]) {
18
+ assert.match(web, /nexowatt\/readonly\/system-info/, 'read-only system information endpoint missing');
19
+ assert.match(web, /sendEosReadonlySystemInfo/, 'read-only system information handler missing');
20
+ assert.match(web, /platform/, 'platform value missing');
21
+ assert.match(web, /ramMb/, 'RAM value missing');
22
+ assert.match(web, /nodejs/, 'Node.js value missing');
23
+ assert.match(web, /npm/, 'NPM value missing');
24
+ }
25
+ for (const role of [sourceRole, runtimeRole]) {
26
+ assert.match(role, /state\.role !== 'enduser' \|\| currentRoute\(\) !== 'tab-intro'/, 'system-card correction must be End User-only');
27
+ assert.match(role, /applyReadonlySystemInfoCard/, 'End User system-card correction missing');
28
+ assert.match(role, /data-eos-enduser-action-hidden/, 'End User action-column suppression missing');
29
+ assert.match(role, /Edit.*Delete.*Settings.*Tune.*Build/s, 'edit/delete/settings icon suppression missing');
30
+ assert.match(role, /const readonly = state\.role === 'enduser' && currentRoute\(\) === 'tab-objects'/, 'datapoint restriction must be End User-only');
31
+ }
32
+ for (const main of [sourceMain, builtMain]) {
33
+ assert.match(main, /if \(role === 'admin'\)/, 'Admin full-rights bypass missing');
34
+ assert.match(main, /end-user datapoints are read-only in EOS Admin/, 'backend End User write denial missing');
35
+ }
36
+ console.log('[NexoWatt EOS user area] OK (End User read-only actions and system info; Admin unchanged)');
@@ -45,6 +45,8 @@ if (!pkg.scripts['check:eos-stability']?.includes('nexowatt-version-sync-selftes
45
45
  if (!pkg.scripts['check:eos-stability']?.includes('nexowatt-merge-update-selftest.cjs')) fail('merge update selftest is not part of check:eos-stability');
46
46
  if (pkg.scripts['check:eos-stable-v7103'] !== 'node tools/nexowatt-stable-v7103-selftest.cjs') fail('stable v7103 selftest script is missing or incorrect');
47
47
  if (pkg.scripts['test:eos-auto-update-placement'] !== 'node tools/nexowatt-auto-update-placement-selftest.cjs') fail('auto-update placement selftest script is missing or incorrect');
48
+ if (pkg.scripts['test:eos-installer-ems'] !== 'node tools/nexowatt-installer-ems-selftest.cjs') fail('Installer EMS selftest script is missing or incorrect');
49
+ if (!pkg.scripts['check:eos-stability']?.includes('nexowatt-installer-ems-selftest.cjs')) fail('Installer EMS selftest is not part of check:eos-stability');
48
50
  if (!pkg.scripts['check:eos-stability']?.includes('nexowatt-auto-update-placement-selftest.cjs')) fail('auto-update placement selftest is not part of check:eos-stability');
49
51
  if (pkg.scripts.prepublishOnly !== canonicalPrepublishOnly) fail('prepublishOnly must use the dependency-free direct-publish workflow');
50
52
  if (/\b(?:tsc|tsx)\b|build:(?:backend|frontend)|\bnpx\b|npm\s+(?:i|install|ci)\b/i.test(pkg.scripts.prepublishOnly || '')) fail('prepublishOnly must not require local development dependencies');
@@ -134,14 +136,14 @@ for (const file of [
134
136
  'LICENSE',
135
137
  'NEXOWATT_PROPRIETARY_LICENSE.md',
136
138
  'THIRD_PARTY_NOTICES.md',
137
- 'README_STABILITY_V7.10.5.md',
138
- 'RELEASE_NOTES_V7.10.5.md',
139
- 'PUBLISH_STABLE_V7.10.5.md',
140
- 'INSTALL_TEST_V7.10.5.md',
141
- 'RELEASE_ACCEPTANCE_V7.10.5.md',
139
+ 'README_STABILITY_V7.10.7.md',
140
+ 'RELEASE_NOTES_V7.10.7.md',
141
+ 'PUBLISH_STABLE_V7.10.7.md',
142
+ 'INSTALL_TEST_V7.10.7.md',
143
+ 'RELEASE_ACCEPTANCE_V7.10.7.md',
142
144
  'MERGE_UPDATE.ps1',
143
145
  'MERGE_UPDATE.cmd',
144
- 'MERGE_UPDATE_README_V7.10.5.md',
146
+ 'MERGE_UPDATE_README_V7.10.7.md',
145
147
  'tools/nexowatt-patch-built-frontend.cjs',
146
148
  'tools/nexowatt-native-shell-selftest.cjs',
147
149
  'tools/nexowatt-clean-legacy-runtime.cjs',
@@ -174,7 +176,7 @@ for (const file of [
174
176
  'tools/nexowatt-ui-overview-runtime-selftest.cjs',
175
177
  'adminWww/js/eos-ems-overview.js',
176
178
  'adminWww/css/eos-ems-overview.css',
177
- 'adminWww/static/js/nexowatt-stable-v7105.js',
179
+ 'adminWww/static/js/nexowatt-stable-v7107.js',
178
180
  'src-admin/src/components/Intro/NexoWattEmsOverview.tsx',
179
181
  'tools/nexowatt-publish-channel-guard.cjs',
180
182
  'tools/nexowatt-publish-channel-selftest.cjs',
@@ -1,8 +0,0 @@
1
- # Installation test 7.10.5
2
-
3
- - Install/update EOS Admin 7.10.5 and verify port 8081 remains reachable.
4
- - Sign in as Admin: datapoints are writable; expert mode can be enabled and disabled; Admin and XTerm overview cards are visible.
5
- - Sign in as Installer: no expert head, ioBroker Admin, XTerm, App Center, License, Simulation or Users/Rights page.
6
- - Sign in as End User: Datapoints tab is visible but every write/edit/delete action is disabled; restricted tools are absent.
7
- - Toggle a navigation item with the pencil: EOS Admin must not restart and `system.config` must remain untouched.
8
- - Disable the backup adapter: its navigation item disappears; re-enable it and the item returns.
@@ -1,7 +0,0 @@
1
- # Merge/update note 7.10.5
2
-
3
- Always replace the previous repository with the complete 7.10.5 repository. Do not merge old `adminWww` bundles or deleted role-security files back into this release. In particular, `nexowatt-role-security.js` and `build/lib/eosRoleSecurity.js` are obsolete and must stay absent.
4
-
5
- After a merge, run the package, stability, role-security and publish dry-run checks before publishing.
6
-
7
- The 7.10.5 publish workflow now removes all three obsolete 7.10.4 role-security files automatically before sealing and packaging, including when the ZIP was extracted over an existing working directory.
@@ -1,8 +0,0 @@
1
- # NPM publication 7.10.5
2
-
3
- 1. Use a freshly extracted repository ZIP.
4
- 2. Run `npm publish --dry-run`.
5
- 3. Confirm version `7.10.5`, complete `build/` runtime and all active `adminWww/assets/*-v84.js` files.
6
- 4. Publish with `npm publish` only after the dry run succeeds.
7
-
8
- No `npm install`, `npm ci`, `tsc` or `tsx` is required for the sealed prebuilt release.
@@ -1,5 +0,0 @@
1
- # NexoWatt EOS Admin 7.10.5 – stability and RBAC baseline
2
-
3
- This release retains the validated 7.10.2–7.10.4 crash, package and update-placement fixes. Role decisions now come exclusively from the authenticated `/nexowatt/security/context` response. The removed heuristic must never be restored.
4
-
5
- Administrator is an unconditional full-rights path. End User datapoints are read-only in both frontend and backend. Menu edits are persisted in an adapter state and must never write `system.config`.
@@ -1,11 +0,0 @@
1
- # Release Acceptance 7.10.5
2
-
3
- - [ ] Admin can write every normally writable datapoint.
4
- - [ ] Admin can enable and disable expert mode repeatedly.
5
- - [ ] Admin sees ioBroker Admin and XTerm overview cards.
6
- - [ ] Installer and End User never see expert mode, ioBroker Admin or XTerm.
7
- - [ ] App Center, License, Simulation and account administration are unavailable to Installer/End User.
8
- - [ ] End User sees Datapoints but cannot write, edit, create or delete.
9
- - [ ] Pencil navigation edits do not restart EOS Admin.
10
- - [ ] Backup navigation follows the enabled state of the backup instance.
11
- - [ ] `npm publish --dry-run` succeeds from a fresh extraction.
@@ -1,11 +0,0 @@
1
- # Release Notes 7.10.5
2
-
3
- Version 7.10.5 is the administrator-rights and RBAC correction for NexoWatt EOS Admin.
4
-
5
- - Restores unrestricted administrator datapoint writes and reversible expert mode.
6
- - Removes the legacy DOM-text role classifier that could misclassify `system.user.admin`.
7
- - Keeps ioBroker Admin and XTerm visible for administrators only.
8
- - Exposes Datapoints to End Users as read-only and denies End User state writes in the backend.
9
- - Blocks App Center, License, Simulation and normal account administration for Installer/End User.
10
- - Stores navigation visibility/order in `eos-admin.0.info.uiTabsVisible` instead of `system.config`, avoiding adapter restarts.
11
- - Shows backup navigation only for enabled backup instances.