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
+