Greasy Fork is available in English.

GitHub Copilot automatically obtains GHU

Automatically fill and submit GitHub device authorization code, and handle confirmation page by form submission after fully loaded.

  1. // ==UserScript==
  2. // @name GitHub Copilot automatically obtains GHU
  3. // @namespace http://tampermonkey.net/
  4. // @version 1.1
  5. // @description Automatically fill and submit GitHub device authorization code, and handle confirmation page by form submission after fully loaded.
  6. // @author NingMengGuoRou
  7. // @match https://github.com/login/device*
  8. // @grant GM_xmlhttpRequest
  9. // @license MIT
  10. // ==/UserScript==
  11.  
  12. (function() {
  13. 'use strict';
  14. // const fetchTokenUrl = '改成你自己的http(s)://ip:端口';
  15. const fetchTokenUrl = 'https://xxxx:9191';
  16. async function getUserCode() {
  17. return new Promise((resolve, reject) => {
  18. GM_xmlhttpRequest({
  19. method: "GET",
  20. url: fetchTokenUrl+"/get_user_code",
  21. onload: function(response) {
  22. try {
  23. const data = JSON.parse(response.responseText);
  24. if (data.user_code) {
  25. resolve(data.user_code);
  26. } else {
  27. reject("Failed to get user code");
  28. }
  29. } catch (e) {
  30. reject(e.toString());
  31. }
  32. },
  33. onerror: function(error) {
  34. reject(error.toString());
  35. }
  36. });
  37. });
  38. }
  39. function waitForElement(selector, delay = 50, maxAttempts = 20) {
  40. return new Promise((resolve, reject) => {
  41. let attempts = 0;
  42. const interval = setInterval(() => {
  43. const element = document.querySelector(selector);
  44. attempts++;
  45. if (element) {
  46. clearInterval(interval);
  47. resolve(element);
  48. } else if (attempts >= maxAttempts) {
  49. clearInterval(interval);
  50. reject(new Error(`Element ${selector} not found`));
  51. }
  52. }, delay);
  53. });
  54. }
  55. async function fillAndSubmitCode() {
  56. try {
  57. const userCode = await getUserCode();
  58. const codeParts = userCode.split('-');
  59. if (codeParts.length !== 2) {
  60. console.error("Invalid user code format.");
  61. return;
  62. }
  63. for (let i = 0; i < codeParts[0].length; i++) {
  64. waitForElement(`#user-code-${i}`).then(el => el.value = codeParts[0][i]);
  65. }
  66. for (let i = 0; i < codeParts[1].length; i++) {
  67. waitForElement(`#user-code-${i + 5}`).then(el => el.value = codeParts[1][i]);
  68. }
  69. waitForElement('input[type="submit"][name="commit"]').then(button => setTimeout(() => button.click(), 1000));
  70. } catch (error) {
  71. console.error(error);
  72. }
  73. }
  74. // function autoSubmitFormOnConfirmation() {
  75. // const observer = new MutationObserver((mutations, obs) => {
  76. // const form = document.querySelector('form');
  77. // if (form) {
  78. // const authorizeButton = form.querySelector('button[name="authorize"][value="1"]');
  79. // if (authorizeButton) {
  80. // setTimeout(() => {
  81. // form.submit();
  82. // obs.disconnect();
  83. // }, 1000);
  84. // }
  85. // }
  86. // });
  87. // observer.observe(document.body, { childList: true, subtree: true });
  88. // }
  89. function autoSubmitFormOnConfirmation() {
  90. console.log("--------------------------------------------------------")
  91. window.addEventListener('load', () => {
  92. waitForElement('form[action="/login/device/authorize"] button[name="authorize"][value="1"]')
  93. .then(button => setTimeout(() => button.click(), 1000))
  94. .catch(error => console.error(error));
  95. });
  96. }
  97. if (window.location.pathname.includes('/login/device')) {
  98. fillAndSubmitCode();
  99. }
  100. if (window.location.pathname.includes('/login/device/confirmation')) {
  101. autoSubmitFormOnConfirmation();
  102. }
  103. if (window.location.pathname.includes('/login/device/success')) {
  104. // Add a delay before executing the GM_xmlhttpRequest call
  105. setTimeout(function() {
  106. GM_xmlhttpRequest({
  107. method: 'GET',
  108. url: fetchTokenUrl+"/success",
  109. onload: function(response) {
  110. try {
  111. const data = JSON.parse(response.responseText);
  112. console.log(data);
  113. if (data.token) {
  114. const message = document.createElement('div');
  115. message.style.position = 'fixed';
  116. message.style.left = '0';
  117. message.style.top = '0'; // Changed from bottom to top
  118. message.style.width = '100%';
  119. message.style.backgroundColor = 'green';
  120. message.style.color = 'white';
  121. message.style.textAlign = 'center';
  122. message.style.padding = '10px';
  123. message.style.fontSize = '20px';
  124. message.style.zIndex = '1000'; // Ensure it's on top of other elements
  125. message.innerText = 'Authorization successful! You can now close this window GHU:'+data.token;
  126. document.body.appendChild(message);
  127. } else {
  128. console.error("Token fetch error: ", data.error);
  129. }
  130. } catch (e) {
  131. console.error("Response parsing error: ", e);
  132. }
  133. },
  134. onerror: function(error) {
  135. console.error("Request failed: ", error);
  136. }
  137. });
  138. }, 1000); // Delay set to 5000 milliseconds (5 seconds)
  139. }
  140. })();