mirror of
https://github.com/immense/Remotely.git
synced 2025-10-26 11:27:15 +00:00
Add custom authorization filter for API.
This commit is contained in:
parent
71c86015aa
commit
43b1152ff5
@ -21,7 +21,6 @@ namespace Remotely.Server.API
|
||||
private IWebHostEnvironment HostingEnv { get; }
|
||||
private DataService DataService { get; }
|
||||
|
||||
// GET: api/<controller>
|
||||
[HttpGet("[action]")]
|
||||
public string CurrentVersion()
|
||||
{
|
||||
|
||||
@ -29,18 +29,12 @@ namespace Remotely.Server.API
|
||||
private DataService DataService { get; set; }
|
||||
private IWebHostEnvironment HostEnv { get; set; }
|
||||
|
||||
[Authorize]
|
||||
[ServiceFilter(typeof(ApiAuthorizationFilter))]
|
||||
[HttpGet("{platformID}")]
|
||||
public async Task<ActionResult> Get(string platformID)
|
||||
{
|
||||
var user = DataService.GetUserByName(User.Identity.Name);
|
||||
return await GetInstallFile(user.OrganizationID, platformID);
|
||||
}
|
||||
|
||||
[HttpGet("{organizationID}/{platformID}")]
|
||||
public async Task<ActionResult> Get(string organizationID, string platformID)
|
||||
{
|
||||
return await GetInstallFile(organizationID, platformID);
|
||||
Request.Headers.TryGetValue("OrganizationID", out var orgID);
|
||||
return await GetInstallFile(orgID, platformID);
|
||||
}
|
||||
|
||||
private async Task<ActionResult> GetInstallFile(string organizationID, string platformID)
|
||||
@ -51,9 +45,6 @@ namespace Remotely.Server.API
|
||||
byte[] fileBytes;
|
||||
switch (platformID)
|
||||
{
|
||||
// TODO: Remove x64/x86 and PS files after a few releases.
|
||||
case "Win10-x64":
|
||||
case "Win10-x86":
|
||||
case "Win10":
|
||||
{
|
||||
fileName = $"Install-{platformID}.ps1";
|
||||
|
||||
@ -28,16 +28,13 @@ namespace Remotely.Server.API
|
||||
|
||||
// GET: api/<controller>
|
||||
[HttpGet("{fileExt}")]
|
||||
[Authorize]
|
||||
[ServiceFilter(typeof(ApiAuthorizationFilter))]
|
||||
public ActionResult DownloadAll(string fileExt)
|
||||
{
|
||||
if (!DataService.GetUserByName(User.Identity.Name).IsAdministrator)
|
||||
{
|
||||
return Unauthorized();
|
||||
}
|
||||
Request.Headers.TryGetValue("OrganizationID", out var orgID);
|
||||
|
||||
var content = "";
|
||||
var commandContexts = DataService.GetAllCommandContexts(User.Identity.Name);
|
||||
var commandContexts = DataService.GetAllCommandContexts(orgID);
|
||||
switch (fileExt.ToUpper())
|
||||
{
|
||||
case "JSON":
|
||||
@ -59,11 +56,13 @@ namespace Remotely.Server.API
|
||||
}
|
||||
|
||||
[HttpGet("{fileExt}/{commandID}")]
|
||||
[Authorize]
|
||||
[ServiceFilter(typeof(ApiAuthorizationFilter))]
|
||||
public FileResult DownloadResults(string fileExt, string commandID)
|
||||
{
|
||||
Request.Headers.TryGetValue("OrganizationID", out var orgID);
|
||||
|
||||
var content = "";
|
||||
var commandContext = DataService.GetCommandContext(commandID, User.Identity.Name);
|
||||
var commandContext = DataService.GetCommandContext(commandID, orgID);
|
||||
switch (fileExt.ToUpper())
|
||||
{
|
||||
case "JSON":
|
||||
@ -85,10 +84,11 @@ namespace Remotely.Server.API
|
||||
}
|
||||
|
||||
[HttpGet("PSCoreResult/{commandID}/{deviceID}")]
|
||||
[Authorize]
|
||||
[ServiceFilter(typeof(ApiAuthorizationFilter))]
|
||||
public PSCoreCommandResult PSCoreResult(string commandID, string deviceID)
|
||||
{
|
||||
return DataService.GetCommandContext(commandID, User.Identity.Name).PSCoreResults.FirstOrDefault(x => x.DeviceID == deviceID);
|
||||
Request.Headers.TryGetValue("OrganizationID", out var orgID);
|
||||
return DataService.GetCommandContext(commandID, orgID).PSCoreResults.FirstOrDefault(x => x.DeviceID == deviceID);
|
||||
}
|
||||
|
||||
[HttpGet("GenericResult/{commandID}/{deviceID}")]
|
||||
|
||||
@ -1,34 +0,0 @@
|
||||
using Microsoft.AspNetCore.Hosting;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.IO.Compression;
|
||||
|
||||
namespace Remotely.Server.API
|
||||
{
|
||||
// TODO: Delete after a few versions.
|
||||
[Route("api/[controller]")]
|
||||
[ApiController]
|
||||
public class CoreVersionController : ControllerBase
|
||||
{
|
||||
public CoreVersionController(IWebHostEnvironment hostingEnv)
|
||||
{
|
||||
this.HostingEnv = hostingEnv;
|
||||
}
|
||||
|
||||
public IWebHostEnvironment HostingEnv { get; }
|
||||
|
||||
// GET: api/<controller>
|
||||
[HttpGet()]
|
||||
public string Get()
|
||||
{
|
||||
var filePath = Path.Combine(HostingEnv.ContentRootPath, "CurrentVersion.txt");
|
||||
if (!System.IO.File.Exists(filePath))
|
||||
{
|
||||
return "0.0.0.0";
|
||||
}
|
||||
return System.IO.File.ReadAllText(filePath).Trim();
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -12,7 +12,6 @@ using Microsoft.AspNetCore.Mvc;
|
||||
|
||||
namespace Remotely.Server.API
|
||||
{
|
||||
[Authorize]
|
||||
[ApiController]
|
||||
[Route("api/[controller]")]
|
||||
public class DevicesController : ControllerBase
|
||||
@ -26,21 +25,35 @@ namespace Remotely.Server.API
|
||||
private DataService DataService { get; set; }
|
||||
private UserManager<RemotelyUser> UserManager { get; set; }
|
||||
|
||||
// GET: api/<controller>
|
||||
|
||||
[HttpGet]
|
||||
public async Task<IEnumerable<Device>> Get()
|
||||
[ServiceFilter(typeof(ApiAuthorizationFilter))]
|
||||
public IEnumerable<Device> Get()
|
||||
{
|
||||
var user = await UserManager.GetUserAsync(User);
|
||||
var devices = DataService.GetAllDevicesForUser(user.Id);
|
||||
return devices;
|
||||
Request.Headers.TryGetValue("OrganizationID", out var orgID);
|
||||
|
||||
if (User.Identity.IsAuthenticated)
|
||||
{
|
||||
return DataService.GetDevicesForUser(User.Identity.Name);
|
||||
}
|
||||
|
||||
return DataService.GetAllDevices(orgID);
|
||||
}
|
||||
|
||||
// GET api/<controller>/5
|
||||
[ServiceFilter(typeof(ApiAuthorizationFilter))]
|
||||
[HttpGet("{id}")]
|
||||
public async Task<Device> Get(string id)
|
||||
public Device Get(string id)
|
||||
{
|
||||
var user = await UserManager.GetUserAsync(User);
|
||||
return DataService.GetDeviceForUser(user.Id, id);
|
||||
Request.Headers.TryGetValue("OrganizationID", out var orgID);
|
||||
|
||||
var device = DataService.GetDevice(orgID, id);
|
||||
|
||||
if (User.Identity.IsAuthenticated &&
|
||||
!DataService.DoesUserHaveAccessToDevice(id, User.Identity.Name))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
return device;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -20,7 +20,6 @@ using Microsoft.AspNetCore.WebUtilities;
|
||||
namespace Remotely.Server.API
|
||||
{
|
||||
[Route("api/[controller]")]
|
||||
[Authorize]
|
||||
[ApiController]
|
||||
public class OrganizationManagementController : ControllerBase
|
||||
{
|
||||
@ -37,37 +36,48 @@ namespace Remotely.Server.API
|
||||
|
||||
|
||||
[HttpPost("ChangeIsAdmin/{userID}")]
|
||||
[ServiceFilter(typeof(ApiAuthorizationFilter))]
|
||||
public IActionResult ChangeIsAdmin(string userID, [FromBody]bool isAdmin)
|
||||
{
|
||||
if (!DataService.GetUserByName(User.Identity.Name).IsAdministrator)
|
||||
if (User.Identity.IsAuthenticated &&
|
||||
!DataService.GetUserByName(User.Identity.Name).IsAdministrator)
|
||||
{
|
||||
return Unauthorized();
|
||||
}
|
||||
|
||||
if (DataService.GetUserByName(User.Identity.Name).Id == userID)
|
||||
if (User.Identity.IsAuthenticated &&
|
||||
DataService.GetUserByName(User.Identity.Name).Id == userID)
|
||||
{
|
||||
return BadRequest("You can't remove administrator rights from yourself.");
|
||||
}
|
||||
|
||||
DataService.ChangeUserIsAdmin(User.Identity.Name, userID, isAdmin);
|
||||
Request.Headers.TryGetValue("OrganizationID", out var orgID);
|
||||
|
||||
DataService.ChangeUserIsAdmin(orgID, userID, isAdmin);
|
||||
return Ok("ok");
|
||||
}
|
||||
|
||||
[HttpDelete("DeleteInvite/{inviteID}")]
|
||||
[ServiceFilter(typeof(ApiAuthorizationFilter))]
|
||||
public IActionResult DeleteInvite(string inviteID)
|
||||
{
|
||||
if (!DataService.GetUserByName(User.Identity.Name).IsAdministrator)
|
||||
if (User.Identity.IsAuthenticated &&
|
||||
!DataService.GetUserByName(User.Identity.Name).IsAdministrator)
|
||||
{
|
||||
return Unauthorized();
|
||||
}
|
||||
DataService.DeleteInvite(User.Identity.Name, inviteID);
|
||||
|
||||
Request.Headers.TryGetValue("OrganizationID", out var orgID);
|
||||
DataService.DeleteInvite(orgID, inviteID);
|
||||
return Ok("ok");
|
||||
}
|
||||
|
||||
[HttpPut("Name")]
|
||||
[ServiceFilter(typeof(ApiAuthorizationFilter))]
|
||||
public IActionResult Name([FromBody]string organizationName)
|
||||
{
|
||||
if (!DataService.GetUserByName(User.Identity.Name).IsAdministrator)
|
||||
if (User.Identity.IsAuthenticated &&
|
||||
!DataService.GetUserByName(User.Identity.Name).IsAdministrator)
|
||||
{
|
||||
return Unauthorized();
|
||||
}
|
||||
@ -75,56 +85,72 @@ namespace Remotely.Server.API
|
||||
{
|
||||
return BadRequest();
|
||||
}
|
||||
DataService.UpdateOrganizationName(User.Identity.Name, organizationName.Trim());
|
||||
|
||||
Request.Headers.TryGetValue("OrganizationID", out var orgID);
|
||||
DataService.UpdateOrganizationName(orgID, organizationName.Trim());
|
||||
return Ok("ok");
|
||||
}
|
||||
|
||||
[HttpDelete("DeviceGroup")]
|
||||
[ServiceFilter(typeof(ApiAuthorizationFilter))]
|
||||
public IActionResult DeviceGroup([FromBody]string deviceGroupID)
|
||||
{
|
||||
if (!DataService.GetUserByName(User.Identity.Name).IsAdministrator)
|
||||
if (User.Identity.IsAuthenticated &&
|
||||
!DataService.GetUserByName(User.Identity.Name).IsAdministrator)
|
||||
{
|
||||
return Unauthorized();
|
||||
}
|
||||
|
||||
DataService.DeleteDeviceGroup(User.Identity.Name, deviceGroupID.Trim());
|
||||
Request.Headers.TryGetValue("OrganizationID", out var orgID);
|
||||
DataService.DeleteDeviceGroup(orgID, deviceGroupID.Trim());
|
||||
return Ok("ok");
|
||||
}
|
||||
|
||||
[HttpPost("DeviceGroup")]
|
||||
[ServiceFilter(typeof(ApiAuthorizationFilter))]
|
||||
public IActionResult DeviceGroup([FromBody]DeviceGroup deviceGroup)
|
||||
{
|
||||
if (!DataService.GetUserByName(User.Identity.Name).IsAdministrator)
|
||||
if (User.Identity.IsAuthenticated &&
|
||||
!DataService.GetUserByName(User.Identity.Name).IsAdministrator)
|
||||
{
|
||||
return Unauthorized();
|
||||
}
|
||||
|
||||
if (!ModelState.IsValid)
|
||||
{
|
||||
return BadRequest();
|
||||
}
|
||||
var result = DataService.AddDeviceGroup(User.Identity.Name, deviceGroup, out var deviceGroupID, out var errorMessage);
|
||||
|
||||
Request.Headers.TryGetValue("OrganizationID", out var orgID);
|
||||
var result = DataService.AddDeviceGroup(orgID, deviceGroup, out var deviceGroupID, out var errorMessage);
|
||||
if (!result)
|
||||
{
|
||||
return BadRequest(errorMessage);
|
||||
}
|
||||
return Ok(deviceGroupID);
|
||||
}
|
||||
|
||||
[HttpDelete("RemoveUserFromOrganization/{userID}")]
|
||||
[ServiceFilter(typeof(ApiAuthorizationFilter))]
|
||||
public IActionResult RemoveUserFromOrganization(string userID)
|
||||
{
|
||||
if (!DataService.GetUserByName(User.Identity.Name).IsAdministrator)
|
||||
if (User.Identity.IsAuthenticated &&
|
||||
!DataService.GetUserByName(User.Identity.Name).IsAdministrator)
|
||||
{
|
||||
return Unauthorized();
|
||||
}
|
||||
|
||||
DataService.RemoveUserFromOrganization(User.Identity.Name, userID);
|
||||
Request.Headers.TryGetValue("OrganizationID", out var orgID);
|
||||
DataService.RemoveUserFromOrganization(orgID, userID);
|
||||
return Ok("ok");
|
||||
}
|
||||
|
||||
[HttpPost("SendInvite")]
|
||||
[ServiceFilter(typeof(ApiAuthorizationFilter))]
|
||||
public async Task<IActionResult> SendInvite([FromBody]Invite invite)
|
||||
{
|
||||
if (!DataService.GetUserByName(User.Identity.Name).IsAdministrator)
|
||||
if (User.Identity.IsAuthenticated &&
|
||||
!DataService.GetUserByName(User.Identity.Name).IsAdministrator)
|
||||
{
|
||||
return Unauthorized();
|
||||
}
|
||||
@ -165,7 +191,9 @@ namespace Remotely.Server.API
|
||||
}
|
||||
}
|
||||
|
||||
var newInvite = DataService.AddInvite(User.Identity.Name, invite);
|
||||
Request.Headers.TryGetValue("OrganizationID", out var orgID);
|
||||
|
||||
var newInvite = DataService.AddInvite(orgID, invite);
|
||||
|
||||
var inviteURL = $"{Request.Scheme}://{Request.Host}/Invite?id={newInvite.ID}";
|
||||
await EmailSender.SendEmailAsync(invite.InvitedUser, "Invitation to Organization in Remotely",
|
||||
@ -173,7 +201,7 @@ namespace Remotely.Server.API
|
||||
<br><br>
|
||||
Hello!
|
||||
<br><br>
|
||||
You've been invited by {User.Identity.Name} to join an organization in Remotely.
|
||||
You've been invited to join an organization in Remotely.
|
||||
{newUserMessage}
|
||||
<br><br>
|
||||
You can join the organization by <a href='{HtmlEncoder.Default.Encode(inviteURL)}'>clicking here</a>.");
|
||||
|
||||
@ -35,10 +35,11 @@ namespace Remotely.Server.API
|
||||
public SignInManager<RemotelyUser> SignInManager { get; }
|
||||
|
||||
[HttpGet("{deviceID}")]
|
||||
[Authorize]
|
||||
[ServiceFilter(typeof(ApiAuthorizationFilter))]
|
||||
public async Task<IActionResult> Get(string deviceID)
|
||||
{
|
||||
return await InitiateRemoteControl(deviceID, HttpContext.User.Identity.Name);
|
||||
Request.Headers.TryGetValue("OrganizationID", out var orgID);
|
||||
return await InitiateRemoteControl(deviceID, orgID);
|
||||
}
|
||||
|
||||
[HttpPost]
|
||||
@ -71,47 +72,46 @@ namespace Remotely.Server.API
|
||||
return BadRequest();
|
||||
}
|
||||
|
||||
private async Task<IActionResult> InitiateRemoteControl(string deviceID, string userName)
|
||||
private async Task<IActionResult> InitiateRemoteControl(string deviceID, string orgID)
|
||||
{
|
||||
var remotelyUser = DataService.GetUserByName(userName);
|
||||
var targetDevice = DeviceSocketHub.ServiceConnections.FirstOrDefault(x =>
|
||||
x.Value.OrganizationID == remotelyUser.OrganizationID &&
|
||||
x.Value.OrganizationID == orgID &&
|
||||
x.Value.ID.ToLower() == deviceID.ToLower());
|
||||
|
||||
if (targetDevice.Value != null)
|
||||
{
|
||||
if (DataService.DoesUserHaveAccessToDevice(targetDevice.Value.ID, remotelyUser))
|
||||
if (User.Identity.IsAuthenticated &&
|
||||
!DataService.DoesUserHaveAccessToDevice(targetDevice.Value.ID, User.Identity.Name))
|
||||
{
|
||||
var currentUsers = RCDeviceSocketHub.SessionInfoList.Count(x => x.Value.OrganizationID == remotelyUser.OrganizationID);
|
||||
if (currentUsers >= AppConfig.RemoteControlSessionLimit)
|
||||
{
|
||||
return BadRequest("There are already the maximum amount of active remote control sessions for your organization.");
|
||||
}
|
||||
return Unauthorized();
|
||||
}
|
||||
|
||||
var existingSessions = RCDeviceSocketHub.SessionInfoList.Where(x => x.Value.DeviceID == targetDevice.Value.ID);
|
||||
|
||||
await DeviceHub.Clients.Client(targetDevice.Key).SendAsync("RemoteControl", Request.HttpContext.Connection.Id, targetDevice.Key);
|
||||
var currentUsers = RCDeviceSocketHub.SessionInfoList.Count(x => x.Value.OrganizationID == orgID);
|
||||
if (currentUsers >= AppConfig.RemoteControlSessionLimit)
|
||||
{
|
||||
return BadRequest("There are already the maximum amount of active remote control sessions for your organization.");
|
||||
}
|
||||
|
||||
var stopWatch = Stopwatch.StartNew();
|
||||
var existingSessions = RCDeviceSocketHub.SessionInfoList.Where(x => x.Value.DeviceID == targetDevice.Value.ID);
|
||||
|
||||
while (!RCDeviceSocketHub.SessionInfoList.Values.Any(x=>x.DeviceID == targetDevice.Value.ID && !existingSessions.Any(y=>y.Key != x.RCDeviceSocketID)) && stopWatch.Elapsed.TotalSeconds < 5)
|
||||
{
|
||||
await Task.Delay(10);
|
||||
}
|
||||
await DeviceHub.Clients.Client(targetDevice.Key).SendAsync("RemoteControl", Request.HttpContext.Connection.Id, targetDevice.Key);
|
||||
|
||||
if (!RCDeviceSocketHub.SessionInfoList.Values.Any(x => x.DeviceID == targetDevice.Value.ID && !existingSessions.Any(y => y.Key != x.RCDeviceSocketID)))
|
||||
{
|
||||
return StatusCode(408, "The remote control process failed to start in time on the remote device.");
|
||||
}
|
||||
else
|
||||
{
|
||||
var rcSession = RCDeviceSocketHub.SessionInfoList.Values.FirstOrDefault(x=>x.DeviceID == targetDevice.Value.ID && !existingSessions.Any(y=>y.Key != x.RCDeviceSocketID));
|
||||
return Ok($"{HttpContext.Request.Scheme}://{Request.Host}/RemoteControl?clientID={rcSession.RCDeviceSocketID}&serviceID={targetDevice.Key}&fromApi=true");
|
||||
}
|
||||
var stopWatch = Stopwatch.StartNew();
|
||||
|
||||
while (!RCDeviceSocketHub.SessionInfoList.Values.Any(x => x.DeviceID == targetDevice.Value.ID && !existingSessions.Any(y => y.Key != x.RCDeviceSocketID)) && stopWatch.Elapsed.TotalSeconds < 5)
|
||||
{
|
||||
await Task.Delay(10);
|
||||
}
|
||||
|
||||
if (!RCDeviceSocketHub.SessionInfoList.Values.Any(x => x.DeviceID == targetDevice.Value.ID && !existingSessions.Any(y => y.Key != x.RCDeviceSocketID)))
|
||||
{
|
||||
return StatusCode(408, "The remote control process failed to start in time on the remote device.");
|
||||
}
|
||||
else
|
||||
{
|
||||
return Unauthorized();
|
||||
var rcSession = RCDeviceSocketHub.SessionInfoList.Values.FirstOrDefault(x => x.DeviceID == targetDevice.Value.ID && !existingSessions.Any(y => y.Key != x.RCDeviceSocketID));
|
||||
return Ok($"{HttpContext.Request.Scheme}://{Request.Host}/RemoteControl?clientID={rcSession.RCDeviceSocketID}&serviceID={targetDevice.Key}&fromApi=true");
|
||||
}
|
||||
}
|
||||
else
|
||||
|
||||
@ -31,7 +31,7 @@ namespace Remotely.Server.API
|
||||
private IHubContext<DeviceSocketHub> DeviceHub { get; }
|
||||
private UserManager<RemotelyUser> UserManager { get; }
|
||||
|
||||
[Authorize]
|
||||
[ServiceFilter(typeof(ApiAuthorizationFilter))]
|
||||
[HttpPost("[action]/{mode}/{deviceID}")]
|
||||
public async Task<ActionResult<CommandContext>> ExecuteCommand(string mode, string deviceID)
|
||||
{
|
||||
@ -40,16 +40,24 @@ namespace Remotely.Server.API
|
||||
{
|
||||
command = await sr.ReadToEndAsync();
|
||||
}
|
||||
var username = Request.HttpContext.User.Identity.Name;
|
||||
var user = await UserManager.FindByNameAsync(username);
|
||||
if (!DataService.DoesUserHaveAccessToDevice(deviceID, user))
|
||||
|
||||
var userID = string.Empty;
|
||||
if (Request.HttpContext.User.Identity.IsAuthenticated)
|
||||
{
|
||||
return Unauthorized();
|
||||
var username = Request.HttpContext.User.Identity.Name;
|
||||
var user = await UserManager.FindByNameAsync(username);
|
||||
userID = user.Id;
|
||||
if (!DataService.DoesUserHaveAccessToDevice(deviceID, user))
|
||||
{
|
||||
return Unauthorized();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Request.Headers.TryGetValue("OrganizationID", out var orgID);
|
||||
|
||||
KeyValuePair<string, Device> connection = DeviceSocketHub.ServiceConnections.FirstOrDefault(x =>
|
||||
x.Value.OrganizationID == user.OrganizationID &&
|
||||
x.Value.OrganizationID == orgID &&
|
||||
x.Value.ID == deviceID);
|
||||
|
||||
if (string.IsNullOrWhiteSpace(connection.Key))
|
||||
@ -62,13 +70,13 @@ namespace Remotely.Server.API
|
||||
CommandMode = "PSCore",
|
||||
CommandText = command,
|
||||
SenderConnectionID = string.Empty,
|
||||
SenderUserID = user.Id,
|
||||
SenderUserID = userID,
|
||||
TargetDeviceIDs = new string[] { deviceID },
|
||||
OrganizationID = user.OrganizationID
|
||||
OrganizationID = orgID
|
||||
};
|
||||
DataService.AddOrUpdateCommandContext(commandContext);
|
||||
var requestID = Guid.NewGuid().ToString();
|
||||
await DeviceHub.Clients.Client(connection.Key).SendAsync("ExecuteCommandFromApi", mode, requestID, command, commandContext.ID, username);
|
||||
await DeviceHub.Clients.Client(connection.Key).SendAsync("ExecuteCommandFromApi", mode, requestID, command, commandContext.ID, Guid.NewGuid().ToString());
|
||||
var success = await TaskHelper.DelayUntil(() => DeviceSocketHub.ApiScriptResults.TryGetValue(requestID, out _), TimeSpan.FromSeconds(30));
|
||||
if (!success)
|
||||
{
|
||||
@ -77,7 +85,7 @@ namespace Remotely.Server.API
|
||||
DeviceSocketHub.ApiScriptResults.TryGetValue(requestID, out var commandID);
|
||||
DeviceSocketHub.ApiScriptResults.Remove(requestID);
|
||||
DataService.DetachEntity(commandContext);
|
||||
var result = DataService.GetCommandContext(commandID.ToString(), username);
|
||||
var result = DataService.GetCommandContext(commandID.ToString(), orgID);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
@ -15,7 +15,6 @@ namespace Remotely.Server.API
|
||||
{
|
||||
[Route("api/[controller]")]
|
||||
[ApiController]
|
||||
[Authorize]
|
||||
public class ServerLogsController : ControllerBase
|
||||
{
|
||||
|
||||
@ -25,11 +24,12 @@ namespace Remotely.Server.API
|
||||
}
|
||||
public DataService DataService { get; set; }
|
||||
|
||||
// GET: api/ServerLogs
|
||||
[ServiceFilter(typeof(ApiAuthorizationFilter))]
|
||||
[HttpGet("Download")]
|
||||
public ActionResult Download()
|
||||
{
|
||||
var logs = DataService.GetAllEventLogs(HttpContext.User.Identity.Name);
|
||||
Request.Headers.TryGetValue("OrganizationID", out var orgID);
|
||||
var logs = DataService.GetAllEventLogs(orgID);
|
||||
var fileBytes = Encoding.UTF8.GetBytes(JsonSerializer.Serialize(logs));
|
||||
return File(fileBytes, "application/octet-stream", "ServerLogs.json");
|
||||
}
|
||||
|
||||
@ -2,7 +2,7 @@
|
||||
@model Remotely.Server.Areas.Identity.Pages.Account.Manage.ApiTokensModel
|
||||
@inject DataService DataService
|
||||
@{
|
||||
ViewData["Title"] = "API Tokens";
|
||||
ViewData["Title"] = "API Access Tokens";
|
||||
}
|
||||
<h4>@ViewData["Title"]</h4>
|
||||
|
||||
|
||||
@ -8,7 +8,7 @@
|
||||
<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.ApiTokensNavClass(ViewContext)" asp-page="./ApiTokens">API Tokens</a></li>
|
||||
<li class="nav-item"><a id="options" class="nav-link @ManageNavPages.ApiTokensNavClass(ViewContext)" asp-page="./ApiTokens">API Access</a></li>
|
||||
<li class="nav-item"><a id="options" class="nav-link @ManageNavPages.ServerLogsNavClass(ViewContext)" asp-page="./ServerLogs">Server Logs</a></li>
|
||||
@if (hasExternalLogins)
|
||||
{
|
||||
|
||||
@ -104,6 +104,12 @@ namespace Remotely.Server.Data
|
||||
.HasConversion(
|
||||
x => JsonConvert.SerializeObject(x),
|
||||
x => JsonConvert.DeserializeObject<List<Drive>>(x));
|
||||
|
||||
builder.Entity<Device>()
|
||||
.HasIndex(x => x.DeviceName);
|
||||
|
||||
builder.Entity<ApiToken>()
|
||||
.HasIndex(x => x.Token);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
620
Server/Migrations/20200216015743_ApiToken and Device indexes.Designer.cs
generated
Normal file
620
Server/Migrations/20200216015743_ApiToken and Device indexes.Designer.cs
generated
Normal file
@ -0,0 +1,620 @@
|
||||
// <auto-generated />
|
||||
using System;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
|
||||
using Remotely.Server.Data;
|
||||
|
||||
namespace Remotely.Server.Migrations
|
||||
{
|
||||
[DbContext(typeof(ApplicationDbContext))]
|
||||
[Migration("20200216015743_ApiToken and Device indexes")]
|
||||
partial class ApiTokenandDeviceindexes
|
||||
{
|
||||
protected override void BuildTargetModel(ModelBuilder modelBuilder)
|
||||
{
|
||||
#pragma warning disable 612, 618
|
||||
modelBuilder
|
||||
.HasAnnotation("ProductVersion", "3.1.1");
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRole", b =>
|
||||
{
|
||||
b.Property<string>("Id")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("ConcurrencyStamp")
|
||||
.IsConcurrencyToken()
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("Name")
|
||||
.HasColumnType("TEXT")
|
||||
.HasMaxLength(256);
|
||||
|
||||
b.Property<string>("NormalizedName")
|
||||
.HasColumnType("TEXT")
|
||||
.HasMaxLength(256);
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("NormalizedName")
|
||||
.IsUnique()
|
||||
.HasName("RoleNameIndex");
|
||||
|
||||
b.ToTable("AspNetRoles");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim<string>", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<string>("ClaimType")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("ClaimValue")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("RoleId")
|
||||
.IsRequired()
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("RoleId");
|
||||
|
||||
b.ToTable("AspNetRoleClaims");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUser", b =>
|
||||
{
|
||||
b.Property<string>("Id")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<int>("AccessFailedCount")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<string>("ConcurrencyStamp")
|
||||
.IsConcurrencyToken()
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("Discriminator")
|
||||
.IsRequired()
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("Email")
|
||||
.HasColumnType("TEXT")
|
||||
.HasMaxLength(256);
|
||||
|
||||
b.Property<bool>("EmailConfirmed")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<bool>("LockoutEnabled")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<DateTimeOffset?>("LockoutEnd")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("NormalizedEmail")
|
||||
.HasColumnType("TEXT")
|
||||
.HasMaxLength(256);
|
||||
|
||||
b.Property<string>("NormalizedUserName")
|
||||
.HasColumnType("TEXT")
|
||||
.HasMaxLength(256);
|
||||
|
||||
b.Property<string>("PasswordHash")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("PhoneNumber")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<bool>("PhoneNumberConfirmed")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<string>("SecurityStamp")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<bool>("TwoFactorEnabled")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<string>("UserName")
|
||||
.HasColumnType("TEXT")
|
||||
.HasMaxLength(256);
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("NormalizedEmail")
|
||||
.HasName("EmailIndex");
|
||||
|
||||
b.HasIndex("NormalizedUserName")
|
||||
.IsUnique()
|
||||
.HasName("UserNameIndex");
|
||||
|
||||
b.ToTable("RemotelyUsers");
|
||||
|
||||
b.HasDiscriminator<string>("Discriminator").HasValue("IdentityUser");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim<string>", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<string>("ClaimType")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("ClaimValue")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("UserId")
|
||||
.IsRequired()
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("UserId");
|
||||
|
||||
b.ToTable("AspNetUserClaims");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin<string>", b =>
|
||||
{
|
||||
b.Property<string>("LoginProvider")
|
||||
.HasColumnType("TEXT")
|
||||
.HasMaxLength(128);
|
||||
|
||||
b.Property<string>("ProviderKey")
|
||||
.HasColumnType("TEXT")
|
||||
.HasMaxLength(128);
|
||||
|
||||
b.Property<string>("ProviderDisplayName")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("UserId")
|
||||
.IsRequired()
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.HasKey("LoginProvider", "ProviderKey");
|
||||
|
||||
b.HasIndex("UserId");
|
||||
|
||||
b.ToTable("AspNetUserLogins");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole<string>", b =>
|
||||
{
|
||||
b.Property<string>("UserId")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("RoleId")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.HasKey("UserId", "RoleId");
|
||||
|
||||
b.HasIndex("RoleId");
|
||||
|
||||
b.ToTable("AspNetUserRoles");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken<string>", b =>
|
||||
{
|
||||
b.Property<string>("UserId")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("LoginProvider")
|
||||
.HasColumnType("TEXT")
|
||||
.HasMaxLength(128);
|
||||
|
||||
b.Property<string>("Name")
|
||||
.HasColumnType("TEXT")
|
||||
.HasMaxLength(128);
|
||||
|
||||
b.Property<string>("Value")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.HasKey("UserId", "LoginProvider", "Name");
|
||||
|
||||
b.ToTable("AspNetUserTokens");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Remotely.Shared.Models.ApiToken", b =>
|
||||
{
|
||||
b.Property<string>("ID")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<DateTime?>("LastUsed")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("Name")
|
||||
.HasColumnType("TEXT")
|
||||
.HasMaxLength(200);
|
||||
|
||||
b.Property<string>("OrganizationID")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("Secret")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("Token")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.HasKey("ID");
|
||||
|
||||
b.HasIndex("OrganizationID");
|
||||
|
||||
b.HasIndex("Token");
|
||||
|
||||
b.ToTable("ApiTokens");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Remotely.Shared.Models.CommandContext", b =>
|
||||
{
|
||||
b.Property<string>("ID")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("CommandMode")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("CommandResults")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("CommandText")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("OrganizationID")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("PSCoreResults")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("SenderConnectionID")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("SenderUserID")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("TargetDeviceIDs")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<DateTime>("TimeStamp")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.HasKey("ID");
|
||||
|
||||
b.HasIndex("OrganizationID");
|
||||
|
||||
b.ToTable("CommandContexts");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Remotely.Shared.Models.Device", b =>
|
||||
{
|
||||
b.Property<string>("ID")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("AgentVersion")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("Alias")
|
||||
.HasColumnType("TEXT")
|
||||
.HasMaxLength(100);
|
||||
|
||||
b.Property<string>("CurrentUser")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("DeviceGroupID")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("DeviceName")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("Drives")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<double>("FreeMemory")
|
||||
.HasColumnType("REAL");
|
||||
|
||||
b.Property<double>("FreeStorage")
|
||||
.HasColumnType("REAL");
|
||||
|
||||
b.Property<bool>("Is64Bit")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<bool>("IsOnline")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<DateTime>("LastOnline")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<int>("OSArchitecture")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<string>("OSDescription")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("OrganizationID")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("Platform")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<int>("ProcessorCount")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<string>("ServerVerificationToken")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("Tags")
|
||||
.HasColumnType("TEXT")
|
||||
.HasMaxLength(200);
|
||||
|
||||
b.Property<double>("TotalMemory")
|
||||
.HasColumnType("REAL");
|
||||
|
||||
b.Property<double>("TotalStorage")
|
||||
.HasColumnType("REAL");
|
||||
|
||||
b.HasKey("ID");
|
||||
|
||||
b.HasIndex("DeviceGroupID");
|
||||
|
||||
b.HasIndex("DeviceName");
|
||||
|
||||
b.HasIndex("OrganizationID");
|
||||
|
||||
b.ToTable("Devices");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Remotely.Shared.Models.DeviceGroup", b =>
|
||||
{
|
||||
b.Property<string>("ID")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("Name")
|
||||
.HasColumnType("TEXT")
|
||||
.HasMaxLength(200);
|
||||
|
||||
b.Property<string>("OrganizationID")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.HasKey("ID");
|
||||
|
||||
b.HasIndex("OrganizationID");
|
||||
|
||||
b.ToTable("DeviceGroups");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Remotely.Shared.Models.EventLog", b =>
|
||||
{
|
||||
b.Property<string>("ID")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<int>("EventType")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<string>("Message")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("OrganizationID")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("Source")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("StackTrace")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<DateTime>("TimeStamp")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.HasKey("ID");
|
||||
|
||||
b.HasIndex("OrganizationID");
|
||||
|
||||
b.ToTable("EventLogs");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Remotely.Shared.Models.InviteLink", b =>
|
||||
{
|
||||
b.Property<string>("ID")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<DateTime>("DateSent")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("InvitedUser")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<bool>("IsAdmin")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<string>("OrganizationID")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("ResetUrl")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.HasKey("ID");
|
||||
|
||||
b.HasIndex("OrganizationID");
|
||||
|
||||
b.ToTable("InviteLinks");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Remotely.Shared.Models.Organization", b =>
|
||||
{
|
||||
b.Property<string>("ID")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("OrganizationName")
|
||||
.HasColumnType("TEXT")
|
||||
.HasMaxLength(25);
|
||||
|
||||
b.HasKey("ID");
|
||||
|
||||
b.ToTable("Organizations");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Remotely.Shared.Models.SharedFile", b =>
|
||||
{
|
||||
b.Property<string>("ID")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("ContentType")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<byte[]>("FileContents")
|
||||
.HasColumnType("BLOB");
|
||||
|
||||
b.Property<string>("FileName")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("OrganizationID")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<DateTime>("Timestamp")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.HasKey("ID");
|
||||
|
||||
b.HasIndex("OrganizationID");
|
||||
|
||||
b.ToTable("SharedFiles");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Remotely.Shared.Models.RemotelyUser", b =>
|
||||
{
|
||||
b.HasBaseType("Microsoft.AspNetCore.Identity.IdentityUser");
|
||||
|
||||
b.Property<bool>("IsAdministrator")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<string>("OrganizationID")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("UserOptions")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.HasIndex("OrganizationID");
|
||||
|
||||
b.HasIndex("UserName");
|
||||
|
||||
b.HasDiscriminator().HasValue("RemotelyUser");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim<string>", b =>
|
||||
{
|
||||
b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole", null)
|
||||
.WithMany()
|
||||
.HasForeignKey("RoleId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim<string>", b =>
|
||||
{
|
||||
b.HasOne("Microsoft.AspNetCore.Identity.IdentityUser", null)
|
||||
.WithMany()
|
||||
.HasForeignKey("UserId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin<string>", b =>
|
||||
{
|
||||
b.HasOne("Microsoft.AspNetCore.Identity.IdentityUser", null)
|
||||
.WithMany()
|
||||
.HasForeignKey("UserId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole<string>", b =>
|
||||
{
|
||||
b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole", null)
|
||||
.WithMany()
|
||||
.HasForeignKey("RoleId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.HasOne("Microsoft.AspNetCore.Identity.IdentityUser", null)
|
||||
.WithMany()
|
||||
.HasForeignKey("UserId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken<string>", b =>
|
||||
{
|
||||
b.HasOne("Microsoft.AspNetCore.Identity.IdentityUser", null)
|
||||
.WithMany()
|
||||
.HasForeignKey("UserId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Remotely.Shared.Models.ApiToken", b =>
|
||||
{
|
||||
b.HasOne("Remotely.Shared.Models.Organization", "Organization")
|
||||
.WithMany("ApiTokens")
|
||||
.HasForeignKey("OrganizationID");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Remotely.Shared.Models.CommandContext", b =>
|
||||
{
|
||||
b.HasOne("Remotely.Shared.Models.Organization", "Organization")
|
||||
.WithMany("CommandContexts")
|
||||
.HasForeignKey("OrganizationID");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Remotely.Shared.Models.Device", b =>
|
||||
{
|
||||
b.HasOne("Remotely.Shared.Models.DeviceGroup", "DeviceGroup")
|
||||
.WithMany("Devices")
|
||||
.HasForeignKey("DeviceGroupID");
|
||||
|
||||
b.HasOne("Remotely.Shared.Models.Organization", "Organization")
|
||||
.WithMany("Devices")
|
||||
.HasForeignKey("OrganizationID");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Remotely.Shared.Models.DeviceGroup", b =>
|
||||
{
|
||||
b.HasOne("Remotely.Shared.Models.Organization", "Organization")
|
||||
.WithMany("DeviceGroups")
|
||||
.HasForeignKey("OrganizationID");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Remotely.Shared.Models.EventLog", b =>
|
||||
{
|
||||
b.HasOne("Remotely.Shared.Models.Organization", "Organization")
|
||||
.WithMany("EventLogs")
|
||||
.HasForeignKey("OrganizationID");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Remotely.Shared.Models.InviteLink", b =>
|
||||
{
|
||||
b.HasOne("Remotely.Shared.Models.Organization", "Organization")
|
||||
.WithMany("InviteLinks")
|
||||
.HasForeignKey("OrganizationID");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Remotely.Shared.Models.SharedFile", b =>
|
||||
{
|
||||
b.HasOne("Remotely.Shared.Models.Organization", "Organization")
|
||||
.WithMany("SharedFiles")
|
||||
.HasForeignKey("OrganizationID");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Remotely.Shared.Models.RemotelyUser", b =>
|
||||
{
|
||||
b.HasOne("Remotely.Shared.Models.Organization", "Organization")
|
||||
.WithMany("RemotelyUsers")
|
||||
.HasForeignKey("OrganizationID");
|
||||
});
|
||||
#pragma warning restore 612, 618
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,47 @@
|
||||
using System;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
|
||||
namespace Remotely.Server.Migrations
|
||||
{
|
||||
public partial class ApiTokenandDeviceindexes : Migration
|
||||
{
|
||||
protected override void Up(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.AlterColumn<DateTime>(
|
||||
name: "LastUsed",
|
||||
table: "ApiTokens",
|
||||
nullable: true,
|
||||
oldClrType: typeof(DateTime),
|
||||
oldType: "TEXT");
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_Devices_DeviceName",
|
||||
table: "Devices",
|
||||
column: "DeviceName");
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_ApiTokens_Token",
|
||||
table: "ApiTokens",
|
||||
column: "Token");
|
||||
}
|
||||
|
||||
protected override void Down(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.DropIndex(
|
||||
name: "IX_Devices_DeviceName",
|
||||
table: "Devices");
|
||||
|
||||
migrationBuilder.DropIndex(
|
||||
name: "IX_ApiTokens_Token",
|
||||
table: "ApiTokens");
|
||||
|
||||
migrationBuilder.AlterColumn<DateTime>(
|
||||
name: "LastUsed",
|
||||
table: "ApiTokens",
|
||||
type: "TEXT",
|
||||
nullable: false,
|
||||
oldClrType: typeof(DateTime),
|
||||
oldNullable: true);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -223,7 +223,7 @@ namespace Remotely.Server.Migrations
|
||||
b.Property<string>("ID")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<DateTime>("LastUsed")
|
||||
b.Property<DateTime?>("LastUsed")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("Name")
|
||||
@ -243,6 +243,8 @@ namespace Remotely.Server.Migrations
|
||||
|
||||
b.HasIndex("OrganizationID");
|
||||
|
||||
b.HasIndex("Token");
|
||||
|
||||
b.ToTable("ApiTokens");
|
||||
});
|
||||
|
||||
@ -356,6 +358,8 @@ namespace Remotely.Server.Migrations
|
||||
|
||||
b.HasIndex("DeviceGroupID");
|
||||
|
||||
b.HasIndex("DeviceName");
|
||||
|
||||
b.HasIndex("OrganizationID");
|
||||
|
||||
b.ToTable("Devices");
|
||||
|
||||
@ -55,7 +55,7 @@ namespace Remotely.Server.Pages
|
||||
var user = DataService.GetUserByName(User.Identity.Name);
|
||||
if (user != null)
|
||||
{
|
||||
var device = DataService.GetDeviceForUser(user.Id, deviceID);
|
||||
var device = DataService.GetDevice(user.OrganizationID, deviceID);
|
||||
DeviceName = device?.DeviceName;
|
||||
AgentVersion = device.AgentVersion;
|
||||
Input.Alias = device?.Alias;
|
||||
|
||||
@ -19,6 +19,11 @@
|
||||
<None Remove="Areas\Identity\Services\**" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Compile Remove="Migrations\20200216033930_Test.cs" />
|
||||
<Compile Remove="Migrations\20200216033930_Test.Designer.cs" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Content Remove="wwwroot\scripts\BrowserSockets.ts" />
|
||||
<Content Remove="wwwroot\scripts\CommandCompletion.ts" />
|
||||
|
||||
44
Server/Services/ApiAuthorizationFilter.cs
Normal file
44
Server/Services/ApiAuthorizationFilter.cs
Normal file
@ -0,0 +1,44 @@
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.AspNetCore.Mvc.Filters;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Remotely.Server.Services
|
||||
{
|
||||
public class ApiAuthorizationFilter : ActionFilterAttribute, IAuthorizationFilter
|
||||
{
|
||||
public ApiAuthorizationFilter(DataService dataService)
|
||||
{
|
||||
DataService = dataService;
|
||||
}
|
||||
|
||||
private DataService DataService { get; }
|
||||
|
||||
public void OnAuthorization(AuthorizationFilterContext context)
|
||||
{
|
||||
|
||||
if (context.HttpContext.User.Identity.IsAuthenticated)
|
||||
{
|
||||
var orgID = DataService.GetUserByName(context.HttpContext.User.Identity.Name)?.OrganizationID;
|
||||
context.HttpContext.Request.Headers.Add("OrganizationID", orgID);
|
||||
return;
|
||||
}
|
||||
|
||||
if (context.HttpContext.Request.Headers.TryGetValue("Authorization", out var result))
|
||||
{
|
||||
var apiToken = result.ToString().Split(":")[0];
|
||||
var apiSecret = result.ToString().Split(":")[1];
|
||||
if (DataService.ValidateApiToken(apiToken, apiSecret))
|
||||
{
|
||||
var orgID = DataService.GetApiToken(apiToken)?.OrganizationID;
|
||||
context.HttpContext.Request.Headers.Add("OrganizationID", orgID);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
context.Result = new UnauthorizedResult();
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -27,31 +27,47 @@ namespace Remotely.Server.Services
|
||||
private IHostEnvironment HostEnvironment { get; }
|
||||
private ApplicationDbContext RemotelyContext { get; }
|
||||
|
||||
public bool AddDeviceGroup(string userName, DeviceGroup deviceGroup, out string deviceGroupID, out string errorMessage)
|
||||
public bool AddDeviceGroup(string orgID, DeviceGroup deviceGroup, out string deviceGroupID, out string errorMessage)
|
||||
{
|
||||
deviceGroupID = null;
|
||||
errorMessage = null;
|
||||
var organization = RemotelyContext.Users
|
||||
.Include(x => x.Organization)
|
||||
.ThenInclude(x => x.DeviceGroups)
|
||||
.FirstOrDefault(x => x.UserName == userName)
|
||||
.Organization;
|
||||
if (organization.DeviceGroups.Any(x => x.Name.ToLower() == deviceGroup.Name.ToLower()))
|
||||
|
||||
var organization = RemotelyContext.Organizations
|
||||
.Include(x => x.DeviceGroups)
|
||||
.FirstOrDefault(x => x.ID == orgID);
|
||||
|
||||
if (RemotelyContext.DeviceGroups.Any(x =>
|
||||
x.OrganizationID == orgID &&
|
||||
x.Name.ToLower() == deviceGroup.Name.ToLower()))
|
||||
{
|
||||
errorMessage = "Device group already exists.";
|
||||
return false;
|
||||
}
|
||||
|
||||
var newDeviceGroup = new DeviceGroup()
|
||||
{
|
||||
Name = deviceGroup.Name,
|
||||
Organization = organization
|
||||
Organization = organization,
|
||||
OrganizationID = orgID
|
||||
};
|
||||
|
||||
organization.DeviceGroups.Add(newDeviceGroup);
|
||||
RemotelyContext.SaveChanges();
|
||||
deviceGroupID = newDeviceGroup.ID;
|
||||
return true;
|
||||
}
|
||||
|
||||
public ApiToken GetApiToken(string apiToken)
|
||||
{
|
||||
return RemotelyContext.ApiTokens.FirstOrDefault(x => x.Token == apiToken);
|
||||
}
|
||||
|
||||
public bool ValidateApiToken(string apiToken, string apiSecret)
|
||||
{
|
||||
var token = RemotelyContext.ApiTokens.FirstOrDefault(x => x.Token == apiToken);
|
||||
return token?.Secret == apiSecret;
|
||||
}
|
||||
|
||||
public async Task RenameApiToken(string userName, string tokenId, string tokenName)
|
||||
{
|
||||
var user = RemotelyContext.Users.FirstOrDefault(x => x.UserName == userName);
|
||||
@ -89,14 +105,13 @@ namespace Remotely.Server.Services
|
||||
await RemotelyContext.SaveChangesAsync();
|
||||
}
|
||||
|
||||
public InviteLink AddInvite(string requesterUserName, Invite invite)
|
||||
public InviteLink AddInvite(string orgID, Invite invite)
|
||||
{
|
||||
invite.InvitedUser = invite.InvitedUser.ToLower();
|
||||
|
||||
var requester = RemotelyContext.Users.FirstOrDefault(x => x.UserName == requesterUserName);
|
||||
var organization = RemotelyContext.Organizations
|
||||
.Include(x => x.InviteLinks)
|
||||
.FirstOrDefault(x => x.ID == requester.OrganizationID);
|
||||
.FirstOrDefault(x => x.ID == orgID);
|
||||
|
||||
var newInvite = new InviteLink()
|
||||
{
|
||||
@ -205,15 +220,17 @@ namespace Remotely.Server.Services
|
||||
return newEntity.Entity.ID;
|
||||
}
|
||||
|
||||
public void ChangeUserIsAdmin(string requesterUserName, string targetUserID, bool isAdmin)
|
||||
public void ChangeUserIsAdmin(string organizationID, string targetUserID, bool isAdmin)
|
||||
{
|
||||
var requester = RemotelyContext.Users
|
||||
.Include(x => x.Organization)
|
||||
.ThenInclude(x => x.RemotelyUsers)
|
||||
.FirstOrDefault(x => x.UserName == requesterUserName);
|
||||
var targetUser = RemotelyContext.Users.FirstOrDefault(x =>
|
||||
x.OrganizationID == organizationID &&
|
||||
x.Id == targetUserID);
|
||||
|
||||
requester.Organization.RemotelyUsers.FirstOrDefault(x => x.Id == targetUserID).IsAdministrator = isAdmin;
|
||||
RemotelyContext.SaveChanges();
|
||||
if (targetUser != null)
|
||||
{
|
||||
targetUser.IsAdministrator = isAdmin;
|
||||
RemotelyContext.SaveChanges();
|
||||
}
|
||||
}
|
||||
|
||||
public void CleanupOldRecords()
|
||||
@ -242,32 +259,29 @@ namespace Remotely.Server.Services
|
||||
}
|
||||
}
|
||||
|
||||
public void DeleteDeviceGroup(string userName, string deviceGroupId)
|
||||
public void DeleteDeviceGroup(string orgID, string deviceGroupId)
|
||||
{
|
||||
var organization = RemotelyContext.Users
|
||||
.Include(x => x.Organization)
|
||||
.ThenInclude(x => x.DeviceGroups)
|
||||
.ThenInclude(x => x.Devices)
|
||||
.FirstOrDefault(x => x.UserName == userName)
|
||||
.Organization;
|
||||
var deviceGroup = RemotelyContext.DeviceGroups.FirstOrDefault(x =>
|
||||
x.ID == deviceGroupId &&
|
||||
x.OrganizationID == orgID);
|
||||
|
||||
var deviceGroup = organization.DeviceGroups.FirstOrDefault(x => x.ID == deviceGroupId);
|
||||
deviceGroup.Devices.ForEach(x =>
|
||||
{
|
||||
x.DeviceGroup = null;
|
||||
});
|
||||
|
||||
RemotelyContext.DeviceGroups.Remove(deviceGroup);
|
||||
RemotelyContext.SaveChanges();
|
||||
}
|
||||
|
||||
public void DeleteInvite(string requesterUserName, string inviteID)
|
||||
public void DeleteInvite(string orgID, string inviteID)
|
||||
{
|
||||
var requester = RemotelyContext.Users
|
||||
.Include(x => x.Organization)
|
||||
.ThenInclude(x => x.InviteLinks)
|
||||
.FirstOrDefault(x => x.UserName == requesterUserName);
|
||||
var invite = requester.Organization.InviteLinks.FirstOrDefault(x => x.ID == inviteID);
|
||||
var invite = RemotelyContext.InviteLinks.FirstOrDefault(x =>
|
||||
x.OrganizationID == orgID &&
|
||||
x.ID == inviteID);
|
||||
|
||||
var user = RemotelyContext.Users.FirstOrDefault(x => x.UserName == invite.InvitedUser);
|
||||
|
||||
if (user != null && string.IsNullOrWhiteSpace(user.PasswordHash))
|
||||
{
|
||||
RemotelyContext.Remove(user);
|
||||
@ -324,12 +338,8 @@ namespace Remotely.Server.Services
|
||||
.ToArray();
|
||||
}
|
||||
|
||||
public IEnumerable<CommandContext> GetAllCommandContexts(string userName)
|
||||
public IEnumerable<CommandContext> GetAllCommandContexts(string orgID)
|
||||
{
|
||||
var orgID = RemotelyContext.Users
|
||||
.FirstOrDefault(x => x.UserName == userName)
|
||||
?.OrganizationID;
|
||||
|
||||
return RemotelyContext.CommandContexts
|
||||
.Where(x => x.OrganizationID == orgID)
|
||||
.OrderByDescending(x => x.TimeStamp);
|
||||
@ -345,19 +355,19 @@ namespace Remotely.Server.Services
|
||||
}
|
||||
|
||||
|
||||
public IEnumerable<Device> GetAllDevicesForUser(string userID)
|
||||
public IEnumerable<Device> GetAllDevices(string orgID)
|
||||
{
|
||||
var user = RemotelyContext.Users.FirstOrDefault(x => x.Id == userID);
|
||||
|
||||
return RemotelyContext.Devices.Where(x => x.OrganizationID == user.OrganizationID);
|
||||
return RemotelyContext.Devices.Where(x => x.OrganizationID == orgID);
|
||||
}
|
||||
|
||||
public IEnumerable<EventLog> GetAllEventLogs(string userName)
|
||||
public IEnumerable<Device> GetDevicesForUser(string userName)
|
||||
{
|
||||
// TODO: Add authorization groups.
|
||||
var user = RemotelyContext.Users.FirstOrDefault(x => x.UserName == userName);
|
||||
return RemotelyContext.Devices.Where(x => x.OrganizationID == user.OrganizationID);
|
||||
}
|
||||
public IEnumerable<EventLog> GetAllEventLogs(string orgID)
|
||||
{
|
||||
var orgID = RemotelyContext.Users
|
||||
.FirstOrDefault(x => x.UserName == userName)
|
||||
?.OrganizationID;
|
||||
|
||||
return RemotelyContext.EventLogs
|
||||
.Where(x => x.OrganizationID == orgID)
|
||||
.OrderByDescending(x => x.TimeStamp);
|
||||
@ -391,13 +401,11 @@ namespace Remotely.Server.Services
|
||||
return RemotelyContext.Users.Where(x => x.OrganizationID == user.OrganizationID);
|
||||
}
|
||||
|
||||
public CommandContext GetCommandContext(string commandContextID, string userName)
|
||||
public CommandContext GetCommandContext(string commandContextID, string orgID)
|
||||
{
|
||||
var user = GetUserByName(userName);
|
||||
return RemotelyContext.CommandContexts
|
||||
.FirstOrDefault(x =>
|
||||
(user.IsAdministrator || x.SenderUserID == user.Id) &&
|
||||
x.OrganizationID == user.OrganizationID &&
|
||||
x.OrganizationID == orgID &&
|
||||
x.ID == commandContextID);
|
||||
}
|
||||
|
||||
@ -422,12 +430,10 @@ namespace Remotely.Server.Services
|
||||
return RemotelyContext.Devices.Count();
|
||||
}
|
||||
|
||||
public Device GetDeviceForUser(string userID, string deviceID)
|
||||
public Device GetDevice(string orgID, string deviceID)
|
||||
{
|
||||
var user = RemotelyContext.Users.FirstOrDefault(x => x.Id == userID);
|
||||
|
||||
return RemotelyContext.Devices.FirstOrDefault(x =>
|
||||
x.OrganizationID == user.OrganizationID &&
|
||||
x.OrganizationID == orgID &&
|
||||
x.ID == deviceID);
|
||||
}
|
||||
|
||||
@ -521,13 +527,11 @@ namespace Remotely.Server.Services
|
||||
RemotelyContext.SaveChanges();
|
||||
}
|
||||
|
||||
public void RemoveUserFromOrganization(string requesterUserName, string targetUserID)
|
||||
public void RemoveUserFromOrganization(string orgID, string targetUserID)
|
||||
{
|
||||
var requester = RemotelyContext.Users
|
||||
.Include(x => x.Organization)
|
||||
.ThenInclude(x => x.RemotelyUsers)
|
||||
.FirstOrDefault(x => x.UserName == requesterUserName);
|
||||
var target = requester.Organization.RemotelyUsers.FirstOrDefault(x => x.Id == targetUserID);
|
||||
var target = RemotelyContext.Users.FirstOrDefault(x =>
|
||||
x.Id == targetUserID &&
|
||||
x.OrganizationID == orgID);
|
||||
|
||||
var newOrganization = new Organization();
|
||||
target.Organization = newOrganization;
|
||||
@ -589,12 +593,10 @@ namespace Remotely.Server.Services
|
||||
RemotelyContext.SaveChanges();
|
||||
}
|
||||
|
||||
public void UpdateOrganizationName(string userName, string organizationName)
|
||||
public void UpdateOrganizationName(string orgID, string organizationName)
|
||||
{
|
||||
RemotelyContext.Users
|
||||
.Include(x => x.Organization)
|
||||
.FirstOrDefault(x => x.UserName == userName)
|
||||
.Organization
|
||||
RemotelyContext.Organizations
|
||||
.FirstOrDefault(x => x.ID == orgID)
|
||||
.OrganizationName = organizationName;
|
||||
RemotelyContext.SaveChanges();
|
||||
}
|
||||
|
||||
@ -157,6 +157,7 @@ namespace Remotely.Server
|
||||
services.AddScoped<RemoteControlSessionRecorder>();
|
||||
services.AddSingleton<ApplicationConfig>();
|
||||
services.AddSingleton<RandomGenerator>();
|
||||
services.AddScoped<ApiAuthorizationFilter>();
|
||||
}
|
||||
|
||||
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
|
||||
|
||||
Loading…
Reference in New Issue
Block a user