Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 10 additions & 1 deletion .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -158,7 +158,8 @@ jobs:
sudo apt-get install -y --no-install-recommends \
build-essential meson ninja-build pkg-config gettext \
libglib2.0-dev nlohmann-json3-dev \
libgtkmm-4.0-dev libadwaita-1-dev libsecret-1-dev
libgtkmm-4.0-dev libadwaita-1-dev libsecret-1-dev \
appstream

- name: Configure and build the GUI
working-directory: app
Expand All @@ -169,3 +170,11 @@ jobs:
- name: Run the test suite
working-directory: app
run: ./build/urnetwork-tests

# app/meson.build stamps the release version and date into the metainfo
# from -Dapp_version, so this validates the GENERATED file, not the
# template. appstreamcli is the same validator Flathub gates on, and
# nothing checked this file before.
- name: Validate the AppStream metainfo
working-directory: app
run: appstreamcli validate --no-net --pedantic build/com.bringyour.network.metainfo.xml
6 changes: 3 additions & 3 deletions APPIMAGE.md
Original file line number Diff line number Diff line change
Expand Up @@ -738,11 +738,11 @@ bundling format inside a `.deb` — legitimate, but then use `/opt` + `$ORIGIN`
- **apt gets strict in 26.04, not 24.04.** apt 3.2 uses Sequoia; `apt-key` is gone;
`Signed-By` must point at a dearmored keyring in `/usr/share/keyrings`, never
`/etc/apt/trusted.gpg.d` (which would trust our key for *all* repositories).
- **Desktop-file naming**: `main.cpp:67` uses app id `network.ur.urnetwork` but the
- **Desktop-file naming**: `main.cpp:67` uses app id `com.bringyour.network` but the
desktop file is `urnetwork.desktop`. Nothing is broken today
(`StartupWMClass` covers window association), but D-Bus activation — the clean way to
deliver a `urnetwork://` URI to a running instance — requires the names to match.
Rename to `network.ur.urnetwork.desktop`.
Rename to `com.bringyour.network.desktop`.

### 10d. The recommended alternative, if the direction changes

Expand Down Expand Up @@ -903,7 +903,7 @@ working with no error anywhere — a changed type is a decode error, and a chang
in from `postinst` (IVPN's latent bug). **`install.sh` must run
`update-desktop-database` and `gtk-update-icon-cache` itself** — see the §5
callout for why this one silently passes testing and reaches users broken.
- [ ] Rename the desktop file to `network.ur.urnetwork.desktop` to match
- [ ] Rename the desktop file to `com.bringyour.network.desktop` to match
`main.cpp:67`'s app id. Harmless today, but D-Bus activation — the clean way to
hand a `urnetwork://` URI to a running instance — requires the names to match.
- [ ] Autostart via a root-owned **inert template** (`/etc/urnetwork/autostart/`) that
Expand Down
6 changes: 3 additions & 3 deletions MIGRATION.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,12 +37,12 @@ a known follow-up, do not silently pretend loopback is private.
| `/usr/lib/urnetwork/libURnetworkSdk.so` | daemon pkg | rpath `$ORIGIN` |
| `/usr/bin/urnetwork` | daemon pkg | **launcher script**, the stable `Exec=` target |
| `/lib/systemd/system/urnetworkd.service` | daemon pkg | `/lib`, in every release's load path |
| `/usr/share/applications/network.ur.urnetwork.desktop` | daemon pkg | filename **must** match `main.cpp`'s app id |
| `/usr/share/icons/hicolor/{48x48,256x256}/apps/urnetwork.png` | daemon pkg | |
| `/usr/share/applications/com.bringyour.network.desktop` | daemon pkg | filename **must** match `main.cpp`'s app id |
| `/usr/share/icons/hicolor/{48x48,64x64,128x128,256x256,512x512}/apps/com.bringyour.network.png` | daemon pkg | one 1024 master, downscaled |
| `/usr/share/urnetwork/world-110m.json` | daemon pkg | globe land outlines |
| `/usr/share/urnetwork/icons/urnetwork-tray-*.png` | daemon pkg | tray art |
| `/usr/share/locale/<l>/LC_MESSAGES/urnetwork.mo` | daemon pkg | gettext catalogs |
| `/etc/urnetwork/autostart/network.ur.urnetwork.desktop` | daemon pkg | **inert template**, GUI symlinks it |
| `/etc/urnetwork/autostart/com.bringyour.network.desktop` | daemon pkg | **inert template**, GUI symlinks it |
| `/etc/NetworkManager/conf.d/95-urnetwork.conf` | daemon pkg | `unmanaged-devices=interface-name:urnet0` |
| `/etc/udev/rules.d/85-urnetwork-unmanaged.rules` | daemon pkg | `ENV{NM_UNMANAGED}="1"` |
| `~/.local/lib/urnetwork/URnetwork.AppImage` | **user** | never packaged; must be user-writable |
Expand Down
2 changes: 1 addition & 1 deletion PLAN.md
Original file line number Diff line number Diff line change
Expand Up @@ -302,7 +302,7 @@ than being the one platform that differs.
refreshed by **dpkg triggers**, no dependency or maintainer script needed; §9.7.1
covers `x-scheme-handler/urnetwork`. ⚠️ Triggers fire only for files **dpkg**
installs, so never symlink one in from `postinst` (IVPN's latent bug). Residual:
`main.cpp:67`'s app id `network.ur.urnetwork` does not match
`main.cpp:67`'s app id `com.bringyour.network` does not match
`urnetwork.desktop`; harmless today, but D-Bus activation requires them to match.
- **R8 — GeoClue ≥ 2.7.0 is required for the location override** [confirmed]:
Ubuntu 22.04 (2.5.7) and Debian 12 (2.6.0) can **never** support it. Those users
Expand Down
93 changes: 81 additions & 12 deletions app/meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -305,30 +305,99 @@ endif
# host_integration=false (Flatpak) drops it with the rest: the GUI never calls
# polkit — the daemon does, against a subject the GUI cannot influence.
if host_integration
install_data('..' / 'packaging' / 'polkit' / 'network.ur.urnetwork.policy',
install_data('..' / 'packaging' / 'polkit' / 'com.bringyour.network.policy',
install_dir : get_option('datadir') / 'polkit-1' / 'actions')
endif

# desktop file: the filename MUST match main.cpp's app id network.ur.urnetwork
# desktop file: the filename MUST match main.cpp's app id com.bringyour.network
# (D-Bus activation requires it; APPIMAGE.md §11d)
install_data('packaging/network.ur.urnetwork.desktop',
install_data('packaging/com.bringyour.network.desktop',
install_dir : get_option('datadir') / 'applications')

# AppStream metadata — required by Flathub, read by GNOME Software / Discover
# for the .deb and .rpm too. The component id matches the .desktop basename.
install_data('packaging/network.ur.urnetwork.metainfo.xml',
# AppStream metadata — required by Flathub, read by GNOME Software / Discover.
# The component id matches the .desktop basename.
#
# THE RELEASE STAMP IS DERIVED, NOT HARDCODED. The release version is
# <YYYY>.<M>.<D>-<run>[-<suffix>]. Nothing used to write it into this file, so
# it sat at whatever was typed last while the pipeline shipped something else —
# and this element is exactly what GNOME Software, KDE Discover and the Flathub
# page display.
#
# The FULL version goes in, suffix and all: appstreamcli 1.0.2 (the version on
# the ubuntu-24.04 image CI validates on) accepts a version like
# "2026.8.16-1020679030-beta" with exit 0, so there is no reason to truncate.
# Truncating would advertise a version that matches no artifact — every other
# consumer of $VERSION (UR_APP_VERSION in both binaries, every package
# filename, the release-asset gates) uses the whole string — and would collapse
# every build of the same UTC day onto one indistinguishable release element.
#
# Only the DATE is derived, from the leading <YYYY>.<M>.<D>.
#
# NB: the .deb, .rpm and tarball do NOT ship this file. packaging/lib/common.sh's
# assemble_daemon_root() copies an explicit whitelist (desktop entry, polkit
# policy, icons) that does not include usr/share/metainfo, and make-appimage.sh
# does not package it either. The Flatpak is the only artifact that installs it,
# which is why -Dapp_version has to reach the Flatpak build.
_appver = get_option('app_version')
_av = _appver.split('-')[0]
_vp = _av.split('.')
if _vp.length() == 3 and _vp[0].to_int() > 2000
_mm = _vp[1].to_int() < 10 ? '0' + _vp[1] : _vp[1]
_dd = _vp[2].to_int() < 10 ? '0' + _vp[2] : _vp[2]
appstream_date = _vp[0] + '-' + _mm + '-' + _dd
else
# -Dapp_version was not passed (the 0.0.0 dev sentinel). LOUD on purpose: a
# document saying version="0.0.0" is perfectly valid AppStream, so neither the
# meson test below nor CI's validate step can catch it — the build log is the
# only place it can surface. A release build must never take this branch.
warning('app_version was not set, so the AppStream release stamp will say "' +
_appver + '". Pass -Dapp_version=<release version> for anything you ' +
'intend to ship; the store front reads this element.')
appstream_date = '2026-08-20'
endif

metainfo_xml = configure_file(
input : 'packaging/com.bringyour.network.metainfo.xml.in',
output : 'com.bringyour.network.metainfo.xml',
configuration : {
'APPSTREAM_VERSION' : _appver,
'APPSTREAM_DATE' : appstream_date,
},
)
install_data(metainfo_xml,
install_dir : get_option('datadir') / 'metainfo')

# hicolor icons (Icon=urnetwork in the desktop file)
install_data('packaging/icons/hicolor/48x48/apps/urnetwork.png',
install_dir : get_option('datadir') / 'icons' / 'hicolor' / '48x48' / 'apps')
install_data('packaging/icons/hicolor/256x256/apps/urnetwork.png',
install_dir : get_option('datadir') / 'icons' / 'hicolor' / '256x256' / 'apps')
# Nothing validated this file before, which is how a stale version survived in
# it. appstreamcli is the validator Flathub gates submissions on, so a bad edit
# fails here instead of in review. Optional: not every build host ships it.
appstreamcli = find_program('appstreamcli', required : false)
if appstreamcli.found()
test('appstream-metainfo', appstreamcli,
args : ['validate', '--no-net', '--pedantic', metainfo_xml])
endif

# hicolor icons (Icon=com.bringyour.network in the desktop file)
# Every size is a downscale of ONE 1024x1024 master, so they cannot drift the
# way separately-drawn assets do. Shipping only 48 and 256 meant the shell had
# to upscale for the 64px app grid and the 128/256 HiDPI lookups, which is the
# softness that showed up on a HiDPI desktop.
#
# 512 IS THE CEILING ON PURPOSE. flatpak refuses to export an icon larger than
# 512x512 -- "Image too large (1024x1024). Max. size 512x512" -- and fails the
# whole build at export time. The master is kept at
# packaging/icons/com.bringyour.network-master-1024.png for regenerating these
# and is deliberately not installed; nothing downstream asks for more than 512
# (Flathub renders the store page at up to 512).
foreach size : ['48', '64', '128', '256', '512']
install_data('packaging/icons/hicolor/' + size + 'x' + size + '/apps/com.bringyour.network.png',
install_dir : get_option('datadir') / 'icons' / 'hicolor' /
(size + 'x' + size) / 'apps')
endforeach

# autostart INERT TEMPLATE: root-owned under /etc/urnetwork/autostart/, where
# no desktop reads it; the GUI symlinks it into ~/.config/autostart atomically
if host_integration
install_data('packaging/autostart/network.ur.urnetwork.desktop',
install_data('packaging/autostart/com.bringyour.network.desktop',
install_dir : '/etc/urnetwork/autostart')
endif

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
Type=Application
Name=URnetwork
Comment=URnetwork VPN
Icon=urnetwork
Icon=com.bringyour.network
Exec=urnetwork
# TryExec self-disables this entry once the daemon package (and with it the
# launcher) is removed, so a stale symlink cannot error at every login.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
Type=Application
Name=URnetwork
Comment=URnetwork VPN
Icon=urnetwork
Icon=com.bringyour.network
# /usr/bin/urnetwork is the launcher script the daemon package installs; it
# finds the user's AppImage (search order in MIGRATION.md) and execs it with
# the same arguments. Keeping Exec= on a stable, package-managed path is what
Expand All @@ -13,7 +13,7 @@ Terminal=false
Categories=Network;Security;
Keywords=VPN;URnetwork;proxy;privacy;
StartupNotify=true
StartupWMClass=network.ur.urnetwork
StartupWMClass=com.bringyour.network
# Register the urnetwork:// scheme so OAuth/SSO callbacks and wallet deep
# links route back to the app. Shipped as a plain dpkg file so the
# desktop-file-utils dpkg trigger refreshes mimeinfo.cache automatically
Expand Down
125 changes: 125 additions & 0 deletions app/packaging/com.bringyour.network.metainfo.xml.in
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
AppStream metadata. Required by Flathub, and read by GNOME Software / KDE
Discover for every other channel too. The component id MUST equal the .desktop
basename and the GTK application id in src/main.cpp (com.bringyour.network) or
the store shows a nameless entry and D-Bus activation misses.

project_license is the CODE license (MPL-2.0). The four commercial brand
faces under assets/fonts are separately licensed and NOT MPL — they are
declared here as a non-free content attribute rather than folded into the
project license, because claiming MPL over them would be false.

SPDX-License-Identifier: MPL-2.0
-->
<component type="desktop-application">
<id>com.bringyour.network</id>

<name>URnetwork</name>
<summary>Private, decentralized VPN powered by a peer network</summary>

<metadata_license>CC0-1.0</metadata_license>
<project_license>MPL-2.0</project_license>

<developer id="ur.io">
<name>URnetwork</name>
</developer>

<description>
<p>
URnetwork routes your traffic through a decentralized network of peers
instead of a single provider's servers. Choose a country or let the app
pick the best available provider, and connect.
</p>
<p>
Provide bandwidth back to the network and earn payouts in USDC. Track
what you have provided, what you are owed, and where your network ranks.
</p>
<p>
A kill switch blocks traffic if the tunnel drops, IPv6 is closed off
rather than leaked, and DNS is pinned to the tunnel so lookups cannot
escape it.
</p>
<p>
Setup takes one extra step: URnetwork installs a small system service
that owns the network tunnel. The app detects your distribution and
shows you the exact command — a package for Debian, Ubuntu, Fedora and
other RPM distributions, or a portable installer that works anywhere
else, including immutable systems such as Silverblue and SteamOS.
</p>
</description>

<launchable type="desktop-id">com.bringyour.network.desktop</launchable>

<!-- Flathub mirrors screenshots at build time, so the URL must be reachable
from a build host; a repo-relative path does NOT work, which is why the
file is both committed here and linked by raw URL. width and height must
match the file exactly. Flathub's linter checks them, and a mismatch is a
submission failure rather than a warning, so update both if the
screenshot is ever retaken. -->
<screenshots>
<screenshot type="default">
<caption>Connected, showing live per-host activity and transport health</caption>
<image type="source" width="1600" height="970">https://raw.githubusercontent.com/urnetwork/linux/main/app/packaging/screenshots/connected.png</image>
</screenshot>
</screenshots>

<url type="homepage">https://ur.io</url>
<url type="bugtracker">https://github.com/urnetwork/linux/issues</url>
<url type="vcs-browser">https://github.com/urnetwork/linux</url>
<url type="help">https://ur.xyz</url>

<!-- Store-page accent. Taken from the app's own connected-state green and
the dark surface the UI is drawn on, so the listing matches the product. -->
<branding>
<color type="primary" scheme_preference="light">#87fb67</color>
<color type="primary" scheme_preference="dark">#101010</color>
</branding>

<categories>
<category>Network</category>
<category>Security</category>
</categories>

<keywords>
<keyword>VPN</keyword>
<keyword>privacy</keyword>
<keyword>proxy</keyword>
<keyword>decentralized</keyword>
</keywords>

<supports>
<control>pointing</control>
<control>keyboard</control>
<control>touch</control>
</supports>

<requires>
<display_length compare="ge">480</display_length>
</requires>

<!-- Explicit rather than empty: an empty element validates but reads as
"not assessed". A VPN client hosts none of the rated categories. -->
<content_rating type="oars-1.1">
<content_attribute id="social-info">mild</content_attribute>
</content_rating>

<!-- STAMPED AT BUILD TIME. app/meson.build configure_file()s this
template, deriving both attributes from -Dapp_version. Do not
hardcode a version here: the file used to say 2026.8.19 while the
pipeline shipped 2026.8.20, and this is what GNOME Software, KDE
Discover and the Flathub page read. -->
<releases>
<release version="@APPSTREAM_VERSION@" date="@APPSTREAM_DATE@">
<description>
<p>First public release of the URnetwork desktop client for Linux.</p>
<ul>
<li>Connect through the peer network, with provider selection and live status</li>
<li>Kill switch, IPv6 leak protection and DNS pinned to the tunnel</li>
<li>Provide bandwidth back to the network and track earnings</li>
<li>Authorization through polkit, so no group membership or re-login is needed</li>
</ul>
</description>
</release>
</releases>
</component>
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file not shown.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file removed app/packaging/icons/hicolor/48x48/apps/urnetwork.png
Binary file not shown.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Loading