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
87 changes: 75 additions & 12 deletions WebAPI/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
using WebAPI.Behaviors;
using WebAPI.FilterException;
using WebAPI.Middlewares;
using Microsoft.OpenApi.Models; // added for Swagger/OpenAPI

var builder = WebApplication.CreateBuilder(args);

Expand All @@ -30,6 +31,57 @@
// Add Pipeline Behavior for validation flow.
builder.Services.AddTransient(typeof(IPipelineBehavior<,>), typeof(ValidationBehavior<,>));

// CORS: add a default policy (adjust AllowedOrigins as needed)
builder.Services.AddCors(options =>
{
options.AddPolicy("DefaultCorsPolicy", policy =>
{
policy
.AllowAnyOrigin()
.AllowAnyHeader()
.AllowAnyMethod();
Comment on lines +40 to +42

Copilot AI Nov 4, 2025

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The CORS policy uses .AllowAnyOrigin() which is overly permissive and cannot be used with credentials (JWT tokens in cookies). For a JWT-based API handling authentication, you should either: (1) specify explicit allowed origins using .WithOrigins(\"https://yourapp.com\") for production, or (2) if you need to allow credentials, use .SetIsOriginAllowed(origin => true) with .AllowCredentials() instead of .AllowAnyOrigin(). The current configuration poses a security risk in production environments.

Suggested change
.AllowAnyOrigin()
.AllowAnyHeader()
.AllowAnyMethod();
.WithOrigins(
"https://yourapp.com", // Production frontend
"http://localhost:3000" // Local development
)
.AllowAnyHeader()
.AllowAnyMethod()
.AllowCredentials();

Copilot uses AI. Check for mistakes.
});
});

// Swagger / OpenAPI (Swashbuckle)
builder.Services.AddEndpointsApiExplorer();

builder.Services.AddSwaggerGen(options =>
{
options.SwaggerDoc("v1", new OpenApiInfo
{
Title = "EV Rental API",
Version = "v1"
});

// JWT Bearer token support in Swagger UI
options.AddSecurityDefinition("Bearer", new OpenApiSecurityScheme
{
Description = "JWT Authorization header using the Bearer scheme. Example: \"Bearer {token}\"",
Name = "Authorization",
In = ParameterLocation.Header,
Type = SecuritySchemeType.Http,
Scheme = "bearer",
BearerFormat = "JWT"
});

options.AddSecurityRequirement(new OpenApiSecurityRequirement
{
{
new OpenApiSecurityScheme
{
Reference = new OpenApiReference
{
Type = ReferenceType.SecurityScheme,
Id = "Bearer"
}
},
new string[] { }
}
});
options.EnableAnnotations();
});
Comment on lines +46 to +83

Copilot AI Nov 4, 2025

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This code introduces redundant API documentation tooling. The application already has OpenAPI support configured with Scalar (lines 86-99, 113-130) including JWT Bearer security via AddOpenApiWithJwtBearer() (line 90) and custom transformers (BearerSecuritySchemeTransformer, AuthorizeOperationTransformer in ServiceExtensions.cs). Running both Swashbuckle and the existing OpenAPI/Scalar stack simultaneously adds maintenance overhead, potential version conflicts, and confusion for API consumers. Consider removing either the Swashbuckle setup or the existing Scalar-based OpenAPI configuration to maintain a single source of truth for API documentation.

Copilot uses AI. Check for mistakes.

// Learn more about configuring OpenAPI at https://aka.ms/aspnet/openapi
builder.Services.AddOpenApi();
builder.Services.AddCustomIdentity();
Expand All @@ -50,6 +102,14 @@
// Configure the HTTP request pipeline.
//if (app.Environment.IsDevelopment())
{
// Enable Swashbuckle middleware (swagger.json + swagger UI)
app.UseSwagger();
app.UseSwaggerUI(c =>
{
c.SwaggerEndpoint("/swagger/v1/swagger.json", "EV Rental API v1");
c.RoutePrefix = "swagger"; // serves UI at /swagger; set to string.Empty to serve at root
});
Comment on lines +105 to +111

Copilot AI Nov 4, 2025

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Swagger middleware is unconditionally enabled for all environments, including production. The commented-out if (app.Environment.IsDevelopment()) check on line 103 suggests this was intended to be development-only. Exposing Swagger UI in production can leak API structure, endpoint details, and potentially sensitive information to attackers. Either move this block inside a proper environment check if (app.Environment.IsDevelopment()) { ... } or use a configuration-based feature flag to control Swagger availability per environment.

Copilot uses AI. Check for mistakes.

app.MapOpenApi();
app.MapScalarApiReference((options, httpContext) =>
{
Expand All @@ -75,6 +135,9 @@
app.UseHttpsRedirection();
app.UseHsts();// Enables HTTP Strict Transport Security (HSTS) for the application.

// Enable CORS - must be before Authentication/Authorization and before endpoints
app.UseCors("DefaultCorsPolicy");

app.UseAuthentication();
app.UseAuthorization();

Expand All @@ -88,18 +151,18 @@
{
var services = scope.ServiceProvider.GetRequiredService<ApplicationDbContext>();
await services.Database.ExecuteSqlRawAsync(@"
IF NOT EXISTS (SELECT 1 FROM [dbo].[AspNetRoles] WHERE [NormalizedName]='ADMIN')
INSERT [dbo].[AspNetRoles] ([Id],[Name],[NormalizedName],[ConcurrencyStamp])
VALUES ('90000000-0000-0000-0000-000000000001','Admin','ADMIN','c0c2f3f6-38c3-4a3f-8a8f-8f3a0a5b1111');

IF NOT EXISTS (SELECT 1 FROM [dbo].[AspNetRoles] WHERE [NormalizedName]='STAFF')
INSERT [dbo].[AspNetRoles] ([Id],[Name],[NormalizedName],[ConcurrencyStamp])
VALUES ('90000000-0000-0000-0000-000000000002','Staff','STAFF','d1d2e3e4-45f6-47a1-9c9a-2b2c3d4e2222');

IF NOT EXISTS (SELECT 1 FROM [dbo].[AspNetRoles] WHERE [NormalizedName]='RENTER')
INSERT [dbo].[AspNetRoles] ([Id],[Name],[NormalizedName],[ConcurrencyStamp])
VALUES ('90000000-0000-0000-0000-000000000003','Renter','RENTER','e2e3f4f5-56a7-48b2-8d8e-3c3d4e5f3333');
");
IF NOT EXISTS (SELECT 1 FROM [dbo].[AspNetRoles] WHERE [NormalizedName]='ADMIN')
INSERT [dbo].[AspNetRoles] ([Id],[Name],[NormalizedName],[ConcurrencyStamp])
VALUES ('90000000-0000-0000-0000-000000000001','Admin','ADMIN','c0c2f3f6-38c3-4a3f-8a8f-8f3a0a5b1111');

IF NOT EXISTS (SELECT 1 FROM [dbo].[AspNetRoles] WHERE [NormalizedName]='STAFF')
INSERT [dbo].[AspNetRoles] ([Id],[Name],[NormalizedName],[ConcurrencyStamp])
VALUES ('90000000-0000-0000-0000-000000000002','Staff','STAFF','d1d2e3e4-45f6-47a1-9c9a-2b2c3d4e2222');

IF NOT EXISTS (SELECT 1 FROM [dbo].[AspNetRoles] WHERE [NormalizedName]='RENTER')
INSERT [dbo].[AspNetRoles] ([Id],[Name],[NormalizedName],[ConcurrencyStamp])
VALUES ('90000000-0000-0000-0000-000000000003','Renter','RENTER','e2e3f4f5-56a7-48b2-8d8e-3c3d4e5f3333');
");
await services.Database.MigrateAsync();
}

Expand Down
2 changes: 2 additions & 0 deletions WebAPI/WebAPI.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@
<PackageReference Include="Microsoft.IdentityModel.Tokens" Version="8.10.0" />
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
<PackageReference Include="Scalar.AspNetCore" Version="2.3.1" />
<PackageReference Include="Swashbuckle.AspNetCore" Version="9.0.6" />
<PackageReference Include="Swashbuckle.AspNetCore.Annotations" Version="9.0.6" />
</ItemGroup>

<ItemGroup>
Expand Down