From 8c212321e067ce247b664037259c6b70529327d5 Mon Sep 17 00:00:00 2001 From: Dmitri Shimanski Date: Wed, 30 Jul 2025 01:37:10 +0300 Subject: [PATCH] Fix bugs --- Aoyo.Taiga.Tests/Aoyo.Taiga.Tests.csproj | 23 ++++++++++++++ Aoyo.Taiga.sln | 6 ++++ Aoyo.Taiga/Controllers/TaigaWebHook.cs | 39 ++++++++++++++---------- Aoyo.Taiga/Dockerfile | 2 +- Aoyo.Taiga/Program.cs | 5 +++ Aoyo.Taiga/WebHookTypes/TaigaUser.cs | 2 ++ Aoyo.Taiga/appsettings.Development.json | 7 +++++ compose.yaml | 7 +++++ 8 files changed, 74 insertions(+), 17 deletions(-) create mode 100644 Aoyo.Taiga.Tests/Aoyo.Taiga.Tests.csproj create mode 100644 compose.yaml diff --git a/Aoyo.Taiga.Tests/Aoyo.Taiga.Tests.csproj b/Aoyo.Taiga.Tests/Aoyo.Taiga.Tests.csproj new file mode 100644 index 0000000..d7f90e2 --- /dev/null +++ b/Aoyo.Taiga.Tests/Aoyo.Taiga.Tests.csproj @@ -0,0 +1,23 @@ + + + + net9.0 + latest + enable + enable + false + + + + + + + + + + + + + + + diff --git a/Aoyo.Taiga.sln b/Aoyo.Taiga.sln index d8a0a6b..3429a68 100644 --- a/Aoyo.Taiga.sln +++ b/Aoyo.Taiga.sln @@ -8,6 +8,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution README.md = README.md EndProjectSection EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Aoyo.Taiga.Tests", "Aoyo.Taiga.Tests\Aoyo.Taiga.Tests.csproj", "{D36CA783-EA93-4B54-B3A4-B911B00D0887}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -18,5 +20,9 @@ Global {CAFC85B2-1606-44DF-A3CD-9DEAA07ADB78}.Debug|Any CPU.Build.0 = Debug|Any CPU {CAFC85B2-1606-44DF-A3CD-9DEAA07ADB78}.Release|Any CPU.ActiveCfg = Release|Any CPU {CAFC85B2-1606-44DF-A3CD-9DEAA07ADB78}.Release|Any CPU.Build.0 = Release|Any CPU + {D36CA783-EA93-4B54-B3A4-B911B00D0887}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {D36CA783-EA93-4B54-B3A4-B911B00D0887}.Debug|Any CPU.Build.0 = Debug|Any CPU + {D36CA783-EA93-4B54-B3A4-B911B00D0887}.Release|Any CPU.ActiveCfg = Release|Any CPU + {D36CA783-EA93-4B54-B3A4-B911B00D0887}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection EndGlobal diff --git a/Aoyo.Taiga/Controllers/TaigaWebHook.cs b/Aoyo.Taiga/Controllers/TaigaWebHook.cs index 0a5238b..f40bd3a 100644 --- a/Aoyo.Taiga/Controllers/TaigaWebHook.cs +++ b/Aoyo.Taiga/Controllers/TaigaWebHook.cs @@ -1,11 +1,14 @@ using System.Diagnostics.CodeAnalysis; using System.Security.Cryptography; using System.Text; +using System.Text.Encodings.Web; using System.Text.Json; +using System.Text.Json.Serialization; using Aoyo.Taiga.WebHookTypes; using Discord; using Discord.WebSocket; using Microsoft.AspNetCore.Mvc; +using Newtonsoft.Json; namespace Aoyo.Taiga.Controllers; @@ -40,17 +43,20 @@ public class TaigaWebHook : Controller { try { - var signature = Request.Headers["X-TAIGA-WEBHOOK-SIGNATURE"].First()!; + var signature = Request.Headers["X-TAIGA-WEBHOOK-SIGNATURE"].First(); + if (signature == null) return BadRequest("Provide signature first"); + using var reader = new StreamReader(Request.Body); var data = await reader.ReadToEndAsync(); _logger.LogInformation(data); - - if (_config.GetValue("ASPNETCORE_ENVIRONMENT") == "Production") - if (!VerifySignature(_key, data, signature)) - { - return BadRequest("Invalid signature"); - } + var hash = VerifySignature(_key, data); + + + if (!string.Equals(signature, hash, StringComparison.OrdinalIgnoreCase)) + { + return BadRequest($"Invalid signature {hash}"); + } var webhookType = DetermineWebhookType(data); @@ -66,6 +72,8 @@ public class TaigaWebHook : Controller case "task": await HandleTaskWebhook(data); break; + case "test": + return Ok("test success!"); default: _logger.LogWarning("Unsupported type of webhook: {WebhookType}", webhookType); return BadRequest($"Unsupported type of webhook: {webhookType}"); @@ -79,14 +87,13 @@ public class TaigaWebHook : Controller return BadRequest(exception.Message); } } - - private bool VerifySignature(string key, string data, string signature) + + private string VerifySignature(string key, string data) { - using HMACSHA1 hmac = new HMACSHA1(Encoding.UTF8.GetBytes(key)); - var hashBytes = hmac.ComputeHash(Encoding.UTF8.GetBytes(data)); - var computedHash = Convert.ToHexString(hashBytes).ToLower(); - - return computedHash.Length == signature.Length; + using var hmac = new HMACSHA1(Encoding.UTF8.GetBytes(key)); + var hashBytes = hmac.ComputeHash(Encoding.ASCII.GetBytes(data)); + var computedSignature = BitConverter.ToString(hashBytes).Replace("-", "").ToLowerInvariant(); + return computedSignature; } private async Task HandleUserStoryWebhook(string json) @@ -386,13 +393,13 @@ public class TaigaWebHook : Controller if (_logChannel == null) { - _logger.LogError("Не удалось получить Discord канал с ID: {ChannelId}", _id); + _logger.LogError("Can`t get channel with ID: {ChannelId}", _id); return; } await _logChannel.SendMessageAsync(embed: new EmbedBuilder() - .WithAuthor(payload.By.Username, payload.By.Photo) + .WithAuthor(payload.By.Username, payload.By.GravatarId != null ? "https://gravatar.com/avatar/" + payload.By.GravatarId : payload.By.Photo) .WithTitle($"{payload.Action} {payload.Type.ToLower()}") .WithDescription(payload.Description) .WithColor(payload.Color) diff --git a/Aoyo.Taiga/Dockerfile b/Aoyo.Taiga/Dockerfile index 678ee2e..4916a78 100644 --- a/Aoyo.Taiga/Dockerfile +++ b/Aoyo.Taiga/Dockerfile @@ -22,7 +22,7 @@ WORKDIR /app COPY --from=publish /app/publish . RUN apt-get update && \ apt-get install -y curl && \ - rm -rf /var/lib/apt/lists/* \ + rm -rf /var/lib/apt/lists/* HEALTHCHECK --interval=30s --timeout=3s --retries=3 CMD curl -f http://localhost:8080/aoyo/health || exit 1 diff --git a/Aoyo.Taiga/Program.cs b/Aoyo.Taiga/Program.cs index a587545..e57064a 100644 --- a/Aoyo.Taiga/Program.cs +++ b/Aoyo.Taiga/Program.cs @@ -9,6 +9,11 @@ public class Program WebHost. CreateDefaultBuilder(args). UseStartup(). + ConfigureAppConfiguration(k => + k. + AddJsonFile("appsettings.json"). + AddJsonFile("appsettings.Development.json"). + AddEnvironmentVariables()). UseKestrel( l => l.ListenAnyIP(8080) diff --git a/Aoyo.Taiga/WebHookTypes/TaigaUser.cs b/Aoyo.Taiga/WebHookTypes/TaigaUser.cs index ac6a0cc..61ae8aa 100644 --- a/Aoyo.Taiga/WebHookTypes/TaigaUser.cs +++ b/Aoyo.Taiga/WebHookTypes/TaigaUser.cs @@ -18,4 +18,6 @@ public class TaigaUser [JsonPropertyName("photo")] public string Photo { get; set; } + [JsonPropertyName("gravatar_id")] + public string? GravatarId { get; set; } } \ No newline at end of file diff --git a/Aoyo.Taiga/appsettings.Development.json b/Aoyo.Taiga/appsettings.Development.json index 0c208ae..b72378a 100644 --- a/Aoyo.Taiga/appsettings.Development.json +++ b/Aoyo.Taiga/appsettings.Development.json @@ -4,5 +4,12 @@ "Default": "Information", "Microsoft.AspNetCore": "Warning" } + }, + "Discord": { + "Token": "as", + "Id": 0 + }, + "Taiga": { + "Key": "123" } } diff --git a/compose.yaml b/compose.yaml new file mode 100644 index 0000000..9f616c6 --- /dev/null +++ b/compose.yaml @@ -0,0 +1,7 @@ +services: + aoyo.taiga: + image: aoyo.taiga + build: + context: . + dockerfile: Aoyo.Taiga/Dockerfile +