Skip to content

Commit a1ec1f4

Browse files
committed
fix(CORS): resolve contact form CORS, CSP warnings, and SVG path errors
- Add CORS support to Google Apps Script backend with proper headers - Remove invalid CSP meta tags from HTML (should be server-side) - Create _headers file for proper security header deployment - Fix malformed SVG path in CareerPage.tsx (missing arc flag spaces) - Improve API error handling with better user-friendly messages - Add 'cors' mode to fetch requests for better cross-origin support Fixes contact form submission failures and eliminates console warnings.
1 parent 5663968 commit a1ec1f4

File tree

5 files changed

+41
-14
lines changed

5 files changed

+41
-14
lines changed

backend/thinkREDBot.js

Lines changed: 19 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,11 @@ const EMAIL_CC_CONTACT_FORM = SCRIPT_PROPS.getProperty('EMAIL_CC_CONTACT_FORM');
1010
const EMAIL_CC_JOB_APPLY = SCRIPT_PROPS.getProperty('EMAIL_CC_JOB_APPLY');
1111

1212
// === ENTRY POINT ===
13+
function doGet(e) {
14+
// Handle preflight OPTIONS requests
15+
return createCorsResponse({ success: true, message: 'CORS preflight OK' });
16+
}
17+
1318
function doPost(e) {
1419
try {
1520
const payload = JSON.parse(e.postData.contents);
@@ -85,8 +90,7 @@ https://docs.google.com/spreadsheets/d/${CONTACT_FORM_SHEET_ID}
8590
htmlBody: htmlBody
8691
});
8792

88-
return ContentService.createTextOutput(JSON.stringify({ success: true }))
89-
.setMimeType(ContentService.MimeType.JSON);
93+
return createCorsResponse({ success: true });
9094
}
9195

9296
// === JOB APPLICATION HANDLER ===
@@ -166,8 +170,7 @@ https://docs.google.com/spreadsheets/d/${JOB_APPLICATION_SHEET_ID}
166170
htmlBody: htmlBody
167171
});
168172

169-
return ContentService.createTextOutput(JSON.stringify({ success: true }))
170-
.setMimeType(ContentService.MimeType.JSON);
173+
return createCorsResponse({ success: true });
171174
}
172175

173176
// === UTILITY FUNCTIONS ===
@@ -177,6 +180,16 @@ function getOrCreateSubFolder(parent, name) {
177180
}
178181

179182
function createErrorResponse(message) {
180-
return ContentService.createTextOutput(JSON.stringify({ success: false, error: message }))
181-
.setMimeType(ContentService.MimeType.JSON);
183+
return createCorsResponse({ success: false, error: message });
184+
}
185+
186+
function createCorsResponse(data) {
187+
return ContentService.createTextOutput(JSON.stringify(data))
188+
.setMimeType(ContentService.MimeType.JSON)
189+
.setHeaders({
190+
'Access-Control-Allow-Origin': '*',
191+
'Access-Control-Allow-Methods': 'GET, POST, OPTIONS',
192+
'Access-Control-Allow-Headers': 'Content-Type, Authorization',
193+
'Access-Control-Max-Age': '3600'
194+
});
182195
}

frontend/index.html

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -13,13 +13,7 @@
1313
<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent" />
1414
<meta name="msapplication-TileColor" content="#E4093E" />
1515

16-
<!-- Security Headers -->
17-
<meta http-equiv="Content-Security-Policy" content="default-src 'self'; script-src 'self' 'unsafe-inline'; style-src 'self' 'unsafe-inline' https://fonts.googleapis.com; font-src 'self' https://fonts.gstatic.com; img-src 'self' data: https:; connect-src 'self' https://api.thinkred.tech https://script.google.com; object-src 'none'; media-src 'self'; child-src 'none'; frame-src 'none'; worker-src 'self'; manifest-src 'self'; frame-ancestors 'none'; base-uri 'self'; form-action 'self'; upgrade-insecure-requests; block-all-mixed-content;" />
18-
<meta http-equiv="X-Content-Type-Options" content="nosniff" />
19-
<meta http-equiv="X-Frame-Options" content="DENY" />
20-
<meta http-equiv="X-XSS-Protection" content="1; mode=block" />
21-
<meta http-equiv="Referrer-Policy" content="strict-origin-when-cross-origin" />
22-
<meta http-equiv="Permissions-Policy" content="geolocation=(), microphone=(), camera=(), fullscreen=(self), payment=()" />
16+
<!-- Note: Security headers should be set by the web server, not in HTML meta tags -->
2317

2418
<!-- SEO Meta Tags -->
2519
<title>ThinkRED Technologies | Simplify Technology & Experience</title>

frontend/public/_headers

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
# Netlify/Vercel Headers Configuration
2+
/*
3+
Content-Security-Policy: default-src 'self'; script-src 'self' 'unsafe-inline'; style-src 'self' 'unsafe-inline' https://fonts.googleapis.com; font-src 'self' https://fonts.gstatic.com; img-src 'self' data: https:; connect-src 'self' https://api.thinkred.tech https://script.google.com; object-src 'none'; media-src 'self'; child-src 'none'; frame-src 'none'; worker-src 'self'; manifest-src 'self'; frame-ancestors 'none'; base-uri 'self'; form-action 'self'
4+
X-Content-Type-Options: nosniff
5+
X-Frame-Options: DENY
6+
X-XSS-Protection: 1; mode=block
7+
Referrer-Policy: strict-origin-when-cross-origin
8+
Permissions-Policy: geolocation=(), microphone=(), camera=(), fullscreen=(self), payment=()

frontend/src/pages/CareerPage.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -517,7 +517,7 @@ const CareerPage = () => {
517517
strokeLinecap="round"
518518
strokeLinejoin="round"
519519
strokeWidth={2}
520-
d="M17.657 18.657A8 8 0 016.343 7.343S7 9 9 10c0-2 .5-5 2.986-7C14 5 16.09 5.777 17.656 7.343A7.975 7.975 0 0720 13a7.975 7.975 0 01-2.343 5.657z"
520+
d="M17.657 18.657A8 8 0 0 1 6.343 7.343S7 9 9 10c0-2 .5-5 2.986-7C14 5 16.09 5.777 17.656 7.343A7.975 7.975 0 0 1 20 13a7.975 7.975 0 0 1-2.343 5.657z"
521521
/>
522522
</svg>
523523
</div>

frontend/src/utils/api.ts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ export const submitContactForm = async (
4646
headers: {
4747
'Content-Type': 'application/json',
4848
},
49+
mode: 'cors',
4950
body: JSON.stringify({
5051
action: 'submitContactForm',
5152
data: formData,
@@ -67,6 +68,17 @@ export const submitContactForm = async (
6768
// eslint-disable-next-line no-console
6869
console.error('Error submitting contact form:', error);
6970
}
71+
72+
// Provide a more user-friendly error message
73+
if (
74+
error instanceof TypeError &&
75+
error.message.includes('Failed to fetch')
76+
) {
77+
throw new Error(
78+
'Unable to submit form. Please check your internet connection or try again later.'
79+
);
80+
}
81+
7082
throw error;
7183
}
7284
};

0 commit comments

Comments
 (0)