VJudge Cookie Filler

Auto fill cookies for those OJ which can submit problems on VJ by using their cookies.

Fra 22.05.2025. Se den seneste versjonen.

  1. // ==UserScript==
  2. // @name VJudge Cookie Filler
  3. // @name:zh-CN VJudge Cookie Filler
  4. // @version 1.0.0
  5. // @description Auto fill cookies for those OJ which can submit problems on VJ by using their cookies.
  6. // @description:zh-CN 自动抓取允许在 VJ 上使用自己账号提交问题的 OJ 的 Cookie
  7. // @author konglils
  8. // @license MIT
  9. // @namespace https://github.com/konglils/vjudge-cookie-filler
  10. // @homepageURL https://github.com/konglils/vjudge-cookie-filler
  11. // @supportURL https://github.com/konglils/vjudge-cookie-filler
  12. // @grant GM_xmlhttpRequest
  13. // @grant GM_openInTab
  14. // @grant GM_cookie
  15. // @run-at document-end
  16. // @connect vjudge.net
  17. // @match https://vjudge.net/*
  18. // @match https://codeforces.com/*
  19. // @match https://qoj.ac/*
  20. // @match https://onlinejudge.org/*
  21. // @match https://www.luogu.com.cn/*
  22. // @match https://www.nowcoder.com/*
  23. // ==/UserScript==
  24.  
  25. (function() {
  26. 'use strict';
  27.  
  28. const OJ = {
  29. "CodeForces": {
  30. url: "https://codeforces.com/",
  31. cookieNames: ["JSESSIONID"],
  32. },
  33. "Gym": {
  34. url: "https://codeforces.com/",
  35. cookieNames: ["JSESSIONID"],
  36. },
  37. "QOJ": {
  38. url: "https://qoj.ac/",
  39. cookieNames: ["UOJSESSID"],
  40. },
  41. "UVA": {
  42. url: "https://onlinejudge.org/",
  43. cookieNames: ["8da11fa2dbfcbf0b9ab349d4b3eba6a3"],
  44. },
  45. "洛谷": {
  46. url: "https://www.luogu.com.cn/",
  47. cookieNames: ["__client_id", "_uid"],
  48. },
  49. "牛客": {
  50. url: "https://www.nowcoder.com/",
  51. cookieNames: ["t"],
  52. },
  53. };
  54.  
  55. const VERIFY_REGEX = /^\/user\/verifiedAccount\?oj=([^&]+)$/;
  56. const CHECK_REGEX = /^\/user\/checkAccount\?oj=([^&]+)$/;
  57.  
  58. const _originOpen = XMLHttpRequest.prototype.open;
  59. const _originSend = XMLHttpRequest.prototype.send;
  60.  
  61. let loggingIn = false; // logging into OJ
  62. let currentOJ = "";
  63.  
  64. window.addEventListener("focus", () => {
  65. if (loggingIn) {
  66. autoFill(currentOJ);
  67. }
  68. })
  69.  
  70. XMLHttpRequest.prototype.open = function(method, url, async, user, password) {
  71. this._url = url;
  72. return _originOpen.apply(this, arguments);
  73. };
  74.  
  75. // hook
  76. XMLHttpRequest.prototype.send = function(body) {
  77. this.addEventListener("readystatechange", function() {
  78. if (location.hostname === "vjudge.net" && this.readyState === 4 && this.status === 200) {
  79. let isVerified = true;
  80. let oj = "";
  81.  
  82. // verify
  83. const matchVerify = this._url.match(VERIFY_REGEX);
  84. if (matchVerify) {
  85. oj = decodeURI(matchVerify[1]);
  86. const response = JSON.parse(this.responseText);
  87. if (Object.keys(response).length == 0) {
  88. isVerified = false;
  89. }
  90. }
  91.  
  92. // check
  93. const matchCheck = this._url.match(CHECK_REGEX);
  94. if (matchCheck) {
  95. oj = decodeURI(matchCheck[1]);
  96. const response = JSON.parse(this.responseText);
  97. if (Object.keys(response).length == 0) {
  98. isVerified = false;
  99. }
  100. }
  101.  
  102. // not login
  103. if (!isVerified && oj in OJ) {
  104. autoFill(oj);
  105. }
  106. }
  107. });
  108. return _originSend.apply(this, arguments);
  109. };
  110.  
  111. function autoFill(oj) {
  112. updatePendInfo("Auto filling ...")
  113.  
  114. GM_cookie.list({ url: OJ[oj].url }, (cookies, error) => {
  115. if (error) {
  116. updateFailInfo(oj, "Failed to read cookies");
  117. console.error(`Failed to read ${oj} cookies: ` + error);
  118. return;
  119. }
  120.  
  121. // filter cookies in order
  122. let ojCookies = [];
  123. for (let name of OJ[oj].cookieNames) {
  124. for (let cookie of cookies) {
  125. if (cookie.name == name && cookie.value !== "") {
  126. ojCookies.push({ "name": name, "value": cookie.value });
  127. }
  128. }
  129. }
  130.  
  131. if (ojCookies.length !== OJ[oj].cookieNames.length) {
  132. loginToOJ(oj);
  133. return;
  134. }
  135.  
  136. GM_xmlhttpRequest({ // new verify request
  137. method: "POST",
  138. url: "/user/verifyAccount",
  139. headers: { "Content-Type": "application/json;charset=UTF-8" },
  140. data: JSON.stringify({ "oj": oj, "proof": ojCookies }),
  141. onload(response) {
  142. response = JSON.parse(response.responseText);
  143. if (response.success) {
  144. updateSuccessInfo(response.accountDisplay);
  145. } else {
  146. loginToOJ(oj);
  147. }
  148. },
  149. onerror(error) {
  150. updateFailInfo(oj, "Network error");
  151. console.error("Network error: " + error);
  152. }
  153. });
  154. });
  155. }
  156.  
  157. function loginToOJ(oj) {
  158. updateFailInfo(oj, oj + " verify failed");
  159. loggingIn = true;
  160. currentOJ = oj;
  161. GM_openInTab(OJ[oj].url, {
  162. active: true, // new tab
  163. insert: true, // insert right
  164. });
  165. }
  166.  
  167. function updatePendInfo(info) {
  168. let accountStatus = document.getElementsByClassName("my-account-status")[0];
  169. let accountInfo = document.getElementsByClassName("my-account")[0];
  170.  
  171. accountStatus.innerHTML = '<i class="fa fa-refresh fa-spin" title="Checking..." data-toggle="tooltip"></i>';
  172. accountInfo.innerHTML = info;
  173. }
  174.  
  175. function updateSuccessInfo(info) {
  176. let accountStatus = document.getElementsByClassName("my-account-status")[0];
  177. let accountInfo = document.getElementsByClassName("my-account")[0];
  178. let removeAccount = document.getElementsByClassName("remove-my-account")[0];
  179.  
  180. accountStatus.innerHTML = '<i class="fa fa-check text-success" title="" data-toggle="tooltip" data-original-title="Connected"></i>';
  181. accountInfo.innerHTML = info;
  182. removeAccount.style.display = "inline";
  183.  
  184. loggingIn = false;
  185. }
  186.  
  187. function updateFailInfo(oj, info) {
  188. let accountStatus = document.getElementsByClassName("my-account-status")[0];
  189. let accountInfo = document.getElementsByClassName("my-account")[0];
  190.  
  191. accountStatus.innerHTML = '<i class="fa fa-exclamation-triangle text-danger" title="" data-toggle="tooltip" data-original-title="Disconnected. Please re-verify."></i>';
  192. accountInfo.innerHTML = `${info} <a href="javascript:void(0)" id="oj-login-retry">Retry</a> `;
  193.  
  194. let fillRetry = document.getElementById("oj-login-retry");
  195. fillRetry.onclick = () => { autoFill(oj) };
  196.  
  197. loggingIn = false;
  198. }
  199. })();