fix(server): Zoho token endpoint hardening + version bump to 0.5.4 (batch 0.6.0)
This commit is contained in:
parent
c4d40c39ba
commit
25ab4c7986
|
|
@ -1,7 +1,7 @@
|
||||||
{
|
{
|
||||||
"name": "queuenorth-website",
|
"name": "queuenorth-website",
|
||||||
"private": true,
|
"private": true,
|
||||||
"version": "0.5.3",
|
"version": "0.5.4",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "concurrently \"vite\" \"node server/index.js\"",
|
"dev": "concurrently \"vite\" \"node server/index.js\"",
|
||||||
|
|
|
||||||
|
|
@ -216,6 +216,9 @@ const ZOHO_REDIRECT_URI = process.env.ZOHO_REDIRECT_URI || ''
|
||||||
let zohoAccessToken = null
|
let zohoAccessToken = null
|
||||||
let zohoTokenExpiry = 0
|
let zohoTokenExpiry = 0
|
||||||
|
|
||||||
|
// 10 second timeout for all Zoho API calls
|
||||||
|
const ZOHO_TIMEOUT_MS = 10000
|
||||||
|
|
||||||
async function getZohoAccessToken() {
|
async function getZohoAccessToken() {
|
||||||
// Return cached token if still valid (with 60s buffer)
|
// Return cached token if still valid (with 60s buffer)
|
||||||
if (zohoAccessToken && Date.now() < zohoTokenExpiry - 60000) {
|
if (zohoAccessToken && Date.now() < zohoTokenExpiry - 60000) {
|
||||||
|
|
@ -232,7 +235,36 @@ async function getZohoAccessToken() {
|
||||||
redirect_uri: ZOHO_REDIRECT_URI,
|
redirect_uri: ZOHO_REDIRECT_URI,
|
||||||
})
|
})
|
||||||
|
|
||||||
const response = await fetch(`${url}?${params.toString()}`, { method: 'POST' })
|
const controller = new AbortController()
|
||||||
|
const timeoutId = setTimeout(() => controller.abort(), ZOHO_TIMEOUT_MS)
|
||||||
|
|
||||||
|
let response
|
||||||
|
try {
|
||||||
|
response = await fetch(url, {
|
||||||
|
method: 'POST',
|
||||||
|
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
|
||||||
|
body: params.toString(),
|
||||||
|
signal: controller.signal,
|
||||||
|
})
|
||||||
|
} catch (err) {
|
||||||
|
if (err.name === 'AbortError') {
|
||||||
|
log.warn('[Zoho] Token fetch timed out after', ZOHO_TIMEOUT_MS, 'ms')
|
||||||
|
} else {
|
||||||
|
log.error('[Zoho] Token fetch error:', err.message)
|
||||||
|
}
|
||||||
|
clearTimeout(timeoutId)
|
||||||
|
return null
|
||||||
|
} finally {
|
||||||
|
clearTimeout(timeoutId)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Issue #3: Check response.ok before parsing JSON
|
||||||
|
if (!response.ok) {
|
||||||
|
const text = await response.text()
|
||||||
|
log.error(`[Zoho] Token fetch failed (${response.status}):`, text)
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
const data = await response.json()
|
const data = await response.json()
|
||||||
|
|
||||||
if (data.access_token) {
|
if (data.access_token) {
|
||||||
|
|
@ -266,7 +298,8 @@ async function forwardToZoho(leadData) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
const url = `${ZOHO_API_DOMAIN}/crm/v8/Leads`
|
// Issue #8: Prevent double-slash in URL path
|
||||||
|
const url = `${ZOHO_API_DOMAIN.replace(/\/$/, '')}/crm/v8/Leads`
|
||||||
const payload = {
|
const payload = {
|
||||||
data: [
|
data: [
|
||||||
{
|
{
|
||||||
|
|
@ -281,9 +314,8 @@ async function forwardToZoho(leadData) {
|
||||||
],
|
],
|
||||||
}
|
}
|
||||||
|
|
||||||
// Issue #5: Add timeout using AbortController
|
|
||||||
const controller = new AbortController()
|
const controller = new AbortController()
|
||||||
const timeoutId = setTimeout(() => controller.abort(), 10000) // 10 second timeout
|
const timeoutId = setTimeout(() => controller.abort(), ZOHO_TIMEOUT_MS)
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const response = await fetch(url, {
|
const response = await fetch(url, {
|
||||||
|
|
@ -307,7 +339,7 @@ async function forwardToZoho(leadData) {
|
||||||
log.info('[Zoho] Lead forwarded successfully:', result.data?.[0]?.details?.id || 'no id returned')
|
log.info('[Zoho] Lead forwarded successfully:', result.data?.[0]?.details?.id || 'no id returned')
|
||||||
} catch (fetchErr) {
|
} catch (fetchErr) {
|
||||||
if (fetchErr.name === 'AbortError') {
|
if (fetchErr.name === 'AbortError') {
|
||||||
log.warn('[Zoho] Lead forwarding timed out after 10 seconds')
|
log.warn('[Zoho] Lead forwarding timed out after', ZOHO_TIMEOUT_MS, 'ms')
|
||||||
} else {
|
} else {
|
||||||
log.error('[Zoho] Forwarding error:', fetchErr.message)
|
log.error('[Zoho] Forwarding error:', fetchErr.message)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue