Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
2 changes: 1 addition & 1 deletion API.IntegrationTests/API.IntegrationTests.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
<!-- Git stuff -->
<Target Name="SetHash" AfterTargets="InitializeSourceControlInformation">
<ItemGroup>
<AssemblyAttribute Include="OpenShock.Common.Utils.GitHashAttribute">
<AssemblyAttribute Include="OpenShock.Internal.Common.Utils.GitHashAttribute">
<_Parameter1>$(SourceRevisionId)</_Parameter1>
</AssemblyAttribute>
</ItemGroup>
Expand Down
4 changes: 3 additions & 1 deletion API.IntegrationTests/Docker/InMemoryDatabase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
using Testcontainers.PostgreSql;
using TUnit.Core.Interfaces;

using OpenShock.Internal.Common.Utils;

namespace OpenShock.API.IntegrationTests.Docker;

public sealed class InMemoryDatabase : IAsyncInitializer, IAsyncDisposable
Expand All @@ -19,7 +21,7 @@ public PostgreSqlContainer Container
.WithName($"tunit-postgresql-{Guid.CreateVersion7()}")
.WithDatabase("openshock")
.WithUsername("openshock")
.WithPassword(CryptoUtils.RandomAlphaNumericString(32))
.WithPassword(CryptoUtils.RandomString(32))
.Build();

return _container;
Expand Down
6 changes: 4 additions & 2 deletions API.IntegrationTests/Helpers/TestHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@
using OpenShock.Common.Services.Session;
using OpenShock.Common.Utils;

using OpenShock.Internal.Common.Utils;

namespace OpenShock.API.IntegrationTests.Helpers;

public static class TestHelper
Expand Down Expand Up @@ -127,7 +129,7 @@ public static async Task<Guid> CreateUserInDb(
var db = scope.ServiceProvider.GetRequiredService<OpenShockContext>();

var deviceId = Guid.CreateVersion7();
var token = CryptoUtils.RandomAlphaNumericString(256);
var token = CryptoUtils.RandomString(256);
db.Devices.Add(new Device
{
Id = deviceId,
Expand All @@ -152,7 +154,7 @@ public static async Task<Guid> CreateUserInDb(
await using var scope = factory.Services.CreateAsyncScope();
var db = scope.ServiceProvider.GetRequiredService<OpenShockContext>();

var rawToken = CryptoUtils.RandomAlphaNumericString(AuthConstants.ApiTokenLength);
var rawToken = CryptoUtils.RandomString(AuthConstants.ApiTokenLength);
var tokenId = Guid.CreateVersion7();
db.ApiTokens.Add(new ApiToken
{
Expand Down
56 changes: 56 additions & 0 deletions API.IntegrationTests/Tests/AdminUsersViewTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.DependencyInjection;
using OpenShock.API.IntegrationTests.Helpers;
using OpenShock.Common.OpenShockDb;

namespace OpenShock.API.IntegrationTests.Tests;

/// <summary>
/// Covers the <c>admin_users_view.password_hash_type</c> mapping. The column is plain text derived
/// from the <c>bcrypt:</c>/<c>pbkdf2:</c> prefix on <c>users.password_hash</c> (not the legacy
/// <c>password_encryption_type</c> Postgres enum), so EF converts it to
/// <see cref="PasswordHashingAlgorithm"/> by matching enum member names case-insensitively. That
/// coupling between the hash prefix and the enum member name is invisible at the call site, hence
/// these tests.
/// </summary>
public sealed class AdminUsersViewTests
{
[ClassDataSource<WebApplicationFactory>(Shared = SharedType.PerTestSession)]
public required WebApplicationFactory WebApplicationFactory { get; init; }

[Test]
public async Task PasswordHashType_ForPasswordUser_MapsToBCrypt()
{
var userId = await TestHelper.CreateUserInDb(WebApplicationFactory, "adminviewbcrypt", "adminviewbcrypt@test.org", "SecurePassword123#");

await using var scope = WebApplicationFactory.Services.CreateAsyncScope();
var db = scope.ServiceProvider.GetRequiredService<OpenShockContext>();

var hash = await db.Users.Where(u => u.Id == userId).Select(u => u.PasswordHash).FirstAsync();
await Assert.That(hash).StartsWith("bcrypt:");

var view = await db.AdminUsersViews.AsNoTracking().FirstAsync(v => v.Id == userId);
await Assert.That(view.PasswordHashType).IsEqualTo(PasswordHashingAlgorithm.BCrypt);
}

[Test]
public async Task PasswordHashType_ForOAuthOnlyUser_IsNull()
{
await using var scope = WebApplicationFactory.Services.CreateAsyncScope();
var db = scope.ServiceProvider.GetRequiredService<OpenShockContext>();

var userId = Guid.CreateVersion7();
db.Users.Add(new User
{
Id = userId,
Name = "adminviewoauth",
Email = "adminviewoauth@test.org",
PasswordHash = null,
ActivatedAt = DateTime.UtcNow
});
await db.SaveChangesAsync();

var view = await db.AdminUsersViews.AsNoTracking().FirstAsync(v => v.Id == userId);
await Assert.That(view.PasswordHashType).IsNull();
}
}
4 changes: 3 additions & 1 deletion API.IntegrationTests/Tests/LcgAssignmentTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@
using OpenShock.Common.Utils;
using Redis.OM.Contracts;

using OpenShock.Internal.Common.Utils;

namespace OpenShock.API.IntegrationTests.Tests;

public sealed class LcgAssignmentTests
Expand All @@ -32,7 +34,7 @@ public async Task Setup()
// Set up variables
_userId = Guid.CreateVersion7();
_hubId = Guid.CreateVersion7();
_hubToken = CryptoUtils.RandomAlphaNumericString(256);
_hubToken = CryptoUtils.RandomString(256);

// Create mock data
db.Users.Add(new User
Expand Down
2 changes: 1 addition & 1 deletion API/API.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@
<!-- Git stuff -->
<Target Name="SetHash" AfterTargets="InitializeSourceControlInformation">
<ItemGroup>
<AssemblyAttribute Include="OpenShock.Common.Utils.GitHashAttribute">
<AssemblyAttribute Include="OpenShock.Internal.Common.Utils.GitHashAttribute">
<_Parameter1>$(SourceRevisionId)</_Parameter1>
</AssemblyAttribute>
</ItemGroup>
Expand Down
2 changes: 2 additions & 0 deletions API/Controller/Account/Activate.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@
using OpenShock.Common.Errors;
using OpenShock.Common.Problems;

using OpenShock.Internal.Common.Problems;

namespace OpenShock.API.Controller.Account;

public sealed partial class AccountController
Expand Down
4 changes: 4 additions & 0 deletions API/Controller/Account/Authenticated/ChangeEmail.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,10 @@
using OpenShock.Common.Problems;
using OpenShock.Common.Utils;

using OpenShock.Internal.Common.Utils;

using OpenShock.Internal.Common.Problems;

namespace OpenShock.API.Controller.Account.Authenticated;

public sealed partial class AuthenticatedAccountController
Expand Down
4 changes: 4 additions & 0 deletions API/Controller/Account/Authenticated/ChangePassword.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,10 @@
using OpenShock.Common.Problems;
using OpenShock.Common.Utils;

using OpenShock.Internal.Common.Utils;

using OpenShock.Internal.Common.Problems;

namespace OpenShock.API.Controller.Account.Authenticated;

public sealed partial class AuthenticatedAccountController
Expand Down
2 changes: 2 additions & 0 deletions API/Controller/Account/Authenticated/ChangeUsername.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
using OpenShock.Common.OpenShockDb;
using OpenShock.Common.Problems;

using OpenShock.Internal.Common.Problems;

namespace OpenShock.API.Controller.Account.Authenticated;

public sealed partial class AuthenticatedAccountController
Expand Down
2 changes: 2 additions & 0 deletions API/Controller/Account/Authenticated/Deactivate.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
using OpenShock.Common.Errors;
using OpenShock.Common.Problems;

using OpenShock.Internal.Common.Problems;

namespace OpenShock.API.Controller.Account.Authenticated;

public sealed partial class AuthenticatedAccountController
Expand Down
2 changes: 2 additions & 0 deletions API/Controller/Account/Login.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
using Microsoft.AspNetCore.Mvc;
using OpenShock.Common.Errors;

using OpenShock.Internal.Common.Problems;

namespace OpenShock.API.Controller.Account;

public sealed partial class AccountController
Expand Down
2 changes: 2 additions & 0 deletions API/Controller/Account/LoginV2.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@
using OpenShock.API.Models.Response;
using OpenShock.API.Services.Turnstile;

using OpenShock.Internal.Common.Problems;

namespace OpenShock.API.Controller.Account;

public sealed partial class AccountController
Expand Down
2 changes: 2 additions & 0 deletions API/Controller/Account/PasswordResetCheckValid.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@
using OpenShock.Common.Problems;
using OpenShock.Common.Models;

using OpenShock.Internal.Common.Problems;

namespace OpenShock.API.Controller.Account;

public sealed partial class AccountController
Expand Down
2 changes: 2 additions & 0 deletions API/Controller/Account/PasswordResetComplete.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@
using OpenShock.Common.Problems;
using OpenShock.Common.Models;

using OpenShock.Internal.Common.Problems;

namespace OpenShock.API.Controller.Account;

public sealed partial class AccountController
Expand Down
2 changes: 2 additions & 0 deletions API/Controller/Account/PasswordResetInitiateV2.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@
using OpenShock.Common.Errors;
using OpenShock.Common.Problems;

using OpenShock.Internal.Common.Problems;

namespace OpenShock.API.Controller.Account;

public sealed partial class AccountController
Expand Down
2 changes: 2 additions & 0 deletions API/Controller/Account/Signup.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
using Microsoft.AspNetCore.Mvc;
using OpenShock.Common.Errors;

using OpenShock.Internal.Common.Problems;

namespace OpenShock.API.Controller.Account;

public sealed partial class AccountController
Expand Down
2 changes: 2 additions & 0 deletions API/Controller/Account/SignupV2.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@
using OpenShock.Common.Options;
using OpenShock.Common.Problems;

using OpenShock.Internal.Common.Problems;

namespace OpenShock.API.Controller.Account;

public sealed partial class AccountController
Expand Down
2 changes: 2 additions & 0 deletions API/Controller/Account/VerifyEmail.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
using OpenShock.Common.Errors;
using OpenShock.Common.Problems;

using OpenShock.Internal.Common.Problems;

namespace OpenShock.API.Controller.Account;

public sealed partial class AccountController
Expand Down
2 changes: 1 addition & 1 deletion API/Controller/Account/_Turnstile.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@
using Microsoft.AspNetCore.Mvc;
using OpenShock.API.Errors;
using OpenShock.API.Services.Turnstile;
using OpenShock.Common.Problems;
using OpenShock.Common.Utils;
using OpenShock.Internal.Common.Problems;

namespace OpenShock.API.Controller.Account;

Expand Down
2 changes: 2 additions & 0 deletions API/Controller/Admin/Configuration.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@
using OpenShock.Common.Services.Configuration;
using System.Net.Mime;

using OpenShock.Internal.Common.Problems;

namespace OpenShock.API.Controller.Admin;

public sealed partial class AdminController
Expand Down
2 changes: 1 addition & 1 deletion API/Controller/Admin/DeactivateUser.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ public sealed partial class AdminController
public async Task<IActionResult> DeactivateUser(
[FromRoute] Guid userId,
[FromQuery(Name = "deleteLater")] bool deleteLater,
[FromQuery][MaxLength(HardLimits.AuditReasonMaxLength)] string? reason,
[FromQuery][MaxLength(ApiHardLimits.AuditReasonMaxLength)] string? reason,
[FromServices] IAccountService accountService)
{
PedanticallyEnsureAdmin();
Expand Down
2 changes: 1 addition & 1 deletion API/Controller/Admin/DeleteUser.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ public sealed partial class AdminController
[ProducesResponseType(StatusCodes.Status200OK)]
public async Task<IActionResult> DeleteUser(
[FromRoute] Guid userId,
[FromQuery][MaxLength(HardLimits.AuditReasonMaxLength)] string? reason,
[FromQuery][MaxLength(ApiHardLimits.AuditReasonMaxLength)] string? reason,
[FromServices] IAccountService accountService)
{
PedanticallyEnsureAdmin();
Expand Down
3 changes: 2 additions & 1 deletion API/Controller/Admin/EmailOutboxList.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@
using OpenShock.Common.Extensions;
using OpenShock.Common.Models;
using OpenShock.Common.OpenShockDb;
using OpenShock.Common.Query;
using OpenShock.Internal.DynamicLinq.Extensions;
using OpenShock.Internal.DynamicLinq.Query;
using System.ComponentModel.DataAnnotations;
using System.Net.Mime;

Expand Down
6 changes: 4 additions & 2 deletions API/Controller/Admin/GetUsers.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,13 @@
using OpenShock.Common.Extensions;
using OpenShock.Common.Models;
using OpenShock.Common.OpenShockDb;
using OpenShock.Common.Query;
using OpenShock.Internal.DynamicLinq.Query;
using System.ComponentModel.DataAnnotations;
using System.Net.Mime;
using Z.EntityFramework.Plus;

using OpenShock.Internal.DynamicLinq.Extensions;

namespace OpenShock.API.Controller.Admin;

public sealed partial class AdminController
Expand Down Expand Up @@ -40,7 +42,7 @@ public async Task<IActionResult> GetUsers(

if (!string.IsNullOrEmpty(orderbyQuery))
{
query = query.ApplyOrderBy(orderbyQuery);
query = OpenShock.Internal.DynamicLinq.Extensions.IQueryableExtensions.ApplyOrderBy(query, orderbyQuery);
}
else
{
Expand Down
2 changes: 1 addition & 1 deletion API/Controller/Admin/ReactivateUser.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ public sealed partial class AdminController
[ProducesResponseType(StatusCodes.Status200OK)]
public async Task<IActionResult> ReactivateUser(
[FromRoute] Guid userId,
[FromQuery][MaxLength(HardLimits.AuditReasonMaxLength)] string? reason,
[FromQuery][MaxLength(ApiHardLimits.AuditReasonMaxLength)] string? reason,
[FromServices] IAccountService accountService)
{
PedanticallyEnsureAdmin();
Expand Down
2 changes: 2 additions & 0 deletions API/Controller/Device/AssignLCG.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@
using OpenShock.Common.Utils;
using OpenShock.Common.Models;

using OpenShock.Internal.Common.Problems;

namespace OpenShock.API.Controller.Device;

public sealed partial class DeviceController
Expand Down
2 changes: 2 additions & 0 deletions API/Controller/Device/AssignLCGV2.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@
using OpenShock.Common.Problems;
using OpenShock.Common.Utils;

using OpenShock.Internal.Common.Problems;

namespace OpenShock.API.Controller.Device;

public sealed partial class DeviceController
Expand Down
19 changes: 15 additions & 4 deletions API/Controller/Device/Pair.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@
using OpenShock.Common.Problems;
using OpenShock.Common.Models;

using OpenShock.Internal.Common.Problems;

namespace OpenShock.API.Controller.Device;

public sealed partial class DeviceController
Expand Down Expand Up @@ -52,9 +54,18 @@ private async Task<IActionResult> PairInternal(string pairCode)
if (pair is null) return Problem(PairError.PairCodeNotFound);
await devicePairs.DeleteAsync(pair);

var deviceToken = await _db.Devices.Where(x => x.Id == pair.Id).Select(x => x.Token).FirstOrDefaultAsync();
if (deviceToken is null) throw new Exception("Device not found for pair code");
var device = await _db.Devices.Where(x => x.Id == pair.Id).Select(x => new { x.Token, x.OwnerId }).FirstOrDefaultAsync();
if (device is null) throw new Exception("Device not found for pair code");

try
{
await _deviceUpdateService.UpdateDevice(device.OwnerId, pair.Id, DeviceUpdateType.Paired);
}
catch (Exception ex)
{
_logger.LogWarning(ex, "Failed to emit paired update for device {DeviceId}", pair.Id);
}

return LegacyDataOk(deviceToken);
return LegacyDataOk(device.Token);
}
}
}
Loading
Loading