Compare commits
239 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5c904d0e02 | ||
|
|
6d9c13affa | ||
|
|
411622016b | ||
|
|
88fb3b7da0 | ||
|
|
e32ed80003 | ||
|
|
8adecbfc1d | ||
|
|
d186b7dd02 | ||
|
|
c24d4ab5a5 | ||
|
|
1dde44596d | ||
|
|
f45cd77923 | ||
|
|
e2389cc6f3 | ||
|
|
569fee8e52 | ||
|
|
3e8936998e | ||
|
|
5aa976dea4 | ||
|
|
94381d02df | ||
|
|
e8f54731bc | ||
|
|
f62cd9cf86 | ||
|
|
7d2f124eb6 | ||
|
|
f06610989a | ||
|
|
0c14df90eb | ||
|
|
910556d627 | ||
|
|
194cfb502b | ||
|
|
f1c386869f | ||
|
|
95bd0e0743 | ||
|
|
7cd47a99bd | ||
|
|
0947330a97 | ||
|
|
52d1f711ec | ||
|
|
85afc2fca4 | ||
|
|
f933b2ee84 | ||
|
|
2214d60adb | ||
|
|
35c7324669 | ||
|
|
cb464bdf37 | ||
|
|
9af16d5a32 | ||
|
|
2ab2b54f66 | ||
|
|
0853fdeed8 | ||
|
|
1728c51e93 | ||
|
|
971586decb | ||
|
|
7df38d7ffd | ||
|
|
7ca5a67d6c | ||
|
|
19bab19ab5 | ||
|
|
1d4edcfab5 | ||
|
|
7c5cf83628 | ||
|
|
4d2d956a68 | ||
|
|
f5773378d8 | ||
|
|
fce82c76e1 | ||
|
|
9c9e7ccb00 | ||
|
|
f2b3df06fd | ||
|
|
98128704a5 | ||
|
|
461a8a56ff | ||
|
|
60dc527cad | ||
|
|
bb43e468ac | ||
|
|
0cfe1ffb4c | ||
|
|
8ea114d36b | ||
|
|
6e7a5ba84a | ||
|
|
6dc19ccd05 | ||
|
|
28e48c8eb8 | ||
|
|
365af0fceb | ||
|
|
962c98f682 | ||
|
|
3a2ed3d23b | ||
|
|
1db75f1b33 | ||
|
|
533ee4f1bb | ||
|
|
f0943ddf1a | ||
|
|
55317863c0 | ||
|
|
b9fdac7d8c | ||
|
|
adc69d499a | ||
|
|
dd5291c9ba | ||
|
|
f9901f2f74 | ||
|
|
27b52d80e9 | ||
|
|
9c471075e3 | ||
|
|
e06ef09d75 | ||
|
|
cbe2b4e60f | ||
|
|
3c312dad7b | ||
|
|
1650994efa | ||
|
|
c74dd0a2e4 | ||
|
|
5fb84b739c | ||
|
|
278234dd08 | ||
|
|
54ff4d8c8b | ||
|
|
ceaf44f71d | ||
|
|
1287e7e5df | ||
|
|
d6d6165c4b | ||
|
|
b133ba0d66 | ||
|
|
47da6243dd | ||
|
|
661f39543c | ||
|
|
f72d9be70c | ||
|
|
88dca7235b | ||
|
|
05906539d7 | ||
|
|
851d8e9771 | ||
|
|
e4420c24c8 | ||
|
|
fae826ef53 | ||
|
|
5052bec676 | ||
|
|
e46d0bd0ef | ||
|
|
67e2bc7df9 | ||
|
|
2e229d0800 | ||
|
|
89ee4822dd | ||
|
|
c429836057 | ||
|
|
6f1bb528bd | ||
|
|
13114d0bc3 | ||
|
|
56c4d9f0b7 | ||
|
|
6c7c1ed3e7 | ||
|
|
abbf4d899b | ||
|
|
3e22a34906 | ||
|
|
b4ec36c59a | ||
|
|
7d578df4c2 | ||
|
|
3169440af6 | ||
|
|
12b5fe1e30 | ||
|
|
23e91a5ea7 | ||
|
|
be47bcbe46 | ||
|
|
668998e390 | ||
|
|
fabbc91fae | ||
|
|
50082d5566 | ||
|
|
ac3d60cae1 | ||
|
|
6755dc1fa0 | ||
|
|
c53548dcce | ||
|
|
e36790addc | ||
|
|
94f1560196 | ||
|
|
6ac5f4b283 | ||
|
|
606a5ee956 | ||
|
|
2548477390 | ||
|
|
885523e2f9 | ||
|
|
253749df21 | ||
|
|
050f4b3130 | ||
|
|
cc59f1d58d | ||
|
|
a56f965344 | ||
|
|
a45bc0acdd | ||
|
|
5ea49e7a00 | ||
|
|
131ec1759d | ||
|
|
bcef3a4026 | ||
|
|
0240a905f9 | ||
|
|
8577a25657 | ||
|
|
465a9d3554 | ||
|
|
f0f67f5be1 | ||
|
|
2c1a5f93b5 | ||
|
|
55c41599be | ||
|
|
9f23f1c94a | ||
|
|
7479fbbd8f | ||
|
|
c0ede165ab | ||
|
|
78ec60d272 | ||
|
|
807f26360e | ||
|
|
bad75caf0b | ||
|
|
b76e34aa1c | ||
|
|
e3c41ee258 | ||
|
|
c76a63d269 | ||
|
|
88918cde01 | ||
|
|
6725aa21b0 | ||
|
|
1978be9edf | ||
|
|
4edff33ebd | ||
|
|
49fd150fe5 | ||
|
|
c8c1fac268 | ||
|
|
a91d66007d | ||
|
|
ca1aa3fcc5 | ||
|
|
409ed5cfa3 | ||
|
|
2ca25d3a39 | ||
|
|
0e975e73db | ||
|
|
62ac82ec2e | ||
|
|
fc239ef7b5 | ||
|
|
71eb691a52 | ||
|
|
256d647f04 | ||
|
|
7644222adf | ||
|
|
fdfebbb01a | ||
|
|
cd1915a4bf | ||
|
|
785d03e46f | ||
|
|
996b3c66b0 | ||
|
|
08af79b930 | ||
|
|
f6be77c68a | ||
|
|
a9718c4f5d | ||
|
|
119b272564 | ||
|
|
50236e59ff | ||
|
|
877ec790d6 | ||
|
|
972451709c | ||
|
|
e2c20567d6 | ||
|
|
6718464f57 | ||
|
|
5148b792e6 | ||
|
|
e79572d55d | ||
|
|
9c1ab4de3c | ||
|
|
d2b36d3876 | ||
|
|
16d0818a28 | ||
|
|
634a77a054 | ||
|
|
3ff33a6efb | ||
|
|
897fe1a487 | ||
|
|
8b04b051fd | ||
|
|
c59a838f7b | ||
|
|
ebaedbcf55 | ||
|
|
21a5dc1bf6 | ||
|
|
e8af50a5fc | ||
|
|
124af41206 | ||
|
|
2e216e9d26 | ||
|
|
8cd0e78ec7 | ||
|
|
581dcd62c3 | ||
|
|
60ec06b3ea | ||
|
|
8253cce1bf | ||
|
|
6167b8f61d | ||
|
|
9fd8f52815 | ||
|
|
50f15f18b4 | ||
|
|
c4cc4a167e | ||
|
|
1d51a43a47 | ||
|
|
905d8039ef | ||
|
|
8b8aff445a | ||
|
|
1b56fa5833 | ||
|
|
ac114152de | ||
|
|
ca0d321873 | ||
|
|
80fc9f6a84 | ||
|
|
b567c74902 | ||
|
|
cc47350fab | ||
|
|
e882a604d7 | ||
|
|
1b7468a1f2 | ||
|
|
1424caffb0 | ||
|
|
47cf713307 | ||
|
|
fe505ed35c | ||
|
|
a68e9d8a83 | ||
|
|
995f78b6a1 | ||
|
|
7951080c6c | ||
|
|
6792760e57 | ||
|
|
da33c6f5fd | ||
|
|
6c2e2f39e9 | ||
|
|
f420425ecb | ||
|
|
4a5dce088a | ||
|
|
51cb240b13 | ||
|
|
a9bf03b34b | ||
|
|
286320cd81 | ||
|
|
0f1b1d1d55 | ||
|
|
ee673c2667 | ||
|
|
2c970680ef | ||
|
|
c973d5363f | ||
|
|
433b02dbfd | ||
|
|
3699490b88 | ||
|
|
743781d662 | ||
|
|
7e81a75b0d | ||
|
|
dc965aa566 | ||
|
|
3c2959fd95 | ||
|
|
2020c85cce | ||
|
|
f1ab7ea43c | ||
|
|
423100c9ea | ||
|
|
8e11af77b8 | ||
|
|
8ce7e6ac50 | ||
|
|
87f587699c | ||
|
|
f294a1feda | ||
|
|
7c370dbcdf | ||
|
|
646ad8d4a1 | ||
|
|
d78c1f7961 |
37
.github/actions/decrypt-secrets/action.yml
vendored
Normal file
37
.github/actions/decrypt-secrets/action.yml
vendored
Normal file
@@ -0,0 +1,37 @@
|
||||
name: 'Decrypt and Mask Secrets'
|
||||
description: 'Decrypts a zip and masks the JSON contents as env vars'
|
||||
inputs:
|
||||
zip_password:
|
||||
description: 'Password for the Zip'
|
||||
required: true
|
||||
zip_path:
|
||||
description: 'Path to the encrypted zip'
|
||||
required: false
|
||||
default: 'secrets.zip'
|
||||
|
||||
runs:
|
||||
using: "composite"
|
||||
steps:
|
||||
- name: install python deps
|
||||
shell: bash
|
||||
run: |
|
||||
pip install pyzipper
|
||||
- name: Decrypt and Mask
|
||||
shell: python
|
||||
run: |
|
||||
import pyzipper
|
||||
import json
|
||||
import os
|
||||
|
||||
with pyzipper.AESZipFile('${{ inputs.zip_path }}') as zf:
|
||||
zf.setpassword('${{ inputs.zip_password }}'.encode())
|
||||
with zf.open('secrets.json') as f:
|
||||
secrets = json.load(f)
|
||||
|
||||
with open(os.environ['GITHUB_ENV'], 'a') as env_file:
|
||||
for key, value in secrets.items():
|
||||
if value:
|
||||
print(f"::add-mask::{value}")
|
||||
env_file.write(f"{key}={value}\n")
|
||||
|
||||
print(f"Successfully masked {len(secrets)} secrets.")
|
||||
615
.github/old-workflows/pre133-generator-android.yml
vendored
615
.github/old-workflows/pre133-generator-android.yml
vendored
File diff suppressed because one or more lines are too long
587
.github/old-workflows/pre133-generator-linux.yml
vendored
587
.github/old-workflows/pre133-generator-linux.yml
vendored
File diff suppressed because one or more lines are too long
566
.github/old-workflows/pre133-generator-windows.yml
vendored
566
.github/old-workflows/pre133-generator-windows.yml
vendored
File diff suppressed because one or more lines are too long
29
.github/patches/allowCustom.diff
vendored
Normal file
29
.github/patches/allowCustom.diff
vendored
Normal file
@@ -0,0 +1,29 @@
|
||||
diff --git a/src/common.rs b/src/common.rs
|
||||
index 56361a5da..92b221e9a 100644
|
||||
--- a/src/common.rs
|
||||
+++ b/src/common.rs
|
||||
@@ -1474,15 +1474,15 @@ pub fn read_custom_client(config: &str) {
|
||||
log::error!("Failed to decode custom client config");
|
||||
return;
|
||||
};
|
||||
- const KEY: &str = "5Qbwsde3unUcJBtrx9ZkvUmwFNoExHzpryHuPUdqlWM=";
|
||||
- let Some(pk) = get_rs_pk(KEY) else {
|
||||
- log::error!("Failed to parse public key of custom client");
|
||||
- return;
|
||||
- };
|
||||
- let Ok(data) = sign::verify(&data, &pk) else {
|
||||
- log::error!("Failed to dec custom client config");
|
||||
- return;
|
||||
- };
|
||||
+ // const KEY: &str = "5Qbwsde3unUcJBtrx9ZkvUmwFNoExHzpryHuPUdqlWM=";
|
||||
+ // let Some(pk) = get_rs_pk(KEY) else {
|
||||
+ // log::error!("Failed to parse public key of custom client");
|
||||
+ // return;
|
||||
+ // };
|
||||
+ // let Ok(data) = sign::verify(&data, &pk) else {
|
||||
+ // log::error!("Failed to dec custom client config");
|
||||
+ // return;
|
||||
+ // };
|
||||
let Ok(mut data) =
|
||||
serde_json::from_slice::<std::collections::HashMap<String, serde_json::Value>>(&data)
|
||||
else {
|
||||
63
.github/patches/allowCustom.py
vendored
Normal file
63
.github/patches/allowCustom.py
vendored
Normal file
@@ -0,0 +1,63 @@
|
||||
import os
|
||||
import shutil
|
||||
|
||||
def remove_line_block(filepath, start_phrase, lines_to_remove_after_start):
|
||||
"""
|
||||
Removes a starting line and a fixed number of lines immediately following it.
|
||||
|
||||
:param filepath: The path to the file to modify.
|
||||
:param start_phrase: The unique string to identify the first line of the block.
|
||||
:param lines_to_remove_after_start: The number of lines to remove after the starting line.
|
||||
"""
|
||||
|
||||
# 1. Configuration for the removal logic
|
||||
# The starting line is: const KEY: &str = "5Qbwsde3unUcJBtrx9ZkvUmwFNoExHzpryHuPUdqlWM=";
|
||||
# The block contains this line plus 8 following lines, so we want to skip 9 lines in total.
|
||||
total_lines_to_skip = 1 + lines_to_remove_after_start # 1 (start line) + 8 (following lines) = 9
|
||||
|
||||
lines_to_keep = []
|
||||
skip_count = 0
|
||||
|
||||
# 2. Read and filter the file content
|
||||
try:
|
||||
with open(filepath, 'r') as file:
|
||||
for line in file:
|
||||
|
||||
# If we are currently in the process of skipping lines, decrement the counter and continue
|
||||
if skip_count > 0:
|
||||
skip_count -= 1
|
||||
continue
|
||||
|
||||
# Check if the line matches the start phrase (we use .strip() to ignore indentation/whitespace)
|
||||
if line.strip().startswith(start_phrase.strip()):
|
||||
# Start skipping the block (including the current line)
|
||||
skip_count = total_lines_to_skip - 1
|
||||
# Note: We subtract 1 because the 'continue' will handle the first line removal immediately
|
||||
continue
|
||||
|
||||
# If we are not skipping, keep the line, but change custom.txt to custom_.txt
|
||||
line = line.replace("custom.txt", "custom_.txt")
|
||||
lines_to_keep.append(line)
|
||||
|
||||
except FileNotFoundError:
|
||||
print(f"Error: File not found at {filepath}")
|
||||
return
|
||||
|
||||
# 3. Write the remaining lines back to the file
|
||||
try:
|
||||
with open(filepath, 'w') as file:
|
||||
file.writelines(lines_to_keep)
|
||||
|
||||
print(f"Success! Removed the 9-line block starting with '{start_phrase.strip()}' from {filepath}.")
|
||||
|
||||
except IOError as e:
|
||||
print(f"An error occurred while writing to the file: {e}")
|
||||
|
||||
def main():
|
||||
file_path = 'src/common.rs'
|
||||
start_phrase = 'const KEY: &str = "5Qbwsde3unUcJBtrx9ZkvUmwFNoExHzpryHuPUdqlWM=";'
|
||||
lines_to_remove_after_start = 8
|
||||
remove_line_block(file_path, start_phrase, lines_to_remove_after_start)
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
16
.github/patches/cycle_monitor.diff
vendored
16
.github/patches/cycle_monitor.diff
vendored
@@ -1,8 +1,8 @@
|
||||
diff --git a/flutter/lib/desktop/widgets/remote_toolbar.dart b/flutter/lib/desktop/widgets/remote_toolbar.dart
|
||||
index 839ea1a81..9cee52263 100644
|
||||
index bc3757f1e..ba6509802 100644
|
||||
--- a/flutter/lib/desktop/widgets/remote_toolbar.dart
|
||||
+++ b/flutter/lib/desktop/widgets/remote_toolbar.dart
|
||||
@@ -437,6 +437,7 @@ class _RemoteToolbarState extends State<RemoteToolbar> {
|
||||
@@ -317,6 +317,7 @@ class _RemoteToolbarState extends State<RemoteToolbar> {
|
||||
borderRadius: borderRadius,
|
||||
child: _DraggableShowHide(
|
||||
id: widget.id,
|
||||
@@ -10,7 +10,7 @@ index 839ea1a81..9cee52263 100644
|
||||
sessionId: widget.ffi.sessionId,
|
||||
dragging: _dragging,
|
||||
fractionX: _fractionX,
|
||||
@@ -2234,6 +2235,7 @@ class RdoMenuButton<T> extends StatelessWidget {
|
||||
@@ -2460,6 +2461,7 @@ class RdoMenuButton<T> extends StatelessWidget {
|
||||
|
||||
class _DraggableShowHide extends StatefulWidget {
|
||||
final String id;
|
||||
@@ -18,7 +18,7 @@ index 839ea1a81..9cee52263 100644
|
||||
final SessionID sessionId;
|
||||
final RxDouble fractionX;
|
||||
final RxBool dragging;
|
||||
@@ -2246,6 +2248,7 @@ class _DraggableShowHide extends StatefulWidget {
|
||||
@@ -2472,6 +2474,7 @@ class _DraggableShowHide extends StatefulWidget {
|
||||
const _DraggableShowHide({
|
||||
Key? key,
|
||||
required this.id,
|
||||
@@ -26,7 +26,7 @@ index 839ea1a81..9cee52263 100644
|
||||
required this.sessionId,
|
||||
required this.fractionX,
|
||||
required this.dragging,
|
||||
@@ -2357,6 +2360,7 @@ class _DraggableShowHideState extends State<_DraggableShowHide> {
|
||||
@@ -2583,6 +2586,7 @@ class _DraggableShowHideState extends State<_DraggableShowHide> {
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
_buildDraggable(context),
|
||||
@@ -34,9 +34,9 @@ index 839ea1a81..9cee52263 100644
|
||||
Obx(() => buttonWrapper(
|
||||
() {
|
||||
widget.setFullscreen(!isFullscreen.value);
|
||||
@@ -2463,3 +2467,50 @@ Widget _buildPointerTrackWidget(Widget child, FFI? ffi) {
|
||||
),
|
||||
);
|
||||
@@ -2742,3 +2746,50 @@ class EdgeThicknessControl extends StatelessWidget {
|
||||
return slider;
|
||||
}
|
||||
}
|
||||
+
|
||||
+class _CycleMonitorMenu extends StatelessWidget {
|
||||
|
||||
32
.github/patches/privacyScreen.py
vendored
Normal file
32
.github/patches/privacyScreen.py
vendored
Normal file
@@ -0,0 +1,32 @@
|
||||
import os
|
||||
|
||||
def convert_png_to_cpp(input_file, output_file, array_name="g_img"):
|
||||
if not os.path.exists(input_file):
|
||||
print(f"Error: {input_file} not found.")
|
||||
return
|
||||
|
||||
with open(input_file, "rb") as f:
|
||||
data = f.read()
|
||||
|
||||
with open(output_file, "w") as f:
|
||||
f.write('#include "pch.h"\n')
|
||||
f.write('#include "./img.h"\n\n')
|
||||
f.write(f"const unsigned char {array_name}[] = {{\n")
|
||||
|
||||
for i in range(0, len(data), 20):
|
||||
chunk = data[i : i + 20]
|
||||
hex_chunk = [f"0x{b:02x}" for b in chunk]
|
||||
|
||||
line = ", ".join(hex_chunk)
|
||||
|
||||
if i + 20 < len(data):
|
||||
f.write(f"{line},\n")
|
||||
else:
|
||||
f.write(f"{line}\n")
|
||||
|
||||
f.write("};\n\n")
|
||||
f.write(f"const long long {array_name}Len = sizeof({array_name});\n")
|
||||
|
||||
#print(f"Successfully converted {input_file} to {output_file}")
|
||||
|
||||
convert_png_to_cpp("privacy.png", "img.cpp")
|
||||
41
.github/patches/removeNewVersionNotif.diff
vendored
Normal file
41
.github/patches/removeNewVersionNotif.diff
vendored
Normal file
@@ -0,0 +1,41 @@
|
||||
diff --git a/flutter/lib/desktop/pages/desktop_home_page.dart b/flutter/lib/desktop/pages/desktop_home_page.dart
|
||||
index ba724eed5..1604c429f 100644
|
||||
--- a/flutter/lib/desktop/pages/desktop_home_page.dart
|
||||
+++ b/flutter/lib/desktop/pages/desktop_home_page.dart
|
||||
@@ -424,21 +424,21 @@ class _DesktopHomePageState extends State<DesktopHomePage>
|
||||
}
|
||||
|
||||
Widget buildHelpCards(String updateUrl) {
|
||||
- if (!bind.isCustomClient() &&
|
||||
- updateUrl.isNotEmpty &&
|
||||
- !isCardClosed &&
|
||||
- bind.mainUriPrefixSync().contains('rustdesk')) {
|
||||
- return buildInstallCard(
|
||||
- "Status",
|
||||
- "${translate("new-version-of-{${bind.mainGetAppNameSync()}}-tip")} (${bind.mainGetNewVersion()}).",
|
||||
- "Click to download", () async {
|
||||
- final Uri url = Uri.parse('https://rustdesk.com/download');
|
||||
- await launchUrl(url);
|
||||
- }, closeButton: true);
|
||||
- }
|
||||
- if (systemError.isNotEmpty) {
|
||||
- return buildInstallCard("", systemError, "", () {});
|
||||
- }
|
||||
+ // if (!bind.isCustomClient() &&
|
||||
+ // updateUrl.isNotEmpty &&
|
||||
+ // !isCardClosed &&
|
||||
+ // bind.mainUriPrefixSync().contains('rustdesk')) {
|
||||
+ // return buildInstallCard(
|
||||
+ // "Status",
|
||||
+ // "${translate("new-version-of-{${bind.mainGetAppNameSync()}}-tip")} (${bind.mainGetNewVersion()}).",
|
||||
+ // "Click to download", () async {
|
||||
+ // final Uri url = Uri.parse('https://rustdesk.com/download');
|
||||
+ // await launchUrl(url);
|
||||
+ // }, closeButton: true);
|
||||
+ // }
|
||||
+ // if (systemError.isNotEmpty) {
|
||||
+ // return buildInstallCard("", systemError, "", () {});
|
||||
+ // }
|
||||
|
||||
if (isWindows && !bind.isDisableInstallation()) {
|
||||
if (!bind.mainIsInstalled()) {
|
||||
13
.github/patches/removeSetupServerTip.diff
vendored
Normal file
13
.github/patches/removeSetupServerTip.diff
vendored
Normal file
@@ -0,0 +1,13 @@
|
||||
diff --git a/flutter/lib/desktop/pages/connection_page.dart b/flutter/lib/desktop/pages/connection_page.dart
|
||||
index d9dc3eec4..76f386b76 100644
|
||||
--- a/flutter/lib/desktop/pages/connection_page.dart
|
||||
+++ b/flutter/lib/desktop/pages/connection_page.dart
|
||||
@@ -131,7 +131,7 @@ class _OnlineStatusWidgetState extends State<OnlineStatusWidget> {
|
||||
if (!isIncomingOnly) startServiceWidget(),
|
||||
// ready && public
|
||||
// No need to show the guide if is custom client.
|
||||
- if (!isIncomingOnly) setupServerWidget(),
|
||||
+ //if (!isIncomingOnly) setupServerWidget(),
|
||||
],
|
||||
);
|
||||
|
||||
@@ -1,22 +0,0 @@
|
||||
diff --git a/flutter/lib/desktop/pages/desktop_home_page.dart b/flutter/lib/desktop/pages/desktop_home_page.dart
|
||||
index ba724eed5..cb66cdaed 100644
|
||||
--- a/flutter/lib/desktop/pages/desktop_home_page.dart
|
||||
+++ b/flutter/lib/desktop/pages/desktop_home_page.dart
|
||||
@@ -424,7 +424,7 @@ class _DesktopHomePageState extends State<DesktopHomePage>
|
||||
}
|
||||
|
||||
Widget buildHelpCards(String updateUrl) {
|
||||
- if (!bind.isCustomClient() &&
|
||||
+ /*if (!bind.isCustomClient() &&
|
||||
updateUrl.isNotEmpty &&
|
||||
!isCardClosed &&
|
||||
bind.mainUriPrefixSync().contains('rustdesk')) {
|
||||
@@ -435,7 +435,7 @@ class _DesktopHomePageState extends State<DesktopHomePage>
|
||||
final Uri url = Uri.parse('https://rustdesk.com/download');
|
||||
await launchUrl(url);
|
||||
}, closeButton: true);
|
||||
- }
|
||||
+ }*/
|
||||
if (systemError.isNotEmpty) {
|
||||
return buildInstallCard("", systemError, "", () {});
|
||||
}
|
||||
33
.github/patches/statussort.diff
vendored
33
.github/patches/statussort.diff
vendored
@@ -1,33 +0,0 @@
|
||||
diff --git a/flutter/lib/common/widgets/peers_view.dart b/flutter/lib/common/widgets/peers_view.dart
|
||||
index 3e34f882d..68d82116b 100644
|
||||
--- a/flutter/lib/common/widgets/peers_view.dart
|
||||
+++ b/flutter/lib/common/widgets/peers_view.dart
|
||||
@@ -25,13 +25,13 @@ class PeerSortType {
|
||||
static const String remoteId = 'Remote ID';
|
||||
static const String remoteHost = 'Remote Host';
|
||||
static const String username = 'Username';
|
||||
- // static const String status = 'Status';
|
||||
+ static const String status = 'Status';
|
||||
|
||||
static List<String> values = [
|
||||
PeerSortType.remoteId,
|
||||
PeerSortType.remoteHost,
|
||||
PeerSortType.username,
|
||||
- // PeerSortType.status
|
||||
+ PeerSortType.status
|
||||
];
|
||||
}
|
||||
|
||||
@@ -384,9 +384,9 @@ class _PeersViewState extends State<_PeersView>
|
||||
peers.sort((p1, p2) =>
|
||||
p1.username.toLowerCase().compareTo(p2.username.toLowerCase()));
|
||||
break;
|
||||
- // case PeerSortType.status:
|
||||
- // peers.sort((p1, p2) => p1.online ? -1 : 1);
|
||||
- // break;
|
||||
+ case PeerSortType.status:
|
||||
+ peers.sort((p1, p2) => p1.online ? -1 : 1);
|
||||
+ break;
|
||||
}
|
||||
}
|
||||
|
||||
8
.github/workflows/bridge.yml
vendored
8
.github/workflows/bridge.yml
vendored
@@ -12,6 +12,7 @@ on:
|
||||
type: string
|
||||
|
||||
env:
|
||||
CARGO_EXPAND_VERSION: "1.0.95"
|
||||
FLUTTER_VERSION: "3.22.3"
|
||||
FLUTTER_RUST_BRIDGE_VERSION: "1.80.1"
|
||||
RUST_VERSION: "1.75" # https://github.com/rustdesk/rustdesk/discussions/7503
|
||||
@@ -25,7 +26,7 @@ jobs:
|
||||
job:
|
||||
- {
|
||||
target: x86_64-unknown-linux-gnu,
|
||||
os: ubuntu-20.04,
|
||||
os: ubuntu-24.04,
|
||||
extra-build-args: "",
|
||||
}
|
||||
steps:
|
||||
@@ -55,9 +56,9 @@ jobs:
|
||||
gcc \
|
||||
git \
|
||||
g++ \
|
||||
libclang-10-dev \
|
||||
libclang-dev \
|
||||
libgtk-3-dev \
|
||||
llvm-10-dev \
|
||||
llvm-dev \
|
||||
nasm \
|
||||
ninja-build \
|
||||
pkg-config \
|
||||
@@ -91,6 +92,7 @@ jobs:
|
||||
- name: Install flutter rust bridge deps
|
||||
shell: bash
|
||||
run: |
|
||||
cargo install cargo-expand --version ${{ env.CARGO_EXPAND_VERSION }} --locked
|
||||
cargo install flutter_rust_bridge_codegen --version ${{ env.FLUTTER_RUST_BRIDGE_VERSION }} --features "uuid" --locked
|
||||
pushd flutter && sed -i -e 's/extended_text: 14.0.0/extended_text: 13.0.0/g' pubspec.yaml && flutter pub get && popd
|
||||
|
||||
|
||||
69
.github/workflows/build-web.yml
vendored
Normal file
69
.github/workflows/build-web.yml
vendored
Normal file
@@ -0,0 +1,69 @@
|
||||
name: Build web
|
||||
on:
|
||||
workflow_dispatch:
|
||||
env:
|
||||
FLUTTER_VERSION: "3.24.5"
|
||||
TAG_NAME: "nightly"
|
||||
VERSION: "1.3.9"
|
||||
|
||||
jobs:
|
||||
build-rustdesk-web:
|
||||
name: build-rustdesk-web
|
||||
runs-on: ubuntu-24.04
|
||||
strategy:
|
||||
fail-fast: false
|
||||
env:
|
||||
RELEASE_NAME: web-basic
|
||||
steps:
|
||||
- name: Checkout source code
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
submodules: recursive
|
||||
|
||||
- name: Prepare env
|
||||
run: |
|
||||
sudo apt-get update -y
|
||||
sudo apt-get install -y wget npm
|
||||
|
||||
- name: Install flutter
|
||||
uses: subosito/flutter-action@v2.12.0 #https://github.com/subosito/flutter-action/issues/277
|
||||
with:
|
||||
channel: "stable"
|
||||
flutter-version: ${{ env.FLUTTER_VERSION }}
|
||||
|
||||
# https://rustdesk.com/docs/en/dev/build/web/
|
||||
- name: Build web
|
||||
shell: bash
|
||||
run: |
|
||||
pushd flutter/web/v2
|
||||
npm install yarn -g
|
||||
npm install typescript -g
|
||||
npm install protoc -g
|
||||
# Install protoc first, see: https://google.github.io/proto-lens/installing-protoc.html
|
||||
npm install ts-proto
|
||||
# Only works with vite <= 2.8, see: https://github.com/vitejs/vite/blob/main/docs/guide/build.md#chunking-strategy
|
||||
npm install vite@2.8
|
||||
yarn install && yarn build
|
||||
popd
|
||||
|
||||
pushd flutter/web/v2
|
||||
wget https://github.com/rustdesk/doc.rustdesk.com/releases/download/console/web_deps.tar.gz
|
||||
tar xzf web_deps.tar.gz
|
||||
popd
|
||||
|
||||
pushd flutter
|
||||
flutter build web --release
|
||||
cd build
|
||||
#cp ../web/README.md web
|
||||
# TODO: Remove the following line when the web is almost complete.
|
||||
#echo -e "\n\nThis build is for preview and not full functionality." >> web/README.md
|
||||
dir_name="rustdesk-${{ env.VERSION }}-${{ env.RELEASE_NAME }}"
|
||||
mv web "${dir_name}" && tar czf "${dir_name}".tar.gz "${dir_name}"
|
||||
sha256sum "${dir_name}".tar.gz
|
||||
popd
|
||||
|
||||
- name: Upload APK artifact
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: web
|
||||
path: flutter/build/rustdesk-${{ env.VERSION }}-${{ env.RELEASE_NAME }}.tar.gz
|
||||
3
.github/workflows/docker-build.yml
vendored
3
.github/workflows/docker-build.yml
vendored
@@ -20,6 +20,9 @@ jobs:
|
||||
elif [[ "${{ github.ref_type }}" == "tag" ]]; then
|
||||
echo "IMAGE_TAG=${{ github.ref_name }}" >> "$GITHUB_ENV"
|
||||
echo "CREATE_IMAGE=true" >> "$GITHUB_ENV"
|
||||
elif [[ "${{ github.ref }}" == "refs/heads/master" ]]; then
|
||||
echo "IMAGE_TAG=latest" >> "$GITHUB_ENV"
|
||||
echo "CREATE_IMAGE=true" >> "$GITHUB_ENV"
|
||||
else
|
||||
echo "CREATE_IMAGE=false" >> "$GITHUB_ENV"
|
||||
fi
|
||||
|
||||
46
.github/workflows/fetch-encrypted-secrets.yml
vendored
Normal file
46
.github/workflows/fetch-encrypted-secrets.yml
vendored
Normal file
@@ -0,0 +1,46 @@
|
||||
name: Fetch Encrypted Secrets
|
||||
|
||||
on:
|
||||
workflow_call:
|
||||
inputs:
|
||||
zip_url_json:
|
||||
required: true
|
||||
type: string
|
||||
|
||||
jobs:
|
||||
download-zip:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Download with Retry
|
||||
uses: nick-fields/retry@v3
|
||||
with:
|
||||
timeout_minutes: 1
|
||||
max_attempts: 3
|
||||
shell: python
|
||||
command: |
|
||||
import requests
|
||||
import json
|
||||
import time
|
||||
|
||||
input_data = json.loads('${{ inputs.zip_url_json }}')
|
||||
url = f"{input_data['url']}/get_zip?filename={input_data['file']}"
|
||||
|
||||
for attempt in range(5):
|
||||
try:
|
||||
print(f"Downloading (Attempt {attempt + 1})...")
|
||||
r = requests.get(url, timeout=20)
|
||||
r.raise_for_status()
|
||||
with open('secrets.zip', 'wb') as f:
|
||||
f.write(r.content)
|
||||
break
|
||||
except Exception as e:
|
||||
if attempt < 4:
|
||||
time.sleep(5 * (2 ** attempt))
|
||||
else: raise e
|
||||
|
||||
- name: Upload Encrypted Artifact
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: encrypted-secrets-zip
|
||||
path: secrets.zip
|
||||
retention-days: 1
|
||||
525
.github/workflows/generator-android.yml
vendored
525
.github/workflows/generator-android.yml
vendored
File diff suppressed because one or more lines are too long
708
.github/workflows/generator-linux.yml
vendored
708
.github/workflows/generator-linux.yml
vendored
File diff suppressed because one or more lines are too long
493
.github/workflows/generator-macos.yml
vendored
493
.github/workflows/generator-macos.yml
vendored
@@ -3,56 +3,16 @@ run-name: Custom macOS Client Generator
|
||||
on:
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
server:
|
||||
description: 'Rendezvous Server'
|
||||
version:
|
||||
description: 'version to buld'
|
||||
required: true
|
||||
default: ''
|
||||
type: string
|
||||
key:
|
||||
description: 'Public Key'
|
||||
zip_url:
|
||||
description: 'url to zip of json'
|
||||
required: true
|
||||
default: ''
|
||||
type: string
|
||||
apiServer:
|
||||
description: 'API Server'
|
||||
required: true
|
||||
default: ''
|
||||
type: string
|
||||
custom:
|
||||
description: "Custom JSON"
|
||||
required: true
|
||||
default: ''
|
||||
type: string
|
||||
uuid:
|
||||
description: "uuid of request"
|
||||
required: true
|
||||
default: ''
|
||||
type: string
|
||||
iconlink:
|
||||
description: "icon link"
|
||||
required: false
|
||||
default: 'false'
|
||||
type: string
|
||||
logolink:
|
||||
description: "logo link"
|
||||
required: false
|
||||
default: 'false'
|
||||
type: string
|
||||
appname:
|
||||
description: "app name"
|
||||
required: true
|
||||
default: 'rustdesk'
|
||||
type: string
|
||||
filename:
|
||||
description: "Filename"
|
||||
required: true
|
||||
default: 'rustdesk'
|
||||
type: string
|
||||
extras:
|
||||
description: "extra inputs in json"
|
||||
required: true
|
||||
default: '{}'
|
||||
type: string
|
||||
|
||||
env:
|
||||
SCITER_RUST_VERSION: "1.75" # https://github.com/rustdesk/rustdesk/discussions/7503, also 1.78 has ABI change which causes our sciter version not working, https://blog.rust-lang.org/2024/03/30/i128-layout-update.html
|
||||
@@ -69,53 +29,76 @@ env:
|
||||
TAG_NAME: "${{ inputs.upload-tag }}"
|
||||
VCPKG_BINARY_SOURCES: "clear;x-gha,readwrite"
|
||||
# vcpkg version: 2024.07.12
|
||||
VCPKG_COMMIT_ID: "b2cb0da531c2f1f740045bfe7c4dac59f0b2b69c"
|
||||
VERSION: "${{ fromJson(inputs.extras).version }}"
|
||||
VCPKG_COMMIT_ID: "120deac3062162151622ca4860575a33844ba10b"
|
||||
ARMV7_VCPKG_COMMIT_ID: "6f29f12e82a8293156836ad81cc9bf5af41fe836"
|
||||
VERSION: "${{ inputs.version }}"
|
||||
NDK_VERSION: "r27c"
|
||||
#signing keys env variable checks
|
||||
ANDROID_SIGNING_KEY: "${{ secrets.ANDROID_SIGNING_KEY }}"
|
||||
MACOS_P12_BASE64: "${{ secrets.MACOS_P12_BASE64 }}"
|
||||
# To make a custom build with your own servers set the below secret values
|
||||
RS_PUB_KEY: "${{ inputs.key }}"
|
||||
RENDEZVOUS_SERVER: "${{ inputs.server }}"
|
||||
CUSTOM: "${{ inputs.custom }}"
|
||||
UUIDFOLDER: "${{ inputs.uuid }}"
|
||||
API_SERVER: "${{ inputs.apiServer }}"
|
||||
UPLOAD_ARTIFACT: 'true'
|
||||
SIGN_BASE_URL: "${{ secrets.SIGN_BASE_URL }}"
|
||||
STATUS_URL: "${{ secrets.GENURL }}/updategh"
|
||||
|
||||
jobs:
|
||||
setup:
|
||||
uses: ./.github/workflows/fetch-encrypted-secrets.yml
|
||||
with:
|
||||
zip_url_json: ${{ inputs.zip_url }}
|
||||
|
||||
generate-bridge:
|
||||
uses: ./.github/workflows/bridge.yml
|
||||
with:
|
||||
version: ${{ fromJson(inputs.extras).version }}
|
||||
version: ${{ inputs.version }}
|
||||
|
||||
build-for-macos-flutter:
|
||||
name: Build macOS
|
||||
runs-on: macos-latest
|
||||
needs: [generate-bridge]
|
||||
build-for-macos:
|
||||
name: ${{ matrix.job.target }}
|
||||
runs-on: ${{ matrix.job.os }}
|
||||
needs: [generate-bridge, setup]
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
job:
|
||||
# - {
|
||||
# target: x86_64-apple-darwin,
|
||||
# os: macos-13, #macos-latest or macos-14 use M1 now, https://docs.github.com/en/actions/using-github-hosted-runners/about-github-hosted-runners/about-github-hosted-runners#:~:text=14%20GB-,macos%2Dlatest%20or%20macos%2D14,-The%20macos%2Dlatestlabel
|
||||
# extra-build-args: "",
|
||||
# arch: x86_64,
|
||||
# vcpkg-triplet: x64-osx,
|
||||
# }
|
||||
- {
|
||||
target: x86_64-apple-darwin,
|
||||
os: macos-15-intel, #macos-latest or macos-14 use M1 now, https://docs.github.com/en/actions/using-github-hosted-runners/about-github-hosted-runners/about-github-hosted-runners#:~:text=14%20GB-,macos%2Dlatest%20or%20macos%2D14,-The%20macos%2Dlatestlabel
|
||||
extra-build-args: "",
|
||||
arch: x86_64,
|
||||
vcpkg-triplet: x64-osx,
|
||||
}
|
||||
- {
|
||||
target: aarch64-apple-darwin,
|
||||
os: macos-latest,
|
||||
os: macos-14,
|
||||
# extra-build-args: "--disable-flutter-texture-render", # disable this for mac, because we see a lot of users reporting flickering both on arm and x64, and we can not confirm if texture rendering has better performance if htere is no vram, https://github.com/rustdesk/rustdesk/issues/6296
|
||||
extra-build-args: "--screencapturekit",
|
||||
arch: aarch64,
|
||||
vcpkg-triplet: arm64-osx,
|
||||
}
|
||||
env:
|
||||
STATUS_URL: "${{ secrets.GENURL }}/updategh"
|
||||
|
||||
steps:
|
||||
- name: Checkout Repository
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: encrypted-secrets-zip
|
||||
|
||||
- name: Load Secrets
|
||||
uses: ./.github/actions/decrypt-secrets
|
||||
with:
|
||||
zip_password: ${{ secrets.ZIP_PASSWORD }}
|
||||
|
||||
- name: Finalize and Cleanup zip/json
|
||||
if: always() # Run even if previous steps fail
|
||||
continue-on-error: true
|
||||
uses: fjogeleit/http-request-action@v1
|
||||
with:
|
||||
url: "${{ secrets.GENURL }}/cleanzip"
|
||||
method: 'POST'
|
||||
customHeaders: '{"Content-Type": "application/json"}'
|
||||
data: '{"uuid": "${{ env.uuid }}"}'
|
||||
|
||||
- name: Export GitHub Actions cache environment variables
|
||||
uses: actions/github-script@v6
|
||||
with:
|
||||
@@ -123,24 +106,6 @@ jobs:
|
||||
core.exportVariable('ACTIONS_CACHE_URL', process.env.ACTIONS_CACHE_URL || '');
|
||||
core.exportVariable('ACTIONS_RUNTIME_TOKEN', process.env.ACTIONS_RUNTIME_TOKEN || '');
|
||||
|
||||
- name: Set rdgen value
|
||||
if: ${{ fromJson(inputs.extras).rdgen == 'true' }}
|
||||
run: |
|
||||
echo "STATUS_URL=${{ secrets.GENURL }}/updategh" >> $env:GITHUB_ENV
|
||||
|
||||
- name: Set rdgen value
|
||||
if: ${{ fromJson(inputs.extras).rdgen == 'false' }}
|
||||
run: |
|
||||
echo "STATUS_URL=${{ inputs.apiServer }}/api/updategh" >> $env:GITHUB_ENV
|
||||
|
||||
- name: Report Status
|
||||
uses: fjogeleit/http-request-action@v1
|
||||
with:
|
||||
url: ${{ env.STATUS_URL }}
|
||||
method: 'POST'
|
||||
customHeaders: '{"Content-Type": "application/json"}'
|
||||
data: '{"uuid": "${{ inputs.uuid }}", "status": "5% complete"}'
|
||||
|
||||
- name: Checkout source code
|
||||
if: ${{ env.VERSION != 'master' }}
|
||||
uses: actions/checkout@v4
|
||||
@@ -156,12 +121,6 @@ jobs:
|
||||
repository: rustdesk/rustdesk
|
||||
submodules: recursive
|
||||
|
||||
- name: Restore bridge files
|
||||
uses: actions/download-artifact@master
|
||||
with:
|
||||
name: bridge-artifact
|
||||
path: ./
|
||||
|
||||
- name: Install imagemagick and potrace and nasm and and
|
||||
shell: bash
|
||||
run: |
|
||||
@@ -172,88 +131,130 @@ jobs:
|
||||
continue-on-error: false
|
||||
shell: bash
|
||||
run: |
|
||||
# MACSTUFF Backup the original Info.plist
|
||||
cp ./flutter/macos/Runner/Info.plist ./flutter/macos/Runner/Info.plist.bak
|
||||
|
||||
# MACSTUFF Update application name and display name
|
||||
sed -i '' -e 's|<key>CFBundleName</key>\s*<string>$(PRODUCT_NAME)</string>|<key>CFBundleName</key>\n\t<string>${{ inputs.appname }}</string>|' ./flutter/macos/Runner/Info.plist
|
||||
sed -i '' -e 's|<key>CFBundleDisplayName</key>\s*<string>$(PRODUCT_NAME)</string>|<key>CFBundleDisplayName</key>\n\t<string>${{ inputs.appname }}</string>|' ./flutter/macos/Runner/Info.plist
|
||||
sed -i '' -e 's|<key>CFBundleIdentifier</key>\s*<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>|<key>CFBundleIdentifier</key>\n\t<string>com.${{ inputs.appname }}.app</string>|' ./flutter/macos/Runner/Info.plist
|
||||
|
||||
# MACSTUFF Update copyright information if needed
|
||||
sed -i '' -e 's|<key>NSHumanReadableCopyright</key>\s*<string>$(PRODUCT_COPYRIGHT)</string>|<key>NSHumanReadableCopyright</key>\n\t<string>${{ inputs.appname }}</string>|' ./flutter/macos/Runner/Info.plist
|
||||
|
||||
# MACSTUFF Update window title and bundle settings
|
||||
# MACSTUFF Backup the original files
|
||||
cp ./flutter/macos/Runner/Info.plist ./flutter/macos/Runner/Info.plist.bak
|
||||
cp ./flutter/macos/Runner/Configs/AppInfo.xcconfig ./flutter/macos/Runner/Configs/AppInfo.xcconfig.bak
|
||||
sed -i '' -e 's|PRODUCT_NAME = .*|PRODUCT_NAME = ${{ inputs.appname }}|' ./flutter/macos/Runner/Configs/AppInfo.xcconfig
|
||||
sed -i '' -e 's|PRODUCT_BUNDLE_IDENTIFIER = .*|PRODUCT_BUNDLE_IDENTIFIER = com.${{ inputs.appname }}.app|' ./flutter/macos/Runner/Configs/AppInfo.xcconfig
|
||||
sed -i '' -e 's|PRODUCT_COPYRIGHT = .*|PRODUCT_COPYRIGHT = ${{ inputs.appname }} All rights reserved.|' ./flutter/macos/Runner/Configs/AppInfo.xcconfig
|
||||
|
||||
# MACSTUFF Update Info.plist
|
||||
sed -i '' -e 's|<key>CFBundleName</key>.*<string>.*</string>|<key>CFBundleName</key>\n\t<string>${{ env.appname }}</string>|' ./flutter/macos/Runner/Info.plist
|
||||
sed -i '' -e 's|<key>CFBundleDisplayName</key>.*<string>.*</string>|<key>CFBundleDisplayName</key>\n\t<string>${{ env.appname }}</string>|' ./flutter/macos/Runner/Info.plist
|
||||
sed -i '' -e 's|<key>CFBundleIdentifier</key>.*<string>.*</string>|<key>CFBundleIdentifier</key>\n\t<string>com.${{ env.appname }}.app</string>|' ./flutter/macos/Runner/Info.plist
|
||||
# sed -i '' '/<key>NSHumanReadableCopyright<\/key>/{n;s/<string>.*<\/string>/<string>Copyright 2025 ${{ env.appname }}. All rights reserved.<\/string>/;}' ./flutter/macos/Runner/Info.plist
|
||||
|
||||
# MACSTUFF Update AppInfo.xcconfig
|
||||
sed -i '' -e 's|PRODUCT_NAME = .*|PRODUCT_NAME = ${{ env.appname }}|' ./flutter/macos/Runner/Configs/AppInfo.xcconfig
|
||||
sed -i '' -e 's|PRODUCT_BUNDLE_IDENTIFIER = .*|PRODUCT_BUNDLE_IDENTIFIER = com.${{ env.appname }}.app|' ./flutter/macos/Runner/Configs/AppInfo.xcconfig
|
||||
sed -i '' -e 's|Purslane Ltd.|${{ env.appname }}|' ./flutter/macos/Runner/Configs/AppInfo.xcconfig
|
||||
# Keep DEVELOPMENT_TEAM if it exists, don't blank it out
|
||||
|
||||
sed -i -e 's|Purslane Ltd.|${{ env.appname }}|' ./Cargo.toml
|
||||
sed -i -e 's|Purslane Ltd|${{ env.appname }}|' ./libs/portable/Cargo.toml
|
||||
|
||||
# Update Xcode project settings
|
||||
sed -i '' -e 's/PRODUCT_NAME = "RustDesk"/PRODUCT_NAME = "${{ inputs.appname }}"/' ./flutter/macos/Runner.xcodeproj/project.pbxproj
|
||||
sed -i '' -e 's/PRODUCT_BUNDLE_IDENTIFIER = ".*"/PRODUCT_BUNDLE_IDENTIFIER = "com.${{ inputs.appname }}.app"/' ./flutter/macos/Runner.xcodeproj/project.pbxproj
|
||||
sed -i '' -e 's/PRODUCT_NAME = "RustDesk"/PRODUCT_NAME = "${{ env.appname }}"/' ./flutter/macos/Runner.xcodeproj/project.pbxproj
|
||||
sed -i '' -e 's/PRODUCT_BUNDLE_IDENTIFIER = ".*"/PRODUCT_BUNDLE_IDENTIFIER = "com.${{ env.appname }}.app"/' ./flutter/macos/Runner.xcodeproj/project.pbxproj
|
||||
# Don't modify DEVELOPMENT_TEAM in project.pbxproj
|
||||
|
||||
# Update CMake settings
|
||||
if [ -f "./flutter/macos/CMakeLists.txt" ]; then
|
||||
sed -i '' -e 's/set(BINARY_NAME ".*")/set(BINARY_NAME "${{ inputs.appname }}")/' ./flutter/macos/CMakeLists.txt
|
||||
sed -i '' -e 's/set(BINARY_NAME ".*")/set(BINARY_NAME "${{ env.appname }}")/' ./flutter/macos/CMakeLists.txt
|
||||
fi
|
||||
|
||||
# Update Podfile - keep the target as 'Runner'
|
||||
# sed -i '' -e 's/target '"'"'Runner'"'"' do/target '"'"'${{ inputs.appname }}'"'"' do/' ./flutter/macos/Podfile
|
||||
# sed -i '' -e 's/target '"'"'Runner'"'"' do/target '"'"'${{ env.appname }}'"'"' do/' ./flutter/macos/Podfile
|
||||
sed -i '' -e 's/target '"'"'Runner'"'"' do/target '"'"'Runner'"'"' do/' ./flutter/macos/Podfile
|
||||
|
||||
cp ./src/lang/en.rs ./src/lang/en.rs.bak
|
||||
cp ./src/lang/nl.rs ./src/lang/nl.rs.bak
|
||||
sed -i '' -e 's|RustDesk|${{ inputs.appname }}|' ./src/lang/en.rs
|
||||
sed -i '' -e 's|RustDesk|${{ inputs.appname }}|' ./src/lang/nl.rs
|
||||
find ./src/lang -name "*.rs" -exec sed -i '' -e 's|RustDesk|${{ env.appname }}|' {} \;
|
||||
sed -i '' -e 's|RustDesk|${{ env.appname }}|' ./src/lang/nl.rs
|
||||
|
||||
sed -i '' -e 's|Homepage: https://rustdesk.com|Homepage: ${{ fromJson(inputs.extras).urlLink }}|' ./build.py
|
||||
sed -i '' -e "s|launchUrl(Uri.parse('https://rustdesk.com'));|launchUrl(Uri.parse('${{ fromJson(inputs.extras).urlLink }}'));|" ./flutter/lib/common.dart
|
||||
sed -i '' -e "s|launchUrlString('https://rustdesk.com');|launchUrlString('${{ fromJson(inputs.extras).urlLink }}');|" ./flutter/lib/desktop/pages/desktop_setting_page.dart
|
||||
sed -i '' -e "s|launchUrlString('https://rustdesk.com/privacy.html')|launchUrlString('${{ fromJson(inputs.extras).urlLink }}/privacy.html')|" ./flutter/lib/desktop/pages/desktop_setting_page.dart
|
||||
sed -i '' -e "s|const url = 'https://rustdesk.com/';|const url = '${{ fromJson(inputs.extras).urlLink }}';|" ./flutter/lib/mobile/pages/settings_page.dart
|
||||
sed -i '' -e "s|launchUrlString('https://rustdesk.com/privacy.html')|launchUrlString('${{ fromJson(inputs.extras).urlLink }}/privacy.html')|" ./flutter/lib/mobile/pages/settings_page.dart
|
||||
sed -i '' -e "s|https://rustdesk.com/privacy.html|${{ fromJson(inputs.extras).urlLink }}/privacy.html|" ./flutter/lib/desktop/pages/install_page.dart
|
||||
|
||||
sed -i '' -e '/const KEY:/,/};/d' ./src/common.rs
|
||||
sed -i '' -e '/let Ok(data) = sign::verify(&data, &pk)/,/};/d' ./src/common.rs
|
||||
sed -i '' -e 's|https://rustdesk.com|${{ env.urlLink }}|' ./build.py
|
||||
sed -i '' -e "s|launchUrl(Uri.parse('https://rustdesk.com'));|launchUrl(Uri.parse('${{ env.urlLink }}'));|" ./flutter/lib/common.dart
|
||||
sed -i '' -e "s|launchUrlString('https://rustdesk.com');|launchUrlString('${{ env.urlLink }}');|" ./flutter/lib/desktop/pages/desktop_setting_page.dart
|
||||
sed -i '' -e "s|launchUrlString('https://rustdesk.com/privacy.html')|launchUrlString('${{ env.urlLink }}/privacy.html')|" ./flutter/lib/desktop/pages/desktop_setting_page.dart
|
||||
sed -i '' -e "s|const url = 'https://rustdesk.com/';|const url = '${{ env.urlLink }}';|" ./flutter/lib/mobile/pages/settings_page.dart
|
||||
sed -i '' -e "s|launchUrlString('https://rustdesk.com/privacy.html')|launchUrlString('${{ env.urlLink }}/privacy.html')|" ./flutter/lib/mobile/pages/settings_page.dart
|
||||
sed -i '' -e "s|https://rustdesk.com/privacy.html|${{ env.urlLink }}/privacy.html|" ./flutter/lib/desktop/pages/install_page.dart
|
||||
|
||||
- name: change download link to custom
|
||||
if: env.downloadLink != 'https://rustdesk.com/download'
|
||||
continue-on-error: true
|
||||
shell: bash
|
||||
run: |
|
||||
sed -i -e 's|https://rustdesk.com/download|${{ env.downloadLink }}|' ./flutter/lib/desktop/pages/desktop_home_page.dart
|
||||
sed -i -e 's|https://rustdesk.com/download|${{ env.downloadLink }}|' ./flutter/lib/mobile/pages/connection_page.dart
|
||||
sed -i -e 's|https://rustdesk.com/download|${{ env.downloadLink }}|' ./src/ui/index.tis
|
||||
|
||||
# Update slogan
|
||||
#sed -i '' '/<key>NSHumanReadableCopyright<\/key>/{n;s/<string>.*<\/string>/<string>Copyright 2025 ${{ env.appname }}. All rights reserved.<\/string>/;}' ./flutter/macos/Runner/Info.plist
|
||||
|
||||
# Update slogan - About in en.rs
|
||||
sed -i '' -e 's/("Slogan_tip", "Made with heart in this chaotic world!")/("Slogan_tip", "Powered by ${{ env.appname }}")/' ./src/lang/en.rs
|
||||
sed -i '' -e 's/("About RustDesk", "")/("About RustDesk", "About ${{ env.appname }}")/' ./src/lang/en.rs
|
||||
|
||||
|
||||
# Update slogan - About in nl.rs
|
||||
sed -i '' -e 's/("Slogan_tip", "Ontwikkeld met het hart voor deze chaotische wereld!")/("Slogan_tip", "Powered by ${{ env.appname }}")/' ./src/lang/nl.rs
|
||||
sed -i '' -e 's/("Your Desktop", "Uw Bureaublad")/("Your Desktop", "Uw ${{ env.appname }}")/' ./src/lang/nl.rs
|
||||
sed -i '' -e 's/("About RustDesk", "Over RustDesk")/("About RustDesk", "Over ${{ env.appname }}")/' ./src/lang/nl.rs
|
||||
sed -i '' -e 's/("About", "Over")/("About", "Over ${{ env.appname }}")/' ./src/lang/nl.rs
|
||||
|
||||
sed -i -e 's|rs-ny.rustdesk.com|${{ env.server }}|' ./libs/hbb_common/src/config.rs
|
||||
sed -i -e 's|OeVuKk5nlHiXp+APNn0Y3pC1Iwpwn44JGqrQCsWqmBw=|${{ env.key }}|' ./libs/hbb_common/src/config.rs
|
||||
sed -i -e 's|https://admin.rustdesk.com|${{ env.apiServer }}|' ./src/common.rs
|
||||
|
||||
wget https://raw.githubusercontent.com/bryangerlach/rdgen/refs/heads/master/.github/patches/allowCustom.py
|
||||
python allowCustom.py
|
||||
wget https://raw.githubusercontent.com/bryangerlach/rdgen/refs/heads/master/.github/patches/removeSetupServerTip.diff
|
||||
git apply removeSetupServerTip.diff
|
||||
|
||||
# Update pubspec.yaml with proper YAML formatting
|
||||
cp ./flutter/pubspec.yaml ./flutter/pubspec.yaml.bak
|
||||
echo " archive: ^3.6.1" > ./flutter/temp_dependency.txt
|
||||
awk '/intl:/{print;system("cat ./flutter/temp_dependency.txt");next}1' ./flutter/pubspec.yaml > ./flutter/pubspec.yaml.tmp
|
||||
mv ./flutter/pubspec.yaml.tmp ./flutter/pubspec.yaml
|
||||
rm ./flutter/temp_dependency.txt
|
||||
rm ./flutter/temp_dependency.txt
|
||||
|
||||
- name: Install build runtime
|
||||
run: |
|
||||
brew install llvm create-dmg
|
||||
# pkg-config is handled in a separate step, because it may be already installed by `macos-latest`(14.7.1) runner
|
||||
if command -v pkg-config &>/dev/null; then
|
||||
echo "pkg-config is already installed"
|
||||
else
|
||||
brew install pkg-config
|
||||
fi
|
||||
|
||||
- name: Report Status
|
||||
uses: fjogeleit/http-request-action@v1
|
||||
with:
|
||||
url: ${{ env.STATUS_URL }}
|
||||
method: 'POST'
|
||||
customHeaders: '{"Content-Type": "application/json"}'
|
||||
data: '{"uuid": "${{ inputs.uuid }}", "status": "10% complete"}'
|
||||
- name: Install NASM
|
||||
run: |
|
||||
# Install NASM 2.16.x from official release.
|
||||
# Do NOT use `brew install nasm` which installs NASM 3.x.
|
||||
# NASM 3.x is a complete rewrite with incompatible CLI options and removed features.
|
||||
# aom and other multimedia libraries require NASM 2.x for x86/x86_64 assembly.
|
||||
wget https://www.nasm.us/pub/nasm/releasebuilds/2.16.03/macosx/nasm-2.16.03-macosx.zip
|
||||
unzip nasm-2.16.03-macosx.zip
|
||||
sudo cp nasm-2.16.03/nasm /usr/local/bin/nasm
|
||||
nasm --version
|
||||
|
||||
- name: Install flutter
|
||||
uses: subosito/flutter-action@v2.12.0
|
||||
uses: subosito/flutter-action@v2
|
||||
with:
|
||||
channel: "stable"
|
||||
flutter-version: ${{ env.FLUTTER_VERSION }}
|
||||
cache: true
|
||||
|
||||
- name: Patch flutter
|
||||
continue-on-error: true
|
||||
run: |
|
||||
cp .github/patches/flutter_3.24.4_dropdown_menu_enableFilter.diff $(dirname $(dirname $(which flutter)))
|
||||
cd $(dirname $(dirname $(which flutter)))
|
||||
[[ "3.24.4" == 3.24.5 ]] && git apply flutter_3.24.4_dropdown_menu_enableFilter.diff
|
||||
[[ "3.24.5" == ${{env.FLUTTER_VERSION}} ]] && git apply ${{ github.workspace }}/.github/patches/flutter_3.24.4_dropdown_menu_enableFilter.diff
|
||||
|
||||
- name: Workaround for flutter issue
|
||||
shell: bash
|
||||
run: |
|
||||
cd "$(dirname "$(which flutter)")"
|
||||
# https://github.com/flutter/flutter/issues/1.3.43
|
||||
# https://github.com/flutter/flutter/issues/133533
|
||||
sed -i -e 's/_setFramesEnabledState(false);/\/\/_setFramesEnabledState(false);/g' ../packages/flutter/lib/src/scheduler/binding.dart
|
||||
grep -n '_setFramesEnabledState(false);' ../packages/flutter/lib/src/scheduler/binding.dart
|
||||
|
||||
@@ -264,13 +265,12 @@ jobs:
|
||||
targets: ${{ matrix.job.target }}
|
||||
components: "rustfmt"
|
||||
|
||||
|
||||
- uses: Swatinem/rust-cache@v2
|
||||
with:
|
||||
prefix-key: ${{ matrix.job.os }}
|
||||
|
||||
- name: Magick stuff for macOS
|
||||
if: ${{ inputs.iconlink != 'false' }}
|
||||
if: ${{ env.iconlink_url != 'false' }}
|
||||
continue-on-error: false
|
||||
shell: bash
|
||||
run: |
|
||||
@@ -284,8 +284,8 @@ jobs:
|
||||
# Download icon using curl with additional SSL options
|
||||
curl -k -L --tlsv1.2 --proto =https --ssl-reqd \
|
||||
-H "User-Agent: Mozilla/5.0" \
|
||||
"${{ fromJson(inputs.iconlink).url }}/get_png?filename=${{ fromJson(inputs.iconlink).file }}&uuid=${{ fromJson(inputs.iconlink).uuid }}" \
|
||||
-o ./res/icon.png || wget --no-check-certificate -O ./res/icon.png "${{ fromJson(inputs.iconlink).url }}/get_png?filename=${{ fromJson(inputs.iconlink).file }}&uuid=${{ fromJson(inputs.iconlink).uuid }}"
|
||||
"${{ env.iconlink_url }}/get_png?filename=${{ env.iconlink_file }}&uuid=${{ env.iconlink_uuid }}" \
|
||||
-o ./res/icon.png || wget --no-check-certificate -O ./res/icon.png "${{ env.iconlink_url }}/get_png?filename=${{ env.iconlink_file }}&uuid=${{ env.iconlink_uuid }}"
|
||||
|
||||
# Backup existing files (if they exist)
|
||||
[ -f "./res/32x32.png" ] && mv ./res/32x32.png ./res/32x32.png.bak
|
||||
@@ -380,7 +380,7 @@ jobs:
|
||||
ls -lh rustdesk/data/flutter_assets/assets/
|
||||
|
||||
- name: replace flutter icons
|
||||
if: ${{ inputs.iconlink != 'false' }}
|
||||
if: ${{ env.iconlink_url != 'false' }}
|
||||
continue-on-error: false
|
||||
shell: bash
|
||||
run: |
|
||||
@@ -388,8 +388,8 @@ jobs:
|
||||
# Create required directories and files
|
||||
mkdir -p web
|
||||
mkdir -p assets
|
||||
echo '{"name":"${{ inputs.appname }}","short_name":"${{ inputs.appname }}","start_url":"/","display":"standalone","background_color":"#ffffff","theme_color":"#ffffff","description":"A remote desktop software."}' > web/manifest.json
|
||||
echo '<!DOCTYPE html><html><head><meta charset="UTF-8"><title>${{ inputs.appname }}</title></head><body></body></html>' > web/index.html
|
||||
echo '{"name":"${{ env.appname }}","short_name":"${{ env.appname }}","start_url":"/","display":"standalone","background_color":"#ffffff","theme_color":"#ffffff","description":"A remote desktop software."}' > web/manifest.json
|
||||
echo '<!DOCTYPE html><html><head><meta charset="UTF-8"><title>${{ env.appname }}</title></head><body></body></html>' > web/index.html
|
||||
|
||||
# Ensure the AppIcon.appiconset directory exists
|
||||
mkdir -p macos/Runner/Assets.xcassets/AppIcon.appiconset
|
||||
@@ -404,7 +404,7 @@ jobs:
|
||||
cd ..
|
||||
|
||||
- name: ui.rs
|
||||
if: ${{ inputs.iconlink != 'false' }}
|
||||
if: ${{ env.iconlink_url != 'false' }}
|
||||
continue-on-error: true
|
||||
shell: bash
|
||||
run: |
|
||||
@@ -417,73 +417,51 @@ jobs:
|
||||
|
||||
- name: fix connection delay
|
||||
continue-on-error: false
|
||||
if: ${{ fromJson(inputs.extras).delayFix == 'true' }}
|
||||
if: ${{ env.delayFix == 'true' }}
|
||||
shell: bash
|
||||
run: |
|
||||
sed -i '' -e '/if !key.is_empty() && !token.is_empty() {/,/}/d' ./src/client.rs
|
||||
sed -i -e 's|!key.is_empty()|false|' ./src/client.rs
|
||||
|
||||
- name: add cycle monitors to toolbar
|
||||
continue-on-error: true
|
||||
if: fromJson(inputs.extras).cycleMonitor == 'true'
|
||||
if: env.cycleMonitor == 'true'
|
||||
run: |
|
||||
wget https://raw.githubusercontent.com/bryangerlach/rdgen/refs/heads/master/.github/patches/cycle_monitor.diff
|
||||
git apply cycle_monitor.diff
|
||||
|
||||
- name: use X for offline display instead of orange circle
|
||||
continue-on-error: true
|
||||
if: fromJson(inputs.extras).xOffline == 'true'
|
||||
if: env.xOffline == 'true'
|
||||
run: |
|
||||
wget https://raw.githubusercontent.com/bryangerlach/rdgen/refs/heads/master/.github/patches/xoffline.diff
|
||||
git apply xoffline.diff
|
||||
|
||||
- name: hide-cm
|
||||
continue-on-error: true
|
||||
if: fromJson(inputs.extras).hidecm == 'true'
|
||||
if: env.hidecm == 'true'
|
||||
run: |
|
||||
wget https://raw.githubusercontent.com/bryangerlach/rdgen/refs/heads/master/.github/patches/hidecm.diff
|
||||
git apply hidecm.diff
|
||||
|
||||
- name: statussort
|
||||
continue-on-error: true
|
||||
if: fromJson(inputs.extras).statussort == 'true'
|
||||
run: |
|
||||
wget https://raw.githubusercontent.com/bryangerlach/rdgen/refs/heads/master/.github/patches/statussort.diff
|
||||
git apply statussort.diff
|
||||
|
||||
- name: removeNewVersionNotif
|
||||
continue-on-error: true
|
||||
if: fromJson(inputs.extras).removeNewVersionNotif == 'true'
|
||||
if: env.removeNewVersionNotif == 'true'
|
||||
run: |
|
||||
wget https://raw.githubusercontent.com/bryangerlach/rdgen/refs/heads/master/.github/patches/removeNewVersionNotif.diff
|
||||
git apply removeNewVersionNotif.diff
|
||||
sed -i -e 's|updateUrl.isNotEmpty|false|' ./flutter/lib/desktop/pages/desktop_home_page.dart
|
||||
sed -i '/let (request, url) =/,/Ok(())/{/Ok(())/!d}' ./src/common.rs
|
||||
|
||||
- name: Report Status
|
||||
uses: fjogeleit/http-request-action@v1
|
||||
- name: Restore bridge files
|
||||
uses: actions/download-artifact@master
|
||||
with:
|
||||
url: ${{ env.STATUS_URL }}
|
||||
method: 'POST'
|
||||
customHeaders: '{"Content-Type": "application/json"}'
|
||||
data: '{"uuid": "${{ inputs.uuid }}", "status": "15% complete"}'
|
||||
|
||||
|
||||
- uses: Swatinem/rust-cache@v2
|
||||
with:
|
||||
prefix-key: ${{ matrix.job.os }}
|
||||
|
||||
- name: Report Status
|
||||
uses: fjogeleit/http-request-action@v1
|
||||
with:
|
||||
url: ${{ env.STATUS_URL }}
|
||||
method: 'POST'
|
||||
customHeaders: '{"Content-Type": "application/json"}'
|
||||
data: '{"uuid": "${{ inputs.uuid }}", "status": "20% complete"}'
|
||||
name: bridge-artifact
|
||||
path: ./
|
||||
|
||||
- name: Setup vcpkg with Github Actions binary cache
|
||||
uses: lukka/run-vcpkg@v11
|
||||
with:
|
||||
vcpkgGitCommitId: ${{ env.VCPKG_COMMIT_ID }}
|
||||
doNotCache: false
|
||||
|
||||
vcpkgGitCommitId: ${{ env.VCPKG_COMMIT_ID }}
|
||||
doNotCache: false
|
||||
|
||||
- name: Install vcpkg dependencies
|
||||
run: |
|
||||
if ! $VCPKG_ROOT/vcpkg \
|
||||
@@ -498,14 +476,7 @@ jobs:
|
||||
done
|
||||
exit 1
|
||||
fi
|
||||
|
||||
- name: Report Status
|
||||
uses: fjogeleit/http-request-action@v1
|
||||
with:
|
||||
url: ${{ env.STATUS_URL }}
|
||||
method: 'POST'
|
||||
customHeaders: '{"Content-Type": "application/json"}'
|
||||
data: '{"uuid": "${{ inputs.uuid }}", "status": "25% complete"}'
|
||||
head -n 100 "${VCPKG_ROOT}/buildtrees/ffmpeg/build-${{ matrix.job.vcpkg-triplet }}-rel-out.log" || true
|
||||
|
||||
- name: Create MacOS directory structure
|
||||
run: |
|
||||
@@ -520,20 +491,12 @@ jobs:
|
||||
sed -i -e "s/osx_minimum_system_version = \"[0-9]*.[0-9]*\"/osx_minimum_system_version = \"${MIN_MACOS_VERSION}\"/" Cargo.toml
|
||||
sed -i -e "s/MACOSX_DEPLOYMENT_TARGET = [0-9]*.[0-9]*;/MACOSX_DEPLOYMENT_TARGET = ${MIN_MACOS_VERSION};/" flutter/macos/Runner.xcodeproj/project.pbxproj
|
||||
fi
|
||||
sed -i -e "s/RustDesk.app/\"${{ inputs.appname }}.app\"/" build.py
|
||||
./build.py --flutter --hwcodec ${{ matrix.job.extra-build-args }}
|
||||
sed -i -e "s/RustDesk.app/\"${{ env.appname }}.app\"/" build.py
|
||||
./build.py --flutter --hwcodec --unix-file-copy-paste ${{ matrix.job.extra-build-args }}
|
||||
|
||||
# - name: Copy service file
|
||||
# run: |
|
||||
# cp -rf ../target/release/service ./build/macos/Build/Products/Release/RustDesk.app/Contents/MacOS/
|
||||
|
||||
- name: Report Status
|
||||
uses: fjogeleit/http-request-action@v1
|
||||
with:
|
||||
url: ${{ env.STATUS_URL }}
|
||||
method: 'POST'
|
||||
customHeaders: '{"Content-Type": "application/json"}'
|
||||
data: '{"uuid": "${{ inputs.uuid }}", "status": "50% complete, this step takes about 5 minutes, be patient."}'
|
||||
|
||||
- name: Install rcodesign tool
|
||||
if: env.MACOS_P12_BASE64 != null
|
||||
@@ -554,14 +517,6 @@ jobs:
|
||||
else
|
||||
brew install pkg-config
|
||||
fi
|
||||
|
||||
- name: Report Status
|
||||
uses: fjogeleit/http-request-action@v1
|
||||
with:
|
||||
url: ${{ env.STATUS_URL }}
|
||||
method: 'POST'
|
||||
customHeaders: '{"Content-Type": "application/json"}'
|
||||
data: '{"uuid": "${{ inputs.uuid }}", "status": "70% complete, this step takes about 5 minutes, be patient."}'
|
||||
|
||||
- name: Show version information (Rust, cargo, Clang)
|
||||
shell: bash
|
||||
@@ -574,7 +529,7 @@ jobs:
|
||||
rustc -V
|
||||
|
||||
- name: icon svg handling
|
||||
if: ${{ inputs.iconlink != 'false' }}
|
||||
if: ${{ env.iconlink_url != 'false' }}
|
||||
continue-on-error: false
|
||||
shell: bash
|
||||
run: |
|
||||
@@ -590,7 +545,7 @@ jobs:
|
||||
rm ./temp_icon.pbm
|
||||
|
||||
- name: logo handling
|
||||
if: ${{ inputs.logolink != 'false' }}
|
||||
if: ${{ env.logolink_url != 'false' }}
|
||||
continue-on-error: false
|
||||
shell: bash
|
||||
run: |
|
||||
@@ -598,19 +553,11 @@ jobs:
|
||||
mkdir -p "$ASSETS_DIR"
|
||||
curl -k -L --tlsv1.2 --proto =https --ssl-reqd \
|
||||
-H "User-Agent: Mozilla/5.0" \
|
||||
"${{ fromJson(inputs.logolink).url }}/get_png?filename=${{ fromJson(inputs.logolink).file }}&uuid=${{ fromJson(inputs.logolink).uuid }}" \
|
||||
"${{ env.logolink_url }}/get_png?filename=${{ env.logolink_file }}&uuid=${{ env.logolink_uuid }}" \
|
||||
-o "$ASSETS_DIR/logo.png" || \
|
||||
wget --no-check-certificate \
|
||||
-O "$ASSETS_DIR/logo.png" \
|
||||
"${{ fromJson(inputs.logolink).url }}/get_png?filename=${{ fromJson(inputs.logolink).file }}&uuid=${{ fromJson(inputs.logolink).uuid }}"
|
||||
|
||||
- name: Report Status
|
||||
uses: fjogeleit/http-request-action@v1
|
||||
with:
|
||||
url: ${{ env.STATUS_URL }}
|
||||
method: 'POST'
|
||||
customHeaders: '{"Content-Type": "application/json"}'
|
||||
data: '{"uuid": "${{ inputs.uuid }}", "status": "85% complete"}'
|
||||
"${{ env.logolink_url }}/get_png?filename=${{ env.logolink_file }}&uuid=${{ env.logolink_uuid }}"
|
||||
|
||||
- name: Sign macOS app bundle
|
||||
if: env.MACOS_P12_BASE64 != ''
|
||||
@@ -623,21 +570,21 @@ jobs:
|
||||
# Rename RustDesk.app to the custom app name first
|
||||
if [ -d "RustDesk.app" ]; then
|
||||
# First rename the app if it's still called RustDesk.app
|
||||
mv "RustDesk.app" "${{ inputs.appname }}.app"
|
||||
echo "Renamed RustDesk.app to ${{ inputs.appname }}.app"
|
||||
mv "RustDesk.app" "${{ env.appname }}.app"
|
||||
echo "Renamed RustDesk.app to ${{ env.appname }}.app"
|
||||
fi
|
||||
|
||||
echo "App bundle contents after rename:"
|
||||
ls -la "${{ inputs.appname }}.app" || echo "App not found"
|
||||
ls -la "${{ inputs.appname }}.app/Contents" || echo "Contents not found"
|
||||
ls -la "${{ env.appname }}.app" || echo "App not found"
|
||||
ls -la "${{ env.appname }}.app/Contents" || echo "Contents not found"
|
||||
|
||||
# Decode the certificate
|
||||
echo "${{ secrets.MACOS_P12_BASE64 }}" | base64 --decode > certificate.p12
|
||||
|
||||
# Sign the app bundle and its contents
|
||||
if [ -d "${{ inputs.appname }}.app/Contents/MacOS" ]; then
|
||||
if [ -d "${{ env.appname }}.app/Contents/MacOS" ]; then
|
||||
echo "Signing main executable..."
|
||||
MAIN_EXECUTABLE="${{ inputs.appname }}.app/Contents/MacOS/${{ inputs.appname }}"
|
||||
MAIN_EXECUTABLE="${{ env.appname }}.app/Contents/MacOS/${{ env.appname }}"
|
||||
if [ -f "$MAIN_EXECUTABLE" ]; then
|
||||
rcodesign sign --p12-file certificate.p12 --p12-password "${{ secrets.MACOS_P12_PASSWORD }}" \
|
||||
--code-signature-flags runtime "$MAIN_EXECUTABLE"
|
||||
@@ -645,23 +592,23 @@ jobs:
|
||||
echo "Main executable not found at expected path: $MAIN_EXECUTABLE"
|
||||
# Try to find the actual executable
|
||||
echo "Available executables in MacOS directory:"
|
||||
ls -la "${{ inputs.appname }}.app/Contents/MacOS/"
|
||||
ACTUAL_EXECUTABLE=$(ls "${{ inputs.appname }}.app/Contents/MacOS/" | head -n 1)
|
||||
ls -la "${{ env.appname }}.app/Contents/MacOS/"
|
||||
ACTUAL_EXECUTABLE=$(ls "${{ env.appname }}.app/Contents/MacOS/" | head -n 1)
|
||||
if [ -n "$ACTUAL_EXECUTABLE" ]; then
|
||||
echo "Found executable: $ACTUAL_EXECUTABLE"
|
||||
rcodesign sign --p12-file certificate.p12 --p12-password "${{ secrets.MACOS_P12_PASSWORD }}" \
|
||||
--code-signature-flags runtime "${{ inputs.appname }}.app/Contents/MacOS/$ACTUAL_EXECUTABLE"
|
||||
--code-signature-flags runtime "${{ env.appname }}.app/Contents/MacOS/$ACTUAL_EXECUTABLE"
|
||||
fi
|
||||
fi
|
||||
|
||||
echo "Signing frameworks..."
|
||||
find "${{ inputs.appname }}.app/Contents/Frameworks" -type f -not -name ".*" -exec \
|
||||
find "${{ env.appname }}.app/Contents/Frameworks" -type f -not -name ".*" -exec \
|
||||
rcodesign sign --p12-file certificate.p12 --p12-password "${{ secrets.MACOS_P12_PASSWORD }}" \
|
||||
--code-signature-flags runtime {} \;
|
||||
|
||||
echo "Signing main bundle..."
|
||||
rcodesign sign --p12-file certificate.p12 --p12-password "${{ secrets.MACOS_P12_PASSWORD }}" \
|
||||
--code-signature-flags runtime "${{ inputs.appname }}.app"
|
||||
--code-signature-flags runtime "${{ env.appname }}.app"
|
||||
else
|
||||
echo "Error: Invalid app bundle structure"
|
||||
exit 1
|
||||
@@ -679,33 +626,25 @@ jobs:
|
||||
# Find the actual .app bundle
|
||||
if [ -d "RustDesk.app" ]; then
|
||||
# First rename the app if it's still called RustDesk.app
|
||||
mv "RustDesk.app" "${{ inputs.appname }}.app"
|
||||
mv "RustDesk.app" "${{ env.appname }}.app"
|
||||
fi
|
||||
if [ ! -d "${{ inputs.appname }}.app" ]; then
|
||||
if [ ! -d "${{ env.appname }}.app" ]; then
|
||||
echo "Could not find .app bundle!"
|
||||
exit 1
|
||||
fi
|
||||
echo "Creating DMG for ${{ inputs.appname }}.app"
|
||||
echo "Creating DMG for ${{ env.appname }}.app"
|
||||
create-dmg \
|
||||
--volname "${{ inputs.appname }}" \
|
||||
--volname "${{ env.appname }}" \
|
||||
--window-pos 200 120 \
|
||||
--window-size 800 400 \
|
||||
--icon-size 100 \
|
||||
--icon "${{ inputs.appname }}.app" 200 190 \
|
||||
--hide-extension "${{ inputs.appname }}.app" \
|
||||
--icon "${{ env.appname }}.app" 200 190 \
|
||||
--hide-extension "${{ env.appname }}.app" \
|
||||
--app-drop-link 600 185 \
|
||||
"${{ inputs.appname }}-${{ matrix.job.arch }}.dmg" \
|
||||
"${{ inputs.appname }}.app"
|
||||
mv "${{ inputs.appname }}-${{ matrix.job.arch }}.dmg" $GITHUB_WORKSPACE/
|
||||
|
||||
#- name: Upload unsigned macOS app
|
||||
# if: env.UPLOAD_ARTIFACT == 'true'
|
||||
# uses: actions/upload-artifact@master
|
||||
# with:
|
||||
# name: ${{ inputs.appname }}-${{ matrix.job.arch }}
|
||||
# path: ${{ inputs.appname }}-${{ matrix.job.arch }}.dmg
|
||||
|
||||
|
||||
"${{ env.appname }}-${{ matrix.job.arch }}.dmg" \
|
||||
"${{ env.appname }}.app"
|
||||
mv "${{ env.appname }}-${{ matrix.job.arch }}.dmg" $GITHUB_WORKSPACE/
|
||||
|
||||
- name: Rename rustdesk
|
||||
if: env.UPLOAD_ARTIFACT == 'true'
|
||||
run: |
|
||||
@@ -714,70 +653,46 @@ jobs:
|
||||
ls -la
|
||||
|
||||
# Find the DMG file dynamically
|
||||
DMG_FILE=$(find . -name "${{ inputs.appname }}-${{ matrix.job.arch }}.dmg")
|
||||
DMG_FILE=$(find . -name "${{ env.appname }}-${{ matrix.job.arch }}.dmg")
|
||||
|
||||
if [ -n "$DMG_FILE" ]; then
|
||||
echo "Found DMG file: $DMG_FILE"
|
||||
mv "$DMG_FILE" "${{ inputs.filename }}.dmg"
|
||||
echo "Renamed to ${{ inputs.filename }}.dmg"
|
||||
mv "$DMG_FILE" "${{ env.filename }}-${{ matrix.job.arch }}.dmg"
|
||||
echo "Renamed to ${{ env.filename }}-${{ matrix.job.arch }}.dmg"
|
||||
else
|
||||
echo "No DMG file found matching the pattern"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
- name: send file to rdgen server
|
||||
if: ${{ fromJson(inputs.extras).rdgen == 'true' }}
|
||||
if: ${{ env.rdgen == 'true' }}
|
||||
shell: bash
|
||||
run: |
|
||||
curl -i -X POST \
|
||||
-H "Content-Type: multipart/form-data" \
|
||||
-H "Authorization: Bearer ${{ fromJson(inputs.extras).token }}" \
|
||||
-F "file=@$GITHUB_WORKSPACE/${{ inputs.filename }}.dmg" \
|
||||
-F "uuid=${{ inputs.uuid }}" \
|
||||
-H "Authorization: Bearer ${{ env.token }}" \
|
||||
-F "file=@$GITHUB_WORKSPACE/${{ env.filename }}-${{ matrix.job.arch }}.dmg" \
|
||||
-F "uuid=${{ env.uuid }}" \
|
||||
"${{ secrets.GENURL }}/save_custom_client"
|
||||
|
||||
|
||||
- name: send file to api server
|
||||
if: ${{ fromJson(inputs.extras).rdgen == 'false' }}
|
||||
if: ${{ env.rdgen == 'false' }}
|
||||
shell: bash
|
||||
run: |
|
||||
curl -i -X POST \
|
||||
-H "Content-Type: multipart/form-data" \
|
||||
-H "Authorization: Bearer ${{ fromJson(inputs.extras).token }}" \
|
||||
-F "file=@$GITHUB_WORKSPACE/${{ inputs.filename }}.dmg" \
|
||||
"${{ inputs.apiServer }}/api/save_custom_client"
|
||||
-H "Authorization: Bearer ${{ env.token }}" \
|
||||
-F "file=@$GITHUB_WORKSPACE/${{ env.filename }}-${{ matrix.job.arch }}.dmg" \
|
||||
"${{ env.apiServer }}/api/save_custom_client"
|
||||
|
||||
- name: Report Status
|
||||
uses: fjogeleit/http-request-action@v1
|
||||
cleanup:
|
||||
needs: [build-for-macos]
|
||||
runs-on: ubuntu-latest
|
||||
continue-on-error: true
|
||||
if: always()
|
||||
steps:
|
||||
- name: Delete secrets artifact
|
||||
uses: geekyeggo/delete-artifact@v5
|
||||
with:
|
||||
url: ${{ env.STATUS_URL }}
|
||||
method: 'POST'
|
||||
customHeaders: '{"Content-Type": "application/json"}'
|
||||
data: '{"uuid": "${{ inputs.uuid }}", "status": "Success"}'
|
||||
|
||||
- name: failed
|
||||
if: failure()
|
||||
uses: fjogeleit/http-request-action@v1
|
||||
with:
|
||||
url: ${{ env.STATUS_URL }}
|
||||
method: 'POST'
|
||||
customHeaders: '{"Content-Type": "application/json"}'
|
||||
data: '{"uuid": "${{ inputs.uuid }}", "status": "Generation failed, try again"}'
|
||||
|
||||
- name: failed
|
||||
if: cancelled()
|
||||
uses: fjogeleit/http-request-action@v1
|
||||
with:
|
||||
url: ${{ env.STATUS_URL }}
|
||||
method: 'POST'
|
||||
customHeaders: '{"Content-Type": "application/json"}'
|
||||
data: '{"uuid": "${{ inputs.uuid }}", "status": "Generation cancelled, try again"}'
|
||||
|
||||
#- name: Publish DMG package
|
||||
# if: env.UPLOAD_ARTIFACT == 'true'
|
||||
# uses: softprops/action-gh-release@v1
|
||||
# with:
|
||||
# prerelease: true
|
||||
# tag_name: ${{ inputs.upload-tag }}
|
||||
# files: |
|
||||
# ${{ inputs.appname }}*-${{ matrix.job.arch }}.dmg
|
||||
name: encrypted-secrets-zip
|
||||
|
||||
454
.github/workflows/generator-windows-x86.yml
vendored
Normal file
454
.github/workflows/generator-windows-x86.yml
vendored
Normal file
File diff suppressed because one or more lines are too long
637
.github/workflows/generator-windows.yml
vendored
637
.github/workflows/generator-windows.yml
vendored
File diff suppressed because one or more lines are too long
110
.github/workflows/pre137-bridge.yml
vendored
110
.github/workflows/pre137-bridge.yml
vendored
@@ -1,110 +0,0 @@
|
||||
# This yaml shares the build bridge steps with ci and nightly.
|
||||
name: Build flutter-rust-bridge
|
||||
# 2023-11-23 18:00:00+00:00
|
||||
|
||||
on:
|
||||
workflow_call:
|
||||
inputs:
|
||||
version:
|
||||
description: 'Rustdesk Version'
|
||||
required: true
|
||||
default: '1.3.1'
|
||||
type: string
|
||||
|
||||
env:
|
||||
FLUTTER_VERSION: "3.22.3"
|
||||
FLUTTER_RUST_BRIDGE_VERSION: "1.80.1"
|
||||
RUST_VERSION: "1.75" # https://github.com/rustdesk/rustdesk/discussions/7503
|
||||
|
||||
jobs:
|
||||
generate_bridge:
|
||||
runs-on: ${{ matrix.job.os }}
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
job:
|
||||
- {
|
||||
target: x86_64-unknown-linux-gnu,
|
||||
os: ubuntu-20.04,
|
||||
extra-build-args: "",
|
||||
}
|
||||
steps:
|
||||
- name: Checkout source code
|
||||
if: ${{ inputs.version != 'master' }}
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
repository: rustdesk/rustdesk
|
||||
ref: refs/tags/${{ inputs.version }}
|
||||
|
||||
- name: Checkout source code
|
||||
if: ${{ inputs.version == 'master' }}
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
repository: rustdesk/rustdesk
|
||||
|
||||
- name: Install prerequisites
|
||||
run: |
|
||||
sudo apt-get install ca-certificates -y
|
||||
sudo apt-get update -y
|
||||
sudo apt-get install -y \
|
||||
clang \
|
||||
cmake \
|
||||
curl \
|
||||
gcc \
|
||||
git \
|
||||
g++ \
|
||||
libclang-10-dev \
|
||||
libgtk-3-dev \
|
||||
llvm-10-dev \
|
||||
nasm \
|
||||
ninja-build \
|
||||
pkg-config \
|
||||
wget
|
||||
|
||||
- name: Install Rust toolchain
|
||||
uses: dtolnay/rust-toolchain@v1
|
||||
with:
|
||||
toolchain: ${{ env.RUST_VERSION }}
|
||||
targets: ${{ matrix.job.target }}
|
||||
components: "rustfmt"
|
||||
|
||||
- uses: Swatinem/rust-cache@v2
|
||||
with:
|
||||
prefix-key: bridge-${{ matrix.job.os }}
|
||||
|
||||
- name: Cache Bridge
|
||||
id: cache-bridge
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
path: /tmp/flutter_rust_bridge
|
||||
key: vcpkg-${{ matrix.job.arch }}
|
||||
|
||||
- name: Install flutter
|
||||
uses: subosito/flutter-action@v2
|
||||
with:
|
||||
channel: "stable"
|
||||
flutter-version: ${{ env.FLUTTER_VERSION }}
|
||||
cache: true
|
||||
|
||||
- name: Install flutter rust bridge deps
|
||||
shell: bash
|
||||
run: |
|
||||
cargo install flutter_rust_bridge_codegen --version ${{ env.FLUTTER_RUST_BRIDGE_VERSION }} --features "uuid" --locked
|
||||
pushd flutter && sed -i -e 's/extended_text: 14.0.0/extended_text: 13.0.0/g' pubspec.yaml && flutter pub get && popd
|
||||
|
||||
- name: Run flutter rust bridge
|
||||
run: |
|
||||
~/.cargo/bin/flutter_rust_bridge_codegen --rust-input ./src/flutter_ffi.rs --dart-output ./flutter/lib/generated_bridge.dart --c-output ./flutter/macos/Runner/bridge_generated.h
|
||||
cp ./flutter/macos/Runner/bridge_generated.h ./flutter/ios/Runner/bridge_generated.h
|
||||
|
||||
- name: Upload Artifact
|
||||
uses: actions/upload-artifact@master
|
||||
with:
|
||||
name: bridge-artifact
|
||||
path: |
|
||||
./src/bridge_generated.rs
|
||||
./src/bridge_generated.io.rs
|
||||
./flutter/lib/generated_bridge.dart
|
||||
./flutter/lib/generated_bridge.freezed.dart
|
||||
./flutter/macos/Runner/bridge_generated.h
|
||||
./flutter/ios/Runner/bridge_generated.h
|
||||
631
.github/workflows/pre137-generator-android.yml
vendored
631
.github/workflows/pre137-generator-android.yml
vendored
File diff suppressed because one or more lines are too long
643
.github/workflows/pre137-generator-linux.yml
vendored
643
.github/workflows/pre137-generator-linux.yml
vendored
File diff suppressed because one or more lines are too long
798
.github/workflows/pre137-generator-macos.yml
vendored
798
.github/workflows/pre137-generator-macos.yml
vendored
@@ -1,798 +0,0 @@
|
||||
name: Custom macOS Client Generator
|
||||
run-name: Custom macOS Client Generator
|
||||
on:
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
server:
|
||||
description: 'Rendezvous Server'
|
||||
required: true
|
||||
default: ''
|
||||
type: string
|
||||
key:
|
||||
description: 'Public Key'
|
||||
required: true
|
||||
default: ''
|
||||
type: string
|
||||
apiServer:
|
||||
description: 'API Server'
|
||||
required: true
|
||||
default: ''
|
||||
type: string
|
||||
custom:
|
||||
description: "Custom JSON"
|
||||
required: true
|
||||
default: ''
|
||||
type: string
|
||||
uuid:
|
||||
description: "uuid of request"
|
||||
required: true
|
||||
default: ''
|
||||
type: string
|
||||
iconlink:
|
||||
description: "icon link"
|
||||
required: false
|
||||
default: 'false'
|
||||
type: string
|
||||
logolink:
|
||||
description: "logo link"
|
||||
required: false
|
||||
default: 'false'
|
||||
type: string
|
||||
appname:
|
||||
description: "app name"
|
||||
required: true
|
||||
default: 'rustdesk'
|
||||
type: string
|
||||
filename:
|
||||
description: "Filename"
|
||||
required: true
|
||||
default: 'rustdesk'
|
||||
type: string
|
||||
extras:
|
||||
description: "extra inputs in json"
|
||||
required: true
|
||||
default: '{}'
|
||||
type: string
|
||||
|
||||
env:
|
||||
SCITER_RUST_VERSION: "1.75" # https://github.com/rustdesk/rustdesk/discussions/7503, also 1.78 has ABI change which causes our sciter version not working, https://blog.rust-lang.org/2024/03/30/i128-layout-update.html
|
||||
RUST_VERSION: "1.75" # sciter failed on m1 with 1.78 because of https://blog.rust-lang.org/2024/03/30/i128-layout-update.html
|
||||
MAC_RUST_VERSION: "1.81"
|
||||
CARGO_NDK_VERSION: "3.1.2"
|
||||
SCITER_ARMV7_CMAKE_VERSION: "3.29.7"
|
||||
SCITER_NASM_DEBVERSION: "2.14-1"
|
||||
LLVM_VERSION: "15.0.6"
|
||||
FLUTTER_VERSION: "3.24.5"
|
||||
ANDROID_FLUTTER_VERSION: "3.24.5" # >= 3.16 is very slow on my android phone, but work well on most of others. We may switch to new flutter after changing to texture rendering (I believe it can solve my problem).
|
||||
FLUTTER_RUST_BRIDGE_VERSION: "1.80.1" # for arm64 linux because official Dart SDK does not work
|
||||
FLUTTER_ELINUX_VERSION: "3.16.9"
|
||||
TAG_NAME: "${{ inputs.upload-tag }}"
|
||||
VCPKG_BINARY_SOURCES: "clear;x-gha,readwrite"
|
||||
# vcpkg version: 2024.07.12
|
||||
VCPKG_COMMIT_ID: "b2cb0da531c2f1f740045bfe7c4dac59f0b2b69c"
|
||||
VERSION: "${{ fromJson(inputs.extras).version }}"
|
||||
NDK_VERSION: "r27c"
|
||||
#signing keys env variable checks
|
||||
ANDROID_SIGNING_KEY: "${{ secrets.ANDROID_SIGNING_KEY }}"
|
||||
MACOS_P12_BASE64: "${{ secrets.MACOS_P12_BASE64 }}"
|
||||
# To make a custom build with your own servers set the below secret values
|
||||
RS_PUB_KEY: "${{ inputs.key }}"
|
||||
RENDEZVOUS_SERVER: "${{ inputs.server }}"
|
||||
CUSTOM: "${{ inputs.custom }}"
|
||||
UUIDFOLDER: "${{ inputs.uuid }}"
|
||||
API_SERVER: "${{ inputs.apiServer }}"
|
||||
UPLOAD_ARTIFACT: 'true'
|
||||
SIGN_BASE_URL: "${{ secrets.SIGN_BASE_URL }}"
|
||||
STATUS_URL: "${{ secrets.GENURL }}/updategh"
|
||||
|
||||
jobs:
|
||||
generate-bridge:
|
||||
uses: ./.github/workflows/pre137-bridge.yml
|
||||
with:
|
||||
version: ${{ fromJson(inputs.extras).version }}
|
||||
|
||||
build-for-macos-flutter:
|
||||
name: Build macOS
|
||||
runs-on: macos-latest
|
||||
needs: [generate-bridge]
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
job:
|
||||
- {
|
||||
target: aarch64-apple-darwin,
|
||||
os: macos-latest,
|
||||
# extra-build-args: "--disable-flutter-texture-render", # disable this for mac, because we see a lot of users reporting flickering both on arm and x64, and we can not confirm if texture rendering has better performance if htere is no vram, https://github.com/rustdesk/rustdesk/issues/6296
|
||||
extra-build-args: "--screencapturekit",
|
||||
arch: aarch64,
|
||||
vcpkg-triplet: arm64-osx,
|
||||
}
|
||||
|
||||
steps:
|
||||
- name: Export GitHub Actions cache environment variables
|
||||
uses: actions/github-script@v6
|
||||
with:
|
||||
script: |
|
||||
core.exportVariable('ACTIONS_CACHE_URL', process.env.ACTIONS_CACHE_URL || '');
|
||||
core.exportVariable('ACTIONS_RUNTIME_TOKEN', process.env.ACTIONS_RUNTIME_TOKEN || '');
|
||||
|
||||
- name: Set rdgen value
|
||||
if: ${{ fromJson(inputs.extras).rdgen == 'true' }}
|
||||
run: |
|
||||
echo "STATUS_URL=${{ secrets.GENURL }}/updategh" >> $env:GITHUB_ENV
|
||||
|
||||
- name: Set rdgen value
|
||||
if: ${{ fromJson(inputs.extras).rdgen == 'false' }}
|
||||
run: |
|
||||
echo "STATUS_URL=${{ inputs.apiServer }}/api/updategh" >> $env:GITHUB_ENV
|
||||
|
||||
- name: Report Status
|
||||
uses: fjogeleit/http-request-action@v1
|
||||
with:
|
||||
url: ${{ env.STATUS_URL }}
|
||||
method: 'POST'
|
||||
customHeaders: '{"Content-Type": "application/json"}'
|
||||
data: '{"uuid": "${{ inputs.uuid }}", "status": "5% complete"}'
|
||||
|
||||
|
||||
|
||||
- name: Checkout source code
|
||||
if: ${{ env.VERSION != 'master' }}
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
repository: rustdesk/rustdesk
|
||||
ref: refs/tags/${{ env.VERSION }}
|
||||
|
||||
- name: Checkout source code
|
||||
if: ${{ env.VERSION == 'master' }}
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
repository: rustdesk/rustdesk
|
||||
|
||||
- name: Restore bridge files
|
||||
uses: actions/download-artifact@master
|
||||
with:
|
||||
name: bridge-artifact
|
||||
path: ./
|
||||
|
||||
- name: Install imagemagick and potrace and nasm and and
|
||||
shell: bash
|
||||
run: |
|
||||
brew install imagemagick potrace nasm cmake gcc wget ninja
|
||||
echo "$(brew --prefix imagemagick)/bin" >> $GITHUB_PATH
|
||||
|
||||
- name: Update macOS Info.plist and settings
|
||||
continue-on-error: false
|
||||
shell: bash
|
||||
run: |
|
||||
# MACSTUFF Backup the original Info.plist
|
||||
cp ./flutter/macos/Runner/Info.plist ./flutter/macos/Runner/Info.plist.bak
|
||||
|
||||
# MACSTUFF Update application name and display name
|
||||
sed -i '' -e 's|<key>CFBundleName</key>\s*<string>$(PRODUCT_NAME)</string>|<key>CFBundleName</key>\n\t<string>${{ inputs.appname }}</string>|' ./flutter/macos/Runner/Info.plist
|
||||
sed -i '' -e 's|<key>CFBundleDisplayName</key>\s*<string>$(PRODUCT_NAME)</string>|<key>CFBundleDisplayName</key>\n\t<string>${{ inputs.appname }}</string>|' ./flutter/macos/Runner/Info.plist
|
||||
sed -i '' -e 's|<key>CFBundleIdentifier</key>\s*<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>|<key>CFBundleIdentifier</key>\n\t<string>com.${{ inputs.appname }}.app</string>|' ./flutter/macos/Runner/Info.plist
|
||||
|
||||
# MACSTUFF Update copyright information if needed
|
||||
sed -i '' -e 's|<key>NSHumanReadableCopyright</key>\s*<string>$(PRODUCT_COPYRIGHT)</string>|<key>NSHumanReadableCopyright</key>\n\t<string>${{ inputs.appname }}</string>|' ./flutter/macos/Runner/Info.plist
|
||||
|
||||
# MACSTUFF Update window title and bundle settings
|
||||
cp ./flutter/macos/Runner/Configs/AppInfo.xcconfig ./flutter/macos/Runner/Configs/AppInfo.xcconfig.bak
|
||||
sed -i '' -e 's|PRODUCT_NAME = .*|PRODUCT_NAME = ${{ inputs.appname }}|' ./flutter/macos/Runner/Configs/AppInfo.xcconfig
|
||||
sed -i '' -e 's|PRODUCT_BUNDLE_IDENTIFIER = .*|PRODUCT_BUNDLE_IDENTIFIER = com.${{ inputs.appname }}.app|' ./flutter/macos/Runner/Configs/AppInfo.xcconfig
|
||||
# Keep DEVELOPMENT_TEAM if it exists, don't blank it out
|
||||
|
||||
# Update Xcode project settings
|
||||
sed -i '' -e 's/PRODUCT_NAME = "RustDesk"/PRODUCT_NAME = "${{ inputs.appname }}"/' ./flutter/macos/Runner.xcodeproj/project.pbxproj
|
||||
sed -i '' -e 's/PRODUCT_BUNDLE_IDENTIFIER = ".*"/PRODUCT_BUNDLE_IDENTIFIER = "com.${{ inputs.appname }}.app"/' ./flutter/macos/Runner.xcodeproj/project.pbxproj
|
||||
# Don't modify DEVELOPMENT_TEAM in project.pbxproj
|
||||
|
||||
# Update CMake settings
|
||||
if [ -f "./flutter/macos/CMakeLists.txt" ]; then
|
||||
sed -i '' -e 's/set(BINARY_NAME ".*")/set(BINARY_NAME "${{ inputs.appname }}")/' ./flutter/macos/CMakeLists.txt
|
||||
fi
|
||||
|
||||
# Update Podfile - keep the target as 'Runner'
|
||||
# sed -i '' -e 's/target '"'"'Runner'"'"' do/target '"'"'${{ inputs.appname }}'"'"' do/' ./flutter/macos/Podfile
|
||||
sed -i '' -e 's/target '"'"'Runner'"'"' do/target '"'"'Runner'"'"' do/' ./flutter/macos/Podfile
|
||||
|
||||
cp ./src/lang/en.rs ./src/lang/en.rs.bak
|
||||
cp ./src/lang/nl.rs ./src/lang/nl.rs.bak
|
||||
sed -i '' -e 's|RustDesk|${{ inputs.appname }}|' ./src/lang/en.rs
|
||||
sed -i '' -e 's|RustDesk|${{ inputs.appname }}|' ./src/lang/nl.rs
|
||||
|
||||
sed -i '' -e 's|Homepage: https://rustdesk.com|Homepage: ${{ fromJson(inputs.extras).urlLink }}|' ./build.py
|
||||
sed -i '' -e "s|launchUrl(Uri.parse('https://rustdesk.com'));|launchUrl(Uri.parse('${{ fromJson(inputs.extras).urlLink }}'));|" ./flutter/lib/common.dart
|
||||
sed -i '' -e "s|launchUrlString('https://rustdesk.com');|launchUrlString('${{ fromJson(inputs.extras).urlLink }}');|" ./flutter/lib/desktop/pages/desktop_setting_page.dart
|
||||
sed -i '' -e "s|launchUrlString('https://rustdesk.com/privacy.html')|launchUrlString('${{ fromJson(inputs.extras).urlLink }}/privacy.html')|" ./flutter/lib/desktop/pages/desktop_setting_page.dart
|
||||
sed -i '' -e "s|const url = 'https://rustdesk.com/';|const url = '${{ fromJson(inputs.extras).urlLink }}';|" ./flutter/lib/mobile/pages/settings_page.dart
|
||||
sed -i '' -e "s|launchUrlString('https://rustdesk.com/privacy.html')|launchUrlString('${{ fromJson(inputs.extras).urlLink }}/privacy.html')|" ./flutter/lib/mobile/pages/settings_page.dart
|
||||
sed -i '' -e "s|https://rustdesk.com/privacy.html|${{ fromJson(inputs.extras).urlLink }}/privacy.html|" ./flutter/lib/desktop/pages/install_page.dart
|
||||
|
||||
sed -i '' -e '/const KEY:/,/};/d' ./src/common.rs
|
||||
sed -i '' -e '/let Ok(data) = sign::verify(&data, &pk)/,/};/d' ./src/common.rs
|
||||
|
||||
# Update pubspec.yaml with proper YAML formatting
|
||||
cp ./flutter/pubspec.yaml ./flutter/pubspec.yaml.bak
|
||||
echo " archive: ^3.6.1" > ./flutter/temp_dependency.txt
|
||||
awk '/intl:/{print;system("cat ./flutter/temp_dependency.txt");next}1' ./flutter/pubspec.yaml > ./flutter/pubspec.yaml.tmp
|
||||
mv ./flutter/pubspec.yaml.tmp ./flutter/pubspec.yaml
|
||||
rm ./flutter/temp_dependency.txt
|
||||
|
||||
- name: Report Status
|
||||
uses: fjogeleit/http-request-action@v1
|
||||
with:
|
||||
url: ${{ env.STATUS_URL }}
|
||||
method: 'POST'
|
||||
customHeaders: '{"Content-Type": "application/json"}'
|
||||
data: '{"uuid": "${{ inputs.uuid }}", "status": "10% complete"}'
|
||||
|
||||
- name: Install flutter
|
||||
uses: subosito/flutter-action@v2.12.0
|
||||
with:
|
||||
channel: "stable"
|
||||
flutter-version: ${{ env.FLUTTER_VERSION }}
|
||||
cache: true
|
||||
|
||||
- name: Patch flutter
|
||||
continue-on-error: true
|
||||
run: |
|
||||
cp .github/patches/flutter_3.24.4_dropdown_menu_enableFilter.diff $(dirname $(dirname $(which flutter)))
|
||||
cd $(dirname $(dirname $(which flutter)))
|
||||
[[ "3.24.4" == 3.24.5 ]] && git apply flutter_3.24.4_dropdown_menu_enableFilter.diff
|
||||
|
||||
- name: Workaround for flutter issue
|
||||
shell: bash
|
||||
run: |
|
||||
cd "$(dirname "$(which flutter)")"
|
||||
# https://github.com/flutter/flutter/issues/1.3.43
|
||||
sed -i -e 's/_setFramesEnabledState(false);/\/\/_setFramesEnabledState(false);/g' ../packages/flutter/lib/src/scheduler/binding.dart
|
||||
grep -n '_setFramesEnabledState(false);' ../packages/flutter/lib/src/scheduler/binding.dart
|
||||
|
||||
- name: Install Rust toolchain
|
||||
uses: dtolnay/rust-toolchain@v1
|
||||
with:
|
||||
toolchain: ${{ env.MAC_RUST_VERSION }}
|
||||
targets: ${{ matrix.job.target }}
|
||||
components: "rustfmt"
|
||||
|
||||
|
||||
- uses: Swatinem/rust-cache@v2
|
||||
with:
|
||||
prefix-key: ${{ matrix.job.os }}
|
||||
|
||||
- name: Setup vcpkg with Github Actions binary cache
|
||||
uses: lukka/run-vcpkg@v11
|
||||
with:
|
||||
vcpkgGitCommitId: ${{ env.VCPKG_COMMIT_ID }}
|
||||
doNotCache: false
|
||||
|
||||
- name: Install vcpkg dependencies
|
||||
run: |
|
||||
if ! $VCPKG_ROOT/vcpkg \
|
||||
install \
|
||||
--x-install-root="$VCPKG_ROOT/installed"; then
|
||||
find "${VCPKG_ROOT}/" -name "*.log" | while read -r _1; do
|
||||
echo "$_1:"
|
||||
echo "======"
|
||||
cat "$_1"
|
||||
echo "======"
|
||||
echo ""
|
||||
done
|
||||
exit 1
|
||||
fi
|
||||
head -n 100 "${VCPKG_ROOT}/buildtrees/ffmpeg/build-${{ matrix.job.vcpkg-triplet }}-rel-out.log" || true
|
||||
shell: bash
|
||||
|
||||
- name: Magick stuff for macOS
|
||||
if: ${{ inputs.iconlink != 'false' }}
|
||||
continue-on-error: false
|
||||
shell: bash
|
||||
run: |
|
||||
# Create all necessary directories first
|
||||
mkdir -p ./res
|
||||
mkdir -p ./flutter/assets
|
||||
mkdir -p ./flutter/macos/Runner/Assets.xcassets/AppIcon.appiconset
|
||||
mkdir -p ./macos/Runner/Assets.xcassets/AppIcon.appiconset
|
||||
mkdir -p ./rustdesk/data/flutter_assets/assets
|
||||
|
||||
# Download icon using curl with additional SSL options
|
||||
curl -k -L --tlsv1.2 --proto =https --ssl-reqd \
|
||||
-H "User-Agent: Mozilla/5.0" \
|
||||
"${{ fromJson(inputs.iconlink).url }}/get_png?filename=${{ fromJson(inputs.iconlink).file }}&uuid=${{ fromJson(inputs.iconlink).uuid }}" \
|
||||
-o ./res/icon.png || wget --no-check-certificate -O ./res/icon.png "${{ fromJson(inputs.iconlink).url }}/get_png?filename=${{ fromJson(inputs.iconlink).file }}&uuid=${{ fromJson(inputs.iconlink).uuid }}"
|
||||
|
||||
# Backup existing files (if they exist)
|
||||
[ -f "./res/32x32.png" ] && mv ./res/32x32.png ./res/32x32.png.bak
|
||||
[ -f "./res/64x64.png" ] && mv ./res/64x64.png ./res/64x64.png.bak
|
||||
[ -f "./res/128x128.png" ] && mv ./res/128x128.png ./res/128x128.png.bak
|
||||
[ -f "./res/mac-icon.png" ] && mv ./res/mac-icon.png ./res/mac-icon.png.bak
|
||||
[ -f "./flutter/assets/icon.png" ] && mv ./flutter/assets/icon.png ./flutter/assets/icon.png.bak
|
||||
[ -f "./flutter/assets/icon.svg" ] && mv ./flutter/assets/icon.svg ./flutter/assets/icon.svg.bak
|
||||
[ -f "./rustdesk/data/flutter_assets/assets/icon.svg" ] && mv ./rustdesk/data/flutter_assets/assets/icon.svg ./rustdesk/data/flutter_assets/assets/icon.svg.bak
|
||||
|
||||
# Create standard app icons
|
||||
magick ./res/icon.png -resize 32x32 ./res/32x32.png
|
||||
magick ./res/icon.png -resize 64x64 ./res/64x64.png
|
||||
magick ./res/icon.png -resize 128x128 ./res/128x128.png
|
||||
|
||||
# Copy icon to Flutter assets
|
||||
cp ./res/icon.png ./flutter/assets/icon.png
|
||||
cp ./res/icon.png ./rustdesk/data/flutter_assets/assets/icon.png
|
||||
|
||||
# Convert PNG to SVG using potrace
|
||||
magick ./res/icon.png -flatten ./temp_icon.pbm
|
||||
potrace --svg -o ./flutter/assets/icon.svg ./temp_icon.pbm
|
||||
cp ./flutter/assets/icon.svg ./rustdesk/data/flutter_assets/assets/icon.svg
|
||||
rm ./temp_icon.pbm
|
||||
|
||||
# Create macOS app icons
|
||||
magick ./res/icon.png -resize 16x16 "flutter/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_16.png"
|
||||
magick ./res/icon.png -resize 32x32 "flutter/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_32.png"
|
||||
magick ./res/icon.png -resize 64x64 "flutter/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_64.png"
|
||||
magick ./res/icon.png -resize 128x128 "flutter/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_128.png"
|
||||
magick ./res/icon.png -resize 256x256 "flutter/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_256.png"
|
||||
magick ./res/icon.png -resize 512x512 "flutter/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_512.png"
|
||||
magick ./res/icon.png -resize 1024x1024 "flutter/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_1024.png"
|
||||
|
||||
# Create macOS specific icons
|
||||
magick ./res/icon.png -resize 128x128 ./res/mac-icon.png
|
||||
|
||||
# Create dark mode tray icon (optimized for macOS menu bar)
|
||||
magick ./res/icon.png -resize 22x22 -colorspace gray -alpha set -background none -channel A -evaluate set 100% ./res/mac-tray-dark-x2.png
|
||||
|
||||
# Create light mode tray icon (optimized for macOS menu bar)
|
||||
magick ./res/icon.png -resize 22x22 -negate -colorspace gray -alpha set -background none -channel A -evaluate set 100% ./res/mac-tray-light-x2.png
|
||||
|
||||
# Create AppIcon.icns (macOS native icon format)
|
||||
mkdir -p ./iconset.iconset
|
||||
cp "flutter/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_16.png" "./iconset.iconset/icon_16x16.png"
|
||||
cp "flutter/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_32.png" "./iconset.iconset/icon_16x16@2x.png"
|
||||
cp "flutter/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_32.png" "./iconset.iconset/icon_32x32.png"
|
||||
cp "flutter/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_64.png" "./iconset.iconset/icon_32x32@2x.png"
|
||||
cp "flutter/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_128.png" "./iconset.iconset/icon_128x128.png"
|
||||
cp "flutter/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_256.png" "./iconset.iconset/icon_128x128@2x.png"
|
||||
cp "flutter/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_256.png" "./iconset.iconset/icon_256x256.png"
|
||||
cp "flutter/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_512.png" "./iconset.iconset/icon_256x256@2x.png"
|
||||
cp "flutter/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_512.png" "./iconset.iconset/icon_512x512.png"
|
||||
cp "flutter/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_1024.png" "./iconset.iconset/icon_512x512@2x.png"
|
||||
iconutil -c icns ./iconset.iconset -o ./flutter/macos/Runner/AppIcon.icns
|
||||
rm -rf ./iconset.iconset
|
||||
|
||||
# Create Contents.json for macOS app icon
|
||||
echo '{
|
||||
"images": [
|
||||
{"size":"16x16","idiom":"mac","filename":"app_icon_16.png","scale":"1x"},
|
||||
{"size":"16x16","idiom":"mac","filename":"app_icon_32.png","scale":"2x"},
|
||||
{"size":"32x32","idiom":"mac","filename":"app_icon_32.png","scale":"1x"},
|
||||
{"size":"32x32","idiom":"mac","filename":"app_icon_64.png","scale":"2x"},
|
||||
{"size":"128x128","idiom":"mac","filename":"app_icon_128.png","scale":"1x"},
|
||||
{"size":"128x128","idiom":"mac","filename":"app_icon_256.png","scale":"2x"},
|
||||
{"size":"256x256","idiom":"mac","filename":"app_icon_256.png","scale":"1x"},
|
||||
{"size":"256x256","idiom":"mac","filename":"app_icon_512.png","scale":"2x"},
|
||||
{"size":"512x512","idiom":"mac","filename":"app_icon_512.png","scale":"1x"},
|
||||
{"size":"512x512","idiom":"mac","filename":"app_icon_1024.png","scale":"2x"}
|
||||
],
|
||||
"info": {
|
||||
"version": 1,
|
||||
"author": "xcode"
|
||||
}
|
||||
}' > "flutter/macos/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json"
|
||||
|
||||
# Copy icons and Contents.json to both locations
|
||||
cp -r flutter/macos/Runner/Assets.xcassets/AppIcon.appiconset/* macos/Runner/Assets.xcassets/AppIcon.appiconset/
|
||||
|
||||
# Verify files exist and show their sizes
|
||||
echo "Verifying generated files:"
|
||||
ls -lh ./res/mac-tray-dark-x2.png
|
||||
ls -lh ./res/mac-tray-light-x2.png
|
||||
ls -lh ./res/mac-icon.png
|
||||
echo "Flutter macOS app icons:"
|
||||
ls -lh flutter/macos/Runner/Assets.xcassets/AppIcon.appiconset/
|
||||
echo "Flutter assets:"
|
||||
ls -lh flutter/assets/icon.*
|
||||
echo "RustDesk Flutter assets:"
|
||||
ls -lh rustdesk/data/flutter_assets/assets/
|
||||
|
||||
- name: replace flutter icons
|
||||
if: ${{ inputs.iconlink != 'false' }}
|
||||
continue-on-error: false
|
||||
shell: bash
|
||||
run: |
|
||||
cd ./flutter
|
||||
# Create required directories and files
|
||||
mkdir -p web
|
||||
mkdir -p assets
|
||||
echo '{"name":"${{ inputs.appname }}","short_name":"${{ inputs.appname }}","start_url":"/","display":"standalone","background_color":"#ffffff","theme_color":"#ffffff","description":"A remote desktop software."}' > web/manifest.json
|
||||
echo '<!DOCTYPE html><html><head><meta charset="UTF-8"><title>${{ inputs.appname }}</title></head><body></body></html>' > web/index.html
|
||||
|
||||
# Ensure the AppIcon.appiconset directory exists
|
||||
mkdir -p macos/Runner/Assets.xcassets/AppIcon.appiconset
|
||||
|
||||
# Copy the processed icons to Flutter locations
|
||||
cp ../res/mac-icon.png ./assets/icon.png
|
||||
cp ../flutter/assets/icon.svg ./assets/icon.svg || true
|
||||
|
||||
flutter pub upgrade win32
|
||||
flutter pub get
|
||||
flutter pub run flutter_launcher_icons
|
||||
cd ..
|
||||
|
||||
- name: ui.rs
|
||||
if: ${{ inputs.iconlink != 'false' }}
|
||||
continue-on-error: true
|
||||
shell: bash
|
||||
run: |
|
||||
cp ./src/ui.rs ./src/ui.rs.bak
|
||||
if [ -f "./res/icon.png" ]; then
|
||||
SEARCH_STR="iVBORw0KGgoAAAANSUhEUgAAAIAAAACACAYAAADDPmHLAAAACXBIWXMAAEiuAABIrgHwmhA7AAAAGXRFWHRTb2Z0d2FyZQB3d3cuaW5rc2NhcGUub3Jnm+48GgAAEx9JREFUeJztnXmYHMV5h9"
|
||||
b64=$(base64 < ./res/icon.png)
|
||||
sed -i '' -e "s~$SEARCH_STR.*\"~$b64\"~" ./src/ui.rs
|
||||
fi
|
||||
|
||||
- name: fix connection delay
|
||||
continue-on-error: false
|
||||
if: ${{ fromJson(inputs.extras).delayFix == 'true' }}
|
||||
shell: bash
|
||||
run: |
|
||||
sed -i '' -e '/if !key.is_empty() && !token.is_empty() {/,/}/d' ./src/client.rs
|
||||
|
||||
- name: add cycle monitors to toolbar
|
||||
continue-on-error: true
|
||||
if: fromJson(inputs.extras).cycleMonitor == 'true'
|
||||
run: |
|
||||
wget https://raw.githubusercontent.com/bryangerlach/rdgen/refs/heads/master/.github/patches/cycle_monitor.diff
|
||||
git apply cycle_monitor.diff
|
||||
|
||||
- name: use X for offline display instead of orange circle
|
||||
continue-on-error: true
|
||||
if: fromJson(inputs.extras).xOffline == 'true'
|
||||
run: |
|
||||
wget https://raw.githubusercontent.com/bryangerlach/rdgen/refs/heads/master/.github/patches/xoffline.diff
|
||||
git apply xoffline.diff
|
||||
|
||||
- name: hide-cm
|
||||
continue-on-error: true
|
||||
if: fromJson(inputs.extras).hidecm == 'true'
|
||||
run: |
|
||||
wget https://raw.githubusercontent.com/bryangerlach/rdgen/refs/heads/master/.github/patches/hidecm.diff
|
||||
git apply hidecm.diff
|
||||
|
||||
- name: statussort
|
||||
continue-on-error: true
|
||||
if: fromJson(inputs.extras).statussort == 'true'
|
||||
run: |
|
||||
wget https://raw.githubusercontent.com/bryangerlach/rdgen/refs/heads/master/.github/patches/statussort.diff
|
||||
git apply statussort.diff
|
||||
|
||||
- name: removeNewVersionNotif
|
||||
continue-on-error: true
|
||||
if: fromJson(inputs.extras).removeNewVersionNotif == 'true'
|
||||
run: |
|
||||
wget https://raw.githubusercontent.com/bryangerlach/rdgen/refs/heads/master/.github/patches/removeNewVersionNotif.diff
|
||||
git apply removeNewVersionNotif.diff
|
||||
|
||||
|
||||
- name: Install Rust toolchain
|
||||
uses: dtolnay/rust-toolchain@v1
|
||||
with:
|
||||
toolchain: ${{ env.MAC_RUST_VERSION }}
|
||||
targets: ${{ matrix.job.target }}
|
||||
components: "rustfmt"
|
||||
|
||||
- name: Report Status
|
||||
uses: fjogeleit/http-request-action@v1
|
||||
with:
|
||||
url: ${{ env.STATUS_URL }}
|
||||
method: 'POST'
|
||||
customHeaders: '{"Content-Type": "application/json"}'
|
||||
data: '{"uuid": "${{ inputs.uuid }}", "status": "15% complete"}'
|
||||
|
||||
|
||||
- uses: Swatinem/rust-cache@v2
|
||||
with:
|
||||
prefix-key: ${{ matrix.job.os }}
|
||||
|
||||
- name: Report Status
|
||||
uses: fjogeleit/http-request-action@v1
|
||||
with:
|
||||
url: ${{ env.STATUS_URL }}
|
||||
method: 'POST'
|
||||
customHeaders: '{"Content-Type": "application/json"}'
|
||||
data: '{"uuid": "${{ inputs.uuid }}", "status": "20% complete"}'
|
||||
|
||||
- name: Setup vcpkg with Github Actions binary cache
|
||||
uses: lukka/run-vcpkg@v11
|
||||
with:
|
||||
vcpkgGitCommitId: ${{ env.VCPKG_COMMIT_ID }}
|
||||
doNotCache: false
|
||||
|
||||
- name: Install vcpkg dependencies
|
||||
run: |
|
||||
if ! $VCPKG_ROOT/vcpkg \
|
||||
install \
|
||||
--x-install-root="$VCPKG_ROOT/installed"; then
|
||||
find "${VCPKG_ROOT}/" -name "*.log" | while read -r _1; do
|
||||
echo "$_1:"
|
||||
echo "======"
|
||||
cat "$_1"
|
||||
echo "======"
|
||||
echo ""
|
||||
done
|
||||
exit 1
|
||||
fi
|
||||
|
||||
- name: Report Status
|
||||
uses: fjogeleit/http-request-action@v1
|
||||
with:
|
||||
url: ${{ env.STATUS_URL }}
|
||||
method: 'POST'
|
||||
customHeaders: '{"Content-Type": "application/json"}'
|
||||
data: '{"uuid": "${{ inputs.uuid }}", "status": "25% complete"}'
|
||||
|
||||
- name: Build rustdesk
|
||||
run: |
|
||||
if [ "${{ matrix.job.target }}" = "aarch64-apple-darwin" ]; then
|
||||
MIN_MACOS_VERSION="12.3"
|
||||
sed -i -e "s/MACOSX_DEPLOYMENT_TARGET\=[0-9]*.[0-9]*/MACOSX_DEPLOYMENT_TARGET=${MIN_MACOS_VERSION}/" build.py
|
||||
sed -i -e "s/platform :osx, '.*'/platform :osx, '${MIN_MACOS_VERSION}'/" flutter/macos/Podfile
|
||||
sed -i -e "s/osx_minimum_system_version = \"[0-9]*.[0-9]*\"/osx_minimum_system_version = \"${MIN_MACOS_VERSION}\"/" Cargo.toml
|
||||
sed -i -e "s/MACOSX_DEPLOYMENT_TARGET = [0-9]*.[0-9]*;/MACOSX_DEPLOYMENT_TARGET = ${MIN_MACOS_VERSION};/" flutter/macos/Runner.xcodeproj/project.pbxproj
|
||||
fi
|
||||
sed -i -e "s/RustDesk.app/\"${{ inputs.appname }}.app\"/" build.py
|
||||
./build.py --flutter --hwcodec ${{ matrix.job.extra-build-args }}
|
||||
|
||||
- name: Report Status
|
||||
uses: fjogeleit/http-request-action@v1
|
||||
with:
|
||||
url: ${{ env.STATUS_URL }}
|
||||
method: 'POST'
|
||||
customHeaders: '{"Content-Type": "application/json"}'
|
||||
data: '{"uuid": "${{ inputs.uuid }}", "status": "50% complete, this step takes about 5 minutes, be patient."}'
|
||||
|
||||
- name: Install rcodesign tool
|
||||
if: env.MACOS_P12_BASE64 != null
|
||||
shell: bash
|
||||
run: |
|
||||
pushd /tmp
|
||||
wget https://github.com/indygreg/apple-platform-rs/releases/download/apple-codesign%2F0.22.0/apple-codesign-0.22.0-macos-universal.tar.gz
|
||||
tar -zxvf apple-codesign-0.22.0-macos-universal.tar.gz
|
||||
mv apple-codesign-0.22.0-macos-universal/rcodesign /usr/local/bin
|
||||
popd
|
||||
|
||||
- name: Install build runtime
|
||||
run: |
|
||||
brew install llvm create-dmg nasm cmake gcc wget ninja
|
||||
# pkg-config is handled in a separate step, because it may be already installed by `macos-latest`(14.7.1) runner
|
||||
if command -v pkg-config &>/dev/null; then
|
||||
echo "pkg-config is already installed"
|
||||
else
|
||||
brew install pkg-config
|
||||
fi
|
||||
|
||||
- name: Report Status
|
||||
uses: fjogeleit/http-request-action@v1
|
||||
with:
|
||||
url: ${{ env.STATUS_URL }}
|
||||
method: 'POST'
|
||||
customHeaders: '{"Content-Type": "application/json"}'
|
||||
data: '{"uuid": "${{ inputs.uuid }}", "status": "70% complete, this step takes about 5 minutes, be patient."}'
|
||||
|
||||
- name: Show version information (Rust, cargo, Clang)
|
||||
shell: bash
|
||||
run: |
|
||||
clang --version || true
|
||||
rustup -V
|
||||
rustup toolchain list
|
||||
rustup default
|
||||
cargo -V
|
||||
rustc -V
|
||||
|
||||
- name: icon svg handling
|
||||
if: ${{ inputs.iconlink != 'false' }}
|
||||
continue-on-error: false
|
||||
shell: bash
|
||||
run: |
|
||||
ASSETS_DIR="build/macos/Build/Products/Release/RustDesk.app/Contents/Frameworks/App.framework/Versions/Current/Resources/flutter_assets/assets"
|
||||
mkdir -p "$ASSETS_DIR"
|
||||
if [ -f "$ASSETS_DIR/icon.svg" ]; then
|
||||
mv "$ASSETS_DIR/icon.svg" "$ASSETS_DIR/icon.svg.bak"
|
||||
fi
|
||||
# First convert PNG to PBM (bitmap)
|
||||
magick convert ./res/icon.png ./temp_icon.pbm
|
||||
# Then use potrace to convert to SVG
|
||||
potrace --svg -o "$ASSETS_DIR/icon.svg" ./temp_icon.pbm
|
||||
rm ./temp_icon.pbm
|
||||
|
||||
- name: logo handling
|
||||
if: ${{ inputs.logolink != 'false' }}
|
||||
continue-on-error: false
|
||||
shell: bash
|
||||
run: |
|
||||
ASSETS_DIR="build/macos/Build/Products/Release/RustDesk.app/Contents/Frameworks/App.framework/Versions/Current/Resources/flutter_assets/assets"
|
||||
mkdir -p "$ASSETS_DIR"
|
||||
curl -k -L --tlsv1.2 --proto =https --ssl-reqd \
|
||||
-H "User-Agent: Mozilla/5.0" \
|
||||
"${{ fromJson(inputs.logolink).url }}/get_png?filename=${{ fromJson(inputs.logolink).file }}&uuid=${{ fromJson(inputs.logolink).uuid }}" \
|
||||
-o "$ASSETS_DIR/logo.png" || \
|
||||
wget --no-check-certificate \
|
||||
-O "$ASSETS_DIR/logo.png" \
|
||||
"${{ fromJson(inputs.logolink).url }}/get_png?filename=${{ fromJson(inputs.logolink).file }}&uuid=${{ fromJson(inputs.logolink).uuid }}"
|
||||
|
||||
- name: Report Status
|
||||
uses: fjogeleit/http-request-action@v1
|
||||
with:
|
||||
url: ${{ env.STATUS_URL }}
|
||||
method: 'POST'
|
||||
customHeaders: '{"Content-Type": "application/json"}'
|
||||
data: '{"uuid": "${{ inputs.uuid }}", "status": "85% complete"}'
|
||||
|
||||
- name: Sign macOS app bundle
|
||||
if: env.MACOS_P12_BASE64 != ''
|
||||
run: |
|
||||
cd flutter/build/macos/Build/Products/Release
|
||||
# Debug info
|
||||
echo "Current directory contents:"
|
||||
ls -la
|
||||
|
||||
# Rename RustDesk.app to the custom app name first
|
||||
if [ -d "RustDesk.app" ]; then
|
||||
# First rename the app if it's still called RustDesk.app
|
||||
mv "RustDesk.app" "${{ inputs.appname }}.app"
|
||||
echo "Renamed RustDesk.app to ${{ inputs.appname }}.app"
|
||||
fi
|
||||
|
||||
echo "App bundle contents after rename:"
|
||||
ls -la "${{ inputs.appname }}.app" || echo "App not found"
|
||||
ls -la "${{ inputs.appname }}.app/Contents" || echo "Contents not found"
|
||||
|
||||
# Decode the certificate
|
||||
echo "${{ secrets.MACOS_P12_BASE64 }}" | base64 --decode > certificate.p12
|
||||
|
||||
# Sign the app bundle and its contents
|
||||
if [ -d "${{ inputs.appname }}.app/Contents/MacOS" ]; then
|
||||
echo "Signing main executable..."
|
||||
MAIN_EXECUTABLE="${{ inputs.appname }}.app/Contents/MacOS/${{ inputs.appname }}"
|
||||
if [ -f "$MAIN_EXECUTABLE" ]; then
|
||||
rcodesign sign --p12-file certificate.p12 --p12-password "${{ secrets.MACOS_P12_PASSWORD }}" \
|
||||
--code-signature-flags runtime "$MAIN_EXECUTABLE"
|
||||
else
|
||||
echo "Main executable not found at expected path: $MAIN_EXECUTABLE"
|
||||
# Try to find the actual executable
|
||||
echo "Available executables in MacOS directory:"
|
||||
ls -la "${{ inputs.appname }}.app/Contents/MacOS/"
|
||||
ACTUAL_EXECUTABLE=$(ls "${{ inputs.appname }}.app/Contents/MacOS/" | head -n 1)
|
||||
if [ -n "$ACTUAL_EXECUTABLE" ]; then
|
||||
echo "Found executable: $ACTUAL_EXECUTABLE"
|
||||
rcodesign sign --p12-file certificate.p12 --p12-password "${{ secrets.MACOS_P12_PASSWORD }}" \
|
||||
--code-signature-flags runtime "${{ inputs.appname }}.app/Contents/MacOS/$ACTUAL_EXECUTABLE"
|
||||
fi
|
||||
fi
|
||||
|
||||
echo "Signing frameworks..."
|
||||
find "${{ inputs.appname }}.app/Contents/Frameworks" -type f -not -name ".*" -exec \
|
||||
rcodesign sign --p12-file certificate.p12 --p12-password "${{ secrets.MACOS_P12_PASSWORD }}" \
|
||||
--code-signature-flags runtime {} \;
|
||||
|
||||
echo "Signing main bundle..."
|
||||
rcodesign sign --p12-file certificate.p12 --p12-password "${{ secrets.MACOS_P12_PASSWORD }}" \
|
||||
--code-signature-flags runtime "${{ inputs.appname }}.app"
|
||||
else
|
||||
echo "Error: Invalid app bundle structure"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Clean up
|
||||
rm certificate.p12
|
||||
|
||||
- name: Create DMG
|
||||
run: |
|
||||
cd /Users/runner/work/${{ github.event.repository.name }}/${{ github.event.repository.name }}/flutter/build/macos/Build/Products/Release
|
||||
# Print directory contents for debugging
|
||||
echo "Directory contents:"
|
||||
ls -la
|
||||
# Find the actual .app bundle
|
||||
if [ -d "RustDesk.app" ]; then
|
||||
# First rename the app if it's still called RustDesk.app
|
||||
mv "RustDesk.app" "${{ inputs.appname }}.app"
|
||||
fi
|
||||
if [ ! -d "${{ inputs.appname }}.app" ]; then
|
||||
echo "Could not find .app bundle!"
|
||||
exit 1
|
||||
fi
|
||||
echo "Creating DMG for ${{ inputs.appname }}.app"
|
||||
create-dmg \
|
||||
--volname "${{ inputs.appname }}" \
|
||||
--window-pos 200 120 \
|
||||
--window-size 800 400 \
|
||||
--icon-size 100 \
|
||||
--icon "${{ inputs.appname }}.app" 200 190 \
|
||||
--hide-extension "${{ inputs.appname }}.app" \
|
||||
--app-drop-link 600 185 \
|
||||
"${{ inputs.appname }}-${{ matrix.job.arch }}.dmg" \
|
||||
"${{ inputs.appname }}.app"
|
||||
mv "${{ inputs.appname }}-${{ matrix.job.arch }}.dmg" $GITHUB_WORKSPACE/
|
||||
|
||||
#- name: Upload unsigned macOS app
|
||||
# if: env.UPLOAD_ARTIFACT == 'true'
|
||||
# uses: actions/upload-artifact@master
|
||||
# with:
|
||||
# name: ${{ inputs.appname }}-${{ matrix.job.arch }}
|
||||
# path: ${{ inputs.appname }}-${{ matrix.job.arch }}.dmg
|
||||
|
||||
|
||||
- name: Rename rustdesk
|
||||
if: env.UPLOAD_ARTIFACT == 'true'
|
||||
run: |
|
||||
cd $GITHUB_WORKSPACE
|
||||
echo "Directory contents:"
|
||||
ls -la
|
||||
|
||||
# Find the DMG file dynamically
|
||||
DMG_FILE=$(find . -name "${{ inputs.appname }}-${{ matrix.job.arch }}.dmg")
|
||||
|
||||
if [ -n "$DMG_FILE" ]; then
|
||||
echo "Found DMG file: $DMG_FILE"
|
||||
mv "$DMG_FILE" "${{ inputs.filename }}.dmg"
|
||||
echo "Renamed to ${{ inputs.filename }}.dmg"
|
||||
else
|
||||
echo "No DMG file found matching the pattern"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
- name: send file to rdgen server
|
||||
if: ${{ fromJson(inputs.extras).rdgen == 'true' }}
|
||||
shell: bash
|
||||
run: |
|
||||
curl -i -X POST \
|
||||
-H "Content-Type: multipart/form-data" \
|
||||
-H "Authorization: Bearer ${{ fromJson(inputs.extras).token }}" \
|
||||
-F "file=@$GITHUB_WORKSPACE/${{ inputs.filename }}.dmg" \
|
||||
-F "uuid=${{ inputs.uuid }}" \
|
||||
"${{ secrets.GENURL }}/save_custom_client"
|
||||
|
||||
|
||||
- name: send file to api server
|
||||
if: ${{ fromJson(inputs.extras).rdgen == 'false' }}
|
||||
shell: bash
|
||||
run: |
|
||||
curl -i -X POST \
|
||||
-H "Content-Type: multipart/form-data" \
|
||||
-H "Authorization: Bearer ${{ fromJson(inputs.extras).token }}" \
|
||||
-F "file=@$GITHUB_WORKSPACE/${{ inputs.filename }}.dmg" \
|
||||
"${{ inputs.apiServer }}/api/save_custom_client"
|
||||
|
||||
- name: Report Status
|
||||
uses: fjogeleit/http-request-action@v1
|
||||
with:
|
||||
url: ${{ env.STATUS_URL }}
|
||||
method: 'POST'
|
||||
customHeaders: '{"Content-Type": "application/json"}'
|
||||
data: '{"uuid": "${{ inputs.uuid }}", "status": "Success"}'
|
||||
|
||||
- name: failed
|
||||
if: failure()
|
||||
uses: fjogeleit/http-request-action@v1
|
||||
with:
|
||||
url: ${{ env.STATUS_URL }}
|
||||
method: 'POST'
|
||||
customHeaders: '{"Content-Type": "application/json"}'
|
||||
data: '{"uuid": "${{ inputs.uuid }}", "status": "Generation failed, try again"}'
|
||||
|
||||
- name: failed
|
||||
if: cancelled()
|
||||
uses: fjogeleit/http-request-action@v1
|
||||
with:
|
||||
url: ${{ env.STATUS_URL }}
|
||||
method: 'POST'
|
||||
customHeaders: '{"Content-Type": "application/json"}'
|
||||
data: '{"uuid": "${{ inputs.uuid }}", "status": "Generation cancelled, try again"}'
|
||||
|
||||
#- name: Publish DMG package
|
||||
# if: env.UPLOAD_ARTIFACT == 'true'
|
||||
# uses: softprops/action-gh-release@v1
|
||||
# with:
|
||||
# prerelease: true
|
||||
# tag_name: ${{ inputs.upload-tag }}
|
||||
# files: |
|
||||
# ${{ inputs.appname }}*-${{ matrix.job.arch }}.dmg
|
||||
665
.github/workflows/pre137-generator-windows.yml
vendored
665
.github/workflows/pre137-generator-windows.yml
vendored
File diff suppressed because one or more lines are too long
562
.github/workflows/sh-generator-windows.yml
vendored
Normal file
562
.github/workflows/sh-generator-windows.yml
vendored
Normal file
@@ -0,0 +1,562 @@
|
||||
name: Custom Windows Client Generator
|
||||
run-name: Custom Windows Client Generator
|
||||
on:
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
version:
|
||||
description: 'version to buld'
|
||||
required: true
|
||||
default: ''
|
||||
type: string
|
||||
zip_url:
|
||||
description: 'url to zip of json'
|
||||
required: true
|
||||
default: ''
|
||||
type: string
|
||||
|
||||
|
||||
env:
|
||||
SCITER_RUST_VERSION: "1.75" # https://github.com/rustdesk/rustdesk/discussions/7503, also 1.78 has ABI change which causes our sciter version not working, https://blog.rust-lang.org/2024/03/30/i128-layout-update.html
|
||||
RUST_VERSION: "1.75" # sciter failed on m1 with 1.78 because of https://blog.rust-lang.org/2024/03/30/i128-layout-update.html
|
||||
CARGO_NDK_VERSION: "3.1.2"
|
||||
SCITER_ARMV7_CMAKE_VERSION: "3.29.7"
|
||||
SCITER_NASM_DEBVERSION: "2.15.05-1"
|
||||
LLVM_VERSION: "15.0.6"
|
||||
FLUTTER_VERSION: "3.24.5"
|
||||
ANDROID_FLUTTER_VERSION: "3.24.5"
|
||||
# for arm64 linux because official Dart SDK does not work
|
||||
FLUTTER_ELINUX_VERSION: "3.16.9"
|
||||
TAG_NAME: "${{ inputs.upload-tag }}"
|
||||
VCPKG_BINARY_SOURCES: "clear;x-gha,readwrite"
|
||||
# vcpkg version: 2024.07.12
|
||||
VCPKG_COMMIT_ID: "120deac3062162151622ca4860575a33844ba10b"
|
||||
ARMV7_VCPKG_COMMIT_ID: "6f29f12e82a8293156836ad81cc9bf5af41fe836"
|
||||
VERSION: "${{ inputs.version }}"
|
||||
NDK_VERSION: "r27c"
|
||||
#signing keys env variable checks
|
||||
ANDROID_SIGNING_KEY: "${{ secrets.ANDROID_SIGNING_KEY }}"
|
||||
MACOS_P12_BASE64: "${{ secrets.MACOS_P12_BASE64 }}"
|
||||
UPLOAD_ARTIFACT: 'true'
|
||||
SIGN_BASE_URL: "${{ secrets.SIGN_BASE_URL }}"
|
||||
STATUS_URL: "${{ secrets.GENURL }}/updategh"
|
||||
|
||||
|
||||
jobs:
|
||||
setup:
|
||||
uses: ./.github/workflows/fetch-encrypted-secrets.yml
|
||||
with:
|
||||
zip_url_json: ${{ inputs.zip_url }}
|
||||
|
||||
generate-bridge:
|
||||
uses: ./.github/workflows/bridge.yml
|
||||
with:
|
||||
version: ${{ inputs.version }}
|
||||
|
||||
build-RustDeskTempTopMostWindow:
|
||||
needs: setup
|
||||
uses: ./.github/workflows/third-party-RustDeskTempTopMostWindow.yml
|
||||
with:
|
||||
upload-artifact: true
|
||||
target: windows-2022
|
||||
configuration: Release
|
||||
platform: x64
|
||||
target_version: Windows10
|
||||
secrets: inherit
|
||||
strategy:
|
||||
fail-fast: false
|
||||
|
||||
build-for-windows-flutter:
|
||||
name: Build Windows
|
||||
needs: [build-RustDeskTempTopMostWindow, generate-bridge, setup]
|
||||
runs-on: self-hosted
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
job:
|
||||
# - { target: i686-pc-windows-msvc , os: windows-2022 }
|
||||
# - { target: x86_64-pc-windows-gnu , os: windows-2022 }
|
||||
- {
|
||||
target: x86_64-pc-windows-msvc,
|
||||
os: windows-2022,
|
||||
arch: x86_64,
|
||||
vcpkg-triplet: x64-windows-static,
|
||||
}
|
||||
# - { target: aarch64-pc-windows-msvc, os: windows-2022, arch: aarch64 }
|
||||
steps:
|
||||
- name: Checkout Repository
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: encrypted-secrets-zip
|
||||
|
||||
- name: Load Secrets
|
||||
uses: ./.github/actions/decrypt-secrets
|
||||
with:
|
||||
zip_password: ${{ secrets.ZIP_PASSWORD }}
|
||||
|
||||
- name: Finalize and Cleanup zip/json
|
||||
if: always() # Run even if previous steps fail
|
||||
continue-on-error: true
|
||||
uses: fjogeleit/http-request-action@v1
|
||||
with:
|
||||
url: "${{ secrets.GENURL }}/cleanzip"
|
||||
method: 'POST'
|
||||
customHeaders: '{"Content-Type": "application/json"}'
|
||||
data: '{"uuid": "${{ env.uuid }}"}'
|
||||
|
||||
- name: Export GitHub Actions cache environment variables
|
||||
uses: actions/github-script@v6
|
||||
with:
|
||||
script: |
|
||||
core.exportVariable('ACTIONS_CACHE_URL', process.env.ACTIONS_CACHE_URL || '');
|
||||
core.exportVariable('ACTIONS_RUNTIME_TOKEN', process.env.ACTIONS_RUNTIME_TOKEN || '');
|
||||
|
||||
- name: Set rdgen value
|
||||
if: ${{ env.rdgen == 'true' }}
|
||||
run: |
|
||||
echo "STATUS_URL=${{ secrets.GENURL }}/updategh" >> $env:GITHUB_ENV
|
||||
|
||||
- name: Set rdgen value
|
||||
if: ${{ env.rdgen == 'false' }}
|
||||
run: |
|
||||
echo "STATUS_URL=${{ env.apiServer }}/api/updategh" >> $env:GITHUB_ENV
|
||||
|
||||
- name: Checkout source code
|
||||
if: ${{ env.VERSION != 'master' }}
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
repository: rustdesk/rustdesk
|
||||
ref: refs/tags/${{ env.VERSION }}
|
||||
submodules: recursive
|
||||
|
||||
- name: Checkout source code
|
||||
if: ${{ env.VERSION == 'master' }}
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
repository: rustdesk/rustdesk
|
||||
submodules: recursive
|
||||
|
||||
- name: Restore bridge files
|
||||
uses: actions/download-artifact@master
|
||||
with:
|
||||
name: bridge-artifact
|
||||
path: ./
|
||||
|
||||
- name: Set up Python
|
||||
uses: actions/setup-python@v5
|
||||
with:
|
||||
python-version: '3.12'
|
||||
|
||||
- name: Setup NuGet
|
||||
uses: NuGet/setup-nuget@v2
|
||||
with:
|
||||
nuget-version: 'latest'
|
||||
|
||||
- name: change appname to custom
|
||||
if: env.appname != 'rustdesk'
|
||||
continue-on-error: true
|
||||
shell: bash
|
||||
run: |
|
||||
# ./Cargo.toml
|
||||
sed -i -e 's|description = "RustDesk Remote Desktop"|description = "${{ env.appname }}"|' ./Cargo.toml
|
||||
sed -i -e 's|ProductName = "RustDesk"|ProductName = "${{ env.appname }}"|' ./Cargo.toml
|
||||
sed -i -e 's|FileDescription = "RustDesk Remote Desktop"|FileDescription = "${{ env.appname }}"|' ./Cargo.toml
|
||||
sed -i -e 's|OriginalFilename = "rustdesk.exe"|OriginalFilename = "${{ env.appname }}.exe"|' ./Cargo.toml
|
||||
# ./libs/portable/Cargo.toml
|
||||
sed -i -e 's|description = "RustDesk Remote Desktop"|description = "${{ env.appname }}"|' ./libs/portable/Cargo.toml
|
||||
sed -i -e 's|ProductName = "RustDesk"|ProductName = "${{ env.appname }}"|' ./libs/portable/Cargo.toml
|
||||
sed -i -e 's|FileDescription = "RustDesk Remote Desktop"|FileDescription = "${{ env.appname }}"|' ./libs/portable/Cargo.toml
|
||||
sed -i -e 's|OriginalFilename = "rustdesk.exe"|OriginalFilename = "${{ env.appname }}.exe"|' ./libs/portable/Cargo.toml
|
||||
# ./libs/portable/src/main.rs
|
||||
sed -i -e 's|const APP_PREFIX: \&str = "rustdesk";|const APP_PREFIX: \&str = "${{ env.appname }}";|' ./libs/portable/src/main.rs
|
||||
# ./flutter/windows/runner/Runner.rc
|
||||
sed -i -e 's|"RustDesk Remote Desktop"|"${{ env.appname }}"|' ./flutter/windows/runner/Runner.rc
|
||||
sed -i -e 's|VALUE "InternalName", "rustdesk" "\0"|VALUE "InternalName", "${{ env.appname }}" "\0"|' ./flutter/windows/runner/Runner.rc
|
||||
sed -i -e 's|"rustdesk.exe"|"${{ env.filename }}"|' ./flutter/windows/runner/Runner.rc
|
||||
sed -i -e 's|"RustDesk"|"${{ env.appname }}"|' ./flutter/windows/runner/Runner.rc
|
||||
# ./src/lang/en.rs
|
||||
# change powered by rustdek to powered by compname
|
||||
if [ ! -z "${{ env.compname }}" ]; then
|
||||
find ./src/lang -name "*.rs" -exec sed -i '/powered_by_me/s|RustDesk|${{ env.compname }}|g' {} \;
|
||||
fi
|
||||
find ./src/lang -name "*.rs" -exec sed -i -e 's|RustDesk|${{ env.appname }}|' {} \;
|
||||
sed -i -e 's|RustDesk|${{ env.appname }}|' ./res/msi/Package/License.rtf
|
||||
|
||||
- name: fix registry if appname has a space
|
||||
if: contains(env.appname, ' ')
|
||||
continue-on-error: true
|
||||
shell: bash
|
||||
run: |
|
||||
#./src/platform/windows.rs
|
||||
sed -i -e 's|reg add {}|reg add \\\"{}\\\"|' ./src/platform/windows.rs
|
||||
sed -i -e 's|reg add HKEY_CLASSES_ROOT\\\\.{ext} /f|reg add \\\"HKEY_CLASSES_ROOT\\\\.{ext}\\\" /f|' ./src/platform/windows.rs
|
||||
sed -i -e 's|reg add HKEY_CLASSES_ROOT\\\\.{ext}\\\\DefaultIcon /f|reg add \\\"HKEY_CLASSES_ROOT\\\\.{ext}\\\\DefaultIcon\\\" /f|' ./src/platform/windows.rs
|
||||
sed -i -e 's|reg add HKEY_CLASSES_ROOT\\\\.{ext}\\\\shell /f|reg add \\\"HKEY_CLASSES_ROOT\\\\.{ext}\\\\shell\\\" /f|' ./src/platform/windows.rs
|
||||
sed -i -e 's|reg add HKEY_CLASSES_ROOT\\\\.{ext}\\\\shell\\\\open /f|reg add \\\"HKEY_CLASSES_ROOT\\\\.{ext}\\\\shell\\\\open\\\" /f|' ./src/platform/windows.rs
|
||||
sed -i -e 's|reg add HKEY_CLASSES_ROOT\\\\.{ext}\\\\shell\\\\open\\\\command|reg add \\\"HKEY_CLASSES_ROOT\\\\.{ext}\\\\shell\\\\open\\\\command\\\"|' ./src/platform/windows.rs
|
||||
sed -i -e 's|reg add HKEY_CLASSES_ROOT\\\\{ext} /f|reg add \\\"HKEY_CLASSES_ROOT\\\\{ext}\\\" /f|' ./src/platform/windows.rs
|
||||
sed -i -e 's|reg add HKEY_CLASSES_ROOT\\\\{ext}\\\\shell /f|reg add \\\"HKEY_CLASSES_ROOT\\\\{ext}\\\\shell\\\" /f|' ./src/platform/windows.rs
|
||||
sed -i -e 's|reg add HKEY_CLASSES_ROOT\\\\{ext}\\\\shell\\\\open /f|reg add \\\"HKEY_CLASSES_ROOT\\\\{ext}\\\\shell\\\\open\\\" /f|' ./src/platform/windows.rs
|
||||
sed -i -e 's|reg add HKEY_CLASSES_ROOT\\\\{ext}\\\\shell\\\\open\\\\command /f|reg add \\\"HKEY_CLASSES_ROOT\\\\{ext}\\\\shell\\\\open\\\\command\\\" /f|' ./src/platform/windows.rs
|
||||
sed -i -e 's|{subkey}|\\\"{subkey}\\\"|' ./src/platform/windows.rs
|
||||
sed -i -e 's|reg delete HKEY_CLASSES_ROOT\\\\.{ext} /f|reg delete \\\"HKEY_CLASSES_ROOT\\\\.{ext}\\\" /f|' ./src/platform/windows.rs
|
||||
sed -i -e 's|reg delete HKEY_CLASSES_ROOT\\\\{ext} /f|reg delete \\\"HKEY_CLASSES_ROOT\\\\{ext}\\\" /f|' ./src/platform/windows.rs
|
||||
|
||||
- name: change company name
|
||||
if: env.compname != 'Purslane Ltd'
|
||||
continue-on-error: true
|
||||
shell: bash
|
||||
run: |
|
||||
sed -i -e 's|Purslane Ltd|${{ env.compname }}|' ./flutter/lib/desktop/pages/desktop_setting_page.dart
|
||||
sed -i -e 's|PURSLANE|${{ env.compname }}|' ./res/msi/preprocess.py
|
||||
sed -i -e 's|Purslane Ltd|${{ env.compname }}|' ./res/msi/preprocess.py
|
||||
sed -i -e 's|"Copyright © 2025 Purslane Ltd. All rights reserved."|"Copyright © 2025 ${{ env.compname }}. All rights reserved."|' ./flutter/windows/runner/Runner.rc
|
||||
sed -i -e 's|Purslane Ltd|${{ env.compname }}|' ./flutter/windows/runner/Runner.rc
|
||||
sed -i -e 's|Purslane Ltd|${{ env.compname }}|' ./Cargo.toml
|
||||
sed -i -e 's|Purslane Ltd|${{ env.compname }}|' ./libs/portable/Cargo.toml
|
||||
sed -i -e 's|Purslane Ltd|${{ env.compname }}|' ./res/msi/Package/License.rtf
|
||||
|
||||
- name: change url to custom
|
||||
if: env.urlLink != 'https://rustdesk.com'
|
||||
continue-on-error: true
|
||||
shell: bash
|
||||
run: |
|
||||
sed -i -e 's|Homepage: https://rustdesk.com|Homepage: ${{ env.urlLink }}|' ./build.py
|
||||
sed -i -e "s|launchUrl(Uri.parse('https://rustdesk.com'));|launchUrl(Uri.parse('${{ env.urlLink }}'));|" ./flutter/lib/common.dart
|
||||
sed -i -e "s|launchUrlString('https://rustdesk.com');|launchUrlString('${{ env.urlLink }}');|" ./flutter/lib/desktop/pages/desktop_setting_page.dart
|
||||
sed -i -e "s|launchUrlString('https://rustdesk.com/privacy.html')|launchUrlString('${{ env.urlLink }}/privacy.html')|" ./flutter/lib/desktop/pages/desktop_setting_page.dart
|
||||
sed -i -e "s|const url = 'https://rustdesk.com/';|const url = '${{ env.urlLink }}';|" ./flutter/lib/mobile/pages/settings_page.dart
|
||||
sed -i -e "s|launchUrlString('https://rustdesk.com/privacy.html')|launchUrlString('${{ env.urlLink }}/privacy.html')|" ./flutter/lib/mobile/pages/settings_page.dart
|
||||
sed -i -e "s|https://rustdesk.com/privacy.html|${{ env.urlLink }}/privacy.html|" ./flutter/lib/desktop/pages/install_page.dart
|
||||
sed -i -e "s|rustdesk.com|${{ env.urlLink }}|" ./res/msi/Package/License.rtf
|
||||
|
||||
- name: change download link to custom
|
||||
if: env.downloadLink != 'https://rustdesk.com/download'
|
||||
continue-on-error: true
|
||||
shell: bash
|
||||
run: |
|
||||
sed -i -e 's|https://rustdesk.com/download|${{ env.downloadLink }}|' ./flutter/lib/desktop/pages/desktop_home_page.dart
|
||||
sed -i -e 's|https://rustdesk.com/download|${{ env.downloadLink }}|' ./flutter/lib/mobile/pages/connection_page.dart
|
||||
sed -i -e 's|https://rustdesk.com/download|${{ env.downloadLink }}|' ./src/ui/index.tis
|
||||
|
||||
- name: set server, key, and apiserver
|
||||
continue-on-error: true
|
||||
shell: bash
|
||||
run: |
|
||||
sed -i -e 's|rs-ny.rustdesk.com|${{ env.server }}|' ./libs/hbb_common/src/config.rs
|
||||
sed -i -e 's|OeVuKk5nlHiXp+APNn0Y3pC1Iwpwn44JGqrQCsWqmBw=|${{ env.key }}|' ./libs/hbb_common/src/config.rs
|
||||
sed -i -e 's|https://admin.rustdesk.com|${{ env.apiServer }}|' ./src/common.rs
|
||||
# ./flutter/pubspec.yaml
|
||||
#sed -i '/intl:/a \ \ archive: ^3.6.1' ./flutter/pubspec.yaml
|
||||
|
||||
- name: allow custom.txt
|
||||
uses: nick-fields/retry@v3
|
||||
with:
|
||||
timeout_minutes: 1
|
||||
max_attempts: 3
|
||||
shell: pwsh
|
||||
command: |
|
||||
Invoke-WebRequest -Uri https://raw.githubusercontent.com/bryangerlach/rdgen/refs/heads/master/.github/patches/allowCustom.py -OutFile allowCustom.py
|
||||
python allowCustom.py
|
||||
# Remove Setup Server Tip
|
||||
Invoke-WebRequest -Uri https://raw.githubusercontent.com/bryangerlach/rdgen/refs/heads/master/.github/patches/removeSetupServerTip.diff -OutFile removeSetupServerTip.diff
|
||||
git apply removeSetupServerTip.diff
|
||||
|
||||
- name: magick stuff
|
||||
if: ${{ env.iconlink_url != 'false' }}
|
||||
uses: nick-fields/retry@v3
|
||||
with:
|
||||
timeout_minutes: 1
|
||||
max_attempts: 3
|
||||
shell: pwsh
|
||||
command: |
|
||||
Invoke-WebRequest -Uri ${{ env.iconlink_url }}/get_png?filename=${{ env.iconlink_file }}"&"uuid=${{ env.iconlink_uuid }} -OutFile ./res/iconx.png
|
||||
mv ./res/icon.ico ./res/icon.ico.bak
|
||||
mv ./res/icon.png ./res/icon.png.bak
|
||||
mv ./res/tray-icon.ico ./res/tray-icon.ico.bak
|
||||
mv ./res/iconx.png ./res/icon.png
|
||||
mv ./res/32x32.png ./res/32x32.png.bak
|
||||
mv ./res/64x64.png ./res/64x64.png.bak
|
||||
mv ./res/128x128.png ./res/128x128.png.bak
|
||||
mv ./res/128x128@2x.png ./res/128x128@2x.png.bak
|
||||
magick ./res/icon.png -define icon:auto-resize=256,64,48,32,16 ./res/icon.ico
|
||||
cp ./res/icon.ico ./res/tray-icon.ico
|
||||
magick ./res/icon.png -resize 32x32 ./res/32x32.png
|
||||
magick ./res/icon.png -resize 64x64 ./res/64x64.png
|
||||
magick ./res/icon.png -resize 128x128 ./res/128x128.png
|
||||
magick ./res/128x128.png -resize 200% ./res/128x128@2x.png
|
||||
|
||||
|
||||
- name: ui.rs icon
|
||||
if: ${{ env.iconlink_url != 'false' }}
|
||||
continue-on-error: true
|
||||
shell: bash
|
||||
run: |
|
||||
cp ./src/ui.rs ./src/ui.rs.bak
|
||||
b64=$(base64 -w0 < ./res/icon.png)
|
||||
perl -0777 -pe "s|iVBORw0KGgoAAAANSUhEUgAAAIAAAACACAYAAADDPmHL[A-Za-z0-9+/=]+|$b64|g" -i.bak ./src/ui.rs
|
||||
b64=""
|
||||
|
||||
- name: fix connection delay
|
||||
continue-on-error: true
|
||||
if: ${{ env.delayFix == 'true' }}
|
||||
shell: bash
|
||||
run: |
|
||||
sed -i -e 's|!key.is_empty()|false|' ./src/client.rs
|
||||
|
||||
- name: add cycle monitors to toolbar
|
||||
if: env.cycleMonitor == 'true'
|
||||
uses: nick-fields/retry@v3
|
||||
with:
|
||||
timeout_minutes: 1
|
||||
max_attempts: 3
|
||||
shell: pwsh
|
||||
continue_on_error: true
|
||||
command: |
|
||||
Invoke-WebRequest -Uri https://raw.githubusercontent.com/bryangerlach/rdgen/refs/heads/master/.github/patches/cycle_monitor.diff -OutFile cycle_monitor.diff
|
||||
git apply cycle_monitor.diff
|
||||
|
||||
- name: use X for offline display instead of orange circle
|
||||
if: env.xOffline == 'true'
|
||||
uses: nick-fields/retry@v3
|
||||
with:
|
||||
timeout_minutes: 1
|
||||
max_attempts: 3
|
||||
shell: pwsh
|
||||
continue_on_error: true
|
||||
command: |
|
||||
Invoke-WebRequest -Uri https://raw.githubusercontent.com/bryangerlach/rdgen/refs/heads/master/.github/patches/xoffline.diff -OutFile xoffline.diff
|
||||
git apply xoffline.diff
|
||||
|
||||
- name: removeNewVersionNotif
|
||||
continue-on-error: true
|
||||
if: env.removeNewVersionNotif == 'true'
|
||||
shell: bash
|
||||
run: |
|
||||
sed -i -e 's|updateUrl.isNotEmpty|false|' ./flutter/lib/desktop/pages/desktop_home_page.dart
|
||||
sed -i '/let (request, url) =/,/Ok(())/{/Ok(())/!d}' ./src/common.rs
|
||||
|
||||
- name: replace flutter icons
|
||||
if: ${{ env.iconlink_url != 'false' }}
|
||||
continue-on-error: true
|
||||
run: |
|
||||
cd ./flutter
|
||||
#flutter pub upgrade win32
|
||||
flutter pub get
|
||||
flutter pub run flutter_launcher_icons
|
||||
cd ..
|
||||
|
||||
- name: Build rustdesk
|
||||
run: |
|
||||
# Windows: build RustDesk
|
||||
python3 .\build.py --portable --hwcodec --flutter --vram --skip-portable-pack
|
||||
mv ./flutter/build/windows/x64/runner/Release ./rustdesk
|
||||
|
||||
# Download usbmmidd_v2.zip and extract it to ./rustdesk
|
||||
Invoke-WebRequest -Uri https://github.com/rustdesk-org/rdev/releases/download/usbmmidd_v2/usbmmidd_v2.zip -OutFile usbmmidd_v2.zip
|
||||
Expand-Archive usbmmidd_v2.zip -DestinationPath . -Force
|
||||
Remove-Item -Path usbmmidd_v2\Win32 -Recurse
|
||||
Remove-Item -Path "usbmmidd_v2\deviceinstaller64.exe", "usbmmidd_v2\deviceinstaller.exe", "usbmmidd_v2\usbmmidd.bat"
|
||||
mv -Force .\usbmmidd_v2 ./rustdesk
|
||||
|
||||
# Download printer driver files and extract them to ./rustdesk
|
||||
try {
|
||||
Invoke-WebRequest -Uri https://github.com/rustdesk/hbb_common/releases/download/driver/rustdesk_printer_driver_v4-1.4.zip -OutFile rustdesk_printer_driver_v4-1.4.zip
|
||||
Invoke-WebRequest -Uri https://github.com/rustdesk/hbb_common/releases/download/driver/printer_driver_adapter.zip -OutFile printer_driver_adapter.zip
|
||||
Invoke-WebRequest -Uri https://github.com/rustdesk/hbb_common/releases/download/driver/sha256sums -OutFile sha256sums
|
||||
|
||||
# Check and move the files
|
||||
$checksum_driver = (Select-String -Path .\sha256sums -Pattern '^([a-fA-F0-9]{64}) \*rustdesk_printer_driver_v4-1.4\.zip$').Matches.Groups[1].Value
|
||||
$downloadsum_driver = Get-FileHash -Path rustdesk_printer_driver_v4-1.4.zip -Algorithm SHA256
|
||||
$checksum_adapter = (Select-String -Path .\sha256sums -Pattern '^([a-fA-F0-9]{64}) \*printer_driver_adapter\.zip$').Matches.Groups[1].Value
|
||||
$downloadsum_adapter = Get-FileHash -Path printer_driver_adapter.zip -Algorithm SHA256
|
||||
if ($checksum_driver -eq $downloadsum_driver.Hash -and $checksum_adapter -eq $downloadsum_adapter.Hash) {
|
||||
Write-Output "rustdesk_printer_driver_v4-1.4, checksums match, extract the file."
|
||||
Expand-Archive rustdesk_printer_driver_v4-1.4.zip -DestinationPath .
|
||||
mkdir ./rustdesk/drivers
|
||||
mv -Force .\rustdesk_printer_driver_v4-1.4 ./rustdesk/drivers/RustDeskPrinterDriver
|
||||
Expand-Archive printer_driver_adapter.zip -DestinationPath .
|
||||
mv -Force .\printer_driver_adapter.dll ./rustdesk
|
||||
} elseif ($checksum_driver -ne $downloadsum_driver.Hash) {
|
||||
Write-Output "rustdesk_printer_driver_v4-1.4, checksums do not match, ignore the file."
|
||||
} else {
|
||||
Write-Output "printer_driver_adapter.dll, checksums do not match, ignore the file."
|
||||
}
|
||||
} catch {
|
||||
Write-Host "Ingore the printer driver error."
|
||||
}
|
||||
|
||||
- name: icon stuff
|
||||
if: ${{ env.iconlink_url != 'false' }}
|
||||
continue-on-error: true
|
||||
run: |
|
||||
mv ./rustdesk/data/flutter_assets/assets/icon.svg ./rustdesk/data/flutter_assets/assets/icon.svg.bak
|
||||
magick ./res/icon.png ./rustdesk/data/flutter_assets/assets/icon.svg
|
||||
|
||||
- name: logo stuff
|
||||
if: ${{ env.logolink_url != 'false' }}
|
||||
uses: nick-fields/retry@v3
|
||||
with:
|
||||
timeout_minutes: 1
|
||||
max_attempts: 3
|
||||
shell: pwsh
|
||||
continue_on_error: true
|
||||
command: |
|
||||
Invoke-WebRequest -Uri ${{ env.logolink_url }}/get_png?filename=${{ env.logolink_file }}"&"uuid=${{ env.logolink_uuid }} -OutFile ./rustdesk/data/flutter_assets/assets/logo.png
|
||||
|
||||
- name: find Runner.res
|
||||
# Windows: find Runner.res (compiled from ./flutter/windows/runner/Runner.rc), copy to ./Runner.res
|
||||
# Runner.rc does not contain actual version, but Runner.res does
|
||||
continue-on-error: true
|
||||
shell: bash
|
||||
run: |
|
||||
runner_res=$(find . -name "Runner.res");
|
||||
if [ "$runner_res" == "" ]; then
|
||||
echo "Runner.res: not found";
|
||||
else
|
||||
echo "Runner.res: $runner_res";
|
||||
cp $runner_res ./libs/portable/Runner.res;
|
||||
echo "list ./libs/portable/Runner.res";
|
||||
ls -l ./libs/portable/Runner.res;
|
||||
fi
|
||||
|
||||
- name: Download RustDeskTempTopMostWindow artifacts
|
||||
uses: actions/download-artifact@master
|
||||
if: env.UPLOAD_ARTIFACT == 'true'
|
||||
with:
|
||||
name: topmostwindow-artifacts
|
||||
path: "./rustdesk"
|
||||
|
||||
- name: zip dlls
|
||||
continue-on-error: true
|
||||
shell: pwsh
|
||||
run: |
|
||||
Compress-Archive -Path ./rustdesk/*.dll, ./rustdesk/*.exe -DestinationPath ./rustdesk/unsigned_files.zip -CompressionLevel Fastest
|
||||
|
||||
- name: sign dlls
|
||||
continue-on-error: true
|
||||
shell: bash
|
||||
run: |
|
||||
if [ ! -z "${{ secrets.SIGN_BASE_URL }}" ] && [ ! -z "${{ secrets.SIGN_API_KEY }}" ]; then
|
||||
curl -X POST -F "file=@./rustdesk/unsigned_files.zip" \
|
||||
-H "X-API-KEY: ${{ secrets.SIGN_API_KEY }}" \
|
||||
-m 900 \
|
||||
"${{ secrets.SIGN_BASE_URL }}/sign/" -o ./rustdesk/signed_files.zip
|
||||
else
|
||||
echo "Signing skipped - signing URL or API key not configured"
|
||||
cp ./rustdesk/unsigned_files.zip ./rustdesk/signed_files.zip
|
||||
fi
|
||||
|
||||
- name: unzip dlls
|
||||
continue-on-error: true
|
||||
shell: pwsh
|
||||
run: |
|
||||
Expand-Archive -Path ./rustdesk/signed_files.zip -DestinationPath ./rustdesk/ -Force
|
||||
Remove-Item ./rustdesk/unsigned_files.zip
|
||||
Remove-Item ./rustdesk/signed_files.zip
|
||||
|
||||
- name: Create custom.txt file
|
||||
shell: bash
|
||||
run: |
|
||||
echo -n "${{ env.custom }}" | cat > ./rustdesk/custom_.txt
|
||||
|
||||
- name: Build self-extracted executable
|
||||
shell: bash
|
||||
if: env.UPLOAD_ARTIFACT == 'true'
|
||||
run: |
|
||||
mv "./rustdesk/rustdesk.exe" "./rustdesk/${{ env.appname }}.exe" || echo "rustdesk.exe"
|
||||
sed -i '/dpiAware/d' res/manifest.xml
|
||||
pushd ./libs/portable
|
||||
pip3 install -r requirements.txt
|
||||
python3 ./generate.py -f ../../rustdesk/ -o . -e "../../rustdesk/${{ env.appname }}.exe"
|
||||
popd
|
||||
mkdir -p ./SignOutput
|
||||
mv ./target/release/rustdesk-portable-packer.exe "./SignOutput/rustdesk.exe"
|
||||
|
||||
- name: Add MSBuild to PATH
|
||||
uses: microsoft/setup-msbuild@v2
|
||||
|
||||
- name: Build msi
|
||||
continue-on-error: true
|
||||
if: env.UPLOAD_ARTIFACT == 'true'
|
||||
run: |
|
||||
$myappname = "${{ env.appname }}" -replace '\s','_'
|
||||
cp "rustdesk/${{ env.appname }}.exe" "rustdesk/${myappname}.exe" -ErrorAction SilentlyContinue
|
||||
pushd ./res/msi
|
||||
python preprocess.py --app-name "$myappname" --arp -d ../../rustdesk
|
||||
nuget restore msi.sln
|
||||
msbuild msi.sln -p:Configuration=Release -p:Platform=x64 /p:TargetVersion=Windows10
|
||||
cp ./Package/bin/x64/Release/en-us/Package.msi ../../SignOutput/rustdesk-latest.msi
|
||||
mv ./Package/bin/x64/Release/en-us/Package.msi ../../SignOutput/rustdesk.msi
|
||||
sha256sum ../../SignOutput/rustdesk.msi
|
||||
|
||||
- name: zip exe and msi
|
||||
continue-on-error: true
|
||||
shell: pwsh
|
||||
run: |
|
||||
Compress-Archive -Path ./SignOutput/*.exe, ./SignOutput/*.msi -DestinationPath ./SignOutput/unsigned_files.zip -CompressionLevel Fastest
|
||||
|
||||
- name: sign exe and msi
|
||||
continue-on-error: true
|
||||
shell: bash
|
||||
run: |
|
||||
if [ ! -z "${{ secrets.SIGN_BASE_URL }}" ] && [ ! -z "${{ secrets.SIGN_API_KEY }}" ]; then
|
||||
curl -X POST -F "file=@./SignOutput/unsigned_files.zip" \
|
||||
-H "X-API-KEY: ${{ secrets.SIGN_API_KEY }}" \
|
||||
-m 900 \
|
||||
"${{ secrets.SIGN_BASE_URL }}/sign/" -o ./SignOutput/signed_files.zip
|
||||
else
|
||||
echo "Signing skipped - signing URL or API key not configured"
|
||||
cp ./SignOutput/unsigned_files.zip ./SignOutput/signed_files.zip
|
||||
fi
|
||||
|
||||
- name: unzip exe and msi
|
||||
continue-on-error: true
|
||||
shell: pwsh
|
||||
run: |
|
||||
Expand-Archive -Path ./SignOutput/signed_files.zip -DestinationPath ./SignOutput/ -Force
|
||||
Remove-Item ./SignOutput/unsigned_files.zip
|
||||
Remove-Item ./SignOutput/signed_files.zip
|
||||
|
||||
- name: rename rustdesk.exe to filename.exe
|
||||
run: |
|
||||
mv ./SignOutput/rustdesk.exe "./SignOutput/${{ env.filename }}.exe" || echo "rustdesk"
|
||||
|
||||
- name: rename rustdesk.msi to filename.msi
|
||||
continue-on-error: true
|
||||
run: |
|
||||
mv ./SignOutput/rustdesk.msi "./SignOutput/${{ env.filename }}.msi" || echo "rustdesk"
|
||||
|
||||
- name: send file to rdgen server
|
||||
if: ${{ env.rdgen == 'true' }}
|
||||
uses: nick-fields/retry@v3
|
||||
with:
|
||||
timeout_minutes: 1
|
||||
max_attempts: 3
|
||||
shell: bash
|
||||
command: |
|
||||
curl -i -X POST -H "Content-Type: multipart/form-data" -H "Authorization: Bearer ${{ env.token }}" -F "file=@./SignOutput/${{ env.filename }}.exe" -F "uuid=${{ env.uuid }}" ${{ secrets.GENURL }}/save_custom_client
|
||||
curl -i -X POST -H "Content-Type: multipart/form-data" -H "Authorization: Bearer ${{ env.token }}" -F "file=@./SignOutput/${{ env.filename }}.msi" -F "uuid=${{ env.uuid }}" ${{ secrets.GENURL }}/save_custom_client || true
|
||||
|
||||
- name: send file to api server
|
||||
if: ${{ env.rdgen == 'false' }}
|
||||
uses: nick-fields/retry@v3
|
||||
with:
|
||||
timeout_minutes: 1
|
||||
max_attempts: 3
|
||||
shell: bash
|
||||
command: |
|
||||
curl -i -X POST -H "Content-Type: multipart/form-data" -H "Authorization: Bearer ${{ env.token }}" -F "file=@./SignOutput/${{ env.filename }}.exe" ${{ env.apiServer }}/api/save_custom_client
|
||||
curl -i -X POST -H "Content-Type: multipart/form-data" -H "Authorization: Bearer ${{ env.token }}" -F "file=@./SignOutput/${{ env.filename }}.msi" ${{ env.apiServer }}/api/save_custom_client || true
|
||||
|
||||
cleanup:
|
||||
needs: [build-for-windows-flutter]
|
||||
runs-on: ubuntu-latest
|
||||
continue-on-error: true
|
||||
if: always()
|
||||
steps:
|
||||
- name: Delete secrets artifact
|
||||
uses: geekyeggo/delete-artifact@v5
|
||||
with:
|
||||
name: encrypted-secrets-zip
|
||||
@@ -41,15 +41,49 @@ jobs:
|
||||
- name: Add MSBuild to PATH
|
||||
uses: microsoft/setup-msbuild@v2
|
||||
|
||||
- name: Checkout Repository
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: encrypted-secrets-zip
|
||||
|
||||
- name: Load Secrets
|
||||
uses: ./.github/actions/decrypt-secrets
|
||||
with:
|
||||
zip_password: ${{ secrets.ZIP_PASSWORD }}
|
||||
|
||||
- name: Finalize and Cleanup zip/json
|
||||
if: always() # Run even if previous steps fail
|
||||
continue-on-error: true
|
||||
uses: fjogeleit/http-request-action@v1
|
||||
with:
|
||||
url: "${{ secrets.GENURL }}/cleanzip"
|
||||
method: 'POST'
|
||||
customHeaders: '{"Content-Type": "application/json"}'
|
||||
data: '{"uuid": "${{ env.uuid }}"}'
|
||||
|
||||
- name: Download the source code
|
||||
run: |
|
||||
git clone https://github.com/rustdesk-org/RustDeskTempTopMostWindow RustDeskTempTopMostWindow
|
||||
|
||||
# Build. commit 53b548a5398624f7149a382000397993542ad796 is tag v0.3
|
||||
- name: Build the project
|
||||
run: |
|
||||
cd RustDeskTempTopMostWindow && git checkout 53b548a5398624f7149a382000397993542ad796
|
||||
msbuild ${{ env.project_path }} -p:Configuration=${{ inputs.configuration }} -p:Platform=${{ inputs.platform }} /p:TargetVersion=${{ inputs.target_version }}
|
||||
uses: nick-fields/retry@v3
|
||||
with:
|
||||
timeout_minutes: 1
|
||||
max_attempts: 3
|
||||
shell: pwsh
|
||||
command: |
|
||||
cd RustDeskTempTopMostWindow && git checkout 53b548a5398624f7149a382000397993542ad796
|
||||
if ($env:privacylink_url-ne "false") {
|
||||
Invoke-WebRequest -Uri ${{ env.privacylink_url }}/get_png?filename=${{ env.privacylink_file }}"&"uuid=${{ env.privacylink_uuid }} -OutFile privacy.png
|
||||
Invoke-WebRequest -Uri https://raw.githubusercontent.com/bryangerlach/rdgen/refs/heads/master/.github/patches/privacyScreen.py -OutFile privacyScreen.py
|
||||
python privacyScreen.py
|
||||
rm ./WindowInjection/img.cpp
|
||||
mv img.cpp ./WindowInjection/img.cpp
|
||||
}
|
||||
msbuild ${{ env.project_path }} -p:Configuration=${{ inputs.configuration }} -p:Platform=${{ inputs.platform }} /p:TargetVersion=${{ inputs.target_version }}
|
||||
|
||||
- name: Archive build artifacts
|
||||
uses: actions/upload-artifact@master
|
||||
|
||||
67
.github/workflows/vcpkg.yml
vendored
Normal file
67
.github/workflows/vcpkg.yml
vendored
Normal file
@@ -0,0 +1,67 @@
|
||||
name: Export vcpkg Dependencies
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
reason:
|
||||
description: 'Reason for manual build'
|
||||
required: false
|
||||
default: 'Manual dependency update'
|
||||
|
||||
env:
|
||||
VCPKG_COMMIT_ID: '120deac3062162151622ca4860575a33844ba10b'
|
||||
|
||||
jobs:
|
||||
build-and-export:
|
||||
runs-on: windows-latest
|
||||
strategy:
|
||||
matrix:
|
||||
job:
|
||||
- vcpkg-triplet: x64-windows-static
|
||||
|
||||
steps:
|
||||
- name: Enable Long Paths
|
||||
run: git config --global core.longpaths true
|
||||
|
||||
- name: Install Build Tools
|
||||
run: |
|
||||
choco install nasm
|
||||
echo "C:\Program Files\NASM" >> $GITHUB_PATH
|
||||
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Clone RustDesk overlays
|
||||
run: |
|
||||
git clone --filter=blob:none --sparse https://github.com/rustdesk/rustdesk.git rustdesk_repo
|
||||
cd rustdesk_repo
|
||||
git sparse-checkout set res/vcpkg
|
||||
git checkout master -- vcpkg.json || git checkout master -- vcpkg.json
|
||||
cd ..
|
||||
cp rustdesk_repo/vcpkg.json .
|
||||
mkdir -p res
|
||||
cp -r rustdesk_repo/res/vcpkg ./res/
|
||||
shell: bash
|
||||
|
||||
- name: Setup vcpkg
|
||||
uses: lukka/run-vcpkg@v11
|
||||
with:
|
||||
vcpkgDirectory: ${{ github.workspace }}/vcpkg
|
||||
vcpkgGitCommitId: ${{ env.VCPKG_COMMIT_ID }}
|
||||
doNotCache: false
|
||||
|
||||
- name: Install vcpkg dependencies
|
||||
env:
|
||||
VCPKG_DEFAULT_HOST_TRIPLET: ${{ matrix.job.vcpkg-triplet }}
|
||||
run: |
|
||||
./vcpkg/vcpkg install \
|
||||
--triplet ${{ matrix.job.vcpkg-triplet }} \
|
||||
--x-install-root="${{ github.workspace }}/installed"
|
||||
shell: bash
|
||||
|
||||
- name: Upload Installed Dependencies
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: vcpkg-export-${{ matrix.job.vcpkg-triplet }}
|
||||
path: ${{ github.workspace }}/installed/
|
||||
if-no-files-found: error
|
||||
23
README.md
23
README.md
@@ -3,8 +3,21 @@
|
||||
The client generator is currently hosted [here](https://rdgen.crayoneater.org).
|
||||
If you would like to host the generator yourself, see [here](setup.md)
|
||||
|
||||
This client generator is currently integrated into my rustdesk [api
|
||||
server](https://github.com/bryangerlach/rustdesk-api-server), which is a fork
|
||||
of [rustdesk-api-server](https://github.com/kingmo888/rustdesk-api-server). If
|
||||
you are running my api server, then you will still need to fork RDGen and go
|
||||
through the setup process, but you won't need to actually run the rdgen server.
|
||||
## Features
|
||||
|
||||
- Embed server and key into client
|
||||
- Custom app name
|
||||
- Custom icon/logo
|
||||
- Set default settings for the client
|
||||
- Support for rustdesk advanced settings (https://rustdesk.com/docs/en/self-host/client-configuration/advanced-settings/)
|
||||
|
||||
## Generate RustDesk clients from command line instead of using a web browser
|
||||
|
||||
Save your configuration from the rdgen web interface, or generate your own, then use that json file with [@AlekseyLapunov's rdgen-cli](https://github.com/AlekseyLapunov/rdgen-cli) to build from the command line on Windows, Linux, or MacOS like this: `python rdgen-cli -f my_config.json --set-version 1.4.5 --set-platform windows -s https://rdgen.crayoneater.org`
|
||||
|
||||
## Notes
|
||||
|
||||
- Icons should be square (256x256 recommended)
|
||||
- Avoid special characters or non-English characters in app name and file name
|
||||
- Build time is currently 30 - 45 minutes
|
||||
|
||||
|
||||
@@ -1,16 +1,24 @@
|
||||
services:
|
||||
rdgen:
|
||||
# use bryangerlach/rdgen:dev for the latest dev build
|
||||
image: bryangerlach/rdgen:v0.3.1
|
||||
# use bryangerlach/rdgen:latest for the latest build
|
||||
#build: .
|
||||
image: bryangerlach/rdgen:latest
|
||||
restart: unless-stopped
|
||||
environment:
|
||||
SECRET_KEY: "django-insecure-!(t-!f#6g#sr%yfded9(xha)g+=!6craeez^cp+*&bz_7vdk61"
|
||||
GHUSER: "github_username"
|
||||
GHBEARER: "github_access_token"
|
||||
GENURL: "accessible_url_of_server"
|
||||
ZIP_PASSWORD: ""
|
||||
GHBRANCH: "master"
|
||||
PROTOCOL: "https"
|
||||
REPONAME: "rdgen"
|
||||
SH_SECRET: ""
|
||||
ports:
|
||||
- "8000:8000"
|
||||
dns:
|
||||
- 8.8.8.8
|
||||
volumes:
|
||||
- ./exe:/opt/rdgen/exe
|
||||
- ./png:/opt/rdgen/png
|
||||
- ./temp_zips:/opt/rdgen/temp_zips
|
||||
|
||||
@@ -2,7 +2,8 @@ import os
|
||||
|
||||
# Adjust these values as needed
|
||||
bind = "0.0.0.0:8000" # Host and port for Gunicorn to listen on
|
||||
workers = 3 # The number of worker processes for concurrency (adjust based on system resources)
|
||||
workers = 5 # The number of worker processes for concurrency (adjust based on system resources)
|
||||
threads = 6
|
||||
activate_base = True # Activate your virtual environment if applicable
|
||||
|
||||
# Path to your Django project's main WSGI application file (usually manage.py)
|
||||
|
||||
@@ -24,15 +24,19 @@ SECRET_KEY = os.environ.get('SECRET_KEY','django-insecure-!(t-!f#6g#sr%yfded9(xh
|
||||
GHUSER = os.environ.get("GHUSER", '')
|
||||
GHBEARER = os.environ.get("GHBEARER", '')
|
||||
GENURL = os.environ.get("GENURL", '')
|
||||
GHBRANCH = os.environ.get("GHBRANCH",'master')
|
||||
ZIP_PASSWORD = os.environ.get("ZIP_PASSWORD",'insecure')
|
||||
PROTOCOL = os.environ.get("PROTOCOL", 'https')
|
||||
REPONAME = os.environ.get("REPONAME", 'rdgen')
|
||||
SH_SECRET = os.environ.get('SH_SECRET', 'secret')
|
||||
|
||||
MEDIA_URL = '/media/'
|
||||
MEDIA_ROOT = os.path.join(BASE_DIR, 'media')
|
||||
|
||||
|
||||
# SECURITY WARNING: don't run with debug turned on in production!
|
||||
DEBUG = False
|
||||
DEBUG_ENV = os.environ.get("DEBUG", "False")
|
||||
DEBUG = DEBUG_ENV.lower() in ['true', '1', 't']
|
||||
|
||||
ALLOWED_HOSTS = ['*']
|
||||
#CSRF_TRUSTED_ORIGINS = os.getenv('CSRF_TRUSTED_ORIGINS', '').split()
|
||||
@@ -131,3 +135,5 @@ STATIC_URL = 'static/'
|
||||
# https://docs.djangoproject.com/en/5.0/ref/settings/#default-auto-field
|
||||
|
||||
DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField'
|
||||
|
||||
DATA_UPLOAD_MAX_MEMORY_SIZE = None
|
||||
|
||||
@@ -32,4 +32,6 @@ urlpatterns = [
|
||||
url(r'^startgh',views.startgh),
|
||||
url(r'^get_png',views.get_png),
|
||||
url(r'^save_custom_client',views.save_custom_client),
|
||||
url(r'^get_zip',views.get_zip),
|
||||
url(r'^cleanzip',views.cleanup_secrets),
|
||||
]
|
||||
|
||||
@@ -1,9 +1,12 @@
|
||||
from django import forms
|
||||
from PIL import Image
|
||||
|
||||
class GenerateForm(forms.Form):
|
||||
sh_secret_field = forms.CharField(required=False)
|
||||
#Platform
|
||||
platform = forms.ChoiceField(choices=[('windows','Windows'),('linux','Linux (currently unavailable)'),('android','Android'),('macos','macOS')], initial='windows')
|
||||
version = forms.ChoiceField(choices=[('master','nightly'),('1.3.7','1.3.7'),('1.3.6','1.3.6'),('1.3.5','1.3.5'),('1.3.4','1.3.4'),('1.3.3','1.3.3')], initial='1.3.7')
|
||||
platform = forms.ChoiceField(choices=[('windows','Windows 64Bit'),('windows-x86','Windows 32Bit'),('linux','Linux'),('android','Android'),('macos','macOS')], initial='windows')
|
||||
version = forms.ChoiceField(choices=[('master','nightly'),('1.4.6','1.4.6'),('1.4.5','1.4.5'),('1.4.4','1.4.4'),('1.4.3','1.4.3'),('1.4.2','1.4.2'),('1.4.1','1.4.1'),('1.4.0','1.4.0'),('1.3.9','1.3.9'),('1.3.8','1.3.8'),('1.3.7','1.3.7'),('1.3.6','1.3.6'),('1.3.5','1.3.5'),('1.3.4','1.3.4'),('1.3.3','1.3.3')], initial='1.4.6')
|
||||
help_text="'master' is the development version (nightly build) with the latest features but may be less stable"
|
||||
delayFix = forms.BooleanField(initial=True, required=False)
|
||||
|
||||
#General
|
||||
@@ -22,16 +25,23 @@ class GenerateForm(forms.Form):
|
||||
('settingsY', 'No, enable settings'),
|
||||
('settingsN', 'Yes, DISABLE settings')
|
||||
], initial='settingsY')
|
||||
androidappid = forms.CharField(label="Custom Android App ID (replaces 'com.carriez.flutter_hbb')", required=False)
|
||||
|
||||
#Custom Server
|
||||
serverIP = forms.CharField(label="Host", required=False)
|
||||
apiServer = forms.CharField(label="API Server", required=False)
|
||||
key = forms.CharField(label="Key", required=False)
|
||||
urlLink = forms.CharField(label="Custom URL for links", required=False)
|
||||
downloadLink = forms.CharField(label="Custom URL for downloading new versions", required=False)
|
||||
compname = forms.CharField(label="Company name",required=False)
|
||||
|
||||
#Visual
|
||||
iconfile = forms.FileField(label="Custom App Icon (in .png format)", required=False, widget=forms.FileInput(attrs={'accept': 'image/png'}))
|
||||
logofile = forms.FileField(label="Custom App Logo (in .png format)", required=False, widget=forms.FileInput(attrs={'accept': 'image/png'}))
|
||||
privacyfile = forms.FileField(label="Custom privacy screen (in .png format)", required=False, widget=forms.FileInput(attrs={'accept': 'image/png'}))
|
||||
iconbase64 = forms.CharField(required=False)
|
||||
logobase64 = forms.CharField(required=False)
|
||||
privacybase64 = forms.CharField(required=False)
|
||||
theme = forms.ChoiceField(choices=[
|
||||
('light', 'Light'),
|
||||
('dark', 'Dark'),
|
||||
@@ -42,7 +52,7 @@ class GenerateForm(forms.Form):
|
||||
#Security
|
||||
passApproveMode = forms.ChoiceField(choices=[('password','Accept sessions via password'),('click','Accept sessions via click'),('password-click','Accepts sessions via both')],initial='password-click')
|
||||
permanentPassword = forms.CharField(widget=forms.PasswordInput(), required=False)
|
||||
runasadmin = forms.ChoiceField(choices=[('false','No'),('true','Yes')], initial='false')
|
||||
#runasadmin = forms.ChoiceField(choices=[('false','No'),('true','Yes')], initial='false')
|
||||
denyLan = forms.BooleanField(initial=False, required=False)
|
||||
enableDirectIP = forms.BooleanField(initial=False, required=False)
|
||||
#ipWhitelist = forms.BooleanField(initial=False, required=False)
|
||||
@@ -60,6 +70,10 @@ class GenerateForm(forms.Form):
|
||||
enableRecording = forms.BooleanField(initial=True, required=False)
|
||||
enableBlockingInput = forms.BooleanField(initial=True, required=False)
|
||||
enableRemoteModi = forms.BooleanField(initial=False, required=False)
|
||||
hidecm = forms.BooleanField(initial=False, required=False)
|
||||
enablePrinter = forms.BooleanField(initial=True, required=False)
|
||||
enableCamera = forms.BooleanField(initial=True, required=False)
|
||||
enableTerminal = forms.BooleanField(initial=True, required=False)
|
||||
|
||||
#Other
|
||||
removeWallpaper = forms.BooleanField(initial=True, required=False)
|
||||
@@ -70,6 +84,29 @@ class GenerateForm(forms.Form):
|
||||
#custom added features
|
||||
cycleMonitor = forms.BooleanField(initial=False, required=False)
|
||||
xOffline = forms.BooleanField(initial=False, required=False)
|
||||
hidecm = forms.BooleanField(initial=False, required=False)
|
||||
statussort = forms.BooleanField(initial=False, required=False)
|
||||
removeNewVersionNotif = forms.BooleanField(initial=False, required=False)
|
||||
removeNewVersionNotif = forms.BooleanField(initial=False, required=False)
|
||||
|
||||
def clean_iconfile(self):
|
||||
print("checking icon")
|
||||
image = self.cleaned_data['iconfile']
|
||||
if image:
|
||||
try:
|
||||
# Open the image using Pillow
|
||||
img = Image.open(image)
|
||||
|
||||
# Check if the image is a PNG (optional, but good practice)
|
||||
if img.format != 'PNG':
|
||||
raise forms.ValidationError("Only PNG images are allowed.")
|
||||
|
||||
# Get image dimensions
|
||||
width, height = img.size
|
||||
|
||||
# Check for square dimensions
|
||||
if width != height:
|
||||
raise forms.ValidationError("Custom App Icon dimensions must be square.")
|
||||
|
||||
return image
|
||||
except OSError: # Handle cases where the uploaded file is not a valid image
|
||||
raise forms.ValidationError("Invalid icon file.")
|
||||
except Exception as e: # Catch any other image processing errors
|
||||
raise forms.ValidationError(f"Error processing icon: {e}")
|
||||
|
||||
18
rdgenerator/migrations/0002_githubrun_github_run_id.py
Normal file
18
rdgenerator/migrations/0002_githubrun_github_run_id.py
Normal file
@@ -0,0 +1,18 @@
|
||||
# Generated by Django 5.0.3 on 2026-03-11 04:58
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('rdgenerator', '0001_initial'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='githubrun',
|
||||
name='github_run_id',
|
||||
field=models.BigIntegerField(blank=True, null=True),
|
||||
),
|
||||
]
|
||||
@@ -4,3 +4,4 @@ class GithubRun(models.Model):
|
||||
id = models.IntegerField(verbose_name="ID",primary_key=True)
|
||||
uuid = models.CharField(verbose_name="uuid", max_length=100)
|
||||
status = models.CharField(verbose_name="status", max_length=100)
|
||||
github_run_id = models.BigIntegerField(null=True, blank=True)
|
||||
|
||||
156
rdgenerator/templates/failure.html
Normal file
156
rdgenerator/templates/failure.html
Normal file
@@ -0,0 +1,156 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title id="pageTitle">Build Failure</title>
|
||||
<style>
|
||||
body {
|
||||
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
height: 100vh;
|
||||
margin: 0;
|
||||
text-align: center;
|
||||
background: linear-gradient(135deg, #ffcfcf 0%, #e2c3c3 100%);
|
||||
}
|
||||
.platform-logo {
|
||||
width: 150px;
|
||||
height: 150px;
|
||||
margin-bottom: 30px;
|
||||
display: none;
|
||||
filter: drop-shadow(0 10px 15px rgba(0,0,0,0.2));
|
||||
transition: transform 0.3s ease;
|
||||
}
|
||||
.error-container {
|
||||
background: white;
|
||||
border-radius: 12px;
|
||||
padding: 30px;
|
||||
box-shadow: 0 10px 25px rgba(0,0,0,0.1);
|
||||
max-width: 500px;
|
||||
width: 90%;
|
||||
}
|
||||
.error-header {
|
||||
color: #c0392b;
|
||||
font-weight: 700;
|
||||
margin-bottom: 10px;
|
||||
font-size: 1.5em;
|
||||
}
|
||||
.warning-box {
|
||||
background-color: #fff3cd;
|
||||
border: 1px solid #ffeeba;
|
||||
color: #856404;
|
||||
padding: 15px;
|
||||
border-radius: 8px;
|
||||
margin-bottom: 20px;
|
||||
font-size: 0.9em;
|
||||
text-align: left;
|
||||
}
|
||||
.download-section {
|
||||
background: #f8f9fa;
|
||||
padding: 15px;
|
||||
border-radius: 10px;
|
||||
border: 1px dashed #ccc;
|
||||
}
|
||||
.download-link {
|
||||
display: block;
|
||||
margin: 10px 0;
|
||||
padding: 12px;
|
||||
background-color: #34495e;
|
||||
color: white;
|
||||
text-decoration: none;
|
||||
border-radius: 5px;
|
||||
transition: opacity 0.3s ease;
|
||||
}
|
||||
.download-link:hover {
|
||||
opacity: 0.8;
|
||||
}
|
||||
.log-link {
|
||||
display: inline-block;
|
||||
margin-top: 15px;
|
||||
color: #3498db;
|
||||
text-decoration: none;
|
||||
font-size: 0.85em;
|
||||
}
|
||||
.platform-note {
|
||||
color: #666;
|
||||
font-size: 0.85em;
|
||||
margin-top: 15px;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<svg id="windowsLogo" class="platform-logo" viewBox="0 0 256 256" xmlns="http://www.w3.org/2000/svg">
|
||||
<rect width="256" height="256" rx="50" ry="50" fill="#0078D7"/>
|
||||
<text x="128" y="160" font-family="Arial" font-size="50" font-weight="bold" text-anchor="middle" fill="white">Win</text>
|
||||
</svg>
|
||||
<div class="error-container">
|
||||
<h2 class="error-header">Workflow Interrupted</h2>
|
||||
|
||||
<div class="warning-box">
|
||||
<strong>Warning:</strong> The build process did not complete successfully. Some files may be missing. You can attempt to download the available files below.
|
||||
</div>
|
||||
|
||||
<div class="download-section">
|
||||
{% if platform == 'windows' %}
|
||||
<a href='/download?filename={{filename}}.exe&uuid={{uuid}}' class="download-link">Download {{filename}}.exe</a>
|
||||
<a href='/download?filename={{filename}}.msi&uuid={{uuid}}' class="download-link">Download {{filename}}.msi</a>
|
||||
{% elif platform == 'windows-x86' %}
|
||||
<a href='/download?filename={{filename}}.exe&uuid={{uuid}}' class="download-link">Download {{filename}}.exe</a>
|
||||
{% elif platform == 'linux' %}
|
||||
<a href='/download?filename={{filename}}-x86_64.deb&uuid={{uuid}}' class="download-link">Download {{filename}}-x86_64.deb</a>
|
||||
<a href='/download?filename={{filename}}-x86_64.rpm&uuid={{uuid}}' class="download-link">Download {{filename}}-x86_64.rpm</a>
|
||||
<a href='/download?filename={{filename}}-suse-x86_64.rpm&uuid={{uuid}}' class="download-link">Download {{filename}}-suse-x86_64.rpm</a>
|
||||
<a href='/download?filename={{filename}}-x86_64.pkg.tar.zst&uuid={{uuid}}' class="download-link">Download {{filename}}-x86_64.pkg.tar.zst</a>
|
||||
<a href='/download?filename={{filename}}-aarch64.deb&uuid={{uuid}}' class="download-link">Download {{filename}}-aarch64.deb</a>
|
||||
<a href='/download?filename={{filename}}-aarch64.rpm&uuid={{uuid}}' class="download-link">Download {{filename}}-aarch64.rpm</a>
|
||||
<a href='/download?filename={{filename}}-suse-aarch64.rpm&uuid={{uuid}}' class="download-link">Download {{filename}}-suse-aarch64.rpm</a>
|
||||
<a href='/download?filename={{filename}}-aarch64.pkg.tar.zst&uuid={{uuid}}' class="download-link">Download {{filename}}-aarch64.pkg.tar.zst</a>
|
||||
<a href='/download?filename={{filename}}-x86_64.AppImage&uuid={{uuid}}' class="download-link">Download {{filename}}-x86_64.AppImage</a>
|
||||
<a href='/download?filename={{filename}}-aarch64.AppImage&uuid={{uuid}}' class="download-link">Download {{filename}}-aarch64.AppImage</a>
|
||||
<a href='/download?filename={{filename}}-x86_64.flatpak&uuid={{uuid}}' class="download-link">Download {{filename}}-x86_64.flatpak</a>
|
||||
<a href='/download?filename={{filename}}-aarch64.flatpak&uuid={{uuid}}' class="download-link">Download {{filename}}-aarch64.flatpak</a>
|
||||
{% elif platform == 'android' %}
|
||||
<a href='/download?filename={{filename}}-aarch64.apk&uuid={{uuid}}' class="download-link">Download {{filename}}-aarch64.apk</a>
|
||||
<a href='/download?filename={{filename}}-x86_64.apk&uuid={{uuid}}' class="download-link">Download {{filename}}-x86_64.apk</a>
|
||||
<a href='/download?filename={{filename}}-armv7.apk&uuid={{uuid}}' class="download-link">Download {{filename}}-armv7.apk</a>
|
||||
{% elif platform == 'macos' %}
|
||||
<a href='/download?filename={{filename}}-x86_64.dmg&uuid={{uuid}}' class="download-link">Download {{filename}}-x86_64.dmg</a>
|
||||
<a href='/download?filename={{filename}}-aarch64.dmg&uuid={{uuid}}' class="download-link">Download {{filename}}-aarch64.dmg</a>
|
||||
{% else %}
|
||||
<p>Error: No file generated</p>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
<a href="{{ log_url }}" target="_blank" class="log-link">Check GitHub Logs for error details ↗</a>
|
||||
|
||||
<div id="platformNote" class="platform-note"></div>
|
||||
<hr style="border: 0; border-top: 1px solid #eee; margin: 20px 0;">
|
||||
<a href="/" style="font-size: 0.9em; color: #666; text-decoration: none;">← Return to Form</a>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
function updatePlatformUI() {
|
||||
const platform = '{{platform}}'.toLowerCase();
|
||||
const platformLogos = {
|
||||
'windows': document.getElementById('windowsLogo'),
|
||||
'macos': document.getElementById('macosLogo'),
|
||||
'linux': document.getElementById('linuxLogo'),
|
||||
'android': document.getElementById('androidLogo')
|
||||
};
|
||||
|
||||
Object.values(platformLogos).forEach(logo => { if(logo) logo.style.display = 'none'; });
|
||||
|
||||
if (platform.includes('windows')) {
|
||||
document.getElementById('pageTitle').textContent = 'Windows Build Failed';
|
||||
if(platformLogos.windows) platformLogos.windows.style.display = 'block';
|
||||
} else if (platform === 'macos') {
|
||||
if(platformLogos.macos) platformLogos.macos.style.display = 'block';
|
||||
} else if (platform === 'linux') {
|
||||
if(platformLogos.linux) platformLogos.linux.style.display = 'block';
|
||||
}
|
||||
}
|
||||
updatePlatformUI();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -129,16 +129,28 @@
|
||||
{% if platform == 'windows' %}
|
||||
<a href='/download?filename={{filename}}.exe&uuid={{uuid}}' class="download-link">Download {{filename}}.exe</a>
|
||||
<a href='/download?filename={{filename}}.msi&uuid={{uuid}}' class="download-link">Download {{filename}}.msi</a>
|
||||
{% elif platform == 'windows-x86' %}
|
||||
<a href='/download?filename={{filename}}.exe&uuid={{uuid}}' class="download-link">Download {{filename}}.exe</a>
|
||||
{% elif platform == 'linux' %}
|
||||
<a href='/download?filename={{filename}}.deb&uuid={{uuid}}' class="download-link">Download {{filename}}.deb</a>
|
||||
<a href='/download?filename={{filename}}.rpm&uuid={{uuid}}' class="download-link">Download {{filename}}.rpm</a>
|
||||
<a href='/download?filename={{filename}}-suse.rpm&uuid={{uuid}}' class="download-link">Download {{filename}}-suse.rpm</a>
|
||||
<a href='/download?filename={{filename}}-x86_64.deb&uuid={{uuid}}' class="download-link">Download {{filename}}-x86_64.deb</a>
|
||||
<a href='/download?filename={{filename}}-x86_64.rpm&uuid={{uuid}}' class="download-link">Download {{filename}}-x86_64.rpm</a>
|
||||
<a href='/download?filename={{filename}}-suse-x86_64.rpm&uuid={{uuid}}' class="download-link">Download {{filename}}-suse-x86_64.rpm</a>
|
||||
<a href='/download?filename={{filename}}-x86_64.pkg.tar.zst&uuid={{uuid}}' class="download-link">Download {{filename}}-x86_64.pkg.tar.zst</a>
|
||||
<a href='/download?filename={{filename}}-aarch64.deb&uuid={{uuid}}' class="download-link">Download {{filename}}-aarch64.deb</a>
|
||||
<a href='/download?filename={{filename}}-aarch64.rpm&uuid={{uuid}}' class="download-link">Download {{filename}}-aarch64.rpm</a>
|
||||
<a href='/download?filename={{filename}}-suse-aarch64.rpm&uuid={{uuid}}' class="download-link">Download {{filename}}-suse-aarch64.rpm</a>
|
||||
<a href='/download?filename={{filename}}-aarch64.pkg.tar.zst&uuid={{uuid}}' class="download-link">Download {{filename}}-aarch64.pkg.tar.zst</a>
|
||||
<a href='/download?filename={{filename}}-x86_64.AppImage&uuid={{uuid}}' class="download-link">Download {{filename}}-x86_64.AppImage</a>
|
||||
<a href='/download?filename={{filename}}-aarch64.AppImage&uuid={{uuid}}' class="download-link">Download {{filename}}-aarch64.AppImage</a>
|
||||
<a href='/download?filename={{filename}}-x86_64.flatpak&uuid={{uuid}}' class="download-link">Download {{filename}}-x86_64.flatpak</a>
|
||||
<a href='/download?filename={{filename}}-aarch64.flatpak&uuid={{uuid}}' class="download-link">Download {{filename}}-aarch64.flatpak</a>
|
||||
{% elif platform == 'android' %}
|
||||
<a href='/download?filename={{filename}}-aarch64.apk&uuid={{uuid}}' class="download-link">Download {{filename}}-aarch64.apk</a>
|
||||
<a href='/download?filename={{filename}}-x86_64.apk&uuid={{uuid}}' class="download-link">Download {{filename}}-x86_64.apk</a>
|
||||
<a href='/download?filename={{filename}}-armv7.apk&uuid={{uuid}}' class="download-link">Download {{filename}}-armv7.apk</a>
|
||||
{% elif platform == 'macos' %}
|
||||
<a href='/download?filename={{filename}}.dmg&uuid={{uuid}}' class="download-link">Download {{filename}}.dmg</a>
|
||||
<a href='/download?filename={{filename}}-x86_64.dmg&uuid={{uuid}}' class="download-link">Download {{filename}}-x86_64.dmg</a>
|
||||
<a href='/download?filename={{filename}}-aarch64.dmg&uuid={{uuid}}' class="download-link">Download {{filename}}-aarch64.dmg</a>
|
||||
{% else %}
|
||||
<p>Error: No file generated</p>
|
||||
{% endif %}
|
||||
@@ -167,7 +179,7 @@
|
||||
platformLogos.macos.style.display = 'block';
|
||||
platformNote.textContent = 'Note: For macOS, you may need to adjust security settings to run the application.';
|
||||
platformNote.style.display = 'block';
|
||||
} else if (platform === 'windows') {
|
||||
} else if (platform === 'windows' || platform === 'windows-x86') {
|
||||
document.getElementById('pageTitle').textContent = 'Windows Build Generated';
|
||||
platformLogos.windows.style.display = 'block';
|
||||
platformNote.textContent = 'Note: You might need to disable SmartScreen or adjust Windows security settings.';
|
||||
@@ -189,4 +201,4 @@
|
||||
updatePlatformUI();
|
||||
</script>
|
||||
</body>
|
||||
</html>{{ ... }}
|
||||
</html>{{ ... }}
|
||||
|
||||
@@ -90,7 +90,26 @@
|
||||
transition: color 0.3s ease;
|
||||
}
|
||||
.platform-icon:hover, .platform-icon.active {
|
||||
color: #fff;
|
||||
color: #2e52f7;
|
||||
}
|
||||
.text-64 {
|
||||
font-size: 0.5em;
|
||||
font-weight: bold;
|
||||
bottom: -0.2em;
|
||||
right: -0.2em;
|
||||
position: absolute;
|
||||
color: white;
|
||||
transform: translate(-50%, -50%);
|
||||
}
|
||||
|
||||
.text-32 {
|
||||
font-size: 0.5em;
|
||||
font-weight: bold;
|
||||
bottom: -0.2em;
|
||||
right: -0.2em;
|
||||
position: absolute;
|
||||
color: white;
|
||||
transform: translate(-50%, -50%);
|
||||
}
|
||||
.checkbox-group {
|
||||
display: grid;
|
||||
@@ -106,27 +125,152 @@
|
||||
max-height: 100px;
|
||||
margin-top: 10px;
|
||||
}
|
||||
.save-load-section-container { /* New container for fixed positioning */
|
||||
position: fixed;
|
||||
top: 20px; /* Adjust as needed */
|
||||
left: 20px; /* Adjust as needed */
|
||||
background-color: #111; /* Match your section background */
|
||||
padding: 0px;
|
||||
border-radius: 8px;
|
||||
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
|
||||
z-index: 100; /* Ensure it's above other content */
|
||||
}
|
||||
.save-load-section {
|
||||
display: none; /* Initially hidden */
|
||||
}
|
||||
.error {
|
||||
color: red;
|
||||
}
|
||||
.errorlist {
|
||||
color: red;
|
||||
display: flex; /* Enable flexbox for centering */
|
||||
justify-content: center; /* Center horizontally */
|
||||
align-items: center; /* Center vertically (if needed) */
|
||||
list-style: none; /* Remove bullet points if it's a list */
|
||||
padding: 0; /* Remove default padding */
|
||||
margin: 10px auto; /* Center the list itself, add some top/bottom margin */
|
||||
width: fit-content; /* Make the width fit the content */
|
||||
}
|
||||
|
||||
.errorlist li {
|
||||
margin: 5px; /* Add some spacing between list items */
|
||||
}
|
||||
@keyframes blink {
|
||||
0% { opacity: 1; }
|
||||
50% { opacity: 0.5; }
|
||||
100% { opacity: 1; }
|
||||
}
|
||||
|
||||
.help-text {
|
||||
color: #ffd700;
|
||||
font-style: italic;
|
||||
animation: blink 2s infinite;
|
||||
padding: 5px;
|
||||
border-radius: 4px;
|
||||
display: inline-block;
|
||||
margin-left: 10px;
|
||||
}
|
||||
|
||||
.password-requirement {
|
||||
display: none; /* Hidden by default */
|
||||
color: orange;
|
||||
font-size: 0.9em;
|
||||
margin-top: 5px;
|
||||
}
|
||||
|
||||
.sponsor-button {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
background: linear-gradient(135deg, #00457C 0%, #0079C1 100%);
|
||||
color: white;
|
||||
padding: 12px 28px;
|
||||
border-radius: 50px;
|
||||
text-decoration: none;
|
||||
font-weight: 600;
|
||||
font-size: 16px;
|
||||
letter-spacing: 0.5px;
|
||||
transition: all 0.3s ease;
|
||||
box-shadow: 0 4px 15px rgba(0, 69, 124, 0.2);
|
||||
border: 2px solid rgba(255, 255, 255, 0.1);
|
||||
text-transform: uppercase;
|
||||
}
|
||||
|
||||
.sponsor-button:hover {
|
||||
transform: translateY(-2px);
|
||||
box-shadow: 0 8px 25px rgba(0, 69, 124, 0.3);
|
||||
background: linear-gradient(135deg, #005AA7 0%, #0095EA 100%);
|
||||
border-color: rgba(255, 255, 255, 0.2);
|
||||
}
|
||||
|
||||
.sponsor-button i {
|
||||
margin-right: 12px;
|
||||
font-size: 20px;
|
||||
background: white;
|
||||
color: #00457C;
|
||||
padding: 8px;
|
||||
border-radius: 50%;
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
|
||||
.sponsor-button:hover i {
|
||||
transform: rotate(360deg);
|
||||
color: #0095EA;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<h1><i class="fas fa-cogs"></i> RustDesk Custom Client Builder</h1>
|
||||
<form action="/generator" method="post" enctype="multipart/form-data">
|
||||
<form id="myForm" action="/generator" method="post" enctype="multipart/form-data">
|
||||
<div class="save-load-section-container">
|
||||
<div class="section">
|
||||
<h2 id="saveLoadTitle">Save/Load Configuration <i class="fas fa-chevron-down"></i></h2>
|
||||
<div class="save-load-section">
|
||||
<button type="button" onclick="saveFormData()">Save Configuration</button>
|
||||
<input type="file" id="fileInput" style="display:none;" accept=".json">
|
||||
<button type="button" onclick="loadFormData()">Load Configuration</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% if form.iconfile.errors %}
|
||||
<ul class="errorlist">
|
||||
{% for error in form.iconfile.errors %}
|
||||
<li>{{ error }}</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
{% endif %}
|
||||
<div class="platform">
|
||||
<h2><i class="fas fa-desktop"></i> Select Platform</h2>
|
||||
<div class="platform-icons">
|
||||
<i class="fab fa-windows platform-icon active" data-platform="windows"></i>
|
||||
<span class="fa-stack fa-lg">
|
||||
<i class="fab fa-windows fa-stack-2x platform-icon active" data-platform="windows"></i>
|
||||
<strong class="fa-stack-1x text-64">64</strong>
|
||||
</span>
|
||||
<span class="fa-stack fa-lg">
|
||||
<i class="fab fa-windows fa-stack-2x platform-icon" data-platform="windows-x86"></i>
|
||||
<strong class="fa-stack-1x text-32">32</strong>
|
||||
</span>
|
||||
<i class="fab fa-linux platform-icon" data-platform="linux"></i>
|
||||
<i class="fab fa-android platform-icon" data-platform="android"></i>
|
||||
<i class="fab fa-apple platform-icon" data-platform="macos"></i>
|
||||
</div>
|
||||
<select name="platform" id="id_platform">
|
||||
<option value="windows" selected>Windows</option>
|
||||
<option value="windows" selected>Windows 64Bit</option>
|
||||
<option value="windows-x86">Windows 32Bit</option>
|
||||
<option value="linux">Linux</option>
|
||||
<option value="android">Android</option>
|
||||
<option value="macos">macOS</option>
|
||||
</select>
|
||||
<label for="{{ form.version.id_for_label }}">Rustdesk Version:</label>
|
||||
{{ form.version }}
|
||||
{% if form.version.help_text %}
|
||||
<span class="help-text">{{ form.version.help_text }}</span>
|
||||
{% endif %}
|
||||
<div class="help-text">{{ form.version.help_text }}</div>
|
||||
<label for="{{ form.delayFix.id_for_label }}">{{ form.delayFix }} Fix connection delay when using third-party API</label>
|
||||
</div>
|
||||
</div>
|
||||
@@ -134,7 +278,7 @@
|
||||
<div class="section">
|
||||
<h2><i class="fas fa-sliders-h"></i> General</h2>
|
||||
<label for="{{ form.exename.id_for_label }}">Name of the configuration (no spaces or special characters, English characters only):</label>
|
||||
{{ form.exename }}<br><br>
|
||||
{{ form.exename }}<span id="filenameError" class="error"></span><br><br>
|
||||
<label for="{{ form.appname.id_for_label }}">Custom Application Name (leave blank to use default):</label>
|
||||
{{ form.appname }}<br><br>
|
||||
<label for="{{ form.direction.id_for_label }}">Connection Type:</label>
|
||||
@@ -143,6 +287,8 @@
|
||||
{{ form.installation }}<br><br>
|
||||
<label for="{{ form.settings.id_for_label }}">Disable Settings:</label>
|
||||
{{ form.settings }}<br><br>
|
||||
<label for="{{ form.androidappid.id_for_label }}">Custom Android App ID (replaces 'com.carriez.flutter_hbb', leave blank to use default):</label>
|
||||
{{ form.androidappid }}<br><br>
|
||||
</div>
|
||||
|
||||
<div class="section">
|
||||
@@ -155,15 +301,18 @@
|
||||
{{ form.apiServer }}<br><br>
|
||||
<label for="{{ form.urlLink.id_for_label }}">Custom URL for links (replaces https://rustdesk.com):</label>
|
||||
{{ form.urlLink }}<br><br>
|
||||
<label for="{{ form.downloadLink.id_for_label }}">Custom URL for downloading updates (replaces https://rustdesk.com/download):</label>
|
||||
{{ form.downloadLink }}<br><br>
|
||||
<label for="{{ form.compname.id_for_label }}">Company name for copyright (replaces Purslane Ltd):</label>
|
||||
{{ form.compname }}<br><br>
|
||||
</div>
|
||||
</div>
|
||||
<div class="container">
|
||||
<div class="section">
|
||||
<h2><i class="fas fa-shield-alt"></i> Security</h2>
|
||||
<label for="{{ form.runasadmin.id_for_label }}">Always run as Administrator?</label>
|
||||
{{ form.runasadmin }}<br><br>
|
||||
<label for="{{ form.passApproveMode.id_for_label }}">Password Approve mode:</label>
|
||||
{{ form.passApproveMode }}<br><br>
|
||||
<div id="passwordRequirement" class="password-requirement">To use the hide connection window feature, please set a permanent password.</div>
|
||||
<label for="{{ form.permanentPassword.id_for_label }}">Set Permanent Password:</label>
|
||||
{{ form.permanentPassword }} *The password is used as default, but can be changed by the client<br><br>
|
||||
|
||||
@@ -172,11 +321,16 @@
|
||||
|
||||
<label for="{{ form.enableDirectIP.id_for_label }}">{{ form.enableDirectIP }} Enable direct IP access</label><br>
|
||||
|
||||
<label for="{{ form.autoClose.id_for_label }}">{{ form.autoClose }} Automatically close incoming sessions on user inactivity</label><br>
|
||||
<label for="{{ form.autoClose.id_for_label }}">{{ form.autoClose }} Automatically close incoming sessions on user inactivity</label><br>
|
||||
|
||||
<label for="{{ form.hidecm.id_for_label }}">{{ form.hidecm }} Allow hiding the connection window from remote screen.</label><br>
|
||||
</div>
|
||||
|
||||
<div class="section">
|
||||
<h2><i class="fas fa-paint-brush"></i> Visual</h2>
|
||||
{{ form.iconbase64.as_hidden }}
|
||||
{{ form.logobase64.as_hidden }}
|
||||
{{ form.privacybase64.as_hidden }}
|
||||
<label for="{{ form.iconfile.id_for_label }}">Custom App Icon (in .png format)</label>
|
||||
{{ form.iconfile }}<br><br>
|
||||
<!-- <input type="file" name="iconfile" id="iconfile" accept="image/png"> -->
|
||||
@@ -185,6 +339,10 @@
|
||||
{{ form.logofile }}<br><br>
|
||||
<!-- <input type="file" name="logofile" id="logofile" accept="image/png"> -->
|
||||
<div id="logo-preview"></div><br><br>
|
||||
<label for="{{ form.privacyfile.id_for_label }}">Custom Privacy Screen (in .png format)</label>
|
||||
{{ form.privacyfile }}<br><br>
|
||||
<!-- <input type="file" name="iconfile" id="iconfile" accept="image/png"> -->
|
||||
<div id="privacy-preview"></div><br><br>
|
||||
<label for="{{ form.theme.id_for_label }}">Theme:</label>
|
||||
{{ form.theme }} {{ form.themeDorO }} *Default sets the theme but allows the client to change it, Override sets the theme permanently.<br><br>
|
||||
</div>
|
||||
@@ -192,7 +350,7 @@
|
||||
<div class="container">
|
||||
<div class="section">
|
||||
<h2><i class="fas fa-lock"></i> Permissions</h2>
|
||||
The following Permissions can be set as default (the user can change the settins) or override (the settings cannot be changed).<br>
|
||||
The following Permissions can be set as default (the user can change the settings) or override (the settings cannot be changed).<br>
|
||||
{{ form.permissionsDorO }}
|
||||
<label for="{{ form.permissionsType.id_for_label }}">Permission type:</label>
|
||||
{{ form.permissionsType }}<br><br>
|
||||
@@ -206,18 +364,20 @@
|
||||
<label for="{{ form.enableRecording.id_for_label }}">{{ form.enableRecording }} Enable recording session</label>
|
||||
<label for="{{ form.enableBlockingInput.id_for_label }}">{{ form.enableBlockingInput }} Enable blocking user input</label>
|
||||
<label for="{{ form.enableRemoteModi.id_for_label }}">{{ form.enableRemoteModi }} Enable remote configuration modification</label>
|
||||
<label for="{{ form.enablePrinter.id_for_label }}">{{ form.enablePrinter }} Enable remote printer</label>
|
||||
<label for="{{ form.enableCamera.id_for_label }}">{{ form.enableCamera }} Enable remote camera</label>
|
||||
<label for="{{ form.enableTerminal.id_for_label }}">{{ form.enableTerminal }} Enable remote terminal</label>
|
||||
</div><br>
|
||||
<h2><i class="fas fa-code"></i> Code Changes</h2>
|
||||
<label for="{{ form.cycleMonitor.id_for_label }}">{{ form.cycleMonitor }} Add a button to cycle through available monitors to the minimized toolbar.</label><br>
|
||||
<label for="{{ form.xOffline.id_for_label }}">{{ form.xOffline }} Display an X for offline devices in the addressbook.</label><br>
|
||||
<label for="{{ form.hidecm.id_for_label }}">{{ form.hidecm }} Allow hiding the connection window from remote screen.</label><br>
|
||||
<label for="{{ form.statussort.id_for_label }}">{{ form.statussort }} Allow sorting by online status.</label><br>
|
||||
<label for="{{ form.removeNewVersionNotif.id_for_label }}">{{ form.removeNewVersionNotif }} Remove notification for new versions.</label><br>
|
||||
</div>
|
||||
|
||||
<div class="section">
|
||||
<h2><i class="fas fa-cog"></i> Other</h2>
|
||||
<label for="{{ form.removeWallpaper.id_for_label }}">{{ form.removeWallpaper }} Remove wallpaper during incoming sessions</label><br>
|
||||
<a href="https://rustdesk.com/docs/en/self-host/client-configuration/advanced-settings/">Click here for a list of Default/Override settings</a>
|
||||
<label for="{{ form.defaultManual.id_for_label }}">Default settings</label><br>
|
||||
{{ form.defaultManual }}<br><br>
|
||||
<label for="{{ form.overrideManual.id_for_label }}">Override settings</label><br>
|
||||
@@ -227,10 +387,24 @@
|
||||
<div class="platform">
|
||||
<div class="section">
|
||||
<button type="submit"><i class="fas fa-rocket"></i> Generate Custom Client</button>
|
||||
<a href="https://github.com/bryangerlach/rdgen">Source Code on github</a>
|
||||
<iframe src="https://github.com/sponsors/bryangerlach/button" title="Sponsor bryangerlach" height="32" width="114" style="border: 0; border-radius: 6px;"></iframe>
|
||||
</div>
|
||||
</div>
|
||||
<div style="text-align: center; margin: 30px 0;">
|
||||
<a href="https://github.com/bryangerlach/rdgen"
|
||||
target="_blank"
|
||||
class="sponsor-button">
|
||||
<i class="fab fa-github"></i>
|
||||
Source Code on Github
|
||||
</a>
|
||||
</div>
|
||||
<div style="text-align: center; margin: 30px 0;">
|
||||
<a href="https://github.com/sponsors/bryangerlach?o=esb"
|
||||
target="_blank"
|
||||
class="sponsor-button">
|
||||
<i class="fab fa-github"></i>
|
||||
Donate
|
||||
</a>
|
||||
</div>
|
||||
</form>
|
||||
<script>
|
||||
document.querySelectorAll('.platform-icon').forEach(icon => {
|
||||
@@ -246,6 +420,101 @@
|
||||
document.getElementById("{{ form.logofile.id_for_label }}").addEventListener('change', function(event) {
|
||||
previewImage(event.target, 'logo-preview');
|
||||
});
|
||||
document.getElementById("{{ form.privacyfile.id_for_label }}").addEventListener('change', function(event) {
|
||||
previewImage(event.target, 'privacy-preview');
|
||||
});
|
||||
|
||||
document.getElementById("{{ form.hidecm.id_for_label }}").addEventListener('change',function() {
|
||||
if (this.checked) {
|
||||
document.getElementById("passwordRequirement").style.display = 'block';
|
||||
document.getElementById("{{ form.permanentPassword.id_for_label }}").focus();
|
||||
document.getElementById("{{ form.passApproveMode.id_for_label }}").value = 'password';
|
||||
} else {
|
||||
document.getElementById("passwordRequirement").style.display = 'none';
|
||||
document.getElementById("{{ form.passApproveMode.id_for_label }}").value = 'password-click';
|
||||
}
|
||||
});
|
||||
const enableKeyboard = document.getElementById("{{ form.enableKeyboard.id_for_label }}");
|
||||
const enableClipboard = document.getElementById("{{ form.enableClipboard.id_for_label }}");
|
||||
const enableFileTransfer = document.getElementById("{{ form.enableFileTransfer.id_for_label }}");
|
||||
const enableAudio = document.getElementById("{{ form.enableAudio.id_for_label }}");
|
||||
const enableTCP = document.getElementById("{{ form.enableTCP.id_for_label }}");
|
||||
const enableRemoteRestart = document.getElementById("{{ form.enableRemoteRestart.id_for_label }}");
|
||||
const enableRecording = document.getElementById("{{ form.enableRecording.id_for_label }}");
|
||||
const enableBlockingInput = document.getElementById("{{ form.enableBlockingInput.id_for_label }}");
|
||||
const enableRemoteModi = document.getElementById("{{ form.enableRemoteModi.id_for_label }}");
|
||||
const enablePrinter = document.getElementById("{{ form.enablePrinter.id_for_label }}");
|
||||
const enableCamera = document.getElementById("{{ form.enableCamera.id_for_label }}");
|
||||
const enableTerminal = document.getElementById("{{ form.enableTerminal.id_for_label }}");
|
||||
|
||||
document.getElementById("{{ form.permissionsType.id_for_label }}").addEventListener('change', function() {
|
||||
if (this.value === 'full') {
|
||||
enableKeyboard.checked = true;
|
||||
enableClipboard.checked = true;
|
||||
enableFileTransfer.checked = true;
|
||||
enableAudio.checked = true;
|
||||
enableTCP.checked = true;
|
||||
enableRemoteRestart.checked = true;
|
||||
enableRecording.checked = true;
|
||||
enableBlockingInput.checked = true;
|
||||
enableRemoteModi.checked = true;
|
||||
enablePrinter.checked = true;
|
||||
enableCamera.checked = true;
|
||||
enableTerminal.checked = true;
|
||||
|
||||
enableKeyboard.disabled = true;
|
||||
enableClipboard.disabled = true;
|
||||
enableFileTransfer.disabled = true;
|
||||
enableAudio.disabled = true;
|
||||
enableTCP.disabled = true;
|
||||
enableRemoteRestart.disabled = true;
|
||||
enableRecording.disabled = true;
|
||||
enableBlockingInput.disabled = true;
|
||||
enableRemoteModi.disabled = true;
|
||||
enablePrinter.disabled = true;
|
||||
enableCamera.disabled = true;
|
||||
enableTerminal.disable = true;
|
||||
} else if (this.value === 'view') {
|
||||
enableKeyboard.checked = false;
|
||||
enableClipboard.checked = false;
|
||||
enableFileTransfer.checked = false;
|
||||
enableAudio.checked = false;
|
||||
enableTCP.checked = false;
|
||||
enableRemoteRestart.checked = false;
|
||||
enableRecording.checked = false;
|
||||
enableBlockingInput.checked = false;
|
||||
enableRemoteModi.checked = false;
|
||||
enablePrinter.checked = false;
|
||||
enableCamera.checked = false;
|
||||
enableTerminal.checked = false;
|
||||
|
||||
enableKeyboard.disabled = true;
|
||||
enableClipboard.disabled = true;
|
||||
enableFileTransfer.disabled = true;
|
||||
enableAudio.disabled = true;
|
||||
enableTCP.disabled = true;
|
||||
enableRemoteRestart.disabled = true;
|
||||
enableRecording.disabled = true;
|
||||
enableBlockingInput.disabled = true;
|
||||
enableRemoteModi.disabled = true;
|
||||
enablePrinter.disabled = true;
|
||||
enableCamera.disabled = true;
|
||||
enableTerminal.disable = true;
|
||||
} else if (this.value === 'custom') {
|
||||
enableKeyboard.disabled = false;
|
||||
enableClipboard.disabled = false;
|
||||
enableFileTransfer.disabled = false;
|
||||
enableAudio.disabled = false;
|
||||
enableTCP.disabled = false;
|
||||
enableRemoteRestart.disabled = false;
|
||||
enableRecording.disabled = false;
|
||||
enableBlockingInput.disabled = false;
|
||||
enableRemoteModi.disabled = false;
|
||||
enablePrinter.checked = false;
|
||||
enableCamera.checked = false;
|
||||
enableTerminal.checked = false;
|
||||
}
|
||||
});
|
||||
function previewImage(input, previewContainerId) {
|
||||
if (input.files && input.files[0]) {
|
||||
var reader = new FileReader();
|
||||
@@ -260,6 +529,165 @@
|
||||
reader.readAsDataURL(input.files[0]);
|
||||
}
|
||||
}
|
||||
const saveLoadTitle = document.getElementById("saveLoadTitle");
|
||||
const saveLoadSection = document.querySelector(".save-load-section");
|
||||
|
||||
saveLoadTitle.addEventListener("click", () => {
|
||||
if (!saveLoadSection.style.display || saveLoadSection.style.display === "none") {
|
||||
saveLoadSection.style.display = "block";
|
||||
} else {
|
||||
saveLoadSection.style.display = "none";
|
||||
}
|
||||
|
||||
const icon = saveLoadTitle.querySelector("i");
|
||||
icon.classList.toggle("fa-chevron-down");
|
||||
icon.classList.toggle("fa-chevron-up");
|
||||
});
|
||||
|
||||
async function saveFormData() {
|
||||
const filename = document.getElementById("{{ form.exename.id_for_label }}").value;
|
||||
if (!filename) {
|
||||
document.getElementById("filenameError").textContent = "Filename is required.";
|
||||
return;
|
||||
} else {
|
||||
document.getElementById("filenameError").textContent = "";
|
||||
}
|
||||
|
||||
const formData = {};
|
||||
const form = document.getElementById("myForm"); // Get the form element
|
||||
|
||||
// 1. Use FormData for robust data collection (handles most input types):
|
||||
const formDataObj = new FormData(form); // Create a FormData object
|
||||
|
||||
formDataObj.forEach((value, key) => {
|
||||
formData[key] = value; // Add each key/value pair to the formData object.
|
||||
});
|
||||
|
||||
// 2. Handle select elements separately (more reliable):
|
||||
const selectElements = form.querySelectorAll('select');
|
||||
selectElements.forEach(select => {
|
||||
formData[select.name] = select.value;
|
||||
});
|
||||
|
||||
// 3. Handle checkboxes and radio buttons (important!):
|
||||
const checkboxRadioElements = form.querySelectorAll('input[type="checkbox"], input[type="radio"]');
|
||||
checkboxRadioElements.forEach(input => {
|
||||
if (input.name) { //only add to form data if it has a name
|
||||
if (input.checked) {
|
||||
formData[input.name] = input.value;
|
||||
} else if (!formData.hasOwnProperty(input.name) && input.type === 'checkbox') { //if it's a checkbox and it's not checked, add it as false
|
||||
formData[input.name] = false;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// 4. Handle icon and logo
|
||||
const iconPreview = document.getElementById('icon-preview');
|
||||
if (iconPreview.firstChild && iconPreview.firstChild.src.startsWith('data:image/png;base64')) {
|
||||
formData.iconfile = iconPreview.firstChild.src; // Use existing base64
|
||||
} else { //if it's a file upload
|
||||
const iconFile = document.getElementById("{{ form.iconfile.id_for_label }}").files[0];
|
||||
if (iconFile) {
|
||||
formData.iconfile = await readFileAsBase64(iconFile);
|
||||
}
|
||||
}
|
||||
|
||||
const logoPreview = document.getElementById('logo-preview');
|
||||
if (logoPreview.firstChild && logoPreview.firstChild.src.startsWith('data:image/png;base64')) {
|
||||
formData.logofile = logoPreview.firstChild.src; // Use existing base64
|
||||
} else { //if it's a file upload
|
||||
const logoFile = document.getElementById("{{ form.logofile.id_for_label }}").files[0];
|
||||
if (logoFile) {
|
||||
formData.logofile = await readFileAsBase64(logoFile);
|
||||
}
|
||||
}
|
||||
|
||||
const privacyPreview = document.getElementById('privacy-preview');
|
||||
if (privacyPreview.firstChild && privacyPreview.firstChild.src.startsWith('data:image/png;base64')) {
|
||||
formData.privacyfile = privacyPreview.firstChild.src; // Use existing base64
|
||||
} else { //if it's a file upload
|
||||
const privacyFile = document.getElementById("{{ form.privacyfile.id_for_label }}").files[0];
|
||||
if (privacyFile) {
|
||||
formData.privacyfile = await readFileAsBase64(privacyFile);
|
||||
}
|
||||
}
|
||||
|
||||
const jsonData = JSON.stringify(formData, null, 2);
|
||||
const blob = new Blob([jsonData], { type: "application/json" });
|
||||
const url = URL.createObjectURL(blob);
|
||||
|
||||
const a = document.createElement("a");
|
||||
a.href = url;
|
||||
a.download = filename + ".json";
|
||||
document.body.appendChild(a);
|
||||
a.click();
|
||||
document.body.removeChild(a);
|
||||
URL.revokeObjectURL(url);
|
||||
}
|
||||
|
||||
async function readFileAsBase64(file) {
|
||||
return new Promise((resolve, reject) => {
|
||||
const reader = new FileReader();
|
||||
reader.onload = (event) => resolve(event.target.result);
|
||||
reader.onerror = (error) => reject(error);
|
||||
reader.readAsDataURL(file);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
function loadFormData() {
|
||||
const fileInput = document.getElementById("fileInput");
|
||||
fileInput.click();
|
||||
|
||||
fileInput.addEventListener("change", (event) => {
|
||||
const file = event.target.files[0];
|
||||
if (file) {
|
||||
const reader = new FileReader();
|
||||
reader.onload = (e) => {
|
||||
try {
|
||||
const formData = JSON.parse(e.target.result);
|
||||
for (const key in formData) {
|
||||
// More robust selector: checks for name OR id
|
||||
const elements = document.querySelectorAll(`[name="${key}"], [id="${key}"]`);
|
||||
|
||||
if (elements.length > 0) { // Check if any element(s) exist
|
||||
elements.forEach(element => { // Loop through all matching elements (important for radios)
|
||||
if (element.type === 'radio') {
|
||||
if (element.value === String(formData[key])) { // Compare value, crucial for radios
|
||||
element.checked = true;
|
||||
} else {
|
||||
element.checked = false; // Uncheck others in the group
|
||||
}
|
||||
} else if (element.type === 'checkbox') {
|
||||
element.checked = formData[key];
|
||||
} else if (element.type !== 'file') {
|
||||
element.value = formData[key];
|
||||
}
|
||||
|
||||
// Handle image previews (as before)
|
||||
if (key === 'iconfile' && formData[key]) {
|
||||
document.getElementById('id_iconbase64').value = formData[key];
|
||||
document.getElementById('icon-preview').innerHTML = `<img src="${formData[key]}" style="max-width: 300px; max-height: 60px;">`;
|
||||
}
|
||||
if (key === 'logofile' && formData[key]) {
|
||||
document.getElementById('id_logobase64').value = formData[key];
|
||||
document.getElementById('logo-preview').innerHTML = `<img src="${formData[key]}" style="max-width: 300px; max-height: 60px;">`;
|
||||
}
|
||||
if (key === 'privacyfile' && formData[key]) {
|
||||
document.getElementById('id_privacybase64').value = formData[key];
|
||||
document.getElementById('privacy-preview').innerHTML = `<img src="${formData[key]}" style="max-width: 300px; max-height: 60px;">`;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
alert("Error loading data. Invalid JSON file.");
|
||||
}
|
||||
};
|
||||
reader.readAsText(file);
|
||||
}
|
||||
});
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
</html>
|
||||
|
||||
60
rdgenerator/templates/maintenance.html
Normal file
60
rdgenerator/templates/maintenance.html
Normal file
@@ -0,0 +1,60 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<title>Rustdesk Client Generator</title>
|
||||
<style>
|
||||
html, body {
|
||||
height: 100%;
|
||||
}
|
||||
body {
|
||||
background-color: #fff;
|
||||
background: radial-gradient(circle at center, #fff 0%, #f8f8f8 75%, #ebebeb 100%);
|
||||
color: #222;
|
||||
font-family: system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", "Liberation Sans", sans-serif;
|
||||
font-size: 1rem;
|
||||
line-height: 1.5;
|
||||
margin: 0;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
main {
|
||||
padding: 1rem;
|
||||
text-align: center;
|
||||
}
|
||||
h1 {
|
||||
font-size: 2.5rem;
|
||||
line-height: 1.1;
|
||||
margin: 0;
|
||||
}
|
||||
@media screen and (max-width: 480px) {
|
||||
h1 {
|
||||
font-size: 1.5rem;
|
||||
}
|
||||
}
|
||||
h1::after {
|
||||
content: "";
|
||||
background-color: #ffe800;
|
||||
background: repeating-linear-gradient(45deg, #ffe800, #ffe800 0.5rem, #222 0.5rem, #222 1.0rem);
|
||||
display: block;
|
||||
height: 0.5rem;
|
||||
margin-top: 1rem;
|
||||
}
|
||||
img {
|
||||
max-width: 100%;
|
||||
height: auto;
|
||||
}
|
||||
p {
|
||||
margin: 1rem 0 0 0;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<main>
|
||||
<h1>Rustdesk Client Generator</h1>
|
||||
<p>The Rustdesk Client Generator is currently under construction, please come back at a later time.</p>
|
||||
</main>
|
||||
</body>
|
||||
</html>
|
||||
@@ -69,6 +69,28 @@
|
||||
background-color: #3498db;
|
||||
transition: width 0.5s ease-in-out;
|
||||
}
|
||||
.log-container {
|
||||
margin-top: 30px;
|
||||
padding: 15px;
|
||||
background: rgba(255, 255, 255, 0.5);
|
||||
border-radius: 12px;
|
||||
font-size: 0.85em;
|
||||
max-width: 320px;
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
border: 1px solid rgba(0,0,0,0.05);
|
||||
}
|
||||
.log-link {
|
||||
color: #3498db;
|
||||
text-decoration: none;
|
||||
font-weight: 600;
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 5px;
|
||||
}
|
||||
.log-link:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
@@ -140,8 +162,16 @@
|
||||
<div class="progress-bar">
|
||||
<div id="progressBarFill" class="progress-bar-fill"></div>
|
||||
</div>
|
||||
<p class="status-text">This can take 20-30 minutes (or longer if there are other users).</p>
|
||||
<p class="status-text">This can take 30-45 minutes. You can leave this page open or come back later.</p>
|
||||
<p class="status-text">Status: <span id="statusText">{{status}}</span></p>
|
||||
|
||||
<div class="log-container">
|
||||
<p style="margin: 0 0 8px 0; color: #888;">Technical View</p>
|
||||
<a href="{{ log_url }}" target="_blank" class="log-link">
|
||||
View GitHub Action Logs
|
||||
<svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path><polyline points="15 3 21 3 21 9"></polyline><line x1="10" y1="14" x2="21" y2="3"></line></svg>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="macosNote" class="macos-note">
|
||||
@@ -154,6 +184,7 @@
|
||||
const platform = '{{platform}}'.toLowerCase();
|
||||
const platformLogos = {
|
||||
'windows': document.getElementById('windowsLogo'),
|
||||
'windows-x86': document.getElementById('windowsLogo'),
|
||||
'macos': document.getElementById('macosLogo'),
|
||||
'linux': document.getElementById('linuxLogo'),
|
||||
'android': document.getElementById('androidLogo')
|
||||
@@ -167,7 +198,7 @@
|
||||
document.getElementById('pageTitle').textContent = 'Generating MacOS Build';
|
||||
platformLogos.macos.style.display = 'block';
|
||||
document.getElementById('macosNote').style.display = 'block';
|
||||
} else if (platform === 'windows') {
|
||||
} else if (platform === 'windows' | platform === 'windows-x86') {
|
||||
document.getElementById('pageTitle').textContent = 'Generating Windows Build';
|
||||
platformLogos.windows.style.display = 'block';
|
||||
} else if (platform === 'linux') {
|
||||
@@ -211,7 +242,7 @@
|
||||
|
||||
setTimeout(function() {
|
||||
window.location.replace('/check_for_file?filename={{filename}}&uuid={{uuid}}&platform={{platform}}');
|
||||
}, 5000); // 5000 milliseconds = 5 seconds
|
||||
}, 30000); // 20000 milliseconds = 20 seconds
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
</html>
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -1,4 +1,5 @@
|
||||
django
|
||||
requests
|
||||
pillow
|
||||
gunicorn
|
||||
gunicorn
|
||||
pyzipper
|
||||
71
setup.md
71
setup.md
@@ -1,4 +1,57 @@
|
||||
## To fully host the client generator yourself, you will need to following:
|
||||
## Host the rdgen server with docker
|
||||
|
||||
1. First you will need to fork this repo on github
|
||||
2. Next, setup a A Github fine-grained access token with permissions for your rdgen
|
||||
repository:
|
||||
* login to your github account
|
||||
* click on your profile picture at the top right, click Settings
|
||||
* at the bottom of the left panel, click Developer Settings
|
||||
* click Personal access tokens
|
||||
* click Fine-grained tokens
|
||||
* click Generate new token
|
||||
* give a token name, change expiration to whatever you want
|
||||
* under Repository access, select Only select repositories, then pick your
|
||||
rdgen repo
|
||||
* give Read and Write access to actions and workflows
|
||||
* You might have to go to: https://github.com/USERNAME/rdgen/actions and hit green Enable Actions button so it works.
|
||||
3. Next, login to your Github account, go to your rdgen repo page (https://github.com/USERNAME/rdgen)
|
||||
* Click on Settings
|
||||
* In the left pane, click on Secrets and variables, then click Actions
|
||||
* Now click New repository secret
|
||||
* Set the Name to GENURL
|
||||
* Set the Secret to https://rdgen.hostname.com (or whatever your server will be accessed from)
|
||||
* Now click New repository secret again
|
||||
* Set the Name to ZIP_PASSWORD
|
||||
* Set the Secret to any password you want (use this in the next step as well) - generate a password by running: ```python3 -c 'import secrets; print(secrets.token_hex(100))'```
|
||||
4. Now download the docker-compose.yml file and fill in the environment variables:
|
||||
* SECRET_KEY="your secret key" - generate a secret key by running: ```python3 -c 'import secrets; print(secrets.token_hex(100))'```
|
||||
* GHUSER="your github username"
|
||||
* GHBEARER="your fine-grained access token"
|
||||
* ZIP_PASSWORD="the same password that you entered as a github secret"
|
||||
* PROTOCOL="https" *optional - defaults to "https", change to "http" if you need to
|
||||
* REPONAME="rdgen" *optional - defaults to "rdgen", change this if you renamed the repo when you forked it
|
||||
5. Now just run ```docker compose up -d```
|
||||
|
||||
|
||||
## Use a self hosted github runner for faster client generation (Windows only right now)
|
||||
|
||||
1. First you need to set up a Windows computer that can build rustdesk
|
||||
2. Once you can build rustdesk, follow github instructions for setting up a self hosted github runner
|
||||
3. Now you need to add an environment variable SH_SECRET, which has a key/password that you will need to send to the server
|
||||
4. Save a json configuration file from your rdgen web ui
|
||||
5. Use the [rdgen-cli] (https://github.com/AlekseyLapunov/rdgen-cli) to submit your json configuration with the added key "sh_secret_field" with the value matching your SH_SECRET
|
||||
|
||||
## Use your own Windows code signing token
|
||||
|
||||
1. You will need a USB signing token plugged into a Windows computer
|
||||
2. On the computer with the USB signing token, you need to make sure it is set up correctly to sign using signtool.exe
|
||||
3. Run a small [signing api](https://github.com/bryangerlach/signing_api) server on the computer with the USB token connected. Follow the setup instructions for this server.
|
||||
4. Now for your rdgen repo, add github secrets for
|
||||
- SIGN_BASE_URL (the accesible over the internet URL for the signing api server)
|
||||
- SIGN_API_KEY (the api key you have set on your signing api server)
|
||||
|
||||
|
||||
## Host manually:
|
||||
|
||||
1. A Github account with a fork of this repo
|
||||
2. A Github fine-grained access token with permissions for your rdgen
|
||||
@@ -24,20 +77,6 @@
|
||||
* GENURL="example.com:8000" *this is the domain and port that you are
|
||||
running rdgen on, needs to be accessible on the internet, depending
|
||||
on how you have this setup the port may not be needed
|
||||
* optional github secrets (for signing the code):
|
||||
* WINDOWS_PFX_BASE64
|
||||
* WINDOWS_PFX_PASSWORD
|
||||
* WINDOWS_PFX_SHA1_THUMBPRINT
|
||||
|
||||
|
||||
## A few notes:
|
||||
|
||||
* If you change your repository name, make sure to change the url on lines
|
||||
172-203 of views.py to reflect the change
|
||||
* If you are running on http instead of https, make sure to make the change on
|
||||
line 75 of views.py
|
||||
|
||||
## To run rdgen on your server without docker:
|
||||
|
||||
```
|
||||
# Open to the directory you want to install rdgen (change /opt to wherever you want)
|
||||
@@ -69,7 +108,7 @@ open your web browser to yourdomain:8000
|
||||
|
||||
use nginx, caddy, traefik, etc. for ssl reverse proxy
|
||||
|
||||
## To autostart the server on boot, you can set up a systemd service called rdgen.service
|
||||
### To autostart the server on boot, you can set up a systemd service called rdgen.service
|
||||
|
||||
replace user, group, and port if you need to replace /opt with wherever you
|
||||
have installed rdgen save the following file as
|
||||
|
||||
Reference in New Issue
Block a user