react-native-nitro-tor
Version:
Tor Daemon and Onion Routing Client for React Native using pure C++ NitroModules.
344 lines (269 loc) • 8.22 kB
Markdown
# react-native-nitro-tor
A Tor Daemon and Onion Routing Client for React Native using pure C++ [NitroModules](https://github.com/mrousavy/nitro).
## Features
- Run a Tor daemon directly in your React Native application
- Create and manage Tor hidden services
- Make HTTP requests over the Tor network (GET, POST, PUT, DELETE)
- Built with performance in mind using React Native's NitroModules
- Cross-platform support for Android, iOS and macOS
## Installation
```bash
# Using npm
npm install react-native-nitro-tor
# Using yarn
yarn add react-native-nitro-tor
```
You'll also need to install the dependency:
```bash
npm install react-native-nitro-modules
# or
yarn add react-native-nitro-modules
```
## Platform Support
| Platform | Support |
| -------- | --------------------------- |
| iOS | ✅ |
| macOS | ✅ |
| Android | ✅ (arm64-v8a, x86_64, x86) |
## Usage
### Basic Example
```typescript
import { RnTor } from 'react-native-nitro-tor';
// Start Tor with a hidden service
const startTor = async () => {
const result = await RnTor.startTorIfNotRunning({
data_dir: '/path/to/tor/data',
socks_port: 9050,
target_port: 8080,
timeout_ms: 60000,
});
if (result.is_success) {
console.log(`Tor started successfully!`);
console.log(`Onion address: ${result.onion_address}`);
console.log(`Control: ${result.control}`);
} else {
console.error(`Failed to start Tor: ${result.error_message}`);
}
};
// Shut down the Tor service
const shutdown = async () => {
const result = await RnTor.shutdownService();
console.log(`Tor shutdown ${result ? 'successful' : 'failed'}`);
};
```
### HTTP Methods Over Tor
```typescript
import { RnTor } from 'react-native-nitro-tor';
// Make an HTTP GET request through Tor
const makeGetRequest = async () => {
const result = await RnTor.httpGet({
url: 'http://example.com',
headers: '',
timeout_ms: 2000,
});
console.log(`Status code: ${result.status_code}`);
console.log(`Response body: ${result.body}`);
if (result.error) {
console.error(`Error: ${result.error}`);
}
};
// Make an HTTP POST request through Tor
const makePostRequest = async () => {
const result = await RnTor.httpPost({
url: 'http://httpbin.org/post',
body: '{"test":"data"}',
headers: '{"Content-Type":"application/json"}',
timeout_ms: 2000,
});
console.log(`Status code: ${result.status_code}`);
console.log(`Response body: ${result.body}`);
if (result.error) {
console.error(`Error: ${result.error}`);
}
};
// Make an HTTP PUT request through Tor
const makePutRequest = async () => {
const result = await RnTor.httpPut({
url: 'http://httpbin.org/put',
body: '{"updated":"value"}',
headers: '{"Content-Type":"application/json"}',
timeout_ms: 2000,
});
console.log(`Status code: ${result.status_code}`);
console.log(`Response body: ${result.body}`);
if (result.error) {
console.error(`Error: ${result.error}`);
}
};
// Make an HTTP DELETE request through Tor
const makeDeleteRequest = async () => {
const result = await RnTor.httpDelete({
url: 'http://httpbin.org/delete',
headers: '{"Content-Type":"application/json"}',
timeout_ms: 2000,
});
console.log(`Status code: ${result.status_code}`);
console.log(`Response body: ${result.body}`);
if (result.error) {
console.error(`Error: ${result.error}`);
}
};
```
### Advanced Usage
```typescript
import { RnTor } from 'react-native-nitro-tor';
// Initialize Tor service
const initTor = async () => {
const initialized = await RnTor.initTorService({
socks_port: 9050,
data_dir: '/path/to/tor/data',
timeout_ms: 60000,
});
if (initialized) {
console.log('Tor service initialized successfully');
return true;
}
return false;
};
// Create a hidden service
const createService = async () => {
const serviceResult = await RnTor.createHiddenService({
port: 9055,
target_port: 9056,
// Optionally provide key_data for persistent services
});
if (serviceResult.is_success) {
console.log(`Created hidden service at: ${serviceResult.onion_address}`);
}
};
// Get the current status of the Tor service.
// 0: Tor is in the process of starting.
// 1: Tor is running.
// 2: Stopped/Not running/error.
// Check service status
const checkStatus = async () => {
const status = await RnTor.getServiceStatus();
console.log(`Current Tor service status: ${status}`);
};
// Shutdown Tor service
const shutdown = async () => {
const result = await RnTor.shutdownService();
console.log(`Tor shutdown ${result ? 'successful' : 'failed'}`);
};
```
## API Reference
### Types
```typescript
type ByteArray64 = number[];
interface TorConfig {
socks_port: number;
data_dir: string;
timeout_ms: number;
}
interface HiddenServiceParams {
port: number;
target_port: number;
key_data?: ByteArray64;
}
interface StartTorParams {
data_dir: string;
key_data?: ByteArray64;
socks_port: number;
target_port: number;
timeout_ms: number;
}
interface StartTorResponse {
is_success: boolean;
onion_address: string;
control: string;
error_message: string;
}
interface HiddenServiceResponse {
is_success: boolean;
onion_address: string;
control: string;
}
interface HttpGetParams {
url: string;
headers: string;
timeout_ms: number;
}
interface HttpPostParams {
url: string;
body: string;
headers: string;
timeout_ms: number;
}
interface HttpPutParams {
url: string;
body: string;
headers: string;
timeout_ms: number;
}
interface HttpDeleteParams {
url: string;
headers: string;
timeout_ms: number;
}
interface HttpResponse {
status_code: number;
body: string;
error: string;
}
```
### Methods
- `initTorService(config: TorConfig): Promise<boolean>`
Initialize the Tor service with the given configuration.
- `createHiddenService(params: HiddenServiceParams): Promise<HiddenServiceResponse>`
Create a new Tor hidden service with the specified parameters.
- `startTorIfNotRunning(params: StartTorParams): Promise<StartTorResponse>`
Start the Tor daemon with a hidden service if it's not already running. This is the recommended method for most use cases.
- `getServiceStatus(): Promise<number>`
Get the current status of the Tor service.
`0`: Tor is in the process of starting.
`1`: Tor is running.
`2`: Stopped/Not running/error.
- `deleteHiddenService(onionAddress: string): Promise<boolean>`
Delete an existing hidden service by its onion address.
- `shutdownService(): Promise<boolean>`
Completely shut down the Tor service.
- `httpGet(params: HttpGetParams): Promise<HttpResponse>`
Make an HTTP GET request through the Tor network.
- `httpPost(params: HttpPostParams): Promise<HttpResponse>`
Make an HTTP POST request through the Tor network.
- `httpPut(params: HttpPutParams): Promise<HttpResponse>`
Make an HTTP PUT request through the Tor network.
- `httpDelete(params: HttpDeleteParams): Promise<HttpResponse>`
Make an HTTP DELETE request through the Tor network.
## Binary Files
- iOS and MacOS: Binaries are located in the root of the project as `Tor.xcframework`
- Android: Binaries are located in `android/src/main/jniLibs`
## Architecture Support
- Android: arm64-v8a, x86_64, x86
## Running the example app
```
# Install dependencies
yarn install
# Generate native interfaces
yarn nitrogen
# Start metro
yarn example start
# For android
yarn example android
# For ios
yarn example ios
# IF ABOVE STEP FOR IOS THROWS ERRORS, you can also try:
cd example/ios && pod install
- Open the NitroTorExample.xcworkspace inside of xcode.
- Drag the Tor.xcframework from the root of the project to xcode project and select the "Copy files to destination" option.
- Build and run from inside of xcode.
```
## License
MIT
## Credits
This project builds upon the work of:
- [react-native-tor](https://github.com/Sifir-io/react-native-tor)
- [sifir-rs-sdk](https://github.com/Sifir-io/sifir-rs-sdk/)
- [libtor](https://github.com/MagicalBitcoin/libtor)
## Contributing
Contributions are welcome! Please feel free to submit a Pull Request.