iobroker.eos-admin 7.10.0 → 7.10.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/INSTALL_TEST_V7.10.2.md +22 -0
- package/MERGE_UPDATE_README_V7.10.2.md +11 -0
- package/NEXOWATT_EOS_BUILD_INFO.json +19 -21
- package/NEXOWATT_EOS_PREBUILT_MANIFEST.json +1410 -0
- package/PUBLISH_STABLE_V7.10.2.md +21 -0
- package/README.md +16 -6
- package/README_STABILITY_V7.10.2.md +20 -0
- package/RELEASE_ACCEPTANCE_V7.10.2.md +13 -0
- package/RELEASE_NOTES_V7.10.2.md +11 -0
- package/adminWww/assets/Intro-DkwRiz1n-v84.js +1 -1
- package/adminWww/assets/bootstrap-COulQZax-v84.js +2 -2
- package/adminWww/css/eos-ems-overview.css +5 -3
- package/adminWww/css/nexowatt-native-shell.css +85 -413
- package/adminWww/index.html +20 -21
- package/adminWww/js/eos-account-management.js +28 -19
- package/adminWww/js/eos-assistant.js +1 -1
- package/adminWww/js/eos-ems-overview.js +1 -1
- package/adminWww/js/eos-role-bootstrap.js +17 -80
- package/adminWww/js/eos-role-ui.js +28 -4
- package/adminWww/js/nexowatt-native-shell.js +1 -1
- package/adminWww/static/js/nexowatt-stable-login.js +43 -70
- package/adminWww/static/js/nexowatt-stable-v7101.js +27 -0
- package/build/lib/eosAutoUpdate.js +418 -20
- package/build/lib/eosAutoUpdate.js.map +1 -0
- package/build/lib/eosRequestSecurity.js +4 -1
- package/build/lib/eosRequestSecurity.js.map +1 -0
- package/build/lib/web.js +161 -254
- package/build/lib/web.js.map +1 -1
- package/build/main.js +39 -67
- package/io-package.json +72 -7
- package/package.json +24 -25
- package/tools/nexowatt-account-management-selftest.cjs +15 -19
- package/tools/nexowatt-account-password-flow-selftest.cjs +15 -0
- package/tools/nexowatt-apply-ems-overview.cjs +4 -2
- package/tools/nexowatt-auto-update-selftest.cjs +144 -32
- package/tools/nexowatt-backend-runtime-selftest.cjs +147 -0
- package/tools/nexowatt-clean-legacy-runtime.cjs +1 -1
- package/tools/nexowatt-ems-overview-selftest.cjs +1 -1
- package/tools/nexowatt-ensure-release-defaults.cjs +1 -1
- package/tools/nexowatt-login-layout-selftest.cjs +9 -13
- package/tools/nexowatt-merge-update-selftest.cjs +7 -1
- package/tools/nexowatt-modern-ui-selftest.cjs +10 -46
- package/tools/nexowatt-password-write-selftest.cjs +46 -16
- package/tools/nexowatt-prebuilt-release-selftest.cjs +292 -0
- package/tools/nexowatt-release-defaults-selftest.cjs +1 -1
- package/tools/nexowatt-runtime-cleanup-selftest.cjs +6 -8
- package/tools/nexowatt-stable-v7102-selftest.cjs +51 -0
- package/tools/nexowatt-sync-release-version.cjs +43 -5
- package/tools/nexowatt-ui-overview-runtime-selftest.cjs +2 -3
- package/tools/nexowatt-validate-package.cjs +54 -29
- package/tools/nexowatt-version-sync-selftest.cjs +18 -1
- package/INSTALL_TEST_V7.10.0.md +0 -11
- package/MERGE_UPDATE_README_V7.10.0.md +0 -5
- package/PUBLISH_STABLE_V7.10.0.md +0 -15
- package/README_STABILITY_V7.10.0.md +0 -3
- package/RELEASE_ACCEPTANCE_V7.10.0.md +0 -11
- package/RELEASE_NOTES_V7.10.0.md +0 -17
- package/adminWww/js/eos-release-watch.js +0 -77
- package/adminWww/static/js/nexowatt-stable-v7100.js +0 -111
- package/build/lib/eosPassword.js +0 -72
- package/build/lib/nexowattStableAuth.js +0 -74
- package/src/lib/eosAutoUpdate.ts +0 -320
- package/tools/nexowatt-cache-update-selftest.cjs +0 -12
- package/tools/nexowatt-request-security-selftest.cjs +0 -11
- package/tools/nexowatt-stable-v7100-selftest.cjs +0 -17
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
(() => {
|
|
2
2
|
'use strict';
|
|
3
3
|
|
|
4
|
-
const VERSION = '
|
|
4
|
+
const VERSION = 'v98-account-management-real-password-write';
|
|
5
5
|
const script = document.currentScript || document.querySelector('script[src*="eos-account-management.js"]');
|
|
6
6
|
const base = new URL('../', script?.src || window.location.href);
|
|
7
7
|
const abort = new AbortController();
|
|
@@ -19,11 +19,10 @@
|
|
|
19
19
|
introInstaller: 'Du kannst Endkundenzugänge zurücksetzen. Admin- und Installateurzugänge bleiben NexoWatt Service vorbehalten.',
|
|
20
20
|
loading: 'Zugänge werden geladen …', empty: 'Keine passenden Konten gefunden.', close: 'Schließen', refresh: 'Aktualisieren',
|
|
21
21
|
installer: 'Installateur', enduser: 'Endkunde / Gast', active: 'Passwort aktiv', first: 'Erstanmeldung offen', disabled: 'Deaktiviert',
|
|
22
|
-
reset: 'Passwort zurücksetzen', resetting: 'Wird zurückgesetzt …', resetConfirm: name => `Soll der Zugang „${name}“ wirklich zurückgesetzt werden? Danach gilt einmalig das Startpasswort „nexowatt“ und
|
|
23
|
-
resetDone: name => `Der Zugang „${name}“
|
|
24
|
-
resetFailed: 'Der Zugang konnte nicht zurückgesetzt werden.', lastSet: 'Letzte Passwortvergabe', lastReset: 'Letzter Reset', by: 'durch',
|
|
22
|
+
reset: 'Passwort zurücksetzen', resetting: 'Wird zurückgesetzt …', resetConfirm: name => `Soll der Zugang „${name}“ wirklich zurückgesetzt werden? Das bisherige Passwort wird ungültig. Danach gilt einmalig das Startpasswort „nexowatt“ und beim nächsten Login muss sofort ein persönliches Passwort vergeben werden.`,
|
|
23
|
+
resetDone: name => `Der Zugang „${name}“ ist zurückgesetzt. Einmalig mit dem Startpasswort „nexowatt“ anmelden und anschließend direkt ein persönliches Passwort festlegen.`,
|
|
24
|
+
resetFailed: 'Der Zugang konnte nicht zurückgesetzt werden.', permissionError: 'Für dieses Konto ist das Zurücksetzen nicht erlaubt.', originError: 'Die Sicherheitsprüfung der Anfrage ist fehlgeschlagen. Seite mit Strg+F5 neu laden.', disabledError: 'Das Konto ist deaktiviert und kann nicht zurückgesetzt werden.', notFoundError: 'Das Konto wurde nicht gefunden.', writeError: 'Das neue Startpasswort konnte nicht in das Benutzerkonto geschrieben werden.', lastSet: 'Letzte Passwortvergabe', lastReset: 'Letzter Reset', by: 'durch',
|
|
25
25
|
security: 'Admin/Service darf Installateur und Endkunde zurücksetzen. Installateure dürfen ausschließlich Endkunden zurücksetzen.',
|
|
26
|
-
errors: { permissionError: 'Die Admin-/Installateurberechtigung konnte nicht bestätigt werden. Bitte neu anmelden.', invalidRequest: 'Die Sicherheitsbestätigung fehlt. Bitte die Seite neu laden.', invalidRequestOrigin: 'Die Sitzung oder Adresse hat sich geändert. Bitte die Seite neu laden.', invalidTarget: 'Dieses Konto darf nicht über EOS zurückgesetzt werden.', accountDisabled: 'Das Konto ist deaktiviert.', accountNotFound: 'Das Benutzerkonto wurde nicht gefunden.', passwordApiUnavailable: 'Die EOS-Passwortverwaltung ist nicht verfügbar.', passwordNotPersisted: 'Das Startpasswort wurde nicht gespeichert.', passwordVerificationFailed: 'Das Startpasswort wurde geschrieben, aber nicht als gültige Anmeldung bestätigt.', passwordMetadataNotPersisted: 'Der Erstanmeldungsstatus wurde nicht gespeichert.', accountResetFailed: 'Das Konto konnte serverseitig nicht zurückgesetzt werden.' },
|
|
27
26
|
},
|
|
28
27
|
en: {
|
|
29
28
|
launcher: 'Accounts', titleAdmin: 'Accounts & roles', titleInstaller: 'End-user accounts',
|
|
@@ -31,11 +30,10 @@
|
|
|
31
30
|
introInstaller: 'You may reset end-user accounts. Admin and installer accounts remain reserved for NexoWatt Service.',
|
|
32
31
|
loading: 'Loading accounts …', empty: 'No matching accounts found.', close: 'Close', refresh: 'Refresh',
|
|
33
32
|
installer: 'Installer', enduser: 'End user / Guest', active: 'Password active', first: 'First activation open', disabled: 'Disabled',
|
|
34
|
-
reset: 'Reset password', resetting: 'Resetting …', resetConfirm: name => `Reset account “${name}”? The
|
|
35
|
-
resetDone: name => `Account “${name}” was reset in
|
|
36
|
-
resetFailed: 'The account could not be reset.', lastSet: 'Last password setup', lastReset: 'Last reset', by: 'by',
|
|
33
|
+
reset: 'Reset password', resetting: 'Resetting …', resetConfirm: name => `Reset account “${name}”? The current password becomes invalid. Sign in once with the initial password “nexowatt”, then create a personal password immediately.`,
|
|
34
|
+
resetDone: name => `Account “${name}” was reset. Sign in once with “nexowatt” and then create a personal password.`,
|
|
35
|
+
resetFailed: 'The account could not be reset.', permissionError: 'Reset is not permitted for this account.', originError: 'The request security check failed. Reload the page with Ctrl+F5.', disabledError: 'The account is disabled and cannot be reset.', notFoundError: 'The account was not found.', writeError: 'The initial password could not be written to the user account.', lastSet: 'Last password setup', lastReset: 'Last reset', by: 'by',
|
|
37
36
|
security: 'Admin/Service may reset installer and end-user accounts. Installers may reset end-user accounts only.',
|
|
38
|
-
errors: { permissionError: 'Admin/Installer permission could not be confirmed. Sign in again.', invalidRequest: 'The security confirmation is missing. Reload the page.', invalidRequestOrigin: 'The session or address changed. Reload the page.', invalidTarget: 'This account cannot be reset through EOS.', accountDisabled: 'The account is disabled.', accountNotFound: 'The user account was not found.', passwordApiUnavailable: 'The EOS password service is unavailable.', passwordNotPersisted: 'The initial password was not saved.', passwordVerificationFailed: 'The initial password was written but could not be verified.', passwordMetadataNotPersisted: 'The first-login status was not saved.', accountResetFailed: 'The account could not be reset on the server.' },
|
|
39
37
|
},
|
|
40
38
|
nl: {
|
|
41
39
|
launcher: 'Toegangen', titleAdmin: 'Toegangen & rollen', titleInstaller: 'Eindgebruikerstoegangen',
|
|
@@ -43,15 +41,26 @@
|
|
|
43
41
|
introInstaller: 'Je kunt eindgebruikersaccounts resetten. Admin- en installateurstoegang blijft voor NexoWatt Service.',
|
|
44
42
|
loading: 'Toegangen worden geladen …', empty: 'Geen passende accounts gevonden.', close: 'Sluiten', refresh: 'Vernieuwen',
|
|
45
43
|
installer: 'Installateur', enduser: 'Eindgebruiker / Guest', active: 'Wachtwoord actief', first: 'Eerste activering open', disabled: 'Uitgeschakeld',
|
|
46
|
-
reset: 'Wachtwoord resetten', resetting: 'Wordt gereset …', resetConfirm: name => `Account „${name}“ resetten?
|
|
47
|
-
resetDone: name => `Account „${name}“ is
|
|
48
|
-
resetFailed: 'Het account kon niet worden gereset.', lastSet: 'Laatste wachtwoordinstelling', lastReset: 'Laatste reset', by: 'door',
|
|
44
|
+
reset: 'Wachtwoord resetten', resetting: 'Wordt gereset …', resetConfirm: name => `Account „${name}“ resetten? Het huidige wachtwoord wordt ongeldig. Meld één keer aan met het startwachtwoord „nexowatt“ en stel daarna direct een persoonlijk wachtwoord in.`,
|
|
45
|
+
resetDone: name => `Account „${name}“ is gereset. Meld één keer aan met „nexowatt“ en stel daarna een persoonlijk wachtwoord in.`,
|
|
46
|
+
resetFailed: 'Het account kon niet worden gereset.', permissionError: 'Resetten is voor dit account niet toegestaan.', originError: 'De veiligheidscontrole van het verzoek is mislukt. Herlaad de pagina met Ctrl+F5.', disabledError: 'Het account is uitgeschakeld en kan niet worden gereset.', notFoundError: 'Het account werd niet gevonden.', writeError: 'Het startwachtwoord kon niet naar het gebruikersaccount worden geschreven.', lastSet: 'Laatste wachtwoordinstelling', lastReset: 'Laatste reset', by: 'door',
|
|
49
47
|
security: 'Admin/service mag installateur- en eindgebruikersaccounts resetten. Installateurs alleen eindgebruikers.',
|
|
50
|
-
errors: { permissionError: 'De Admin-/Installateurrechten konden niet worden bevestigd. Meld opnieuw aan.', invalidRequest: 'De beveiligingsbevestiging ontbreekt. Herlaad de pagina.', invalidRequestOrigin: 'De sessie of het adres is gewijzigd. Herlaad de pagina.', invalidTarget: 'Dit account kan niet via EOS worden gereset.', accountDisabled: 'Het account is uitgeschakeld.', accountNotFound: 'Het gebruikersaccount is niet gevonden.', passwordApiUnavailable: 'De EOS-wachtwoordservice is niet beschikbaar.', passwordNotPersisted: 'Het startwachtwoord is niet opgeslagen.', passwordVerificationFailed: 'Het startwachtwoord is geschreven maar kon niet worden geverifieerd.', passwordMetadataNotPersisted: 'De eerste-aanmeldstatus is niet opgeslagen.', accountResetFailed: 'Het account kon server-side niet worden gereset.' },
|
|
51
48
|
},
|
|
52
49
|
};
|
|
53
50
|
const t = () => i18n[language()];
|
|
54
|
-
const
|
|
51
|
+
const accountErrorText = code => {
|
|
52
|
+
const text = t();
|
|
53
|
+
return ({
|
|
54
|
+
permissionError: text.permissionError,
|
|
55
|
+
invalidRequestOrigin: text.originError,
|
|
56
|
+
accountDisabled: text.disabledError,
|
|
57
|
+
accountNotFound: text.notFoundError,
|
|
58
|
+
passwordApiUnavailable: text.writeError,
|
|
59
|
+
passwordWriteFailed: text.writeError,
|
|
60
|
+
passwordVerificationFailed: text.writeError,
|
|
61
|
+
userObjectUnavailableAfterPasswordChange: text.writeError,
|
|
62
|
+
})[String(code || '')] || text.resetFailed;
|
|
63
|
+
};
|
|
55
64
|
const roleFromPolicy = policy => {
|
|
56
65
|
const raw = normalize(policy?.role || '');
|
|
57
66
|
if (policy?.isAdmin || policy?.isEosAdminGroup || /admin|service/.test(raw)) return 'admin';
|
|
@@ -148,17 +157,17 @@
|
|
|
148
157
|
reset.disabled = true; reset.textContent = t().resetting; setStatus('', '');
|
|
149
158
|
try {
|
|
150
159
|
const response = await fetch(new URL('nexowatt/account/reset', base).href, {
|
|
151
|
-
method: 'POST', credentials: '
|
|
160
|
+
method: 'POST', credentials: 'include', cache: 'no-store',
|
|
152
161
|
headers: { 'Content-Type': 'application/json', Accept: 'application/json', 'X-NexoWatt-EOS-Account-Reset': '1' },
|
|
153
162
|
body: JSON.stringify({ user: account.id }),
|
|
154
163
|
});
|
|
155
164
|
const payload = await response.json().catch(() => ({}));
|
|
156
|
-
if (!response.ok || payload.error) throw new Error(payload.error
|
|
165
|
+
if (!response.ok || payload.error) throw new Error(accountErrorText(payload.error));
|
|
157
166
|
setStatus(t().resetDone(label), 'success');
|
|
158
167
|
await loadAccounts();
|
|
159
168
|
} catch (error) {
|
|
160
169
|
reset.disabled = false; reset.textContent = t().reset;
|
|
161
|
-
setStatus(
|
|
170
|
+
setStatus(error?.message || t().resetFailed, 'error');
|
|
162
171
|
}
|
|
163
172
|
});
|
|
164
173
|
actions.appendChild(reset);
|
|
@@ -180,12 +189,12 @@
|
|
|
180
189
|
if (!state.overlay) return;
|
|
181
190
|
setStatus(t().loading, '');
|
|
182
191
|
try {
|
|
183
|
-
const response = await fetch(new URL('nexowatt/account/manage', base).href, { credentials: '
|
|
192
|
+
const response = await fetch(new URL('nexowatt/account/manage', base).href, { credentials: 'include', cache: 'no-store', headers: { Accept: 'application/json' } });
|
|
184
193
|
const data = await response.json().catch(() => ({}));
|
|
185
194
|
if (!response.ok || data.error) throw new Error(data.error || t().resetFailed);
|
|
186
195
|
renderAccounts(data); setStatus('', '');
|
|
187
196
|
} catch (error) {
|
|
188
|
-
setStatus(
|
|
197
|
+
setStatus(error?.message || t().resetFailed, 'error');
|
|
189
198
|
}
|
|
190
199
|
};
|
|
191
200
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
(() => {
|
|
2
2
|
'use strict';
|
|
3
|
-
// NexoWatt EOS stable 7.
|
|
3
|
+
// NexoWatt EOS stable 7.9.97: EOS Assist remains disabled until the
|
|
4
4
|
// read-only system assistant is rebuilt and accepted separately.
|
|
5
5
|
window.NEXOWATT_EOS_ASSIST_DISABLED = true;
|
|
6
6
|
document.documentElement.classList.add('eos-assist-disabled');
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
(() => {
|
|
2
2
|
'use strict';
|
|
3
3
|
|
|
4
|
-
const VERSION = '
|
|
4
|
+
const VERSION = 'v7101-standard-password-native-overview';
|
|
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;
|
|
@@ -80,7 +80,6 @@
|
|
|
80
80
|
required: 'Bitte beide Passwortfelder ausfüllen.', mismatch: 'Die Passwörter stimmen nicht überein.',
|
|
81
81
|
length: min => `Das Passwort muss mindestens ${min} Zeichen lang sein.`, complexity: 'Groß-/Kleinbuchstabe, Zahl und Sonderzeichen sind erforderlich.',
|
|
82
82
|
easy: 'Das Passwort ist zu leicht oder enthält den Kontonamen.', generic: 'Das Passwort konnte nicht gespeichert werden.', success: 'Passwort gespeichert. Die Anmeldung wird neu gestartet …',
|
|
83
|
-
backendErrors: { invalidRequest: 'Die Sicherheitsbestätigung fehlt. Bitte erneut anmelden.', invalidRequestOrigin: 'Die Sitzung oder aufgerufene Adresse hat sich geändert. Bitte erneut anmelden.', passwordApiUnavailable: 'Die ioBroker-Passwortverwaltung ist nicht verfügbar.', passwordNotPersisted: 'Das Passwort wurde vom ioBroker-Controller nicht gespeichert. Bitte Systemlog prüfen.', passwordVerificationFailed: 'Das neue Passwort wurde geschrieben, aber nicht als gültige Anmeldung bestätigt.', passwordMetadataNotPersisted: 'Das Passwort wurde gespeichert, aber der Erstanmeldungsstatus konnte nicht abgeschlossen werden.', passwordSetupFailed: 'Das Passwort konnte serverseitig nicht gespeichert werden. Bitte das EOS-Systemlog prüfen.', passwordSetupTokenExpired: 'Die sichere Passwortfreigabe ist abgelaufen. Bitte erneut anmelden.', passwordSetupTokenMismatch: 'Die Passwortfreigabe gehört nicht zu dieser Sitzung. Bitte erneut anmelden.' },
|
|
84
83
|
securityTitle: 'Zugriff wird geprüft', securityIntro: 'Die sichere Anmeldung wird gerade geprüft. Die Oberfläche bleibt gesperrt, bis die Berechtigungen eindeutig geladen wurden.',
|
|
85
84
|
securityRetry: 'Jetzt erneut prüfen', securityLogout: 'Zur Anmeldung', securityAuto: seconds => `Automatischer neuer Versuch in ${seconds} Sekunden …`,
|
|
86
85
|
claimLauncher: 'Erstanmeldung', claimTitle: 'Konto erstmals aktivieren',
|
|
@@ -100,7 +99,6 @@
|
|
|
100
99
|
required: 'Please complete both password fields.', mismatch: 'The passwords do not match.',
|
|
101
100
|
length: min => `The password must contain at least ${min} characters.`, complexity: 'Upper/lower case, a number and a special character are required.',
|
|
102
101
|
easy: 'The password is too easy or contains the account name.', generic: 'The password could not be saved.', success: 'Password saved. Restarting sign-in …',
|
|
103
|
-
backendErrors: { invalidRequest: 'The security confirmation is missing. Sign in again.', invalidRequestOrigin: 'The session or address changed. Sign in again.', passwordApiUnavailable: 'The ioBroker password service is unavailable.', passwordNotPersisted: 'The ioBroker controller did not persist the password. Check the system log.', passwordVerificationFailed: 'The new password was written but could not be verified as a valid login.', passwordMetadataNotPersisted: 'The password was saved, but the first-login status could not be completed.', passwordSetupFailed: 'The password could not be saved on the server. Check the EOS system log.', passwordSetupTokenExpired: 'The secure password setup ticket expired. Sign in again.', passwordSetupTokenMismatch: 'The password setup ticket does not belong to this session. Sign in again.' },
|
|
104
102
|
securityTitle: 'Checking access', securityIntro: 'The secure sign-in is being verified. The interface stays locked until the permissions are loaded unambiguously.',
|
|
105
103
|
securityRetry: 'Check again now', securityLogout: 'Return to sign-in', securityAuto: seconds => `Retrying automatically in ${seconds} seconds …`,
|
|
106
104
|
claimLauncher: 'First sign-in', claimTitle: 'Activate account for the first time',
|
|
@@ -120,7 +118,6 @@
|
|
|
120
118
|
required: 'Vul beide wachtwoordvelden in.', mismatch: 'De wachtwoorden zijn niet gelijk.',
|
|
121
119
|
length: min => `Het wachtwoord moet minimaal ${min} tekens bevatten.`, complexity: 'Hoofdletter, kleine letter, cijfer en speciaal teken zijn verplicht.',
|
|
122
120
|
easy: 'Het wachtwoord is te eenvoudig of bevat de accountnaam.', generic: 'Het wachtwoord kon niet worden opgeslagen.', success: 'Wachtwoord opgeslagen. De aanmelding wordt opnieuw gestart …',
|
|
123
|
-
backendErrors: { invalidRequest: 'De beveiligingsbevestiging ontbreekt. Meld opnieuw aan.', invalidRequestOrigin: 'De sessie of het adres is gewijzigd. Meld opnieuw aan.', passwordApiUnavailable: 'De ioBroker-wachtwoordservice is niet beschikbaar.', passwordNotPersisted: 'De ioBroker-controller heeft het wachtwoord niet opgeslagen. Controleer het systeemlogboek.', passwordVerificationFailed: 'Het nieuwe wachtwoord is geschreven maar kon niet als geldige aanmelding worden bevestigd.', passwordMetadataNotPersisted: 'Het wachtwoord is opgeslagen, maar de eerste-aanmeldstatus kon niet worden afgerond.', passwordSetupFailed: 'Het wachtwoord kon server-side niet worden opgeslagen. Controleer het EOS-systeemlogboek.', passwordSetupTokenExpired: 'De beveiligde wachtwoordtoestemming is verlopen. Meld opnieuw aan.', passwordSetupTokenMismatch: 'De wachtwoordtoestemming hoort niet bij deze sessie. Meld opnieuw aan.' },
|
|
124
121
|
securityTitle: 'Toegang wordt gecontroleerd', securityIntro: 'De veilige aanmelding wordt gecontroleerd. De interface blijft vergrendeld totdat de rechten eenduidig zijn geladen.',
|
|
125
122
|
securityRetry: 'Nu opnieuw controleren', securityLogout: 'Terug naar aanmelden', securityAuto: seconds => `Automatisch opnieuw proberen over ${seconds} seconden …`,
|
|
126
123
|
claimLauncher: 'Eerste aanmelding', claimTitle: 'Account voor het eerst activeren',
|
|
@@ -133,32 +130,11 @@
|
|
|
133
130
|
},
|
|
134
131
|
};
|
|
135
132
|
|
|
136
|
-
const waitForPasswordSocket = async (timeoutMs = 10000) => {
|
|
137
|
-
const started = Date.now();
|
|
138
|
-
while (Date.now() - started < timeoutMs) {
|
|
139
|
-
const socket = window.NEXOWATT_EOS_ADMIN_SOCKET || window.NEXOWATT_EOS_SOCKET;
|
|
140
|
-
if (socket && typeof socket.changePassword === 'function') return socket;
|
|
141
|
-
await new Promise(resolve => window.setTimeout(resolve, 120));
|
|
142
|
-
}
|
|
143
|
-
return null;
|
|
144
|
-
};
|
|
145
|
-
|
|
146
|
-
const postWithTimeout = async (url, options, timeoutMs = 25000) => {
|
|
147
|
-
const controller = new AbortController();
|
|
148
|
-
const timer = window.setTimeout(() => controller.abort(), timeoutMs);
|
|
149
|
-
try {
|
|
150
|
-
return await fetch(url, { ...options, signal: controller.signal });
|
|
151
|
-
} finally {
|
|
152
|
-
window.clearTimeout(timer);
|
|
153
|
-
}
|
|
154
|
-
};
|
|
155
|
-
|
|
156
133
|
const showFirstLoginPassword = (policy, base) => {
|
|
157
134
|
const t = translations[language()];
|
|
158
135
|
const passwordSetup = policy?.passwordSetup || {};
|
|
159
136
|
const minLength = Number(passwordSetup.minLength || 10);
|
|
160
137
|
const userName = String(passwordSetup.userName || policy?.user || '').replace(/^system\.user\./, '') || 'user';
|
|
161
|
-
const setupToken = String(passwordSetup.setupToken || '');
|
|
162
138
|
const endpoint = new URL('nexowatt/account/first-password', base).href;
|
|
163
139
|
const logoutUrl = new URL('logout', base).href;
|
|
164
140
|
window.NEXOWATT_EOS_PASSWORD_SETUP_ACTIVE = true;
|
|
@@ -215,49 +191,21 @@
|
|
|
215
191
|
if (!/[a-z]/.test(password.value) || !/[A-Z]/.test(password.value) || !/\d/.test(password.value) || !/[^A-Za-z0-9]/.test(password.value)) return setStatus(t.complexity, 'error');
|
|
216
192
|
submit.disabled = true; submit.textContent = t.saving; setStatus('', '');
|
|
217
193
|
try {
|
|
218
|
-
const
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
// Use the same native path as the working ioBroker user editor.
|
|
223
|
-
await socket.changePassword(`system.user.${userName}`, password.value);
|
|
224
|
-
passwordAlreadyWritten = true;
|
|
225
|
-
} catch (socketError) {
|
|
226
|
-
console.warn('[NexoWatt EOS] Native password write failed; using server fallback:', socketError);
|
|
227
|
-
}
|
|
228
|
-
}
|
|
229
|
-
const response = await postWithTimeout(endpoint, {
|
|
230
|
-
method: 'POST', credentials: 'same-origin', cache: 'no-store',
|
|
231
|
-
headers: {
|
|
232
|
-
'Content-Type': 'application/json',
|
|
233
|
-
Accept: 'application/json',
|
|
234
|
-
'X-NexoWatt-EOS-First-Login': '1',
|
|
235
|
-
...(setupToken ? { 'X-NexoWatt-EOS-Password-Setup-Token': setupToken } : {}),
|
|
236
|
-
},
|
|
237
|
-
body: JSON.stringify({
|
|
238
|
-
password: password.value,
|
|
239
|
-
passwordRepeat: repeat.value,
|
|
240
|
-
setupToken,
|
|
241
|
-
passwordAlreadyWritten,
|
|
242
|
-
}),
|
|
194
|
+
const response = await fetch(endpoint, {
|
|
195
|
+
method: 'POST', credentials: 'include', cache: 'no-store',
|
|
196
|
+
headers: { 'Content-Type': 'application/json', Accept: 'application/json', 'X-NexoWatt-EOS-First-Login': '1' },
|
|
197
|
+
body: JSON.stringify({ password: password.value, passwordRepeat: repeat.value }),
|
|
243
198
|
});
|
|
244
199
|
const data = await response.json().catch(() => ({}));
|
|
245
200
|
if (!response.ok || data.error) {
|
|
246
|
-
const messages = { passwordRequired: t.required, passwordMismatch: t.mismatch, passwordLength: t.length(minLength), passwordComplexity: t.complexity, passwordTooEasy: t.easy,
|
|
201
|
+
const messages = { passwordRequired: t.required, passwordMismatch: t.mismatch, passwordLength: t.length(minLength), passwordComplexity: t.complexity, passwordTooEasy: t.easy, passwordSetupNotAllowed: t.generic, invalidRequestOrigin: t.generic, passwordApiUnavailable: t.generic, passwordWriteFailed: t.generic, passwordVerificationFailed: t.generic, userObjectUnavailableAfterPasswordChange: t.generic };
|
|
247
202
|
throw new Error(messages[data.error] || t.generic);
|
|
248
203
|
}
|
|
249
204
|
setStatus(t.success, 'success');
|
|
250
205
|
window.setTimeout(() => window.location.replace(logoutUrl), 650);
|
|
251
206
|
} catch (error) {
|
|
252
207
|
submit.disabled = false; submit.textContent = t.submit;
|
|
253
|
-
|
|
254
|
-
? (language() === 'de'
|
|
255
|
-
? 'Das Speichern hat zu lange gedauert. Bitte erneut versuchen.'
|
|
256
|
-
: language() === 'nl'
|
|
257
|
-
? 'Opslaan duurde te lang. Probeer opnieuw.'
|
|
258
|
-
: 'Saving timed out. Please try again.')
|
|
259
|
-
: error?.message || t.generic;
|
|
260
|
-
setStatus(message, 'error');
|
|
208
|
+
setStatus(error?.message || t.generic, 'error');
|
|
261
209
|
}
|
|
262
210
|
});
|
|
263
211
|
window.setTimeout(() => password.focus(), 0);
|
|
@@ -317,13 +265,13 @@
|
|
|
317
265
|
submit.disabled = true; submit.textContent = t.saving; setStatus('', '');
|
|
318
266
|
try {
|
|
319
267
|
const response = await fetch(endpoint, {
|
|
320
|
-
method: 'POST', credentials: '
|
|
268
|
+
method: 'POST', credentials: 'include', cache: 'no-store',
|
|
321
269
|
headers: { 'Content-Type': 'application/json', Accept: 'application/json', 'X-NexoWatt-EOS-Passwordless-Password': '1' },
|
|
322
270
|
body: JSON.stringify({ password: password.value, passwordRepeat: repeat.value }),
|
|
323
271
|
});
|
|
324
272
|
const data = await response.json().catch(() => ({}));
|
|
325
273
|
if (!response.ok || data.error) {
|
|
326
|
-
const messages = { passwordRequired: t.required, passwordMismatch: t.mismatch, passwordLength: t.length(minLength), passwordComplexity: t.complexity, passwordTooEasy: t.easy, claimExpired: t.claimExpired
|
|
274
|
+
const messages = { passwordRequired: t.required, passwordMismatch: t.mismatch, passwordLength: t.length(minLength), passwordComplexity: t.complexity, passwordTooEasy: t.easy, claimExpired: t.claimExpired };
|
|
327
275
|
throw new Error(messages[data.error] || t.generic);
|
|
328
276
|
}
|
|
329
277
|
overlay.querySelector('.eos-activation-steps span:nth-of-type(2)')?.classList.add('done');
|
|
@@ -367,17 +315,9 @@
|
|
|
367
315
|
const loginElements = () => {
|
|
368
316
|
const username = document.querySelector('input#username,input[name="username"]');
|
|
369
317
|
const password = document.querySelector('input#password,input[name="password"]');
|
|
370
|
-
const
|
|
371
|
-
const
|
|
372
|
-
|
|
373
|
-
|| password?.closest?.('.MuiPaper-root')
|
|
374
|
-
|| form
|
|
375
|
-
|| username?.closest?.('main,section')
|
|
376
|
-
|| password?.closest?.('main,section');
|
|
377
|
-
const submit = form?.querySelector?.('button[type="submit"]')
|
|
378
|
-
|| card?.querySelector?.('button[type="submit"]')
|
|
379
|
-
|| Array.from(card?.querySelectorAll?.('button') || []).find(button => /anmelden|login|sign in|aanmelden/.test(normalize(button.textContent || '')));
|
|
380
|
-
return { username, password, form, card, submit };
|
|
318
|
+
const card = username?.closest?.('.MuiPaper-root,form,main,section') || password?.closest?.('.MuiPaper-root,form,main,section');
|
|
319
|
+
const submit = card?.querySelector?.('button[type="submit"]') || Array.from(card?.querySelectorAll?.('button') || []).find(button => /anmelden|login|sign in|aanmelden/.test(normalize(button.textContent || '')));
|
|
320
|
+
return { username, password, card, submit };
|
|
381
321
|
};
|
|
382
322
|
const statusNode = card => card?.querySelector?.('.eos-login-first-status');
|
|
383
323
|
const directChildWithin = (ancestor, node) => {
|
|
@@ -533,7 +473,7 @@
|
|
|
533
473
|
setStatus(card, t.claimChecking, '');
|
|
534
474
|
try {
|
|
535
475
|
const response = await fetch(new URL('nexowatt/account/passwordless-claim', base).href, {
|
|
536
|
-
method: 'POST', credentials: '
|
|
476
|
+
method: 'POST', credentials: 'include', cache: 'no-store',
|
|
537
477
|
headers: { 'Content-Type': 'application/json', Accept: 'application/json', 'X-NexoWatt-EOS-Passwordless-Claim': '1' },
|
|
538
478
|
body: JSON.stringify({ user: account }),
|
|
539
479
|
});
|
|
@@ -560,7 +500,7 @@
|
|
|
560
500
|
const { username, password, card, submit } = loginElements();
|
|
561
501
|
if (!username || !password || !card) return;
|
|
562
502
|
card.classList.add('eos-login-card-modern');
|
|
563
|
-
//
|
|
503
|
+
// v98 compact normal-login first activation: do not add role buttons or a second panel.
|
|
564
504
|
// The account is entered in the existing Loginname field; a blank password is accepted only
|
|
565
505
|
// after the backend confirms that this exact managed account is eligible.
|
|
566
506
|
card.querySelectorAll('.eos-login-role-selector').forEach(element => element.remove());
|
|
@@ -685,7 +625,6 @@
|
|
|
685
625
|
const isLoginRequest = /(?:^|[?&])login(?:[=&]|$)/i.test(window.location.search || '');
|
|
686
626
|
if (isLoginRequest) {
|
|
687
627
|
launch();
|
|
688
|
-
installIntegratedFirstLogin(base);
|
|
689
628
|
return;
|
|
690
629
|
}
|
|
691
630
|
|
|
@@ -694,7 +633,7 @@
|
|
|
694
633
|
const timeout = window.setTimeout(() => controller.abort(), 8000);
|
|
695
634
|
|
|
696
635
|
window.NEXOWATT_EOS_BOOTSTRAP_READY = fetch(contextUrl, {
|
|
697
|
-
credentials: '
|
|
636
|
+
credentials: 'include', cache: 'no-store', headers: { Accept: 'application/json' }, signal: controller.signal,
|
|
698
637
|
})
|
|
699
638
|
.then(response => { if (!response.ok) throw new Error(`HTTP ${response.status}`); return response.json(); })
|
|
700
639
|
.then(policy => {
|
|
@@ -710,10 +649,6 @@
|
|
|
710
649
|
window.NEXOWATT_EOS_ACCESS_ROLE = role;
|
|
711
650
|
try { window.sessionStorage.removeItem('NEXOWATT_EOS_SECURITY_RETRY_COUNT'); } catch (_) { /* ignore */ }
|
|
712
651
|
lockExpertMode(role);
|
|
713
|
-
if (role !== 'admin' && (resolved.mustChangePassword || resolved.passwordSetup?.required)) {
|
|
714
|
-
showFirstLoginPassword(resolved, base);
|
|
715
|
-
return resolved;
|
|
716
|
-
}
|
|
717
652
|
const route = currentRoute();
|
|
718
653
|
if (!isAllowed(role, route)) navigate(defaultTab(role));
|
|
719
654
|
launch();
|
|
@@ -727,6 +662,8 @@
|
|
|
727
662
|
})
|
|
728
663
|
.finally(() => window.clearTimeout(timeout));
|
|
729
664
|
|
|
665
|
+
window.NEXOWATT_EOS_STANDARD_PASSWORD_MODE = true;
|
|
666
|
+
document.documentElement.classList.remove('eos-first-login-active');
|
|
730
667
|
window.NEXOWATT_EOS_ROLE_BOOTSTRAP = Object.freeze({
|
|
731
668
|
version: VERSION, getRole: () => window.NEXOWATT_EOS_ACCESS_ROLE || 'unknown',
|
|
732
669
|
getPolicy: () => window.NEXOWATT_EOS_BOOTSTRAP_POLICY || null, isAllowed, defaultTab,
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
(() => {
|
|
2
2
|
'use strict';
|
|
3
3
|
|
|
4
|
-
const VERSION = '
|
|
4
|
+
const VERSION = 'v7101-native-overview-standard-users';
|
|
5
5
|
window.NEXOWATT_EOS_ROLE_UI_VERSION = VERSION;
|
|
6
6
|
|
|
7
7
|
const state = {
|
|
@@ -65,7 +65,7 @@
|
|
|
65
65
|
if (role === 'admin') return true;
|
|
66
66
|
if (isOfficialReserveTab(route)) return false;
|
|
67
67
|
if (role === 'installer') return route === 'tab-intro' || route === 'tab-users' || !isInstallerDenied(route, label);
|
|
68
|
-
if (role === 'enduser') return isEndUserTab(route, label);
|
|
68
|
+
if (role === 'enduser') return route === 'tab-users' || isEndUserTab(route, label);
|
|
69
69
|
return false;
|
|
70
70
|
};
|
|
71
71
|
const defaultTab = () => 'tab-intro';
|
|
@@ -226,7 +226,7 @@
|
|
|
226
226
|
['Datenpunkte', 'Messwerte prüfen und freigegebene Werte schreiben', 'tab-objects', 'datapoints'],
|
|
227
227
|
['Struktur', 'Räume und Funktionen für Smart Home zuordnen', 'tab-enums', 'structure'],
|
|
228
228
|
['Geräte', 'Geräteintegration und Inbetriebnahme öffnen', 'tab-devicemanager', 'devices'],
|
|
229
|
-
['Zugänge & Rechte', '
|
|
229
|
+
['Zugänge & Rechte', 'Passwörter im nativen Benutzereditor verwalten', 'tab-users', 'rights'],
|
|
230
230
|
['Basis-Einstellungen', 'Standort, Sprache und Anlagenparameter', 'basic-settings', 'settings'],
|
|
231
231
|
...(backupTab ? [['NexoWatt Sicherung', 'Sicherung und Wiederherstellung des EOS-Systems', backupTab, 'backup']] : []),
|
|
232
232
|
['EOS Cockpit', 'Energie-, Lade- und Gebäudesteuerung öffnen', uiTab, 'eos'],
|
|
@@ -277,8 +277,31 @@
|
|
|
277
277
|
if (!admin) button.setAttribute('aria-hidden', 'true'); else button.removeAttribute('aria-hidden');
|
|
278
278
|
});
|
|
279
279
|
};
|
|
280
|
+
const filterNativeUsersPage = () => safe(() => {
|
|
281
|
+
if (currentRoute() !== 'tab-users' || state.role === 'admin') return;
|
|
282
|
+
const paper = appPaper(); if (!paper) return;
|
|
283
|
+
const policyUser = String(state.policy?.user || state.policy?.userId || window.NEXOWATT_EOS_BOOTSTRAP_POLICY?.user || '').replace(/^system\.user\./, '').toLowerCase();
|
|
284
|
+
const allowed = state.role === 'installer'
|
|
285
|
+
? new Set(['installer', 'user', 'guest', policyUser].filter(Boolean))
|
|
286
|
+
: new Set([policyUser || (state.role === 'enduser' ? 'user' : '')].filter(Boolean));
|
|
287
|
+
paper.querySelectorAll('.MuiCard-root,[role="row"],li').forEach(row => {
|
|
288
|
+
const text = normalize(row.textContent || '');
|
|
289
|
+
const match = text.match(/system user ([a-z0-9_.@-]+)/) || text.match(/system\.user\.([a-z0-9_.@-]+)/);
|
|
290
|
+
if (!match) return;
|
|
291
|
+
row.classList.toggle('eos-role-hidden', !allowed.has(match[1]));
|
|
292
|
+
});
|
|
293
|
+
paper.querySelectorAll('button').forEach(button => {
|
|
294
|
+
const title = normalize(button.getAttribute('aria-label') || button.getAttribute('title') || button.textContent || '');
|
|
295
|
+
if (/add user|add group|delete|remove|benutzer hinzufugen|gruppe hinzufugen|loschen/.test(title)) {
|
|
296
|
+
button.classList.add('eos-role-hidden'); button.disabled = true;
|
|
297
|
+
}
|
|
298
|
+
});
|
|
299
|
+
paper.querySelectorAll('[data-eos-user-role-filter]').forEach(node => node.removeAttribute('data-eos-user-role-filter'));
|
|
300
|
+
paper.setAttribute('data-eos-user-role-filter', state.role);
|
|
301
|
+
});
|
|
302
|
+
|
|
280
303
|
const ensureSafeOverview = () => safe(() => {
|
|
281
|
-
// 7.
|
|
304
|
+
// 7.9.97: never cover the real Admin Intro with a second tile surface.
|
|
282
305
|
// Installer and end-user use the native card component; security remains
|
|
283
306
|
// enforced by route/instance filters and backend permissions.
|
|
284
307
|
removeSafeOverview();
|
|
@@ -415,6 +438,7 @@
|
|
|
415
438
|
applySensitiveDialogPolicy();
|
|
416
439
|
redirectIfNeeded();
|
|
417
440
|
ensureSafeOverview();
|
|
441
|
+
filterNativeUsersPage();
|
|
418
442
|
hideOfficialReserveSurfaces();
|
|
419
443
|
ensureReserveObserver();
|
|
420
444
|
suppressPermissionErrors();
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
(() => {
|
|
2
2
|
'use strict';
|
|
3
3
|
|
|
4
|
-
const VERSION = '
|
|
4
|
+
const VERSION = 'v7101-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,72 +1,45 @@
|
|
|
1
|
-
/* NexoWatt EOS stable
|
|
1
|
+
/* NexoWatt EOS stable runtime v98 */
|
|
2
2
|
(() => {
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
const
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
submit.disabled = true;
|
|
46
|
-
submit.setAttribute('aria-disabled', 'true');
|
|
47
|
-
}
|
|
48
|
-
};
|
|
49
|
-
const hideLegacyUi = () => {
|
|
50
|
-
for (const element of document.querySelectorAll('button,a,[role="button"],div,span')) {
|
|
51
|
-
const value = (element.textContent || '').trim();
|
|
52
|
-
if (!value || value.length > 100) continue;
|
|
53
|
-
if (ASSIST_TEXT.test(value) || PASSWORDLESS_TEXT.test(value)) {
|
|
54
|
-
const target = element.closest('button,a,[role="button"],[data-eos-assist],.eos-assist') || element;
|
|
55
|
-
target.style.setProperty('display', 'none', 'important');
|
|
56
|
-
target.setAttribute('aria-hidden', 'true');
|
|
57
|
-
}
|
|
58
|
-
}
|
|
59
|
-
};
|
|
60
|
-
const apply = () => { sync(); hideLegacyUi(); };
|
|
61
|
-
let scheduled = false;
|
|
62
|
-
const schedule = () => {
|
|
63
|
-
if (scheduled) return;
|
|
64
|
-
scheduled = true;
|
|
65
|
-
requestAnimationFrame(() => { scheduled = false; apply(); });
|
|
66
|
-
};
|
|
67
|
-
new MutationObserver(schedule).observe(document.documentElement, { subtree: true, childList: true });
|
|
68
|
-
document.addEventListener('input', schedule, true);
|
|
69
|
-
document.addEventListener('change', schedule, true);
|
|
70
|
-
if (document.readyState === 'loading') document.addEventListener('DOMContentLoaded', apply, { once: true }); else apply();
|
|
71
|
-
window.NEXOWATT_EOS_STABLE_LOGIN = Object.freeze({ version: VERSION, refresh: apply });
|
|
3
|
+
'use strict';
|
|
4
|
+
const MANAGED_USERS = new Set(['installer', 'guest', 'user']);
|
|
5
|
+
const ASSIST_TEXT = /EOS\s*Assist/i;
|
|
6
|
+
const PASSWORDLESS_TEXT = /Erstanmeldung\s+ohne\s+Passwort|first\s+sign-?in\s+without\s+password/i;
|
|
7
|
+
const isLogin = () => /(?:\?|&)login(?:[=&]|$)/i.test(location.search) || /\/login(?:[/?#]|$)/i.test(location.pathname + location.hash);
|
|
8
|
+
const visible = element => !!element && element.getClientRects().length > 0;
|
|
9
|
+
const findInput = kind => {
|
|
10
|
+
const inputs = [...document.querySelectorAll('input')].filter(visible);
|
|
11
|
+
if (kind === 'password') return inputs.find(input => input.type === 'password');
|
|
12
|
+
return inputs.find(input => input.type !== 'password' && /user|login|name/i.test(`${input.name} ${input.id} ${input.autocomplete} ${input.getAttribute('aria-label') || ''}`)) || inputs.find(input => input.type !== 'password');
|
|
13
|
+
};
|
|
14
|
+
const findSubmit = () => [...document.querySelectorAll('button,input[type="submit"]')].find(element => visible(element) && (/anmelden|login|sign in/i.test((element.textContent || element.value || '').trim()) || element.type === 'submit'));
|
|
15
|
+
const sync = () => {
|
|
16
|
+
if (!isLogin()) return;
|
|
17
|
+
document.documentElement.classList.add('nw-eos-login-v98');
|
|
18
|
+
document.body?.classList.add('nw-eos-login-v98');
|
|
19
|
+
const username = findInput('user');
|
|
20
|
+
const password = findInput('password');
|
|
21
|
+
const submit = findSubmit();
|
|
22
|
+
const account = String(username?.value || '').trim().toLowerCase().replace(/^system\.user\./, '');
|
|
23
|
+
if (submit && MANAGED_USERS.has(account) && !String(password?.value || '')) {
|
|
24
|
+
submit.disabled = true;
|
|
25
|
+
submit.setAttribute('aria-disabled', 'true');
|
|
26
|
+
}
|
|
27
|
+
};
|
|
28
|
+
const hideLegacyUi = () => {
|
|
29
|
+
for (const element of document.querySelectorAll('button,a,[role="button"],div,span')) {
|
|
30
|
+
const value = (element.textContent || '').trim();
|
|
31
|
+
if (!value || value.length > 100) continue;
|
|
32
|
+
if (ASSIST_TEXT.test(value) || PASSWORDLESS_TEXT.test(value)) {
|
|
33
|
+
const target = element.closest('button,a,[role="button"],[data-eos-assist],.eos-assist') || element;
|
|
34
|
+
target.style.setProperty('display', 'none', 'important');
|
|
35
|
+
target.setAttribute('aria-hidden', 'true');
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
};
|
|
39
|
+
const apply = () => { sync(); hideLegacyUi(); };
|
|
40
|
+
const observer = new MutationObserver(() => requestAnimationFrame(apply));
|
|
41
|
+
observer.observe(document.documentElement, { subtree: true, childList: true });
|
|
42
|
+
document.addEventListener('input', apply, true);
|
|
43
|
+
document.addEventListener('change', apply, true);
|
|
44
|
+
if (document.readyState === 'loading') document.addEventListener('DOMContentLoaded', apply, { once: true }); else apply();
|
|
72
45
|
})();
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
(() => {
|
|
2
|
+
'use strict';
|
|
3
|
+
const VERSION = 'v7101-scroll-standard-password';
|
|
4
|
+
const ensureScroll = () => {
|
|
5
|
+
const root = document.documentElement;
|
|
6
|
+
const paper = document.getElementById('app-paper');
|
|
7
|
+
if (!paper || !root.classList.contains('eos-app') || !root.classList.contains('eos-route-intro')) return;
|
|
8
|
+
paper.dataset.nexowattScrollable = 'true';
|
|
9
|
+
paper.style.setProperty('overflow-x','hidden','important');
|
|
10
|
+
paper.style.setProperty('overflow-y','scroll','important');
|
|
11
|
+
paper.style.setProperty('height','calc(100dvh - var(--nx-content-top) - 12px)','important');
|
|
12
|
+
paper.style.setProperty('max-height','calc(100dvh - var(--nx-content-top) - 12px)','important');
|
|
13
|
+
paper.style.setProperty('min-height','0','important');
|
|
14
|
+
};
|
|
15
|
+
const apply = () => {
|
|
16
|
+
document.documentElement.classList.add('eos-assist-disabled');
|
|
17
|
+
document.documentElement.classList.remove('eos-first-login-active');
|
|
18
|
+
document.querySelectorAll('.eos-assist-root,.eos-assist-header-root,[data-eos-assist-root],.eos-passwordless-launcher,.eos-first-login-overlay')
|
|
19
|
+
.forEach(element => element.remove());
|
|
20
|
+
ensureScroll();
|
|
21
|
+
};
|
|
22
|
+
let scheduled=false;
|
|
23
|
+
const schedule=()=>{if(scheduled)return;scheduled=true;requestAnimationFrame(()=>{scheduled=false;apply();});};
|
|
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
|
+
document.readyState==='loading'?document.addEventListener('DOMContentLoaded',start,{once:true}):start();
|
|
26
|
+
window.NEXOWATT_EOS_STABLE_V7101=Object.freeze({version:VERSION,refresh:apply,ensureScroll});
|
|
27
|
+
})();
|