The UI shells out to xdg-open at runtime to open links and reveal
files in the file manager, but neither the deb nor the rpm declared
xdg-utils, so it could be missing on minimal installs. The package
is named xdg-utils on Debian/Ubuntu, Fedora and OpenSUSE alike.
Hardcoded RPM dependency names (gtk4, webkitgtk6.0) only exist on
Fedora; OpenSUSE names them libgtk-4-1 / libwebkitgtk-6_0-4, so the
shared RPM failed to install there with a missing webkitgtk6.0 error.
Depend on the soname capabilities the ELF auto-generates instead
(libgtk-4.so.1, libwebkitgtk-6.0.so.4), which every distro that
ships these libraries Provides, so a single RPM resolves on Fedora,
OpenSUSE and RHEL 10 (EPEL) alike.
Route services.Session errors through the same classifier Connection
uses so RequestExtend/WaitExtend return a structured ClientError with a
clean localized short message instead of the raw daemon error. Extract
the shared errorClassifier into errors.go, and fall back to the gRPC
status code when no message substring matches, since the daemon now
forwards a clean desc without the English marker text.
The daemon wrapped the management ExtendAuthSession error through two
%v/%w layers and remapped it to codes.Internal, so the UI surfaced the
full wrapped chain instead of the root cause. Forward only the innermost
gRPC status (original code + clean desc) to the client and log the full
chain. gstatus.FromError does not unwrap, so add innermostStatus to walk
the %w chain.
Resolve conflicts and complete the profile display-name -> ID migration
across the daemon, CLI, UI services, tray, and React frontend.
- Regenerate client/proto daemon.pb.go from the merged proto so it carries
both branches' RPCs (ui-refactor: SubscribeStatus/RegisterUILog/ExtendAuthSession,
main: RenameProfile + id fields); keep the v6.33.1 generator header
- server.go: combine ui-refactor's profile-list-changed events with main's
id-bearing responses; publish profile-list-changed on rename
- Drop the deleted Fyne client_ui.go/profile.go and port main's profile-ID
changes into the refactored services/tray
- UI services, tray and React: send the profile ID as the daemon handle and
keep the display name for rendering only (activeProfileId vs activeProfile)
- Relax the profile-name input to match the daemon's sanitizeDisplayName
(spaces, emoji, any valid UTF-8); cap at 128
- Expose RenameProfile via a Profiles.Rename services wrapper (+ regenerated
bindings) for the frontend to wire up
- cmd/login.go: use the profile ID for GetProfileState
* Migrate to profile ids
* Migrate android profile manager
* Clean up
* Fix review
* Add ID type
* Fix test and runes in ShortID()
* Fix profile switch on up and android comments
* Revert android profile to string id
* Fix feedback
* Fix UI feedback
* Fix id assignment
* Add renaming of profiles
* Fix review
* Remove ui binary
* Fix getProfileConfigPath not validating id
* Change resolve handle order and fix server merge problems
* Fix mdm test
- introduce variables to avoid publishing latest docker tags and installers
- Refactor .goreleaser.yaml to simplify docker configurations and add environment-driven flags
- removed management debug containers (it was doing only log var)
- Stopped building arm v6 32bits in favor of v7 32 bits for services (not client)
- Add target argument to docker files
* [client] fix iOS route-update reordering that black-holed IPv6 on exit-node disable
On iOS the route notifier delivered each prefix update from its own
fire-and-forget goroutine (notify -> `go func`), so Go provided no ordering
guarantee between consecutive updates. It also read currentPrefixes inside
that goroutine without holding the lock, racing the next OnNewPrefixes write.
On exit-node disable the core removes the default routes as two separate
prefix updates (0.0.0.0/0, then the synthesized ::/0). When the two
goroutines were reordered, the stale snapshot still containing ::/0 was
delivered last and clobbered the correct default-free one. iOS then kept the
::/0 default route on the tunnel with no exit node to carry it, black-holing
all IPv6 traffic while IPv4 recovered correctly.
Fix: deliver updates through a single worker goroutine fed by a buffered
channel, preserving production order, and snapshot the joined prefix string
under the mutex so it can't race a concurrent update. Buffered so producers
(which run under the route manager lock) don't block on the listener callback.
* [client] close iOS notifier delivery goroutine on Stop, unbounded queue
The delivery goroutine was never stopped, leaking on every engine
restart. Add Notifier.Close, called from the route manager Stop after
routing cleanup.
Replace the buffered update channel with a cond-driven linked-list
queue so route-update producers (running under the route manager lock)
never block when the listener callback is slow.
The _other.go fallback stubs in client/ui and client/ui/services matched
FreeBSD, dragging the Wails-importing services package into the FreeBSD
build and failing it (Wails v3 has no FreeBSD port). Add !freebsd (plus
!android/!ios/!js) to align them with the rest of these packages so the
whole UI is excluded on FreeBSD.
The daemon SetConfig only persisted the lazy connection flag to the
profile config; the running engine was untouched, so a UI/CLI change
took effect only after a down/up or daemon restart.
Wire SetConfig to push the change into the running engine via a new
ConnMgr.SetLocalLazyConn, which sets enabledLocally like an env/CLI
flag so a later management sync cannot override it, and starts or
stops the lazy manager in place.
Add a no-op WailsUIReady RPC the UI probes once at startup. A reachable
daemon that returns Unimplemented predates this UI and is too old to
drive it; the probe distinguishes that from an unreachable daemon. On an
outdated daemon the UI fires a localized OS notification, since the main
window may not open to show an in-app error.
Proto regenerated with protoc 33.1 to keep the v6.33.1 header.
tray_theme_other.go references Tray but its build tag selected it on
FreeBSD, where tray.go (which defines Tray) is excluded via !freebsd.
Add the same !android && !ios && !freebsd && !js exclusions to the stub.
Expose a network-free login-required check backed by the in-memory status
recorder. Unlike IsLoginRequired(), which creates a fresh auth client and
performs a blocking network call, IsLoginRequiredCached() reports whether the
LAST observed management error was an auth failure (PermissionDenied/
InvalidArgument).
This lets the iOS connection listener detect a mid-session token expiry from
within onDisconnected during teardown without blocking on a slow or
unavailable network.
* Add iOS debug bundle support in Go
Thread cacheDir through NewClient -> RunOniOS -> MobileDependency.TempDir
so the iOS client can pass its sandbox-writable cache directory for
debug bundle zip file creation instead of os.TempDir().
Move log collection into platform-dispatched addPlatformLog():
- iOS: adds the file-based Go client log (with rotation, stderr/stdout
companions and anonymization handled by addLogfile) plus the Swift app
log (swift-log.log) written by the iOS app into the same log directory
- Other non-Android platforms: existing file-based log + systemd fallback
Narrow the debug_nonandroid.go build tag to !android && !ios so iOS no
longer attempts the systemd journal fallback.
Add a DebugBundle() entry point to the iOS Go client that generates a
bundle, uploads it and returns the upload key. It works with or without
a running engine: when the engine is up it reuses the live config, sync
response and client metrics; otherwise it loads the config from disk (or
the preloaded tvOS config). Guard the live config/ConnectClient behind a
state mutex since DebugBundle may run on a different thread.
* Include the iOS state file in the debug bundle
addStateFile() resolved the state path via ServiceManager.GetStatePath(),
which on iOS points at a hard-coded default that does not exist in the app
sandbox, so the state file was silently skipped.
Add an optional StatePath to GeneratorDependencies and use it when set,
falling back to the ServiceManager default otherwise. The iOS DebugBundle
passes the client's actual state file path (the App Group profile state),
matching the Android bundle which includes the state file.
* ios: enable sync response persistence for debug bundle
Turn on sync response persistence before starting the engine so
DebugBundle can include the network map. On iOS the store is disk-backed
(see syncstore) to keep the map out of the constrained process memory.
* ios: pass log file path through NewClient constructor (#6393)
Add logFilePath field to Client struct and expose it as a parameter
in NewClient so callers provide the Go log path at construction time.
Wire it into DebugBundle via GeneratorDependencies.LogPath so the
debug bundle includes client.log and swift-log.log regardless of
whether the bundle is triggered by the app or the management server.
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
* ios: pass log file path to engine for remote debug bundles
RunOniOS started the engine with an empty LogPath, so EngineConfig.LogPath
was never set. Management-triggered (jobs) debug bundles read the log path
from the engine config, so they collected no client logs (client.log,
rotated logs, swift-log.log). The GUI path was unaffected because it passes
c.logFilePath directly to the bundle generator.
Thread c.logFilePath through RunOniOS into the engine config so remote
bundles include the client logs too.
---------
Co-authored-by: evgeniyChepelev <68751844+evgeniyChepelev@users.noreply.github.com>
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
The daemon runs as SYSTEM and writes the bundle into C:\Windows\SystemTemp,
whose ACL denies the logged-in user, so a plain 'explorer /select' could not
open it. The Windows reveal now elevates via ShellExecuteW with the runas verb,
falling back to an unelevated reveal of the parent dir on decline.