Commit Graph
11641 Commits
Author SHA1 Message Date
fufesou 2228db8a10 fix(windows): retry service IPC before terminating the GUI (#16913)
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>
2026-11-08 16:17:26 +08:00
fufesou 78450f4987 Fix/windows installer directory guard (#16908)
* 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>
2026-11-08 13:06:43 +08:00
xpehter 3513c9751d fix(audio): look up the named audio input among input devices only (#16906)
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>
2026-11-07 11:00:14 +08:00
f4c0b13df7 fix(windows): drop the named-pipe installer handoff that F-Secure blocks (#16889)
* 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>
2026-11-07 00:11:18 +08:00
bovirus cd2e41383b Update ialian language (#16896) 2026-11-06 17:13:32 +08:00
Minh Nguyen 8d74ff0e57 fix(windows): write the clipboard owner marker first (#16695)
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
2026-11-06 17:11:02 +08:00
fufesou 9382ab2607 fix: ci (#16890)
Signed-off-by: fufesou <linlong1266@gmail.com>
2026-11-06 14:17:10 +08:00
LukasandRustDesk fdffc37bb0 fix(server): ignore spaces around IP whitelist entries (#16692)
* 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>
2026-11-06 10:00:54 +08:00
Lukas f2c16e1e20 fix: report the CPU frequency in GHz with /1000, not /1024 (#16887)
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.
2026-11-06 09:34:00 +08:00
fufesou 91e43e24ea fix: clarify unlimited trusted-device duration (#16886)
Signed-off-by: fufesou <linlong1266@gmail.com>
2026-11-06 09:30:31 +08:00
fufesou cbde394666 fix(windows): address IPC review follow-ups (#16885)
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>
2026-11-05 23:43:54 +08:00
RustDeskandClaude Opus 5.5 2c085f91db Only relay to addresses this peer offered, and bound relay uuids (#16858)
* 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>
2026-11-05 23:42:38 +08:00
Lukas 78742bcd31 fix(lang): pick Hebrew and Indonesian from legacy Android locale codes (#16882)
* 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
2026-11-05 22:55:53 +08:00
fufesou 83e508cfdf Fix/windows ipc server auth (#16755)
* 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>
2026-11-05 22:35:07 +08:00
RustDeskandClaude Opus 5.5 7b5540bd61 fix(port-forward): keep the KCP handle alive and send a close reason (#16880)
* 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>
2026-11-05 21:39:53 +08:00
RustDeskandClaude Opus 5.5 1d828eee7a fix(macos): launch the service daemon directly instead of through sh (#16879)
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>
2026-11-05 16:44:21 +08:00
fufesou 13cccb2f7b Fix/windows installer temp junction (#16871)
* 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>
2026-11-05 15:52:35 +08:00
fufesou 79c63639ea refact(ci): update, metadata, nightly (#16868)
Signed-off-by: fufesou <linlong1266@gmail.com>
2026-11-05 15:06:53 +08:00
deagusandClaude Opus 5.5 6ef56d779f fix(lang): correct typos in the Indonesian translation (#16875)
* 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>
2026-11-05 14:37:47 +08:00
RustDeskandClaude Opus 5.5 55786aaa57 perf(android): hand the captured frame over instead of copying it again (#16835)
#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>
2026-11-03 12:26:12 +08:00
rustdeskandClaude Opus 5.5 661befbb6d test: drop the Material 3 case from the approval arrow alignment test
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>
2026-11-03 11:35:37 +08:00
rustdesk df529f149a remove CLAUDE.md 2026-11-03 11:19:11 +08:00
RustDesk 47740e8fd7 Update reference from AGENTS.md to @AGENTS.md 2026-11-03 11:16:03 +08:00
rustdeskandClaude Opus 5.5 beeeef14f0 fix(wayland): pass on an unclassified capture error instead of "x11 expected"
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>
2026-11-03 08:26:06 +08:00
Victor Lamers 41f182e636 fix(android): copy captured frames before the Image is released (#16827)
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.
2026-11-03 08:15:44 +08:00
21pages a85ad89ffc feat: request approval (#16784)
* 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.
2026-11-02 23:48:27 +08:00
mblbr 037b8787fe Clarify that "Forget Password" clears the saved password (#16826)
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>
2026-11-02 23:47:00 +08:00
MikeO7 6aec3069ae fix(ios): follow system dark mode on launch screen (#16816)
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.
2026-11-02 22:34:48 +08:00
RustDeskandClaude Opus 5.5 4ec4ec3d14 fix(ci): build macOS arm64 with Flutter 3.44 (#16821)
* 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>
2026-11-02 22:15:54 +08:00
fufesou 29d1ab26a1 fix(sciter): avoid double DPI scaling of main window minimum size (#16824)
Signed-off-by: fufesou <linlong1266@gmail.com>
2026-11-02 22:15:10 +08:00
ignat10 f9586e1714 fix(android): prevent crash on large clipboard payload (>1MB) (#16767)
* 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.
2026-11-02 12:14:30 +08:00
rustdeskandClaude Opus 5.5 23e5bb471a finish translations
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>
1.5.1
2026-11-01 13:50:20 +08:00
fufesou 82301f1776 Fix/windows install directory confirmation (#16783)
* 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>
2026-11-01 13:39:54 +08:00
Maison da Silva fa611556f8 Clarify auto login requirements in Portuguese (#16792)
* 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.
2026-11-01 13:39:33 +08:00
fufesou c5201d600b Allow trusted devices for direct IP connections (#16778)
* Allow trusted devices for direct IP connections

Signed-off-by: fufesou <linlong1266@gmail.com>

* test: preserve existing V2 trusted-device credentials

Signed-off-by: fufesou <linlong1266@gmail.com>

---------

Signed-off-by: fufesou <linlong1266@gmail.com>
2026-11-01 13:39:15 +08:00
rustdeskandClaude Opus 5.5 94c321d05c fix(ci): fail Windows signing on error and retry transient HTTP failures
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>
2026-10-31 23:13:40 +08:00
fufesou 3b7e2cebd9 fix: restore readiness after service restart and macOS update (#16780)
* 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>
2026-10-31 19:59:06 +08:00
fufesou eab27cc249 Build Windows custom client packers in CI (#16781)
* 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>
2026-10-31 15:40:32 +08:00
RustDeskandClaude Opus 5.5 0d6265bb26 fix(ios): adopt the UIScene life cycle (#16776)
* 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>
2026-10-31 10:11:24 +08:00
Vasyl Gello 33a154a5d7 Fix F-Droid 1.5.0 build by disabling lockfile enforcement (#16673)
* 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>
2026-10-30 22:06:37 +08:00
rustdesk ef827fdb34 update ios minver 2026-10-30 16:30:09 +08:00
Joel Town Road cda3847337 Strip all whitespace from pasted IDs, not only spaces (#16762) 2026-10-30 10:05:56 +08:00
fufesou e1ca09766c refact(update): change the pub key for metadata (#16758)
Signed-off-by: fufesou <linlong1266@gmail.com>
2026-10-30 02:29:40 +08:00
rustdesk 0aaf3a02bf finish translations 2026-10-29 23:15:12 +08:00
fufesou eba0a6e552 fix(web): preserve peer card clicks with semantics enabled (#16709)
* 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>
2026-10-29 19:30:58 +08:00
Raz AsheriandRustDesk 3cb027a372 Update Hebrew translation (#16690)
* Add missing Hebrew translations

Signed-off-by: Raz Asheri <37867699+RazAsheri@users.noreply.github.com>

* Fix a few Hebrew translations

Signed-off-by: Raz Asheri <37867699+RazAsheri@users.noreply.github.com>

* Fix wording for fullscreen toggle

Signed-off-by: Raz Asheri <37867699+RazAsheri@users.noreply.github.com>

---------

Signed-off-by: Raz Asheri <37867699+RazAsheri@users.noreply.github.com>
Co-authored-by: RustDesk <71636191+rustdesk@users.noreply.github.com>
2026-10-29 11:02:20 +08:00
Maison da Silva 5217f32a12 Improve Portuguese translations in pt_BR.rs (#16752)
Updated Portuguese translations for API server tips and RustDesk storage.
2026-10-29 10:11:04 +08:00
VenusGirl❤ c8cb6fb509 Update ko.rs (#16749)
* Update ko.rs

Update Korean

* Fix Korean translation

Update Korean
2026-10-29 10:00:55 +08:00
Ricardo Simõesandgreptile-apps[bot] df9df7e914 Update pt_PT.rs (#16748)
* Update pt_PT.rs

* Update src/lang/pt_PT.rs

Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com>

* Update src/lang/pt_PT.rs

fixed "dispostivos" typo

Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com>

---------

Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com>
2026-10-29 10:00:45 +08:00
bovirus acda5a73e2 Update Italian language (#16747) 2026-10-29 10:00:36 +08:00