mutagen-io / mutagen

Fast file synchronization and network forwarding for remote development
https://mutagen.io
Other
3.41k stars 151 forks source link

Stabilize the Mutagen daemon API for third-party usage via a more portable transport #38

Open Toilal opened 5 years ago

Toilal commented 5 years ago

Would you consider adding an API to mutagen daemon ? Maybe with Websocket support to get notifications from the daemon ?

My idea is to build a web UI on top of this API to display synchronisation session informations, create/terminate/pause sessions, configure ignore list, and so on.

Using the command line to start/stop sessions is not that easy when you are running multiple synchronisation sessions.

xenoscopic commented 5 years ago

I should preface this by saying that I'm also working on a GUI for Mutagen, though the code is not yet public. I think I'll have a beta version out by November.

There is actually already a Mutagen daemon API which is used by the Mutagen commands (create, list, monitor, etc.) to implement their functionality. The daemon itself is composed of three gRPC services: one for daemon lifecycle control, one for prompting, and one for session management. Their service definitions can be found here:

https://github.com/havoc-io/mutagen/blob/master/pkg/service/daemon/daemon.proto https://github.com/havoc-io/mutagen/blob/master/pkg/service/prompt/prompt.proto https://github.com/havoc-io/mutagen/blob/master/pkg/service/session/session.proto

For what you want to do, I think you'd only need the session service.

Right now the communication with this service is performed via UNIX domain sockets on POSIX systems and Named Pipes on Windows.

I've intentionally avoided using any sort of TCP-based transport just because of the inability to secure it with OS-level permissions. A raw local TCP socket is bad enough because it's going to be exposed to anybody on the local machine. A websocket is significantly more difficult to secure because it's going to be available to any webpage you visit. Websockets aren't restricted by CORS, and although Chrome has blocked websocket access to localhost, I think it's one of the only browsers to do so. Thus, any webpage you visit can open a connection to ws://localhost and start poking at the Mutagen daemon. You can reduce the attack surface a bit by randomizing the port, and it's probably possible to set up some level of mutual authentication using a shared secret, but it would be a lot of work and quite risky still. Dropbox used to do this until Chrome broke it. It's very difficult to get right from a security standpoint.

If you're thinking about building such an interface through something like Electron or NW.js, then you have a few more options. I believe the Node.js gRPC bindings allow you to use UNIX domain sockets, though I don't know about Windows Named Pipes. In fact, I think Go may be the only gRPC implementation where you can use Named Pipes at the moment, but there are requests to add it to core gRPC (e.g. here and here).

I think that you'd be best off continuing to use gRPC, because a few of the session API calls (e.g. Create and Resume) are streaming calls.

If you really want to go the websocket route, e.g. because you want to go through your browser, you could build a little Go program that would act as a proxy to the daemon, possibly using one websocket connection per call to provide support for streaming. You'd probably be in a better position to do this anyway since you could manage sending the necessary authentication information between the front-end and the websocket. But I still think this is a dangerous approach... so many other programs have had security issues in the past due to local websockets.

Regarding the gRPC APIs themselves: When v0.8.0 comes out, I hope to have Mutagen's daemon API and other internal protocols frozen. They are already mostly stable, but I do sometimes make small changes. I'm not exactly sure on the timeline. I would eventually like to have them stable so that people can make calls from third-party components like text editor plugins.

Another option might be for Mutagen to add a "plumbing" interface like Git has to support API access through invoking commands, but that's probably several months away at least.