Added Server Logs page. Added outgoing buffer throttling in screen caster. Refactoring.

This commit is contained in:
Jared Goodwin 2020-01-14 17:48:43 -08:00
parent 8a1a642d2b
commit 9736ed31c3
36 changed files with 264 additions and 99 deletions

View File

@ -15,9 +15,9 @@ namespace Remotely.Agent.Services
public static object WriteLock { get; } = new object();
public static void Write(string message)
{
lock (WriteLock)
try
{
try
lock (WriteLock)
{
var path = Path.Combine(Path.GetTempPath(), "Remotely_Logs.txt");
if (!File.Exists(path))
@ -28,12 +28,6 @@ namespace Remotely.Agent.Services
Process.Start("sudo", $"chmod 666 {path}").WaitForExit();
}
}
var jsoninfo = new
{
Type = "Info",
Timestamp = DateTime.Now.ToString(),
Message = message
};
if (File.Exists(path))
{
var fi = new FileInfo(path);
@ -44,10 +38,11 @@ namespace Remotely.Agent.Services
fi = new FileInfo(path);
}
}
File.AppendAllText(path, JsonConvert.SerializeObject(jsoninfo) + Environment.NewLine);
File.AppendAllText(path, $"{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff")}\t[INFO]\t{message}{Environment.NewLine}");
Console.WriteLine(message);
}
catch { }
}
catch { }
}
public static void Write(Exception ex)
@ -59,6 +54,15 @@ namespace Remotely.Agent.Services
var exception = ex;
var path = Path.Combine(Path.GetTempPath(), "Remotely_Logs.txt");
if (!File.Exists(path))
{
File.Create(path).Close();
if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
{
Process.Start("sudo", $"chmod 666 {path}").WaitForExit();
}
}
while (exception != null)
{
var jsonError = new
@ -79,7 +83,8 @@ namespace Remotely.Agent.Services
fi = new FileInfo(path);
}
}
File.AppendAllText(path, JsonConvert.SerializeObject(jsonError) + Environment.NewLine);
File.AppendAllText(path, $"{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff")}\t[ERROR]\t{exception?.Message}\t{exception?.StackTrace}\t{exception?.Source}{Environment.NewLine}");
Console.WriteLine(exception.Message);
exception = exception.InnerException;
}
}

View File

@ -98,7 +98,14 @@ namespace Remotely.ScreenCast.Core.Capture
fpsQueue.Dequeue();
}
fpsQueue.Enqueue(DateTime.Now);
Debug.WriteLine("Capture FPS: " + fpsQueue.Count);
Debug.WriteLine($"Capture FPS: {fpsQueue.Count}");
}
if (viewer.OutputBuffer > 150_000)
{
Debug.WriteLine($"Waiting for buffer to clear. Size: {viewer.OutputBuffer}");
await Task.Delay(50);
continue;
}
capturer.GetNextFrame();
@ -120,7 +127,7 @@ namespace Remotely.ScreenCast.Core.Capture
if (viewer.AutoAdjustQuality && viewer.Latency > 1000)
{
var quality = (int)(viewer.ImageQuality * 1000 / viewer.Latency);
Logger.Write($"Auto-adjusting image quality. Latency: {viewer.Latency}. Quality: {quality}");
Debug.WriteLine($"Auto-adjusting image quality. Latency: {viewer.Latency}. Quality: {quality}");
encodedImageBytes = ImageUtils.EncodeBitmap(newImage, new EncoderParameters()
{
Param = new[]
@ -138,6 +145,7 @@ namespace Remotely.ScreenCast.Core.Capture
{
await conductor.CasterSocket.SendScreenCapture(encodedImageBytes, viewerID, diffArea.Left, diffArea.Top, diffArea.Width, diffArea.Height, DateTime.UtcNow);
viewer.Latency += 300;
viewer.OutputBuffer += encodedImageBytes.Length;
}
}
}

View File

@ -53,6 +53,7 @@ namespace Remotely.ScreenCast.Core.Models
public double Latency { get; set; } = 1;
public string Name { get; set; }
public int OutputBuffer { get; set; }
public string ViewerConnectionID { get; set; }
}
}

View File

@ -29,12 +29,6 @@ namespace Remotely.ScreenCast.Core.Services
Process.Start("sudo", $"chmod 666 {path}").WaitForExit();
}
}
var jsoninfo = new
{
Type = "Info",
Timestamp = DateTime.Now.ToString(),
Message = message
};
if (File.Exists(path))
{
var fi = new FileInfo(path);
@ -45,7 +39,7 @@ namespace Remotely.ScreenCast.Core.Services
fi = new FileInfo(path);
}
}
File.AppendAllText(path, JsonSerializer.Serialize(jsoninfo) + Environment.NewLine);
File.AppendAllText(path, $"{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff")}\t[INFO]\t{message}{Environment.NewLine}");
Console.WriteLine(message);
}
}
@ -90,7 +84,7 @@ namespace Remotely.ScreenCast.Core.Services
fi = new FileInfo(path);
}
}
File.AppendAllText(path, JsonSerializer.Serialize(jsonError) + Environment.NewLine);
File.AppendAllText(path, $"{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff")}\t[ERROR]\t{exception?.Message}\t{exception?.StackTrace}\t{exception?.Source}{Environment.NewLine}");
Console.WriteLine(exception.Message);
exception = exception.InnerException;
}

View File

@ -271,12 +271,13 @@ namespace Remotely.ScreenCast.Core.Sockets
conductor.InvokeViewerRemoved(viewerID);
});
Connection.On("LatencyUpdate", (DateTime sentTime, string viewerID) =>
Connection.On("LatencyUpdate", (DateTime sentTime, int bytesReceived, string viewerID) =>
{
if (conductor.Viewers.TryGetValue(viewerID, out var viewer))
{
var latency = DateTime.UtcNow - sentTime;
viewer.Latency = latency.TotalMilliseconds;
viewer.OutputBuffer -= bytesReceived;
}
});

View File

@ -3,12 +3,12 @@ using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using Remotely.Server.Data;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.FileProviders;
using Microsoft.AspNetCore.Hosting;
using Remotely.Server.Services;
// For more information on enabling Web API for empty projects, visit https://go.microsoft.com/fwlink/?LinkID=397860

View File

@ -7,10 +7,9 @@ using System.Text;
using System.Threading.Tasks;
using System.Xml.Serialization;
using Remotely.Shared.Models;
using Remotely.Server.Data;
using Remotely.Server.Services;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Newtonsoft.Json;
// For more information on enabling Web API for empty projects, visit https://go.microsoft.com/fwlink/?LinkID=397860
@ -41,7 +40,7 @@ namespace Remotely.Server.API
switch (fileExt.ToUpper())
{
case "JSON":
content = JsonConvert.SerializeObject(commandContexts);
content = System.Text.Json.JsonSerializer.Serialize(commandContexts);
break;
case "XML":
var serializer = new DataContractSerializer(typeof(CommandContext));
@ -67,7 +66,7 @@ namespace Remotely.Server.API
switch (fileExt.ToUpper())
{
case "JSON":
content = JsonConvert.SerializeObject(commandContext);
content = System.Text.Json.JsonSerializer.Serialize(commandContext);
break;
case "XML":
var serializer = new DataContractSerializer(typeof(CommandContext));
@ -108,7 +107,7 @@ namespace Remotely.Server.API
{
case "PSCore":
{
var result = JsonConvert.DeserializeObject<PSCoreCommandResult>(content);
var result = System.Text.Json.JsonSerializer.Deserialize<PSCoreCommandResult>(content);
var commandContext = DataService.GetCommandContext(result.CommandContextID);
commandContext.PSCoreResults.Add(result);
DataService.AddOrUpdateCommandContext(commandContext);
@ -118,7 +117,7 @@ namespace Remotely.Server.API
case "CMD":
case "Bash":
{
var result = JsonConvert.DeserializeObject<GenericCommandResult>(content);
var result = System.Text.Json.JsonSerializer.Deserialize<GenericCommandResult>(content);
var commandContext = DataService.GetCommandContext(result.CommandContextID);
commandContext.CommandResults.Add(result);
DataService.AddOrUpdateCommandContext(commandContext);

View File

@ -3,7 +3,7 @@ using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Remotely.Shared.Models;
using Remotely.Server.Data;
using Remotely.Server.Services;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Mvc;

View File

@ -3,7 +3,7 @@ using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using Remotely.Server.Data;
using Remotely.Server.Services;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
@ -14,14 +14,14 @@ using Microsoft.Net.Http.Headers;
namespace Remotely.Server.API
{
[Route("api/[controller]")]
public class FileSharing : Controller
public class FileSharingController : Controller
{
public FileSharing(DataService dataService)
public FileSharingController(DataService dataService)
{
DataService = dataService;
}
public DataService DataService { get; set; }
// GET api/<controller>/5
[HttpGet("{id}")]
public ActionResult Get(string id)
{

View File

@ -36,30 +36,40 @@ namespace Remotely.Server.API
{
return NotFound();
}
var orgId = DataService.GetUserByName(login.Email)?.OrganizationID;
var result = await SignInManager.PasswordSignInAsync(login.Email, login.Password, false, true);
if (result.Succeeded)
{
DataService.WriteEvent($"API login successful for {login.Email}.");
DataService.WriteEvent($"API login successful for {login.Email}.", orgId);
return Ok();
}
else if (result.IsLockedOut)
{
DataService.WriteEvent($"API login unsuccessful due to lockout for {login.Email}.");
DataService.WriteEvent($"API login unsuccessful due to lockout for {login.Email}.", orgId);
return Unauthorized("Account is locked.");
}
else if (result.RequiresTwoFactor)
{
DataService.WriteEvent($"API login unsuccessful due to 2FA for {login.Email}.");
DataService.WriteEvent($"API login unsuccessful due to 2FA for {login.Email}.", orgId);
return Unauthorized("Account requires two-factor authentication.");
}
DataService.WriteEvent($"API login unsuccessful due to bad attempt for {login.Email}.");
DataService.WriteEvent($"API login unsuccessful due to bad attempt for {login.Email}.", orgId);
return BadRequest();
}
[HttpGet("Logout")]
public async Task<IActionResult> Logout()
{
string orgId = null;
if (HttpContext?.User?.Identity?.IsAuthenticated == true)
{
orgId = DataService.GetUserByName(HttpContext.User.Identity.Name)?.OrganizationID;
}
await SignInManager.SignOutAsync();
DataService.WriteEvent($"API logout successful for {HttpContext?.User?.Identity?.Name}.", orgId);
return Ok();
}
}

View File

@ -47,23 +47,26 @@ namespace Remotely.Server.API
{
return NotFound();
}
var orgId = DataService.GetUserByName(rcRequest.Email)?.OrganizationID;
var result = await SignInManager.PasswordSignInAsync(rcRequest.Email, rcRequest.Password, false, true);
if (result.Succeeded)
{
DataService.WriteEvent($"API login successful for {rcRequest.Email}.");
DataService.WriteEvent($"API login successful for {rcRequest.Email}.", orgId);
return await InitiateRemoteControl(rcRequest.DeviceID, rcRequest.Email);
}
else if (result.IsLockedOut)
{
DataService.WriteEvent($"API login unsuccessful due to lockout for {rcRequest.Email}.");
DataService.WriteEvent($"API login unsuccessful due to lockout for {rcRequest.Email}.", orgId);
return Unauthorized("Account is locked.");
}
else if (result.RequiresTwoFactor)
{
DataService.WriteEvent($"API login unsuccessful due to 2FA for {rcRequest.Email}.");
DataService.WriteEvent($"API login unsuccessful due to 2FA for {rcRequest.Email}.", orgId);
return Unauthorized("Account requires two-factor authentication.");
}
DataService.WriteEvent($"API login unsuccessful due to bad attempt for {rcRequest.Email}.");
DataService.WriteEvent($"API login unsuccessful due to bad attempt for {rcRequest.Email}.", orgId);
return BadRequest();
}

View File

@ -0,0 +1,37 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Mime;
using System.Text;
using System.Text.Json;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Remotely.Server.Services;
using Remotely.Shared.Models;
namespace Remotely.Server.API
{
[Route("api/[controller]")]
[ApiController]
[Authorize]
public class ServerLogsController : ControllerBase
{
public ServerLogsController(DataService dataService)
{
DataService = dataService;
}
public DataService DataService { get; set; }
// GET: api/ServerLogs
[HttpGet("Download")]
public ActionResult Download()
{
var logs = DataService.GetAllEventLogs(HttpContext.User.Identity.Name);
var fileBytes = Encoding.UTF8.GetBytes(JsonSerializer.Serialize(logs));
return File(fileBytes, "application/octet-stream", "ServerLogs.json");
}
}
}

View File

@ -24,6 +24,8 @@ namespace Remotely.Server.Areas.Identity.Pages.Account.Manage
public static string Options => "Options";
public static string Organization => "Organization";
public static string ServerLogs => "ServerLogs";
public static string IndexNavClass(ViewContext viewContext) => PageNavClass(viewContext, Index);
public static string ChangePasswordNavClass(ViewContext viewContext) => PageNavClass(viewContext, ChangePassword);
@ -39,6 +41,7 @@ namespace Remotely.Server.Areas.Identity.Pages.Account.Manage
public static string TwoFactorAuthenticationNavClass(ViewContext viewContext) => PageNavClass(viewContext, TwoFactorAuthentication);
public static string OptionsNavClass(ViewContext viewContext) => PageNavClass(viewContext, Options);
public static string OrganizationNavClass(ViewContext viewContext) => PageNavClass(viewContext, Organization);
public static string ServerLogsNavClass(ViewContext viewContext) => PageNavClass(viewContext, ServerLogs);
public static string PageNavClass(ViewContext viewContext, string page)
{

View File

@ -3,7 +3,7 @@ using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Remotely.Shared.Models;
using Remotely.Server.Data;
using Remotely.Server.Services;
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;

View File

@ -1,6 +1,6 @@
using Remotely.Shared.Models;
using Remotely.Shared.ViewModels;
using Remotely.Server.Data;
using Remotely.Server.Services;
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Mvc.RazorPages;
using System.Collections.Generic;
@ -13,10 +13,9 @@ namespace Remotely.Server.Areas.Identity.Pages.Account.Manage
{
public class OrganizationModel : PageModel
{
public OrganizationModel(DataService dataService, UserManager<RemotelyUser> userManager)
public OrganizationModel(DataService dataService)
{
DataService = dataService;
UserManager = userManager;
}
public List<SelectListItem> DeviceGroups { get; } = new List<SelectListItem>();
@ -31,7 +30,6 @@ namespace Remotely.Server.Areas.Identity.Pages.Account.Manage
public List<OrganizationUser> Users { get; set; }
private DataService DataService { get; }
private UserManager<RemotelyUser> UserManager { get; }
public void OnGet()
{
OrganizationName = DataService.GetOrganizationName(User.Identity.Name);

View File

@ -0,0 +1,53 @@
@page
@model Remotely.Server.Areas.Identity.Pages.Account.Manage.ServerLogsModel
@inject DataService DataService
@{
ViewData["Title"] = "Server Logs";
var currentUser = DataService.GetUserByName(User.Identity.Name);
var isAdmin = currentUser.IsAdministrator;
var eventLogs = DataService.GetAllEventLogs(User.Identity.Name);
}
<h4>@ViewData["Title"]</h4>
@if (isAdmin)
{
<div class="row mb-3">
<div class="col-sm-12 text-right">
<button class="btn btn-primary mr-3"
onclick="location.assign('/API/Commands/JSON')">
Scripting History
</button>
<button class="btn btn-primary"
onclick="location.assign('/API/ServerLogs/Download')">
Server Logs
</button>
</div>
</div>
<table class="table table-hover table-striped">
<thead>
<tr>
<th>Type</th>
<th>Timestamp</th>
<th>Message</th>
<th>Source</th>
<th>Stack Trace</th>
</tr>
</thead>
<tbody>
@foreach (var eventLog in eventLogs)
{
<tr>
<td>@eventLog.EventType</td>
<td>@eventLog.TimeStamp</td>
<td>@eventLog.Message</td>
<td>@eventLog.Source</td>
<td>@eventLog.StackTrace</td>
</tr>
}
</tbody>
</table>
}
else
{
<h5 class="text-muted">Only organization administrators can view this page.</h5>
}

View File

@ -0,0 +1,16 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
namespace Remotely.Server.Areas.Identity.Pages.Account.Manage
{
public class ServerLogsModel : PageModel
{
public void OnGet()
{
}
}
}

View File

@ -3,15 +3,16 @@
var hasExternalLogins = (await SignInManager.GetExternalAuthenticationSchemesAsync()).Any();
}
<ul class="nav nav-pills flex-column">
<li class="nav-item"><a class="nav-link @ManageNavPages.IndexNavClass(ViewContext)" id="profile" asp-page="./Index">Profile</a></li>
<li class="nav-item"><a class="nav-link @ManageNavPages.ChangePasswordNavClass(ViewContext)" id="change-password" asp-page="./ChangePassword">Password</a></li>
<li class="nav-item"><a id="options" class="nav-link @ManageNavPages.OptionsNavClass(ViewContext)" asp-page="./Options">Options</a></li>
<li class="nav-item"><a id="options" class="nav-link @ManageNavPages.OrganizationNavClass(ViewContext)" asp-page="./Organization">Organization</a></li>
@if (hasExternalLogins)
{
<li id="external-logins" class="nav-item"><a id="external-login" class="nav-link @ManageNavPages.ExternalLoginsNavClass(ViewContext)" asp-page="./ExternalLogins">External logins</a></li>
}
<li class="nav-item"><a class="nav-link @ManageNavPages.TwoFactorAuthenticationNavClass(ViewContext)" id="two-factor" asp-page="./TwoFactorAuthentication">Two-factor authentication</a></li>
<li class="nav-item"><a class="nav-link @ManageNavPages.PersonalDataNavClass(ViewContext)" id="personal-data" asp-page="./PersonalData">Personal data</a></li>
</ul>
<ul class="nav nav-pills flex-column">
<li class="nav-item"><a class="nav-link @ManageNavPages.IndexNavClass(ViewContext)" id="profile" asp-page="./Index">Profile</a></li>
<li class="nav-item"><a class="nav-link @ManageNavPages.ChangePasswordNavClass(ViewContext)" id="change-password" asp-page="./ChangePassword">Password</a></li>
<li class="nav-item"><a id="options" class="nav-link @ManageNavPages.OptionsNavClass(ViewContext)" asp-page="./Options">Options</a></li>
<li class="nav-item"><a id="options" class="nav-link @ManageNavPages.OrganizationNavClass(ViewContext)" asp-page="./Organization">Organization</a></li>
<li class="nav-item"><a id="options" class="nav-link @ManageNavPages.ServerLogsNavClass(ViewContext)" asp-page="./ServerLogs">Server Logs</a></li>
@if (hasExternalLogins)
{
<li id="external-logins" class="nav-item"><a id="external-login" class="nav-link @ManageNavPages.ExternalLoginsNavClass(ViewContext)" asp-page="./ExternalLogins">External logins</a></li>
}
<li class="nav-item"><a class="nav-link @ManageNavPages.TwoFactorAuthenticationNavClass(ViewContext)" id="two-factor" asp-page="./TwoFactorAuthentication">Two-factor authentication</a></li>
<li class="nav-item"><a class="nav-link @ManageNavPages.PersonalDataNavClass(ViewContext)" id="personal-data" asp-page="./PersonalData">Personal data</a></li>
</ul>

View File

@ -1,3 +1,3 @@
@using Remotely.Server.Areas.Identity.Pages.Account.Manage
@using Remotely.Server.Data;
@using Remotely.Server.Services
@using Remotely.Shared.Models

View File

@ -1,6 +1,6 @@
@page
@inject Remotely.Server.Services.ApplicationConfig AppConfig
@inject Remotely.Server.Data.DataService DataService
@inject Remotely.Server.Services.DataService DataService
@model RegisterModel
@{
ViewData["Title"] = "Register";

View File

@ -7,7 +7,7 @@ using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
using Microsoft.AspNetCore.Mvc.Rendering;
using Remotely.Server.Data;
using Remotely.Server.Services;
namespace Remotely.Server.Pages
{

View File

@ -3,7 +3,7 @@ using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Threading.Tasks;
using Remotely.Server.Data;
using Remotely.Server.Services;
using Microsoft.AspNetCore.Diagnostics;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Mvc;
@ -38,7 +38,7 @@ namespace Remotely.Server.Pages
{
var logEntry = new Remotely.Shared.Models.EventLog()
{
EventType = Remotely.Shared.Models.EventTypes.Error,
EventType = Remotely.Shared.Models.EventType.Error,
Message = error.Message,
Source = error.Source,
StackTrace = error.StackTrace,

View File

@ -2,12 +2,12 @@
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Remotely.Server.Data;
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
using Remotely.Shared.Models;
using Microsoft.AspNetCore.Mvc.Rendering;
using Remotely.Server.Services;
namespace Remotely.Server.Pages
{

View File

@ -2,7 +2,7 @@
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Remotely.Server.Data;
using Remotely.Server.Services;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;

View File

@ -1,5 +1,5 @@
@inject Remotely.Server.Services.ApplicationConfig AppConfig
@inject Remotely.Server.Data.DataService DataService
@inject Remotely.Server.Services.DataService DataService
@model IndexModel
@{
var organizationCount = DataService.GetOrganizationCount();

View File

@ -1,5 +1,5 @@
@using Microsoft.AspNetCore.Identity
@using Remotely.Server
@using Remotely.Server.Data
@using Remotely.Server.Services
@namespace Remotely.Server.Pages
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers

View File

@ -140,7 +140,7 @@ namespace Remotely.Server.Services
{
DataService.WriteEvent(new EventLog()
{
EventType = EventTypes.Info,
EventType = EventType.Info,
Message = $"File transfer started by {RemotelyUser.UserName}. File transfer IDs: {string.Join(", ", fileIDs)}.",
TimeStamp = DateTime.Now,
OrganizationID = RemotelyUser.OrganizationID

View File

@ -1,6 +1,5 @@
using Remotely.Shared.Models;
using Remotely.Shared.ViewModels;
using Remotely.Server.Services;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Identity;
using Microsoft.EntityFrameworkCore;
@ -9,8 +8,9 @@ using System.Collections.Generic;
using System.IO;
using System.Linq;
using Remotely.Shared.ViewModels.Organization;
using Remotely.Server.Data;
namespace Remotely.Server.Data
namespace Remotely.Server.Services
{
public class DataService
{
@ -119,7 +119,7 @@ namespace Remotely.Server.Data
{
WriteEvent(new EventLog()
{
EventType = EventTypes.Info,
EventType = EventType.Info,
Message = $"Unable to add device {device.DeviceName} because organization {device.OrganizationID} does not exist.",
Source = "DataService.AddOrUpdateDevice"
});
@ -269,9 +269,20 @@ namespace Remotely.Server.Data
public IEnumerable<CommandContext> GetAllCommandContexts(string userName)
{
var orgID = GetUserByName(userName).OrganizationID;
var orgID = RemotelyContext.Users
.FirstOrDefault(x => x.UserName == userName)
?.OrganizationID;
return RemotelyContext.CommandContexts.Where(x => x.OrganizationID == orgID);
}
public IEnumerable<EventLog> GetAllEventLogs(string userName)
{
var orgID = RemotelyContext.Users
.FirstOrDefault(x => x.UserName == userName)
?.OrganizationID;
return RemotelyContext.EventLogs.Where(x => x.OrganizationID == orgID);
}
public IEnumerable<Device> GetAllDevicesForUser(string userID)
{
@ -513,7 +524,7 @@ namespace Remotely.Server.Data
{
RemotelyContext.EventLogs.Add(new EventLog()
{
EventType = EventTypes.Error,
EventType = EventType.Error,
Message = ex.Message,
Source = ex.Source,
StackTrace = ex.StackTrace,
@ -522,13 +533,26 @@ namespace Remotely.Server.Data
RemotelyContext.SaveChanges();
}
public void WriteEvent(string message)
public void WriteEvent(string message, string organizationId)
{
RemotelyContext.EventLogs.Add(new EventLog()
{
EventType = EventTypes.Info,
EventType = EventType.Info,
Message = message,
TimeStamp = DateTime.Now
TimeStamp = DateTime.Now,
OrganizationID = organizationId
});
RemotelyContext.SaveChanges();
}
public void WriteEvent(string message, EventType eventType, string organizationId)
{
RemotelyContext.EventLogs.Add(new EventLog()
{
EventType = eventType,
Message = message,
TimeStamp = DateTime.Now,
OrganizationID = organizationId
});
RemotelyContext.SaveChanges();
}

View File

@ -68,7 +68,7 @@ namespace Remotely.Server.Services
{
DataService.WriteEvent(new EventLog()
{
EventType = EventTypes.Info,
EventType = EventType.Info,
OrganizationID = device.OrganizationID,
Message = $"Device connection for {device?.DeviceName} was denied because it is already connected."
});

View File

@ -6,7 +6,7 @@ using System.Threading.Tasks;
namespace Remotely.Server.Services
{
public class PascalCase : JsonNamingPolicy
public class PascalCasePolicy : JsonNamingPolicy
{
public override string ConvertName(string name)
{

View File

@ -150,9 +150,9 @@ namespace Remotely.Server.Services
await RCDeviceHub.Clients.Client(ScreenCasterID).SendAsync("ClipboardTransfer", transferText, typeText, Context.ConnectionId);
}
public async Task SendLatencyUpdate(DateTime sentTime)
public async Task SendLatencyUpdate(DateTime sentTime, int bytesRecieved)
{
await RCDeviceHub.Clients.Client(ScreenCasterID).SendAsync("LatencyUpdate", sentTime, Context.ConnectionId);
await RCDeviceHub.Clients.Client(ScreenCasterID).SendAsync("LatencyUpdate", sentTime, bytesRecieved, Context.ConnectionId);
}
public async Task SendQualityChange(int qualityLevel)
@ -177,24 +177,35 @@ namespace Remotely.Server.Services
screenCasterID = RCDeviceSocketHub.SessionInfoList.First(x => x.Value.AttendedSessionID == screenCasterID).Value.RCSocketID;
}
string orgId = null;
if (Context?.User?.Identity?.IsAuthenticated == true)
{
orgId = DataService.GetUserByID(Context.UserIdentifier).OrganizationID;
}
RCDeviceSocketHub.SessionInfoList.TryGetValue(screenCasterID, out var sessionInfo);
DataService.WriteEvent(new EventLog()
{
EventType = EventTypes.Info,
EventType = EventType.Info,
TimeStamp = DateTime.Now,
Message = $"Remote control session requested. " +
$"Login ID (if logged in): {Context?.User?.Identity?.Name}. " +
$"Machine Name: {sessionInfo.MachineName}. " +
$"Requester Name (if specified): {requesterName}. " +
$"Connection ID: {Context.ConnectionId}. User ID: {Context.UserIdentifier}. " +
$"Screen Caster ID: {screenCasterID}. " +
$"Mode: {((RemoteControlMode)remoteControlMode).ToString()}. " +
$"Login ID (if logged in): {Context?.User?.Identity?.Name}. " +
$"Rquester Name (if specified): {requesterName}. " +
$"Requester IP Address: " + Context?.GetHttpContext()?.Connection?.RemoteIpAddress?.ToString()
$"Requester IP Address: " + Context?.GetHttpContext()?.Connection?.RemoteIpAddress?.ToString(),
OrganizationID = orgId
});
ScreenCasterID = screenCasterID;
Mode = (RemoteControlMode)remoteControlMode;
RequesterName = requesterName;
var sessionInfo = RCDeviceSocketHub.SessionInfoList.FirstOrDefault(x => x.Value.RCSocketID == screenCasterID).Value;
if (Mode == RemoteControlMode.Unattended)
{
sessionInfo.Mode = RemoteControlMode.Unattended;

View File

@ -132,7 +132,7 @@ namespace Remotely.Server
services.AddMvc()
.SetCompatibilityVersion(CompatibilityVersion.Version_3_0).AddJsonOptions(options =>
{
options.JsonSerializerOptions.PropertyNamingPolicy = new PascalCase();
options.JsonSerializerOptions.PropertyNamingPolicy = new PascalCasePolicy();
});
services.AddSignalR(options =>
@ -142,7 +142,7 @@ namespace Remotely.Server
})
.AddJsonProtocol(options =>
{
options.PayloadSerializerOptions.PropertyNamingPolicy = new PascalCase();
options.PayloadSerializerOptions.PropertyNamingPolicy = new PascalCasePolicy();
})
.AddMessagePackProtocol();

View File

@ -36,8 +36,8 @@ export class RCBrowserSockets {
SendScreenCastRequestToDevice() {
this.Connection.invoke("SendScreenCastRequestToDevice", RemoteControl.ClientID, RemoteControl.RequesterName, RemoteControl.Mode);
}
SendLatencyUpdate(sentTime) {
this.Connection.invoke("SendLatencyUpdate", sentTime);
SendLatencyUpdate(sentTime, bytesReceived) {
this.Connection.invoke("SendLatencyUpdate", sentTime, bytesReceived);
}
SendSelectScreen(index) {
this.Connection.invoke("SelectScreen", index);
@ -128,7 +128,7 @@ export class RCBrowserSockets {
UI.Screen2DContext.clearRect(0, 0, width, height);
});
hubConnection.on("ScreenCapture", (buffer, left, top, width, height, captureTime) => {
this.SendLatencyUpdate(captureTime);
this.SendLatencyUpdate(captureTime, buffer.byteLength);
var url = window.URL.createObjectURL(new Blob([buffer]));
var img = document.createElement("img");
img.onload = () => {

File diff suppressed because one or more lines are too long

View File

@ -49,8 +49,8 @@ export class RCBrowserSockets {
SendScreenCastRequestToDevice() {
this.Connection.invoke("SendScreenCastRequestToDevice", RemoteControl.ClientID, RemoteControl.RequesterName, RemoteControl.Mode);
}
SendLatencyUpdate(sentTime: Date) {
this.Connection.invoke("SendLatencyUpdate", sentTime);
SendLatencyUpdate(sentTime: Date, bytesReceived: number) {
this.Connection.invoke("SendLatencyUpdate", sentTime, bytesReceived);
}
SendSelectScreen(index: number) {
this.Connection.invoke("SelectScreen", index);
@ -142,7 +142,7 @@ export class RCBrowserSockets {
});
hubConnection.on("ScreenCapture", (buffer: Uint8Array, left:number, top:number, width:number, height:number, captureTime: Date) => {
this.SendLatencyUpdate(captureTime);
this.SendLatencyUpdate(captureTime, buffer.byteLength);
var url = window.URL.createObjectURL(new Blob([buffer]));
var img = document.createElement("img");

View File

@ -10,7 +10,7 @@ namespace Remotely.Shared.Models
{
[Key]
public string ID { get; set; } = Guid.NewGuid().ToString();
public EventTypes EventType { get; set; }
public EventType EventType { get; set; }
public string Message { get; set; }
public string Source { get; set; }
public string StackTrace { get; set; }
@ -19,10 +19,11 @@ namespace Remotely.Shared.Models
[JsonIgnore]
public virtual Organization Organization { get; set; }
}
public enum EventTypes
public enum EventType
{
Info = 0,
Error = 1,
Debug = 2
Debug = 2,
Warning = 3
}
}