get-telegram-backup-ip.ts 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110
  1. // https://reserve-5a846.firebaseio.com/ipconfigv3.json
  2. // apv3.stel.com tapv3.stel.com
  3. import { Buffer } from 'node:buffer';
  4. import crypto from 'node:crypto';
  5. import { Api, extensions as TgExtensions } from 'telegram';
  6. import { bigint2ip } from 'fast-cidr-tools';
  7. import { base64ToUint8Array, concatUint8Arrays } from 'foxts/uint8array-utils';
  8. const mtptoto_public_rsa = `-----BEGIN RSA PUBLIC KEY-----
  9. MIIBCgKCAQEAyr+18Rex2ohtVy8sroGP
  10. BwXD3DOoKCSpjDqYoXgCqB7ioln4eDCFfOBUlfXUEvM/fnKCpF46VkAftlb4VuPD
  11. eQSS/ZxZYEGqHaywlroVnXHIjgqoxiAd192xRGreuXIaUKmkwlM9JID9WS2jUsTp
  12. zQ91L8MEPLJ/4zrBwZua8W5fECwCCh2c9G5IzzBm+otMS/YKwmR1olzRCyEkyAEj
  13. XWqBI9Ftv5eG8m0VkBzOG655WIYdyV0HfDK/NWcvGqa0w/nriMD6mDjKOryamw0O
  14. P9QuYgMN0C9xMW9y8SmP4h92OAWodTYgY1hZCxdv6cs5UnW9+PWvS+WIbkh+GaWY
  15. xwIDAQAB
  16. -----END RSA PUBLIC KEY-----
  17. `;
  18. export function getTelegramBackupIPFromBase64(base64: string) {
  19. // 1. Check base64 size
  20. if (base64.length !== 344) {
  21. throw new TypeError('Invalid base64 length');
  22. }
  23. // 2. Filter to base64 and check length
  24. // Not needed with Buffer.from
  25. // 3. Decode base64 to Buffer
  26. const decoded = base64ToUint8Array(base64);
  27. if (decoded.length !== 256) {
  28. throw new TypeError('Decoded buffer length is not 344 bytes, received ' + decoded.length);
  29. }
  30. // 4. RSA decrypt (public key, "decrypt signature" - usually means "verify and extract")
  31. // In Node.js, publicDecrypt is used for signature verification (Note that no padding is needed)
  32. const publicKey = crypto.createPublicKey(mtptoto_public_rsa);
  33. const decrypted = crypto.publicDecrypt(
  34. {
  35. key: publicKey,
  36. padding: crypto.constants.RSA_NO_PADDING
  37. },
  38. decoded
  39. );
  40. // 5. Extract AES key/iv and encrypted payload
  41. const key = decrypted.subarray(0, 32);
  42. const iv = decrypted.subarray(16, 32);
  43. const dataCbc = decrypted.subarray(32); // 224 bytes
  44. if (dataCbc.length !== 224) {
  45. throw new Error(`Invalid AES payload length: ${dataCbc.length}`);
  46. }
  47. // 6. AES-CBC decrypt
  48. const decipher = crypto.createDecipheriv('aes-256-cbc', key, iv);
  49. decipher.setAutoPadding(false);
  50. const decryptedCbc = concatUint8Arrays([decipher.update(dataCbc), decipher.final()]);
  51. if (decryptedCbc.length !== 224) {
  52. throw new Error(`Decrypted AES payload length is not 224 bytes, received ${decryptedCbc.length}`);
  53. }
  54. // 7. SHA256 check
  55. const currentHash = crypto
  56. .createHash('sha256')
  57. .update(decryptedCbc.subarray(0, 208))
  58. .digest()
  59. .subarray(0, 16);
  60. const expectedHash = decryptedCbc.subarray(208, 224);
  61. // check if hash matches
  62. if (!currentHash.equals(expectedHash)) {
  63. throw new Error('SHA256 hash mismatch');
  64. }
  65. const parser = new TgExtensions.BinaryReader(Buffer.from(decryptedCbc));
  66. const len = parser.readInt();
  67. if (len < 8 || len > 208) throw new Error(`Invalid TL data length: ${len}`);
  68. const constructorId = parser.readInt();
  69. if (constructorId !== Api.help.ConfigSimple.CONSTRUCTOR_ID) {
  70. throw new Error(`Invalid constructor ID: ${constructorId.toString(16)}`);
  71. }
  72. const payload = decryptedCbc.subarray(8, len);
  73. const configSimple = Api.help.ConfigSimple.fromReader(new TgExtensions.BinaryReader(Buffer.from(payload)));
  74. return configSimple.rules.flatMap(rule => rule.ips.map(ip => {
  75. switch (ip.CONSTRUCTOR_ID) {
  76. case Api.IpPort.CONSTRUCTOR_ID:
  77. case Api.IpPortSecret.CONSTRUCTOR_ID:
  78. return {
  79. ip: bigint2ip(
  80. ip.ipv4 > 0
  81. ? BigInt(ip.ipv4)
  82. : (2n ** 32n) + BigInt(ip.ipv4),
  83. 4
  84. ),
  85. port: ip.port
  86. };
  87. default:
  88. throw new TypeError(`Unknown IP type: 0x${ip.CONSTRUCTOR_ID.toString(16)}`);
  89. }
  90. }));
  91. }