iobroker.js-controller 7.0.1 → 7.0.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.
@@ -1,7 +1,12 @@
1
+ /** The upgrade arguments provided to the constructor of the UpgradeManager */
1
2
  export interface UpgradeArguments {
2
3
  /** Version of controller to upgrade too */
3
4
  version: string;
4
5
  /** Admin instance which triggered the upgrade */
5
6
  adminInstance: number;
7
+ /** User id the process should run as */
8
+ uid: number;
9
+ /** Group id the process should run as */
10
+ gid: number;
6
11
  }
7
12
  //# sourceMappingURL=upgradeManager.d.ts.map
@@ -26,12 +26,15 @@ var import_node_https = __toESM(require("node:https"), 1);
26
26
  var import_promises = require("node:timers/promises");
27
27
  var import_fs_extra = __toESM(require("fs-extra"), 1);
28
28
  var import_node_url = __toESM(require("node:url"), 1);
29
+ var import_node_process = __toESM(require("node:process"), 1);
29
30
  const import_meta = {};
30
31
  class UpgradeManager {
31
32
  STOP_TIMEOUT_MS = 5e3;
32
33
  SHUTDOWN_TIMEOUT = 1e4;
33
34
  adminInstance;
34
35
  version;
36
+ gid;
37
+ uid;
35
38
  response = {
36
39
  running: true,
37
40
  stderr: [],
@@ -46,15 +49,35 @@ class UpgradeManager {
46
49
  this.adminInstance = args.adminInstance;
47
50
  this.version = args.version;
48
51
  this.logger = this.setupLogger();
52
+ this.gid = args.gid;
53
+ this.uid = args.uid;
54
+ this.applyUser();
55
+ }
56
+ applyUser() {
57
+ if (!import_node_process.default.setuid || !import_node_process.default.setgid) {
58
+ const errMessage = "Cannot ensure user and group ids on this system, because no POSIX platform";
59
+ this.log(errMessage, true);
60
+ throw new Error(errMessage);
61
+ }
62
+ try {
63
+ import_node_process.default.setgid(this.gid);
64
+ import_node_process.default.setuid(this.uid);
65
+ } catch (e) {
66
+ const errMessage = `Could not ensure user and group ids on this system: ${e.message}`;
67
+ this.log(errMessage, true);
68
+ throw new Error(errMessage);
69
+ }
49
70
  }
50
71
  setupLogger() {
51
72
  const config = import_fs_extra.default.readJSONSync(import_js_controller_common.tools.getConfigFileName());
52
73
  return (0, import_js_controller_common.logger)({ ...config.log, noStdout: false });
53
74
  }
54
75
  static parseCliCommands() {
55
- const additionalArgs = process.argv.slice(2);
76
+ const additionalArgs = import_node_process.default.argv.slice(2);
56
77
  const version = additionalArgs[0];
57
78
  const adminInstance = parseInt(additionalArgs[1]);
79
+ const uid = parseInt(additionalArgs[2]);
80
+ const gid = parseInt(additionalArgs[3]);
58
81
  const isValid = !!(0, import_semver.valid)(version);
59
82
  if (!isValid) {
60
83
  UpgradeManager.printUsage();
@@ -64,7 +87,15 @@ class UpgradeManager {
64
87
  UpgradeManager.printUsage();
65
88
  throw new Error("Please provide a valid admin instance");
66
89
  }
67
- return { version, adminInstance };
90
+ if (isNaN(uid)) {
91
+ UpgradeManager.printUsage();
92
+ throw new Error("Please provide a valid uid");
93
+ }
94
+ if (isNaN(gid)) {
95
+ UpgradeManager.printUsage();
96
+ throw new Error("Please provide a valid gid");
97
+ }
98
+ return { version, adminInstance, uid, gid };
68
99
  }
69
100
  log(message, error = false) {
70
101
  if (error) {
@@ -90,7 +121,7 @@ class UpgradeManager {
90
121
  return (0, import_promisify_child_process.exec)(`${import_js_controller_common.tools.appNameLowerCase} start`);
91
122
  }
92
123
  static printUsage() {
93
- console.info('Example usage: "node upgradeManager.js <version> <adminInstance>"');
124
+ console.info('Example usage: "node upgradeManager.js <version> <adminInstance> <uid> <gid>"');
94
125
  }
95
126
  async npmInstall() {
96
127
  const res = await import_js_controller_common.tools.installNodeModule(`iobroker.js-controller@${this.version}`, {
@@ -117,13 +148,13 @@ class UpgradeManager {
117
148
  this.shutdownAbortController.abort();
118
149
  }
119
150
  if (!this.server) {
120
- process.exit();
151
+ import_node_process.default.exit();
121
152
  }
122
153
  this.destroySockets();
123
154
  this.server.close(async () => {
124
155
  await this.startController();
125
156
  this.log("Successfully started js-controller");
126
- process.exit();
157
+ import_node_process.default.exit();
127
158
  });
128
159
  }
129
160
  destroySockets() {
@@ -239,15 +270,15 @@ async function main() {
239
270
  await upgradeManager.setFinished();
240
271
  }
241
272
  function registerErrorHandlers(upgradeManager) {
242
- process.on("uncaughtException", (e) => {
273
+ import_node_process.default.on("uncaughtException", (e) => {
243
274
  upgradeManager.log(`Uncaught Exception: ${e.stack}`, true);
244
275
  });
245
- process.on("unhandledRejection", (rej) => {
276
+ import_node_process.default.on("unhandledRejection", (rej) => {
246
277
  upgradeManager.log(`Unhandled rejection: ${rej instanceof Error ? rej.stack : JSON.stringify(rej)}`, true);
247
278
  });
248
279
  }
249
280
  const modulePath = import_node_url.default.fileURLToPath(import_meta.url || `file://${__filename}`);
250
- if (process.argv[1] === modulePath) {
281
+ if (import_node_process.default.argv[1] === modulePath) {
251
282
  main();
252
283
  }
253
284
  //# sourceMappingURL=upgradeManager.js.map
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../src/lib/upgradeManager.ts"],
4
- "sourcesContent": ["import { type ChildProcessPromise, exec as execAsync } from 'promisify-child-process';\nimport { tools, logger } from '@iobroker/js-controller-common';\nimport { valid } from 'semver';\nimport { dbConnectAsync } from '@iobroker/js-controller-cli';\nimport http from 'node:http';\nimport https from 'node:https';\nimport type { Client as ObjectsClient } from '@iobroker/db-objects-redis';\nimport { setTimeout as wait } from 'node:timers/promises';\nimport type { Logger } from 'winston';\nimport fs from 'fs-extra';\nimport type { Socket } from 'node:net';\nimport type { Duplex } from 'node:stream';\nimport url from 'node:url';\n\nexport interface UpgradeArguments {\n /** Version of controller to upgrade too */\n version: string;\n /** Admin instance which triggered the upgrade */\n adminInstance: number;\n}\n\ninterface Certificates {\n /** Public certificate */\n certPublic: string;\n /** Private certificate */\n certPrivate: string;\n}\n\ninterface InsecureWebServerParameters {\n /** if https should be used for the webserver */\n useHttps: false;\n /** port of the web server */\n port: number;\n}\n\ntype SecureWebServerParameters = Omit<InsecureWebServerParameters, 'useHttps'> & { useHttps: true } & Certificates;\ntype WebServerParameters = InsecureWebServerParameters | SecureWebServerParameters;\n\ninterface GetCertificatesParams {\n /** The objects DB */\n objects: ObjectsClient;\n /** Name of the public certificate */\n certPublicName: string;\n /** Name of the private certificate */\n certPrivateName: string;\n}\n\ninterface ServerResponse {\n /** If the update is still running */\n running: boolean;\n stderr: string[];\n stdout: string[];\n /** if installation process succeeded */\n success?: boolean;\n}\n\nclass UpgradeManager {\n /** Wait ms until controller is stopped */\n private readonly STOP_TIMEOUT_MS = 5_000;\n /** Wait ms for delivery of final response */\n private readonly SHUTDOWN_TIMEOUT = 10_000;\n /** Instance of admin to get information from */\n private readonly adminInstance: number;\n /** Desired controller version */\n private readonly version: string;\n /** Response send by webserver */\n private readonly response: ServerResponse = {\n running: true,\n stderr: [],\n stdout: [],\n };\n /** Used to stop the stop shutdown timeout */\n private shutdownAbortController?: AbortController;\n /** Logger to log to file and other transports */\n private readonly logger: Logger;\n\n /** The server used for communicating upgrade status */\n private server?: https.Server | http.Server;\n /** All socket connections of the webserver */\n private sockets = new Set<Socket | Duplex>();\n /** Name of the host for logging purposes */\n private readonly hostname = tools.getHostName();\n\n constructor(args: UpgradeArguments) {\n this.adminInstance = args.adminInstance;\n this.version = args.version;\n this.logger = this.setupLogger();\n }\n\n /**\n * Set up the logger, to stream to file and other configured transports\n */\n private setupLogger(): Logger {\n const config = fs.readJSONSync(tools.getConfigFileName());\n return logger({ ...config.log, noStdout: false });\n }\n\n /**\n * Parse the commands from the cli\n */\n static parseCliCommands(): UpgradeArguments {\n const additionalArgs = process.argv.slice(2);\n\n const version = additionalArgs[0];\n const adminInstance = parseInt(additionalArgs[1]);\n\n const isValid = !!valid(version);\n\n if (!isValid) {\n UpgradeManager.printUsage();\n throw new Error('The provided version is not valid');\n }\n\n if (isNaN(adminInstance)) {\n UpgradeManager.printUsage();\n throw new Error('Please provide a valid admin instance');\n }\n\n return { version, adminInstance };\n }\n\n /**\n * Log via console and provide the logs for the server too\n *\n * @param message the message which will be logged\n * @param error if it is an error\n */\n log(message: string, error = false): void {\n if (error) {\n this.logger.error(`host.${this.hostname} [CONTROLLER_AUTO_UPGRADE] ${message}`);\n this.response.stderr.push(message);\n return;\n }\n\n this.logger.info(`host.${this.hostname} [CONTROLLER_AUTO_UPGRADE] ${message}`);\n this.response.stdout.push(message);\n }\n\n /**\n * Stops the js-controller via cli call\n */\n async stopController(): Promise<void> {\n if (tools.isDocker()) {\n await execAsync('/opt/scripts/maintenance.sh on -kbn');\n } else {\n await execAsync(`${tools.appNameLowerCase} stop`);\n }\n await wait(this.STOP_TIMEOUT_MS);\n }\n\n /**\n * Starts the js-controller via cli\n */\n startController(): ChildProcessPromise {\n if (tools.isDocker()) {\n return execAsync('/opt/scripts/maintenance.sh off -y');\n }\n\n return execAsync(`${tools.appNameLowerCase} start`);\n }\n\n /**\n * Print how the module should be used\n */\n static printUsage(): void {\n console.info('Example usage: \"node upgradeManager.js <version> <adminInstance>\"');\n }\n\n /**\n * Install given version of js-controller\n */\n async npmInstall(): Promise<void> {\n const res = await tools.installNodeModule(`iobroker.js-controller@${this.version}`, {\n cwd: '/opt/iobroker',\n debug: true,\n });\n\n this.response.stderr.push(...res.stderr.split('\\n'));\n this.response.stdout.push(...res.stdout.split('\\n'));\n\n this.response.success = res.success;\n\n if (!res.success) {\n throw new Error(`Could not install js-controller@${this.version}`);\n }\n }\n\n /**\n * Starts the web server for admin communication either secure or insecure\n *\n * @param params Web server configuration\n */\n startWebServer(params: WebServerParameters): void {\n const { useHttps } = params;\n if (useHttps) {\n this.startSecureWebServer(params);\n } else {\n this.startInsecureWebServer(params);\n }\n }\n\n /**\n * Shuts down the server, restarts the controller and exits the program\n */\n shutdownApp(): void {\n if (this.shutdownAbortController) {\n this.shutdownAbortController.abort();\n }\n\n if (!this.server) {\n process.exit();\n }\n\n this.destroySockets();\n\n this.server.close(async () => {\n await this.startController();\n this.log('Successfully started js-controller');\n\n process.exit();\n });\n }\n\n /**\n * Destroy all sockets, to prevent requests from keeping server alive\n */\n destroySockets(): void {\n for (const socket of this.sockets) {\n socket.destroy();\n this.sockets.delete(socket);\n }\n }\n\n /**\n * This function is called when the webserver receives a message\n *\n * @param res server response\n */\n webServerCallback(res: http.ServerResponse): void {\n res.writeHead(200, {\n 'Access-Control-Allow-Origin': '*',\n });\n\n res.end(JSON.stringify(this.response));\n\n if (!this.response.running) {\n this.log('Final information delivered');\n this.shutdownApp();\n }\n }\n\n /**\n * Start an insecure web server for admin communication\n *\n * @param params Web server configuration\n */\n startInsecureWebServer(params: InsecureWebServerParameters): void {\n const { port } = params;\n\n this.server = http.createServer((_req, res) => {\n this.webServerCallback(res);\n });\n\n this.monitorSockets(this.server);\n\n this.server.listen(port, () => {\n this.log(`Server is running on http://localhost:${port}`);\n });\n }\n\n /**\n * Start a secure web server for admin communication\n *\n * @param params Web server configuration\n */\n startSecureWebServer(params: SecureWebServerParameters): void {\n const { port, certPublic, certPrivate } = params;\n\n this.server = https.createServer({ key: certPrivate, cert: certPublic }, (_req, res) => {\n this.webServerCallback(res);\n });\n\n this.monitorSockets(this.server);\n\n this.server.listen(port, () => {\n this.log(`Server is running on https://localhost:${port}`);\n });\n }\n\n /**\n * Keep track of all existing sockets\n *\n * @param server the webserver\n */\n monitorSockets(server: http.Server | https.Server): void {\n server.on('connection', socket => {\n this.sockets.add(socket);\n\n server.once('close', () => {\n this.sockets.delete(socket);\n });\n });\n }\n\n /**\n * Get certificates from the DB\n *\n * @param params certificate information\n */\n async getCertificates(params: GetCertificatesParams): Promise<Certificates> {\n const { objects, certPublicName, certPrivateName } = params;\n\n const obj = await objects.getObjectAsync('system.certificates');\n\n if (!obj) {\n throw new Error('No certificates found');\n }\n\n const certs = obj.native.certificates;\n\n return { certPrivate: certs[certPrivateName], certPublic: certs[certPublicName] };\n }\n\n /**\n * Collect parameters for webserver from admin instance\n */\n async collectWebServerParameters(): Promise<WebServerParameters> {\n const { objects } = await dbConnectAsync(false);\n\n const obj = await objects.getObjectAsync(`system.adapter.admin.${this.adminInstance}`);\n\n if (!obj) {\n UpgradeManager.printUsage();\n throw new Error('Please provide a valid admin instance');\n }\n\n if (obj.native.secure) {\n const { certPublic: certPublicName, certPrivate: certPrivateName } = obj.native;\n const { certPublic, certPrivate } = await this.getCertificates({\n objects,\n certPublicName,\n certPrivateName,\n });\n\n return {\n useHttps: obj.native.secure,\n port: obj.native.port,\n certPublic,\n certPrivate,\n };\n }\n\n return {\n useHttps: false,\n port: obj.native.port,\n };\n }\n\n /**\n * Tells the upgrade manager, that server can be shut down on next response or on timeout\n */\n async setFinished(): Promise<void> {\n this.response.running = false;\n\n await this.startShutdownTimeout();\n }\n\n /**\n * Start a timeout which starts controller and shuts down the app if expired\n */\n async startShutdownTimeout(): Promise<void> {\n this.shutdownAbortController = new AbortController();\n try {\n await wait(this.SHUTDOWN_TIMEOUT, null, { signal: this.shutdownAbortController.signal });\n\n this.log('Timeout expired, initializing shutdown');\n this.shutdownApp();\n } catch (e) {\n if (e.code !== 'ABORT_ERR') {\n this.log(e.message, true);\n }\n }\n }\n}\n\n/**\n * Main logic\n */\nasync function main(): Promise<void> {\n const upgradeArguments = UpgradeManager.parseCliCommands();\n const upgradeManager = new UpgradeManager(upgradeArguments);\n registerErrorHandlers(upgradeManager);\n\n const webServerParameters = await upgradeManager.collectWebServerParameters();\n\n upgradeManager.log('Stopping controller');\n await upgradeManager.stopController();\n upgradeManager.log('Successfully stopped js-controller');\n\n upgradeManager.startWebServer(webServerParameters);\n\n try {\n await upgradeManager.npmInstall();\n } catch (e) {\n upgradeManager.log(e.message, true);\n }\n\n await upgradeManager.setFinished();\n}\n\n/**\n * Stream unhandled errors to the log files\n *\n * @param upgradeManager the instance of Upgrade Manager\n */\nfunction registerErrorHandlers(upgradeManager: UpgradeManager): void {\n process.on('uncaughtException', e => {\n upgradeManager.log(`Uncaught Exception: ${e.stack}`, true);\n });\n\n process.on('unhandledRejection', rej => {\n upgradeManager.log(`Unhandled rejection: ${rej instanceof Error ? rej.stack : JSON.stringify(rej)}`, true);\n });\n}\n\n/**\n * This file always needs to be executed in a process different from js-controller\n * else it will be canceled when the file itself stops the controller\n */\n// eslint-disable-next-line unicorn/prefer-module\nconst modulePath = url.fileURLToPath(import.meta.url || `file://${__filename}`);\nif (process.argv[1] === modulePath) {\n main();\n}\n"],
5
- "mappings": "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",
6
- "names": ["fs", "execAsync", "wait", "http", "https", "url"]
4
+ "sourcesContent": ["import { type ChildProcessPromise, exec as execAsync } from 'promisify-child-process';\nimport { tools, logger } from '@iobroker/js-controller-common';\nimport { valid } from 'semver';\nimport { dbConnectAsync } from '@iobroker/js-controller-cli';\nimport http from 'node:http';\nimport https from 'node:https';\nimport type { Client as ObjectsClient } from '@iobroker/db-objects-redis';\nimport { setTimeout as wait } from 'node:timers/promises';\nimport type { Logger } from 'winston';\nimport fs from 'fs-extra';\nimport type { Socket } from 'node:net';\nimport type { Duplex } from 'node:stream';\nimport url from 'node:url';\nimport process from 'node:process';\n\n/** The upgrade arguments provided to the constructor of the UpgradeManager */\nexport interface UpgradeArguments {\n /** Version of controller to upgrade too */\n version: string;\n /** Admin instance which triggered the upgrade */\n adminInstance: number;\n /** User id the process should run as */\n uid: number;\n /** Group id the process should run as */\n gid: number;\n}\n\ninterface Certificates {\n /** Public certificate */\n certPublic: string;\n /** Private certificate */\n certPrivate: string;\n}\n\ninterface InsecureWebServerParameters {\n /** if https should be used for the webserver */\n useHttps: false;\n /** port of the web server */\n port: number;\n}\n\ntype SecureWebServerParameters = Omit<InsecureWebServerParameters, 'useHttps'> & { useHttps: true } & Certificates;\ntype WebServerParameters = InsecureWebServerParameters | SecureWebServerParameters;\n\ninterface GetCertificatesParams {\n /** The objects DB */\n objects: ObjectsClient;\n /** Name of the public certificate */\n certPublicName: string;\n /** Name of the private certificate */\n certPrivateName: string;\n}\n\ninterface ServerResponse {\n /** If the update is still running */\n running: boolean;\n stderr: string[];\n stdout: string[];\n /** if installation process succeeded */\n success?: boolean;\n}\n\nclass UpgradeManager {\n /** Wait ms until controller is stopped */\n private readonly STOP_TIMEOUT_MS = 5_000;\n /** Wait ms for delivery of final response */\n private readonly SHUTDOWN_TIMEOUT = 10_000;\n /** Instance of admin to get information from */\n private readonly adminInstance: number;\n /** Desired controller version */\n private readonly version: string;\n /** Group id the process should run as */\n private readonly gid: number;\n /** User id the process should run as */\n private readonly uid: number;\n /** Response send by webserver */\n private readonly response: ServerResponse = {\n running: true,\n stderr: [],\n stdout: [],\n };\n /** Used to stop the stop shutdown timeout */\n private shutdownAbortController?: AbortController;\n /** Logger to log to file and other transports */\n private readonly logger: Logger;\n\n /** The server used for communicating upgrade status */\n private server?: https.Server | http.Server;\n /** All socket connections of the webserver */\n private sockets = new Set<Socket | Duplex>();\n /** Name of the host for logging purposes */\n private readonly hostname = tools.getHostName();\n\n constructor(args: UpgradeArguments) {\n this.adminInstance = args.adminInstance;\n this.version = args.version;\n this.logger = this.setupLogger();\n this.gid = args.gid;\n this.uid = args.uid;\n\n this.applyUser();\n }\n\n /**\n * To prevent commands (including npm) running as root, we apply the passed in gid and uid\n */\n private applyUser(): void {\n if (!process.setuid || !process.setgid) {\n const errMessage = 'Cannot ensure user and group ids on this system, because no POSIX platform';\n this.log(errMessage, true);\n throw new Error(errMessage);\n }\n\n try {\n process.setgid(this.gid);\n process.setuid(this.uid);\n } catch (e) {\n const errMessage = `Could not ensure user and group ids on this system: ${e.message}`;\n this.log(errMessage, true);\n throw new Error(errMessage);\n }\n }\n\n /**\n * Set up the logger, to stream to file and other configured transports\n */\n private setupLogger(): Logger {\n const config = fs.readJSONSync(tools.getConfigFileName());\n return logger({ ...config.log, noStdout: false });\n }\n\n /**\n * Parse the commands from the cli\n */\n static parseCliCommands(): UpgradeArguments {\n const additionalArgs = process.argv.slice(2);\n\n const version = additionalArgs[0];\n const adminInstance = parseInt(additionalArgs[1]);\n const uid = parseInt(additionalArgs[2]);\n const gid = parseInt(additionalArgs[3]);\n\n const isValid = !!valid(version);\n\n if (!isValid) {\n UpgradeManager.printUsage();\n throw new Error('The provided version is not valid');\n }\n\n if (isNaN(adminInstance)) {\n UpgradeManager.printUsage();\n throw new Error('Please provide a valid admin instance');\n }\n\n if (isNaN(uid)) {\n UpgradeManager.printUsage();\n throw new Error('Please provide a valid uid');\n }\n\n if (isNaN(gid)) {\n UpgradeManager.printUsage();\n throw new Error('Please provide a valid gid');\n }\n\n return { version, adminInstance, uid, gid };\n }\n\n /**\n * Log via console and provide the logs for the server too\n *\n * @param message the message which will be logged\n * @param error if it is an error\n */\n log(message: string, error = false): void {\n if (error) {\n this.logger.error(`host.${this.hostname} [CONTROLLER_AUTO_UPGRADE] ${message}`);\n this.response.stderr.push(message);\n return;\n }\n\n this.logger.info(`host.${this.hostname} [CONTROLLER_AUTO_UPGRADE] ${message}`);\n this.response.stdout.push(message);\n }\n\n /**\n * Stops the js-controller via cli call\n */\n async stopController(): Promise<void> {\n if (tools.isDocker()) {\n await execAsync('/opt/scripts/maintenance.sh on -kbn');\n } else {\n await execAsync(`${tools.appNameLowerCase} stop`);\n }\n await wait(this.STOP_TIMEOUT_MS);\n }\n\n /**\n * Starts the js-controller via cli\n */\n startController(): ChildProcessPromise {\n if (tools.isDocker()) {\n return execAsync('/opt/scripts/maintenance.sh off -y');\n }\n\n return execAsync(`${tools.appNameLowerCase} start`);\n }\n\n /**\n * Print how the module should be used\n */\n static printUsage(): void {\n console.info('Example usage: \"node upgradeManager.js <version> <adminInstance> <uid> <gid>\"');\n }\n\n /**\n * Install given version of js-controller\n */\n async npmInstall(): Promise<void> {\n const res = await tools.installNodeModule(`iobroker.js-controller@${this.version}`, {\n cwd: '/opt/iobroker',\n debug: true,\n });\n\n this.response.stderr.push(...res.stderr.split('\\n'));\n this.response.stdout.push(...res.stdout.split('\\n'));\n\n this.response.success = res.success;\n\n if (!res.success) {\n throw new Error(`Could not install js-controller@${this.version}`);\n }\n }\n\n /**\n * Starts the web server for admin communication either secure or insecure\n *\n * @param params Web server configuration\n */\n startWebServer(params: WebServerParameters): void {\n const { useHttps } = params;\n if (useHttps) {\n this.startSecureWebServer(params);\n } else {\n this.startInsecureWebServer(params);\n }\n }\n\n /**\n * Shuts down the server, restarts the controller and exits the program\n */\n shutdownApp(): void {\n if (this.shutdownAbortController) {\n this.shutdownAbortController.abort();\n }\n\n if (!this.server) {\n process.exit();\n }\n\n this.destroySockets();\n\n this.server.close(async () => {\n await this.startController();\n this.log('Successfully started js-controller');\n\n process.exit();\n });\n }\n\n /**\n * Destroy all sockets, to prevent requests from keeping server alive\n */\n destroySockets(): void {\n for (const socket of this.sockets) {\n socket.destroy();\n this.sockets.delete(socket);\n }\n }\n\n /**\n * This function is called when the webserver receives a message\n *\n * @param res server response\n */\n webServerCallback(res: http.ServerResponse): void {\n res.writeHead(200, {\n 'Access-Control-Allow-Origin': '*',\n });\n\n res.end(JSON.stringify(this.response));\n\n if (!this.response.running) {\n this.log('Final information delivered');\n this.shutdownApp();\n }\n }\n\n /**\n * Start an insecure web server for admin communication\n *\n * @param params Web server configuration\n */\n startInsecureWebServer(params: InsecureWebServerParameters): void {\n const { port } = params;\n\n this.server = http.createServer((_req, res) => {\n this.webServerCallback(res);\n });\n\n this.monitorSockets(this.server);\n\n this.server.listen(port, () => {\n this.log(`Server is running on http://localhost:${port}`);\n });\n }\n\n /**\n * Start a secure web server for admin communication\n *\n * @param params Web server configuration\n */\n startSecureWebServer(params: SecureWebServerParameters): void {\n const { port, certPublic, certPrivate } = params;\n\n this.server = https.createServer({ key: certPrivate, cert: certPublic }, (_req, res) => {\n this.webServerCallback(res);\n });\n\n this.monitorSockets(this.server);\n\n this.server.listen(port, () => {\n this.log(`Server is running on https://localhost:${port}`);\n });\n }\n\n /**\n * Keep track of all existing sockets\n *\n * @param server the webserver\n */\n monitorSockets(server: http.Server | https.Server): void {\n server.on('connection', socket => {\n this.sockets.add(socket);\n\n server.once('close', () => {\n this.sockets.delete(socket);\n });\n });\n }\n\n /**\n * Get certificates from the DB\n *\n * @param params certificate information\n */\n async getCertificates(params: GetCertificatesParams): Promise<Certificates> {\n const { objects, certPublicName, certPrivateName } = params;\n\n const obj = await objects.getObjectAsync('system.certificates');\n\n if (!obj) {\n throw new Error('No certificates found');\n }\n\n const certs = obj.native.certificates;\n\n return { certPrivate: certs[certPrivateName], certPublic: certs[certPublicName] };\n }\n\n /**\n * Collect parameters for webserver from admin instance\n */\n async collectWebServerParameters(): Promise<WebServerParameters> {\n const { objects } = await dbConnectAsync(false);\n\n const obj = await objects.getObjectAsync(`system.adapter.admin.${this.adminInstance}`);\n\n if (!obj) {\n UpgradeManager.printUsage();\n throw new Error('Please provide a valid admin instance');\n }\n\n if (obj.native.secure) {\n const { certPublic: certPublicName, certPrivate: certPrivateName } = obj.native;\n const { certPublic, certPrivate } = await this.getCertificates({\n objects,\n certPublicName,\n certPrivateName,\n });\n\n return {\n useHttps: obj.native.secure,\n port: obj.native.port,\n certPublic,\n certPrivate,\n };\n }\n\n return {\n useHttps: false,\n port: obj.native.port,\n };\n }\n\n /**\n * Tells the upgrade manager, that server can be shut down on next response or on timeout\n */\n async setFinished(): Promise<void> {\n this.response.running = false;\n\n await this.startShutdownTimeout();\n }\n\n /**\n * Start a timeout which starts controller and shuts down the app if expired\n */\n async startShutdownTimeout(): Promise<void> {\n this.shutdownAbortController = new AbortController();\n try {\n await wait(this.SHUTDOWN_TIMEOUT, null, { signal: this.shutdownAbortController.signal });\n\n this.log('Timeout expired, initializing shutdown');\n this.shutdownApp();\n } catch (e) {\n if (e.code !== 'ABORT_ERR') {\n this.log(e.message, true);\n }\n }\n }\n}\n\n/**\n * Main logic\n */\nasync function main(): Promise<void> {\n const upgradeArguments = UpgradeManager.parseCliCommands();\n const upgradeManager = new UpgradeManager(upgradeArguments);\n registerErrorHandlers(upgradeManager);\n\n const webServerParameters = await upgradeManager.collectWebServerParameters();\n\n upgradeManager.log('Stopping controller');\n await upgradeManager.stopController();\n upgradeManager.log('Successfully stopped js-controller');\n\n upgradeManager.startWebServer(webServerParameters);\n\n try {\n await upgradeManager.npmInstall();\n } catch (e) {\n upgradeManager.log(e.message, true);\n }\n\n await upgradeManager.setFinished();\n}\n\n/**\n * Stream unhandled errors to the log files\n *\n * @param upgradeManager the instance of Upgrade Manager\n */\nfunction registerErrorHandlers(upgradeManager: UpgradeManager): void {\n process.on('uncaughtException', e => {\n upgradeManager.log(`Uncaught Exception: ${e.stack}`, true);\n });\n\n process.on('unhandledRejection', rej => {\n upgradeManager.log(`Unhandled rejection: ${rej instanceof Error ? rej.stack : JSON.stringify(rej)}`, true);\n });\n}\n\n/**\n * This file always needs to be executed in a process different from js-controller\n * else it will be canceled when the file itself stops the controller\n */\n// eslint-disable-next-line unicorn/prefer-module\nconst modulePath = url.fileURLToPath(import.meta.url || `file://${__filename}`);\nif (process.argv[1] === modulePath) {\n main();\n}\n"],
5
+ "mappings": "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",
6
+ "names": ["process", "fs", "execAsync", "wait", "http", "https", "url"]
7
7
  }
package/build/cjs/main.js CHANGED
@@ -1903,7 +1903,12 @@ async function processMessage(msg) {
1903
1903
  }
1904
1904
  const { version: version2, adminInstance } = msg.message;
1905
1905
  logger.info(`${hostLogPrefix} Controller will upgrade itself to version ${version2}`);
1906
- await startUpgradeManager({ version: version2, adminInstance });
1906
+ await startUpgradeManager({
1907
+ version: version2,
1908
+ adminInstance,
1909
+ uid: process.getuid ? process.getuid() : 0,
1910
+ gid: process.getgid ? process.getgid() : 0
1911
+ });
1907
1912
  if (msg.callback) {
1908
1913
  sendTo(msg.from, msg.command, { result: true }, msg.callback);
1909
1914
  }
@@ -4042,7 +4047,7 @@ async function upgradeOsPackages(packages) {
4042
4047
  await packManager.upgrade(packages);
4043
4048
  }
4044
4049
  async function startUpgradeManager(options) {
4045
- const { version: version2, adminInstance } = options;
4050
+ const { version: version2, adminInstance, uid, gid } = options;
4046
4051
  const upgradeProcessPath = require2.resolve("./lib/upgradeManager");
4047
4052
  let upgradeProcess;
4048
4053
  const isSystemd = await import_js_controller_common.tools.isIoBrokerInstalledAsSystemd();
@@ -4053,7 +4058,9 @@ async function startUpgradeManager(options) {
4053
4058
  process.execPath,
4054
4059
  upgradeProcessPath,
4055
4060
  version2,
4056
- adminInstance.toString()
4061
+ adminInstance.toString(),
4062
+ uid.toString(),
4063
+ gid.toString()
4057
4064
  ], {
4058
4065
  detached: true,
4059
4066
  stdio: "ignore"