Files
2025-10-02 16:59:42 +05:00

143 lines
4.8 KiB
C#

using Dapper;
using DexDemoBackend;
using Microsoft.AspNetCore.Mvc;
using Npgsql;
var builder = WebApplication.CreateBuilder(args);
// // Force binding to all interfaces in Kubernetes
// Console.WriteLine($"ASPNETCORE_URLS env var: {Environment.GetEnvironmentVariable("ASPNETCORE_URLS")}");
// Console.WriteLine($"ASPNETCORE_HTTP_PORTS env var: {Environment.GetEnvironmentVariable("ASPNETCORE_HTTP_PORTS")}");
// // Clear any existing configuration and force our URL
// builder.WebHost.ConfigureKestrel(options =>
// {
// options.ListenAnyIP(8000);
// });
// Configuration
var config = new AppConfig
{
DbHost = Environment.GetEnvironmentVariable("DB_HOST") ?? "postgres",
DbPort = Environment.GetEnvironmentVariable("DB_PORT") ?? "5440",
DbName = Environment.GetEnvironmentVariable("DB_NAME") ?? "dexdemo",
DbUser = Environment.GetEnvironmentVariable("DB_USER") ?? "dexdemo",
DbPassword = Environment.GetEnvironmentVariable("DB_PASSWORD") ?? "dexdemo",
DexIssuer = Environment.GetEnvironmentVariable("DEX_ISSUER") ?? "https://dex.127.0.0.1.sslip.io/",
InsecureDevMode = Environment.GetEnvironmentVariable("INSECURE_DEV_MODE")?.ToLower() == "true",
InsecureDevEmail = Environment.GetEnvironmentVariable("INSECURE_DEV_EMAIL")
};
builder.Services.AddSingleton(config);
builder.Services.AddSingleton<JwtValidator>();
// Configure JSON serialization to use snake_case
builder.Services.ConfigureHttpJsonOptions(options =>
{
options.SerializerOptions.PropertyNamingPolicy = System.Text.Json.JsonNamingPolicy.SnakeCaseLower;
});
builder.Services.AddCors(options =>
{
options.AddDefaultPolicy(policy =>
{
policy.AllowAnyOrigin()
.AllowAnyMethod()
.AllowAnyHeader();
});
});
var app = builder.Build();
Dapper.DefaultTypeMap.MatchNamesWithUnderscores = true;
app.UseCors();
// Health check endpoint
app.MapGet("/api/health", () => Results.Ok(new { status = "ok" }));
// User info endpoint
app.MapGet("/api/user-info", async (HttpContext context, [FromServices] AppConfig cfg, [FromServices] JwtValidator jwtValidator) =>
{
var email = await GetUserEmail(context, cfg, jwtValidator);
await using var conn = new NpgsqlConnection(cfg.ConnectionString);
await conn.OpenAsync();
// Get user info
var userResult = await conn.QuerySingleOrDefaultAsync<UserQueryResult>(@"
SELECT u.email, u.full_name, u.organization_id, o.name as org_name
FROM users u
LEFT JOIN organizations o ON u.organization_id = o.id
WHERE u.email = @email",
new { email });
if (userResult is null)
{
return Results.NotFound(new { detail = "User not found in database" });
}
var organization = userResult.OrganizationId.HasValue && userResult.OrgName != null
? new Organization(userResult.OrganizationId.Value, userResult.OrgName)
: null;
// Get user roles
var roles = (await conn.QueryAsync<Role>(@"
SELECT r.id, r.name, r.description
FROM roles r
JOIN user_roles ur ON r.id = ur.role_id
JOIN users u ON ur.user_id = u.id
WHERE u.email = @email",
new { email })).ToList();
// Get available links
var links = (await conn.QueryAsync<Link>(@"
SELECT DISTINCT l.id, l.title, l.url, l.description
FROM links l
JOIN role_links rl ON l.id = rl.link_id
JOIN user_roles ur ON rl.role_id = ur.role_id
JOIN users u ON ur.user_id = u.id
WHERE u.email = @email
ORDER BY l.id",
new { email })).ToList();
return Results.Ok(new UserInfo(userResult.Email, userResult.FullName, organization, roles, links));
});
app.Run();
static async Task<string> GetUserEmail(HttpContext context, AppConfig config, JwtValidator jwtValidator)
{
// Dev mode
if (config.InsecureDevMode)
{
Console.WriteLine($"INSECURE_DEV_MODE: Using email {config.InsecureDevEmail}");
return config.InsecureDevEmail!;
}
// Try Authorization header
if (context.Request.Headers.TryGetValue("Authorization", out var authHeader))
{
var headerValue = authHeader.ToString();
if (headerValue.StartsWith("Bearer ", StringComparison.OrdinalIgnoreCase))
{
var token = headerValue[7..];
var payload = await jwtValidator.ValidateToken(token);
if (payload.TryGetValue("email", out var emailClaim))
{
return emailClaim.ToString()!;
}
}
}
// Try OAuth2 proxy header
if (context.Request.Headers.TryGetValue("X-Auth-Request-Email", out var emailHeader))
{
return emailHeader.ToString();
}
throw new UnauthorizedAccessException("No authentication information found");
}
// Internal query result model
record UserQueryResult(string Email, string FullName, int? OrganizationId, string? OrgName);