185 lines
5.7 KiB
C#
185 lines
5.7 KiB
C#
using System.Security.Claims;
|
|
using System.Text;
|
|
using System.Text.Json.Nodes;
|
|
using Microsoft.AspNetCore.Authentication.JwtBearer;
|
|
using Microsoft.AspNetCore.Http.HttpResults;
|
|
using Microsoft.IdentityModel.Tokens;
|
|
using USEntryCoach.Server.Data;
|
|
using USEntryCoach.Server.Services;
|
|
|
|
var builder = WebApplication.CreateBuilder(args);
|
|
|
|
// Add services to the container.
|
|
// Learn more about configuring OpenAPI at https://aka.ms/aspnet/openapi
|
|
builder.Services.AddOpenApi();
|
|
builder.Services.AddSingleton<TokenService>();
|
|
|
|
// Configure JWT token generation.
|
|
builder.Services.AddAuthentication(config =>
|
|
{
|
|
config.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
|
|
config.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
|
|
}).AddJwtBearer(config =>
|
|
{
|
|
// TODO: Use Microsoft.Extensions.Options?
|
|
// var myOptions = new MyOptions(); // Your settings class
|
|
// builder.Configuration.GetSection("MySection").Bind(myOptions);
|
|
// myOptions now has the values
|
|
//
|
|
// TODO: This is identical in TokenService
|
|
string? secretToken = builder.Configuration.GetValue<string>("Authentication:Secret");
|
|
|
|
if (secretToken == null)
|
|
{
|
|
throw new Exception("No Authentication Secret Token set! Please define a value for \"Authentication:SecretToken\" in appsettings.json.");
|
|
}
|
|
|
|
byte[] secretKey = Encoding.ASCII.GetBytes(secretToken);
|
|
|
|
// TODO: Only for debug!
|
|
config.RequireHttpsMetadata = false;
|
|
config.SaveToken = true;
|
|
config.TokenValidationParameters = new TokenValidationParameters()
|
|
{
|
|
ValidateIssuerSigningKey = true,
|
|
IssuerSigningKey = new SymmetricSecurityKey(secretKey),
|
|
ValidateIssuer = false,
|
|
ValidateAudience = false
|
|
};
|
|
});
|
|
|
|
builder.Services.AddAuthorization(options =>
|
|
{
|
|
options.AddPolicy(nameof(UserRole.Developer), policy => policy.RequireRole(nameof(UserRole.Developer)));
|
|
options.AddPolicy(nameof(UserRole.User), policy =>
|
|
{
|
|
// Also allow Developers to do anything a user can do.
|
|
policy.RequireRole(nameof(UserRole.User), nameof(UserRole.Developer));
|
|
});
|
|
});
|
|
|
|
var app = builder.Build();
|
|
|
|
app.UseAuthentication();
|
|
app.UseAuthorization();
|
|
|
|
app.UseDefaultFiles();
|
|
app.MapStaticAssets();
|
|
|
|
// Configure the HTTP request pipeline.
|
|
if (app.Environment.IsDevelopment())
|
|
{
|
|
app.MapOpenApi();
|
|
}
|
|
|
|
app.UseHttpsRedirection();
|
|
|
|
HttpClient client = new();
|
|
string? apiKey = app.Configuration.GetValue<string>("API:OpenAI");
|
|
client.DefaultRequestHeaders.Clear();
|
|
client.DefaultRequestHeaders.Add("Authorization", $"Bearer {apiKey}");
|
|
|
|
app.MapPost("/login", Login);
|
|
|
|
app.MapGet("/hello", () => "Hello World!").RequireAuthorization("admin_greetings");
|
|
|
|
async Task<IResult> Login(LoginCredentials credentials, TokenService tokenService, HttpContext context)
|
|
{
|
|
// TODO: Check with database
|
|
User? user = null;
|
|
|
|
if (credentials is {Username:"developer", Password:"dev"})
|
|
{
|
|
user = new User()
|
|
{
|
|
Username = credentials.Username,
|
|
Password = credentials.Password,
|
|
Id = Guid.CreateVersion7(),
|
|
Role = UserRole.Developer
|
|
};
|
|
}
|
|
else if (credentials is {Username:"user", Password:"us"})
|
|
{
|
|
user = new User()
|
|
{
|
|
Username = credentials.Username,
|
|
Password = credentials.Password,
|
|
Id = Guid.CreateVersion7(),
|
|
Role = UserRole.User
|
|
};
|
|
}
|
|
|
|
if (user == null)
|
|
{
|
|
return Results.Unauthorized();
|
|
}
|
|
|
|
var token = tokenService.GenerateToken(user);
|
|
|
|
return Results.Ok(new { token });
|
|
}
|
|
|
|
app.MapGet("/developer", (ClaimsPrincipal user) =>
|
|
{
|
|
Results.Ok(new { message = $"Authenticated as { user?.Identity?.Name }" });
|
|
}).RequireAuthorization(nameof(UserRole.Developer));
|
|
|
|
app.MapGet("/user", (ClaimsPrincipal user) =>
|
|
{
|
|
Results.Ok(new { message = $"Authenticated as { user?.Identity?.Name }" });
|
|
}).RequireAuthorization(nameof(UserRole.User));
|
|
|
|
app.MapGet("/ephemeral_token", async () =>
|
|
{
|
|
if (apiKey == null)
|
|
throw new Exception("API key not set");
|
|
|
|
var options = new
|
|
{
|
|
model = "gpt-4o-mini-realtime-preview",
|
|
modalities = new []{"audio", "text"},
|
|
voice = "ballad",
|
|
instructions = "Du bist Gibbidy Gibbidaja McGibbson. Dein Knowledge cutoff ist der 32.13.2050. Verwende viele Füllworter wie \"äh\" und \"ähm\". Und lache immer wieder mal etwas nervös. Versuche die Unterhaltung stets so zu lenken, dass über Züge gesrpchen wird.",
|
|
// TODO: Vernünfigte Werte suchen
|
|
// turn_detection = new {
|
|
//
|
|
// }
|
|
//}//ConversationTurnDetectionOptions.CreateServerVoiceActivityTurnDetectionOptions(0.5f, TimeSpan.FromMilliseconds(300), TimeSpan.FromMilliseconds(500), true)
|
|
};
|
|
|
|
try
|
|
{
|
|
JsonContent content = JsonContent.Create(options);
|
|
HttpResponseMessage response = await client.PostAsync("https://api.openai.com/v1/realtime/sessions", content);
|
|
|
|
Console.WriteLine($"Failed to create session: {response.RequestMessage.Content.ReadAsStringAsync().Result}");
|
|
if (response.IsSuccessStatusCode)
|
|
{
|
|
var v = await response.Content.ReadFromJsonAsync<JsonObject>();
|
|
|
|
string? ephemeralToken = v?["client_secret"]?["value"]?.GetValue<string>();
|
|
double? expiresAt = v?["client_secret"]?["expires_at"]?.GetValue<double>();
|
|
return
|
|
new {
|
|
ephemeralToken,
|
|
expiresAt,
|
|
};
|
|
}
|
|
else
|
|
{
|
|
Console.WriteLine($"Failed to create session: {response}");
|
|
}
|
|
}
|
|
catch (Exception e)
|
|
{
|
|
Console.WriteLine(e);
|
|
throw;
|
|
}
|
|
|
|
return null;
|
|
}).WithName("GetEphemeralToken").RequireAuthorization(nameof(UserRole.User));
|
|
|
|
app.MapFallbackToFile("/index.html");
|
|
|
|
app.Run();
|