tor 0.0.3 copy "tor: ^0.0.3" to clipboard
tor: ^0.0.3 copied to clipboard

A multi-platform Flutter plugin for managing a Tor proxy. Based on arti.

example/lib/main.dart

// SPDX-FileCopyrightText: 2023 Foundation Devices Inc.
//
// SPDX-License-Identifier: GPL-3.0-or-later

// Example app deps, not necessarily needed for tor usage.
import 'dart:async';
import 'dart:convert';
import 'dart:io';

import 'package:flutter/material.dart';
// Imports needed for tor usage:
import 'package:socks5_proxy/socks_client.dart'; // Just for example; can use any socks5 proxy package, pick your favorite.
import 'package:tor/tor.dart';
import 'package:tor/socks_socket.dart'; // For socket connections

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return const MaterialApp(
      home: Home(),
    );
  }
}

class Home extends StatefulWidget {
  const Home({super.key});

  @override
  State<Home> createState() => _MyAppState();
}

class _MyAppState extends State<Home> {
  // Flag to track if tor has started.
  bool torStarted = false;

  // Set the default text for the host input field.
  final hostController = TextEditingController(text: 'https://icanhazip.com/');
  // https://check.torproject.org is another good option.

  Future<void> startTor() async {
    await Tor.init();

    // Start the proxy
    await Tor.instance.start();

    // Toggle started flag.
    setState(() {
      torStarted = Tor.instance.started; // Update flag
    });

    print('Done awaiting; tor should be running');
  }

  @override
  void dispose() {
    // Clean up the controller when the widget is disposed.
    hostController.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    const spacerSmall = SizedBox(height: 10);
    return Scaffold(
      appBar: AppBar(
        title: const Text('Tor example'),
      ),
      body: SingleChildScrollView(
        child: Container(
          padding: const EdgeInsets.all(10),
          child: Column(
            children: [
              Row(
                children: [
                  TextButton(
                    onPressed: torStarted
                        ? null
                        : () async {
                            unawaited(
                              showDialog(
                                barrierDismissible: false,
                                context: context,
                                builder: (_) => const Dialog(
                                  child: Padding(
                                    padding: EdgeInsets.all(20.0),
                                    child: Text("Starting tor..."),
                                  ),
                                ),
                              ),
                            );

                            final time = DateTime.now();

                            print("NOW: $time");

                            await startTor();

                            print("Starting tor took "
                                "${DateTime.now().difference(time).inSeconds} "
                                "seconds. Proxy running on port ${Tor.instance.port}");

                            if (mounted) {
                              Navigator.of(context).pop();
                            }
                          },
                    child: const Text("Start"),
                  ),
                  TextButton(
                    onPressed: !torStarted
                        ? null
                        : () async {
                            await Tor.instance.stop();
                            setState(() {
                              torStarted = false; // Update flag
                            });
                          },
                    child: const Text("Stop"),
                  ),
                ],
              ),
              Row(
                children: [
                  // Host input field.
                  Expanded(
                    child: TextField(
                      controller: hostController,
                      decoration: const InputDecoration(
                        border: OutlineInputBorder(),
                        hintText: 'Host to request',
                      ),
                    ),
                  ),
                  spacerSmall,
                  TextButton(
                    onPressed: torStarted
                        ? () async {
                            // `socks5_proxy` package example, use another socks5
                            // connection of your choice.

                            // Create HttpClient object
                            final client = HttpClient();

                            // Assign connection factory.
                            SocksTCPClient.assignToHttpClient(client, [
                              ProxySettings(InternetAddress.loopbackIPv4,
                                  Tor.instance.port,
                                  password:
                                      null), // TODO Need to get from tor config file.
                            ]);

                            // GET request.
                            final request = await client
                                .getUrl(Uri.parse(hostController.text));
                            final response = await request.close();

                            // Print response.
                            var responseString =
                                await utf8.decodeStream(response);
                            print(responseString);
                            // If host input left to default icanhazip.com, a Tor
                            // exit node IP should be printed to the console.
                            //
                            // https://check.torproject.org is also good for
                            // doublechecking torability.

                            // Close client
                            client.close();
                          }
                        : null,
                    child: const Text("Make proxied request"),
                  ),
                ],
              ),
              spacerSmall,
              TextButton(
                onPressed: torStarted
                    ? () async {
                        // Instantiate a socks socket at localhost and on the port selected by the tor service.
                        var socksSocket = await SOCKSSocket.create(
                          proxyHost: InternetAddress.loopbackIPv4.address,
                          proxyPort: Tor.instance.port,
                          sslEnabled: true, // For SSL connections.
                        );

                        // Connect to the socks instantiated above.
                        await socksSocket.connect();

                        // Connect to bitcoin.stackwallet.com on port 50002 via socks socket.
                        //
                        // Note that this is an SSL example.
                        await socksSocket.connectTo(
                            'bitcoin.stackwallet.com', 50002);

                        // Send a server features command to the connected socket, see method for more specific usage example..
                        await socksSocket.sendServerFeaturesCommand();

                        // You should see a server response printed to the console.
                        //
                        // Example response:
                        // `flutter: secure responseData: {
                        // 	"id": "0",
                        // 	"jsonrpc": "2.0",
                        // 	"result": {
                        // 		"cashtokens": true,
                        // 		"dsproof": true,
                        // 		"genesis_hash": "000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f",
                        // 		"hash_function": "sha256",
                        // 		"hosts": {
                        // 			"bitcoin.stackwallet.com": {
                        // 				"ssl_port": 50002,
                        // 				"tcp_port": 50001,
                        // 				"ws_port": 50003,
                        // 				"wss_port": 50004
                        // 			}
                        // 		},
                        // 		"protocol_max": "1.5",
                        // 		"protocol_min": "1.4",
                        // 		"pruning": null,
                        // 		"server_version": "Fulcrum 1.9.1"
                        // 	}
                        // }

                        // Close the socket.
                        await socksSocket.close();
                      }
                    : null,
                child: const Text(
                  "Connect to bitcoin.stackwallet.com:50002 (SSL) via socks socket",
                ),
              ),
            ],
          ),
        ),
      ),
    );
  }
}
5
likes
140
pub points
70%
popularity

Publisher

verified publisherfoundationdevices.com

A multi-platform Flutter plugin for managing a Tor proxy. Based on arti.

Repository (GitHub)
View/report issues

Documentation

API reference

License

GPL-3.0 (LICENSE)

Dependencies

ffi, flutter, path_provider, plugin_platform_interface

More

Packages that depend on tor