Opened 4 years ago

Last modified 5 weeks ago

#15035 new task

URI format for bridges

Reported by: eighthave Owned by: n8fr8
Priority: Medium Milestone:
Component: Applications/Orbot Version:
Severity: Normal Keywords: uri, url, bridge
Cc: brade, mcs, hans@… Actual Points:
Parent ID: #28015 Points:
Reviewer: Sponsor:

Description (last modified by n8fr8)

Right now, according to @n8fr8, this is the URI format for the bridge URIs:

bridge://obfs3+99.999.99.999%3A10223+c6fa110ebcd8979b0a57617bf2d6e82bbecd287d+%0A

There is a problem with this format because it doesn't follow the URI RFC so that standard URI parsers won't parse it very well. Adding the // after bridge: makes it a "hierarchical" URI, which means that it has the standard sections of authority, user info, host, port, path, query, and fragment. But the above URI will just stick all of the text in the "authority" part, but that section can't be broken down into the standard parts of the "authority", i.e. user info, host, and port.

To keep the same data format, then this URI should be an "opaque" URI. That just means removing the //. So that makes it like a mailto: URI.

Otherwise, the data could be refactored to fit into the standard parts for a hierarchical URI, then standard URI parsing classes will be able to parse it. For example, android.net.Uri, java.net.URL, etc. That would make the URI look something like this:

obfs4://xx.xx.xxx.xxx:18965/asdasdasldkasjlasjkdd4?cert=3wYasdasdasdasBmsIat+RMmMDV5BV4jDvXuzasdasdasdas8Dz8J1MUvLKHKaQ&iat-mode=0

  • getScheme() would be bridge type
  • getAuthority() would be IP and port number
  • getHost() would be IP
  • getPort() would be port number
  • getPath() would be this thing: 95151988dc29fccb4f610a1c700a1ddf7d5ffbd4
  • then cert=, iat-mode=, etc. would be in the query string

The downside of this approach is that there could only be a single bridge per URI, but maybe that's not so bad.

Child Tickets

Attachments (3)

bridge-url-writer.py (1.5 KB) - added by eighthave 7 weeks ago.
script to handle bridge: URLs
bridge-url-writer.desktop (187 bytes) - added by eighthave 7 weeks ago.
XDG desktop file for associating
bridge-url-writer.html.zip (1.4 KB) - added by eighthave 7 weeks ago.
lots of example URIs in and HTML doc

Download all attachments as: .zip

Change History (17)

comment:1 Changed 4 years ago by n8fr8

Description: modified (diff)

comment:2 Changed 4 years ago by n8fr8

Description: modified (diff)

comment:3 Changed 4 years ago by n8fr8

Description: modified (diff)

comment:4 Changed 4 years ago by eighthave

FYI, submitted a pull request to K-9 Mail to make it linkify bridge: links if Orbot supports them:

https://github.com/k9mail/k-9/pull/684

Other URI schemes are also possible to add.

Last edited 4 years ago by eighthave (previous) (diff)

comment:5 Changed 17 months ago by teor

Severity: Normal

Set all open tickets without a severity to "Normal"

comment:6 Changed 9 months ago by eighthave

After a couple of years of working with URLs for sending info around in ChatSecure, F-Droid, etc. I think should revisit the original ideas of these bridge URIs.

To make the URI clickable in as many places as possible, it must be a http:// or https:// URI. @n8fr8 & Co did nice work for https://chatsecure.org for a URI format. I think its a good example for what bridge URIs should be. For bridges, we could use something like https://torproject.org/#bridge=foo

Maybe it still makes sense to define two URI formats:

  • https:// for sending via messages, etc. so they are clickable
  • bridge:foo for cases where the software handling them knows what it is handling, e.g. QR code read by a scanner built into a tor-enabled browser

Then the concern there is the person distributing the URI needs to know which one is the most appropriate.

Last edited 6 weeks ago by eighthave (previous) (diff)

comment:8 Changed 3 months ago by gaba

Parent ID: #28015

comment:9 Changed 3 months ago by mcs

Cc: brade mcs added

comment:10 Changed 2 months ago by eighthave

Cc: hans@… added

comment:11 Changed 7 weeks ago by eighthave

Here's an outline of the possible URI formats for bridges:

Bridge meek_lite 0.0.2.0:2 97700DFE9F483596DDA6264C4D7DF7641E1E39CE url=https://meek.azureedge.net/ front=ajax.aspnetcdn.com
bridge://meek_lite@0.0.2.0:2/97700DFE9F483596DDA6264C4D7DF7641E1E39CE?url=https%3A//meek.azureedge.net/&front=ajax.aspnetcdn.com
http://bridge.onion/97700DFE9F483596DDA6264C4D7DF7641E1E39CE?transport=meek_lite&ip=0.0.2.0&port=2&url=https%3A//meek.azureedge.net/&front=ajax.aspnetcdn.com
https://bridges.torproject.org/97700DFE9F483596DDA6264C4D7DF7641E1E39CE?transport=meek_lite&ip=0.0.2.0&port=2&url=https%3A//meek.azureedge.net/&front=ajax.aspnetcdn.com


Bridge obfs4 104.224.78.19:443 FD9DAEE45A2FDF70D462914A75ADE99A29957920 cert=LSOd9qOffpIFM4az+ueou7sY0eQRAsI/joW4QgCl/LSDo2ecQzAQHNu281oAivLDZuTQNA iat-mode=0
bridge://obfs4@104.224.78.19:443/FD9DAEE45A2FDF70D462914A75ADE99A29957920?cert=LSOd9qOffpIFM4az%2Bueou7sY0eQRAsI%2FjoW4QgCl/LSDo2ecQzAQHNu281oAivLDZuTQNA&iat-mode=0
http://bridge.onion/FD9DAEE45A2FDF70D462914A75ADE99A29957920?transport=obfs4&ip=104.224.78.19&port=443&cert=LSOd9qOffpIFM4az%2Bueou7sY0eQRAsI%2FjoW4QgCl/LSDo2ecQzAQHNu281oAivLDZuTQNA&iat-mode=0
https://bridges.torproject.org/FD9DAEE45A2FDF70D462914A75ADE99A29957920?transport=obfs4&ip=104.224.78.19&port=443&cert=LSOd9qOffpIFM4az%2Bueou7sY0eQRAsI%2FjoW4QgCl/LSDo2ecQzAQHNu281oAivLDZuTQNA&iat-mode=0

bridge: link for use in-app

The most popular custom scheme that I can think of are magnet: links for torrents. They are a very similar idea as a bridge link. So we should be able to use BitTorrent apps on all platfroms as an example of how to handle these links. Using a custom URI scheme makes it easier to make a link that the browser will never handle, and always look for an app to send it too. Also, using a custom URI Scheme like bridge: means that clicking these URIs in apps is much less likely to ever go to another app, since those apps would have to have specifically created the association. Also, browser let you specific custom handlers for URI Schemes they do not understand. These can be specified to closely match the Bridge lines in torrc. So this collection of fake bridges:

In desktop Firefox, you can add support for bridge: URIs by adding a custom "Protocol Handler":

  1. load about:config
  2. Right-click -> New -> Boolean -> Name: network.protocol-handler.expose.bridge -> Value -> false
  3. Next time you click a link of protocol-type bridge you will be asked which application to open it with.

Chromium on Ubuntu will automatically prompt to open with xdg-open. That will then use the standard, cross-distro XDG methods for registering and using custom schemes that are used in GNOME, KDE, etc. etc. Tor Browser's .desktop file should be able to do this. Any Debian/etc. package can install and configure the .desktop files and XDG Mime stuff as part of the package install. Here's a manual example:

$ cp bridge-url-writer.py /tmp/
$ chmod 0755 /tmp/bridge-url-writer.py
$ mkdir ~/.local/share/applications/
$ cp bridge-url-writer.desktop ~/.local/share/applications/
$ sudo update-desktop-database
$ xdg-mime default bridge-url-writer.desktop x-scheme-handler/bridge

There are similar mechanisms on Windows and MacOS. For example MacOS has the open util which does was GNU/Linux's xdg-open does.

http: link with fake domain name

One problem with having the bridge link clickable and having a real domain name is that it could leak info to the internet that the user is looking for a bridge. So there could be a fake domain name for these links to provide a pattern to match for in things like the OS-level URL matchers in Android and iOS. Something like http://bridge.onion/ will never exist but is somehow a reserved domain name. These links would then automatically show up as clickable on desktop and mobile apps, but should never cause network traffic.

his will lead to confusing failures since the browser will say "bridge.onion’s server IP address could not be found."

https: link with real domain name, like ChatSecure

Using a real domain name like https://bridges.torproject.org provides a way to provide the user direct feedback when they are trying to add a bridge via URL. If the user clicks on a bridge URL and it fails to go to Tor Browser, then they'll see the page on bridges.torproject.org. If the config information is included in the query string, then bridges.torproject.org can automatically generate a proper bridge: URI, which the user can click to send the info out of the browser. The page can also provide a HOWTO for setting up bridge: support for their OS.

ChatSecure's invite links have a nice feature in that Android and iOS will automatically route them to the ChatSecure app, even if they are clicked in the browser. Then if the ChatSecure app is not installed, the link will open up in the browser with instructions on how to get ChatSecure and use the links. With these links, the data is included in the URI Fragment, (e.g. stuff after #) which should never be sent to the network. That protects privacy, but makes it harder for the server to provide useful feedback. Here is an example URI:

https://chatsecure.org/i/#YWhkdmRqZW5kYmRicmVpQGR1a2dvLmNvbT9vdHI9M0EyN0FDODZBRkVGOENGMDlEOTAyMEQwNTJBNzNGMUVGMEQyOUI2Rg

Android has this method of registering a domain name as the official domain name that is tied to the app. It has the nice feature that any link with that domain name will go straight to the matching app, and not be sent to other apps. It does require some setup on the web server. The big downside is that it only works if that app only claims links with that domain name and nothing else. We tried using this in F-Droid, but did not want to give up claiming market: and https://play.google.com links. They are known as "Android App Links". iOS also has this, they are known as "Apple Universal Links".

Use URL-safe base64!**

Right now, the data is encoded in standard base64, which means it had to be encoded and decoded to work in URIs. It would be better to switch to URL-safe base64 (RFC4648), which replaces the use of the chars + and / with - and _. This is because and _. + and / have special meaning in URIs. I don't know what all this entails, so for now, the URL generation will need to know to URL-encode +, /, and =. (e.g. %2B, %2F, and %3D). Just encoding + is often enough, since / often works fine in a URL query string value, and the base64 padding character = does not seem to be often used in bridge configs.

Last edited 6 weeks ago by eighthave (previous) (diff)

Changed 7 weeks ago by eighthave

Attachment: bridge-url-writer.py added

script to handle bridge: URLs

Changed 7 weeks ago by eighthave

Attachment: bridge-url-writer.desktop added

XDG desktop file for associating

Changed 7 weeks ago by eighthave

Attachment: bridge-url-writer.html.zip added

lots of example URIs in and HTML doc

comment:12 Changed 6 weeks ago by eighthave

I also wrote some Python and Java scripts to work with Bridge lines and bridge URLs:
https://gitlab.com/torproject/Bridge-URLs/

comment:13 Changed 6 weeks ago by n8fr8

The additional idea with the " https: link with real domain name, like ChatSecure" proposal, is that if no app intercepts the https link, it will go to a page, that can offer step-by-step how-to and also a bridge: direct link.

This is useful, as well, for someone who doesn't have any app installed yet, and is just given a bridge link. It can take them to the approach app download/install page.

This is what ChatSecure does, offering an xmpp: link on the link invite page.

comment:14 Changed 5 weeks ago by eighthave

I updated the URL parsing stuff to also handle non-PT bridges with no _transport_.

Here is how Tor Browser handles incoming Bridges config (from GeKo):
https://gitweb.torproject.org/tor-launcher.git/tree/src/components/tl-protocol.js#n379

what we are doing is TorSetConf(), the key is "Bridge" and the value is an array with the bridge lines you got, (that's part of aSettingsObj). Part of aSettingsObj in that case is UseBridges: true as well. This is then sent to tor via a SETCONF command. The resulting changes are written to disk in your tor browser dir at Browser/TorBrowser/Data/Tor/torrc.

Here's an Android utility class for working with these:
https://github.com/guardianproject/AndroidPluggableTransports/pull/15

Note: See TracTickets for help on using tickets.