-
-
Notifications
You must be signed in to change notification settings - Fork 266
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
15 changed files
with
355 additions
and
42 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
import net from 'net'; | ||
|
||
export const checkSocks5Proxy = (host: string, port: number): Promise<boolean> => { | ||
return new Promise((resolve, reject) => { | ||
const socket = new net.Socket(); | ||
|
||
socket.setTimeout(2_000); | ||
|
||
socket.on('connect', () => { | ||
// Version 5, 1 method, no authentication | ||
const handshakeRequest = Buffer.from([0x05, 0x01, 0x00]); | ||
socket.write(handshakeRequest); | ||
}); | ||
|
||
socket.on('data', data => { | ||
if (data[0] === 0x05 && data[1] === 0x00) { | ||
resolve(true); | ||
} else { | ||
resolve(false); | ||
} | ||
socket.destroy(); | ||
}); | ||
|
||
socket.on('error', err => { | ||
reject(err); | ||
}); | ||
|
||
socket.on('timeout', () => { | ||
socket.destroy(); | ||
reject(new Error('Connection timed out')); | ||
}); | ||
|
||
socket.connect(port, host); | ||
}); | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,61 @@ | ||
import net from 'net'; | ||
import { checkSocks5Proxy } from '../checkSocks5Proxy'; | ||
|
||
jest.mock('net'); | ||
|
||
describe('checkSocks5Proxy', () => { | ||
const host = '127.0.0.1'; | ||
const port = 9050; | ||
|
||
afterEach(() => { | ||
jest.clearAllMocks(); | ||
}); | ||
|
||
it('should return true for a valid SOCKS5 proxy', async () => { | ||
const mockSocket = { | ||
connect: jest.fn(), | ||
write: jest.fn(), | ||
on: jest.fn((event, callback) => { | ||
if (event === 'connect') { | ||
callback(); | ||
} | ||
if (event === 'data') { | ||
// Valid SOCKS5 response. | ||
callback(Buffer.from([0x05, 0x00])); | ||
} | ||
}), | ||
setTimeout: jest.fn(), | ||
destroy: jest.fn(), | ||
}; | ||
|
||
// @ts-expect-error | ||
net.Socket.mockImplementation(() => mockSocket); | ||
|
||
const result = await checkSocks5Proxy(host, port); | ||
expect(result).toBe(true); | ||
}); | ||
|
||
it('should return false for an invalid SOCKS5 proxy', async () => { | ||
const mockSocket = { | ||
connect: jest.fn(), | ||
write: jest.fn(), | ||
on: jest.fn((event, callback) => { | ||
if (event === 'connect') { | ||
callback(); | ||
} | ||
if (event === 'data') { | ||
// Not valid SOCKS5 response | ||
callback(Buffer.from([0x05, 0x01])); | ||
} | ||
}), | ||
setTimeout: jest.fn(), | ||
destroy: jest.fn(), | ||
}; | ||
|
||
// @ts-expect-error | ||
net.Socket.mockImplementation(() => mockSocket); | ||
|
||
const result = await checkSocks5Proxy(host, port); | ||
expect(result).toBe(false); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,39 @@ | ||
import { createTimeoutPromise } from '@trezor/utils'; | ||
|
||
export const waitUntil = ( | ||
MAX_TRIES_WAITING: number, | ||
WAITING_TIME: number, | ||
checkToSuccess: () => Promise<boolean>, | ||
getIsStopped: () => boolean, | ||
): Promise<void> => { | ||
const errorMessages: string[] = []; | ||
|
||
const waitUntilResponse = async (triesCount: number): Promise<void> => { | ||
if (getIsStopped()) { | ||
// If stopped we do not wait anymore. | ||
return; | ||
} | ||
if (triesCount >= MAX_TRIES_WAITING) { | ||
throw new Error(`Timeout waiting: \n${errorMessages.join('\n')}`); | ||
} | ||
try { | ||
const completed = await checkToSuccess(); | ||
if (completed) { | ||
return; | ||
} | ||
} catch (error) { | ||
// Some error here is expected when waiting but | ||
// we do not want to throw until MAX_TRIES_WAITING is reach. | ||
// Instead we want to log it to know what causes the error. | ||
if (error && error.message) { | ||
console.warn('error:', error.message); | ||
errorMessages.push(error.message); | ||
} | ||
} | ||
await createTimeoutPromise(WAITING_TIME); | ||
|
||
return waitUntilResponse(triesCount + 1); | ||
}; | ||
|
||
return waitUntilResponse(1); | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
95 changes: 95 additions & 0 deletions
95
packages/suite-desktop-core/src/libs/processes/TorExternalProcess.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,95 @@ | ||
import { TorConnectionOptions } from '@trezor/request-manager/src/types'; | ||
import { checkSocks5Proxy } from '@trezor/node-utils'; | ||
|
||
import { Status } from './BaseProcess'; | ||
import { waitUntil } from '@trezor/request-manager/src/utils'; | ||
|
||
export type TorProcessStatus = Status & { isBootstrapping?: boolean; isSocks5ProxyPort?: boolean }; | ||
|
||
const WAITING_TIME = 1_000; | ||
const MAX_TRIES_WAITING = 200; | ||
const DEFAULT_TOR_EXTERNAL_HOST = '127.0.0.1'; | ||
const DEFAULT_TOR_EXTERNAL_PORT = 9050; | ||
|
||
export class TorExternalProcess { | ||
// torController: TorController; | ||
// port: number; | ||
// controlPort: number; | ||
// torHost: string; | ||
// torDataDir: string; | ||
// snowflakeBinaryPath: string; | ||
// useExternalTor: boolean; | ||
|
||
stop = true; | ||
|
||
constructor(_options: TorConnectionOptions & { useExternalTor: boolean }) { | ||
// this.port = options.port; | ||
// this.controlPort = options.controlPort; | ||
// this.torHost = options.host; | ||
// this.torDataDir = options.torDataDir; | ||
// this.useExternalTor = options.useExternalTor; | ||
// this.snowflakeBinaryPath = ''; | ||
// this.torController = new TorController({ | ||
// host: this.torHost, | ||
// port: this.port, | ||
// controlPort: this.controlPort, | ||
// torDataDir: this.torDataDir, | ||
// snowflakeBinaryPath: this.snowflakeBinaryPath, | ||
// }); | ||
} | ||
|
||
setTorConfig(_torConfig: { useExternalTor: boolean; snowflakeBinaryPath: string }) { | ||
// Do nothing | ||
} | ||
|
||
async status(): Promise<TorProcessStatus> { | ||
console.log('check status in TorExternalProcess'); | ||
|
||
let isSocks5ProxyPort = false; | ||
try { | ||
isSocks5ProxyPort = await checkSocks5Proxy( | ||
DEFAULT_TOR_EXTERNAL_HOST, | ||
DEFAULT_TOR_EXTERNAL_PORT, | ||
); | ||
} catch { | ||
// Ignore errors. | ||
} | ||
|
||
return { | ||
service: false, | ||
process: false, | ||
isBootstrapping: false, | ||
isSocks5ProxyPort: isSocks5ProxyPort, | ||
}; | ||
} | ||
|
||
public getIsStopped() { | ||
return this.stop; | ||
} | ||
|
||
public async waitUntilAliveExternal(host: string, port: number): Promise<void> { | ||
await waitUntil( | ||
MAX_TRIES_WAITING, | ||
WAITING_TIME, | ||
async () => { | ||
let isSocks5ProxyPort = false; | ||
try { | ||
console.log('calling checkSocks5Proxy in waitUntilAliveExternal'); | ||
isSocks5ProxyPort = await checkSocks5Proxy(host, port); | ||
} catch { | ||
// Ignore errors. | ||
} | ||
return isSocks5ProxyPort; | ||
}, | ||
() => { | ||
return this.getIsStopped(); | ||
}, | ||
); | ||
} | ||
|
||
async start(): Promise<void> { | ||
console.log('startExternal in TorProcess start'); | ||
await this.waitUntilAliveExternal(DEFAULT_TOR_EXTERNAL_HOST, DEFAULT_TOR_EXTERNAL_PORT); | ||
this.stop = false; | ||
} | ||
} |
Oops, something went wrong.