From 239c2605d9e1c2eff5a921583569465f1ddf6890 Mon Sep 17 00:00:00 2001 From: Lars Gebhardt-Kusche Date: Mon, 12 Jan 2026 22:35:43 +0100 Subject: [PATCH] yxcxc --- public/page/retool/bridgetoolbyside.php | 176 ++++++++++++++++++++ public/page/retool/emailtemplate_bridge.php | 15 +- 2 files changed, 184 insertions(+), 7 deletions(-) create mode 100644 public/page/retool/bridgetoolbyside.php diff --git a/public/page/retool/bridgetoolbyside.php b/public/page/retool/bridgetoolbyside.php new file mode 100644 index 0000000..a930f8f --- /dev/null +++ b/public/page/retool/bridgetoolbyside.php @@ -0,0 +1,176 @@ + getenv('EMAILTEMPLATE_BRIDGE_TOKEN') ?: 'kgIqdL9aNWsFWy6mhSRpnuLc1EbZ62sGCcJAwjjlqqznEGE13szhksWUan0cEdjE', + 'db' => [ + 'dsn' => getenv('EMAILTEMPLATE_BRIDGE_DSN') ?: 'mysql:host=127.0.0.1;dbname=example;charset=utf8mb4', + 'user' => getenv('EMAILTEMPLATE_BRIDGE_DB_USER') ?: 'root', + 'pass' => getenv('EMAILTEMPLATE_BRIDGE_DB_PASS') ?: '', + 'options' => [ + PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION, + PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC, + ], + ], + 'tables_allow' => ['event', 'mail_accounts', 'users', 'verification_codes'], // optional whitelist: ['customers', 'orders'] +]; + +$localOverride = __DIR__ . '/emailtemplate.bridge.conf.php'; +if (is_file($localOverride)) { + $override = include $localOverride; + if (is_array($override)) { + $bridgeConfig = array_replace_recursive($bridgeConfig, $override); + } +} + +function bridgeRespond($payload, int $status = 200): void +{ + http_response_code($status); + header('Content-Type: application/json; charset=utf-8'); + header('Cache-Control: no-store, max-age=0'); + echo json_encode($payload, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES); + exit; +} + +function bridgeRequireToken(array $config): void +{ + $expected = (string)($config['token'] ?? ''); + if ($expected === '') { + bridgeRespond(['ok' => false, 'error' => 'Bridge token not configured'], 500); + } + + $provided = null; + if (!empty($_SERVER['HTTP_AUTHORIZATION']) && stripos($_SERVER['HTTP_AUTHORIZATION'], 'Bearer ') === 0) { + $provided = trim(substr($_SERVER['HTTP_AUTHORIZATION'], 7)); + } elseif (!empty($_SERVER['HTTP_X_EMAILTEMPLATE_TOKEN'])) { + $provided = trim($_SERVER['HTTP_X_EMAILTEMPLATE_TOKEN']); + } elseif (isset($_GET['token'])) { + $provided = (string)$_GET['token']; + } elseif (isset($_POST['token'])) { + $provided = (string)$_POST['token']; + } + + if (!$provided || !hash_equals($expected, $provided)) { + bridgeRespond(['ok' => false, 'error' => 'Unauthorized'], 403); + } +} + +function bridgeDb(array $config): PDO +{ + static $pdo = null; + if ($pdo instanceof PDO) { + return $pdo; + } + + try { + $pdo = new PDO( + $config['db']['dsn'], + $config['db']['user'], + $config['db']['pass'], + $config['db']['options'] + ); + } catch (Throwable $e) { + bridgeRespond(['ok' => false, 'error' => 'DB connection failed', 'detail' => $e->getMessage()], 500); + } + + return $pdo; +} + +bridgeRequireToken($bridgeConfig); + +$action = strtolower((string)($_GET['action'] ?? $_POST['action'] ?? 'schema')); + +if ($action === 'ping') { + bridgeRespond(['ok' => true, 'time' => date(DATE_ATOM)]); +} + +if ($action !== 'schema') { + bridgeRespond(['ok' => false, 'error' => 'Unknown action'], 404); +} + +$pdo = bridgeDb($bridgeConfig); + +try { + $dbName = ''; + if (preg_match('/dbname=([^;]+)/i', $bridgeConfig['db']['dsn'], $m)) { + $dbName = $m[1]; + } + + $tablesStmt = $pdo->query('SHOW FULL TABLES'); + $tables = []; + $whitelist = []; + if (!empty($bridgeConfig['tables_allow']) && is_array($bridgeConfig['tables_allow'])) { + foreach ($bridgeConfig['tables_allow'] as $tbl) { + if (is_string($tbl) && $tbl !== '') { + $whitelist[strtolower($tbl)] = true; + } + } + } + while ($row = $tablesStmt->fetch(PDO::FETCH_NUM)) { + $tableName = $row[0]; + if ($tableName === null) { + continue; + } + if ($whitelist && empty($whitelist[strtolower($tableName)])) { + continue; + } + + $columnsStmt = $pdo->prepare( + 'SELECT COLUMN_NAME, DATA_TYPE, IS_NULLABLE, COLUMN_DEFAULT, COLUMN_KEY, EXTRA + FROM INFORMATION_SCHEMA.COLUMNS + WHERE TABLE_SCHEMA = :schema AND TABLE_NAME = :table + ORDER BY ORDINAL_POSITION' + ); + $columnsStmt->execute([ + ':schema' => $dbName ?: $pdo->query('SELECT DATABASE()')->fetchColumn(), + ':table' => $tableName, + ]); + + $columns = []; + foreach ($columnsStmt as $col) { + $columns[] = [ + 'name' => $col['COLUMN_NAME'], + 'type' => $col['DATA_TYPE'], + 'nullable' => ($col['IS_NULLABLE'] === 'YES'), + 'default' => $col['COLUMN_DEFAULT'], + 'key' => $col['COLUMN_KEY'], + 'extra' => $col['EXTRA'], + 'placeholder'=> strtoupper($tableName) . '__' . strtoupper($col['COLUMN_NAME']), + ]; + } + + $tables[] = [ + 'name' => $tableName, + 'columns' => $columns, + ]; + } + + bridgeRespond([ + 'ok' => true, + 'tables' => $tables, + 'fetched' => date(DATE_ATOM), + ]); +} catch (Throwable $e) { + bridgeRespond(['ok' => false, 'error' => 'Schema fetch failed', 'detail' => $e->getMessage()], 500); +} +// Bridge DB Setup: direkte Angaben aus dem EmailTemplate-Backend. \ No newline at end of file diff --git a/public/page/retool/emailtemplate_bridge.php b/public/page/retool/emailtemplate_bridge.php index ad6b0c8..da96e29 100644 --- a/public/page/retool/emailtemplate_bridge.php +++ b/public/page/retool/emailtemplate_bridge.php @@ -29,22 +29,23 @@ use App\App; // 1) App-Konfiguration holen $appConfig = App::get()->config(); +$dbConfig = $appConfig->db ?? []; // 2) Bridge-spezifische Konfiguration auf Basis der App-Config $bridgeConfig = [ 'token' => getenv('EMAILTEMPLATE_BRIDGE_TOKEN') ?: 'kgIqdL9aNWsFWy6mhSRpnuLc1EbZ62sGCcJAwjjlqqznEGE13szhksWUan0cEdjE', 'db' => [ - 'dsn' => $appConfig->db['dsn'] ?? '', - 'user' => $appConfig->db['user'] ?? '', - 'pass' => $appConfig->db['password'] ?? '', - 'options' => $appConfig->db['options'] ?? [ - PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION, + 'dsn' => getenv('EMAILTEMPLATE_BRIDGE_DSN') ?: ($dbConfig['dsn'] ?? ''), + 'user' => getenv('EMAILTEMPLATE_BRIDGE_DB_USER') ?: ($dbConfig['user'] ?? ''), + 'pass' => getenv('EMAILTEMPLATE_BRIDGE_DB_PASS') ?: ($dbConfig['password'] ?? ''), + 'options' => $dbConfig['options'] ?? [ + PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION, PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC, ], ], // Optional: Tabellen-Whitelist - 'tables_allow' => [], // z.B. ['customers', 'orders'] + 'tables_allow' => ['event', 'mail_accounts', 'users', 'verification_codes'], // z.B. ['customers', 'orders'] ]; @@ -185,4 +186,4 @@ try { ]); } catch (Throwable $e) { bridgeRespond(['ok' => false, 'error' => 'Schema fetch failed', 'detail' => $e->getMessage()], 500); -} \ No newline at end of file +}