Wachtwoordgenerator
Genereer sterke of makkelijk te onthouden wachtwoorden met entropy-berekening en geschiedenis.
Sterk wachtwoord
Volledig willekeurig, maximale entropie.
Makkelijk wachtwoord
Leesbare blokken – eenvoudig te onthouden, toch sterk.
Geschiedenis
Gegenereerde wachtwoorden deze sessie. Niet opgeslagen na sluiten.
(function(){ const btn=document.querySelector('[data-theme-toggle]'); const root=document.documentElement; let dark=root.getAttribute('data-theme')==='dark'; function apply(){ root.setAttribute('data-theme',dark?'dark':'light'); if(btn)btn.innerHTML=dark? '': ''; } apply(); btn&&btn.addEventListener('click',()=>{dark=!dark;apply()}); })(); function tick(){const n=new Date();const el=document.getElementById('liveTime');if(el)el.textContent=n.toLocaleTimeString('nl-NL',{hour:'2-digit',minute:'2-digit',second:'2-digit'})} tick();setInterval(tick,1000);
const CHARS={lower:'abcdefghjkmnpqrstuvwxyz',upper:'ABCDEFGHJKLMNPQRSTUVWXYZ',digits:'23456789',symbols:'!@#$%&*+=?-_'}; const CONS='bcdfghjklmnpqrstvwxyz',VOWS='aeiou'; function ri(max){const a=new Uint32Array(1);crypto.getRandomValues(a);return a[0]%max} function pc(s){return s[ri(s.length)]} function shuffle(arr){const a=[...arr];for(let i=a.length-1;i>0;i--){const j=ri(i+1);[a[i],a[j]]=[a[j],a[i]];}return a}
function genStrong(){
const pools=[];
if(document.getElementById('useLower').checked)pools.push(CHARS.lower);
if(document.getElementById('useUpper').checked)pools.push(CHARS.upper);
if(document.getElementById('useNums').checked)pools.push(CHARS.digits);
if(document.getElementById('useSymbols').checked)pools.push(CHARS.symbols);
if(!pools.length){document.getElementById('pwOutput').textContent='Selecteer minstens 1 optie.';return''}
const len=+document.getElementById('lengthSlider').value;
const mandatory=pools.map(p=>pc(p));
const all=pools.join('');
while(mandatory.length
function mkBlock(caps){let b=pc(CONS)+pc(VOWS)+pc(VOWS)+pc(CONS);return caps?b[0].toUpperCase()+b.slice(1):b} function genPP(){ const n=+document.getElementById('blockCount').value; const caps=document.getElementById('ppCaps').checked; const nums=document.getElementById('ppNums').checked; const sym=document.getElementById('ppSymbol').checked; const dash=document.getElementById('ppDash').checked; const sep=dash?'-':''; const blocks=Array.from({length:n},()=>mkBlock(caps)); let pw=blocks.join(sep); if(nums)pw+=String(ri(90)+10); if(sym)pw+='!'; const bd=document.getElementById('ppBreakdown'); const bdc=document.getElementById('ppBreakdownContent'); bd.style.display='block'; const cols=['var(--primary)','var(--blue)','var(--green)','var(--orange)','var(--red)']; let html=blocks.map((b,i)=>`${b}`).join(''); if(nums)html+=`+getal`; if(sym)html+=`+!`; bdc.innerHTML=html; document.getElementById('ppOutput').textContent=pw; updateStr(pw,'ppStrengthFill','ppStrengthLabel','ppStrengthScore'); return pw; }
function updateStr(pw,fillId,labelId,scoreId){ let s=0; if(pw.length>=8)s+=15;if(pw.length>=12)s+=15;if(pw.length>=16)s+=15;if(pw.length>=20)s+=5; if(/[a-z]/.test(pw))s+=12;if(/[A-Z]/.test(pw))s+=12;if(/\d/.test(pw))s+=12;if(/[^A-Za-z0-9]/.test(pw))s+=14; s=Math.min(s,100); const fill=document.getElementById(fillId); const label=document.getElementById(labelId); const score=document.getElementById(scoreId); fill.style.width=s+'%'; let lbl,col; if(s>=85){lbl='Zeer sterk';col='var(--green)'} else if(s>=65){lbl='Sterk';col='var(--blue)'} else if(s>=45){lbl='Gemiddeld';col='var(--orange)'} else{lbl='Zwak';col='var(--red)'} fill.style.background=`linear-gradient(90deg,${col},${col}99)`; label.textContent=lbl;label.style.color=col; score.textContent=s+'/100'; }
const hist=[]; function addHist(pw,type){hist.unshift({pw,type});if(hist.length>20)hist.pop();renderHist()} function renderHist(){ const el=document.getElementById('historyList'); if(!hist.length){el.innerHTML='
';return} el.innerHTML=hist.map(h=>`
${h.type}
`).join(''); }
async function cp(text,btn){ try{await navigator.clipboard.writeText(text)}catch{const t=document.createElement('textarea');t.value=text;document.body.appendChild(t);t.select();document.execCommand('copy');t.remove()} if(btn){const o=btn.textContent;btn.textContent='✓';btn.classList.add('copied');setTimeout(()=>{btn.textContent=o;btn.classList.remove('copied')},1800)} }
document.getElementById('lengthSlider').addEventListener('input',e=>document.getElementById('lengthVal').textContent=e.target.value);
document.getElementById('genPwBtn').addEventListener('click',()=>{const pw=genStrong();if(pw)addHist(pw,'Sterk')});
document.getElementById('genPpBtn').addEventListener('click',()=>{const pp=genPP();if(pp)addHist(pp,'Makkelijk')});
document.getElementById('copyPwBtn').addEventListener('click',function(){cp(document.getElementById('pwOutput').textContent,this)});
document.getElementById('copyPpBtn').addEventListener('click',function(){cp(document.getElementById('ppOutput').textContent,this)});
document.getElementById('clearHistoryBtn').addEventListener('click',()=>{hist.length=0;renderHist()});
genStrong();genPP();