Fügt Unterstützung für die neue nuscore API hinzu. Aktualisiert die Backend-Routen zur Verarbeitung von Anfragen an die nuscore API und integriert die neuen Dialogkomponenten im Frontend. Ermöglicht das Erstellen lokaler Kopien von nuscore-Daten und verbessert die Benutzeroberfläche durch neue Schaltflächen und Dialoge. Entfernt veraltete Konsolenausgaben und optimiert die Logik zur PIN-Verwaltung.
This commit is contained in:
193
backend/routes/nuscoreApiRoutes.js
Normal file
193
backend/routes/nuscoreApiRoutes.js
Normal file
@@ -0,0 +1,193 @@
|
||||
import express from 'express';
|
||||
import fetch from 'node-fetch';
|
||||
|
||||
const router = express.Router();
|
||||
|
||||
// Cookie-Store für nuscore-Sessions
|
||||
const cookieStore = new Map();
|
||||
|
||||
// Hilfsfunktion zum Extrahieren von Cookies aus Set-Cookie Headers
|
||||
function extractCookies(setCookieHeaders) {
|
||||
const cookies = {};
|
||||
if (setCookieHeaders) {
|
||||
setCookieHeaders.forEach(cookie => {
|
||||
const [nameValue] = cookie.split(';');
|
||||
const [name, value] = nameValue.split('=');
|
||||
if (name && value) {
|
||||
cookies[name.trim()] = value.trim();
|
||||
}
|
||||
});
|
||||
}
|
||||
return cookies;
|
||||
}
|
||||
|
||||
// Hilfsfunktion zum Formatieren von Cookies für Requests
|
||||
function formatCookies(cookies) {
|
||||
return Object.entries(cookies)
|
||||
.map(([name, value]) => `${name}=${value}`)
|
||||
.join('; ');
|
||||
}
|
||||
|
||||
// Meeting-Info API-Endpunkt
|
||||
router.get('/meetinginfo/:code', async (req, res) => {
|
||||
const { code } = req.params;
|
||||
console.log(`📊 Meeting-Info API für Code: ${code}`);
|
||||
|
||||
try {
|
||||
// Hole Cookies für diesen Code (falls vorhanden)
|
||||
const cookies = cookieStore.get(code) || {};
|
||||
|
||||
const url = `https://ttde-apps.liga.nu/nuliga/rs/tt/2022/meetingentry/reports/${code}/meetinginfo`;
|
||||
|
||||
const response = await fetch(url, {
|
||||
method: 'GET',
|
||||
headers: {
|
||||
'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64; rv:141.0) Gecko/20100101 Firefox/141.0',
|
||||
'Accept': 'application/json, text/plain, */*',
|
||||
'Accept-Language': 'de,en-US;q=0.7,en;q=0.3',
|
||||
'Accept-Encoding': 'gzip, deflate, br, zstd',
|
||||
'Referer': 'https://ttde-apps.liga.nu/nuliga/nuscore-tt/meetings-list',
|
||||
'Sec-Fetch-Dest': 'empty',
|
||||
'Sec-Fetch-Mode': 'cors',
|
||||
'Sec-Fetch-Site': 'same-origin',
|
||||
'Connection': 'keep-alive',
|
||||
...(Object.keys(cookies).length > 0 && { 'Cookie': formatCookies(cookies) })
|
||||
}
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error(`HTTP ${response.status}: ${response.statusText}`);
|
||||
}
|
||||
|
||||
const data = await response.json();
|
||||
|
||||
// Speichere neue Cookies falls vorhanden
|
||||
const newCookies = extractCookies(response.headers.raw()['set-cookie']);
|
||||
if (Object.keys(newCookies).length > 0) {
|
||||
cookieStore.set(code, { ...cookies, ...newCookies });
|
||||
console.log(`🍪 Cookies für Code ${code} gespeichert:`, Object.keys(newCookies));
|
||||
}
|
||||
|
||||
// CORS-Header setzen
|
||||
res.set({
|
||||
'Content-Type': 'application/json; charset=utf-8',
|
||||
'Access-Control-Allow-Origin': '*',
|
||||
'Access-Control-Allow-Methods': 'GET, POST, OPTIONS',
|
||||
'Access-Control-Allow-Headers': 'Content-Type',
|
||||
'Cache-Control': 'no-cache, no-store, must-revalidate'
|
||||
});
|
||||
|
||||
res.json(data);
|
||||
console.log(`✅ Meeting-Info für Code ${code} erfolgreich abgerufen`);
|
||||
|
||||
} catch (error) {
|
||||
console.error(`❌ Fehler beim Abrufen der Meeting-Info für Code ${code}:`, error);
|
||||
res.status(500).json({
|
||||
error: 'Fehler beim Abrufen der Meeting-Info',
|
||||
details: error.message
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// Cookie-Initialisierung (für den ersten Request)
|
||||
router.post('/init-cookies/:code', async (req, res) => {
|
||||
const { code } = req.params;
|
||||
console.log(`🍪 Cookie-Initialisierung für Code: ${code}`);
|
||||
|
||||
try {
|
||||
// Erster Request an die nuscore-Seite um Cookies zu erhalten
|
||||
const response = await fetch(`https://ttde-apps.liga.nu/nuliga/nuscore-tt/meetings-list?code=${code}`, {
|
||||
method: 'GET',
|
||||
headers: {
|
||||
'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64; rv:141.0) Gecko/20100101 Firefox/141.0',
|
||||
'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8',
|
||||
'Accept-Language': 'de,en-US;q=0.7,en;q=0.3',
|
||||
'Accept-Encoding': 'gzip, deflate, br, zstd',
|
||||
'Connection': 'keep-alive'
|
||||
}
|
||||
});
|
||||
|
||||
// Extrahiere Cookies
|
||||
const cookies = extractCookies(response.headers.raw()['set-cookie']);
|
||||
if (Object.keys(cookies).length > 0) {
|
||||
cookieStore.set(code, cookies);
|
||||
console.log(`🍪 Cookies für Code ${code} initialisiert:`, Object.keys(cookies));
|
||||
}
|
||||
|
||||
res.json({
|
||||
success: true,
|
||||
cookies: Object.keys(cookies),
|
||||
message: `Cookies für Code ${code} initialisiert`
|
||||
});
|
||||
|
||||
} catch (error) {
|
||||
console.error(`❌ Fehler bei Cookie-Initialisierung für Code ${code}:`, error);
|
||||
res.status(500).json({
|
||||
error: 'Fehler bei Cookie-Initialisierung',
|
||||
details: error.message
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// Detaillierte Meeting-Daten API-Endpunkt
|
||||
router.get('/meetingdetails/:uuid', async (req, res) => {
|
||||
const { uuid } = req.params;
|
||||
console.log(`📊 Meeting-Details API für UUID: ${uuid}`);
|
||||
|
||||
try {
|
||||
// Hole Cookies für diesen Code (falls vorhanden)
|
||||
const cookies = cookieStore.get(uuid) || {};
|
||||
|
||||
const url = `https://ttde-apps.liga.nu/nuliga/rs/tt/2022/meetingentry/reports/${uuid}`;
|
||||
|
||||
const response = await fetch(url, {
|
||||
method: 'GET',
|
||||
headers: {
|
||||
'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64; rv:141.0) Gecko/20100101 Firefox/141.0',
|
||||
'Accept': 'application/json, text/plain, */*',
|
||||
'Accept-Language': 'de,en-US;q=0.7,en;q=0.3',
|
||||
'Accept-Encoding': 'gzip, deflate, br, zstd',
|
||||
'Referer': 'https://ttde-apps.liga.nu/nuliga/nuscore-tt/meetings-list',
|
||||
'Sec-Fetch-Dest': 'empty',
|
||||
'Sec-Fetch-Mode': 'cors',
|
||||
'Sec-Fetch-Site': 'same-origin',
|
||||
'Connection': 'keep-alive',
|
||||
...(Object.keys(cookies).length > 0 && { 'Cookie': formatCookies(cookies) })
|
||||
}
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error(`HTTP ${response.status}: ${response.statusText}`);
|
||||
}
|
||||
|
||||
const data = await response.json();
|
||||
|
||||
// Speichere neue Cookies falls vorhanden
|
||||
const newCookies = extractCookies(response.headers.raw()['set-cookie']);
|
||||
if (Object.keys(newCookies).length > 0) {
|
||||
cookieStore.set(uuid, { ...cookies, ...newCookies });
|
||||
console.log(`🍪 Cookies für UUID ${uuid} gespeichert:`, Object.keys(newCookies));
|
||||
}
|
||||
|
||||
// CORS-Header setzen
|
||||
res.set({
|
||||
'Content-Type': 'application/json; charset=utf-8',
|
||||
'Access-Control-Allow-Origin': '*',
|
||||
'Access-Control-Allow-Methods': 'GET, POST, OPTIONS',
|
||||
'Access-Control-Allow-Headers': 'Content-Type',
|
||||
'Cache-Control': 'no-cache, no-store, must-revalidate'
|
||||
});
|
||||
|
||||
res.json(data);
|
||||
console.log(`✅ Meeting-Details für UUID ${uuid} erfolgreich abgerufen`);
|
||||
|
||||
} catch (error) {
|
||||
console.error(`❌ Fehler beim Abrufen der Meeting-Details für UUID ${uuid}:`, error);
|
||||
res.status(500).json({
|
||||
error: 'Fehler beim Abrufen der Meeting-Details',
|
||||
details: error.message
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
export default router;
|
||||
78
backend/routes/nuscoreProxyRoutes.js
Normal file
78
backend/routes/nuscoreProxyRoutes.js
Normal file
@@ -0,0 +1,78 @@
|
||||
import express from 'express';
|
||||
import nuscoreProxyService from '../services/nuscoreProxyService.js';
|
||||
|
||||
const router = express.Router();
|
||||
|
||||
// Hauptroute für nuscore-Seite
|
||||
router.get('/', async (req, res) => {
|
||||
try {
|
||||
const { code, pin } = req.query;
|
||||
|
||||
if (!code) {
|
||||
return res.status(400).json({
|
||||
error: 'Code-Parameter ist erforderlich'
|
||||
});
|
||||
}
|
||||
|
||||
console.log(`📊 Proxy-Anfrage für Code: ${code}, PIN: ${pin || 'nicht angegeben'}`);
|
||||
|
||||
const html = await nuscoreProxyService.proxyNuscorePage(code, pin);
|
||||
|
||||
// CORS-Header setzen für iframe-Einbettung
|
||||
res.set({
|
||||
'Content-Type': 'text/html; charset=utf-8',
|
||||
'Access-Control-Allow-Origin': '*',
|
||||
'Access-Control-Allow-Methods': 'GET, POST, OPTIONS',
|
||||
'Access-Control-Allow-Headers': 'Content-Type',
|
||||
'X-Frame-Options': 'ALLOWALL',
|
||||
'Cache-Control': 'no-cache, no-store, must-revalidate'
|
||||
});
|
||||
|
||||
res.send(html);
|
||||
|
||||
} catch (error) {
|
||||
console.error('❌ Proxy-Fehler:', error);
|
||||
res.status(500).json({
|
||||
error: 'Fehler beim Laden der nuscore-Seite',
|
||||
details: error.message
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// Asset-Proxy für CSS, JS, Bilder etc.
|
||||
router.get('/assets/*', async (req, res) => {
|
||||
try {
|
||||
const assetPath = req.params[0];
|
||||
const originalUrl = `https://ttde-apps.liga.nu/nuliga/nuscore-tt/${assetPath}`;
|
||||
|
||||
console.log(`📦 Lade Asset: ${originalUrl}`);
|
||||
|
||||
const { content, contentType } = await nuscoreProxyService.proxyAsset(originalUrl);
|
||||
|
||||
res.set({
|
||||
'Content-Type': contentType,
|
||||
'Access-Control-Allow-Origin': '*',
|
||||
'Cache-Control': 'public, max-age=3600'
|
||||
});
|
||||
|
||||
res.send(content);
|
||||
|
||||
} catch (error) {
|
||||
console.error(`❌ Asset-Fehler für ${req.params[0]}:`, error.message);
|
||||
res.status(404).json({
|
||||
error: 'Asset nicht gefunden',
|
||||
path: req.params[0]
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// Health-Check Route
|
||||
router.get('/health', (req, res) => {
|
||||
res.json({
|
||||
status: 'ok',
|
||||
service: 'nuscore-proxy',
|
||||
timestamp: new Date().toISOString()
|
||||
});
|
||||
});
|
||||
|
||||
export default router;
|
||||
140
backend/routes/nuscoreSimpleProxyRoutes.js
Normal file
140
backend/routes/nuscoreSimpleProxyRoutes.js
Normal file
@@ -0,0 +1,140 @@
|
||||
import express from 'express';
|
||||
import fetch from 'node-fetch';
|
||||
|
||||
const router = express.Router();
|
||||
|
||||
// Einfacher HTTP-Proxy ohne Playwright
|
||||
router.get('/', async (req, res) => {
|
||||
try {
|
||||
const { code, pin } = req.query;
|
||||
|
||||
if (!code) {
|
||||
return res.status(400).json({
|
||||
error: 'Code-Parameter ist erforderlich'
|
||||
});
|
||||
}
|
||||
|
||||
console.log(`📊 Einfacher Proxy für Code: ${code}, PIN: ${pin || 'nicht angegeben'}`);
|
||||
|
||||
// Direkte HTTP-Anfrage an nuscore
|
||||
const nuscoreUrl = `https://ttde-apps.liga.nu/nuliga/nuscore-tt/meetings-list?code=${encodeURIComponent(code)}`;
|
||||
|
||||
const response = await fetch(nuscoreUrl, {
|
||||
headers: {
|
||||
'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36',
|
||||
'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8',
|
||||
'Accept-Language': 'de,en-US;q=0.7,en;q=0.3',
|
||||
'Accept-Encoding': 'gzip, deflate, br',
|
||||
'DNT': '1',
|
||||
'Connection': 'keep-alive',
|
||||
'Upgrade-Insecure-Requests': '1'
|
||||
},
|
||||
timeout: 30000
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error(`HTTP ${response.status}: ${response.statusText}`);
|
||||
}
|
||||
|
||||
let html = await response.text();
|
||||
|
||||
// Einfache HTML-Modifikationen
|
||||
html = html
|
||||
.replace(/<meta[^>]*http-equiv=["']content-security-policy["'][^>]*>/gi, '')
|
||||
.replace(/<meta[^>]*http-equiv=["']x-frame-options["'][^>]*>/gi, '')
|
||||
.replace(/<meta[^>]*http-equiv=["']x-content-type-options["'][^>]*>/gi, '');
|
||||
|
||||
// Entferne Service Worker
|
||||
html = html.replace(
|
||||
/navigator\.serviceWorker\.register\([^)]+\)/g,
|
||||
'// Service Worker deaktiviert für Proxy'
|
||||
);
|
||||
|
||||
// Korrigiere alle Asset-URLs zu absoluten URLs
|
||||
html = html.replace(
|
||||
/src="\.\//g,
|
||||
'src="https://ttde-apps.liga.nu/nuliga/nuscore-tt/'
|
||||
);
|
||||
html = html.replace(
|
||||
/href="\.\//g,
|
||||
'href="https://ttde-apps.liga.nu/nuliga/nuscore-tt/'
|
||||
);
|
||||
|
||||
// Korrigiere auch URLs die bereits auf localhost zeigen
|
||||
html = html.replace(
|
||||
/src="http:\/\/localhost:3000\/nuliga\/nuscore-tt\//g,
|
||||
'src="https://ttde-apps.liga.nu/nuliga/nuscore-tt/'
|
||||
);
|
||||
html = html.replace(
|
||||
/href="http:\/\/localhost:3000\/nuliga\/nuscore-tt\//g,
|
||||
'href="https://ttde-apps.liga.nu/nuliga/nuscore-tt/'
|
||||
);
|
||||
|
||||
// Entferne vorhandene base-Tags und füge unseres hinzu
|
||||
html = html.replace(
|
||||
/<base[^>]*>/gi,
|
||||
''
|
||||
);
|
||||
|
||||
// Füge base-Tag hinzu für korrekte Asset-Auflösung
|
||||
html = html.replace(
|
||||
'<head>',
|
||||
'<head><base href="https://ttde-apps.liga.nu/nuliga/nuscore-tt/">'
|
||||
);
|
||||
|
||||
// Debug: Logge die HTML-Struktur
|
||||
console.log('🔍 HTML nach base-Tag:', html.substring(html.indexOf('<base'), html.indexOf('</head>') + 7));
|
||||
|
||||
// Füge PIN-Injektion hinzu falls PIN vorhanden
|
||||
if (pin) {
|
||||
const pinScript = `
|
||||
<script>
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
setTimeout(function() {
|
||||
const pinInput = document.querySelector('input[type="password"][placeholder*="PIN"], input[placeholder*="Pin"], input[placeholder*="pin"]');
|
||||
if (pinInput) {
|
||||
pinInput.value = '${pin}';
|
||||
pinInput.dispatchEvent(new Event('input', { bubbles: true }));
|
||||
pinInput.dispatchEvent(new Event('change', { bubbles: true }));
|
||||
console.log('PIN automatisch eingefügt: ${pin}');
|
||||
}
|
||||
}, 2000);
|
||||
});
|
||||
</script>
|
||||
`;
|
||||
html = html.replace('</head>', `${pinScript}</head>`);
|
||||
}
|
||||
|
||||
// CORS-Header setzen für iframe-Einbettung
|
||||
res.set({
|
||||
'Content-Type': 'text/html; charset=utf-8',
|
||||
'Access-Control-Allow-Origin': '*',
|
||||
'Access-Control-Allow-Methods': 'GET, POST, OPTIONS',
|
||||
'Access-Control-Allow-Headers': 'Content-Type',
|
||||
'X-Frame-Options': 'ALLOWALL',
|
||||
'Content-Security-Policy': "frame-ancestors *;",
|
||||
'Cache-Control': 'no-cache, no-store, must-revalidate'
|
||||
});
|
||||
|
||||
res.send(html);
|
||||
console.log('✅ Einfacher Proxy erfolgreich');
|
||||
|
||||
} catch (error) {
|
||||
console.error('❌ Einfacher Proxy-Fehler:', error);
|
||||
res.status(500).json({
|
||||
error: 'Fehler beim Laden der nuscore-Seite',
|
||||
details: error.message
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// Health-Check Route
|
||||
router.get('/health', (req, res) => {
|
||||
res.json({
|
||||
status: 'ok',
|
||||
service: 'nuscore-simple-proxy',
|
||||
timestamp: new Date().toISOString()
|
||||
});
|
||||
});
|
||||
|
||||
export default router;
|
||||
Reference in New Issue
Block a user