Repository navigation
link2linux 0.1.0
Pre-release
Pre-release
The first release: an Android phone and a Linux desktop pair once, then find
each other on the local network by themselves, and the phone's notifications
appear on the desktop.
Added
- Pairing. Pair a phone by scanning the QR code the desktop shows. A phone
that can't scan pairs by comparing a six-digit code on both screens instead. - Finding each other. Once paired, the desktop finds the phone on the local
network through mDNS, or through the phone's own announcements where the
network filters multicast, and reconnects by itself after the phone sleeps
or changes networks. - Notifications. The phone's notifications appear on the desktop with their
action buttons. Reply to messages from the desktop: inside the notification
on KDE Plasma, and from the link2linux window elsewhere. Dismissing a
notification on the desktop dismisses it on the phone too; this dismiss sync
is on by default and can be turned off. Content that Android withholds from
other apps, such as one-time codes, shows as hidden rather than as
placeholder text. - Desktop app. Pages for pairing and notifications, and the connection
status of each paired phone. - Phone app. For Android 8.0 and newer. Each feature asks for its Android
permission only when you turn it on. - Downloads. A .deb, an .rpm and an AppImage for 64-bit x86 Linux, and a
signed APK, each with a SHA-256 checksum and a build provenance attestation,
plus a one-line installer for the desktop app.
Security
- Everything stays on the local network: no account, no server and no relay.
- Every connection is mutually authenticated TLS 1.3, with each device's own
P-256 key pinned at pairing. The QR code's one-time secret and the six-digit
code are bound to the TLS connection, so they can't be relayed to another
device. - The desktop never accepts incoming connections: it dials the phone, and only
addresses on its own local networks. The firewalld and ufw definitions that
come with the packages open only mDNS and the beacon port, and only once you
allow them.
Known limitations
- Messages, calls, photos, files, the clipboard and screen mirroring are not
in this release. - GNOME has no reply field inside notifications, so replies go through the
link2linux window there. - There are no ARM64 builds and no Flatpak yet.
Install
Linux desktop, 64-bit x86
Install this version in one line. It picks the .deb on Debian and Ubuntu, the
.rpm on Fedora and openSUSE, and the AppImage elsewhere:
curl -fsSL https://codesensei-tushar.github.io/link2linux/install.sh | L2L_VERSION=v0.1.0 shOr download a package below: link2linux_amd64.deb, link2linux.x86_64.rpm,
or link2linux-x86_64.AppImage (which needs FUSE 2).
Android phone, 8.0 and newer
Download link2linux.apk on the phone and open it. If Android asks, allow your
browser to install apps.
Then open link2linux on the desktop and scan the QR code it shows with the
phone.
Verify
sha256sum -c SHA256SUMS --ignore-missing
gh attestation verify link2linux_amd64.deb --repo codesensei-tushar/link2linuxWhat's Changed
- Run CI jobs only for the parts of the repo a change touches by @codesensei-tushar in #1
- Add the protocol crate with types generated from proto/ by @codesensei-tushar in #2
- Add the length-delimited Envelope codec by @codesensei-tushar in #3
- Add the core crate with device identity and discovery types by @codesensei-tushar in #4
- Add pairing and transport types to core by @codesensei-tushar in #5
- Add the session Hello exchange to core by @codesensei-tushar in #6
- Add Ping/Pong liveness and the message loop to the session by @codesensei-tushar in #7
- Add notifications, messages, calls and clipboard stubs to core by @codesensei-tushar in #8
- Add photos, files and screen stubs to core by @codesensei-tushar in #9
- Add the platform crate: OS traits and Linux stubs by @codesensei-tushar in #10
- Add desktop frontend tooling: Vite, React, TypeScript, ESLint, Vitest by @codesensei-tushar in #11
- Add the Tauri v2 shell for the desktop app by @codesensei-tushar in #12
- Add design tokens, global styles and the Button component by @codesensei-tushar in #13
- Add the shared UI components: badges, cards, empty states, headers by @codesensei-tushar in #14
- Add the typed backend client and shared paired-device state by @codesensei-tushar in #15
- Add the pairing page with its empty state and pairing steps by @codesensei-tushar in #16
- Add placeholder pages for the seven remaining features by @codesensei-tushar in #17
- Add the app shell: sidebar navigation, routing and providers by @codesensei-tushar in #18
- Add the website foundation and its GitHub Pages deployment by @codesensei-tushar in #20
- Add the connection status area and a browser preview backend by @codesensei-tushar in #19
- Add the features grid and the how-it-works steps to the website by @codesensei-tushar in #21
- Add privacy, platforms, FAQ and a closing call to action to the website by @codesensei-tushar in #22
- Set up the Android Gradle build and a minimal app module by @codesensei-tushar in #23
- Add core/model and core/common as plain Kotlin modules by @codesensei-tushar in #24
- Add core/designsystem with the Material 3 theme by @codesensei-tushar in #25
- Generate protocol types from proto/ and add length-delimited framing by @codesensei-tushar in #26
- Add a session skeleton over a pinned TLS transport by @codesensei-tushar in #27
- Add Hilt and core/data with in-memory repositories by @codesensei-tushar in #28
- Add Navigation 3 and the pairing feature by @codesensei-tushar in #29
- List the features on the start screen and add the first feature modules by @codesensei-tushar in #30
- Add the photos, files, clipboard and screen feature modules by @codesensei-tushar in #31
- Remove the template Pages workflow that published the whole repository by @codesensei-tushar in #33
- Run checks locally with make ci and make the GitHub CI workflow manual-only by @codesensei-tushar in #32
- Add a download section with every package to the website by @codesensei-tushar in #34
- Add a one-line install script for the desktop app by @codesensei-tushar in #35
- Ship the desktop app as a .deb first on the website and in install.sh by @codesensei-tushar in #36
- Ship .deb, .rpm and AppImage for x86_64; keep Flatpak and ARM64 for later by @codesensei-tushar in #43
- Add a tag-triggered release workflow and the release checklist by @codesensei-tushar in #51
- Add session control, shared replies and pairing messages to the schema by @codesensei-tushar in #37
- Add the notifications feature to the schema by @codesensei-tushar in #38
- Record the pairing, discovery and message-pattern decisions by @codesensei-tushar in #39
- Start the v1 protocol spec: conventions, identity and discovery by @codesensei-tushar in #40
- Specify pairing in the protocol spec by @codesensei-tushar in #41
- Specify transport and session rules in the protocol spec by @codesensei-tushar in #42
- Specify message patterns, errors and versioning in the spec by @codesensei-tushar in #44
- Specify notifications and security considerations in the spec by @codesensei-tushar in #45
- Switch discovery to phone-sent beacons and ports below 32768 by @codesensei-tushar in #46
- Bind pairing to labelled exporters and add the pairing test vector by @codesensei-tushar in #47
- Tighten pairing: SAS attempts, records found by key, strict TLS checks by @codesensei-tushar in #48
- Correct discovery for Android background limits and real firewalls by @codesensei-tushar in #49
- Align notifications with Android, ping less while idle, strict sequence numbers by @codesensei-tushar in #50
- Check wire compatibility with buf breaking in the proto job by @codesensei-tushar in #52
- Add presence and pairing tags and TXT record parsing by @codesensei-tushar in #53
- Add the beacon codec with replay protection by @codesensei-tushar in #54
- Listen for beacons on UDP 27381 over IPv4 and IPv6 by @codesensei-tushar in #55
- Browse for phones with mDNS and track which ones matter by @codesensei-tushar in #56
- Add the reconnect policy for paired phones by @codesensei-tushar in #57
- Make Discovery browse-only and join mDNS and beacons in LanDiscovery by @codesensei-tushar in #58
- Add the Bluetooth LE presence types and trait to the platform crate by @codesensei-tushar in #59
- Advertise the desktop over Bluetooth LE through BlueZ by @codesensei-tushar in #60
- Rewrite the README as a product page by @codesensei-tushar in #63
- Add a contributing guide by @codesensei-tushar in #64
- Ship a firewalld service and a ufw profile in the desktop packages by @codesensei-tushar in #62
- Check that an address is on-link before dialing it by @codesensei-tushar in #65
- Identify paired desktops by key fingerprint by @codesensei-tushar in #66
- Add the pairing controller interface for the pairing screens by @codesensei-tushar in #67
- Add a security module with SPKI fingerprints by @codesensei-tushar in #68
- Compute the pairing proofs and SAS code on the phone by @codesensei-tushar in #69
- Keep the identity key and a storage key in the Android Keystore by @codesensei-tushar in #70
- Make the phone a TLS 1.3 server on bundled Conscrypt by @codesensei-tushar in #71
- Test the phone's TLS server over loopback and check the new vector entries by @codesensei-tushar in #72
- Negotiate the protocol version range and check sequence numbers strictly by @codesensei-tushar in #73
- Store pairings in a sealed file in no-backup storage by @codesensei-tushar in #74
- Use the persistent pairing store in the app by @codesensei-tushar in #75
- Run the phone's side of QR and SAS pairing by @codesensei-tushar in #76
- Test both pairing methods over a real TLS connection by @codesensei-tushar in #77
- Confirm record replacement and track the pairing window by @codesensei-tushar in #78
- Serve key rotation and unpairing in a paired session by @codesensei-tushar in #79
- Implement the pairing controller on the phone's listener by @codesensei-tushar in #80
- Test the pairing service end to end and expose listener start and stop by @codesensei-tushar in #81
- Negotiate the protocol version from both Hellos' ranges by @codesensei-tushar in #82
- Queue outgoing frames so sending and next_event are cancel safe by @codesensei-tushar in #83
- End sessions with Goodbye and map its reason to a reconnect policy by @codesensei-tushar in #84
- Require each sequence number to be exactly one above the last by @codesensei-tushar in #85
- Add the notifications core module with snapshot types and wire text rules by @codesensei-tushar in #99
- Share the scripted-phone helpers between session test files by @codesensei-tushar in #86
- Serve notification images by SHA-256 from a bounded cache by @codesensei-tushar in #100
- Hand the peer's requests over and refuse what the session cannot serve by @codesensei-tushar in #87
- Map notification snapshots to the protocol's PhoneNotification by @codesensei-tushar in #101
- Answer the peer's requests with reply, ack and reply_error by @codesensei-tushar in #88
- Send requests and match their answers by sequence number by @codesensei-tushar in #89
- Wait for answers with send_request and next_reply by @codesensei-tushar in #90
- Take the peer's FeatureStatus and PresenceUpdate by @codesensei-tushar in #91
- Send this side's FeatureStatus and PresenceUpdate after Hello by @codesensei-tushar in #92
- Send requests only while their feature is ready on both sides by @codesensei-tushar in #93
- Run the pairing exchange first and check the peer's device id by @codesensei-tushar in #94
- Ping on the spec's cadence and let the phone only answer by @codesensei-tushar in #95
- Add the sync cursor that follows a mirrored collection by @codesensei-tushar in #96
- Store the user's actions in an outbox with idempotency keys by @codesensei-tushar in #97
- Deliver outbox actions until an answer ends them by @codesensei-tushar in #98
- Keep the shared notifications in a change log with epoch, revisions and tombstones by @codesensei-tushar in #102
- Add the notifications model and API surface to the desktop app by @codesensei-tushar in #108
- Add the notification list logic and live-update hook by @codesensei-tushar in #109
- Show mirrored notifications on the notifications page by @codesensei-tushar in #110
- Add notification actions, inline reply and dismissal by @codesensei-tushar in #111
- Explain withheld notification content and locked actions by @codesensei-tushar in #112
- Mirror the phone's notifications through delta sync by @codesensei-tushar in #115
- Describe richer desktop notifications in the platform API by @codesensei-tushar in #113
- Add the notifications engine core: snapshot sync over a transport by @codesensei-tushar in #116
- Test the engine's snapshot sync with a fake transport by @codesensei-tushar in #117
- Send live notification events with removal reasons once the desktop has synced by @codesensei-tushar in #118
- Add notification policy, availability changes and group summaries to the engine by @codesensei-tushar in #119
- Answer dismiss requests once per idempotency key and report them as dismissed from the desktop by @codesensei-tushar in #120
- Answer action, reply and image requests by @codesensei-tushar in #121
- Read Android notifications into snapshots and render their images by @codesensei-tushar in #122
- Store the notification settings and per-app filters by @codesensei-tushar in #123
- Run the notification listener and feed the engine from it by @codesensei-tushar in #124
- Add the notifications settings screen with an access rationale and per-app filters by @codesensei-tushar in #125
- Add the discovery module with presence tags, TXT records and beacons by @codesensei-tushar in #126
- Read the pairing QR code strictly into an offer by @codesensei-tushar in #127
- Schedule beacon bursts and rotate the announcement by @codesensei-tushar in #128
- Describe the platform pieces discovery needs behind interfaces by @codesensei-tushar in #129
- Keep the announcement and beacon bursts in step with pairing state by @codesensei-tushar in #130
- Test the discovery controller with fakes by @codesensei-tushar in #131
- Register the service with NsdManager and send beacons per network by @codesensei-tushar in #132
- Wire discovery into the app and tell the screens how the phone can be found by @codesensei-tushar in #133
- Add the pairing home screen and its view model by @codesensei-tushar in #134
- Test the pairing view model with a fake controller by @codesensei-tushar in #135
- Show the steps of a pairing attempt by @codesensei-tushar in #136
- Add the scanning screen with the camera permission flow by @codesensei-tushar in #137
- Read QR codes with CameraX and zxing-cpp by @codesensei-tushar in #138
- Offer the optional companion-device step after pairing by @codesensei-tushar in #139
- Add the connection service, the presence service and the manifest by @codesensei-tushar in #140
- Use the real pairing service and start its listener with the connection service by @codesensei-tushar in #141
- Let the user turn the background connection off and on by @codesensei-tushar in #142
- Run notifications in sessions with paired desktops by @codesensei-tushar in #143
- Test notification sessions over loopback TLS by @codesensei-tushar in #144
- Show connected computers and run the listener by pairing and switch by @codesensei-tushar in #145
- Show desktop notifications through org.freedesktop.Notifications by @codesensei-tushar in #114
- Prepare the v0.1.0 release: changelog, build-only runs, release notes by @codesensei-tushar in #146
- Present mirrored notifications as desktop banners by @codesensei-tushar in #147
- Keep the images notifications refer to on disk by SHA-256 by @codesensei-tushar in #148
- Run the notifications mirror and banners over a desktop session by @codesensei-tushar in #149
- Send the user's dismissals and actions to the phone through the outbox by @codesensei-tushar in #150
- Fetch notification images from the phone and show them when they arrive by @codesensei-tushar in #151
- Sign the APK with the keystore password unless the key has its own by @codesensei-tushar in #181
- Send live notification events to every connected desktop by @codesensei-tushar in #182
- Give the desktop a P-256 identity and compute key fingerprints by @codesensei-tushar in #152
- Implement the pairing proofs and the SAS code, checked against the shared vector by @codesensei-tushar in #153
- Build the pairing QR code URI and describe peers by key pins by @codesensei-tushar in #154
- Dial phones over TLS 1.3 with key pinning by @codesensei-tushar in #155
- Key pairing records by fingerprint and keep them current by @codesensei-tushar in #156
- Persist pairing records, define pairing's interfaces and track QR offers by @codesensei-tushar in #157
- Pair by QR code and by SAS on the desktop by @codesensei-tushar in #158
- Test the TLS client against a stand-in phone on loopback by @codesensei-tushar in #159
- Test QR code and SAS pairing end to end over loopback TLS by @codesensei-tushar in #160
- Run desktop pairing on the session layer and race a phone's addresses by @codesensei-tushar in #161
- Add the pairing backend contract and render the QR code by @codesensei-tushar in #162
- Add the fake backend's data and pairing state machine by @codesensei-tushar in #163
- Test the fake pairing machine by @codesensei-tushar in #164
- Wrap the fake machine in a backend and expose pairing over IPC by @codesensei-tushar in #165
- Extend the desktop API with pairing and follow backend events live by @codesensei-tushar in #166
- Add the pairing context, a confirmation dialog and the address form by @codesensei-tushar in #167
- Add and style the pairing flow screens by @codesensei-tushar in #168
- Show the pairing page and the paired phone list by @codesensei-tushar in #169
- Add the runtime crate with the data directory and shared view types by @codesensei-tushar in #170
- Choose and race the addresses of a dial attempt by @codesensei-tushar in #171
- Run each phone's notifications through the core's service in a live session by @codesensei-tushar in #172
- Draw the pairing QR code and describe pairing in the runtime by @codesensei-tushar in #173
- Keep a session with each paired phone under the reconnect policy by @codesensei-tushar in #174
- Pair a phone by QR code or by comparing codes by @codesensei-tushar in #175
- Run discovery and expose the runtime to the app shell by @codesensei-tushar in #176
- Test pairing, reconnecting and mirroring over loopback TLS by @codesensei-tushar in #177
- Run the real runtime in the desktop app, keeping the scripted fake for development by @codesensei-tushar in #178
- Describe mirrored notifications for the notifications page by @codesensei-tushar in #179
- Let the notifications page list, dismiss and act on a phone's notifications by @codesensei-tushar in #180
- Test the desktop core against the phone app's TLS listener and pairing by @codesensei-tushar in #184
- Release 0.1.0 by @codesensei-tushar in #183
New Contributors
- @codesensei-tushar made their first contribution in #1
Full Changelog: https://github.com/codesensei-tushar/link2linux/commits/v0.1.0