chore: add csharpier to husky, format backend with csharpier
This commit is contained in:
parent
5fab66444f
commit
7f971e8549
73 changed files with 2098 additions and 1048 deletions
|
@ -17,7 +17,9 @@ public class AuthenticationMiddleware(DatabaseContext db) : IMiddleware
|
|||
return;
|
||||
}
|
||||
|
||||
if (!AuthUtils.TryParseToken(ctx.Request.Headers.Authorization.ToString(), out var rawToken))
|
||||
if (
|
||||
!AuthUtils.TryParseToken(ctx.Request.Headers.Authorization.ToString(), out var rawToken)
|
||||
)
|
||||
{
|
||||
await next(ctx);
|
||||
return;
|
||||
|
@ -40,6 +42,7 @@ public static class HttpContextExtensions
|
|||
private const string Key = "token";
|
||||
|
||||
public static void SetToken(this HttpContext ctx, Token token) => ctx.Items.Add(Key, token);
|
||||
|
||||
public static User? GetUser(this HttpContext ctx) => ctx.GetToken()?.User;
|
||||
|
||||
public static User GetUserOrThrow(this HttpContext ctx) =>
|
||||
|
@ -54,4 +57,4 @@ public static class HttpContextExtensions
|
|||
}
|
||||
|
||||
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)]
|
||||
public class AuthenticateAttribute : Attribute;
|
||||
public class AuthenticateAttribute : Attribute;
|
||||
|
|
|
@ -18,14 +18,26 @@ public class AuthorizationMiddleware : IMiddleware
|
|||
|
||||
var token = ctx.GetToken();
|
||||
if (token == null)
|
||||
throw new ApiError.Unauthorized("This endpoint requires an authenticated user.",
|
||||
ErrorCode.AuthenticationRequired);
|
||||
if (attribute.Scopes.Length > 0 && attribute.Scopes.Except(token.Scopes.ExpandScopes()).Any())
|
||||
throw new ApiError.Forbidden("This endpoint requires ungranted scopes.",
|
||||
attribute.Scopes.Except(token.Scopes.ExpandScopes()), ErrorCode.MissingScopes);
|
||||
throw new ApiError.Unauthorized(
|
||||
"This endpoint requires an authenticated user.",
|
||||
ErrorCode.AuthenticationRequired
|
||||
);
|
||||
if (
|
||||
attribute.Scopes.Length > 0
|
||||
&& attribute.Scopes.Except(token.Scopes.ExpandScopes()).Any()
|
||||
)
|
||||
throw new ApiError.Forbidden(
|
||||
"This endpoint requires ungranted scopes.",
|
||||
attribute.Scopes.Except(token.Scopes.ExpandScopes()),
|
||||
ErrorCode.MissingScopes
|
||||
);
|
||||
if (attribute.RequireAdmin && token.User.Role != UserRole.Admin)
|
||||
throw new ApiError.Forbidden("This endpoint can only be used by admins.");
|
||||
if (attribute.RequireModerator && token.User.Role != UserRole.Admin && token.User.Role != UserRole.Moderator)
|
||||
if (
|
||||
attribute.RequireModerator
|
||||
&& token.User.Role != UserRole.Admin
|
||||
&& token.User.Role != UserRole.Moderator
|
||||
)
|
||||
throw new ApiError.Forbidden("This endpoint can only be used by moderators.");
|
||||
|
||||
await next(ctx);
|
||||
|
@ -39,4 +51,4 @@ public class AuthorizeAttribute(params string[] scopes) : Attribute
|
|||
public readonly bool RequireModerator = scopes.Contains(":moderator");
|
||||
|
||||
public readonly string[] Scopes = scopes.Except([":admin", ":moderator"]).ToArray();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -21,19 +21,26 @@ public class ErrorHandlerMiddleware(ILogger baseLogger, IHub sentry) : IMiddlewa
|
|||
|
||||
if (ctx.Response.HasStarted)
|
||||
{
|
||||
logger.Error(e, "Error in {ClassName} ({Path}) after response started being sent", typeName,
|
||||
ctx.Request.Path);
|
||||
logger.Error(
|
||||
e,
|
||||
"Error in {ClassName} ({Path}) after response started being sent",
|
||||
typeName,
|
||||
ctx.Request.Path
|
||||
);
|
||||
|
||||
sentry.CaptureException(e, scope =>
|
||||
{
|
||||
var user = ctx.GetUser();
|
||||
if (user != null)
|
||||
scope.User = new SentryUser
|
||||
{
|
||||
Id = user.Id.ToString(),
|
||||
Username = user.Username
|
||||
};
|
||||
});
|
||||
sentry.CaptureException(
|
||||
e,
|
||||
scope =>
|
||||
{
|
||||
var user = ctx.GetUser();
|
||||
if (user != null)
|
||||
scope.User = new SentryUser
|
||||
{
|
||||
Id = user.Id.ToString(),
|
||||
Username = user.Username,
|
||||
};
|
||||
}
|
||||
);
|
||||
|
||||
return;
|
||||
}
|
||||
|
@ -45,13 +52,17 @@ public class ErrorHandlerMiddleware(ILogger baseLogger, IHub sentry) : IMiddlewa
|
|||
ctx.Response.ContentType = "application/json; charset=utf-8";
|
||||
if (ae is ApiError.Forbidden fe)
|
||||
{
|
||||
await ctx.Response.WriteAsync(JsonConvert.SerializeObject(new HttpApiError
|
||||
{
|
||||
Status = (int)fe.StatusCode,
|
||||
Code = ErrorCode.Forbidden,
|
||||
Message = fe.Message,
|
||||
Scopes = fe.Scopes.Length > 0 ? fe.Scopes : null
|
||||
}));
|
||||
await ctx.Response.WriteAsync(
|
||||
JsonConvert.SerializeObject(
|
||||
new HttpApiError
|
||||
{
|
||||
Status = (int)fe.StatusCode,
|
||||
Code = ErrorCode.Forbidden,
|
||||
Message = fe.Message,
|
||||
Scopes = fe.Scopes.Length > 0 ? fe.Scopes : null,
|
||||
}
|
||||
)
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -61,45 +72,61 @@ public class ErrorHandlerMiddleware(ILogger baseLogger, IHub sentry) : IMiddlewa
|
|||
return;
|
||||
}
|
||||
|
||||
await ctx.Response.WriteAsync(JsonConvert.SerializeObject(new HttpApiError
|
||||
{
|
||||
Status = (int)ae.StatusCode,
|
||||
Code = ae.ErrorCode,
|
||||
Message = ae.Message,
|
||||
}));
|
||||
await ctx.Response.WriteAsync(
|
||||
JsonConvert.SerializeObject(
|
||||
new HttpApiError
|
||||
{
|
||||
Status = (int)ae.StatusCode,
|
||||
Code = ae.ErrorCode,
|
||||
Message = ae.Message,
|
||||
}
|
||||
)
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
if (e is FoxnounsError fce)
|
||||
{
|
||||
logger.Error(fce.Inner ?? fce, "Exception in {ClassName} ({Path})", typeName, ctx.Request.Path);
|
||||
logger.Error(
|
||||
fce.Inner ?? fce,
|
||||
"Exception in {ClassName} ({Path})",
|
||||
typeName,
|
||||
ctx.Request.Path
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
logger.Error(e, "Exception in {ClassName} ({Path})", typeName, ctx.Request.Path);
|
||||
}
|
||||
|
||||
var errorId = sentry.CaptureException(e, scope =>
|
||||
{
|
||||
var user = ctx.GetUser();
|
||||
if (user != null)
|
||||
scope.User = new SentryUser
|
||||
{
|
||||
Id = user.Id.ToString(),
|
||||
Username = user.Username
|
||||
};
|
||||
});
|
||||
var errorId = sentry.CaptureException(
|
||||
e,
|
||||
scope =>
|
||||
{
|
||||
var user = ctx.GetUser();
|
||||
if (user != null)
|
||||
scope.User = new SentryUser
|
||||
{
|
||||
Id = user.Id.ToString(),
|
||||
Username = user.Username,
|
||||
};
|
||||
}
|
||||
);
|
||||
|
||||
ctx.Response.StatusCode = (int)HttpStatusCode.InternalServerError;
|
||||
ctx.Response.Headers.RequestId = ctx.TraceIdentifier;
|
||||
ctx.Response.ContentType = "application/json; charset=utf-8";
|
||||
await ctx.Response.WriteAsync(JsonConvert.SerializeObject(new HttpApiError
|
||||
{
|
||||
Status = (int)HttpStatusCode.InternalServerError,
|
||||
Code = ErrorCode.InternalServerError,
|
||||
ErrorId = errorId.ToString(),
|
||||
Message = "Internal server error",
|
||||
}));
|
||||
await ctx.Response.WriteAsync(
|
||||
JsonConvert.SerializeObject(
|
||||
new HttpApiError
|
||||
{
|
||||
Status = (int)HttpStatusCode.InternalServerError,
|
||||
Code = ErrorCode.InternalServerError,
|
||||
ErrorId = errorId.ToString(),
|
||||
Message = "Internal server error",
|
||||
}
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -118,4 +145,4 @@ public record HttpApiError
|
|||
|
||||
[JsonProperty(NullValueHandling = NullValueHandling.Ignore)]
|
||||
public string[]? Scopes { get; init; }
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue