mirror of
https://github.com/immense/Remotely.git
synced 2025-10-26 11:27:15 +00:00
Swap chat host/client roles.
This commit is contained in:
parent
1c81aaa523
commit
45b17b8a9a
@ -8,7 +8,7 @@
|
||||
<OutputType>WinExe</OutputType>
|
||||
<RootNamespace>Remotely.Agent.Installer.Win</RootNamespace>
|
||||
<AssemblyName>Remotely_Installer</AssemblyName>
|
||||
<TargetFrameworkVersion>v4.6.2</TargetFrameworkVersion>
|
||||
<TargetFrameworkVersion>v4.8</TargetFrameworkVersion>
|
||||
<FileAlignment>512</FileAlignment>
|
||||
<ProjectTypeGuids>{60dc8134-eba5-43b8-bcc9-bb4bc16c2548};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<configuration>
|
||||
<startup>
|
||||
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.6.2"/>
|
||||
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.8"/>
|
||||
</startup>
|
||||
</configuration>
|
||||
|
||||
@ -5,6 +5,6 @@ namespace Remotely.Agent.Models
|
||||
public class ChatSession
|
||||
{
|
||||
public int ProcessID { get; set; }
|
||||
public NamedPipeClientStream PipeStream { get; set; }
|
||||
public NamedPipeServerStream PipeStream { get; set; }
|
||||
}
|
||||
}
|
||||
|
||||
@ -44,7 +44,7 @@ namespace Remotely.Agent
|
||||
builder.AddConsole().AddDebug();
|
||||
});
|
||||
serviceCollection.AddSingleton<AgentSocket>();
|
||||
serviceCollection.AddScoped<ChatClientService>();
|
||||
serviceCollection.AddScoped<ChatHostService>();
|
||||
serviceCollection.AddTransient<Bash>();
|
||||
serviceCollection.AddTransient<CMD>();
|
||||
serviceCollection.AddTransient<PSCore>();
|
||||
|
||||
@ -26,7 +26,7 @@ namespace Remotely.Agent.Services
|
||||
Uninstaller uninstaller,
|
||||
CommandExecutor commandExecutor,
|
||||
ScriptRunner scriptRunner,
|
||||
ChatClientService chatService,
|
||||
ChatHostService chatService,
|
||||
IAppLauncher appLauncher,
|
||||
IUpdater updater)
|
||||
{
|
||||
@ -40,7 +40,7 @@ namespace Remotely.Agent.Services
|
||||
}
|
||||
public bool IsConnected => HubConnection?.State == HubConnectionState.Connected;
|
||||
private IAppLauncher AppLauncher { get; }
|
||||
private ChatClientService ChatService { get; }
|
||||
private ChatHostService ChatService { get; }
|
||||
private CommandExecutor CommandExecutor { get; }
|
||||
private ConfigService ConfigService { get; }
|
||||
private ConnectionInfo ConnectionInfo { get; set; }
|
||||
|
||||
@ -14,9 +14,9 @@ using System.Threading.Tasks;
|
||||
|
||||
namespace Remotely.Agent.Services
|
||||
{
|
||||
public class ChatClientService
|
||||
public class ChatHostService
|
||||
{
|
||||
public ChatClientService(IAppLauncher appLauncher)
|
||||
public ChatHostService(IAppLauncher appLauncher)
|
||||
{
|
||||
AppLauncher = appLauncher;
|
||||
}
|
||||
@ -71,15 +71,20 @@ namespace Remotely.Agent.Services
|
||||
Logger.Write($"Chat app did not start successfully.");
|
||||
return;
|
||||
}
|
||||
var serverStream = new NamedPipeServerStream("Remotely_Chat" + senderConnectionID,
|
||||
PipeDirection.InOut,
|
||||
NamedPipeServerStream.MaxAllowedServerInstances,
|
||||
PipeTransmissionMode.Byte,
|
||||
PipeOptions.Asynchronous);
|
||||
|
||||
var clientPipe = new NamedPipeClientStream(".", "Remotely_Chat" + senderConnectionID, PipeDirection.InOut, PipeOptions.Asynchronous);
|
||||
clientPipe.Connect(15000);
|
||||
if (!clientPipe.IsConnected)
|
||||
var cts = new CancellationTokenSource(15000);
|
||||
await serverStream.WaitForConnectionAsync(cts.Token);
|
||||
if (!serverStream.IsConnected)
|
||||
{
|
||||
Logger.Write("Failed to connect to chat host.");
|
||||
Logger.Write("Failed to connect to chat client.");
|
||||
return;
|
||||
}
|
||||
chatSession = new ChatSession() { PipeStream = clientPipe, ProcessID = procID };
|
||||
chatSession = new ChatSession() { PipeStream = serverStream, ProcessID = procID };
|
||||
_ = Task.Run(async () => { await ReadFromStream(chatSession.PipeStream, senderConnectionID, hubConnection); });
|
||||
ChatClients.Add(senderConnectionID, chatSession, CacheItemPolicy);
|
||||
}
|
||||
@ -108,11 +113,11 @@ namespace Remotely.Agent.Services
|
||||
}
|
||||
}
|
||||
|
||||
private async Task ReadFromStream(NamedPipeClientStream clientPipe, string senderConnectionID, HubConnection hubConnection)
|
||||
private async Task ReadFromStream(NamedPipeServerStream clientPipe, string senderConnectionID, HubConnection hubConnection)
|
||||
{
|
||||
using var sr = new StreamReader(clientPipe, leaveOpen: true);
|
||||
while (clientPipe.IsConnected)
|
||||
{
|
||||
using var sr = new StreamReader(clientPipe, leaveOpen: true);
|
||||
var messageJson = await sr.ReadLineAsync();
|
||||
if (!string.IsNullOrWhiteSpace(messageJson))
|
||||
{
|
||||
@ -2,7 +2,7 @@
|
||||
|
||||
namespace Remotely.Desktop.Core.Interfaces
|
||||
{
|
||||
public interface IChatHostService
|
||||
public interface IChatClientService
|
||||
{
|
||||
Task StartChat(string requesterID, string organizationName);
|
||||
}
|
||||
@ -13,29 +13,29 @@ using System.Threading.Tasks;
|
||||
|
||||
namespace Remotely.Desktop.Core.Services
|
||||
{
|
||||
public class ChatHostService : IChatHostService
|
||||
public class ChatClientService : IChatClientService
|
||||
{
|
||||
private readonly IChatUiService _chatUiService;
|
||||
|
||||
public ChatHostService(IChatUiService chatUiService)
|
||||
public ChatClientService(IChatUiService chatUiService)
|
||||
{
|
||||
_chatUiService = chatUiService;
|
||||
}
|
||||
|
||||
private NamedPipeServerStream NamedPipeStream { get; set; }
|
||||
private NamedPipeClientStream NamedPipeStream { get; set; }
|
||||
private StreamReader Reader { get; set; }
|
||||
private StreamWriter Writer { get; set; }
|
||||
|
||||
public async Task StartChat(string requesterID, string organizationName)
|
||||
{
|
||||
NamedPipeStream = new NamedPipeServerStream("Remotely_Chat" + requesterID, PipeDirection.InOut, 10, PipeTransmissionMode.Byte, PipeOptions.Asynchronous);
|
||||
NamedPipeStream = new NamedPipeClientStream(".", "Remotely_Chat" + requesterID, PipeDirection.InOut, PipeOptions.Asynchronous);
|
||||
Writer = new StreamWriter(NamedPipeStream);
|
||||
Reader = new StreamReader(NamedPipeStream);
|
||||
|
||||
var cts = new CancellationTokenSource(10000);
|
||||
|
||||
try
|
||||
{
|
||||
await NamedPipeStream.WaitForConnectionAsync(cts.Token);
|
||||
await NamedPipeStream.ConnectAsync(15_000);
|
||||
}
|
||||
catch (TaskCanceledException)
|
||||
{
|
||||
@ -43,6 +43,12 @@ namespace Remotely.Desktop.Core.Services
|
||||
Environment.Exit(0);
|
||||
}
|
||||
|
||||
if (!NamedPipeStream.IsConnected)
|
||||
{
|
||||
Logger.Write("Failed to connect to chat host.");
|
||||
return;
|
||||
}
|
||||
|
||||
_chatUiService.ChatWindowClosed += OnChatWindowClosed;
|
||||
|
||||
_chatUiService.ShowChatWindow(organizationName, Writer);
|
||||
@ -54,7 +60,6 @@ namespace Remotely.Desktop.Core.Services
|
||||
{
|
||||
try
|
||||
{
|
||||
NamedPipeStream?.Disconnect();
|
||||
NamedPipeStream?.Dispose();
|
||||
}
|
||||
catch { }
|
||||
@ -55,7 +55,7 @@ namespace Remotely.Desktop.Linux
|
||||
|
||||
if (Conductor.Mode == Core.Enums.AppMode.Chat)
|
||||
{
|
||||
await Services.GetRequiredService<IChatHostService>().StartChat(Conductor.RequesterID, Conductor.OrganizationName);
|
||||
await Services.GetRequiredService<IChatClientService>().StartChat(Conductor.RequesterID, Conductor.OrganizationName);
|
||||
}
|
||||
else if (Conductor.Mode == Core.Enums.AppMode.Unattended)
|
||||
{
|
||||
@ -107,7 +107,7 @@ namespace Remotely.Desktop.Linux
|
||||
serviceCollection.AddSingleton<ICasterSocket, CasterSocket>();
|
||||
serviceCollection.AddSingleton<IdleTimer>();
|
||||
serviceCollection.AddSingleton<Conductor>();
|
||||
serviceCollection.AddSingleton<IChatHostService, ChatHostService>();
|
||||
serviceCollection.AddSingleton<IChatClientService, ChatClientService>();
|
||||
serviceCollection.AddSingleton<IChatUiService, ChatUiServiceLinux>();
|
||||
serviceCollection.AddTransient<IScreenCapturer, ScreenCapturerLinux>();
|
||||
serviceCollection.AddTransient<Viewer>();
|
||||
|
||||
@ -61,7 +61,7 @@ namespace Remotely.Desktop.Win
|
||||
StartUiThreads(false);
|
||||
_ = Task.Run(async () =>
|
||||
{
|
||||
var chatService = Services.GetRequiredService<IChatHostService>();
|
||||
var chatService = Services.GetRequiredService<IChatClientService>();
|
||||
await chatService.StartChat(Conductor.RequesterID, Conductor.OrganizationName);
|
||||
});
|
||||
}
|
||||
@ -105,7 +105,7 @@ namespace Remotely.Desktop.Win
|
||||
serviceCollection.AddSingleton<ICasterSocket, CasterSocket>();
|
||||
serviceCollection.AddSingleton<IdleTimer>();
|
||||
serviceCollection.AddSingleton<Conductor>();
|
||||
serviceCollection.AddSingleton<IChatHostService, ChatHostService>();
|
||||
serviceCollection.AddSingleton<IChatClientService, ChatClientService>();
|
||||
serviceCollection.AddSingleton<IChatUiService, ChatUiServiceWin>();
|
||||
serviceCollection.AddTransient<IScreenCapturer, ScreenCapturerWin>();
|
||||
serviceCollection.AddTransient<Viewer>();
|
||||
|
||||
@ -139,6 +139,13 @@
|
||||
<br />
|
||||
<span asp-validation-for="AppSettingsInput.MaxConcurrentUpdates" class="text-danger"></span>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label asp-for="AppSettingsInput.MessageOfTheDay" class="control-label"></label>
|
||||
<br />
|
||||
<input asp-for="AppSettingsInput.MessageOfTheDay" class="form-control" />
|
||||
<br />
|
||||
<span asp-validation-for="AppSettingsInput.MessageOfTheDay" class="text-danger"></span>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label asp-for="AppSettingsInput.RedirectToHttps"></label>
|
||||
<br />
|
||||
|
||||
@ -199,6 +199,8 @@ namespace Remotely.Server.Areas.Identity.Pages.Account.Manage
|
||||
|
||||
[Display(Name = "Max Organizations")]
|
||||
public int MaxOrganizationCount { get; set; }
|
||||
[Display(Name = "Message of the Day")]
|
||||
public string MessageOfTheDay { get; set; }
|
||||
|
||||
[Display(Name = "Redirect To HTTPS")]
|
||||
public bool RedirectToHttps { get; set; }
|
||||
|
||||
@ -1,7 +1,9 @@
|
||||
@page
|
||||
@model IndexModel
|
||||
@inject Microsoft.AspNetCore.Hosting.IWebHostEnvironment HostEnv
|
||||
@{
|
||||
ViewData["Title"] = "Home";
|
||||
|
||||
}
|
||||
|
||||
@if (!User.Identity.IsAuthenticated)
|
||||
@ -10,6 +12,15 @@
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!string.IsNullOrWhiteSpace(Model.Motd))
|
||||
{
|
||||
<div id="motdAlert" class="alert alert-info alert-dismissible mr-5" role="alert" hidden>
|
||||
<button type="button" class="close" data-dismiss="alert" aria-label="Close"><span aria-hidden="true">×</span></button>
|
||||
<span id="motdContentSpan">@Model.Motd</span>
|
||||
</div>
|
||||
|
||||
}
|
||||
|
||||
<partial name="_LoadingWheel" model="Model" />
|
||||
<partial name="_IndexLoggedIn" model="Model" />
|
||||
}
|
||||
@ -1,10 +1,13 @@
|
||||
using Microsoft.AspNetCore.Identity;
|
||||
using Microsoft.AspNetCore.Hosting;
|
||||
using Microsoft.AspNetCore.Identity;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.AspNetCore.Mvc.RazorPages;
|
||||
using Microsoft.AspNetCore.Mvc.Rendering;
|
||||
using Remotely.Server.Services;
|
||||
using Remotely.Shared.Models;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
@ -12,53 +15,58 @@ namespace Remotely.Server.Pages
|
||||
{
|
||||
public class IndexModel : PageModel
|
||||
{
|
||||
private readonly IApplicationConfig _appConfig;
|
||||
|
||||
private readonly IDataService _dataService;
|
||||
|
||||
private readonly SignInManager<RemotelyUser> _signInManager;
|
||||
|
||||
public IndexModel(IDataService dataService,
|
||||
SignInManager<RemotelyUser> signInManager,
|
||||
IApplicationConfig appConfig)
|
||||
{
|
||||
DataService = dataService;
|
||||
SignInManager = signInManager;
|
||||
AppConfig = appConfig;
|
||||
_dataService = dataService;
|
||||
_signInManager = signInManager;
|
||||
_appConfig = appConfig;
|
||||
}
|
||||
|
||||
public string DefaultPrompt { get; set; }
|
||||
public List<SelectListItem> DeviceGroups { get; set; } = new List<SelectListItem>();
|
||||
public List<Alert> Alerts { get; set; } = new List<Alert>();
|
||||
private IApplicationConfig AppConfig { get; }
|
||||
private IDataService DataService { get; }
|
||||
private SignInManager<RemotelyUser> SignInManager { get; }
|
||||
public string DefaultPrompt { get; set; }
|
||||
public string Motd { get; set; }
|
||||
public List<SelectListItem> DeviceGroups { get; set; } = new List<SelectListItem>();
|
||||
public async Task<IActionResult> OnGet()
|
||||
{
|
||||
if (User?.Identity?.IsAuthenticated == true)
|
||||
{
|
||||
var user = DataService.GetUserByName(User.Identity.Name);
|
||||
var user = _dataService.GetUserByName(User.Identity.Name);
|
||||
if (user is null)
|
||||
{
|
||||
await SignInManager.SignOutAsync();
|
||||
await _signInManager.SignOutAsync();
|
||||
return RedirectToPage();
|
||||
}
|
||||
|
||||
if (AppConfig.Require2FA && !user.TwoFactorEnabled)
|
||||
if (_appConfig.Require2FA && !user.TwoFactorEnabled)
|
||||
{
|
||||
return RedirectToPage("TwoFactorRequired");
|
||||
}
|
||||
|
||||
DefaultPrompt = DataService.GetDefaultPrompt(User.Identity.Name);
|
||||
var groups = DataService.GetDeviceGroups(User.Identity.Name);
|
||||
DefaultPrompt = _dataService.GetDefaultPrompt(User.Identity.Name);
|
||||
var groups = _dataService.GetDeviceGroups(User.Identity.Name);
|
||||
if (groups?.Any() == true)
|
||||
{
|
||||
DeviceGroups.AddRange(groups.Select(x => new SelectListItem(x.Name, x.ID)));
|
||||
}
|
||||
var alerts = DataService.GetAlerts(user.Id);
|
||||
var alerts = _dataService.GetAlerts(user.Id);
|
||||
if (alerts.Any())
|
||||
{
|
||||
Alerts.AddRange(alerts);
|
||||
}
|
||||
|
||||
Motd = _appConfig.MessageOfTheDay;
|
||||
}
|
||||
else
|
||||
{
|
||||
DefaultPrompt = DataService.GetDefaultPrompt();
|
||||
DefaultPrompt = _dataService.GetDefaultPrompt();
|
||||
}
|
||||
|
||||
return Page();
|
||||
|
||||
@ -16,6 +16,7 @@ namespace Remotely.Server.Services
|
||||
string[] KnownProxies { get; }
|
||||
int MaxConcurrentUpdates { get; }
|
||||
int MaxOrganizationCount { get; }
|
||||
string MessageOfTheDay { get; }
|
||||
bool RedirectToHttps { get; }
|
||||
bool RemoteControlNotifyUser { get; }
|
||||
bool RemoteControlRequiresAuthentication { get; }
|
||||
@ -58,6 +59,7 @@ namespace Remotely.Server.Services
|
||||
public string[] KnownProxies => Config.GetSection("ApplicationOptions:KnownProxies").Get<string[]>() ?? new string[0];
|
||||
public int MaxConcurrentUpdates => int.Parse(Config["ApplicationOptions:MaxConcurrentUpdates"] ?? "10");
|
||||
public int MaxOrganizationCount => int.Parse(Config["ApplicationOptions:MaxOrganizationCount"] ?? "1");
|
||||
public string MessageOfTheDay => Config["ApplicationOptions:MessageOfTheDay"];
|
||||
public bool RedirectToHttps => bool.Parse(Config["ApplicationOptions:RedirectToHttps"] ?? "false");
|
||||
public bool RemoteControlNotifyUser => bool.Parse(Config["ApplicationOptions:RemoteControlNotifyUser"] ?? "true");
|
||||
public bool RemoteControlRequiresAuthentication => bool.Parse(Config["ApplicationOptions:RemoteControlRequiresAuthentication"] ?? "true");
|
||||
|
||||
@ -32,6 +32,7 @@
|
||||
"KnownProxies": [],
|
||||
"MaxConcurrentUpdates": 10,
|
||||
"MaxOrganizationCount": 1,
|
||||
"MessageOfTheDay": "",
|
||||
"RedirectToHttps": false,
|
||||
"RemoteControlNotifyUser": true,
|
||||
"RemoteControlSessionLimit": 3,
|
||||
|
||||
@ -26,7 +26,19 @@ export const MainApp = {
|
||||
HubConnection: BrowserHubConnection,
|
||||
UserSettings: UserSettings,
|
||||
Sound: Sound,
|
||||
GetMotd() {
|
||||
if (!UI.MotdContentSpan.innerHTML || localStorage["remotely-motd"] == UI.MotdContentSpan.innerHTML) {
|
||||
return;
|
||||
}
|
||||
|
||||
UI.MotdAlert.querySelector("button").addEventListener("click", () => {
|
||||
localStorage["remotely-motd"] = UI.MotdContentSpan.innerHTML;
|
||||
});
|
||||
|
||||
UI.MotdAlert.removeAttribute("hidden");
|
||||
},
|
||||
Init() {
|
||||
MainApp.GetMotd();
|
||||
UI.ConsoleTextArea.focus();
|
||||
ApplyInputEventHandlers();
|
||||
BrowserHubConnection.Connect();
|
||||
|
||||
@ -25,4 +25,6 @@ export var RightPaginationButton = document.querySelector("#rightPaginationButto
|
||||
export var TabContentWrapper = document.getElementById("tabContentWrapper") as HTMLDivElement;
|
||||
export var ToastsWrapper = document.getElementById("toastsWrapper") as HTMLDivElement;
|
||||
export var TotalDevicesCount = document.querySelector("#totalDevicesSpan") as HTMLSpanElement;
|
||||
export var TotalPagesSpan = document.querySelector("#totalPagesSpan") as HTMLSpanElement;
|
||||
export var TotalPagesSpan = document.querySelector("#totalPagesSpan") as HTMLSpanElement;
|
||||
export var MotdAlert = document.getElementById("motdAlert") as HTMLDivElement;
|
||||
export var MotdContentSpan = document.getElementById("motdContentSpan") as HTMLSpanElement;
|
||||
Loading…
Reference in New Issue
Block a user