|
|
**Status**: this page is currently a draft
|
|
|
|
|
|
We want to make sharing bridges easier.
|
|
|
|
|
|
Therefore, we would like to implement a clickable URI format to automatically add bridges to Tor Browser (or any other Tor-based application).
|
|
|
|
|
|
# The `bridge://` scheme
|
|
|
|
|
|
Having a dedicated scheme has the advantage that it could contain only the information we need, which is an advantage when dealing with QR codes.
|
|
|
|
|
|
Also, it allows registering a handler application basically in all OS.
|
|
|
|
|
|
## Bridge Address
|
|
|
|
|
|
Keeping the bridge address in the authority part is semantically correct and guarantees compatibility with existing URI parsers. It also makes the URI appear more familiar.
|
|
|
|
|
|
## Fingerprint
|
|
|
|
|
|
The fingerprint is just after the address in the bridge string. Therefore, it makes sense to have it as the path.
|
|
|
|
|
|
Please notice that the fingerprint is optional, according to `tor(1)`.
|
|
|
|
|
|
## Transport
|
|
|
|
|
|
Additional parameters depend on the transport. Therefore, a proposal was to have it as a scheme. But we want to stay transport-agnostic, to keep them _pluggable_. In other words, if a new transport is added, any apps already recognizing our scheme will not need to be updated.
|
|
|
|
|
|
This prevents compound schemes like `bridge+obfs4` or `bridge+snowflake` (which would not have any advantages anyway).
|
|
|
|
|
|
A proposal is to have it as the user information, which would have two benefits:
|
|
|
|
|
|
1. it would match the order on the bridge string;
|
|
|
2. we would have a separate URI part for it.
|
|
|
|
|
|
The alternative is placing it after the fingerprint, separated with a slash. Both are optional, but the fingerprint has a fixed length, and the transports are just a few known strings, so detecting them should be trivial anyway.
|
|
|
|
|
|
The final alternative is to have the transport in the query string.
|
|
|
|
|
|
## Other parameters
|
|
|
|
|
|
Other parameters depend on the transport. They can be added to the query, percent-encoded, and separated by an ampersand. On the final bridge string, they will be separated by a space. The parameter order must be preserved when converting the bridge URL to the bridge string.
|
|
|
|
|
|
# The HTTP(S) fallback
|
|
|
|
|
|
The disadvantage of a custom scheme is that applications may only recognize a few common ones (`http`, `https`, `mailto`, etc...).
|
|
|
|
|
|
On Android, apps can be registered as handlers for HTTP links with a specific host.
|
|
|
|
|
|
For other platforms, the URL could be opened on the browser, which could, in turn, redirect to the `bridge://` URL. We should also add the decoded bridge string, the instructions to add it to Tor Browser/other apps, and a small introduction to bridges/Tor.
|
|
|
|
|
|
In any case, all the information should be on the fragment to avoid it being transferred through the network.
|
|
|
|
|
|
As for the format, we could just base64-encode the bridge string.
|
|
|
|
|
|
# The QR code
|
|
|
|
|
|
Using the `bridge://` scheme makes the QR shorter and less dense.
|
|
|
|
|
|
However, we should implement its decoding and ask for camera permission on Android. This may be annoying for users of a privacy-focused app, but we could explain that it is needed only for this reason and that they can revoke it on the settings.
|
|
|
|
|
|
# The human-friendly ID
|
|
|
|
|
|
Bridge sharing is prone to errors, especially if done through copy&paste.
|
|
|
|
|
|
Therefore, we have added a checksum of the bridge string to Tor Browser.
|
|
|
|
|
|
It is the FNV-1a hash of the bridge string (trimmed of any leading and trailing white spaces). Since FNV-1a works on bytes, the bridge string should be converted to UTF-8, even though bridge strings use only ASCII characters currently.
|
|
|
|
|
|
For maximum compatibility amongst platforms, architectures, and programming languages, the hash is computed using **signed** 32-bit integers. We checked, for example, that the Tor Browser JS implementation is interoperable with a C++ implementation.
|
|
|
|
|
|
For reference, here is the JS implementation:
|
|
|
|
|
|
```javascript
|
|
|
const prime = 0x01000193;
|
|
|
const offset = 0x811c9dc5;
|
|
|
let hash = offset;
|
|
|
const encoder = new TextEncoder();
|
|
|
for (const charCode of encoder.encode(bridgeString)) {
|
|
|
hash = Math.imul(hash ^ charCode, prime);
|
|
|
}
|
|
|
```
|
|
|
|
|
|
Finally, the 32-bit hash is split into 4 (unsigned) bytes, which are used as indices on an array of 256 emojis. The emojis are shown from the most significant byte to the least significant one.
|
|
|
|
|
|
# References
|
|
|
|
|
|
* The original discussion, on legacy/trac#15035
|
|
|
* [Some implementations based on that discussion](https://gitlab.com/torproject/Bridge-URLs/)
|
|
|
* [Android Intent Filters](https://developer.android.com/guide/components/intents-filters), to associate URIs to apps
|
|
|
* [FNV hashes](https://en.wikipedia.org/wiki/Fowler%E2%80%93Noll%E2%80%93Vo_hash_function) |
|
|
\ No newline at end of file |