From f44011725ac0a9d2012632c25d5b2c837cb3b216 Mon Sep 17 00:00:00 2001 From: Emi Date: Tue, 5 Dec 2023 12:06:53 +0100 Subject: [PATCH] fix: wrap tor path in double quotes to handle spaces in path; spawn tor in shell; kill group of processes (shell: true spawns 2 processes) --- .../backend/src/nest/common/test.module.ts | 4 +-- packages/backend/src/nest/common/utils.ts | 21 ++++++++++- .../connections-manager.service.tor.spec.ts | 5 ++- packages/backend/src/nest/tor/tor.service.ts | 36 +++++++++++++------ packages/e2e-tests/src/utils.ts | 3 -- 5 files changed, 50 insertions(+), 19 deletions(-) diff --git a/packages/backend/src/nest/common/test.module.ts b/packages/backend/src/nest/common/test.module.ts index 12e79c308c..d653c1228c 100644 --- a/packages/backend/src/nest/common/test.module.ts +++ b/packages/backend/src/nest/common/test.module.ts @@ -25,11 +25,9 @@ import { createTmpDir, getCors, torBinForPlatform, torDirForPlatform } from './u const torPath = torBinForPlatform() const libPath = torDirForPlatform() -// torBinaryPath: '../../../../../3rd-party/tor/linux/tor', -// torResourcesPath: '../../../../../3rd-party/tor/linux', export const defaultConfigForTest = { socketIOPort: TEST_DATA_PORT, - torBinaryPath: torBinForPlatform(), + torBinaryPath: torPath, torResourcesPath: torPath, torControlPort: await getPort(), options: { diff --git a/packages/backend/src/nest/common/utils.ts b/packages/backend/src/nest/common/utils.ts index 9350fc5948..10c32c9456 100644 --- a/packages/backend/src/nest/common/utils.ts +++ b/packages/backend/src/nest/common/utils.ts @@ -6,7 +6,7 @@ import { UserData } from '@quiet/types' import createHttpsProxyAgent from 'https-proxy-agent' import PeerId from 'peer-id' import tmp from 'tmp' -import crypto from 'crypto' +import crypto, { sign } from 'crypto' import { type PermsData } from '@quiet/types' import { TestConfig } from '../const' import logger from './logger' @@ -14,6 +14,7 @@ import { Libp2pNodeParams } from '../libp2p/libp2p.types' import { createLibp2pAddress, createLibp2pListenAddress, isDefined } from '@quiet/common' import { Libp2pService } from '../libp2p/libp2p.service' import { CertFieldsTypes, getReqFieldValue, loadCSR } from '@quiet/identity' +import { exec } from 'child_process' const log = logger('test') @@ -249,3 +250,21 @@ export async function createPeerId(): Promise { const peerId = await PeerId.create() return peerIdFromKeys(peerId.marshalPubKey(), peerId.marshalPrivKey()) } + +export function killAll(pid: number, signal: string | number = 'SIGTERM') { + // Kills group of processes + console.log(`Killing processes group with pid ${pid}. Signal: ${signal}`) + if (process.platform == 'win32') { + exec(`taskkill /PID ${pid} /T /F`, (error, stdout, stderr) => { + console.log('taskkill stdout: ' + stdout) + console.log('taskkill stderr: ' + stderr) + if (error) { + console.log('error: ' + error.message) + } + }) + } else { + // see https://nodejs.org/api/child_process.html#child_process_options_detached + // If pid is less than -1, then sig is sent to every process in the process group whose ID is -pid. + process.kill(-pid, signal) + } +} diff --git a/packages/backend/src/nest/connections-manager/connections-manager.service.tor.spec.ts b/packages/backend/src/nest/connections-manager/connections-manager.service.tor.spec.ts index 36424a1ff2..7302b54b52 100644 --- a/packages/backend/src/nest/connections-manager/connections-manager.service.tor.spec.ts +++ b/packages/backend/src/nest/connections-manager/connections-manager.service.tor.spec.ts @@ -80,7 +80,10 @@ beforeEach(async () => { ], }) .overrideProvider(TOR_PASSWORD_PROVIDER) - .useValue({ torPassword: 'b5e447c10b0d99e7871636ee5e0839b5', torHashedPassword: '16:FCFFE21F3D9138906021FAADD9E49703CC41848A95F829E0F6E1BDBE63' }) + .useValue({ + torPassword: 'b5e447c10b0d99e7871636ee5e0839b5', + torHashedPassword: '16:FCFFE21F3D9138906021FAADD9E49703CC41848A95F829E0F6E1BDBE63', + }) .compile() connectionsManagerService = await module.resolve(ConnectionsManagerService) diff --git a/packages/backend/src/nest/tor/tor.service.ts b/packages/backend/src/nest/tor/tor.service.ts index 66dea78194..2ac93c45e0 100644 --- a/packages/backend/src/nest/tor/tor.service.ts +++ b/packages/backend/src/nest/tor/tor.service.ts @@ -1,11 +1,10 @@ import * as child_process from 'child_process' -import crypto from 'crypto' import * as fs from 'fs' import path from 'path' import getPort from 'get-port' -import { removeFilesFromDir } from '../common/utils' +import { killAll, removeFilesFromDir } from '../common/utils' import { EventEmitter } from 'events' -import { ConnectionProcessInfo, SocketActionTypes, SupportedPlatform } from '@quiet/types' +import { SocketActionTypes, SupportedPlatform } from '@quiet/types' import { Inject, OnModuleInit } from '@nestjs/common' import { ConfigOptions, ServerIoProviderTypes } from '../types' import { CONFIG_OPTIONS, QUIET_DIR, SERVER_IO_PROVIDER, TOR_PARAMS_PROVIDER, TOR_PASSWORD_PROVIDER } from '../const' @@ -16,7 +15,7 @@ import Logger from '../common/logger' export class Tor extends EventEmitter implements OnModuleInit { socksPort: number - process: child_process.ChildProcessWithoutNullStreams | any = null + process: child_process.ChildProcessWithoutNullStreams | null = null torDataDirectory: string torPidPath: string extraTorProcessParams: TorParams @@ -93,7 +92,7 @@ export class Tor extends EventEmitter implements OnModuleInit { try { this.clearHangingTorProcess() } catch (e) { - this.logger('Error occured while trying to clear hanging tor processes') + this.logger('Error occured while trying to clear hanging tor processes', e) } try { @@ -113,7 +112,7 @@ export class Tor extends EventEmitter implements OnModuleInit { resolve() } catch { this.logger('Killing tor') - await this.process.kill() + this.process?.pid && killAll(this.process?.pid) removeFilesFromDir(this.torDataDirectory) // eslint-disable-next-line @@ -161,7 +160,7 @@ export class Tor extends EventEmitter implements OnModuleInit { if (!torProcessId) return this.logger(`Found tor process with pid ${torProcessId}. Killing...`) try { - process.kill(Number(torProcessId), 'SIGTERM') + killAll(Number(torProcessId)) } catch (e) { this.logger.error(`Tried killing hanging tor process. Failed. Reason: ${e.message}`) } @@ -204,8 +203,12 @@ export class Tor extends EventEmitter implements OnModuleInit { reject(new Error("Can't spawn tor - no controlPort")) return } + const options: child_process.SpawnOptionsWithoutStdio = { + ...this.torParamsProvider.options, + shell: true, + } this.process = child_process.spawn( - `${this.torParamsProvider.torPath}`, + this.torParamsProvider.torPath, [ '--SocksPort', this.socksPort.toString(), @@ -221,8 +224,19 @@ export class Tor extends EventEmitter implements OnModuleInit { this.torPasswordProvider.torHashedPassword, // ...this.torProcessParams ], - Object.assign(this.torParamsProvider.options, { shell: true }) + options ) + this.process.stderr.on('data', e => { + this.logger.error('Tor process. Stderr:', e) + }) + + this.process.on('exit', (code, signal) => { + this.logger(`Tor exited with code ${code} and signal ${signal}`) + }) + + this.process.on('error', err => { + this.logger.error(`Tor process. Error occurred: ${err.message}`) + }) this.process.stdout.on('data', (data: any) => { this.logger(data.toString()) @@ -321,7 +335,7 @@ export class Tor extends EventEmitter implements OnModuleInit { public async kill(): Promise { return await new Promise((resolve, reject) => { - this.logger('Killing tor...') + this.logger('Killing tor... with pid', this.process?.pid) if (this.process === null) { this.logger('TOR: Process is not initalized.') resolve() @@ -337,7 +351,7 @@ export class Tor extends EventEmitter implements OnModuleInit { this.process?.on('error', () => { reject(new Error('TOR: Something went wrong with killing tor process')) }) - this.process?.kill() + this.process?.pid && killAll(this.process?.pid) }) } } diff --git a/packages/e2e-tests/src/utils.ts b/packages/e2e-tests/src/utils.ts index add72edeba..1abe46ec1d 100644 --- a/packages/e2e-tests/src/utils.ts +++ b/packages/e2e-tests/src/utils.ts @@ -105,9 +105,6 @@ export class BuildSetup { DEBUG: 'backend*,desktop*,utils*', DATA_DIR: this.dataDir, } - // if (this.dataDir) { - // env = Object.assign(env, { DATA_DIR: this.dataDir }) - // } if (process.platform === 'win32') { console.log('!WINDOWS!') this.child = spawn(`cd node_modules/.bin & chromedriver.cmd --port=${this.port} --verbose`, [], {