diff --git a/services/service.ts b/services/service.ts index 1b3931f..40b1541 100644 --- a/services/service.ts +++ b/services/service.ts @@ -48,9 +48,12 @@ const availableFlags = { blockUpdates: 'webosbrew_block_updates', } as Record; -function runningAsRoot(): boolean { +const runningAsRoot: boolean = (() => { + if (typeof process.getuid === 'undefined') { + throw new Error('process.getuid() is missing'); + } return process.getuid() === 0; -} +})(); function asyncCall>(srv: Service, uri: string, args: Record): Promise { return new Promise((resolve, reject) => { @@ -119,13 +122,15 @@ function hashString(data: string, algorithm: string): string { /** * Elevates a package by name. */ -async function elevateService(pkg: string): Promise { - if (runningAsRoot()) { - console.info('Elevating service...'); - await asyncExecFile(path.join(__dirname, 'elevate-service'), [pkg]); - } else { +async function elevateService(pkg: string): Promise { + if (!runningAsRoot) { console.error('Trying to elevate service without running as root. Skipping.'); + return false; } + + console.info('Elevating service...'); + await asyncExecFile(path.join(__dirname, 'elevate-service'), [pkg]); + return true; } /** @@ -325,7 +330,7 @@ function runService() { service.activityManager.idleTimeout = 30; function getInstallerService(): Service { - if (runningAsRoot()) { + if (runningAsRoot) { return service; } return serviceRemote as Service; @@ -396,7 +401,7 @@ function runService() { // If reelevation fails for some reason the service should still be // reelevated on reboot on devices with persistent autostart hooks (since // we launch elevate-service in startup.sh script) - if (runningAsRoot() && pkginfo && pkginfo.Package === kHomebrewChannelPackageId) { + if (runningAsRoot && pkginfo && pkginfo.Package === kHomebrewChannelPackageId) { message.respond({ statusText: 'Self-update…' }); await createToast('Performing self-update...', service); @@ -484,7 +489,7 @@ function runService() { */ service.register( 'checkRoot', - tryRespond(async () => ({ returnValue: runningAsRoot() })), + tryRespond(async () => ({ returnValue: runningAsRoot })), ); /** @@ -493,7 +498,7 @@ function runService() { service.register( 'updateStartupScript', tryRespond(async () => { - if (!runningAsRoot()) { + if (!runningAsRoot) { return { returnValue: true, statusText: 'Not running as root.' }; } @@ -666,7 +671,7 @@ function runService() { service.register( 'autostart', tryRespond(async (message) => { - if (!runningAsRoot()) { + if (!runningAsRoot) { return { message: 'Not running as root.', returnValue: true }; } if (await asyncExists('/tmp/webosbrew_startup')) { @@ -703,6 +708,35 @@ function runService() { return { returnValue: true }; }), ); + + /** + * Elevates the service specified by "id". + */ + type ElevateServicePayload = { id: string }; + service.register( + 'elevateService', + tryRespond(async (message: Message) => { + if (!('id' in message.payload)) { + throw new Error('missing "id"'); + } else if (typeof message.payload['id'] !== 'string') { + throw new Error('"id" is not a string'); + } else if (message.payload['id'] === '') { + throw new Error('"id" is empty'); + } + + if (!runningAsRoot) { + throw new Error('not running as root'); + } + + const payload = message.payload as ElevateServicePayload; + + const status = await elevateService(payload.id); + + if (!status) { + throw new Error('elevateService() failed'); + } + }), + ); } if (process.argv[2] === 'self-update') {