1
0

Helpers.js 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130
  1. const crypto = require('crypto');
  2. const fs = require("fs").promises;
  3. class Helpers {
  4. /**
  5. * Generates a random long integer (8 bytes), which is optionally signed
  6. * @returns {number}
  7. */
  8. static generateRandomLong() {
  9. let buf = Buffer.from(this.generateRandomBytes(8)); // 0x12345678 = 305419896
  10. return buf.readUInt32BE(0);
  11. }
  12. /**
  13. * Generates a random bytes array
  14. * @param count
  15. * @returns {Buffer}
  16. */
  17. static generateRandomBytes(count) {
  18. return crypto.randomBytes(count);
  19. }
  20. /**
  21. * Loads the user settings located under `api/`
  22. * @param path
  23. * @returns {Promise<void>}
  24. */
  25. static async loadSettings(path = "../api/settings") {
  26. let settings = {};
  27. let left, right, value_pair;
  28. let data = await fs.readFile(path, 'utf-8');
  29. for (let line of data.toString().split('\n')) {
  30. value_pair = line.split("=");
  31. if (value_pair.length !== 2) {
  32. break;
  33. }
  34. left = value_pair[0].replace(/ \r?\n|\r/g, '');
  35. right = value_pair[1].replace(/ \r?\n|\r/g, '');
  36. if (!isNaN(right)) {
  37. settings[left] = Number.parseInt(right);
  38. } else {
  39. settings[left] = right;
  40. }
  41. }
  42. return settings;
  43. }
  44. /**
  45. * Calculate the key based on Telegram guidelines, specifying whether it's the client or not
  46. * @param shared_key
  47. * @param msg_key
  48. * @param client
  49. * @returns {[*, *]}
  50. */
  51. static calcKey(shared_key, msg_key, client) {
  52. let x = client !== null ? 0 : 8;
  53. let iv, key, sha1a, sha1b, sha1c, sha1d;
  54. sha1a = this.sha1((msg_key + shared_key.slice(x, (x + 32))));
  55. sha1b = this.sha1(((shared_key.slice((x + 32), (x + 48)) + msg_key) + shared_key.slice((x + 48), (x + 64))));
  56. sha1c = this.sha1((shared_key.slice((x + 64), (x + 96)) + msg_key));
  57. sha1d = this.sha1((msg_key + shared_key.slice((x + 96), (x + 128))));
  58. key = ((sha1a.slice(0, 8) + sha1b.slice(8, 20)) + sha1c.slice(4, 16));
  59. iv = (((sha1a.slice(8, 20) + sha1b.slice(0, 8)) + sha1c.slice(16, 20)) + sha1d.slice(0, 8));
  60. return [key, iv];
  61. }
  62. /**
  63. * Calculates the message key from the given data
  64. * @param data
  65. * @returns {Buffer}
  66. */
  67. static calcMsgKey(data) {
  68. return this.sha1(data).slice(4, 20);
  69. }
  70. /**
  71. * Generates the key data corresponding to the given nonces
  72. * @param serverNonce
  73. * @param newNonce
  74. * @returns {{ivBuffer: Buffer, keyBuffer: Buffer}}
  75. */
  76. static generateKeyDataFromNonces(serverNonce, newNonce) {
  77. let hash1 = this.sha1(Buffer.concat([newNonce, serverNonce]));
  78. let hash2 = this.sha1(Buffer.concat([serverNonce, newNonce]));
  79. let hash3 = this.sha1(Buffer.concat([newNonce, newNonce]));
  80. let keyBuffer = Buffer.concat([hash1, hash1.slice(0, 12)]);
  81. let ivBuffer = Buffer.concat([hash2.slice(12, 20), hash3, newNonce.slice(0, 4)]);
  82. return {keyBuffer: keyBuffer, ivBuffer: ivBuffer}
  83. }
  84. /**
  85. * Calculates the SHA1 digest for the given data
  86. * @param data
  87. * @returns {Buffer}
  88. */
  89. static sha1(data) {
  90. let shaSum = crypto.createHash('sha1');
  91. shaSum.update(data);
  92. return shaSum.digest();
  93. }
  94. /**
  95. * returns a random int from min (inclusive) and max (inclusive)
  96. * @param min
  97. * @param max
  98. * @returns {number}
  99. */
  100. static getRandomInt(min, max) {
  101. min = Math.ceil(min);
  102. max = Math.floor(max);
  103. return Math.floor(Math.random() * (max - min + 1)) + min;
  104. }
  105. }
  106. exports.helpers = Helpers;