feat: Security

This commit is contained in:
2026-06-05 18:34:01 +02:00
parent ee293d7daf
commit 45675192a5
134 changed files with 4128 additions and 446 deletions

View File

@@ -0,0 +1,91 @@
import { Injectable } from '@angular/core';
interface StoredAuthToken {
token: string;
expiresAt: number;
}
const STORAGE_KEY = 'metoyou.authTokens';
@Injectable({ providedIn: 'root' })
export class AuthTokenStoreService {
setToken(serverUrl: string, token: string, expiresAt: number): void {
const normalizedUrl = this.normalizeServerUrl(serverUrl);
const store = this.readStore();
store[normalizedUrl] = { token, expiresAt };
this.writeStore(store);
}
getToken(serverUrl: string): string | null {
const normalizedUrl = this.normalizeServerUrl(serverUrl);
const entry = this.readStore()[normalizedUrl];
if (!entry) {
return null;
}
if (entry.expiresAt <= Date.now()) {
this.clearToken(serverUrl);
return null;
}
return entry.token;
}
clearToken(serverUrl: string): void {
const normalizedUrl = this.normalizeServerUrl(serverUrl);
const store = this.readStore();
const nextStore = Object.fromEntries(
Object.entries(store).filter(([key]) => key !== normalizedUrl)
) as Record<string, StoredAuthToken>;
this.writeStore(nextStore);
}
hasAnyValidToken(): boolean {
const now = Date.now();
return Object.values(this.readStore()).some((entry) => entry.expiresAt > now);
}
findTokenForApiUrl(apiUrl: string): string | null {
const normalizedApiUrl = apiUrl.trim().replace(/\/+$/, '');
for (const [serverUrl, entry] of Object.entries(this.readStore())) {
if (entry.expiresAt <= Date.now()) {
continue;
}
if (normalizedApiUrl === serverUrl || normalizedApiUrl.startsWith(`${serverUrl}/`)) {
return entry.token;
}
}
return null;
}
private readStore(): Record<string, StoredAuthToken> {
try {
const raw = localStorage.getItem(STORAGE_KEY);
if (!raw) {
return {};
}
const parsed = JSON.parse(raw) as Record<string, StoredAuthToken>;
return parsed && typeof parsed === 'object' ? parsed : {};
} catch {
return {};
}
}
private writeStore(store: Record<string, StoredAuthToken>): void {
localStorage.setItem(STORAGE_KEY, JSON.stringify(store));
}
private normalizeServerUrl(serverUrl: string): string {
return serverUrl.trim().replace(/\/+$/, '');
}
}