anacrolix / torrent

Full-featured BitTorrent client package and utilities
Mozilla Public License 2.0
5.51k stars 622 forks source link

Adding custom authentication headers #784

Closed marcovidonis closed 1 year ago

marcovidonis commented 1 year ago

I'm looking at adding custom headers to http or websocket requests that I send from the client to a tracker I control. The idea is to filter the requests coming to the tracker to only allow the ones from clients authenticated via a token.

It doesn't seem like there's currently an option for this in the client. How would you approach this @anacrolix?

anacrolix commented 1 year ago

Hm, I suspect something like the Director field should be exposed on torrent.ClientConfig. It should be a func that takes and modifies the http.Request before it's sent to the tracker. It would probably run just after the user agent and host header fields are handled, here. Thanks!

marcovidonis commented 1 year ago

Thanks for the feedback, I've followed your suggestions and made it so that we can apply a user-defined function that modifies the http.Request just before it's sent. I could open a PR for it if you'd like.

My question now is, the way I've set it up, it's not limited to custom headers, as I simply run any function that modifies the request. Is this an acceptable behaviour, or should I put some limits in place, for example just allow adding new headers?

anacrolix commented 1 year ago

It's fine to give complete access to the Request.

marcovidonis commented 1 year ago

I actually just realised that #787 didn't cover the case where the connection to the tracker is done via a websocket, as HttpRequestDirector is not applied to the Upgrade request.

I'm thinking of exposing HttpRequestDirector in webtorrent.TrackerClient and calling it just before Dial(), here. However, the HTTP request is not available in TrackerClient. The Dialer takes a header as an optional parameter, so I thought I could just create an empty http.Request, apply HttpRequestDirector and then extract the header from the request, to be used in the Dialer.

I'm not 100% sure of this approach, though. On one hand, it feels a bit hacky, but on the other, I prefer using the same Director function rather than making another method in ClientConfig just to add headers. Any thoughts @anacrolix?

anacrolix commented 1 year ago

Hm, interestingly nhooyr.io/websocket allows passing a http.Client, which I believe you could hook with a http.Request director by wrapping the Transport inside http.Client. But the redirector thing doesn't apply very well to websockets, since the request is very specific, and it's likely a HTTP director would be set up for more general cases like for trackers and web sources.

github.com/gorilla/websocket seems to only allow providing headers, and does its connection manually and then manually writes out the request. nhooyr.io/websocket is a much better implementation, but it's probably not trivial to switch to that just for this case (unless you're interested).

I think the easy, and clear way is to add a WebsocketTrackerHttpHeaders or WebtorrentTrackerHttpHeaders` config field, and pass that in. It's very clear what it's for, and any user that's altering the HttpRequestDirectory will probably want to make specific changes for websocket too (or not, but it's clear how to do it, and what it does).

marcovidonis commented 1 year ago

Thanks, I'll go for a new config field then, sounds like the most straightforward way to do it.