Compare commits

..

No commits in common. "565252382c10020c6899aaece6437758757e1bdc" and "c189cc69557a01bbeeb699232798c1f8607d88ab" have entirely different histories.

10 changed files with 13 additions and 131 deletions

View File

@ -1,26 +0,0 @@
using System;
namespace Mirea.Api.Endpoint.Common.Attributes;
[AttributeUsage(AttributeTargets.Method | AttributeTargets.Class, AllowMultiple = false, Inherited = false)]
public class CacheMaxAgeAttribute : Attribute
{
public int MaxAge { get; }
public CacheMaxAgeAttribute(int days = 0, int hours = 0, int minutes = 0)
{
MaxAge = (int)new TimeSpan(days, hours, minutes, 0).TotalSeconds;
}
public CacheMaxAgeAttribute(int minutes) : this(0, 0, minutes)
{
}
public CacheMaxAgeAttribute(bool usingSetting = false)
{
if (usingSetting)
MaxAge = -1;
else
MaxAge = 0;
}
}

View File

@ -6,7 +6,7 @@ namespace Mirea.Api.Endpoint.Common.Services;
public static class UrlHelper public static class UrlHelper
{ {
public static string GetCurrentDomain(this HttpContext context) => public static string CurrentDomain(HttpContext context) =>
context.Request.Headers["X-Forwarded-Host"].FirstOrDefault() ?? context.Request.Host.Host; context.Request.Headers["X-Forwarded-Host"].FirstOrDefault() ?? context.Request.Host.Host;
private static string CreateSubPath(string? path) private static string CreateSubPath(string? path)

View File

@ -74,11 +74,9 @@ public partial class SetupController(
Response.Cookies.Append("AuthToken", token, new CookieOptions Response.Cookies.Append("AuthToken", token, new CookieOptions
{ {
Path = UrlHelper.GetSubPathWithoutFirstApiName + "api", Path = UrlHelper.GetSubPathWithoutFirstApiName + "api",
Domain = HttpContext.GetCurrentDomain(), Domain = UrlHelper.CurrentDomain(ControllerContext.HttpContext),
#if !DEBUG
Secure = true, Secure = true,
HttpOnly = true HttpOnly = true
#endif
}); });
return Ok(true); return Ok(true);
} }

View File

@ -30,11 +30,9 @@ public class AuthController(IOptionsSnapshot<Admin> user, AuthService auth, Pass
{ {
Expires = expires, Expires = expires,
Path = UrlHelper.GetSubPathWithoutFirstApiName + "api", Path = UrlHelper.GetSubPathWithoutFirstApiName + "api",
Domain = HttpContext.GetCurrentDomain(), Domain = UrlHelper.CurrentDomain(ControllerContext.HttpContext),
#if !DEBUG
Secure = true, Secure = true,
HttpOnly = true HttpOnly = true
#endif
}; };
Response.Cookies.Append(name, value, cookieOptions); Response.Cookies.Append(name, value, cookieOptions);

View File

@ -17,14 +17,11 @@ using System.Threading.Tasks;
namespace Mirea.Api.Endpoint.Controllers.V1; namespace Mirea.Api.Endpoint.Controllers.V1;
[ApiVersion("1.0")] [ApiVersion("1.0")]
[CacheMaxAge(true)]
public class ScheduleController(IMediator mediator, IOptionsSnapshot<GeneralConfig> config) : BaseController public class ScheduleController(IMediator mediator, IOptionsSnapshot<GeneralConfig> config) : BaseController
{ {
[CacheMaxAge(1, 0)]
[HttpGet("StartTerm")] [HttpGet("StartTerm")]
public ActionResult<DateOnly> GetStartTerm() => config.Value.ScheduleSettings!.StartTerm; public ActionResult<DateOnly> GetStartTerm() => config.Value.ScheduleSettings!.StartTerm;
[CacheMaxAge(1, 0)]
[HttpGet("PairPeriod")] [HttpGet("PairPeriod")]
public ActionResult<Dictionary<int, PairPeriodTime>> GetPairPeriod() => config.Value.ScheduleSettings!.PairPeriod.ConvertToDto(); public ActionResult<Dictionary<int, PairPeriodTime>> GetPairPeriod() => config.Value.ScheduleSettings!.PairPeriod.ConvertToDto();
@ -108,7 +105,7 @@ public class ScheduleController(IMediator mediator, IOptionsSnapshot<GeneralConf
[FromQuery] int[]? professors = null, [FromQuery] int[]? professors = null,
[FromQuery] int[]? lectureHalls = null) => [FromQuery] int[]? lectureHalls = null) =>
await Get(new ScheduleRequest await Get(new ScheduleRequest
{ {
Disciplines = disciplines, Disciplines = disciplines,
IsEven = isEven, IsEven = isEven,
Groups = [id], Groups = [id],
@ -136,7 +133,7 @@ public class ScheduleController(IMediator mediator, IOptionsSnapshot<GeneralConf
[FromQuery] int[]? groups = null, [FromQuery] int[]? groups = null,
[FromQuery] int[]? lectureHalls = null) => [FromQuery] int[]? lectureHalls = null) =>
await Get(new ScheduleRequest await Get(new ScheduleRequest
{ {
Disciplines = disciplines, Disciplines = disciplines,
IsEven = isEven, IsEven = isEven,
Groups = groups, Groups = groups,
@ -164,7 +161,7 @@ public class ScheduleController(IMediator mediator, IOptionsSnapshot<GeneralConf
[FromQuery] int[]? groups = null, [FromQuery] int[]? groups = null,
[FromQuery] int[]? professors = null) => [FromQuery] int[]? professors = null) =>
await Get(new ScheduleRequest await Get(new ScheduleRequest
{ {
Disciplines = disciplines, Disciplines = disciplines,
IsEven = isEven, IsEven = isEven,
Groups = groups, Groups = groups,
@ -192,11 +189,11 @@ public class ScheduleController(IMediator mediator, IOptionsSnapshot<GeneralConf
[FromQuery] int[]? professors = null, [FromQuery] int[]? professors = null,
[FromQuery] int[]? lectureHalls = null) => [FromQuery] int[]? lectureHalls = null) =>
await Get(new ScheduleRequest await Get(new ScheduleRequest
{ {
Disciplines = [id], Disciplines = [id],
IsEven = isEven, IsEven = isEven,
Groups = groups, Groups = groups,
Professors = professors, Professors = professors,
LectureHalls = lectureHalls LectureHalls = lectureHalls
}); });
} }

View File

@ -1,81 +0,0 @@
using Cronos;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Options;
using Mirea.Api.Endpoint.Common.Attributes;
using Mirea.Api.Endpoint.Common.Settings;
using System;
using System.Reflection;
using System.Threading.Tasks;
namespace Mirea.Api.Endpoint.Middleware;
public class CacheMaxAgeMiddleware(RequestDelegate next, IServiceProvider serviceProvider)
{
public async Task InvokeAsync(HttpContext context)
{
if (!context.Response.StatusCode.ToString().StartsWith('2'))
{
await next(context);
return;
}
var endpoint = context.GetEndpoint();
var actionDescriptor = endpoint?.Metadata.GetMetadata<Microsoft.AspNetCore.Mvc.Controllers.ControllerActionDescriptor>();
if (actionDescriptor == null)
{
await next(context);
return;
}
var controllerType = actionDescriptor.ControllerTypeInfo;
var methodInfo = actionDescriptor.MethodInfo;
var maxAgeAttribute = methodInfo.GetCustomAttribute<CacheMaxAgeAttribute>() ?? controllerType.GetCustomAttribute<CacheMaxAgeAttribute>();
if (maxAgeAttribute == null)
{
await next(context);
return;
}
switch (maxAgeAttribute.MaxAge)
{
case < 0:
{
DateTime? nextDate;
var now = DateTime.UtcNow;
using (var scope = serviceProvider.CreateScope())
{
var updateCronString = scope.ServiceProvider.GetRequiredService<IOptionsSnapshot<GeneralConfig>>().Value.ScheduleSettings?.CronUpdateSchedule;
if (string.IsNullOrEmpty(updateCronString) ||
!CronExpression.TryParse(updateCronString, CronFormat.Standard, out var updateCron))
{
await next(context);
return;
}
nextDate = updateCron.GetNextOccurrence(now);
}
if (!nextDate.HasValue)
{
await next(context);
return;
}
context.Response.Headers.CacheControl = "max-age=" + (int)(nextDate.Value - now).TotalSeconds;
break;
}
case > 0:
context.Response.Headers.CacheControl = "max-age=" + maxAgeAttribute.MaxAge;
break;
}
await next(context);
}
}

View File

@ -11,7 +11,7 @@ namespace Mirea.Api.Endpoint.Middleware;
public class CustomExceptionHandlerMiddleware(RequestDelegate next) public class CustomExceptionHandlerMiddleware(RequestDelegate next)
{ {
public async Task InvokeAsync(HttpContext context) public async Task Invoke(HttpContext context)
{ {
try try
{ {

View File

@ -6,7 +6,7 @@ namespace Mirea.Api.Endpoint.Middleware;
public class JwtRevocationMiddleware(RequestDelegate next) public class JwtRevocationMiddleware(RequestDelegate next)
{ {
public async Task InvokeAsync(HttpContext context, IRevokedToken revokedTokenStore) public async Task Invoke(HttpContext context, IRevokedToken revokedTokenStore)
{ {
if (context.Request.Headers.ContainsKey("Authorization")) if (context.Request.Headers.ContainsKey("Authorization"))
{ {

View File

@ -13,7 +13,7 @@ public class MaintenanceModeMiddleware(RequestDelegate next, IMaintenanceModeSer
return endpoint?.Metadata.GetMetadata<MaintenanceModeIgnoreAttribute>() != null; return endpoint?.Metadata.GetMetadata<MaintenanceModeIgnoreAttribute>() != null;
} }
public async Task InvokeAsync(HttpContext context) public async Task Invoke(HttpContext context)
{ {
if (!maintenanceModeService.IsMaintenanceMode && !maintenanceModeNotConfigureService.IsMaintenanceMode || IsIgnoreMaintenanceMode(context)) if (!maintenanceModeService.IsMaintenanceMode && !maintenanceModeNotConfigureService.IsMaintenanceMode || IsIgnoreMaintenanceMode(context))
await next(context); await next(context);

View File

@ -1,5 +1,4 @@
using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.DataProtection;
using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.HttpOverrides; using Microsoft.AspNetCore.HttpOverrides;
using Microsoft.Extensions.Configuration; using Microsoft.Extensions.Configuration;
@ -95,15 +94,13 @@ public class Program
builder.Services.AddJwtToken(builder.Configuration); builder.Services.AddJwtToken(builder.Configuration);
builder.Services.AddSecurity(builder.Configuration); builder.Services.AddSecurity(builder.Configuration);
builder.Services.AddDataProtection()
.PersistKeysToFileSystem(new DirectoryInfo(PathBuilder.Combine("DataProtection")));
var app = builder.Build(); var app = builder.Build();
app.UseForwardedHeaders(); app.UseForwardedHeaders();
app.UseStaticFiles(UrlHelper.GetSubPath.TrimEnd('/')); app.UseStaticFiles(UrlHelper.GetSubPath.TrimEnd('/'));
app.UseCors("AllowAll"); app.UseCors("AllowAll");
app.UseCustomSerilog(); app.UseCustomSerilog();
app.UseForwardedHeaders();
using (var scope = app.Services.CreateScope()) using (var scope = app.Services.CreateScope())
{ {
@ -125,10 +122,9 @@ public class Program
app.UseCustomSwagger(app.Services); app.UseCustomSwagger(app.Services);
app.UseMiddleware<CustomExceptionHandlerMiddleware>();
app.UseMiddleware<MaintenanceModeMiddleware>(); app.UseMiddleware<MaintenanceModeMiddleware>();
app.UseMiddleware<CustomExceptionHandlerMiddleware>();
app.UseMiddleware<JwtRevocationMiddleware>(); app.UseMiddleware<JwtRevocationMiddleware>();
app.UseMiddleware<CacheMaxAgeMiddleware>();
app.UseHttpsRedirection(); app.UseHttpsRedirection();