kundenkarte/pwa_auth.php
data 16e51a799a feat(v8.6): Räumlichkeit, Verteilungs-Tabellen, Bundled-Terminals, PWA-Updates
- output_location (Räumlichkeit): Neues Textfeld am Abgang für Raum/Ort des
  Verbrauchers. DB-Migration, Backend (AJAX), Frontend (Website + PWA),
  Anzeige im Schaltplan (kursiv) und in PDF-Tabellen.
- Verteilungs-Tabellen: Kundenansicht (A4, Nr/Verbraucher/Räumlichkeit) und
  Technikeransicht (A4, R.Klem/FI/Nr/Verbraucher/Räumlichkeit/Typ) im
  Leitungslaufplan-PDF. Gruppiert nach Feld/Reihe mit automatischem Seitenumbruch.
- Bundled-Terminals Checkbox: Im Website-Abgang-Dialog (war vorher nur PWA).
- PWA: Diverse Verbesserungen, Service Worker v12.4, Connection-Modal erweitert.
- Typ-Flags: has_product auch für Gebäudetypen, Equipment-Typ Erweiterungen.
- CLAUDE.md + Doku aktualisiert.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-09 01:33:05 +01:00

152 lines
4 KiB
PHP
Executable file

<?php
/* Copyright (C) 2026 Alles Watt lauft
*
* PWA Authentication - Token-basierte Authentifizierung
* Für Offline-First Mobile App
*/
if (!defined('NOLOGIN')) {
define('NOLOGIN', '1');
}
if (!defined('NOREQUIREMENU')) {
define('NOREQUIREMENU', '1');
}
if (!defined('NOREQUIREHTML')) {
define('NOREQUIREHTML', '1');
}
if (!defined('NOREQUIREAJAX')) {
define('NOREQUIREAJAX', '1');
}
// Load Dolibarr environment
$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) {
die(json_encode(array('success' => false, 'error' => 'Dolibarr not loaded')));
}
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 protection
usleep(100000); // 100ms delay
// Load user
require_once DOL_DOCUMENT_ROOT.'/user/class/user.class.php';
$userLogin = new User($db);
// Find user by login
$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();
// Check password
require_once DOL_DOCUMENT_ROOT.'/core/lib/security2.lib.php';
$passOk = false;
if (!empty($userLogin->pass_indatabase_crypted)) {
// Check crypted password
$passOk = dol_verifyHash($password, $userLogin->pass_indatabase_crypted);
}
if ($passOk) {
// Check kundenkarte permission
if ($userLogin->hasRight('kundenkarte', 'read')) {
// Generate token (valid for 15 days)
$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 für KundenKarte';
}
} 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'] = 'Ungültiges Token';
break;
}
// Check expiration
if ($tokenData['expires'] < time()) {
$response['error'] = 'Token abgelaufen';
break;
}
// Verify hash
$expectedHash = md5($tokenData['user_id'] . $tokenData['login'] . getDolGlobalString('MAIN_SECURITY_SALT', 'defaultsalt'));
if ($tokenData['hash'] !== $expectedHash) {
$response['error'] = 'Token manipuliert';
break;
}
// Load user to verify still active
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();