iobroker.eos-admin 7.9.97 → 7.9.98
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.
- package/INSTALL_TEST_V7.9.98.md +39 -0
- package/MERGE_UPDATE_README_V7.9.98.md +29 -0
- package/NEXOWATT_EOS_BUILD_INFO.json +20 -20
- package/PUBLISH_STABLE_V7.9.98.md +33 -0
- package/README.md +16 -6
- package/README_STABILITY_V7.9.98.md +22 -0
- package/RELEASE_ACCEPTANCE_V7.9.98.md +48 -0
- package/RELEASE_NOTES_V7.9.98.md +32 -0
- package/adminWww/assets/bootstrap-COulQZax-v84.js +2 -2
- package/adminWww/css/eos-ems-overview.css +1 -1
- package/adminWww/css/nexowatt-native-shell.css +117 -0
- package/adminWww/index.html +15 -15
- package/adminWww/js/eos-account-management.js +26 -13
- package/adminWww/js/eos-ems-overview.js +1 -1
- package/adminWww/js/eos-role-bootstrap.js +7 -7
- package/adminWww/js/eos-role-ui.js +1 -1
- package/adminWww/js/nexowatt-native-shell.js +1 -1
- package/adminWww/static/js/nexowatt-stable-login.js +3 -3
- package/adminWww/static/js/{nexowatt-stable-v97.js → nexowatt-stable-v98.js} +2 -2
- package/build/lib/web.js +112 -79
- package/build/main.js +1 -1
- package/io-package.json +10 -5
- package/package.json +14 -12
- package/tools/nexowatt-account-management-selftest.cjs +16 -57
- package/tools/nexowatt-account-password-flow-selftest.cjs +186 -0
- package/tools/nexowatt-login-layout-selftest.cjs +8 -8
- package/tools/nexowatt-merge-update-selftest.cjs +1 -1
- package/tools/nexowatt-modern-ui-selftest.cjs +2 -2
- package/tools/nexowatt-password-write-selftest.cjs +48 -0
- package/tools/nexowatt-runtime-cleanup-selftest.cjs +5 -5
- package/tools/nexowatt-stable-v98-selftest.cjs +14 -0
- package/tools/nexowatt-sync-release-version.cjs +42 -1
- package/tools/nexowatt-ui-overview-runtime-selftest.cjs +1 -1
- package/tools/nexowatt-validate-package.cjs +20 -11
- package/tools/nexowatt-version-sync-selftest.cjs +18 -1
- package/INSTALL_TEST_V7.9.97.md +0 -11
- package/MERGE_UPDATE_README_V7.9.97.md +0 -5
- package/PUBLISH_STABLE_V7.9.97.md +0 -15
- package/README_STABILITY_V7.9.97.md +0 -18
- package/RELEASE_ACCEPTANCE_V7.9.97.md +0 -11
- package/RELEASE_NOTES_V7.9.97.md +0 -19
- package/tools/nexowatt-stable-v97-selftest.cjs +0 -16
package/build/lib/web.js
CHANGED
|
@@ -713,22 +713,53 @@ class Web {
|
|
|
713
713
|
}
|
|
714
714
|
return { valid: true, password: value };
|
|
715
715
|
}
|
|
716
|
+
getEosPasswordUserName(userId) {
|
|
717
|
+
const userName = String(userId || '').trim().replace(/^system\.user\./, '');
|
|
718
|
+
if (!/^[A-Za-z0-9_.@-]+$/.test(userName)) {
|
|
719
|
+
throw new Error('invalidPasswordTarget');
|
|
720
|
+
}
|
|
721
|
+
return userName;
|
|
722
|
+
}
|
|
716
723
|
async setEosUserPassword(userId, password) {
|
|
717
|
-
//
|
|
718
|
-
|
|
719
|
-
//
|
|
724
|
+
// ioBroker's password API expects the account name, not the system.user.* object id.
|
|
725
|
+
const userName = this.getEosPasswordUserName(userId);
|
|
726
|
+
// The server-side Admin/Service context performs the controller password write, so managed
|
|
727
|
+
// Installer and End User accounts do not need global users.write rights in the browser.
|
|
720
728
|
const options = { user: EOS_PASSWORD_SERVICE_USER };
|
|
721
729
|
if (typeof this.adapter.setPasswordAsync === 'function') {
|
|
722
|
-
await this.adapter.setPasswordAsync(
|
|
723
|
-
return;
|
|
730
|
+
await this.adapter.setPasswordAsync(userName, password, options);
|
|
724
731
|
}
|
|
725
|
-
if (typeof this.adapter.setPassword === 'function') {
|
|
732
|
+
else if (typeof this.adapter.setPassword === 'function') {
|
|
726
733
|
await new Promise((resolve, reject) => {
|
|
727
|
-
this.adapter.setPassword?.(
|
|
734
|
+
this.adapter.setPassword?.(userName, password, options, error => (error ? reject(error) : resolve()));
|
|
728
735
|
});
|
|
736
|
+
}
|
|
737
|
+
else {
|
|
738
|
+
throw new Error('passwordApiUnavailable');
|
|
739
|
+
}
|
|
740
|
+
if (typeof this.adapter.checkPasswordAsync === 'function') {
|
|
741
|
+
const result = await this.adapter.checkPasswordAsync(userName, password, options);
|
|
742
|
+
const valid = Array.isArray(result) ? result[0] === true : result === true;
|
|
743
|
+
if (!valid) {
|
|
744
|
+
throw new Error('passwordVerificationFailed');
|
|
745
|
+
}
|
|
729
746
|
return;
|
|
730
747
|
}
|
|
731
|
-
|
|
748
|
+
const userObject = (await this.adapter.getForeignObjectAsync(userId));
|
|
749
|
+
if (!String(userObject?.common?.password || '').trim()) {
|
|
750
|
+
throw new Error('passwordWriteFailed');
|
|
751
|
+
}
|
|
752
|
+
}
|
|
753
|
+
async updateEosAccountMetadata(userId, updater) {
|
|
754
|
+
const userObject = (await this.adapter.getForeignObjectAsync(userId));
|
|
755
|
+
if (!userObject) {
|
|
756
|
+
throw new Error('userObjectUnavailableAfterPasswordChange');
|
|
757
|
+
}
|
|
758
|
+
const native = { ...(userObject.native || {}) };
|
|
759
|
+
const account = { ...(native.nexowattEosAccount || {}) };
|
|
760
|
+
native.nexowattEosAccount = account;
|
|
761
|
+
updater(native, account);
|
|
762
|
+
await this.adapter.extendForeignObjectAsync(userId, { native }, { user: EOS_PASSWORD_SERVICE_USER });
|
|
732
763
|
}
|
|
733
764
|
async destroyEosRequestSessions(req) {
|
|
734
765
|
const token = this.readAccessTokenFromRequest(req);
|
|
@@ -777,29 +808,24 @@ class Web {
|
|
|
777
808
|
return;
|
|
778
809
|
}
|
|
779
810
|
await this.setEosUserPassword(access.userId, validation.password);
|
|
780
|
-
const userObject = (await this.adapter.getForeignObjectAsync(access.userId));
|
|
781
|
-
if (!userObject) {
|
|
782
|
-
throw new Error('userObjectUnavailableAfterPasswordChange');
|
|
783
|
-
}
|
|
784
|
-
const native = (userObject.native ||= {});
|
|
785
|
-
const account = (native.nexowattEosAccount ||= {});
|
|
786
811
|
const now = new Date().toISOString();
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
812
|
+
await this.updateEosAccountMetadata(access.userId, (native, account) => {
|
|
813
|
+
account.passwordInitialized = true;
|
|
814
|
+
account.passwordInitializedAt = Date.now();
|
|
815
|
+
account.passwordInitializationVersion = 1;
|
|
816
|
+
account.passwordInitializedBy = 'self';
|
|
817
|
+
account.passwordSetupVersion = 1;
|
|
818
|
+
account.passwordSetAt = now;
|
|
819
|
+
account.firstLoginCompletedAt = now;
|
|
820
|
+
account.forcePasswordChange = false;
|
|
821
|
+
account.passwordlessFirstLoginAllowed = false;
|
|
822
|
+
native.nexowattPasswordChangeRequired = false;
|
|
823
|
+
native.eosPasswordChangeRequired = false;
|
|
824
|
+
native.nexowattFirstLoginPending = false;
|
|
825
|
+
native.eosFirstLoginRequired = false;
|
|
826
|
+
native.nexowattInitialPasswordApplied = false;
|
|
827
|
+
native.nexowattPasswordChangedAt = now;
|
|
828
|
+
});
|
|
803
829
|
await this.destroyEosRequestSessions(req);
|
|
804
830
|
for (const cookie of ['access_token', 'refresh_token', 'connect.sid']) {
|
|
805
831
|
res.clearCookie(cookie);
|
|
@@ -1023,24 +1049,25 @@ class Web {
|
|
|
1023
1049
|
return;
|
|
1024
1050
|
}
|
|
1025
1051
|
await this.setEosUserPassword(claim.userId, validation.password);
|
|
1026
|
-
const user = (await this.adapter.getForeignObjectAsync(claim.userId));
|
|
1027
|
-
if (!user) {
|
|
1028
|
-
throw new Error('userObjectUnavailableAfterPasswordChange');
|
|
1029
|
-
}
|
|
1030
|
-
const native = (user.native ||= {});
|
|
1031
|
-
const account = (native.nexowattEosAccount ||= {});
|
|
1032
1052
|
const now = new Date().toISOString();
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
|
|
1037
|
-
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
|
|
1042
|
-
|
|
1043
|
-
|
|
1053
|
+
await this.updateEosAccountMetadata(claim.userId, (native, account) => {
|
|
1054
|
+
account.passwordInitialized = true;
|
|
1055
|
+
account.passwordInitializedAt = Date.now();
|
|
1056
|
+
account.passwordInitializationVersion = 1;
|
|
1057
|
+
account.passwordInitializedBy = 'passwordless-first-activation';
|
|
1058
|
+
account.passwordSetupVersion = 1;
|
|
1059
|
+
account.passwordSetAt = now;
|
|
1060
|
+
account.firstLoginCompletedAt = now;
|
|
1061
|
+
account.forcePasswordChange = false;
|
|
1062
|
+
account.passwordlessFirstLoginAllowed = false;
|
|
1063
|
+
account.passwordlessClaimCompletedAt = now;
|
|
1064
|
+
native.nexowattPasswordChangeRequired = false;
|
|
1065
|
+
native.eosPasswordChangeRequired = false;
|
|
1066
|
+
native.nexowattFirstLoginPending = false;
|
|
1067
|
+
native.eosFirstLoginRequired = false;
|
|
1068
|
+
native.nexowattInitialPasswordApplied = false;
|
|
1069
|
+
native.nexowattPasswordChangedAt = now;
|
|
1070
|
+
});
|
|
1044
1071
|
this.invalidateEosPasswordClaimsForUser(claim.userId);
|
|
1045
1072
|
res.clearCookie('nexowatt_eos_first_login', { path: '/nexowatt/account' });
|
|
1046
1073
|
this.adapter.log.info(`EOS passwordless first activation completed for ${claim.userId}`);
|
|
@@ -1106,13 +1133,14 @@ class Web {
|
|
|
1106
1133
|
async resetEosAccountPassword(req, res) {
|
|
1107
1134
|
res.setHeader('Cache-Control', 'no-store, no-cache, must-revalidate, proxy-revalidate');
|
|
1108
1135
|
const access = await this.getEosRequestAccess(req);
|
|
1109
|
-
if (!access.userId
|
|
1110
|
-
|| (access.role !== 'admin' && access.role !== 'installer')
|
|
1111
|
-
|| !this.isEosSameOriginWrite(req)
|
|
1112
|
-
|| req.headers['x-nexowatt-eos-account-reset'] !== '1') {
|
|
1136
|
+
if (!access.userId || (access.role !== 'admin' && access.role !== 'installer')) {
|
|
1113
1137
|
res.status(403).json({ error: 'permissionError' });
|
|
1114
1138
|
return;
|
|
1115
1139
|
}
|
|
1140
|
+
if (!this.isEosSameOriginWrite(req) || req.headers['x-nexowatt-eos-account-reset'] !== '1') {
|
|
1141
|
+
res.status(403).json({ error: 'invalidRequestOrigin' });
|
|
1142
|
+
return;
|
|
1143
|
+
}
|
|
1116
1144
|
const targetUserId = this.normalizeEosUserId(req.body?.user);
|
|
1117
1145
|
if (!targetUserId || targetUserId === 'system.user.admin' || targetUserId === access.userId) {
|
|
1118
1146
|
res.status(400).json({ error: 'invalidTarget' });
|
|
@@ -1144,31 +1172,26 @@ class Web {
|
|
|
1144
1172
|
return;
|
|
1145
1173
|
}
|
|
1146
1174
|
await this.setEosUserPassword(targetUserId, 'nexowatt');
|
|
1147
|
-
const user = (await this.adapter.getForeignObjectAsync(targetUserId));
|
|
1148
|
-
if (!user) {
|
|
1149
|
-
throw new Error('userObjectUnavailableAfterPasswordReset');
|
|
1150
|
-
}
|
|
1151
|
-
const native = (user.native ||= {});
|
|
1152
|
-
const account = (native.nexowattEosAccount ||= {});
|
|
1153
1175
|
const now = new Date().toISOString();
|
|
1154
|
-
|
|
1155
|
-
|
|
1156
|
-
|
|
1157
|
-
|
|
1158
|
-
|
|
1159
|
-
|
|
1160
|
-
|
|
1161
|
-
|
|
1162
|
-
|
|
1163
|
-
|
|
1164
|
-
|
|
1165
|
-
|
|
1166
|
-
|
|
1167
|
-
|
|
1168
|
-
|
|
1169
|
-
|
|
1170
|
-
|
|
1171
|
-
|
|
1176
|
+
await this.updateEosAccountMetadata(targetUserId, (native, account) => {
|
|
1177
|
+
account.passwordInitialized = false;
|
|
1178
|
+
account.passwordSetupVersion = 0;
|
|
1179
|
+
account.passwordInitializationVersion = 0;
|
|
1180
|
+
account.forcePasswordChange = true;
|
|
1181
|
+
account.passwordlessFirstLoginAllowed = false;
|
|
1182
|
+
account.passwordResetAt = now;
|
|
1183
|
+
account.passwordResetBy = access.userId;
|
|
1184
|
+
account.passwordResetMode = 'initial-password';
|
|
1185
|
+
account.passwordSetAt = null;
|
|
1186
|
+
account.firstLoginCompletedAt = null;
|
|
1187
|
+
native.nexowattPasswordChangeRequired = true;
|
|
1188
|
+
native.eosPasswordChangeRequired = true;
|
|
1189
|
+
native.nexowattFirstLoginPending = true;
|
|
1190
|
+
native.eosFirstLoginRequired = true;
|
|
1191
|
+
native.nexowattInitialPasswordApplied = true;
|
|
1192
|
+
native.nexowattInitialPasswordVersion = 1;
|
|
1193
|
+
native.nexowattStableInitialCredentialVersion = 1;
|
|
1194
|
+
});
|
|
1172
1195
|
this.invalidateEosPasswordClaimsForUser(targetUserId);
|
|
1173
1196
|
this.adapter.log.warn(`EOS account ${targetUserId} was reset to the mandatory initial-password flow by ${access.userId}`);
|
|
1174
1197
|
res.status(200).json({
|
|
@@ -1245,14 +1268,24 @@ class Web {
|
|
|
1245
1268
|
});
|
|
1246
1269
|
}
|
|
1247
1270
|
isEosSameOriginWrite(req) {
|
|
1271
|
+
const fetchSite = String(req.headers['sec-fetch-site'] || '').trim().toLowerCase();
|
|
1272
|
+
if (fetchSite === 'cross-site') {
|
|
1273
|
+
return false;
|
|
1274
|
+
}
|
|
1248
1275
|
const origin = String(req.headers.origin || '').trim();
|
|
1249
1276
|
if (!origin) {
|
|
1250
1277
|
return true;
|
|
1251
1278
|
}
|
|
1252
|
-
|
|
1253
|
-
|
|
1254
|
-
|
|
1255
|
-
|
|
1279
|
+
try {
|
|
1280
|
+
const originUrl = new URL(origin);
|
|
1281
|
+
const directHost = String(req.headers.host || '').trim().toLowerCase();
|
|
1282
|
+
const forwardedHost = String(req.headers['x-forwarded-host'] || '').split(',')[0].trim().toLowerCase();
|
|
1283
|
+
const allowedHosts = new Set([directHost, forwardedHost].filter(Boolean));
|
|
1284
|
+
return allowedHosts.has(originUrl.host.toLowerCase());
|
|
1285
|
+
}
|
|
1286
|
+
catch {
|
|
1287
|
+
return false;
|
|
1288
|
+
}
|
|
1256
1289
|
}
|
|
1257
1290
|
async saveEosBasicSettings(req, res) {
|
|
1258
1291
|
res.setHeader('Cache-Control', 'no-store, no-cache, must-revalidate, proxy-revalidate');
|
package/build/main.js
CHANGED
|
@@ -1152,7 +1152,7 @@ class Admin extends adapter_core_1.Adapter {
|
|
|
1152
1152
|
}
|
|
1153
1153
|
if (String(user.common.password || '') === '') {
|
|
1154
1154
|
const bootstrapSecret = `${(0, node_crypto_1.randomBytes)(48).toString('base64url')}!aA1`;
|
|
1155
|
-
await this.setPasswordAsync(userId, bootstrapSecret, { user: ADMIN_OWNER_USER });
|
|
1155
|
+
await this.setPasswordAsync(userId.replace(/^system\.user\./, ''), bootstrapSecret, { user: ADMIN_OWNER_USER });
|
|
1156
1156
|
user = (await this.getForeignObjectAsync(userId));
|
|
1157
1157
|
if (!user) {
|
|
1158
1158
|
return;
|
package/io-package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"common": {
|
|
3
3
|
"name": "eos-admin",
|
|
4
|
-
"version": "7.9.
|
|
4
|
+
"version": "7.9.98",
|
|
5
5
|
"titleLang": {
|
|
6
6
|
"en": "NexoWatt EOS Admin",
|
|
7
7
|
"de": "NexoWatt EOS Admin",
|
|
@@ -18,6 +18,11 @@
|
|
|
18
18
|
"connectionType": "local",
|
|
19
19
|
"dataSource": "push",
|
|
20
20
|
"news": {
|
|
21
|
+
"7.9.98": {
|
|
22
|
+
"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.",
|
|
23
|
+
"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.",
|
|
24
|
+
"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."
|
|
25
|
+
},
|
|
21
26
|
"7.9.95": {
|
|
22
27
|
"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
28
|
"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 +334,7 @@
|
|
|
329
334
|
"icon": "admin.svg",
|
|
330
335
|
"messagebox": true,
|
|
331
336
|
"enabled": true,
|
|
332
|
-
"extIcon": "https://unpkg.com/iobroker.eos-admin@7.9.
|
|
337
|
+
"extIcon": "https://unpkg.com/iobroker.eos-admin@7.9.98/admin/admin.svg",
|
|
333
338
|
"keywords": [
|
|
334
339
|
"NexoWatt",
|
|
335
340
|
"EOS",
|
|
@@ -340,7 +345,7 @@
|
|
|
340
345
|
"licensed"
|
|
341
346
|
],
|
|
342
347
|
"compact": true,
|
|
343
|
-
"readme": "https://unpkg.com/iobroker.eos-admin@7.9.
|
|
348
|
+
"readme": "https://unpkg.com/iobroker.eos-admin@7.9.98/README.md",
|
|
344
349
|
"authors": [
|
|
345
350
|
"NexoWatt"
|
|
346
351
|
],
|
|
@@ -408,7 +413,7 @@
|
|
|
408
413
|
"nondeletable": false,
|
|
409
414
|
"allowAdapterUpdate": true,
|
|
410
415
|
"allowAdapterDelete": false,
|
|
411
|
-
"meta": "https://unpkg.com/iobroker.eos-admin@7.9.
|
|
416
|
+
"meta": "https://unpkg.com/iobroker.eos-admin@7.9.98/io-package.json",
|
|
412
417
|
"npmPackage": "iobroker.eos-admin",
|
|
413
418
|
"packetName": "iobroker.eos-admin",
|
|
414
419
|
"publisher": "NexoWatt"
|
|
@@ -1117,5 +1122,5 @@
|
|
|
1117
1122
|
}
|
|
1118
1123
|
}
|
|
1119
1124
|
},
|
|
1120
|
-
"version": "7.9.
|
|
1125
|
+
"version": "7.9.98"
|
|
1121
1126
|
}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "iobroker.eos-admin",
|
|
3
|
-
"description": "NexoWatt EOS Admin – stable sales
|
|
4
|
-
"version": "7.9.
|
|
3
|
+
"description": "NexoWatt EOS Admin – stable sales candidate with scrollable cockpit, clean login and verified account password writes.",
|
|
4
|
+
"version": "7.9.98",
|
|
5
5
|
"contributors": [
|
|
6
6
|
"bluefox <dogafox@gmail.com>",
|
|
7
7
|
"apollon77",
|
|
@@ -118,19 +118,21 @@
|
|
|
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.9.
|
|
122
|
-
"RELEASE_NOTES_V7.9.
|
|
123
|
-
"PUBLISH_STABLE_V7.9.
|
|
124
|
-
"INSTALL_TEST_V7.9.
|
|
125
|
-
"RELEASE_ACCEPTANCE_V7.9.
|
|
126
|
-
"MERGE_UPDATE_README_V7.9.
|
|
121
|
+
"README_STABILITY_V7.9.98.md",
|
|
122
|
+
"RELEASE_NOTES_V7.9.98.md",
|
|
123
|
+
"PUBLISH_STABLE_V7.9.98.md",
|
|
124
|
+
"INSTALL_TEST_V7.9.98.md",
|
|
125
|
+
"RELEASE_ACCEPTANCE_V7.9.98.md",
|
|
126
|
+
"MERGE_UPDATE_README_V7.9.98.md",
|
|
127
127
|
"README_EMS_OVERVIEW_MERGE.md",
|
|
128
128
|
"RC73_EOS_ADMIN_MERGE_VALIDATION.md",
|
|
129
129
|
"VALIDATION_EMS_OVERVIEW_MERGE.md",
|
|
130
130
|
"NexoWatt_EOS_Admin_EMS_OVERVIEW_MERGE_VALIDATION.md",
|
|
131
131
|
"tools/nexowatt-apply-ems-overview.cjs",
|
|
132
132
|
"tools/nexowatt-ui-overview-runtime-selftest.cjs",
|
|
133
|
-
"tools/nexowatt-stable-
|
|
133
|
+
"tools/nexowatt-stable-v98-selftest.cjs",
|
|
134
|
+
"tools/nexowatt-password-write-selftest.cjs",
|
|
135
|
+
"tools/nexowatt-account-password-flow-selftest.cjs"
|
|
134
136
|
],
|
|
135
137
|
"scripts": {
|
|
136
138
|
"npm": "npm i -f && cd src-admin && npm i -f",
|
|
@@ -165,7 +167,7 @@
|
|
|
165
167
|
"nexowatt:repo-entry": "node tools/nexowatt-generate-repo-entry.cjs",
|
|
166
168
|
"nexowatt:patch-repo": "node tools/nexowatt-patch-repo.cjs",
|
|
167
169
|
"nexowatt:repair-update": "node tools/nexowatt-repair-eos-admin-update.cjs",
|
|
168
|
-
"check:eos-stability": "node tools/nexowatt-stability-check.cjs && node tools/nexowatt-esm-syntax-selftest.cjs && node tools/nexowatt-import-integrity-selftest.cjs && node tools/nexowatt-entrypoint-smoke-selftest.cjs && node tools/nexowatt-frontend-graph-check.cjs && node tools/nexowatt-policy-selftest.cjs && node tools/nexowatt-publish-channel-selftest.cjs && node tools/nexowatt-release-defaults-selftest.cjs && node tools/nexowatt-role-access-selftest.cjs && node tools/nexowatt-internal-reserve-selftest.cjs && node tools/nexowatt-first-login-selftest.cjs && node tools/nexowatt-account-management-selftest.cjs && node tools/nexowatt-modern-ui-selftest.cjs && node tools/nexowatt-login-layout-selftest.cjs && node tools/nexowatt-branding-selftest.cjs && node tools/nexowatt-default-port-selftest.cjs && node tools/nexowatt-module-popup-selftest.cjs && node tools/nexowatt-datapoint-selftest.cjs && node tools/nexowatt-update-selftest.cjs && node tools/nexowatt-datapoint-interaction-selftest.cjs && node tools/nexowatt-manual-write-policy-selftest.cjs && node tools/nexowatt-value-column-selftest.cjs && node tools/nexowatt-native-shell-selftest.cjs && node tools/nexowatt-assistant-separation-selftest.cjs && node tools/nexowatt-runtime-cleanup-selftest.cjs && node tools/nexowatt-version-sync-selftest.cjs && node tools/nexowatt-merge-update-selftest.cjs && npm run check:eos-stable-
|
|
170
|
+
"check:eos-stability": "node tools/nexowatt-stability-check.cjs && node tools/nexowatt-esm-syntax-selftest.cjs && node tools/nexowatt-import-integrity-selftest.cjs && node tools/nexowatt-entrypoint-smoke-selftest.cjs && node tools/nexowatt-frontend-graph-check.cjs && node tools/nexowatt-policy-selftest.cjs && node tools/nexowatt-publish-channel-selftest.cjs && node tools/nexowatt-release-defaults-selftest.cjs && node tools/nexowatt-role-access-selftest.cjs && node tools/nexowatt-internal-reserve-selftest.cjs && node tools/nexowatt-first-login-selftest.cjs && node tools/nexowatt-account-management-selftest.cjs && node tools/nexowatt-modern-ui-selftest.cjs && node tools/nexowatt-login-layout-selftest.cjs && node tools/nexowatt-branding-selftest.cjs && node tools/nexowatt-default-port-selftest.cjs && node tools/nexowatt-module-popup-selftest.cjs && node tools/nexowatt-datapoint-selftest.cjs && node tools/nexowatt-update-selftest.cjs && node tools/nexowatt-datapoint-interaction-selftest.cjs && node tools/nexowatt-manual-write-policy-selftest.cjs && node tools/nexowatt-value-column-selftest.cjs && node tools/nexowatt-native-shell-selftest.cjs && node tools/nexowatt-assistant-separation-selftest.cjs && node tools/nexowatt-runtime-cleanup-selftest.cjs && node tools/nexowatt-version-sync-selftest.cjs && node tools/nexowatt-merge-update-selftest.cjs && node tools/nexowatt-password-write-selftest.cjs && node tools/nexowatt-account-password-flow-selftest.cjs && npm run check:eos-stable-v98 && node tools/nexowatt-ems-overview-selftest.cjs && node tools/nexowatt-ui-overview-runtime-selftest.cjs",
|
|
169
171
|
"nexowatt:patch-built-frontend": "node tools/nexowatt-patch-built-frontend.cjs",
|
|
170
172
|
"clean:eos-runtime": "node tools/nexowatt-clean-legacy-runtime.cjs",
|
|
171
173
|
"precheck:eos-package": "npm run sync:eos-version && npm run prepare:eos-release-defaults && npm run clean:eos-runtime",
|
|
@@ -189,7 +191,7 @@
|
|
|
189
191
|
"sync:eos-version": "node tools/nexowatt-sync-release-version.cjs",
|
|
190
192
|
"test:eos-version-sync": "node tools/nexowatt-version-sync-selftest.cjs",
|
|
191
193
|
"verify:eos-merge": "node tools/nexowatt-merge-update-selftest.cjs",
|
|
192
|
-
"check:eos-stable-
|
|
194
|
+
"check:eos-stable-v98": "node tools/nexowatt-stable-v98-selftest.cjs"
|
|
193
195
|
},
|
|
194
196
|
"author": "NexoWatt",
|
|
195
197
|
"private": false,
|
|
@@ -200,7 +202,7 @@
|
|
|
200
202
|
},
|
|
201
203
|
"nexowattReleasePolicy": {
|
|
202
204
|
"distTag": "latest",
|
|
203
|
-
"purpose": "accepted stable NexoWatt EOS sales-product release 7.9.
|
|
205
|
+
"purpose": "accepted stable NexoWatt EOS sales-product release 7.9.98"
|
|
204
206
|
},
|
|
205
207
|
"publisher": "NexoWatt"
|
|
206
208
|
}
|
|
@@ -1,60 +1,19 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
'use strict';
|
|
3
|
-
const fs =
|
|
4
|
-
const
|
|
5
|
-
const
|
|
6
|
-
const
|
|
7
|
-
const
|
|
8
|
-
|
|
9
|
-
const
|
|
10
|
-
|
|
11
|
-
const mainSource = read('src/main.ts');
|
|
12
|
-
const mainBuilt = read('build/main.js');
|
|
13
|
-
const webSource = read('src/lib/web.ts');
|
|
14
|
-
const webBuilt = read('build/lib/web.js');
|
|
15
|
-
const sourceUi = read('src-admin/public/js/eos-account-management.js');
|
|
16
|
-
const builtUi = read('adminWww/js/eos-account-management.js');
|
|
17
|
-
const roleUi = read('adminWww/js/eos-role-ui.js');
|
|
18
|
-
const css = read('adminWww/css/nexowatt-native-shell.css');
|
|
19
|
-
const index = read('adminWww/index.html');
|
|
20
|
-
const info = json('NEXOWATT_EOS_BUILD_INFO.json');
|
|
21
|
-
const shellTag = String(info.shellCacheTag || info.shellCacheVersion);
|
|
22
|
-
|
|
23
|
-
for (const code of [mainSource, mainBuilt]) {
|
|
24
|
-
for (const marker of [
|
|
25
|
-
'system.user.installer', 'system.user.guest', 'ensureEosDefaultRoleUsers', 'unknown random bootstrap secret',
|
|
26
|
-
'eosPasswordSetupRequired', 'personal password setup is required',
|
|
27
|
-
]) if (!code.includes(marker)) fail(`main account marker missing: ${marker}`);
|
|
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}`);
|
|
6
|
+
for(const code of [webSource,webBuilt]){
|
|
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');
|
|
28
11
|
}
|
|
29
|
-
for
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
]) if (!code.includes(marker)) fail(`web account marker missing: ${marker}`);
|
|
38
|
-
if (!code.includes('const explicitInstaller = targetAccess.groups.some')) fail('reset target is not restricted to explicit installer membership');
|
|
39
|
-
if (!code.includes('const explicitEndUser = targetAccess.groups.some')) fail('reset target is not restricted to explicit end-user membership');
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
for (const marker of [
|
|
43
|
-
'v91-account-management-under-access-rights', "['admin', 'installer']", 'nexowatt/account/manage',
|
|
44
|
-
'nexowatt/account/reset', 'X-NexoWatt-EOS-Account-Reset', 'data.canResetInstaller === true',
|
|
45
|
-
"account.role === 'enduser'", 'Admin/Service', 'Installateure', 'NEXOWATT_EOS_ACCOUNT_MANAGEMENT',
|
|
46
|
-
'ensureEntrySurface', "currentRoute() !== 'tab-users'", 'eos-account-management-entry',
|
|
47
|
-
]) if (!sourceUi.includes(marker)) fail(`account UI marker missing: ${marker}`);
|
|
48
|
-
if (sourceUi.includes("launcher.className = 'eos-account-management-launcher'")) fail('standalone account launcher is still created');
|
|
49
|
-
if (sourceUi.includes('new MutationObserver')) fail('account management adds a second broad MutationObserver');
|
|
50
|
-
if (sourceUi !== builtUi) fail('account management source/build drift');
|
|
51
|
-
if (!roleUi.includes("route === 'tab-users'")) fail('installer cannot reach Zugänge & Rechte');
|
|
52
|
-
if (roleUi.includes('NEXOWATT_EOS_ACCOUNT_MANAGEMENT.open')) fail('role overview opens account management outside Zugänge & Rechte');
|
|
53
|
-
if (!index.includes(`eos-account-management.js?v=${shellTag}`)) fail('account management asset is not active with the current cache tag');
|
|
54
|
-
for (const marker of [
|
|
55
|
-
'.eos-account-management-entry', '.eos-account-management-overlay', '.eos-account-management-dialog',
|
|
56
|
-
'.eos-account-row', '.eos-account-reset', 'html.eos-account-page-installer',
|
|
57
|
-
]) if (!css.includes(marker)) fail(`account management CSS marker missing: ${marker}`);
|
|
58
|
-
|
|
59
|
-
if (bad) process.exit(1);
|
|
60
|
-
console.log('[NexoWatt EOS account management] OK');
|
|
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');
|