[FIX] Fix some securiry issues

This commit is contained in:
NADAL Jean-Baptiste
2026-02-18 15:27:55 +01:00
parent 3abc6f6371
commit 039cecc4a6
15 changed files with 2179 additions and 200 deletions

View File

@@ -3,7 +3,10 @@ import { auth } from '$lib/stores/auth';
import { browser } from '$app/environment';
import { get } from 'svelte/store';
const API_BASE_URL = browser ? 'http://localhost:8000' : 'http://localhost:8000';
// Use environment variable or default to localhost
const API_BASE_URL = browser
? (import.meta.env.VITE_API_URL || 'http://localhost:8000')
: (import.meta.env.VITE_API_URL || 'http://localhost:8000');
const api = axios.create({
baseURL: API_BASE_URL,
@@ -107,15 +110,21 @@ export const apiService = {
},
getDownloadUrl(path: string): string {
let token = '';
auth.subscribe((state) => {
token = state.token || '';
})();
return `${API_BASE_URL}/download/${path}?token=${token}`;
// Security: Token is now passed via Authorization header, not URL
// The backend will read the token from the header in the request
return `${API_BASE_URL}/download/${path}`;
},
async createScore(name: string, compositor: string): Promise<{ success: boolean; score?: any; error?: string }> {
const response = await api.post('/admin/scores', { name, compositor });
// New method to download with proper auth header
async downloadFileWithAuth(path: string): Promise<Blob> {
const response = await api.get(`/download/${path}`, {
responseType: 'blob'
});
return response.data;
},
async createScore(name: string, compositor: string, pieces: { number: number; name: string }[] = []): Promise<{ success: boolean; score?: any; error?: string }> {
const response = await api.post('/admin/scores', { name, compositor, pieces });
return response.data;
},
@@ -146,5 +155,17 @@ export const apiService = {
}
});
return response.data;
},
async getScoreFiles(scoreId: string): Promise<{ success: boolean; files: any[]; error?: string }> {
const response = await api.get(`/admin/scores/${scoreId}/files`);
return response.data;
},
async deleteScoreFile(scoreId: string, filePath: string): Promise<{ success: boolean; error?: string }> {
const response = await api.delete(`/admin/scores/${scoreId}/files`, {
params: { path: filePath }
});
return response.data;
}
};

View File

@@ -11,9 +11,34 @@ interface AuthState {
user: User | null;
}
/**
* Auth Store
*
* SECURITY NOTE: Token is stored in localStorage which is vulnerable to XSS attacks.
* The CSP (Content Security Policy) helps mitigate XSS risks.
* For production with higher security requirements, consider migrating to httpOnly cookies.
*/
function createAuthStore() {
// SECURITY: Validate stored data before parsing to prevent XSS via localStorage
const stored = browser ? localStorage.getItem('auth') : null;
const initial: AuthState = stored ? JSON.parse(stored) : { token: null, user: null };
let initial: AuthState = { token: null, user: null };
if (stored) {
try {
const parsed = JSON.parse(stored);
// Validate structure to prevent injection
if (parsed && typeof parsed === 'object' &&
(parsed.token === null || typeof parsed.token === 'string') &&
(parsed.user === null || (typeof parsed.user === 'object' && parsed.user.username && parsed.user.role))) {
initial = parsed;
}
} catch (e) {
// Invalid stored data, clear it
if (browser) {
localStorage.removeItem('auth');
}
}
}
const { subscribe, set, update } = writable<AuthState>(initial);