fix: stabilize mini app login and safe area
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
using System.Security.Cryptography;
|
||||
using System.Text;
|
||||
using System.Text.Json;
|
||||
using System.Text.Json.Serialization;
|
||||
using Microsoft.AspNetCore.WebUtilities;
|
||||
|
||||
namespace GmRelay.Web.Services;
|
||||
@@ -113,6 +114,69 @@ public sealed class TelegramAuthService(IConfiguration configuration)
|
||||
return TryReadWebAppUser(userJson.ToString(), out telegramId, out name);
|
||||
}
|
||||
|
||||
public bool VerifyLoginPayload(TelegramLoginPayload payload, out long telegramId, out string name)
|
||||
{
|
||||
telegramId = 0;
|
||||
name = string.Empty;
|
||||
|
||||
if (payload.Id <= 0 ||
|
||||
string.IsNullOrWhiteSpace(payload.FirstName) ||
|
||||
payload.AuthDate <= 0 ||
|
||||
string.IsNullOrWhiteSpace(payload.Hash))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
var token = configuration["Telegram__BotToken"] ?? configuration["Telegram:BotToken"];
|
||||
if (string.IsNullOrEmpty(token))
|
||||
return false;
|
||||
|
||||
var values = new SortedDictionary<string, string>(StringComparer.Ordinal)
|
||||
{
|
||||
["auth_date"] = payload.AuthDate.ToString(System.Globalization.CultureInfo.InvariantCulture),
|
||||
["first_name"] = payload.FirstName,
|
||||
["id"] = payload.Id.ToString(System.Globalization.CultureInfo.InvariantCulture)
|
||||
};
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(payload.LastName))
|
||||
values["last_name"] = payload.LastName;
|
||||
if (!string.IsNullOrWhiteSpace(payload.PhotoUrl))
|
||||
values["photo_url"] = payload.PhotoUrl;
|
||||
if (!string.IsNullOrWhiteSpace(payload.Username))
|
||||
values["username"] = payload.Username;
|
||||
|
||||
var dataCheckString = string.Join("\n", values.Select(pair => $"{pair.Key}={pair.Value}"));
|
||||
var secretKey = SHA256.HashData(Encoding.UTF8.GetBytes(token));
|
||||
var computedHashBytes = HMACSHA256.HashData(secretKey, Encoding.UTF8.GetBytes(dataCheckString));
|
||||
|
||||
byte[] hashBytes;
|
||||
try
|
||||
{
|
||||
hashBytes = Convert.FromHexString(payload.Hash);
|
||||
}
|
||||
catch (FormatException)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
catch (ArgumentException)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!CryptographicOperations.FixedTimeEquals(computedHashBytes, hashBytes))
|
||||
return false;
|
||||
|
||||
var now = DateTimeOffset.UtcNow.ToUnixTimeSeconds();
|
||||
if (now - payload.AuthDate > 86400)
|
||||
return false;
|
||||
|
||||
telegramId = payload.Id;
|
||||
name = string.IsNullOrWhiteSpace(payload.LastName)
|
||||
? payload.FirstName
|
||||
: $"{payload.FirstName} {payload.LastName}";
|
||||
return true;
|
||||
}
|
||||
|
||||
private static bool TryReadWebAppUser(string userJson, out long telegramId, out string name)
|
||||
{
|
||||
telegramId = 0;
|
||||
@@ -152,3 +216,12 @@ public sealed class TelegramAuthService(IConfiguration configuration)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public sealed record TelegramLoginPayload(
|
||||
[property: JsonPropertyName("id")] long Id,
|
||||
[property: JsonPropertyName("first_name")] string FirstName,
|
||||
[property: JsonPropertyName("last_name")] string? LastName,
|
||||
[property: JsonPropertyName("username")] string? Username,
|
||||
[property: JsonPropertyName("photo_url")] string? PhotoUrl,
|
||||
[property: JsonPropertyName("auth_date")] long AuthDate,
|
||||
[property: JsonPropertyName("hash")] string Hash);
|
||||
|
||||
Reference in New Issue
Block a user