Files
server/src/Api/Controllers/DevicesController.cs

Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

187 lines
6.1 KiB
C#
Raw Normal View History

using Bit.Api.Models.Request;
2021-12-14 15:05:07 +00:00
using Bit.Api.Models.Response;
using Bit.Core.Entities;
using Bit.Core.Enums;
2016-06-18 16:03:33 -04:00
using Bit.Core.Exceptions;
using Bit.Core.Repositories;
using Bit.Core.Services;
using Bit.Core.Utilities;
2016-06-18 16:03:33 -04:00
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
namespace Bit.Api.Controllers;
2022-08-29 16:06:55 -04:00
2016-06-18 16:03:33 -04:00
[Route("devices")]
[Authorize("Application")]
public class DevicesController : Controller
{
private readonly IDeviceRepository _deviceRepository;
private readonly IDeviceService _deviceService;
private readonly IUserService _userService;
[SG-167] Implement Passwordless Authentication via Notifications (#2276) * [SG-549] Commit Initial AuthRequest Repository (#2174) * Model Passwordless * Scaffold database for Passwordless * Implement SQL Repository * [SG-167] Base Passwordless API (#2185) * Implement Passwordless notifications * Implement Controller * Add documentation to BaseRequestValidator * Register AuthRequestRepo * Remove ExpirationDate from the AuthRequest table * [SG-407] Create job to delete expired requests (#2187) * chore: init * remove exp date * fix: log name * [SG-167] Added fingerprint phrase to response model. (#2233) * Remove FailedLoginAttempt logic * Block unknown devices * Add EF Support for passwordless * Got SignalR working for responses * Added delete job method to EF repo * Implement a GetMany API endpoint for AuthRequests * Ran dotnet format * Fix a merge issues * Redated migration scripts * tried sorting sqlproj * Remove FailedLoginAttempts from SQL * Groom Postgres script * Remove extra commas from migration script * Correct isSpent() * [SG-167] Adde identity validation for passwordless requests. Registered IAuthRepository. * [SG-167] Added origin of the request to response model * Use display name for device identifier in response * Add datetime conversions back to postgres migration script * [SG-655] Add anonymous endpoint for checking if a device & user combo match * [review] Consolidate error conditions Co-authored-by: Brandon Maharaj <107377945+BrandonM-Bitwarden@users.noreply.github.com> Co-authored-by: André Filipe da Silva Bispo <andrefsbispo@hotmail.com> Co-authored-by: André Bispo <abispo@bitwarden.com>
2022-09-26 13:21:13 -04:00
private readonly IUserRepository _userRepository;
2016-06-18 16:03:33 -04:00
public DevicesController(
IDeviceRepository deviceRepository,
IDeviceService deviceService,
[SG-167] Implement Passwordless Authentication via Notifications (#2276) * [SG-549] Commit Initial AuthRequest Repository (#2174) * Model Passwordless * Scaffold database for Passwordless * Implement SQL Repository * [SG-167] Base Passwordless API (#2185) * Implement Passwordless notifications * Implement Controller * Add documentation to BaseRequestValidator * Register AuthRequestRepo * Remove ExpirationDate from the AuthRequest table * [SG-407] Create job to delete expired requests (#2187) * chore: init * remove exp date * fix: log name * [SG-167] Added fingerprint phrase to response model. (#2233) * Remove FailedLoginAttempt logic * Block unknown devices * Add EF Support for passwordless * Got SignalR working for responses * Added delete job method to EF repo * Implement a GetMany API endpoint for AuthRequests * Ran dotnet format * Fix a merge issues * Redated migration scripts * tried sorting sqlproj * Remove FailedLoginAttempts from SQL * Groom Postgres script * Remove extra commas from migration script * Correct isSpent() * [SG-167] Adde identity validation for passwordless requests. Registered IAuthRepository. * [SG-167] Added origin of the request to response model * Use display name for device identifier in response * Add datetime conversions back to postgres migration script * [SG-655] Add anonymous endpoint for checking if a device & user combo match * [review] Consolidate error conditions Co-authored-by: Brandon Maharaj <107377945+BrandonM-Bitwarden@users.noreply.github.com> Co-authored-by: André Filipe da Silva Bispo <andrefsbispo@hotmail.com> Co-authored-by: André Bispo <abispo@bitwarden.com>
2022-09-26 13:21:13 -04:00
IUserService userService,
IUserRepository userRepository)
2016-06-18 16:03:33 -04:00
{
_deviceRepository = deviceRepository;
_deviceService = deviceService;
_userService = userService;
[SG-167] Implement Passwordless Authentication via Notifications (#2276) * [SG-549] Commit Initial AuthRequest Repository (#2174) * Model Passwordless * Scaffold database for Passwordless * Implement SQL Repository * [SG-167] Base Passwordless API (#2185) * Implement Passwordless notifications * Implement Controller * Add documentation to BaseRequestValidator * Register AuthRequestRepo * Remove ExpirationDate from the AuthRequest table * [SG-407] Create job to delete expired requests (#2187) * chore: init * remove exp date * fix: log name * [SG-167] Added fingerprint phrase to response model. (#2233) * Remove FailedLoginAttempt logic * Block unknown devices * Add EF Support for passwordless * Got SignalR working for responses * Added delete job method to EF repo * Implement a GetMany API endpoint for AuthRequests * Ran dotnet format * Fix a merge issues * Redated migration scripts * tried sorting sqlproj * Remove FailedLoginAttempts from SQL * Groom Postgres script * Remove extra commas from migration script * Correct isSpent() * [SG-167] Adde identity validation for passwordless requests. Registered IAuthRepository. * [SG-167] Added origin of the request to response model * Use display name for device identifier in response * Add datetime conversions back to postgres migration script * [SG-655] Add anonymous endpoint for checking if a device & user combo match * [review] Consolidate error conditions Co-authored-by: Brandon Maharaj <107377945+BrandonM-Bitwarden@users.noreply.github.com> Co-authored-by: André Filipe da Silva Bispo <andrefsbispo@hotmail.com> Co-authored-by: André Bispo <abispo@bitwarden.com>
2022-09-26 13:21:13 -04:00
_userRepository = userRepository;
2016-06-18 16:03:33 -04:00
}
[HttpGet("{id}")]
public async Task<DeviceResponseModel> Get(string id)
2022-08-29 16:06:55 -04:00
{
2016-06-18 16:03:33 -04:00
var device = await _deviceRepository.GetByIdAsync(new Guid(id), _userService.GetProperUserId(User).Value);
if (device == null)
2016-06-18 16:03:33 -04:00
{
throw new NotFoundException();
}
var response = new DeviceResponseModel(device);
return response;
2022-08-29 14:53:16 -04:00
}
2016-06-18 16:03:33 -04:00
[HttpGet("identifier/{identifier}")]
2016-06-18 16:03:33 -04:00
public async Task<DeviceResponseModel> GetByIdentifier(string identifier)
2022-08-29 16:06:55 -04:00
{
2016-06-18 16:03:33 -04:00
var device = await _deviceRepository.GetByIdentifierAsync(identifier, _userService.GetProperUserId(User).Value);
if (device == null)
2022-08-29 14:53:16 -04:00
{
2016-06-18 16:03:33 -04:00
throw new NotFoundException();
}
var response = new DeviceResponseModel(device);
return response;
2022-08-29 16:06:55 -04:00
}
2016-06-18 16:03:33 -04:00
[HttpGet("")]
2016-06-18 16:03:33 -04:00
public async Task<ListResponseModel<DeviceResponseModel>> Get()
2022-08-29 16:06:55 -04:00
{
ICollection<Device> devices = await _deviceRepository.GetManyByUserIdAsync(_userService.GetProperUserId(User).Value);
var responses = devices.Select(d => new DeviceResponseModel(d));
2016-06-18 16:03:33 -04:00
return new ListResponseModel<DeviceResponseModel>(responses);
2022-08-29 14:53:16 -04:00
}
2016-06-18 16:03:33 -04:00
[HttpPost("exist-by-types")]
public async Task<ActionResult<bool>> GetExistenceByTypes([FromBody] DeviceType[] deviceTypes)
{
var userId = _userService.GetProperUserId(User).Value;
var devices = await _deviceRepository.GetManyByUserIdAsync(userId);
var userHasDeviceOfTypes = devices.Any(d => deviceTypes.Contains(d.Type));
return Ok(userHasDeviceOfTypes);
}
[HttpPost("")]
2016-06-18 16:03:33 -04:00
public async Task<DeviceResponseModel> Post([FromBody] DeviceRequestModel model)
2022-08-29 14:53:16 -04:00
{
2016-06-18 16:03:33 -04:00
var device = model.ToDevice(_userService.GetProperUserId(User));
await _deviceService.SaveAsync(device);
var response = new DeviceResponseModel(device);
2016-06-18 16:03:33 -04:00
return response;
2022-08-29 16:06:55 -04:00
}
2016-06-18 16:03:33 -04:00
[HttpPut("{id}")]
[HttpPost("{id}")]
public async Task<DeviceResponseModel> Put(string id, [FromBody] DeviceRequestModel model)
2022-08-29 16:06:55 -04:00
{
var device = await _deviceRepository.GetByIdAsync(new Guid(id), _userService.GetProperUserId(User).Value);
if (device == null)
2022-08-29 16:06:55 -04:00
{
2016-06-18 16:03:33 -04:00
throw new NotFoundException();
}
await _deviceService.SaveAsync(model.ToDevice(device));
2016-06-18 16:03:33 -04:00
var response = new DeviceResponseModel(device);
return response;
2022-08-29 14:53:16 -04:00
}
[HttpPut("{identifier}/keys")]
[HttpPost("{identifier}/keys")]
public async Task<DeviceResponseModel> PutKeys(string identifier, [FromBody] DeviceKeysRequestModel model)
{
var device = await _deviceRepository.GetByIdentifierAsync(identifier, _userService.GetProperUserId(User).Value);
if (device == null)
{
throw new NotFoundException();
}
await _deviceService.SaveAsync(model.ToDevice(device));
var response = new DeviceResponseModel(device);
return response;
}
2016-06-18 16:03:33 -04:00
[HttpPut("identifier/{identifier}/token")]
[HttpPost("identifier/{identifier}/token")]
2016-06-18 16:03:33 -04:00
public async Task PutToken(string identifier, [FromBody] DeviceTokenRequestModel model)
2022-08-29 16:06:55 -04:00
{
2016-06-18 16:03:33 -04:00
var device = await _deviceRepository.GetByIdentifierAsync(identifier, _userService.GetProperUserId(User).Value);
if (device == null)
2016-06-18 16:03:33 -04:00
{
throw new NotFoundException();
2016-06-18 16:03:33 -04:00
}
await _deviceService.SaveAsync(model.ToDevice(device));
2022-08-29 16:06:55 -04:00
}
[AllowAnonymous]
[HttpPut("identifier/{identifier}/clear-token")]
[HttpPost("identifier/{identifier}/clear-token")]
2016-08-06 18:46:02 -04:00
public async Task PutClearToken(string identifier)
2022-08-29 16:06:55 -04:00
{
2016-08-06 18:46:02 -04:00
var device = await _deviceRepository.GetByIdentifierAsync(identifier);
if (device == null)
2022-08-29 14:53:16 -04:00
{
throw new NotFoundException();
2022-08-29 16:06:55 -04:00
}
await _deviceService.ClearTokenAsync(device);
2016-06-18 16:03:33 -04:00
}
2022-08-29 14:53:16 -04:00
[HttpDelete("{id}")]
[HttpPost("{id}/delete")]
public async Task Delete(string id)
2022-08-29 16:06:55 -04:00
{
var device = await _deviceRepository.GetByIdAsync(new Guid(id), _userService.GetProperUserId(User).Value);
if (device == null)
2022-08-29 16:06:55 -04:00
{
2016-06-18 16:03:33 -04:00
throw new NotFoundException();
}
2022-08-29 16:06:55 -04:00
await _deviceService.DeleteAsync(device);
2016-06-18 16:03:33 -04:00
}
[SG-167] Implement Passwordless Authentication via Notifications (#2276) * [SG-549] Commit Initial AuthRequest Repository (#2174) * Model Passwordless * Scaffold database for Passwordless * Implement SQL Repository * [SG-167] Base Passwordless API (#2185) * Implement Passwordless notifications * Implement Controller * Add documentation to BaseRequestValidator * Register AuthRequestRepo * Remove ExpirationDate from the AuthRequest table * [SG-407] Create job to delete expired requests (#2187) * chore: init * remove exp date * fix: log name * [SG-167] Added fingerprint phrase to response model. (#2233) * Remove FailedLoginAttempt logic * Block unknown devices * Add EF Support for passwordless * Got SignalR working for responses * Added delete job method to EF repo * Implement a GetMany API endpoint for AuthRequests * Ran dotnet format * Fix a merge issues * Redated migration scripts * tried sorting sqlproj * Remove FailedLoginAttempts from SQL * Groom Postgres script * Remove extra commas from migration script * Correct isSpent() * [SG-167] Adde identity validation for passwordless requests. Registered IAuthRepository. * [SG-167] Added origin of the request to response model * Use display name for device identifier in response * Add datetime conversions back to postgres migration script * [SG-655] Add anonymous endpoint for checking if a device & user combo match * [review] Consolidate error conditions Co-authored-by: Brandon Maharaj <107377945+BrandonM-Bitwarden@users.noreply.github.com> Co-authored-by: André Filipe da Silva Bispo <andrefsbispo@hotmail.com> Co-authored-by: André Bispo <abispo@bitwarden.com>
2022-09-26 13:21:13 -04:00
[AllowAnonymous]
[HttpGet("knowndevice")]
public async Task<bool> GetByIdentifierQuery(
[FromHeader(Name = "X-Request-Email")] string email,
[FromHeader(Name = "X-Device-Identifier")] string deviceIdentifier)
=> await GetByIdentifier(CoreHelpers.Base64UrlDecodeString(email), deviceIdentifier);
[Obsolete("Path is deprecated due to encoding issues, use /knowndevice instead.")]
[SG-167] Implement Passwordless Authentication via Notifications (#2276) * [SG-549] Commit Initial AuthRequest Repository (#2174) * Model Passwordless * Scaffold database for Passwordless * Implement SQL Repository * [SG-167] Base Passwordless API (#2185) * Implement Passwordless notifications * Implement Controller * Add documentation to BaseRequestValidator * Register AuthRequestRepo * Remove ExpirationDate from the AuthRequest table * [SG-407] Create job to delete expired requests (#2187) * chore: init * remove exp date * fix: log name * [SG-167] Added fingerprint phrase to response model. (#2233) * Remove FailedLoginAttempt logic * Block unknown devices * Add EF Support for passwordless * Got SignalR working for responses * Added delete job method to EF repo * Implement a GetMany API endpoint for AuthRequests * Ran dotnet format * Fix a merge issues * Redated migration scripts * tried sorting sqlproj * Remove FailedLoginAttempts from SQL * Groom Postgres script * Remove extra commas from migration script * Correct isSpent() * [SG-167] Adde identity validation for passwordless requests. Registered IAuthRepository. * [SG-167] Added origin of the request to response model * Use display name for device identifier in response * Add datetime conversions back to postgres migration script * [SG-655] Add anonymous endpoint for checking if a device & user combo match * [review] Consolidate error conditions Co-authored-by: Brandon Maharaj <107377945+BrandonM-Bitwarden@users.noreply.github.com> Co-authored-by: André Filipe da Silva Bispo <andrefsbispo@hotmail.com> Co-authored-by: André Bispo <abispo@bitwarden.com>
2022-09-26 13:21:13 -04:00
[AllowAnonymous]
[HttpGet("knowndevice/{email}/{identifier}")]
public async Task<bool> GetByIdentifier(string email, string identifier)
{
if (string.IsNullOrWhiteSpace(email) || string.IsNullOrWhiteSpace(identifier))
{
throw new BadRequestException("Please provide an email and device identifier");
}
var user = await _userRepository.GetByEmailAsync(email);
if (user == null)
{
return false;
}
var device = await _deviceRepository.GetByIdentifierAsync(identifier, user.Id);
return device != null;
}
2016-06-18 16:03:33 -04:00
}