MCPcopy Index your code
hub / github.com/simstudioai/sim / handleChallenge

Function handleChallenge

apps/sim/lib/webhooks/providers/zoom.ts:165–222  ·  view source on GitHub ↗

* Handle Zoom endpoint URL validation challenges. * Zoom sends an `endpoint.url_validation` event with a `plainToken` that must * be hashed with the app's secret token and returned alongside the original token.

(
    body: unknown,
    request: NextRequest,
    requestId: string,
    path: string,
    rawBody?: string
  )

Source from the content-addressed store, hash-verified

163 * be hashed with the app's secret token and returned alongside the original token.
164 */
165 async handleChallenge(
166 body: unknown,
167 request: NextRequest,
168 requestId: string,
169 path: string,
170 rawBody?: string
171 ) {
172 const obj = body as Record<string, unknown> | null
173 if (obj?.event !== 'endpoint.url_validation') {
174 return null
175 }
176
177 const payload = obj.payload as Record<string, unknown> | undefined
178 const plainToken = payload?.plainToken as string | undefined
179 if (!plainToken) {
180 return null
181 }
182
183 logger.info(`[${requestId}] Zoom URL validation request received for path: ${path}`)
184
185 const signature = request.headers.get('x-zm-signature')
186 const timestamp = request.headers.get('x-zm-request-timestamp')
187 if (!signature || !timestamp) {
188 logger.warn(`[${requestId}] Zoom challenge request missing signature headers — rejecting`)
189 return null
190 }
191
192 const bodyForSignature =
193 rawBody !== undefined && rawBody !== null ? rawBody : JSON.stringify(body)
194
195 let rows: Array<{ secretToken: string }> = []
196 try {
197 rows = await resolveZoomChallengeSecrets(path, requestId)
198 } catch (err) {
199 logger.warn(`[${requestId}] Failed to look up webhook secret for Zoom validation`, err)
200 return null
201 }
202
203 for (const row of rows) {
204 const secretToken = row.secretToken
205 if (
206 secretToken &&
207 validateZoomSignature(secretToken, signature, timestamp, bodyForSignature)
208 ) {
209 const hashForValidate = hmacSha256Hex(plainToken, secretToken)
210
211 return NextResponse.json({
212 plainToken,
213 encryptedToken: hashForValidate,
214 })
215 }
216 }
217
218 logger.warn(
219 `[${requestId}] Zoom challenge: no matching secret for path ${path} (${rows.length} webhook row(s))`
220 )
221 return null
222 },

Callers

nothing calls this directly

Calls 6

hmacSha256HexFunction · 0.90
validateZoomSignatureFunction · 0.85
infoMethod · 0.80
getMethod · 0.65
warnMethod · 0.65

Tested by

no test coverage detected