Commit: 188fc92

Commit Details

SHA188fc92ac938e5ecdaaba64fb6d1dbffeba30181
Tree2cc04755c4f7f8be29aafd7e581f1f25e14edd58
Author<f69e50@finnacloud.com> 1766442998 +0300
Committer<f69e50@finnacloud.com> 1766442998 +0300
Message
increment
GPG Signature
-----BEGIN PGP SIGNATURE-----

iQJSBAABCAA8FiEEWJb139mJI+vZ81KkoAIVSUsXI0oFAmlJx/YeHHNvcGhpYS5l
cmFzbGFuQGZpbm5hY2xvdWQuY29tAAoJEKACFUlLFyNKyF8P/j6F8McjkGTBhDFX
frSY0CqkszvNegnZnDj4AkVjoJl7AK0RY0KLLQxrRUJq/MIA/FPj9G7df9jUJcae
TS+tvTZzWOXZ3EXomyNPangFgm5yAgmelwJYgeQdTmzIY3miM8/BdQg10GNC6Fjq
iEn6PKkpkItfiy+vftAABqe73SI9Vn6nwkUn2zVEsXBX1Kmv/ya9auodjFegvcbz
pRx5BL3xNYaA57c8WG9Fx+XaQPdaeLMcu/kM8diY0XTWqtdR+OfrPlU2JOApB0yO
G4P6zG6h5w2XWCqtbqfszDt94drbArJ9cQbWLlgbiNjpK+qJVvG+HGXxPGgvzLA3
9HhZxzUJobkt0MycngmZryj25b6kdO6OA5BCBCjdMkHjIvmBpLXYD5y5uYnerR0n
YEDyB5noRAiYbb2Skg1dp9dpNxq5LF1WkJpWM+nCXlOU6jKj3ucOJ7JP2+gVWA7N
jFdEUIfX65Q9CcBQqQX1vWyGJCc/Z0sNGE0Dc06PrpPk/U10oFNZOdCbUNEWU4Pk
yqATdaAI1BdvZjAip6QQ/jtIuHkwigAk9uUp21VlZ1NnXXLixmA53y12fi8f3DnB
yl55qYeoTOyEg5N7k1ukOt5rgoJ28szscEwvYmwL56uDtlrXly/vrSNrMi322aJK
IJeozLKMpf6Q9A3vN000vGTA6VjP
=Whh7
-----END PGP SIGNATURE-----

✓ Verified

File: src/main/resources/static/js/csrf.js

1 // CSRF Token Management
2 let csrfToken = null;
3 let tokenPromise = null;
4
5 // Get CSRF token from server (force refresh if needed)
6 async function getCsrfToken(forceRefresh = false) {
7 // If forcing refresh, clear existing token
8 if (forceRefresh) {
9 csrfToken = null;
10 tokenPromise = null;
11 }
12
13 // Return existing token if available and not forcing refresh
14 if (csrfToken && !forceRefresh) {
15 return csrfToken;
16 }
17
18 // If a request is already in progress, wait for it
19 if (tokenPromise) {
20 return tokenPromise;
21 }
22
23 // Fetch new token
24 tokenPromise = (async () => {
25 try {
26 const response = await fetch('/api/csrf-token', {
27 credentials: 'include' // Include cookies
28 });
29 const data = await response.json();
30
31 if (data.success) {
32 csrfToken = data.csrfToken;
33 tokenPromise = null;
34 return csrfToken;
35 }
36 } catch (error) {
37 console.error('Error fetching CSRF token:', error);
38 tokenPromise = null;
39 }
40
41 return null;
42 })();
43
44 return tokenPromise;
45 }
46
47 // Refresh CSRF token (alias for force refresh)
48 async function refreshCsrfToken() {
49 return await getCsrfToken(true);
50 }
51
52 // Add CSRF token to fetch request
53 async function fetchWithCsrf(url, options = {}) {
54 const method = options.method || 'GET';
55 const stateChangingMethods = ['POST', 'PUT', 'PATCH', 'DELETE'];
56
57 // For state-changing requests, always get a fresh token first
58 if (stateChangingMethods.includes(method.toUpperCase())) {
59 // Always refresh token before state-changing requests
60 // This ensures we have a valid token even if the previous one was invalidated
61 await refreshCsrfToken();
62 } else if (!csrfToken) {
63 // For GET requests, only fetch if we don't have a token
64 await getCsrfToken();
65 }
66
67 // Add CSRF token to headers
68 const headers = {
69 ...options.headers,
70 'X-CSRF-Token': csrfToken || ''
71 };
72
73 const response = await fetch(url, {
74 ...options,
75 headers,
76 credentials: 'include' // Include cookies
77 });
78
79 // After state-changing requests, always refresh the token
80 // The server invalidates the used token, so we need a new one for the next request
81 if (stateChangingMethods.includes(method.toUpperCase())) {
82 // Try to get new token from response header (server sends it)
83 const newToken = response.headers.get('X-New-CSRF-Token');
84 if (newToken) {
85 csrfToken = newToken;
86 } else {
87 // If no header (or header not accessible), refresh token immediately
88 // This ensures we always have a fresh token for the next request
89 try {
90 await refreshCsrfToken();
91 } catch (err) {
92 console.error('Error refreshing CSRF token:', err);
93 }
94 }
95 }
96
97 return response;
98 }
99
100 // Initialize CSRF token on page load
101 if (document.readyState === 'loading') {
102 document.addEventListener('DOMContentLoaded', async () => {
103 await getCsrfToken();
104 });
105 } else {
106 // DOM already loaded
107 getCsrfToken();
108 }
109
110 // Make functions globally available
111 window.getCsrfToken = getCsrfToken;
112 window.refreshCsrfToken = refreshCsrfToken;
113 window.fetchWithCsrf = fetchWithCsrf;
114
115
116