From 0df0505775424cce8c7f8f9a0897bb5c24d1567a Mon Sep 17 00:00:00 2001 From: Jared Goodwin Date: Wed, 21 Apr 2021 08:28:18 -0700 Subject: [PATCH 01/22] Begin building Mac services in Agent project. --- .gitignore | 1 + Agent/Program.cs | 6 +- Agent/Services/AppLauncherLinux.cs | 29 +++-- Agent/Services/AppLauncherMac.cs | 25 ++++ Agent/Services/ConfigService.cs | 2 +- .../Services/DeviceInformationServiceBase.cs | 1 + .../Services/DeviceInformationServiceLinux.cs | 11 +- Agent/Services/DeviceInformationServiceMac.cs | 115 ++++++++++++++++++ Agent/Services/UpdaterMac.cs | 23 ++++ Shared/Services/ProcessLauncher.cs | 37 ++++++ Shared/Utilities/EnvironmentHelper.cs | 58 +++------ 11 files changed, 249 insertions(+), 59 deletions(-) create mode 100644 Agent/Services/AppLauncherMac.cs create mode 100644 Agent/Services/DeviceInformationServiceMac.cs create mode 100644 Agent/Services/UpdaterMac.cs create mode 100644 Shared/Services/ProcessLauncher.cs diff --git a/.gitignore b/.gitignore index 75b00b93e..adba666ac 100644 --- a/.gitignore +++ b/.gitignore @@ -291,3 +291,4 @@ Server/wwwroot/Content/Win-x86/* Server/.config/dotnet-tools.json /Server/Properties/ServiceDependencies/* Server.Installer/Properties/launchSettings.json +.DS_Store diff --git a/Agent/Program.cs b/Agent/Program.cs index 5542baa0f..3ede2390c 100644 --- a/Agent/Program.cs +++ b/Agent/Program.cs @@ -4,6 +4,7 @@ using Remotely.Agent.Services; using Remotely.Shared.Enums; using Remotely.Shared.Utilities; +using Remotely.Shared.Services; using System; using System.Diagnostics; using System.IO; @@ -52,6 +53,7 @@ private static void BuildServices() serviceCollection.AddScoped(); serviceCollection.AddScoped(); serviceCollection.AddScoped(); + serviceCollection.AddScoped(); if (EnvironmentHelper.IsWindows) { @@ -67,7 +69,9 @@ private static void BuildServices() } else if (EnvironmentHelper.IsMac) { - // TODO: Mac. + serviceCollection.AddScoped(); + serviceCollection.AddSingleton(); + serviceCollection.AddSingleton(); } else { diff --git a/Agent/Services/AppLauncherLinux.cs b/Agent/Services/AppLauncherLinux.cs index 8e5d3a390..0f04ebcd0 100644 --- a/Agent/Services/AppLauncherLinux.cs +++ b/Agent/Services/AppLauncherLinux.cs @@ -1,6 +1,7 @@ using Microsoft.AspNetCore.SignalR.Client; using Remotely.Agent.Interfaces; using Remotely.Shared.Models; +using Remotely.Shared.Services; using Remotely.Shared.Utilities; using System; using System.Collections.Generic; @@ -15,13 +16,15 @@ namespace Remotely.Agent.Services public class AppLauncherLinux : IAppLauncher { private readonly string _rcBinaryPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Desktop", EnvironmentHelper.DesktopExecutableFileName); + private readonly IProcessInvoker _processInvoker; + private readonly ConnectionInfo _connectionInfo; - public AppLauncherLinux(ConfigService configService) + public AppLauncherLinux(ConfigService configService, IProcessInvoker processInvoker) { - ConnectionInfo = configService.GetConnectionInfo(); + _processInvoker = processInvoker; + _connectionInfo = configService.GetConnectionInfo(); } - private ConnectionInfo ConnectionInfo { get; } public async Task LaunchChatService(string orgName, string requesterID, HubConnection hubConnection) { @@ -43,8 +46,8 @@ await hubConnection.SendAsync("DisplayMessage", $"-mode Chat " + $"-requester \"{requesterID}\" " + $"-organization \"{orgName}\" " + - $"-host \"{ConnectionInfo.Host}\" " + - $"-orgid \"{ConnectionInfo.OrganizationID}\""; + $"-host \"{_connectionInfo.Host}\" " + + $"-orgid \"{_connectionInfo.OrganizationID}\""; return StartLinuxDesktopApp(args); } catch (Exception ex) @@ -76,9 +79,9 @@ await hubConnection.SendAsync("DisplayMessage", $"-mode Unattended " + $"-requester \"{requesterID}\" " + $"-serviceid \"{serviceID}\" " + - $"-deviceid {ConnectionInfo.DeviceID} " + - $"-host \"{ConnectionInfo.Host}\" " + - $"-orgid \"{ConnectionInfo.OrganizationID}\""; + $"-deviceid {_connectionInfo.DeviceID} " + + $"-host \"{_connectionInfo.Host}\" " + + $"-orgid \"{_connectionInfo.OrganizationID}\""; StartLinuxDesktopApp(args); } catch (Exception ex) @@ -96,9 +99,9 @@ public async Task RestartScreenCaster(List viewerIDs, string serviceID, $"-mode Unattended " + $"-requester \"{requesterID}\" " + $"-serviceid \"{serviceID}\" " + - $"-deviceid {ConnectionInfo.DeviceID} " + - $"-host \"{ConnectionInfo.Host}\" " + - $"-orgid \"{ConnectionInfo.OrganizationID}\" " + + $"-deviceid {_connectionInfo.DeviceID} " + + $"-host \"{_connectionInfo.Host}\" " + + $"-orgid \"{_connectionInfo.OrganizationID}\" " + $"-relaunch true " + $"-viewers {string.Join(",", viewerIDs)}"; StartLinuxDesktopApp(args); @@ -116,7 +119,7 @@ private int StartLinuxDesktopApp(string args) var xauthority = GetXorgAuth(); var display = ":0"; - var whoString = EnvironmentHelper.StartProcessWithResults("who", "")?.Trim(); + var whoString = _processInvoker.InvokeProcessOutput("who", "")?.Trim(); var username = ""; if (!string.IsNullOrWhiteSpace(whoString)) @@ -155,7 +158,7 @@ private string GetXorgAuth() { try { - var processes = EnvironmentHelper.StartProcessWithResults("ps", "-eaf")?.Split(Environment.NewLine); + var processes = _processInvoker.InvokeProcessOutput("ps", "-eaf")?.Split(Environment.NewLine); if (processes?.Length > 0) { var xorgLine = processes.FirstOrDefault(x => x.Contains("xorg", StringComparison.OrdinalIgnoreCase)); diff --git a/Agent/Services/AppLauncherMac.cs b/Agent/Services/AppLauncherMac.cs new file mode 100644 index 000000000..cc11855aa --- /dev/null +++ b/Agent/Services/AppLauncherMac.cs @@ -0,0 +1,25 @@ +using System.Collections.Generic; +using System.Threading.Tasks; +using Microsoft.AspNetCore.SignalR.Client; +using Remotely.Agent.Interfaces; + +namespace Remotely.Agent.Services +{ + public class AppLauncherMac : IAppLauncher + { + public async Task LaunchChatService(string orgName, string requesterID, HubConnection hubConnection) + { + return 0; + } + + public async Task LaunchRemoteControl(int targetSessionId, string requesterID, string serviceID, HubConnection hubConnection) + { + + } + + public async Task RestartScreenCaster(List viewerIDs, string serviceID, string requesterID, HubConnection hubConnection, int targetSessionID = -1) + { + + } + } +} diff --git a/Agent/Services/ConfigService.cs b/Agent/Services/ConfigService.cs index ff7ccebb2..653a1c789 100644 --- a/Agent/Services/ConfigService.cs +++ b/Agent/Services/ConfigService.cs @@ -62,7 +62,7 @@ public ConnectionInfo GetConnectionInfo() return new ConnectionInfo() { DeviceID = _debugGuid, - Host = "https://localhost:5001", + Host = "http://localhost:5000", OrganizationID = orgID }; } diff --git a/Agent/Services/DeviceInformationServiceBase.cs b/Agent/Services/DeviceInformationServiceBase.cs index 1d5af63ee..ac01b042d 100644 --- a/Agent/Services/DeviceInformationServiceBase.cs +++ b/Agent/Services/DeviceInformationServiceBase.cs @@ -1,4 +1,5 @@ using Remotely.Shared.Models; +using Remotely.Shared.Services; using Remotely.Shared.Utilities; using System; using System.Collections.Generic; diff --git a/Agent/Services/DeviceInformationServiceLinux.cs b/Agent/Services/DeviceInformationServiceLinux.cs index 7ad696178..33fb0c2fa 100644 --- a/Agent/Services/DeviceInformationServiceLinux.cs +++ b/Agent/Services/DeviceInformationServiceLinux.cs @@ -1,5 +1,6 @@ using Remotely.Agent.Interfaces; using Remotely.Shared.Models; +using Remotely.Shared.Services; using Remotely.Shared.Utilities; using System; using System.Collections.Generic; @@ -11,6 +12,12 @@ namespace Remotely.Agent.Services { public class DeviceInformationServiceLinux : DeviceInformationServiceBase, IDeviceInformationService { + private readonly IProcessInvoker _processInvoker; + + public DeviceInformationServiceLinux(IProcessInvoker processInvoker) + { + _processInvoker = processInvoker; + } public async Task CreateDevice(string deviceId, string orgId) { var device = GetDeviceBase(deviceId, orgId); @@ -40,7 +47,7 @@ public async Task CreateDevice(string deviceId, string orgId) private string GetCurrentUser() { - var users = EnvironmentHelper.StartProcessWithResults("users", ""); + var users = _processInvoker.InvokeProcessOutput("users", ""); return users?.Split()?.FirstOrDefault()?.Trim(); } @@ -48,7 +55,7 @@ private string GetCurrentUser() { try { - var results = EnvironmentHelper.StartProcessWithResults("cat", "/proc/meminfo"); + var results = _processInvoker.InvokeProcessOutput("cat", "/proc/meminfo"); var resultsArr = results.Split("\n".ToCharArray()); var freeKB = resultsArr .FirstOrDefault(x => x.Trim().StartsWith("MemAvailable")) diff --git a/Agent/Services/DeviceInformationServiceMac.cs b/Agent/Services/DeviceInformationServiceMac.cs new file mode 100644 index 000000000..f9b2cd3fa --- /dev/null +++ b/Agent/Services/DeviceInformationServiceMac.cs @@ -0,0 +1,115 @@ +using Remotely.Agent.Interfaces; +using Remotely.Shared.Models; +using Remotely.Shared.Services; +using Remotely.Shared.Utilities; +using Remotely.Shared.Win32; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Remotely.Agent.Services +{ + public class DeviceInformationServiceMac : DeviceInformationServiceBase, IDeviceInformationService + { + private readonly IProcessInvoker _processInvoker; + + public DeviceInformationServiceMac(IProcessInvoker processInvoker) + { + _processInvoker = processInvoker; + } + public async Task CreateDevice(string deviceId, string orgId) + { + var device = GetDeviceBase(deviceId, orgId); + + try + { + + var (usedStorage, totalStorage) = GetSystemDriveInfo(); + var (usedMemory, totalMemory) = GetMemoryInGB(); + + device.CurrentUser = Environment.UserName; + device.Drives = GetAllDrives(); + device.UsedStorage = usedStorage; + device.TotalStorage = totalStorage; + device.UsedMemory = usedMemory; + device.TotalMemory = totalMemory; + device.CpuUtilization = await GetCpuUtilization(); + device.AgentVersion = GetAgentVersion(); + } + catch (Exception ex) + { + Logger.Write(ex, "Error getting device info."); + } + + return device; + } + + public new Task GetCpuUtilization() + { + try + { + var cpuPercentStrings = _processInvoker.InvokeProcessOutput("zsh", "-c \"ps -A -o %cpu\""); + + double cpuPercent = 0; + cpuPercentStrings + .Split(Environment.NewLine) + .ToList() + .ForEach(x => { + if (double.TryParse(x, out var result)) + { + cpuPercent += result; + } + }); + + return Task.FromResult(cpuPercent / Environment.ProcessorCount / 100); + } + catch (Exception ex) + { + Logger.Write(ex, "Error while getting CPU utilization."); + } + + return Task.FromResult((double)0); + } + + public (double usedGB, double totalGB) GetMemoryInGB() + { + try + { + double totalGB = default; + + var totalMemoryString = _processInvoker.InvokeProcessOutput("zsh", "-c \"sysctl -n hw.memsize\""); + if (double.TryParse(totalMemoryString, out var totalMemory)) + { + totalGB = (double)Math.Round(totalMemory / 1024 / 1024 / 1024, 2); + } + + + double usedGB = default; + + var memPercentStrings = _processInvoker.InvokeProcessOutput("zsh", $"-c \"ps -A -o %mem\""); + + double usedMemPercent = 0; + memPercentStrings + .Split(Environment.NewLine) + .ToList() + .ForEach(x => { + if (double.TryParse(x, out var result)) + { + usedMemPercent += result; + } + }); + + usedMemPercent = usedMemPercent / 4 / 100; + usedGB = usedMemPercent * totalGB; + + return (usedGB,totalGB); + } + catch + { + return (0, 0); + } + } + } +} diff --git a/Agent/Services/UpdaterMac.cs b/Agent/Services/UpdaterMac.cs new file mode 100644 index 000000000..3a4cd8c3b --- /dev/null +++ b/Agent/Services/UpdaterMac.cs @@ -0,0 +1,23 @@ +using System.Threading.Tasks; +using Remotely.Agent.Interfaces; + +namespace Remotely.Agent.Services +{ + public class UpdaterMac : IUpdater + { + public async Task BeginChecking() + { + + } + + public async Task CheckForUpdates() + { + + } + + public async Task InstallLatestVersion() + { + + } + } +} diff --git a/Shared/Services/ProcessLauncher.cs b/Shared/Services/ProcessLauncher.cs new file mode 100644 index 000000000..dca50e7c7 --- /dev/null +++ b/Shared/Services/ProcessLauncher.cs @@ -0,0 +1,37 @@ +using System; +using System.Diagnostics; +using Remotely.Shared.Utilities; + +namespace Remotely.Shared.Services +{ + public interface IProcessInvoker + { + string InvokeProcessOutput(string command, string arguments); + } + public class ProcessLauncher : IProcessInvoker + { + public string InvokeProcessOutput(string command, string arguments) + { + try + { + var psi = new ProcessStartInfo(command, arguments) + { + WindowStyle = ProcessWindowStyle.Hidden, + Verb = "RunAs", + UseShellExecute = false, + RedirectStandardOutput = true + }; + + var proc = Process.Start(psi); + proc.WaitForExit(); + + return proc.StandardOutput.ReadToEnd(); + } + catch (Exception ex) + { + Logger.Write(ex, "Failed to start process."); + return string.Empty; + } + } + } +} \ No newline at end of file diff --git a/Shared/Utilities/EnvironmentHelper.cs b/Shared/Utilities/EnvironmentHelper.cs index 6f58ea3e2..0a63475fa 100644 --- a/Shared/Utilities/EnvironmentHelper.cs +++ b/Shared/Utilities/EnvironmentHelper.cs @@ -10,16 +10,16 @@ public static string AgentExecutableFileName { get { - string fileExt = ""; - if (IsWindows) - { - fileExt = "Remotely_Agent.exe"; - } - else if (IsLinux) + switch (Platform) { - fileExt = "Remotely_Agent"; + case Platform.Windows: + return "Remotely_Agent.exe"; + case Platform.Linux: + case Platform.OSX: + return "Remotely_Agent"; + default: + throw new PlatformNotSupportedException(); } - return fileExt; } } @@ -27,17 +27,15 @@ public static string DesktopExecutableFileName { get { - if (IsWindows) - { - return "Remotely_Desktop.exe"; - } - else if (IsLinux) - { - return "Remotely_Desktop"; - } - else + switch (Platform) { - throw new Exception("Unsupported operating system."); + case Platform.Windows: + return "Remotely_Desktop.exe"; + case Platform.Linux: + case Platform.OSX: + return "Remotely_Desktop"; + default: + throw new PlatformNotSupportedException(); } } } @@ -84,29 +82,5 @@ public static Platform Platform } } } - public static string StartProcessWithResults(string command, string arguments) - { - try - { - var psi = new ProcessStartInfo(command, arguments) - { - WindowStyle = ProcessWindowStyle.Hidden, - Verb = "RunAs", - UseShellExecute = false, - RedirectStandardOutput = true - }; - - var proc = Process.Start(psi); - proc.WaitForExit(); - - return proc.StandardOutput.ReadToEnd(); - } - catch (Exception ex) - { - Logger.Write(ex, "Failed to start process."); - return string.Empty; - } - } - } } From c77b857afbbeb80e7845407eb62c56cc5aecd4d6 Mon Sep 17 00:00:00 2001 From: Jared Goodwin Date: Thu, 22 Apr 2021 08:04:44 -0700 Subject: [PATCH 02/22] Add MacOSX install script. --- Server/wwwroot/Content/Install-MacOSX.sh | 94 ++++++++++++++++++++++++ 1 file changed, 94 insertions(+) create mode 100644 Server/wwwroot/Content/Install-MacOSX.sh diff --git a/Server/wwwroot/Content/Install-MacOSX.sh b/Server/wwwroot/Content/Install-MacOSX.sh new file mode 100644 index 000000000..8280c0eb3 --- /dev/null +++ b/Server/wwwroot/Content/Install-MacOSX.sh @@ -0,0 +1,94 @@ +#!/bin/zsh + +HostName= +Organization= +GUID=$(uuidgen) +UpdatePackagePath="" + +Args=( "$@" ) +ArgLength=${#Args[@]} + +for (( i=0; i<${ArgLength}; i+=2 )); +do + if [ "${Args[$i]}" = "--uninstall" ]; then + launchctl unload -w /System/Library/LaunchDaemons/remotely-agent.plist + rm -r -f /Applications/Remotely/ + rm -f /System/Library/LaunchDaemons/remotely-agent.plist + exit + elif [ "${Args[$i]}" = "--path" ]; then + UpdatePackagePath="${Args[$i+1]}" + fi +done + + +# Install Homebrew +/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)" +brew update + +# Install .NET Runtime +brew install --cask dotnet + +# Install dependency for System.Drawing.Common +brew install mono-libgdiplus + +# Install other dependencies +brew install wget +brew install curl +brew install jq + + +if [ -f "/Applications/Remotely/ConnectionInfo.json" ]; then + GUID=`cat "/Applications/Remotely/ConnectionInfo.json" | jq -r '.DeviceID'` +fi + +rm -r -f /Applications/Remotely +rm -f /System/Library/LaunchDaemons/remotely-agent.plist + +mkdir -p /Applications/Remotely/ +cd /Applications/Remotely/ + +if [ -z "$UpdatePackagePath" ]; then + echo "Downloading client..." >> /tmp/Remotely_Install.log + wget $HostName/Content/Remotely-MacOSX.zip +else + echo "Copying install files..." >> /tmp/Remotely_Install.log + cp "$UpdatePackagePath" /Applications/Remotely/Remotely-MacOSX.zip + rm -f "$UpdatePackagePath" +fi + +unzip ./Remotely-MacOSX.zip +rm -f ./Remotely-MacOSX.zip + + +connectionInfo="{ + \"DeviceID\":\"$GUID\", + \"Host\":\"$HostName\", + \"OrganizationID\": \"$Organization\", + \"ServerVerificationToken\":\"\" +}" + +echo "$connectionInfo" > ./ConnectionInfo.json + +curl --head $HostName/Content/Remotely-MacOSX.zip | grep -i "etag" | cut -d' ' -f 2 > ./etag.txt + + +plistFile=" + + + + + Label + com.translucency.remotely-agent + ProgramArguments + + /usr/bin/dotnet + /Applications/Remotely/Remotely_Agent.dll + + KeepAlive + + + +" +echo "$plistFile" > "/System/Library/LaunchDaemons/remotely-agent.plist" + +launchctl load -w /System/Library/LaunchDaemons/remotely-agent.plist \ No newline at end of file From c0ecfff5e3c27a876744966a5a43d70c4e2f132f Mon Sep 17 00:00:00 2001 From: Jared Goodwin Date: Sat, 24 Apr 2021 09:06:07 -0700 Subject: [PATCH 03/22] Add Mac downloads. --- Desktop.Linux/App.xaml.cs | 2 +- Server/API/ClientDownloadsController.cs | 15 +++++++++++++++ Server/Pages/Downloads.razor | 8 ++++++++ .../{Install-MacOSX.sh => Install-MacOS.sh} | 10 +++++----- Shared/Enums/Platform.cs | 2 +- Shared/Utilities/EnvironmentHelper.cs | 6 +++--- 6 files changed, 33 insertions(+), 10 deletions(-) rename Server/wwwroot/Content/{Install-MacOSX.sh => Install-MacOS.sh} (91%) diff --git a/Desktop.Linux/App.xaml.cs b/Desktop.Linux/App.xaml.cs index 546485b2c..7eee9d66e 100644 --- a/Desktop.Linux/App.xaml.cs +++ b/Desktop.Linux/App.xaml.cs @@ -78,7 +78,7 @@ private void BuildServices() serviceCollection.AddScoped(); } break; - case Shared.Enums.Platform.OSX: + case Shared.Enums.Platform.MacOS: { } diff --git a/Server/API/ClientDownloadsController.cs b/Server/API/ClientDownloadsController.cs index 28c788130..b325f345b 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", "Remotely_Desktop"); return await GetDesktopFile(filePath); } + case "MacOS": + { + var filePath = Path.Combine(_hostEnv.WebRootPath, "Content", "MacOS", "Remotely_Desktop"); + return await GetDesktopFile(filePath); + } default: return NotFound(); } @@ -76,6 +81,11 @@ public async Task GetDesktop(string platformId, string organizati var filePath = Path.Combine(_hostEnv.WebRootPath, "Content", "Remotely_Desktop"); return await GetDesktopFile(filePath, organizationId); } + case "MacOS": + { + var filePath = Path.Combine(_hostEnv.WebRootPath, "Content", "Remotely_Desktop"); + return await GetDesktopFile(filePath); + } default: return NotFound(); } @@ -172,7 +182,12 @@ private async Task GetInstallFile(string organizationId, string p return await GetBashInstaller(fileName, organizationId); } + case "MacOS": + { + var fileName = "Install-MacOS.sh"; + return await GetBashInstaller(fileName, organizationId); + } default: return BadRequest(); } diff --git a/Server/Pages/Downloads.razor b/Server/Pages/Downloads.razor index f7b82af35..e27ce2042 100644 --- a/Server/Pages/Downloads.razor +++ b/Server/Pages/Downloads.razor @@ -38,6 +38,14 @@ Ubuntu Executable

+
+
macOS (10.15+)
+

+ Download: +
+ macOS Executable +

+
diff --git a/Server/wwwroot/Content/Install-MacOSX.sh b/Server/wwwroot/Content/Install-MacOS.sh similarity index 91% rename from Server/wwwroot/Content/Install-MacOSX.sh rename to Server/wwwroot/Content/Install-MacOS.sh index 8280c0eb3..883b724f9 100644 --- a/Server/wwwroot/Content/Install-MacOSX.sh +++ b/Server/wwwroot/Content/Install-MacOS.sh @@ -49,15 +49,15 @@ cd /Applications/Remotely/ if [ -z "$UpdatePackagePath" ]; then echo "Downloading client..." >> /tmp/Remotely_Install.log - wget $HostName/Content/Remotely-MacOSX.zip + wget $HostName/Content/Remotely-MacOS.zip else echo "Copying install files..." >> /tmp/Remotely_Install.log - cp "$UpdatePackagePath" /Applications/Remotely/Remotely-MacOSX.zip + cp "$UpdatePackagePath" /Applications/Remotely/Remotely-MacOS.zip rm -f "$UpdatePackagePath" fi -unzip ./Remotely-MacOSX.zip -rm -f ./Remotely-MacOSX.zip +unzip ./Remotely-MacOS.zip +rm -f ./Remotely-MacOS.zip connectionInfo="{ @@ -69,7 +69,7 @@ connectionInfo="{ echo "$connectionInfo" > ./ConnectionInfo.json -curl --head $HostName/Content/Remotely-MacOSX.zip | grep -i "etag" | cut -d' ' -f 2 > ./etag.txt +curl --head $HostName/Content/Remotely-MacOS.zip | grep -i "etag" | cut -d' ' -f 2 > ./etag.txt plistFile=" diff --git a/Shared/Enums/Platform.cs b/Shared/Enums/Platform.cs index dc1d00cd0..f5ba25774 100644 --- a/Shared/Enums/Platform.cs +++ b/Shared/Enums/Platform.cs @@ -4,7 +4,7 @@ public enum Platform { Windows, Linux, - OSX, + MacOS, Unknown } } diff --git a/Shared/Utilities/EnvironmentHelper.cs b/Shared/Utilities/EnvironmentHelper.cs index 0a63475fa..66379c020 100644 --- a/Shared/Utilities/EnvironmentHelper.cs +++ b/Shared/Utilities/EnvironmentHelper.cs @@ -15,7 +15,7 @@ public static string AgentExecutableFileName case Platform.Windows: return "Remotely_Agent.exe"; case Platform.Linux: - case Platform.OSX: + case Platform.MacOS: return "Remotely_Agent"; default: throw new PlatformNotSupportedException(); @@ -32,7 +32,7 @@ public static string DesktopExecutableFileName case Platform.Windows: return "Remotely_Desktop.exe"; case Platform.Linux: - case Platform.OSX: + case Platform.MacOS: return "Remotely_Desktop"; default: throw new PlatformNotSupportedException(); @@ -74,7 +74,7 @@ public static Platform Platform } else if (IsMac) { - return Platform.OSX; + return Platform.MacOS; } else { From c87e0055cca1674a269fd072946cefaf1498a922 Mon Sep 17 00:00:00 2001 From: Jared Goodwin Date: Sat, 24 Apr 2021 10:46:31 -0700 Subject: [PATCH 04/22] Adjust styling on Downloads page. --- Server/API/ClientDownloadsController.cs | 2 +- Server/Pages/Downloads.razor | 97 ++++++++++++------------- 2 files changed, 49 insertions(+), 50 deletions(-) diff --git a/Server/API/ClientDownloadsController.cs b/Server/API/ClientDownloadsController.cs index b325f345b..430b1c6ad 100644 --- a/Server/API/ClientDownloadsController.cs +++ b/Server/API/ClientDownloadsController.cs @@ -83,7 +83,7 @@ public async Task GetDesktop(string platformId, string organizati } case "MacOS": { - var filePath = Path.Combine(_hostEnv.WebRootPath, "Content", "Remotely_Desktop"); + var filePath = Path.Combine(_hostEnv.WebRootPath, "Content", "MacOS", "Remotely_Desktop"); return await GetDesktopFile(filePath); } default: diff --git a/Server/Pages/Downloads.razor b/Server/Pages/Downloads.razor index e27ce2042..1bb6d7eb9 100644 --- a/Server/Pages/Downloads.razor +++ b/Server/Pages/Downloads.razor @@ -119,45 +119,44 @@

- Quiet Install: -
- +

Example Quiet Install:
+ + Remotely_Installer.exe -install -quiet -organizationid "0b3d706b-9c5d-41e6-8ae9-5720d16324e6" -serverurl "https://remotely.mytechshop.com" - +

- Quiet Uninstall: +

Example Quiet Uninstall:

- Remotely_Installer.exe -uninstall -quiet + Remotely_Installer.exe -uninstall -quiet

- Local Install: - -
- +

Example Local Install:
+ + Remotely_Installer.exe -install -quiet -organizationid "0b3d706b-9c5d-41e6-8ae9-5720d16324e6" -serverurl "https://remotely.mytechshop.com" -path "[path]\Remotely-Win10-x64.zip" - +

- Override Options: -
- +

All Override Options:
+ + Remotely_Installer.exe -install -quiet -supportshortcut -organizationid "0b3d706b-9c5d-41e6-8ae9-5720d16324e6" -serverurl "https://remotely.mytechshop.com" -devicegroup "Customer Group 1" -devicealias "Front Desk" -deviceuuid "eebb4d87-5459-4976-989e-a7876dffc69c" - +

@@ -165,7 +164,6 @@
Linux 64-Bit

Download: -
Ubuntu x64 Bash Installer
Manjaro x64 Bash Installer @@ -173,49 +171,50 @@ Linux x64 Files Only

- Install: -
- sudo [path]/Install-Ubuntu-x64.sh +

Example Install:
+ + sudo [path]/Install-Ubuntu-x64.sh

- Local Install: - -
- sudo [path]/Install-Ubuntu-x64.sh --path [path]/Remotely-Linux.zip +

Example Local Install:
+ + sudo [path]/Install-Ubuntu-x64.sh --path [path]/Remotely-Linux.zip

- Uninstall: +

Uninstall:
+ + sudo [path]/Install-Ubuntu-x64.sh --uninstall +

+ + +
+
macOS (10.5+)
+

+ Download: +
+ macOS ZSH Installer
- sudo [path]/Install-Ubuntu-x64.sh --uninstall + macOS Files Only +

+

+

Example Install:
+ + sudo [path]/Install-Ubuntu-x64.sh +

+

+

Example Local Install:
+ + sudo [path]/Install-MacOS.sh --path [path]/Remotely-MacOS.zip +

+

+

Example Uninstall:
+ + sudo [path]/Install-MacOS.sh --uninstall

} - @code { private string _organizationId; From 62875cedb0f7f3681b391d1af545ebc6200f83ec Mon Sep 17 00:00:00 2001 From: Jared Goodwin Date: Sat, 24 Apr 2021 17:46:30 -0700 Subject: [PATCH 05/22] Rename "Linux" to "XPlat" --- {Desktop.Linux => Desktop.XPlat}/App.xaml | 4 ++-- {Desktop.Linux => Desktop.XPlat}/App.xaml.cs | 6 +++--- {Desktop.Linux => Desktop.XPlat}/Assets/Gear.png | Bin .../Assets/Remotely_Icon.png | Bin .../Assets/avalonia-logo.ico | Bin .../Assets/favicon.ico | Bin .../Controls/MessageBox.axaml | 4 ++-- .../Controls/MessageBox.axaml.cs | 4 ++-- .../Desktop.XPlat.csproj | 2 +- .../Native/Linux}/LibX11.cs | 2 +- .../Native/Linux}/LibXtst.cs | 2 +- .../Native => Desktop.XPlat/Native/Linux}/Libc.cs | 2 +- .../Native/Linux}/libXrandr.cs | 2 +- {Desktop.Linux => Desktop.XPlat}/Program.cs | 2 +- .../PublishProfiles/desktop-linux-x64.pubxml | 0 .../PublishProfiles/packaged-linux-x64.pubxml | 0 .../Properties/launchSettings.json | 0 .../Services/AudioCapturerLinux.cs | 2 +- .../Services/ChatUiServiceLinux.cs | 8 ++++---- .../Services/ClipboardServiceLinux.cs | 2 +- .../Services/ConfigServiceLinux.cs | 2 +- .../Services/CursorIconWatcherLinux.cs | 2 +- .../Services/Executor.cs | 2 +- .../Services/FileTransferServiceLinux.cs | 8 ++++---- .../Services/KeyboardMouseInputLinux.cs | 4 ++-- .../Services/RemoteControlAccessServiceLinux.cs | 6 +++--- .../Services/ScreenCapturerLinux.cs | 4 ++-- .../Services/SessionIndicatorLinux.cs | 4 ++-- .../Services/ShutdownServiceLinux.cs | 2 +- {Desktop.Linux => Desktop.XPlat}/ViewLocator.cs | 4 ++-- .../ViewModels/BrandedViewModelBase.cs | 4 ++-- .../ViewModels/ChatWindowViewModel.cs | 4 ++-- .../ViewModels/FileTransferWindowViewModel.cs | 6 +++--- .../ViewModels/HostNamePromptViewModel.cs | 4 ++-- .../ViewModels/MainWindowViewModel.cs | 10 +++++----- .../ViewModels/MessageBoxViewModel.cs | 6 +++--- .../ViewModels/PromptForAccessWindowViewModel.cs | 4 ++-- .../ViewModels/ReactiveViewModel.cs | 2 +- .../Views/ChatWindow.axaml | 4 ++-- .../Views/ChatWindow.axaml.cs | 4 ++-- .../Views/FileTransferWindow.axaml | 6 +++--- .../Views/FileTransferWindow.axaml.cs | 2 +- .../Views/HostNamePrompt.axaml | 4 ++-- .../Views/HostNamePrompt.axaml.cs | 6 +++--- .../Views/MainWindow.axaml | 4 ++-- .../Views/MainWindow.axaml.cs | 4 ++-- .../Views/PromptForAccessWindow.axaml | 4 ++-- .../Views/PromptForAccessWindow.axaml.cs | 2 +- .../Views/SessionIndicatorWindow.axaml | 4 ++-- .../Views/SessionIndicatorWindow.axaml.cs | 4 ++-- {Desktop.Linux => Desktop.XPlat}/nuget.config | 0 Remotely.sln | 2 +- Server/API/ClientDownloadsController.cs | 14 +++++++------- Server/Pages/Downloads.razor | 12 ++++++------ .../{Install-MacOS.sh => Install-MacOS-x64.sh} | 0 55 files changed, 98 insertions(+), 98 deletions(-) rename {Desktop.Linux => Desktop.XPlat}/App.xaml (94%) rename {Desktop.Linux => Desktop.XPlat}/App.xaml.cs (98%) rename {Desktop.Linux => Desktop.XPlat}/Assets/Gear.png (100%) rename {Desktop.Linux => Desktop.XPlat}/Assets/Remotely_Icon.png (100%) rename {Desktop.Linux => Desktop.XPlat}/Assets/avalonia-logo.ico (100%) rename {Desktop.Linux => Desktop.XPlat}/Assets/favicon.ico (100%) rename {Desktop.Linux => Desktop.XPlat}/Controls/MessageBox.axaml (93%) rename {Desktop.Linux => Desktop.XPlat}/Controls/MessageBox.axaml.cs (96%) rename Desktop.Linux/Desktop.Linux.csproj => Desktop.XPlat/Desktop.XPlat.csproj (97%) rename {Desktop.Linux/Native => Desktop.XPlat/Native/Linux}/LibX11.cs (99%) rename {Desktop.Linux/Native => Desktop.XPlat/Native/Linux}/LibXtst.cs (93%) rename {Desktop.Linux/Native => Desktop.XPlat/Native/Linux}/Libc.cs (86%) rename {Desktop.Linux/Native => Desktop.XPlat/Native/Linux}/libXrandr.cs (98%) rename {Desktop.Linux => Desktop.XPlat}/Program.cs (97%) rename {Desktop.Linux => Desktop.XPlat}/Properties/PublishProfiles/desktop-linux-x64.pubxml (100%) rename {Desktop.Linux => Desktop.XPlat}/Properties/PublishProfiles/packaged-linux-x64.pubxml (100%) rename {Desktop.Linux => Desktop.XPlat}/Properties/launchSettings.json (100%) rename {Desktop.Linux => Desktop.XPlat}/Services/AudioCapturerLinux.cs (88%) rename {Desktop.Linux => Desktop.XPlat}/Services/ChatUiServiceLinux.cs (92%) rename {Desktop.Linux => Desktop.XPlat}/Services/ClipboardServiceLinux.cs (98%) rename {Desktop.Linux => Desktop.XPlat}/Services/ConfigServiceLinux.cs (96%) rename {Desktop.Linux => Desktop.XPlat}/Services/CursorIconWatcherLinux.cs (89%) rename {Desktop.Linux => Desktop.XPlat}/Services/Executor.cs (95%) rename {Desktop.Linux => Desktop.XPlat}/Services/FileTransferServiceLinux.cs (96%) rename {Desktop.Linux => Desktop.XPlat}/Services/KeyboardMouseInputLinux.cs (98%) rename {Desktop.Linux => Desktop.XPlat}/Services/RemoteControlAccessServiceLinux.cs (92%) rename {Desktop.Linux => Desktop.XPlat}/Services/ScreenCapturerLinux.cs (98%) rename {Desktop.Linux => Desktop.XPlat}/Services/SessionIndicatorLinux.cs (83%) rename {Desktop.Linux => Desktop.XPlat}/Services/ShutdownServiceLinux.cs (93%) rename {Desktop.Linux => Desktop.XPlat}/ViewLocator.cs (90%) rename {Desktop.Linux => Desktop.XPlat}/ViewModels/BrandedViewModelBase.cs (96%) rename {Desktop.Linux => Desktop.XPlat}/ViewModels/ChatWindowViewModel.cs (96%) rename {Desktop.Linux => Desktop.XPlat}/ViewModels/FileTransferWindowViewModel.cs (96%) rename {Desktop.Linux => Desktop.XPlat}/ViewModels/HostNamePromptViewModel.cs (84%) rename {Desktop.Linux => Desktop.XPlat}/ViewModels/MainWindowViewModel.cs (98%) rename {Desktop.Linux => Desktop.XPlat}/ViewModels/MessageBoxViewModel.cs (92%) rename {Desktop.Linux => Desktop.XPlat}/ViewModels/PromptForAccessWindowViewModel.cs (95%) rename {Desktop.Linux => Desktop.XPlat}/ViewModels/ReactiveViewModel.cs (67%) rename {Desktop.Linux => Desktop.XPlat}/Views/ChatWindow.axaml (97%) rename {Desktop.Linux => Desktop.XPlat}/Views/ChatWindow.axaml.cs (96%) rename {Desktop.Linux => Desktop.XPlat}/Views/FileTransferWindow.axaml (93%) rename {Desktop.Linux => Desktop.XPlat}/Views/FileTransferWindow.axaml.cs (94%) rename {Desktop.Linux => Desktop.XPlat}/Views/HostNamePrompt.axaml (89%) rename {Desktop.Linux => Desktop.XPlat}/Views/HostNamePrompt.axaml.cs (79%) rename {Desktop.Linux => Desktop.XPlat}/Views/MainWindow.axaml (97%) rename {Desktop.Linux => Desktop.XPlat}/Views/MainWindow.axaml.cs (92%) rename {Desktop.Linux => Desktop.XPlat}/Views/PromptForAccessWindow.axaml (96%) rename {Desktop.Linux => Desktop.XPlat}/Views/PromptForAccessWindow.axaml.cs (95%) rename {Desktop.Linux => Desktop.XPlat}/Views/SessionIndicatorWindow.axaml (88%) rename {Desktop.Linux => Desktop.XPlat}/Views/SessionIndicatorWindow.axaml.cs (95%) rename {Desktop.Linux => Desktop.XPlat}/nuget.config (100%) rename Server/wwwroot/Content/{Install-MacOS.sh => Install-MacOS-x64.sh} (100%) diff --git a/Desktop.Linux/App.xaml b/Desktop.XPlat/App.xaml similarity index 94% rename from Desktop.Linux/App.xaml rename to Desktop.XPlat/App.xaml index 1bd7b475e..cbb188228 100644 --- a/Desktop.Linux/App.xaml +++ b/Desktop.XPlat/App.xaml @@ -1,7 +1,7 @@  + xmlns:local="clr-namespace:Remotely.Desktop.XPlat;assembly=Remotely_Desktop" + x:Class="Remotely.Desktop.XPlat.App"> diff --git a/Desktop.Linux/App.xaml.cs b/Desktop.XPlat/App.xaml.cs similarity index 98% rename from Desktop.Linux/App.xaml.cs rename to Desktop.XPlat/App.xaml.cs index 7eee9d66e..f90f2bf9a 100644 --- a/Desktop.Linux/App.xaml.cs +++ b/Desktop.XPlat/App.xaml.cs @@ -8,15 +8,15 @@ using Remotely.Desktop.Core; using Remotely.Desktop.Core.Interfaces; using Remotely.Desktop.Core.Services; -using Remotely.Desktop.Linux.Services; -using Remotely.Desktop.Linux.Views; +using Remotely.Desktop.XPlat.Services; +using Remotely.Desktop.XPlat.Views; using Remotely.Shared.Utilities; using System; using System.Linq; using System.Threading; using System.Threading.Tasks; -namespace Remotely.Desktop.Linux +namespace Remotely.Desktop.XPlat { public class App : Application { diff --git a/Desktop.Linux/Assets/Gear.png b/Desktop.XPlat/Assets/Gear.png similarity index 100% rename from Desktop.Linux/Assets/Gear.png rename to Desktop.XPlat/Assets/Gear.png diff --git a/Desktop.Linux/Assets/Remotely_Icon.png b/Desktop.XPlat/Assets/Remotely_Icon.png similarity index 100% rename from Desktop.Linux/Assets/Remotely_Icon.png rename to Desktop.XPlat/Assets/Remotely_Icon.png diff --git a/Desktop.Linux/Assets/avalonia-logo.ico b/Desktop.XPlat/Assets/avalonia-logo.ico similarity index 100% rename from Desktop.Linux/Assets/avalonia-logo.ico rename to Desktop.XPlat/Assets/avalonia-logo.ico diff --git a/Desktop.Linux/Assets/favicon.ico b/Desktop.XPlat/Assets/favicon.ico similarity index 100% rename from Desktop.Linux/Assets/favicon.ico rename to Desktop.XPlat/Assets/favicon.ico diff --git a/Desktop.Linux/Controls/MessageBox.axaml b/Desktop.XPlat/Controls/MessageBox.axaml similarity index 93% rename from Desktop.Linux/Controls/MessageBox.axaml rename to Desktop.XPlat/Controls/MessageBox.axaml index cf288fcb3..3fc24335f 100644 --- a/Desktop.Linux/Controls/MessageBox.axaml +++ b/Desktop.XPlat/Controls/MessageBox.axaml @@ -3,8 +3,8 @@ xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450" - xmlns:vm="clr-namespace:Remotely.Desktop.Linux.ViewModels;assembly=Remotely_Desktop" - x:Class="Remotely.Desktop.Linux.Controls.MessageBox" + xmlns:vm="clr-namespace:Remotely.Desktop.XPlat.ViewModels;assembly=Remotely_Desktop" + x:Class="Remotely.Desktop.XPlat.Controls.MessageBox" Icon="{Binding WindowIcon}" Title="{Binding Caption}" SizeToContent="WidthAndHeight" MinWidth="300" MinHeight="100" diff --git a/Desktop.Linux/Controls/MessageBox.axaml.cs b/Desktop.XPlat/Controls/MessageBox.axaml.cs similarity index 96% rename from Desktop.Linux/Controls/MessageBox.axaml.cs rename to Desktop.XPlat/Controls/MessageBox.axaml.cs index 7596a751e..08173eff3 100644 --- a/Desktop.Linux/Controls/MessageBox.axaml.cs +++ b/Desktop.XPlat/Controls/MessageBox.axaml.cs @@ -2,13 +2,13 @@ using Avalonia.Controls; using Avalonia.Controls.ApplicationLifetimes; using Avalonia.Markup.Xaml; -using Remotely.Desktop.Linux.ViewModels; +using Remotely.Desktop.XPlat.ViewModels; using Remotely.Shared.Utilities; using System; using System.Linq; using System.Threading.Tasks; -namespace Remotely.Desktop.Linux.Controls +namespace Remotely.Desktop.XPlat.Controls { public class MessageBox : Window { diff --git a/Desktop.Linux/Desktop.Linux.csproj b/Desktop.XPlat/Desktop.XPlat.csproj similarity index 97% rename from Desktop.Linux/Desktop.Linux.csproj rename to Desktop.XPlat/Desktop.XPlat.csproj index 165b92c67..4b7763f8b 100644 --- a/Desktop.Linux/Desktop.Linux.csproj +++ b/Desktop.XPlat/Desktop.XPlat.csproj @@ -4,7 +4,7 @@ net5.0 Assets\favicon.ico Remotely_Desktop - Remotely.Desktop.Linux + Remotely.Desktop.XPlat AnyCPU;x64;x86 diff --git a/Desktop.Linux/Native/LibX11.cs b/Desktop.XPlat/Native/Linux/LibX11.cs similarity index 99% rename from Desktop.Linux/Native/LibX11.cs rename to Desktop.XPlat/Native/Linux/LibX11.cs index 33ccf3849..d4e9a6f03 100644 --- a/Desktop.Linux/Native/LibX11.cs +++ b/Desktop.XPlat/Native/Linux/LibX11.cs @@ -27,7 +27,7 @@ in this Software without prior written authorization from The Open Group. using System; using System.Runtime.InteropServices; -namespace Remotely.Desktop.Linux.Native +namespace Remotely.Desktop.XPlat.Native.Linux { public static unsafe class LibX11 { diff --git a/Desktop.Linux/Native/LibXtst.cs b/Desktop.XPlat/Native/Linux/LibXtst.cs similarity index 93% rename from Desktop.Linux/Native/LibXtst.cs rename to Desktop.XPlat/Native/Linux/LibXtst.cs index 1e74c74fe..19fd546df 100644 --- a/Desktop.Linux/Native/LibXtst.cs +++ b/Desktop.XPlat/Native/Linux/LibXtst.cs @@ -1,7 +1,7 @@ using System; using System.Runtime.InteropServices; -namespace Remotely.Desktop.Linux.Native +namespace Remotely.Desktop.XPlat.Native.Linux { public class LibXtst { diff --git a/Desktop.Linux/Native/Libc.cs b/Desktop.XPlat/Native/Linux/Libc.cs similarity index 86% rename from Desktop.Linux/Native/Libc.cs rename to Desktop.XPlat/Native/Linux/Libc.cs index 7df9c0ab2..30f903331 100644 --- a/Desktop.Linux/Native/Libc.cs +++ b/Desktop.XPlat/Native/Linux/Libc.cs @@ -5,7 +5,7 @@ using System.Text; using System.Threading.Tasks; -namespace Remotely.Desktop.Linux.Native +namespace Remotely.Desktop.XPlat.Native.Linux { public class Libc { diff --git a/Desktop.Linux/Native/libXrandr.cs b/Desktop.XPlat/Native/Linux/libXrandr.cs similarity index 98% rename from Desktop.Linux/Native/libXrandr.cs rename to Desktop.XPlat/Native/Linux/libXrandr.cs index 22132c729..a55c4263b 100644 --- a/Desktop.Linux/Native/libXrandr.cs +++ b/Desktop.XPlat/Native/Linux/libXrandr.cs @@ -34,7 +34,7 @@ using System.Text; using System.Threading.Tasks; -namespace Remotely.Desktop.Linux.Native +namespace Remotely.Desktop.XPlat.Native.Linux { public static class LibXrandr { diff --git a/Desktop.Linux/Program.cs b/Desktop.XPlat/Program.cs similarity index 97% rename from Desktop.Linux/Program.cs rename to Desktop.XPlat/Program.cs index 52587b7ff..7a2aa7e92 100644 --- a/Desktop.Linux/Program.cs +++ b/Desktop.XPlat/Program.cs @@ -6,7 +6,7 @@ using System; using System.Threading; -namespace Remotely.Desktop.Linux +namespace Remotely.Desktop.XPlat { class Program { diff --git a/Desktop.Linux/Properties/PublishProfiles/desktop-linux-x64.pubxml b/Desktop.XPlat/Properties/PublishProfiles/desktop-linux-x64.pubxml similarity index 100% rename from Desktop.Linux/Properties/PublishProfiles/desktop-linux-x64.pubxml rename to Desktop.XPlat/Properties/PublishProfiles/desktop-linux-x64.pubxml diff --git a/Desktop.Linux/Properties/PublishProfiles/packaged-linux-x64.pubxml b/Desktop.XPlat/Properties/PublishProfiles/packaged-linux-x64.pubxml similarity index 100% rename from Desktop.Linux/Properties/PublishProfiles/packaged-linux-x64.pubxml rename to Desktop.XPlat/Properties/PublishProfiles/packaged-linux-x64.pubxml diff --git a/Desktop.Linux/Properties/launchSettings.json b/Desktop.XPlat/Properties/launchSettings.json similarity index 100% rename from Desktop.Linux/Properties/launchSettings.json rename to Desktop.XPlat/Properties/launchSettings.json diff --git a/Desktop.Linux/Services/AudioCapturerLinux.cs b/Desktop.XPlat/Services/AudioCapturerLinux.cs similarity index 88% rename from Desktop.Linux/Services/AudioCapturerLinux.cs rename to Desktop.XPlat/Services/AudioCapturerLinux.cs index ad7323c7a..f336236ed 100644 --- a/Desktop.Linux/Services/AudioCapturerLinux.cs +++ b/Desktop.XPlat/Services/AudioCapturerLinux.cs @@ -1,7 +1,7 @@ using Remotely.Desktop.Core.Interfaces; using System; -namespace Remotely.Desktop.Linux.Services +namespace Remotely.Desktop.XPlat.Services { public class AudioCapturerLinux : IAudioCapturer { diff --git a/Desktop.Linux/Services/ChatUiServiceLinux.cs b/Desktop.XPlat/Services/ChatUiServiceLinux.cs similarity index 92% rename from Desktop.Linux/Services/ChatUiServiceLinux.cs rename to Desktop.XPlat/Services/ChatUiServiceLinux.cs index 5f4be5d3c..2eff2488c 100644 --- a/Desktop.Linux/Services/ChatUiServiceLinux.cs +++ b/Desktop.XPlat/Services/ChatUiServiceLinux.cs @@ -1,9 +1,9 @@ using Avalonia.Controls; using Avalonia.Threading; using Remotely.Desktop.Core.Interfaces; -using Remotely.Desktop.Linux.Controls; -using Remotely.Desktop.Linux.ViewModels; -using Remotely.Desktop.Linux.Views; +using Remotely.Desktop.XPlat.Controls; +using Remotely.Desktop.XPlat.ViewModels; +using Remotely.Desktop.XPlat.Views; using Remotely.Shared.Models; using System; using System.Collections.Generic; @@ -14,7 +14,7 @@ using System.Text; using System.Threading.Tasks; -namespace Remotely.Desktop.Linux.Services +namespace Remotely.Desktop.XPlat.Services { public class ChatUiServiceLinux : IChatUiService { diff --git a/Desktop.Linux/Services/ClipboardServiceLinux.cs b/Desktop.XPlat/Services/ClipboardServiceLinux.cs similarity index 98% rename from Desktop.Linux/Services/ClipboardServiceLinux.cs rename to Desktop.XPlat/Services/ClipboardServiceLinux.cs index d9c3ea0f0..5a3b8c67f 100644 --- a/Desktop.Linux/Services/ClipboardServiceLinux.cs +++ b/Desktop.XPlat/Services/ClipboardServiceLinux.cs @@ -4,7 +4,7 @@ using System.Threading; using System.Threading.Tasks; -namespace Remotely.Desktop.Linux.Services +namespace Remotely.Desktop.XPlat.Services { public class ClipboardServiceLinux : IClipboardService { diff --git a/Desktop.Linux/Services/ConfigServiceLinux.cs b/Desktop.XPlat/Services/ConfigServiceLinux.cs similarity index 96% rename from Desktop.Linux/Services/ConfigServiceLinux.cs rename to Desktop.XPlat/Services/ConfigServiceLinux.cs index 641cc11b1..0eadf56f8 100644 --- a/Desktop.Linux/Services/ConfigServiceLinux.cs +++ b/Desktop.XPlat/Services/ConfigServiceLinux.cs @@ -5,7 +5,7 @@ using System.IO; using System.Text.Json; -namespace Remotely.Desktop.Linux.Services +namespace Remotely.Desktop.XPlat.Services { public class ConfigServiceLinux : IConfigService { diff --git a/Desktop.Linux/Services/CursorIconWatcherLinux.cs b/Desktop.XPlat/Services/CursorIconWatcherLinux.cs similarity index 89% rename from Desktop.Linux/Services/CursorIconWatcherLinux.cs rename to Desktop.XPlat/Services/CursorIconWatcherLinux.cs index eac7eff73..f677b8a9c 100644 --- a/Desktop.Linux/Services/CursorIconWatcherLinux.cs +++ b/Desktop.XPlat/Services/CursorIconWatcherLinux.cs @@ -3,7 +3,7 @@ using System; using System.Drawing; -namespace Remotely.Desktop.Linux.Services +namespace Remotely.Desktop.XPlat.Services { public class CursorIconWatcherLinux : ICursorIconWatcher { diff --git a/Desktop.Linux/Services/Executor.cs b/Desktop.XPlat/Services/Executor.cs similarity index 95% rename from Desktop.Linux/Services/Executor.cs rename to Desktop.XPlat/Services/Executor.cs index e7d0b85a7..0217eea98 100644 --- a/Desktop.Linux/Services/Executor.cs +++ b/Desktop.XPlat/Services/Executor.cs @@ -1,7 +1,7 @@ using System; using System.Windows.Input; -namespace Remotely.Desktop.Linux.Services +namespace Remotely.Desktop.XPlat.Services { public class Executor : ICommand { diff --git a/Desktop.Linux/Services/FileTransferServiceLinux.cs b/Desktop.XPlat/Services/FileTransferServiceLinux.cs similarity index 96% rename from Desktop.Linux/Services/FileTransferServiceLinux.cs rename to Desktop.XPlat/Services/FileTransferServiceLinux.cs index 527dd623d..0cb78419c 100644 --- a/Desktop.Linux/Services/FileTransferServiceLinux.cs +++ b/Desktop.XPlat/Services/FileTransferServiceLinux.cs @@ -2,9 +2,9 @@ using Remotely.Desktop.Core.Interfaces; using Remotely.Desktop.Core.Services; using Remotely.Desktop.Core.ViewModels; -using Remotely.Desktop.Linux.Controls; -using Remotely.Desktop.Linux.ViewModels; -using Remotely.Desktop.Linux.Views; +using Remotely.Desktop.XPlat.Controls; +using Remotely.Desktop.XPlat.ViewModels; +using Remotely.Desktop.XPlat.Views; using Remotely.Shared.Utilities; using System; using System.Collections.Concurrent; @@ -13,7 +13,7 @@ using System.Threading; using System.Threading.Tasks; -namespace Remotely.Desktop.Linux.Services +namespace Remotely.Desktop.XPlat.Services { public class FileTransferServiceLinux : IFileTransferService { diff --git a/Desktop.Linux/Services/KeyboardMouseInputLinux.cs b/Desktop.XPlat/Services/KeyboardMouseInputLinux.cs similarity index 98% rename from Desktop.Linux/Services/KeyboardMouseInputLinux.cs rename to Desktop.XPlat/Services/KeyboardMouseInputLinux.cs index f1bfbfcdf..86f6046db 100644 --- a/Desktop.Linux/Services/KeyboardMouseInputLinux.cs +++ b/Desktop.XPlat/Services/KeyboardMouseInputLinux.cs @@ -1,11 +1,11 @@ using Remotely.Desktop.Core.Enums; using Remotely.Desktop.Core.Interfaces; using Remotely.Desktop.Core.Services; -using Remotely.Desktop.Linux.Native; +using Remotely.Desktop.XPlat.Native.Linux; using Remotely.Shared.Utilities; using System; -namespace Remotely.Desktop.Linux.Services +namespace Remotely.Desktop.XPlat.Services { public class KeyboardMouseInputLinux : IKeyboardMouseInput { diff --git a/Desktop.Linux/Services/RemoteControlAccessServiceLinux.cs b/Desktop.XPlat/Services/RemoteControlAccessServiceLinux.cs similarity index 92% rename from Desktop.Linux/Services/RemoteControlAccessServiceLinux.cs rename to Desktop.XPlat/Services/RemoteControlAccessServiceLinux.cs index 3482cb4f8..e2bd90a93 100644 --- a/Desktop.Linux/Services/RemoteControlAccessServiceLinux.cs +++ b/Desktop.XPlat/Services/RemoteControlAccessServiceLinux.cs @@ -1,7 +1,7 @@ using Avalonia.Threading; using Remotely.Desktop.Core.Interfaces; -using Remotely.Desktop.Linux.ViewModels; -using Remotely.Desktop.Linux.Views; +using Remotely.Desktop.XPlat.ViewModels; +using Remotely.Desktop.XPlat.Views; using Remotely.Shared.Utilities; using System; using System.Collections.Generic; @@ -9,7 +9,7 @@ using System.Text; using System.Threading.Tasks; -namespace Remotely.Desktop.Linux.Services +namespace Remotely.Desktop.XPlat.Services { public class RemoteControlAccessServiceLinux : IRemoteControlAccessService { diff --git a/Desktop.Linux/Services/ScreenCapturerLinux.cs b/Desktop.XPlat/Services/ScreenCapturerLinux.cs similarity index 98% rename from Desktop.Linux/Services/ScreenCapturerLinux.cs rename to Desktop.XPlat/Services/ScreenCapturerLinux.cs index a6d932e4a..0adb07155 100644 --- a/Desktop.Linux/Services/ScreenCapturerLinux.cs +++ b/Desktop.XPlat/Services/ScreenCapturerLinux.cs @@ -1,5 +1,5 @@ using Remotely.Desktop.Core.Interfaces; -using Remotely.Desktop.Linux.Native; +using Remotely.Desktop.XPlat.Native.Linux; using Remotely.Shared.Utilities; using System; using System.Collections.Generic; @@ -10,7 +10,7 @@ using System.Text.Json; using System.Threading; -namespace Remotely.Desktop.Linux.Services +namespace Remotely.Desktop.XPlat.Services { public class ScreenCapturerLinux : IScreenCapturer { diff --git a/Desktop.Linux/Services/SessionIndicatorLinux.cs b/Desktop.XPlat/Services/SessionIndicatorLinux.cs similarity index 83% rename from Desktop.Linux/Services/SessionIndicatorLinux.cs rename to Desktop.XPlat/Services/SessionIndicatorLinux.cs index a9b74e4a1..e32adf9bf 100644 --- a/Desktop.Linux/Services/SessionIndicatorLinux.cs +++ b/Desktop.XPlat/Services/SessionIndicatorLinux.cs @@ -1,9 +1,9 @@ using Avalonia.Controls; using Avalonia.Threading; using Remotely.Desktop.Core.Interfaces; -using Remotely.Desktop.Linux.Views; +using Remotely.Desktop.XPlat.Views; -namespace Remotely.Desktop.Linux.Services +namespace Remotely.Desktop.XPlat.Services { public class SessionIndicatorLinux : ISessionIndicator { diff --git a/Desktop.Linux/Services/ShutdownServiceLinux.cs b/Desktop.XPlat/Services/ShutdownServiceLinux.cs similarity index 93% rename from Desktop.Linux/Services/ShutdownServiceLinux.cs rename to Desktop.XPlat/Services/ShutdownServiceLinux.cs index bc1a7962b..21e15f2b0 100644 --- a/Desktop.Linux/Services/ShutdownServiceLinux.cs +++ b/Desktop.XPlat/Services/ShutdownServiceLinux.cs @@ -7,7 +7,7 @@ using System.Diagnostics; using System.Threading.Tasks; -namespace Remotely.Desktop.Linux.Services +namespace Remotely.Desktop.XPlat.Services { public class ShutdownServiceLinux : IShutdownService { diff --git a/Desktop.Linux/ViewLocator.cs b/Desktop.XPlat/ViewLocator.cs similarity index 90% rename from Desktop.Linux/ViewLocator.cs rename to Desktop.XPlat/ViewLocator.cs index 357648711..36aace436 100644 --- a/Desktop.Linux/ViewLocator.cs +++ b/Desktop.XPlat/ViewLocator.cs @@ -1,9 +1,9 @@ using Avalonia.Controls; using Avalonia.Controls.Templates; -using Remotely.Desktop.Linux.ViewModels; +using Remotely.Desktop.XPlat.ViewModels; using System; -namespace Remotely.Desktop.Linux +namespace Remotely.Desktop.XPlat { public class ViewLocator : IDataTemplate { diff --git a/Desktop.Linux/ViewModels/BrandedViewModelBase.cs b/Desktop.XPlat/ViewModels/BrandedViewModelBase.cs similarity index 96% rename from Desktop.Linux/ViewModels/BrandedViewModelBase.cs rename to Desktop.XPlat/ViewModels/BrandedViewModelBase.cs index 2f6752b8b..326072bb2 100644 --- a/Desktop.Linux/ViewModels/BrandedViewModelBase.cs +++ b/Desktop.XPlat/ViewModels/BrandedViewModelBase.cs @@ -11,7 +11,7 @@ using System.Linq; using System.Reflection; -namespace Remotely.Desktop.Linux.ViewModels +namespace Remotely.Desktop.XPlat.ViewModels { public class BrandedViewModelBase : ReactiveViewModel { @@ -66,7 +66,7 @@ public void ApplyBranding() } else { - using var imageStream = Assembly.GetExecutingAssembly().GetManifestResourceStream("Remotely.Desktop.Linux.Assets.Remotely_Icon.png"); + using var imageStream = Assembly.GetExecutingAssembly().GetManifestResourceStream("Remotely.Desktop.XPlat.Assets.Remotely_Icon.png"); Icon = new Bitmap(imageStream); } diff --git a/Desktop.Linux/ViewModels/ChatWindowViewModel.cs b/Desktop.XPlat/ViewModels/ChatWindowViewModel.cs similarity index 96% rename from Desktop.Linux/ViewModels/ChatWindowViewModel.cs rename to Desktop.XPlat/ViewModels/ChatWindowViewModel.cs index 8bb415e85..24798a3aa 100644 --- a/Desktop.Linux/ViewModels/ChatWindowViewModel.cs +++ b/Desktop.XPlat/ViewModels/ChatWindowViewModel.cs @@ -1,6 +1,6 @@ using Avalonia.Controls; using ReactiveUI; -using Remotely.Desktop.Linux.Services; +using Remotely.Desktop.XPlat.Services; using Remotely.Shared.Models; using System.Collections.ObjectModel; using System.IO; @@ -8,7 +8,7 @@ using System.Threading.Tasks; using System.Windows.Input; -namespace Remotely.Desktop.Linux.ViewModels +namespace Remotely.Desktop.XPlat.ViewModels { public class ChatWindowViewModel : BrandedViewModelBase { diff --git a/Desktop.Linux/ViewModels/FileTransferWindowViewModel.cs b/Desktop.XPlat/ViewModels/FileTransferWindowViewModel.cs similarity index 96% rename from Desktop.Linux/ViewModels/FileTransferWindowViewModel.cs rename to Desktop.XPlat/ViewModels/FileTransferWindowViewModel.cs index ebe059e50..2a57534af 100644 --- a/Desktop.Linux/ViewModels/FileTransferWindowViewModel.cs +++ b/Desktop.XPlat/ViewModels/FileTransferWindowViewModel.cs @@ -4,8 +4,8 @@ using Remotely.Desktop.Core.Interfaces; using Remotely.Desktop.Core.Services; using Remotely.Desktop.Core.ViewModels; -using Remotely.Desktop.Linux.Services; -using Remotely.Desktop.Linux.Views; +using Remotely.Desktop.XPlat.Services; +using Remotely.Desktop.XPlat.Views; using System; using System.Collections.ObjectModel; using System.IO; @@ -13,7 +13,7 @@ using System.Threading.Tasks; using System.Windows.Input; -namespace Remotely.Desktop.Linux.ViewModels +namespace Remotely.Desktop.XPlat.ViewModels { public class FileTransferWindowViewModel : BrandedViewModelBase { diff --git a/Desktop.Linux/ViewModels/HostNamePromptViewModel.cs b/Desktop.XPlat/ViewModels/HostNamePromptViewModel.cs similarity index 84% rename from Desktop.Linux/ViewModels/HostNamePromptViewModel.cs rename to Desktop.XPlat/ViewModels/HostNamePromptViewModel.cs index 4a0f97bdd..db3d3c5dc 100644 --- a/Desktop.Linux/ViewModels/HostNamePromptViewModel.cs +++ b/Desktop.XPlat/ViewModels/HostNamePromptViewModel.cs @@ -1,9 +1,9 @@ using Avalonia.Controls; using ReactiveUI; -using Remotely.Desktop.Linux.Services; +using Remotely.Desktop.XPlat.Services; using System.Windows.Input; -namespace Remotely.Desktop.Linux.ViewModels +namespace Remotely.Desktop.XPlat.ViewModels { public class HostNamePromptViewModel : BrandedViewModelBase { diff --git a/Desktop.Linux/ViewModels/MainWindowViewModel.cs b/Desktop.XPlat/ViewModels/MainWindowViewModel.cs similarity index 98% rename from Desktop.Linux/ViewModels/MainWindowViewModel.cs rename to Desktop.XPlat/ViewModels/MainWindowViewModel.cs index 80858e732..6d5d040c1 100644 --- a/Desktop.Linux/ViewModels/MainWindowViewModel.cs +++ b/Desktop.XPlat/ViewModels/MainWindowViewModel.cs @@ -6,10 +6,10 @@ using Remotely.Desktop.Core; using Remotely.Desktop.Core.Interfaces; using Remotely.Desktop.Core.Services; -using Remotely.Desktop.Linux.Controls; -using Remotely.Desktop.Linux.Native; -using Remotely.Desktop.Linux.Services; -using Remotely.Desktop.Linux.Views; +using Remotely.Desktop.XPlat.Controls; +using Remotely.Desktop.XPlat.Native.Linux; +using Remotely.Desktop.XPlat.Services; +using Remotely.Desktop.XPlat.Views; using Remotely.Shared.Models; using Remotely.Shared.Utilities; using System; @@ -19,7 +19,7 @@ using System.Threading.Tasks; using System.Windows.Input; -namespace Remotely.Desktop.Linux.ViewModels +namespace Remotely.Desktop.XPlat.ViewModels { public class MainWindowViewModel : BrandedViewModelBase { diff --git a/Desktop.Linux/ViewModels/MessageBoxViewModel.cs b/Desktop.XPlat/ViewModels/MessageBoxViewModel.cs similarity index 92% rename from Desktop.Linux/ViewModels/MessageBoxViewModel.cs rename to Desktop.XPlat/ViewModels/MessageBoxViewModel.cs index 22b31fa6e..ba5a5e6c5 100644 --- a/Desktop.Linux/ViewModels/MessageBoxViewModel.cs +++ b/Desktop.XPlat/ViewModels/MessageBoxViewModel.cs @@ -1,10 +1,10 @@ using Avalonia.Controls; using ReactiveUI; -using Remotely.Desktop.Linux.Controls; -using Remotely.Desktop.Linux.Services; +using Remotely.Desktop.XPlat.Controls; +using Remotely.Desktop.XPlat.Services; using System.Windows.Input; -namespace Remotely.Desktop.Linux.ViewModels +namespace Remotely.Desktop.XPlat.ViewModels { public class MessageBoxViewModel : BrandedViewModelBase { diff --git a/Desktop.Linux/ViewModels/PromptForAccessWindowViewModel.cs b/Desktop.XPlat/ViewModels/PromptForAccessWindowViewModel.cs similarity index 95% rename from Desktop.Linux/ViewModels/PromptForAccessWindowViewModel.cs rename to Desktop.XPlat/ViewModels/PromptForAccessWindowViewModel.cs index 9b0f3b348..dbec8797c 100644 --- a/Desktop.Linux/ViewModels/PromptForAccessWindowViewModel.cs +++ b/Desktop.XPlat/ViewModels/PromptForAccessWindowViewModel.cs @@ -1,12 +1,12 @@ using Avalonia.Controls; using ReactiveUI; -using Remotely.Desktop.Linux.Services; +using Remotely.Desktop.XPlat.Services; using System; using System.Collections.Generic; using System.Text; using System.Windows.Input; -namespace Remotely.Desktop.Linux.ViewModels +namespace Remotely.Desktop.XPlat.ViewModels { public class PromptForAccessWindowViewModel : BrandedViewModelBase { diff --git a/Desktop.Linux/ViewModels/ReactiveViewModel.cs b/Desktop.XPlat/ViewModels/ReactiveViewModel.cs similarity index 67% rename from Desktop.Linux/ViewModels/ReactiveViewModel.cs rename to Desktop.XPlat/ViewModels/ReactiveViewModel.cs index 72886e72a..92bd489fe 100644 --- a/Desktop.Linux/ViewModels/ReactiveViewModel.cs +++ b/Desktop.XPlat/ViewModels/ReactiveViewModel.cs @@ -1,6 +1,6 @@ using ReactiveUI; -namespace Remotely.Desktop.Linux.ViewModels +namespace Remotely.Desktop.XPlat.ViewModels { public class ReactiveViewModel : ReactiveObject { diff --git a/Desktop.Linux/Views/ChatWindow.axaml b/Desktop.XPlat/Views/ChatWindow.axaml similarity index 97% rename from Desktop.Linux/Views/ChatWindow.axaml rename to Desktop.XPlat/Views/ChatWindow.axaml index 34b6d82ac..f91bef515 100644 --- a/Desktop.Linux/Views/ChatWindow.axaml +++ b/Desktop.XPlat/Views/ChatWindow.axaml @@ -2,10 +2,10 @@ xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" - xmlns:vm="clr-namespace:Remotely.Desktop.Linux.ViewModels;assembly=Remotely_Desktop" + xmlns:vm="clr-namespace:Remotely.Desktop.XPlat.ViewModels;assembly=Remotely_Desktop" xmlns:Models="clr-namespace:Remotely.Shared.Models;assembly=Remotely_Shared" mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450" - x:Class="Remotely.Desktop.Linux.Views.ChatWindow" + x:Class="Remotely.Desktop.XPlat.Views.ChatWindow" Icon="{Binding WindowIcon}" HasSystemDecorations="False" BorderBrush="DimGray" diff --git a/Desktop.Linux/Views/ChatWindow.axaml.cs b/Desktop.XPlat/Views/ChatWindow.axaml.cs similarity index 96% rename from Desktop.Linux/Views/ChatWindow.axaml.cs rename to Desktop.XPlat/Views/ChatWindow.axaml.cs index 2819e07d5..73ef3ceed 100644 --- a/Desktop.Linux/Views/ChatWindow.axaml.cs +++ b/Desktop.XPlat/Views/ChatWindow.axaml.cs @@ -1,11 +1,11 @@ using Avalonia; using Avalonia.Controls; using Avalonia.Markup.Xaml; -using Remotely.Desktop.Linux.ViewModels; +using Remotely.Desktop.XPlat.ViewModels; using System; using System.Threading.Tasks; -namespace Remotely.Desktop.Linux.Views +namespace Remotely.Desktop.XPlat.Views { public class ChatWindow : Window { diff --git a/Desktop.Linux/Views/FileTransferWindow.axaml b/Desktop.XPlat/Views/FileTransferWindow.axaml similarity index 93% rename from Desktop.Linux/Views/FileTransferWindow.axaml rename to Desktop.XPlat/Views/FileTransferWindow.axaml index dd78f64b9..f43a134a9 100644 --- a/Desktop.Linux/Views/FileTransferWindow.axaml +++ b/Desktop.XPlat/Views/FileTransferWindow.axaml @@ -2,10 +2,10 @@ xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" - xmlns:vm="clr-namespace:Remotely.Desktop.Linux.ViewModels;assembly=Remotely_Desktop" - xmlns:local="clr-namespace:Remotely.Desktop.Linux.Views;assembly=Remotely_Desktop" + xmlns:vm="clr-namespace:Remotely.Desktop.XPlat.ViewModels;assembly=Remotely_Desktop" + xmlns:local="clr-namespace:Remotely.Desktop.XPlat.Views;assembly=Remotely_Desktop" mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450" - x:Class="Remotely.Desktop.Linux.Views.FileTransferWindow" + x:Class="Remotely.Desktop.XPlat.Views.FileTransferWindow" Title="File Transfer" Height="300" Width="400" Topmost="True" diff --git a/Desktop.Linux/Views/FileTransferWindow.axaml.cs b/Desktop.XPlat/Views/FileTransferWindow.axaml.cs similarity index 94% rename from Desktop.Linux/Views/FileTransferWindow.axaml.cs rename to Desktop.XPlat/Views/FileTransferWindow.axaml.cs index 4a62b2546..0648eca12 100644 --- a/Desktop.Linux/Views/FileTransferWindow.axaml.cs +++ b/Desktop.XPlat/Views/FileTransferWindow.axaml.cs @@ -3,7 +3,7 @@ using Avalonia.Markup.Xaml; using System; -namespace Remotely.Desktop.Linux.Views +namespace Remotely.Desktop.XPlat.Views { public class FileTransferWindow : Window { diff --git a/Desktop.Linux/Views/HostNamePrompt.axaml b/Desktop.XPlat/Views/HostNamePrompt.axaml similarity index 89% rename from Desktop.Linux/Views/HostNamePrompt.axaml rename to Desktop.XPlat/Views/HostNamePrompt.axaml index f033013df..8ae7968ea 100644 --- a/Desktop.Linux/Views/HostNamePrompt.axaml +++ b/Desktop.XPlat/Views/HostNamePrompt.axaml @@ -3,8 +3,8 @@ xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450" - x:Class="Remotely.Desktop.Linux.Views.HostNamePrompt" - xmlns:ViewModels="clr-namespace:Remotely.Desktop.Linux.ViewModels;assembly=Remotely_Desktop" + x:Class="Remotely.Desktop.XPlat.Views.HostNamePrompt" + xmlns:ViewModels="clr-namespace:Remotely.Desktop.XPlat.ViewModels;assembly=Remotely_Desktop" Title="Host Name" Icon="{Binding WindowIcon}" Height="150" Width="350" diff --git a/Desktop.Linux/Views/HostNamePrompt.axaml.cs b/Desktop.XPlat/Views/HostNamePrompt.axaml.cs similarity index 79% rename from Desktop.Linux/Views/HostNamePrompt.axaml.cs rename to Desktop.XPlat/Views/HostNamePrompt.axaml.cs index 9b274b2f5..18208441c 100644 --- a/Desktop.Linux/Views/HostNamePrompt.axaml.cs +++ b/Desktop.XPlat/Views/HostNamePrompt.axaml.cs @@ -1,10 +1,10 @@ using Avalonia; using Avalonia.Controls; using Avalonia.Markup.Xaml; -using Remotely.Desktop.Linux.ViewModels; -using Remotely.Desktop.Linux.Views; +using Remotely.Desktop.XPlat.ViewModels; +using Remotely.Desktop.XPlat.Views; -namespace Remotely.Desktop.Linux.Views +namespace Remotely.Desktop.XPlat.Views { public class HostNamePrompt : Window { diff --git a/Desktop.Linux/Views/MainWindow.axaml b/Desktop.XPlat/Views/MainWindow.axaml similarity index 97% rename from Desktop.Linux/Views/MainWindow.axaml rename to Desktop.XPlat/Views/MainWindow.axaml index 8f74e5655..d7df046b5 100644 --- a/Desktop.Linux/Views/MainWindow.axaml +++ b/Desktop.XPlat/Views/MainWindow.axaml @@ -1,10 +1,10 @@  diff --git a/Desktop.Linux/Views/MainWindow.axaml.cs b/Desktop.XPlat/Views/MainWindow.axaml.cs similarity index 92% rename from Desktop.Linux/Views/MainWindow.axaml.cs rename to Desktop.XPlat/Views/MainWindow.axaml.cs index 7ee60f2f2..2a45aa64d 100644 --- a/Desktop.Linux/Views/MainWindow.axaml.cs +++ b/Desktop.XPlat/Views/MainWindow.axaml.cs @@ -1,9 +1,9 @@ using Avalonia; using Avalonia.Controls; using Avalonia.Markup.Xaml; -using Remotely.Desktop.Linux.ViewModels; +using Remotely.Desktop.XPlat.ViewModels; -namespace Remotely.Desktop.Linux.Views +namespace Remotely.Desktop.XPlat.Views { public class MainWindow : Window { diff --git a/Desktop.Linux/Views/PromptForAccessWindow.axaml b/Desktop.XPlat/Views/PromptForAccessWindow.axaml similarity index 96% rename from Desktop.Linux/Views/PromptForAccessWindow.axaml rename to Desktop.XPlat/Views/PromptForAccessWindow.axaml index e8ef7f3d7..56752d42e 100644 --- a/Desktop.Linux/Views/PromptForAccessWindow.axaml +++ b/Desktop.XPlat/Views/PromptForAccessWindow.axaml @@ -2,9 +2,9 @@ xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" - xmlns:vm="clr-namespace:Remotely.Desktop.Linux.ViewModels;assembly=Remotely_Desktop" + xmlns:vm="clr-namespace:Remotely.Desktop.XPlat.ViewModels;assembly=Remotely_Desktop" mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450" - x:Class="Remotely.Desktop.Linux.Views.PromptForAccessWindow" + x:Class="Remotely.Desktop.XPlat.Views.PromptForAccessWindow" HasSystemDecorations="False" BorderBrush="DimGray" BorderThickness="1" diff --git a/Desktop.Linux/Views/PromptForAccessWindow.axaml.cs b/Desktop.XPlat/Views/PromptForAccessWindow.axaml.cs similarity index 95% rename from Desktop.Linux/Views/PromptForAccessWindow.axaml.cs rename to Desktop.XPlat/Views/PromptForAccessWindow.axaml.cs index ffc93c29f..08cbacc80 100644 --- a/Desktop.Linux/Views/PromptForAccessWindow.axaml.cs +++ b/Desktop.XPlat/Views/PromptForAccessWindow.axaml.cs @@ -3,7 +3,7 @@ using Avalonia.Markup.Xaml; using System; -namespace Remotely.Desktop.Linux.Views +namespace Remotely.Desktop.XPlat.Views { public class PromptForAccessWindow : Window { diff --git a/Desktop.Linux/Views/SessionIndicatorWindow.axaml b/Desktop.XPlat/Views/SessionIndicatorWindow.axaml similarity index 88% rename from Desktop.Linux/Views/SessionIndicatorWindow.axaml rename to Desktop.XPlat/Views/SessionIndicatorWindow.axaml index 9a9ced59a..a382c17dd 100644 --- a/Desktop.Linux/Views/SessionIndicatorWindow.axaml +++ b/Desktop.XPlat/Views/SessionIndicatorWindow.axaml @@ -2,11 +2,11 @@ xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" - xmlns:vm="clr-namespace:Remotely.Desktop.Linux.ViewModels;assembly=Remotely_Desktop" + xmlns:vm="clr-namespace:Remotely.Desktop.XPlat.ViewModels;assembly=Remotely_Desktop" mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450" Width="300" Height="100" - x:Class="Remotely.Desktop.Linux.Views.SessionIndicatorWindow" + x:Class="Remotely.Desktop.XPlat.Views.SessionIndicatorWindow" Background="#2b2726" Title="{Binding ProductName}p" Icon="{Binding WindowIcon}" diff --git a/Desktop.Linux/Views/SessionIndicatorWindow.axaml.cs b/Desktop.XPlat/Views/SessionIndicatorWindow.axaml.cs similarity index 95% rename from Desktop.Linux/Views/SessionIndicatorWindow.axaml.cs rename to Desktop.XPlat/Views/SessionIndicatorWindow.axaml.cs index b07f1ae67..49616345b 100644 --- a/Desktop.Linux/Views/SessionIndicatorWindow.axaml.cs +++ b/Desktop.XPlat/Views/SessionIndicatorWindow.axaml.cs @@ -4,10 +4,10 @@ using Microsoft.Extensions.DependencyInjection; using Remotely.Desktop.Core; using Remotely.Desktop.Core.Interfaces; -using Remotely.Desktop.Linux.Controls; +using Remotely.Desktop.XPlat.Controls; using System; -namespace Remotely.Desktop.Linux.Views +namespace Remotely.Desktop.XPlat.Views { public class SessionIndicatorWindow : Window { diff --git a/Desktop.Linux/nuget.config b/Desktop.XPlat/nuget.config similarity index 100% rename from Desktop.Linux/nuget.config rename to Desktop.XPlat/nuget.config diff --git a/Remotely.sln b/Remotely.sln index c4e5c5f95..5b00862e4 100644 --- a/Remotely.sln +++ b/Remotely.sln @@ -29,7 +29,7 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Desktop.Core", "Desktop.Cor EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Shared", "Shared\Shared.csproj", "{3B1B36AE-7A60-4974-A868-1E24894D4149}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Desktop.Linux", "Desktop.Linux\Desktop.Linux.csproj", "{FF7FD66A-B3E2-4D39-A457-A00C94EDE9E6}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Desktop.XPlat", "Desktop.XPlat\Desktop.XPlat.csproj", "{FF7FD66A-B3E2-4D39-A457-A00C94EDE9E6}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Desktop.Win", "Desktop.Win\Desktop.Win.csproj", "{6B726FC4-A907-4813-BF38-3342E02AA8D2}" EndProject diff --git a/Server/API/ClientDownloadsController.cs b/Server/API/ClientDownloadsController.cs index 430b1c6ad..26e16c395 100644 --- a/Server/API/ClientDownloadsController.cs +++ b/Server/API/ClientDownloadsController.cs @@ -47,12 +47,12 @@ public async Task GetDesktop(string platformID) } case "UbuntuDesktop": { - var filePath = Path.Combine(_hostEnv.WebRootPath, "Content", "Remotely_Desktop"); + var filePath = Path.Combine(_hostEnv.WebRootPath, "Content", "Linux-x64", "Remotely_Desktop"); return await GetDesktopFile(filePath); } - case "MacOS": + case "MacOS-x64": { - var filePath = Path.Combine(_hostEnv.WebRootPath, "Content", "MacOS", "Remotely_Desktop"); + var filePath = Path.Combine(_hostEnv.WebRootPath, "Content", "MacOS-x64", "Remotely_Desktop"); return await GetDesktopFile(filePath); } default: @@ -78,12 +78,12 @@ public async Task GetDesktop(string platformId, string organizati } case "UbuntuDesktop": { - var filePath = Path.Combine(_hostEnv.WebRootPath, "Content", "Remotely_Desktop"); + var filePath = Path.Combine(_hostEnv.WebRootPath, "Content", "Linux-x64", "Remotely_Desktop"); return await GetDesktopFile(filePath, organizationId); } case "MacOS": { - var filePath = Path.Combine(_hostEnv.WebRootPath, "Content", "MacOS", "Remotely_Desktop"); + var filePath = Path.Combine(_hostEnv.WebRootPath, "Content", "MacOS-x64", "Remotely_Desktop"); return await GetDesktopFile(filePath); } default: @@ -182,9 +182,9 @@ private async Task GetInstallFile(string organizationId, string p return await GetBashInstaller(fileName, organizationId); } - case "MacOS": + case "MacOS-x64": { - var fileName = "Install-MacOS.sh"; + var fileName = "Install-MacOS-x64.sh"; return await GetBashInstaller(fileName, organizationId); } diff --git a/Server/Pages/Downloads.razor b/Server/Pages/Downloads.razor index 1bb6d7eb9..0bcc3fd0f 100644 --- a/Server/Pages/Downloads.razor +++ b/Server/Pages/Downloads.razor @@ -43,7 +43,7 @@

Download:
- macOS Executable + macOS Executable

@@ -188,13 +188,13 @@
-
macOS (10.5+)
+
macOS x64 (10.15+)

Download:
- macOS ZSH Installer + macOS ZSH Installer
- macOS Files Only + macOS Files Only

Example Install:
@@ -204,12 +204,12 @@

Example Local Install:
- sudo [path]/Install-MacOS.sh --path [path]/Remotely-MacOS.zip + sudo [path]/Install-MacOS-x64.sh --path [path]/Remotely-MacOS-x64.zip

Example Uninstall:
- sudo [path]/Install-MacOS.sh --uninstall + sudo [path]/Install-MacOS-x64.sh --uninstall

} diff --git a/Server/wwwroot/Content/Install-MacOS.sh b/Server/wwwroot/Content/Install-MacOS-x64.sh similarity index 100% rename from Server/wwwroot/Content/Install-MacOS.sh rename to Server/wwwroot/Content/Install-MacOS-x64.sh From cf67902c71cdf166e839d118848d1bb2967fc934 Mon Sep 17 00:00:00 2001 From: Jared Goodwin Date: Wed, 28 Apr 2021 15:56:08 -0700 Subject: [PATCH 06/22] Add Mac updater. --- Agent/Agent.csproj | 4 - Agent/Interfaces/IUpdater.cs | 5 +- Agent/Program.cs | 3 +- Agent/Services/UpdaterLinux.cs | 68 ++++---- Agent/Services/UpdaterMac.cs | 153 +++++++++++++++++- Agent/Services/UpdaterWin.cs | 74 ++++----- Agent/Services/WebClientEx.cs | 30 ++++ Server/API/AgentUpdateController.cs | 5 +- Server/API/ClientDownloadsController.cs | 2 +- Server/wwwroot/Content/Install-MacOS-x64.sh | 10 +- .../{ProcessLauncher.cs => ProcessInvoker.cs} | 3 +- 11 files changed, 259 insertions(+), 98 deletions(-) create mode 100644 Agent/Services/WebClientEx.cs rename Shared/Services/{ProcessLauncher.cs => ProcessInvoker.cs} (95%) diff --git a/Agent/Agent.csproj b/Agent/Agent.csproj index c390acb9d..c9964b9c0 100644 --- a/Agent/Agent.csproj +++ b/Agent/Agent.csproj @@ -40,8 +40,4 @@ - - - - diff --git a/Agent/Interfaces/IUpdater.cs b/Agent/Interfaces/IUpdater.cs index 562d07132..e9eda814f 100644 --- a/Agent/Interfaces/IUpdater.cs +++ b/Agent/Interfaces/IUpdater.cs @@ -1,8 +1,9 @@ -using System.Threading.Tasks; +using System; +using System.Threading.Tasks; namespace Remotely.Agent.Interfaces { - public interface IUpdater + public interface IUpdater : IDisposable { Task BeginChecking(); Task CheckForUpdates(); diff --git a/Agent/Program.cs b/Agent/Program.cs index 3ede2390c..650b4a32f 100644 --- a/Agent/Program.cs +++ b/Agent/Program.cs @@ -53,7 +53,8 @@ private static void BuildServices() serviceCollection.AddScoped(); serviceCollection.AddScoped(); serviceCollection.AddScoped(); - serviceCollection.AddScoped(); + serviceCollection.AddScoped(); + serviceCollection.AddScoped(); if (EnvironmentHelper.IsWindows) { diff --git a/Agent/Services/UpdaterLinux.cs b/Agent/Services/UpdaterLinux.cs index ef33689d4..187ce44c4 100644 --- a/Agent/Services/UpdaterLinux.cs +++ b/Agent/Services/UpdaterLinux.cs @@ -13,19 +13,23 @@ namespace Remotely.Agent.Services { + public class UpdaterLinux : IUpdater { - public UpdaterLinux(ConfigService configService) + private readonly SemaphoreSlim _checkForUpdatesLock = new SemaphoreSlim(1, 1); + private readonly ConfigService _configService; + private readonly IWebClientEx _webClientEx; + private readonly SemaphoreSlim _installLatestVersionLock = new SemaphoreSlim(1, 1); + private DateTimeOffset _lastUpdateFailure; + private readonly System.Timers.Timer _updateTimer = new System.Timers.Timer(TimeSpan.FromHours(6).TotalMilliseconds); + + public UpdaterLinux(ConfigService configService, IWebClientEx webClientEx) { - ConfigService = configService; + _configService = configService; + _webClientEx = webClientEx; + _webClientEx.SetRequestTimeout((int)_updateTimer.Interval); } - private SemaphoreSlim CheckForUpdatesLock { get; } = new SemaphoreSlim(1, 1); - private ConfigService ConfigService { get; } - private SemaphoreSlim InstallLatestVersionLock { get; } = new SemaphoreSlim(1, 1); - private DateTimeOffset LastUpdateFailure { get; set; } - private System.Timers.Timer UpdateTimer { get; } = new System.Timers.Timer(TimeSpan.FromHours(6).TotalMilliseconds); - public async Task BeginChecking() { @@ -35,30 +39,30 @@ public async Task BeginChecking() } await CheckForUpdates(); - UpdateTimer.Elapsed += UpdateTimer_Elapsed; - UpdateTimer.Start(); + _updateTimer.Elapsed += UpdateTimer_Elapsed; + _updateTimer.Start(); } public async Task CheckForUpdates() { try { - await CheckForUpdatesLock.WaitAsync(); + await _checkForUpdatesLock.WaitAsync(); if (EnvironmentHelper.IsDebug) { return; } - if (LastUpdateFailure.AddDays(1) > DateTimeOffset.Now) + if (_lastUpdateFailure.AddDays(1) > DateTimeOffset.Now) { Logger.Write("Skipping update check due to previous failure. Restart the service to try again, or manually install the update."); return; } - var connectionInfo = ConfigService.GetConnectionInfo(); - var serverUrl = ConfigService.GetConnectionInfo().Host; + var connectionInfo = _configService.GetConnectionInfo(); + var serverUrl = _configService.GetConnectionInfo().Host; var fileUrl = serverUrl + $"/Content/Remotely-Linux.zip"; @@ -98,22 +102,26 @@ public async Task CheckForUpdates() } finally { - CheckForUpdatesLock.Release(); + _checkForUpdatesLock.Release(); } } + public void Dispose() + { + _webClientEx?.Dispose(); + } + public async Task InstallLatestVersion() { try { - await InstallLatestVersionLock.WaitAsync(); + await _installLatestVersionLock.WaitAsync(); - var connectionInfo = ConfigService.GetConnectionInfo(); + var connectionInfo = _configService.GetConnectionInfo(); var serverUrl = connectionInfo.Host; Logger.Write("Service Updater: Downloading install package."); - using var wc = new WebClientEx((int)UpdateTimer.Interval); var downloadId = Guid.NewGuid().ToString(); var zipPath = Path.Combine(Path.GetTempPath(), "RemotelyUpdate.zip"); @@ -134,11 +142,11 @@ public async Task InstallLatestVersion() throw new PlatformNotSupportedException(); } - await wc.DownloadFileTaskAsync( + await _webClientEx.DownloadFileTaskAsync( serverUrl + $"/API/ClientDownloads/{connectionInfo.OrganizationID}/{platform}", installerPath); - await wc.DownloadFileTaskAsync( + await _webClientEx.DownloadFileTaskAsync( serverUrl + $"/API/AgentUpdate/DownloadPackage/linux/{downloadId}", zipPath); @@ -153,16 +161,16 @@ await wc.DownloadFileTaskAsync( catch (WebException ex) when (ex.Status == WebExceptionStatus.Timeout) { Logger.Write("Timed out while waiting to download update.", Shared.Enums.EventType.Warning); - LastUpdateFailure = DateTimeOffset.Now; + _lastUpdateFailure = DateTimeOffset.Now; } catch (Exception ex) { Logger.Write(ex); - LastUpdateFailure = DateTimeOffset.Now; + _lastUpdateFailure = DateTimeOffset.Now; } finally { - InstallLatestVersionLock.Release(); + _installLatestVersionLock.Release(); } } @@ -170,20 +178,6 @@ private async void UpdateTimer_Elapsed(object sender, System.Timers.ElapsedEvent { await CheckForUpdates(); } - private class WebClientEx : WebClient - { - private readonly int _requestTimeout; - public WebClientEx(int requestTimeout) - { - _requestTimeout = requestTimeout; - } - protected override WebRequest GetWebRequest(Uri uri) - { - WebRequest webRequest = base.GetWebRequest(uri); - webRequest.Timeout = _requestTimeout; - return webRequest; - } - } } } diff --git a/Agent/Services/UpdaterMac.cs b/Agent/Services/UpdaterMac.cs index 3a4cd8c3b..e44aa06f9 100644 --- a/Agent/Services/UpdaterMac.cs +++ b/Agent/Services/UpdaterMac.cs @@ -1,23 +1,168 @@ -using System.Threading.Tasks; using Remotely.Agent.Interfaces; +using Remotely.Shared.Utilities; +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.IO; +using System.Linq; +using System.Net; +using System.Runtime.InteropServices; +using System.Text; +using System.Threading; +using System.Threading.Tasks; + namespace Remotely.Agent.Services { public class UpdaterMac : IUpdater { + private readonly SemaphoreSlim _checkForUpdatesLock = new SemaphoreSlim(1, 1); + private readonly ConfigService _configService; + private readonly IWebClientEx _webClientEx; + private readonly SemaphoreSlim _installLatestVersionLock = new SemaphoreSlim(1, 1); + private DateTimeOffset _lastUpdateFailure; + private readonly System.Timers.Timer _updateTimer = new System.Timers.Timer(TimeSpan.FromHours(6).TotalMilliseconds); + + public UpdaterMac(ConfigService configService, IWebClientEx webClientEx) + { + _configService = configService; + _webClientEx = webClientEx; + _webClientEx.SetRequestTimeout((int)_updateTimer.Interval); + } + + public async Task BeginChecking() { - + if (EnvironmentHelper.IsDebug) + { + return; + } + + await CheckForUpdates(); + _updateTimer.Elapsed += UpdateTimer_Elapsed; + _updateTimer.Start(); } public async Task CheckForUpdates() { - + try + { + await _checkForUpdatesLock.WaitAsync(); + + if (EnvironmentHelper.IsDebug) + { + return; + } + + if (_lastUpdateFailure.AddDays(1) > DateTimeOffset.Now) + { + Logger.Write("Skipping update check due to previous failure. Restart the service to try again, or manually install the update."); + return; + } + + + var connectionInfo = _configService.GetConnectionInfo(); + var serverUrl = _configService.GetConnectionInfo().Host; + + var fileUrl = serverUrl + $"/Content/Remotely-MacOS.zip"; + + var lastEtag = string.Empty; + + if (File.Exists("etag.txt")) + { + lastEtag = await File.ReadAllTextAsync("etag.txt"); + } + + try + { + var wr = WebRequest.CreateHttp(fileUrl); + wr.Method = "Head"; + wr.Headers.Add("If-None-Match", lastEtag); + using var response = (HttpWebResponse)await wr.GetResponseAsync(); + if (response.StatusCode == HttpStatusCode.NotModified) + { + Logger.Write("Service Updater: Version is current."); + return; + } + } + catch (WebException ex) when ((ex.Response as HttpWebResponse).StatusCode == HttpStatusCode.NotModified) + { + Logger.Write("Service Updater: Version is current."); + return; + } + + Logger.Write("Service Updater: Update found."); + + await InstallLatestVersion(); + + } + catch (Exception ex) + { + Logger.Write(ex); + } + finally + { + _checkForUpdatesLock.Release(); + } + } + + public void Dispose() + { + _webClientEx?.Dispose(); } public async Task InstallLatestVersion() { - + try + { + await _installLatestVersionLock.WaitAsync(); + + var connectionInfo = _configService.GetConnectionInfo(); + var serverUrl = connectionInfo.Host; + + Logger.Write("Service Updater: Downloading install package."); + + var downloadId = Guid.NewGuid().ToString(); + var zipPath = Path.Combine(Path.GetTempPath(), "RemotelyUpdate.zip"); + + var installerPath = Path.Combine(Path.GetTempPath(), "RemotelyUpdate.sh"); + + await _webClientEx.DownloadFileTaskAsync( + serverUrl + $"/API/ClientDownloads/{connectionInfo.OrganizationID}/MacOSInstaller-x64", + installerPath); + + await _webClientEx.DownloadFileTaskAsync( + serverUrl + $"/API/AgentUpdate/DownloadPackage/macos-x64/{downloadId}", + zipPath); + + (await WebRequest.CreateHttp(serverUrl + $"/api/AgentUpdate/ClearDownload/{downloadId}").GetResponseAsync()).Dispose(); + + Logger.Write("Launching installer to perform update."); + + Process.Start("sudo", $"chmod +x {installerPath}").WaitForExit(); + + Process.Start("sudo", $"{installerPath} --path {zipPath}"); + } + catch (WebException ex) when (ex.Status == WebExceptionStatus.Timeout) + { + Logger.Write("Timed out while waiting to download update.", Shared.Enums.EventType.Warning); + _lastUpdateFailure = DateTimeOffset.Now; + } + catch (Exception ex) + { + Logger.Write(ex); + _lastUpdateFailure = DateTimeOffset.Now; + } + finally + { + _installLatestVersionLock.Release(); + } + } + + private async void UpdateTimer_Elapsed(object sender, System.Timers.ElapsedEventArgs e) + { + await CheckForUpdates(); } + } } diff --git a/Agent/Services/UpdaterWin.cs b/Agent/Services/UpdaterWin.cs index e97dd03ee..9248bdcc0 100644 --- a/Agent/Services/UpdaterWin.cs +++ b/Agent/Services/UpdaterWin.cs @@ -1,6 +1,4 @@ -using Microsoft.Extensions.DependencyInjection; -using Microsoft.Win32; -using Remotely.Agent.Interfaces; +using Remotely.Agent.Interfaces; using Remotely.Agent.Utilities; using Remotely.Shared.Utilities; using System; @@ -14,17 +12,20 @@ namespace Remotely.Agent.Services { public class UpdaterWin : IUpdater { - public UpdaterWin(ConfigService configService) - { - ConfigService = configService; - } + private readonly SemaphoreSlim _checkForUpdatesLock = new SemaphoreSlim(1, 1); + private readonly ConfigService _configService; + private readonly IWebClientEx _webClientEx; + private readonly SemaphoreSlim _installLatestVersionLock = new SemaphoreSlim(1, 1); + private readonly System.Timers.Timer _updateTimer = new System.Timers.Timer(TimeSpan.FromHours(6).TotalMilliseconds); + private DateTimeOffset _lastUpdateFailure; - private SemaphoreSlim CheckForUpdatesLock { get; } = new SemaphoreSlim(1, 1); - private ConfigService ConfigService { get; } - private SemaphoreSlim InstallLatestVersionLock { get; } = new SemaphoreSlim(1, 1); - private DateTimeOffset LastUpdateFailure { get; set; } - private System.Timers.Timer UpdateTimer { get; } = new System.Timers.Timer(TimeSpan.FromHours(6).TotalMilliseconds); + public UpdaterWin(ConfigService configService, IWebClientEx webClientEx) + { + _configService = configService; + _webClientEx = webClientEx; + _webClientEx.SetRequestTimeout((int)_updateTimer.Interval); + } public async Task BeginChecking() { @@ -39,30 +40,30 @@ public async Task BeginChecking() } await CheckForUpdates(); - UpdateTimer.Elapsed += UpdateTimer_Elapsed; - UpdateTimer.Start(); + _updateTimer.Elapsed += UpdateTimer_Elapsed; + _updateTimer.Start(); } public async Task CheckForUpdates() { try { - await CheckForUpdatesLock.WaitAsync(); + await _checkForUpdatesLock.WaitAsync(); if (EnvironmentHelper.IsDebug) { return; } - if (LastUpdateFailure.AddDays(1) > DateTimeOffset.Now) + if (_lastUpdateFailure.AddDays(1) > DateTimeOffset.Now) { Logger.Write("Skipping update check due to previous failure. Updating will be tried again after 24 hours have passed."); return; } - var connectionInfo = ConfigService.GetConnectionInfo(); - var serverUrl = ConfigService.GetConnectionInfo().Host; + var connectionInfo = _configService.GetConnectionInfo(); + var serverUrl = _configService.GetConnectionInfo().Host; var platform = Environment.Is64BitOperatingSystem ? "x64" : "x86"; var fileUrl = serverUrl + $"/Content/Remotely-Win10-{platform}.zip"; @@ -103,33 +104,37 @@ public async Task CheckForUpdates() } finally { - CheckForUpdatesLock.Release(); + _checkForUpdatesLock.Release(); } } + public void Dispose() + { + _webClientEx?.Dispose(); + } + public async Task InstallLatestVersion() { try { - await InstallLatestVersionLock.WaitAsync(); + await _installLatestVersionLock.WaitAsync(); - var connectionInfo = ConfigService.GetConnectionInfo(); + var connectionInfo = _configService.GetConnectionInfo(); var serverUrl = connectionInfo.Host; Logger.Write("Service Updater: Downloading install package."); - using var wc = new WebClientEx((int)UpdateTimer.Interval); var downloadId = Guid.NewGuid().ToString(); var zipPath = Path.Combine(Path.GetTempPath(), "RemotelyUpdate.zip"); var installerPath = Path.Combine(Path.GetTempPath(), "Remotely_Installer.exe"); var platform = Environment.Is64BitOperatingSystem ? "x64" : "x86"; - await wc.DownloadFileTaskAsync( + await _webClientEx.DownloadFileTaskAsync( serverUrl + $"/Content/Remotely_Installer.exe", installerPath); - await wc.DownloadFileTaskAsync( + await _webClientEx.DownloadFileTaskAsync( serverUrl + $"/api/AgentUpdate/DownloadPackage/win-{platform}/{downloadId}", zipPath); @@ -148,16 +153,16 @@ await wc.DownloadFileTaskAsync( catch (WebException ex) when (ex.Status == WebExceptionStatus.Timeout) { Logger.Write("Timed out while waiting to download update.", Shared.Enums.EventType.Warning); - LastUpdateFailure = DateTimeOffset.Now; + _lastUpdateFailure = DateTimeOffset.Now; } catch (Exception ex) { Logger.Write(ex); - LastUpdateFailure = DateTimeOffset.Now; + _lastUpdateFailure = DateTimeOffset.Now; } finally { - InstallLatestVersionLock.Release(); + _installLatestVersionLock.Release(); } } @@ -165,20 +170,5 @@ private async void UpdateTimer_Elapsed(object sender, System.Timers.ElapsedEvent { await CheckForUpdates(); } - private class WebClientEx : WebClient - { - private readonly int _requestTimeout; - - public WebClientEx(int requestTimeout) - { - _requestTimeout = requestTimeout; - } - protected override WebRequest GetWebRequest(Uri uri) - { - WebRequest webRequest = base.GetWebRequest(uri); - webRequest.Timeout = _requestTimeout; - return webRequest; - } - } } } diff --git a/Agent/Services/WebClientEx.cs b/Agent/Services/WebClientEx.cs new file mode 100644 index 000000000..6c5d0c774 --- /dev/null +++ b/Agent/Services/WebClientEx.cs @@ -0,0 +1,30 @@ +using System; +using System.Net; +using System.Threading.Tasks; + +namespace Remotely.Agent.Services +{ + public interface IWebClientEx : IDisposable + { + void SetRequestTimeout(int requestTimeoutMs); + Task DownloadFileTaskAsync(string address, string fileName); + } + + public class WebClientEx : WebClient, IWebClientEx + { + private int _requestTimeout; + + public void SetRequestTimeout(int requestTimeoutMs) + { + _requestTimeout = requestTimeoutMs; + } + + protected override WebRequest GetWebRequest(Uri uri) + { + WebRequest webRequest = base.GetWebRequest(uri); + webRequest.Timeout = _requestTimeout; + return webRequest; + } + } + +} \ No newline at end of file diff --git a/Server/API/AgentUpdateController.cs b/Server/API/AgentUpdateController.cs index 19163586a..a99ec0a6a 100644 --- a/Server/API/AgentUpdateController.cs +++ b/Server/API/AgentUpdateController.cs @@ -104,8 +104,11 @@ public async Task DownloadPackage(string platform, string download case "linux": filePath = Path.Combine(HostEnv.WebRootPath, "Content", "Remotely-Linux.zip"); break; + case "macos-x64": + filePath = Path.Combine(HostEnv.WebRootPath, "Content", "Remotely-MacOS-x64.zip"); + break; default: - DataService.WriteEvent($"Unknown platform requested in { nameof(AgentUpdateController)}. " + + DataService.WriteEvent($"Unknown platform requested in {nameof(AgentUpdateController)}. " + $"Platform: {platform}. " + $"IP: {remoteIp}.", EventType.Warning, diff --git a/Server/API/ClientDownloadsController.cs b/Server/API/ClientDownloadsController.cs index 26e16c395..bf3e8a749 100644 --- a/Server/API/ClientDownloadsController.cs +++ b/Server/API/ClientDownloadsController.cs @@ -182,7 +182,7 @@ private async Task GetInstallFile(string organizationId, string p return await GetBashInstaller(fileName, organizationId); } - case "MacOS-x64": + case "MacOSInstaller-x64": { var fileName = "Install-MacOS-x64.sh"; diff --git a/Server/wwwroot/Content/Install-MacOS-x64.sh b/Server/wwwroot/Content/Install-MacOS-x64.sh index 883b724f9..bc9ab625a 100644 --- a/Server/wwwroot/Content/Install-MacOS-x64.sh +++ b/Server/wwwroot/Content/Install-MacOS-x64.sh @@ -49,15 +49,15 @@ cd /Applications/Remotely/ if [ -z "$UpdatePackagePath" ]; then echo "Downloading client..." >> /tmp/Remotely_Install.log - wget $HostName/Content/Remotely-MacOS.zip + wget $HostName/Content/Remotely-MacOS-x64.zip else echo "Copying install files..." >> /tmp/Remotely_Install.log - cp "$UpdatePackagePath" /Applications/Remotely/Remotely-MacOS.zip + cp "$UpdatePackagePath" /Applications/Remotely/Remotely-MacOS-x64.zip rm -f "$UpdatePackagePath" fi -unzip ./Remotely-MacOS.zip -rm -f ./Remotely-MacOS.zip +unzip ./Remotely-MacOS-x64.zip +rm -f ./Remotely-MacOS-x64.zip connectionInfo="{ @@ -69,7 +69,7 @@ connectionInfo="{ echo "$connectionInfo" > ./ConnectionInfo.json -curl --head $HostName/Content/Remotely-MacOS.zip | grep -i "etag" | cut -d' ' -f 2 > ./etag.txt +curl --head $HostName/Content/Remotely-MacOS-x64.zip | grep -i "etag" | cut -d' ' -f 2 > ./etag.txt plistFile=" diff --git a/Shared/Services/ProcessLauncher.cs b/Shared/Services/ProcessInvoker.cs similarity index 95% rename from Shared/Services/ProcessLauncher.cs rename to Shared/Services/ProcessInvoker.cs index dca50e7c7..8cf77f19b 100644 --- a/Shared/Services/ProcessLauncher.cs +++ b/Shared/Services/ProcessInvoker.cs @@ -8,7 +8,8 @@ public interface IProcessInvoker { string InvokeProcessOutput(string command, string arguments); } - public class ProcessLauncher : IProcessInvoker + + public class ProcessInvoker : IProcessInvoker { public string InvokeProcessOutput(string command, string arguments) { From d594527448edfaa83e2e9841bcbe81c2d86d0d51 Mon Sep 17 00:00:00 2001 From: Jared Goodwin Date: Thu, 6 May 2021 06:22:29 -0700 Subject: [PATCH 07/22] Display message when attempting MacOS remote control. --- Agent/Services/AppLauncherMac.cs | 5 +++-- Server/API/ClientDownloadsController.cs | 2 +- Server/Pages/Downloads.razor | 2 +- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/Agent/Services/AppLauncherMac.cs b/Agent/Services/AppLauncherMac.cs index cc11855aa..b9bed7652 100644 --- a/Agent/Services/AppLauncherMac.cs +++ b/Agent/Services/AppLauncherMac.cs @@ -9,17 +9,18 @@ public class AppLauncherMac : IAppLauncher { public async Task LaunchChatService(string orgName, string requesterID, HubConnection hubConnection) { + await hubConnection.SendAsync("DisplayMessage", "Feature under development.", "Feature is under development.", "bg-warning", requesterID); return 0; } public async Task LaunchRemoteControl(int targetSessionId, string requesterID, string serviceID, HubConnection hubConnection) { - + await hubConnection.SendAsync("DisplayMessage", "Feature under development.", "Feature is under development.", "bg-warning", requesterID); } public async Task RestartScreenCaster(List viewerIDs, string serviceID, string requesterID, HubConnection hubConnection, int targetSessionID = -1) { - + await hubConnection.SendAsync("DisplayMessage", "Feature under development.", "Feature is under development.", "bg-warning", requesterID); } } } diff --git a/Server/API/ClientDownloadsController.cs b/Server/API/ClientDownloadsController.cs index bf3e8a749..adee41856 100644 --- a/Server/API/ClientDownloadsController.cs +++ b/Server/API/ClientDownloadsController.cs @@ -81,7 +81,7 @@ 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 "MacOS": + case "MacOS-x64": { var filePath = Path.Combine(_hostEnv.WebRootPath, "Content", "MacOS-x64", "Remotely_Desktop"); return await GetDesktopFile(filePath); diff --git a/Server/Pages/Downloads.razor b/Server/Pages/Downloads.razor index 0bcc3fd0f..98349f867 100644 --- a/Server/Pages/Downloads.razor +++ b/Server/Pages/Downloads.razor @@ -192,7 +192,7 @@

Download:
- macOS ZSH Installer + macOS ZSH Installer
macOS Files Only

From f9a4fcd19f60b69d823e59732f15221cd790d90e Mon Sep 17 00:00:00 2001 From: Jared Goodwin Date: Thu, 6 May 2021 07:39:21 -0700 Subject: [PATCH 08/22] Add Mac agent to Actions workflow. --- .github/workflows/build.yml | 48 ++++++++++++++++++++++++++++++++++++- 1 file changed, 47 insertions(+), 1 deletion(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 06d26167c..97949c815 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -32,11 +32,50 @@ on: default: "linux-x64" jobs: + build-mac: + runs-on: macos-10.15 + + steps: + - name: Checkout + uses: actions/checkout@v2 + + - name: Install .NET Core + uses: actions/setup-dotnet@v1.7.2 + + - name: Set current version + shell: powershell + run: | + $VersionString = git show -s --format=%ci + $VersionDate = [DateTimeOffset]::Parse($VersionString) + + $Year = $VersionDate.Year.ToString() + $Month = $VersionDate.Month.ToString().PadLeft(2, "0") + $Day = $VersionDate.Day.ToString().PadLeft(2, "0") + $Hour = $VersionDate.Hour.ToString().PadLeft(2, "0") + $Minute = $VersionDate.Minute.ToString().PadLeft(2, "0") + $CurrentVersion = "$Year.$Month.$Day.$Hour$Minute" + + echo "CurrentVersion=$CurrentVersion" >> $GITHUB_ENV + + Write-Host "Setting current version to $CurrentVersion." - build: + - name: Set current version + shell: powershell + run: | + dotnet publish /p:Version=$env:CurrentVersion /p:FileVersion=$env:CurrentVersion --runtime osx-x64 --configuration Release --output "./Agent/bin/publish" ".\Agent" + Compress-Archive -Path "./Agent/bin/publish/*" -DestinationPath "./Agent/bin/Remotely-MacOS-x64.zip" -Force + + - name: Upload build artifact + uses: actions/upload-artifact@v2 + with: + path: ./Agent/bin/Remotely-MacOS-x64.zip + name: Mac-Agent-x64 + + build-windows: runs-on: windows-latest # For a list of available runner types, refer to # https://help.github.com/en/actions/reference/workflow-syntax-for-github-actions#jobsjob_idruns-on + needs: build-mac env: Solution_Name: Remotely.sln @@ -46,6 +85,13 @@ jobs: ServerUrl: ${{ github.event.inputs.serverUrl }} steps: + + - uses: actions/download-artifact@v2 + with: + name: Mac-Agent-x64 + path: ./Server/wwwroot/Content/Remotely-MacOS-x64.zip + + - name: Checkout uses: actions/checkout@v2 with: From bf584b204e454b077d8425a50a2a64ccd027c058 Mon Sep 17 00:00:00 2001 From: Jared Goodwin Date: Fri, 7 May 2021 07:02:27 -0700 Subject: [PATCH 09/22] Fix macOS installer. --- Agent/Services/UpdaterMac.cs | 2 +- Server/wwwroot/Content/Install-MacOS-x64.sh | 51 ++++++++++----------- 2 files changed, 26 insertions(+), 27 deletions(-) diff --git a/Agent/Services/UpdaterMac.cs b/Agent/Services/UpdaterMac.cs index e44aa06f9..7f295d476 100644 --- a/Agent/Services/UpdaterMac.cs +++ b/Agent/Services/UpdaterMac.cs @@ -64,7 +64,7 @@ public async Task CheckForUpdates() var connectionInfo = _configService.GetConnectionInfo(); var serverUrl = _configService.GetConnectionInfo().Host; - var fileUrl = serverUrl + $"/Content/Remotely-MacOS.zip"; + var fileUrl = serverUrl + $"/Content/Remotely-MacOS-x64.zip"; var lastEtag = string.Empty; diff --git a/Server/wwwroot/Content/Install-MacOS-x64.sh b/Server/wwwroot/Content/Install-MacOS-x64.sh index bc9ab625a..1f42f818c 100644 --- a/Server/wwwroot/Content/Install-MacOS-x64.sh +++ b/Server/wwwroot/Content/Install-MacOS-x64.sh @@ -11,9 +11,9 @@ ArgLength=${#Args[@]} for (( i=0; i<${ArgLength}; i+=2 )); do if [ "${Args[$i]}" = "--uninstall" ]; then - launchctl unload -w /System/Library/LaunchDaemons/remotely-agent.plist - rm -r -f /Applications/Remotely/ - rm -f /System/Library/LaunchDaemons/remotely-agent.plist + launchctl unload -w /Library/LaunchDaemons/remotely-agent.plist + rm -r -f /usr/local/bin/Remotely/ + rm -f /Library/LaunchDaemons/remotely-agent.plist exit elif [ "${Args[$i]}" = "--path" ]; then UpdatePackagePath="${Args[$i+1]}" @@ -22,41 +22,41 @@ done # Install Homebrew -/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)" -brew update +su - $SUDO_USER -c '/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"' +su - $SUDO_USER -c "brew update" # Install .NET Runtime -brew install --cask dotnet +su - $SUDO_USER -c "brew install --cask dotnet" # Install dependency for System.Drawing.Common -brew install mono-libgdiplus +su - $SUDO_USER -c "brew install mono-libgdiplus" # Install other dependencies -brew install wget -brew install curl -brew install jq +su - $SUDO_USER -c "brew install curl" +su - $SUDO_USER -c "brew install jq" -if [ -f "/Applications/Remotely/ConnectionInfo.json" ]; then - GUID=`cat "/Applications/Remotely/ConnectionInfo.json" | jq -r '.DeviceID'` +if [ -f "/usr/local/bin/Remotely/ConnectionInfo.json" ]; then + GUID=`cat "/usr/local/bin/Remotely/ConnectionInfo.json" | jq -r '.DeviceID'` fi rm -r -f /Applications/Remotely -rm -f /System/Library/LaunchDaemons/remotely-agent.plist +rm -f /Library/LaunchDaemons/remotely-agent.plist -mkdir -p /Applications/Remotely/ -cd /Applications/Remotely/ +mkdir -p /usr/local/bin/Remotely/ +chmod -R 755 /usr/local/bin/Remotely/ +cd /usr/local/bin/Remotely/ if [ -z "$UpdatePackagePath" ]; then echo "Downloading client..." >> /tmp/Remotely_Install.log - wget $HostName/Content/Remotely-MacOS-x64.zip + curl $HostName/Content/Remotely-MacOS-x64.zip --output /usr/local/bin/Remotely/Remotely-MacOS-x64.zip else echo "Copying install files..." >> /tmp/Remotely_Install.log - cp "$UpdatePackagePath" /Applications/Remotely/Remotely-MacOS-x64.zip + cp "$UpdatePackagePath" /usr/local/bin/Remotely/Remotely-MacOS-x64.zip rm -f "$UpdatePackagePath" fi -unzip ./Remotely-MacOS-x64.zip +unzip -o ./Remotely-MacOS-x64.zip rm -f ./Remotely-MacOS-x64.zip @@ -72,8 +72,7 @@ echo "$connectionInfo" > ./ConnectionInfo.json curl --head $HostName/Content/Remotely-MacOS-x64.zip | grep -i "etag" | cut -d' ' -f 2 > ./etag.txt -plistFile=" - +plistFile=" @@ -81,14 +80,14 @@ plistFile=" com.translucency.remotely-agent ProgramArguments - /usr/bin/dotnet - /Applications/Remotely/Remotely_Agent.dll + /usr/local/bin/dotnet + /usr/local/bin/Remotely/Remotely_Agent.dll KeepAlive - -" -echo "$plistFile" > "/System/Library/LaunchDaemons/remotely-agent.plist" +" +echo "$plistFile" > "/Library/LaunchDaemons/remotely-agent.plist" -launchctl load -w /System/Library/LaunchDaemons/remotely-agent.plist \ No newline at end of file +launchctl load -w /Library/LaunchDaemons/remotely-agent.plist +launchctl kickstart -k system/com.translucency.remotely-agent \ No newline at end of file From 25706e57049efedf296e5dee271651fbdd28b74e Mon Sep 17 00:00:00 2001 From: Jared Goodwin Date: Fri, 7 May 2021 07:02:49 -0700 Subject: [PATCH 10/22] Extend timeout for GitHub API calls. --- Server.Installer/Services/GitHubApi.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/Server.Installer/Services/GitHubApi.cs b/Server.Installer/Services/GitHubApi.cs index 1aef0dd88..3d98cdfa7 100644 --- a/Server.Installer/Services/GitHubApi.cs +++ b/Server.Installer/Services/GitHubApi.cs @@ -30,6 +30,7 @@ public class GitHubApi : IGitHubApi public GitHubApi() { _httpClient = new HttpClient(); + _httpClient.Timeout = TimeSpan.FromHours(8); _httpClient.DefaultRequestHeaders.Add("User-Agent", "Remotely Server Installer"); } From d2a28cedc44ef84b46f07ff40fe22af9498d089b Mon Sep 17 00:00:00 2001 From: Jared Goodwin Date: Fri, 7 May 2021 07:03:43 -0700 Subject: [PATCH 11/22] Fix handling of existing w3wp processes. --- Server.Installer/Services/ServerInstaller.cs | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/Server.Installer/Services/ServerInstaller.cs b/Server.Installer/Services/ServerInstaller.cs index aa2fe41d3..5540530a7 100644 --- a/Server.Installer/Services/ServerInstaller.cs +++ b/Server.Installer/Services/ServerInstaller.cs @@ -100,11 +100,20 @@ public async Task PerformInstall(CliParams cliParams) // website process first. if (cliParams.WebServer == WebServerType.IisWindows) { - var initialW3wpCount = Process.GetProcessesByName("w3wp").Length; - Process.Start("powershell.exe", "-Command & \"{ Stop-WebAppPool -Name Remotely -ErrorAction SilentlyContinue }\"").WaitForExit(); - Process.Start("powershell.exe", "-Command & \"{ Stop-Website -Name Remotely -ErrorAction SilentlyContinue }\"").WaitForExit(); - ConsoleHelper.WriteLine("Waiting for w3wp processes to close..."); - TaskHelper.DelayUntil(() => Process.GetProcessesByName("w3wp").Length < initialW3wpCount, TimeSpan.FromMinutes(5), 100); + var w3wpProcs = Process.GetProcessesByName("w3wp"); + if (w3wpProcs.Length > 0) + { + Process.Start("powershell.exe", "-Command & \"{ Stop-WebAppPool -Name Remotely -ErrorAction SilentlyContinue }\"").WaitForExit(); + Process.Start("powershell.exe", "-Command & \"{ Stop-Website -Name Remotely -ErrorAction SilentlyContinue }\"").WaitForExit(); + + ConsoleHelper.WriteLine("Waiting for w3wp processes to close..."); + foreach (var proc in w3wpProcs) + { + try { proc.Kill(); } + catch { } + } + TaskHelper.DelayUntil(() => Process.GetProcessesByName("w3wp").Length < w3wpProcs.Length, TimeSpan.FromMinutes(5), 100); + } } ConsoleHelper.WriteLine("Extracting files."); From 6a64e2dac6c3909b95a7165c30191e75968d4ce3 Mon Sep 17 00:00:00 2001 From: Jared Goodwin Date: Fri, 7 May 2021 07:04:05 -0700 Subject: [PATCH 12/22] Use lock when updating devices. --- .../Components/Devices/DevicesFrame.razor.cs | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/Server/Components/Devices/DevicesFrame.razor.cs b/Server/Components/Devices/DevicesFrame.razor.cs index 7e07f8e0f..59c7dd033 100644 --- a/Server/Components/Devices/DevicesFrame.razor.cs +++ b/Server/Components/Devices/DevicesFrame.razor.cs @@ -27,6 +27,7 @@ namespace Remotely.Server.Components.Devices [Authorize] public partial class DevicesFrame : AuthComponentBase, IDisposable { + private readonly object _devicesLock = new(); private readonly List _allDevices = new(); private readonly string _deviceGroupAll = Guid.NewGuid().ToString(); private readonly string _deviceGroupNone = Guid.NewGuid().ToString(); @@ -89,8 +90,11 @@ public void Dispose() public void Refresh() { - LoadDevices(); - InvokeAsync(StateHasChanged); + lock (_devicesLock) + { + LoadDevices(); + InvokeAsync(StateHasChanged); + } } protected override async Task OnInitializedAsync() @@ -112,7 +116,10 @@ protected override async Task OnInitializedAsync() _sortableProperties.AddRange(sortableProperties); - LoadDevices(); + lock (_devicesLock) + { + LoadDevices(); + } } protected override bool ShouldRender() @@ -120,7 +127,10 @@ protected override bool ShouldRender() var shouldRender = base.ShouldRender(); if (shouldRender) { - FilterDevices(); + lock (_devicesLock) + { + FilterDevices(); + } } return shouldRender; } From 4c210c29659c77174a1f5f808be5615a3ab9f90b Mon Sep 17 00:00:00 2001 From: Jared Goodwin Date: Fri, 7 May 2021 07:04:23 -0700 Subject: [PATCH 13/22] Rework formatting of Downloads page. --- Server/Pages/Downloads.razor | 37 ++++++++++-------------------------- 1 file changed, 10 insertions(+), 27 deletions(-) diff --git a/Server/Pages/Downloads.razor b/Server/Pages/Downloads.razor index 98349f867..61cc82081 100644 --- a/Server/Pages/Downloads.razor +++ b/Server/Pages/Downloads.razor @@ -15,34 +15,26 @@ Instant desktop sharing. No account required.
-
Windows (64-Bit)
+ Windows (64-Bit)

- Download: -
Windows EXE

-
Windows (32-Bit)
+ Windows (32-Bit)

- Download: -
Windows EXE

-
Linux 64-Bit
+ Linux 64-Bit

- Download: -
Ubuntu Executable

-
macOS (10.15+)
+ macOS (Catalina)

- Download: -
macOS Executable

@@ -64,24 +56,20 @@
-
Windows (64-Bit)
+ Windows (64-Bit)

Note: Only the default organization's branding will apply to these.

- Download: -
Windows Installer

-
Windows (32-Bit)
+ Windows (32-Bit)

Note: Only the default organization's branding will apply to these.

- Download: -
Windows Installer

@@ -104,13 +92,11 @@ else {
-
Windows 10 / 8.1 / 7 (64-Bit and 32-Bit)
+ Windows 10 / 8.1 / 7 (64-Bit and 32-Bit)

Note: GPU-accelerated screen capture and PowerShell Core is unavailable on Windows 7.

- Download: -
Windows Installer (x64/x86)
Windows x64 Files Only @@ -131,7 +117,7 @@

Example Quiet Uninstall:
-
+ Remotely_Installer.exe -uninstall -quiet

@@ -161,9 +147,8 @@

-
Linux 64-Bit
+ Linux 64-Bit

- Download: Ubuntu x64 Bash Installer
Manjaro x64 Bash Installer @@ -188,10 +173,8 @@

-
macOS x64 (10.15+)
+ macOS x64 (Catalina)

- Download: -
macOS ZSH Installer
macOS Files Only From 7433f919c35c0d345dc49c58ffb5ea578bbd52a4 Mon Sep 17 00:00:00 2001 From: Jared Goodwin Date: Fri, 7 May 2021 07:53:59 -0700 Subject: [PATCH 14/22] Add condition for device no longer existing when filtering users. --- Server/Services/DataService.cs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/Server/Services/DataService.cs b/Server/Services/DataService.cs index 578dc121e..a68f2b73a 100644 --- a/Server/Services/DataService.cs +++ b/Server/Services/DataService.cs @@ -2091,6 +2091,11 @@ private string[] FilterUsersByDevicePermissionInternal(AppDb dbContext, IEnumera .ThenInclude(x => x.Users) .FirstOrDefault(x => x.ID == deviceID); + if (device is null) + { + return Array.Empty(); + } + var orgUsers = dbContext.Users .Where(user => user.OrganizationID == device.OrganizationID && From a864c01a76aa44c48a3acbad3207e91c05c49ad9 Mon Sep 17 00:00:00 2001 From: Jared Goodwin Date: Fri, 7 May 2021 07:54:09 -0700 Subject: [PATCH 15/22] Fix UUID gen. --- Server/wwwroot/Content/Install-MacOS-x64.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Server/wwwroot/Content/Install-MacOS-x64.sh b/Server/wwwroot/Content/Install-MacOS-x64.sh index 1f42f818c..fbbb1894b 100644 --- a/Server/wwwroot/Content/Install-MacOS-x64.sh +++ b/Server/wwwroot/Content/Install-MacOS-x64.sh @@ -2,7 +2,7 @@ HostName= Organization= -GUID=$(uuidgen) +GUID="$(uuidgen)" UpdatePackagePath="" Args=( "$@" ) From a43732db6412381eb7ca407179c3193f11069dfb Mon Sep 17 00:00:00 2001 From: Jared Goodwin Date: Fri, 7 May 2021 10:47:10 -0700 Subject: [PATCH 16/22] Add macOS arm64. --- Agent/Services/UpdaterMac.cs | 7 +- Server/API/ClientDownloadsController.cs | 16 ++++ Server/Pages/Downloads.razor | 11 ++- Server/wwwroot/Content/Install-MacOS-arm64.sh | 93 +++++++++++++++++++ Server/wwwroot/Content/Install-MacOS-x64.sh | 2 +- 5 files changed, 122 insertions(+), 7 deletions(-) create mode 100644 Server/wwwroot/Content/Install-MacOS-arm64.sh diff --git a/Agent/Services/UpdaterMac.cs b/Agent/Services/UpdaterMac.cs index 7f295d476..38e803c08 100644 --- a/Agent/Services/UpdaterMac.cs +++ b/Agent/Services/UpdaterMac.cs @@ -16,6 +16,7 @@ namespace Remotely.Agent.Services { public class UpdaterMac : IUpdater { + private readonly string _achitecture = RuntimeInformation.OSArchitecture.ToString().ToLower(); private readonly SemaphoreSlim _checkForUpdatesLock = new SemaphoreSlim(1, 1); private readonly ConfigService _configService; private readonly IWebClientEx _webClientEx; @@ -64,7 +65,7 @@ public async Task CheckForUpdates() var connectionInfo = _configService.GetConnectionInfo(); var serverUrl = _configService.GetConnectionInfo().Host; - var fileUrl = serverUrl + $"/Content/Remotely-MacOS-x64.zip"; + var fileUrl = serverUrl + $"/Content/Remotely-MacOS-{_achitecture}.zip"; var lastEtag = string.Empty; @@ -128,11 +129,11 @@ public async Task InstallLatestVersion() var installerPath = Path.Combine(Path.GetTempPath(), "RemotelyUpdate.sh"); await _webClientEx.DownloadFileTaskAsync( - serverUrl + $"/API/ClientDownloads/{connectionInfo.OrganizationID}/MacOSInstaller-x64", + serverUrl + $"/API/ClientDownloads/{connectionInfo.OrganizationID}/MacOSInstaller-{_achitecture}", installerPath); await _webClientEx.DownloadFileTaskAsync( - serverUrl + $"/API/AgentUpdate/DownloadPackage/macos-x64/{downloadId}", + serverUrl + $"/API/AgentUpdate/DownloadPackage/macos-{_achitecture}/{downloadId}", zipPath); (await WebRequest.CreateHttp(serverUrl + $"/api/AgentUpdate/ClearDownload/{downloadId}").GetResponseAsync()).Dispose(); diff --git a/Server/API/ClientDownloadsController.cs b/Server/API/ClientDownloadsController.cs index adee41856..86e51f6fa 100644 --- a/Server/API/ClientDownloadsController.cs +++ b/Server/API/ClientDownloadsController.cs @@ -55,6 +55,11 @@ public async Task GetDesktop(string platformID) var filePath = Path.Combine(_hostEnv.WebRootPath, "Content", "MacOS-x64", "Remotely_Desktop"); return await GetDesktopFile(filePath); } + case "MacOS-arm64": + { + var filePath = Path.Combine(_hostEnv.WebRootPath, "Content", "MacOS-arm64", "Remotely_Desktop"); + return await GetDesktopFile(filePath); + } default: return NotFound(); } @@ -86,6 +91,11 @@ public async Task GetDesktop(string platformId, string organizati var filePath = Path.Combine(_hostEnv.WebRootPath, "Content", "MacOS-x64", "Remotely_Desktop"); return await GetDesktopFile(filePath); } + case "MacOS-arm64": + { + var filePath = Path.Combine(_hostEnv.WebRootPath, "Content", "MacOS-arm64", "Remotely_Desktop"); + return await GetDesktopFile(filePath); + } default: return NotFound(); } @@ -186,6 +196,12 @@ private async Task GetInstallFile(string organizationId, string p { var fileName = "Install-MacOS-x64.sh"; + return await GetBashInstaller(fileName, organizationId); + } + case "MacOSInstaller-arm64": + { + var fileName = "Install-MacOS-arm64.sh"; + return await GetBashInstaller(fileName, organizationId); } default: diff --git a/Server/Pages/Downloads.razor b/Server/Pages/Downloads.razor index 61cc82081..b6f31d86c 100644 --- a/Server/Pages/Downloads.razor +++ b/Server/Pages/Downloads.razor @@ -35,7 +35,8 @@

@@ -175,9 +176,13 @@
macOS x64 (Catalina)

- macOS ZSH Installer + macOS x64 Bash Installer
- macOS Files Only + macOS x64 Files Only +
+ macOS arm64 Bash Installer +
+ macOS arm64 Files Only

Example Install:
diff --git a/Server/wwwroot/Content/Install-MacOS-arm64.sh b/Server/wwwroot/Content/Install-MacOS-arm64.sh new file mode 100644 index 000000000..246acf71e --- /dev/null +++ b/Server/wwwroot/Content/Install-MacOS-arm64.sh @@ -0,0 +1,93 @@ +#!/bin/bash + +HostName= +Organization= +GUID="$(uuidgen)" +UpdatePackagePath="" + +Args=( "$@" ) +ArgLength=${#Args[@]} + +for (( i=0; i<${ArgLength}; i+=2 )); +do + if [ "${Args[$i]}" = "--uninstall" ]; then + launchctl unload -w /Library/LaunchDaemons/remotely-agent.plist + rm -r -f /usr/local/bin/Remotely/ + rm -f /Library/LaunchDaemons/remotely-agent.plist + exit + elif [ "${Args[$i]}" = "--path" ]; then + UpdatePackagePath="${Args[$i+1]}" + fi +done + + +# Install Homebrew +su - $SUDO_USER -c '/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"' +su - $SUDO_USER -c "brew update" + +# Install .NET Runtime +su - $SUDO_USER -c "brew install --cask dotnet" + +# Install dependency for System.Drawing.Common +su - $SUDO_USER -c "brew install mono-libgdiplus" + +# Install other dependencies +su - $SUDO_USER -c "brew install curl" +su - $SUDO_USER -c "brew install jq" + + +if [ -f "/usr/local/bin/Remotely/ConnectionInfo.json" ]; then + GUID=`cat "/usr/local/bin/Remotely/ConnectionInfo.json" | jq -r '.DeviceID'` +fi + +rm -r -f /Applications/Remotely +rm -f /Library/LaunchDaemons/remotely-agent.plist + +mkdir -p /usr/local/bin/Remotely/ +chmod -R 755 /usr/local/bin/Remotely/ +cd /usr/local/bin/Remotely/ + +if [ -z "$UpdatePackagePath" ]; then + echo "Downloading client..." >> /tmp/Remotely_Install.log + curl $HostName/Content/Remotely-MacOS-arm64.zip --output /usr/local/bin/Remotely/Remotely-MacOS-arm64.zip +else + echo "Copying install files..." >> /tmp/Remotely_Install.log + cp "$UpdatePackagePath" /usr/local/bin/Remotely/Remotely-MacOS-arm64.zip + rm -f "$UpdatePackagePath" +fi + +unzip -o ./Remotely-MacOS-arm64.zip +rm -f ./Remotely-MacOS-arm64.zip + + +connectionInfo="{ + \"DeviceID\":\"$GUID\", + \"Host\":\"$HostName\", + \"OrganizationID\": \"$Organization\", + \"ServerVerificationToken\":\"\" +}" + +echo "$connectionInfo" > ./ConnectionInfo.json + +curl --head $HostName/Content/Remotely-MacOS-arm64.zip | grep -i "etag" | cut -d' ' -f 2 > ./etag.txt + + +plistFile=" + + + + Label + com.translucency.remotely-agent + ProgramArguments + + /usr/local/bin/dotnet + /usr/local/bin/Remotely/Remotely_Agent.dll + + KeepAlive + + +" +echo "$plistFile" > "/Library/LaunchDaemons/remotely-agent.plist" + +launchctl load -w /Library/LaunchDaemons/remotely-agent.plist +launchctl kickstart -k system/com.translucency.remotely-agent \ No newline at end of file diff --git a/Server/wwwroot/Content/Install-MacOS-x64.sh b/Server/wwwroot/Content/Install-MacOS-x64.sh index fbbb1894b..06cbbb5cb 100644 --- a/Server/wwwroot/Content/Install-MacOS-x64.sh +++ b/Server/wwwroot/Content/Install-MacOS-x64.sh @@ -1,4 +1,4 @@ -#!/bin/zsh +#!/bin/bash HostName= Organization= From 8de7561c1159042f383639c3beca5df0326b42bf Mon Sep 17 00:00:00 2001 From: Jared Goodwin Date: Fri, 7 May 2021 10:58:09 -0700 Subject: [PATCH 17/22] Comment out macOS arm64 links until runners are available on Azure Pipelines. --- Server/Pages/Downloads.razor | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Server/Pages/Downloads.razor b/Server/Pages/Downloads.razor index b6f31d86c..36268dc17 100644 --- a/Server/Pages/Downloads.razor +++ b/Server/Pages/Downloads.razor @@ -36,7 +36,7 @@ macOS (Catalina)

macOS x64 Executable - macOS arm64 Executable + @*macOS arm64 Executable*@

@@ -179,10 +179,10 @@ macOS x64 Bash Installer
macOS x64 Files Only -
+ @*
macOS arm64 Bash Installer
- macOS arm64 Files Only + macOS arm64 Files Only*@

Example Install:
From 6e03a39ed5b4883e5ae4745fc392a8306c65a4a8 Mon Sep 17 00:00:00 2001 From: Jared Goodwin Date: Fri, 7 May 2021 17:12:37 -0700 Subject: [PATCH 18/22] Separate macOS x64 and arm64 sections. --- Server/Pages/Downloads.razor | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/Server/Pages/Downloads.razor b/Server/Pages/Downloads.razor index 36268dc17..a03efe9f1 100644 --- a/Server/Pages/Downloads.razor +++ b/Server/Pages/Downloads.razor @@ -33,11 +33,14 @@

- macOS (Catalina) + macOS x64 (10.12 - 10.15)

macOS x64 Executable - @*macOS arm64 Executable*@

+ @*macOS arm64 (11.01) +

+ macOS arm64 Executable +

*@
@@ -174,16 +177,20 @@
- macOS x64 (Catalina) + macOS x64 (10.12 - 10.15)

macOS x64 Bash Installer
macOS x64 Files Only - @*
+

+ + @*macOS arm64 (11.01) +

macOS arm64 Bash Installer
- macOS arm64 Files Only*@ -

+ macOS arm64 Files Only +

*@ +

Example Install:
From 0a904cbcd166e70f25a025eb64e0c1df376b7fe0 Mon Sep 17 00:00:00 2001 From: Jared Goodwin Date: Fri, 7 May 2021 18:17:16 -0700 Subject: [PATCH 19/22] Rename Desktop.Linux in Publish script. --- Utilities/Publish.ps1 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Utilities/Publish.ps1 b/Utilities/Publish.ps1 index 61ef20e9a..c8f44570d 100644 --- a/Utilities/Publish.ps1 +++ b/Utilities/Publish.ps1 @@ -128,10 +128,10 @@ New-Item -Path "$Root\Agent\bin\Release\net5.0\linux-x64\publish\Desktop\" -Item # Publish Linux ScreenCaster -dotnet publish /p:Version=$CurrentVersion /p:FileVersion=$CurrentVersion -p:PublishProfile=packaged-linux-x64 --configuration Release "$Root\Desktop.Linux\" +dotnet publish /p:Version=$CurrentVersion /p:FileVersion=$CurrentVersion -p:PublishProfile=packaged-linux-x64 --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.Linux\" +dotnet publish /p:Version=$CurrentVersion /p:FileVersion=$CurrentVersion -p:PublishProfile=desktop-linux-x64 --configuration Release "$Root\Desktop.XPlat\" # Publish Windows ScreenCaster (32-bit) From afb5029ad5aa2e586d29bff63de6debb376ee6f0 Mon Sep 17 00:00:00 2001 From: Jared Goodwin Date: Fri, 7 May 2021 19:41:27 -0700 Subject: [PATCH 20/22] Update build.yml --- .github/workflows/build.yml | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 97949c815..1460edc9e 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -58,12 +58,12 @@ jobs: echo "CurrentVersion=$CurrentVersion" >> $GITHUB_ENV Write-Host "Setting current version to $CurrentVersion." - - - name: Set current version - shell: powershell - run: | - dotnet publish /p:Version=$env:CurrentVersion /p:FileVersion=$env:CurrentVersion --runtime osx-x64 --configuration Release --output "./Agent/bin/publish" ".\Agent" - Compress-Archive -Path "./Agent/bin/publish/*" -DestinationPath "./Agent/bin/Remotely-MacOS-x64.zip" -Force + + - name: Set current version + shell: powershell + run: | + dotnet publish /p:Version=$env:CurrentVersion /p:FileVersion=$env:CurrentVersion --runtime osx-x64 --configuration Release --output "./Agent/bin/publish" ".\Agent" + Compress-Archive -Path "./Agent/bin/publish/*" -DestinationPath "./Agent/bin/Remotely-MacOS-x64.zip" -Force - name: Upload build artifact uses: actions/upload-artifact@v2 From dcecf657bdb657c6c04680a875d330ebea430f7e Mon Sep 17 00:00:00 2001 From: Jared Goodwin Date: Fri, 7 May 2021 21:24:50 -0700 Subject: [PATCH 21/22] Update build.yml --- .github/workflows/build.yml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 97949c815..984bad73b 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -59,11 +59,11 @@ jobs: Write-Host "Setting current version to $CurrentVersion." - - name: Set current version - shell: powershell - run: | - dotnet publish /p:Version=$env:CurrentVersion /p:FileVersion=$env:CurrentVersion --runtime osx-x64 --configuration Release --output "./Agent/bin/publish" ".\Agent" - Compress-Archive -Path "./Agent/bin/publish/*" -DestinationPath "./Agent/bin/Remotely-MacOS-x64.zip" -Force + - name: Set current version + shell: powershell + run: | + dotnet publish /p:Version=$env:CurrentVersion /p:FileVersion=$env:CurrentVersion --runtime osx-x64 --configuration Release --output "./Agent/bin/publish" ".\Agent" + Compress-Archive -Path "./Agent/bin/publish/*" -DestinationPath "./Agent/bin/Remotely-MacOS-x64.zip" -Force - name: Upload build artifact uses: actions/upload-artifact@v2 From c7d6b7bef772b4a235d12e590e17aeb8beda514e Mon Sep 17 00:00:00 2001 From: Jared Goodwin Date: Fri, 7 May 2021 21:35:05 -0700 Subject: [PATCH 22/22] Update build.yml --- .github/workflows/build.yml | 74 +++++++++++++++++++------------------ 1 file changed, 38 insertions(+), 36 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 984bad73b..32dc0475e 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -32,44 +32,46 @@ on: default: "linux-x64" jobs: + build-mac: - runs-on: macos-10.15 - steps: - - name: Checkout - uses: actions/checkout@v2 - - - name: Install .NET Core - uses: actions/setup-dotnet@v1.7.2 - - - name: Set current version - shell: powershell - run: | - $VersionString = git show -s --format=%ci - $VersionDate = [DateTimeOffset]::Parse($VersionString) - - $Year = $VersionDate.Year.ToString() - $Month = $VersionDate.Month.ToString().PadLeft(2, "0") - $Day = $VersionDate.Day.ToString().PadLeft(2, "0") - $Hour = $VersionDate.Hour.ToString().PadLeft(2, "0") - $Minute = $VersionDate.Minute.ToString().PadLeft(2, "0") - $CurrentVersion = "$Year.$Month.$Day.$Hour$Minute" - - echo "CurrentVersion=$CurrentVersion" >> $GITHUB_ENV - - Write-Host "Setting current version to $CurrentVersion." - - - name: Set current version - shell: powershell - run: | - dotnet publish /p:Version=$env:CurrentVersion /p:FileVersion=$env:CurrentVersion --runtime osx-x64 --configuration Release --output "./Agent/bin/publish" ".\Agent" - Compress-Archive -Path "./Agent/bin/publish/*" -DestinationPath "./Agent/bin/Remotely-MacOS-x64.zip" -Force - - - name: Upload build artifact - uses: actions/upload-artifact@v2 - with: - path: ./Agent/bin/Remotely-MacOS-x64.zip - name: Mac-Agent-x64 + runs-on: macos-10.15 + + steps: + - name: Checkout + uses: actions/checkout@v2 + + - name: Install .NET Core + uses: actions/setup-dotnet@v1.7.2 + + - name: Set current version + shell: pwsh + run: | + $VersionString = git show -s --format=%ci + $VersionDate = [DateTimeOffset]::Parse($VersionString) + + $Year = $VersionDate.Year.ToString() + $Month = $VersionDate.Month.ToString().PadLeft(2, "0") + $Day = $VersionDate.Day.ToString().PadLeft(2, "0") + $Hour = $VersionDate.Hour.ToString().PadLeft(2, "0") + $Minute = $VersionDate.Minute.ToString().PadLeft(2, "0") + $CurrentVersion = "$Year.$Month.$Day.$Hour$Minute" + + echo "CurrentVersion=$CurrentVersion" >> $GITHUB_ENV + + Write-Host "Setting current version to $CurrentVersion." + + - name: Set current version + shell: pwsh + run: | + dotnet publish /p:Version=$env:CurrentVersion /p:FileVersion=$env:CurrentVersion --runtime osx-x64 --configuration Release --output "./Agent/bin/publish" ".\Agent" + Compress-Archive -Path "./Agent/bin/publish/*" -DestinationPath "./Agent/bin/Remotely-MacOS-x64.zip" -Force + + - name: Upload build artifact + uses: actions/upload-artifact@v2 + with: + path: ./Agent/bin/Remotely-MacOS-x64.zip + name: Mac-Agent-x64 build-windows: