Give the Start service caller one second to arrange its replacement and exit before retrying main IPC startup. Keep this workaround in the server startup thread and preserve the existing termination path when the retry fails.
Signed-off-by: fufesou <linlong1266@gmail.com>
* fix(windows): guard staged installer directories during handoff
Create restrictive staging directories and retain non-delete-sharing handles while CMD consumes packages, scripts and shortcuts. Adapt output paths and cleanup, and add a directory-replacement regression.
Validated with 11 focused Windows tests. Directory protection remains tied to the lifetime of the creating process.
Signed-off-by: fufesou <linlong1266@gmail.com>
* test(windows): streamline installer directory guard tests
Keep installer-file tests in their original inline module and remove the duplicate CMD-copy check from the directory replacement regression. Preserve directory protection and existing handoff coverage.
Validation: Windows library test compilation, four focused tests, rustfmt and git diff --check.
Signed-off-by: fufesou <linlong1266@gmail.com>
* fix(windows): use plain rd for empty staging directories
Remove the inapplicable /q switch from non-recursive staging-directory cleanup. Keep recursive deletion confined to the runner directory.
Validated with Windows library test compilation, four focused tests and isolated CMD probes for owner termination, nonempty staging directories and exit-code preservation.
Signed-off-by: fufesou <linlong1266@gmail.com>
* test(windows): pin installer staging directory permissions
Check effective ordinary-owner directory rights independently of the sharing guard. Clarify guard lifetime and the Rust and CMD cleanup responsibilities.
Validation: Windows library test compilation, four focused tests, rustfmt and git diff --check.
Signed-off-by: fufesou <linlong1266@gmail.com>
---------
Signed-off-by: fufesou <linlong1266@gmail.com>
get_audio_input() searched HOST.devices(), which lists input and output
devices together, and took the first device whose name matched. CoreAudio
gives a USB microphone with a headphone jack two devices with the same
name, and the output one can come first. RustDesk then picked the output
device, default_input_config() failed with StreamTypeNotSupported, and the
voice call sent no audio from the macOS side ("Failed to get default input
format" every second).
Search HOST.input_devices() instead, so only devices that support input
can match the configured or default input name.
Signed-off-by: xpehter <32315536+xpehter@users.noreply.github.com>
* fix(windows): drop the named-pipe handoff that F-Secure blocks
Since #16562 the elevated cmd.exe waited on
`set /p RUSTDESK_HANDOFF=<"\\.\pipe\rustdesk-install-<uuid>"` until the
unelevated parent released the staged files' DELETE handles. F-Secure's
behavior detection closes that cmd's end of the pipe, so installation and
Stop service fail with "The pipe is being closed. (0x800700E8)"
(ERROR_NO_DATA) and the BAT never runs (#16840, #16842).
The handles exist only to delete the staged files when UAC is cancelled.
Tampering is prevented by the DACL set at creation, which grants the
unelevated owner read/execute only, and that is unchanged. Release the
handles before launching cmd and run the BAT directly. A cancelled UAC
prompt now leaves the staged BAT and shortcut in the protected directory.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JAxkkiaGp2k8okvs4MpCUq
* docs(windows): correct the handoff comments after dropping the pipe
The cleanup handle is no longer held through the UAC prompt, and the files
stay protected by their DACLs together with the parent directory's
permissions, not by the DACL alone. Describe the F-Secure failure as what
was observed: cmd's end of the pipe closed before the release signal.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JAxkkiaGp2k8okvs4MpCUq
* fix(windows): stage installer inputs in guarded directories
Create private staging directories atomically with restrictive ACLs and retained handles that forbid delete sharing. Reuse the existing handle-based cleanup and cover BAT, shortcut and verified-update inputs with Windows regression tests.
Known limitation: terminating the RustDesk caller before CMD exits still releases the directory guards and can leave staging directories behind.
Signed-off-by: fufesou <linlong1266@gmail.com>
* fix(windows): clean up staging directories after batch execution
Remove each batch's own empty staging directories after its files, including when uninstall has terminated the Rust owner. Preserve the installer exit code and cover standalone batch cleanup with a regression test.
Signed-off-by: fufesou <linlong1266@gmail.com>
* test(windows): create protected output directory in handoff test
Exercise the production directory constructor under the retained staging-directory guard while preserving the existing elevated and unelevated assertions.
Signed-off-by: fufesou <linlong1266@gmail.com>
* test(windows): avoid protected installer fixture leftovers
Retain the production directory ACL check with native fixture cleanup. Remove the replacement and handoff tests that leave protected files after unelevated runs.
Signed-off-by: fufesou <linlong1266@gmail.com>
* revert(windows): restore installer handoff to 8ea7251e3
Restore the tracked tree to 8ea7251e35.
Remove the later guarded staging directories and cleanup/test changes,
while retaining the original direct CMD launch without a named pipe.
Reverted changes:
- 6f71c7d3a0
- a188f7b8f1
- d7fb4aff5f
- 6ace789b13
Signed-off-by: fufesou <linlong1266@gmail.com>
---------
Signed-off-by: fufesou <linlong1266@gmail.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: fufesou <linlong1266@gmail.com>
The Windows clipboard setter empties the clipboard and writes each format
in order, stopping at the first one that fails. With the marker written
last, a failure after an earlier format succeeded could leave unmarked
content on the clipboard. RustDesk could then read it back as a fresh local
copy and return it, causing the controller to empty its clipboard again.
For applications such as Excel, that destroys the application's copy state.
Write the marker first on Windows so a partial write stays identifiable
as RustDesk-owned. Other platforms keep appending it, so their payload
order is unchanged.
This covers a format failure before the marker is written, not a marker
that is written but later missing or unreadable.
Refs #16291
* fix(server): ignore spaces around IP whitelist entries
* fix(server): parse the IP and ID whitelists the same way, and fail closed
Both checks now read their option through one parser that accepts the
separators the settings dialogs accept (commas, semicolons, whitespace) and
drops empty entries. The IP whitelist split only at commas, so an entry
with a space around it, or a list from custom client settings separated by
semicolons or newlines, matched no address and locked the listed ones out.
A list is off only when the option is empty or holds only commas, which is
how the dialogs store a cleared list. Any other value without entries, such
as a lone space, now blocks every peer for the ID whitelist too, where it
used to let everyone in.
* fix(flutter): skip empty entries in the IP whitelist dialog
A leading or trailing comma gave an empty entry that the dialog rejected
as an invalid IP. Drop empty entries before the check, as the ID whitelist
dialog already does.
* fix(flutter): reject whitelist input that holds only separators
Dropping empty entries made the IP dialog save `,` or `;` as a cleared
whitelist, which turned the restriction off; before, that input failed
the IP check, and the server reads the same text as a list that allows
no one. Both dialogs now split through whitelistInputEntries, which
returns null for separator-only input, and show "Invalid IP" or "Invalid
ID" for it. Empty input and the Clear button still clear the whitelist.
* fix(flutter): keep a whitelist that lets no one in when its dialog is saved unchanged
A stored whitelist such as " , " is on but names no entry, so the server
lets no one in. Its dialog shows it as blank lines, and OK pressed
without an edit trimmed those to an empty field and saved a cleared
whitelist, lifting the restriction.
Both dialogs now take the shown text from whitelistDialogText and, when
the field is unchanged and whitelistLetsNoOneIn says the stored value
lets no one in, close without saving. Clearing the field and the Clear
button still clear the whitelist. The tests cover the load, unchanged
OK and save path for both cleared values (',' and '').
* style(flutter): drop a doubled blank line in whitelist_input.dart
* fix(ui): keep a whitelist that lets no one in when the Sciter dialog is saved unchanged
The Sciter IP whitelist dialog shows " , " as blank lines, trimmed the
submitted text before comparing it with what it showed, and so saved an
unchanged deny-all whitelist as a cleared one. The submitted text is now
compared first, as the Flutter dialogs do.
* test(flutter): name the round-trip test after the helper it checks
* fix(server): narrow the change to ignoring spaces around IP whitelist entries
As the review suggests, only the original fix stays: IP whitelist
entries are trimmed, so "192.168.1.0/24, 10.0.0.1" admits 10.0.0.1.
The ID whitelist keeps master's parsing and its "empty means allow"
behavior. The Flutter dialogs and the Sciter UI are back to master,
and the shared parse_whitelist and the dialog helpers are gone. The
trim lives in ip_whitelist_entries so that one regression test can pin
it. A whitespace-only IP whitelist still blocks everyone, as on master.
* Refactor IP whitelist entries handling and comments
Updated comments for clarity and adjusted whitespace handling in IP whitelist entries.
---------
Co-authored-by: RustDesk <71636191+rustdesk@users.noreply.github.com>
sysinfo's Cpu::frequency() is in MHz: on Linux it is scaling_cur_freq
(kHz) divided by 1000, or the "cpu MHz" line of /proc/cpuinfo, and on
macOS its documentation says MHz. get_sysinfo divided it by 1024 before
printing GHz, so a CPU at 2885 MHz showed as 2.82GHz instead of 2.89GHz
in the device info sent to the server.
Require a dedicated child success exit code so an unmatched test filter cannot pass the GUI startup regression. Replace the ACE type binding with a local constant and drop the unused SystemServices feature.
Signed-off-by: fufesou <linlong1266@gmail.com>
* Only relay to addresses this peer offered, and bound relay uuids
A RequestRelay forwarded by the rendezvous server carries the relay
address and uuid the requester filled in, and the controlled peer
dialed that address as given. A genuine controller only echoes the
relay this peer put in its own PunchHoleSent or LocalAddr, so remember
those (plus the relay this peer would pick by itself) and drop any
request that names something else, before resolving or connecting.
Relay uuids are opaque pairing keys that arrive from the network and
are sent on to the relay, so both the controlled side (RequestRelay)
and the controller (RelayResponse) now refuse ones that are empty,
longer than 128 bytes, or carry anything but ASCII alphanumerics, '-'
and '_'. This matches the check hbbs applies before forwarding.
Known limits: a WebRTC-failure fallback that follows a peer-initiated
relay whose address hbbs rewrote for the LAN is refused; a refused
request gets no reply, so the controller sees its relay attempts time
out.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JAxkkh9Gd5dwGW8vL9JNV8
* Expire reported relays after ten minutes
A relay dropped from the configuration or no longer offered by the
rendezvous server stops being an accepted RequestRelay destination once
its last report is ten minutes old. Reporting it again restarts the
clock. The list is shared by all mediators, so it is not cleared when
one starts.
The comment now says where the entries come from and that the list only
bounds where a request can send this peer; it does not authenticate the
request.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JAxkkh9Gd5dwGW8vL9JNV8
* Test relay expiry through the relay request check
The expiry tests only called the cache helpers, so a request check that
stopped honouring the expiry would still pass them. check_relay_request
now takes the time like the helpers do, and the request test asserts an
expired relay is refused and accepted again once re-reported. Passing a
later time instead of recording an earlier one avoids Instant underflow
on Windows hosts up for less than ten minutes.
Also formats this PR's own relay check and expiry tests with rustfmt.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JAxkkh9Gd5dwGW8vL9JNV8
---------
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
* fix(lang): pick Hebrew and Indonesian from legacy Android locale codes
The Android service translates its notifications and floating window
menu with Locale.getDefault().toString(). Android's Locale reports
Hebrew and Indonesian with their legacy ISO 639 codes, iw_IL and in_ID,
unless both the device and the app's target SDK are Android 15 or
later. resolve_lang took "iw" and "in" as language codes, found no
table, and fell back to English.
Map "iw" to "he" and "in" to "id", next to the Kazakh and Georgian
mappings.
* fix(lang): say which Android versions report the legacy codes
* fix(ipc): authenticate Windows named pipe servers
Restrict main and service pipe instance creation and authenticate the
connected server before exchanging IPC data. Open clients with data access
that excludes FILE_CREATE_PIPE_INSTANCE.
Require SYSTEM ownership for service channels. For main IPC, also accept a
same-user server with a restricted DACL, matching session and executable,
and sufficient elevation. This includes the UI hosting main IPC while the
service is unavailable, without relying on installation or service config.
Elevated clients reject non-elevated servers, and SYSTEM clients reject
user-owned pipes. New clients reject old permissive listeners until those
processes restart on the fixed version.
Add native Windows regression tests for instance-creation permissions,
DACL rejection before application data, and normal client communication.
Signed-off-by: fufesou <linlong1266@gmail.com>
* refactor(ipc): clarify Windows pipe security policy
Signed-off-by: fufesou <linlong1266@gmail.com>
* test(ipc): bound the Windows server rejection test
Signed-off-by: fufesou <linlong1266@gmail.com>
* test(ipc): bound the complete Windows client communication test
Signed-off-by: fufesou <linlong1266@gmail.com>
* fix(windows): keep portable GUI alive on IPC startup failure
Only attempt GUI fallback hosting when the main IPC pipe is absent. Bind its listener before marking hosting active or starting rendezvous, and return on bind failure without terminating the GUI.
Preserve IPC authentication and explicit server-process behavior. Cover rejected listeners, bind collisions, and standalone IPC communication with Windows regression tests.
Signed-off-by: fufesou <linlong1266@gmail.com>
* refactor(windows): simplify portable IPC startup fallback
Rely on exclusive listener creation instead of a separate pipe-presence probe. Keep GUI bind failures recoverable and require a successful bind before starting host services.
Retain the subprocess regression for bind-failure process survival, removing redundant GUI tests and their helper parameters and delay.
Signed-off-by: fufesou <linlong1266@gmail.com>
---------
Signed-off-by: fufesou <linlong1266@gmail.com>
* fix(port-forward): keep the KCP handle alive and send a close reason
A port forward whose connection was won by a UDP punch (KCP) died right
after login. `Client::start` returns, next to the stream, the KCP handle
that drives the stream's UDP I/O, and both login functions dropped it on
return, so the stream failed with "stream closed" on first use. The handle
now goes with the stream to whichever task owns it: the raw pipe's task,
`run_legacy`'s task, or `tunnel_loop`.
Closing such a stream needs care as well. KCP's FIN is sent by the
handle's own tasks and dies with the handle, so the peer would hold the
connection until its own timeout. A KCP tunnel closed from this side now
sends a close reason first, as the remote session does. The port-forward
window's io_loop passes Close on to every mapping and waits 100ms before
its runtime is dropped, so the tunnels get to send it; a login that
receives the Close now ends instead of swallowing it.
Known limits: the raw pipe (a peer without mux) cannot carry a close
reason after `set_raw`, and exits during login send none.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* docs(port-forward): say what the close-reason send bound covers
The bound on sending the close reason keeps that step inside the window's
wait, but a data send already in flight in another arm of `tunnel_loop` is
not bounded by it and holds the close until it returns. The comment said
the whole close fit; say which part does.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
The LaunchDaemon ran `/bin/sh -c .../Contents/MacOS/service`, so macOS
attributes the background item to /bin/sh: Login Items shows "sh", and
AssociatedBundleIdentifiers cannot link it to the app because the
launched executable is not signed by the app's team. Start the signed
service binary itself.
sh exec'd the single command anyway, so the running process is the
same. App names are limited to letters, digits, '-' and '_', so the
path never needed shell parsing.
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
* fix(windows): support secure installer temp junctions
Preserve Windows Temp when persistent ACLs are available, validate resolved junction targets, and fall back to ProgramData only when the target volume lacks ACL support. Guard parent directories while creating protected installer files and cover the Windows sharing behavior with regression tests.
Refs rustdesk/rustdesk#16841
Signed-off-by: fufesou <linlong1266@gmail.com>
* fix(windows): simplify installer temp junction fallback
Signed-off-by: fufesou <linlong1266@gmail.com>
* test(windows): cover installer staging path selection
Signed-off-by: fufesou <linlong1266@gmail.com>
---------
Signed-off-by: fufesou <linlong1266@gmail.com>
* fix(lang): correct typos in the Indonesian translation
Fix misspellings such as "kd", "halam", "ketik", "kostum" and
"kadaluwarsa", and the capitalization of "Anda" and "kamu" in the
middle of a sentence. Keys and placeholders are unchanged.
Signed-off-by: deagus <dedeaskyt121@gmail.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* fix(lang): translate the Indonesian elevation username hint
The value was "panduan_elevasi_nama_pengguna", a translated copy of the
key rather than a sentence, and it showed as the hint of the username
field in the elevation dialog. Translate the English text instead. The
double backslash is a literal one, as in en.rs.
Signed-off-by: deagus <dedeaskyt121@gmail.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
---------
Signed-off-by: deagus <dedeaskyt121@gmail.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
#16827 made FrameRaw copy each frame while the Image is still valid, and
then copy it a second time into the capturer in take(). Swap the owned
buffer into dst instead: both callers own dst and only read it until
their next call, so the two buffers alternate and take() holds the lock
for constant time. A taken frame is copied once, as before #16827.
Release the buffer whenever capture is enabled or disabled. FrameRaw is
global, so it would otherwise keep a full frame after capture stops.
Note why the would_block_if_equal check never fires, so that nobody
revives it by accident.
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Flutter 3.44's Material 3 TextButton gives icons inside it an 18px default
(3.24.5 has none, so they stay 24px). The approval row sits in a TextButton,
so under M3 on 3.44 its arrow renders at 18px while the inset is computed
for 24px, and the test's ThemeData() case fails by 3px on the macOS arm64
job, which runs the Dart tests on 3.44. The app sets useMaterial3: false,
where neither version shrinks the icon; the three M2 cases still pin the
alignment and pass on both 3.24.5 and 3.44.9.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Every portal handshake failure is tagged and gets its own message, so the
untagged errors that still reach this fallback at login are internal ones
(GStreamer init, a poisoned lock). Reporting them as "x11 expected" sent
users off to switch to X11 for faults X11 does not fix, and hid the real
error. Send the error itself, as the Ubuntu 21+ branch already does.
No regression test: CI runs on Ubuntu 24.04, where map_err_scrap takes the
Ubuntu branch and returns the raw error both before and after this change.
Refs #16829
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
O FrameRaw guardava apenas o ponteiro do ByteBuffer do Image recebido via
JNI. O Kotlin fecha o Image logo após onVideoFrameUpdate, devolvendo o
buffer ao ImageReader; quando a thread de vídeo chamava take(), o
SurfaceFlinger já podia estar desenhando o quadro seguinte no mesmo
buffer, gerando regiões pretas/parciais na imagem remota em qualquer codec
(visível em Android x86, ex.: Bliss OS 13 em Intel UHD).
Agora update() copia o quadro para um buffer próprio enquanto o Image
ainda é válido, e take() copia desse buffer. O áudio usa a mesma
estrutura e passa a ter a mesma garantia.
* feat: add connections without sending passwords
Add Without password actions and pass the selection through desktop,
mobile and Web sessions. Omit the password when constructing LoginRequest,
preserve saved credentials, and reuse the existing approval and OS login
dialogs. Keep protocol and controlled-side authentication changes separate.
* fix: preserve login method across session windows
* fix: skip password persistence for consent connections
* refactor: unify request approval menus and naming
* chore: move request approval translation key to the end
* i18n: translate request approval menu label
* fix: align request approval menu layout and icons
* fix: avoid duplicate focus stops in request approval menus
* fix: distinguish request approval submenus on mobile
* fix: open overflowing submenus to the left
* Revert "fix: distinguish request approval submenus on mobile"
This reverts commit 7f0e50d4e4.
Update the text for "Forget Password" to "Clear saved password" to avoid confusion with password recovery. Both Flutter and legacy Sciter UIs use this key and share the updated translations.
Keep the existing translation key, UI calls, and password-clearing behavior unchanged. Leave Italian translations untouched.
Signed-off-by: mblbr <150243082+mblbr@users.noreply.github.com>
The iOS launch screen and the Flutter view controller's storyboard both
hard-coded a pure white background, so the app flashes bright white on
every cold start, even in dark mode. Use systemBackgroundColor so the
launch/loading screen is black in dark mode and white in light mode.
* fix(ci): build macOS arm64 with Flutter 3.44
Flutter 3.24.5's macOS engine can crash in attributedSubstringForProposedRange
with an out-of-bounds range on an empty string (#16817). The fix
(flutter/flutter#153157) landed after 3.24 and was never cherry-picked, and
3.44 has the bounds check. So macOS arm64 now builds with Flutter 3.44.9, the
same way Windows arm64 does: the 3.44 bridge artifact and the shared source
patch script. The script uses GNU `sed -i`, which BSD sed on macOS rejects,
so the step puts GNU sed first on PATH. The 3.24 dropdown patch is skipped,
because 3.44 already has that fix.
macOS x86_64 stays on 3.24.5: 3.44's FlutterMacOS needs macOS 10.15 there,
and the build targets 10.14. The Dart tests move to the x86_64 job, so CI
still runs them against the 3.24.5 sources that most platforms ship.
Refs #16817
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* fix(ci): keep CocoaPods on macOS arm64 and run Dart tests on both arches
Flutter 3.44 turns on Swift Package Manager by default. On the first
`flutter build macos` it would migrate Runner.xcodeproj and Runner.xcscheme,
and build file_selector_macos, path_provider_foundation, url_launcher_macos
and video_player_avfoundation through SwiftPM while the other 12 plugins stay
on CocoaPods. If the migration fails, the build fails. All 16 macOS plugins
still ship a podspec, so turning SwiftPM off keeps arm64 on the CocoaPods-only
path the 3.24.5 build uses, and this change only swaps the engine.
The Dart tests now run on both macOS jobs: x86_64 covers the 3.24.5 sources
most platforms ship, and arm64 covers the patched 3.44 sources it ships.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* ci: update comments that still call Windows arm64 the only Flutter 3.44 build
The FLUTTER_WINDOWS_ARM_VERSION note, the Windows source-patch step and the
header of apply_flutter_3.44_source_patches.sh still said Windows arm64 is
the only Flutter 3.44 target. They now mention macOS arm64 too, and the
script header records that macOS needs GNU sed for its `sed -i` calls.
Comments only.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* test: make test_RustDesk_interval_sleep deterministic
The test recorded tick times as wall-clock seconds, rounded to the nearest
second, and asserted all 5 were unique. If the runner stalled for close to a
second, two correct ticks rounded to the same value and the test failed
(macOS arm64 CI on #16821: left 5, right 4).
It now runs on tokio's paused clock and checks what ThrottledInterval
guarantees: ticks are at least 0.9 * period apart. A plain tokio interval
bursts its missed ticks with no gap, so a lost throttle still fails. This
needs tokio's test-util feature for the existing dev-dependency. It adds no
crates, so Cargo.lock is unchanged.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
* Limit oversized remote clipboard text on Android
* Add write permission
* Increase MAX_CLIPBOARD_TEXT_CODE_UNITS to 1MB
* fix: revert unrelated workflow permission changes
* fix(android): address review feedback on clipboard size and exception handling
- Replace UTF-16 character count check with a serialized Parcel size check capped at 800 KB, leaving headroom for Android Binder transaction overhead.
- Wrap setPrimaryClip() in a try-catch to safely absorb direct and runtime-wrapped Binder exceptions (e.g. TransactionTooLargeException) without crashing.
- Assign lastUpdatedClipData only after a successful clipboard write to preserve consistent synchronization bookkeeping on failure.
Fill install-directory-not-empty-tip (added in #16783) for every
language, including it.rs at the maintainer's request.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* fix(windows): warn before removing installation directory
Signed-off-by: fufesou <linlong1266@gmail.com>
* fix(windows): show inline installation directory warning
Signed-off-by: fufesou <linlong1266@gmail.com>
* refactor(windows): simplify installation directory warning
Key the warning widget by its path and remove the optional widget test suite.
Signed-off-by: fufesou <linlong1266@gmail.com>
* fix(windows): limit installation warnings to the selected directory
Share install-directory-not-empty-tip between inline and confirmation warnings, and remove the separate previous-installation warning.
Signed-off-by: fufesou <linlong1266@gmail.com>
* fix(windows): skip directory warnings when reinstalling in place
Signed-off-by: fufesou <linlong1266@gmail.com>
---------
Signed-off-by: fufesou <linlong1266@gmail.com>
* Clarify auto login requirements in Portuguese
Updated the auto login message to clarify requirements.
* Fix translation for terminal admin login tip
Updated the translation for the terminal admin login tip in Portuguese.
res/job.py sign_files exited 0 when a file was left unsigned: a sign
task that never reached "done" only broke out of the current directory,
and a failed download of the signed file was ignored, keeping the
unsigned original in place. Both now exit non-zero, so the Windows
signing steps fail the job.
Retry requests.get/post on connection-level errors with the same wrapper
the signing service's client uses, rewinding upload streams before each
retry. Tunable via HTTP_RETRY_MAX_TRIES and HTTP_RETRY_SLEEP_SECS.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* fix: restore readiness after service restart and macOS update
Wake rendezvous retry waits when a manual restart is requested. For app-only macOS updates with an in-process backend, wait for the old process to exit before relaunching the updated app so it cannot attach to the departing backend.
Signed-off-by: fufesou <linlong1266@gmail.com>
* test: cover service restart and macOS update readiness
Signed-off-by: fufesou <linlong1266@gmail.com>
* test: remove macOS relaunch script regression test
Signed-off-by: fufesou <linlong1266@gmail.com>
* docs: explain macOS update relaunch ordering
Signed-off-by: fufesou <linlong1266@gmail.com>
* fix: isolate macOS update relaunch process group
Signed-off-by: fufesou <linlong1266@gmail.com>
* docs: clarify macOS relaunch process group isolation
Signed-off-by: fufesou <linlong1266@gmail.com>
* fix: clarify macOS update restart failure
Signed-off-by: fufesou <linlong1266@gmail.com>
---------
Signed-off-by: fufesou <linlong1266@gmail.com>
* Build Windows custom client packers in CI
Verify payload signatures, build templates for all three Windows architectures, and include the packers in the unsigned release archive.
Signed-off-by: fufesou <linlong1266@gmail.com>
* fix(ci): preserve unsigned Windows releases without signing
Signed-off-by: fufesou <linlong1266@gmail.com>
* fix(ci): align template packer DPI manifests
Signed-off-by: fufesou <linlong1266@gmail.com>
---------
Signed-off-by: fufesou <linlong1266@gmail.com>
* fix(ios): adopt the UIScene life cycle
UIKit refuses to launch an app linked against the iOS 27 SDK that has
not adopted the UIScene life cycle: it traps in
_UIApplicationEvaluateRuntimeIssueForNoSceneLifecycleAdoption with
"UIScene life cycle is required for apps built with this SDK". 1.5.1
(69) is the first build made with Xcode 27.1, so it crashes at launch on
every iOS 27 device.
Flutter 3.24.5 has no FlutterSceneDelegate, so add a minimal one:
- Info.plist declares a single-scene manifest that loads Main.storyboard.
- SceneDelegate hands the storyboard window to AppDelegate when the
scene connects. FlutterAppDelegate finds the engine for plugin
registration through its window, which no longer exists in
didFinishLaunching, so registration moves there.
- The launch URL now arrives in the scene connection options and later
URLs in scene(_:openURLContexts:). Forward both to plugins through the
app delegate callbacks uni_links listens on, so rustdesk:// links keep
working on cold and warm start.
Verified on the iOS 27.1 simulator with a Flutter 3.24.5 app that has
the same Runner setup: the app launches, plugin channels respond, the
initial link and stream links arrive, and lifecycle states reach Dart.
Fixes#16766
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* fix(ios): drive the status bar from the view controller under UIScene
With UIViewControllerBasedStatusBarAppearance=false, Flutter 3.24.5 hides
and styles the status bar through the app-level UIApplication setters.
UIKit ignores those once the app uses the UIScene life cycle, so
SystemChrome.setEnabledSystemUIMode(manual, overlays: []) no longer hides
the status bar during a remote session.
Set the key to true so Flutter goes through FlutterViewController's
prefersStatusBarHidden / preferredStatusBarStyle instead. Checked on the
iOS 27.1 simulator in scene mode: hiding, showing again and the light
overlay style all take effect. The Dart side only uses SystemChrome, so
it does not depend on this key.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
* build_fdroid.sh: Revert unnecessary sed un-bracing
Claude has identified the issue but optimized stuff blindly:
the fact that F-Droid recipe for RustDesk 1.4.9 abused the sed
instruction does not mean it will be abused continuously, nor
that it should be abused (and fixed).
Signed-off-by: Vasyl Gello <vasek.gello@gmail.com>
* build_fdroid.sh: do not attempt applying dropdown patch on 3.44.0+
Signed-off-by: Vasyl Gello <vasek.gello@gmail.com>
* Disable lockfile enforcement for now
Signed-off-by: Vasyl Gello <vasek.gello@gmail.com>
---------
Signed-off-by: Vasyl Gello <vasek.gello@gmail.com>
* fix(web): preserve peer card clicks with semantics enabled
Give the More menu semantic tap and double-click actions, and expose multi-selection through separate checkboxes. Exclude redundant outer desktop web tap semantics while preserving card-body double-click connections.
Cover mouse single/double clicks and semantic activation under the parent card gesture detector.
Signed-off-by: fufesou <linlong1266@gmail.com>
* fix(web): reuse accessible More control in portrait cards
Signed-off-by: fufesou <linlong1266@gmail.com>
* fix(web): keep peer More taps immediate and cancellable
Signed-off-by: fufesou <linlong1266@gmail.com>
* fix(web): keep keyboard wrapper out of accessibility focus
Signed-off-by: fufesou <linlong1266@gmail.com>
---------
Signed-off-by: fufesou <linlong1266@gmail.com>