mirror of
https://github.com/rustdesk/rustdesk.git
synced 2026-11-04 00:33:12 +00:00
76dacea54b17e72e9514c9974863dc9e67da97a4
3208
Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
3fc11c0f81 |
port forward shared conn (#16062)
* hbb_common: bump to the port-forward-mux proto Also latches PortForward.multiplex into login_scope_digest, which destructures PortForward's fields exhaustively by design (a new field must be latched or deliberately ignored to compile). Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01EZ49AbZJYfm8NTp5yDPMab * port_forward_mux: window accounting and channel frame builders Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01EZ49AbZJYfm8NTp5yDPMab * port_forward_mux: fix RecvWindow counter overflow on long transfers Replace cumulative accounting (granted/received) with remaining credit tracking to prevent u32 overflow after 4 GiB of data on a single channel. Wire behavior is identical, but the fix allows large file transfers without mid-stream channel closure. Add regression test for 8 GiB transfer to verify fix. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01EZ49AbZJYfm8NTp5yDPMab * port_forward_mux: credit-windowed relay halves and channel coordinator Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01EZ49AbZJYfm8NTp5yDPMab * server: PortForwardMux channel table and per-channel tasks Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01EZ49AbZJYfm8NTp5yDPMab * server: multiplexed port-forward connections stay in the protobuf loop Wire PortForwardMux into Connection: take the multiplexed path at login when the controller sets PortForward.multiplex, route PortForwardChannel frames to it from on_message, sweep the channel table's targets after open/close, and clean it up on connection close. Introduce is_port_forward() (socket-based or multiplexed) and use it at the four sites that classify the connection, so a multiplexed connection stays in the message loop, gets TestDelay keepalives, and reports features.port_forward_mux in PeerInfo. The three sites that break into the raw pipe loop or gate the keepalive still check port_forward_socket specifically, since a multiplexed connection must not take that path. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01EZ49AbZJYfm8NTp5yDPMab * cm: update a port-forward row's targets as tunnel channels come and go Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01EZ49AbZJYfm8NTp5yDPMab * port_forward_mux: controller tunnel with a single-writer stream loop Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01EZ49AbZJYfm8NTp5yDPMab * port_forward_mux: publish Muxed before spawning the tunnel loop Publishing after spawn let a loop that dies immediately reset the state first, so the later publish pinned it at Muxed with a dead handle forever. Also adds a test pinning open-before-data ordering across many concurrently opened channels, and drops an unused Clone derive. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01EZ49AbZJYfm8NTp5yDPMab * port forward: share one multiplexed tunnel across a window's listeners Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01EZ49AbZJYfm8NTp5yDPMab * port forward: fix round 1 review findings Drop the mux default-false assignment now that definite-assignment proves every path that reads it has set it; the enable-port-forward-mux config commit picks up the missing attribution trailers; the default-on test pins the enable- prefix itself rather than option2bool's weaker fallback. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01EZ49AbZJYfm8NTp5yDPMab * port_forward_mux: end-to-end tests over a loopback tunnel Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01EZ49AbZJYfm8NTp5yDPMab * port_forward_mux: fix bulk test's premature half-close, pin the half-close limitation many_channels_echo_concurrently_and_a_bulk_one_does_not_starve_them dropped its bulk write half as soon as writing finished, which shuts down the write side of the socket and, by design (see the design doc's TCP half-close non-goal; today's run_forward does the same), ends the whole channel. Keep the write half alive until the reader is done so the test measures starvation, not half-close. Add a_local_half_close_ends_the_whole_channel to pin that limitation in code. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01EZ49AbZJYfm8NTp5yDPMab * port_forward_mux: cap send credit and other final review fixes Fix 1 (critical): clamp SendCredit to MAX_SEND_CREDIT (= CHANNEL_WINDOW) in both new() and add(), so a peer with tunnel permission can no longer advertise an unbounded window and force the controlled side's unbounded FrameSink::Direct sink to buffer unlimited target data per channel. Fix 2: rename the "starve" test to many_channels_echo_concurrently and drop its (untrue) starvation claim, since it opens every channel before the bulk transfer starts. Add a_channel_opened_during_a_bulk_transfer_ is_served_promptly, which opens the small channel while the bulk one is demonstrably mid-flight. Fix 3: only look up the tunnel permission for `open` frames in the PortForwardChannel arm of on_message, instead of once per data frame. Fix 4: two rustfmt deviations in connection.rs (matches! wrapping and a tuple literal), fixed by hand without a blanket cargo fmt run. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01EZ49AbZJYfm8NTp5yDPMab * port_forward_mux: report a refused channel's reason as an error dialog The controlled side already answers a refused port-forward channel with opened { success: false, message }; on the multiplexed path TunnelHandle:: on_frame only logged that message at debug and closed the channel, so the user saw a closed connection with no explanation, worst on the RDP path where only the RDP client's own error remained. on_frame now returns the message the window should show, deduplicated per distinct reason (capped at MAX_REPORTED_OPEN_ERRORS) so one page load's dozen refused connections surface one dialog per reason instead of a dozen. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01EZ49AbZJYfm8NTp5yDPMab * Use on_error for refused-channel dialog in tunnel_loop Redirect the refused-channel error through the standard on_error path instead of calling msgbox directly, for consistency with other errors in the port-forward flow. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01EZ49AbZJYfm8NTp5yDPMab * port forward: apply the whole-branch review Correctness: - listen(): the Legacy arm is merged with the Claimed arm. On its own it ignored outcome.local_eof, so a client that hung up during login still got a target connect, an audit record and a CM row on the controlled side, and ignored outcome.mux, so a peer upgraded while a legacy window stayed open answered as a tunnel while the controller went raw. - Refusal dialogs are deduplicated per quiet spell (10 s) rather than per tunnel lifetime; the lifetime set went silent for the rest of a long-lived window after the first burst. - Android's CM listener handles UpdatePortForward; it fell into `_ => {}`. - relay_socket_to_tunnel reads into one scratch buffer per channel and sends an exact-size copy. A frame owning its 64 KiB read allocation pinned it until sent, once per byte on interactive traffic. Consistency and cleanups: - The controlled side's refusal text is the raw pipe's wording, RDP substitution included. - connection.rs: the PortForwardChannel arm is a one-line hook, the CM label is pushed from the 1 s tick alone, and the unreachable inner.tx fall-through is gone. - The Ready enum is removed; wait_ready() returns Option<Claim>. - SendCredit::add wakes with notify_one alone. - on_ui_command() replaces the two ui_receiver handlers in listen(). - TunnelHandle is no longer re-exported (unused-import warning). Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01EZ49AbZJYfm8NTp5yDPMab * port forward: a legacy window stays legacy until it is reopened Review: the merged `Claimed | Legacy` arm gave a legacy window a hot transition to a tunnel — every accept re-negotiated, and a peer upgraded while the window stayed open was promoted underneath live connections. The product does not need a mode switch inside a window's lifetime, and the transition was extra state-machine surface for nothing: reopening the window picks up an upgraded peer. The two arms are separate again. `Claimed` negotiates once and the peer's answer fixes the window's mode. `Legacy` logs in for every accept as before, asks for no tunnel — `LoginConfigHandler::port_forward_mux` carries the request per login, so the raw pipe never has to talk to a peer that thinks it agreed to multiplex — and ignores what the peer reports. Both arms keep skipping a local socket that hung up during login. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01EZ49AbZJYfm8NTp5yDPMab * hbb_common: bump to main with rustdesk/hbb_common#594 merged Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01EZ49AbZJYfm8NTp5yDPMab * server: admit only INITIAL_WINDOW on a channel before opened The demultiplexer accepted CHANNEL_WINDOW into a pending channel's unbounded queue, four times the bound the channel task enforces once it polls. The window now starts at INITIAL_WINDOW and is widened right before `opened` advertises the rest. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01EZ49AbZJYfm8NTp5yDPMab * port_forward_mux: a tunnel ends when its window drops the Tunnel The loop held its own handle and state sender, so once the window closed nothing was left to stop it: it kept answering TestDelay and the peer connection, CM row included, lived on until the peer went away. `Tunnel` now owns a watch sender nobody sends on; the loop's receiver errors when the last `Tunnel` drops, and the loop ends. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01EZ49AbZJYfm8NTp5yDPMab * port forward: one tunnel per mapping, bound to the authenticated target The login latches `PortForward.host`/`port` into the session scope and approval is shown that target, but a window-wide tunnel let any later `open` name another target with only `enable-tunnel` rechecked. A tunnel now belongs to one listener and serves the one target its login authenticated: the controlled side refuses an `open` for any other target, and a window with several targets uses one connection each, approved on its own. With one owner per tunnel the claim needs no waiters: `Establishing`, `Claim::Wait` and `wait_ready` go, and `try_claim` becomes a plain read. The CM label that followed a tunnel's targets goes with them; a row shows its mapping's target, as before. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01EZ49AbZJYfm8NTp5yDPMab * port forward: the legacy comment names the mapping, not the window Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01EZ49AbZJYfm8NTp5yDPMab * port_forward_mux: a window violation drops the channel on the spot Both demultiplexers only queued a `Violation` and left the entry until the channel task woke and exited, so a peer that kept sending past the window queued one more entry per frame in the meantime, bounded by nothing. The entry now goes the moment `accept` fails; later frames for that id are unknown-channel noise. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01EZ49AbZJYfm8NTp5yDPMab * port forward: the login's target travels with the accept, not the handler `listen()` wrote `lc.port_forward` (and, on this branch, `port_forward_mux`) into the window's shared `LoginConfigHandler` before connecting, and `create_login_msg` read them back only when the peer's `Hash` arrived. Two mappings logging in at the same time could therefore swap targets: on master that bridged a local socket to the wrong target, and with a tunnel bound to its login's target it also left the mapping refusing every later accept until it was recreated. The target is now a `PortForward` carried by the interface clone that handles one accept, passed explicitly down to `create_login_msg`; the handler no longer has a field to race on. No lock spans the login. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01EZ49AbZJYfm8NTp5yDPMab * port_forward_mux: pin permission revocation and whole-tunnel failure in tests Both already hold; the review asked for them to be stated. `enable-tunnel` turned off mid-session refuses the next `open` while the live channel keeps relaying, and a dead tunnel ends every channel on it together, after which the next accept establishes again on the same `Tunnel`. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01EZ49AbZJYfm8NTp5yDPMab * port forward: the legacy comment names re-adding the mapping only Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01EZ49AbZJYfm8NTp5yDPMab * port forward: the raw pipe runs the code it always ran The multiplexed login had replaced `connect_and_login`, so a mapping with the setting off, a peer without the feature, or a listener latched `Legacy` still went through the tunnel's state machine, the capped pre-read and the changed local-EOF rule. Feature off now means the old code: `listen()` keeps its accept arm and `connect_and_login` as they were, and the tunnel is a branch taken only when the setting is on, in `establish_tunnel` with its own `connect_and_login_mux`. The one line the raw path does differently is the target riding with the accept's interface clone instead of the shared handler. `get_port_forward_mux_enabled` had one caller and moves in here, so `common.rs` is untouched. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01EZ49AbZJYfm8NTp5yDPMab * port forward: a UI login answers the challenge its own connection was given `handle_login_from_ui` hashed the typed password against `lc.hash`, the window's shared handler field, and the window's password prompt is broadcast to every listener. With two mappings both waiting on that prompt, the `Hash` that arrived last had overwritten the other's, so one of the two answered the wrong challenge and failed to log in. Master shares the same state and broadcasts the same way. The `Hash` is now a parameter of the login; `Session` keeps it beside the connection it belongs to, and the per-accept clone that `with_port_forward` makes gets a slot of its own. `lc.hash` stays for `handle_peer_info`, which only needs the salt, and that is per peer. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01EZ49AbZJYfm8NTp5yDPMab * port forward: a mapping without its hash waits for it before answering the prompt The window's password prompt is broadcast to every mapping, and can reach one whose own connection has not received its `Hash` yet. That mapping used to answer anyway, with a digest over an empty challenge: the peer refused it and counted a failed attempt, and the empty-salt result was written into the shared `lc.password`, where the mapping that prompted had just stored the right one and the next `handle_peer_info` would persist whatever was there. The connection's challenge is now `Option<Hash>`, `None` until `handle_hash` runs, and `handle_login_from_ui` sends nothing without it. The mapping that prompted stores the salted password in the shared handler, and the waiting one logs in with that against its own challenge when its `Hash` arrives, without prompting again. Test: A answers its prompt, the same broadcast reaches B before its hash, B sends nothing, B's hash arrives and its login carries B's challenge and B's target with no dialog. It runs the real `handle_hash` for B. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01EZ49AbZJYfm8NTp5yDPMab * port forward: the tunnel's login is the raw pipe's, asked for by a window flag Master's fix for the shared login slots (#16069) keeps the target and the challenge in the window's `LoginConfigHandler` and serializes the mappings' logins with a turn lock, all inside `port_forward.rs`. This branch had carried a broader shape of the same fix, a `with_port_forward` on `Interface` and the target and `Hash` as parameters through the login functions, which every caller had to follow. That is gone: `Interface`, `Session`, `create_login_msg`, `send_login`, `handle_hash` and `handle_login_from_ui` are as on master. What the tunnel needs on top is one bit in the login, `multiplex`. It is a window flag beside `port_forward` in the handler, set once in `io_loop` before the window's mappings start, so an accept's claim and its login read the same value; the setting takes effect for windows opened after it changes. `connect_and_login_mux` is now master's `connect_and_login` with the tunnel's three differences and the same `hash_arrived` and `login_from_ui` calls. The raw pipe is master's, line for line. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01EZ49AbZJYfm8NTp5yDPMab * hbb_common: bump to main with rustdesk/hbb_common#595 merged 840c8ec..f94e3fe is that one merge: the five local settings custom clients could not preset. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01EZ49AbZJYfm8NTp5yDPMab * port forward: the off switch gets a checkbox in Settings → General `enable-port-forward-mux` was readable only by editing the config file. It is a local setting of the controlling side, so it sits with the other outgoing ones, after "Open connection in new tab", with a tooltip saying what it does. The two new keys are translated in every language. The three that the mobile file manager added, "Export", "Export Logs" and "Import Folder", were empty everywhere but five languages; they are filled in too, and Korean's "xdp-portal-unavailable" with them. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01EZ49AbZJYfm8NTp5yDPMab * Urdu: fill the backlog of empty and missing translations ur.rs had fallen behind: 104 keys carried an empty value and 35 keys the other languages have were absent altogether. Both are filled in, the missing ones in the order template.rs lists them. Eight entries stay empty on purpose. They are keys that only ur.rs still carries, absent from template.rs and from every other language, so their English source cannot be recovered and nothing reads them: remember_account_tip, os_account_desk_tip, another_user_login_*_tip, xorg_not_found_*_tip and no_desktop_*_tip. Twelve more dead keys keep the values they have; removing either group is a separate decision. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01EZ49AbZJYfm8NTp5yDPMab * Urdu: drop the keys template.rs no longer lists The twenty keys removed here are absent from template.rs and from every other language file; ur.rs was the only one still carrying them, eight of them with no value at all. They are leftovers of features that are gone: the plugin menu, the OS-account login prompts, the Xorg and no-desktop errors. ur.rs now holds exactly the template's key set, all of it translated. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01EZ49AbZJYfm8NTp5yDPMab * port forward: closing the tunnel reaches channels parked on their socket A channel whose far end neither reads nor writes has both relays parked on the socket, not on the inbound queue, so `close_all` dropping the queue's sender woke neither: the socket and both tasks lived on until the far end hung up. Both sides now hold a per-tunnel teardown signal that `run_channel` selects on beside its own cancel, and `close_all` sends it after clearing the map. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01EZ49AbZJYfm8NTp5yDPMab * port forward: a mapping latched to the raw pipe logs in without asking for the tunnel The login copied the window's `port_forward_mux` into `multiplex`, so a mapping that had latched to the raw pipe on an old peer kept asking for the tunnel. Once that peer was upgraded it answered with a tunnel while the controller switched to raw framing, and every later connection on the mapping was dead until it was re-added. The login now carries its own `port_forward_multiplex`, filled with the target under the turn lock: the probe asks, the raw pipe does not. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01EZ49AbZJYfm8NTp5yDPMab * port forward: a channel opened as its tunnel closes still gets the teardown `open` can straddle `close_all`: the claim passed, the frame receiver was still alive, and the channel subscribed after the signal had gone out. `watch::subscribe` marks earlier sends as seen, and the entry sits in a map that was already cleared, so nothing would ever end it. The signal is now a level: `close_all` raises it with `send_replace`, which stores even with no channel live, and `run_channel` waits for the value rather than for a change. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01EZ49AbZJYfm8NTp5yDPMab * port forward: the connect guard counts a live tunnel as connected `connect_port_forward_if_needed` returned early only for a raw-pipe socket; called again with a tunnel up it would have built a second `PortForwardMux` and dropped every channel of the first. Not reachable today, since the logon response is sent once, but the other checks in this change already read `is_port_forward()`. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01EZ49AbZJYfm8NTp5yDPMab * Urdu: the two terminal clipboard keys master added Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01EZ49AbZJYfm8NTp5yDPMab * port forward: a tunnel's TCP stream refuses packets over twice MAX_FRAME The codec takes a header declaring up to 1 GiB and hands the packet up only once it has all arrived, so the channel window bounded what the peer may send, not what this side buffers. Both sides now cap the codec at 2 * MAX_FRAME as soon as multiplexing is agreed: a data frame with its envelope and MAC fits with room to spare, and a header over the cap ends the tunnel before a byte of payload is read. TCP only; the WebSocket and WebRTC codecs carry caps of their own. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01EZ49AbZJYfm8NTp5yDPMab * port forward: a channel id still live when the counter comes round is skipped The controller handed out `next_id` unchecked. 2^32 opens later it lands on a channel still up: the entry here was replaced, while the peer, which ignores an `open` for a live id, kept routing that id to the old socket, so the new local connection's bytes went into the old target connection. The id is now taken under the map's lock and advanced past any id in use. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01EZ49AbZJYfm8NTp5yDPMab --------- Co-authored-by: Claude Opus 5 <noreply@anthropic.com> |
||
|
|
618bf37deb |
feat(terminal): add opt-in OSC 52 clipboard writes (#16072)
* feat(terminal): add opt-in OSC 52 clipboard writes * Remove dup tr Signed-off-by: fufesou <linlong1266@gmail.com> --------- Signed-off-by: fufesou <linlong1266@gmail.com> |
||
|
|
c1a587cfa4 |
connection page: the Connect menu offers TCP tunneling, as the peer card does (#16075)
The dropdown beside Connect listed file transfer, camera and terminal but not port forwarding, so reaching it meant having a card for the peer. `connect` already takes `isTcpTunneling`; only the menu entry and the parameter that carries it were missing. Shown on desktop only. The peer card gates the same entry on `isDesktop` because `connect` routes a tunnel through the desktop path alone; on web it would have opened a plain remote session instead. Claude-Session: https://claude.ai/code/session_01EZ49AbZJYfm8NTp5yDPMab Co-authored-by: Claude Opus 5 <noreply@anthropic.com> |
||
|
|
f28ac38ccf |
feat: optionally sync clipboard between connected sessions (#15934)
* feat(clipboard): optionally sync clipboard between connected sessions Clipboard content received from a remote session is written to the local clipboard with an owner marker, so the client clipboard loop deliberately skips re-broadcasting it to avoid echo loops. As a result, text copied in one remote window could not be pasted in another connected remote window. Add an opt-in local option (allow-sync-clipboard-between-sessions) that relays Clipboard/MultiClipboards messages received from one session to all other connected sessions, excluding the source session. Per-session clipboard permissions and view-only mode are still respected via the existing send path, and the owner marker on the receiving peers prevents any echo back. Desktop (flutter) only; file clipboard is not affected. * fix(lang): propagate sync-clipboard-between-sessions-tip to all locale files Add the new key to template.rs and every locale file per the localization convention, move the en.rs entry to the end of the list, and drop comments that only restated the names next to them. * fix(lang): add the 'Sync clipboard between sessions' label to the localization catalog The checkbox label goes through translate(), so add it to template.rs and every locale file so non-English locales can translate it. en.rs is skipped since the English display text is identical to the key. * fix(clipboard): check the source session's full clipboard permission before relaying The relay was gated only by the incoming clipboard_allowed check (!disable_clipboard && !view_only). Gate it with is_text_clipboard_required() instead, which additionally respects the source session's server_clipboard_enabled and server_keyboard_enabled state, matching the predicate already applied to destination sessions. A message arriving after the source permission was revoked (or from a non-conforming peer) is no longer propagated to other sessions. The existing local update_clipboard behavior is unchanged. * fix(lang): translate the new clipboard sync entries in all locale files Fill the 'Sync clipboard between sessions' label and its tooltip in every locale file instead of leaving them blank, following each file's existing terminology. template.rs keeps the empty master entries. |
||
|
|
28cf1836e6 | bump to 1.5.0 | ||
|
|
1ec1b9e7e3 |
fix: android: target API 36 (#15603)
* fix: android: target API 35 Signed-off-by: michaeljclarkk <104532890+michaeljclarkk@users.noreply.github.com> * fix: android: handle API 35 foreground service types Integrate the foreground-service and MediaProjection lifecycle changes from fufesou/rustdesk#68 while leaving storage permission handling to #15602. Co-authored-by: fufesou <linlong1266@gmail.com> Signed-off-by: fufesou <linlong1266@gmail.com> Signed-off-by: michaeljclarkk <104532890+michaeljclarkk@users.noreply.github.com> * fix: bump required android sdk version to 36, per recent google requirement change. Signed-off-by: michaeljclarkk <104532890+michaeljclarkk@users.noreply.github.com> * fix(android): clear microphone FGS type when capture stops Signed-off-by: fufesou <linlong1266@gmail.com> * fix(android): harden API 36 capture service lifecycle - isolate MediaProjection callbacks per session - keep foreground service types in sync with capture state - handle audio startup failures and shared frame ownership - upgrade AGP to 8.10.1 for API 36 support Signed-off-by: fufesou <linlong1266@gmail.com> * fix(android): reset capture state on FGS update failure Signed-off-by: fufesou <linlong1266@gmail.com> * fix(android): recover capture after projection failure Propagate virtual display startup failures, clean up partial video resources, and resume capture after media projection is reauthorized. Signed-off-by: fufesou <linlong1266@gmail.com> * fix(android): preserve voice call during projection replacement Keep the existing capture active until a new projection is acquired, and restore the voice-call audio source when capture restarts. Signed-off-by: fufesou <linlong1266@gmail.com> * fix(android): use JDK 17 in playground workflow Signed-off-by: fufesou <linlong1266@gmail.com> * fix(android): clear pending capture restart on denial Notify MainService when a recovery projection request is canceled so a later projection grant cannot restart stale capture state. Signed-off-by: fufesou <linlong1266@gmail.com> * fix(android): handle audio and projection recovery failures Verify AudioRecord startup, propagate voice-call restoration failures, and clear stale capture recovery state when projection setup fails. Signed-off-by: fufesou <linlong1266@gmail.com> --------- Signed-off-by: michaeljclarkk <104532890+michaeljclarkk@users.noreply.github.com> Signed-off-by: fufesou <linlong1266@gmail.com> Co-authored-by: fufesou <linlong1266@gmail.com> |
||
|
|
d4b06a6c5c |
fix: android: replace all-files access with scoped storage (#15602)
* fix: android: replace all-files access with scoped storage + system picker Remove MANAGE_EXTERNAL_STORAGE, READ_EXTERNAL_STORAGE, and WRITE_EXTERNAL_STORAGE from the Android manifest. Remove requestLegacyExternalStorage. Replace broad external storage with app-scoped external storage for the file-transfer workspace. File import uses the system file_picker. File export uses Android's SAF ACTION_CREATE_DOCUMENT with path validation that restricts export sources to app-owned directories. Remove the external_path dependency. Signed-off-by: michaeljclarkk <104532890+michaeljclarkk@users.noreply.github.com> * fix: android: refine file import feedback Signed-off-by: michaeljclarkk <104532890+michaeljclarkk@users.noreply.github.com> * fix: android: use SAF for file imports Replace file_picker imports with Android's Storage Access Framework to avoid legacy storage permissions, stale cached files, and duplicate staging of large imports. Stream selected documents into app-scoped storage with failure-safe replacement, keep exports restricted to validated app storage roots, use filesDir for the internal fallback workspace, and remove legacy permissions contributed during manifest merging. Signed-off-by: michaeljclarkk <104532890+michaeljclarkk@users.noreply.github.com> * fix: android: keep file imports in the selected directory Signed-off-by: michaeljclarkk <104532890+michaeljclarkk@users.noreply.github.com> * fix: android: reset projection and constrain file workspace Release capture resources when media projection is revoked externally. Keep Android local file navigation within the app-scoped workspace. Signed-off-by: michaeljclarkk <104532890+michaeljclarkk@users.noreply.github.com> * fix: android: handle scoped storage start-up regressions. Allow zero digits in POSIX filenames by rejecting NUL explicitly, and initialise the app-specific home directory before the Android service starts the native server. Signed-off-by: michaeljclarkk <104532890+michaeljclarkk@users.noreply.github.com> * fix: update content resolver mode to use 'wt' instead of 'w' to prevent trailing bytes from old document whilst reporting sucess Signed-off-by: michaeljclarkk <104532890+michaeljclarkk@users.noreply.github.com> * fix: android, enforce file workspace boundary on the server, and unblock the ui thread. Signed-off-by: michaeljclarkk <104532890+michaeljclarkk@users.noreply.github.com> * fix: android: validate rename destinations against the app workspace bound file-operation paths. report rename failures, general import failures, and unregister / reregister projection when its onStop callback fires. Signed-off-by: michaeljclarkk <104532890+michaeljclarkk@users.noreply.github.com> * fix: reconnect was refreshing the directory with net entry instances, while selected items retained the old instances, it was reporting a selected item, but checkbox statue used object identity, and appeared unchecked. Fixed by reconciling by path and entry type before replacing the directory snapshot, rebinding valid selections, and dropping missing ones. Signed-off-by: michaeljclarkk <104532890+michaeljclarkk@users.noreply.github.com> * fix: (android) add SAF folder import and multi item export - import directories using ACTION_OPEN_DOCUMENT_TREE. Export multiple files, logs, and screen recordings via export buttons, add localisation keys for new actions Signed-off-by: michaeljclarkk <104532890+michaeljclarkk@users.noreply.github.com> * fix(android): harden scoped storage file handling - create new SAF documents instead of overwriting export sources - reject empty peer paths except for home directory reads - report directory backup restore and cleanup failures - resolve log export paths from the configured app name Signed-off-by: fufesou <linlong1266@gmail.com> * fix(android): harden scoped-storage file operations - snapshot directory exports before writing to the destination - query document provider metadata off the main thread - reject invalid remote directories without read timeouts Signed-off-by: fufesou <linlong1266@gmail.com> * fix(android): handle SAF directory name collisions - reject dot-segment folder names during import - fail imports with duplicate document display names - only reuse matching directories during export Signed-off-by: fufesou <linlong1266@gmail.com> * fix(android): handle SAF folder import collisions Reject filesystem-equivalent destination names and avoid showing a failure when folder overwrite is skipped. Signed-off-by: fufesou <linlong1266@gmail.com> --------- Signed-off-by: michaeljclarkk <104532890+michaeljclarkk@users.noreply.github.com> Signed-off-by: fufesou <linlong1266@gmail.com> Co-authored-by: fufesou <linlong1266@gmail.com> |
||
|
|
03a7fc5992 |
fix(flutter): align terminal shortcuts with platform conventions (#15970)
* fix(flutter): align terminal shortcuts with platform conventions Signed-off-by: fufesou <linlong1266@gmail.com> * fix(flutter): handle Linux terminal paste with modifier locks Detect platform-specific paste shortcuts so Ctrl+Shift+V bypasses virtual Ctrl/Alt modifiers on Linux. Add regression coverage. Signed-off-by: fufesou <linlong1266@gmail.com> --------- Signed-off-by: fufesou <linlong1266@gmail.com> |
||
|
|
1fe451c2e8 |
chore(flutter): bump desktop_multi_window for show recovery (#15959)
Pick up rustdesk-org/rustdesk_desktop_multi_window#37, which re-arms the existing bounded redraw timer whenever a secondary window is shown, including when its first frame was generated while hidden but not presented. This may perform one delayed child refresh on each show. It intentionally does not add a presentation-complete flag: Flutter reports frame generation rather than successful presentation, so recording success after a synthetic refresh could suppress later self-recovery without a reliable success signal. |
||
|
|
0b08a83d4b |
fix(file-transfer): improve large directory loading (#15830)
* fix(file-transfer): improve large directory loading Signed-off-by: fufesou <linlong1266@gmail.com> * fix(file-transfer): avoid failing newer directory reads Track each remote directory request by its registered completer and only remove the task when it still matches, preventing stale failures from affecting newer requests for the same path. Signed-off-by: fufesou <linlong1266@gmail.com> * fix(file-transfer): handle slow directory listings safely Signed-off-by: fufesou <linlong1266@gmail.com> * fix(file transfer): correlate directory responses with requests Signed-off-by: fufesou <linlong1266@gmail.com> * fix(file transfer): prevent automatic directory responses from matching requests Signed-off-by: fufesou <linlong1266@gmail.com> * fix(file-transfer): handle large remote directory listings reliably - build file rows lazily - register remote reads before sending requests - handle Home paths, stale responses, errors, and timeouts - serialize same-path reads with different hidden-file options Signed-off-by: fufesou <linlong1266@gmail.com> * fix(file transfer): reduce diffs Signed-off-by: fufesou <linlong1266@gmail.com> * fix: build Signed-off-by: fufesou <linlong1266@gmail.com> * fix: invalidate pending dir reads on reconnect Signed-off-by: fufesou <linlong1266@gmail.com> * test(file-transfer): cover remote directory read lifecycle Signed-off-by: fufesou <linlong1266@gmail.com> --------- Signed-off-by: fufesou <linlong1266@gmail.com> |
||
|
|
fd471fcf02 |
fix: show speed in desktop file transfer status (#15980)
* fix: show speed in desktop file transfer status Signed-off-by: fufesou <linlong1266@gmail.com> * fix: move file transfer speed beside progress bar Signed-off-by: fufesou <linlong1266@gmail.com> * fix: move file transfer speed into progress bar Signed-off-by: fufesou <linlong1266@gmail.com> * fix: refine file transfer speed display Signed-off-by: fufesou <linlong1266@gmail.com> * fix: adapt file transfer progress text colors Signed-off-by: fufesou <linlong1266@gmail.com> * fix: reduce file transfer speed text weight Signed-off-by: fufesou <linlong1266@gmail.com> --------- Signed-off-by: fufesou <linlong1266@gmail.com> |
||
|
|
3f207e91f6 |
fix(linux): a session logout should hand the peer to the login screen (#15905)
* fix(linux): a session logout should hand the peer to the login screen Logging out closes every window in the session, the connection manager's included, and its close handler kicks every peer with the reason a person gets when they disconnect one by hand. That reason is the one thing the client never retries on, so the remote session dies on a frozen frame instead of reconnecting to the greeter that is already there. The close carries nothing to tell the two apart: measured on KDE, the CM receives no signal and logind still reports the session active at that instant, and the server is killed within a few hundred ms either way, so neither a state check nor a grace period can decide it. What is distinguishable is the ACTION: disconnecting a peer is not the same event as this window going away. So the window-close path now says so, and the server ends the session without poisoning the retry; the Disconnect button and the app's own close control keep kicking exactly as before. Linux only, since that is where a logout closes the window. Verified on plasma/sddm with a client attached: a logout now reconnects to the greeter with no dialog, while closing the manager window still shows Closed manually by the peer. * fix(linux): close the tunnel too, and keep the web build compiling Three seams the first pass missed. The web bridge is hand written, not generated, so the new call needs its stub there or flutter build web stops compiling - and that job is disabled in CI, so it would have gone green. try_port_forward_loop is a second consumer of the same channel and only knew Close, so a forwarded tunnel outlived the window it was supposed to die with. And the variant had landed inside the DRM section, whose comment says everything below it is drm-gated. |
||
|
|
a3bab27a2a | fix: Show My Cursor freezes in View Only mode when remote user mo... (#15936) | ||
|
|
d5a7f67999 | fix appimage pixbuf crash | ||
|
|
92eb137178 | feat(terminal): use platform-native copy and paste shortcuts (#15931) | ||
|
|
61ddade049 |
fix(windows): restore keyboard focus when the cursor re-enters the remote image (#15880)
* fix(windows): restore keyboard focus when the cursor re-enters the remote image On Windows the raw key focus node is unfocused on window blur and nothing requests it back, so returning to an already connected session left the keyboard dead until the remote image was clicked. Request focus from enterView(), gated on the window being active, the tab being selected and no blocking overlay, so a background window cannot grab system keys. enterOrLeave(true) is still driven by RawKeyFocusScope's onFocusChange, so it is not called twice. * fix(windows): refocus on window focus when the cursor already hovers the image Alt+Tab or a taskbar click returns focus without a PointerEnter, so enterView() cannot restore the keyboard. Reuse _cursorOverImage, gated on the selected tab and no blocking overlay. * refactor(windows): share one focus predicate for every requestFocus path The relative-mouse-mode restore on window focus could hand remote input to this page while a blocking dialog was up or the tab was not selected. |
||
|
|
c78bdefc44 |
fix: dialog, trackpad speed, buttons (close -> ok, cancel) (#15918)
* fix: dialog, trackpad speed, buttons (close -> ok, cancel) Signed-off-by: fufesou <linlong1266@gmail.com> * fix(flutter): handle trackpad speed dialog submission - commit typed values from Enter and OK - validate input before saving - prevent duplicate submissions - surface save failures Signed-off-by: fufesou <linlong1266@gmail.com> * fix(flutter): sync trackpad speed input and slider - handle trackpad speed submission from IME actions - update the slider when a valid speed is typed - cover Enter, OK, IME, and invalid input behavior Signed-off-by: fufesou <linlong1266@gmail.com> --------- Signed-off-by: fufesou <linlong1266@gmail.com> |
||
|
|
0a4b431ea2 |
fix: correct terminal mouse selection and scroll coordinates (#15915)
Signed-off-by: fufesou <linlong1266@gmail.com> |
||
|
|
5679670506 |
fix(flutter): make Adjust Window reliable across desktop platforms (#15853)
* fix(flutter): make Adjust Window reliable across desktop platforms
- Fix incorrect sizing on scaled displays by calculating the target from the
rendered canvas scale and platform-specific window coordinate units.
- Fix adjustments using the wrong monitor by querying the current remote
window's screen, with the main window as fallback.
- Fix stale geometry after fullscreen or maximized transitions by refreshing
metrics before calculating and applying the target frame.
- Fix fullscreen availability checks on Windows and macOS by predicting the
restored window borders and caching each macOS window's pre-fullscreen work area.
- Fix incorrect Linux work areas by handling GNOME Wayland fractional scaling
and caching compositor/X11 work-area measurements when visibleFrame is wrong.
- Prevent unsafe adjustments by rejecting invalid, oversized, or implausibly
small target frames.
- Avoid failures during window teardown by skipping adjustment when the view,
screen, or native window frame is unavailable.
Signed-off-by: 21pages <sunboeasy@gmail.com>
* fix(flutter): harden Adjust Window handling
- Use the dynamic Linux resize edge when predicting restored window bounds.
- Treat GNOME fractional-scaling lookup failures as unknown without repeating
the lookup for the remote window.
- Stop adjustment safely when native window calls fail during window teardown.
Signed-off-by: 21pages <sunboeasy@gmail.com>
* fix(flutter): correct Linux monitor selection
Update window_size to use monitor height for vertical bounds, preventing incorrect screen selection with vertically stacked displays.
Signed-off-by: 21pages <sunboeasy@gmail.com>
* docs(flutter): simplify Linux screen handling comments
Keep the source rationale concise and move platform measurements and investigation details out of the implementation.
Signed-off-by: 21pages <sunboeasy@gmail.com>
* fix(flutter): align Adjust Window resize padding
Use the shared drag-to-resize padding for Linux restored-window predictions so menu validation matches the applied frame dimensions.
Signed-off-by: 21pages <sunboeasy@gmail.com>
* fix(flutter): remove Adjust Window screen fallback
Return null when the current window screen is unavailable instead of using the main window's scale factor and work area.
Signed-off-by: 21pages <sunboeasy@gmail.com>
* fix(linux): query Mutter monitor layout mode
Use DisplayConfig.GetCurrentState instead of inferring scaling from
experimental features, and handle Ubuntu's UI-scaled logical mode.
Signed-off-by: 21pages <sunboeasy@gmail.com>
* fix(flutter): use native maximized state for Wayland cache
Signed-off-by: 21pages <sunboeasy@gmail.com>
* fix(flutter): allow Adjust Window to fill work area
Signed-off-by: 21pages <sunboeasy@gmail.com>
* fix(flutter): avoid racing screen info updates
Signed-off-by: 21pages <sunboeasy@gmail.com>
* refactor(flutter): remove dead Adjust Window web plumbing
Signed-off-by: 21pages <sunboeasy@gmail.com>
* fix(flutter): tolerate near-unity Wayland scale factors
Signed-off-by: 21pages <sunboeasy@gmail.com>
* fix(flutter): harden window screen detection
Signed-off-by: 21pages <sunboeasy@gmail.com>
* fix(linux): drop deprecated GNOME session detection
Signed-off-by: 21pages <sunboeasy@gmail.com>
* fix(flutter): remove GNOME monitor layout mode flutter cache
Signed-off-by: 21pages <sunboeasy@gmail.com>
---------
Signed-off-by: 21pages <sunboeasy@gmail.com>
|
||
|
|
630b531108 |
fix(flutter): initialize the cursor hotspot y from its own origin (#15898)
The CursorData constructor copies hotxOrigin into hoty. Latent today: both consumers call updateGetKey() before reading, and _checkUpdateScale recomputes hoty from hotyOrigin - but any future read before that call inherits the x value silently. |
||
|
|
1984678785 |
Hide printer tab when settings disabled (#15901)
* fix: hide the printer settings tab when settings are disabled The Security and Network tabs already honour `disable-settings`, but the Printer tab was gated only on `hide-remote-printer-settings`, so custom clients built with settings disabled still exposed it. https://github.com/rustdesk/rustdesk-server-pro/issues/1001 Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * feat: add hide-general-settings builtin option Hides the General tab of the settings page. Unlike the other hide-*-settings options this one is still useful when settings are disabled, since `disable-settings` does not cover the General tab. https://github.com/rustdesk/rustdesk-server-pro/issues/1001 Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com> |
||
|
|
b0008edcb5 |
refact: remove linux headless (#15866)
* refact: remove linux headless Signed-off-by: fufesou <linlong1266@gmail.com> * fix(linux): probe DRM availability asynchronously on login Signed-off-by: fufesou <linlong1266@gmail.com> * revert changes in drm_capturer.rs Signed-off-by: fufesou <linlong1266@gmail.com> * Update submodule hbb_common Signed-off-by: fufesou <linlong1266@gmail.com> * docs(linux): clarify DRM availability comments Remove stale headless and unauthenticated-request wording, and document the Available-only login-screen gate. Signed-off-by: fufesou <linlong1266@gmail.com> * fix(linux): remove unreachable session cleanup branch Remove the obsolete empty-session path and clarify the intended use of cached DRM availability. Signed-off-by: fufesou <linlong1266@gmail.com> --------- Signed-off-by: fufesou <linlong1266@gmail.com> |
||
|
|
8ffe3117a5 |
feat(flutter): add mobile canvas lock (#15877)
* feat: add mobile canvas lock * Update flutter/lib/models/model.dart Remove redundant canvas-lock comment Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com> * remove redundant logic Signed-off-by: fufesou <linlong1266@gmail.com> --------- Signed-off-by: fufesou <linlong1266@gmail.com> Co-authored-by: Krik Jin <isjinhk@outlook.com> Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com> Co-authored-by: fufesou <linlong1266@gmail.com> |
||
|
|
7aa98d43cf |
Refact/plugin removal leftovers (#15864)
* fix(flutter): dispose the settings PageController and order dispose() correctly `dispose()` began with `super.dispose()`, so the mixin chain marked the State defunct before the WidgetsBindingObserver registration and the periodic timer were released. The `PageController` was never disposed at all: `Get.delete` only runs `onDelete()` for a `GetLifeCycleBase`, and a plain `ChangeNotifier` is not one, so every open/close of the Settings tab leaked one controller with its listener still attached. Also guard `switch2page` on the `Rx<SettingsTabKey>` registration it actually reads rather than only the `PageController` — now that both are really deleted, a partial teardown would throw into the catch and silently open the wrong tab — and re-check `mounted` after the await in the `_videoConnTimer` tick, which `Timer::cancel` cannot stop once the body has started. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * refact: finish the plugin-framework removal sweep #15854 removed the feature but stopped short of its leftovers: - `Uninstall`, `Enable`, `Disable`, `Options` and `Please install plugins` were consumed only by the deleted `flutter/lib/plugin/**`; drop them from template.rs and the 50 locale files (250 dead entries). `Update` and `Install` stay, still used by desktop_home_page.dart. - The server no longer sends `PrvOnFailedPlugin`, and the client no longer offers to install plugins when privacy mode fails to turn on. - Drop the MSI `F_Client_Plugins` / `F_Server_Plugins` localization strings; no `.wxs` references them. - `_DisplayMenu`'s constructor became a pure pass-through once `pluginItem` was removed, and the cfg inside `handle_input` repeats the one on the function itself. - Normalize `src/lang/sl.rs` to 0644, the only executable file under src/. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix(client): handle legacy privacy mode plugin failures Signed-off-by: fufesou <linlong1266@gmail.com> --------- Signed-off-by: fufesou <linlong1266@gmail.com> Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com> Co-authored-by: fufesou <linlong1266@gmail.com> |
||
|
|
d1da05c4db |
refact: remove feature plugin-framework (#15854)
* refact: remove feature plugin-framework Signed-off-by: fufesou <linlong1266@gmail.com> * refact: remove unused translations Signed-off-by: fufesou <linlong1266@gmail.com> * fix: delete settings tab observable with correct type Signed-off-by: fufesou <linlong1266@gmail.com> --------- Signed-off-by: fufesou <linlong1266@gmail.com> |
||
|
|
1d09760ef7 |
fix(terminal): keep selection aligned after clearing scrollback (#15831)
Remove scrollback lines through the index-aware buffer operation so deleted anchors are detached and retained lines are reindexed. Signed-off-by: fufesou <linlong1266@gmail.com> |
||
|
|
ff07ff7f13 |
fix(terminal): send SGR mouse wheel reports with the button codes app… (#15817)
* fix(terminal): send SGR mouse wheel reports with the button codes apps expect xterm.dart 4.0.0 encodes the wheel buttons as 64+4..64+7 rather than 64+0..64+3, so the low bits land on the modifier field and every wheel report the terminal emits reads as wheel-with-Shift. Strict full-screen applications reject the modified event, which is why neither the mouse wheel nor the trackpad scrolls anything once the peer application takes over the alternate screen. Install a mouse handler that keeps every upstream reporting decision and only re-encodes the wheel buttons as 64..67. Non-wheel reports pass through untouched, and the emitted bytes stay identical once upstream ships the same fix, so this can be dropped without a behavior change. Upstream: TerminalStudio/xterm.dart#238 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * fix(terminal): correct the wheel report row, drop the wasted report build Address review feedback on the wheel button fix: - The X10/utf row was encoded as `32 + y + 1` while y is already 1-based, so every normal-mode report pointed one row too low and the `y > limit` guard disagreed with what it emitted. - Gate the wheel path on `mouseMode.reportScroll` and the button state instead of building and discarding a full report string from `defaultMouseHandler` on every scroll tick. This also makes the hardcoded SGR 'M' provably right, since a wheel release now returns before the report is built. - Derive the wire code as `id - 4` and drop `_wheelButtonId`, whose `default` branch was unreachable and defeated enum exhaustiveness. - Assign `mouseHandler` after construction so the `Terminal(...)` line stays untouched. Cover the utf, urxvt, null-byte overflow and click-only branches, and assert that TerminalModel actually installs the handler. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> --------- Co-authored-by: Claude Fable 5 <noreply@anthropic.com> |
||
|
|
4234b99029 |
WebClient: 3.44 webcodecs offline (#15722)
* feat(web): zero-readback WebCodecs video path Decoded VideoFrames from js/src/webcodecs.js are handed to Flutter via window.onVideoFrame and imported GPU-side with createImageFromTextureSource; any failure unregisters the hook so the JS side falls back to RGBA readback. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * fix(web): load bundled terminal font when Google CDNs are unreachable In air-gapped deployments GoogleFonts.robotoMono() cannot download the terminal font; when index.html signals offline mode, load the copy bundled with the web app under the family name google_fonts registers. Part of the fix for rustdesk/rustdesk-server-pro#996. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * ci: bump windows arm64 to Flutter 3.44.8, add web build patch script apply_flutter_3.44_web_patches.sh prepares a 3.44.x web build on top of the shared source patches: qr_code_scanner's web impl needs dart:ui_web for the removed platformViewRegistry, and flutter/web/fonts is refreshed to the font paths the 3.44 engine requests. The disabled build-rustdesk-web job runs it automatically once FLUTTER_VERSION moves to 3.44.x, and version-guarded 'Patch flutter' steps no longer fail when the guard does not match. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * fix(web): prevent stale WebCodecs frames across sessions Signed-off-by: fufesou <linlong1266@gmail.com> * fix(web): harden WebCodecs reconnect and Flutter 3.44 patches Signed-off-by: fufesou <linlong1266@gmail.com> * fix(ci): harden Flutter 3.44 patch input validation Validate required files before checking patch state, parameterize the theme-range validator, and prevent missing inputs from satisfying NO_MATCHES checks. Signed-off-by: fufesou <linlong1266@gmail.com> * Remove unused code Signed-off-by: fufesou <linlong1266@gmail.com> * fix(web): retry font loading and dispose stale decoded images Signed-off-by: fufesou <linlong1266@gmail.com> * remove unused code Signed-off-by: fufesou <linlong1266@gmail.com> * fix(web): Bad state: RenderBox was not laid out Signed-off-by: fufesou <linlong1266@gmail.com> --------- Signed-off-by: fufesou <linlong1266@gmail.com> Co-authored-by: Claude Fable 5 <noreply@anthropic.com> Co-authored-by: fufesou <linlong1266@gmail.com> |
||
|
|
a84bad4639 |
refact(oidc): manually open the browser (#15706)
* refact(oidc): manually open the browser Signed-off-by: fufesou <linlong1266@gmail.com> * refact(oidc): allow copying OIDC authentication links Signed-off-by: fufesou <linlong1266@gmail.com> * Remove unused translation in ko.rs Signed-off-by: fufesou <linlong1266@gmail.com> * refact(oidc): better hint on browser didn't open Signed-off-by: fufesou <linlong1266@gmail.com> * refact(oidc): login handle exception Signed-off-by: fufesou <linlong1266@gmail.com> * refact(oidc): remove unused translations Signed-off-by: fufesou <linlong1266@gmail.com> * refact(oidc): login handle error Signed-off-by: fufesou <linlong1266@gmail.com> * refact(oidc): login in flight Signed-off-by: fufesou <linlong1266@gmail.com> * refact(translation): move "Continue" to the end of template.rs Signed-off-by: fufesou <linlong1266@gmail.com> * refact(oidc): var rename Signed-off-by: fufesou <linlong1266@gmail.com> * refact(oidc): remove useless "open sign-in page" Signed-off-by: fufesou <linlong1266@gmail.com> * Remove unecessary translation contents Signed-off-by: fufesou <linlong1266@gmail.com> * refact(oidc): better way to show&expand the url Signed-off-by: fufesou <linlong1266@gmail.com> * refact(oidc): better login ui Signed-off-by: fufesou <linlong1266@gmail.com> * fix(oidc): discard stale auth results after cancellation Signed-off-by: fufesou <linlong1266@gmail.com> * fix(oidc): handle auth status query failures safely Signed-off-by: fufesou <linlong1266@gmail.com> * fix(oidc): prevent concurrent login operations - reuse the active login dialog and block duplicate password submissions - cancel only active OIDC operations when closing the dialog - preserve authentication state until failure cancellation succeeds Signed-off-by: fufesou <linlong1266@gmail.com> * fix(oidc): refine login options error feedback Preserve typed errors to hide the network tip for HTTP failures and clarify the login-options API contract. Signed-off-by: fufesou <linlong1266@gmail.com> --------- Signed-off-by: fufesou <linlong1266@gmail.com> |
||
|
|
e6dd925ab0 |
fix(android): close outgoing sessions when the task is swiped away (#15753)
* fix(android): close outgoing sessions when the task is swiped away
Swiping RustDesk away from recents destroys the UI but does not
necessarily end the process: when MainService is running (screen share
enabled, or started at boot) the process survives, and with it the
native io_loop of any active outgoing session.
That orphaned io_loop keeps echoing TestDelay (client.rs handle_test_delay
runs entirely on the network thread, no UI involved), which keeps
refreshing last_recv_time on the controlled side. Its 30s inactivity
timeout in server/connection.rs therefore never fires, so the remote
session stays established with no UI left to close it, and the peer
cannot be reconnected to.
Close client sessions from Service.onTaskRemoved, which fires only on
explicit task removal -- not on Home or backgrounding, so ordinary
backgrounding is unaffected. The service itself keeps running, so
incoming connections and the device staying reachable are unchanged.
This complements
|
||
|
|
ffe20bb297 |
Login options error feedback (#15727)
* fix(flutter): show error and retry when fetching login options fails The third-party login section of the login dialog was silently hidden whenever /api/login-options could not be fetched (e.g. TLS handshake aborted by a router/ISP scam filter, discussion #15700), leaving users staring at a dialog with no feedback. The pure-Dart HTTP path also had no timeout, so a black-holed connection could hang indefinitely. - let transport errors propagate from queryOidcLoginOptions instead of swallowing them; a non-JSON response still means "no third-party login" so self-hosted servers without this API keep the old behavior - show network_error_tip, a Retry button, and the underlying error in the login dialog so users and supporters can see what failed - bound the Dart HTTP branch with a 15s timeout; the Rust branch keeps its own bounded per-attempt timeouts and is awaited to completion so a retry never races the URL-keyed ASYNC_HTTP_STATUS entry of an abandoned in-flight request Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * fix(flutter): surface currentUser refresh failures that were only logged Non-transport failures of the token auto-login (/api/currentUser) -- a bad HTTP status, a filter's HTML block page, or an error field in the body -- were only debugPrinted, so the address book / group tabs showed nothing and offered no retry. Reuse the existing networkError channel so netWorkErrorWidget shows the error with its Retry button. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * fix(flutter): keep retry row visible with progress while refetching login options Review follow-ups: clicking Retry used to clear the error and hide the row with no pending feedback, which could read as a dead click while the Rust fallback chain runs; keep the row, disable the button, and show the usual LinearProgressIndicator instead. Also raise the Dart HTTP branch timeout to 30s so large web address book pulls on slow links do not newly time out; it still bounds the previously unbounded hang and stays above the Rust side's 12s per-attempt timeout. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * chore: update webpki-roots to latest Mozilla root store 0.26.9 -> 0.26.11 (now a forwarding shim over 1.x, used by tungstenite) 1.0.4 -> 1.0.9 (used by reqwest / hyper-rustls / hbb_common) The 0.26.9 line carried its own root snapshot frozen in early 2025, so the websocket TLS path was building against a stale bundle. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * ci: weekly workflow to PR webpki-roots root store updates webpki-roots is a transitive dependency, so dependabot's cargo version updates would not cover it. A scheduled job runs cargo update for every webpki-roots instance in each lockfile and opens a PR when the pinned Mozilla root snapshot is behind, keeping root store changes reviewable instead of baking them silently into release builds. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * fix(flutter): hide network tip for server-reported currentUser errors Review follow-up: when /api/currentUser fails with an error the server itself reported (an error field in a JSON body, or an unexpected schema), "Please check your network connection" was misleading. Track whether the surfaced error came from a server response and skip the network tip for those; FormatException (a non-JSON body such as a filter's block page) keeps it, since that still indicates a network or middlebox problem. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * fix(flutter): close timed-out HTTP clients * fix(flutter): flag server-reported errors at the throw site Review follow-up (CodeRabbit). Classifying by `e is! FormatException` mislabeled ambiguous failures: a middlebox block page returning 200 with valid-but-wrong-shape JSON throws a TypeError from fromJson and was shown without the check-your-network tip, though it is a network artifact. Set networkErrorFromServer only at the one site that is certainly server-reported (an error field in the body); every other failure keeps the network tip plus the raw error text. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * ci: serialize webpki-roots update runs, null-delimit lockfile paths Review follow-up (CodeRabbit). A manual dispatch overlapping the weekly cron could have an older run force-push over the newer branch state; queue runs via a concurrency group without cancel-in-progress. Also iterate lockfiles with git ls-files -z so a path with spaces cannot be word-split, and keep the loop failing the step on any cargo error. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * fix(flutter): improve login retry feedback Use the theme primary color for the Retry button and hide stale error messages while a retry is in progress. Signed-off-by: fufesou <linlong1266@gmail.com> * fix(flutter): surface login option response errors Signed-off-by: fufesou <linlong1266@gmail.com> --------- Signed-off-by: fufesou <linlong1266@gmail.com> Co-authored-by: Claude Fable 5 <noreply@anthropic.com> Co-authored-by: fufesou <linlong1266@gmail.com> |
||
|
|
a5018a022b |
chore(ios): remove unused GoogleService-Info.plist (#15752)
Leftover from an abandoned Firebase integration. The file is not referenced anywhere in the repository and is not listed in Runner.xcodeproj, so it was never copied into the app bundle. No Firebase or Google Sign-In pod is present in Podfile/Podfile.lock, nothing calls FirebaseApp.configure(), Info.plist declares no REVERSED_CLIENT_ID URL scheme, and on the Dart side both Firebase.initializeApp() and firebase_analytics stay commented out. Note the values it held were Firebase client configuration (project identifiers and a public OAuth client id), which are public by design and ship inside client binaries -- not secrets. This removes dead weight, it is not a credential rotation. Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com> |
||
|
|
006b9737e4 |
fix(linux): load librustdesk.so relative to the executable (#15719)
* fix(linux): load librustdesk.so relative to the executable The runner and the Dart FFI init loaded the core library by bare name, relying on the runner's $ORIGIN/lib RPATH. Repackaged installs (CachyOS repo, AUR) can lose that RPATH, making the app fail to start with "Failed to load librustdesk.so" unless users add the lib directory to ld.so.conf. Resolve lib/librustdesk.so next to the executable first, then fall back to the loader search path. https://github.com/rustdesk/rustdesk/discussions/14407 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * fix(linux): harden bundled librustdesk.so resolution Address review: bail out when readlink() may have truncated the executable path, and widen the Dart try block so any failure probing the bundled library falls back to the loader search path. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> --------- Co-authored-by: Claude Fable 5 <noreply@anthropic.com> |
||
|
|
c6c53f094a |
chore(flutter): bump desktop_multi_window to fix the Windows /WX build
The give-up log added in the white-window follow-ups declared a local named message inside MessageHandler, shadowing its UINT message parameter. MSVC C4457 plus /WX failed both Windows nightly jobs. Point the lock at rustdesk_desktop_multi_window#35 which renames it. https://github.com/rustdesk/rustdesk/actions/runs/30512756157 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> |
||
|
|
9aeb54cf33 |
Fix flutter white window forceredraw (#15717)
* fix(flutter/windows): heal the white window left by a resize around the first frame If the window is resized between the creation of the Flutter surface and the present of the first frame - which is what the PowerToys FancyZones option "Move newly created windows to their last known zone" does - the embedder's resize synchronization enters kResizeStarted and from then on only presents frames that match the new size. A frame already generated for the old size is rejected, nothing schedules a matching one, and the window stays white until a real resize re-enters OnWindowSizeChanged, which resets the resize target and resends the window metrics. Sciter is unaffected: it repaints synchronously on WM_PAINT and has no such handshake. Upstream has no fix (flutter/flutter#159630, open at P3). Recover with a timer armed at creation and re-armed on WM_SHOWWINDOW (covers windows created hidden and shown much later, e.g. the connection manager): until the first frame arrives, kick the engine - first with the cheap ForceRedraw(), which only helps when no resize is pending (it is gated on resize_status_ == kDone), then by nudging the Flutter child window by 1px and back, which re-enters OnWindowSizeChanged and heals the wedge the same way minimize/restore does. Because the first-frame callback fires on frame generation even when the present is rejected, a resize observed before the first frame forces one final child refresh - in practice nearly every window sees a pre-first-frame WM_SIZE, so this acts as a cheap unconditional guarantee. Giving up after 5s is logged. The remote session windows get the same fix in rustdesk_desktop_multi_window. https://github.com/rustdesk/rustdesk/issues/6756 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * chore(flutter): bump desktop_multi_window for the white-window fix Picks up rustdesk-org/rustdesk_desktop_multi_window#33 (340ca43), the session-window side of the FancyZones white-window workaround. Only the resolved-ref of this one dependency is moved; nothing else is upgraded. https://github.com/rustdesk/rustdesk/issues/6756 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * fix(flutter/windows): drop a dead guard and log where users can see it Two follow-ups on the force-redraw timer. The resized_before_first_frame_ guard never discriminated. CreateWindow() sends a WM_SIZE before it returns, and WM_NCCREATE has already installed the window pointer by then, so the flag was set during construction - before OnCreate() even arms the timer - and was therefore always true when the first frame arrived. Drop the flag and do the final child refresh unconditionally, which is what the code already did, and say so instead of implying there is an exceptional case. The give-up message went to std::cerr, which lands nowhere on the machines that hit this: main.cpp only attaches a console when the process is started from one or runs under a debugger. Use OutputDebugString so it is actually readable with DebugView in the field. Also note in the comment that the "callback fires on frame generation" premise is not load-bearing - if it only fired on a successful present, the timer would simply keep nudging - so the redundancy is not mistaken for duplication and removed later. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * chore(flutter): bump desktop_multi_window to pick up the follow-ups Moves the pin from the #33 merge (340ca43) to current master (f8c4fce), which adds #34: the dead resized_before_first_frame_ guard is gone and the give-up message goes to OutputDebugString instead of a stderr nobody sees. Keeps the sub-window fix in step with the runner fix in this branch; without it the two would ship the same logic in two different states. Edited by hand, not via pub upgrade - that re-resolves unrelated packages. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Fable 5 <noreply@anthropic.com> |
||
|
|
12f2de5959 |
chore(flutter): point window_manager at the post-revert main (#15709)
The lock still pinned 7d9a674, the commit rustdesk-org/window_manager#8 reverted. Move it to current main (cf4aef0), which carries the reworked guard for methods called after the toplevel window is destroyed. Edited by hand rather than via pub upgrade: upgrading re-resolved 17 packages, downgrading some and pulling flutter_test and its leak_tracker tree in as new entries, none of which belongs in this change. https://github.com/rustdesk/rustdesk/issues/15703 Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com> |
||
|
|
a6708f40e7 | fix https://github.com/rustdesk/rustdesk/issues/15703 | ||
|
|
d6ea170061 |
Id whitelist (#15586)
* id whitelist * hbb_common * Update flutter/lib/common/widgets/dialog.dart Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * support wss:// for web client Signed-off-by: 21pages <sunboeasy@gmail.com> * fix: handle ID copying separately and remove whitelist logs Signed-off-by: 21pages <sunboeasy@gmail.com> * fix en translation Signed-off-by: 21pages <sunboeasy@gmail.com> * fix: check switch-side ID whitelist after login initialization Signed-off-by: 21pages <sunboeasy@gmail.com> * track pending 2FA challenge state Signed-off-by: 21pages <sunboeasy@gmail.com> * support Unicode IDs in whitelist settings Signed-off-by: 21pages <sunboeasy@gmail.com> * refactor: unify client ID resolution Signed-off-by: 21pages <sunboeasy@gmail.com> --------- Signed-off-by: 21pages <sunboeasy@gmail.com> Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> Co-authored-by: 21pages <sunboeasy@gmail.com> |
||
|
|
eefd22b205 |
fix(macos): prevent remote keyboard focus leaks (#15629)
* fix(macos): prevent remote keyboard focus leaks Gate keyboard grabbing on window, tab, lifecycle, and primary focus state. Release grabs on focus loss or minimize and avoid duplicate grab transitions. Signed-off-by: fufesou <linlong1266@gmail.com> * fix: macos, keyboard focus, comments known issue Signed-off-by: fufesou <linlong1266@gmail.com> * fix: macos, keyboard, fullscreen space switch Signed-off-by: fufesou <linlong1266@gmail.com> * fix: macos, keyboard, focus, relative mouse mode Signed-off-by: fufesou <linlong1266@gmail.com> * fix(macOS): preserve local overlay focus during input recovery Prevent fullscreen and relative-mouse focus recovery from reclaiming remote keyboard input while a local chat or dialog overlay owns focus. Signed-off-by: fufesou <linlong1266@gmail.com> * fix: macos, keyboard, comments trade-off Signed-off-by: fufesou <linlong1266@gmail.com> --------- Signed-off-by: fufesou <linlong1266@gmail.com> |
||
|
|
57456f0b52 |
feat(terminal): add Ctrl and Alt toggles to mobile terminal keyboard (#15532)
* feat(terminal): add Ctrl toggle and Ctrl+X shortcut keys to mobile terminal floating keyboard Signed-off-by: dongrencd <dongrencd@users.noreply.github.com> * refactor(terminal): restructure keyboard layout with collapse button - Move | from Row1 position 3 to Row1 end (aligned with collapse button) - Remove ~ from Row2, add collapse button (∨/∧) after PgDn - Row3: conditional render, add ~ and -, remove trailing placeholders - Collapse state persisted via kOptionEnableShowTerminalCtrlKeys - Row3 defaults to collapsed for compact layout Signed-off-by: dongrencd <dongrencd@users.noreply.github.com> * fix(terminal): restore trailing placeholders in Row3 for alignment Row3 needs trailing placeholders to match Row1/Row2 width (348px) so Ctrl aligns with Tab in Row2 and Esc in Row1. Signed-off-by: dongrencd <dongrencd@users.noreply.github.com> * fix(terminal): update mobile keyboard layout per review Signed-off-by: dong.ren.cd <dong.ren.cd@tcl.com> * fix(terminal): address mobile keyboard review regressions Signed-off-by: dong.ren.cd <dong.ren.cd@tcl.com> * fix(terminal): preserve ctrl-j newline mapping on mobile Signed-off-by: dong.ren.cd <dong.ren.cd@tcl.com> * fix(terminal): preserve pasted input with modifiers Signed-off-by: dong.ren.cd <dong.ren.cd@tcl.com> * fix(terminal): harden mobile modifier and paste input Signed-off-by: dong.ren.cd <dong.ren.cd@tcl.com> * fix(terminal): harden mobile paste shortcut handling Signed-off-by: dong.ren.cd <dong.ren.cd@tcl.com> * fix(terminal): preserve unicode graphemes under ctrl * fix(terminal): avoid modifier scan for inactive locks * fix(terminal): keep default hardware paste shortcuts * fix(terminal): guard hardware paste with modifier locks * fix(terminal): update mobile key button color role --------- Signed-off-by: dongrencd <dongrencd@users.noreply.github.com> Signed-off-by: dong.ren.cd <dong.ren.cd@tcl.com> Co-authored-by: dongrencd <dongrencd@users.noreply.github.com> Co-authored-by: dong.ren.cd <dong.ren.cd@tcl.com> |
||
|
|
cefff781d4 |
feat(recording): add visibility and service storage options (#15662)
* feat(recording): add visibility and service storage options
- support hide-recording-button in Flutter and Sciter
- allow a custom save directory for Windows service recordings
- sanitize peer IDs used in recording filenames
Tested:
- with hide-recording-button=Y and allow-auto-record-outgoing=Y,
outgoing sessions are recorded automatically while the recording button
remains hidden and cannot be stopped from the UI; verified on Flutter
desktop, Sciter, and Android
- windows-service-video-save-directory takes effect when the Windows client
runs as an installed service
- the Windows controlling side can save recordings for direct IP:port
connections
Signed-off-by: 21pages <sunboeasy@gmail.com>
* update hbb_common
Signed-off-by: 21pages <sunboeasy@gmail.com>
* fix(recording): validate configured save directories
- trim configured recording directory paths
- reject non-absolute paths and fall back to defaults
- warn when a non-empty path is invalid
Signed-off-by: 21pages <sunboeasy@gmail.com>
* fix(recording): validate configured save directories
Signed-off-by: 21pages <sunboeasy@gmail.com>
---------
Signed-off-by: 21pages <sunboeasy@gmail.com>
|
||
|
|
929e989f17 |
feat(macos): silent auto-update with security hardening (#15550)
Co-authored-by: bmmh1 <bmmh1@users.noreply.github.com> |
||
|
|
082a5a2a4e |
Revert "Fix Adjust Window sizing across DPI (#15592)" (#15620)
This reverts commit
|
||
|
|
61f0944990 |
Fix Adjust Window sizing across DPI (#15592)
* Fix Adjust Window sizing across DPI and fullscreen transitions Signed-off-by: 21pages <sunboeasy@gmail.com> * Use visible screen frame for Adjust Window Signed-off-by: 21pages <sunboeasy@gmail.com> * Tolerate floating-point errors in Adjust Window sizing Signed-off-by: 21pages <sunboeasy@gmail.com> * Fix review, fix Adjust Window async metric guards Capture the current screen before awaiting window geometry so one target-frame calculation uses consistent screen metrics. Return early when adjusting without a context and the Flutter view list is empty, instead of calling views.first after the window or engine may have been torn down. Clarify the platform coordinate units used for Adjust Window scaling. * Fix Adjust Window for maximized Linux windows Unmaximize Linux remote windows before applying Adjust Window because native setFrame may be ignored while the window is maximized. * Fix Adjust Window screen refresh guards Refresh screen metrics before checking Adjust Window availability and again after exiting fullscreen so target-frame calculation uses current window geometry. Hide Adjust Window on web because resizing relies on desktop window APIs. * Fix review, handle missing window frame in Adjust Window Return null when WindowController.getFrame fails so Adjust Window availability checks and resize attempts skip cleanly if the window is hidden or disposed. --------- Signed-off-by: 21pages <sunboeasy@gmail.com> |
||
|
|
5abf4e9724 |
Fix disabled installation bypass (#15598)
* Fix disabled installation bypass Prevent install.exe and --install from opening the install flow when disable-installation is set. Signed-off-by: 21pages <sunboeasy@gmail.com> * Refine disabled installation handling for portable clients Document why --install must be filtered from both Rust and Flutter runner arguments for portable wrappers such as no-install.exe. Remove redundant UI- layer installation checks because the install entry points are already gated upstream. --------- Signed-off-by: 21pages <sunboeasy@gmail.com> |
||
|
|
94a2a2bb4a | fix https://github.com/rustdesk/rustdesk/issues/15566 | ||
|
|
137298e05a | revert back | ||
|
|
685a89a171 | target Android 15 | ||
|
|
480e9e8234 |
Fix default Android API version mismatch between vcpkg and rest of build (for working on android 6) (#14850)
* Fork vcpkg triplets to keep Android API version on 21 Fixes crash on API platforms 21 to 23 due to missing symbol `__write_chk` (available since API 24). Signed-off-by: Vasyl Gello <vasek.gello@gmail.com> * flutter/build_android_deps.sh: Refactor to remove unused ... variables and shellcheck warnings. Signed-off-by: Vasyl Gello <vasek.gello@gmail.com> --------- Signed-off-by: Vasyl Gello <vasek.gello@gmail.com> |
||
|
|
6c578292e8 | bump to 1.4.9 |