@iobroker/js-controller-common 4.0.0-alpha.9-20211115-5dac659e → 4.0.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.
package/LICENSE CHANGED
@@ -1,6 +1,6 @@
1
1
  The MIT License (MIT)
2
2
 
3
- Copyright (c) 2014-2021 bluefox<dogafox@gmail.com>,
3
+ Copyright (c) 2014-2022 bluefox<dogafox@gmail.com>,
4
4
  Copyright (c) 2014 hobbyquaker
5
5
 
6
6
  Permission is hereby granted, free of charge, to any person obtaining a copy
package/README.md CHANGED
@@ -3,4 +3,4 @@ The Library contains the common utils for the ioBroker controller.
3
3
 
4
4
  ## License
5
5
  MIT
6
- Copyright 2018-2021 bluefox <dogafox@gmail.com>
6
+ Copyright 2018-2022 bluefox <dogafox@gmail.com>
package/index.js CHANGED
@@ -3,4 +3,4 @@ module.exports = {
3
3
  EXIT_CODES: require('./lib/common/exitCodes'),
4
4
  password: require('./lib/common/password'),
5
5
  logger: require('./lib/common/logger')
6
- };
6
+ };
@@ -45,13 +45,17 @@ const EXIT_CODES = {
45
45
  CANNOT_UPDATE_VENDOR: 44,
46
46
  INVALID_REPO: 45,
47
47
  CANNOT_UPDATE_LICENSE: 46,
48
+ CANNOT_DELETE_DEPENDENCY: 47,
48
49
  CANNOT_GET_STATES: 50,
49
50
  ADAPTER_ALREADY_INSTALLED: 51,
51
+ CANNOT_RESTORE_BACKUP: 52,
52
+ MIGRATION_ERROR: 78,
50
53
  CONTROLLER_RUNNING: 99,
51
54
  CONTROLLER_NOT_RUNNING: 100,
52
55
  CANNOT_GET_UUID: 101,
53
56
  CANNOT_GET_REPO_LIST: 102,
54
- START_IMMEDIATELY_AFTER_STOP: 156
57
+ START_IMMEDIATELY_AFTER_STOP: 156,
58
+ FILE_NOT_FOUND: 404
55
59
  };
56
60
  // Allow reverse lookup (exit code -> error name)
57
61
  for (const [name, code] of Object.entries(EXIT_CODES)) {
@@ -4,16 +4,16 @@
4
4
  /* jslint esversion: 6 */
5
5
  'use strict';
6
6
 
7
- const winston = require('winston');
7
+ const winston = require('winston');
8
8
  const DailyRotateFile = require('winston-daily-rotate-file');
9
- const fs = require('fs');
10
- const path = require('path');
11
- const os = require('os');
12
- const tools = require('./tools');
13
- const hostname = tools.getHostName();
14
- const Transport = require('winston-transport');
15
- const {LEVEL} = require('triple-beam');
16
- const deepClone = require('deep-clone');
9
+ const fs = require('fs');
10
+ const path = require('path');
11
+ const os = require('os');
12
+ const tools = require('./tools');
13
+ const hostname = tools.getHostName();
14
+ const Transport = require('winston-transport');
15
+ const { LEVEL } = require('triple-beam');
16
+ const deepClone = require('deep-clone');
17
17
 
18
18
  let SysLog;
19
19
  try {
@@ -24,77 +24,76 @@ try {
24
24
 
25
25
  let Seq;
26
26
  try {
27
- Seq = require('winston-seq-updated').default;
27
+ Seq = require('@datalust/winston-seq').SeqTransport;
28
28
  } catch {
29
29
  //console.log('No seq support');
30
30
  }
31
31
 
32
32
  // We must check if SysLog is defined before extending it
33
- const IoSysLog = SysLog && class extends SysLog {
34
- constructor(options) {
35
- super(options);
36
- }
37
-
38
- log(info, callback) {
39
- // we need to map the ioBroker loglevels to the Syslog ones
40
- const ioInfo = info;
41
- if (ioInfo[LEVEL] === 'warn') {
42
- ioInfo[LEVEL] = 'warning';
43
- }
44
- if (ioInfo[LEVEL] === 'info') {
45
- ioInfo[LEVEL] = 'notice';
46
- }
47
- if (ioInfo[LEVEL] === 'debug') {
48
- ioInfo[LEVEL] = 'info';
33
+ const IoSysLog =
34
+ SysLog &&
35
+ class extends SysLog {
36
+ constructor(options) {
37
+ super(options);
49
38
  }
50
- if (ioInfo[LEVEL] === 'silly') {
51
- ioInfo[LEVEL] = 'debug';
52
- }
53
- super.log(ioInfo, callback);
54
- }
55
- };
56
39
 
57
- // We want to enhance some data for Seq
58
- const IoSeq = Seq && class extends Seq {
59
- constructor(options) {
60
- options.levelMapper = options.levelMapper || function (level) {
61
- level = (level || '').toLowerCase();
62
- if (level.includes('error')) {
63
- return 'Error';
40
+ log(info, callback) {
41
+ // we need to map the ioBroker loglevels to the Syslog ones
42
+ const ioInfo = info;
43
+ if (ioInfo[LEVEL] === 'warn') {
44
+ ioInfo[LEVEL] = 'warning';
64
45
  }
65
- if (level.includes('warn')) {
66
- return 'Warning';
46
+ if (ioInfo[LEVEL] === 'info') {
47
+ ioInfo[LEVEL] = 'notice';
67
48
  }
68
- if (level.includes('info')) {
69
- return 'Information';
49
+ if (ioInfo[LEVEL] === 'debug') {
50
+ ioInfo[LEVEL] = 'info';
70
51
  }
71
- if (level.includes('debug')) {
72
- return 'Debug';
52
+ if (ioInfo[LEVEL] === 'silly') {
53
+ ioInfo[LEVEL] = 'debug';
73
54
  }
74
- if (level.includes('silly')) {
75
- return 'Verbose';
55
+ super.log(ioInfo, callback);
56
+ }
57
+ };
58
+
59
+ // We want to enhance some data for Seq
60
+ const IoSeq =
61
+ Seq &&
62
+ class extends Seq {
63
+ log(info, callback) {
64
+ const ioInfo = info;
65
+ ioInfo.props = ioInfo.props || {};
66
+
67
+ // map our log levels to Seq levels
68
+ const level = (info.level || '').toLowerCase();
69
+ if (level.includes('error')) {
70
+ info.level = 'Error';
71
+ } else if (level.includes('warn')) {
72
+ info.level = 'Warning';
73
+ } else if (level.includes('info')) {
74
+ info.level = 'Information';
75
+ } else if (level.includes('debug')) {
76
+ info.level = 'Debug';
77
+ } else if (level.includes('silly')) {
78
+ info.level = 'Verbose';
79
+ } else {
80
+ info.level = 'Information';
76
81
  }
77
- return 'Information';
78
- };
79
- super(options);
80
- }
81
82
 
82
- log(info, callback) {
83
- const ioInfo = info;
84
- ioInfo.meta = ioInfo.meta || {};
85
-
86
- // we add own properties
87
- ioInfo.meta.Hostname = tools.getHostName();
88
- const msgParts = ioInfo.message.match(/^([^.]+\.[0-9]+) \(([^)]+)\) (.*)$/);
89
- if (msgParts) {
90
- ioInfo.meta.Source = msgParts[1];
91
- ioInfo.meta.Pid = msgParts[2];
92
- } else {
93
- ioInfo.meta.Source = 'js-controller';
83
+ // we add own properties
84
+ ioInfo.props.Hostname = tools.getHostName();
85
+ if (ioInfo.message) {
86
+ const msgParts = ioInfo.message.match(/^([^.]+\.[0-9]+) \(([^)]+)\) (.*)$/);
87
+ if (msgParts) {
88
+ ioInfo.props.Source = msgParts[1];
89
+ ioInfo.props.Pid = msgParts[2];
90
+ } else {
91
+ ioInfo.props.Source = 'js-controller';
92
+ }
93
+ }
94
+ super.log(ioInfo, callback);
94
95
  }
95
- super.log(ioInfo, callback);
96
- }
97
- };
96
+ };
98
97
 
99
98
  // Class used to inform adapter about new log entry
100
99
  class NotifierTransport extends Transport {
@@ -126,23 +125,25 @@ const logger = function (level, files, noStdout, prefix) {
126
125
  files = [files];
127
126
  }
128
127
 
129
- const formatter = info =>
130
- `${timestamp(info.timestamp)} - ${info.level}: ${info.message}`;
128
+ const formatter = info => `${timestamp(info.timestamp)} - ${info.level}: ${info.message}`;
131
129
 
132
130
  files = files || [];
133
131
 
134
132
  // indicator which is used to determine the log dir for developing, where it should be inside the repository
135
- const isNpm = !__dirname.replace(/\\/g, '/').toLowerCase().includes(tools.appName.toLowerCase() + `.js-controller/packages/`);
133
+ const isNpm = !__dirname
134
+ .replace(/\\/g, '/')
135
+ .toLowerCase()
136
+ .includes(tools.appName.toLowerCase() + `.js-controller/packages/`);
136
137
 
137
138
  if (typeof level === 'object') {
138
139
  userOptions = deepClone(level);
139
140
 
140
- level = userOptions.level;
141
- prefix = userOptions.prefix;
141
+ level = userOptions.level;
142
+ prefix = userOptions.prefix;
142
143
  noStdout = userOptions.noStdout;
143
144
 
144
145
  const winstonFormats = [];
145
- winstonFormats.push(winston.format.timestamp({format: timestamp}));
146
+ winstonFormats.push(winston.format.timestamp({ format: timestamp }));
146
147
  if (userOptions.json === undefined || userOptions.json) {
147
148
  winstonFormats.push(winston.format.json());
148
149
  }
@@ -160,12 +161,15 @@ const logger = function (level, files, noStdout, prefix) {
160
161
 
161
162
  if (userOptions.transport) {
162
163
  let fName = 0;
163
- const isWindows = os.platform().match(/^win/);
164
+ const isWindows = os.platform().startsWith('win');
164
165
  Object.keys(userOptions.transport).forEach(f => {
165
166
  const transport = userOptions.transport[f];
166
- if (transport.type === 'file' && transport.enabled !== false) {
167
167
 
168
- transport.filename = transport.filename || ('log/' + tools.appName);
168
+ transport._defaultConfigLoglevel = transport.level; // remember Loglevel if set
169
+ transport.level = transport.level || level;
170
+
171
+ if (transport.type === 'file' && transport.enabled !== false) {
172
+ transport.filename = transport.filename || 'log/' + tools.appName;
169
173
 
170
174
  if (!transport.fileext && transport.filename.indexOf('.log') === -1) {
171
175
  transport.fileext = '.log';
@@ -176,39 +180,46 @@ const logger = function (level, files, noStdout, prefix) {
176
180
  }
177
181
 
178
182
  transport.handleExceptions = false;
179
- transport.name = !fName ? tools.appName : 'dailyRotateFile' + fName;
183
+ transport.name = !fName ? tools.appName : 'dailyRotateFile' + fName;
180
184
  fName++;
181
- transport.filename = transport.filename.replace(/\\/g, '/');
185
+ transport.filename = transport.filename.replace(/\\/g, '/');
182
186
  if (transport.filename.match(/^\w:\/|^\//)) {
183
187
  transport.filename = path.normalize(transport.filename);
184
188
  } else {
185
- const _path = path.normalize(`${tools.getControllerDir()}${isNpm ? '/../../' : '/'}${transport.filename}`);
186
- /*
187
- if (_path.indexOf('js-controller') !== -1 && isNpm) {
188
- _path = path.normalize(`${__dirname}/../../${transport.filename}`);
189
- }
190
- */
191
-
192
- transport.filename = _path;
189
+ transport.filename = path.normalize(
190
+ `${tools.getControllerDir()}${isNpm ? '/../../' : '/'}${transport.filename}`
191
+ );
193
192
  }
194
- transport.auditFile = transport.filename + '-audit.json';
193
+ transport.auditFile = transport.filename + '-audit.json';
195
194
 
196
- transport.createSymlink = (transport.createSymlink !== undefined) ? transport.createSymlink : !isWindows;
197
- transport.symlinkName = (transport.symlinkName !== undefined) ? transport.symlinkName : (path.basename(transport.filename + '.current.log'));
195
+ transport.createSymlink =
196
+ transport.createSymlink !== undefined ? transport.createSymlink : !isWindows;
197
+ transport.symlinkName =
198
+ transport.symlinkName !== undefined
199
+ ? transport.symlinkName
200
+ : path.basename(transport.filename + '.current.log');
198
201
 
199
- transport.filename += '.%DATE%' + (transport.fileext || '');
202
+ transport.filename += '.%DATE%' + (transport.fileext || '');
200
203
  //transport.label = prefix || ''; //TODO format.label()
201
- transport.level = transport.level || level;
202
204
  // transport.json = (transport.json !== undefined) ? transport.json : false; // TODO format.json(), new Default!!
203
- transport.silent = (transport.silent !== undefined) ? transport.silent : false;
205
+ transport.silent = transport.silent !== undefined ? transport.silent : false;
204
206
  // transport.colorize = (transport.colorize !== undefined) ? transport.colorize : ((userOptions.colorize === undefined) ? true : userOptions.colorize); //TODO format.colorize()
205
- transport.localTime = (transport.localTime !== undefined) ? transport.localTime : ((userOptions.localTime === undefined) ? true : userOptions.localTime);
206
- transport.datePattern = 'YYYY-MM-DD';
207
- transport.format = winston.format.combine(winston.format.printf(formatter));
207
+ transport.localTime =
208
+ transport.localTime !== undefined
209
+ ? transport.localTime
210
+ : userOptions.localTime === undefined
211
+ ? true
212
+ : userOptions.localTime;
213
+ transport.datePattern = 'YYYY-MM-DD';
214
+ transport.format = winston.format.combine(winston.format.printf(formatter));
208
215
  /*transport.logException = function (message, info, next, err) {
209
216
  console.error(message);
210
217
  };*/
211
- transport.zippedArchive = isWindows ? false: (transport.zippedArchive !== undefined ? transport.zippedArchive : true);
218
+ transport.zippedArchive = isWindows
219
+ ? false
220
+ : transport.zippedArchive !== undefined
221
+ ? transport.zippedArchive
222
+ : true;
212
223
 
213
224
  if (transport.maxFiles === null && userOptions.maxDays) {
214
225
  transport.maxFiles = userOptions.maxDays + 'd';
@@ -253,7 +264,7 @@ const logger = function (level, files, noStdout, prefix) {
253
264
  try {
254
265
  options.transports.push(new IoSysLog(transport));
255
266
  } catch (err) {
256
- console.log(`Cannot activate Syslog: ${err}`);
267
+ console.log(`Cannot activate Syslog: ${err.message}`);
257
268
  }
258
269
  } else if (transport.type === 'http' && transport.enabled !== false) {
259
270
  // host: (Default: localhost) Remote host of the HTTP logging endpoint
@@ -268,7 +279,7 @@ const logger = function (level, files, noStdout, prefix) {
268
279
  try {
269
280
  options.transports.push(new winston.transports.Http(transport));
270
281
  } catch (err) {
271
- console.log('Cannot activate HTTP: ' + err);
282
+ console.log(`Cannot activate HTTP: ${err.message}`);
272
283
  }
273
284
  } else if (transport.type === 'stream' && transport.enabled !== false) {
274
285
  // stream: any Node.js stream. If an objectMode stream is provided then the entire info object will be written. Otherwise info[MESSAGE] will be written.
@@ -283,7 +294,7 @@ const logger = function (level, files, noStdout, prefix) {
283
294
  if (typeof transport.stream === 'string') {
284
295
  transport.stream = fs.createWriteStream(transport.stream);
285
296
  transport.stream.on('error', err => {
286
- console.log('Error in Stream: ' + err);
297
+ console.log(`Error in Stream: ${err}`);
287
298
  });
288
299
  }
289
300
 
@@ -301,13 +312,13 @@ const logger = function (level, files, noStdout, prefix) {
301
312
  // Add only if serverUrl is configured at least
302
313
  if (transport.serverUrl) {
303
314
  try {
315
+ transport.onError = e => {
316
+ console.log(`SEQ error: ${e}`);
317
+ };
304
318
  const seqLogger = new IoSeq(transport);
305
- seqLogger.on('error', error => {
306
- console.log(`SEQ error: ${error}`);
307
- });
308
319
  options.transports.push(seqLogger);
309
320
  } catch (err) {
310
- console.log(`Cannot activate SEQ: ${err}`);
321
+ console.log(`Cannot activate SEQ: ${err.message}`);
311
322
  }
312
323
  } else {
313
324
  console.log('Cannot activate SEQ: No serverUrl specified');
@@ -318,14 +329,16 @@ const logger = function (level, files, noStdout, prefix) {
318
329
  } else {
319
330
  for (let i = 0; i < files.length; i++) {
320
331
  const opt = {
321
- name: i ? 'dailyRotateFile' + i : tools.appName,
322
- filename: path.normalize(isNpm ? `${__dirname}/../../../log/${files[i]}` : `${__dirname}/../log/${files[i]}`),
323
- extension: '.log',
324
- datePattern: 'YYYY-MM-DD',
332
+ name: i ? 'dailyRotateFile' + i : tools.appName,
333
+ filename: path.normalize(
334
+ isNpm ? `${__dirname}/../../../log/${files[i]}` : `${__dirname}/../log/${files[i]}`
335
+ ),
336
+ extension: '.log',
337
+ datePattern: 'YYYY-MM-DD',
325
338
  //json: false, // If true, messages will be logged as JSON (default true). TODO format.json()
326
339
  level,
327
- silent: false,
328
- localTime: true,
340
+ silent: false,
341
+ localTime: true,
329
342
  //colorize: (userOptions.colorize === undefined) ? true : userOptions.colorize, // TODO format.colorize()
330
343
  //timestamp: timestamp, // TODO: format.timestamp()
331
344
  //label: prefix || '', // TODO format.label()
@@ -338,21 +351,25 @@ const logger = function (level, files, noStdout, prefix) {
338
351
  }
339
352
 
340
353
  if (!noStdout) {
341
- options.transports.push(new winston.transports.Console({
342
- level,
343
- silent: false,
344
- format: winston.format.combine(winston.format.printf(formatter))
345
- //colorize: (userOptions.colorize === undefined) ? true : userOptions.colorize, // TODO format.colorize()
346
- //timestamp: timestamp, // TODO: format.timestamp()
347
- //label: prefix || '' // TODO format.label()
348
- }));
354
+ options.transports.push(
355
+ new winston.transports.Console({
356
+ level,
357
+ silent: false,
358
+ format: winston.format.combine(winston.format.printf(formatter))
359
+ //colorize: (userOptions.colorize === undefined) ? true : userOptions.colorize, // TODO format.colorize()
360
+ //timestamp: timestamp, // TODO: format.timestamp()
361
+ //label: prefix || '' // TODO format.label()
362
+ })
363
+ );
349
364
  }
350
365
 
351
366
  // Must be registered, for adapter.js notification about new logs
352
- options.transports.push(new NotifierTransport({
353
- level,
354
- silent: false
355
- }));
367
+ options.transports.push(
368
+ new NotifierTransport({
369
+ level,
370
+ silent: false
371
+ })
372
+ );
356
373
 
357
374
  const log = winston.createLogger(options);
358
375
 
@@ -383,7 +400,11 @@ const logger = function (level, files, noStdout, prefix) {
383
400
  // Check every hour
384
401
  this._fileChecker = setInterval(() => {
385
402
  this.transports.forEach(transport => {
386
- if (transport.name !=='dailyRotateFile' || !transport.options || transport.options.name !== tools.appName) {
403
+ if (
404
+ transport.name !== 'dailyRotateFile' ||
405
+ !transport.options ||
406
+ transport.options.name !== tools.appName
407
+ ) {
387
408
  return;
388
409
  }
389
410
 
@@ -414,10 +435,16 @@ const logger = function (level, files, noStdout, prefix) {
414
435
  } catch (e) {
415
436
  // there is a bug under windows, that file stays opened and cannot be deleted
416
437
  this.log({
417
- level: os.platform().match(/^win/) ? 'info' : 'error',
418
- message: `host.${hostname} Cannot delete file "${path.normalize(transport.dirname + '/' + files[i])}": ${e}`
438
+ level: os.platform().startsWith('win') ? 'info' : 'error',
439
+ message: `host.${hostname} Cannot delete file "${path.normalize(
440
+ transport.dirname + '/' + files[i]
441
+ )}": ${e}`
419
442
  });
420
- console.log(`host.${hostname} Cannot delete file "${path.normalize(transport.dirname + '/' + files[i])}": ${e}`);
443
+ console.log(
444
+ `host.${hostname} Cannot delete file "${path.normalize(
445
+ transport.dirname + '/' + files[i]
446
+ )}": ${e}`
447
+ );
421
448
  }
422
449
  }
423
450
  }
@@ -490,8 +517,7 @@ function timestamp(date) {
490
517
  value = ts.getMilliseconds();
491
518
  if (value < 10) {
492
519
  value = '00' + value;
493
- } else
494
- if (value < 100) {
520
+ } else if (value < 100) {
495
521
  value = '0' + value;
496
522
  }
497
523
 
@@ -2,7 +2,7 @@
2
2
  *
3
3
  * password hash and check
4
4
  *
5
- * 7'2014-2021 Bluefox <dogafox@gmail.com>
5
+ * 7'2014-2022 Bluefox <dogafox@gmail.com>
6
6
  * 2014 hobbyquaker <hq@ccu.io>
7
7
  *
8
8
  * derived from https://github.com/florianheinemann/password-hash-and-salt/ (MIT License)
@@ -34,20 +34,19 @@
34
34
  /* jslint node: true */
35
35
  'use strict';
36
36
 
37
- const crypto = require('crypto');
38
- let version = null;
37
+ const crypto = require('crypto');
38
+ let version = null;
39
39
 
40
40
  const password = pw => {
41
41
  return {
42
42
  hash: (salt, iterations, callback) => {
43
-
44
43
  salt = salt || crypto.randomBytes(16).toString('hex');
45
44
  iterations = iterations || 10000;
46
45
 
47
46
  // version 0.10 has no 'sha256' and this option must be ignored
48
47
  if (version === null) {
49
48
  version = process.version.replace('v', '');
50
- version = !version.match(/^0\.10\./);
49
+ version = !version.startsWith('0.10.');
51
50
  }
52
51
 
53
52
  if (version) {
@@ -66,7 +65,6 @@ const password = pw => {
66
65
 
67
66
  callback(null, `pbkdf2$${iterations}$${key.toString('hex')}$${salt}`);
68
67
  });
69
-
70
68
  }
71
69
  },
72
70
  check: function (hashedPassword, callback) {
@@ -93,10 +91,10 @@ const password = pw => {
93
91
  let result = false;
94
92
  if (typeof password === 'string') {
95
93
  result =
96
- password.length >= 8 && // minimum length is 8
97
- password.match(/\d/) && // contains at least one digit
94
+ password.length >= 8 && // minimum length is 8
95
+ password.match(/\d/) && // contains at least one digit
98
96
  password.match(/[a-z]/) && // contains at least one lower case letter
99
- password.match(/[A-Z]/); // contains at least one upper case letter
97
+ password.match(/[A-Z]/); // contains at least one upper case letter
100
98
  }
101
99
  typeof callback === 'function' && callback(result);
102
100
  return result; // true if the complexity OK