SecureMyPass Bot UI

Automate login + export for multiple accounts on SecureMyPass

目前為 2025-08-20 提交的版本,檢視 最新版本

// ==UserScript==
// @name         SecureMyPass Bot UI
// @namespace    https://securemypass.com/
// @version      1.0
// @description  Automate login + export for multiple accounts on SecureMyPass
// @match        https://securemypass.com/*
// @run-at       document-end
// @grant        none
// ==/UserScript==

(function() {
  'use strict';

  // Only inject once per page
  if (window.__SMP_BOT_LOADED__) return;
  window.__SMP_BOT_LOADED__ = true;

  // --- UI ---
  const css = `
    #smpUI{position:fixed;z-index:999999;right:20px;bottom:20px;width:300px;
      background:#111;color:#eee;font:13px/1.4 system-ui;padding:12px;border:1px solid #333;
      border-radius:10px;box-shadow:0 8px 30px rgba(0,0,0,.5)}
    #smpUI h3{margin:0 0 8px;font-size:14px}
    #smpUI label{display:block;margin:6px 0 2px}
    #smpUI input{width:100%;padding:6px 8px;margin-bottom:6px;border-radius:6px;
      border:1px solid #444;background:#1b1b1b;color:#eee}
    #smpUI button{padding:8px 10px;margin-top:8px;width:48%;border-radius:6px;border:1px solid #444;
      background:#222;color:#eee;cursor:pointer}
    #smpUI .cred{padding:8px;margin-top:8px;border:1px solid #333;border-radius:8px;background:#181818}
  `;
  const st = document.createElement('style'); st.textContent = css; document.head.appendChild(st);

  const box = document.createElement('div');
  box.id = 'smpUI';
  box.innerHTML = `
    <h3>SecureMyPass Bot</h3>
    <label>Number of Accounts</label>
    <input id="smpCount" type="number" value="1" min="1"/>
    <div id="smpCreds"></div>
    <div style="display:flex;justify-content:space-between">
      <button id="smpStart">Start</button>
      <button id="smpStop" style="background:#400;border-color:#600">Stop</button>
    </div>
    <div id="smpLog" style="margin-top:6px;font-size:12px;color:#aaa">Idle.</div>
  `;
  document.body.appendChild(box);

  const el = (id) => box.querySelector(id);
  const log = (m) => el('#smpLog').textContent = m;
  const renderCreds = () => {
    const n = parseInt(el('#smpCount').value || '1', 10);
    const wrap = el('#smpCreds');
    wrap.innerHTML = '';
    for (let i=0;i<n;i++){
      const d=document.createElement('div');
      d.className='cred';
      d.innerHTML=`
        <div style="font-weight:600;margin-bottom:4px">Account ${i+1}</div>
        <label>Username</label><input class="smpUser" type="text"/>
        <label>Password</label><input class="smpPass" type="password"/>
      `;
      wrap.appendChild(d);
    }
  };
  renderCreds();
  el('#smpCount').addEventListener('input', renderCreds);

  // --- Helpers ---
  const sleep = (ms) => new Promise(r=>setTimeout(r,ms));
  const waitForXPath = async (xp, {timeout=20000}={})=>{
    const t0=performance.now();
    while(true){
      const res=document.evaluate(xp,document,null,XPathResult.FIRST_ORDERED_NODE_TYPE,null);
      if(res.singleNodeValue) return res.singleNodeValue;
      if(performance.now()-t0>timeout) throw new Error(`Timeout waiting for ${xp}`);
      await sleep(100);
    }
  };
  const setNativeValue=(el,val)=>{
    const {set:v1}=Object.getOwnPropertyDescriptor(el,'value')||{};
    const {set:v2}=Object.getOwnPropertyDescriptor(Object.getPrototypeOf(el),'value')||{};
    (v1||v2).call(el,val);
  };
  const typeIntoEl=async(el,text)=>{
    el.focus(); setNativeValue(el,''); el.dispatchEvent(new Event('input',{bubbles:true}));
    for(const ch of text){
      setNativeValue(el,el.value+ch);
      el.dispatchEvent(new Event('input',{bubbles:true}));
      await sleep(20);
    }
    el.dispatchEvent(new Event('change',{bubbles:true}));
  };
  const pressEnter=(el)=>{
    ['keydown','keypress','keyup'].forEach(t=>{
      el.dispatchEvent(new KeyboardEvent(t,{bubbles:true,key:'Enter',code:'Enter'}));
    });
  };
  const clickNode=(el)=>{ el.scrollIntoView({block:'center'}); el.click(); };

  // --- Core flow ---
  async function runForAccount({username,password}){
    log('Navigating to login…');
    location.href='https://securemypass.com/login';
    await new Promise(r=>{const done=()=>{window.removeEventListener('load',done);r();};
      if(document.readyState==='complete')r();else window.addEventListener('load',done)});
    await sleep(400);

    log('Filling username…');
    const u=await waitForXPath('//*[@id="loginUsername"]');
    await typeIntoEl(u,username);

    log('Filling password…');
    const p=await waitForXPath('//*[@id="loginPassword"]');
    await typeIntoEl(p,password);

    log('Submitting…');
    pressEnter(p);
    await sleep(1500);

    log('Going to My Links…');
    location.href='https://securemypass.com/my-links';
    await new Promise(r=>{const done=()=>{window.removeEventListener('load',done);r();};
      if(document.readyState==='complete')r();else window.addEventListener('load',done)});
    await sleep(500);

    log('Exporting…');
    const exp=await waitForXPath('//*[@id=":r3s:"]',{timeout:30000});
    clickNode(exp);
    log('Export clicked (check downloads)');
    await sleep(1000);
  }

  // --- Buttons ---
  window.__SMP_STOP__=false;
  el('#smpStop').onclick=()=>{window.__SMP_STOP__=true; log('Stopping…');};
  el('#smpStart').onclick=async()=>{
    window.__SMP_STOP__=false;
    const users=[...box.querySelectorAll('.smpUser')].map(i=>i.value.trim());
    const passes=[...box.querySelectorAll('.smpPass')].map(i=>i.value);
    for(let i=0;i<users.length;i++){
      if(window.__SMP_STOP__) break;
      if(!users[i]||!passes[i]){log('Fill all usernames/passwords');return;}
      log(`Running account ${i+1}/${users.length}`);
      try{await runForAccount({username:users[i],password:passes[i]});}
      catch(e){console.error(e);log(`Error: ${e.message}`);}
      await sleep(1000);
    }
    log(window.__SMP_STOP__?'Stopped.':'All done.');
  };
})();

QingJ © 2025

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