398 lines
22 KiB
HTML
398 lines
22 KiB
HTML
<!DOCTYPE html>
|
|
<html lang="en">
|
|
<head>
|
|
<meta charset="UTF-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
<title>Payment Recon — Site Explorer</title>
|
|
<style>
|
|
:root{--bg:#080812;--card:#12121f;--accent:#f7931a;--accent2:#00d4aa;--text:#e0e0e0;--muted:#777;--danger:#ff4757;--success:#2ed573;--warning:#ffa502;--radius:10px}
|
|
*{margin:0;padding:0;box-sizing:border-box}
|
|
body{font-family:-apple-system,BlinkMacSystemFont,sans-serif;background:var(--bg);color:var(--text);padding:0.8rem;height:100vh;display:flex;flex-direction:column}
|
|
h1{font-size:1.2rem;background:linear-gradient(135deg,var(--accent),var(--accent2));-webkit-background-clip:text;-webkit-text-fill-color:transparent}
|
|
.sub{color:var(--muted);font-size:0.65rem;margin:0.1rem 0 0.5rem}
|
|
|
|
.toolbar{display:flex;gap:0.5rem;align-items:center;flex-wrap:wrap;padding:0.5rem 0;border-bottom:1px solid rgba(255,255,255,0.05);margin-bottom:0.5rem}
|
|
.toolbar select,.toolbar input{background:rgba(0,0,0,0.4);color:var(--text);border:1px solid rgba(255,255,255,0.1);border-radius:4px;padding:0.35rem 0.5rem;font-size:0.72rem}
|
|
.toolbar input{width:180px}
|
|
.btn{padding:0.35rem 0.8rem;border-radius:4px;border:none;cursor:pointer;font-weight:600;font-size:0.7rem;white-space:nowrap}
|
|
.btn-add{background:var(--accent2);color:#000}
|
|
.btn-remove{background:var(--danger);color:#fff}
|
|
.btn-dork{background:rgba(247,147,26,0.2);color:var(--accent);border:1px solid rgba(247,147,26,0.3)}
|
|
.btn-export{background:rgba(108,99,255,0.2);color:#a78bfa;border:1px solid rgba(108,99,255,0.3)}
|
|
.btn-bulk{background:rgba(6,182,212,0.2);color:#06b6d4;border:1px solid rgba(6,182,212,0.3)}
|
|
.btn:hover{filter:brightness(1.2)}
|
|
|
|
.main{flex:1;display:flex;gap:0.5rem;overflow:hidden}
|
|
.sidebar{width:240px;min-width:200px;background:var(--card);border-radius:var(--radius);padding:0.5rem;overflow-y:auto;border:1px solid rgba(255,255,255,0.05)}
|
|
.sidebar h3{font-size:0.6rem;text-transform:uppercase;letter-spacing:1px;color:var(--muted);margin:0.6rem 0 0.3rem}
|
|
.sidebar h3:first-child{margin-top:0}
|
|
.p-btn{display:block;width:100%;padding:0.25rem 0.5rem;margin:0.1rem 0;background:transparent;border:1px solid rgba(255,255,255,0.05);border-radius:3px;color:var(--text);cursor:pointer;font-size:0.68rem;text-align:left}
|
|
.p-btn:hover{background:rgba(247,147,26,0.08);border-color:var(--accent)}
|
|
.p-btn.active{background:rgba(247,147,26,0.2);border-color:var(--accent);color:var(--accent);font-weight:700}
|
|
.p-btn .c{float:right;color:var(--muted);font-size:0.55rem}
|
|
|
|
.content{flex:1;background:var(--card);border-radius:var(--radius);padding:0.8rem;overflow-y:auto;border:1px solid rgba(255,255,255,0.05)}
|
|
|
|
.tag{display:inline-block;padding:0.1rem 0.35rem;border-radius:3px;font-size:0.6rem;margin:0.1rem;cursor:pointer;font-weight:600}
|
|
.tag:hover{filter:brightness(1.3)}
|
|
.t-gambling{background:rgba(255,71,87,0.2);color:var(--danger)}
|
|
.t-adult{background:rgba(247,147,26,0.2);color:var(--accent)}
|
|
.t-cbd{background:rgba(34,197,94,0.2);color:var(--success)}
|
|
.t-ecommerce{background:rgba(0,212,170,0.2);color:var(--accent2)}
|
|
.t-electronics{background:rgba(59,130,246,0.2);color:#60a5fa}
|
|
.t-nutra{background:rgba(168,85,247,0.2);color:#a78bfa}
|
|
.t-firearms{background:rgba(148,163,184,0.2);color:#94a3b8}
|
|
.t-forex{background:rgba(251,191,36,0.2);color:#fbbf24}
|
|
.t-travel{background:rgba(6,182,212,0.2);color:#06b6d4}
|
|
.t-subscription{background:rgba(236,72,153,0.2);color:#ec4899}
|
|
.t-crypto{background:rgba(247,147,26,0.2);color:var(--accent)}
|
|
.t-gaming{background:rgba(59,130,246,0.2);color:#60a5fa}
|
|
.t-retail{background:rgba(46,213,115,0.2);color:var(--success)}
|
|
.t-active{outline:2px solid #fff}
|
|
|
|
.site-table{width:100%;border-collapse:collapse;font-size:0.72rem}
|
|
.site-table th{text-align:left;padding:0.4rem 0.5rem;border-bottom:1px solid rgba(255,255,255,0.06);font-size:0.58rem;text-transform:uppercase;letter-spacing:1px;color:var(--muted);position:sticky;top:0;background:var(--card)}
|
|
.site-table td{padding:0.35rem 0.5rem;border-bottom:1px solid rgba(255,255,255,0.03)}
|
|
.site-table tr:hover{background:rgba(247,147,26,0.03)}
|
|
.site-table .domain{color:var(--accent2);font-weight:600;cursor:pointer}
|
|
.site-table .domain:hover{text-decoration:underline}
|
|
.site-table .notes{color:var(--muted);font-size:0.65rem;max-width:200px}
|
|
.site-table .actions{white-space:nowrap}
|
|
|
|
.dork-box{font-family:'SF Mono',monospace;font-size:0.65rem;padding:0.3rem 0.5rem;background:rgba(0,0,0,0.4);border-radius:3px;margin:0.2rem 0;border-left:2px solid var(--accent)}
|
|
.dork-box a{color:var(--accent2);text-decoration:none}
|
|
|
|
.modal-overlay{display:none;position:fixed;inset:0;background:rgba(0,0,0,0.7);z-index:100;align-items:center;justify-content:center}
|
|
.modal-overlay.show{display:flex}
|
|
.modal{background:var(--card);padding:1.5rem;border-radius:var(--radius);border:1px solid rgba(255,255,255,0.1);min-width:400px;max-width:600px}
|
|
.modal h3{margin-bottom:1rem}
|
|
.modal label{display:block;font-size:0.65rem;color:var(--muted);margin:0.5rem 0 0.15rem;text-transform:uppercase;letter-spacing:0.5px}
|
|
.modal input,.modal select,.modal textarea{width:100%;background:rgba(0,0,0,0.4);color:var(--text);border:1px solid rgba(255,255,255,0.1);border-radius:4px;padding:0.4rem;font-size:0.75rem}
|
|
.modal textarea{height:80px;font-family:monospace}
|
|
.modal .btn-row{display:flex;gap:0.5rem;margin-top:1rem;justify-content:flex-end}
|
|
|
|
.empty-state{text-align:center;padding:3rem;color:var(--muted)}
|
|
.empty-state .big{font-size:3rem}
|
|
|
|
.dork-open-all{display:flex;gap:0.3rem;flex-wrap:wrap;margin-top:0.5rem}
|
|
|
|
.badge{display:inline-block;padding:0.1rem 0.35rem;border-radius:3px;font-size:0.55rem;font-weight:700}
|
|
.b-ok{background:rgba(46,213,115,0.15);color:var(--success)}
|
|
.b-warn{background:rgba(255,165,2,0.15);color:var(--warning)}
|
|
</style>
|
|
</head>
|
|
<body>
|
|
|
|
<div style="display:flex;justify-content:space-between;align-items:center;">
|
|
<div>
|
|
<h1>🔍 Payment Recon</h1>
|
|
<div class="sub"><span id="stats"></span></div>
|
|
</div>
|
|
<div style="display:flex;gap:0.3rem;">
|
|
<button class="btn btn-add" onclick="showAddModal()">+ Add Site</button>
|
|
<button class="btn btn-bulk" onclick="showBulkModal()">📋 Bulk Import</button>
|
|
<button class="btn btn-dork" onclick="showDorkPanel()">🔍 Dorks</button>
|
|
<button class="btn btn-export" onclick="exportData()">⬇ Export</button>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="toolbar">
|
|
<select id="proc-filter" onchange="applyFilters()"><option value="">All Processors</option></select>
|
|
<select id="industry-filter" onchange="applyFilters()"><option value="">All Industries</option></select>
|
|
<input type="text" id="search-input" placeholder="Search domain..." oninput="applyFilters()">
|
|
<span style="font-size:0.65rem;color:var(--muted);" id="result-count"></span>
|
|
</div>
|
|
|
|
<div class="main">
|
|
<div class="sidebar">
|
|
<h3>HIGH-RISK</h3><div id="hr-nav"></div>
|
|
<h3>MID-TIER</h3><div id="mt-nav"></div>
|
|
<h3>GAMBLING</h3><div id="gb-nav"></div>
|
|
<h3 style="margin-top:0.8rem;">INDUSTRIES</h3><div id="ind-nav" style="line-height:1.8;"></div>
|
|
</div>
|
|
<div class="content" id="content">
|
|
<div class="empty-state"><div class="big">🔍</div><p>No sites cataloged yet.</p><p style="font-size:0.7rem;margin-top:0.3rem;">Click "+ Add Site" to start building your database,<br>or use the Dorks panel to discover real sites on Google.</p></div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- ADD SITE MODAL -->
|
|
<div class="modal-overlay" id="add-modal">
|
|
<div class="modal">
|
|
<h3>Add Site</h3>
|
|
<label>Domain</label><input type="text" id="add-domain" placeholder="store.example.com">
|
|
<label>Processor</label><select id="add-proc"></select>
|
|
<label>Industry</label><select id="add-industry">
|
|
<option>ecommerce</option><option>electronics</option><option>gambling</option><option>adult</option><option>cbd</option><option>nutra</option><option>firearms</option><option>forex</option><option>crypto</option><option>travel</option><option>subscription</option><option>gaming</option><option>retail</option>
|
|
</select>
|
|
<label>Notes</label><textarea id="add-notes" placeholder="What does this site sell? How did you find it?"></textarea>
|
|
<div class="btn-row">
|
|
<button class="btn" onclick="closeModal('add-modal')" style="background:var(--muted)">Cancel</button>
|
|
<button class="btn btn-add" onclick="addSite()">Add Site</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- BULK IMPORT MODAL -->
|
|
<div class="modal-overlay" id="bulk-modal">
|
|
<div class="modal">
|
|
<h3>Bulk Import</h3>
|
|
<label>Paste domains (one per line) with optional industry</label>
|
|
<textarea id="bulk-text" placeholder="store.example.com electronics casino-site.com gambling shop.example.com ecommerce"></textarea>
|
|
<label>Default Processor</label><select id="bulk-proc"></select>
|
|
<label>Default Industry</label><select id="bulk-industry"><option>ecommerce</option><option>electronics</option><option>gambling</option><option>adult</option><option>cbd</option><option>nutra</option><option>firearms</option><option>forex</option><option>crypto</option><option>travel</option><option>subscription</option><option>gaming</option><option>retail</option></select>
|
|
<div class="btn-row">
|
|
<button class="btn" onclick="closeModal('bulk-modal')" style="background:var(--muted)">Cancel</button>
|
|
<button class="btn btn-add" onclick="bulkImport()">Import</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- DORK PANEL -->
|
|
<div class="modal-overlay" id="dork-modal">
|
|
<div class="modal">
|
|
<h3>Google Dorks — Find Real Sites</h3>
|
|
<div id="dork-proc-select" style="margin-bottom:0.5rem;">
|
|
<select id="dork-proc" onchange="showDorks()"></select>
|
|
<select id="dork-industry" onchange="showDorks()"><option value="">+ industry filter</option></select>
|
|
</div>
|
|
<div id="dork-results"></div>
|
|
<div class="btn-row">
|
|
<button class="btn btn-dork" onclick="document.querySelectorAll('#dork-results a').forEach(a=>window.open(a.href,'_blank'))">Open All in Tabs</button>
|
|
<button class="btn" onclick="closeModal('dork-modal')" style="background:var(--muted)">Close</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<script>
|
|
// ─── PROCESSOR DATABASE (no fake sites, just metadata + dorks) ───
|
|
const DB = {
|
|
"PaymentCloud":{type:"highrisk",url:"paymentcloud.com",inds:["gambling","adult","cbd","nutra","firearms","crypto","subscription"],
|
|
dorks:['"PaymentCloud" site:*.com -site:paymentcloud.com','"powered by PaymentCloud"','inurl:checkout "PaymentCloud"']},
|
|
"eMerchantBroker":{type:"highrisk",url:"emerchantbroker.com",inds:["gambling","adult","cbd","nutra","subscription","forex","crypto"],
|
|
dorks:['"eMerchantBroker" site:*.com -site:emerchantbroker.com','"powered by eMerchantBroker"','inurl:checkout "eMerchantBroker"']},
|
|
"PayKings":{type:"highrisk",url:"paykings.com",inds:["gambling","adult","cbd","firearms","nutra"],
|
|
dorks:['"PayKings" site:*.com -site:paykings.com','"processed by PayKings"']},
|
|
"Soar Payments":{type:"highrisk",url:"soarpay.com",inds:["gambling","adult","cbd","nutra","travel","subscription"],
|
|
dorks:['"Soar Payments" site:*.com -site:soarpay.com','"powered by Soar" payment']},
|
|
"Durango Merchant":{type:"highrisk",url:"durangomerchantservices.com",inds:["gambling","adult","firearms","nutra","subscription"],
|
|
dorks:['"Durango Merchant" site:*.com -site:durangomerchantservices.com','"processed by Durango"']},
|
|
"Helcim":{type:"midtier",url:"helcim.com",inds:["ecommerce","electronics","retail"],
|
|
dorks:['site:*.com "js.helcim.com"','"Powered by Helcim"','"Helcim" inurl:checkout -site:helcim.com']},
|
|
"CardX":{type:"midtier",url:"cardx.com",inds:["ecommerce","subscription"],
|
|
dorks:['"CardX" site:*.com -site:cardx.com','"powered by CardX"','inurl:payment "CardX"']},
|
|
"Forte":{type:"midtier",url:"forte.net",inds:["ecommerce","subscription"],
|
|
dorks:['"Forte Payments" site:*.com -site:forte.net','"forte.net" checkout']},
|
|
"CDGcommerce":{type:"midtier",url:"cdgcommerce.com",inds:["ecommerce","electronics"],
|
|
dorks:['"CDGcommerce" site:*.com -site:cdgcommerce.com','"powered by CDGcommerce"']},
|
|
"Adyen":{type:"midtier",url:"adyen.com",inds:["ecommerce","electronics","travel","subscription","gambling","gaming"],
|
|
dorks:['site:*.com "checkout.adyen.com"','"Powered by Adyen"','"Adyen" inurl:checkout -site:adyen.com']},
|
|
"Stripe":{type:"midtier",url:"stripe.com",inds:["ecommerce","electronics","subscription","travel","retail"],
|
|
dorks:['site:*.com "js.stripe.com"','"Powered by Stripe"','"stripe.com/checkout" site:*.com']},
|
|
"MuchBetter":{type:"gambling",url:"muchbetter.com",inds:["gambling"],
|
|
dorks:['"Pay with MuchBetter" casino OR betting','"MuchBetter" inurl:deposit','"MuchBetter" casino OR sportsbook']},
|
|
"AstroPay":{type:"gambling",url:"astropay.com",inds:["gambling","forex"],
|
|
dorks:['"AstroPay" casino OR betting OR sportsbook','"Pay with AstroPay" site:*.com']},
|
|
"Trustly":{type:"gambling",url:"trustly.com",inds:["gambling","ecommerce","travel"],
|
|
dorks:['"Trustly" casino OR betting OR sportsbook','"Pay with Trustly" site:*.com','"Trustly" "Pay N Play" casino']},
|
|
"Zimpler":{type:"gambling",url:"zimpler.com",inds:["gambling"],
|
|
dorks:['"Zimpler" casino OR betting','"Pay with Zimpler" site:*.com']},
|
|
"Interac":{type:"gambling",url:"interac.ca",inds:["gambling"],
|
|
dorks:['"Interac" casino OR betting site:*.ca','"Pay with Interac" casino']},
|
|
};
|
|
|
|
// ─── STATE (localStorage) ───
|
|
const STORAGE_KEY = 'payment_recon_sites';
|
|
let sites = JSON.parse(localStorage.getItem(STORAGE_KEY) || '[]');
|
|
let activeProc = null;
|
|
let activeInd = null;
|
|
|
|
// ─── INIT ───
|
|
function init(){
|
|
buildSidebar();
|
|
populateFilters();
|
|
applyFilters();
|
|
updateStats();
|
|
}
|
|
function buildSidebar(){
|
|
const sections={hr:[],mt:[],gb:[]};
|
|
for(const[n,p]of Object.entries(DB)){
|
|
if(p.type==='highrisk') sections.hr.push(n);
|
|
else if(p.type==='midtier') sections.mt.push(n);
|
|
else sections.gb.push(n);
|
|
}
|
|
for(const[id,names]of Object.entries({hr:'hr-nav',mt:'mt-nav',gb:'gb-nav'})){
|
|
document.getElementById(id).innerHTML=names.map(n=>{
|
|
const count=sites.filter(s=>s.processor===n).length;
|
|
return `<button class="p-btn" onclick="filterByProc('${n}')" id="pbtn-${n.replace(/\s/g,'')}">${n}<span class="c">${count}</span></button>`;
|
|
}).join('');
|
|
}
|
|
// Industries
|
|
const ics={};
|
|
for(const[,p]of Object.entries(DB)) for(const i of p.inds) ics[i]=(ics[i]||0)+1;
|
|
document.getElementById('ind-nav').innerHTML=Object.entries(ics).sort((a,b)=>b[1]-a[1]).map(([i,c])=>
|
|
`<span class="tag t-${i}" onclick="filterByInd('${i}')" id="itag-${i}">${i} (${c})</span>`
|
|
).join(' ');
|
|
}
|
|
function populateFilters(){
|
|
const ps=document.getElementById('proc-filter');
|
|
ps.innerHTML='<option value="">All Processors</option>'+Object.keys(DB).map(n=>`<option>${n}</option>`).join('');
|
|
const allInds=new Set();
|
|
for(const[,p]of Object.entries(DB)) for(const i of p.inds) allInds.add(i);
|
|
const is=document.getElementById('industry-filter');
|
|
is.innerHTML='<option value="">All Industries</option>'+[...allInds].sort().map(i=>`<option>${i}</option>`).join('');
|
|
// Modals
|
|
document.getElementById('add-proc').innerHTML=Object.keys(DB).map(n=>`<option>${n}</option>`).join('');
|
|
document.getElementById('bulk-proc').innerHTML='<option value="">-- Select --</option>'+Object.keys(DB).map(n=>`<option>${n}</option>`).join('');
|
|
document.getElementById('dork-proc').innerHTML='<option value="">-- Select Processor --</option>'+Object.keys(DB).map(n=>`<option>${n}</option>`).join('');
|
|
const di=document.getElementById('dork-industry');
|
|
di.innerHTML='<option value="">+ industry filter</option>'+[...allInds].sort().map(i=>`<option>${i}</option>`).join('');
|
|
}
|
|
|
|
// ─── FILTERS ───
|
|
function filterByProc(name){
|
|
activeProc=(activeProc===name)?null:name;activeInd=null;
|
|
document.querySelectorAll('.p-btn').forEach(b=>b.classList.remove('active'));
|
|
if(activeProc) document.getElementById('pbtn-'+name.replace(/\s/g,'')).classList.add('active');
|
|
document.querySelectorAll('.tag').forEach(t=>t.classList.remove('t-active'));
|
|
document.getElementById('proc-filter').value=activeProc||'';
|
|
document.getElementById('industry-filter').value='';
|
|
applyFilters();
|
|
}
|
|
function filterByInd(ind){
|
|
activeInd=(activeInd===ind)?null:ind;activeProc=null;
|
|
document.querySelectorAll('.tag').forEach(t=>t.classList.remove('t-active'));
|
|
if(activeInd) document.getElementById('itag-'+ind)?.classList.add('t-active');
|
|
document.querySelectorAll('.p-btn').forEach(b=>b.classList.remove('active'));
|
|
document.getElementById('proc-filter').value='';
|
|
document.getElementById('industry-filter').value=activeInd||'';
|
|
applyFilters();
|
|
}
|
|
function applyFilters(){
|
|
const pf=document.getElementById('proc-filter').value;
|
|
const inf=document.getElementById('industry-filter').value;
|
|
const q=document.getElementById('search-input').value.toLowerCase();
|
|
if(pf) activeProc=pf;
|
|
if(inf) activeInd=inf;
|
|
|
|
let filtered=sites;
|
|
if(activeProc) filtered=filtered.filter(s=>s.processor===activeProc);
|
|
if(activeInd) filtered=filtered.filter(s=>s.industry===activeInd);
|
|
if(q) filtered=filtered.filter(s=>s.domain.toLowerCase().includes(q)||(s.notes||'').toLowerCase().includes(q));
|
|
|
|
renderSites(filtered);
|
|
document.getElementById('result-count').textContent=`${filtered.length} site${filtered.length!==1?'s':''}`;
|
|
}
|
|
|
|
// ─── RENDER ───
|
|
function renderSites(list){
|
|
const c=document.getElementById('content');
|
|
if(!list.length){
|
|
c.innerHTML=`<div class="empty-state"><div class="big">🔍</div><p>No sites match your filters.</p><p style="font-size:0.7rem;margin-top:0.3rem;">Click <strong>+ Add Site</strong> or use <strong>Dorks</strong> to find real sites on Google.</p></div>`;
|
|
return;
|
|
}
|
|
c.innerHTML=`
|
|
<table class="site-table">
|
|
<thead><tr><th>Domain</th><th>Processor</th><th>Industry</th><th>Notes</th><th></th></tr></thead>
|
|
<tbody>${list.map((s,i)=>{
|
|
const idx=sites.indexOf(s);
|
|
return `<tr>
|
|
<td><span class="domain" onclick="window.open('https://${s.domain}','_blank')">${s.domain}</span></td>
|
|
<td><span style="color:var(--accent);cursor:pointer;font-size:0.68rem;" onclick="filterByProc('${s.processor}')">${s.processor}</span></td>
|
|
<td><span class="tag t-${s.industry}" onclick="filterByInd('${s.industry}')">${s.industry}</span></td>
|
|
<td class="notes">${s.notes||''}</td>
|
|
<td class="actions"><button class="btn btn-remove" style="padding:0.15rem 0.4rem;font-size:0.6rem;" onclick="removeSite(${idx})">✕</button></td>
|
|
</tr>`;
|
|
}).join('')}</tbody>
|
|
</table>`;
|
|
}
|
|
|
|
// ─── CRUD ───
|
|
function showAddModal(){document.getElementById('add-modal').classList.add('show')}
|
|
function showBulkModal(){document.getElementById('bulk-modal').classList.add('show')}
|
|
function showDorkPanel(){document.getElementById('dork-modal').classList.add('show');showDorks();}
|
|
function closeModal(id){document.getElementById(id).classList.remove('show')}
|
|
|
|
function addSite(){
|
|
const d=document.getElementById('add-domain').value.trim().replace(/^https?:\/\//,'').replace(/\/.*/,'');
|
|
const p=document.getElementById('add-proc').value;
|
|
const i=document.getElementById('add-industry').value;
|
|
const n=document.getElementById('add-notes').value.trim();
|
|
if(!d||!p||!i) return alert('Domain, processor, and industry required');
|
|
sites.push({domain:d,processor:p,industry:i,notes:n,added:new Date().toISOString()});
|
|
save();
|
|
closeModal('add-modal');
|
|
document.getElementById('add-domain').value='';
|
|
document.getElementById('add-notes').value='';
|
|
buildSidebar();
|
|
applyFilters();
|
|
updateStats();
|
|
}
|
|
|
|
function bulkImport(){
|
|
const text=document.getElementById('bulk-text').value.trim();
|
|
const defProc=document.getElementById('bulk-proc').value;
|
|
const defInd=document.getElementById('bulk-industry').value;
|
|
if(!text) return;
|
|
const lines=text.split('\n').map(l=>l.trim()).filter(l=>l);
|
|
let added=0;
|
|
for(const line of lines){
|
|
const parts=line.split(/\s+/);
|
|
const domain=parts[0].replace(/^https?:\/\//,'').replace(/\/.*/,'');
|
|
const industry=parts[1]||defInd;
|
|
if(!domain||!defProc) continue;
|
|
if(sites.find(s=>s.domain===domain&&s.processor===defProc)) continue;
|
|
sites.push({domain,processor:defProc,industry,notes:'',added:new Date().toISOString()});
|
|
added++;
|
|
}
|
|
save();
|
|
closeModal('bulk-modal');
|
|
document.getElementById('bulk-text').value='';
|
|
buildSidebar();
|
|
applyFilters();
|
|
updateStats();
|
|
}
|
|
|
|
function removeSite(idx){
|
|
if(confirm('Remove '+sites[idx].domain+'?')){
|
|
sites.splice(idx,1);
|
|
save();
|
|
buildSidebar();
|
|
applyFilters();
|
|
updateStats();
|
|
}
|
|
}
|
|
|
|
function save(){localStorage.setItem(STORAGE_KEY,JSON.stringify(sites))}
|
|
function updateStats(){
|
|
document.getElementById('stats').textContent=`${Object.keys(DB).length} processors · ${sites.length} sites cataloged`;
|
|
}
|
|
|
|
function exportData(){
|
|
const blob=new Blob([JSON.stringify(sites,null,2)],{type:'application/json'});
|
|
const a=document.createElement('a');a.href=URL.createObjectURL(blob);
|
|
a.download='payment-recon-sites.json';a.click();
|
|
}
|
|
|
|
// ─── DORKS ───
|
|
function showDorks(){
|
|
const proc=document.getElementById('dork-proc').value;
|
|
const ind=document.getElementById('dork-industry').value;
|
|
const r=document.getElementById('dork-results');
|
|
if(!proc){r.innerHTML='<p style="color:var(--muted);font-size:0.7rem;">Select a processor to see Google dorks.</p>';return}
|
|
const p=DB[proc];
|
|
let dorks=p.dorks.slice();
|
|
if(ind) dorks=dorks.map(d=>d+' '+ind);
|
|
r.innerHTML=dorks.map(d=>`<div class="dork-box"><a href="https://www.google.com/search?q=${encodeURIComponent(d)}" target="_blank">🔗 ${d}</a></div>`).join('');
|
|
}
|
|
|
|
// Keyboard shortcuts
|
|
document.addEventListener('keydown',e=>{
|
|
if(e.key==='Escape'){document.querySelectorAll('.modal-overlay.show').forEach(m=>m.classList.remove('show'))}
|
|
if((e.metaKey||e.ctrlKey)&&e.key==='n'){e.preventDefault();showAddModal()}
|
|
});
|
|
|
|
init();
|
|
</script>
|
|
</body>
|
|
</html>
|