PWA (neue Dateien): - Vollständige Progressive Web App mit Token-basierter Auth - 4 Swipe-Panels: Alle STZ, Stundenzettel, Produktliste, Lieferauflistung - Kundensuche, Leistungen-Accordion, Mehraufwand-Sektion - Produkt-Übernahme aus Auftrag + Mehraufwand in STZ - Service Worker, Manifest, App-Icons für Installation Desktop-Änderungen: - Produktliste: Checkboxen immer sichtbar (außer bereits auf STZ) - Lieferauflistung: Vereinfachte Ansicht (nur Verbaut-Spalte) - Admin: PWA-Link in Einstellungen - Sprachdatei: PWA-Übersetzungen Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
144 lines
4 KiB
PHP
144 lines
4 KiB
PHP
<?php
|
|
/* Copyright (C) 2026 Eduard Wisch <data@data-it-solution.de>
|
|
*
|
|
* Stundenzettel PWA - Token-basierte Authentifizierung
|
|
*/
|
|
|
|
if (!defined('NOLOGIN')) {
|
|
define('NOLOGIN', '1');
|
|
}
|
|
if (!defined('NOREQUIREMENU')) {
|
|
define('NOREQUIREMENU', '1');
|
|
}
|
|
if (!defined('NOREQUIREHTML')) {
|
|
define('NOREQUIREHTML', '1');
|
|
}
|
|
if (!defined('NOREQUIREAJAX')) {
|
|
define('NOREQUIREAJAX', '1');
|
|
}
|
|
|
|
// Dolibarr-Umgebung laden
|
|
$res = 0;
|
|
if (!$res && file_exists("../../main.inc.php")) $res = @include "../../main.inc.php";
|
|
if (!$res && file_exists("../../../main.inc.php")) $res = @include "../../../main.inc.php";
|
|
if (!$res && file_exists("../../../../main.inc.php")) $res = @include "../../../../main.inc.php";
|
|
if (!$res) die(json_encode(array('success' => false, 'error' => 'Dolibarr nicht geladen')));
|
|
|
|
header('Content-Type: application/json; charset=UTF-8');
|
|
|
|
$action = GETPOST('action', 'aZ09');
|
|
$response = array('success' => false);
|
|
|
|
switch ($action) {
|
|
case 'login':
|
|
$username = GETPOST('username', 'alphanohtml');
|
|
$password = GETPOST('password', 'none');
|
|
|
|
if (empty($username) || empty($password)) {
|
|
$response['error'] = 'Benutzername und Passwort erforderlich';
|
|
break;
|
|
}
|
|
|
|
// Brute-Force-Schutz
|
|
usleep(100000); // 100ms Verzoegerung
|
|
|
|
require_once DOL_DOCUMENT_ROOT.'/user/class/user.class.php';
|
|
$userLogin = new User($db);
|
|
|
|
// Benutzer per Login suchen
|
|
$sql = "SELECT rowid FROM ".MAIN_DB_PREFIX."user WHERE login = '".$db->escape($username)."' AND statut = 1";
|
|
$result = $db->query($sql);
|
|
|
|
if ($result && $db->num_rows($result) > 0) {
|
|
$obj = $db->fetch_object($result);
|
|
$userLogin->fetch($obj->rowid);
|
|
$userLogin->getrights();
|
|
|
|
// Passwort pruefen
|
|
require_once DOL_DOCUMENT_ROOT.'/core/lib/security2.lib.php';
|
|
|
|
$passOk = false;
|
|
if (!empty($userLogin->pass_indatabase_crypted)) {
|
|
$passOk = dol_verifyHash($password, $userLogin->pass_indatabase_crypted);
|
|
}
|
|
|
|
if ($passOk) {
|
|
// Stundenzettel-Berechtigung pruefen
|
|
if ($userLogin->hasRight('stundenzettel', 'read')) {
|
|
// Token generieren (15 Tage gueltig)
|
|
$tokenData = array(
|
|
'user_id' => $userLogin->id,
|
|
'login' => $userLogin->login,
|
|
'created' => time(),
|
|
'expires' => time() + (15 * 24 * 60 * 60),
|
|
'hash' => md5($userLogin->id . $userLogin->login . getDolGlobalString('MAIN_SECURITY_SALT', 'defaultsalt'))
|
|
);
|
|
$token = base64_encode(json_encode($tokenData));
|
|
|
|
$response['success'] = true;
|
|
$response['token'] = $token;
|
|
$response['user'] = array(
|
|
'id' => $userLogin->id,
|
|
'login' => $userLogin->login,
|
|
'name' => $userLogin->getFullName($langs)
|
|
);
|
|
} else {
|
|
$response['error'] = 'Keine Berechtigung fuer Stundenzettel';
|
|
}
|
|
} else {
|
|
$response['error'] = 'Falsches Passwort';
|
|
}
|
|
} else {
|
|
$response['error'] = 'Benutzer nicht gefunden';
|
|
}
|
|
break;
|
|
|
|
case 'verify':
|
|
$token = GETPOST('token', 'none');
|
|
|
|
if (empty($token)) {
|
|
$response['error'] = 'Kein Token';
|
|
break;
|
|
}
|
|
|
|
$tokenData = json_decode(base64_decode($token), true);
|
|
|
|
if (!$tokenData || empty($tokenData['user_id']) || empty($tokenData['expires'])) {
|
|
$response['error'] = 'Ungueltiges Token';
|
|
break;
|
|
}
|
|
|
|
// Ablaufdatum pruefen
|
|
if ($tokenData['expires'] < time()) {
|
|
$response['error'] = 'Token abgelaufen';
|
|
break;
|
|
}
|
|
|
|
// Hash verifizieren
|
|
$expectedHash = md5($tokenData['user_id'] . $tokenData['login'] . getDolGlobalString('MAIN_SECURITY_SALT', 'defaultsalt'));
|
|
if ($tokenData['hash'] !== $expectedHash) {
|
|
$response['error'] = 'Token manipuliert';
|
|
break;
|
|
}
|
|
|
|
// Benutzer noch aktiv?
|
|
require_once DOL_DOCUMENT_ROOT.'/user/class/user.class.php';
|
|
$userCheck = new User($db);
|
|
if ($userCheck->fetch($tokenData['user_id']) > 0 && $userCheck->statut == 1) {
|
|
$response['success'] = true;
|
|
$response['user'] = array(
|
|
'id' => $userCheck->id,
|
|
'login' => $userCheck->login,
|
|
'name' => $userCheck->getFullName($langs)
|
|
);
|
|
} else {
|
|
$response['error'] = 'Benutzer nicht mehr aktiv';
|
|
}
|
|
break;
|
|
|
|
default:
|
|
$response['error'] = 'Unbekannte Aktion';
|
|
}
|
|
|
|
echo json_encode($response);
|
|
$db->close();
|