diff --git a/public/views/createuser.php b/public/views/createuser.php
index 17ff793..b870686 100644
--- a/public/views/createuser.php
+++ b/public/views/createuser.php
@@ -166,6 +166,14 @@ declare(strict_types=1);
+
+
+
CSV-Vorschau geladen. Passwörter werden geprüft.
+
+
+
@@ -278,14 +286,184 @@ declare(strict_types=1);
});
}
- // Optional: Intercept submit to ensure csvcontent is present when no file is uploaded.
+ // CSV utilities and validation for passwords in preview
+ function parseCsvText(text, delimiter) {
+ const lines = text.split(/\r?\n/).map(l => l.trim()).filter(l => l !== '');
+ if (lines.length === 0) return { headers: [], rows: [] };
+ const headers = lines[0].split(delimiter).map(h => h.trim().replace(/^"|"$/g, ''));
+ const rows = lines.slice(1).map(l => l.split(delimiter).map(c => c.trim().replace(/^"|"$/g, '')));
+ return { headers, rows };
+ }
+
+ function validatePasswordJS(password, sam) {
+ const errors = [];
+ if (!password || password.length < 7) {
+ errors.push('Passwort muss mindestens 7 Zeichen lang sein.');
+ }
+ let categories = 0;
+ if (/[A-Z]/.test(password)) categories++;
+ if (/[a-z]/.test(password)) categories++;
+ if (/\d/.test(password)) categories++;
+ if (/[^A-Za-z0-9]/.test(password)) categories++;
+ if (categories < 3) {
+ errors.push('Passwort muss Zeichen aus mindestens 3 von 4 Kategorien enthalten.');
+ }
+ if (sam) {
+ const pwLower = password.toLowerCase();
+ const samLower = sam.toLowerCase();
+ if (pwLower.includes(samLower)) {
+ errors.push('Passwort darf den Benutzernamen nicht enthalten.');
+ } else {
+ const minLen = 4;
+ if (samLower.length >= minLen) {
+ outer: for (let len = minLen; len <= samLower.length; len++) {
+ for (let s = 0; s <= samLower.length - len; s++) {
+ const sub = samLower.substr(s, len);
+ if (pwLower.includes(sub)) { errors.push('Passwort darf keine größeren Teile des Benutzernamens enthalten.'); break outer; }
+ }
+ }
+ }
+ }
+ }
+ return errors;
+ }
+
+ function renderCsvPreview(text, delimiter) {
+ const parsed = parseCsvText(text, delimiter);
+ const headers = parsed.headers;
+ const rows = parsed.rows;
+ const previewArea = document.getElementById('csvPreviewArea');
+ const previewInfo = document.getElementById('csvPreviewInfo');
+ const table = document.getElementById('csvPreviewTable');
+ table.innerHTML = '';
+ if (headers.length === 0) {
+ previewArea.style.display = 'none';
+ return { invalidCount: 0 };
+ }
+
+ // build header
+ const thead = document.createElement('thead');
+ const trh = document.createElement('tr');
+ headers.forEach(h => { const th = document.createElement('th'); th.textContent = h; trh.appendChild(th); });
+ thead.appendChild(trh);
+ table.appendChild(thead);
+
+ // find indexes
+ const pwdIdx = headers.findIndex(h => /pass(word)?/i.test(h));
+ const samIdx = headers.findIndex(h => /(sam(accountname)?)|samaccountname/i.test(h));
+
+ const tbody = document.createElement('tbody');
+ let invalidCount = 0;
+ rows.forEach((rowArr, rowIndex) => {
+ const tr = document.createElement('tr');
+ rowArr.forEach((cell, colIndex) => {
+ const td = document.createElement('td');
+ const input = document.createElement('input');
+ input.type = 'text';
+ input.value = cell;
+ input.className = 'form-control form-control-sm';
+ input.addEventListener('input', function () {
+ // re-validate this row when edited
+ const currentPwd = (pwdIdx >= 0) ? tr.querySelectorAll('input')[pwdIdx].value : '';
+ const currentSam = (samIdx >= 0) ? tr.querySelectorAll('input')[samIdx].value : '';
+ const errs = validatePasswordJS(currentPwd, currentSam);
+ if (errs.length > 0) {
+ tr.classList.add('table-danger');
+ } else {
+ tr.classList.remove('table-danger');
+ }
+ });
+ td.appendChild(input);
+ tr.appendChild(td);
+ });
+
+ // validate password for this row if applicable
+ if (pwdIdx >= 0) {
+ const pwd = rowArr[pwdIdx] || '';
+ const sam = (samIdx >= 0) ? (rowArr[samIdx] || '') : '';
+ const errs = validatePasswordJS(pwd, sam);
+ if (errs.length > 0) {
+ tr.classList.add('table-danger');
+ invalidCount++;
+ }
+ }
+
+ tbody.appendChild(tr);
+ });
+ table.appendChild(tbody);
+ previewArea.style.display = 'block';
+ previewInfo.textContent = (invalidCount > 0)
+ ? `${invalidCount} Zeile(n) haben ungültige Passwörter. Bitte korrigieren Sie diese in der Tabelle bevor Sie die CSV verarbeiten.`
+ : 'CSV-Vorschau geladen. Alle Passwörter entsprechen den Anforderungen.';
+ return { invalidCount };
+ }
+
+ if (loadBtn) {
+ loadBtn.addEventListener('click', function () {
+ const file = fileInput.files && fileInput.files[0];
+ const delim = document.getElementById('csvdelimiter').value || ',';
+ if (file) {
+ const reader = new FileReader();
+ reader.onload = function (e) {
+ preview.value = e.target.result || '';
+ renderCsvPreview(preview.value, delim);
+ };
+ reader.readAsText(file, 'utf-8');
+ return;
+ }
+ if (preview.value.trim() === '') {
+ alert('Bitte wählen Sie zuerst eine CSV-Datei aus oder fügen Sie CSV-Text direkt in das Feld ein.');
+ return;
+ }
+ renderCsvPreview(preview.value, delim);
+ });
+ }
+
+ if (clearBtn) {
+ clearBtn.addEventListener('click', function () {
+ preview.value = '';
+ fileInput.value = '';
+ document.getElementById('csvPreviewArea').style.display = 'none';
+ });
+ }
+
+ if (fileInput) {
+ fileInput.addEventListener('change', function () {
+ // auto-load content into preview textarea (but do not auto-validate until user clicks 'In Vorschau laden')
+ const file = fileInput.files && fileInput.files[0];
+ if (file) {
+ const reader = new FileReader();
+ reader.onload = function (e) {
+ preview.value = e.target.result || '';
+ };
+ reader.readAsText(file, 'utf-8');
+ }
+ });
+ }
+
+ // Intercept submit: require preview validation or loaded file to have been checked
form.addEventListener('submit', function (e) {
- // If no file was sent, ensure csvcontent isn't empty.
+ const delim = document.getElementById('csvdelimiter').value || ',';
const file = fileInput.files && fileInput.files[0];
- if (!file && preview.value.trim() === '') {
+ // If no preview is present, require user to load preview first to ensure validation
+ if (preview.value.trim() === '') {
+ if (file) {
+ e.preventDefault();
+ alert('Bitte klicken Sie auf "In Vorschau laden" bevor Sie die CSV verarbeiten, damit Passwörter validiert werden.');
+ return false;
+ }
e.preventDefault();
alert('Die CSV-Vorschau ist leer. Bitte wählen Sie eine Datei oder fügen Sie CSV-Inhalt ein.');
+ return false;
}
+
+ const res = renderCsvPreview(preview.value, delim);
+ if (res.invalidCount > 0) {
+ e.preventDefault();
+ alert('Import abgebrochen: Es gibt ungültige Passwörter in der CSV-Vorschau. Bitte korrigieren Sie diese zuerst.');
+ return false;
+ }
+ return true;
});
})();