Add custom authorization filter for API.

This commit is contained in:
Jared Goodwin 2020-02-15 19:40:21 -08:00
parent 71c86015aa
commit 43b1152ff5
20 changed files with 928 additions and 194 deletions

View File

@ -21,7 +21,6 @@ namespace Remotely.Server.API
private IWebHostEnvironment HostingEnv { get; }
private DataService DataService { get; }
// GET: api/<controller>
[HttpGet("[action]")]
public string CurrentVersion()
{

View File

@ -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";

View File

@ -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}")]

View File

@ -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();
}
}
}

View File

@ -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;
}
}
}

View File

@ -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>.");

View File

@ -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

View File

@ -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;
}
}

View File

@ -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");
}

View File

@ -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>

View File

@ -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)
{

View File

@ -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);
}
}
}

View 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
}
}
}

View File

@ -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);
}
}
}

View File

@ -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");

View File

@ -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;

View File

@ -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" />

View 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();
}
}
}

View File

@ -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();
}

View File

@ -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.