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:
168
backend/node_modules/.package-lock.json
generated
vendored
168
backend/node_modules/.package-lock.json
generated
vendored
@@ -595,6 +595,26 @@
|
||||
"node-pre-gyp": "bin/node-pre-gyp"
|
||||
}
|
||||
},
|
||||
"node_modules/@mapbox/node-pre-gyp/node_modules/node-fetch": {
|
||||
"version": "2.7.0",
|
||||
"resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz",
|
||||
"integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"whatwg-url": "^5.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": "4.x || >=6.0.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"encoding": "^0.1.0"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"encoding": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/@nodelib/fs.scandir": {
|
||||
"version": "2.1.5",
|
||||
"resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz",
|
||||
@@ -1278,6 +1298,15 @@
|
||||
"node": ">= 10"
|
||||
}
|
||||
},
|
||||
"node_modules/data-uri-to-buffer": {
|
||||
"version": "4.0.1",
|
||||
"resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-4.0.1.tgz",
|
||||
"integrity": "sha512-0R9ikRb668HB7QDxT1vkpuUBtqc53YyAwMwGeUFKRojY/NWKvdZ+9UYtRfGmhqNbRkTSVpMbmyhXipFFv2cb/A==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 12"
|
||||
}
|
||||
},
|
||||
"node_modules/date-fns": {
|
||||
"version": "2.30.0",
|
||||
"resolved": "https://registry.npmjs.org/date-fns/-/date-fns-2.30.0.tgz",
|
||||
@@ -1778,6 +1807,29 @@
|
||||
"reusify": "^1.0.4"
|
||||
}
|
||||
},
|
||||
"node_modules/fetch-blob": {
|
||||
"version": "3.2.0",
|
||||
"resolved": "https://registry.npmjs.org/fetch-blob/-/fetch-blob-3.2.0.tgz",
|
||||
"integrity": "sha512-7yAQpD2UMJzLi1Dqv7qFYnPbaPx7ZfFK6PiIxQ4PfkGPyNyl2Ugx+a/umUonmKqjhM4DnfbMvdX6otXq83soQQ==",
|
||||
"funding": [
|
||||
{
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/jimmywarting"
|
||||
},
|
||||
{
|
||||
"type": "paypal",
|
||||
"url": "https://paypal.me/jimmywarting"
|
||||
}
|
||||
],
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"node-domexception": "^1.0.0",
|
||||
"web-streams-polyfill": "^3.0.3"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^12.20 || >= 14.13"
|
||||
}
|
||||
},
|
||||
"node_modules/file-entry-cache": {
|
||||
"version": "8.0.0",
|
||||
"resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-8.0.0.tgz",
|
||||
@@ -1902,6 +1954,18 @@
|
||||
"node": ">= 6"
|
||||
}
|
||||
},
|
||||
"node_modules/formdata-polyfill": {
|
||||
"version": "4.0.10",
|
||||
"resolved": "https://registry.npmjs.org/formdata-polyfill/-/formdata-polyfill-4.0.10.tgz",
|
||||
"integrity": "sha512-buewHzMvYL29jdeQTVILecSaZKnt/RJWjoZCF5OW60Z67/GmSLBkOFM7qh1PI3zFNtJbaZL5eQu1vLfazOwj4g==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"fetch-blob": "^3.1.2"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=12.20.0"
|
||||
}
|
||||
},
|
||||
"node_modules/forwarded": {
|
||||
"version": "0.2.0",
|
||||
"resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz",
|
||||
@@ -2816,6 +2880,26 @@
|
||||
"resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-5.1.0.tgz",
|
||||
"integrity": "sha512-eh0GgfEkpnoWDq+VY8OyvYhFEzBk6jIYbRKdIlyTiAXIVJ8PyBaKb0rp7oDtoddbdoHWhq8wwr+XZ81F1rpNdA=="
|
||||
},
|
||||
"node_modules/node-domexception": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/node-domexception/-/node-domexception-1.0.0.tgz",
|
||||
"integrity": "sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==",
|
||||
"deprecated": "Use your platform's native DOMException instead",
|
||||
"funding": [
|
||||
{
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/jimmywarting"
|
||||
},
|
||||
{
|
||||
"type": "github",
|
||||
"url": "https://paypal.me/jimmywarting"
|
||||
}
|
||||
],
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=10.5.0"
|
||||
}
|
||||
},
|
||||
"node_modules/node-ensure": {
|
||||
"version": "0.0.0",
|
||||
"resolved": "https://registry.npmjs.org/node-ensure/-/node-ensure-0.0.0.tgz",
|
||||
@@ -2823,22 +2907,21 @@
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/node-fetch": {
|
||||
"version": "2.7.0",
|
||||
"resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz",
|
||||
"integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==",
|
||||
"version": "3.3.2",
|
||||
"resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-3.3.2.tgz",
|
||||
"integrity": "sha512-dRB78srN/l6gqWulah9SrxeYnxeddIG30+GOqK/9OlLVyLg3HPnr6SqOWTWOXKRwC2eGYCkZ59NNuSgvSrpgOA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"whatwg-url": "^5.0.0"
|
||||
"data-uri-to-buffer": "^4.0.0",
|
||||
"fetch-blob": "^3.1.4",
|
||||
"formdata-polyfill": "^4.0.10"
|
||||
},
|
||||
"engines": {
|
||||
"node": "4.x || >=6.0.0"
|
||||
"node": "^12.20.0 || ^14.13.1 || >=16.0.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"encoding": "^0.1.0"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"encoding": {
|
||||
"optional": true
|
||||
}
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/node-fetch"
|
||||
}
|
||||
},
|
||||
"node_modules/nodemailer": {
|
||||
@@ -3124,6 +3207,51 @@
|
||||
"url": "https://github.com/sponsors/jonschlinkert"
|
||||
}
|
||||
},
|
||||
"node_modules/playwright": {
|
||||
"version": "1.55.1",
|
||||
"resolved": "https://registry.npmjs.org/playwright/-/playwright-1.55.1.tgz",
|
||||
"integrity": "sha512-cJW4Xd/G3v5ovXtJJ52MAOclqeac9S/aGGgRzLabuF8TnIb6xHvMzKIa6JmrRzUkeXJgfL1MhukP0NK6l39h3A==",
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"playwright-core": "1.55.1"
|
||||
},
|
||||
"bin": {
|
||||
"playwright": "cli.js"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"fsevents": "2.3.2"
|
||||
}
|
||||
},
|
||||
"node_modules/playwright-core": {
|
||||
"version": "1.55.1",
|
||||
"resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.55.1.tgz",
|
||||
"integrity": "sha512-Z6Mh9mkwX+zxSlHqdr5AOcJnfp+xUWLCt9uKV18fhzA8eyxUd8NUWzAjxUh55RZKSYwDGX0cfaySdhZJGMoJ+w==",
|
||||
"license": "Apache-2.0",
|
||||
"bin": {
|
||||
"playwright-core": "cli.js"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/playwright/node_modules/fsevents": {
|
||||
"version": "2.3.2",
|
||||
"resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz",
|
||||
"integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==",
|
||||
"hasInstallScript": true,
|
||||
"ideallyInert": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"darwin"
|
||||
],
|
||||
"engines": {
|
||||
"node": "^8.16.0 || ^10.6.0 || >=11.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/prelude-ls": {
|
||||
"version": "1.2.1",
|
||||
"resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz",
|
||||
@@ -3792,7 +3920,8 @@
|
||||
"node_modules/tr46": {
|
||||
"version": "0.0.3",
|
||||
"resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz",
|
||||
"integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw=="
|
||||
"integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/tslib": {
|
||||
"version": "2.7.0",
|
||||
@@ -3992,15 +4121,26 @@
|
||||
"integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/web-streams-polyfill": {
|
||||
"version": "3.3.3",
|
||||
"resolved": "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-3.3.3.tgz",
|
||||
"integrity": "sha512-d2JWLCivmZYTSIoge9MsgFCZrt571BikcWGYkjC1khllbTeDlGqZ2D8vD8E/lJa8WGWbb7Plm8/XJYV7IJHZZw==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 8"
|
||||
}
|
||||
},
|
||||
"node_modules/webidl-conversions": {
|
||||
"version": "3.0.1",
|
||||
"resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz",
|
||||
"integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ=="
|
||||
"integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==",
|
||||
"license": "BSD-2-Clause"
|
||||
},
|
||||
"node_modules/whatwg-url": {
|
||||
"version": "5.0.0",
|
||||
"resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz",
|
||||
"integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"tr46": "~0.0.3",
|
||||
"webidl-conversions": "^3.0.0"
|
||||
|
||||
2
backend/node_modules/node-fetch/LICENSE.md
generated
vendored
2
backend/node_modules/node-fetch/LICENSE.md
generated
vendored
@@ -1,6 +1,6 @@
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2016 David Frank
|
||||
Copyright (c) 2016 - 2020 Node Fetch Team
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
|
||||
816
backend/node_modules/node-fetch/README.md
generated
vendored
816
backend/node_modules/node-fetch/README.md
generated
vendored
File diff suppressed because it is too large
Load Diff
25
backend/node_modules/node-fetch/browser.js
generated
vendored
25
backend/node_modules/node-fetch/browser.js
generated
vendored
@@ -1,25 +0,0 @@
|
||||
"use strict";
|
||||
|
||||
// ref: https://github.com/tc39/proposal-global
|
||||
var getGlobal = function () {
|
||||
// the only reliable means to get the global object is
|
||||
// `Function('return this')()`
|
||||
// However, this causes CSP violations in Chrome apps.
|
||||
if (typeof self !== 'undefined') { return self; }
|
||||
if (typeof window !== 'undefined') { return window; }
|
||||
if (typeof global !== 'undefined') { return global; }
|
||||
throw new Error('unable to locate global object');
|
||||
}
|
||||
|
||||
var globalObject = getGlobal();
|
||||
|
||||
module.exports = exports = globalObject.fetch;
|
||||
|
||||
// Needed for TypeScript and Webpack.
|
||||
if (globalObject.fetch) {
|
||||
exports.default = globalObject.fetch.bind(globalObject);
|
||||
}
|
||||
|
||||
exports.Headers = globalObject.Headers;
|
||||
exports.Request = globalObject.Request;
|
||||
exports.Response = globalObject.Response;
|
||||
1777
backend/node_modules/node-fetch/lib/index.es.js
generated
vendored
1777
backend/node_modules/node-fetch/lib/index.es.js
generated
vendored
File diff suppressed because it is too large
Load Diff
1787
backend/node_modules/node-fetch/lib/index.js
generated
vendored
1787
backend/node_modules/node-fetch/lib/index.js
generated
vendored
File diff suppressed because it is too large
Load Diff
1775
backend/node_modules/node-fetch/lib/index.mjs
generated
vendored
1775
backend/node_modules/node-fetch/lib/index.mjs
generated
vendored
File diff suppressed because it is too large
Load Diff
214
backend/node_modules/node-fetch/package.json
generated
vendored
214
backend/node_modules/node-fetch/package.json
generated
vendored
@@ -1,89 +1,131 @@
|
||||
{
|
||||
"name": "node-fetch",
|
||||
"version": "2.7.0",
|
||||
"description": "A light-weight module that brings window.fetch to node.js",
|
||||
"main": "lib/index.js",
|
||||
"browser": "./browser.js",
|
||||
"module": "lib/index.mjs",
|
||||
"files": [
|
||||
"lib/index.js",
|
||||
"lib/index.mjs",
|
||||
"lib/index.es.js",
|
||||
"browser.js"
|
||||
],
|
||||
"engines": {
|
||||
"node": "4.x || >=6.0.0"
|
||||
},
|
||||
"scripts": {
|
||||
"build": "cross-env BABEL_ENV=rollup rollup -c",
|
||||
"prepare": "npm run build",
|
||||
"test": "cross-env BABEL_ENV=test mocha --require babel-register --throw-deprecation test/test.js",
|
||||
"report": "cross-env BABEL_ENV=coverage nyc --reporter lcov --reporter text mocha -R spec test/test.js",
|
||||
"coverage": "cross-env BABEL_ENV=coverage nyc --reporter json --reporter text mocha -R spec test/test.js && codecov -f coverage/coverage-final.json"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/bitinn/node-fetch.git"
|
||||
},
|
||||
"keywords": [
|
||||
"fetch",
|
||||
"http",
|
||||
"promise"
|
||||
],
|
||||
"author": "David Frank",
|
||||
"license": "MIT",
|
||||
"bugs": {
|
||||
"url": "https://github.com/bitinn/node-fetch/issues"
|
||||
},
|
||||
"homepage": "https://github.com/bitinn/node-fetch",
|
||||
"dependencies": {
|
||||
"whatwg-url": "^5.0.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"encoding": "^0.1.0"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"encoding": {
|
||||
"optional": true
|
||||
}
|
||||
},
|
||||
"devDependencies": {
|
||||
"@ungap/url-search-params": "^0.1.2",
|
||||
"abort-controller": "^1.1.0",
|
||||
"abortcontroller-polyfill": "^1.3.0",
|
||||
"babel-core": "^6.26.3",
|
||||
"babel-plugin-istanbul": "^4.1.6",
|
||||
"babel-plugin-transform-async-generator-functions": "^6.24.1",
|
||||
"babel-polyfill": "^6.26.0",
|
||||
"babel-preset-env": "1.4.0",
|
||||
"babel-register": "^6.16.3",
|
||||
"chai": "^3.5.0",
|
||||
"chai-as-promised": "^7.1.1",
|
||||
"chai-iterator": "^1.1.1",
|
||||
"chai-string": "~1.3.0",
|
||||
"codecov": "3.3.0",
|
||||
"cross-env": "^5.2.0",
|
||||
"form-data": "^2.3.3",
|
||||
"is-builtin-module": "^1.0.0",
|
||||
"mocha": "^5.0.0",
|
||||
"nyc": "11.9.0",
|
||||
"parted": "^0.1.1",
|
||||
"promise": "^8.0.3",
|
||||
"resumer": "0.0.0",
|
||||
"rollup": "^0.63.4",
|
||||
"rollup-plugin-babel": "^3.0.7",
|
||||
"string-to-arraybuffer": "^1.0.2",
|
||||
"teeny-request": "3.7.0"
|
||||
},
|
||||
"release": {
|
||||
"branches": [
|
||||
"+([0-9]).x",
|
||||
"main",
|
||||
"next",
|
||||
{
|
||||
"name": "beta",
|
||||
"prerelease": true
|
||||
}
|
||||
]
|
||||
"name": "node-fetch",
|
||||
"version": "3.3.2",
|
||||
"description": "A light-weight module that brings Fetch API to node.js",
|
||||
"main": "./src/index.js",
|
||||
"sideEffects": false,
|
||||
"type": "module",
|
||||
"files": [
|
||||
"src",
|
||||
"@types/index.d.ts"
|
||||
],
|
||||
"types": "./@types/index.d.ts",
|
||||
"engines": {
|
||||
"node": "^12.20.0 || ^14.13.1 || >=16.0.0"
|
||||
},
|
||||
"scripts": {
|
||||
"test": "mocha",
|
||||
"coverage": "c8 report --reporter=text-lcov | coveralls",
|
||||
"test-types": "tsd",
|
||||
"lint": "xo"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/node-fetch/node-fetch.git"
|
||||
},
|
||||
"keywords": [
|
||||
"fetch",
|
||||
"http",
|
||||
"promise",
|
||||
"request",
|
||||
"curl",
|
||||
"wget",
|
||||
"xhr",
|
||||
"whatwg"
|
||||
],
|
||||
"author": "David Frank",
|
||||
"license": "MIT",
|
||||
"bugs": {
|
||||
"url": "https://github.com/node-fetch/node-fetch/issues"
|
||||
},
|
||||
"homepage": "https://github.com/node-fetch/node-fetch",
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/node-fetch"
|
||||
},
|
||||
"devDependencies": {
|
||||
"abort-controller": "^3.0.0",
|
||||
"abortcontroller-polyfill": "^1.7.1",
|
||||
"busboy": "^1.4.0",
|
||||
"c8": "^7.7.2",
|
||||
"chai": "^4.3.4",
|
||||
"chai-as-promised": "^7.1.1",
|
||||
"chai-iterator": "^3.0.2",
|
||||
"chai-string": "^1.5.0",
|
||||
"coveralls": "^3.1.0",
|
||||
"form-data": "^4.0.0",
|
||||
"formdata-node": "^4.2.4",
|
||||
"mocha": "^9.1.3",
|
||||
"p-timeout": "^5.0.0",
|
||||
"stream-consumers": "^1.0.1",
|
||||
"tsd": "^0.14.0",
|
||||
"xo": "^0.39.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"data-uri-to-buffer": "^4.0.0",
|
||||
"fetch-blob": "^3.1.4",
|
||||
"formdata-polyfill": "^4.0.10"
|
||||
},
|
||||
"tsd": {
|
||||
"cwd": "@types",
|
||||
"compilerOptions": {
|
||||
"esModuleInterop": true
|
||||
}
|
||||
},
|
||||
"xo": {
|
||||
"envs": [
|
||||
"node",
|
||||
"browser"
|
||||
],
|
||||
"ignores": [
|
||||
"example.js"
|
||||
],
|
||||
"rules": {
|
||||
"complexity": 0,
|
||||
"import/extensions": 0,
|
||||
"import/no-useless-path-segments": 0,
|
||||
"import/no-anonymous-default-export": 0,
|
||||
"import/no-named-as-default": 0,
|
||||
"unicorn/import-index": 0,
|
||||
"unicorn/no-array-reduce": 0,
|
||||
"unicorn/prefer-node-protocol": 0,
|
||||
"unicorn/numeric-separators-style": 0,
|
||||
"unicorn/explicit-length-check": 0,
|
||||
"capitalized-comments": 0,
|
||||
"node/no-unsupported-features/es-syntax": 0,
|
||||
"@typescript-eslint/member-ordering": 0
|
||||
},
|
||||
"overrides": [
|
||||
{
|
||||
"files": "test/**/*.js",
|
||||
"envs": [
|
||||
"node",
|
||||
"mocha"
|
||||
],
|
||||
"rules": {
|
||||
"max-nested-callbacks": 0,
|
||||
"no-unused-expressions": 0,
|
||||
"no-warning-comments": 0,
|
||||
"new-cap": 0,
|
||||
"guard-for-in": 0,
|
||||
"unicorn/no-array-for-each": 0,
|
||||
"unicorn/prevent-abbreviations": 0,
|
||||
"promise/prefer-await-to-then": 0,
|
||||
"ava/no-import-test-files": 0
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"runkitExampleFilename": "example.js",
|
||||
"release": {
|
||||
"branches": [
|
||||
"+([0-9]).x",
|
||||
"main",
|
||||
"next",
|
||||
{
|
||||
"name": "beta",
|
||||
"prerelease": true
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
169
backend/package-lock.json
generated
169
backend/package-lock.json
generated
@@ -22,8 +22,10 @@
|
||||
"jsonwebtoken": "^9.0.2",
|
||||
"multer": "^1.4.5-lts.1",
|
||||
"mysql2": "^3.10.3",
|
||||
"node-fetch": "^3.3.2",
|
||||
"nodemailer": "^6.9.14",
|
||||
"pdf-parse": "^1.1.1",
|
||||
"playwright": "^1.55.1",
|
||||
"sequelize": "^6.37.3",
|
||||
"sharp": "^0.33.5"
|
||||
},
|
||||
@@ -607,6 +609,26 @@
|
||||
"node-pre-gyp": "bin/node-pre-gyp"
|
||||
}
|
||||
},
|
||||
"node_modules/@mapbox/node-pre-gyp/node_modules/node-fetch": {
|
||||
"version": "2.7.0",
|
||||
"resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz",
|
||||
"integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"whatwg-url": "^5.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": "4.x || >=6.0.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"encoding": "^0.1.0"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"encoding": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/@nodelib/fs.scandir": {
|
||||
"version": "2.1.5",
|
||||
"resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz",
|
||||
@@ -1290,6 +1312,15 @@
|
||||
"node": ">= 10"
|
||||
}
|
||||
},
|
||||
"node_modules/data-uri-to-buffer": {
|
||||
"version": "4.0.1",
|
||||
"resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-4.0.1.tgz",
|
||||
"integrity": "sha512-0R9ikRb668HB7QDxT1vkpuUBtqc53YyAwMwGeUFKRojY/NWKvdZ+9UYtRfGmhqNbRkTSVpMbmyhXipFFv2cb/A==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 12"
|
||||
}
|
||||
},
|
||||
"node_modules/date-fns": {
|
||||
"version": "2.30.0",
|
||||
"resolved": "https://registry.npmjs.org/date-fns/-/date-fns-2.30.0.tgz",
|
||||
@@ -1790,6 +1821,29 @@
|
||||
"reusify": "^1.0.4"
|
||||
}
|
||||
},
|
||||
"node_modules/fetch-blob": {
|
||||
"version": "3.2.0",
|
||||
"resolved": "https://registry.npmjs.org/fetch-blob/-/fetch-blob-3.2.0.tgz",
|
||||
"integrity": "sha512-7yAQpD2UMJzLi1Dqv7qFYnPbaPx7ZfFK6PiIxQ4PfkGPyNyl2Ugx+a/umUonmKqjhM4DnfbMvdX6otXq83soQQ==",
|
||||
"funding": [
|
||||
{
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/jimmywarting"
|
||||
},
|
||||
{
|
||||
"type": "paypal",
|
||||
"url": "https://paypal.me/jimmywarting"
|
||||
}
|
||||
],
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"node-domexception": "^1.0.0",
|
||||
"web-streams-polyfill": "^3.0.3"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^12.20 || >= 14.13"
|
||||
}
|
||||
},
|
||||
"node_modules/file-entry-cache": {
|
||||
"version": "8.0.0",
|
||||
"resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-8.0.0.tgz",
|
||||
@@ -1914,6 +1968,18 @@
|
||||
"node": ">= 6"
|
||||
}
|
||||
},
|
||||
"node_modules/formdata-polyfill": {
|
||||
"version": "4.0.10",
|
||||
"resolved": "https://registry.npmjs.org/formdata-polyfill/-/formdata-polyfill-4.0.10.tgz",
|
||||
"integrity": "sha512-buewHzMvYL29jdeQTVILecSaZKnt/RJWjoZCF5OW60Z67/GmSLBkOFM7qh1PI3zFNtJbaZL5eQu1vLfazOwj4g==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"fetch-blob": "^3.1.2"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=12.20.0"
|
||||
}
|
||||
},
|
||||
"node_modules/forwarded": {
|
||||
"version": "0.2.0",
|
||||
"resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz",
|
||||
@@ -2827,6 +2893,26 @@
|
||||
"resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-5.1.0.tgz",
|
||||
"integrity": "sha512-eh0GgfEkpnoWDq+VY8OyvYhFEzBk6jIYbRKdIlyTiAXIVJ8PyBaKb0rp7oDtoddbdoHWhq8wwr+XZ81F1rpNdA=="
|
||||
},
|
||||
"node_modules/node-domexception": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/node-domexception/-/node-domexception-1.0.0.tgz",
|
||||
"integrity": "sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==",
|
||||
"deprecated": "Use your platform's native DOMException instead",
|
||||
"funding": [
|
||||
{
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/jimmywarting"
|
||||
},
|
||||
{
|
||||
"type": "github",
|
||||
"url": "https://paypal.me/jimmywarting"
|
||||
}
|
||||
],
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=10.5.0"
|
||||
}
|
||||
},
|
||||
"node_modules/node-ensure": {
|
||||
"version": "0.0.0",
|
||||
"resolved": "https://registry.npmjs.org/node-ensure/-/node-ensure-0.0.0.tgz",
|
||||
@@ -2834,22 +2920,21 @@
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/node-fetch": {
|
||||
"version": "2.7.0",
|
||||
"resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz",
|
||||
"integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==",
|
||||
"version": "3.3.2",
|
||||
"resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-3.3.2.tgz",
|
||||
"integrity": "sha512-dRB78srN/l6gqWulah9SrxeYnxeddIG30+GOqK/9OlLVyLg3HPnr6SqOWTWOXKRwC2eGYCkZ59NNuSgvSrpgOA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"whatwg-url": "^5.0.0"
|
||||
"data-uri-to-buffer": "^4.0.0",
|
||||
"fetch-blob": "^3.1.4",
|
||||
"formdata-polyfill": "^4.0.10"
|
||||
},
|
||||
"engines": {
|
||||
"node": "4.x || >=6.0.0"
|
||||
"node": "^12.20.0 || ^14.13.1 || >=16.0.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"encoding": "^0.1.0"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"encoding": {
|
||||
"optional": true
|
||||
}
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/node-fetch"
|
||||
}
|
||||
},
|
||||
"node_modules/nodemailer": {
|
||||
@@ -3135,6 +3220,50 @@
|
||||
"url": "https://github.com/sponsors/jonschlinkert"
|
||||
}
|
||||
},
|
||||
"node_modules/playwright": {
|
||||
"version": "1.55.1",
|
||||
"resolved": "https://registry.npmjs.org/playwright/-/playwright-1.55.1.tgz",
|
||||
"integrity": "sha512-cJW4Xd/G3v5ovXtJJ52MAOclqeac9S/aGGgRzLabuF8TnIb6xHvMzKIa6JmrRzUkeXJgfL1MhukP0NK6l39h3A==",
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"playwright-core": "1.55.1"
|
||||
},
|
||||
"bin": {
|
||||
"playwright": "cli.js"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"fsevents": "2.3.2"
|
||||
}
|
||||
},
|
||||
"node_modules/playwright-core": {
|
||||
"version": "1.55.1",
|
||||
"resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.55.1.tgz",
|
||||
"integrity": "sha512-Z6Mh9mkwX+zxSlHqdr5AOcJnfp+xUWLCt9uKV18fhzA8eyxUd8NUWzAjxUh55RZKSYwDGX0cfaySdhZJGMoJ+w==",
|
||||
"license": "Apache-2.0",
|
||||
"bin": {
|
||||
"playwright-core": "cli.js"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/playwright/node_modules/fsevents": {
|
||||
"version": "2.3.2",
|
||||
"resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz",
|
||||
"integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==",
|
||||
"hasInstallScript": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"darwin"
|
||||
],
|
||||
"engines": {
|
||||
"node": "^8.16.0 || ^10.6.0 || >=11.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/prelude-ls": {
|
||||
"version": "1.2.1",
|
||||
"resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz",
|
||||
@@ -3803,7 +3932,8 @@
|
||||
"node_modules/tr46": {
|
||||
"version": "0.0.3",
|
||||
"resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz",
|
||||
"integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw=="
|
||||
"integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/tslib": {
|
||||
"version": "2.7.0",
|
||||
@@ -4002,15 +4132,26 @@
|
||||
"integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/web-streams-polyfill": {
|
||||
"version": "3.3.3",
|
||||
"resolved": "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-3.3.3.tgz",
|
||||
"integrity": "sha512-d2JWLCivmZYTSIoge9MsgFCZrt571BikcWGYkjC1khllbTeDlGqZ2D8vD8E/lJa8WGWbb7Plm8/XJYV7IJHZZw==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 8"
|
||||
}
|
||||
},
|
||||
"node_modules/webidl-conversions": {
|
||||
"version": "3.0.1",
|
||||
"resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz",
|
||||
"integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ=="
|
||||
"integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==",
|
||||
"license": "BSD-2-Clause"
|
||||
},
|
||||
"node_modules/whatwg-url": {
|
||||
"version": "5.0.0",
|
||||
"resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz",
|
||||
"integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"tr46": "~0.0.3",
|
||||
"webidl-conversions": "^3.0.0"
|
||||
|
||||
@@ -26,8 +26,10 @@
|
||||
"jsonwebtoken": "^9.0.2",
|
||||
"multer": "^1.4.5-lts.1",
|
||||
"mysql2": "^3.10.3",
|
||||
"node-fetch": "^3.3.2",
|
||||
"nodemailer": "^6.9.14",
|
||||
"pdf-parse": "^1.1.1",
|
||||
"playwright": "^1.55.1",
|
||||
"sequelize": "^6.37.3",
|
||||
"sharp": "^0.33.5"
|
||||
},
|
||||
|
||||
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;
|
||||
@@ -38,6 +38,8 @@ import teamRoutes from './routes/teamRoutes.js';
|
||||
import clubTeamRoutes from './routes/clubTeamRoutes.js';
|
||||
import teamDocumentRoutes from './routes/teamDocumentRoutes.js';
|
||||
import seasonRoutes from './routes/seasonRoutes.js';
|
||||
import nuscoreSimpleProxyRoutes from './routes/nuscoreSimpleProxyRoutes.js';
|
||||
import nuscoreApiRoutes from './routes/nuscoreApiRoutes.js';
|
||||
|
||||
const app = express();
|
||||
const port = process.env.PORT || 3000;
|
||||
@@ -87,6 +89,8 @@ app.use('/api/teams', teamRoutes);
|
||||
app.use('/api/club-teams', clubTeamRoutes);
|
||||
app.use('/api/team-documents', teamDocumentRoutes);
|
||||
app.use('/api/seasons', seasonRoutes);
|
||||
app.use('/api/proxy/nuscore', nuscoreSimpleProxyRoutes);
|
||||
app.use('/api/nuscore', nuscoreApiRoutes);
|
||||
|
||||
app.use(express.static(path.join(__dirname, '../frontend/dist')));
|
||||
|
||||
|
||||
148
backend/services/nuscoreProxyService.js
Normal file
148
backend/services/nuscoreProxyService.js
Normal file
@@ -0,0 +1,148 @@
|
||||
import { chromium } from 'playwright';
|
||||
|
||||
class NuscoreProxyService {
|
||||
constructor() {
|
||||
this.browser = null;
|
||||
this.context = null;
|
||||
}
|
||||
|
||||
async initialize() {
|
||||
if (!this.browser) {
|
||||
console.log('🚀 Initialisiere Playwright Browser...');
|
||||
this.browser = await chromium.launch({
|
||||
headless: true,
|
||||
args: [
|
||||
'--no-sandbox',
|
||||
'--disable-setuid-sandbox',
|
||||
'--disable-dev-shm-usage',
|
||||
'--disable-web-security',
|
||||
'--disable-features=VizDisplayCompositor'
|
||||
]
|
||||
});
|
||||
|
||||
this.context = await this.browser.newContext({
|
||||
userAgent: 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36',
|
||||
viewport: { width: 1920, height: 1080 },
|
||||
ignoreHTTPSErrors: true
|
||||
});
|
||||
|
||||
console.log('✅ Playwright Browser initialisiert');
|
||||
}
|
||||
}
|
||||
|
||||
async proxyNuscorePage(code, pin = null) {
|
||||
try {
|
||||
await this.initialize();
|
||||
|
||||
console.log(`🔍 Lade nuscore-Seite für Code: ${code}`);
|
||||
|
||||
const page = await this.context.newPage();
|
||||
|
||||
// Navigiere direkt zur nuscore-Seite ohne Request-Interception
|
||||
const nuscoreUrl = `https://ttde-apps.liga.nu/nuliga/nuscore-tt/meetings-list?code=${encodeURIComponent(code)}`;
|
||||
await page.goto(nuscoreUrl, {
|
||||
waitUntil: 'load',
|
||||
timeout: 30000
|
||||
});
|
||||
|
||||
console.log('📄 Seite geladen');
|
||||
|
||||
// Optional: PIN automatisch einfügen falls vorhanden
|
||||
if (pin) {
|
||||
console.log(`🔑 Versuche PIN ${pin} einzufügen...`);
|
||||
try {
|
||||
// Suche nach PIN-Eingabefeld
|
||||
const pinInput = await page.locator('input[type="password"][placeholder*="PIN"], input[placeholder*="Pin"], input[placeholder*="pin"]').first();
|
||||
if (await pinInput.isVisible()) {
|
||||
await pinInput.fill(pin);
|
||||
console.log('✅ PIN eingefügt');
|
||||
|
||||
// Optional: Submit-Button klicken falls vorhanden
|
||||
const submitBtn = await page.locator('button[type="submit"], input[type="submit"], button:has-text("Einloggen"), button:has-text("Anmelden")').first();
|
||||
if (await submitBtn.isVisible()) {
|
||||
await submitBtn.click();
|
||||
await page.waitForLoadState('load', { timeout: 5000 });
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
console.log('⚠️ PIN-Einfügung fehlgeschlagen:', error.message);
|
||||
}
|
||||
}
|
||||
|
||||
// HTML-Inhalt abrufen und modifizieren
|
||||
const html = await page.content();
|
||||
|
||||
// HTML modifizieren für Proxy-Betrieb
|
||||
const modifiedHtml = this.modifyHtmlForProxy(html, code);
|
||||
|
||||
await page.close();
|
||||
|
||||
console.log('✅ nuscore-Seite erfolgreich proxiert');
|
||||
return modifiedHtml;
|
||||
|
||||
} catch (error) {
|
||||
console.error('❌ Fehler beim Proxying der nuscore-Seite:', error);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
modifyHtmlForProxy(html, code) {
|
||||
// Entferne problematische Headers/Meta-Tags
|
||||
let modified = 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 Registrierung (kann Probleme verursachen)
|
||||
modified = modified.replace(
|
||||
/navigator\.serviceWorker\.register\([^)]+\)/g,
|
||||
'// Service Worker deaktiviert für Proxy'
|
||||
);
|
||||
|
||||
return modified;
|
||||
}
|
||||
|
||||
async proxyAsset(url) {
|
||||
try {
|
||||
await this.initialize();
|
||||
|
||||
const page = await this.context.newPage();
|
||||
const response = await page.goto(url, {
|
||||
waitUntil: 'networkidle',
|
||||
timeout: 15000
|
||||
});
|
||||
|
||||
if (!response || !response.ok()) {
|
||||
throw new Error(`Asset nicht erreichbar: ${url}`);
|
||||
}
|
||||
|
||||
const content = await response.body();
|
||||
const contentType = response.headers()['content-type'] || 'application/octet-stream';
|
||||
|
||||
await page.close();
|
||||
|
||||
return { content, contentType };
|
||||
|
||||
} catch (error) {
|
||||
console.error(`❌ Fehler beim Laden von Asset ${url}:`, error.message);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
async cleanup() {
|
||||
if (this.context) {
|
||||
await this.context.close();
|
||||
this.context = null;
|
||||
}
|
||||
if (this.browser) {
|
||||
await this.browser.close();
|
||||
this.browser = null;
|
||||
}
|
||||
console.log('🧹 Playwright Browser bereinigt');
|
||||
}
|
||||
}
|
||||
|
||||
// Singleton-Instanz
|
||||
const nuscoreProxyService = new NuscoreProxyService();
|
||||
|
||||
export default nuscoreProxyService;
|
||||
Reference in New Issue
Block a user