mirror of
https://github.com/immense/Remotely.git
synced 2025-10-26 11:27:15 +00:00
346 lines
10 KiB
C#
346 lines
10 KiB
C#
using Immense.RemoteControl.Desktop.Native.Windows;
|
|
using Immense.RemoteControl.Shared;
|
|
using Immense.RemoteControl.Shared.Extensions;
|
|
using MailKit;
|
|
using Microsoft.AspNetCore.Identity;
|
|
using Microsoft.AspNetCore.Mvc;
|
|
using Microsoft.AspNetCore.WebUtilities;
|
|
using Microsoft.Build.Framework;
|
|
using Microsoft.Extensions.Logging;
|
|
using Org.BouncyCastle.Crypto.Agreement;
|
|
using Remotely.Server.Auth;
|
|
using Remotely.Server.Extensions;
|
|
using Remotely.Server.Services;
|
|
using Remotely.Shared.Models;
|
|
using Remotely.Shared.ViewModels;
|
|
using System;
|
|
using System.Text;
|
|
using System.Text.Encodings.Web;
|
|
using System.Threading.Tasks;
|
|
|
|
// For more information on enabling Web API for empty projects, visit https://go.microsoft.com/fwlink/?LinkID=397860
|
|
|
|
namespace Remotely.Server.API;
|
|
|
|
[Route("api/[controller]")]
|
|
[ApiController]
|
|
public class OrganizationManagementController : ControllerBase
|
|
{
|
|
private readonly IDataService _dataService;
|
|
private readonly IEmailSenderEx _emailSender;
|
|
private readonly ILogger<OrganizationManagementController> _logger;
|
|
private readonly UserManager<RemotelyUser> _userManager;
|
|
|
|
public OrganizationManagementController(
|
|
UserManager<RemotelyUser> userManager,
|
|
IDataService dataService,
|
|
IEmailSenderEx emailSender,
|
|
ILogger<OrganizationManagementController> logger)
|
|
{
|
|
_dataService = dataService;
|
|
_userManager = userManager;
|
|
_emailSender = emailSender;
|
|
_logger = logger;
|
|
}
|
|
|
|
[HttpPost("ChangeIsAdmin/{userID}")]
|
|
[ServiceFilter(typeof(ApiAuthorizationFilter))]
|
|
public async Task<IActionResult> ChangeIsAdmin(string userId, [FromBody] bool isAdmin)
|
|
{
|
|
if (!Request.Headers.TryGetOrganizationId(out var orgId))
|
|
{
|
|
return Unauthorized();
|
|
}
|
|
|
|
if (User.Identity?.IsAuthenticated == true)
|
|
{
|
|
var userResult = await _dataService.GetUserByNameWithOrg($"{User.Identity.Name}");
|
|
if (userResult.IsSuccess && userResult.Value.Id == userId)
|
|
{
|
|
return BadRequest("You can't remove administrator rights from yourself.");
|
|
}
|
|
}
|
|
|
|
_dataService.ChangeUserIsAdmin(orgId, userId, isAdmin);
|
|
return NoContent();
|
|
}
|
|
|
|
[HttpDelete("DeleteInvite/{inviteID}")]
|
|
[ServiceFilter(typeof(ApiAuthorizationFilter))]
|
|
public async Task<IActionResult> DeleteInvite(string inviteID)
|
|
{
|
|
if (!Request.Headers.TryGetOrganizationId(out var orgId))
|
|
{
|
|
return Unauthorized();
|
|
}
|
|
|
|
var result = await _dataService.DeleteInvite(orgId, inviteID);
|
|
_logger.LogResult(result);
|
|
|
|
if (!result.IsSuccess)
|
|
{
|
|
return BadRequest(result.Reason);
|
|
}
|
|
|
|
return NoContent();
|
|
}
|
|
|
|
[HttpDelete("DeleteUser/{userID}")]
|
|
[ServiceFilter(typeof(ApiAuthorizationFilter))]
|
|
public async Task<IActionResult> DeleteUser(string userId)
|
|
{
|
|
if (!Request.Headers.TryGetOrganizationId(out var orgId))
|
|
{
|
|
return Unauthorized();
|
|
}
|
|
|
|
if (User.Identity?.IsAuthenticated == true)
|
|
{
|
|
var userResult = await _dataService.GetUserByNameWithOrg($"{User.Identity.Name}");
|
|
if (userResult.IsSuccess && userResult.Value.Id == userId)
|
|
{
|
|
return BadRequest("You can't delete yourself here. You must go to the Personal Data page to delete your own account.");
|
|
}
|
|
}
|
|
|
|
|
|
var result = await _dataService.DeleteUser(orgId, userId);
|
|
_logger.LogResult(result);
|
|
if (!result.IsSuccess)
|
|
{
|
|
return BadRequest(result.Reason);
|
|
}
|
|
|
|
return NoContent();
|
|
}
|
|
|
|
[HttpGet("DeviceGroup")]
|
|
[ServiceFilter(typeof(ApiAuthorizationFilter))]
|
|
public IActionResult DeviceGroup()
|
|
{
|
|
if (!Request.Headers.TryGetOrganizationId(out var orgId))
|
|
{
|
|
return Unauthorized();
|
|
}
|
|
|
|
return Ok(_dataService.GetDeviceGroupsForOrganization(orgId));
|
|
}
|
|
|
|
[HttpDelete("DeviceGroup")]
|
|
[ServiceFilter(typeof(ApiAuthorizationFilter))]
|
|
public async Task<IActionResult> DeviceGroup([FromBody] string deviceGroupId)
|
|
{
|
|
if (!Request.Headers.TryGetOrganizationId(out var orgId))
|
|
{
|
|
return Unauthorized();
|
|
}
|
|
|
|
var result = await _dataService.DeleteDeviceGroup(orgId, deviceGroupId.Trim());
|
|
_logger.LogResult(result);
|
|
if (!result.IsSuccess)
|
|
{
|
|
return BadRequest(result.Reason);
|
|
}
|
|
return NoContent();
|
|
}
|
|
|
|
[HttpPost("DeviceGroup")]
|
|
[ServiceFilter(typeof(ApiAuthorizationFilter))]
|
|
public async Task<IActionResult> DeviceGroup([FromBody] DeviceGroup deviceGroup)
|
|
{
|
|
if (!Request.Headers.TryGetOrganizationId(out var orgId))
|
|
{
|
|
return Unauthorized();
|
|
}
|
|
|
|
if (!ModelState.IsValid)
|
|
{
|
|
return BadRequest();
|
|
}
|
|
|
|
var result = await _dataService.AddDeviceGroup(orgId, deviceGroup);
|
|
if (!result.IsSuccess)
|
|
{
|
|
return BadRequest(result.Reason);
|
|
}
|
|
return Ok(result.Value.ID);
|
|
}
|
|
|
|
[HttpDelete("DeviceGroup/{groupID}/Users/")]
|
|
[ServiceFilter(typeof(ApiAuthorizationFilter))]
|
|
public async Task<IActionResult> DeviceGroupRemoveUser([FromBody] string userID, string groupID)
|
|
{
|
|
if (!Request.Headers.TryGetOrganizationId(out var orgId))
|
|
{
|
|
return Unauthorized();
|
|
}
|
|
|
|
if (!ModelState.IsValid)
|
|
{
|
|
return BadRequest();
|
|
}
|
|
|
|
if (!await _dataService.RemoveUserFromDeviceGroup(orgId, groupID, userID))
|
|
{
|
|
return BadRequest("Failed to remove user from group.");
|
|
}
|
|
return Ok();
|
|
}
|
|
|
|
[HttpPost("DeviceGroup/{groupID}/Users/")]
|
|
[ServiceFilter(typeof(ApiAuthorizationFilter))]
|
|
public IActionResult DeviceGroupAddUser([FromBody] string userID, string groupID)
|
|
{
|
|
if (!Request.Headers.TryGetOrganizationId(out var orgId))
|
|
{
|
|
return Unauthorized();
|
|
}
|
|
|
|
if (!ModelState.IsValid)
|
|
{
|
|
return BadRequest();
|
|
}
|
|
|
|
var result = _dataService.AddUserToDeviceGroup(orgId, groupID, userID, out var resultMessage);
|
|
if (!result)
|
|
{
|
|
return BadRequest(resultMessage);
|
|
}
|
|
|
|
return Ok(resultMessage);
|
|
}
|
|
|
|
[HttpGet("GenerateResetUrl/{userID}")]
|
|
[ServiceFilter(typeof(ApiAuthorizationFilter))]
|
|
public async Task<IActionResult> GenerateResetUrl(string userId)
|
|
{
|
|
if (!Request.Headers.TryGetOrganizationId(out var orgId))
|
|
{
|
|
return Unauthorized();
|
|
}
|
|
|
|
var user = await _userManager.FindByIdAsync(userId);
|
|
|
|
if (user is null)
|
|
{
|
|
return NotFound();
|
|
}
|
|
|
|
if (user.OrganizationID != orgId)
|
|
{
|
|
return Unauthorized();
|
|
}
|
|
|
|
var code = await _userManager.GeneratePasswordResetTokenAsync(user);
|
|
code = WebEncoders.Base64UrlEncode(Encoding.UTF8.GetBytes(code));
|
|
var callbackUrl = Url.Page(
|
|
"/Account/ResetPassword",
|
|
pageHandler: null,
|
|
values: new { area = "Identity", code },
|
|
protocol: Request.Scheme);
|
|
|
|
return Ok(callbackUrl);
|
|
|
|
}
|
|
|
|
[HttpPut("Name")]
|
|
[ServiceFilter(typeof(ApiAuthorizationFilter))]
|
|
public async Task<IActionResult> Name([FromBody] string organizationName)
|
|
{
|
|
if (!Request.Headers.TryGetOrganizationId(out var orgId))
|
|
{
|
|
return Unauthorized();
|
|
}
|
|
|
|
if (organizationName.Length > 25)
|
|
{
|
|
return BadRequest();
|
|
}
|
|
|
|
var result = await _dataService.UpdateOrganizationName(orgId, organizationName.Trim());
|
|
_logger.LogResult(result);
|
|
if (!result.IsSuccess)
|
|
{
|
|
return BadRequest(result.Reason);
|
|
}
|
|
return NoContent();
|
|
}
|
|
|
|
[HttpPut("SetDefault")]
|
|
[ServiceFilter(typeof(ApiAuthorizationFilter))]
|
|
public async Task<IActionResult> SetDefault([FromBody] bool isDefault)
|
|
{
|
|
if (!Request.Headers.TryGetOrganizationId(out var orgId))
|
|
{
|
|
return Unauthorized();
|
|
}
|
|
|
|
await _dataService.SetIsDefaultOrganization(orgId, isDefault);
|
|
return NoContent();
|
|
}
|
|
|
|
[HttpPost("SendInvite")]
|
|
[ServiceFilter(typeof(ApiAuthorizationFilter))]
|
|
public async Task<IActionResult> SendInvite([FromBody] InviteViewModel invite)
|
|
{
|
|
if (!Request.Headers.TryGetOrganizationId(out var orgId))
|
|
{
|
|
return Unauthorized();
|
|
}
|
|
|
|
if (!ModelState.IsValid)
|
|
{
|
|
return BadRequest();
|
|
}
|
|
|
|
|
|
if (!_dataService.DoesUserExist(invite.InvitedUser))
|
|
{
|
|
var result = await _dataService.CreateUser(invite.InvitedUser, invite.IsAdmin, orgId);
|
|
if (!result.IsSuccess)
|
|
{
|
|
return BadRequest("There was an issue creating the new account.");
|
|
}
|
|
|
|
var user = await _userManager.FindByEmailAsync(invite.InvitedUser);
|
|
|
|
if (user is null)
|
|
{
|
|
return BadRequest("User not found.");
|
|
}
|
|
|
|
await _userManager.ConfirmEmailAsync(user, await _userManager.GenerateEmailConfirmationTokenAsync(user));
|
|
|
|
return Ok();
|
|
}
|
|
else
|
|
{
|
|
var newInvite = await _dataService.AddInvite(orgId, invite);
|
|
|
|
if (!newInvite.IsSuccess)
|
|
{
|
|
return BadRequest(newInvite.Reason);
|
|
}
|
|
|
|
var inviteURL = $"{Request.Scheme}://{Request.Host}/Invite?id={newInvite.Value.ID}";
|
|
var emailResult = await _emailSender.SendEmailAsync(invite.InvitedUser, "Invitation to Organization in Remotely",
|
|
$@"<img src='{Request.Scheme}://{Request.Host}/images/Remotely_Logo.png'/>
|
|
<br><br>
|
|
Hello!
|
|
<br><br>
|
|
You've been invited to join an organization in Remotely.
|
|
<br><br>
|
|
You can join the organization by <a href='{HtmlEncoder.Default.Encode(inviteURL)}'>clicking here</a>.",
|
|
orgId);
|
|
|
|
if (!emailResult)
|
|
{
|
|
return Problem("There was an error sending the invitation email.");
|
|
}
|
|
|
|
return Ok();
|
|
}
|
|
|
|
}
|
|
}
|