Commit: e6d1548

Commit Details

SHAe6d1548c463d8763fb5547ff07a35c521f15c296
Tree2d2b62527861022ccf13eb205ea2bf7c0e4013fd
Author<f69e50@finnacloud.com> 1766442769 +0300
Committer<f69e50@finnacloud.com> 1766442769 +0300
Message
add initial test workflow file
GPG Signature
-----BEGIN PGP SIGNATURE-----

iQJSBAABCAA8FiEEWJb139mJI+vZ81KkoAIVSUsXI0oFAmlJxxEeHHNvcGhpYS5l
cmFzbGFuQGZpbm5hY2xvdWQuY29tAAoJEKACFUlLFyNKb7YP/2QctdaPuHu4+vFn
fh0Opgqt1brKy9JQxV9JZ9tF5XA+rWVi6pyIZK4lywX+a4er+h29sQY7TEHZt9Xn
meAyRUhPbRPmIpRJMMCgstfILUpjNMkMcPE80kJfpp6+ZmLtO8vC4TnW3ATCK1tv
XISV00T4ajCAhZUmYTveNsvSiMMv/Tq4sF9Is4ix+JN7O/lSLseRtuUE1Vv7T7nY
citxLPwR42Eb/1CYhy0JbRYXP816cbe6dGeDeiDZp7EHKx5D8VAqULKRsAL19tSX
hup8N7owBXieuzNQ4RyaDfDJAfNoN3o9pFeD6vQPq8s7x6AloN625g58p0ssxfK+
CGhR0YHR7atR0pEens22p7g2dVJ7NsrKqDBE3TTeUOpfXfjOwqpVh1Bn/v7a2Vg9
o9mhIClSOLfYv2SXJ06+fn8l6oc70nLJkBfcTevmeF//Z9yGH7TXZNUcedxuBbFg
xfEHeJibTamiE3Z1SfHW1YLwe7QqbBogCIxq4RrpYtN15a65vT5HxyLHDJDGG20V
7z34QJhKXIni/AIGscZqx2kE/C42KSD2fBvqvA4YnPwEUQyMvnSSDSKuJ6flXPTv
RsPZMdNsWWWyJ8P/NTo0Y/PPwA/28p9pX064H2lHFNvSEzUYJdKyQXNV3pGWYAvc
PR8Z+nHfbK/EF5jOVJ8+erXzzXUN
=COmA
-----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