diff --git a/Desktop.Core/Interfaces/IShutdownService.cs b/Desktop.Core/Interfaces/IShutdownService.cs new file mode 100644 index 00000000..150dfc1b --- /dev/null +++ b/Desktop.Core/Interfaces/IShutdownService.cs @@ -0,0 +1,12 @@ +using System; +using System.Collections.Generic; +using System.Text; +using System.Threading.Tasks; + +namespace Remotely.Desktop.Core.Interfaces +{ + public interface IShutdownService + { + Task Shutdown(); + } +} diff --git a/Desktop.Core/Models/Viewer.cs b/Desktop.Core/Models/Viewer.cs index 40dc218a..38f030d6 100644 --- a/Desktop.Core/Models/Viewer.cs +++ b/Desktop.Core/Models/Viewer.cs @@ -103,8 +103,11 @@ namespace Remotely.Desktop.Core.Models public void Dispose() { DisconnectRequested = true; - RtcSession?.Dispose(); - Capturer?.Dispose(); + Disposer.TryDisposeAll(new IDisposable[] + { + RtcSession, + Capturer + }); } public async Task InitializeWebRtc() diff --git a/Desktop.Core/Services/CasterSocket.cs b/Desktop.Core/Services/CasterSocket.cs index c4794f5e..0d875767 100644 --- a/Desktop.Core/Services/CasterSocket.cs +++ b/Desktop.Core/Services/CasterSocket.cs @@ -272,11 +272,16 @@ namespace Remotely.Desktop.Core.Services await DisconnectAllViewers(); }); - Connection.On("GetScreenCast", (string viewerID, string requesterName) => + Connection.On("GetScreenCast", (string viewerID, string requesterName, bool notifyUser) => { try { - ScreenCaster.BeginScreenCasting(new ScreenCastRequest() { ViewerID = viewerID, RequesterName = requesterName }); + ScreenCaster.BeginScreenCasting(new ScreenCastRequest() + { + NotifyUser = notifyUser, + ViewerID = viewerID, + RequesterName = requesterName + }); } catch (Exception ex) { @@ -292,9 +297,14 @@ namespace Remotely.Desktop.Core.Services } }); - Connection.On("RequestScreenCast", (string viewerID, string requesterName) => + Connection.On("RequestScreenCast", (string viewerID, string requesterName, bool notifyUser) => { - conductor.InvokeScreenCastRequested(new ScreenCastRequest() { ViewerID = viewerID, RequesterName = requesterName }); + conductor.InvokeScreenCastRequested(new ScreenCastRequest() + { + NotifyUser = notifyUser, + ViewerID = viewerID, + RequesterName = requesterName + }); }); Connection.On("KeyDown", (string key, string viewerID) => diff --git a/Desktop.Core/Services/ScreenCaster.cs b/Desktop.Core/Services/ScreenCaster.cs index b58b4eb1..adb734f2 100644 --- a/Desktop.Core/Services/ScreenCaster.cs +++ b/Desktop.Core/Services/ScreenCaster.cs @@ -22,16 +22,19 @@ namespace Remotely.Desktop.Core.Services { public ScreenCaster(Conductor conductor, ICursorIconWatcher cursorIconWatcher, - ISessionIndicator sessionIndicator) + ISessionIndicator sessionIndicator, + IShutdownService shutdownService) { Conductor = conductor; CursorIconWatcher = cursorIconWatcher; SessionIndicator = sessionIndicator; + ShutdownService = shutdownService; } private Conductor Conductor { get; } private ICursorIconWatcher CursorIconWatcher { get; } private ISessionIndicator SessionIndicator { get; } + private IShutdownService ShutdownService { get; } public async Task BeginScreenCasting(ScreenCastRequest screenCastRequest) { @@ -56,7 +59,8 @@ namespace Remotely.Desktop.Core.Services { Conductor.InvokeViewerAdded(viewer); } - else + + if (mode == AppMode.Unattended && screenCastRequest.NotifyUser) { SessionIndicator.Show(); } @@ -174,8 +178,7 @@ namespace Remotely.Desktop.Core.Services // Close if no one is viewing. if (Conductor.Viewers.Count == 0 && mode == AppMode.Unattended) { - Logger.Debug($"Exiting process ID {Process.GetCurrentProcess().Id}."); - Environment.Exit(0); + await ShutdownService.Shutdown(); } } } diff --git a/Desktop.Core/Services/WebRtcSession.cs b/Desktop.Core/Services/WebRtcSession.cs index b756c218..89ba4fcb 100644 --- a/Desktop.Core/Services/WebRtcSession.cs +++ b/Desktop.Core/Services/WebRtcSession.cs @@ -1,6 +1,7 @@ using MessagePack; using Microsoft.MixedReality.WebRTC; using Remotely.Desktop.Core.Models; +using Remotely.Shared.Helpers; using Remotely.Shared.Models; using Remotely.Shared.Models.RtcDtos; using Remotely.Shared.Utilities; @@ -57,18 +58,17 @@ namespace Remotely.Desktop.Core.Services { try { - Transceiver?.LocalVideoTrack?.Dispose(); - VideoSource?.Dispose(); - try - { - // Unable to exit process until DataChannel is removed/disposed, - // and this throws internally (at least in 2.0 version). - PeerSession?.RemoveDataChannel(CaptureChannel); - } - catch { } - PeerSession?.Dispose(); + // Unable to exit process until DataChannel is removed/disposed, + // and this throws internally (at least in 2.0 version). + PeerSession?.RemoveDataChannel(CaptureChannel); } catch { } + Disposer.TryDisposeAll(new IDisposable[] + { + PeerSession, + Transceiver?.LocalVideoTrack, + VideoSource + }); } public async Task Init(IceServerModel[] iceServers) diff --git a/Desktop.Linux/Controls/HostNamePrompt.axaml.cs b/Desktop.Linux/Controls/HostNamePrompt.axaml.cs index af94ce59..2343d6e9 100644 --- a/Desktop.Linux/Controls/HostNamePrompt.axaml.cs +++ b/Desktop.Linux/Controls/HostNamePrompt.axaml.cs @@ -9,7 +9,7 @@ namespace Remotely.Desktop.Linux.Controls { public HostNamePrompt() { - this.InitializeComponent(); + InitializeComponent(); #if DEBUG this.AttachDevTools(); #endif diff --git a/Desktop.Linux/Controls/MessageBox.axaml.cs b/Desktop.Linux/Controls/MessageBox.axaml.cs index 20c35dac..2dc0a009 100644 --- a/Desktop.Linux/Controls/MessageBox.axaml.cs +++ b/Desktop.Linux/Controls/MessageBox.axaml.cs @@ -34,7 +34,7 @@ namespace Remotely.Desktop.Linux.Controls } public MessageBox() { - this.InitializeComponent(); + InitializeComponent(); #if DEBUG this.AttachDevTools(); #endif diff --git a/Desktop.Linux/Program.cs b/Desktop.Linux/Program.cs index e2f9b33d..ea3cffeb 100644 --- a/Desktop.Linux/Program.cs +++ b/Desktop.Linux/Program.cs @@ -109,6 +109,7 @@ namespace Remotely.Desktop.Linux serviceCollection.AddScoped(); serviceCollection.AddSingleton(); serviceCollection.AddSingleton(); + serviceCollection.AddSingleton(); ServiceContainer.Instance = serviceCollection.BuildServiceProvider(); } diff --git a/Desktop.Linux/Services/SessionIndicatorLinux.cs b/Desktop.Linux/Services/SessionIndicatorLinux.cs index e9b12bbc..db5acc00 100644 --- a/Desktop.Linux/Services/SessionIndicatorLinux.cs +++ b/Desktop.Linux/Services/SessionIndicatorLinux.cs @@ -1,4 +1,6 @@ -using Remotely.Desktop.Core.Interfaces; +using Avalonia.Threading; +using Remotely.Desktop.Core.Interfaces; +using Remotely.Desktop.Linux.Views; using System; using System.Collections.Generic; using System.Text; @@ -9,7 +11,11 @@ namespace Remotely.Desktop.Linux.Services { public void Show() { - // TODO. + Dispatcher.UIThread.Post(() => + { + var indicatorWindow = new SessionIndicatorWindow(); + indicatorWindow.Show(); + }); } } } diff --git a/Desktop.Linux/Services/ShutdownServiceLinux.cs b/Desktop.Linux/Services/ShutdownServiceLinux.cs new file mode 100644 index 00000000..483d9d6b --- /dev/null +++ b/Desktop.Linux/Services/ShutdownServiceLinux.cs @@ -0,0 +1,24 @@ +using Microsoft.Extensions.DependencyInjection; +using Remotely.Desktop.Core; +using Remotely.Desktop.Core.Interfaces; +using Remotely.Desktop.Core.Services; +using Remotely.Shared.Utilities; +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Text; +using System.Threading.Tasks; + +namespace Remotely.Desktop.Linux.Services +{ + public class ShutdownServiceLinux : IShutdownService + { + public async Task Shutdown() + { + Logger.Debug($"Exiting process ID {Process.GetCurrentProcess().Id}."); + var casterSocket = ServiceContainer.Instance.GetRequiredService(); + await casterSocket.DisconnectAllViewers(); + Environment.Exit(0); + } + } +} diff --git a/Desktop.Linux/Views/ChatWindow.axaml.cs b/Desktop.Linux/Views/ChatWindow.axaml.cs index 8fe50815..9372342a 100644 --- a/Desktop.Linux/Views/ChatWindow.axaml.cs +++ b/Desktop.Linux/Views/ChatWindow.axaml.cs @@ -15,7 +15,7 @@ namespace Remotely.Desktop.Linux.Views { public ChatWindow() { - this.InitializeComponent(); + InitializeComponent(); #if DEBUG this.AttachDevTools(); #endif @@ -40,7 +40,7 @@ namespace Remotely.Desktop.Linux.Views { AvaloniaXamlLoader.Load(this); - this.Closed += ChatWindow_Closed; + Closed += ChatWindow_Closed; this.FindControl("TitleBanner").PointerPressed += TitleBanner_PointerPressed; @@ -63,7 +63,7 @@ namespace Remotely.Desktop.Linux.Views { if (e.GetCurrentPoint(this).Properties.PointerUpdateKind == Avalonia.Input.PointerUpdateKind.LeftButtonPressed) { - this.BeginMoveDrag(e); + BeginMoveDrag(e); } } } diff --git a/Desktop.Linux/Views/MainWindow.axaml.cs b/Desktop.Linux/Views/MainWindow.axaml.cs index 7b65825c..a146d5e5 100644 --- a/Desktop.Linux/Views/MainWindow.axaml.cs +++ b/Desktop.Linux/Views/MainWindow.axaml.cs @@ -7,11 +7,10 @@ namespace Remotely.Desktop.Linux.Views { public class MainWindow : Window { - public static MainWindow Current { get; set; } public MainWindow() { Current = this; - + InitializeComponent(); #if DEBUG @@ -19,26 +18,27 @@ namespace Remotely.Desktop.Linux.Views #endif } - private void TitleBanner_PointerPressed(object sender, Avalonia.Input.PointerPressedEventArgs e) - { - if (e.GetCurrentPoint(this).Properties.PointerUpdateKind == Avalonia.Input.PointerUpdateKind.LeftButtonPressed) - { - this.BeginMoveDrag(e); - } - } - + public static MainWindow Current { get; set; } private void InitializeComponent() { AvaloniaXamlLoader.Load(this); this.FindControl("TitleBanner").PointerPressed += TitleBanner_PointerPressed; - this.Opened += MainWindow_Opened; + Opened += MainWindow_Opened; } private async void MainWindow_Opened(object sender, System.EventArgs e) { - await (this.DataContext as MainWindowViewModel).Init(); + await (DataContext as MainWindowViewModel).Init(); + } + + private void TitleBanner_PointerPressed(object sender, Avalonia.Input.PointerPressedEventArgs e) + { + if (e.GetCurrentPoint(this).Properties.PointerUpdateKind == Avalonia.Input.PointerUpdateKind.LeftButtonPressed) + { + BeginMoveDrag(e); + } } } } diff --git a/Desktop.Linux/Views/SessionIndicatorWindow.axaml b/Desktop.Linux/Views/SessionIndicatorWindow.axaml new file mode 100644 index 00000000..5e96dcbd --- /dev/null +++ b/Desktop.Linux/Views/SessionIndicatorWindow.axaml @@ -0,0 +1,23 @@ + + + + + Remote Control Started + + + A remote control session has started. + + + diff --git a/Desktop.Linux/Views/SessionIndicatorWindow.axaml.cs b/Desktop.Linux/Views/SessionIndicatorWindow.axaml.cs new file mode 100644 index 00000000..4fa7dedb --- /dev/null +++ b/Desktop.Linux/Views/SessionIndicatorWindow.axaml.cs @@ -0,0 +1,58 @@ +using Avalonia; +using Avalonia.Controls; +using Avalonia.Markup.Xaml; +using Microsoft.Extensions.DependencyInjection; +using Remotely.Desktop.Core; +using Remotely.Desktop.Core.Interfaces; +using Remotely.Desktop.Linux.Controls; +using System; + +namespace Remotely.Desktop.Linux.Views +{ + public class SessionIndicatorWindow : Window + { + public SessionIndicatorWindow() + { + InitializeComponent(); +#if DEBUG + this.AttachDevTools(); +#endif + } + + private void InitializeComponent() + { + AvaloniaXamlLoader.Load(this); + + Closing += SessionIndicatorWindow_Closing; + PointerPressed += SessionIndicatorWindow_PointerPressed; + Opened += SessionIndicatorWindow_Opened; + } + + private void SessionIndicatorWindow_Opened(object sender, EventArgs e) + { + var left = Screens.Primary.WorkingArea.Width - Width; + var top = Screens.Primary.WorkingArea.Width - Width; + + Position = new PixelPoint((int)left, (int)top); + } + + private void SessionIndicatorWindow_PointerPressed(object sender, Avalonia.Input.PointerPressedEventArgs e) + { + if (e.GetCurrentPoint(this).Properties.PointerUpdateKind == Avalonia.Input.PointerUpdateKind.LeftButtonPressed) + { + BeginMoveDrag(e); + } + } + + private async void SessionIndicatorWindow_Closing(object sender, System.ComponentModel.CancelEventArgs e) + { + e.Cancel = true; + var result = await MessageBox.Show("Stop the remote control session?", "Stop Session", MessageBoxType.YesNo); + if (result == MessageBoxResult.Yes) + { + var shutdownService = ServiceContainer.Instance.GetRequiredService(); + await shutdownService.Shutdown(); + } + } + } +} diff --git a/Desktop.Win/Models/DirectXOutput.cs b/Desktop.Win/Models/DirectXOutput.cs index cd7c564d..90c0ad30 100644 --- a/Desktop.Win/Models/DirectXOutput.cs +++ b/Desktop.Win/Models/DirectXOutput.cs @@ -1,4 +1,5 @@ -using SharpDX.Direct3D11; +using Remotely.Shared.Helpers; +using SharpDX.Direct3D11; using SharpDX.DXGI; using System; @@ -24,10 +25,13 @@ namespace Remotely.Desktop.Win.Models public void Dispose() { - Adapter?.Dispose(); - Device?.Dispose(); - OutputDuplication?.Dispose(); - Texture2D?.Dispose(); + Disposer.TryDisposeAll(new IDisposable[] + { + Adapter, + Device, + OutputDuplication, + Texture2D + }); } } } diff --git a/Desktop.Win/Program.cs b/Desktop.Win/Program.cs index 8087b5d8..cc03e6f0 100644 --- a/Desktop.Win/Program.cs +++ b/Desktop.Win/Program.cs @@ -98,6 +98,7 @@ namespace Remotely.Desktop.Win serviceCollection.AddScoped(); serviceCollection.AddScoped(); serviceCollection.AddSingleton(); + serviceCollection.AddSingleton(); BackgroundForm = new Form() { diff --git a/Desktop.Win/Services/ScreenCapturerWin.cs b/Desktop.Win/Services/ScreenCapturerWin.cs index 5c7707a9..a8f5eb48 100644 --- a/Desktop.Win/Services/ScreenCapturerWin.cs +++ b/Desktop.Win/Services/ScreenCapturerWin.cs @@ -149,7 +149,11 @@ namespace Remotely.Desktop.Win.Services { foreach (var screen in directxScreens.Values) { - screen.Dispose(); + try + { + screen.Dispose(); + } + catch { } } directxScreens.Clear(); } diff --git a/Desktop.Win/Services/SessionIndicatorWin.cs b/Desktop.Win/Services/SessionIndicatorWin.cs index 68f4249d..719bb2a6 100644 --- a/Desktop.Win/Services/SessionIndicatorWin.cs +++ b/Desktop.Win/Services/SessionIndicatorWin.cs @@ -40,7 +40,7 @@ namespace Remotely.Desktop.Win.Services return; } - BackgroundForm.Invoke(new Action(()=> + BackgroundForm.Invoke(new Action(() => { container = new Container(); contextMenuStrip = new ContextMenuStrip(container); diff --git a/Desktop.Win/Services/ShutdownServiceWin.cs b/Desktop.Win/Services/ShutdownServiceWin.cs new file mode 100644 index 00000000..14fe2dd7 --- /dev/null +++ b/Desktop.Win/Services/ShutdownServiceWin.cs @@ -0,0 +1,25 @@ +using Microsoft.Extensions.DependencyInjection; +using Remotely.Desktop.Core; +using Remotely.Desktop.Core.Interfaces; +using Remotely.Desktop.Core.Services; +using Remotely.Shared.Utilities; +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Text; +using System.Threading.Tasks; + +namespace Remotely.Desktop.Win.Services +{ + public class ShutdownServiceWin : IShutdownService + { + public async Task Shutdown() + { + Logger.Debug($"Exiting process ID {Process.GetCurrentProcess().Id}."); + var casterSocket = ServiceContainer.Instance.GetRequiredService(); + await casterSocket.DisconnectAllViewers(); + System.Windows.Forms.Application.Exit(); + App.Current.Shutdown(); + } + } +} diff --git a/README.md b/README.md index 914e39a4..85798057 100644 --- a/README.md +++ b/README.md @@ -99,21 +99,24 @@ The following settings are available in appsettings.json. Note: To retain your settings between upgrades, copy your settings to appsettings.Production.json, which will supersede the original. -* DefaultPrompt: The default prompt string you'll see for each line on the console. +* AllowApiLogin: Whether to allow logging in via the API controller. API access tokens are recommended over this approach. +* DataRetentionInDays: How long event logs and remote command logs will be kept. * DBProvider: Determines which of the three connection strings (at the top) will be used. The appropriate DB provider for the database type is automatically loaded in code. +* DefaultPrompt: The default prompt string you'll see for each line on the console. +* EnableWindowsEventLog: Whether to also add server log entries to the Windows Event Log. +* IceServers: The ICE (STUN/TURN) servers to use for WebRTC. +* KnownProxies: If your Nginx server is on a different machine and is forwarding requests to the Remotely server, you will need to add the IP of the Nginx server to this array. * MaxOrganizationCount: By default, one organization can exist on the server, which is created automatically when the first account is registered. Afterward, self-registration will be disabled. * Set this to -1 or increase it to a specific number to allow multi-tenancy. * RedirectToHttps: Whether ASP.NET Core will redirect all traffic from HTTP to HTTPS. This is independent of Nginx and IIS configurations that do the same. -* UseHsts: Whether ASP.NET Core will use HTTP Strict Transport Security. -* DataRetentionInDays: How long event logs and remote command logs will be kept. +* RemoteControlNotifyUsers: Whether to show a notification to the end user when an unattended remote control session starts. * RemoteControlSessionLimit: How many concurrent remote control sessions are allowed per organization. * RemoteControlRequiresAuthentication: Whether the remote control page requires authentication to establish a connection. * Require2FA: Require users to set up 2FA before they can use the main app. -* AllowApiLogin: Whether to allow logging in via the API controller. API access tokens are recommended over this approach. -* TrustedCorsOrigins: For cross-origin API requests via JavaScript. The websites listed in this array with be allowed to make requests to the API. This does not grant authentication, which is still required on most endpoints. -* KnownProxies: If your Nginx server is on a different machine and is forwarding requests to the Remotely server, you will need to add the IP of the Nginx server to this array. * Smpt*: SMTP settings for auto-generated system emails (such as registration and password reset). * Theme: The color theme to use for the site. Values are "Light" or "Dark". This can also be configured per-user in Account - Options. +* TrustedCorsOrigins: For cross-origin API requests via JavaScript. The websites listed in this array with be allowed to make requests to the API. This does not grant authentication, which is still required on most endpoints. +* UseHsts: Whether ASP.NET Core will use HTTP Strict Transport Security. * UseWebRtc: Attempt to create a peer-to-peer connection via WebRTC for screen sharing. * Only works on Windows agents. diff --git a/Server/Areas/Identity/Pages/Account/Manage/ServerConfig.cshtml b/Server/Areas/Identity/Pages/Account/Manage/ServerConfig.cshtml index fb626881..7a2b90e9 100644 --- a/Server/Areas/Identity/Pages/Account/Manage/ServerConfig.cshtml +++ b/Server/Areas/Identity/Pages/Account/Manage/ServerConfig.cshtml @@ -92,6 +92,13 @@
+
+ +
+ +
+ +

diff --git a/Server/Areas/Identity/Pages/Account/Manage/ServerConfig.cshtml.cs b/Server/Areas/Identity/Pages/Account/Manage/ServerConfig.cshtml.cs index 265915a8..fa69bed0 100644 --- a/Server/Areas/Identity/Pages/Account/Manage/ServerConfig.cshtml.cs +++ b/Server/Areas/Identity/Pages/Account/Manage/ServerConfig.cshtml.cs @@ -169,6 +169,9 @@ namespace Remotely.Server.Areas.Identity.Pages.Account.Manage [Display(Name = "Redirect To HTTPS")] public bool RedirectToHttps { get; set; } + [Display(Name = "Remote Control Notify User")] + public bool RemoteControlNotifyUser { get; set; } + [Display(Name = "Remote Control Requires Authentication")] public bool RemoteControlRequiresAuthentication { get; set; } diff --git a/Server/Hubs/RCBrowserHub.cs b/Server/Hubs/RCBrowserHub.cs index 5eb13dad..70d6b516 100644 --- a/Server/Hubs/RCBrowserHub.cs +++ b/Server/Hubs/RCBrowserHub.cs @@ -268,7 +268,7 @@ namespace Remotely.Server.Hubs (Context.User.Identity.IsAuthenticated && DataService.DoesUserHaveAccessToDevice(deviceID, Context.UserIdentifier))) { - return CasterHubContext.Clients.Client(screenCasterID).SendAsync("GetScreenCast", Context.ConnectionId, requesterName); + return CasterHubContext.Clients.Client(screenCasterID).SendAsync("GetScreenCast", Context.ConnectionId, requesterName, AppConfig.RemoteControlNotifyUser); } else { @@ -279,7 +279,7 @@ namespace Remotely.Server.Hubs { SessionInfo.Mode = RemoteControlMode.Normal; _ = Clients.Caller.SendAsync("RequestingScreenCast"); - return CasterHubContext.Clients.Client(screenCasterID).SendAsync("RequestScreenCast", Context.ConnectionId, requesterName); + return CasterHubContext.Clients.Client(screenCasterID).SendAsync("RequestScreenCast", Context.ConnectionId, requesterName, AppConfig.RemoteControlNotifyUser); } } public Task SendSetKeyStatesUp() diff --git a/Server/Services/ApplicationConfig.cs b/Server/Services/ApplicationConfig.cs index 85ff6ed1..e36a8cfc 100644 --- a/Server/Services/ApplicationConfig.cs +++ b/Server/Services/ApplicationConfig.cs @@ -26,6 +26,7 @@ namespace Remotely.Server.Services public int MaxConcurrentUpdates => int.Parse(Config["ApplicationOptions:MaxConcurrentUpdates"] ?? "10"); public int MaxOrganizationCount => int.Parse(Config["ApplicationOptions:MaxOrganizationCount"] ?? "1"); 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"); public double RemoteControlSessionLimit => double.Parse(Config["ApplicationOptions:RemoteControlSessionLimit"] ?? "3"); public bool Require2FA => bool.Parse(Config["ApplicationOptions:Require2FA"] ?? "false"); diff --git a/Server/Startup.cs b/Server/Startup.cs index 6819c909..8f2e03f0 100644 --- a/Server/Startup.cs +++ b/Server/Startup.cs @@ -81,8 +81,6 @@ namespace Remotely.Server .AddDefaultUI() .AddDefaultTokenProviders(); - var remoteControlAuthentication = Configuration.GetSection("ApplicationOptions:RemoteControlRequiresAuthentication").Get(); - services.ConfigureApplicationCookie(cookieOptions => { cookieOptions.Cookie.SameSite = SameSiteMode.None; diff --git a/Server/appsettings.json b/Server/appsettings.json index ef618e78..9943db0e 100644 --- a/Server/appsettings.json +++ b/Server/appsettings.json @@ -31,6 +31,7 @@ "MaxConcurrentUpdates": 10, "MaxOrganizationCount": 1, "RedirectToHttps": false, + "RemoteControlNotifyUser": true, "RemoteControlSessionLimit": 3, "RemoteControlRequiresAuthentication": true, "Require2FA": false, diff --git a/Shared/Helpers/Disposer.cs b/Shared/Helpers/Disposer.cs new file mode 100644 index 00000000..28a081e0 --- /dev/null +++ b/Shared/Helpers/Disposer.cs @@ -0,0 +1,26 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace Remotely.Shared.Helpers +{ + public static class Disposer + { + public static void TryDisposeAll(IDisposable[] disposables) + { + if (disposables is null) + { + return; + } + + foreach (var disposable in disposables) + { + try + { + disposable?.Dispose(); + } + catch { } + } + } + } +} diff --git a/Shared/Models/ScreenCastRequest.cs b/Shared/Models/ScreenCastRequest.cs index e7f91baf..afb9d2a1 100644 --- a/Shared/Models/ScreenCastRequest.cs +++ b/Shared/Models/ScreenCastRequest.cs @@ -2,7 +2,8 @@ { public class ScreenCastRequest { - public string ViewerID { get; set; } + public bool NotifyUser { get; set; } public string RequesterName { get; set; } + public string ViewerID { get; set; } } }