async webhook()

in nodes/YouTrack/YoutrackTrigger.node.ts [147:256]


	async webhook(this: IWebhookFunctions): Promise<IWebhookResponseData> {
		const req = this.getRequestObject();
		const selectedEvents = this.getNodeParameter('events', []) as string[];

		// Validate authentication if webhook credential is configured
		try {
			const webhookCredentials = await this.getCredentials('youTrackWebhookAuthApi');
			
			if (webhookCredentials) {
				const authMethod = webhookCredentials.authMethod as string;
				const expectedToken = webhookCredentials.authToken as string;
				
				let receivedToken: string | undefined;
				
				if (authMethod === 'headerAuth') {
					// Header-based authentication
					const headerName = webhookCredentials.headerName as string;
					receivedToken = req.headers[headerName.toLowerCase()] as string;
				} else if (authMethod === 'queryAuth') {
					// Query parameter authentication
					const queryParamName = webhookCredentials.queryParameterName as string;
					receivedToken = req.query?.[queryParamName] as string;
				}
				
				// Validate the token
				if (!receivedToken || receivedToken !== expectedToken) {
					return {
						webhookResponse: {
							message: 'Unauthorized: Invalid or missing authentication token',
							statusCode: 401,
						},
					};
				}
			}
		} catch (error) {
			return {
				webhookResponse: {
					message: `Error validating authentication: ${error}`,
					statusCode: 401,
				},
			};
		}

		// Parse the webhook payload safely
		let body: IDataObject = {};
		try {
			body = req.body as IDataObject || {};
		} catch (error) {
			return {
				webhookResponse: {
					error: `Invalid payload format. ${error}`,
					statusCode: 400,
				},
			};
		}
		
		// Determine the event type from the payload
		let detectedEvent = 'unknown';
		
		if (body && typeof body === 'object') {
			// Check for the explicit 'event' field from YouTrack app workflows
			if (body.event && typeof body.event === 'string') {
				const eventValue = body.event as string;
				// Validate against known events - automatically includes all events from YOUTRACK_EVENTS
				if (EVENT_VALUES.includes(eventValue)) {
					detectedEvent = eventValue;
				}
			}
		}

		// Check if this event matches our configured event filter
		const acceptsAllEvents = selectedEvents && selectedEvents.length > 0 && selectedEvents.includes('*');
		
		// If specific events are selected, verify the detected event is in the list
		if (!acceptsAllEvents) {
			// Ensure selectedEvents is an array and not empty
			if (!selectedEvents || selectedEvents.length === 0) {
				return {
					webhookResponse: {
						message: 'No events selected',
						statusCode: 200,
					},
				};
			}
			
			// Check if detected event is in the selected events
			if (!selectedEvents.includes(detectedEvent)) {
				return {
					webhookResponse: {
						message: `Event type '${detectedEvent}' does not match filter. Selected events: ${selectedEvents.join(', ')}`,
						statusCode: 200,
					},
				};
			}
		}

		return {
			workflowData: [
				[
					{
						json: body,
					},
				],
			],
			webhookResponse: {
				message: 'Webhook received successfully',
				statusCode: 200,
			},
		};
	}