iobroker.eos-admin 7.10.1 → 7.10.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (37) hide show
  1. package/INSTALL_TEST_V7.10.3.md +7 -0
  2. package/MERGE_UPDATE_README_V7.10.3.md +3 -0
  3. package/NEXOWATT_EOS_BUILD_INFO.json +16 -16
  4. package/NEXOWATT_EOS_PREBUILT_MANIFEST.json +1412 -0
  5. package/PUBLISH_STABLE_V7.10.3.md +10 -0
  6. package/README.md +4 -4
  7. package/README_STABILITY_V7.10.3.md +5 -0
  8. package/RELEASE_ACCEPTANCE_V7.10.3.md +3 -0
  9. package/RELEASE_NOTES_V7.10.3.md +7 -0
  10. package/adminWww/css/eos-auto-update.css +4 -3
  11. package/adminWww/index.html +2 -2
  12. package/adminWww/js/eos-auto-update.js +127 -33
  13. package/build/lib/eosAutoUpdate.js +418 -20
  14. package/build/lib/eosAutoUpdate.js.map +1 -0
  15. package/build/lib/eosRequestSecurity.js +4 -1
  16. package/build/lib/eosRequestSecurity.js.map +1 -0
  17. package/build/lib/web.js +40 -9
  18. package/build/lib/web.js.map +1 -1
  19. package/io-package.json +65 -5
  20. package/package.json +24 -16
  21. package/tools/nexowatt-auto-update-placement-selftest.cjs +46 -0
  22. package/tools/nexowatt-auto-update-selftest.cjs +144 -32
  23. package/tools/nexowatt-backend-runtime-selftest.cjs +147 -0
  24. package/tools/nexowatt-merge-update-selftest.cjs +7 -1
  25. package/tools/nexowatt-prebuilt-release-selftest.cjs +292 -0
  26. package/tools/nexowatt-stable-v7103-selftest.cjs +61 -0
  27. package/tools/nexowatt-validate-package.cjs +45 -12
  28. package/INSTALL_TEST_V7.10.1.md +0 -10
  29. package/MERGE_UPDATE_README_V7.10.1.md +0 -10
  30. package/PUBLISH_STABLE_V7.10.1.md +0 -10
  31. package/README_STABILITY_V7.10.1.md +0 -10
  32. package/RELEASE_ACCEPTANCE_V7.10.1.md +0 -10
  33. package/RELEASE_NOTES_V7.10.1.md +0 -10
  34. package/adminWww/js/eos-release-watch.js +0 -77
  35. package/build/lib/eosPassword.js +0 -72
  36. package/build/lib/nexowattStableAuth.js +0 -74
  37. package/tools/nexowatt-stable-v7101-selftest.cjs +0 -15
@@ -1,43 +1,441 @@
1
1
  "use strict";
2
+ /**
3
+ * NexoWatt stable adapter auto-update policy manager.
4
+ *
5
+ * This class does not install packages itself. It configures ioBroker's native
6
+ * adapterAutoUpgrade manager so only installed NexoWatt adapters present in the
7
+ * detected Stable repository receive the `major` policy. All other adapters and
8
+ * existing user policies are preserved.
9
+ *
10
+ * Runtime status is deliberately stored in adapter states, never in the native
11
+ * configuration of the running eos-admin instance. Changing an instance native
12
+ * object causes ioBroker to restart that instance. Version 7.10.1 persisted a
13
+ * fresh timestamp there during every startup and therefore created an endless
14
+ * restart loop while the browser was still loading its JavaScript and CSS.
15
+ */
2
16
  Object.defineProperty(exports, "__esModule", { value: true });
3
17
  exports.NexoWattStableUpdateManager = void 0;
4
18
  exports.isNexoWattRepositoryEntry = isNexoWattRepositoryEntry;
5
19
  const ADMIN_USER = 'system.user.admin';
6
20
  const POLICY = 'major';
7
21
  const RECONCILE_INTERVAL_MS = 6 * 60 * 60 * 1000;
22
+ const STARTUP_RECONCILE_DELAY_MS = 30_000;
8
23
  const REPOSITORY_REFRESH_DELAY_MS = 2500;
9
- const clone = value => JSON.parse(JSON.stringify(value));
10
- const normalizedName = value => String(value || '').trim().replace(/^system\.adapter\./, '').replace(/\.\d+$/, '');
11
- const stableVersion = value => /^\d+\.\d+\.\d+$/.test(String(value || '').trim());
24
+ const ENABLED_STATE_ID = 'info.nexowattStableUpdatesEnabled';
25
+ const STATUS_STATE_ID = 'info.nexowattStableUpdatesState';
26
+ const clone = (value) => JSON.parse(JSON.stringify(value));
27
+ const normalizedName = (value) => String(value || '').trim().replace(/^system\.adapter\./, '').replace(/\.\d+$/, '');
28
+ const stableVersion = (value) => /^\d+\.\d+\.\d+$/.test(String(value || '').trim());
12
29
  function isNexoWattRepositoryEntry(name, entry) {
13
30
  const adapterName = normalizedName(entry?.name || name).toLowerCase();
14
31
  if (adapterName === 'eos-admin' || adapterName.startsWith('nexowatt-') || adapterName.startsWith('eos-'))
15
32
  return true;
16
- const evidence = JSON.stringify({ name, adapterName, title: entry?.title, desc: entry?.desc, author: entry?.author, authors: entry?.authors, publisher: entry?.publisher, url: entry?.url, meta: entry?.meta, readme: entry?.readme, extIcon: entry?.extIcon, licenseInformation: entry?.licenseInformation }).toLowerCase();
33
+ const evidence = JSON.stringify({
34
+ name,
35
+ adapterName,
36
+ title: entry?.title,
37
+ desc: entry?.desc,
38
+ author: entry?.author,
39
+ authors: entry?.authors,
40
+ publisher: entry?.publisher,
41
+ url: entry?.url,
42
+ meta: entry?.meta,
43
+ readme: entry?.readme,
44
+ extIcon: entry?.extIcon,
45
+ licenseInformation: entry?.licenseInformation,
46
+ }).toLowerCase();
17
47
  return evidence.includes('nexowatt') || evidence.includes('github.com/nexowatt/');
18
48
  }
19
49
  class NexoWattStableUpdateManager {
20
50
  adapter;
21
51
  timer;
52
+ startupTimer;
22
53
  reconcilePromise;
23
54
  refreshTimer;
24
55
  retryTimer;
25
- constructor(adapter) { this.adapter = adapter; }
56
+ stopped = false;
57
+ cachedEnabled;
58
+ cachedState = {};
59
+ constructor(adapter) {
60
+ this.adapter = adapter;
61
+ }
26
62
  get instanceId() { return `system.adapter.${this.adapter.namespace}`; }
27
- async start() { const status = await this.reconcile('startup'); if (!this.timer) { this.timer = setInterval(() => void this.reconcile('interval'), RECONCILE_INTERVAL_MS); this.timer.unref?.(); } return status; }
28
- stop() { if (this.timer) clearInterval(this.timer); if (this.refreshTimer) clearTimeout(this.refreshTimer); if (this.retryTimer) clearTimeout(this.retryTimer); this.timer = undefined; this.refreshTimer = undefined; this.retryTimer = undefined; }
29
- async getStatus(refresh = false) { if (refresh) return this.reconcile('status'); const instance = await this.adapter.getForeignObjectAsync(this.instanceId); return this.statusFromNative(instance?.native || {}); }
30
- async setEnabled(enabled) { await this.adapter.extendForeignObjectAsync(this.instanceId, { native: { eosNexoWattAutoUpdate: enabled } }, { user: ADMIN_USER }); return this.reconcile(enabled ? 'enabled' : 'disabled'); }
31
- async reconcile(reason = 'manual') { if (this.reconcilePromise) return this.reconcilePromise; this.reconcilePromise = this.reconcileInternal(reason).finally(() => { this.reconcilePromise = undefined; }); return this.reconcilePromise; }
32
- statusFromNative(native) { const state = native.eosNexoWattAutoUpdateState || {}; return { enabled: native.eosNexoWattAutoUpdate !== false, repository: String(state.selectedRepository || ''), managedAdapters: Array.isArray(state.managedAdapters) ? state.managedAdapters.map(String).sort() : [], availableStableAdapters: Array.isArray(state.availableStableAdapters) ? state.availableStableAdapters.map(String).sort() : [], lastSync: Number(state.lastSync || 0), lastRepositoryRefresh: Number(state.lastRepositoryRefresh || 0), error: String(state.error || ''), policy: POLICY, source: 'ioBroker-native-auto-upgrade' }; }
33
- async reconcileInternal(reason) { const instance = await this.adapter.getForeignObjectAsync(this.instanceId); const native = instance?.native || {}; const enabled = native.eosNexoWattAutoUpdate !== false; const state = clone(native.eosNexoWattAutoUpdateState || {}); try { if (!enabled) return await this.disable(state, reason); return await this.enable(state, reason); } catch (error) { const message = error instanceof Error ? error.message : String(error || 'unknownError'); state.error = message; state.lastSync = Date.now(); await this.persist(false, state); this.adapter.log.warn(`[NexoWatt stable updates] ${message}`); return this.statusFromNative({ eosNexoWattAutoUpdate: enabled, eosNexoWattAutoUpdateState: state }); } }
34
- async readInstalledAdapters() { const view = await this.adapter.getObjectViewAsync('system', 'adapter', { startkey: 'system.adapter.', endkey: 'system.adapter.\u9999' }, { user: ADMIN_USER }); const result = new Map(); for (const row of view?.rows || []) { const object = row?.value || row?.doc; const name = normalizedName(object?.common?.name || row?.id || object?._id); if (name && object?.common?.version) result.set(name, object); } return result; }
35
- async readRepositorySelection(systemConfig) { const repositories = await this.adapter.getForeignObjectAsync('system.repositories'); const rows = repositories?.native?.repositories || {}; const active = Array.isArray(systemConfig?.common?.activeRepo) ? systemConfig.common.activeRepo.map(String) : []; const candidates = Object.entries(rows).map(([name, repo]) => { const entries = repo?.json && typeof repo.json === 'object' ? repo.json : {}; const stableNames = Object.entries(entries).filter(([entryName, entry]) => stableVersion(entry?.version) && isNexoWattRepositoryEntry(entryName, entry)).map(([entryName, entry]) => normalizedName(entry?.name || entryName)).filter(Boolean); return { name, entries, stableNames: [...new Set(stableNames)].sort(), activeIndex: active.indexOf(name) }; }).filter(row => row.stableNames.length > 0); if (!candidates.length) throw new Error('nexowattStableRepositoryNotFound'); candidates.sort((a, b) => { const aa = a.activeIndex < 0 ? Number.MAX_SAFE_INTEGER : a.activeIndex; const bb = b.activeIndex < 0 ? Number.MAX_SAFE_INTEGER : b.activeIndex; return aa - bb || b.stableNames.length - a.stableNames.length || a.name.localeCompare(b.name); }); return candidates[0]; }
36
- async enable(state, reason) { const systemConfig = await this.adapter.getForeignObjectAsync('system.config'); if (!systemConfig?.common) throw new Error('systemConfigUnavailable'); const selected = await this.readRepositorySelection(systemConfig); const installed = await this.readInstalledAdapters(); const managedNames = selected.stableNames.filter(name => installed.has(name)).sort(); if (!managedNames.length) throw new Error('noInstalledNexoWattStableAdapters'); state.previousPolicies ||= {}; for (const name of managedNames) { if (!(name in state.previousPolicies)) { const current = installed.get(name)?.common?.automaticUpgrade; state.previousPolicies[name] = current == null ? null : current; } await this.writeAdapterPolicy(name, POLICY); } const common = systemConfig.common; const activeRepo = Array.isArray(common.activeRepo) ? [...common.activeRepo] : []; const auto = common.adapterAutoUpgrade && typeof common.adapterAutoUpgrade === 'object' ? clone(common.adapterAutoUpgrade) : { repositories: {}, defaultPolicy: 'none' }; auto.repositories = auto.repositories && typeof auto.repositories === 'object' ? { ...auto.repositories } : {}; if (state.previousRepositoryEnabled === undefined) state.previousRepositoryEnabled = Object.prototype.hasOwnProperty.call(auto.repositories, selected.name) ? Boolean(auto.repositories[selected.name]) : null; auto.repositories[selected.name] = true; if (!auto.defaultPolicy) auto.defaultPolicy = 'none'; common.adapterAutoUpgrade = auto; if (activeRepo[0] !== selected.name) { if (!state.previousActiveRepo) state.previousActiveRepo = [...activeRepo]; state.ownsActiveRepoOrder = true; common.activeRepo = [selected.name, ...activeRepo.filter(name => name !== selected.name)]; } await this.adapter.setForeignObjectAsync('system.config', systemConfig, { user: ADMIN_USER }); state.selectedRepository = selected.name; state.availableStableAdapters = selected.stableNames; state.managedAdapters = managedNames; state.lastSync = Date.now(); state.error = ''; await this.persist(true, state); this.scheduleRepositoryRefresh(selected.name, state); this.adapter.log.info(`[NexoWatt stable updates] Enabled for ${managedNames.join(', ')} from repository "${selected.name}" (${reason})`); return this.statusFromNative({ eosNexoWattAutoUpdate: true, eosNexoWattAutoUpdateState: state }); }
37
- async disable(state, reason) { for (const [name, previous] of Object.entries(state.previousPolicies || {})) { const current = await this.adapter.getForeignObjectAsync(`system.adapter.${normalizedName(name)}`); if (current?.common?.automaticUpgrade === POLICY) await this.writeAdapterPolicy(name, previous); } const systemConfig = await this.adapter.getForeignObjectAsync('system.config'); if (systemConfig?.common) { const auto = systemConfig.common.adapterAutoUpgrade && typeof systemConfig.common.adapterAutoUpgrade === 'object' ? clone(systemConfig.common.adapterAutoUpgrade) : null; if (auto && state.selectedRepository) { auto.repositories = auto.repositories && typeof auto.repositories === 'object' ? { ...auto.repositories } : {}; if (auto.repositories[state.selectedRepository] === true) { if (state.previousRepositoryEnabled === null || state.previousRepositoryEnabled === undefined) delete auto.repositories[state.selectedRepository]; else auto.repositories[state.selectedRepository] = state.previousRepositoryEnabled; } systemConfig.common.adapterAutoUpgrade = auto; } if (state.ownsActiveRepoOrder && Array.isArray(state.previousActiveRepo) && Array.isArray(systemConfig.common.activeRepo) && systemConfig.common.activeRepo[0] === state.selectedRepository) systemConfig.common.activeRepo = [...state.previousActiveRepo]; await this.adapter.setForeignObjectAsync('system.config', systemConfig, { user: ADMIN_USER }); } state.previousPolicies = {}; state.previousRepositoryEnabled = undefined; state.previousActiveRepo = undefined; state.ownsActiveRepoOrder = false; state.managedAdapters = []; state.lastSync = Date.now(); state.error = ''; await this.persist(false, state); this.adapter.log.info(`[NexoWatt stable updates] Disabled and previous policies restored (${reason})`); return this.statusFromNative({ eosNexoWattAutoUpdate: false, eosNexoWattAutoUpdateState: state }); }
38
- async writeAdapterPolicy(name, policy) { const id = `system.adapter.${normalizedName(name)}`; const object = await this.adapter.getForeignObjectAsync(id); if (!object?.common) return; if (policy === null) delete object.common.automaticUpgrade; else object.common.automaticUpgrade = policy; await this.adapter.setForeignObjectAsync(id, object, { user: ADMIN_USER }); }
39
- async persist(enabled, state) { await this.adapter.extendForeignObjectAsync(this.instanceId, { native: { eosNexoWattAutoUpdate: enabled, eosNexoWattAutoUpdateState: state } }, { user: ADMIN_USER }); }
40
- scheduleRetry() { if (this.retryTimer) clearTimeout(this.retryTimer); this.retryTimer = setTimeout(() => void this.reconcile('retry'), 60000); this.retryTimer.unref?.(); }
41
- scheduleRepositoryRefresh(repository, state) { if (!this.adapter.sendToHostAsync || !this.adapter.host) return; if (this.refreshTimer) clearTimeout(this.refreshTimer); this.refreshTimer = setTimeout(() => { void this.adapter.sendToHostAsync?.(this.adapter.host, 'getRepository', { repo: repository, update: true }).then(async () => { const current = await this.adapter.getForeignObjectAsync(this.instanceId); if (current?.native?.eosNexoWattAutoUpdate === false) return; state.lastRepositoryRefresh = Date.now(); await this.persist(true, state); }).catch(error => this.adapter.log.warn(`[NexoWatt stable updates] Repository refresh failed: ${error instanceof Error ? error.message : error}`)); }, REPOSITORY_REFRESH_DELAY_MS); this.refreshTimer.unref?.(); }
63
+ async start() {
64
+ this.stopped = false;
65
+ const status = await this.getStatus(false);
66
+ this.scheduleStartupReconcile();
67
+ this.ensurePeriodicTimer();
68
+ return status;
69
+ }
70
+ stop() {
71
+ this.stopped = true;
72
+ if (this.timer)
73
+ clearInterval(this.timer);
74
+ if (this.startupTimer)
75
+ clearTimeout(this.startupTimer);
76
+ if (this.refreshTimer)
77
+ clearTimeout(this.refreshTimer);
78
+ if (this.retryTimer)
79
+ clearTimeout(this.retryTimer);
80
+ this.timer = undefined;
81
+ this.startupTimer = undefined;
82
+ this.refreshTimer = undefined;
83
+ this.retryTimer = undefined;
84
+ }
85
+ async getStatus(refresh = false) {
86
+ if (refresh)
87
+ return this.reconcile('status');
88
+ const persisted = await this.readPersisted();
89
+ return this.statusFromPersisted(persisted.enabled, persisted.state);
90
+ }
91
+ async setEnabled(enabled) {
92
+ this.stopped = false;
93
+ if (this.startupTimer) {
94
+ clearTimeout(this.startupTimer);
95
+ this.startupTimer = undefined;
96
+ }
97
+ const persisted = await this.readPersisted();
98
+ await this.persist(enabled, persisted.state);
99
+ const status = await this.reconcile(enabled ? 'enabled' : 'disabled');
100
+ this.ensurePeriodicTimer();
101
+ return status;
102
+ }
103
+ async reconcile(reason = 'manual') {
104
+ if (this.reconcilePromise)
105
+ return this.reconcilePromise;
106
+ this.reconcilePromise = this.reconcileInternal(reason).finally(() => { this.reconcilePromise = undefined; });
107
+ return this.reconcilePromise;
108
+ }
109
+ scheduleStartupReconcile() {
110
+ if (this.startupTimer || this.stopped)
111
+ return;
112
+ this.startupTimer = setTimeout(() => {
113
+ this.startupTimer = undefined;
114
+ if (!this.stopped) {
115
+ void this.reconcile('startup').catch(error => this.adapter.log.warn(`[NexoWatt stable updates] Startup reconciliation failed: ${error instanceof Error ? error.message : error}`));
116
+ }
117
+ }, STARTUP_RECONCILE_DELAY_MS);
118
+ this.startupTimer.unref?.();
119
+ }
120
+ ensurePeriodicTimer() {
121
+ if (this.timer || this.stopped)
122
+ return;
123
+ this.timer = setInterval(() => {
124
+ if (!this.stopped)
125
+ void this.reconcile('interval');
126
+ }, RECONCILE_INTERVAL_MS);
127
+ this.timer.unref?.();
128
+ }
129
+ parseState(value) {
130
+ if (value && typeof value === 'object' && !Array.isArray(value))
131
+ return clone(value);
132
+ if (typeof value !== 'string' || !value.trim())
133
+ return null;
134
+ try {
135
+ const parsed = JSON.parse(value);
136
+ return parsed && typeof parsed === 'object' && !Array.isArray(parsed) ? parsed : null;
137
+ }
138
+ catch {
139
+ return null;
140
+ }
141
+ }
142
+ async readPersisted() {
143
+ // Legacy 7.10.1 values are read once as a migration fallback. They are
144
+ // never written back to the instance native object.
145
+ let legacyNative = {};
146
+ try {
147
+ const instance = await this.adapter.getForeignObjectAsync(this.instanceId);
148
+ legacyNative = instance?.native || {};
149
+ }
150
+ catch (error) {
151
+ this.adapter.log.debug(`[NexoWatt stable updates] Cannot read legacy native state: ${error instanceof Error ? error.message : error}`);
152
+ }
153
+ let enabled = this.cachedEnabled ?? (legacyNative.eosNexoWattAutoUpdate !== false);
154
+ let state = Object.keys(this.cachedState).length
155
+ ? clone(this.cachedState)
156
+ : clone((legacyNative.eosNexoWattAutoUpdateState || {}));
157
+ try {
158
+ const enabledState = await this.adapter.getStateAsync(ENABLED_STATE_ID);
159
+ if (typeof enabledState?.val === 'boolean')
160
+ enabled = enabledState.val;
161
+ }
162
+ catch (error) {
163
+ this.adapter.log.debug(`[NexoWatt stable updates] Cannot read enabled state: ${error instanceof Error ? error.message : error}`);
164
+ }
165
+ try {
166
+ const persistedState = await this.adapter.getStateAsync(STATUS_STATE_ID);
167
+ const parsed = this.parseState(persistedState?.val);
168
+ if (parsed)
169
+ state = parsed;
170
+ }
171
+ catch (error) {
172
+ this.adapter.log.debug(`[NexoWatt stable updates] Cannot read status state: ${error instanceof Error ? error.message : error}`);
173
+ }
174
+ this.cachedEnabled = enabled;
175
+ this.cachedState = clone(state);
176
+ return { enabled, state };
177
+ }
178
+ statusFromPersisted(enabled, state) {
179
+ return {
180
+ enabled,
181
+ repository: String(state.selectedRepository || ''),
182
+ managedAdapters: Array.isArray(state.managedAdapters) ? state.managedAdapters.map(String).sort() : [],
183
+ availableStableAdapters: Array.isArray(state.availableStableAdapters) ? state.availableStableAdapters.map(String).sort() : [],
184
+ lastSync: Number(state.lastSync || 0),
185
+ lastRepositoryRefresh: Number(state.lastRepositoryRefresh || 0),
186
+ error: String(state.error || ''),
187
+ policy: POLICY,
188
+ source: 'ioBroker-native-auto-upgrade',
189
+ };
190
+ }
191
+ async reconcileInternal(reason) {
192
+ const persisted = await this.readPersisted();
193
+ const { enabled } = persisted;
194
+ const state = clone(persisted.state);
195
+ if (this.stopped)
196
+ return this.statusFromPersisted(enabled, state);
197
+ try {
198
+ if (!enabled)
199
+ return await this.disable(state, reason);
200
+ return await this.enable(state, reason);
201
+ }
202
+ catch (error) {
203
+ const message = error instanceof Error ? error.message : String(error || 'unknownError');
204
+ state.error = message;
205
+ state.lastSync = Date.now();
206
+ if (!this.stopped)
207
+ await this.persist(enabled, state);
208
+ if (enabled && !this.stopped)
209
+ this.scheduleRetry();
210
+ if (!this.stopped)
211
+ this.adapter.log.warn(`[NexoWatt stable updates] ${message}`);
212
+ return this.statusFromPersisted(enabled, state);
213
+ }
214
+ }
215
+ async readInstalledAdapters() {
216
+ const view = await this.adapter.getObjectViewAsync('system', 'adapter', {
217
+ startkey: 'system.adapter.',
218
+ endkey: 'system.adapter.\u9999',
219
+ }, { user: ADMIN_USER });
220
+ const result = new Map();
221
+ for (const row of view?.rows || []) {
222
+ const object = row?.value || row?.doc;
223
+ const name = normalizedName(object?.common?.name || row?.id || object?._id);
224
+ if (name && object?.common?.version)
225
+ result.set(name, object);
226
+ }
227
+ return result;
228
+ }
229
+ async readRepositorySelection(systemConfig) {
230
+ const repositories = await this.adapter.getForeignObjectAsync('system.repositories');
231
+ const rows = repositories?.native?.repositories || {};
232
+ const active = Array.isArray(systemConfig?.common?.activeRepo) ? systemConfig.common.activeRepo.map(String) : [];
233
+ const candidates = Object.entries(rows).map(([name, repo]) => {
234
+ const entries = repo?.json && typeof repo.json === 'object' ? repo.json : {};
235
+ const stableNames = Object.entries(entries)
236
+ .filter(([entryName, entry]) => stableVersion(entry?.version) && isNexoWattRepositoryEntry(entryName, entry))
237
+ .map(([entryName, entry]) => normalizedName(entry?.name || entryName))
238
+ .filter(Boolean);
239
+ return { name, entries, stableNames: [...new Set(stableNames)].sort(), activeIndex: active.indexOf(name) };
240
+ }).filter(row => row.stableNames.length > 0);
241
+ if (!candidates.length)
242
+ throw new Error('nexowattStableRepositoryNotFound');
243
+ candidates.sort((a, b) => {
244
+ const aa = a.activeIndex < 0 ? Number.MAX_SAFE_INTEGER : a.activeIndex;
245
+ const bb = b.activeIndex < 0 ? Number.MAX_SAFE_INTEGER : b.activeIndex;
246
+ return aa - bb || b.stableNames.length - a.stableNames.length || a.name.localeCompare(b.name);
247
+ });
248
+ return candidates[0];
249
+ }
250
+ async enable(state, reason) {
251
+ const systemConfig = await this.adapter.getForeignObjectAsync('system.config');
252
+ if (!systemConfig?.common)
253
+ throw new Error('systemConfigUnavailable');
254
+ const selected = await this.readRepositorySelection(systemConfig);
255
+ const installed = await this.readInstalledAdapters();
256
+ const managedNames = selected.stableNames.filter(name => installed.has(name)).sort();
257
+ if (!managedNames.length)
258
+ throw new Error('noInstalledNexoWattStableAdapters');
259
+ if (this.stopped)
260
+ return this.statusFromPersisted(true, state);
261
+ state.previousPolicies ||= {};
262
+ for (const name of managedNames) {
263
+ if (this.stopped)
264
+ return this.statusFromPersisted(true, state);
265
+ if (!(name in state.previousPolicies)) {
266
+ const current = installed.get(name)?.common?.automaticUpgrade;
267
+ state.previousPolicies[name] = current == null ? null : current;
268
+ }
269
+ await this.writeAdapterPolicy(name, POLICY);
270
+ }
271
+ const common = systemConfig.common;
272
+ const activeRepo = Array.isArray(common.activeRepo) ? [...common.activeRepo] : [];
273
+ const auto = common.adapterAutoUpgrade && typeof common.adapterAutoUpgrade === 'object'
274
+ ? clone(common.adapterAutoUpgrade)
275
+ : { repositories: {}, defaultPolicy: 'none' };
276
+ auto.repositories = auto.repositories && typeof auto.repositories === 'object' ? { ...auto.repositories } : {};
277
+ let systemConfigChanged = false;
278
+ if (state.previousRepositoryEnabled === undefined) {
279
+ state.previousRepositoryEnabled = Object.prototype.hasOwnProperty.call(auto.repositories, selected.name)
280
+ ? Boolean(auto.repositories[selected.name])
281
+ : null;
282
+ }
283
+ if (auto.repositories[selected.name] !== true) {
284
+ auto.repositories[selected.name] = true;
285
+ systemConfigChanged = true;
286
+ }
287
+ if (!auto.defaultPolicy) {
288
+ auto.defaultPolicy = 'none';
289
+ systemConfigChanged = true;
290
+ }
291
+ if (JSON.stringify(common.adapterAutoUpgrade) !== JSON.stringify(auto)) {
292
+ common.adapterAutoUpgrade = auto;
293
+ systemConfigChanged = true;
294
+ }
295
+ if (activeRepo[0] !== selected.name) {
296
+ if (!state.previousActiveRepo)
297
+ state.previousActiveRepo = [...activeRepo];
298
+ state.ownsActiveRepoOrder = true;
299
+ common.activeRepo = [selected.name, ...activeRepo.filter((name) => name !== selected.name)];
300
+ systemConfigChanged = true;
301
+ }
302
+ if (systemConfigChanged && !this.stopped) {
303
+ await this.adapter.setForeignObjectAsync('system.config', systemConfig, { user: ADMIN_USER });
304
+ }
305
+ state.selectedRepository = selected.name;
306
+ state.availableStableAdapters = selected.stableNames;
307
+ state.managedAdapters = managedNames;
308
+ state.lastSync = Date.now();
309
+ state.error = '';
310
+ if (!this.stopped)
311
+ await this.persist(true, state);
312
+ if (!this.stopped)
313
+ this.scheduleRepositoryRefresh(selected.name, state);
314
+ if (!this.stopped)
315
+ this.adapter.log.info(`[NexoWatt stable updates] Enabled for ${managedNames.join(', ')} from repository "${selected.name}" (${reason})`);
316
+ return this.statusFromPersisted(true, state);
317
+ }
318
+ async disable(state, reason) {
319
+ for (const [name, previous] of Object.entries(state.previousPolicies || {})) {
320
+ if (this.stopped)
321
+ return this.statusFromPersisted(false, state);
322
+ const current = await this.adapter.getForeignObjectAsync(`system.adapter.${normalizedName(name)}`);
323
+ if (current?.common?.automaticUpgrade === POLICY)
324
+ await this.writeAdapterPolicy(name, previous);
325
+ }
326
+ const systemConfig = await this.adapter.getForeignObjectAsync('system.config');
327
+ if (systemConfig?.common) {
328
+ let systemConfigChanged = false;
329
+ const auto = systemConfig.common.adapterAutoUpgrade && typeof systemConfig.common.adapterAutoUpgrade === 'object'
330
+ ? clone(systemConfig.common.adapterAutoUpgrade)
331
+ : null;
332
+ if (auto && state.selectedRepository) {
333
+ auto.repositories = auto.repositories && typeof auto.repositories === 'object' ? { ...auto.repositories } : {};
334
+ if (auto.repositories[state.selectedRepository] === true) {
335
+ if (state.previousRepositoryEnabled === null || state.previousRepositoryEnabled === undefined) {
336
+ delete auto.repositories[state.selectedRepository];
337
+ }
338
+ else {
339
+ auto.repositories[state.selectedRepository] = state.previousRepositoryEnabled;
340
+ }
341
+ systemConfigChanged = true;
342
+ }
343
+ if (JSON.stringify(systemConfig.common.adapterAutoUpgrade) !== JSON.stringify(auto)) {
344
+ systemConfig.common.adapterAutoUpgrade = auto;
345
+ systemConfigChanged = true;
346
+ }
347
+ }
348
+ if (state.ownsActiveRepoOrder && Array.isArray(state.previousActiveRepo)
349
+ && Array.isArray(systemConfig.common.activeRepo)
350
+ && systemConfig.common.activeRepo[0] === state.selectedRepository) {
351
+ systemConfig.common.activeRepo = [...state.previousActiveRepo];
352
+ systemConfigChanged = true;
353
+ }
354
+ if (systemConfigChanged && !this.stopped) {
355
+ await this.adapter.setForeignObjectAsync('system.config', systemConfig, { user: ADMIN_USER });
356
+ }
357
+ }
358
+ state.previousPolicies = {};
359
+ state.previousRepositoryEnabled = undefined;
360
+ state.previousActiveRepo = undefined;
361
+ state.ownsActiveRepoOrder = false;
362
+ state.managedAdapters = [];
363
+ state.lastSync = Date.now();
364
+ state.error = '';
365
+ if (!this.stopped)
366
+ await this.persist(false, state);
367
+ if (!this.stopped)
368
+ this.adapter.log.info(`[NexoWatt stable updates] Disabled and previous policies restored (${reason})`);
369
+ return this.statusFromPersisted(false, state);
370
+ }
371
+ async writeAdapterPolicy(name, policy) {
372
+ const id = `system.adapter.${normalizedName(name)}`;
373
+ const object = await this.adapter.getForeignObjectAsync(id);
374
+ if (!object?.common || this.stopped)
375
+ return;
376
+ const current = object.common.automaticUpgrade;
377
+ if ((policy === null && current === undefined) || current === policy)
378
+ return;
379
+ if (policy === null)
380
+ delete object.common.automaticUpgrade;
381
+ else
382
+ object.common.automaticUpgrade = policy;
383
+ await this.adapter.setForeignObjectAsync(id, object, { user: ADMIN_USER });
384
+ }
385
+ async persist(enabled, state) {
386
+ if (this.stopped)
387
+ return;
388
+ this.cachedEnabled = enabled;
389
+ this.cachedState = clone(state);
390
+ const currentEnabled = await this.adapter.getStateAsync(ENABLED_STATE_ID).catch(() => null);
391
+ if (currentEnabled?.val !== enabled) {
392
+ await this.adapter.setStateAsync(ENABLED_STATE_ID, enabled, true);
393
+ }
394
+ const serialized = JSON.stringify(state);
395
+ const currentState = await this.adapter.getStateAsync(STATUS_STATE_ID).catch(() => null);
396
+ const currentSerialized = typeof currentState?.val === 'string'
397
+ ? currentState.val
398
+ : currentState?.val == null ? '' : JSON.stringify(currentState.val);
399
+ if (currentSerialized !== serialized) {
400
+ await this.adapter.setStateAsync(STATUS_STATE_ID, serialized, true);
401
+ }
402
+ }
403
+ scheduleRetry() {
404
+ if (this.retryTimer)
405
+ clearTimeout(this.retryTimer);
406
+ this.retryTimer = setTimeout(() => {
407
+ this.retryTimer = undefined;
408
+ if (!this.stopped)
409
+ void this.reconcile('retry');
410
+ }, 60_000);
411
+ this.retryTimer.unref?.();
412
+ }
413
+ scheduleRepositoryRefresh(repository, state) {
414
+ if (!this.adapter.sendToHostAsync || !this.adapter.host || this.stopped)
415
+ return;
416
+ if (this.refreshTimer)
417
+ clearTimeout(this.refreshTimer);
418
+ this.refreshTimer = setTimeout(() => {
419
+ this.refreshTimer = undefined;
420
+ if (this.stopped)
421
+ return;
422
+ void this.adapter.sendToHostAsync?.(this.adapter.host, 'getRepository', { repo: repository, update: true })
423
+ .then(async () => {
424
+ if (this.stopped)
425
+ return;
426
+ const current = await this.readPersisted();
427
+ if (!current.enabled)
428
+ return;
429
+ const nextState = { ...current.state, ...state, lastRepositoryRefresh: Date.now() };
430
+ await this.persist(true, nextState);
431
+ })
432
+ .catch(error => {
433
+ if (!this.stopped)
434
+ this.adapter.log.warn(`[NexoWatt stable updates] Repository refresh failed: ${error instanceof Error ? error.message : error}`);
435
+ });
436
+ }, REPOSITORY_REFRESH_DELAY_MS);
437
+ this.refreshTimer.unref?.();
438
+ }
42
439
  }
43
440
  exports.NexoWattStableUpdateManager = NexoWattStableUpdateManager;
441
+ //# sourceMappingURL=eosAutoUpdate.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"eosAutoUpdate.js","sourceRoot":"./src/","sources":["eosAutoUpdate.ts"],"names":[],"mappings":"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"}
@@ -1,9 +1,11 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.isEosSameOriginRequest = isEosSameOriginRequest;
4
+ /** Testable same-origin guard for EOS JSON write routes. */
4
5
  function isEosSameOriginRequest(headers) {
5
6
  const origin = String(headers.origin || '').trim();
6
7
  if (!origin) {
8
+ // Older embedded browsers can omit Origin for same-site POST requests.
7
9
  return true;
8
10
  }
9
11
  try {
@@ -12,7 +14,7 @@ function isEosSameOriginRequest(headers) {
12
14
  return false;
13
15
  }
14
16
  const allowedHosts = new Set();
15
- const addHost = value => {
17
+ const addHost = (value) => {
16
18
  const host = String(value || '').split(',')[0].trim().toLowerCase();
17
19
  if (host)
18
20
  allowedHosts.add(host);
@@ -29,3 +31,4 @@ function isEosSameOriginRequest(headers) {
29
31
  return false;
30
32
  }
31
33
  }
34
+ //# sourceMappingURL=eosRequestSecurity.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"eosRequestSecurity.js","sourceRoot":"./src/","sources":["eosRequestSecurity.ts"],"names":[],"mappings":";;AACA,wDA0BC;AA3BD,4DAA4D;AAC5D,SAAgB,sBAAsB,CAAC,OAAgC;IACnE,MAAM,MAAM,GAAG,MAAM,CAAC,OAAO,CAAC,MAAM,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC;IACnD,IAAI,CAAC,MAAM,EAAE,CAAC;QACV,uEAAuE;QACvE,OAAO,IAAI,CAAC;IAChB,CAAC;IACD,IAAI,CAAC;QACD,MAAM,MAAM,GAAG,IAAI,GAAG,CAAC,MAAM,CAAC,CAAC;QAC/B,IAAI,MAAM,CAAC,QAAQ,KAAK,OAAO,IAAI,MAAM,CAAC,QAAQ,KAAK,QAAQ,EAAE,CAAC;YAC9D,OAAO,KAAK,CAAC;QACjB,CAAC;QACD,MAAM,YAAY,GAAG,IAAI,GAAG,EAAU,CAAC;QACvC,MAAM,OAAO,GAAG,CAAC,KAAc,EAAQ,EAAE;YACrC,MAAM,IAAI,GAAG,MAAM,CAAC,KAAK,IAAI,EAAE,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;YACpE,IAAI,IAAI;gBAAE,YAAY,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;QACrC,CAAC,CAAC;QACF,OAAO,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;QACtB,OAAO,CAAC,OAAO,CAAC,kBAAkB,CAAC,CAAC,CAAC;QACrC,IAAI,CAAC,YAAY,CAAC,IAAI,IAAI,CAAC,YAAY,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,WAAW,EAAE,CAAC,EAAE,CAAC;YACrE,OAAO,KAAK,CAAC;QACjB,CAAC;QACD,MAAM,SAAS,GAAG,MAAM,CAAC,OAAO,CAAC,gBAAgB,CAAC,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;QAC/E,OAAO,CAAC,SAAS,IAAI,SAAS,KAAK,aAAa,IAAI,SAAS,KAAK,WAAW,IAAI,SAAS,KAAK,MAAM,CAAC;IAC1G,CAAC;IAAC,MAAM,CAAC;QACL,OAAO,KAAK,CAAC;IACjB,CAAC;AACL,CAAC"}
package/build/lib/web.js CHANGED
@@ -195,6 +195,7 @@ class Web {
195
195
  this.checkTimeout = null;
196
196
  }
197
197
  this.mcpServer?.unload();
198
+ this.nexowattStableUpdateManager?.stop();
198
199
  void this.adapter.setState('info.connection', false, true);
199
200
  this.server.server?.close();
200
201
  }
@@ -724,7 +725,9 @@ class Web {
724
725
  return userName;
725
726
  }
726
727
  async setEosUserPassword(userId, password) {
727
- // ioBroker's password API expects the account name, not the system.user.* object id.
728
+ // ioBroker's password API expects the account name (for example "user"), not the
729
+ // object id ("system.user.user"). Supplying the object id can return without changing
730
+ // the password on some controller versions. Always normalize to the real account name.
728
731
  const userName = this.getEosPasswordUserName(userId);
729
732
  // The server-side Admin/Service context performs the controller password write, so managed
730
733
  // Installer and End User accounts do not need global users.write rights in the browser.
@@ -740,6 +743,8 @@ class Web {
740
743
  else {
741
744
  throw new Error('passwordApiUnavailable');
742
745
  }
746
+ // Verify the write with the controller API whenever it is exposed. This prevents the
747
+ // UI from reporting success while the object database still contains the old hash.
743
748
  if (typeof this.adapter.checkPasswordAsync === 'function') {
744
749
  const result = await this.adapter.checkPasswordAsync(userName, password, options);
745
750
  const valid = Array.isArray(result) ? result[0] === true : result === true;
@@ -748,6 +753,7 @@ class Web {
748
753
  }
749
754
  return;
750
755
  }
756
+ // Compatibility fallback for older controllers: require a non-empty stored password hash.
751
757
  const userObject = (await this.adapter.getForeignObjectAsync(userId));
752
758
  if (!String(userObject?.common?.password || '').trim()) {
753
759
  throw new Error('passwordWriteFailed');
@@ -762,6 +768,8 @@ class Web {
762
768
  const account = { ...(native.nexowattEosAccount || {}) };
763
769
  native.nexowattEosAccount = account;
764
770
  updater(native, account);
771
+ // Extend only the EOS metadata. Replacing the complete user object here could overwrite the
772
+ // password hash which was just written by setPasswordAsync/changePassword.
765
773
  await this.adapter.extendForeignObjectAsync(userId, { native }, { user: EOS_PASSWORD_SERVICE_USER });
766
774
  }
767
775
  async destroyEosRequestSessions(req) {
@@ -1270,12 +1278,37 @@ class Web {
1270
1278
  ],
1271
1279
  });
1272
1280
  }
1273
-
1274
- getNexoWattStableUpdateManager() { this.nexowattStableUpdateManager ||= new eosAutoUpdate_1.NexoWattStableUpdateManager(this.adapter); return this.nexowattStableUpdateManager; }
1275
- async sendNexoWattStableUpdateStatus(req, res) { const access = await this.getEosRequestAccess(req); if (access.role !== 'admin') { res.status(403).json({ error: 'permissionError' }); return; } res.status(200).json(await this.getNexoWattStableUpdateManager().getStatus(false)); }
1276
- async saveNexoWattStableUpdateSettings(req, res) { const access = await this.getEosRequestAccess(req); if (access.role !== 'admin') { res.status(403).json({ error: 'permissionError' }); return; } if (req.headers['x-nexowatt-eos-auto-update'] !== '1' || !this.isEosSameOriginWrite(req)) { res.status(403).json({ error: 'invalidRequest' }); return; } if (typeof req.body?.enabled !== 'boolean') { res.status(400).json({ error: 'invalidEnabledValue' }); return; } res.status(200).json(await this.getNexoWattStableUpdateManager().setEnabled(req.body.enabled)); }
1277
-
1278
- isEosSameOriginWrite(req) { return (0, eosRequestSecurity_1.isEosSameOriginRequest)(req.headers); }
1281
+ getNexoWattStableUpdateManager() {
1282
+ this.nexowattStableUpdateManager ||= new eosAutoUpdate_1.NexoWattStableUpdateManager(this.adapter);
1283
+ return this.nexowattStableUpdateManager;
1284
+ }
1285
+ async sendNexoWattStableUpdateStatus(req, res) {
1286
+ const access = await this.getEosRequestAccess(req);
1287
+ if (access.role !== 'admin') {
1288
+ res.status(403).json({ error: 'permissionError' });
1289
+ return;
1290
+ }
1291
+ res.status(200).json(await this.getNexoWattStableUpdateManager().getStatus(false));
1292
+ }
1293
+ async saveNexoWattStableUpdateSettings(req, res) {
1294
+ const access = await this.getEosRequestAccess(req);
1295
+ if (access.role !== 'admin') {
1296
+ res.status(403).json({ error: 'permissionError' });
1297
+ return;
1298
+ }
1299
+ if (req.headers['x-nexowatt-eos-auto-update'] !== '1' || !this.isEosSameOriginWrite(req)) {
1300
+ res.status(403).json({ error: 'invalidRequest' });
1301
+ return;
1302
+ }
1303
+ if (typeof req.body?.enabled !== 'boolean') {
1304
+ res.status(400).json({ error: 'invalidEnabledValue' });
1305
+ return;
1306
+ }
1307
+ res.status(200).json(await this.getNexoWattStableUpdateManager().setEnabled(req.body.enabled));
1308
+ }
1309
+ isEosSameOriginWrite(req) {
1310
+ return (0, eosRequestSecurity_1.isEosSameOriginRequest)(req.headers);
1311
+ }
1279
1312
  async saveEosBasicSettings(req, res) {
1280
1313
  res.setHeader('Cache-Control', 'no-store, no-cache, must-revalidate, proxy-revalidate');
1281
1314
  const access = await this.getEosRequestAccess(req);
@@ -1505,11 +1538,9 @@ class Web {
1505
1538
  res.header('Access-Control-Allow-Headers', 'Origin, X-Requested-With, Content-Type, Accept');
1506
1539
  next();
1507
1540
  });*/
1508
-
1509
1541
  void this.getNexoWattStableUpdateManager().start().catch(error => this.adapter.log.warn(`[NexoWatt stable updates] Startup reconciliation failed: ${error instanceof Error ? error.message : error}`));
1510
1542
  this.server.app.get('/nexowatt/updates/status', (req, res) => { void this.sendNexoWattStableUpdateStatus(req, res).catch(error => res.status(500).json({ error: String(error) })); });
1511
1543
  this.server.app.post('/nexowatt/updates/settings', (req, res) => { void this.saveNexoWattStableUpdateSettings(req, res).catch(error => res.status(500).json({ error: String(error) })); });
1512
-
1513
1544
  this.server.app.get('/version', (_req, res) => {
1514
1545
  res.status(200).send(this.adapter.version);
1515
1546
  });