@@ -11,12 +11,18 @@ import fs from 'fs-extra';
1111import type { Socket } from 'node:net' ;
1212import type { Duplex } from 'node:stream' ;
1313import url from 'node:url' ;
14+ import process from 'node:process' ;
1415
16+ /** The upgrade arguments provided to the constructor of the UpgradeManager */
1517export interface UpgradeArguments {
1618 /** Version of controller to upgrade too */
1719 version : string ;
1820 /** Admin instance which triggered the upgrade */
1921 adminInstance : number ;
22+ /** User id the process should run as */
23+ uid : number ;
24+ /** Group id the process should run as */
25+ gid : number ;
2026}
2127
2228interface Certificates {
@@ -63,6 +69,10 @@ class UpgradeManager {
6369 private readonly adminInstance : number ;
6470 /** Desired controller version */
6571 private readonly version : string ;
72+ /** Group id the process should run as */
73+ private readonly gid : number ;
74+ /** User id the process should run as */
75+ private readonly uid : number ;
6676 /** Response send by webserver */
6777 private readonly response : ServerResponse = {
6878 running : true ,
@@ -85,6 +95,30 @@ class UpgradeManager {
8595 this . adminInstance = args . adminInstance ;
8696 this . version = args . version ;
8797 this . logger = this . setupLogger ( ) ;
98+ this . gid = args . gid ;
99+ this . uid = args . uid ;
100+
101+ this . applyUser ( ) ;
102+ }
103+
104+ /**
105+ * To prevent commands (including npm) running as root, we apply the passed in gid and uid
106+ */
107+ private applyUser ( ) : void {
108+ if ( ! process . setuid || ! process . setgid ) {
109+ const errMessage = 'Cannot ensure user and group ids on this system, because no POSIX platform' ;
110+ this . log ( errMessage , true ) ;
111+ throw new Error ( errMessage ) ;
112+ }
113+
114+ try {
115+ process . setgid ( this . gid ) ;
116+ process . setuid ( this . uid ) ;
117+ } catch ( e ) {
118+ const errMessage = `Could not ensure user and group ids on this system: ${ e . message } ` ;
119+ this . log ( errMessage , true ) ;
120+ throw new Error ( errMessage ) ;
121+ }
88122 }
89123
90124 /**
@@ -103,6 +137,8 @@ class UpgradeManager {
103137
104138 const version = additionalArgs [ 0 ] ;
105139 const adminInstance = parseInt ( additionalArgs [ 1 ] ) ;
140+ const uid = parseInt ( additionalArgs [ 2 ] ) ;
141+ const gid = parseInt ( additionalArgs [ 3 ] ) ;
106142
107143 const isValid = ! ! valid ( version ) ;
108144
@@ -116,7 +152,17 @@ class UpgradeManager {
116152 throw new Error ( 'Please provide a valid admin instance' ) ;
117153 }
118154
119- return { version, adminInstance } ;
155+ if ( isNaN ( uid ) ) {
156+ UpgradeManager . printUsage ( ) ;
157+ throw new Error ( 'Please provide a valid uid' ) ;
158+ }
159+
160+ if ( isNaN ( gid ) ) {
161+ UpgradeManager . printUsage ( ) ;
162+ throw new Error ( 'Please provide a valid gid' ) ;
163+ }
164+
165+ return { version, adminInstance, uid, gid } ;
120166 }
121167
122168 /**
@@ -163,7 +209,7 @@ class UpgradeManager {
163209 * Print how the module should be used
164210 */
165211 static printUsage ( ) : void {
166- console . info ( 'Example usage: "node upgradeManager.js <version> <adminInstance>"' ) ;
212+ console . info ( 'Example usage: "node upgradeManager.js <version> <adminInstance> <uid> <gid> "' ) ;
167213 }
168214
169215 /**
0 commit comments