|
83 | 83 | this.container = container; |
84 | 84 | this.config = config; |
85 | 85 | this.iframe = null; |
86 | | - this.csrfToken = this.generateCsrfToken(); |
| 86 | + this.csrfToken = null; // Will be set by server in init() |
87 | 87 | this.state = { |
88 | 88 | loading: true, |
89 | 89 | error: null, |
|
141 | 141 | // Store the signed origin token - will be passed to iframe and used in API calls |
142 | 142 | this.originToken = initData.token; |
143 | 143 |
|
| 144 | + // Store the CSRF token from server (cryptographically signed, origin-specific) |
| 145 | + this.csrfToken = initData.csrfToken || this.generateCsrfToken(); // Fallback for older servers |
| 146 | + |
144 | 147 | } catch (e) { |
145 | 148 | console.error('[CommentKit] Failed to initialize:', e); |
146 | 149 | this.state.error = 'Failed to connect to CommentKit. Please try again later.'; |
|
1601 | 1604 | </div> |
1602 | 1605 | <div class="ck-form-group"> |
1603 | 1606 | <label for="ck-email">Email (optional)</label> |
1604 | | - <input type="email" id="ck-email" name="email" placeholder="your@email.com"> |
| 1607 | + <input type="email" id="ck-email" name="email" placeholder="your@email.com" pattern="[^\\s@]+@[^\\s@]+\\.[^\\s@]+" title="Please enter a valid email address (e.g., user@example.com)"> |
1605 | 1608 | </div> |
1606 | 1609 | </div> |
1607 | 1610 | <div class="ck-form-group"> |
|
1620 | 1623 | <form id="ck-login-form"> |
1621 | 1624 | <div class="ck-form-group"> |
1622 | 1625 | <label for="ck-login-email">Email address</label> |
1623 | | - <input type="email" id="ck-login-email" name="email" required placeholder="your@email.com"> |
| 1626 | + <input type="email" id="ck-login-email" name="email" required placeholder="your@email.com" pattern="[^\\s@]+@[^\\s@]+\\.[^\\s@]+" title="Please enter a valid email address (e.g., user@example.com)"> |
1624 | 1627 | </div> |
1625 | 1628 | <p style="font-size: 0.85rem; color: #6b7280; margin-bottom: 12px;"> |
1626 | 1629 | We'll send you a magic link to sign in. No password needed. |
|
1729 | 1732 | </div> |
1730 | 1733 | <div class="ck-form-group"> |
1731 | 1734 | <label>Email (optional)</label> |
1732 | | - <input type="email" name="email" placeholder="your@email.com"> |
| 1735 | + <input type="email" name="email" placeholder="your@email.com" pattern="[^\\s@]+@[^\\s@]+\\.[^\\s@]+" title="Please enter a valid email address (e.g., user@example.com)"> |
1733 | 1736 | </div> |
1734 | 1737 | </div> |
1735 | 1738 | <div class="ck-form-group"> |
|
1752 | 1755 | if (form) { |
1753 | 1756 | form.addEventListener('submit', (e) => { |
1754 | 1757 | e.preventDefault(); |
| 1758 | + |
| 1759 | + // Use native HTML5 form validation |
| 1760 | + if (!form.checkValidity()) { |
| 1761 | + form.reportValidity(); |
| 1762 | + return; |
| 1763 | + } |
| 1764 | + |
1755 | 1765 | const formData = new FormData(form); |
| 1766 | + const email = formData.get('email'); |
| 1767 | + |
1756 | 1768 | const commentData = { |
1757 | 1769 | content: formData.get('content'), |
1758 | 1770 | parent_id: null, // Top-level comments have no parent |
1759 | 1771 | }; |
1760 | 1772 | // Include guest fields only if not authenticated |
1761 | 1773 | if (!this.state.user) { |
1762 | 1774 | commentData.author_name = formData.get('name'); |
1763 | | - commentData.author_email = formData.get('email'); |
| 1775 | + commentData.author_email = email || undefined; |
1764 | 1776 | } |
1765 | 1777 | // Set scroll anchor to first visible comment |
1766 | 1778 | this.scrollAnchor = this.findFirstVisibleComment(); |
|
1868 | 1880 | if (loginForm) { |
1869 | 1881 | loginForm.addEventListener('submit', (e) => { |
1870 | 1882 | e.preventDefault(); |
| 1883 | + |
| 1884 | + // Use native HTML5 form validation |
| 1885 | + if (!loginForm.checkValidity()) { |
| 1886 | + loginForm.reportValidity(); |
| 1887 | + return; |
| 1888 | + } |
| 1889 | + |
1871 | 1890 | const formData = new FormData(loginForm); |
| 1891 | + const email = formData.get('email'); |
| 1892 | + |
1872 | 1893 | this.state.authLoading = true; |
1873 | 1894 | this.render(); |
1874 | 1895 | this.sendToIframe({ |
1875 | 1896 | action: 'login', |
1876 | | - email: formData.get('email'), |
| 1897 | + email: email, |
1877 | 1898 | redirectUrl: window.location.href, // Redirect back to this page after auth |
1878 | 1899 | }); |
1879 | 1900 | }); |
|
2034 | 2055 | if (form) { |
2035 | 2056 | form.addEventListener('submit', (e) => { |
2036 | 2057 | e.preventDefault(); |
| 2058 | + |
| 2059 | + // Use native HTML5 form validation |
| 2060 | + if (!form.checkValidity()) { |
| 2061 | + form.reportValidity(); |
| 2062 | + return; |
| 2063 | + } |
| 2064 | + |
2037 | 2065 | const formData = new FormData(form); |
| 2066 | + const email = formData.get('email'); |
| 2067 | + |
2038 | 2068 | const commentData = { |
2039 | 2069 | content: formData.get('content'), |
2040 | 2070 | parent_id: parentId, |
2041 | 2071 | }; |
2042 | 2072 | // Include guest fields only if not authenticated |
2043 | 2073 | if (!this.state.user) { |
2044 | 2074 | commentData.author_name = formData.get('name'); |
2045 | | - commentData.author_email = formData.get('email'); |
| 2075 | + commentData.author_email = email || undefined; |
2046 | 2076 | } |
2047 | 2077 | // Set scroll anchor to the parent comment being replied to |
2048 | 2078 | this.scrollAnchor = parentId; |
|
2284 | 2314 | if (loginForm) { |
2285 | 2315 | loginForm.addEventListener('submit', (e) => { |
2286 | 2316 | e.preventDefault(); |
| 2317 | + |
| 2318 | + // Use native HTML5 form validation |
| 2319 | + if (!loginForm.checkValidity()) { |
| 2320 | + loginForm.reportValidity(); |
| 2321 | + return; |
| 2322 | + } |
| 2323 | + |
2287 | 2324 | const formData = new FormData(loginForm); |
| 2325 | + const email = formData.get('email'); |
| 2326 | + |
2288 | 2327 | this.state.authLoading = true; |
2289 | 2328 | this.updateModalBody(); |
2290 | 2329 | this.sendToIframe({ |
2291 | 2330 | action: 'login', |
2292 | | - email: formData.get('email'), |
| 2331 | + email: email, |
2293 | 2332 | redirectUrl: window.location.href, |
2294 | 2333 | }); |
2295 | 2334 | }); |
|
2353 | 2392 | if (loginForm) { |
2354 | 2393 | loginForm.addEventListener('submit', (e) => { |
2355 | 2394 | e.preventDefault(); |
| 2395 | + |
| 2396 | + // Use native HTML5 form validation |
| 2397 | + if (!loginForm.checkValidity()) { |
| 2398 | + loginForm.reportValidity(); |
| 2399 | + return; |
| 2400 | + } |
| 2401 | + |
2356 | 2402 | const formData = new FormData(loginForm); |
| 2403 | + const email = formData.get('email'); |
| 2404 | + |
2357 | 2405 | this.state.authLoading = true; |
2358 | 2406 | this.updateModalBody(); |
2359 | 2407 | this.sendToIframe({ |
2360 | 2408 | action: 'login', |
2361 | | - email: formData.get('email'), |
| 2409 | + email: email, |
2362 | 2410 | redirectUrl: window.location.href, |
2363 | 2411 | }); |
2364 | 2412 | }); |
|
2379 | 2427 | <form id="ck-modal-login-form"> |
2380 | 2428 | <div class="ck-form-group"> |
2381 | 2429 | <label for="ck-modal-email">Email address</label> |
2382 | | - <input type="email" id="ck-modal-email" name="email" required placeholder="your@email.com" autocomplete="email"> |
| 2430 | + <input type="email" id="ck-modal-email" name="email" required placeholder="your@email.com" autocomplete="email" pattern="[^\\s@]+@[^\\s@]+\\.[^\\s@]+" title="Please enter a valid email address (e.g., user@example.com)"> |
2383 | 2431 | </div> |
2384 | 2432 | <p style="font-size: 0.875rem; color: #6b7280; margin: 0 0 28px 0; line-height: 1.6;"> |
2385 | 2433 | We'll send you a magic link to sign in. No password needed. |
|
0 commit comments