Files
ccsite-manager/payment-recon.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&#10;casino-site.com gambling&#10;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>