# frozen_string_literal: true module Api module V1 module Webhooks module Concerns # Helpers para webhooks module WebhookConcern extend ActiveSupport::Concern included do # Responde con forbidden si falla la validación del token rescue_from ActiveRecord::RecordNotFound, with: :platforms_answer rescue_from ActiveRecord::RecordInvalid, with: :platforms_answer private # Valida el token que envía la plataforma en el webhook # # @return [String] def token @token ||= begin header = request.headers token = header['X-Social-Inbox'].presence token ||= header['X-Gitlab-Token'].presence token ||= token_from_signature(header['X-Gitea-Signature'].presence) token ||= token_from_signature(header['X-Hub-Signature-256'].presence, 'sha256=') token ensure raise ActiveRecord::RecordNotFound, 'Proveedor no soportado' if token.blank? end end # Valida token a partir de firma # # @param signature [String,nil] # @param prepend [String] # @return [String, nil] def token_from_signature(signature, prepend = '') return if signature.nil? payload = request.raw_post site.roles.where(temporal: false, rol: 'usuarie').pluck(:token).find do |token| new_signature = prepend + OpenSSL::HMAC.hexdigest(OpenSSL::Digest.new('sha256'), token, payload) ActiveSupport::SecurityUtils.secure_compare(new_signature, signature.to_s) end end # Encuentra el sitio a partir de la URL # # @return [Site] def site @site ||= Site.find_by_name!(params[:site_id]) end # Encuentra le usuarie # # @return [Site] def usuarie @usuarie ||= site.roles.find_by!(temporal: false, rol: 'usuarie', token: token).usuarie end # Respuesta de error a plataformas def platforms_answer(exception) ExceptionNotifier.notify_exception(exception, data: { headers: request.headers.to_h }) head :forbidden end end end end end end end