GitHub Auto Signup

Automate github signup

当前为 2024-02-23 提交的版本,查看 最新版本

  1. // ==UserScript==
  2. // @name GitHub Auto Signup
  3. // @version 0.5
  4. // @description Automate github signup
  5. // @author Young Jimmy
  6. // @match https://github.com/signup*
  7. // @match https://github.com/signup?source=login
  8. // @match https://github.com/login?return_to=*device*
  9. // @match https://github.com/account_verifications?recommend_plan=true
  10. // @grant GM_xmlhttpRequest
  11. // @connect 127.0.0.1:9191
  12. // @license MIT
  13. // @namespace https://greasyfork.org/users/1218336
  14. // ==/UserScript==
  15.  
  16.  
  17.  
  18. (function() {
  19. 'use strict';
  20. // 创建日志框
  21. var logBox = document.createElement("div");
  22. logBox.style.position = "fixed";
  23. logBox.style.width = "200px";
  24. logBox.style.height = "200px";
  25. logBox.style.overflowY = "scroll";
  26. logBox.style.border = "1px solid black";
  27. logBox.style.padding = "5px";
  28. logBox.style.backgroundColor = "rgba(255, 255, 255, 0.5)"; // 半透明白色背景
  29. logBox.style.zIndex = "9999";
  30. logBox.style.bottom = "0"; // 放在页面左下角
  31. document.body.appendChild(logBox);
  32.  
  33. // 让日志框可以拖动
  34. logBox.onmousedown = function(event) {
  35. event.preventDefault();
  36.  
  37. var shiftX = event.clientX - logBox.getBoundingClientRect().left;
  38. var shiftY = event.clientY - logBox.getBoundingClientRect().top;
  39.  
  40. logBox.style.position = 'absolute';
  41. document.body.append(logBox);
  42. moveAt(event.pageX, event.pageY);
  43.  
  44. function moveAt(pageX, pageY) {
  45. logBox.style.left = pageX - shiftX + 'px';
  46. logBox.style.top = pageY - shiftY + 'px';
  47. }
  48.  
  49. function onMouseMove(event) {
  50. moveAt(event.pageX, event.pageY);
  51. }
  52.  
  53. document.addEventListener('mousemove', onMouseMove);
  54.  
  55. logBox.onmouseup = function() {
  56. document.removeEventListener('mousemove', onMouseMove);
  57. logBox.onmouseup = null;
  58. };
  59. };
  60.  
  61. logBox.ondragstart = function() {
  62. return false;
  63. };
  64.  
  65. // 将日志添加到框中的函数
  66. unsafeWindow.logMessage = function(message) {
  67. var p = document.createElement("p");
  68. p.textContent = message;
  69. logBox.appendChild(p);
  70. logBox.scrollTop = logBox.scrollHeight; // 自动滚动到底部
  71. };
  72. // Delay function
  73. function delay(time) {
  74. return new Promise(function(resolve) {
  75. setTimeout(resolve, time);
  76. });
  77. }
  78.  
  79. // Wait for label with specific content to exist
  80. function labelReady(content) {
  81. return new Promise((resolve, reject) => {
  82. new MutationObserver((mutationRecords, observer) => {
  83. Array.from(document.querySelectorAll('label')).forEach((element) => {
  84. if (element.textContent.trim() === content) {
  85. logMessage(`Label with content "${content}" found.`);
  86. resolve(element);
  87. observer.disconnect();
  88. }
  89. });
  90. })
  91. .observe(document.documentElement, {childList: true, subtree: true});
  92. });
  93. }
  94.  
  95. function generatePassword(length) {
  96. const lowercase = "abcdefghijklmnopqrstuvwxyz";
  97. const uppercase = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
  98. const numbers = "0123456789";
  99. const symbols = "!@#$%^&*()_+~`|}{[]:;?><,./-=";
  100.  
  101. // Ensure the length is at least 4 to accommodate all character types.
  102. if (length < 4) {
  103. logMessage("Password length must be at least 4.");
  104. return null;
  105. }
  106.  
  107. let password = "";
  108. password += lowercase.charAt(Math.floor(Math.random() * lowercase.length));
  109. password += uppercase.charAt(Math.floor(Math.random() * uppercase.length));
  110. password += numbers.charAt(Math.floor(Math.random() * numbers.length));
  111. password += symbols.charAt(Math.floor(Math.random() * symbols.length));
  112.  
  113. for (let i = 4, n = lowercase.length + uppercase.length + numbers.length + symbols.length; i < length; ++i) {
  114. let randomPickedSet;
  115. switch(Math.floor(Math.random() * 4)) {
  116. case 0:
  117. randomPickedSet = lowercase;
  118. break;
  119. case 1:
  120. randomPickedSet = uppercase;
  121. break;
  122. case 2:
  123. randomPickedSet = numbers;
  124. break;
  125. case 3:
  126. randomPickedSet = symbols;
  127. break;
  128. }
  129. password += randomPickedSet.charAt(Math.floor(Math.random() * randomPickedSet.length));
  130. }
  131.  
  132. // Shuffle the result to ensure randomness
  133. password = password.split('').sort(function(){return 0.5-Math.random()}).join('');
  134.  
  135. return password;
  136. }
  137.  
  138. function generateUsername(length) {
  139. let result = '';
  140. const characters = '0123456789';
  141. const charactersLength = characters.length;
  142. for (let i = 0; i < length; i++) {
  143. result += characters.charAt(Math.floor(Math.random() * charactersLength));
  144. }
  145. return result;
  146. }
  147.  
  148. // Wait for element to exist
  149. function elementReady(selector) {
  150. return new Promise((resolve, reject) => {
  151. let el = document.querySelector(selector);
  152. if (el) { resolve(el); }
  153. new MutationObserver((mutationRecords, observer) => {
  154. // Query for elements matching the specified selector
  155. Array.from(document.querySelectorAll(selector)).forEach((element) => {
  156. resolve(element);
  157. //Once we have resolved we don't need the observer anymore.
  158. observer.disconnect();
  159. });
  160. })
  161. .observe(document.documentElement, {childList: true, subtree: true});
  162. });
  163. }
  164.  
  165. async function signup() {
  166. const password = generatePassword(12);
  167. const username = generateUsername(Math.floor(Math.random() * 5) + 8);
  168.  
  169. logMessage("Waiting for label...");
  170. await labelReady("Enter your email*");
  171. logMessage('start get eamil')
  172. let email = await getEmail();
  173. logMessage('API get email '+ email)
  174. logMessage("Starting signup process...");
  175. localStorage.setItem('email', email);
  176. localStorage.setItem(email, password);
  177. await elementReady(".js-continue-container").then(element => element.click());
  178. await delay(1000);
  179.  
  180. await elementReady("#email").then(element => element.value = email);
  181. await elementReady(".mx-1").then(element => element.click());
  182. await elementReady("#email-container .js-continue-button").then(element => element.click());
  183. await delay(1000);
  184.  
  185. await elementReady("#password").then(element => {element.click(); element.value = password;});
  186. await elementReady(".mx-1").then(element => element.click());
  187. await elementReady("#password-container .js-continue-button").then(element => element.click());
  188. await delay(1000);
  189.  
  190. await elementReady("#login").then(element => {element.click(); element.value = username;});
  191. await elementReady(".mx-1").then(element => element.click());
  192. await elementReady("#username-container .js-continue-button").then(element => element.click());
  193. await elementReady("#opt-in-container .js-continue-button").then(element => element.click());
  194. await elementReady("button[name=button]").then(element => element.click());
  195. observeAttributeChange('.js-octocaptcha-form-submit', (node) => {
  196. return !node.hasAttribute('disabled') && !node.hasAttribute('hidden');
  197. }).then((node) => {
  198. node.click();
  199. }).catch((error) => {
  200. console.error(error);
  201. });
  202. await labelReady("Email preferences*");
  203. await elementReady("#opt_in").then(element => element.click());
  204. await elementReady('#opt_in').then(element =>{ element.checked= false;});
  205. await elementReady('#opt_in').then(element =>{ element.checked= false;});
  206. await elementReady("button[name=button]").then(element => element.click());
  207.  
  208. logMessage("Signup process completed.");
  209.  
  210. // Store the email in localStorage after signup
  211. localStorage.setItem('email', email);
  212. localStorage.setItem(email, password);
  213.  
  214. }
  215.  
  216. async function getEmail() {
  217. return new Promise((resolve, reject) => {
  218. GM_xmlhttpRequest({
  219. method: "GET",
  220. url: "http://127.0.0.1:9191/get_email",
  221. onload: function(response) {
  222. const data = JSON.parse(response.responseText);
  223. if (data.account) {
  224. resolve(data.account);
  225. } else {
  226. reject('Failed to get email');
  227. }
  228. }
  229. });
  230. });
  231. }
  232.  
  233. async function getVerificationCode(email) {
  234. return new Promise((resolve, reject) => {
  235. GM_xmlhttpRequest({
  236. method: "GET",
  237. url: `http://127.0.0.1:9191/get_verification_code?account=${email}`,
  238. onload: function(response) {
  239. logMessage(response.responseText)
  240. const data = JSON.parse(response.responseText);
  241. if (data.verification_code) {
  242. resolve(data.verification_code);
  243. } else {
  244. reject('Failed to get verification code');
  245. }
  246. }
  247. });
  248. });
  249. }
  250. function observeAttributeChange(selector, condition) {
  251. return new Promise((resolve, reject) => {
  252. // 获取目标节点
  253. const targetNode = document.querySelector(selector);
  254.  
  255. if (!targetNode) {
  256. reject('No element found with the given selector.');
  257. return;
  258. }
  259.  
  260. // 检查元素是否已经满足条件
  261. if (condition(targetNode)) {
  262. resolve(targetNode); // 如果已经满足,直接返回该元素
  263. return;
  264. }
  265.  
  266. // 设置观察器配置项
  267. const config = { attributes: true };
  268.  
  269. // 创建一个观察器实例并传入回调函数
  270. const observer = new MutationObserver((mutations) => {
  271. mutations.forEach((mutation) => {
  272. if (condition(targetNode)) {
  273. observer.disconnect(); // 停止观察
  274. resolve(targetNode); // 返回符合条件的DOM元素
  275. }
  276. });
  277. });
  278.  
  279. // 开始观察目标节点
  280. observer.observe(targetNode, config);
  281. });
  282. }
  283.  
  284.  
  285.  
  286. async function fillVerificationCode(code) {
  287. const codeInputs = Array.from(document.querySelectorAll('.form-control.input-monospace'));
  288. const codeArray = code.split('');
  289. codeInputs.forEach((input, index) => {
  290. if (codeArray[index]) {
  291. input.value = codeArray[index];
  292. input.dispatchEvent(new Event('input', { bubbles: true, cancelable: true }));
  293. }
  294. });
  295. }
  296.  
  297.  
  298.  
  299. async function checkVerificationCode(email) {
  300. while (true) {
  301. try {
  302. const code = await getVerificationCode(email);
  303. if (code) {
  304. fillVerificationCode(code);
  305. break;
  306. }
  307. } catch (error) {
  308. console.error(error);
  309. }
  310. await delay(3000);
  311. }
  312. }
  313.  
  314. logMessage("Script loaded, waiting for page load...");
  315. window.addEventListener('load', async function() {
  316.  
  317.  
  318.  
  319. logMessage("Page loaded, starting script...");
  320. if (window.location.href === 'https://github.com/login?return_to=https%3A%2F%2Fgithub.com%2Flogin%2Fdevice') {
  321. window.location.replace('https://github.com/signup?source=login');
  322. }
  323. if (window.location.href === 'https://github.com/signup?source=login' || window.location.href ==='https://github.com/signup') {
  324.  
  325. signup();
  326. } else if (window.location.href === 'https://github.com/account_verifications?recommend_plan=true') {
  327. // Retrieve the email from localStorage on the verification page
  328. let email = localStorage.getItem('email');
  329. logMessage('checkVerificationCode '+ email)
  330. if (email) {
  331. checkVerificationCode(email);
  332. }
  333. }
  334. }, false);
  335.  
  336. })();