iobroker.js-controller 3.3.15 → 3.3.19

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/io-package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "$schema": "./schemas/io-package.json",
3
3
  "common": {
4
4
  "name": "js-controller",
5
- "version": "3.3.15",
5
+ "version": "3.3.19",
6
6
  "platform": "Javascript/Node.js",
7
7
  "controller": true,
8
8
  "mode": "daemon",
@@ -20,6 +20,54 @@
20
20
  "zh-cn": "JS控制器"
21
21
  },
22
22
  "news": {
23
+ "3.3.19": {
24
+ "en": "we fixed a crash due to multilingual instance objects",
25
+ "de": "wir haben einen Absturz aufgrund mehrsprachiger Instanzobjekte behoben",
26
+ "ru": "мы исправили сбой из-за многоязычных экземпляров объектов",
27
+ "pt": "corrigimos uma falha devido a objetos multilingues de instância",
28
+ "nl": "we hebben een crash verholpen vanwege meertalige instantieobjecten",
29
+ "fr": "nous avons corrigé un plantage dû à des objets d'instance multilingues",
30
+ "it": "abbiamo risolto un arresto anomalo dovuto a oggetti istanza multilingue",
31
+ "es": "arreglamos un bloqueo debido a objetos de instancia multilingües",
32
+ "pl": "naprawiliśmy awarię z powodu wielojęzycznych obiektów instancji",
33
+ "zh-cn": "我们修复了由于多语言实例对象导致的崩溃"
34
+ },
35
+ "3.3.18": {
36
+ "en": "Fix another edge case for UUID generation",
37
+ "de": "Beheben Sie einen weiteren Randfall für die UUID-Generierung",
38
+ "ru": "Исправить еще один крайний случай для генерации UUID",
39
+ "pt": "Corrigir outro caso extremo para a geração de UUID",
40
+ "nl": "Een andere edge-case repareren voor UUID-generatie",
41
+ "fr": "Correction d'un autre cas de bord pour la génération d'UUID",
42
+ "it": "Risolvi un altro caso limite per la generazione di UUID",
43
+ "es": "Arregle otro caso de borde para la generación de UUID",
44
+ "pl": "Napraw inny przypadek brzegowy do generowania UUID",
45
+ "zh-cn": "修复 UUID 生成的另一个边缘情况"
46
+ },
47
+ "3.3.17": {
48
+ "en": "Fix edge case for UUID generation",
49
+ "de": "Edge-Case für UUID-Generierung behoben",
50
+ "ru": "Исправить крайний случай для генерации UUID",
51
+ "pt": "Corrigir caso extremo para geração de UUID",
52
+ "nl": "Fix edge-case voor UUID-generatie",
53
+ "fr": "Correction du cas de bord pour la génération d'UUID",
54
+ "it": "Fix edge case per la generazione di UUID",
55
+ "es": "Arregle el caso de borde para la generación de UUID",
56
+ "pl": "Napraw przypadek krawędzi do generowania UUID",
57
+ "zh-cn": "修复 UUID 生成的边缘情况"
58
+ },
59
+ "3.3.16": {
60
+ "en": "Adjust generation of installation UUID",
61
+ "de": "Generierung der Installations-UUID anpassen",
62
+ "ru": "Настроить генерацию UUID установки",
63
+ "pt": "Ajuste a geração do UUID de instalação",
64
+ "nl": "Aanpassen generatie van installatie UUID",
65
+ "fr": "Ajuster la génération de l'UUID d'installation",
66
+ "it": "Regola la generazione dell'UUID di installazione",
67
+ "es": "Ajustar generación de UUID de instalación",
68
+ "pl": "Dostosuj generowanie UUID instalacji",
69
+ "zh-cn": "调整安装 UUID 的生成"
70
+ },
23
71
  "3.3.15": {
24
72
  "en": "avoid deleting too many meta objects starting with the same name as adapter",
25
73
  "de": "Vermeiden Sie das Löschen von zu vielen Metaobjekten, die mit dem gleichen Namen wie der Adapter beginnen",
@@ -1002,7 +1002,7 @@ function Install(options) {
1002
1002
  if (adapterConf.instanceObjects[i].common.name) {
1003
1003
  // if name has many languages
1004
1004
  if (typeof adapterConf.instanceObjects[i].common.name === 'object') {
1005
- Object.keys(adapterConf.instanceObjects[i].common.name).forEach(lang => adapterConf.instanceObjects[i].common.name[lang] = adapterConf.instanceObjects[i].common.name.replace('%INSTANCE%', instance));
1005
+ Object.keys(adapterConf.instanceObjects[i].common.name).forEach(lang => adapterConf.instanceObjects[i].common.name[lang] = adapterConf.instanceObjects[i].common.name[lang].replace('%INSTANCE%', instance));
1006
1006
  } else {
1007
1007
  adapterConf.instanceObjects[i].common.name = adapterConf.instanceObjects[i].common.name.replace('%INSTANCE%', instance);
1008
1008
  }
@@ -1010,7 +1010,7 @@ function Install(options) {
1010
1010
  if (adapterConf.instanceObjects[i].common.desc) {
1011
1011
  // if name has many languages
1012
1012
  if (typeof adapterConf.instanceObjects[i].common.desc === 'object') {
1013
- Object.keys(adapterConf.instanceObjects[i].common.desc).forEach(lang => adapterConf.instanceObjects[i].common.desc[lang] = adapterConf.instanceObjects[i].common.desc.replace('%INSTANCE%', instance));
1013
+ Object.keys(adapterConf.instanceObjects[i].common.desc).forEach(lang => adapterConf.instanceObjects[i].common.desc[lang] = adapterConf.instanceObjects[i].common.desc[lang].replace('%INSTANCE%', instance));
1014
1014
  } else {
1015
1015
  adapterConf.instanceObjects[i].common.desc = adapterConf.instanceObjects[i].common.desc.replace('%INSTANCE%', instance);
1016
1016
  }
@@ -1707,4 +1707,4 @@ function Install(options) {
1707
1707
  };
1708
1708
  }
1709
1709
 
1710
- module.exports = Install;
1710
+ module.exports = Install;
package/lib/tools.js CHANGED
@@ -7,6 +7,7 @@ const os = require('os');
7
7
  const forge = require('node-forge');
8
8
  const deepClone = require('deep-clone');
9
9
  const cpPromise = require('promisify-child-process');
10
+ const jwt = require('jsonwebtoken');
10
11
  const { createInterface } = require('readline');
11
12
 
12
13
  // @ts-ignore
@@ -278,6 +279,27 @@ function getMac(callback) {
278
279
  });
279
280
  }
280
281
 
282
+ // Is docker environment
283
+ function isDocker() {
284
+ let _isDocker = false;
285
+ try {
286
+ fs.statSync('/.dockerenv');
287
+ _isDocker = true;
288
+ } catch {
289
+ // ignore error
290
+ }
291
+
292
+ let _isDockerGroup = false;
293
+
294
+ try {
295
+ _isDockerGroup = fs.readFileSync('/proc/self/cgroup', 'utf8').includes('docker');
296
+ } catch {
297
+ // ignore error
298
+ }
299
+
300
+ return _isDocker || _isDockerGroup;
301
+ }
302
+
281
303
  // Build unique uuid based on MAC address if possible
282
304
  function uuid(givenMac, callback) {
283
305
  if (typeof givenMac === 'function') {
@@ -285,10 +307,17 @@ function uuid(givenMac, callback) {
285
307
  givenMac = '';
286
308
  }
287
309
 
288
- let mac = (givenMac !== null) ? (givenMac || '') : null;
310
+ const _isDocker = isDocker();
311
+
312
+ // return constant UUID for all CI environments to keep the statistics clean
313
+ if (require('ci-info').isCI) {
314
+ return callback('55travis-pipe-line-cior-githubaction');
315
+ }
316
+
317
+ let mac = givenMac !== null ? (givenMac || '') : null;
289
318
  let u;
290
319
 
291
- if (mac === '') {
320
+ if (!_isDocker && mac === '') {
292
321
  const ifaces = require('os').networkInterfaces();
293
322
 
294
323
  // Find first not empty MAC
@@ -299,18 +328,18 @@ function uuid(givenMac, callback) {
299
328
  break;
300
329
  }
301
330
  }
331
+
302
332
  if (mac) {
303
333
  break;
304
334
  }
305
335
  }
306
336
  }
307
337
 
308
- if (mac === '') {
309
- getMac((_err, mac) => uuid(mac || null, callback));
310
- return;
338
+ if (!_isDocker && mac === '') {
339
+ return getMac((_err, mac) => uuid(mac || null, callback));
311
340
  }
312
341
 
313
- if (mac) {
342
+ if (!_isDocker && mac) {
314
343
  const md5sum = require('crypto').createHash('md5');
315
344
  md5sum.update(mac);
316
345
  mac = md5sum.digest('hex');
@@ -330,92 +359,139 @@ function uuid(givenMac, callback) {
330
359
  callback(u);
331
360
  }
332
361
 
333
- function createUuid(_objects, callback) {
334
- let tasks = 2;
335
- let _uuid;
336
- _objects.getObject('system.user.admin', (err, obj) => {
337
- if (err || !obj) {
338
- password = password || require('./password');
339
-
340
- // Default Password for user 'admin' is application name in lower case
341
- password(getAppName()).hash(null, null, (err, res) => {
342
- if (err) {
343
- console.error(err);
362
+ function updateUuid(newUuid, _objects, callback) {
363
+ uuid('', _uuid => {
364
+ _uuid = newUuid || _uuid;
365
+ // Add vendor prefix to UUID
366
+ if (fs.existsSync(VENDOR_FILE)) {
367
+ try {
368
+ const vendor = require(VENDOR_FILE);
369
+ if (vendor.vendor && vendor.vendor.uuidPrefix && vendor.vendor.uuidPrefix.length === 2) {
370
+ _uuid = vendor.vendor.uuidPrefix + _uuid;
344
371
  }
345
- // Create user here and not in io-package.js because of hash password
346
- let tasks = 0;
347
-
348
- tasks++;
349
- _objects.setObject('system.user.admin', {
350
- type: 'user',
351
- common: {
352
- name: 'admin',
353
- password: res,
354
- dontDelete: true,
355
- enabled: true
356
- },
357
- ts: new Date().getTime(),
358
- from: 'system.host.' + getHostName() + '.tools',
359
- native: {}
360
- }, () => {
361
- console.log('object system.user.admin created');
362
- !--tasks && callback && callback(_uuid);
363
- });
364
- });
365
- } else {
366
- !--tasks && callback && callback(_uuid);
372
+ } catch {
373
+ console.error(`Cannot parse ${VENDOR_FILE}`);
374
+ }
367
375
  }
368
- });
369
-
370
- _objects.getObject('system.meta.uuid', (err, obj) => {
371
- if (!err && obj && obj.native && obj.native.uuid) {
372
- !--tasks && callback && callback();
373
- } else {
374
- uuid(__uuid => {
375
- _uuid = __uuid;
376
376
 
377
- // Add vendor prefix to UUID
378
- if (fs.existsSync(VENDOR_FILE)) {
379
- try {
380
- const vendor = require(VENDOR_FILE);
381
- if (vendor.vendor && vendor.vendor.uuidPrefix && vendor.vendor.uuidPrefix.length === 2) {
382
- _uuid = vendor.vendor.uuidPrefix + _uuid;
383
- }
384
- } catch {
385
- console.error(`Cannot parse ${VENDOR_FILE}`);
377
+ _objects.setObject('system.meta.uuid', {
378
+ type: 'meta',
379
+ common: {
380
+ name: 'uuid',
381
+ type: 'uuid'
382
+ },
383
+ ts: new Date().getTime(),
384
+ from: 'system.host.' + getHostName() + '.tools',
385
+ native: {
386
+ uuid: _uuid
387
+ }
388
+ }, err => {
389
+ if (err) {
390
+ console.error('object system.meta.uuid cannot be updated: ' + err);
391
+ callback();
392
+ } else {
393
+ _objects.getObject('system.meta.uuid', (err, obj) => {
394
+ if (obj.native.uuid !== _uuid) {
395
+ console.error('object system.meta.uuid cannot be updated: write protected');
396
+ } else {
397
+ console.log('object system.meta.uuid created: ' + _uuid);
386
398
  }
387
- }
388
399
 
389
- _objects.setObject('system.meta.uuid', {
390
- type: 'meta',
391
- common: {
392
- name: 'uuid',
393
- type: 'uuid'
394
- },
395
- ts: new Date().getTime(),
396
- from: 'system.host.' + getHostName() + '.tools',
397
- native: {
398
- uuid: _uuid
399
- }
400
- }, err => {
401
- if (err) {
402
- console.error('object system.meta.uuid cannot be updated: ' + err);
403
- !--tasks && callback && callback(_uuid);
404
- } else {
405
- _objects.getObject('system.meta.uuid', (err, obj) => {
406
- if (obj.native.uuid !== _uuid) {
407
- console.error('object system.meta.uuid cannot be updated: write protected');
400
+ callback(_uuid);
401
+ });
402
+ }
403
+ });
404
+ });
405
+ }
406
+
407
+ function createUuid(_objects, callback) {
408
+ const promiseCheckPassword = new Promise(resolve =>
409
+ _objects.getObject('system.user.admin', (err, obj) => {
410
+ if (err || !obj) {
411
+ password = password || require('./password');
412
+
413
+ // Default Password for user 'admin' is application name in lower case
414
+ password(getAppName()).hash(null, null, (err, res) => {
415
+ err && console.error(err);
416
+
417
+ // Create user here and not in io-package.js because of hash password
418
+ _objects.setObject('system.user.admin', {
419
+ type: 'user',
420
+ common: {
421
+ name: 'admin',
422
+ password: res,
423
+ dontDelete: true,
424
+ enabled: true
425
+ },
426
+ ts: new Date().getTime(),
427
+ from: 'system.host.' + getHostName() + '.tools',
428
+ native: {}
429
+ }, () => {
430
+ console.log('object system.user.admin created');
431
+ resolve();
432
+ });
433
+ });
434
+ } else {
435
+ resolve();
436
+ }
437
+ })
438
+ );
439
+
440
+ const promiseCheckUuid = new Promise(resolve =>
441
+ _objects.getObject('system.meta.uuid', (err, obj) => {
442
+ if (!err && obj && obj.native && obj.native.uuid) {
443
+ const PROBLEM_UUIDS = [
444
+ 'ab265f4a-67f9-a46a-c0b2-61e4b95cefe5',
445
+ '7abd3182-d399-f7bd-da19-9550d8babede',
446
+ 'deb6f2a8-fe69-5491-0a50-a9f9b8f3419c',
447
+ 'ec66c85e-fc36-f6f9-f1c9-f5a2882d23c7',
448
+ 'e6203b03-f5f4-253a-e4f6-b295fc543ab7',
449
+ 'd659fa3d-7ef9-202a-ea23-acd0aff67b24'
450
+ ];
451
+
452
+ // if COMMON invalid docker uuid
453
+ if (PROBLEM_UUIDS.find(u => u === obj.native.uuid)) {
454
+ // Read vis license
455
+ _objects.getObject('system.adapter.vis.0', (err, licObj) => {
456
+ if (!licObj || !licObj.native || !licObj.native.license) {
457
+ // generate new UUID
458
+ updateUuid('', _objects, _uuid => resolve(_uuid));
459
+ } else {
460
+ // decode obj.native.license
461
+ let data;
462
+ try {
463
+ data = jwt.decode(licObj.native.license);
464
+ } catch {
465
+ data = null;
466
+ }
467
+
468
+ if (!data || !data.uuid) {
469
+ // generate new UUID
470
+ updateUuid('', _objects, __uuid => resolve(__uuid));
408
471
  } else {
409
- console.log('object system.meta.uuid created: ' + _uuid);
472
+ if (data.uuid !== obj.native.uuid) {
473
+ updateUuid(data.correct ? data.uuid : '', _objects, _uuid => resolve(_uuid));
474
+ } else {
475
+ // Show error
476
+ console.warn(`Your iobroker.vis license must be updated. Please contact info@iobroker.net to get a new license!`);
477
+ console.warn(`Provide following information in email: ${data.email}, invoice: ${data.invoice}`);
478
+ resolve();
479
+ }
410
480
  }
481
+ }
482
+ });
483
+ } else {
484
+ resolve();
485
+ }
486
+ } else {
487
+ // generate new UUID
488
+ updateUuid('', _objects, _uuid => resolve(_uuid));
489
+ }
490
+ })
491
+ );
411
492
 
412
- !--tasks && callback && callback(_uuid);
413
- });
414
- }
415
- });
416
- });
417
- }
418
- });
493
+ return Promise.all([promiseCheckPassword, promiseCheckUuid])
494
+ .then(result => callback && callback(result[1]));
419
495
  }
420
496
 
421
497
  // Download file to tmp or return file name directly
@@ -425,10 +501,10 @@ function getFile(urlOrPath, fileName, callback) {
425
501
  // If object was read
426
502
  if (urlOrPath.substring(0, 'http://'.length) === 'http://' ||
427
503
  urlOrPath.substring(0, 'https://'.length) === 'https://') {
428
- const tmpFile = __dirname + '/../tmp/' + (fileName || Math.floor(Math.random() * 0xFFFFFFE) + '.zip');
504
+ const tmpFile = `${__dirname}/../tmp/${fileName || Math.floor(Math.random() * 0xFFFFFFE) + '.zip'}`;
429
505
  // Add some information to user-agent, like chrome, IE and Firefox do
430
506
  request({url: urlOrPath, gzip: true, headers: {'User-Agent': `${module.exports.appName}, RND: ${randomID}, N: ${process.version}`}}).on('error', error => {
431
- console.log('Cannot download "' + tmpFile + '": ' + error);
507
+ console.log(`Cannot download "${tmpFile}": ${error}`);
432
508
  if (callback) {
433
509
  callback(tmpFile);
434
510
  }
package/main.js CHANGED
@@ -834,7 +834,7 @@ function changeHost(objs, oldHostname, newHostname, callback) {
834
834
  if (row && row.value && row.value.common && row.value.common.host === oldHostname) {
835
835
  const obj = row.value;
836
836
  obj.common.host = newHostname;
837
- logger.info(hostLogPrefix + ' Reassign instance ' + obj._id.substring('system.adapter.'.length) + ' from ' + oldHostname + ' to ' + newHostname);
837
+ logger.info(`${hostLogPrefix} Reassign instance ${obj._id.substring('system.adapter.'.length)} from ${oldHostname} to ${newHostname}`);
838
838
  obj.from = 'system.host.' + tools.getHostName();
839
839
  obj.ts = Date.now();
840
840
 
@@ -856,7 +856,7 @@ function cleanAutoSubscribe(instance, autoInstance, callback) {
856
856
  try {
857
857
  subs = JSON.parse(state.val);
858
858
  } catch {
859
- logger.error(hostLogPrefix + ' Cannot parse subscribes: ' + state.val);
859
+ logger.error(`${hostLogPrefix} Cannot parse subscribes: ${state.val}`);
860
860
  return typeof callback === 'function' && setImmediate(() => callback());
861
861
  }
862
862
  let modified = false;
@@ -937,12 +937,11 @@ function delObjects(objs, callback) {
937
937
  * @return none
938
938
  */
939
939
  function checkHost(callback) {
940
- const objectData = objects.getStatus();
941
940
  // only main host controller needs to check/fix the host assignments from the instances
942
- if (compactGroupController || !objectData.server) {
943
- callback && callback();
944
- return;
941
+ if (compactGroupController) {
942
+ return callback && callback();
945
943
  }
944
+
946
945
  objects.getObjectView('system', 'host', {}, (_err, doc) => {
947
946
  if (!_err && doc && doc.rows &&
948
947
  doc.rows.length === 1 &&
@@ -961,7 +960,7 @@ function checkHost(callback) {
961
960
  } else {
962
961
  // reassign all instances
963
962
  changeHost(doc.rows, oldHostname, hostname, () => {
964
- logger.info(hostLogPrefix + ' Delete host ' + oldId);
963
+ logger.info(`${hostLogPrefix} Delete host ${oldId}`);
965
964
 
966
965
  // delete host object
967
966
  objects.delObject(oldId, () =>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "iobroker.js-controller",
3
- "version": "3.3.15",
3
+ "version": "3.3.19",
4
4
  "engines": {
5
5
  "node": ">=10.0.0"
6
6
  },
@@ -27,6 +27,7 @@
27
27
  "@iobroker/db-states-redis": "~1.2.7",
28
28
  "@iobroker/plugin-base": "~1.2.1",
29
29
  "@iobroker/plugin-sentry": "~1.1.10",
30
+ "ci-info": "^3.2.0",
30
31
  "chokidar": "^3.5.1",
31
32
  "daemonize2": "^0.4.2",
32
33
  "debug": "^4.3.1",