Skip to content

Commit

Permalink
Replace RewritableStream with AppendableStream. Use PowerShell instal…
Browse files Browse the repository at this point in the history
…ler for Windows (exe not working)
  • Loading branch information
bitbound committed Feb 22, 2024
1 parent 417792a commit 07905ee
Show file tree
Hide file tree
Showing 9 changed files with 95 additions and 292 deletions.
5 changes: 3 additions & 2 deletions Agent.Installer.Win/Models/EmbeddedServerData.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System;
#nullable enable
using System;
using System.Runtime.Serialization;

namespace Remotely.Agent.Installer.Models;
Expand All @@ -23,5 +24,5 @@ public EmbeddedServerData(Uri serverUrl, string organizationId)
public string OrganizationId { get; set; } = string.Empty;

[DataMember]
public Uri ServerUrl { get; set; }
public Uri? ServerUrl { get; set; }
}
71 changes: 21 additions & 50 deletions Agent.Installer.Win/Services/EmbeddedServerDataReader.cs
Original file line number Diff line number Diff line change
@@ -1,22 +1,18 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Runtime.Serialization.Json;
using System.Text;
using System.Threading.Tasks;
using System.Web.Script.Serialization;
using Remotely.Agent.Installer.Models;
using Remotely.Agent.Installer.Win.Utilities;
using Remotely.Shared;

namespace Remotely.Agent.Installer.Win.Services;

internal class EmbeddedServerDataReader
{
private readonly JavaScriptSerializer _serializer = new JavaScriptSerializer();

public Task<EmbeddedServerData> TryGetEmbeddedData(string filePath)
public async Task<EmbeddedServerData> TryGetEmbeddedData(string filePath)
{
try
{
Expand All @@ -25,60 +21,35 @@ public Task<EmbeddedServerData> TryGetEmbeddedData(string filePath)
throw new Exception($"File path does not exist: {filePath}");
}

using (var fs = File.Open(filePath, FileMode.Open, FileAccess.Read, FileShare.Read))
{
var result = SearchBuffer(fs, AppConstants.EmbeddedImmySignature);
if (result == -1)
{
throw new Exception("Signature not found in file buffer.");
}
using var fs = File.Open(filePath, FileMode.Open, FileAccess.Read, FileShare.Read);
using var br = new BinaryReader(fs);
using var sr = new StreamReader(fs);

Logger.Write($"Found data signature at index {result}.");
fs.Seek(-4, SeekOrigin.End);
var dataSize = br.ReadInt32();
fs.Seek(-dataSize - 4, SeekOrigin.End);

fs.Seek(result + AppConstants.EmbeddedImmySignature.Length, SeekOrigin.Begin);
using (var reader = new BinaryReader(fs, Encoding.UTF8))
{
var serializedData = reader.ReadString();
if (dataSize == 0)
{
return EmbeddedServerData.Empty;
}

Logger.Write($"Extracted embedded data from EXE: {serializedData}");
var buffer = new byte[dataSize];
await fs.ReadAsync(buffer, 0, dataSize);
var json = Encoding.UTF8.GetString(buffer);

var embeddedData = _serializer.Deserialize<EmbeddedServerData>(serializedData);
if (embeddedData != null)
{
return Task.FromResult(embeddedData);
}
}
Logger.Write($"Extracted embedded data from EXE: {json}");

var embeddedData = _serializer.Deserialize<EmbeddedServerData>(json);
if (embeddedData is not null)
{
return embeddedData;
}
}
catch (Exception ex)
{
Logger.Write(ex);
}
return Task.FromResult(EmbeddedServerData.Empty);
}

private long SearchBuffer(FileStream fileStream, byte[] matchPattern)
{
var matchSize = matchPattern.Length;
var limit = fileStream.Length - matchSize;

for (var i = 0; i <= limit; i++)
{
var k = 0;

for (; k < matchSize; k++)
{
if (matchPattern[k] != fileStream.ReadByte())
{
break;
}
}

if (k == matchSize)
{
return fileStream.Position - matchSize;
}
}
return -1;
return EmbeddedServerData.Empty;
}
}
15 changes: 6 additions & 9 deletions Remotely.sln
Original file line number Diff line number Diff line change
Expand Up @@ -55,14 +55,6 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Submodules", "Submodules",
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Desktop.Shared", "Desktop.Shared\Desktop.Shared.csproj", "{38099844-F6B6-4975-BEC5-D58A547145F0}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Docker", "Docker", "{963B5555-30AE-428E-9686-59C4B6FEC052}"
ProjectSection(SolutionItems) = preProject
.docker\Dockerfile = .docker\Dockerfile
.docker\Dockerfile.old = .docker\Dockerfile.old
.docker\Dockerfile.rootless = .docker\Dockerfile.rootless
.docker\DockerMain.sh = .docker\DockerMain.sh
EndProjectSection
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Immense.RemoteControl.Desktop.Shared", "submodules\Immense.RemoteControl\Immense.RemoteControl.Desktop.Shared\Immense.RemoteControl.Desktop.Shared.csproj", "{3EB48B01-A672-4658-868B-8CA21FF73929}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Immense.RemoteControl.Desktop.Windows", "submodules\Immense.RemoteControl\Immense.RemoteControl.Desktop.Windows\Immense.RemoteControl.Desktop.Windows.csproj", "{7FA4456D-8695-4990-B20A-B897CF9DF0EF}"
Expand All @@ -79,6 +71,11 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Immense.RemoteControl.Deskt
EndProject
Project("{E53339B2-1760-4266-BCC7-CA923CBCF16C}") = "docker-compose", "docker-compose\docker-compose.dcproj", "{90EC49B2-B56A-4ECD-8F63-2162DD140F7C}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "pipelines", "pipelines", "{9484AB47-2F99-43DE-9F5D-5B8679B01B3B}"
ProjectSection(SolutionItems) = preProject
.azure-pipelines\Release Build.yml = .azure-pipelines\Release Build.yml
EndProjectSection
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Expand Down Expand Up @@ -301,14 +298,14 @@ Global
{48D9D0E6-5781-44A9-84C0-56F56C2A1193} = {0754E195-7080-4AAC-B5A3-A9923B1283CE}
{6C25240C-613D-4A86-A04E-784BA6726094} = {0754E195-7080-4AAC-B5A3-A9923B1283CE}
{B6C1030D-1F74-4143-BB70-FC79C0274653} = {0754E195-7080-4AAC-B5A3-A9923B1283CE}
{963B5555-30AE-428E-9686-59C4B6FEC052} = {2176596E-12DA-4766-96E1-4D23EA7DBEC8}
{3EB48B01-A672-4658-868B-8CA21FF73929} = {48C738FB-359E-43DB-B338-FD7CB1CCF6A8}
{7FA4456D-8695-4990-B20A-B897CF9DF0EF} = {48C738FB-359E-43DB-B338-FD7CB1CCF6A8}
{8CBED18D-64A8-44C0-8433-EE14E93B472A} = {48C738FB-359E-43DB-B338-FD7CB1CCF6A8}
{FEF0D431-EB2F-4C08-A125-8DF59AFDA525} = {48C738FB-359E-43DB-B338-FD7CB1CCF6A8}
{E4D83C37-8B98-44FB-898B-9AA1BB223C66} = {48C738FB-359E-43DB-B338-FD7CB1CCF6A8}
{2FF27827-1F43-474E-A0E3-DA76BC598BCC} = {48C738FB-359E-43DB-B338-FD7CB1CCF6A8}
{3095BA44-D5E0-42B4-9161-7F7AB8E68A10} = {48C738FB-359E-43DB-B338-FD7CB1CCF6A8}
{9484AB47-2F99-43DE-9F5D-5B8679B01B3B} = {2176596E-12DA-4766-96E1-4D23EA7DBEC8}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {EAE10B28-119B-437C-9E68-06F0EE3F968A}
Expand Down
53 changes: 35 additions & 18 deletions Server/API/ClientDownloadsController.cs
Original file line number Diff line number Diff line change
@@ -1,18 +1,12 @@
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Logging;
using Microsoft.AspNetCore.Mvc;
using Remotely.Server.Auth;
using Remotely.Server.Extensions;
using Remotely.Server.Services;
using Remotely.Shared.Extensions;
using Remotely.Shared.Models;
using Remotely.Shared.Services;
using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using FileIO = System.IO.File;

namespace Remotely.Server.API;

Expand All @@ -25,6 +19,7 @@ public class ClientDownloadsController : ControllerBase
private readonly SemaphoreSlim _fileLock = new(1, 1);
private readonly IWebHostEnvironment _hostEnv;
private readonly ILogger<ClientDownloadsController> _logger;

public ClientDownloadsController(
IWebHostEnvironment hostEnv,
IEmbeddedServerDataSearcher embeddedDataSearcher,
Expand Down Expand Up @@ -128,7 +123,7 @@ public async Task<IActionResult> GetInstaller(string organizationID, string plat
private async Task<IActionResult> GetBashInstaller(string fileName, string organizationId)
{
var fileContents = new List<string>();
fileContents.AddRange(await System.IO.File.ReadAllLinesAsync(Path.Combine(_hostEnv.WebRootPath, "Content", fileName)));
fileContents.AddRange(await FileIO.ReadAllLinesAsync(Path.Combine(_hostEnv.WebRootPath, "Content", fileName)));

var hostIndex = fileContents.IndexOf("HostName=");
var orgIndex = fileContents.IndexOf("Organization=");
Expand All @@ -150,7 +145,7 @@ private async Task<IActionResult> GetDesktopFile(string filePath, string? organi
var effectiveScheme = settings.ForceClientHttps ? "https" : Request.Scheme;
var serverUrl = $"{effectiveScheme}://{Request.Host}";
var embeddedData = new EmbeddedServerData(new Uri(serverUrl), organizationId);
var result = await _embeddedDataSearcher.GetRewrittenStream(filePath, embeddedData);
var result = await _embeddedDataSearcher.GetAppendedStream(filePath, embeddedData);

if (!result.IsSuccess)
{
Expand All @@ -177,17 +172,39 @@ private async Task<IActionResult> GetInstallFile(string organizationId, string p
case "WindowsInstaller":
{
var effectiveScheme = settings.ForceClientHttps ? "https" : Request.Scheme;
var serverUrl = $"{effectiveScheme}://{Request.Host}";
var filePath = Path.Combine(_hostEnv.WebRootPath, "Content", "Remotely_Installer.exe");
var embeddedData = new EmbeddedServerData(new Uri(serverUrl), organizationId);
var result = await _embeddedDataSearcher.GetRewrittenStream(filePath, embeddedData);
//var serverUrl = $"{effectiveScheme}://{Request.Host}";
//var filePath = Path.Combine(_hostEnv.WebRootPath, "Content", "Remotely_Installer.exe");
//var embeddedData = new EmbeddedServerData(new Uri(serverUrl), organizationId);
//var result = await _embeddedDataSearcher.GetAppendedStream(filePath, embeddedData);

//if (!result.IsSuccess)
//{
// throw result.Exception ?? new Exception(result.Reason);
//}

if (!result.IsSuccess)

var filePath = Path.Combine(_hostEnv.WebRootPath, "Content", "Install-Remotely.ps1");
if (!FileIO.Exists(filePath))
{
throw result.Exception ?? new Exception(result.Reason);
return NotFound();
}

var fileContents = await FileIO.ReadAllLinesAsync(filePath);
var hostIndex = fileContents.IndexWhere(x =>
x.Contains("[string]$HostName = $null", StringComparison.OrdinalIgnoreCase));
var orgIndex = fileContents.IndexWhere(x =>
x.Contains("[string]$Organization = $null", StringComparison.OrdinalIgnoreCase));

if (hostIndex < 0 || orgIndex < 0)
{
return NotFound();
}

fileContents[hostIndex] = $"$HostName = \"{effectiveScheme}://{Request.Host}\"";
fileContents[orgIndex] = $"$Organization = \"{organizationId}\"";
var fileBytes = Encoding.UTF8.GetBytes(string.Join("\n", fileContents));

return File(result.Value, "application/octet-stream", "Remotely_Installer.exe");
return File(fileBytes, "application/octet-stream", "Install-Remotely.ps1");
}
case "ManjaroInstaller-x64":
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@
.DESCRIPTION
Do not modify this script. It was generated specifically for your account.
.EXAMPLE
powershell.exe -f Install-Win.ps1
powershell.exe -f Install-Win.ps1 -DeviceAlias "My Super Computer" -DeviceGroup "My Stuff"
powershell.exe -f Install-Remotely.ps1
powershell.exe -f Install-Remotely.ps1 -DeviceAlias "My Super Computer" -DeviceGroup "My Stuff"
#>

param (
Expand Down Expand Up @@ -71,7 +71,7 @@ function Stop-Remotely {
function Uninstall-Remotely {
Stop-Remotely
Remove-Item -Path $InstallPath -Force -Recurse -ErrorAction SilentlyContinue
Remove-NetFirewallRule -Name "Remotely ScreenCast" -ErrorAction SilentlyContinue
Remove-NetFirewallRule -Name "Remotely Desktop Unattended" -ErrorAction SilentlyContinue
}

function Install-Remotely {
Expand Down Expand Up @@ -118,7 +118,7 @@ function Install-Remotely {
}

Stop-Remotely
Get-ChildItem -Path "C:\Program Files\Remotely" | Where-Object {$_.Name -notlike "ConnectionInfo.json"} | Remove-Item -Recurse -Force
Get-ChildItem -Path $InstallPath | Where-Object {$_.Name -notlike "ConnectionInfo.json"} | Remove-Item -Recurse -Force

Expand-Archive -Path "$env:TEMP\Remotely-Win-$Platform.zip" -DestinationPath "$InstallPath" -Force

Expand All @@ -127,7 +127,7 @@ function Install-Remotely {
if ($DeviceAlias -or $DeviceGroup) {
$DeviceSetupOptions = @{
DeviceAlias = $DeviceAlias;
DeviceGroup = $DeviceGroup;
DeviceGroupName = $DeviceGroup;
OrganizationID = $Organization;
DeviceID = $ConnectionInfo.DeviceID;
}
Expand All @@ -138,8 +138,6 @@ function Install-Remotely {
New-Service -Name "Remotely_Service" -BinaryPathName "$InstallPath\Remotely_Agent.exe" -DisplayName "Remotely Service" -StartupType Automatic -Description "Background service that maintains a connection to the Remotely server. The service is used for remote support and maintenance by this computer's administrators."
Start-Process -FilePath "cmd.exe" -ArgumentList "/c sc.exe failure `"Remotely_Service`" reset=5 actions=restart/5000" -Wait -WindowStyle Hidden
Start-Service -Name Remotely_Service

New-NetFirewallRule -Name "Remotely Desktop Unattended" -DisplayName "Remotely Desktop Unattended" -Description "The agent that allows screen sharing and remote control for Remotely." -Direction Inbound -Enabled True -Action Allow -Program "C:\Program Files\Remotely\Desktop\Remotely_Desktop.exe" -ErrorAction SilentlyContinue
}

try {
Expand Down
4 changes: 0 additions & 4 deletions Shared/AppConstants.cs
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,4 @@ public class AppConstants
public const double ScriptRunExpirationMinutes = 30;
public const string ApiKeyHeaderName = "X-Api-Key";
public const string ExpiringTokenHeaderName = "X-Expiring-Token";

#pragma warning disable IDE0230 // Use UTF-8 string literal
public static byte[] EmbeddedImmySignature { get; } = new byte[] { 73, 109, 109, 121, 66, 111, 116, 32, 114, 111, 99, 107, 115, 32, 116, 104, 101, 32, 115, 111, 99, 107, 115, 32, 117, 110, 116, 105, 108, 32, 116, 104, 101, 32, 101, 113, 117, 105, 110, 111, 120, 33 };
#pragma warning restore IDE0230 // Use UTF-8 string literal
}
Loading

0 comments on commit 07905ee

Please sign in to comment.