Skip to content

Commit

Permalink
Merge branch 'develop'
Browse files Browse the repository at this point in the history
  • Loading branch information
LucHeart committed Dec 6, 2024
2 parents 689f2de + e1ae550 commit b4a4e7c
Show file tree
Hide file tree
Showing 123 changed files with 4,821 additions and 1,249 deletions.
55 changes: 55 additions & 0 deletions .github/workflows/codeql.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
name: "CodeQL Advanced"

on:
push:
branches: [ "develop", "master" ]
pull_request:
branches: [ "develop", "master" ]
schedule:
- cron: '0 6 * * 1'

env:
DOTNET_VERSION: 9.x.x

jobs:
analyze:
name: Analyze (csharp)
runs-on: 'ubuntu-latest'
permissions:
# required for all workflows
security-events: write

# required to fetch internal or private CodeQL packs
packages: read

# only required for workflows in private repositories
actions: read
contents: read
steps:
- name: Checkout repository
uses: actions/checkout@v4

# Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL
uses: github/codeql-action/init@v3
with:
languages: csharp
build-mode: manual

- name: Setup .NET SDK ${{ env.DOTNET_VERSION }}
uses: actions/setup-dotnet@v4
with:
dotnet-version: ${{ env.DOTNET_VERSION }}

- name: Build .NET
shell: bash
run: |
dotnet restore
dotnet publish API/API.csproj -c Release
dotnet publish LiveControlGateway/LiveControlGateway.csproj -c Release
dotnet publish Cron/Cron.csproj -c Release
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v3
with:
category: "/language:csharp"
17 changes: 8 additions & 9 deletions API/API.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@

<ItemGroup>
<PackageReference Include="Asp.Versioning.Mvc.ApiExplorer" Version="8.1.0" />
<PackageReference Include="Fluid.Core" Version="2.12.0" />
<PackageReference Include="Fluid.Core" Version="2.14.0" />
<PackageReference Include="MailKit" Version="4.8.0" />
<PackageReference Include="Microsoft.AspNetCore.SignalR.StackExchangeRedis" Version="9.0.0" />
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="9.0.0" />
Expand All @@ -36,20 +36,19 @@
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="MiniValidation" Version="0.9.1" />
<PackageReference Include="Npgsql.EntityFrameworkCore.PostgreSQL" Version="9.0.0" />
<PackageReference Include="Npgsql.EntityFrameworkCore.PostgreSQL" Version="9.0.1" />
<PackageReference Include="OneOf" Version="3.0.271" />
<PackageReference Include="Redis.OM" Version="0.7.6" />
<PackageReference Include="Scalar.AspNetCore" Version="1.2.39" />
<PackageReference Include="Scalar.AspNetCore" Version="1.2.45" />
<PackageReference Include="Serilog" Version="4.1.0" />
<PackageReference Include="Serilog.AspNetCore" Version="8.0.3" />
<PackageReference Include="Serilog.Sinks.Console" Version="6.0.0" />
<PackageReference Include="Serilog.Sinks.Grafana.Loki" Version="8.3.0" />
<PackageReference Include="StackExchange.Redis" Version="2.8.16" />
<PackageReference Include="Swashbuckle.AspNetCore" Version="7.0.0" />
<PackageReference Include="Swashbuckle.AspNetCore.Swagger" Version="7.0.0" />
<PackageReference Include="Swashbuckle.AspNetCore.SwaggerGen" Version="7.0.0" />
<PackageReference Include="Swashbuckle.AspNetCore.SwaggerUI" Version="7.0.0" />
<PackageReference Include="StackExchange.Redis" Version="2.8.22" />
<PackageReference Include="Swashbuckle.AspNetCore" Version="7.1.0" />
<PackageReference Include="Swashbuckle.AspNetCore.Swagger" Version="7.1.0" />
<PackageReference Include="Swashbuckle.AspNetCore.SwaggerGen" Version="7.1.0" />
<PackageReference Include="Swashbuckle.AspNetCore.SwaggerUI" Version="7.1.0" />
</ItemGroup>

<Target Name="SetSourceRevisionId" BeforeTargets="InitializeSourceControlInformation">
Expand Down
4 changes: 2 additions & 2 deletions API/Controller/Account/Authenticated/ChangePassword.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,12 @@ public sealed partial class AuthenticatedAccountController
[ProducesResponseType(StatusCodes.Status200OK)]
public async Task<IActionResult> ChangePassword(ChangePasswordRequest data)
{
if (!PasswordHashingUtils.VerifyPassword(data.OldPassword, CurrentUser.DbUser.PasswordHash).Verified)
if (!PasswordHashingUtils.VerifyPassword(data.OldPassword, CurrentUser.PasswordHash).Verified)
{
return Problem(AccountError.PasswordChangeInvalidPassword);
}

var result = await _accountService.ChangePassword(CurrentUser.DbUser.Id, data.NewPassword);
var result = await _accountService.ChangePassword(CurrentUser.Id, data.NewPassword);

return result.Match(success => Ok(),
notFound => throw new Exception("Unexpected result, apparently our current user does not exist..."));
Expand Down
4 changes: 2 additions & 2 deletions API/Controller/Account/Authenticated/ChangeUsername.cs
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,8 @@ public sealed partial class AuthenticatedAccountController
[ProducesResponseType<OpenShockProblem>(StatusCodes.Status403Forbidden, MediaTypeNames.Application.ProblemJson)] // UsernameRecentlyChanged
public async Task<IActionResult> ChangeUsername(ChangeUsernameRequest data)
{
var result = await _accountService.ChangeUsername(CurrentUser.DbUser.Id, data.Username,
CurrentUser.DbUser.Rank.IsAllowed(RankType.Staff));
var result = await _accountService.ChangeUsername(CurrentUser.Id, data.Username,
CurrentUser.Rank.IsAllowed(RankType.Staff));

return result.Match<IActionResult>(
success => Ok(),
Expand Down
24 changes: 7 additions & 17 deletions API/Controller/Account/Authenticated/_ApiController.cs
Original file line number Diff line number Diff line change
@@ -1,40 +1,30 @@
using Asp.Versioning;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using OpenShock.API.Services.Account;
using OpenShock.Common.Authentication.Attributes;
using OpenShock.Common.Authentication;
using OpenShock.Common.Authentication.ControllerBase;
using OpenShock.Common.OpenShockDb;
using OpenShock.Common.Services.Session;
using Redis.OM.Contracts;

namespace OpenShock.API.Controller.Account.Authenticated;

/// <summary>
/// User account management
/// </summary>
[ApiController]
[UserSessionOnly]
[ApiVersion("1")]
[Route("/{version:apiVersion}/account")]
[Authorize(AuthenticationSchemes = OpenShockAuthSchemas.UserSessionCookie)]
public sealed partial class AuthenticatedAccountController : AuthenticatedSessionControllerBase
{
private readonly OpenShockContext _db;
private readonly IRedisConnectionProvider _redis;
private readonly ILogger<AuthenticatedAccountController> _logger;
private readonly IAccountService _accountService;
private readonly ISessionService _sessionService;
private readonly ILogger<AuthenticatedAccountController> _logger;

public AuthenticatedAccountController(
OpenShockContext db,
IRedisConnectionProvider redis,
ILogger<AuthenticatedAccountController> logger,
IAccountService accountService,
ISessionService sessionService)
ILogger<AuthenticatedAccountController> logger
)
{
_db = db;
_redis = redis;
_logger = logger;
_accountService = accountService;
_sessionService = sessionService;
_logger = logger;
}
}
9 changes: 8 additions & 1 deletion API/Controller/Account/LoginV2.cs
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,14 @@ public async Task<IActionResult> LoginV2(
var remoteIP = HttpContext.GetRemoteIP();

var turnStile = await turnstileService.VerifyUserResponseToken(body.TurnstileResponse, remoteIP, cancellationToken);
if (!turnStile.IsT0) return Problem(TurnstileError.InvalidTurnstile);
if (!turnStile.IsT0)
{
var cfErrors = turnStile.AsT1.Value!;
if (cfErrors.All(err => err == CloduflareTurnstileError.InvalidResponse))
return Problem(TurnstileError.InvalidTurnstile);

return Problem(new OpenShockProblem("InternalServerError", "Internal Server Error", HttpStatusCode.InternalServerError));
}

var loginAction = await _accountService.Login(body.UsernameOrEmail, body.Password, new LoginContext
{
Expand Down
4 changes: 2 additions & 2 deletions API/Controller/Account/Logout.cs
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,9 @@ public async Task<IActionResult> Logout(
[FromServices] ApiConfig apiConfig)
{
// Remove session if valid
if (HttpContext.TryGetSessionKey(out var sessionKey))
if (HttpContext.TryGetUserSessionCookie(out var sessionCookie))
{
await sessionService.DeleteSessionById(sessionKey);
await sessionService.DeleteSessionById(sessionCookie);
}

// Make sure cookie is removed, no matter if authenticated or not
Expand Down
12 changes: 7 additions & 5 deletions API/Controller/Account/SignupV2.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@ public sealed partial class AccountController
/// </summary>
/// <param name="body"></param>
/// <param name="turnstileService"></param>
/// <param name="apiConfig"></param>
/// <param name="cancellationToken"></param>
/// <response code="200">User successfully signed up</response>
/// <response code="400">Username or email already exists</response>
Expand All @@ -31,13 +30,16 @@ public sealed partial class AccountController
public async Task<IActionResult> SignUpV2(
[FromBody] SignUpV2 body,
[FromServices] ICloudflareTurnstileService turnstileService,
[FromServices] ApiConfig apiConfig,
CancellationToken cancellationToken)
{
if (apiConfig.Turnstile.Enabled)
var turnStile = await turnstileService.VerifyUserResponseToken(body.TurnstileResponse, HttpContext.GetRemoteIP(), cancellationToken);
if (!turnStile.IsT0)
{
var turnStile = await turnstileService.VerifyUserResponseToken(body.TurnstileResponse, HttpContext.GetRemoteIP(), cancellationToken);
if (!turnStile.IsT0) return Problem(TurnstileError.InvalidTurnstile);
var cfErrors = turnStile.AsT1.Value!;
if (cfErrors.All(err => err == CloduflareTurnstileError.InvalidResponse))
return Problem(TurnstileError.InvalidTurnstile);

return Problem(new OpenShockProblem("InternalServerError", "Internal Server Error", HttpStatusCode.InternalServerError));
}

var creationAction = await _accountService.Signup(body.Email, body.Username, body.Password);
Expand Down
11 changes: 3 additions & 8 deletions API/Controller/Account/_ApiController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,22 +12,17 @@ namespace OpenShock.API.Controller.Account;
/// User account management
/// </summary>
[ApiController]
[AllowAnonymous]
[ApiVersion("1")]
[ApiVersion("2")]
[Route("/{version:apiVersion}/account")]
public sealed partial class AccountController : OpenShockControllerBase
{
private readonly OpenShockContext _db;
private readonly IRedisConnectionProvider _redis;
private readonly ILogger<Authenticated.AuthenticatedAccountController> _logger;
private readonly IAccountService _accountService;
private readonly ILogger<AccountController> _logger;

public AccountController(OpenShockContext db, IRedisConnectionProvider redis, ILogger<Authenticated.AuthenticatedAccountController> logger, IAccountService accountService)
public AccountController(IAccountService accountService, ILogger<AccountController> logger)
{
_db = db;
_redis = redis;
_logger = logger;
_accountService = accountService;
_logger = logger;
}
}
9 changes: 4 additions & 5 deletions API/Controller/Admin/_ApiController.cs
Original file line number Diff line number Diff line change
@@ -1,16 +1,15 @@
using Microsoft.AspNetCore.Mvc;
using OpenShock.Common.Authentication.Attributes;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using OpenShock.Common.Authentication;
using OpenShock.Common.Authentication.ControllerBase;
using OpenShock.Common.Models;
using OpenShock.Common.OpenShockDb;
using Redis.OM.Contracts;

namespace OpenShock.API.Controller.Admin;

[ApiController]
[Rank(RankType.Admin)]
[UserSessionOnly]
[Route("/{version:apiVersion}/admin")]
[Authorize(AuthenticationSchemes = OpenShockAuthSchemas.UserSessionCookie, Policy = OpenShockAuthPolicies.AdminAccess)]
public sealed partial class AdminController : AuthenticatedSessionControllerBase
{
private readonly OpenShockContext _db;
Expand Down
7 changes: 5 additions & 2 deletions API/Controller/Device/_ApiController.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using OpenShock.Common.Authentication;
using OpenShock.Common.Authentication.ControllerBase;
using OpenShock.Common.OpenShockDb;
using Redis.OM.Contracts;
Expand All @@ -10,7 +12,8 @@ namespace OpenShock.API.Controller.Device;
/// </summary>
[ApiController]
[Route("/{version:apiVersion}/device")]
public sealed partial class DeviceController : AuthenticatedDeviceControllerBase
[Authorize(AuthenticationSchemes = OpenShockAuthSchemas.HubToken)]
public sealed partial class DeviceController : AuthenticatedHubControllerBase
{
private readonly OpenShockContext _db;
private readonly IRedisConnectionProvider _redis;
Expand Down
8 changes: 5 additions & 3 deletions API/Controller/Devices/DeviceOtaController.cs
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
using System.Net;
using System.Net.Mime;
using Asp.Versioning;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using OpenShock.Common.Authentication;
using OpenShock.Common.Authentication.Attributes;
using OpenShock.Common.Errors;
using OpenShock.Common.Models;
Expand All @@ -22,15 +24,15 @@ public sealed partial class DevicesController
/// <response code="200">OK</response>
/// <response code="404">Could not find device or you do not have access to it</response>
[HttpGet("{deviceId}/ota")]
[UserSessionOnly]
[MapToApiVersion("1")]
[Authorize(Policy = OpenShockAuthPolicies.UserAccess)]
[ProducesResponseType<BaseResponse<IReadOnlyCollection<OtaItem>>>(StatusCodes.Status200OK, MediaTypeNames.Application.Json)]
[ProducesResponseType<OpenShockProblem>(StatusCodes.Status404NotFound, MediaTypeNames.Application.ProblemJson)] // DeviceNotFound
[MapToApiVersion("1")]
public async Task<IActionResult> GetOtaUpdateHistory([FromRoute] Guid deviceId, [FromServices] IOtaService otaService)
{
// Check if user owns device or has a share
var deviceExistsAndYouHaveAccess = await _db.Devices.AnyAsync(x =>
x.Id == deviceId && x.Owner == CurrentUser.DbUser.Id);
x.Id == deviceId && x.Owner == CurrentUser.Id);
if (!deviceExistsAndYouHaveAccess) return Problem(DeviceError.DeviceNotFound);

return RespondSuccessLegacy(await otaService.GetUpdates(deviceId));
Expand Down
Loading

0 comments on commit b4a4e7c

Please sign in to comment.