pdf / kdeconnect-chrome-extension

A browser extension to send pages and content from your browser to connected KDE Connect devices.
https://chrome.google.com/webstore/detail/kde-connect/ofmplbbfigookafjahpeepbggpofdhbo
MIT License
233 stars 29 forks source link

Determine KDE Connect's DBUS_SESSION_BUS_ADDRESS on Windows #44

Open qwerty12 opened 2 years ago

qwerty12 commented 2 years ago

This adds support for determining KDE Connect's dbus-daemon's session bus's address on Windows. I haven't tested to see if this breaks building on Linux.

Outdated It works like this: 1. Get a list of processes in the same [Windows session](https://brianbondy.com/blog/100/understanding-windows-at-a-deeper-level-sessions-window-stations-and-desktops) as the one kdeconnect-chrome-extension.exe is running in (on a system where multiple users are logged in at the same time, this avoids possibly connecting to the wrong KDE Connect instance) 2. For any dbus-daemon.exe processes, store their PIDs 3. Read the system's TCP table and for anything listening to a port bound on 127.0.0.1, see if the PID matches one collected in step 2 4. If so, call `org.freedesktop.DBus.NameHasOwner` and see if `org.kde.kdeconnect` has registered on the bus. If that is the case, the connection string is cached and the connection is returned

See https://github.com/pdf/kdeconnect-chrome-extension/pull/44#issuecomment-955607153

If this is acceptable, the remaning two issues for fully fledged Windows support would be to adapt the installer (climenu won't build on Windows) and updating godbus to v5.

(As an aside, if someone's interested in adding macOS support...)

EDIT: This requires a newer version of golang.org/x/sys than the one that is automatically pulled in by glide as a dependency

pdf commented 2 years ago

Well, this is quite a dance to go through. I do note that kdeconnect-cli.exe works on windows, and I'd be somewhat surprised to discover they were using a similar method. Perhaps it might be possible to work out how they're discovering the bus address?

Also, I vaguely recall it being a requirement to write registry keys to install a native host on windows, do you know off-hand if my recollection is correct, and would that mean we'd need to deal with UAC or something for the installer?

I'm afraid I haven't spent any real time on Windows in decades, so I appreciate the assistance.

qwerty12 commented 2 years ago

Oh, wow, after just now hearing of kdeconnect-cli and trying it myself, I do not disagree. At least this isn't the code where it reads processes' environment variables... But I think have the gist (with assumptions made) of how it works:

Reading the Section and obtaining its contents is trivial. Finding KDE Connect's installation directory is not. There's two issues there:

Once KDE Connect's path has been determined, the hashing can be done in kdeconnect-chrome-extension. I looked at the D-Bus code: you take the location of where libdbus.dll is, dirname() it, strip "\bin" off the end if present, and then make the path (with trailing backslash) lower-case and then just SHA1 the path (and then lower-case the result)

Also, I vaguely recall it being a requirement to write registry keys to install a native host on windows, do you know off-hand if my recollection is correct, and would that mean we'd need to deal with UAC or something for the installer?

You're right, but UAC would only be an issue if you're wanting to do a system-wide install (really, you'd just have to relaunch). Both Chrome (and its derivatives I presume) and Firefox read a per-user registry key on Windows for manifest paths, which doesn't require special privileges to write to.

I'm afraid I haven't spent any real time on Windows in decades, so I appreciate the assistance.

I'm very much appreciative of this. The approach I've used currently may be... well... convoluted but kdeconnect-chrome-extension has saved me time nevertheless on Windows.

pdf commented 2 years ago

This is good analysis, not as straight-forward as I was hoping. I'm open to this approach if you agree it would be cleaner than the current method.

I'll sort out the installer stuff once it's decided what the path is here.

qwerty12 commented 2 years ago

I'm not sure on what GitHub PR etiquette is, to be honest, so I've just rebased the branch this PR is pointing to with code that does the Section reading. It is more complex, but the possible race condition between reading the TCP tables and scanning the processes isn't a problem any more. EDIT: unless you're getting something else calling itself kdeconnect-indicator.exe, this way will always connect to KDE Connect's D-Bus daemon too

To try and obtain KDE Connect's path, the following is tried:

For the Windows Store code, Windows.Management.Deployment is a COM API. The code to utilise it is ugly (but I'm 99.999999% sure I free everything that needs to be freed) and relies on the https://github.com/go-ole/go-ole library.
Maybe it's the way I've written it, but the COM code does look really ugly in Go. It's pretty much the equivalent of this, which is much easier to read.

I've split the path determination code for both ways into separate files for readability purposes. I can merge the code into one file or get rid of a method entirely. Both do not rely on any undocumented code; however, borrowing a trick from syscall_unix.go's Mmap, the code to read from the section does use reflect.SliceHeader to turn the mapped view's uintptr result into a []byte.

Once the path has been found, the hashed version is cached (naïvely - assumes a single thread) to avoid the path lookups. But the Section is always read. IMO the path isn't likely to change, but relaunching KDE Connect (slightly more likely to happen) may cause its dbus-daemon to change ports.

I do not know Go at all, so if there's basic errors or better ways to do things (or even better names for functions or variables), let me know or just have at it. Cheers.

pdf commented 2 years ago

Sorry for the delay, been a little busy. I think my preference would be to include only the generic implementation that searches for running processes, since that gives us the best coverage for install methods, and lets us drop a bunch of code. I'll try to find time for a proper review over this weekend.

qwerty12 commented 2 years ago

No worries. Getting rid of the Windows Store-specific code is probably for the best... The one thing I need to add: capping the maximum amount of data read from the Section/Mapping, as I cannot imagine in practice a DBUS_SESSION_BUS_ADDRESS greater than, say, 64Kb. Thanks.

niks255 commented 2 years ago
  • It installs it to C:\Program Files\WindowsApps\KDEe.V.KDEConnect_0.0.878.0_x64__7vt06qxq7ptv8\ - not exactly determinable.

You should not use that path. And you can't access it easily anyway. Just use its execution alias, which has a stable path ("C:\Users\yourprofilename\AppData\Local\Microsoft\WindowsApps\kdeconnect-cli.exe" or just determine it from PATH variable, since it has this path added). This will make things much easier.

qwerty12 commented 2 years ago

An execution alias wouldn't help any here. libdbus, when creating its Section with the information that is needed, doesn't use one but does hash the actual path it's in. In any case, getting the actual path isn't a problem any more - it's pulled from the running processes. I did write code to read it from the Windows APIs designed for getting Store applications' information, but removed it following pdf's comments.

niks255 commented 2 years ago

libdbus, when creating its Section with the information that is needed, doesn't use one but does hash the actual path it's in

Oh, in that case you are doing it right. Sorry. But the path changes every time the app is updated. Is that going to be a problem?

qwerty12 commented 2 years ago

But the path changes every time the app is updated. Is that going to be a problem?

Yes. This code caches the Section name to open, which, as you point out, is liable to change in the case of an update. I don't consider fixing it a huge priority yet, because there's no way (as far as I can tell) to get this native extension to refresh its connection to KDE Connect's D-Bus daemon anyway*. In the two months I've been running this on Windows, I've only had it mess up once, at which point I just disabled and re-enabled the extension and all was well...

* I assume there's no need for such a thing in Linux, where the Session Bus is provided by the system

niks255 commented 2 years ago

I've only had it mess up once, at which point I just disabled and re-enabled the extension and all was well...

So basically, it's refreshed every time you restart a browser?

qwerty12 commented 2 years ago

Yes

pdf commented 2 years ago

I feel like I need to apologise for the further delays here - I have some of the required changes staged, but I need to replace the installer code with something that will work on Windows and I just haven't made the time yet.