root.js 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568
  1. /*
  2. ©️ Dan Gazizullin, 2021-2023
  3. This file is a part of Hikka Userbot
  4. 🌐 https://github.com/hikariatama/Hikka
  5. You can redistribute it and/or modify it under the terms of the GNU AGPLv3
  6. 🔑 https://www.gnu.org/licenses/agpl-3.0.html
  7. */
  8. function auth(callback) {
  9. $(".main").fadeOut(250);
  10. setTimeout(() => {
  11. $(".auth").hide().fadeIn(250, () => {
  12. $("#tg_icon").html("");
  13. bodymovin.loadAnimation({
  14. container: document.getElementById("tg_icon"),
  15. renderer: "canvas",
  16. loop: true,
  17. autoplay: true,
  18. path: "https://assets9.lottiefiles.com/packages/lf20_bgqoyj8l.json",
  19. rendererSettings: {
  20. clearCanvas: true,
  21. }
  22. });
  23. });
  24. fetch("/web_auth", {
  25. method: "POST",
  26. credentials: "include",
  27. timeout: 250000
  28. })
  29. .then(response => response.text())
  30. .then((response) => {
  31. if (response == "TIMEOUT") {
  32. error_message("Code waiting timeout exceeded. Reload page and try again.");
  33. $(".auth").fadeOut(250);
  34. return
  35. }
  36. if (response.startsWith("hikka_")) {
  37. $.cookie("session", response)
  38. auth_required = false;
  39. $(".authorized").hide().fadeIn(100);
  40. $(".auth").fadeOut(250, () => {
  41. $(".installation").fadeIn(250);
  42. });
  43. callback();
  44. return;
  45. }
  46. })
  47. }, 250);
  48. }
  49. var qr_interval = null;
  50. var qr_login = false;
  51. var old_qr_sizes = [
  52. document.querySelector(".qr_inner").style.width,
  53. document.querySelector(".qr_inner").style.height,
  54. ]
  55. document.querySelector(".qr_inner").style.width = "100px";
  56. document.querySelector(".qr_inner").style.height = "100px";
  57. $("#get_started")
  58. .click(() => {
  59. fetch("/can_add", {
  60. method: "POST",
  61. credentials: "include"
  62. }).then((response) => {
  63. if (!response.ok) {
  64. show_eula();
  65. return;
  66. }
  67. if (auth_required) return auth(() => {
  68. $("#get_started").click();
  69. });
  70. $("continue_btn").hide().fadeIn(250);
  71. $("#enter_api").fadeOut(250);
  72. $("#get_started").fadeOut(250, () => {
  73. if (_current_block == "phone") {
  74. switch_block(_current_block);
  75. $("#continue_btn").hide().fadeIn(250);
  76. return;
  77. }
  78. switch_block(_current_block);
  79. $("#denyqr").hide().fadeIn(250);
  80. $(".title, .description").fadeOut(250);
  81. // bodymovin.loadAnimation({
  82. // container: document.querySelector(".qr_inner"),
  83. // renderer: "canvas",
  84. // loop: true,
  85. // autoplay: true,
  86. // path: "https://static.hikari.gay/4T7FajtZbx.json",
  87. // rendererSettings: {
  88. // clearCanvas: true,
  89. // }
  90. // });
  91. fetch("/init_qr_login", {
  92. method: "POST",
  93. credentials: "include"
  94. })
  95. .then(response => response.text())
  96. .then((response) => {
  97. const qrCode = new QRCodeStyling({
  98. width: window.innerHeight / 3,
  99. height: window.innerHeight / 3,
  100. type: "svg",
  101. data: response,
  102. dotsOptions: {
  103. type: "rounded"
  104. },
  105. cornersSquareOptions: {
  106. type: "extra-rounded",
  107. },
  108. backgroundOptions: {
  109. color: "transparent",
  110. },
  111. imageOptions: {
  112. imageSize: 0.4,
  113. margin: 8,
  114. },
  115. qrOptions: {
  116. errorCorrectionLevel: "M",
  117. },
  118. });
  119. document.querySelector(".qr_inner").innerHTML = "";
  120. document.querySelector(".qr_inner").style.width = old_qr_sizes[0];
  121. document.querySelector(".qr_inner").style.height = old_qr_sizes[1];
  122. qrCode.append(document.querySelector(".qr_inner"));
  123. qr_interval = setInterval(() => {
  124. fetch("/get_qr_url", {
  125. method: "POST",
  126. credentials: "include"
  127. })
  128. .then(response => response.text())
  129. .then((response) => {
  130. if (response == "SUCCESS" || response == "2FA") {
  131. $("#block_qr_login").fadeOut(250);
  132. $("#denyqr").fadeOut(250);
  133. $("#continue_btn, .title, .description").hide().fadeIn(250);
  134. if (response == "SUCCESS") switch_block("custom_bot");
  135. if (response == "2FA") {
  136. show_2fa();
  137. qr_login = true;
  138. }
  139. clearInterval(qr_interval);
  140. return;
  141. }
  142. qrCode.update({ data: response });
  143. })
  144. }, 1250);
  145. })
  146. });
  147. });
  148. });
  149. $("#enter_api")
  150. .click(() => {
  151. if (auth_required) return auth(() => {
  152. $("#enter_api").click();
  153. });
  154. $("#get_started").fadeOut(250);
  155. $("#enter_api")
  156. .fadeOut(250, () => {
  157. $("#continue_btn")
  158. .hide()
  159. .fadeIn(250);
  160. switch_block("api_id");
  161. });
  162. });
  163. function isInt(value) {
  164. var x = parseFloat(value);
  165. return !isNaN(value) && (x | 0) === x;
  166. }
  167. function isValidPhone(p) {
  168. var phoneRe = /^[+]?\d{11,13}$/;
  169. return phoneRe.test(p);
  170. }
  171. function finish_login() {
  172. fetch("/finish_login", {
  173. method: "POST",
  174. credentials: "include"
  175. })
  176. .then(() => {
  177. $(".installation").fadeOut(2000);
  178. setTimeout(() => {
  179. $("#installation_icon").html("");
  180. bodymovin.loadAnimation({
  181. container: document.getElementById("installation_icon"),
  182. renderer: "canvas",
  183. loop: true,
  184. autoplay: true,
  185. path: "https://assets1.lottiefiles.com/packages/lf20_n3jgitst.json",
  186. rendererSettings: {
  187. clearCanvas: true,
  188. }
  189. });
  190. $(".finish_block").fadeIn(250);
  191. }, 2000);
  192. })
  193. .catch((err) => {
  194. error_state();
  195. error_message("Login confirmation error: " + err.toString());
  196. });
  197. }
  198. function show_2fa() {
  199. $(".auth-code-form").hide().fadeIn(250, () => {
  200. $("#monkey-close").html("");
  201. anim = bodymovin.loadAnimation({
  202. container: document.getElementById("monkey-close"),
  203. renderer: "canvas",
  204. loop: true,
  205. autoplay: true,
  206. path: "https://assets1.lottiefiles.com/packages/lf20_eg88dyk9.json",
  207. rendererSettings: {
  208. clearCanvas: true,
  209. }
  210. });
  211. anim.addEventListener("complete", () => {
  212. setTimeout(() => {
  213. anim.goToAndPlay(0);
  214. }, 2000);
  215. })
  216. });
  217. $(".code-input").removeAttr("disabled");
  218. $(".code-input").attr("inputmode", "text");
  219. if ($(".enter").hasClass("tgcode"))
  220. $(".enter").removeClass("tgcode");
  221. $(".code-caption").html("Enter your Telegram 2FA password, then press <span style='color: #dc137b;'>Enter</span>");
  222. cnt_btn.setAttribute("current-step", "2fa");
  223. $("#monkey").hide();
  224. $("#monkey-close").hide().fadeIn(100);
  225. _current_block = "2fa";
  226. }
  227. function show_eula() {
  228. $(".main").fadeOut(250);
  229. $(".eula-form").hide().fadeIn(250, () => {
  230. $("#law").html("");
  231. anim = bodymovin.loadAnimation({
  232. container: document.getElementById("law"),
  233. renderer: "canvas",
  234. loop: true,
  235. autoplay: true,
  236. path: "https://static.hikari.gay/forbidden.json",
  237. rendererSettings: {
  238. clearCanvas: true,
  239. }
  240. });
  241. });
  242. }
  243. function tg_code(processing_2fa = false) {
  244. if (processing_2fa && qr_login) {
  245. fetch("/qr_2fa", {
  246. method: "POST",
  247. credentials: "include",
  248. body: _2fa_pass,
  249. }).then((response) => {
  250. if (!response.ok) {
  251. $(".code-input").removeAttr("disabled");
  252. response.text().then((text) => {
  253. error_state();
  254. Swal.fire(
  255. "Error",
  256. text,
  257. "error"
  258. );
  259. });
  260. } else {
  261. $(".auth-code-form").fadeOut();
  262. $("#block_phone").fadeOut();
  263. switch_block("custom_bot");
  264. }
  265. })
  266. return;
  267. }
  268. fetch("/tg_code", {
  269. method: "POST",
  270. body: `${_tg_pass}\n${_phone}\n${_2fa_pass}`
  271. })
  272. .then((response) => {
  273. if (!response.ok) {
  274. if (response.status == 401) {
  275. show_2fa();
  276. } else {
  277. $(".code-input").removeAttr("disabled");
  278. response.text().then((text) => {
  279. error_state();
  280. Swal.fire(
  281. "Error",
  282. text,
  283. "error"
  284. );
  285. });
  286. }
  287. } else {
  288. $(".auth-code-form").fadeOut();
  289. $("#block_phone").fadeOut();
  290. switch_block("custom_bot");
  291. }
  292. })
  293. .catch(error => {
  294. Swal.showValidationMessage(
  295. `Auth failed: ${error.toString()}`
  296. )
  297. })
  298. }
  299. function switch_block(block) {
  300. cnt_btn.setAttribute("current-step", block);
  301. try {
  302. $(`#block_${_current_block}`)
  303. .fadeOut(() => {
  304. $(`#block_${block}`)
  305. .hide()
  306. .fadeIn();
  307. });
  308. } catch {
  309. $(`#block_${block}`)
  310. .hide()
  311. .fadeIn();
  312. }
  313. _current_block = block;
  314. }
  315. function error_message(message) {
  316. Swal.fire({
  317. "icon": "error",
  318. "title": message
  319. });
  320. }
  321. function error_state() {
  322. $("body").addClass("red_state");
  323. cnt_btn.disabled = true;
  324. setTimeout(() => {
  325. cnt_btn.disabled = false;
  326. $("body").removeClass("red_state");
  327. }, 1000);
  328. }
  329. var _api_id = "",
  330. _api_hash = "",
  331. _phone = "",
  332. _2fa_pass = "",
  333. _tg_pass = "",
  334. _current_block = skip_creds ? "qr_login" : "api_id";
  335. function is_phone() {
  336. return /Android|webOS|iPhone|iPad|iPod|BlackBerry|BB|PlayBook|IEMobile|Windows Phone|Kindle|Silk|Opera Mini/i.test(navigator.userAgent);
  337. }
  338. if (is_phone() && _current_block == "qr_login") {
  339. _current_block = "phone";
  340. }
  341. const cnt_btn = document.querySelector("#continue_btn");
  342. function process_next() {
  343. let step = cnt_btn.getAttribute("current-step");
  344. if (step == "api_id") {
  345. let api_id = document.querySelector("#api_id").value;
  346. if (api_id.length < 4 || !isInt(api_id)) {
  347. error_state();
  348. return;
  349. }
  350. _api_id = parseInt(api_id, 10);
  351. switch_block("api_hash");
  352. return;
  353. }
  354. if (step == "api_hash") {
  355. let api_hash = document.querySelector("#api_hash").value;
  356. if (api_hash.length != 32) {
  357. error_state();
  358. return;
  359. }
  360. _api_hash = api_hash;
  361. fetch("/set_api", {
  362. method: "PUT",
  363. body: _api_hash + _api_id,
  364. credentials: "include"
  365. })
  366. .then(response => response.text())
  367. .then((response) => {
  368. if (response != "ok") {
  369. error_state();
  370. error_message(response)
  371. } else {
  372. switch_block(is_phone() ? "phone" : "qr_login");
  373. }
  374. })
  375. .catch((err) => {
  376. error_state();
  377. error_message("Error occured while saving credentials: " + err.toString());
  378. });
  379. return;
  380. }
  381. if (step == "phone") {
  382. let phone = document.querySelector("#phone").value;
  383. if (!isValidPhone(phone)) {
  384. error_state();
  385. return;
  386. }
  387. _phone = phone;
  388. fetch("/send_tg_code", {
  389. method: "POST",
  390. body: _phone,
  391. credentials: "include"
  392. })
  393. .then((response) => {
  394. if (!response.ok) {
  395. if (response.status == 403) {
  396. show_eula();
  397. } else {
  398. response.text().then((text) => {
  399. error_state();
  400. error_message(text);
  401. });
  402. }
  403. } else {
  404. $(".auth-code-form").hide().fadeIn(250, () => {
  405. $("#monkey").html("");
  406. anim2 = bodymovin.loadAnimation({
  407. container: document.getElementById("monkey"),
  408. renderer: "canvas",
  409. loop: false,
  410. autoplay: true,
  411. path: "https://assets8.lottiefiles.com/private_files/lf30_t52znxni.json",
  412. rendererSettings: {
  413. clearCanvas: true,
  414. }
  415. });
  416. anim2.addEventListener("complete", () => {
  417. setTimeout(() => {
  418. anim2.goToAndPlay(0);
  419. }, 2000);
  420. })
  421. });
  422. $(".code-input").removeAttr("disabled");
  423. $(".enter").addClass("tgcode");
  424. $(".code-caption").text("Enter the code you recieved in Telegram");
  425. cnt_btn.setAttribute("current-step", "code");
  426. _current_block = "code";
  427. }
  428. })
  429. .catch((err) => {
  430. error_state();
  431. error_message("Code send failed: " + err.toString());
  432. });
  433. }
  434. if (step == "2fa") {
  435. let _2fa = document.querySelector("#_2fa").value;
  436. _2fa_pass = _2fa;
  437. tg_code();
  438. return
  439. }
  440. if (step == "custom_bot") {
  441. let custom_bot = document.querySelector("#custom_bot").value;
  442. if (custom_bot != "" && (!custom_bot.toLowerCase().endsWith("bot") || custom_bot.length < 5)) {
  443. Swal.fire({
  444. "icon": "error",
  445. "title": "Bot username invalid",
  446. "text": "It must end with `bot` and be at least 5 symbols in length"
  447. })
  448. return
  449. }
  450. if (custom_bot == "") {
  451. finish_login();
  452. return
  453. }
  454. fetch("/custom_bot", {
  455. method: "POST",
  456. credentials: "include",
  457. body: custom_bot
  458. })
  459. .then(response => response.text())
  460. .then((response) => {
  461. if (response == "OCCUPIED") {
  462. Swal.fire({
  463. "icon": "error",
  464. "title": "This bot username is already occupied!"
  465. })
  466. return;
  467. }
  468. finish_login();
  469. })
  470. .catch((err) => {
  471. error_state();
  472. error_message("Custom bot setting error: " + err.toString());
  473. });
  474. return
  475. }
  476. }
  477. cnt_btn.onclick = () => {
  478. if (cnt_btn.disabled) return;
  479. if (auth_required) return auth(() => {
  480. cnt_btn.click();
  481. });
  482. process_next();
  483. }
  484. $("#denyqr").on("click", () => {
  485. if (qr_interval) clearInterval(qr_interval);
  486. $("#denyqr").fadeOut(250);
  487. $("#continue_btn, .title, .description").hide().fadeIn(250);
  488. switch_block("phone");
  489. });
  490. $(".installation input").on("keyup", (e) => {
  491. if (cnt_btn.disabled) return;
  492. if (auth_required) return auth(() => {
  493. cnt_btn.click();
  494. });
  495. if (e.key === "Enter" || e.keyCode === 13) {
  496. process_next();
  497. }
  498. });
  499. $(".code-input").on("keyup", (e) => {
  500. if (_current_block == "code" && $(".code-input").val().length == 5) {
  501. _tg_pass = $(".code-input").val();
  502. $(".code-input").attr("disabled", "true");
  503. $(".code-input").val("");
  504. tg_code();
  505. } else if (_current_block == "2fa" && (e.key === "Enter" || e.keyCode === 13)) {
  506. let _2fa = $(".code-input").val();
  507. _2fa_pass = _2fa;
  508. $(".code-input").attr("disabled", "true");
  509. $(".code-input").val("");
  510. tg_code(true);
  511. }
  512. });
  513. $(".enter").on("click", () => {
  514. if (_current_block == "2fa") {
  515. let _2fa = $(".code-input").val();
  516. _2fa_pass = _2fa;
  517. $(".code-input").attr("disabled", "true");
  518. $(".code-input").val("");
  519. tg_code(true);
  520. }
  521. });