-
Notifications
You must be signed in to change notification settings - Fork 0
Using Voynich to Create Chat Applications
Voynich is mainly aimed at allowing people to create chat applications using it as a library. There is example code for a simple terminal-based chat application that you can use as a template.
Your code should do the following, roughly in this order:
- Parse the command line and/or read in any configuration files
- Create the
StandardLogger
object (see below) - Connect to Tor using whatever connection options (host/port, authentication, etc) to get a control connection. This will be used to create the onion service(s)
- Create the onion service you'll be using using the control connection
- Run an (optional) connection test. This basically tries to connect to the onion service you just created to make sure it's accessible. This step is optional, but recommended, in case there is any issue with the Tor connection.
- Create the
Engine
(see below) - Hook the
Engine
and the Onion service listener created when you created your onion service into your UI's event loop and run it.
Example code for the terminal application is here
These are the values that are configurable within Voynich:
- Tor address - the address of the Tor control connection (default:
127.0.0.1:9051
) - Tor proxy address - the address of the Tor proxy for outgoing Tor connections (default:
127.0.0.1:9050
) - Tor onion service port - the port to associate with your onion service
- Listen address - the local address to listen for incoming connections to your onion service (default:
127.0.0.1:<service-port>
) - Tor authentication - how to authenticate to the Tor control connection. Possible values are "safe-cookie", "hashed-password" or "null". See the "Authentication" section below for more information. (default:
null
) - Onion service type - either "transient" or "persistent". If "persistent", and a service doesn't exist with the same onion address, it will be created; otherwise Voynich will just use the existing one (no default)
There's an optional configuration file format which you can use, in the Config
struct. By default, it looks for a TOML file that looks something like this. There's also a file with the values filled in here.
There's a utility function for reading the config file, an example of using it is here. If you don't pass in an explicit location for the file, it, by default, looks for it in the following directories, in the given order:
$XDG_CONFIG_HOME/voynich/config.toml
~/.config/voynich/config.toml
If it doesn't find it in either place, it sets reasonable defaults.
Tor has three different methods for authenticating to the control connection (used for creating the onion services):
- Null - No authentication. Anyone who can connect to the control connection can issue commands
- Hashed Password - A password is configured (see the Tor docs) and that password has to be passed to the Tor control connection when connecting
- Safe Cookie - A random cookie value is created and stored in a file. To authenticate you must pass the cookie value when connecting to the Tor control connection. Voynich can query the control connection for the location of this cookie file and, if it has read permissions, can read the file and pass the cookie value to Tor without you having to give it to it.
The StandardLogger
is an asynchronous logging object used throughout the Voynich code. It's basically a circular buffer of log messages written by the various parts of Voynich, which you can display to the user as you see fit. It's intended for both application- and system-level messages which will be displayed to the user. If you set the debug
option, troubleshooting messages will also be displayed.
The Onion service listener is a standard network listener which listens for incoming connection via your onion service using the OnionServiceListener::accept()
method. It is created when the onion service is created, and should be one of the things your UI event handler should be multiplexing on.
The Engine
is the heart of the Voynich application. It's how you connect to other users, send and receive messages, and it serves as the event manager for the whole system. Your UI should make calls to Engine::get_event()
to receive and handle Voynich network events (new incoming connections, incoming messages and closed connections), and call Engine::handle_incoming_connection()
when receiving connections through the Onion service listener accept()
method.
An example of putting this all together can be found here.