mnemo_cards/mnemo_cards_backend/lib/user/telegram.dart

108 lines
3.3 KiB
Dart
Raw Normal View History

2025-11-16 11:25:27 +00:00
import 'dart:convert';
import 'dart:developer';
import 'package:crypto/crypto.dart' as crypto;
2025-12-02 23:17:15 +00:00
import 'package:http/http.dart' as http;
2025-11-16 11:25:27 +00:00
class TelegramUtils {
static const _botToken = '7057032753:AAFP-BCpdry-YuBUOqx1W8dGxiFQdSOJlpI';
/// Validates the data received from the Telegram web app
/// Following the Python implementation exactly
bool checkValidateInitData(String hashStr, String initData, String token,
{String cStr = "WebAppData"}) {
try {
// Decode URL-encoded string
final decodedData = Uri.decodeComponent(initData);
// Split into chunks and filter out hash parameter
final chunks = decodedData
.split('&')
.where((chunk) => !chunk.startsWith('hash='))
.map((chunk) => chunk.split('='))
.toList();
// Sort by first element (key)
chunks.sort((a, b) => a[0].compareTo(b[0]));
// Create data string with newline separator
final dataString = chunks.map((rec) => '${rec[0]}=${rec[1]}').join('\n');
// Create secret key: HMAC_SHA256(cStr, token)
final secretKey = crypto.Hmac(crypto.sha256, utf8.encode(cStr))
.convert(utf8.encode(token));
// Create data check hash: HMAC_SHA256(secretKey, dataString)
final dataCheck = crypto.Hmac(crypto.sha256, secretKey.bytes)
.convert(utf8.encode(dataString));
// Compare hex digests
return dataCheck.toString() == hashStr;
} catch (e) {
return false;
}
}
2025-11-27 21:58:56 +00:00
Future<({String id, String? username})?> getUserId(String initialData) async {
2025-11-16 11:25:27 +00:00
try {
final tgWebAppData = Uri.decodeComponent(initialData);
// Extract hash from the data
final hashMatch = RegExp(r'hash=([^&]+)').firstMatch(tgWebAppData);
if (hashMatch == null) {
return null;
}
final hash = hashMatch.group(1)!;
// Validate using the new method
if (!checkValidateInitData(hash, tgWebAppData, _botToken)) {
return null;
}
// Extract user ID from user parameter
final userMatch = RegExp(r'user=([^&]+)').firstMatch(tgWebAppData);
if (userMatch == null) {
return null;
}
final userJson = Uri.decodeComponent(userMatch.group(1)!);
final userData = jsonDecode(userJson) as Map<String, dynamic>;
final userId = userData['id']?.toString();
2025-11-27 21:58:56 +00:00
final username = userData['username']?.toString();
if (userId == null) {
return null;
}
return (id: userId, username: username);
2025-11-16 11:25:27 +00:00
} catch (e) {
return null;
}
}
2025-12-02 23:17:15 +00:00
/// Send message to admin via Telegram Bot API
2025-12-11 19:00:11 +00:00
static Future<bool> sendMessageToAdmin(
String telegramUserId, String message) async {
2025-12-02 23:17:15 +00:00
try {
2025-12-11 19:00:11 +00:00
final url =
Uri.parse('https://api.telegram.org/bot$_botToken/sendMessage');
2025-12-02 23:17:15 +00:00
final response = await http.post(
url,
headers: {'Content-Type': 'application/json'},
body: jsonEncode({
'chat_id': telegramUserId,
'text': message,
'parse_mode': 'HTML',
}),
);
if (response.statusCode == 200) {
final data = jsonDecode(response.body);
return data['ok'] == true;
}
log('Failed to send Telegram message: ${response.statusCode} ${response.body}');
return false;
} catch (e) {
log('Error sending Telegram message: $e');
return false;
}
}
2025-11-16 11:25:27 +00:00
}