133 lines
4.4 KiB
C#
133 lines
4.4 KiB
C#
using Dapper;
|
|
using DexDemoBackend;
|
|
using Microsoft.AspNetCore.Mvc;
|
|
using Npgsql;
|
|
|
|
var builder = WebApplication.CreateBuilder(args);
|
|
|
|
// 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); |