Skip to content

Instantly share code, notes, and snippets.

@thibaultmol
Created July 28, 2026 12:17
Show Gist options
  • Select an option

  • Save thibaultmol/db631c246eabfcc5ccec05992054cdf2 to your computer and use it in GitHub Desktop.

Select an option

Save thibaultmol/db631c246eabfcc5ccec05992054cdf2 to your computer and use it in GitHub Desktop.
Extract list of all entries in Vault/bitwarden web vault that contain attachments
(async () => {
const vp = document.querySelector('cdk-virtual-scroll-viewport');
const main = document.getElementById('main-content');
if (!vp) return console.error('no viewport');
const spacer = vp.querySelector('.cdk-virtual-scroll-spacer');
const total = parseInt(spacer.style.height, 10) || spacer.offsetHeight;
const sleep = ms => new Promise(r => setTimeout(r, ms));
const found = new Set();
const step = Math.max(200, (main?.clientHeight || vp.clientHeight) * 0.8);
const scanNow = () => {
vp.querySelectorAll('tr[bitrow]').forEach(tr => {
if (!tr.querySelector('i.bwi-paperclip')) return;
const btn = tr.querySelector('button[bitlink]');
const name = (btn?.textContent || '').trim();
if (name) found.add(name);
});
};
scanNow();
let lastPct = -1;
for (let y = 0; y <= total + step; y += step) {
if (main) main.scrollTop = y;
vp.scrollTop = y;
await new Promise(r => requestAnimationFrame(r));
await sleep(100);
scanNow();
const pct = Math.min(100, Math.round(100 * y / total));
if (pct !== lastPct && pct % 5 === 0) { console.log(`${pct}% — ${found.size} items w/ attachments`); lastPct = pct; }
}
if (main) main.scrollTop = 0; vp.scrollTop = 0;
const names = [...found].sort((a, b) => a.localeCompare(b));
console.log(`%cFound ${names.length} items with attachments:`, 'color:#0a0;font-weight:bold');
console.log(names.join('\n'));
try { await navigator.clipboard.writeText(names.join('\n')); console.log('(copied to clipboard)'); } catch (e) {}
})();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment