-
-
Notifications
You must be signed in to change notification settings - Fork 19
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Linking account with telegram (#2744)
* add fork of Telegram.Bot.Extensions.LoginWidget * modernize Telegram.Bot.Extensions.LoginWidget * Implement linking with telegram
- Loading branch information
Showing
26 changed files
with
552 additions
and
102 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,5 @@ | ||
Notifications__ServiceAccountEmail=support@dev.joinrpg.ru | ||
MailGun__ApiDomain=dev.joinrpg.ru | ||
MailGun__Enabled=true | ||
Telegram__BotName=joinrpg_bot | ||
Telegram__BotId=6987034096 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,5 @@ | ||
Notifications__ServiceAccountEmail=support@joinrpg.ru | ||
MailGun__ApiDomain=joinrpg.ru | ||
MailGun__Enabled=true | ||
Telegram__BotName=joinrpg_dev_bot | ||
Telegram__BotId=7431625317 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
10 changes: 10 additions & 0 deletions
10
src/JoinRpg.Portal/Infrastructure/Authentication/Telegram/TelegramAuthorizationResult.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
namespace JoinRpg.Portal.Infrastructure.Authentication.Telegram; | ||
|
||
public enum TelegramAuthorizationResult | ||
{ | ||
InvalidHash, | ||
MissingFields, | ||
InvalidAuthDateFormat, | ||
TooOld, | ||
Valid | ||
} |
12 changes: 12 additions & 0 deletions
12
src/JoinRpg.Portal/Infrastructure/Authentication/Telegram/TelegramLoginOptions.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
namespace JoinRpg.Portal.Infrastructure.Authentication.Telegram; | ||
public class TelegramLoginOptions | ||
{ | ||
public required string BotName { get; set; } | ||
public int BotId { get; set; } | ||
public required string BotSecret { get; set; } | ||
|
||
/// <summary> | ||
/// How old (in seconds) can authorization attempts be to be considered valid (compared to the auth_date field) | ||
/// </summary> | ||
public TimeSpan AllowedTimeOffset { get; set; } = TimeSpan.FromSeconds(30); | ||
} |
102 changes: 102 additions & 0 deletions
102
src/JoinRpg.Portal/Infrastructure/Authentication/Telegram/TelegramLoginValidator.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,102 @@ | ||
using System.Security.Cryptography; | ||
using System.Text; | ||
using Microsoft.Extensions.Options; | ||
|
||
namespace JoinRpg.Portal.Infrastructure.Authentication.Telegram; | ||
|
||
/// <summary> | ||
/// A helper class used to verify authorization data. | ||
/// Based on https://github.com/TelegramBots/Telegram.Bot.Extensions.LoginWidget/ | ||
/// </summary> | ||
/// <remarks> | ||
/// Construct a new <see cref="TelegramLoginValidator"/> instance | ||
/// </remarks> | ||
public class TelegramLoginValidator(IOptions<TelegramLoginOptions> options) | ||
{ | ||
private static readonly DateTime _unixStart = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc); | ||
|
||
/// <summary> | ||
/// Checks whether the authorization data received from the user is valid | ||
/// </summary> | ||
/// <param name="fields">A collection containing query string fields as sorted key-value pairs</param> | ||
/// <returns></returns> | ||
public TelegramAuthorizationResult CheckAuthorization(SortedDictionary<string, string> fields) | ||
{ | ||
ArgumentNullException.ThrowIfNull(fields); | ||
|
||
var _hmac = new HMACSHA256(SHA256.HashData(Encoding.ASCII.GetBytes(options.Value.BotId + ":" + options.Value.BotSecret))); | ||
|
||
if (!fields.ContainsKey(Field.Id) || | ||
!fields.TryGetValue(Field.AuthDate, out var authDate) || | ||
!fields.TryGetValue(Field.Hash, out var hash) | ||
) | ||
{ | ||
return TelegramAuthorizationResult.MissingFields; | ||
} | ||
|
||
if (hash.Length != 64) | ||
{ | ||
return TelegramAuthorizationResult.InvalidHash; | ||
} | ||
|
||
if (!long.TryParse(authDate, out var timestamp)) | ||
{ | ||
return TelegramAuthorizationResult.InvalidAuthDateFormat; | ||
} | ||
|
||
if (TimeSpan.FromSeconds(Math.Abs(DateTime.UtcNow.Subtract(_unixStart).TotalSeconds - timestamp)) > options.Value.AllowedTimeOffset) | ||
{ | ||
return TelegramAuthorizationResult.TooOld; | ||
} | ||
|
||
fields.Remove(Field.Hash); | ||
var dataStringBuilder = new StringBuilder(256); | ||
foreach (var field in fields) | ||
{ | ||
if (!string.IsNullOrEmpty(field.Value)) | ||
{ | ||
dataStringBuilder.Append(field.Key); | ||
dataStringBuilder.Append('='); | ||
dataStringBuilder.Append(field.Value); | ||
dataStringBuilder.Append('\n'); | ||
} | ||
} | ||
dataStringBuilder.Length -= 1; // Remove the last \n | ||
|
||
var signature = _hmac.ComputeHash(Encoding.UTF8.GetBytes(dataStringBuilder.ToString())); | ||
|
||
// Adapted from: https://stackoverflow.com/a/14333437/6845657 | ||
for (var i = 0; i < signature.Length; i++) | ||
{ | ||
if (hash[i * 2] != 87 + (signature[i] >> 4) + ((signature[i] >> 4) - 10 >> 31 & -39)) | ||
{ | ||
return TelegramAuthorizationResult.InvalidHash; | ||
} | ||
|
||
if (hash[i * 2 + 1] != 87 + (signature[i] & 0xF) + ((signature[i] & 0xF) - 10 >> 31 & -39)) | ||
{ | ||
return TelegramAuthorizationResult.InvalidHash; | ||
} | ||
} | ||
|
||
return TelegramAuthorizationResult.Valid; | ||
} | ||
|
||
/// <summary> | ||
/// Checks whether the authorization data received from the user is valid | ||
/// </summary> | ||
/// <param name="fields">A collection containing query string fields as key-value pairs</param> | ||
/// <returns></returns> | ||
public TelegramAuthorizationResult CheckAuthorization(Dictionary<string, string> fields) | ||
{ | ||
ArgumentNullException.ThrowIfNull(fields); | ||
return CheckAuthorization(new SortedDictionary<string, string>(fields, StringComparer.Ordinal)); | ||
} | ||
|
||
private static class Field | ||
{ | ||
public const string AuthDate = "auth_date"; | ||
public const string Id = "id"; | ||
public const string Hash = "hash"; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.