diff --git a/Agent/Services/AppLauncherLinux.cs b/Agent/Services/AppLauncherLinux.cs
index 0f04ebcd0..23637e07d 100644
--- a/Agent/Services/AppLauncherLinux.cs
+++ b/Agent/Services/AppLauncherLinux.cs
@@ -126,13 +126,26 @@ private int StartLinuxDesktopApp(string args)
{
try
{
- var whoLine = whoString
- .Split('\n', StringSplitOptions.RemoveEmptyEntries)
- .First();
-
- var whoSplit = whoLine.Split(' ', StringSplitOptions.RemoveEmptyEntries);
- username = whoSplit[0];
- display = whoSplit.Last().TrimStart('(').TrimEnd(')');
+ var whoLines = whoString
+ .Split('\n', StringSplitOptions.RemoveEmptyEntries);
+
+ for(int i = 0; i < whoLines.Length; i++)
+ {
+ var whoLine = whoLines[i];
+ var whoSplit = whoLine.Split(' ', StringSplitOptions.RemoveEmptyEntries);
+
+ username = whoSplit[0];
+ Logger.Write($"split last: {whoSplit.Last()}");
+
+ display = whoSplit.Last().TrimStart('(').TrimEnd(')');
+ Logger.Write($"display: {display}");
+
+ if(display.Length >0 && display[0] == ':')
+ {
+ break;
+ }
+
+ }
xauthority = $"/home/{username}/.Xauthority";
args = $"-u {username} {args}";
}
diff --git a/Desktop.XPlat/Native/Linux/LibX11_32.cs b/Desktop.XPlat/Native/Linux/LibX11_32.cs
new file mode 100644
index 000000000..fd369db79
--- /dev/null
+++ b/Desktop.XPlat/Native/Linux/LibX11_32.cs
@@ -0,0 +1,38 @@
+/*
+
+Copyright 1985, 1986, 1987, 1991, 1998 The Open Group
+
+Permission to use, copy, modify, distribute, and sell this software and its
+documentation for any purpose is hereby granted without fee, provided that
+the above copyright notice appear in all copies and that both that
+copyright notice and this permission notice appear in supporting
+documentation.
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+Except as contained in this notice, the name of The Open Group shall not be
+used in advertising or otherwise to promote the sale, use or other dealings
+in this Software without prior written authorization from The Open Group.
+
+*/
+
+using System;
+using System.Runtime.InteropServices;
+
+namespace Remotely.Desktop.XPlat.Native.Linux
+{
+ public static unsafe class LibX11_32
+ {
+
+ [DllImport("libX11")]
+ public static extern IntPtr XGetImage(IntPtr display, IntPtr drawable, int x, int y, int width, int height, uint plane_mask, int format);
+ }
+}
diff --git a/Desktop.XPlat/Native/Linux/LibXtst_32.cs b/Desktop.XPlat/Native/Linux/LibXtst_32.cs
new file mode 100644
index 000000000..5c2cb2135
--- /dev/null
+++ b/Desktop.XPlat/Native/Linux/LibXtst_32.cs
@@ -0,0 +1,15 @@
+using System;
+using System.Runtime.InteropServices;
+
+namespace Remotely.Desktop.XPlat.Native.Linux
+{
+ public class LibXtst_32
+ {
+ [DllImport("libXtst")]
+ public static extern void XTestFakeKeyEvent(IntPtr display, uint keycode, bool is_press, uint delay);
+ [DllImport("libXtst")]
+ public static extern void XTestFakeButtonEvent(IntPtr display, uint button, bool is_press, uint delay);
+ [DllImport("libXtst")]
+ public static extern void XTestFakeMotionEvent(IntPtr display, int screen_number, int x, int y, uint delay);
+ }
+}
diff --git a/Desktop.XPlat/Properties/PublishProfiles/desktop-linux-arm.pubxml b/Desktop.XPlat/Properties/PublishProfiles/desktop-linux-arm.pubxml
new file mode 100644
index 000000000..9ad02ee4f
--- /dev/null
+++ b/Desktop.XPlat/Properties/PublishProfiles/desktop-linux-arm.pubxml
@@ -0,0 +1,19 @@
+
+
+
+
+ FileSystem
+ Release
+ arm
+ net6.0
+ ..\Server\wwwroot\Content\Linux-arm\
+ linux-arm
+ true
+ True
+ False
+ true
+ true
+
+
\ No newline at end of file
diff --git a/Desktop.XPlat/Properties/PublishProfiles/packaged-linux-arm.pubxml b/Desktop.XPlat/Properties/PublishProfiles/packaged-linux-arm.pubxml
new file mode 100644
index 000000000..94d882739
--- /dev/null
+++ b/Desktop.XPlat/Properties/PublishProfiles/packaged-linux-arm.pubxml
@@ -0,0 +1,17 @@
+
+
+
+
+ FileSystem
+ Release
+ arm
+ net6.0
+ ..\Agent\bin\Release\net6.0\linux-arm\publish\Desktop
+ linux-arm
+ true
+ False
+ False
+
+
\ No newline at end of file
diff --git a/Desktop.XPlat/Services/KeyboardMouseInputLinux.cs b/Desktop.XPlat/Services/KeyboardMouseInputLinux.cs
index 86f6046db..65bb2f6cc 100644
--- a/Desktop.XPlat/Services/KeyboardMouseInputLinux.cs
+++ b/Desktop.XPlat/Services/KeyboardMouseInputLinux.cs
@@ -32,7 +32,13 @@ public void SendKeyDown(string key)
}
var keyCode = LibX11.XKeysymToKeycode(Display, keySim);
- LibXtst.XTestFakeKeyEvent(Display, keyCode, true, 0);
+ if(EnvironmentHelper.Is64)
+ {
+ LibXtst.XTestFakeKeyEvent(Display, keyCode, true, 0);
+ }
+ else{
+ LibXtst_32.XTestFakeKeyEvent(Display, keyCode, true, 0);
+ }
LibX11.XSync(Display, false);
}
catch (Exception ex)
@@ -55,7 +61,13 @@ public void SendKeyUp(string key)
}
var keyCode = LibX11.XKeysymToKeycode(Display, keySim);
- LibXtst.XTestFakeKeyEvent(Display, keyCode, false, 0);
+ if(EnvironmentHelper.Is64)
+ {
+ LibXtst.XTestFakeKeyEvent(Display, keyCode, false, 0);
+ }
+ else{
+ LibXtst_32.XTestFakeKeyEvent(Display, keyCode, false, 0);
+ }
LibX11.XSync(Display, false);
}
catch (Exception ex)
@@ -75,8 +87,14 @@ public void SendMouseButtonAction(int button, ButtonAction buttonAction, double
var mouseButton = (uint)(button + 1);
InitDisplay();
- SendMouseMove(percentX, percentY, viewer);
- LibXtst.XTestFakeButtonEvent(Display, mouseButton, isPressed, 0);
+ SendMouseMove(percentX, percentY, viewer);
+ if(EnvironmentHelper.Is64)
+ {
+ LibXtst.XTestFakeButtonEvent(Display, mouseButton, isPressed, 0);
+ }
+ else{
+ LibXtst_32.XTestFakeButtonEvent(Display, mouseButton, isPressed, 0);
+ }
LibX11.XSync(Display, false);
}
catch (Exception ex)
@@ -92,11 +110,22 @@ public void SendMouseMove(double percentX, double percentY, Viewer viewer)
InitDisplay();
var screenBounds = viewer.Capturer.CurrentScreenBounds;
- LibXtst.XTestFakeMotionEvent(Display,
- LibX11.XDefaultScreen(Display),
- screenBounds.X + (int)(screenBounds.Width * percentX),
- screenBounds.Y + (int)(screenBounds.Height * percentY),
+ if(EnvironmentHelper.Is64)
+ {
+ LibXtst.XTestFakeMotionEvent(Display,
+ LibX11.XDefaultScreen(Display),
+ screenBounds.X + (int)(screenBounds.Width * percentX),
+ screenBounds.Y + (int)(screenBounds.Height * percentY),
+ 0);
+ }
+ else{
+ LibXtst_32.XTestFakeMotionEvent(Display,
+ LibX11.XDefaultScreen(Display),
+ screenBounds.X + (int)(screenBounds.Width * percentX),
+ screenBounds.Y + (int)(screenBounds.Height * percentY),
0);
+ }
+
LibX11.XSync(Display, false);
}
catch (Exception ex)
@@ -114,11 +143,27 @@ public void SendMouseWheel(int deltaY)
{
LibXtst.XTestFakeButtonEvent(Display, 4, true, 0);
LibXtst.XTestFakeButtonEvent(Display, 4, false, 0);
+ if(EnvironmentHelper.Is64)
+ {
+ LibXtst.XTestFakeButtonEvent(Display, 4, true, 0);
+ LibXtst.XTestFakeButtonEvent(Display, 4, false, 0);
+ }
+ else{
+ LibXtst_32.XTestFakeButtonEvent(Display, 4, true, 0);
+ LibXtst_32.XTestFakeButtonEvent(Display, 4, false, 0);
+ }
}
else
{
- LibXtst.XTestFakeButtonEvent(Display, 5, true, 0);
- LibXtst.XTestFakeButtonEvent(Display, 5, false, 0);
+ if(EnvironmentHelper.Is64)
+ {
+ LibXtst.XTestFakeButtonEvent(Display, 5, true, 0);
+ LibXtst.XTestFakeButtonEvent(Display, 5, false, 0);
+ }
+ else{
+ LibXtst_32.XTestFakeButtonEvent(Display, 5, true, 0);
+ LibXtst_32.XTestFakeButtonEvent(Display, 5, false, 0);
+ }
}
LibX11.XSync(Display, false);
}
@@ -134,7 +179,13 @@ public void SendRightMouseDown(double percentX, double percentY, Viewer viewer)
{
InitDisplay();
SendMouseMove(percentX, percentY, viewer);
- LibXtst.XTestFakeButtonEvent(Display, 3, true, 0);
+ if(EnvironmentHelper.Is64)
+ {
+ LibXtst.XTestFakeButtonEvent(Display, 3, true, 0);
+ }
+ else{
+ LibXtst_32.XTestFakeButtonEvent(Display, 3, true, 0);
+ }
LibX11.XSync(Display, false);
}
catch (Exception ex)
@@ -149,7 +200,13 @@ public void SendRightMouseUp(double percentX, double percentY, Viewer viewer)
{
InitDisplay();
SendMouseMove(percentX, percentY, viewer);
- LibXtst.XTestFakeButtonEvent(Display, 3, false, 0);
+ if(EnvironmentHelper.Is64)
+ {
+ LibXtst.XTestFakeButtonEvent(Display, 3, false, 0);
+ }
+ else{
+ LibXtst_32.XTestFakeButtonEvent(Display, 3, false, 0);
+ }
LibX11.XSync(Display, false);
}
catch (Exception ex)
diff --git a/Desktop.XPlat/Services/ScreenCapturerLinux.cs b/Desktop.XPlat/Services/ScreenCapturerLinux.cs
index 0adb07155..a46329469 100644
--- a/Desktop.XPlat/Services/ScreenCapturerLinux.cs
+++ b/Desktop.XPlat/Services/ScreenCapturerLinux.cs
@@ -146,14 +146,35 @@ private Bitmap GetX11Capture()
var window = LibX11.XDefaultRootWindow(Display);
- var imagePointer = LibX11.XGetImage(Display,
- window,
- CurrentScreenBounds.X,
- CurrentScreenBounds.Y,
- CurrentScreenBounds.Width,
- CurrentScreenBounds.Height,
- ~0,
- 2);
+ IntPtr imagePointer = IntPtr.Zero;
+
+ if(EnvironmentHelper.Is64)
+ {
+ imagePointer = LibX11.XGetImage(Display,
+ window,
+ CurrentScreenBounds.X,
+ CurrentScreenBounds.Y,
+ CurrentScreenBounds.Width,
+ CurrentScreenBounds.Height,
+ ~0,
+ 2);
+ }
+ else
+ {
+ imagePointer = LibX11_32.XGetImage(Display,
+ window,
+ CurrentScreenBounds.X,
+ CurrentScreenBounds.Y,
+ CurrentScreenBounds.Width,
+ CurrentScreenBounds.Height,
+ 0xffffffff,
+ 2);
+ }
+
+ if(imagePointer == IntPtr.Zero)
+ {
+ Logger.Write($"libX11 XGetImage error");
+ }
var image = Marshal.PtrToStructure(imagePointer);
diff --git a/Server.Installer/Models/WebServerType.cs b/Server.Installer/Models/WebServerType.cs
index e7ad4db3a..309c5bdd6 100644
--- a/Server.Installer/Models/WebServerType.cs
+++ b/Server.Installer/Models/WebServerType.cs
@@ -14,6 +14,7 @@ public enum WebServerType
UbuntuNginx,
CentOsCaddy,
CentOsNginx,
- IisWindows
+ IisWindows,
+ LinuxNginx
}
}
diff --git a/Server.Installer/Program.cs b/Server.Installer/Program.cs
index ca418323d..145fe0ffa 100644
--- a/Server.Installer/Program.cs
+++ b/Server.Installer/Program.cs
@@ -103,7 +103,8 @@ public static async Task Main(string[] args)
"Nginx on Ubuntu",
"Caddy on CentOS",
"Nginx on CentOS",
- "IIS on Windows Server 2016+");
+ "IIS on Windows Server 2016+",
+ "Nginx on linux-arm");
if (Enum.TryParse(webServerType, out var result))
{
diff --git a/Server.Installer/Resources/LinuxArm_Nginx_Install.sh b/Server.Installer/Resources/LinuxArm_Nginx_Install.sh
new file mode 100644
index 000000000..d811fc23e
--- /dev/null
+++ b/Server.Installer/Resources/LinuxArm_Nginx_Install.sh
@@ -0,0 +1,169 @@
+#!/bin/bash
+echo "Thanks for trying Remotely!"
+echo
+
+Args=( "$@" )
+ArgLength=${#Args[@]}
+
+for (( i=0; i<${ArgLength}; i+=2 ));
+do
+ if [ "${Args[$i]}" = "--host" ]; then
+ HostName="${Args[$i+1]}"
+ elif [ "${Args[$i]}" = "--approot" ]; then
+ AppRoot="${Args[$i+1]}"
+ fi
+done
+
+if [ -z "$AppRoot" ]; then
+ read -p "Enter path where the Remotely server files should be installed (typically /var/www/remotely): " AppRoot
+ if [ -z "$AppRoot" ]; then
+ AppRoot="/var/www/remotely"
+ fi
+fi
+
+if [ -z "$HostName" ]; then
+ read -p "Enter server host (e.g. remotely.yourdomainname.com): " HostName
+fi
+
+chmod +x "$AppRoot/Remotely_Server"
+
+echo "Using $AppRoot as the Remotely website's content directory."
+
+UbuntuVersion=$(lsb_release -r -s)
+
+apt-get -y install curl
+apt-get -y install software-properties-common
+apt-get -y install gnupg
+
+# Install .NET Core Runtime.
+# Install .NET Core Runtime.
+curl -sSL https://dot.net/v1/dotnet-install.sh | bash /dev/stdin -c 6.0
+echo 'export DOTNET_ROOT=$HOME/.dotnet' >> ~/.bashrc
+echo 'export PATH=$PATH:$HOME/.dotnet' >> ~/.bashrc
+source ~/.bashrc
+
+# Install other prerequisites.
+apt-get -y install unzip
+apt-get -y install acl
+apt-get -y install libc6-dev
+apt-get -y install libgdiplus
+
+
+# Set permissions on Remotely files.
+setfacl -R -m u:www-data:rwx $AppRoot
+chown -R "$USER":www-data $AppRoot
+chmod +x "$AppRoot/Remotely_Server"
+
+
+# Install Nginx
+apt-get update
+apt-get -y install nginx
+
+systemctl start nginx
+
+
+# Configure Nginx
+nginxConfig="
+
+server {
+ listen 80;
+ server_name $HostName *.$HostName;
+ location / {
+ proxy_pass http://localhost:5000;
+ proxy_http_version 1.1;
+ proxy_set_header Upgrade \$http_upgrade;
+ proxy_set_header Connection keep-alive;
+ proxy_set_header Host \$host;
+ proxy_cache_bypass \$http_upgrade;
+ proxy_set_header X-Forwarded-For \$proxy_add_x_forwarded_for;
+ proxy_set_header X-Forwarded-Proto \$scheme;
+ }
+
+ location /_blazor {
+ proxy_pass http://localhost:5000;
+ proxy_http_version 1.1;
+ proxy_set_header Upgrade \$http_upgrade;
+ proxy_set_header Connection \"upgrade\";
+ proxy_set_header Host \$host;
+ proxy_cache_bypass \$http_upgrade;
+ proxy_set_header X-Forwarded-For \$proxy_add_x_forwarded_for;
+ proxy_set_header X-Forwarded-Proto \$scheme;
+ }
+ location /AgentHub {
+ proxy_pass http://localhost:5000;
+ proxy_http_version 1.1;
+ proxy_set_header Upgrade \$http_upgrade;
+ proxy_set_header Connection \"upgrade\";
+ proxy_set_header Host \$host;
+ proxy_cache_bypass \$http_upgrade;
+ proxy_set_header X-Forwarded-For \$proxy_add_x_forwarded_for;
+ proxy_set_header X-Forwarded-Proto \$scheme;
+ }
+ location /ViewerHub {
+ proxy_pass http://localhost:5000;
+ proxy_http_version 1.1;
+ proxy_set_header Upgrade \$http_upgrade;
+ proxy_set_header Connection \"upgrade\";
+ proxy_set_header Host \$host;
+ proxy_cache_bypass \$http_upgrade;
+ proxy_set_header X-Forwarded-For \$proxy_add_x_forwarded_for;
+ proxy_set_header X-Forwarded-Proto \$scheme;
+ }
+ location /CasterHub {
+ proxy_pass http://localhost:5000;
+ proxy_http_version 1.1;
+ proxy_set_header Upgrade \$http_upgrade;
+ proxy_set_header Connection \"upgrade\";
+ proxy_set_header Host \$host;
+ proxy_cache_bypass \$http_upgrade;
+ proxy_set_header X-Forwarded-For \$proxy_add_x_forwarded_for;
+ proxy_set_header X-Forwarded-Proto \$scheme;
+ }
+}"
+
+echo "$nginxConfig" > /etc/nginx/sites-available/remotely
+
+ln -s /etc/nginx/sites-available/remotely /etc/nginx/sites-enabled/remotely
+
+# Test config.
+nginx -t
+
+# Reload.
+nginx -s reload
+
+
+
+
+# Create service.
+
+serviceConfig="[Unit]
+Description=Remotely Server
+
+[Service]
+WorkingDirectory=$AppRoot
+ExecStart=/home/pi/.dotnet/dotnet $AppRoot/Remotely_Server.dll
+Restart=always
+# Restart service after 10 seconds if the dotnet service crashes:
+RestartSec=10
+SyslogIdentifier=remotely
+User=www-data
+Environment=ASPNETCORE_ENVIRONMENT=Production
+Environment=DOTNET_PRINT_TELEMETRY_MESSAGE=false
+
+[Install]
+WantedBy=multi-user.target"
+
+echo "$serviceConfig" > /etc/systemd/system/remotely.service
+
+chown -R www-data:www-data /var/www/remotely
+
+# Enable service.
+systemctl enable remotely.service
+# Start service.
+systemctl restart remotely.service
+
+
+# Install Certbot and get SSL cert.
+apt-get -y install certbot python3-certbot-nginx
+
+certbot --nginx
\ No newline at end of file
diff --git a/Server.Installer/Services/ServerInstaller.cs b/Server.Installer/Services/ServerInstaller.cs
index 5540530a7..b3073cfe7 100644
--- a/Server.Installer/Services/ServerInstaller.cs
+++ b/Server.Installer/Services/ServerInstaller.cs
@@ -136,6 +136,7 @@ private async Task LaunchExternalInstaller(CliParams cliParams)
WebServerType.CentOsCaddy => "CentOS_Caddy_Install.sh",
WebServerType.CentOsNginx => "CentOS_Nginx_Install.sh",
WebServerType.IisWindows => "IIS_Windows_Install.ps1",
+ WebServerType.LinuxNginx => "LinuxArm_Nginx_Install.sh",
_ => throw new Exception("Unrecognized reverse proxy type."),
};
diff --git a/Server/API/ClientDownloadsController.cs b/Server/API/ClientDownloadsController.cs
index 86e51f6fa..9c43b1585 100644
--- a/Server/API/ClientDownloadsController.cs
+++ b/Server/API/ClientDownloadsController.cs
@@ -50,6 +50,11 @@ public async Task GetDesktop(string platformID)
var filePath = Path.Combine(_hostEnv.WebRootPath, "Content", "Linux-x64", "Remotely_Desktop");
return await GetDesktopFile(filePath);
}
+ case "linux-arm":
+ {
+ var filePath = Path.Combine(_hostEnv.WebRootPath, "Content", "Linux-arm", "Remotely_Desktop");
+ return await GetDesktopFile(filePath);
+ }
case "MacOS-x64":
{
var filePath = Path.Combine(_hostEnv.WebRootPath, "Content", "MacOS-x64", "Remotely_Desktop");
@@ -86,6 +91,11 @@ public async Task GetDesktop(string platformId, string organizati
var filePath = Path.Combine(_hostEnv.WebRootPath, "Content", "Linux-x64", "Remotely_Desktop");
return await GetDesktopFile(filePath, organizationId);
}
+ case "linux-arm":
+ {
+ var filePath = Path.Combine(_hostEnv.WebRootPath, "Content", "Linux-arm", "Remotely_Desktop");
+ return await GetDesktopFile(filePath, organizationId);
+ }
case "MacOS-x64":
{
var filePath = Path.Combine(_hostEnv.WebRootPath, "Content", "MacOS-x64", "Remotely_Desktop");
@@ -190,6 +200,12 @@ private async Task GetInstallFile(string organizationId, string p
{
var fileName = "Install-Ubuntu-x64.sh";
+ return await GetBashInstaller(fileName, organizationId);
+ }
+ case "armInstaller":
+ {
+ var fileName = "Install-arm.sh";
+
return await GetBashInstaller(fileName, organizationId);
}
case "MacOSInstaller-x64":
diff --git a/Server/Pages/Downloads.razor b/Server/Pages/Downloads.razor
index 6e7efb13e..dfbc24025 100644
--- a/Server/Pages/Downloads.razor
+++ b/Server/Pages/Downloads.razor
@@ -32,6 +32,12 @@
Ubuntu Executable
+
@*
macOS x64 (10.12 - 10.15)
@@ -176,6 +182,31 @@
+
+
Linux arm-32-Bit
+
+ linux-arm-32bit Bash Installer
+
+ Linux Files Only
+
+
+
Example Install:
+
+
sudo chmod +x [path]/Install-arm.sh
+
sudo [path]/./Install-arm.sh
+
+
+
Example Local Install:
+
+
sudo [path]/Install-arm.sh --path [path]/Remotely-Linux.zip
+
+
+
Uninstall:
+
+
sudo [path]/Install-arm.sh --uninstall
+
+
+
macOS x64 (10.12 - 10.15)
diff --git a/Server/wwwroot/Content/Install-arm.sh b/Server/wwwroot/Content/Install-arm.sh
new file mode 100644
index 000000000..94cda9a52
--- /dev/null
+++ b/Server/wwwroot/Content/Install-arm.sh
@@ -0,0 +1,114 @@
+#!/bin/bash
+HostName=
+Organization=
+GUID=$(cat /proc/sys/kernel/random/uuid)
+UpdatePackagePath=""
+
+
+Args=( "$@" )
+ArgLength=${#Args[@]}
+
+for (( i=0; i<${ArgLength}; i+=2 ));
+do
+ if [ "${Args[$i]}" = "--uninstall" ]; then
+ systemctl stop remotely-agent
+ rm -r -f /usr/local/bin/Remotely
+ rm -f /etc/systemd/system/remotely-agent.service
+ systemctl daemon-reload
+ exit
+ elif [ "${Args[$i]}" = "--path" ]; then
+ UpdatePackagePath="${Args[$i+1]}"
+ fi
+done
+
+UbuntuVersion=$(lsb_release -r -s)
+
+# Install .NET Core Runtime.
+curl -sSL https://dot.net/v1/dotnet-install.sh | bash /dev/stdin -c 6.0
+echo 'export DOTNET_ROOT=$HOME/.dotnet' >> ~/.bashrc
+echo 'export PATH=$PATH:$HOME/.dotnet' >> ~/.bashrc
+source ~/.bashrc
+
+apt-get -y install libx11-dev
+apt-get -y install libxrandr-dev
+apt-get -y install unzip
+apt-get -y install libc6-dev
+apt-get -y install libgdiplus
+apt-get -y install libxtst-dev
+apt-get -y install xclip
+apt-get -y install jq
+apt-get -y install curl
+
+sudo curl -fsSL https://deb.nodesource.com/setup_17.x | bash -
+sudo apt install nodejs
+
+if [ -f "/usr/local/bin/Remotely/ConnectionInfo.json" ]; then
+ SavedGUID=`cat "/usr/local/bin/Remotely/ConnectionInfo.json" | jq -r '.DeviceID'`
+ if [[ "$SavedGUID" != "null" && -n "$SavedGUID" ]]; then
+ GUID="$SavedGUID"
+ fi
+fi
+
+rm -r -f /usr/local/bin/Remotely
+rm -f /etc/systemd/system/remotely-agent.service
+
+mkdir -p /usr/local/bin/Remotely/
+cd /usr/local/bin/Remotely/
+
+if [ -z "$UpdatePackagePath" ]; then
+ echo "Downloading client..." >> /tmp/Remotely_Install.log
+ wget $HostName/Content/Remotely-Linux-arm.zip
+else
+ echo "Copying install files..." >> /tmp/Remotely_Install.log
+ cp "$UpdatePackagePath" /usr/local/bin/Remotely/Remotely-Linux-arm.zip
+ rm -f "$UpdatePackagePath"
+fi
+
+unzip ./Remotely-Linux-arm.zip
+rm -f ./Remotely-Linux-arm.zip
+chmod +x ./Remotely_Agent
+chmod +x ./Desktop/Remotely_Desktop
+
+
+connectionInfo="{
+ \"DeviceID\":\"$GUID\",
+ \"Host\":\"$HostName\",
+ \"OrganizationID\": \"$Organization\",
+ \"ServerVerificationToken\":\"\"
+}"
+
+echo "$connectionInfo" > ./ConnectionInfo.json
+
+runtimeOptions="{
+ \"runtimeOptions\": {
+ \"configProperties\": {
+ \"System.Drawing.EnableUnixSupport\": true
+ }
+ }
+}"
+
+echo "$runtimeOptions" > ./Desktop/Remotely_Desktop.runtimeconfig.json
+
+curl --head $HostName/Content/Remotely-Linux.zip | grep -i "etag" | cut -d' ' -f 2 > ./etag.txt
+
+echo Creating service... >> /tmp/Remotely_Install.log
+
+serviceConfig="[Unit]
+Description=The Remotely agent used for remote access.
+
+[Service]
+WorkingDirectory=/usr/local/bin/Remotely/
+ExecStart=/usr/local/bin/Remotely/Remotely_Agent
+Restart=always
+StartLimitIntervalSec=0
+RestartSec=10
+
+[Install]
+WantedBy=graphical.target"
+
+echo "$serviceConfig" > /etc/systemd/system/remotely-agent.service
+
+systemctl enable remotely-agent
+systemctl restart remotely-agent
+
+echo Install complete. >> /tmp/Remotely_Install.log
diff --git a/Shared/Utilities/EnvironmentHelper.cs b/Shared/Utilities/EnvironmentHelper.cs
index 66379c020..6ff1ce84f 100644
--- a/Shared/Utilities/EnvironmentHelper.cs
+++ b/Shared/Utilities/EnvironmentHelper.cs
@@ -60,6 +60,8 @@ public static bool IsDebug
public static bool IsWindows => OperatingSystem.IsWindows();
+ public static bool Is64 => Environment.Is64BitProcess;
+
public static Platform Platform
{
get
diff --git a/Utilities/Publish.ps1 b/Utilities/Publish.ps1
index 74c7a584a..ceb39797e 100644
--- a/Utilities/Publish.ps1
+++ b/Utilities/Publish.ps1
@@ -116,23 +116,30 @@ if ((Test-Path -Path "$Root\Agent\bin\Release\net6.0\win10-x86\publish" ) -eq $
if ((Test-Path -Path "$Root\Agent\bin\Release\net6.0\linux-x64\publish") -eq $true) {
Get-ChildItem -Path "$Root\Agent\bin\Release\net6.0\linux-x64\publish" | Remove-Item -Force -Recurse
}
+if ((Test-Path -Path "$Root\Agent\bin\Release\net6.0\linux-arm\publish") -eq $true) {
+ Get-ChildItem -Path "$Root\Agent\bin\Release\net6.0\linux-arm\publish" | Remove-Item -Force -Recurse
+}
# Publish Core clients.
dotnet publish /p:Version=$CurrentVersion /p:FileVersion=$CurrentVersion --runtime win10-x64 --self-contained --configuration Release --output "$Root\Agent\bin\Release\net6.0\win10-x64\publish" "$Root\Agent"
dotnet publish /p:Version=$CurrentVersion /p:FileVersion=$CurrentVersion --runtime linux-x64 --self-contained --configuration Release --output "$Root\Agent\bin\Release\net6.0\linux-x64\publish" "$Root\Agent"
dotnet publish /p:Version=$CurrentVersion /p:FileVersion=$CurrentVersion --runtime win10-x86 --self-contained --configuration Release --output "$Root\Agent\bin\Release\net6.0\win10-x86\publish" "$Root\Agent"
+dotnet publish /p:Version=$CurrentVersion /p:FileVersion=$CurrentVersion --runtime linux-arm --self-contained --configuration Release --output "$Root\Agent\bin\Release\net6.0\linux-arm\publish" "$Root\Agent"
New-Item -Path "$Root\Agent\bin\Release\net6.0\win10-x64\publish\Desktop\" -ItemType Directory -Force
New-Item -Path "$Root\Agent\bin\Release\net6.0\win10-x86\publish\Desktop\" -ItemType Directory -Force
New-Item -Path "$Root\Agent\bin\Release\net6.0\linux-x64\publish\Desktop\" -ItemType Directory -Force
+New-Item -Path "$Root\Agent\bin\Release\net6.0\linux-arm\publish\Desktop\" -ItemType Directory -Force
# Publish Linux ScreenCaster
dotnet publish /p:Version=$CurrentVersion /p:FileVersion=$CurrentVersion -p:PublishProfile=packaged-linux-x64 --configuration Release "$Root\Desktop.XPlat\"
+dotnet publish /p:Version=$CurrentVersion /p:FileVersion=$CurrentVersion -p:PublishProfile=packaged-linux-arm --configuration Release "$Root\Desktop.XPlat\"
# Publish Linux GUI App
dotnet publish /p:Version=$CurrentVersion /p:FileVersion=$CurrentVersion -p:PublishProfile=desktop-linux-x64 --configuration Release "$Root\Desktop.XPlat\"
+dotnet publish /p:Version=$CurrentVersion /p:FileVersion=$CurrentVersion -p:PublishProfile=desktop-linux-arm --configuration Release "$Root\Desktop.XPlat\"
# Publish Windows ScreenCaster (32-bit)
@@ -159,7 +166,7 @@ if ($SignAssemblies) {
&"$Root\Utilities\signtool.exe" sign /f "$CertificatePath" /p $CertificatePassword /t http://timestamp.digicert.com "$Root\Server\wwwroot\Content\Win-x86\Remotely_Desktop.exe"
}
-# Build installer.
+# Build installer (Windows).
&"$MSBuildPath" "$Root\Agent.Installer.Win" /t:Restore
&"$MSBuildPath" "$Root\Agent.Installer.Win" /t:Build /p:Configuration=Release /p:Platform=AnyCPU /p:Version=$CurrentVersion /p:FileVersion=$CurrentVersion
Copy-Item -Path "$Root\Agent.Installer.Win\bin\Release\Remotely_Installer.exe" -Destination "$Root\Server\wwwroot\Content\Remotely_Installer.exe" -Force
@@ -189,6 +196,13 @@ while ((Test-Path -Path "$PublishDir\Remotely-Linux.zip") -eq $false){
}
Move-Item -Path "$PublishDir\Remotely-Linux.zip" -Destination "$Root\Server\wwwroot\Content\Remotely-Linux.zip" -Force
+$PublishDir = "$Root\Agent\bin\Release\net6.0\linux-arm\publish"
+Compress-Archive -Path "$PublishDir\*" -DestinationPath "$PublishDir\Remotely-Linux-arm.zip" -Force
+while ((Test-Path -Path "$PublishDir\Remotely-Linux-arm.zip") -eq $false){
+ Start-Sleep -Seconds 1
+}
+Move-Item -Path "$PublishDir\Remotely-Linux-arm.zip" -Destination "$Root\Server\wwwroot\Content\Remotely-Linux-arm.zip" -Force
+
if ($RID.Length -gt 0 -and $OutDir.Length -gt 0) {