2024-02-20 20:13:42 +00:00
|
|
|
# frozen_string_literal: true
|
|
|
|
|
|
|
|
module Api
|
|
|
|
module V1
|
|
|
|
module Webhooks
|
|
|
|
module Concerns
|
|
|
|
# Helpers para webhooks
|
|
|
|
module WebhookConcern
|
|
|
|
extend ActiveSupport::Concern
|
|
|
|
|
|
|
|
included do
|
2024-02-21 19:42:02 +00:00
|
|
|
skip_before_action :verify_authenticity_token
|
|
|
|
|
2024-02-20 20:13:42 +00:00
|
|
|
# Responde con forbidden si falla la validación del token
|
|
|
|
rescue_from ActiveRecord::RecordNotFound, with: :platforms_answer
|
2024-02-21 18:43:10 +00:00
|
|
|
rescue_from ActiveRecord::RecordInvalid, with: :platforms_answer
|
2024-02-20 20:13:42 +00:00
|
|
|
|
|
|
|
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
|