Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. Weโ€™ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Auth/pm 2996/add auth request data to devices response model #5152

Merged
Show file tree
Hide file tree
Changes from 24 commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
bca5eff
Have the dapper query working. Working on the ef query.
Patrick-Pimentel-Bitwarden Nov 30, 2024
e916faf
Stored procedure and entity framework query written. Still have cleanโ€ฆ
Patrick-Pimentel-Bitwarden Dec 4, 2024
406f941
Query for sqlite is working. Testing the other backends.
Patrick-Pimentel-Bitwarden Dec 6, 2024
23c049a
Optimized implementations of sqlite and other db interactions.
Patrick-Pimentel-Bitwarden Dec 9, 2024
1cf6d08
Merge remote-tracking branch 'origin/main' into auth/pm-2996/add-authโ€ฆ
Patrick-Pimentel-Bitwarden Dec 9, 2024
a922d8b
First device repo test working. Controller test working as well.
Patrick-Pimentel-Bitwarden Dec 12, 2024
585a36a
Repo tests working.
Patrick-Pimentel-Bitwarden Dec 13, 2024
ef2051f
Repository test is working properly.
Patrick-Pimentel-Bitwarden Dec 16, 2024
366dabf
Validating the endpoint is retreiving the correct auth request.
Patrick-Pimentel-Bitwarden Dec 16, 2024
52560a3
Removed unnessesary files
Patrick-Pimentel-Bitwarden Dec 16, 2024
cef7a02
Tiny fixes.
Patrick-Pimentel-Bitwarden Dec 16, 2024
c1f12de
Merge remote-tracking branch 'origin' into auth/pm-2996/add-auth-requโ€ฆ
Patrick-Pimentel-Bitwarden Dec 16, 2024
04b335e
Merge remote-tracking branch 'origin' into auth/pm-2996/add-auth-requโ€ฆ
Patrick-Pimentel-Bitwarden Dec 16, 2024
7687a16
All tests working
Patrick-Pimentel-Bitwarden Dec 16, 2024
647fad8
Tightened constraints for testing.
Patrick-Pimentel-Bitwarden Dec 16, 2024
77a38b7
Rename controller test file.
Patrick-Pimentel-Bitwarden Dec 16, 2024
97fa55a
feat(device): Devices with Auth Request
Patrick-Pimentel-Bitwarden Dec 19, 2024
092b83c
Merge remote-tracking branch 'origin' into auth/pm-2996/add-auth-requโ€ฆ
Patrick-Pimentel-Bitwarden Dec 19, 2024
c5d8b4c
feat(device): Devices with Auth Request
Patrick-Pimentel-Bitwarden Dec 19, 2024
f183427
feat(device): Devices with Auth Request
Patrick-Pimentel-Bitwarden Dec 26, 2024
a5eaa6a
fix(device): [PM-2996] Devices with Auth Request
Patrick-Pimentel-Bitwarden Dec 27, 2024
e19b761
Merge remote-tracking branch 'origin' into auth/pm-2996/add-auth-requโ€ฆ
Patrick-Pimentel-Bitwarden Dec 27, 2024
040d0c6
fix(device): [PM-2996] Devices with Auth Request
Patrick-Pimentel-Bitwarden Dec 27, 2024
aaa8380
fix(device): [PM-2996] Devices with Auth Request - Fixed the stored pโ€ฆ
Patrick-Pimentel-Bitwarden Dec 28, 2024
67b35da
fix(device): [PM-2996] Devices with Auth Request - Updated the storedโ€ฆ
Patrick-Pimentel-Bitwarden Dec 30, 2024
2ad97af
Merge remote-tracking branch 'origin' into auth/pm-2996/add-auth-requโ€ฆ
Patrick-Pimentel-Bitwarden Jan 2, 2025
474bdee
fix(device): [PM-2996] Devices with Auth Request - Fixed typo.
Patrick-Pimentel-Bitwarden Jan 2, 2025
7035779
fix(device): [PM-2996] Devices with Auth Request - Updated a comment โ€ฆ
Patrick-Pimentel-Bitwarden Jan 2, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 10 additions & 5 deletions src/Api/Controllers/DevicesController.cs
Patrick-Pimentel-Bitwarden marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@
using Bit.Core.Auth.Models.Api.Request;
using Bit.Core.Auth.Models.Api.Response;
using Bit.Core.Context;
using Bit.Core.Entities;
using Bit.Core.Exceptions;
using Bit.Core.Repositories;
using Bit.Core.Services;
Expand Down Expand Up @@ -70,11 +69,17 @@ public async Task<DeviceResponseModel> GetByIdentifier(string identifier)
}

[HttpGet("")]
public async Task<ListResponseModel<DeviceResponseModel>> Get()
public async Task<ListResponseModel<DeviceAuthRequestResponseModel>> Get()
{
ICollection<Device> devices = await _deviceRepository.GetManyByUserIdAsync(_userService.GetProperUserId(User).Value);
var responses = devices.Select(d => new DeviceResponseModel(d));
return new ListResponseModel<DeviceResponseModel>(responses);
var devicesWithPendingAuthData = await _deviceRepository.GetManyByUserIdWithDeviceAuth(_userService.GetProperUserId(User).Value);

// Convert from DeviceAuthDetails to DeviceAuthRequestResponseModel
var deviceAuthRequestResponseList = devicesWithPendingAuthData
.Select(DeviceAuthRequestResponseModel.From)
.ToList();

var response = new ListResponseModel<DeviceAuthRequestResponseModel>(deviceAuthRequestResponseList);
return response;
}

[HttpPost("")]
Expand Down
7 changes: 7 additions & 0 deletions src/Core/Auth/Enums/AuthRequestType.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,12 @@
๏ปฟnamespace Bit.Core.Auth.Enums;

/**
* The type of auth request.
*
* Note:
* Used by the Device_ReadActiveWithPendingAuthRequestsByUserId.sql stored procedure.
* If the enum changes be aware of this reference.
*/
public enum AuthRequestType : byte
{
AuthenticateAndUnlock = 0,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
๏ปฟusing Bit.Core.Auth.Models.Data;
using Bit.Core.Auth.Utilities;
using Bit.Core.Enums;
using Bit.Core.Models.Api;

namespace Bit.Core.Auth.Models.Api.Response;

public class DeviceAuthRequestResponseModel : ResponseModel
{
public DeviceAuthRequestResponseModel()
: base("device") { }

public static DeviceAuthRequestResponseModel From(DeviceAuthDetails deviceAuthDetails)
{
var converted = new DeviceAuthRequestResponseModel
{
Id = deviceAuthDetails.Id,
Name = deviceAuthDetails.Name,
Type = deviceAuthDetails.Type,
Identifier = deviceAuthDetails.Identifier,
CreationDate = deviceAuthDetails.CreationDate,
IsTrusted = deviceAuthDetails.IsTrusted()
};

if (deviceAuthDetails.AuthRequestId != null && deviceAuthDetails.AuthRequestCreatedAt != null)
{
converted.DevicePendingAuthRequest = new PendingAuthRequest
{
Id = (Guid)deviceAuthDetails.AuthRequestId,
CreationDate = (DateTime)deviceAuthDetails.AuthRequestCreatedAt
};
}

return converted;
}

public Guid Id { get; set; }
public string Name { get; set; }
public DeviceType Type { get; set; }
public string Identifier { get; set; }
public DateTime CreationDate { get; set; }
public bool IsTrusted { get; set; }

public PendingAuthRequest DevicePendingAuthRequest { get; set; }

public class PendingAuthRequest
{
public Guid Id { get; set; }
public DateTime CreationDate { get; set; }
}
}
82 changes: 82 additions & 0 deletions src/Core/Auth/Models/Data/DeviceAuthDetails.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
๏ปฟusing Bit.Core.Auth.Utilities;
using Bit.Core.Entities;
using Bit.Core.Enums;

namespace Bit.Core.Auth.Models.Data;

public class DeviceAuthDetails : Device
{
public bool IsTrusted { get; set; }
public Guid? AuthRequestId { get; set; }
public DateTime? AuthRequestCreatedAt { get; set; }

/**
* Constructor for EF response.
*/
public DeviceAuthDetails(
Device device,
Guid? authRequestId,
DateTime? authRequestCreationDate)
{
if (device == null)
{
throw new ArgumentNullException(nameof(device));

Check warning on line 23 in src/Core/Auth/Models/Data/DeviceAuthDetails.cs

View check run for this annotation

Codecov / codecov/patch

src/Core/Auth/Models/Data/DeviceAuthDetails.cs#L22-L23

Added lines #L22 - L23 were not covered by tests
}

Id = device.Id;
Name = device.Name;
Type = device.Type;
Identifier = device.Identifier;
CreationDate = device.CreationDate;
IsTrusted = device.IsTrusted();
AuthRequestId = authRequestId;
AuthRequestCreatedAt = authRequestCreationDate;
}


/**
* Constructor for dapper response.
* Note: if the authRequestId or authRequestCreationDate is null it comes back as
* an empty guid and a min value for datetime. That could change if the stored
* procedure runs on a different kind of db.
*/
public DeviceAuthDetails(
Guid id,
Guid userId,
string name,
short type,
string identifier,
string pushToken,
DateTime creationDate,
DateTime revisionDate,
string encryptedUserKey,
string encryptedPublicKey,
string encryptedPrivateKey,
bool active,
Guid authRequestId,
DateTime authRequestCreationDate)
{
Id = id;
Name = name;
Type = (DeviceType)type;
Identifier = identifier;
CreationDate = creationDate;
IsTrusted = new Device
{
Id = id,
UserId = userId,
Name = name,
Type = (DeviceType)type,
Identifier = identifier,
PushToken = pushToken,
RevisionDate = revisionDate,
EncryptedUserKey = encryptedUserKey,
EncryptedPublicKey = encryptedPublicKey,
EncryptedPrivateKey = encryptedPrivateKey,
Active = active
}.IsTrusted();

Check warning on line 77 in src/Core/Auth/Models/Data/DeviceAuthDetails.cs

View check run for this annotation

Codecov / codecov/patch

src/Core/Auth/Models/Data/DeviceAuthDetails.cs#L43-L77

Added lines #L43 - L77 were not covered by tests
AuthRequestId = authRequestId != Guid.Empty ? authRequestId : null;
AuthRequestCreatedAt =
authRequestCreationDate != DateTime.MinValue ? authRequestCreationDate : null;
}

Check warning on line 81 in src/Core/Auth/Models/Data/DeviceAuthDetails.cs

View check run for this annotation

Codecov / codecov/patch

src/Core/Auth/Models/Data/DeviceAuthDetails.cs#L80-L81

Added lines #L80 - L81 were not covered by tests
}
3 changes: 1 addition & 2 deletions src/Core/Auth/Models/Data/EmergencyAccessDetails.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
๏ปฟ
using Bit.Core.Auth.Entities;
๏ปฟusing Bit.Core.Auth.Entities;

namespace Bit.Core.Auth.Models.Data;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@ namespace Bit.Core.Auth.UserFeatures.Registration.Implementations;

public class RegisterUserCommand : IRegisterUserCommand
{

private readonly IGlobalSettings _globalSettings;
private readonly IOrganizationUserRepository _organizationUserRepository;
private readonly IPolicyRepository _policyRepository;
Expand Down
7 changes: 6 additions & 1 deletion src/Core/Repositories/IDeviceRepository.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
๏ปฟusing Bit.Core.Entities;
๏ปฟusing Bit.Core.Auth.Models.Data;
using Bit.Core.Entities;

#nullable enable

Expand All @@ -10,5 +11,9 @@ public interface IDeviceRepository : IRepository<Device, Guid>
Task<Device?> GetByIdentifierAsync(string identifier);
Task<Device?> GetByIdentifierAsync(string identifier, Guid userId);
Task<ICollection<Device>> GetManyByUserIdAsync(Guid userId);
// DeviceAuthDetails is passed back to decouple the response model from the
// repository in case more fields are ever added to the details response for
// other requests.
Task<ICollection<DeviceAuthDetails>> GetManyByUserIdWithDeviceAuth(Guid userId);
Task ClearPushTokenAsync(Guid id);
}
2 changes: 2 additions & 0 deletions src/Core/Settings/IGlobalSettings.cs
Original file line number Diff line number Diff line change
Expand Up @@ -24,5 +24,7 @@ public interface IGlobalSettings
IPasswordlessAuthSettings PasswordlessAuth { get; set; }
IDomainVerificationSettings DomainVerification { get; set; }
ILaunchDarklySettings LaunchDarkly { get; set; }
string DatabaseProvider { get; set; }
GlobalSettings.SqlSettings SqlServer { get; set; }
string DevelopmentDirectory { get; set; }
}
25 changes: 24 additions & 1 deletion src/Infrastructure.Dapper/Repositories/DeviceRepository.cs
ike-kottlowski marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
๏ปฟusing System.Data;
using Bit.Core.Auth.Models.Data;
using Bit.Core.Entities;
using Bit.Core.Repositories;
using Bit.Core.Settings;
Expand All @@ -11,11 +12,15 @@

public class DeviceRepository : Repository<Device, Guid>, IDeviceRepository
{
private readonly IGlobalSettings _globalSettings;

public DeviceRepository(GlobalSettings globalSettings)
: this(globalSettings.SqlServer.ConnectionString, globalSettings.SqlServer.ReadOnlyConnectionString)
{ }
{
_globalSettings = globalSettings;
}

Check warning on line 21 in src/Infrastructure.Dapper/Repositories/DeviceRepository.cs

View check run for this annotation

Codecov / codecov/patch

src/Infrastructure.Dapper/Repositories/DeviceRepository.cs#L19-L21

Added lines #L19 - L21 were not covered by tests

public DeviceRepository(string connectionString, string readOnlyConnectionString)

Check warning on line 23 in src/Infrastructure.Dapper/Repositories/DeviceRepository.cs

View workflow job for this annotation

GitHub Actions / Build artifacts (Events, ./src)

Non-nullable field '_globalSettings' must contain a non-null value when exiting constructor. Consider adding the 'required' modifier or declaring the field as nullable.

Check warning on line 23 in src/Infrastructure.Dapper/Repositories/DeviceRepository.cs

View workflow job for this annotation

GitHub Actions / Build artifacts (Billing, ./src)

Non-nullable field '_globalSettings' must contain a non-null value when exiting constructor. Consider adding the 'required' modifier or declaring the field as nullable.

Check warning on line 23 in src/Infrastructure.Dapper/Repositories/DeviceRepository.cs

View workflow job for this annotation

GitHub Actions / Build artifacts (Icons, ./src)

Non-nullable field '_globalSettings' must contain a non-null value when exiting constructor. Consider adding the 'required' modifier or declaring the field as nullable.

Check warning on line 23 in src/Infrastructure.Dapper/Repositories/DeviceRepository.cs

View workflow job for this annotation

GitHub Actions / Build artifacts (EventsProcessor, ./src)

Non-nullable field '_globalSettings' must contain a non-null value when exiting constructor. Consider adding the 'required' modifier or declaring the field as nullable.

Check warning on line 23 in src/Infrastructure.Dapper/Repositories/DeviceRepository.cs

View workflow job for this annotation

GitHub Actions / Build artifacts (Api, ./src)

Non-nullable field '_globalSettings' must contain a non-null value when exiting constructor. Consider adding the 'required' modifier or declaring the field as nullable.

Check warning on line 23 in src/Infrastructure.Dapper/Repositories/DeviceRepository.cs

View workflow job for this annotation

GitHub Actions / Build artifacts (Sso, ./bitwarden_license/src, true)

Non-nullable field '_globalSettings' must contain a non-null value when exiting constructor. Consider adding the 'required' modifier or declaring the field as nullable.

Check warning on line 23 in src/Infrastructure.Dapper/Repositories/DeviceRepository.cs

View workflow job for this annotation

GitHub Actions / Build artifacts (Identity, ./src)

Non-nullable field '_globalSettings' must contain a non-null value when exiting constructor. Consider adding the 'required' modifier or declaring the field as nullable.

Check warning on line 23 in src/Infrastructure.Dapper/Repositories/DeviceRepository.cs

View workflow job for this annotation

GitHub Actions / Build artifacts (Scim, ./bitwarden_license/src, true)

Non-nullable field '_globalSettings' must contain a non-null value when exiting constructor. Consider adding the 'required' modifier or declaring the field as nullable.

Check warning on line 23 in src/Infrastructure.Dapper/Repositories/DeviceRepository.cs

View workflow job for this annotation

GitHub Actions / Build artifacts (Admin, ./src, true)

Non-nullable field '_globalSettings' must contain a non-null value when exiting constructor. Consider adding the 'required' modifier or declaring the field as nullable.

Check warning on line 23 in src/Infrastructure.Dapper/Repositories/DeviceRepository.cs

View workflow job for this annotation

GitHub Actions / Build artifacts (Notifications, ./src)

Non-nullable field '_globalSettings' must contain a non-null value when exiting constructor. Consider adding the 'required' modifier or declaring the field as nullable.

Check warning on line 23 in src/Infrastructure.Dapper/Repositories/DeviceRepository.cs

View workflow job for this annotation

GitHub Actions / Quality scan

Non-nullable field '_globalSettings' must contain a non-null value when exiting constructor. Consider adding the 'required' modifier or declaring the field as nullable.

Check warning on line 23 in src/Infrastructure.Dapper/Repositories/DeviceRepository.cs

View workflow job for this annotation

GitHub Actions / Run tests

Non-nullable field '_globalSettings' must contain a non-null value when exiting constructor. Consider adding the 'required' modifier or declaring the field as nullable.

Check warning on line 23 in src/Infrastructure.Dapper/Repositories/DeviceRepository.cs

View workflow job for this annotation

GitHub Actions / Run tests

Non-nullable field '_globalSettings' must contain a non-null value when exiting constructor. Consider adding the 'required' modifier or declaring the field as nullable.

Check warning on line 23 in src/Infrastructure.Dapper/Repositories/DeviceRepository.cs

View workflow job for this annotation

GitHub Actions / Upload

Non-nullable field '_globalSettings' must contain a non-null value when exiting constructor. Consider adding the 'required' modifier or declaring the field as nullable.
: base(connectionString, readOnlyConnectionString)
{ }

Expand Down Expand Up @@ -76,6 +81,24 @@
}
}

public async Task<ICollection<DeviceAuthDetails>> GetManyByUserIdWithDeviceAuth(Guid userId)
{
var expirationMinutes = _globalSettings.PasswordlessAuth.UserRequestExpiration.TotalMinutes;
using (var connection = new SqlConnection(ConnectionString))
{
var results = await connection.QueryAsync<DeviceAuthDetails>(
$"[{Schema}].[{Table}_ReadActiveWithPendingAuthRequestsByUserId]",
new
{
UserId = userId,
ExpirationMinutes = expirationMinutes
},
commandType: CommandType.StoredProcedure);

Check warning on line 96 in src/Infrastructure.Dapper/Repositories/DeviceRepository.cs

View check run for this annotation

Codecov / codecov/patch

src/Infrastructure.Dapper/Repositories/DeviceRepository.cs#L85-L96

Added lines #L85 - L96 were not covered by tests

return results.ToList();

Check warning on line 98 in src/Infrastructure.Dapper/Repositories/DeviceRepository.cs

View check run for this annotation

Codecov / codecov/patch

src/Infrastructure.Dapper/Repositories/DeviceRepository.cs#L98

Added line #L98 was not covered by tests
}
}

Check warning on line 100 in src/Infrastructure.Dapper/Repositories/DeviceRepository.cs

View check run for this annotation

Codecov / codecov/patch

src/Infrastructure.Dapper/Repositories/DeviceRepository.cs#L100

Added line #L100 was not covered by tests

public async Task ClearPushTokenAsync(Guid id)
{
using (var connection = new SqlConnection(ConnectionString))
Expand Down
4 changes: 2 additions & 2 deletions src/Infrastructure.Dapper/Repositories/Repository.cs
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@
var parameters = new DynamicParameters();
parameters.AddDynamicParams(obj);
parameters.Add("Id", obj.Id, direction: ParameterDirection.InputOutput);
var results = await connection.ExecuteAsync(
await connection.ExecuteAsync(

Check warning on line 54 in src/Infrastructure.Dapper/Repositories/Repository.cs

View check run for this annotation

Codecov / codecov/patch

src/Infrastructure.Dapper/Repositories/Repository.cs#L54

Added line #L54 was not covered by tests
$"[{Schema}].[{Table}_Create]",
parameters,
commandType: CommandType.StoredProcedure);
Expand All @@ -64,7 +64,7 @@
{
using (var connection = new SqlConnection(ConnectionString))
{
var results = await connection.ExecuteAsync(
await connection.ExecuteAsync(

Check warning on line 67 in src/Infrastructure.Dapper/Repositories/Repository.cs

View check run for this annotation

Codecov / codecov/patch

src/Infrastructure.Dapper/Repositories/Repository.cs#L67

Added line #L67 was not covered by tests
$"[{Schema}].[{Table}_Update]",
obj,
commandType: CommandType.StoredProcedure);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
๏ปฟusing Bit.Core.Auth.Enums;
using Bit.Core.Auth.Models.Data;
using Bit.Infrastructure.EntityFramework.Repositories;

namespace Bit.Infrastructure.EntityFramework.Auth.Repositories.Queries;

public class DeviceWithPendingAuthByUserIdQuery
{
public IQueryable<DeviceAuthDetails> GetQuery(
DatabaseContext dbContext,
Guid userId,
int expirationMinutes)
{
var devicesWithAuthQuery = (
from device in dbContext.Devices
where device.UserId == userId && device.Active
select new
{
device,
authRequest =
(
from authRequest in dbContext.AuthRequests
where authRequest.RequestDeviceIdentifier == device.Identifier
where authRequest.Type == AuthRequestType.AuthenticateAndUnlock || authRequest.Type == AuthRequestType.Unlock
where authRequest.Approved == null
where authRequest.UserId == userId
where authRequest.CreationDate.AddMinutes(expirationMinutes) > DateTime.UtcNow
orderby authRequest.CreationDate descending
select authRequest
).First()
}).Select(deviceWithAuthRequest => new DeviceAuthDetails(
deviceWithAuthRequest.device,
deviceWithAuthRequest.authRequest.Id,
deviceWithAuthRequest.authRequest.CreationDate));

Check warning on line 34 in src/Infrastructure.EntityFramework/Auth/Repositories/Queries/DeviceWithPendingAuthByUserIdQuery.cs

View check run for this annotation

Codecov / codecov/patch

src/Infrastructure.EntityFramework/Auth/Repositories/Queries/DeviceWithPendingAuthByUserIdQuery.cs#L13-L34

Added lines #L13 - L34 were not covered by tests

return devicesWithAuthQuery;
}

Check warning on line 37 in src/Infrastructure.EntityFramework/Auth/Repositories/Queries/DeviceWithPendingAuthByUserIdQuery.cs

View check run for this annotation

Codecov / codecov/patch

src/Infrastructure.EntityFramework/Auth/Repositories/Queries/DeviceWithPendingAuthByUserIdQuery.cs#L36-L37

Added lines #L36 - L37 were not covered by tests
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
๏ปฟusing AutoMapper;
using Bit.Core.Auth.Models.Data;
using Bit.Core.Repositories;
using Bit.Core.Settings;
using Bit.Infrastructure.EntityFramework.Auth.Repositories.Queries;
using Bit.Infrastructure.EntityFramework.Models;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.DependencyInjection;
Expand All @@ -10,9 +13,17 @@

public class DeviceRepository : Repository<Core.Entities.Device, Device, Guid>, IDeviceRepository
{
public DeviceRepository(IServiceScopeFactory serviceScopeFactory, IMapper mapper)
private readonly IGlobalSettings _globalSettings;

public DeviceRepository(
IServiceScopeFactory serviceScopeFactory,
IMapper mapper,
IGlobalSettings globalSettings
)
: base(serviceScopeFactory, mapper, (DatabaseContext context) => context.Devices)
{ }
{
_globalSettings = globalSettings;
}

public async Task ClearPushTokenAsync(Guid id)
{
Expand Down Expand Up @@ -69,4 +80,15 @@
return Mapper.Map<List<Core.Entities.Device>>(devices);
}
}

public async Task<ICollection<DeviceAuthDetails>> GetManyByUserIdWithDeviceAuth(Guid userId)
{
var expirationMinutes = (int)_globalSettings.PasswordlessAuth.UserRequestExpiration.TotalMinutes;
using (var scope = ServiceScopeFactory.CreateScope())
{
var dbContext = GetDatabaseContext(scope);
var query = new DeviceWithPendingAuthByUserIdQuery();
return await query.GetQuery(dbContext, userId, expirationMinutes).ToListAsync();

Check warning on line 91 in src/Infrastructure.EntityFramework/Repositories/DeviceRepository.cs

View check run for this annotation

Codecov / codecov/patch

src/Infrastructure.EntityFramework/Repositories/DeviceRepository.cs#L85-L91

Added lines #L85 - L91 were not covered by tests
}
}

Check warning on line 93 in src/Infrastructure.EntityFramework/Repositories/DeviceRepository.cs

View check run for this annotation

Codecov / codecov/patch

src/Infrastructure.EntityFramework/Repositories/DeviceRepository.cs#L93

Added line #L93 was not covered by tests
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
CREATE PROCEDURE [dbo].[Device_ReadActiveWithPendingAuthRequestsByUserId]
@UserId UNIQUEIDENTIFIER,
@ExpirationMinutes INT
AS
BEGIN
SELECT
D.*,
AR.Id as AuthRequestId,
AR.CreationDate as AuthRequestCreationDate
FROM [dbo].[DeviceView] D
LEFT OUTER JOIN (
SELECT TOP 1 -- Take only the top record sorted by auth request creation date
AR.Id,
AR.CreationDate,
AR.RequestDeviceIdentifier
FROM [dbo].[AuthRequestView] AR
WHERE AR.Type IN (0, 1) -- Include only AuthenticateAndUnlock and Unlock types, excluding Admin Approval (type 2)
AND DATEADD(mi, @ExpirationMinutes, AR.CreationDate) > GETUTCDATE() -- Ensure the request hasn't expired
AND AR.Approved IS NULL -- Include only requests that haven't been acknowledged or approved
ORDER BY AR.CreationDate DESC
) AR ON D.Identifier = AR.RequestDeviceIdentifier
WHERE
D.UserId = @UserId
AND D.Active = 1 -- Include only active devices
END
Loading
Loading