signup-page.js 9.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266
  1. // content/signup-page.js — Content script for OpenAI auth pages (steps 2, 3, 4-receive, 5)
  2. // Injected on: auth0.openai.com, auth.openai.com, accounts.openai.com
  3. console.log('[MultiPage:signup-page] Content script loaded on', location.href);
  4. // Listen for commands from Background
  5. chrome.runtime.onMessage.addListener((message, sender, sendResponse) => {
  6. if (message.type === 'EXECUTE_STEP' || message.type === 'FILL_CODE') {
  7. handleCommand(message).then(() => {
  8. sendResponse({ ok: true });
  9. }).catch(err => {
  10. reportError(message.step, err.message);
  11. sendResponse({ error: err.message });
  12. });
  13. return true;
  14. }
  15. });
  16. async function handleCommand(message) {
  17. switch (message.type) {
  18. case 'EXECUTE_STEP':
  19. switch (message.step) {
  20. case 2: return await step2_clickRegister();
  21. case 3: return await step3_fillEmailPassword(message.payload);
  22. case 5: return await step5_fillNameBirthday(message.payload);
  23. default: throw new Error(`signup-page.js does not handle step ${message.step}`);
  24. }
  25. case 'FILL_CODE':
  26. return await step4_fillVerificationCode(message.payload);
  27. }
  28. }
  29. // ============================================================
  30. // Step 2: Click Register
  31. // ============================================================
  32. async function step2_clickRegister() {
  33. log('Step 2: Looking for Register/Sign up button...');
  34. // TODO: Adjust selectors based on actual OpenAI auth page
  35. let registerBtn = null;
  36. try {
  37. registerBtn = await waitForElementByText(
  38. 'a, button, [role="button"], [role="link"]',
  39. /sign\s*up|register|create\s*account|注册/i,
  40. 10000
  41. );
  42. } catch {
  43. // Some pages may have a direct link
  44. try {
  45. registerBtn = await waitForElement('a[href*="signup"], a[href*="register"]', 5000);
  46. } catch {
  47. throw new Error(
  48. 'Could not find Register/Sign up button. ' +
  49. 'Check auth page DOM in DevTools. URL: ' + location.href
  50. );
  51. }
  52. }
  53. simulateClick(registerBtn);
  54. log('Step 2: Clicked Register button');
  55. // Wait for page transition
  56. await sleep(2000);
  57. reportComplete(2);
  58. }
  59. // ============================================================
  60. // Step 3: Fill Email & Password
  61. // ============================================================
  62. async function step3_fillEmailPassword(payload) {
  63. const { email } = payload;
  64. if (!email) throw new Error('No email provided. Paste email in Side Panel first.');
  65. log(`Step 3: Filling email: ${email}`);
  66. // Find email input
  67. let emailInput = null;
  68. try {
  69. emailInput = await waitForElement(
  70. 'input[type="email"], input[name="email"], input[name="username"], input[id*="email"], input[placeholder*="email"], input[placeholder*="Email"]',
  71. 10000
  72. );
  73. } catch {
  74. throw new Error('Could not find email input field on signup page. URL: ' + location.href);
  75. }
  76. fillInput(emailInput, email);
  77. log('Step 3: Email filled');
  78. // Check if password field is on the same page
  79. let passwordInput = document.querySelector('input[type="password"]');
  80. if (!passwordInput) {
  81. // Need to submit email first to get to password page
  82. log('Step 3: No password field yet, submitting email first...');
  83. const submitBtn = document.querySelector('button[type="submit"]')
  84. || await waitForElementByText('button', /continue|next|submit|继续|下一步/i, 5000).catch(() => null);
  85. if (submitBtn) {
  86. simulateClick(submitBtn);
  87. log('Step 3: Submitted email, waiting for password field...');
  88. await sleep(2000);
  89. }
  90. try {
  91. passwordInput = await waitForElement('input[type="password"]', 10000);
  92. } catch {
  93. throw new Error('Could not find password input after submitting email. URL: ' + location.href);
  94. }
  95. }
  96. fillInput(passwordInput, 'mimashisha0.0');
  97. log('Step 3: Password filled');
  98. // Submit the form
  99. await sleep(500);
  100. const submitBtn = document.querySelector('button[type="submit"]')
  101. || await waitForElementByText('button', /continue|sign\s*up|submit|注册|创建|create/i, 5000).catch(() => null);
  102. if (submitBtn) {
  103. simulateClick(submitBtn);
  104. log('Step 3: Form submitted');
  105. }
  106. await sleep(2000);
  107. reportComplete(3, { email });
  108. }
  109. // ============================================================
  110. // Step 4 (receiving end): Fill Verification Code
  111. // ============================================================
  112. async function step4_fillVerificationCode(payload) {
  113. const { code } = payload;
  114. if (!code) throw new Error('No verification code provided.');
  115. log(`Step 4: Filling verification code: ${code}`);
  116. // Find code input — could be a single input or multiple separate inputs
  117. let codeInput = null;
  118. try {
  119. codeInput = await waitForElement(
  120. 'input[name="code"], input[name="otp"], input[type="text"][maxlength="6"], input[aria-label*="code"], input[placeholder*="code"], input[placeholder*="Code"], input[inputmode="numeric"]',
  121. 10000
  122. );
  123. } catch {
  124. // Check for multiple single-digit inputs (common pattern)
  125. const singleInputs = document.querySelectorAll('input[maxlength="1"]');
  126. if (singleInputs.length >= 6) {
  127. log('Step 4: Found single-digit code inputs, filling individually...');
  128. for (let i = 0; i < 6 && i < singleInputs.length; i++) {
  129. fillInput(singleInputs[i], code[i]);
  130. await sleep(100);
  131. }
  132. await sleep(1000);
  133. reportComplete(4);
  134. return;
  135. }
  136. throw new Error('Could not find verification code input. URL: ' + location.href);
  137. }
  138. fillInput(codeInput, code);
  139. log('Step 4: Code filled');
  140. // Submit
  141. await sleep(500);
  142. const submitBtn = document.querySelector('button[type="submit"]')
  143. || await waitForElementByText('button', /verify|confirm|submit|continue|确认|验证/i, 5000).catch(() => null);
  144. if (submitBtn) {
  145. simulateClick(submitBtn);
  146. log('Step 4: Verification submitted');
  147. }
  148. // Wait for page transition
  149. await sleep(2000);
  150. reportComplete(4);
  151. }
  152. // ============================================================
  153. // Step 5: Fill Name & Birthday
  154. // ============================================================
  155. async function step5_fillNameBirthday(payload) {
  156. const { firstName, lastName, year, month, day } = payload;
  157. if (!firstName || !lastName) throw new Error('No name data provided.');
  158. log(`Step 5: Filling name: ${firstName} ${lastName}, Birthday: ${year}-${month}-${day}`);
  159. // --- First name ---
  160. let firstNameInput = null;
  161. try {
  162. firstNameInput = await waitForElement(
  163. 'input[name="firstName"], input[name="first_name"], input[name="fname"], input[placeholder*="first" i], input[placeholder*="First"], input[id*="first" i]',
  164. 10000
  165. );
  166. } catch {
  167. throw new Error('Could not find first name input. URL: ' + location.href);
  168. }
  169. fillInput(firstNameInput, firstName);
  170. log(`Step 5: First name filled: ${firstName}`);
  171. // --- Last name ---
  172. let lastNameInput = null;
  173. try {
  174. lastNameInput = await waitForElement(
  175. 'input[name="lastName"], input[name="last_name"], input[name="lname"], input[placeholder*="last" i], input[placeholder*="Last"], input[id*="last" i]',
  176. 5000
  177. );
  178. } catch {
  179. throw new Error('Could not find last name input. URL: ' + location.href);
  180. }
  181. fillInput(lastNameInput, lastName);
  182. log(`Step 5: Last name filled: ${lastName}`);
  183. // --- Birthday ---
  184. const dateStr = `${year}-${String(month).padStart(2, '0')}-${String(day).padStart(2, '0')}`;
  185. // Try single date input first
  186. const dateInput = document.querySelector('input[type="date"], input[name="birthday"], input[name="dob"], input[name="birthdate"]');
  187. if (dateInput) {
  188. fillInput(dateInput, dateStr);
  189. log(`Step 5: Birthday filled (single input): ${dateStr}`);
  190. } else {
  191. // Try separate fields (month/day/year selects or inputs)
  192. log('Step 5: Looking for separate birthday fields...');
  193. const monthEl = document.querySelector('select[name*="month" i], input[name*="month" i], input[placeholder*="month" i], select[id*="month" i]');
  194. const dayEl = document.querySelector('select[name*="day" i], input[name*="day" i], input[placeholder*="day" i], select[id*="day" i]');
  195. const yearEl = document.querySelector('select[name*="year" i], input[name*="year" i], input[placeholder*="year" i], select[id*="year" i]');
  196. if (monthEl) {
  197. if (monthEl.tagName === 'SELECT') fillSelect(monthEl, String(month));
  198. else fillInput(monthEl, String(month).padStart(2, '0'));
  199. }
  200. if (dayEl) {
  201. if (dayEl.tagName === 'SELECT') fillSelect(dayEl, String(day));
  202. else fillInput(dayEl, String(day).padStart(2, '0'));
  203. }
  204. if (yearEl) {
  205. if (yearEl.tagName === 'SELECT') fillSelect(yearEl, String(year));
  206. else fillInput(yearEl, String(year));
  207. }
  208. if (!monthEl && !dayEl && !yearEl) {
  209. log('Step 5: WARNING - Could not find any birthday fields. May need to adjust selectors.', 'warn');
  210. } else {
  211. log(`Step 5: Birthday filled (separate fields): ${year}-${month}-${day}`);
  212. }
  213. }
  214. // Submit / Complete
  215. await sleep(500);
  216. const completeBtn = document.querySelector('button[type="submit"]')
  217. || await waitForElementByText('button', /complete|continue|finish|done|create|agree|完成|创建|同意/i, 5000).catch(() => null);
  218. if (completeBtn) {
  219. simulateClick(completeBtn);
  220. log('Step 5: Profile form submitted');
  221. }
  222. await sleep(2000);
  223. reportComplete(5);
  224. }