[pull] master from rustdesk:master - #637
Merged
Merged
Conversation
- add admin role CRUD and membership management - add non-protobuf control role operations Signed-off-by: 21pages <sunboeasy@gmail.com>
Re. export and import. Without detailed information, reference or examples from en.rs, de.rs or fr.rs, I have simply translated the three strings verbatim
* feat(portable): load per-customer payload from a PE resource Customizing a Windows client recompiled the packer for every customer, because data.bin was baked in with include_bytes!. The generic payload is identical across customers, so only the small per-customer delta needs to vary: the branded runner exe, custom.txt and the icons. The packer now also reads an RDPKG RCDATA resource holding a second blob in the same format, and folds it over the compiled-in payload. A build can then inject that resource into a prebuilt template instead of running cargo. The executable to launch comes from the package trailer, and the extraction directory follows its stem, which replaces the sed of APP_PREFIX. Where the executable itself is not customized (sciter x86) it stays in the generic payload and is only renamed, so the merge covers both shapes. custom.txt keeps being written to disk next to the app: that is what the client reads at startup and what the updater stages so a customization survives an upgrade to a stock build. Also fixes generate.py restoring os.curdir (the literal ".") instead of the previous working directory, which left it inside the source folder. CI: ship windows-aarch64 in the unsigned tarball, so ARM custom clients have a template to build from. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Q7fBdTwziR5BHTkSz7Tzcm * ci: publish msi templates for custom client builds Custom clients rebuild the msi through WiX for every customer, though the package only differs by the app name, a few GUIDs and four files. Build the msi once more per release with a __RDAPPNAME__ placeholder and ship it unsigned in the unsigned tarball, so a customer's build can patch it rather than run msbuild. It stays unsigned because patching would invalidate a signature anyway. Doing this in CI is what makes ARM custom clients possible: preprocess.py runs the packaged exe to read its version and build date, so an arm64 msi can only be produced on a native arm64 machine, which the runner already is and the build agents are not. Patching runs no exe, so an x64 agent can then patch the arm64 template. preprocess.py rewrites res/msi in place and locates the app as <app-name>.exe inside the dist, so the tree is reset around the second build and the dist copy is renamed to match. Sciter x86 ships no msi and is untouched. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Q7fBdTwziR5BHTkSz7Tzcm * refactor(msi): pass the app name to the printer custom actions preprocess.py rewrote the CustomActions sources per customer so the printer carried the app name, which meant the dll was recompiled for every custom client and, worse, left the app name baked into a compiled binary. Pass it through CustomActionData instead. Only the printer and its port ever varied: the INF path and the driver name ship under their stock names and preprocess.py already forced the driver name back to RustDesk, so a single build of the dll now serves every custom client. Both actions treat the name as optional and fall back to the stock name, so a package built before this still installs and uninstalls its printer. This also unblocks patching a prebuilt msi template, which cannot work while a compiled dll contains the app name: replacing a string inside a PE would shift everything after it. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Q7fBdTwziR5BHTkSz7Tzcm * ci: use an 8.3-safe placeholder for the msi template WiX derives a short name for any name that is not valid 8.3, and a patch cannot rewrite a truncated placeholder, so a long placeholder would leave the package's short names pointing at it. RDAPPNAM is eight characters like "RustDesk" and needs no short name, keeping the template as close to the shipped package as the mechanism allows. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Q7fBdTwziR5BHTkSz7Tzcm * feat(msi): give a template its own cabinet for per-customer files Rebranding recompressed the whole ~100MB payload because one cabinet held everything. In template mode preprocess.py puts the handful of files a custom client replaces on a second cabinet, so a patch rebuilds a few hundred KB and leaves the payload cabinet alone. The shipped msi is built without template mode and keeps its single cabinet. The branding assets need conditional components. A stock build ships none of them -- there is no icon.ico, icon.png or logo*.png, only icon.svg -- so the template has to carry placeholders for the File rows to exist, and a customer supplies whichever they want. Installing a placeholder unconditionally would give a customer with no logo a placeholder image, where today a missing asset means no logo at all: the client tries each candidate and treats the failure as absence. So each optional asset installs only when its property says the customer supplied one. CI creates those placeholders and builds the template with the new mode. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Q7fBdTwziR5BHTkSz7Tzcm * ci: build the msi template with a sentinel revision preprocess.py appends a build-time revision as the fourth version field, so a template built without one would bake the CI clock into every customer's package. Revision 0 marks the field as the patcher's to fill in, and makes the template deterministic. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Q7fBdTwziR5BHTkSz7Tzcm * fix(portable): delete files a later package no longer carries The extraction directory is wiped only when the packer's compiled-in timestamp changes. That used to be per customer, because generate.py ran for each build; now the packer is compiled once per release, so every customer and every rebuild within a release share one timestamp and nothing is ever wiped. A customer who removes their logo and rebuilds would therefore keep showing it: the new package simply omits logo.png, and md5 skipping only covers files that are still present. Record the package's paths in the extraction's meta file and delete the ones a later package drops. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Q7fBdTwziR5BHTkSz7Tzcm * fix(portable): build the dropped-file path from plain components meta.toml lives in a user-writable directory and now drives deletion, but the traversal guard tested the normalised string while the join used the raw one. Path::join replaces the base outright when handed an absolute path, so an edited meta.toml could point remove_file anywhere. The path is now rebuilt from Normal components only. A colon is rejected explicitly rather than left to the host's parser: a drive-relative "C:x" parses as a Normal component everywhere, and only a Windows host reads "C:/..." as a prefix, so the same input escaped when the logic was exercised off-Windows -- which is what the new test catches. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Q7fBdTwziR5BHTkSz7Tzcm * fix(msi): pass the printer name in a format the custom action can read [~] is MSI's escape for a NUL character, not the delimiter WcaReadStringFromCaData splits on -- that is a literal wide char 128, which a Formatted property value cannot carry -- and WcaGetProperty returns a null-terminated string anyway. So the second field was unreachable: InstallPrinter always fell back to the stock name and installed a printer and port called "RustDesk Printer" inside a customer's branded package, while UninstallPrinter, whose data is a single field and parsed fine, went looking for "Acme Printer" and left the real one behind for good. Both actions now read CustomActionData directly and split on a character that cannot occur in a Windows path or in a validated app name. A package built before this carries no separator and keeps the stock name, as it did. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Q7fBdTwziR5BHTkSz7Tzcm * fix(portable): retry failed stale branding cleanup Signed-off-by: fufesou <linlong1266@gmail.com> * fix(portable): reject malformed RDPKG resources Distinguish an absent customer package from an invalid resource and propagate package errors instead of launching the stock payload. Signed-off-by: fufesou <linlong1266@gmail.com> * refact: format 2 files Signed-off-by: fufesou <linlong1266@gmail.com> * fix(msi): match process names case-insensitively during uninstall Signed-off-by: fufesou <linlong1266@gmail.com> * fix(custom-client): validate portable exclusion and MSI action data Fail when --exclude-exe does not match a file, and propagate MSI CustomActionData read failures while preserving legacy fallback behavior. Signed-off-by: fufesou <linlong1266@gmail.com> * fix: generate.py, exclude-exe Signed-off-by: fufesou <linlong1266@gmail.com> * Revert "fix: generate.py, exclude-exe" This reverts commit 5104664. * fix: simple path fix in generate.py Signed-off-by: fufesou <linlong1266@gmail.com> * Remove useless comments Signed-off-by: fufesou <linlong1266@gmail.com> * fix(portable): remove expect() anyway Signed-off-by: fufesou <linlong1266@gmail.com> * fix(portable): validate executable path boundaries Reject executables outside the source folder and reuse the package path normalization logic during stale file cleanup. Signed-off-by: fufesou <linlong1266@gmail.com> * fix, remove useless file Signed-off-by: fufesou <linlong1266@gmail.com> --------- Signed-off-by: fufesou <linlong1266@gmail.com> Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com> Co-authored-by: fufesou <linlong1266@gmail.com>
Translate export-related strings to Portuguese
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to subscribe to this conversation on GitHub.
Already have an account?
Sign in.
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
See Commits and Changes for more details.
Created by
pull[bot] (v2.0.0-alpha.4)
Can you help keep this open source service alive? 💖 Please sponsor : )