SecureMyPass Bare Bot (home-loop with static XPath)

For each account: Home -> Login -> My Links -> Export, then back to Home for next

当前为 2025-08-20 提交的版本,查看 最新版本

// ==UserScript==
// @name         SecureMyPass Bare Bot (home-loop with static XPath)
// @namespace    https://securemypass.com/
// @version      1.6
// @description  For each account: Home -> Login -> My Links -> Export, then back to Home for next
// @match        https://securemypass.com/*
// @run-at       document-end
// @grant        none
// ==/UserScript==

(function () {
  'use strict';
  if (window.__SMP_HOME_LOOP__) return;
  window.__SMP_HOME_LOOP__ = true;

  // --- UI ---
  const box = document.createElement('div');
  box.style = `
    position:fixed;bottom:20px;right:20px;z-index:2147483647;
    background:#111;color:#eee;padding:10px;border:1px solid #333;border-radius:6px;
    font:13px/1.4 system-ui;width:260px
  `;
  box.innerHTML = `
    <h3 style="margin:0 0 6px;font-size:14px">SMP Bot</h3>
    <label>Number of Accounts</label>
    <input id="smpCount" type="number" value="1" min="1" style="width:100%;margin:4px 0"/>
    <div id="smpCreds"></div>
    <button id="smpStart" style="margin-top:6px;width:100%">Start</button>
    <div id="smpLog" style="margin-top:6px;font-size:12px;color:#aaa">Idle</div>
  `;
  document.body.appendChild(box);

  const el = (sel) => box.querySelector(sel);
  const log = (m) => (el('#smpLog').textContent = m);

  const renderCreds = () => {
    const n = parseInt(el('#smpCount').value || '1', 10);
    const wrap = document.createElement('div');
    for (let i = 0; i < n; i++) {
      const d = document.createElement('div');
      d.style = 'border:1px solid #333;padding:4px;margin:4px 0;border-radius:4px';
      d.innerHTML = `
        <div>Account ${i + 1}</div>
        <input class="smpUser" type="text" placeholder="Username" style="width:100%"/>
        <input class="smpPass" type="password" placeholder="Password" style="width:100%"/>
      `;
      wrap.appendChild(d);
    }
    el('#smpCreds').innerHTML = '';
    el('#smpCreds').appendChild(wrap);
  };
  renderCreds();
  el('#smpCount').addEventListener('input', renderCreds);

  // --- Utils ---
  const sleep = (ms) => new Promise((r) => setTimeout(r, ms));
  const xp = (path) =>
    document.evaluate(path, document, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null).singleNodeValue;

  // --- State in sessionStorage ---
  const S = {
    get queue() { try { return JSON.parse(sessionStorage.getItem('SMP_QUEUE') || '[]'); } catch { return []; } },
    set queue(v) { sessionStorage.setItem('SMP_QUEUE', JSON.stringify(v || [])); },

    get idx() { return parseInt(sessionStorage.getItem('SMP_IDX') || '0', 10); },
    set idx(v) { sessionStorage.setItem('SMP_IDX', String(v)); },

    get phase() { return sessionStorage.getItem('SMP_PHASE') || 'IDLE'; },
    set phase(v) { sessionStorage.setItem('SMP_PHASE', v); },

    clear() {
      sessionStorage.removeItem('SMP_QUEUE');
      sessionStorage.removeItem('SMP_IDX');
      sessionStorage.removeItem('SMP_PHASE');
    }
  };

  // --- Steps ---
  async function doHomeStep() {
    if (location.pathname !== '/') {
      log('Going to Home…');
      location.href = 'https://securemypass.com/';
      return;
    }
    log('Proceeding to Login…');
    S.phase = 'LOGIN';
    location.href = 'https://securemypass.com/login';
  }

  async function doLoginStep(u, p) {
    log('Typing username…');
    const uEl = xp('//*[@id="loginUsername"]');
    if (!uEl) throw new Error('Username field not found');
    uEl.value = u;
    await sleep(500);

    log('Clicking continue…');
    const btn1 = xp('//*[@id="root"]/div[1]/main/div/div/div/div/div[1]/div/form/div[2]/button');
    btn1?.click();
    await sleep(1500);

    log('Typing password…');
    const pEl = xp('//*[@id="loginPassword"]');
    pEl.value = p;
    await sleep(500);

    log('Clicking login…');
    const btn2 = xp('//*[@id="root"]/div[1]/main/div/div/div/div/div[1]/div/form/div[2]/button');
    btn2?.click();
    await sleep(2500);

    S.phase = 'EXPORT';
    log('Going to My Links…');
    location.href = 'https://securemypass.com/my-links';
  }

  async function doExportStep() {
    log('Waiting for Export button…');
    const t0 = performance.now();
    let btn;
    while (!(btn = xp('//*[@id=":r24:"]'))) {  // <-- direct XPath
      if (performance.now() - t0 > 20000) throw new Error('Export button not found');
      await sleep(500);
    }
    await sleep(800);
    btn.click();
    log('Export clicked (check downloads).');
    await sleep(2000);

    const next = S.idx + 1;
    if (next < S.queue.length) {
      S.idx = next;
      S.phase = 'HOME';
      log(`Next account ${next + 1}/${S.queue.length}…`);
      location.href = 'https://securemypass.com/';
    } else {
      log('All done.');
      S.clear();
    }
  }

  // --- Resume on load ---
  (async function resume() {
    const phase = S.phase;
    if (phase === 'IDLE') return;

    const q = S.queue, i = S.idx, acct = q[i];
    if (!acct) { S.clear(); log('Idle'); return; }

    if (phase === 'HOME') return doHomeStep();
    if (phase === 'LOGIN' && location.pathname.startsWith('/login')) return doLoginStep(acct.username, acct.password);
    if (phase === 'EXPORT' && location.pathname.startsWith('/my-links')) return doExportStep();
  })();

  // --- Start button seeds state ---
  el('#smpStart').onclick = async () => {
    const users = [...box.querySelectorAll('.smpUser')].map((i) => i.value.trim());
    const passes = [...box.querySelectorAll('.smpPass')].map((i) => i.value);
    const queue = users.map((u, idx) => ({ username: u, password: passes[idx] })).filter(a => a.username && a.password);
    if (!queue.length) { log('Enter credentials'); return; }

    S.queue = queue
    S.idx = 0;
    S.phase = 'HOME';
    log(`Starting account 1/${queue.length}…`);
    location.href = 'https://securemypass.com/';
  };
})();

QingJ © 2025

镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址