stuff
Some checks are pending
Backend CI / test (push) Waiting to run
Backend CI / build (push) Blocked by required conditions
Deploy Mnemo Cards / Deploy Backend (push) Waiting to run
Deploy Mnemo Cards / Deploy Web App (push) Blocked by required conditions
Deploy Mnemo Cards / Final Verification (push) Blocked by required conditions
Some checks are pending
Backend CI / test (push) Waiting to run
Backend CI / build (push) Blocked by required conditions
Deploy Mnemo Cards / Deploy Backend (push) Waiting to run
Deploy Mnemo Cards / Deploy Web App (push) Blocked by required conditions
Deploy Mnemo Cards / Final Verification (push) Blocked by required conditions
This commit is contained in:
parent
5ab6ba9705
commit
79692cf6f9
2 changed files with 37 additions and 5 deletions
|
|
@ -238,21 +238,29 @@ class AuthApiV2 {
|
||||||
Future<Response> authenticateTelegramWebApp(Request request) async {
|
Future<Response> authenticateTelegramWebApp(Request request) async {
|
||||||
try {
|
try {
|
||||||
final body = await request.readAsString();
|
final body = await request.readAsString();
|
||||||
|
log('Telegram Web App auth request body: ${body.length} chars', name: 'AuthApiV2');
|
||||||
|
|
||||||
final json = jsonDecode(body) as Map<String, dynamic>;
|
final json = jsonDecode(body) as Map<String, dynamic>;
|
||||||
final initData = json['initData'] as String?;
|
final initData = json['initData'] as String?;
|
||||||
|
|
||||||
if (initData == null || initData.isEmpty) {
|
if (initData == null || initData.isEmpty) {
|
||||||
|
log('Telegram Web App auth: initData is null or empty', name: 'AuthApiV2');
|
||||||
return _badRequest('Telegram Web App init data is required');
|
return _badRequest('Telegram Web App init data is required');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
log('Telegram Web App auth: initData received, length: ${initData.length}', name: 'AuthApiV2');
|
||||||
|
|
||||||
// Use the existing telegram utils to get user ID
|
// Use the existing telegram utils to get user ID
|
||||||
final telegramUtils = TelegramUtils();
|
final telegramUtils = TelegramUtils();
|
||||||
final userData = await telegramUtils.getUserId(initData);
|
final userData = await telegramUtils.getUserId(initData);
|
||||||
|
|
||||||
if (userData == null) {
|
if (userData == null) {
|
||||||
return _badRequest('Invalid Telegram Web App data');
|
log('Telegram Web App auth: getUserId returned null - validation failed', name: 'AuthApiV2');
|
||||||
|
return _badRequest('Invalid Telegram Web App data: validation failed');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
log('Telegram Web App auth: userData extracted, userId: ${userData.id}', name: 'AuthApiV2');
|
||||||
|
|
||||||
// Find or create user based on telegram user ID
|
// Find or create user based on telegram user ID
|
||||||
var (user, _) = await _userManager.createOrGetUser(
|
var (user, _) = await _userManager.createOrGetUser(
|
||||||
externalId: userData.id,
|
externalId: userData.id,
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,8 @@ class TelegramUtils {
|
||||||
|
|
||||||
/// Validates the data received from the Telegram web app
|
/// Validates the data received from the Telegram web app
|
||||||
/// Following the Python implementation exactly
|
/// Following the Python implementation exactly
|
||||||
|
///
|
||||||
|
/// [initData] should be URL-encoded (as received from Telegram Web App)
|
||||||
bool checkValidateInitData(String hashStr, String initData, String token,
|
bool checkValidateInitData(String hashStr, String initData, String token,
|
||||||
{String cStr = "WebAppData"}) {
|
{String cStr = "WebAppData"}) {
|
||||||
try {
|
try {
|
||||||
|
|
@ -35,30 +37,49 @@ class TelegramUtils {
|
||||||
final dataCheck = crypto.Hmac(crypto.sha256, secretKey.bytes)
|
final dataCheck = crypto.Hmac(crypto.sha256, secretKey.bytes)
|
||||||
.convert(utf8.encode(dataString));
|
.convert(utf8.encode(dataString));
|
||||||
|
|
||||||
|
final calculatedHash = dataCheck.toString();
|
||||||
|
final isValid = calculatedHash == hashStr;
|
||||||
|
|
||||||
|
if (!isValid) {
|
||||||
|
log('checkValidateInitData: hash mismatch. Expected: ${hashStr.substring(0, hashStr.length > 20 ? 20 : hashStr.length)}..., Got: ${calculatedHash.substring(0, calculatedHash.length > 20 ? 20 : calculatedHash.length)}...');
|
||||||
|
}
|
||||||
|
|
||||||
// Compare hex digests
|
// Compare hex digests
|
||||||
return dataCheck.toString() == hashStr;
|
return isValid;
|
||||||
} catch (e) {
|
} catch (e, s) {
|
||||||
|
log('checkValidateInitData error: $e', error: e, stackTrace: s);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<({String id, String? username})?> getUserId(String initialData) async {
|
Future<({String id, String? username})?> getUserId(String initialData) async {
|
||||||
try {
|
try {
|
||||||
|
log('getUserId: initialData length: ${initialData.length}');
|
||||||
final tgWebAppData = Uri.decodeComponent(initialData);
|
final tgWebAppData = Uri.decodeComponent(initialData);
|
||||||
|
log('getUserId: decoded data length: ${tgWebAppData.length}');
|
||||||
|
|
||||||
// Extract hash from the data
|
// Extract hash from the data
|
||||||
final hashMatch = RegExp(r'hash=([^&]+)').firstMatch(tgWebAppData);
|
final hashMatch = RegExp(r'hash=([^&]+)').firstMatch(tgWebAppData);
|
||||||
if (hashMatch == null) {
|
if (hashMatch == null) {
|
||||||
|
log('getUserId: hash not found in data');
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
final hash = hashMatch.group(1)!;
|
final hash = hashMatch.group(1)!;
|
||||||
|
log('getUserId: hash extracted: ${hash.substring(0, hash.length > 20 ? 20 : hash.length)}...');
|
||||||
|
|
||||||
// Validate using the new method
|
// Validate using the new method
|
||||||
if (!checkValidateInitData(hash, tgWebAppData, _botToken)) {
|
// Note: checkValidateInitData expects the original URL-encoded data
|
||||||
|
// (as received from Telegram Web App), so we pass initialData, not tgWebAppData
|
||||||
|
if (!checkValidateInitData(hash, initialData, _botToken)) {
|
||||||
|
log('getUserId: validation failed');
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
log('getUserId: validation passed');
|
||||||
|
|
||||||
// Extract user ID from user parameter
|
// Extract user ID from user parameter
|
||||||
final userMatch = RegExp(r'user=([^&]+)').firstMatch(tgWebAppData);
|
final userMatch = RegExp(r'user=([^&]+)').firstMatch(tgWebAppData);
|
||||||
if (userMatch == null) {
|
if (userMatch == null) {
|
||||||
|
log('getUserId: user parameter not found');
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -67,10 +88,13 @@ class TelegramUtils {
|
||||||
final userId = userData['id']?.toString();
|
final userId = userData['id']?.toString();
|
||||||
final username = userData['username']?.toString();
|
final username = userData['username']?.toString();
|
||||||
if (userId == null) {
|
if (userId == null) {
|
||||||
|
log('getUserId: user ID is null in user data');
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
log('getUserId: successfully extracted userId: $userId');
|
||||||
return (id: userId, username: username);
|
return (id: userId, username: username);
|
||||||
} catch (e) {
|
} catch (e, s) {
|
||||||
|
log('getUserId error: $e', error: e, stackTrace: s);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue