diff --git a/TicketSystem/.vs/ProjectEvaluation/ticket_system.metadata.v10.bin b/TicketSystem/.vs/ProjectEvaluation/ticket_system.metadata.v10.bin
new file mode 100644
index 0000000..e00dde6
Binary files /dev/null and b/TicketSystem/.vs/ProjectEvaluation/ticket_system.metadata.v10.bin differ
diff --git a/TicketSystem/.vs/ProjectEvaluation/ticket_system.projects.v10.bin b/TicketSystem/.vs/ProjectEvaluation/ticket_system.projects.v10.bin
new file mode 100644
index 0000000..17c7f8f
Binary files /dev/null and b/TicketSystem/.vs/ProjectEvaluation/ticket_system.projects.v10.bin differ
diff --git a/TicketSystem/.vs/ProjectEvaluation/ticket_system.strings.v10.bin b/TicketSystem/.vs/ProjectEvaluation/ticket_system.strings.v10.bin
new file mode 100644
index 0000000..be40a8c
Binary files /dev/null and b/TicketSystem/.vs/ProjectEvaluation/ticket_system.strings.v10.bin differ
diff --git a/TicketSystem/.vs/Ticket_System.slnx/DesignTimeBuild/.dtbcache.v2 b/TicketSystem/.vs/Ticket_System.slnx/DesignTimeBuild/.dtbcache.v2
new file mode 100644
index 0000000..839c45b
Binary files /dev/null and b/TicketSystem/.vs/Ticket_System.slnx/DesignTimeBuild/.dtbcache.v2 differ
diff --git a/TicketSystem/.vs/Ticket_System.slnx/FileContentIndex/121a73de-a590-4a4a-969c-42d78a3f9afd.vsidx b/TicketSystem/.vs/Ticket_System.slnx/FileContentIndex/121a73de-a590-4a4a-969c-42d78a3f9afd.vsidx
new file mode 100644
index 0000000..c6625e3
Binary files /dev/null and b/TicketSystem/.vs/Ticket_System.slnx/FileContentIndex/121a73de-a590-4a4a-969c-42d78a3f9afd.vsidx differ
diff --git a/TicketSystem/.vs/Ticket_System.slnx/FileContentIndex/8c41bb0e-532e-4c6d-b2ec-e5facbfaaf68.vsidx b/TicketSystem/.vs/Ticket_System.slnx/FileContentIndex/8c41bb0e-532e-4c6d-b2ec-e5facbfaaf68.vsidx
new file mode 100644
index 0000000..5e69c85
Binary files /dev/null and b/TicketSystem/.vs/Ticket_System.slnx/FileContentIndex/8c41bb0e-532e-4c6d-b2ec-e5facbfaaf68.vsidx differ
diff --git a/TicketSystem/.vs/Ticket_System.slnx/FileContentIndex/92ed99a3-f291-44fc-be20-db4f2041685b.vsidx b/TicketSystem/.vs/Ticket_System.slnx/FileContentIndex/92ed99a3-f291-44fc-be20-db4f2041685b.vsidx
new file mode 100644
index 0000000..2ec0f26
Binary files /dev/null and b/TicketSystem/.vs/Ticket_System.slnx/FileContentIndex/92ed99a3-f291-44fc-be20-db4f2041685b.vsidx differ
diff --git a/TicketSystem/.vs/Ticket_System.slnx/config/applicationhost.config b/TicketSystem/.vs/Ticket_System.slnx/config/applicationhost.config
new file mode 100644
index 0000000..cdd2df8
--- /dev/null
+++ b/TicketSystem/.vs/Ticket_System.slnx/config/applicationhost.config
@@ -0,0 +1,1026 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/TicketSystem/.vs/Ticket_System.slnx/v18/.futdcache.v2 b/TicketSystem/.vs/Ticket_System.slnx/v18/.futdcache.v2
new file mode 100644
index 0000000..e015ed1
Binary files /dev/null and b/TicketSystem/.vs/Ticket_System.slnx/v18/.futdcache.v2 differ
diff --git a/TicketSystem/.vs/Ticket_System.slnx/v18/.suo b/TicketSystem/.vs/Ticket_System.slnx/v18/.suo
new file mode 100644
index 0000000..e37650c
Binary files /dev/null and b/TicketSystem/.vs/Ticket_System.slnx/v18/.suo differ
diff --git a/TicketSystem/.vs/Ticket_System.slnx/v18/DocumentLayout.backup.json b/TicketSystem/.vs/Ticket_System.slnx/v18/DocumentLayout.backup.json
new file mode 100644
index 0000000..ce056de
--- /dev/null
+++ b/TicketSystem/.vs/Ticket_System.slnx/v18/DocumentLayout.backup.json
@@ -0,0 +1,37 @@
+{
+ "Version": 1,
+ "WorkspaceRootPath": "C:\\Users\\tweee\\source\\repos\\Projekt-dev-env\\src\\Project-CBackend\\TicketSystem\\",
+ "Documents": [
+ {
+ "AbsoluteMoniker": "D:0:0:{0BBF8E29-1D9F-41AD-A1A2-637C72FA90D1}|TicketSystem.csproj|c:\\users\\tweee\\source\\repos\\projekt-dev-env\\src\\project-cbackend\\ticketsystem\\program.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
+ "RelativeMoniker": "D:0:0:{0BBF8E29-1D9F-41AD-A1A2-637C72FA90D1}|TicketSystem.csproj|solutionrelative:program.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
+ }
+ ],
+ "DocumentGroupContainers": [
+ {
+ "Orientation": 0,
+ "VerticalTabListWidth": 256,
+ "DocumentGroups": [
+ {
+ "DockedWidth": 200,
+ "SelectedChildIndex": 0,
+ "Children": [
+ {
+ "$type": "Document",
+ "DocumentIndex": 0,
+ "Title": "Program.cs",
+ "DocumentMoniker": "C:\\Users\\tweee\\source\\repos\\Projekt-dev-env\\src\\Project-CBackend\\TicketSystem\\Program.cs",
+ "RelativeDocumentMoniker": "Program.cs",
+ "ToolTip": "C:\\Users\\tweee\\source\\repos\\Projekt-dev-env\\src\\Project-CBackend\\TicketSystem\\Program.cs",
+ "RelativeToolTip": "Program.cs",
+ "ViewState": "AgIAAHwAAAAAAAAAAAAAAIEAAABEAAAAAAAAAA==",
+ "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
+ "WhenOpened": "2026-02-03T10:53:32.912Z",
+ "EditorCaption": ""
+ }
+ ]
+ }
+ ]
+ }
+ ]
+}
\ No newline at end of file
diff --git a/TicketSystem/.vs/Ticket_System.slnx/v18/DocumentLayout.json b/TicketSystem/.vs/Ticket_System.slnx/v18/DocumentLayout.json
new file mode 100644
index 0000000..86af009
--- /dev/null
+++ b/TicketSystem/.vs/Ticket_System.slnx/v18/DocumentLayout.json
@@ -0,0 +1,37 @@
+{
+ "Version": 1,
+ "WorkspaceRootPath": "C:\\Users\\tweee\\source\\repos\\Projekt-dev-env\\src\\Project-CBackend\\TicketSystem\\",
+ "Documents": [
+ {
+ "AbsoluteMoniker": "D:0:0:{0BBF8E29-1D9F-41AD-A1A2-637C72FA90D1}|TicketSystem.csproj|c:\\users\\tweee\\source\\repos\\projekt-dev-env\\src\\project-cbackend\\ticketsystem\\program.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
+ "RelativeMoniker": "D:0:0:{0BBF8E29-1D9F-41AD-A1A2-637C72FA90D1}|TicketSystem.csproj|solutionrelative:program.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
+ }
+ ],
+ "DocumentGroupContainers": [
+ {
+ "Orientation": 0,
+ "VerticalTabListWidth": 256,
+ "DocumentGroups": [
+ {
+ "DockedWidth": 200,
+ "SelectedChildIndex": 0,
+ "Children": [
+ {
+ "$type": "Document",
+ "DocumentIndex": 0,
+ "Title": "Program.cs",
+ "DocumentMoniker": "C:\\Users\\tweee\\source\\repos\\Projekt-dev-env\\src\\Project-CBackend\\TicketSystem\\Program.cs",
+ "RelativeDocumentMoniker": "Program.cs",
+ "ToolTip": "C:\\Users\\tweee\\source\\repos\\Projekt-dev-env\\src\\Project-CBackend\\TicketSystem\\Program.cs",
+ "RelativeToolTip": "Program.cs",
+ "ViewState": "AgIAACoAAAAAAAAAAAAAADIAAAA4AAAAAAAAAA==",
+ "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
+ "WhenOpened": "2026-02-03T10:53:32.912Z",
+ "EditorCaption": ""
+ }
+ ]
+ }
+ ]
+ }
+ ]
+}
\ No newline at end of file
diff --git a/TicketSystem/Program.cs b/TicketSystem/Program.cs
index cc47829..36b86d7 100644
--- a/TicketSystem/Program.cs
+++ b/TicketSystem/Program.cs
@@ -1,12 +1,20 @@
using BCrypt.Net;
+using Microsoft.AspNetCore.Http.Features;
using Microsoft.AspNetCore.Identity.Data;
+using Microsoft.AspNetCore.WebSockets;
using Microsoft.IdentityModel.Tokens;
using MySqlConnector;
+using SIPSorcery.Net;
using System.Collections.Generic;
using System.Data;
using System.IdentityModel.Tokens.Jwt;
+using System.Net.WebSockets;
+using System.Reflection.Metadata;
+using System.Reflection.PortableExecutable;
using System.Security.Claims;
using System.Text;
+using System.Text.Json;
+
var builder = WebApplication.CreateBuilder(args);
@@ -17,13 +25,24 @@ var jwtAudience = builder.Configuration["Jwt:Audience"] ?? "Ticket-System";
builder.Services.AddTransient(_ => new MySqlConnection(connectionString));
+builder.Services.AddWebSockets(options =>
+{
+ options.KeepAliveInterval = TimeSpan.FromSeconds(120);
+});
+
var app = builder.Build();
+app.UseWebSockets();
+
app.Use(async (context, next) =>
{
+
+
var path = context.Request.Path.Value ?? "";
- if (path.Equals("/signin", StringComparison.OrdinalIgnoreCase)) //|| path.Equals("/user/create", StringComparison.OrdinalIgnoreCase))
+ if (path.Equals("/signin", StringComparison.OrdinalIgnoreCase)
+ || path.Equals("/webrtc", StringComparison.OrdinalIgnoreCase)
+ || path.Equals("/user/create", StringComparison.OrdinalIgnoreCase))
{
await next();
return;
@@ -55,40 +74,365 @@ app.Use(async (context, next) =>
await context.Response.WriteAsJsonAsync(new { error = "Invalid token specified" });
return;
}
-
- context.Items["user"] = principal.Identity?.Name ?? principal.FindFirstValue(ClaimTypes.Name) ?? "";
+ context.Items["user"] = principal.FindFirstValue(ClaimTypes.NameIdentifier) ?? "";
+ //context.Items["user"] = principal.Identity?.Name ?? principal.FindFirstValue(ClaimTypes.Name) ?? "";
await next();
});
+
+
app.MapPost("/signin", async (SignInRequest req, MySqlConnection conn) =>
{
- const string sql = "SELECT userID, username, password FROM User WHERE username = @username LIMIT 1;";
+ try
+ {
+ const string sql = "SELECT userID, username, password FROM User WHERE username = @username LIMIT 1;";
+
+ await conn.OpenAsync();
+
+ await using var cmd = new MySqlCommand(sql, conn);
+ cmd.Parameters.AddWithValue("@username", req.user);
+
+ await using var reader = await cmd.ExecuteReaderAsync();
+
+ if (!await reader.ReadAsync())
+ return Results.Unauthorized();
+
+ var userId = reader.GetInt32("userID").ToString();
+ var username = reader.GetString("username");
+ var pwHash = reader.GetString("password");
+
+ var ok = BCrypt.Net.BCrypt.Verify(req.password, pwHash);
+ if (!ok)
+ return Results.Unauthorized();
+
+ conn.Close();
+
+ await conn.OpenAsync();
+
+ var token = CreateJwt(userId, username, jwtSecret, jwtIssuer, jwtAudience, minutesValid: 120);
+
+ const string cleanupSql = "DELETE FROM ValidateToken\r\nWHERE STR_TO_DATE(validationDate, '%Y-%m-%d %H:%i:%s')\r\n < (UTC_TIMESTAMP() - INTERVAL 24 HOUR);\r\n";
+ await using (var cleanup = new MySqlCommand(cleanupSql, conn))
+ {
+ await cleanup.ExecuteNonQueryAsync();
+ }
+
+ conn.Close();
+
+ await conn.OpenAsync();
+
+ const string insertTokenSql = """
+ INSERT INTO ValidateToken (validationDate, token)
+ VALUES (@validationdate, @token);
+ """;
+
+ await using (var ins = new MySqlCommand(insertTokenSql, conn))
+ {
+ ins.Parameters.AddWithValue("@token", token);
+ ins.Parameters.AddWithValue("@validationdate", DateTime.Now);
+ await ins.ExecuteNonQueryAsync();
+ }
+
+ conn.Close();
+
+ return Results.Ok(new ResponseToken(token));
+ }
+ catch (Exception ex)
+ {
+ return Results.Problem(ex.Message);
+ }
+});
+
+#region web rtc
+
+app.Map("/webrtc", async context =>
+{
+ if (!context.WebSockets.IsWebSocketRequest)
+ {
+ context.Response.StatusCode = 400;
+ return;
+ }
+
+ var token = context.Request.Query["token"].ToString();
+ var principal = string.IsNullOrWhiteSpace(token) ? null : ValidateJwt(token, jwtSecret, jwtIssuer, jwtAudience);
+ if (principal == null)
+ {
+ context.Response.StatusCode = 401;
+ return;
+ }
+
+ using var socket = await context.WebSockets.AcceptWebSocketAsync();
+
+ var pc = new RTCPeerConnection(new RTCConfiguration
+ {
+ iceServers = new List
+ {
+ new RTCIceServer { urls = "http://10.204.192.64:3000" }
+ }
+ });
+
+ pc.oniceconnectionstatechange += (state) =>
+ Console.WriteLine($"[webrtc] ICE: {state}");
+
+ pc.onconnectionstatechange += (state) =>
+ Console.WriteLine($"[webrtc] PC: {state}");
+
+ // Server -> Client: ICE candidates
+ pc.onicecandidate += async cand =>
+ {
+ if (cand == null || socket.State != WebSocketState.Open) return;
+
+ var json = JsonSerializer.Serialize(cand);
+ await socket.SendAsync(Encoding.UTF8.GetBytes(json),
+ WebSocketMessageType.Text, true, CancellationToken.None);
+ };
+
+ var buffer = new byte[32 * 1024];
+ var jsonOpts = new JsonSerializerOptions { PropertyNameCaseInsensitive = true };
+
+ while (socket.State == WebSocketState.Open)
+ {
+ using var ms = new MemoryStream();
+ WebSocketReceiveResult res;
+
+ do
+ {
+ res = await socket.ReceiveAsync(buffer, CancellationToken.None);
+
+ if (res.MessageType == WebSocketMessageType.Close)
+ {
+ await socket.CloseAsync(WebSocketCloseStatus.NormalClosure, "bye", CancellationToken.None);
+ return;
+ }
+
+ ms.Write(buffer, 0, res.Count);
+ }
+ while (!res.EndOfMessage);
+
+ var msg = Encoding.UTF8.GetString(ms.ToArray());
+
+ if (msg.Contains("\"sdp\"", StringComparison.OrdinalIgnoreCase))
+ {
+ // Browser sendet meist { type: "offer", sdp: "..." }
+ var sdp = JsonSerializer.Deserialize(msg, jsonOpts);
+ if (sdp == null)
+ {
+ Console.WriteLine("[webrtc] SDP deserialize = null");
+ continue;
+ }
+
+ // SIPSorcery kann je nach Version sync/async sein -> wir behandeln BEIDES:
+ var setRemoteOk = await SetRemote(pc, sdp);
+ if (!setRemoteOk)
+ {
+ Console.WriteLine("[webrtc] setRemoteDescription failed");
+ continue;
+ }
+
+ if (sdp.type == RTCSdpType.offer)
+ {
+ var answer = pc.createAnswer(null);
+
+ var setLocalOk = await SetLocal(pc, answer);
+ if (!setLocalOk)
+ {
+ Console.WriteLine("[webrtc] setLocalDescription failed");
+ continue;
+ }
+
+ var json = JsonSerializer.Serialize(answer, jsonOpts);
+ await socket.SendAsync(Encoding.UTF8.GetBytes(json),
+ WebSocketMessageType.Text, true, CancellationToken.None);
+ }
+
+ continue;
+ }
+
+ // ---- ICE candidate from client
+ if (msg.Contains("candidate", StringComparison.OrdinalIgnoreCase))
+ {
+ var ice = JsonSerializer.Deserialize(msg, jsonOpts);
+ if (ice == null)
+ {
+ Console.WriteLine("[webrtc] ICE deserialize = null");
+ continue;
+ }
+
+ pc.addIceCandidate(ice);
+ continue;
+ }
+
+ Console.WriteLine($"[webrtc] unknown msg: {msg}");
+ }
+});
+static async Task HandleWebRtc(WebSocket socket)
+{
+ var pc = new RTCPeerConnection(new RTCConfiguration
+ {
+ iceServers = new List
+ {
+ new RTCIceServer { urls = "stun:stun.l.google.com:19302" }
+ }
+ });
+
+ pc.onicecandidate += async candidate =>
+ {
+ if (candidate != null)
+ {
+ var json = JsonSerializer.Serialize(candidate);
+ await socket.SendAsync(
+ Encoding.UTF8.GetBytes(json),
+ WebSocketMessageType.Text,
+ true,
+ CancellationToken.None
+ );
+ }
+ };
+
+ pc.onconnectionstatechange += (state) =>
+ {
+ Console.WriteLine($"[webrtc] connection state: {state}");
+ };
+
+ pc.oniceconnectionstatechange += (state) =>
+ {
+ Console.WriteLine($"[webrtc] ICE state: {state}");
+ };
+
+ pc.onicecandidate += (cand) =>
+ {
+ if (cand != null) Console.WriteLine("[webrtc] ICE candidate generated");
+ };
+
+
+ var buffer = new byte[8192];
+
+ var jsonOptions = new JsonSerializerOptions { PropertyNameCaseInsensitive = true };
+
+ while (socket.State == WebSocketState.Open)
+ {
+ var result = await socket.ReceiveAsync(buffer, CancellationToken.None);
+
+ if (result.MessageType == WebSocketMessageType.Close)
+ break;
+
+ var msg = Encoding.UTF8.GetString(buffer, 0, result.Count);
+
+ if (msg.Contains("\"sdp\""))
+ {
+ var sdp = JsonSerializer.Deserialize(msg, jsonOptions);
+ if (sdp == null) continue;
+
+ var r1 = pc.setRemoteDescription(sdp);
+ if (r1 != SetDescriptionResultEnum.OK)
+ {
+ Console.WriteLine($"setRemoteDescription failed: {r1}");
+ continue;
+ }
+
+ if (sdp.type == RTCSdpType.offer)
+ {
+ var answer = pc.createAnswer(null);
+
+ var r2 = pc.setLocalDescription(answer);
+
+ var json = JsonSerializer.Serialize(answer, jsonOptions);
+ await socket.SendAsync(
+ Encoding.UTF8.GetBytes(json),
+ WebSocketMessageType.Text,
+ true,
+ CancellationToken.None
+ );
+ }
+ }
+ else if (msg.Contains("candidate"))
+ {
+ var ice = JsonSerializer.Deserialize(msg, jsonOptions);
+ if (ice == null) continue;
+
+ pc.addIceCandidate(ice);
+ }
+ }
+}
+
+static async Task SetRemote(RTCPeerConnection pc, RTCSessionDescriptionInit sdp)
+{
+ var r = pc.setRemoteDescription(sdp);
+
+ if (r is SetDescriptionResultEnum e)
+ return e == SetDescriptionResultEnum.OK;
+
+ if (r != null && r.GetType().Name.Contains("SetDescriptionResult"))
+ {
+ var prop = r.GetType().GetProperty("Result");
+ if (prop?.GetValue(r) is SetDescriptionResultEnum e2)
+ return e2 == SetDescriptionResultEnum.OK;
+ }
+
+ return false;
+}
+
+static async Task SetLocal(RTCPeerConnection pc, RTCSessionDescriptionInit sdp)
+{
+ var r = pc.setLocalDescription(sdp);
+
+ //if (r is SetDescriptionResultEnum e)
+ // return e == SetDescriptionResultEnum.OK;
+
+ //if (r != SetDescriptionResultEnum.OK)
+ //{
+ // Console.WriteLine($"setLocalDescription failed: {r}");
+ // //continue;
+ //}
+
+ if (r is Task t)
+ return (await t) == SetDescriptionResultEnum.OK;
+
+ if (r != null && r.GetType().Name.Contains("SetDescriptionResult"))
+ {
+ var prop = r.GetType().GetProperty("Result");
+ if (prop?.GetValue(r) is SetDescriptionResultEnum e2)
+ return e2 == SetDescriptionResultEnum.OK;
+ }
+
+ return false;
+}
+
+#endregion
+
+static ClaimsPrincipal? ValidateJwtFromQuery(HttpContext ctx, string secret, string issuer, string audience)
+{
+ var token = ctx.Request.Query["token"].ToString();
+ if (string.IsNullOrEmpty(token)) return null;
+ return ValidateJwt(token, secret, issuer, audience);
+}
+
+app.MapGet("/token/validate", async (HttpContext ctx, MySqlConnection conn) =>
+{
+ if (!ctx.Request.Headers.TryGetValue("Authorization", out var authHeaderValues))
+ return Results.Unauthorized();
+
+ var parts = authHeaderValues.ToString().Split(' ', StringSplitOptions.RemoveEmptyEntries);
+ if (parts.Length != 2 || !parts[0].Equals("Bearer", StringComparison.OrdinalIgnoreCase))
+ return Results.Unauthorized();
+
+ var token = parts[1];
await conn.OpenAsync();
- await using var cmd = new MySqlCommand(sql, conn);
- cmd.Parameters.AddWithValue("@username", req.name);
+ const string checkSql = """
+ SELECT 1
+ FROM ValidateToken
+ WHERE token = @token
+ AND STR_TO_DATE(validationDate, '%Y-%m-%d %H:%i') >= (UTC_TIMESTAMP() - INTERVAL 24 HOUR)
+ LIMIT 1;
+ """;
- await using var reader = await cmd.ExecuteReaderAsync();
+ await using var cmd = new MySqlCommand(checkSql, conn);
+ cmd.Parameters.AddWithValue("@token", token);
- if (!await reader.ReadAsync())
- return Results.Unauthorized();
-
- var userId = reader.GetInt32("userID").ToString();
- var username = reader.GetString("username");
- var pwHash = reader.GetString("password");
-
- var ok = BCrypt.Net.BCrypt.Verify(req.password, pwHash);
- if (!ok)
- return Results.Unauthorized();
-
- var token = CreateJwt(userId, username, jwtSecret, jwtIssuer, jwtAudience, minutesValid: 120);
- return Results.Ok(new ResponseToken(token));
-});
-
-app.MapGet("/token/validate", (HttpContext ctx) =>
-{
- return Results.Ok(new TokenIsValid(true));
+ var ok = (await cmd.ExecuteScalarAsync()) != null;
+ return Results.Ok(new TokenIsValid(ok));
});
app.MapGet("/me", (HttpContext ctx) =>
@@ -112,19 +456,19 @@ app.MapPost("/user/create", async (RegisterRequest req, MySqlConnection conn) =>
await using var cmd = new MySqlCommand(insertSql, conn);
cmd.Parameters.AddWithValue("@userID", userId);
- cmd.Parameters.AddWithValue("@username", req.name);
+ cmd.Parameters.AddWithValue("@username", req.user);
cmd.Parameters.AddWithValue("@password", pwHash);
var rows = await cmd.ExecuteNonQueryAsync();
if (rows != 1)
return Results.Problem("User konnte nicht angelegt werden.");
- var token = CreateJwt(userId, req.name, jwtSecret, jwtIssuer, jwtAudience, minutesValid: 120);
+ var token = CreateJwt(userId, req.user, jwtSecret, jwtIssuer, jwtAudience, minutesValid: 120);
return Results.Created($"/user/{userId}", new ResponseToken(token));
});
-app.MapPost("/ticket/create", async (HttpContext ctx, CreateTicketRequest req, MySqlConnection conn) =>
+app.MapGet("/user/show/all", async (HttpContext ctx, MySqlConnection conn) =>
{
var userId = ctx.Items["user"]?.ToString();
if (string.IsNullOrEmpty(userId))
@@ -132,19 +476,182 @@ app.MapPost("/ticket/create", async (HttpContext ctx, CreateTicketRequest req, M
await conn.OpenAsync();
- const string insertSql = """
- INSERT INTO ticket (userID, ticketID, ticketname, status, priority, OpenAt, property)
- VALUES (@userID,(select max(ticketID) from ticket) + 1, @ticketname, @beschreibung, @status, @priority, @openAt, @property);
+ const string sql = """
+ SELECT *
+ FROM User
""";
- await using var cmd = new MySqlCommand(insertSql, conn);
+ await using var cmd = new MySqlCommand(sql, conn);
+
+ await using var reader = await cmd.ExecuteReaderAsync();
+
+ var user = new List