mirror of
https://github.com/weyne85/rustdesk.git
synced 2025-10-29 17:00:05 +00:00
Fix conflicts
This commit is contained in:
commit
bcfb649815
2
.github/workflows/flutter-nightly.yml
vendored
2
.github/workflows/flutter-nightly.yml
vendored
@ -86,7 +86,7 @@ jobs:
|
||||
shell: bash
|
||||
|
||||
- name: Build rustdesk
|
||||
run: python3 .\build.py --portable --hwcodec --flutter
|
||||
run: python3 .\build.py --portable --hwcodec --flutter --feature IddDriver
|
||||
|
||||
- name: Sign rustdesk files
|
||||
uses: GermanBluefox/code-sign-action@v7
|
||||
|
||||
1
Cargo.lock
generated
1
Cargo.lock
generated
@ -4943,6 +4943,7 @@ dependencies = [
|
||||
"flutter_rust_bridge_codegen",
|
||||
"fruitbasket",
|
||||
"hbb_common",
|
||||
"hex",
|
||||
"hound",
|
||||
"image 0.24.5",
|
||||
"impersonate_system",
|
||||
|
||||
@ -64,6 +64,7 @@ errno = "0.2.8"
|
||||
rdev = { git = "https://github.com/fufesou/rdev" }
|
||||
url = { version = "2.1", features = ["serde"] }
|
||||
dlopen = "0.1"
|
||||
hex = "0.4.3"
|
||||
|
||||
reqwest = { version = "0.11", features = ["blocking", "json", "rustls-tls"], default-features=false }
|
||||
chrono = "0.4.23"
|
||||
@ -87,7 +88,7 @@ system_shutdown = "3.0.0"
|
||||
[target.'cfg(target_os = "windows")'.dependencies]
|
||||
trayicon = { git = "https://github.com/open-trade/trayicon-rs", features = ["winit"] }
|
||||
winit = "0.26"
|
||||
winapi = { version = "0.3", features = ["winuser"] }
|
||||
winapi = { version = "0.3", features = ["winuser", "wincrypt"] }
|
||||
winreg = "0.10"
|
||||
windows-service = "0.4"
|
||||
virtual_display = { path = "libs/virtual_display" }
|
||||
|
||||
2
build.py
2
build.py
@ -37,7 +37,7 @@ def parse_rc_features(feature):
|
||||
'IddDriver': {
|
||||
'zip_url': 'https://github.com/fufesou/RustDeskIddDriver/releases/download/v0.1/RustDeskIddDriver_x64.zip',
|
||||
'checksum_url': 'https://github.com/fufesou/RustDeskIddDriver/releases/download/v0.1/checksum_md5',
|
||||
'exclude': ['README.md'],
|
||||
'exclude': ['README.md', 'certmgr.exe', 'install_cert_runas_admin.bat'],
|
||||
},
|
||||
'PrivacyMode': {
|
||||
'zip_url': 'https://github.com/fufesou/RustDeskTempTopMostWindow/releases/download/v0.1'
|
||||
|
||||
@ -6,18 +6,18 @@
|
||||
<a href="#dateistruktur">Dateistruktur</a> •
|
||||
<a href="#screenshots">Screenshots</a><br>
|
||||
[<a href="../README.md">English</a>] | [<a href="README-UA.md">Українська</a>] | [<a href="README-CS.md">česky</a>] | [<a href="README-ZH.md">中文</a>] | [<a href="README-HU.md">Magyar</a>] | [<a href="README-ES.md">Español</a>] | [<a href="README-FA.md">فارسی</a>] | [<a href="README-FR.md">Français</a>] | [<a href="README-PL.md">Polski</a>] | [<a href="README-ID.md">Indonesian</a>] | [<a href="README-FI.md">Suomi</a>] | [<a href="README-ML.md">മലയാളം</a>] | [<a href="README-JP.md">日本語</a>] | [<a href="README-NL.md">Nederlands</a>] | [<a href="README-IT.md">Italiano</a>] | [<a href="README-RU.md">Русский</a>] | [<a href="README-PTBR.md">Português (Brasil)</a>] | [<a href="README-EO.md">Esperanto</a>] | [<a href="README-KR.md">한국어</a>] | [<a href="README-AR.md">العربي</a>] | [<a href="README-VN.md">Tiếng Việt</a>] | [<a href="README-DA.md">Dansk</a>] | [<a href="README-GR.md">Ελληνικά</a>]<br>
|
||||
<b>Wir brauchen deine Hilfe, um dieses README, die <a href="https://github.com/rustdesk/rustdesk/tree/master/src/lang">RustDesk-Benutzeroberfläche</a> und die <a href="https://github.com/rustdesk/doc.rustdesk.com">Dokumentation</a> in deine Muttersprache zu übersetzen.</b>
|
||||
<b>Wir brauchen Ihre Hilfe, um dieses README, die <a href="https://github.com/rustdesk/rustdesk/tree/master/src/lang">RustDesk-Benutzeroberfläche</a> und die <a href="https://github.com/rustdesk/doc.rustdesk.com">Dokumentation</a> in Ihre Muttersprache zu übersetzen.</b>
|
||||
</p>
|
||||
|
||||
Rede mit uns auf: [Discord](https://discord.gg/nDceKgxnkV) | [Twitter](https://twitter.com/rustdesk) | [Reddit](https://www.reddit.com/r/rustdesk)
|
||||
Reden Sie mit uns auf: [Discord](https://discord.gg/nDceKgxnkV) | [Twitter](https://twitter.com/rustdesk) | [Reddit](https://www.reddit.com/r/rustdesk)
|
||||
|
||||
[](https://ko-fi.com/I2I04VU09)
|
||||
|
||||
RustDesk ist eine in Rust geschriebene Remote-Desktop-Software, die out of the box ohne besondere Konfiguration funktioniert. Du hast die volle Kontrolle über deine Daten und musst dir keine Sorgen um die Sicherheit machen. Du kannst unseren Rendezvous/Relay-Server nutzen, [einen eigenen Server aufsetzen](https://rustdesk.com/server) oder [einen eigenen Server programmieren](https://github.com/rustdesk/rustdesk-server-demo).
|
||||
RustDesk ist eine in Rust geschriebene Remote-Desktop-Software, die out of the box ohne besondere Konfiguration funktioniert. Sie haben die volle Kontrolle über Ihre Daten und müssen sich keine Sorgen um die Sicherheit machen. Sie können unseren Rendezvous/Relay-Server nutzen, [einen eigenen Server aufsetzen](https://rustdesk.com/server) oder [einen eigenen Server programmieren](https://github.com/rustdesk/rustdesk-server-demo).
|
||||
|
||||

|
||||
|
||||
RustDesk heißt jegliche Mitarbeit willkommen. Schau dir [CONTRIBUTING-DE.md](CONTRIBUTING-DE.md) an, wenn du Unterstützung beim Start brauchst.
|
||||
RustDesk heißt jegliche Mitarbeit willkommen. Schauen Sie sich [CONTRIBUTING-DE.md](CONTRIBUTING-DE.md) an, wenn Sie Unterstützung beim Start brauchen.
|
||||
|
||||
[**FAQ**](https://github.com/rustdesk/rustdesk/wiki/FAQ)
|
||||
|
||||
@ -31,29 +31,29 @@ RustDesk heißt jegliche Mitarbeit willkommen. Schau dir [CONTRIBUTING-DE.md](CO
|
||||
|
||||
## Freie öffentliche Server
|
||||
|
||||
Nachfolgend sind die Server gelistet, die du kostenlos nutzen kannst. Es kann sein, dass sich diese Liste immer mal wieder ändert. Falls du nicht in der Nähe einer dieser Server bist, kann es sein, dass deine Verbindung langsam sein wird.
|
||||
Nachfolgend sind die Server gelistet, die Sie kostenlos nutzen können. Es kann sein, dass sich diese Liste immer mal wieder ändert. Falls Sie nicht in der Nähe einer dieser Server sind, kann es sein, dass Ihre Verbindung langsam sein wird.
|
||||
| Standort | Anbieter | Spezifikation |
|
||||
| --------- | ------------- | ------------------ |
|
||||
| Südkorea (Seoul) | AWS lightsail | 1 vCPU / 0,5 GB RAM |
|
||||
| Deutschland | Hetzner | 2 vCPU / 4 GB RAM |
|
||||
| Deutschland | Codext | 4 vCPU / 8 GB RAM |
|
||||
| Finnland (Helsinki) | 0x101 Cyber Security | 4 vCPU / 8 GB RAM |
|
||||
| USA (Ashburn) | 0x101 Cyber Security | 4 vCPU / 8 GB RAM |
|
||||
| Ukraine (Kiew) | dc.volia (2VM) | 2 vCPU / 4 GB RAM |
|
||||
| Südkorea (Seoul) | [AWS lightsail](https://aws.amazon.com/de/) | 1 vCPU / 0,5 GB RAM |
|
||||
| Deutschland | [Hetzner](https://www.hetzner.com/de/) | 2 vCPU / 4 GB RAM |
|
||||
| Deutschland | [Codext](https://codext.de/) | 4 vCPU / 8 GB RAM |
|
||||
| Finnland (Helsinki) | [Netlock](https://netlockendpoint.com/de/index.html) | 4 vCPU / 8 GB RAM |
|
||||
| USA (Ashburn) | [Netlock](https://netlockendpoint.com/de/index.html) | 4 vCPU / 8 GB RAM |
|
||||
| Ukraine (Kiew) | [dc.volia](https://dc.volia.com) | 2 vCPU / 4 GB RAM |
|
||||
|
||||
## Dev-Container
|
||||
|
||||
[](https://vscode.dev/redirect?url=vscode://ms-vscode-remote.remote-containers/cloneInVolume?url=https://github.com/rustdesk/rustdesk)
|
||||
|
||||
Wenn du VS Code und Docker bereits installiert hast, kannst du auf das Abzeichen oben klicken, um loszulegen. Wenn du darauf klickst, wird VS Code automatisch die Dev-Container-Erweiterung installieren, den Quellcode in ein Container-Volume klonen und einen Dev-Container für die Verwendung aufsetzen.
|
||||
Wenn Sie VS Code und Docker bereits installiert haben, können Sie auf das Abzeichen oben klicken, um loszulegen. Wenn Sie darauf klicken, wird VS Code automatisch die Dev-Container-Erweiterung installieren, den Quellcode in ein Container-Volume klonen und einen Dev-Container für die Verwendung aufsetzen.
|
||||
|
||||
Weitere Informationen findest du in [DEVCONTAINER-DE.md](DEVCONTAINER-DE.md).
|
||||
Weitere Informationen finden Sie in [DEVCONTAINER-DE.md](DEVCONTAINER-DE.md).
|
||||
|
||||
## Abhängigkeiten
|
||||
|
||||
Desktop-Versionen verwenden [Sciter](https://sciter.com/) oder Flutter für die GUI, dieses Tutorial ist nur für Sciter.
|
||||
|
||||
Bitte lade die dynamische Bibliothek Sciter selbst herunter.
|
||||
Bitte laden Sie die dynamische Bibliothek Sciter selbst herunter.
|
||||
|
||||
[Windows](https://raw.githubusercontent.com/c-smile/sciter-sdk/master/bin.win/x64/sciter.dll) |
|
||||
[Linux](https://raw.githubusercontent.com/c-smile/sciter-sdk/master/bin.lnx/x64/libsciter-gtk.so) |
|
||||
@ -61,14 +61,14 @@ Bitte lade die dynamische Bibliothek Sciter selbst herunter.
|
||||
|
||||
## Grobe Schritte zum Kompilieren
|
||||
|
||||
- Bereite deine Rust-Entwicklungsumgebung und C++-Build-Umgebung vor
|
||||
- Bereiten Sie Ihre Rust-Entwicklungsumgebung und C++-Build-Umgebung vor
|
||||
|
||||
- Installiere [vcpkg](https://github.com/microsoft/vcpkg) und füge die Systemumgebungsvariable `VCPKG_ROOT` hinzu
|
||||
- Installieren Sie [vcpkg](https://github.com/microsoft/vcpkg) und fügen Sie die Systemumgebungsvariable `VCPKG_ROOT` hinzu
|
||||
|
||||
- Windows: `vcpkg install libvpx:x64-windows-static libyuv:x64-windows-static opus:x64-windows-static`
|
||||
- Linux/macOS: `vcpkg install libvpx libyuv opus`
|
||||
|
||||
- Nutze `cargo run`
|
||||
- Nutzen Sie `cargo run`
|
||||
|
||||
## [Erstellen](https://rustdesk.com/docs/de/dev/build/)
|
||||
|
||||
@ -167,7 +167,7 @@ method return time=1662544486.931020 sender=:1.54 -> destination=:1.139 serial=2
|
||||
|
||||
## Auf Docker kompilieren
|
||||
|
||||
Beginne damit, das Repository zu klonen und den Docker-Container zu bauen:
|
||||
Beginnen Sie damit, das Repository zu klonen und den Docker-Container zu bauen:
|
||||
|
||||
```sh
|
||||
git clone https://github.com/rustdesk/rustdesk
|
||||
@ -175,25 +175,25 @@ cd rustdesk
|
||||
docker build -t "rustdesk-builder" .
|
||||
```
|
||||
|
||||
Führe jedes Mal, wenn du das Programm kompilieren musst, folgenden Befehl aus:
|
||||
Führen Sie jedes Mal, wenn Sie das Programm kompilieren müssen, folgenden Befehl aus:
|
||||
|
||||
```sh
|
||||
docker run --rm -it -v $PWD:/home/user/rustdesk -v rustdesk-git-cache:/home/user/.cargo/git -v rustdesk-registry-cache:/home/user/.cargo/registry -e PUID="$(id -u)" -e PGID="$(id -g)" rustdesk-builder
|
||||
```
|
||||
|
||||
Bedenke, dass das erste Kompilieren länger dauern kann, bis die Abhängigkeiten zwischengespeichert sind. Nachfolgende Kompiliervorgänge sind schneller. Wenn du verschiedene Argumente für den Kompilierbefehl angeben musst, kannst du dies am Ende des Befehls an der Position `<OPTIONAL-ARGS>` tun. Wenn du zum Beispiel eine optimierte Releaseversion kompilieren willst, kannst du `--release` am Ende des Befehls anhängen. Das daraus entstehende Programm findest du im Zielordner auf deinem System. Du kannst es mit folgendem Befehl ausführen:
|
||||
Bedenken Sie, dass das erste Kompilieren länger dauern kann, bis die Abhängigkeiten zwischengespeichert sind. Nachfolgende Kompiliervorgänge sind schneller. Wenn Sie verschiedene Argumente für den Kompilierbefehl angeben müssen, können Sie dies am Ende des Befehls an der Position `<OPTIONAL-ARGS>` tun. Wenn Sie zum Beispiel eine optimierte Releaseversion kompilieren wollen, können Sie `--release` am Ende des Befehls anhängen. Das daraus entstehende Programm finden Sie im Zielordner auf Ihrem System. Sie können es mit folgendem Befehl ausführen:
|
||||
|
||||
```sh
|
||||
target/debug/rustdesk
|
||||
```
|
||||
|
||||
Oder, wenn du eine Releaseversion benutzt:
|
||||
Oder, wenn Sie eine Releaseversion benutzen:
|
||||
|
||||
```sh
|
||||
target/release/rustdesk
|
||||
```
|
||||
|
||||
Bitte stelle sicher, dass du diese Befehle im Stammverzeichnis des RustDesk-Repositorys nutzt. Ansonsten kann es passieren, dass das Programm die Ressourcen nicht finden kann. Bitte bedenke auch, dass andere Cargo-Unterbefehle wie `install` oder `run` aktuell noch nicht unterstützt werden, da sie das Programm innerhalb des Containers starten oder installieren würden, anstatt auf deinem eigentlichen System.
|
||||
Bitte stellen Sie sicher, dass Sie diese Befehle im Stammverzeichnis des RustDesk-Repositorys nutzen. Ansonsten kann es passieren, dass das Programm die Ressourcen nicht finden kann. Bitte bedenken Sie auch, dass andere Cargo-Unterbefehle wie `install` oder `run` aktuell noch nicht unterstützt werden, da sie das Programm innerhalb des Containers starten oder installieren würden, anstatt auf Ihrem eigentlichen System.
|
||||
|
||||
## Dateistruktur
|
||||
|
||||
|
||||
@ -623,7 +623,7 @@ class MainService : Service() {
|
||||
.setAutoCancel(true)
|
||||
.setPriority(NotificationCompat.PRIORITY_DEFAULT)
|
||||
.setContentTitle(DEFAULT_NOTIFY_TITLE)
|
||||
.setContentText(translate(DEFAULT_NOTIFY_TEXT) + '!')
|
||||
.setContentText(translate(DEFAULT_NOTIFY_TEXT))
|
||||
.setOnlyAlertOnce(true)
|
||||
.setContentIntent(pendingIntent)
|
||||
.setColor(ContextCompat.getColor(this, R.color.primary))
|
||||
@ -689,7 +689,7 @@ class MainService : Service() {
|
||||
|
||||
private fun setTextNotification(_title: String?, _text: String?) {
|
||||
val title = _title ?: DEFAULT_NOTIFY_TITLE
|
||||
val text = _text ?: translate(DEFAULT_NOTIFY_TEXT) + '!'
|
||||
val text = _text ?: translate(DEFAULT_NOTIFY_TEXT)
|
||||
val notification = notificationBuilder
|
||||
.clearActions()
|
||||
.setStyle(null)
|
||||
|
||||
@ -368,7 +368,7 @@ class MyTheme {
|
||||
|
||||
static void changeDarkMode(ThemeMode mode) async {
|
||||
Get.changeThemeMode(mode);
|
||||
if (desktopType == DesktopType.main) {
|
||||
if (desktopType == DesktopType.main || isAndroid || isIOS) {
|
||||
if (mode == ThemeMode.system) {
|
||||
await bind.mainSetLocalOption(key: kCommConfKeyTheme, value: '');
|
||||
} else {
|
||||
@ -946,7 +946,6 @@ Widget msgboxContent(String type, String title, String text) {
|
||||
void msgBoxCommon(OverlayDialogManager dialogManager, String title,
|
||||
Widget content, List<Widget> buttons,
|
||||
{bool hasCancel = true}) {
|
||||
dialogManager.dismissAll();
|
||||
dialogManager.show((setState, close) => CustomAlertDialog(
|
||||
title: Text(
|
||||
translate(title),
|
||||
|
||||
@ -1130,7 +1130,7 @@ void _rdpDialog(String id) async {
|
||||
}
|
||||
|
||||
return CustomAlertDialog(
|
||||
title: Text('RDP ${translate('Settings')}'),
|
||||
title: Text(translate('RDP Settings')),
|
||||
content: ConstrainedBox(
|
||||
constraints: const BoxConstraints(minWidth: 500),
|
||||
child: Column(
|
||||
@ -1141,56 +1141,67 @@ void _rdpDialog(String id) async {
|
||||
),
|
||||
Row(
|
||||
children: [
|
||||
ConstrainedBox(
|
||||
isDesktop
|
||||
? ConstrainedBox(
|
||||
constraints: const BoxConstraints(minWidth: 140),
|
||||
child: Text(
|
||||
"${translate('Port')}:",
|
||||
textAlign: TextAlign.right,
|
||||
).marginOnly(right: 10)),
|
||||
).marginOnly(right: 10))
|
||||
: SizedBox.shrink(),
|
||||
Expanded(
|
||||
child: TextField(
|
||||
inputFormatters: [
|
||||
FilteringTextInputFormatter.allow(RegExp(
|
||||
r'^([0-9]|[1-9]\d|[1-9]\d{2}|[1-9]\d{3}|[1-5]\d{4}|6[0-4]\d{3}|65[0-4]\d{2}|655[0-2]\d|6553[0-5])$'))
|
||||
],
|
||||
decoration: const InputDecoration(
|
||||
border: OutlineInputBorder(), hintText: '3389'),
|
||||
decoration: InputDecoration(
|
||||
labelText: isDesktop ? null : translate('Port'),
|
||||
border: isDesktop ? const OutlineInputBorder() : null,
|
||||
hintText: '3389'),
|
||||
controller: portController,
|
||||
autofocus: true,
|
||||
),
|
||||
),
|
||||
],
|
||||
).marginOnly(bottom: 8),
|
||||
).marginOnly(bottom: isDesktop ? 8 : 0),
|
||||
Row(
|
||||
children: [
|
||||
ConstrainedBox(
|
||||
isDesktop
|
||||
? ConstrainedBox(
|
||||
constraints: const BoxConstraints(minWidth: 140),
|
||||
child: Text(
|
||||
"${translate('Username')}:",
|
||||
textAlign: TextAlign.right,
|
||||
).marginOnly(right: 10)),
|
||||
).marginOnly(right: 10))
|
||||
: SizedBox.shrink(),
|
||||
Expanded(
|
||||
child: TextField(
|
||||
decoration:
|
||||
const InputDecoration(border: OutlineInputBorder()),
|
||||
decoration: InputDecoration(
|
||||
labelText: isDesktop ? null : translate('Username'),
|
||||
border: isDesktop ? const OutlineInputBorder() : null),
|
||||
controller: userController,
|
||||
),
|
||||
),
|
||||
],
|
||||
).marginOnly(bottom: 8),
|
||||
).marginOnly(bottom: isDesktop ? 8 : 0),
|
||||
Row(
|
||||
children: [
|
||||
ConstrainedBox(
|
||||
isDesktop
|
||||
? ConstrainedBox(
|
||||
constraints: const BoxConstraints(minWidth: 140),
|
||||
child: Text(
|
||||
"${translate('Password')}:",
|
||||
textAlign: TextAlign.right,
|
||||
).marginOnly(right: 10)),
|
||||
).marginOnly(right: 10))
|
||||
: SizedBox.shrink(),
|
||||
Expanded(
|
||||
child: Obx(() => TextField(
|
||||
obscureText: secure.value,
|
||||
decoration: InputDecoration(
|
||||
border: const OutlineInputBorder(),
|
||||
labelText: isDesktop ? null : translate('Password'),
|
||||
border:
|
||||
isDesktop ? const OutlineInputBorder() : null,
|
||||
suffixIcon: IconButton(
|
||||
onPressed: () => secure.value = !secure.value,
|
||||
icon: Icon(secure.value
|
||||
@ -1200,7 +1211,7 @@ void _rdpDialog(String id) async {
|
||||
)),
|
||||
),
|
||||
],
|
||||
).marginOnly(bottom: 8),
|
||||
).marginOnly(bottom: isDesktop ? 8 : 0),
|
||||
],
|
||||
),
|
||||
),
|
||||
|
||||
@ -14,7 +14,10 @@ const String kPeerPlatformAndroid = "Android";
|
||||
|
||||
/// [kAppTypeMain] used by 'Desktop Main Page' , 'Mobile (Client and Server)', "Install Page"
|
||||
const String kAppTypeMain = "main";
|
||||
|
||||
/// [kAppTypeConnectionManager] only for 'Desktop CM Page'
|
||||
const String kAppTypeConnectionManager = "cm";
|
||||
|
||||
const String kAppTypeDesktopRemote = "remote";
|
||||
const String kAppTypeDesktopFileTransfer = "file transfer";
|
||||
const String kAppTypeDesktopPortForward = "port forward";
|
||||
|
||||
@ -1,3 +1,5 @@
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:file_picker/file_picker.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_hbb/common.dart';
|
||||
@ -63,6 +65,7 @@ class _InstallPageBodyState extends State<_InstallPageBody>
|
||||
late final TextEditingController controller;
|
||||
final RxBool startmenu = true.obs;
|
||||
final RxBool desktopicon = true.obs;
|
||||
final RxBool driverCert = true.obs;
|
||||
final RxBool showProgress = false.obs;
|
||||
final RxBool btnEnabled = true.obs;
|
||||
|
||||
@ -145,26 +148,63 @@ class _InstallPageBodyState extends State<_InstallPageBody>
|
||||
.marginOnly(left: em))
|
||||
],
|
||||
).marginSymmetric(vertical: 2 * em),
|
||||
Row(
|
||||
TextButton(
|
||||
onPressed: () => startmenu.value = !startmenu.value,
|
||||
child: Row(
|
||||
children: [
|
||||
Obx(() => Checkbox(
|
||||
value: startmenu.value,
|
||||
onChanged: (b) {
|
||||
if (b != null) startmenu.value = b;
|
||||
})),
|
||||
Text(translate('Create start menu shortcuts'))
|
||||
RichText(
|
||||
text: TextSpan(
|
||||
text: translate('Create start menu shortcuts'),
|
||||
style: DefaultTextStyle.of(context).style,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
Row(
|
||||
),
|
||||
TextButton(
|
||||
onPressed: () => desktopicon.value = !desktopicon.value,
|
||||
child: Row(
|
||||
children: [
|
||||
Obx(() => Checkbox(
|
||||
value: desktopicon.value,
|
||||
onChanged: (b) {
|
||||
if (b != null) desktopicon.value = b;
|
||||
})),
|
||||
Text(translate('Create desktop icon'))
|
||||
RichText(
|
||||
text: TextSpan(
|
||||
text: translate('Create desktop icon'),
|
||||
style: DefaultTextStyle.of(context).style,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
Offstage(
|
||||
offstage: !Platform.isWindows,
|
||||
child: TextButton(
|
||||
onPressed: () => driverCert.value = !driverCert.value,
|
||||
child: Row(
|
||||
children: [
|
||||
Obx(() => Checkbox(
|
||||
value: driverCert.value,
|
||||
onChanged: (b) {
|
||||
if (b != null) driverCert.value = b;
|
||||
})),
|
||||
RichText(
|
||||
text: TextSpan(
|
||||
text: translate('idd_driver_tip'),
|
||||
style: DefaultTextStyle.of(context).style,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
GestureDetector(
|
||||
onTap: () => launchUrlString('http://rustdesk.com/privacy'),
|
||||
child: Row(
|
||||
@ -225,14 +265,49 @@ class _InstallPageBodyState extends State<_InstallPageBody>
|
||||
}
|
||||
|
||||
void install() {
|
||||
do_install() {
|
||||
btnEnabled.value = false;
|
||||
showProgress.value = true;
|
||||
String args = '';
|
||||
if (startmenu.value) args += ' startmenu';
|
||||
if (desktopicon.value) args += ' desktopicon';
|
||||
if (driverCert.value) args += ' driverCert';
|
||||
bind.installInstallMe(options: args, path: controller.text);
|
||||
}
|
||||
|
||||
if (driverCert.isTrue) {
|
||||
final tag = 'install-info-install-cert-confirm';
|
||||
final btns = [
|
||||
dialogButton(
|
||||
'Cancel',
|
||||
onPressed: () => gFFI.dialogManager.dismissByTag(tag),
|
||||
isOutline: true,
|
||||
),
|
||||
dialogButton(
|
||||
'OK',
|
||||
onPressed: () {
|
||||
gFFI.dialogManager.dismissByTag(tag);
|
||||
do_install();
|
||||
},
|
||||
isOutline: false,
|
||||
),
|
||||
];
|
||||
gFFI.dialogManager.show(
|
||||
(setState, close) => CustomAlertDialog(
|
||||
title: null,
|
||||
content: SelectionArea(
|
||||
child:
|
||||
msgboxContent('info', 'Warning', 'confirm_idd_driver_tip')),
|
||||
actions: btns,
|
||||
onCancel: close,
|
||||
),
|
||||
tag: tag,
|
||||
);
|
||||
} else {
|
||||
do_install();
|
||||
}
|
||||
}
|
||||
|
||||
void selectInstallPath() async {
|
||||
String? install_path = await FilePicker.platform
|
||||
.getDirectoryPath(initialDirectory: controller.text);
|
||||
|
||||
@ -263,8 +263,11 @@ class ServerModel with ChangeNotifier {
|
||||
toggleInput() {
|
||||
if (_inputOk) {
|
||||
parent.target?.invokeMethod("stop_input");
|
||||
bind.mainSetOption(key: "enable-keyboard", value: 'N');
|
||||
} else {
|
||||
if (parent.target != null) {
|
||||
/// the result of toggle-on depends on user actions in the settings page.
|
||||
/// handle result, see [ServerModel.changeStatue]
|
||||
showInputWarnAlert(parent.target!);
|
||||
}
|
||||
}
|
||||
|
||||
@ -81,8 +81,10 @@ fn get_display_server_of_session(session: &str) -> String {
|
||||
display_server = sestype;
|
||||
}
|
||||
}
|
||||
// If the session is not a tty, then just return the type as usual
|
||||
display_server
|
||||
if display_server == "" {
|
||||
display_server = "x11".to_owned();
|
||||
}
|
||||
display_server.to_lowercase()
|
||||
}
|
||||
|
||||
pub fn get_values_of_seat0(indices: Vec<usize>) -> Vec<String> {
|
||||
|
||||
@ -143,6 +143,10 @@ pub fn core_main() -> Option<Vec<String>> {
|
||||
#[cfg(feature = "with_rc")]
|
||||
hbb_common::allow_err!(crate::rc::extract_resources(&args[1]));
|
||||
return None;
|
||||
} else if args[0] == "--install-cert" {
|
||||
#[cfg(windows)]
|
||||
hbb_common::allow_err!(crate::platform::windows::install_cert(&args[1]));
|
||||
return None;
|
||||
} else if args[0] == "--portable-service" {
|
||||
crate::platform::elevate_or_run_as_system(
|
||||
click_setup,
|
||||
|
||||
@ -26,8 +26,14 @@ use std::{
|
||||
sync::{Arc, RwLock},
|
||||
};
|
||||
|
||||
/// tag "main" for [Desktop Main Page] and [Mobile (Client and Server)] (the mobile don't need multiple windows, only one global event stream is needed)
|
||||
/// tag "cm" only for [Desktop CM Page]
|
||||
pub(super) const APP_TYPE_MAIN: &str = "main";
|
||||
#[cfg(not(any(target_os = "android", target_os = "ios")))]
|
||||
pub(super) const APP_TYPE_CM: &str = "cm";
|
||||
#[cfg(any(target_os = "android", target_os = "ios"))]
|
||||
pub(super) const APP_TYPE_CM: &str = "main";
|
||||
|
||||
pub(super) const APP_TYPE_DESKTOP_REMOTE: &str = "remote";
|
||||
pub(super) const APP_TYPE_DESKTOP_FILE_TRANSFER: &str = "file transfer";
|
||||
pub(super) const APP_TYPE_DESKTOP_PORT_FORWARD: &str = "port forward";
|
||||
|
||||
@ -215,6 +215,7 @@ static mut IS_0X021D_DOWN: bool = false;
|
||||
static mut IS_LEFT_OPTION_DOWN: bool = false;
|
||||
|
||||
pub fn start_grab_loop() {
|
||||
std::env::set_var("KEYBOARD_ONLY", "y");
|
||||
#[cfg(any(target_os = "windows", target_os = "macos"))]
|
||||
std::thread::spawn(move || {
|
||||
let try_handle_keyboard = move |event: Event, key: Key, is_press: bool| -> Option<Event> {
|
||||
|
||||
@ -10,7 +10,7 @@ mod eo;
|
||||
mod es;
|
||||
mod fa;
|
||||
mod fr;
|
||||
mod gr;
|
||||
mod el;
|
||||
mod hu;
|
||||
mod id;
|
||||
mod it;
|
||||
@ -59,7 +59,7 @@ pub const LANGS: &[(&str, &str)] = &[
|
||||
("ua", "Українська"),
|
||||
("fa", "فارسی"),
|
||||
("ca", "Català"),
|
||||
("gr", "Ελληνικά"),
|
||||
("el", "Ελληνικά"),
|
||||
("sv", "Svenska"),
|
||||
("sq", "Shqip"),
|
||||
("sr", "Srpski"),
|
||||
@ -122,7 +122,7 @@ pub fn translate_locale(name: String, locale: &str) -> String {
|
||||
"ua" => ua::T.deref(),
|
||||
"fa" => fa::T.deref(),
|
||||
"ca" => ca::T.deref(),
|
||||
"gr" => gr::T.deref(),
|
||||
"el" => el::T.deref(),
|
||||
"sv" => sv::T.deref(),
|
||||
"sq" => sq::T.deref(),
|
||||
"sr" => sr::T.deref(),
|
||||
|
||||
@ -461,6 +461,9 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
||||
("Resolution", ""),
|
||||
("No transfers in progress", ""),
|
||||
("Set one-time password length", ""),
|
||||
("idd_driver_tip", ""),
|
||||
("confirm_idd_driver_tip", ""),
|
||||
("RDP Settings", ""),
|
||||
("Sort by", ""),
|
||||
].iter().cloned().collect();
|
||||
}
|
||||
|
||||
@ -349,7 +349,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
||||
("Security", "安全"),
|
||||
("Theme", "主题"),
|
||||
("Dark Theme", "暗黑主题"),
|
||||
("Light Theme", ""),
|
||||
("Light Theme", "明亮主题"),
|
||||
("Dark", "黑暗"),
|
||||
("Light", "明亮"),
|
||||
("Follow System", "跟随系统"),
|
||||
@ -461,6 +461,9 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
||||
("Resolution", "分辨率"),
|
||||
("No transfers in progress", ""),
|
||||
("Set one-time password length", ""),
|
||||
("idd_driver_tip", "安装虚拟显示器驱动,以便在没有连接显示器的情况下启动虚拟显示器进行控制。"),
|
||||
("confirm_idd_driver_tip", "安装虚拟显示器驱动的选项已勾选。请注意,测试证书将被安装以信任虚拟显示器驱动。测试证书仅会用于信任Rustdesk的驱动。"),
|
||||
("RDP Settings", ""),
|
||||
("Sort by", ""),
|
||||
].iter().cloned().collect();
|
||||
}
|
||||
|
||||
@ -461,6 +461,9 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
||||
("Resolution", ""),
|
||||
("No transfers in progress", ""),
|
||||
("Set one-time password length", ""),
|
||||
("idd_driver_tip", ""),
|
||||
("confirm_idd_driver_tip", ""),
|
||||
("RDP Settings", ""),
|
||||
("Sort by", ""),
|
||||
].iter().cloned().collect();
|
||||
}
|
||||
|
||||
@ -461,6 +461,9 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
||||
("Resolution", ""),
|
||||
("No transfers in progress", ""),
|
||||
("Set one-time password length", ""),
|
||||
("idd_driver_tip", ""),
|
||||
("confirm_idd_driver_tip", ""),
|
||||
("RDP Settings", ""),
|
||||
("Sort by", ""),
|
||||
].iter().cloned().collect();
|
||||
}
|
||||
|
||||
@ -461,6 +461,9 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
||||
("Resolution", "Auflösung"),
|
||||
("No transfers in progress", "Keine Übertragungen im Gange"),
|
||||
("Set one-time password length", "Länge des Einmalpassworts festlegen"),
|
||||
("idd_driver_tip", "Installieren Sie den virtuellen Anzeigetreiber, der verwendet wird, wenn Sie keine physischen Anzeigen haben."),
|
||||
("confirm_idd_driver_tip", "Die Option zur Installation des virtuellen Anzeigetreibers ist aktiviert. Beachten Sie, dass ein Testzertifikat installiert wird, um dem virtuellen Anzeigetreiber zu vertrauen. Dieses Testzertifikat wird nur verwendet, um Rustdesk-Treibern zu vertrauen."),
|
||||
("RDP Settings", "RDP-Einstellungen"),
|
||||
("Sort by", ""),
|
||||
].iter().cloned().collect();
|
||||
}
|
||||
|
||||
@ -24,7 +24,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
||||
("Refresh random password", "Νέος τυχαίος κωδικός πρόσβασης"),
|
||||
("Set your own password", "Ορίστε τον δικό σας κωδικό πρόσβασης"),
|
||||
("Enable Keyboard/Mouse", "Ενεργοποίηση πληκτρολογίου/ποντικιού"),
|
||||
("Enable Clipboard", "Ενεργοποίηση Προχείρου"),
|
||||
("Enable Clipboard", "Ενεργοποίηση προχείρου"),
|
||||
("Enable File Transfer", "Ενεργοποίηση μεταφοράς αρχείων"),
|
||||
("Enable TCP Tunneling", "Ενεργοποίηση TCP Tunneling"),
|
||||
("IP Whitelisting", "Λίστα επιτρεπόμενων IP"),
|
||||
@ -44,7 +44,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
||||
("id_change_tip", "Επιτρέπονται μόνο οι χαρακτήρες a-z, A-Z, 0-9 και _ (υπογράμμιση). Το πρώτο γράμμα πρέπει να είναι a-z, A-Z και το μήκος πρέπει να είναι μεταξύ 6 και 16 χαρακτήρων."),
|
||||
("Website", "Ιστότοπος"),
|
||||
("About", "Πληροφορίες"),
|
||||
("Slogan_tip", "Προγραμματισμένος με πάθος - σε έναν κόσμο που βυθίζεται στο χάος!"),
|
||||
("Slogan_tip", "Φτιαγμένο με πάθος - σε έναν κόσμο που βυθίζεται στο χάος!"),
|
||||
("Privacy Statement", "Πολιτική απορρήτου"),
|
||||
("Mute", "Σίγαση"),
|
||||
("Build Date", "Ημερομηνία δημιουργίας"),
|
||||
@ -120,12 +120,12 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
||||
("Original", "Πρωτότυπο"),
|
||||
("Shrink", "Συρρίκνωση"),
|
||||
("Stretch", "Προσαρμογή"),
|
||||
("Scrollbar", "Γραμμή κύλισης"),
|
||||
("Scrollbar", "Μπάρα κύλισης"),
|
||||
("ScrollAuto", "Αυτόματη κύλιση"),
|
||||
("Good image quality", "Καλή ποιότητα εικόνας"),
|
||||
("Balanced", "Ισορροπημένο"),
|
||||
("Optimize reaction time", "Βελτιστοποίηση χρόνου αντίδρασης"),
|
||||
("Custom", "Προσαρμογή ποιότητας εικόνας"),
|
||||
("Balanced", "Ισορροπημένη"),
|
||||
("Optimize reaction time", "Βελτιστοποίηση απόκρισης"),
|
||||
("Custom", "Προσαρμοσμένη ποιότητας εικόνας"),
|
||||
("Show remote cursor", "Εμφάνιση απομακρυσμένου κέρσορα"),
|
||||
("Show quality monitor", "Εμφάνιση παρακολούθησης ποιότητας σύνδεσης"),
|
||||
("Disable clipboard", "Απενεργοποίηση προχείρου"),
|
||||
@ -146,9 +146,9 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
||||
("Set Password", "Ορίστε κωδικό πρόσβασης"),
|
||||
("OS Password", "Κωδικός πρόσβασης λειτουργικού συστήματος"),
|
||||
("install_tip", "Λόγω UAC, το RustDesk ενδέχεται να μην λειτουργεί σωστά σε ορισμένες περιπτώσεις. Για να αποφύγετε το UAC, κάντε κλικ στο κουμπί παρακάτω για να εγκαταστήσετε το RustDesk στο σύστημα"),
|
||||
("Click to upgrade", "Κάντε κλικ για αναβάθμιση"),
|
||||
("Click to download", "Κάντε κλικ για λήψη"),
|
||||
("Click to update", "Κάντε κλικ για ενημέρωση"),
|
||||
("Click to upgrade", "Πιέστε για αναβάθμιση"),
|
||||
("Click to download", "Πιέστε για λήψη"),
|
||||
("Click to update", "Πιέστε για ενημέρωση"),
|
||||
("Configure", "Διαμόρφωση"),
|
||||
("config_acc", "Για τον απομακρυσμένο έλεγχο του υπολογιστή σας, πρέπει να εκχωρήσετε δικαιώματα πρόσβασης στο RustDesk."),
|
||||
("config_screen", "Για να αποκτήσετε απομακρυσμένη πρόσβαση στον υπολογιστή σας, πρέπει να εκχωρήσετε το δικαίωμα RustDesk \"Screen Capture\"."),
|
||||
@ -242,7 +242,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
||||
("Invalid folder name", "Μη έγκυρο όνομα φακέλου"),
|
||||
("Socks5 Proxy", "Διαμεσολαβητής Socks5"),
|
||||
("Hostname", "Όνομα υπολογιστή"),
|
||||
("Discovered", "Ανακαλύφθηκε"),
|
||||
("Discovered", "Ανακαλύφθηκαν"),
|
||||
("install_daemon_tip", "Για να ξεκινά με την εκκίνηση του υπολογιστή, πρέπει να εγκαταστήσετε την υπηρεσία συστήματος"),
|
||||
("Remote ID", "Απομακρυσμένο ID"),
|
||||
("Paste", "Επικόλληση"),
|
||||
@ -344,7 +344,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
||||
("Secure Connection", "Ασφαλής σύνδεση"),
|
||||
("Insecure Connection", "Μη ασφαλής σύνδεση"),
|
||||
("Scale original", "Κλιμάκωση πρωτότυπου"),
|
||||
("Scale adaptive", "Προσαρμοστική κλίμακα"),
|
||||
("Scale adaptive", "Προσαρμοσμένη κλίμακα"),
|
||||
("General", "Γενικά"),
|
||||
("Security", "Ασφάλεια"),
|
||||
("Theme", "Θέμα"),
|
||||
@ -460,7 +460,10 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
||||
("Codec", "Κωδικοποίηση"),
|
||||
("Resolution", "Ανάλυση"),
|
||||
("No transfers in progress", "Δεν υπάρχει μεταφορά σε εξέλιξη"),
|
||||
("Set one-time password length", ""),
|
||||
("Set one-time password length", "Μέγεθος κωδικού μιας χρήσης"),
|
||||
("idd_driver_tip", ""),
|
||||
("confirm_idd_driver_tip", ""),
|
||||
("RDP Settings", ""),
|
||||
("Sort by", ""),
|
||||
].iter().cloned().collect();
|
||||
}
|
||||
@ -45,5 +45,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
||||
("config_microphone", "In order to speak remotely, you need to grant RustDesk \"Record Audio\" permissions."),
|
||||
("relay_hint_tip", "It may not be possible to connect directly, you can try to connect via relay. \nIn addition, if you want to use relay on your first try, you can add the \"/r\" suffix to the ID, or select the option \"Always connect via relay\" in the peer card."),
|
||||
("No transfers in progress", ""),
|
||||
("idd_driver_tip", "Install virtual display driver which is used when you have no physical displays."),
|
||||
("confirm_idd_driver_tip", "The option to install the virtual display driver is checked. Note that a test certificate will be installed to trust the virtual display driver. This test certificate will only be used to trust Rustdesk drivers.")
|
||||
].iter().cloned().collect();
|
||||
}
|
||||
|
||||
@ -461,6 +461,9 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
||||
("Resolution", ""),
|
||||
("No transfers in progress", ""),
|
||||
("Set one-time password length", ""),
|
||||
("idd_driver_tip", ""),
|
||||
("confirm_idd_driver_tip", ""),
|
||||
("RDP Settings", ""),
|
||||
("Sort by", ""),
|
||||
].iter().cloned().collect();
|
||||
}
|
||||
|
||||
@ -461,6 +461,9 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
||||
("Resolution", "Resolución"),
|
||||
("No transfers in progress", "No hay transferencias en curso"),
|
||||
("Set one-time password length", "Establecer contraseña de un solo uso"),
|
||||
("idd_driver_tip", ""),
|
||||
("confirm_idd_driver_tip", ""),
|
||||
("RDP Settings", ""),
|
||||
("Sort by", ""),
|
||||
].iter().cloned().collect();
|
||||
}
|
||||
|
||||
@ -461,6 +461,9 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
||||
("Resolution", "وضوح"),
|
||||
("No transfers in progress", "هیچ انتقالی در حال انجام نیست"),
|
||||
("Set one-time password length", "طول رمز یکبار مصرف را تعیین کنید"),
|
||||
("idd_driver_tip", ""),
|
||||
("confirm_idd_driver_tip", ""),
|
||||
("RDP Settings", ""),
|
||||
("Sort by", ""),
|
||||
].iter().cloned().collect();
|
||||
}
|
||||
|
||||
@ -461,6 +461,9 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
||||
("Resolution", ""),
|
||||
("No transfers in progress", ""),
|
||||
("Set one-time password length", ""),
|
||||
("idd_driver_tip", ""),
|
||||
("confirm_idd_driver_tip", ""),
|
||||
("RDP Settings", ""),
|
||||
("Sort by", ""),
|
||||
].iter().cloned().collect();
|
||||
}
|
||||
|
||||
@ -461,6 +461,9 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
||||
("Resolution", ""),
|
||||
("No transfers in progress", ""),
|
||||
("Set one-time password length", ""),
|
||||
("idd_driver_tip", ""),
|
||||
("confirm_idd_driver_tip", ""),
|
||||
("RDP Settings", ""),
|
||||
("Sort by", ""),
|
||||
].iter().cloned().collect();
|
||||
}
|
||||
|
||||
@ -461,6 +461,9 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
||||
("Resolution", ""),
|
||||
("No transfers in progress", ""),
|
||||
("Set one-time password length", ""),
|
||||
("idd_driver_tip", ""),
|
||||
("confirm_idd_driver_tip", ""),
|
||||
("RDP Settings", ""),
|
||||
("Sort by", ""),
|
||||
].iter().cloned().collect();
|
||||
}
|
||||
|
||||
@ -460,7 +460,10 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
||||
("Codec", "Codec"),
|
||||
("Resolution", "Risoluzione"),
|
||||
("No transfers in progress", "Nessun trasferimento in corso"),
|
||||
("Set one-time password length", "Imposta lunghezza password monouso"),
|
||||
("Set one-time password length", "Imposta la lunghezza della password monouso"),
|
||||
("idd_driver_tip", ""),
|
||||
("confirm_idd_driver_tip", ""),
|
||||
("RDP Settings", "Imposta lunghezza password monouso"),
|
||||
("Sort by", "Ordina per"),
|
||||
].iter().cloned().collect();
|
||||
}
|
||||
|
||||
@ -461,6 +461,9 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
||||
("Resolution", ""),
|
||||
("No transfers in progress", ""),
|
||||
("Set one-time password length", ""),
|
||||
("idd_driver_tip", ""),
|
||||
("confirm_idd_driver_tip", ""),
|
||||
("RDP Settings", ""),
|
||||
("Sort by", ""),
|
||||
].iter().cloned().collect();
|
||||
}
|
||||
|
||||
@ -461,6 +461,9 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
||||
("Resolution", ""),
|
||||
("No transfers in progress", ""),
|
||||
("Set one-time password length", ""),
|
||||
("idd_driver_tip", ""),
|
||||
("confirm_idd_driver_tip", ""),
|
||||
("RDP Settings", ""),
|
||||
("Sort by", ""),
|
||||
].iter().cloned().collect();
|
||||
}
|
||||
|
||||
@ -461,6 +461,9 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
||||
("Resolution", ""),
|
||||
("No transfers in progress", ""),
|
||||
("Set one-time password length", ""),
|
||||
("idd_driver_tip", ""),
|
||||
("confirm_idd_driver_tip", ""),
|
||||
("RDP Settings", ""),
|
||||
("Sort by", ""),
|
||||
].iter().cloned().collect();
|
||||
}
|
||||
|
||||
@ -461,6 +461,9 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
||||
("Resolution", "Resolutie"),
|
||||
("No transfers in progress", "Geen overdrachten in uitvoering"),
|
||||
("Set one-time password length", ""),
|
||||
("idd_driver_tip", ""),
|
||||
("confirm_idd_driver_tip", ""),
|
||||
("RDP Settings", ""),
|
||||
("Sort by", ""),
|
||||
].iter().cloned().collect();
|
||||
}
|
||||
|
||||
@ -461,6 +461,9 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
||||
("Resolution", "Rozdzielczość"),
|
||||
("No transfers in progress", "Brak transferów w toku"),
|
||||
("Set one-time password length", ""),
|
||||
("idd_driver_tip", ""),
|
||||
("confirm_idd_driver_tip", ""),
|
||||
("RDP Settings", ""),
|
||||
("Sort by", ""),
|
||||
].iter().cloned().collect();
|
||||
}
|
||||
|
||||
@ -461,6 +461,9 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
||||
("Resolution", ""),
|
||||
("No transfers in progress", ""),
|
||||
("Set one-time password length", ""),
|
||||
("idd_driver_tip", ""),
|
||||
("confirm_idd_driver_tip", ""),
|
||||
("RDP Settings", ""),
|
||||
("Sort by", ""),
|
||||
].iter().cloned().collect();
|
||||
}
|
||||
|
||||
@ -461,6 +461,9 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
||||
("Resolution", ""),
|
||||
("No transfers in progress", ""),
|
||||
("Set one-time password length", ""),
|
||||
("idd_driver_tip", ""),
|
||||
("confirm_idd_driver_tip", ""),
|
||||
("RDP Settings", ""),
|
||||
("Sort by", ""),
|
||||
].iter().cloned().collect();
|
||||
}
|
||||
|
||||
@ -461,6 +461,9 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
||||
("Resolution", ""),
|
||||
("No transfers in progress", ""),
|
||||
("Set one-time password length", ""),
|
||||
("idd_driver_tip", ""),
|
||||
("confirm_idd_driver_tip", ""),
|
||||
("RDP Settings", ""),
|
||||
("Sort by", ""),
|
||||
].iter().cloned().collect();
|
||||
}
|
||||
|
||||
@ -461,6 +461,9 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
||||
("Resolution", "Разрешение"),
|
||||
("No transfers in progress", "Передача не осуществляется"),
|
||||
("Set one-time password length", "Установить длину одноразового пароля"),
|
||||
("idd_driver_tip", ""),
|
||||
("confirm_idd_driver_tip", ""),
|
||||
("RDP Settings", ""),
|
||||
("Sort by", ""),
|
||||
].iter().cloned().collect();
|
||||
}
|
||||
|
||||
@ -461,6 +461,9 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
||||
("Resolution", ""),
|
||||
("No transfers in progress", ""),
|
||||
("Set one-time password length", ""),
|
||||
("idd_driver_tip", ""),
|
||||
("confirm_idd_driver_tip", ""),
|
||||
("RDP Settings", ""),
|
||||
("Sort by", ""),
|
||||
].iter().cloned().collect();
|
||||
}
|
||||
|
||||
@ -461,6 +461,9 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
||||
("Resolution", ""),
|
||||
("No transfers in progress", ""),
|
||||
("Set one-time password length", ""),
|
||||
("idd_driver_tip", ""),
|
||||
("confirm_idd_driver_tip", ""),
|
||||
("RDP Settings", ""),
|
||||
("Sort by", ""),
|
||||
].iter().cloned().collect();
|
||||
}
|
||||
|
||||
@ -461,6 +461,9 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
||||
("Resolution", ""),
|
||||
("No transfers in progress", ""),
|
||||
("Set one-time password length", ""),
|
||||
("idd_driver_tip", ""),
|
||||
("confirm_idd_driver_tip", ""),
|
||||
("RDP Settings", ""),
|
||||
("Sort by", ""),
|
||||
].iter().cloned().collect();
|
||||
}
|
||||
|
||||
@ -461,6 +461,9 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
||||
("Resolution", ""),
|
||||
("No transfers in progress", ""),
|
||||
("Set one-time password length", ""),
|
||||
("idd_driver_tip", ""),
|
||||
("confirm_idd_driver_tip", ""),
|
||||
("RDP Settings", ""),
|
||||
("Sort by", ""),
|
||||
].iter().cloned().collect();
|
||||
}
|
||||
|
||||
@ -461,6 +461,9 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
||||
("Resolution", ""),
|
||||
("No transfers in progress", ""),
|
||||
("Set one-time password length", ""),
|
||||
("idd_driver_tip", ""),
|
||||
("confirm_idd_driver_tip", ""),
|
||||
("RDP Settings", ""),
|
||||
("Sort by", ""),
|
||||
].iter().cloned().collect();
|
||||
}
|
||||
|
||||
@ -461,6 +461,9 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
||||
("Resolution", ""),
|
||||
("No transfers in progress", ""),
|
||||
("Set one-time password length", ""),
|
||||
("idd_driver_tip", ""),
|
||||
("confirm_idd_driver_tip", ""),
|
||||
("RDP Settings", ""),
|
||||
("Sort by", ""),
|
||||
].iter().cloned().collect();
|
||||
}
|
||||
|
||||
@ -461,6 +461,9 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
||||
("Resolution", ""),
|
||||
("No transfers in progress", ""),
|
||||
("Set one-time password length", ""),
|
||||
("idd_driver_tip", ""),
|
||||
("confirm_idd_driver_tip", ""),
|
||||
("RDP Settings", ""),
|
||||
("Sort by", ""),
|
||||
].iter().cloned().collect();
|
||||
}
|
||||
|
||||
@ -461,6 +461,9 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
||||
("Resolution", ""),
|
||||
("No transfers in progress", ""),
|
||||
("Set one-time password length", ""),
|
||||
("idd_driver_tip", ""),
|
||||
("confirm_idd_driver_tip", ""),
|
||||
("RDP Settings", ""),
|
||||
("Sort by", ""),
|
||||
].iter().cloned().collect();
|
||||
}
|
||||
|
||||
@ -349,7 +349,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
||||
("Security", "安全"),
|
||||
("Theme", "主題"),
|
||||
("Dark Theme", "暗黑主題"),
|
||||
("Light Theme", ""),
|
||||
("Light Theme", "明亮主題"),
|
||||
("Dark", "黑暗"),
|
||||
("Light", "明亮"),
|
||||
("Follow System", "跟隨系統"),
|
||||
@ -461,6 +461,9 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
||||
("Resolution", "分辨率"),
|
||||
("No transfers in progress", ""),
|
||||
("Set one-time password length", ""),
|
||||
("idd_driver_tip", ""),
|
||||
("confirm_idd_driver_tip", ""),
|
||||
("RDP Settings", ""),
|
||||
("Sort by", ""),
|
||||
].iter().cloned().collect();
|
||||
}
|
||||
|
||||
@ -461,6 +461,9 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
||||
("Resolution", ""),
|
||||
("No transfers in progress", ""),
|
||||
("Set one-time password length", ""),
|
||||
("idd_driver_tip", ""),
|
||||
("confirm_idd_driver_tip", ""),
|
||||
("RDP Settings", ""),
|
||||
("Sort by", ""),
|
||||
].iter().cloned().collect();
|
||||
}
|
||||
|
||||
@ -461,6 +461,9 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
||||
("Resolution", ""),
|
||||
("No transfers in progress", ""),
|
||||
("Set one-time password length", ""),
|
||||
("idd_driver_tip", ""),
|
||||
("confirm_idd_driver_tip", ""),
|
||||
("RDP Settings", ""),
|
||||
("Sort by", ""),
|
||||
].iter().cloned().collect();
|
||||
}
|
||||
|
||||
@ -1108,6 +1108,12 @@ if exist \"{tmp_path}\\{app_name} Tray.lnk\" del /f /q \"{tmp_path}\\{app_name}
|
||||
);
|
||||
let src_exe = std::env::current_exe()?.to_str().unwrap_or("").to_string();
|
||||
|
||||
let install_cert = if options.contains("driverCert") {
|
||||
format!("\"{}\" --install-cert \"RustDeskIddDriver.cer\"", src_exe)
|
||||
} else {
|
||||
"".to_owned()
|
||||
};
|
||||
|
||||
let cmds = format!(
|
||||
"
|
||||
{uninstall_str}
|
||||
@ -1139,6 +1145,7 @@ sc create {app_name} binpath= \"\\\"{exe}\\\" --import-config \\\"{config_path}\
|
||||
sc start {app_name}
|
||||
sc stop {app_name}
|
||||
sc delete {app_name}
|
||||
{install_cert}
|
||||
{after_install}
|
||||
{sleep}
|
||||
",
|
||||
@ -1159,6 +1166,7 @@ sc delete {app_name}
|
||||
shortcuts=shortcuts,
|
||||
config_path=Config::file().to_str().unwrap_or(""),
|
||||
lic=register_licence(),
|
||||
install_cert=install_cert,
|
||||
after_install=get_after_install(&exe),
|
||||
sleep=if debug {
|
||||
"timeout 300"
|
||||
@ -1236,6 +1244,7 @@ fn get_uninstall(kill_self: bool) -> String {
|
||||
}
|
||||
|
||||
pub fn uninstall_me(kill_self: bool) -> ResultType<()> {
|
||||
allow_err!(cert::uninstall_certs());
|
||||
run_cmds(get_uninstall(kill_self), true, "uninstall")
|
||||
}
|
||||
|
||||
@ -1902,3 +1911,177 @@ pub fn user_accessible_folder() -> ResultType<PathBuf> {
|
||||
}
|
||||
Ok(dir)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn install_cert(cert_file: &str) -> ResultType<()> {
|
||||
let exe_file = std::env::current_exe()?;
|
||||
if let Some(cur_dir) = exe_file.parent() {
|
||||
allow_err!(cert::install_cert(cur_dir.join(cert_file)));
|
||||
} else {
|
||||
bail!(
|
||||
"Invalid exe parent for {}",
|
||||
exe_file.to_string_lossy().as_ref()
|
||||
);
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
mod cert {
|
||||
use hbb_common::{allow_err, bail, log, ResultType};
|
||||
use std::{path::Path, str::from_utf8};
|
||||
use winapi::shared::{
|
||||
minwindef::{BYTE, DWORD, TRUE},
|
||||
ntdef::NULL,
|
||||
};
|
||||
use winapi::um::{
|
||||
errhandlingapi::GetLastError,
|
||||
wincrypt::{
|
||||
CertCloseStore, CertEnumCertificatesInStore, CertNameToStrA, CertOpenSystemStoreA,
|
||||
CryptHashCertificate, ALG_ID, CALG_SHA1, CERT_ID_SHA1_HASH, CERT_X500_NAME_STR,
|
||||
PCCERT_CONTEXT,
|
||||
},
|
||||
winreg::HKEY_LOCAL_MACHINE,
|
||||
};
|
||||
use winreg::{
|
||||
enums::{KEY_WRITE, REG_BINARY},
|
||||
RegKey,
|
||||
};
|
||||
|
||||
const ROOT_CERT_STORE_PATH: &str = "SOFTWARE\\Microsoft\\SystemCertificates\\ROOT\\Certificates\\";
|
||||
const THUMBPRINT_ALG: ALG_ID = CALG_SHA1;
|
||||
const THUMBPRINT_LEN: DWORD = 20;
|
||||
|
||||
#[inline]
|
||||
unsafe fn compute_thumbprint(pb_encoded: *const BYTE, cb_encoded: DWORD) -> (Vec<u8>, String) {
|
||||
let mut size = THUMBPRINT_LEN;
|
||||
let mut thumbprint = [0u8; THUMBPRINT_LEN as usize];
|
||||
if CryptHashCertificate(
|
||||
0,
|
||||
THUMBPRINT_ALG,
|
||||
0,
|
||||
pb_encoded,
|
||||
cb_encoded,
|
||||
thumbprint.as_mut_ptr(),
|
||||
&mut size,
|
||||
) == TRUE
|
||||
{
|
||||
(thumbprint.to_vec(), hex::encode(thumbprint).to_ascii_uppercase())
|
||||
} else {
|
||||
(thumbprint.to_vec(), "".to_owned())
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
unsafe fn open_reg_cert_store() -> ResultType<RegKey> {
|
||||
let hklm = winreg::RegKey::predef(HKEY_LOCAL_MACHINE);
|
||||
Ok(hklm.open_subkey_with_flags(ROOT_CERT_STORE_PATH, KEY_WRITE)?)
|
||||
}
|
||||
|
||||
// https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-gpef/6a9e35fa-2ac7-4c10-81e1-eabe8d2472f1
|
||||
fn create_cert_blob(thumbprint: Vec<u8>, encoded: Vec<u8>) -> Vec<u8> {
|
||||
let mut blob = Vec::new();
|
||||
|
||||
let mut property_id = (CERT_ID_SHA1_HASH as u32).to_le_bytes().to_vec();
|
||||
let mut pro_reserved = [0x01, 0x00, 0x00, 0x00].to_vec();
|
||||
let mut pro_length = (THUMBPRINT_LEN as u32).to_le_bytes().to_vec();
|
||||
let mut pro_val = thumbprint;
|
||||
blob.append(&mut property_id);
|
||||
blob.append(&mut pro_reserved);
|
||||
blob.append(&mut pro_length);
|
||||
blob.append(&mut pro_val);
|
||||
|
||||
let mut blob_reserved = [0x20, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00].to_vec();
|
||||
let mut blob_length = (encoded.len() as u32).to_le_bytes().to_vec();
|
||||
let mut blob_val = encoded;
|
||||
blob.append(&mut blob_reserved);
|
||||
blob.append(&mut blob_length);
|
||||
blob.append(&mut blob_val);
|
||||
|
||||
blob
|
||||
}
|
||||
|
||||
pub fn install_cert<P: AsRef<Path>>(path: P) -> ResultType<()> {
|
||||
let mut cert_bytes = std::fs::read(path)?;
|
||||
unsafe {
|
||||
let thumbprint = compute_thumbprint(cert_bytes.as_mut_ptr(), cert_bytes.len() as _);
|
||||
log::debug!("Thumbprint of cert {}", &thumbprint.1);
|
||||
|
||||
let reg_cert_key = open_reg_cert_store()?;
|
||||
let (cert_key, _) = reg_cert_key.create_subkey(&thumbprint.1)?;
|
||||
let data = winreg::RegValue {
|
||||
vtype: REG_BINARY,
|
||||
bytes: create_cert_blob(thumbprint.0, cert_bytes),
|
||||
};
|
||||
cert_key.set_raw_value("Blob", &data)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn get_thumbprints_to_rm() -> ResultType<Vec<String>> {
|
||||
let issuers_to_rm = ["CN=\"WDKTestCert admin,133225435702113567\""];
|
||||
|
||||
let mut thumbprints = Vec::new();
|
||||
let mut buf = [0u8; 1024];
|
||||
|
||||
unsafe {
|
||||
let store_handle = CertOpenSystemStoreA(0 as _, "ROOT\0".as_ptr() as _);
|
||||
if store_handle.is_null() {
|
||||
bail!("Error opening certificate store: {}", GetLastError());
|
||||
}
|
||||
|
||||
let mut cert_ctx: PCCERT_CONTEXT = CertEnumCertificatesInStore(store_handle, NULL as _);
|
||||
while !cert_ctx.is_null() {
|
||||
// https://stackoverflow.com/a/66432736
|
||||
let cb_size = CertNameToStrA(
|
||||
(*cert_ctx).dwCertEncodingType,
|
||||
&mut ((*(*cert_ctx).pCertInfo).Issuer) as _,
|
||||
CERT_X500_NAME_STR,
|
||||
buf.as_mut_ptr() as _,
|
||||
buf.len() as _,
|
||||
);
|
||||
if cb_size != 1 {
|
||||
if let Ok(issuer) = from_utf8(&buf[..cb_size as _]) {
|
||||
for iss in issuers_to_rm.iter() {
|
||||
if issuer.contains(iss) {
|
||||
let (_, thumbprint) = compute_thumbprint(
|
||||
(*cert_ctx).pbCertEncoded,
|
||||
(*cert_ctx).cbCertEncoded,
|
||||
);
|
||||
if !thumbprint.is_empty() {
|
||||
thumbprints.push(thumbprint);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
cert_ctx = CertEnumCertificatesInStore(store_handle, cert_ctx);
|
||||
}
|
||||
CertCloseStore(store_handle, 0);
|
||||
}
|
||||
|
||||
Ok(thumbprints)
|
||||
}
|
||||
|
||||
pub fn uninstall_certs() -> ResultType<()> {
|
||||
let thumbprints = get_thumbprints_to_rm()?;
|
||||
let reg_cert_key = unsafe { open_reg_cert_store()? };
|
||||
for thumbprint in thumbprints.iter() {
|
||||
allow_err!(reg_cert_key.delete_subkey(thumbprint));
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
#[test]
|
||||
fn test_install_cert() {
|
||||
println!("install driver cert: {:?}", cert::install_cert("RustDeskIddDriver.cer"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_uninstall_cert() {
|
||||
println!("uninstall driver certs: {:?}", cert::uninstall_certs());
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user