Created
December 27, 2024 14:34
-
-
Save btspoony/f27dd2377d378ed579172548eae4f538 to your computer and use it in GitHub Desktop.
Telegram initData verifier
This file contains hidden or 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
import { | |
charStringToUint8Array, | |
hexStringToUint8Array, | |
} from './utilities.ts'; | |
import nacl from 'tweetnacl'; | |
import { atob } from 'js-base64'; | |
export function parseQueryStr(initData: string): Record<string, string> { | |
const data = initData || import.meta.env.PUBLIC_TELEGRAM_USER_DATA; // For test using PUBLIC_TELEGRAM_USER_DATA env | |
const result: Record<string, string> = {}; | |
const params = data.split('&'); | |
for (const param of params) { | |
const [key, value] = param.split('='); | |
result[key] = | |
key === 'hash' || key === 'signature' ? value : decodeURIComponent(value); | |
} | |
return result; | |
} | |
export function verifyFromThirdParty(obj: Record<string, string>): boolean { | |
if (typeof obj.signature !== 'string') { | |
return false; | |
} | |
const urlParams: string[] = []; | |
for (const key in obj) { | |
if (key !== 'hash' && key !== 'signature') { | |
urlParams.push(`${key}=${obj[key]}`); | |
} | |
} | |
urlParams.sort(); | |
const urlStr = urlParams.join('\n'); | |
const botId = import.meta.env.PUBLIC_TELEGRAM_BOT_ID; | |
const checkString = `${botId}:WebAppData\n${urlStr}`; | |
const telegramPublicKey = | |
'e7bf03a2fa4602af4580703d88dda5bb59f32ed8b02a56c187fe7d34caed242d'; // Telegram's public key for production | |
// const telegramPublicKey = | |
// '40055058a4ee38156a06562e52eece92a771bcd8346a8c4615cb7376eddf72ec'; // Telegram's public key for telegram test environment | |
const sig = base64UrlDecode(obj.signature); | |
const message = new TextEncoder().encode(checkString); | |
const signatureUint8Array = charStringToUint8Array(sig); | |
const publicKeyUint8Array = hexStringToUint8Array(telegramPublicKey); | |
let isValid = false; | |
try { | |
isValid = nacl.sign.detached.verify( | |
message, | |
signatureUint8Array, | |
publicKeyUint8Array | |
); | |
} catch (error) { | |
console.error(error); | |
} | |
return isValid; | |
} | |
function base64UrlDecode(str: string) { | |
console.log('Original', str); | |
str = str.replace(/-/g, '+').replace(/_/g, '/'); | |
while (str.length % 4) { | |
str += '='; | |
} | |
console.log('Base64UrlDecode', str); | |
return atob(str); | |
} |
This file contains hidden or 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
export function hexStringToUint8Array(hex: string) { | |
if (hex.length % 2 !== 0) { | |
throw new Error('Invalid hex string'); | |
} | |
const byteArray = new Uint8Array(hex.length / 2); | |
for (let i = 0; i < hex.length; i += 2) { | |
byteArray[i / 2] = parseInt(hex.substring(i, i + 2), 16); | |
} | |
return byteArray; | |
} | |
export function charStringToUint8Array(str: string) { | |
const byteArray = new Uint8Array(str.length); | |
for (let i = 0; i < str.length; i++) { | |
byteArray[i] = str.charCodeAt(i); | |
} | |
return byteArray; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
| How to use
set
PUBLIC_TELEGRAM_BOT_ID
, which is the number before:
in your telegram bot token.