- 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>
152 lines
4 KiB
PHP
Executable file
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();
|