diff --git a/cmdb b/cmdb index 805f0fe..63caa76 160000 --- a/cmdb +++ b/cmdb @@ -1 +1 @@ -Subproject commit 805f0fe00b1314970a95c717c2945102130a0fd4 +Subproject commit 63caa769a0646db22b4a8381742a456739f95ddb diff --git a/password-generator/password_generator.html b/password-generator/password_generator.html index fd36986..aee520e 100644 --- a/password-generator/password_generator.html +++ b/password-generator/password_generator.html @@ -73,7 +73,6 @@ .psw-txt b{display:block;font-size:13px;color:var(--ink);font-weight:600;white-space:nowrap;overflow:hidden;text-overflow:ellipsis} .psw-txt small{display:block;font-size:10.5px;color:var(--muted);white-space:nowrap;overflow:hidden;text-overflow:ellipsis} .sidebar-footer{margin-top:auto;display:flex;flex-direction:column;gap:7px;padding-top:14px;border-top:1px solid var(--border)} - .db-status{font-size:11px;color:var(--muted);padding:4px 8px;word-break:break-word;line-height:1.5} /* ---------- main ---------- */ main{flex:1;padding:30px 36px;max-width:1100px;min-width:0} @@ -244,7 +243,6 @@
PréférencesRéglages du générateur
-
chargement…
@@ -768,13 +766,6 @@ function applyAdFromMap(map){ }else AD_CFG = null; } function renderAdStatus(){ - const status = document.getElementById('adStatus'); - if(!SERVER_MODE){ - status.innerHTML = '● Base locale (localStorage)'; - }else{ - const ad = AD_CFG ? 'AD : ' + (AD_CFG.label || AD_CFG.host) : 'AD non configuré'; - status.innerHTML = '● Base partagée (v' + dbVersion + ')
' + ad + ''; - } const hint = document.getElementById('adHint'); if(hint) hint.textContent = AD_CFG ? '' : 'Recherche AD indisponible : configurez l’AD dans Préférences CMDB (base partagée).'; @@ -1054,6 +1045,15 @@ function fillTplHtml(text, ctx){ réinterprétées) — un mot de passe contenant * ou ` ne casse donc rien. ========================================================================== */ function emailEsc(s){ return String(s == null ? '' : s).replace(/[&<>]/g, c => ({'&':'&','<':'<','>':'>'}[c])); } +/* URL sûre en attribut : whitelist de scheme + échappe les guillemets. + Neutralise javascript:, data:text/html, vbscript:… → « # » si scheme non autorisé. + (emailEsc a déjà neutralisé & < > ; il reste les " qui casseraient l'attribut.) */ +function emailUrl(u){ + const s = String(u == null ? '' : u).trim(); + const sch = /^([a-z][a-z0-9+.\-]*):/i.exec(s); + const ok = !sch || /^(https?|mailto|tel)$/i.test(sch[1]) || /^data:image\//i.test(s); + return (ok ? s : '#').replace(/"/g, '"'); +} function emailFillVars(html, ctx){ return html.replace(/\{\{\s*(\w+)\s*\}\}/g, (m, k) => { if(!(k in ctx)) return m; @@ -1068,7 +1068,7 @@ function renderEmailHtml(src, ctx){ const inline = t => t .replace(/`([^`]+)`/g, '$1') .replace(/\*\*([^*]+)\*\*/g, '$1') - .replace(/\[([^\]]+)\]\(([^)\s]+)\)/g, '$1'); + .replace(/\[([^\]]+)\]\(([^)\s]+)\)/g, (mm, txt, url) => '' + txt + ''); let html = '', i = 0, m; while(i < lines.length){ const line = lines[i]; @@ -1076,18 +1076,18 @@ function renderEmailHtml(src, ctx){ const color = m[1] || '#5b9cf5', buf = []; for(i++; i < lines.length && !/^:::\s*$/.test(lines[i]); i++) buf.push(lines[i]); i++; - html += '
' + inline(buf.join('
')) + '
'; + html += '
' + inline(buf.join('
')) + '
'; continue; } if(/^```/.test(line)){ const buf = []; for(i++; i < lines.length && !/^```/.test(lines[i]); i++) buf.push(lines[i]); i++; - html += '
' + buf.join('\n') + '
'; + html += '
' + buf.join('\n') + '
'; continue; } if(m = line.match(/^!\[([^\]]*)\]\(([^)]+)\)\s*$/)){ - html += '
' + m[1] + '
'; + html += '
' + m[1].replace(/
'; i++; continue; } if(/^---+\s*$/.test(line)){ html += '
'; i++; continue; }