From 991d57d183607162fe29bc49d612330bc86bcbfe Mon Sep 17 00:00:00 2001 From: "Tizian.Breuch" Date: Mon, 29 Sep 2025 14:37:54 +0200 Subject: [PATCH] error logs --- package-lock.json | 464 ++++++++++++++++-- package.json | 1 + src/app/app.config.ts | 21 +- .../core/interceptors/error.interceptor.ts | 34 ++ src/app/core/services/auth.service.ts | 84 +++- 5 files changed, 541 insertions(+), 63 deletions(-) create mode 100644 src/app/core/interceptors/error.interceptor.ts diff --git a/package-lock.json b/package-lock.json index d40603d..e6dbb02 100644 --- a/package-lock.json +++ b/package-lock.json @@ -23,6 +23,7 @@ "@swimlane/ngx-charts": "^23.0.1", "@tailwindcss/postcss": "^4.1.11", "express": "^4.18.2", + "jwt-decode": "^4.0.0", "postcss": "^8.5.6", "rxjs": "~7.8.0", "tailwindcss": "^4.1.11", @@ -97,17 +98,17 @@ } }, "node_modules/@angular-devkit/build-angular": { - "version": "19.2.16", - "resolved": "https://registry.npmjs.org/@angular-devkit/build-angular/-/build-angular-19.2.16.tgz", - "integrity": "sha512-06Ry1GJ77wwy/yCSjzTcPn7mE61CRUDN1npQKwRZOQd63hrPvxFp/ueyZUODXxbqkAyieCgBwQ7qAKP6lFiZNg==", + "version": "19.2.17", + "resolved": "https://registry.npmjs.org/@angular-devkit/build-angular/-/build-angular-19.2.17.tgz", + "integrity": "sha512-lbvzNoSjHlhP6bcHtFMlEQHG/Zxc1tTdwoelm4+AWPuQH4rGfoty4SXH4rr50SXVBUg9Zb4xZuChOYZmYKpGLQ==", "dev": true, "license": "MIT", "dependencies": { "@ampproject/remapping": "2.3.0", - "@angular-devkit/architect": "0.1902.16", - "@angular-devkit/build-webpack": "0.1902.16", - "@angular-devkit/core": "19.2.16", - "@angular/build": "19.2.16", + "@angular-devkit/architect": "0.1902.17", + "@angular-devkit/build-webpack": "0.1902.17", + "@angular-devkit/core": "19.2.17", + "@angular/build": "19.2.17", "@babel/core": "7.26.10", "@babel/generator": "7.26.10", "@babel/helper-annotate-as-pure": "7.25.9", @@ -118,7 +119,7 @@ "@babel/preset-env": "7.26.9", "@babel/runtime": "7.26.10", "@discoveryjs/json-ext": "0.6.3", - "@ngtools/webpack": "19.2.16", + "@ngtools/webpack": "19.2.17", "@vitejs/plugin-basic-ssl": "1.2.0", "ansi-colors": "4.1.3", "autoprefixer": "10.4.20", @@ -172,7 +173,7 @@ "@angular/localize": "^19.0.0 || ^19.2.0-next.0", "@angular/platform-server": "^19.0.0 || ^19.2.0-next.0", "@angular/service-worker": "^19.0.0 || ^19.2.0-next.0", - "@angular/ssr": "^19.2.16", + "@angular/ssr": "^19.2.17", "@web/test-runner": "^0.20.0", "browser-sync": "^3.0.2", "jest": "^29.5.0", @@ -223,13 +224,13 @@ } }, "node_modules/@angular-devkit/build-angular/node_modules/@angular-devkit/architect": { - "version": "0.1902.16", - "resolved": "https://registry.npmjs.org/@angular-devkit/architect/-/architect-0.1902.16.tgz", - "integrity": "sha512-E5cM4D5nHmCpuQkvyYJjJ/GEfygfU5NoN1YAWRnIMLwTyC9s6ms13L/FuCfr7HqGPY8NjkOWG2517Xda03+jAw==", + "version": "0.1902.17", + "resolved": "https://registry.npmjs.org/@angular-devkit/architect/-/architect-0.1902.17.tgz", + "integrity": "sha512-/LV8lXi6/SqevyI9ZAk2uAqlnN/pUwNwD6SyjotCqU55FBhBW8vM3/GucFXawJqTOzNmBXuMx1YVvQN5H0v5LQ==", "dev": true, "license": "MIT", "dependencies": { - "@angular-devkit/core": "19.2.16", + "@angular-devkit/core": "19.2.17", "rxjs": "7.8.1" }, "engines": { @@ -239,9 +240,9 @@ } }, "node_modules/@angular-devkit/build-angular/node_modules/@angular-devkit/core": { - "version": "19.2.16", - "resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-19.2.16.tgz", - "integrity": "sha512-3MHfTTUMT/nSXLdhoilQATCY38XcnoJd7u7K0tLajTT7C+iNknvkzaV4g5qMA+E3yNzefcAkY7MZpgreNJuKEg==", + "version": "19.2.17", + "resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-19.2.17.tgz", + "integrity": "sha512-Ah008x2RJkd0F+NLKqIpA34/vUGwjlprRCkvddjDopAWRzYn6xCkz1Tqwuhn0nR1Dy47wTLKYD999TYl5ONOAQ==", "dev": true, "license": "MIT", "dependencies": { @@ -306,13 +307,13 @@ } }, "node_modules/@angular-devkit/build-webpack": { - "version": "0.1902.16", - "resolved": "https://registry.npmjs.org/@angular-devkit/build-webpack/-/build-webpack-0.1902.16.tgz", - "integrity": "sha512-KtTz1z/beiQqyB/gaw4k9xnYhymPHDeX5AOMp4f5xfn/iiUd+CKsRO/P7wyVADI9IUxEPjy7BCJFhmOYHM9anQ==", + "version": "0.1902.17", + "resolved": "https://registry.npmjs.org/@angular-devkit/build-webpack/-/build-webpack-0.1902.17.tgz", + "integrity": "sha512-8NVJL7ujeTYKR1LgErkc5UN3EEoGYasqtu5AACXraFf9NLOw2p9N0+QY4cfjIwip1nyBp0RRzlBS4omGEymJCw==", "dev": true, "license": "MIT", "dependencies": { - "@angular-devkit/architect": "0.1902.16", + "@angular-devkit/architect": "0.1902.17", "rxjs": "7.8.1" }, "engines": { @@ -326,13 +327,13 @@ } }, "node_modules/@angular-devkit/build-webpack/node_modules/@angular-devkit/architect": { - "version": "0.1902.16", - "resolved": "https://registry.npmjs.org/@angular-devkit/architect/-/architect-0.1902.16.tgz", - "integrity": "sha512-E5cM4D5nHmCpuQkvyYJjJ/GEfygfU5NoN1YAWRnIMLwTyC9s6ms13L/FuCfr7HqGPY8NjkOWG2517Xda03+jAw==", + "version": "0.1902.17", + "resolved": "https://registry.npmjs.org/@angular-devkit/architect/-/architect-0.1902.17.tgz", + "integrity": "sha512-/LV8lXi6/SqevyI9ZAk2uAqlnN/pUwNwD6SyjotCqU55FBhBW8vM3/GucFXawJqTOzNmBXuMx1YVvQN5H0v5LQ==", "dev": true, "license": "MIT", "dependencies": { - "@angular-devkit/core": "19.2.16", + "@angular-devkit/core": "19.2.17", "rxjs": "7.8.1" }, "engines": { @@ -342,9 +343,9 @@ } }, "node_modules/@angular-devkit/build-webpack/node_modules/@angular-devkit/core": { - "version": "19.2.16", - "resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-19.2.16.tgz", - "integrity": "sha512-3MHfTTUMT/nSXLdhoilQATCY38XcnoJd7u7K0tLajTT7C+iNknvkzaV4g5qMA+E3yNzefcAkY7MZpgreNJuKEg==", + "version": "19.2.17", + "resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-19.2.17.tgz", + "integrity": "sha512-Ah008x2RJkd0F+NLKqIpA34/vUGwjlprRCkvddjDopAWRzYn6xCkz1Tqwuhn0nR1Dy47wTLKYD999TYl5ONOAQ==", "dev": true, "license": "MIT", "dependencies": { @@ -463,14 +464,14 @@ } }, "node_modules/@angular/build": { - "version": "19.2.16", - "resolved": "https://registry.npmjs.org/@angular/build/-/build-19.2.16.tgz", - "integrity": "sha512-sgxyrzWs2b4O19pOtWUoeDHkZ53pDoGK8GQYEdqHLNgM1JQRrHBTQts8pteopS+oPsG7WJinfXZww/c9P7BuSQ==", + "version": "19.2.17", + "resolved": "https://registry.npmjs.org/@angular/build/-/build-19.2.17.tgz", + "integrity": "sha512-JrF9dSrsMip2xJzSz3zNoozBXu/OYg0bHuKfuPA/usPhz5AomJ2SQ2unvl6sDF00pTlgJohJMQ6SUHjylybn2g==", "dev": true, "license": "MIT", "dependencies": { "@ampproject/remapping": "2.3.0", - "@angular-devkit/architect": "0.1902.16", + "@angular-devkit/architect": "0.1902.17", "@babel/core": "7.26.10", "@babel/helper-annotate-as-pure": "7.25.9", "@babel/helper-split-export-declaration": "7.24.7", @@ -493,7 +494,7 @@ "sass": "1.85.0", "semver": "7.7.1", "source-map-support": "0.5.21", - "vite": "6.2.7", + "vite": "6.3.6", "watchpack": "2.4.2" }, "engines": { @@ -510,7 +511,7 @@ "@angular/localize": "^19.0.0 || ^19.2.0-next.0", "@angular/platform-server": "^19.0.0 || ^19.2.0-next.0", "@angular/service-worker": "^19.0.0 || ^19.2.0-next.0", - "@angular/ssr": "^19.2.16", + "@angular/ssr": "^19.2.17", "karma": "^6.4.0", "less": "^4.2.0", "ng-packagr": "^19.0.0 || ^19.2.0-next.0", @@ -549,13 +550,13 @@ } }, "node_modules/@angular/build/node_modules/@angular-devkit/architect": { - "version": "0.1902.16", - "resolved": "https://registry.npmjs.org/@angular-devkit/architect/-/architect-0.1902.16.tgz", - "integrity": "sha512-E5cM4D5nHmCpuQkvyYJjJ/GEfygfU5NoN1YAWRnIMLwTyC9s6ms13L/FuCfr7HqGPY8NjkOWG2517Xda03+jAw==", + "version": "0.1902.17", + "resolved": "https://registry.npmjs.org/@angular-devkit/architect/-/architect-0.1902.17.tgz", + "integrity": "sha512-/LV8lXi6/SqevyI9ZAk2uAqlnN/pUwNwD6SyjotCqU55FBhBW8vM3/GucFXawJqTOzNmBXuMx1YVvQN5H0v5LQ==", "dev": true, "license": "MIT", "dependencies": { - "@angular-devkit/core": "19.2.16", + "@angular-devkit/core": "19.2.17", "rxjs": "7.8.1" }, "engines": { @@ -565,9 +566,9 @@ } }, "node_modules/@angular/build/node_modules/@angular-devkit/core": { - "version": "19.2.16", - "resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-19.2.16.tgz", - "integrity": "sha512-3MHfTTUMT/nSXLdhoilQATCY38XcnoJd7u7K0tLajTT7C+iNknvkzaV4g5qMA+E3yNzefcAkY7MZpgreNJuKEg==", + "version": "19.2.17", + "resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-19.2.17.tgz", + "integrity": "sha512-Ah008x2RJkd0F+NLKqIpA34/vUGwjlprRCkvddjDopAWRzYn6xCkz1Tqwuhn0nR1Dy47wTLKYD999TYl5ONOAQ==", "dev": true, "license": "MIT", "dependencies": { @@ -4175,9 +4176,9 @@ } }, "node_modules/@ngtools/webpack": { - "version": "19.2.16", - "resolved": "https://registry.npmjs.org/@ngtools/webpack/-/webpack-19.2.16.tgz", - "integrity": "sha512-KJf/pmpQl8SGhTof91EUuSFfR34kSTjcCQp3JQWDvG08+Lnx3wKbnKrZjC9vz0fhRrB+ZFVxeAyDAh1zZk07wg==", + "version": "19.2.17", + "resolved": "https://registry.npmjs.org/@ngtools/webpack/-/webpack-19.2.17.tgz", + "integrity": "sha512-HpbOLwS8tIW041UXcMqwfySqpZ9ztObH8U4NWKwjPBe0S5UDnF6doW2rS3GQm71hkiuB8sqbxOWz5I/NNvZFNQ==", "dev": true, "license": "MIT", "engines": { @@ -4988,6 +4989,20 @@ "linux" ] }, + "node_modules/@rollup/rollup-linux-loong64-gnu": { + "version": "4.52.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.52.2.tgz", + "integrity": "sha512-8wTRM3+gVMDLLDdaT6tKmOE3lJyRy9NpJUS/ZRWmLCmOPIJhVyXwjBo+XbrrwtV33Em1/eCTd5TuGJm4+DmYjw==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, "node_modules/@rollup/rollup-linux-loongarch64-gnu": { "version": "4.34.8", "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loongarch64-gnu/-/rollup-linux-loongarch64-gnu-4.34.8.tgz", @@ -5016,6 +5031,20 @@ "linux" ] }, + "node_modules/@rollup/rollup-linux-ppc64-gnu": { + "version": "4.52.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.52.2.tgz", + "integrity": "sha512-6yqEfgJ1anIeuP2P/zhtfBlDpXUb80t8DpbYwXQ3bQd95JMvUaqiX+fKqYqUwZXqdJDd8xdilNtsHM2N0cFm6A==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, "node_modules/@rollup/rollup-linux-riscv64-gnu": { "version": "4.34.8", "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.34.8.tgz", @@ -5030,6 +5059,20 @@ "linux" ] }, + "node_modules/@rollup/rollup-linux-riscv64-musl": { + "version": "4.52.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.52.2.tgz", + "integrity": "sha512-duBLgd+3pqC4MMwBrKkFxaZerUxZcYApQVC5SdbF5/e/589GwVvlRUnyqMFbM8iUSb1BaoX/3fRL7hB9m2Pj8Q==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, "node_modules/@rollup/rollup-linux-s390x-gnu": { "version": "4.34.8", "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.34.8.tgz", @@ -5072,6 +5115,20 @@ "linux" ] }, + "node_modules/@rollup/rollup-openharmony-arm64": { + "version": "4.52.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.52.2.tgz", + "integrity": "sha512-uPj7MQ6/s+/GOpolavm6BPo+6CbhbKYyZHUDvZ/SmJM7pfDBgdGisFX3bY/CBDMg2ZO4utfhlApkSfZ92yXw7Q==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ] + }, "node_modules/@rollup/rollup-win32-arm64-msvc": { "version": "4.34.8", "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.34.8.tgz", @@ -5100,6 +5157,20 @@ "win32" ] }, + "node_modules/@rollup/rollup-win32-x64-gnu": { + "version": "4.52.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.52.2.tgz", + "integrity": "sha512-ApXFKluSB6kDQkAqZOKXBjiaqdF1BlKi+/eqnYe9Ee7U2K3pUDKsIyr8EYm/QDHTJIM+4X+lI0gJc3TTRhd+dA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, "node_modules/@rollup/rollup-win32-x64-msvc": { "version": "4.34.8", "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.34.8.tgz", @@ -9969,6 +10040,15 @@ ], "license": "MIT" }, + "node_modules/jwt-decode": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/jwt-decode/-/jwt-decode-4.0.0.tgz", + "integrity": "sha512-+KJGIyHgkGuIq3IEBNftfhW/LfWhXUIY6OmyVWjliu5KH1y0fw7VQ8YndE2O4qZdMSd9SqbnC8GOcZEy0Om7sA==", + "license": "MIT", + "engines": { + "node": ">=18" + } + }, "node_modules/karma": { "version": "6.4.4", "resolved": "https://registry.npmjs.org/karma/-/karma-6.4.4.tgz", @@ -14646,15 +14726,18 @@ } }, "node_modules/vite": { - "version": "6.2.7", - "resolved": "https://registry.npmjs.org/vite/-/vite-6.2.7.tgz", - "integrity": "sha512-qg3LkeuinTrZoJHHF94coSaTfIPyBYoywp+ys4qu20oSJFbKMYoIJo0FWJT9q6Vp49l6z9IsJRbHdcGtiKbGoQ==", + "version": "6.3.6", + "resolved": "https://registry.npmjs.org/vite/-/vite-6.3.6.tgz", + "integrity": "sha512-0msEVHJEScQbhkbVTb/4iHZdJ6SXp/AvxL2sjwYQFfBqleHtnCqv1J3sa9zbWz/6kW1m9Tfzn92vW+kZ1WV6QA==", "dev": true, "license": "MIT", "dependencies": { "esbuild": "^0.25.0", + "fdir": "^6.4.4", + "picomatch": "^4.0.2", "postcss": "^8.5.3", - "rollup": "^4.30.1" + "rollup": "^4.34.9", + "tinyglobby": "^0.2.13" }, "bin": { "vite": "bin/vite.js" @@ -14717,6 +14800,293 @@ } } }, + "node_modules/vite/node_modules/@rollup/rollup-android-arm-eabi": { + "version": "4.52.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.52.2.tgz", + "integrity": "sha512-o3pcKzJgSGt4d74lSZ+OCnHwkKBeAbFDmbEm5gg70eA8VkyCuC/zV9TwBnmw6VjDlRdF4Pshfb+WE9E6XY1PoQ==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/vite/node_modules/@rollup/rollup-android-arm64": { + "version": "4.52.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.52.2.tgz", + "integrity": "sha512-cqFSWO5tX2vhC9hJTK8WAiPIm4Q8q/cU8j2HQA0L3E1uXvBYbOZMhE2oFL8n2pKB5sOCHY6bBuHaRwG7TkfJyw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/vite/node_modules/@rollup/rollup-darwin-arm64": { + "version": "4.52.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.52.2.tgz", + "integrity": "sha512-vngduywkkv8Fkh3wIZf5nFPXzWsNsVu1kvtLETWxTFf/5opZmflgVSeLgdHR56RQh71xhPhWoOkEBvbehwTlVA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/vite/node_modules/@rollup/rollup-darwin-x64": { + "version": "4.52.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.52.2.tgz", + "integrity": "sha512-h11KikYrUCYTrDj6h939hhMNlqU2fo/X4NB0OZcys3fya49o1hmFaczAiJWVAFgrM1NCP6RrO7lQKeVYSKBPSQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/vite/node_modules/@rollup/rollup-freebsd-arm64": { + "version": "4.52.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.52.2.tgz", + "integrity": "sha512-/eg4CI61ZUkLXxMHyVlmlGrSQZ34xqWlZNW43IAU4RmdzWEx0mQJ2mN/Cx4IHLVZFL6UBGAh+/GXhgvGb+nVxw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/vite/node_modules/@rollup/rollup-freebsd-x64": { + "version": "4.52.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.52.2.tgz", + "integrity": "sha512-QOWgFH5X9+p+S1NAfOqc0z8qEpJIoUHf7OWjNUGOeW18Mx22lAUOiA9b6r2/vpzLdfxi/f+VWsYjUOMCcYh0Ng==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/vite/node_modules/@rollup/rollup-linux-arm-gnueabihf": { + "version": "4.52.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.52.2.tgz", + "integrity": "sha512-kDWSPafToDd8LcBYd1t5jw7bD5Ojcu12S3uT372e5HKPzQt532vW+rGFFOaiR0opxePyUkHrwz8iWYEyH1IIQA==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/vite/node_modules/@rollup/rollup-linux-arm-musleabihf": { + "version": "4.52.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.52.2.tgz", + "integrity": "sha512-gKm7Mk9wCv6/rkzwCiUC4KnevYhlf8ztBrDRT9g/u//1fZLapSRc+eDZj2Eu2wpJ+0RzUKgtNijnVIB4ZxyL+w==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/vite/node_modules/@rollup/rollup-linux-arm64-gnu": { + "version": "4.52.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.52.2.tgz", + "integrity": "sha512-66lA8vnj5mB/rtDNwPgrrKUOtCLVQypkyDa2gMfOefXK6rcZAxKLO9Fy3GkW8VkPnENv9hBkNOFfGLf6rNKGUg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/vite/node_modules/@rollup/rollup-linux-arm64-musl": { + "version": "4.52.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.52.2.tgz", + "integrity": "sha512-s+OPucLNdJHvuZHuIz2WwncJ+SfWHFEmlC5nKMUgAelUeBUnlB4wt7rXWiyG4Zn07uY2Dd+SGyVa9oyLkVGOjA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/vite/node_modules/@rollup/rollup-linux-riscv64-gnu": { + "version": "4.52.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.52.2.tgz", + "integrity": "sha512-sshYUiYVSEI2B6dp4jMncwxbrUqRdNApF2c3bhtLAU0qA8Lrri0p0NauOsTWh3yCCCDyBOjESHMExonp7Nzc0w==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/vite/node_modules/@rollup/rollup-linux-s390x-gnu": { + "version": "4.52.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.52.2.tgz", + "integrity": "sha512-tzhYJJidDUVGMgVyE+PmxENPHlvvqm1KILjjZhB8/xHYqAGeizh3GBGf9u6WdJpZrz1aCpIIHG0LgJgH9rVjHQ==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/vite/node_modules/@rollup/rollup-linux-x64-gnu": { + "version": "4.52.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.52.2.tgz", + "integrity": "sha512-opH8GSUuVcCSSyHHcl5hELrmnk4waZoVpgn/4FDao9iyE4WpQhyWJ5ryl5M3ocp4qkRuHfyXnGqg8M9oKCEKRA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/vite/node_modules/@rollup/rollup-linux-x64-musl": { + "version": "4.52.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.52.2.tgz", + "integrity": "sha512-LSeBHnGli1pPKVJ79ZVJgeZWWZXkEe/5o8kcn23M8eMKCUANejchJbF/JqzM4RRjOJfNRhKJk8FuqL1GKjF5oQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/vite/node_modules/@rollup/rollup-win32-arm64-msvc": { + "version": "4.52.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.52.2.tgz", + "integrity": "sha512-Z9MUCrSgIaUeeHAiNkm3cQyst2UhzjPraR3gYYfOjAuZI7tcFRTOD+4cHLPoS/3qinchth+V56vtqz1Tv+6KPA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/vite/node_modules/@rollup/rollup-win32-ia32-msvc": { + "version": "4.52.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.52.2.tgz", + "integrity": "sha512-+GnYBmpjldD3XQd+HMejo+0gJGwYIOfFeoBQv32xF/RUIvccUz20/V6Otdv+57NE70D5pa8W/jVGDoGq0oON4A==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/vite/node_modules/@rollup/rollup-win32-x64-msvc": { + "version": "4.52.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.52.2.tgz", + "integrity": "sha512-ARz+Bs8kY6FtitYM96PqPEVvPXqEZmPZsSkXvyX19YzDqkCaIlhCieLLMI5hxO9SRZ2XtCtm8wxhy0iJ2jxNfw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/vite/node_modules/@types/estree": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz", + "integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==", + "dev": true, + "license": "MIT" + }, + "node_modules/vite/node_modules/rollup": { + "version": "4.52.2", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.52.2.tgz", + "integrity": "sha512-I25/2QgoROE1vYV+NQ1En9T9UFB9Cmfm2CJ83zZOlaDpvz29wGQSZXWKw7MiNXau7wYgB/T9fVIdIuEQ+KbiiA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/estree": "1.0.8" + }, + "bin": { + "rollup": "dist/bin/rollup" + }, + "engines": { + "node": ">=18.0.0", + "npm": ">=8.0.0" + }, + "optionalDependencies": { + "@rollup/rollup-android-arm-eabi": "4.52.2", + "@rollup/rollup-android-arm64": "4.52.2", + "@rollup/rollup-darwin-arm64": "4.52.2", + "@rollup/rollup-darwin-x64": "4.52.2", + "@rollup/rollup-freebsd-arm64": "4.52.2", + "@rollup/rollup-freebsd-x64": "4.52.2", + "@rollup/rollup-linux-arm-gnueabihf": "4.52.2", + "@rollup/rollup-linux-arm-musleabihf": "4.52.2", + "@rollup/rollup-linux-arm64-gnu": "4.52.2", + "@rollup/rollup-linux-arm64-musl": "4.52.2", + "@rollup/rollup-linux-loong64-gnu": "4.52.2", + "@rollup/rollup-linux-ppc64-gnu": "4.52.2", + "@rollup/rollup-linux-riscv64-gnu": "4.52.2", + "@rollup/rollup-linux-riscv64-musl": "4.52.2", + "@rollup/rollup-linux-s390x-gnu": "4.52.2", + "@rollup/rollup-linux-x64-gnu": "4.52.2", + "@rollup/rollup-linux-x64-musl": "4.52.2", + "@rollup/rollup-openharmony-arm64": "4.52.2", + "@rollup/rollup-win32-arm64-msvc": "4.52.2", + "@rollup/rollup-win32-ia32-msvc": "4.52.2", + "@rollup/rollup-win32-x64-gnu": "4.52.2", + "@rollup/rollup-win32-x64-msvc": "4.52.2", + "fsevents": "~2.3.2" + } + }, "node_modules/void-elements": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/void-elements/-/void-elements-2.0.1.tgz", diff --git a/package.json b/package.json index 4d71d53..2b133b9 100644 --- a/package.json +++ b/package.json @@ -26,6 +26,7 @@ "@swimlane/ngx-charts": "^23.0.1", "@tailwindcss/postcss": "^4.1.11", "express": "^4.18.2", + "jwt-decode": "^4.0.0", "postcss": "^8.5.6", "rxjs": "~7.8.0", "tailwindcss": "^4.1.11", diff --git a/src/app/app.config.ts b/src/app/app.config.ts index ad0bed6..4a79648 100644 --- a/src/app/app.config.ts +++ b/src/app/app.config.ts @@ -1,11 +1,20 @@ // /src/app/app.config.ts -import { ApplicationConfig, importProvidersFrom, provideZoneChangeDetection } from '@angular/core'; +import { + ApplicationConfig, + importProvidersFrom, + provideZoneChangeDetection, +} from '@angular/core'; import { provideRouter } from '@angular/router'; import { provideAnimations } from '@angular/platform-browser/animations'; -import { provideHttpClient, withFetch, withInterceptors } from '@angular/common/http'; +import { + provideHttpClient, + withFetch, + withInterceptors, +} from '@angular/common/http'; import { provideClientHydration } from '@angular/platform-browser'; import { ReactiveFormsModule, FormsModule } from '@angular/forms'; +import { errorInterceptor } from './core/interceptors/error.interceptor'; import { routes } from './app.routes'; @@ -25,7 +34,7 @@ export const appConfig: ApplicationConfig = { // withFetch() entfernen, da es mit Interceptors noch Probleme geben kann // Stattdessen withInterceptors() verwenden provideHttpClient( - withInterceptors([authInterceptor]) // Registriert unseren neuen Interceptor + withInterceptors([authInterceptor, errorInterceptor]) // Registriert unseren neuen Interceptor ), // --- Forms Provider (sauberer Import) --- @@ -37,6 +46,6 @@ export const appConfig: ApplicationConfig = { // --- API_URL Provider hinzufügen --- // Stellt den API_URL-Token mit dem Wert aus der passenden environment-Datei bereit - { provide: API_URL, useValue: environment.apiUrl } - ] -}; \ No newline at end of file + { provide: API_URL, useValue: environment.apiUrl }, + ], +}; diff --git a/src/app/core/interceptors/error.interceptor.ts b/src/app/core/interceptors/error.interceptor.ts new file mode 100644 index 0000000..99bf6b5 --- /dev/null +++ b/src/app/core/interceptors/error.interceptor.ts @@ -0,0 +1,34 @@ +// /src/app/core/interceptors/error.interceptor.ts + +import { HttpErrorResponse, HttpInterceptorFn } from '@angular/common/http'; +import { inject } from '@angular/core'; +import { catchError, throwError } from 'rxjs'; +import { AuthService } from '../services/auth.service'; +import { LoggingService } from '../services/logging.service'; + +export const errorInterceptor: HttpInterceptorFn = (req, next) => { + const authService = inject(AuthService); + const logger = inject(LoggingService); + + return next(req).pipe( + catchError((error: unknown) => { + if (error instanceof HttpErrorResponse) { + // Speziell den 401-Fehler (Unauthorized) abfangen + if (error.status === 401) { + logger.warn('Unauthorized request (401). Token might be expired or invalid. Logging out.'); + // Den Benutzer ausloggen und zur Login-Seite weiterleiten + authService.logout(); + } else { + // Andere Server-Fehler loggen + logger.error(`HTTP Error: ${error.status} ${error.statusText}`, error); + } + } else { + // Client-seitige Fehler loggen + logger.error('An unknown client-side error occurred', error); + } + + // Den Fehler an den aufrufenden Service weitergeben + return throwError(() => error); + }) + ); +}; \ No newline at end of file diff --git a/src/app/core/services/auth.service.ts b/src/app/core/services/auth.service.ts index a5b522f..17ce50e 100644 --- a/src/app/core/services/auth.service.ts +++ b/src/app/core/services/auth.service.ts @@ -5,11 +5,18 @@ import { HttpClient } from '@angular/common/http'; import { isPlatformBrowser } from '@angular/common'; import { Router } from '@angular/router'; import { Observable, BehaviorSubject, of } from 'rxjs'; -import { tap, catchError, map } from 'rxjs/operators'; +import { tap, catchError } from 'rxjs/operators'; +import { jwtDecode } from 'jwt-decode'; -import { LoginRequest, AuthResponse, RegisterRequest } from '../models/auth.models' +import { LoginRequest, AuthResponse, RegisterRequest } from '../models/auth.models'; import { API_URL } from '../tokens/api-url.token'; +// Ein Hilfs-Interface, um die Struktur des dekodierten Tokens typsicher zu machen. +interface DecodedToken { + exp: number; // Expiration time als UNIX-Timestamp in Sekunden + // Hier könnten weitere Claims wie 'email', 'sub', 'role' etc. stehen +} + @Injectable({ providedIn: 'root' }) @@ -18,30 +25,46 @@ export class AuthService { private http = inject(HttpClient); private router = inject(Router); private platformId = inject(PLATFORM_ID); - private apiUrl = inject(API_URL); // <-- SAUBERE INJEKTION! + private apiUrl = inject(API_URL); private readonly endpoint = '/Auth'; - - // Keys für die Speicherung im localStorage private readonly TOKEN_KEY = 'auth-token'; private readonly ROLES_KEY = 'auth-user-roles'; private loggedInStatus = new BehaviorSubject(this.isBrowser() && !!this.getToken()); public isLoggedIn$ = this.loggedInStatus.asObservable(); + private tokenExpirationTimer: any; + + constructor() { + // Beim Initialisieren des Services prüfen, ob bereits ein Token vorhanden ist + // und ggf. den Logout-Timer dafür starten (z.B. nach einem Neuladen der Seite). + this.initTokenCheck(); + } + loginAdmin(credentials: LoginRequest): Observable { return this.http.post(`${this.apiUrl}${this.endpoint}/login/admin`, credentials).pipe( - tap(response => this.setSession(response)), + tap(response => { + if (response?.isAuthSuccessful) { + this.setSession(response); + this.startTokenExpirationTimer(); // Timer nach erfolgreichem Login starten + } + }), catchError(() => { - this.clearSession(); // Bei fehlgeschlagenem Login immer die Session aufräumen - return of(null); // Gib ein "leeres" Observable zurück statt einen Fehler zu werfen + this.clearSession(); + return of(null); }) ); } loginCustomer(credentials: LoginRequest): Observable { return this.http.post(`${this.apiUrl}${this.endpoint}/login/customer`, credentials).pipe( - tap(response => this.setSession(response)), + tap(response => { + if (response?.isAuthSuccessful) { + this.setSession(response); + this.startTokenExpirationTimer(); // Timer nach erfolgreichem Login starten + } + }), catchError(() => { this.clearSession(); return of(null); @@ -57,7 +80,11 @@ export class AuthService { logout(): void { this.clearSession(); - this.router.navigate(['/auth/login']); // Empfehlung: Routen gruppieren + // Den proaktiven Timer stoppen, da der Logout manuell erfolgt. + if (this.tokenExpirationTimer) { + clearTimeout(this.tokenExpirationTimer); + } + this.router.navigate(['/auth/login']); } getToken(): string | null { @@ -93,4 +120,41 @@ export class AuthService { private isBrowser(): boolean { return isPlatformBrowser(this.platformId); } + + private startTokenExpirationTimer(): void { + if (this.tokenExpirationTimer) { + clearTimeout(this.tokenExpirationTimer); + } + + const token = this.getToken(); + if (!token) { + return; + } + + try { + const decodedToken = jwtDecode(token); + const expirationDate = new Date(decodedToken.exp * 1000); // JWT 'exp' ist in Sekunden, Date() braucht Millisekunden + const timeoutDuration = expirationDate.getTime() - new Date().getTime(); + + if (timeoutDuration > 0) { + this.tokenExpirationTimer = setTimeout(() => { + console.warn('Sitzung proaktiv beendet, da das Token abgelaufen ist.'); + this.logout(); + // Hier könnte man eine Snackbar-Nachricht anzeigen + }, timeoutDuration); + } else { + // Das gespeicherte Token ist bereits abgelaufen + this.clearSession(); + } + } catch (error) { + console.error('Fehler beim Dekodieren des Tokens. Session wird bereinigt.', error); + this.clearSession(); + } + } + + private initTokenCheck(): void { + if (this.isBrowser()) { + this.startTokenExpirationTimer(); + } + } } \ No newline at end of file