110 lines
3.7 KiB
C#
110 lines
3.7 KiB
C#
using System.Security.Cryptography;
|
|
using System.Text;
|
|
using GmRelay.Web.Services;
|
|
using Microsoft.AspNetCore.Http;
|
|
using Microsoft.Extensions.Configuration;
|
|
using Microsoft.Extensions.Primitives;
|
|
|
|
namespace GmRelay.Bot.Tests.Web;
|
|
|
|
public sealed class TelegramAuthServiceTests
|
|
{
|
|
[Fact]
|
|
public void Verify_ShouldAcceptValidTelegramPayload()
|
|
{
|
|
const string botToken = "test-bot-token";
|
|
var authDate = DateTimeOffset.UtcNow.ToUnixTimeSeconds().ToString();
|
|
var query = CreateQueryCollection(
|
|
botToken,
|
|
new Dictionary<string, string>
|
|
{
|
|
["auth_date"] = authDate,
|
|
["first_name"] = "Ada",
|
|
["id"] = "424242",
|
|
["last_name"] = "Lovelace",
|
|
["username"] = "ada"
|
|
});
|
|
var service = new TelegramAuthService(CreateConfiguration(botToken));
|
|
|
|
var verified = service.Verify(query, out var telegramId, out var name);
|
|
|
|
Assert.True(verified);
|
|
Assert.Equal(424242L, telegramId);
|
|
Assert.Equal("Ada Lovelace", name);
|
|
}
|
|
|
|
[Fact]
|
|
public void Verify_ShouldRejectTamperedHash()
|
|
{
|
|
const string botToken = "test-bot-token";
|
|
var values = new Dictionary<string, string>
|
|
{
|
|
["auth_date"] = DateTimeOffset.UtcNow.ToUnixTimeSeconds().ToString(),
|
|
["first_name"] = "Ada",
|
|
["id"] = "424242"
|
|
};
|
|
var query = CreateQueryCollection(botToken, values);
|
|
var invalidQuery = new QueryCollection(new Dictionary<string, StringValues>(query.ToDictionary(
|
|
pair => pair.Key,
|
|
pair => pair.Value))
|
|
{
|
|
["hash"] = "00"
|
|
});
|
|
var service = new TelegramAuthService(CreateConfiguration(botToken));
|
|
|
|
var verified = service.Verify(invalidQuery, out _, out _);
|
|
|
|
Assert.False(verified);
|
|
}
|
|
|
|
[Fact]
|
|
public void Verify_ShouldRejectExpiredPayload()
|
|
{
|
|
const string botToken = "test-bot-token";
|
|
var expiredAuthDate = DateTimeOffset.UtcNow.AddDays(-2).ToUnixTimeSeconds().ToString();
|
|
var query = CreateQueryCollection(
|
|
botToken,
|
|
new Dictionary<string, string>
|
|
{
|
|
["auth_date"] = expiredAuthDate,
|
|
["first_name"] = "Ada",
|
|
["id"] = "424242"
|
|
});
|
|
var service = new TelegramAuthService(CreateConfiguration(botToken));
|
|
|
|
var verified = service.Verify(query, out _, out _);
|
|
|
|
Assert.False(verified);
|
|
}
|
|
|
|
private static IConfiguration CreateConfiguration(string botToken) =>
|
|
new ConfigurationBuilder()
|
|
.AddInMemoryCollection(new Dictionary<string, string?>
|
|
{
|
|
["Telegram:BotToken"] = botToken
|
|
})
|
|
.Build();
|
|
|
|
private static QueryCollection CreateQueryCollection(string botToken, Dictionary<string, string> values)
|
|
{
|
|
var hash = ComputeTelegramHash(botToken, values);
|
|
var queryValues = values.ToDictionary(
|
|
pair => pair.Key,
|
|
pair => new StringValues(pair.Value));
|
|
queryValues["hash"] = new StringValues(hash);
|
|
return new QueryCollection(queryValues);
|
|
}
|
|
|
|
private static string ComputeTelegramHash(string botToken, IReadOnlyDictionary<string, string> values)
|
|
{
|
|
var dataCheckString = string.Join(
|
|
"\n",
|
|
values
|
|
.OrderBy(pair => pair.Key, StringComparer.Ordinal)
|
|
.Select(pair => $"{pair.Key}={pair.Value}"));
|
|
var secretKey = SHA256.HashData(Encoding.UTF8.GetBytes(botToken));
|
|
var hashBytes = HMACSHA256.HashData(secretKey, Encoding.UTF8.GetBytes(dataCheckString));
|
|
return Convert.ToHexString(hashBytes).ToLowerInvariant();
|
|
}
|
|
}
|