mirror of
https://0xacab.org/sutty/sutty
synced 2024-11-20 04:16:22 +00:00
feat: poder reutilizar webhooks
This commit is contained in:
parent
6d0ea6fa5d
commit
b792cb2d43
3 changed files with 75 additions and 56 deletions
71
app/controllers/api/v1/concerns/webhook_concern.rb
Normal file
71
app/controllers/api/v1/concerns/webhook_concern.rb
Normal file
|
@ -0,0 +1,71 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
module Api
|
||||||
|
module V1
|
||||||
|
# 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
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
# Valida el token que envía la plataforma en el webhook
|
||||||
|
#
|
||||||
|
# @return [String]
|
||||||
|
def token
|
||||||
|
@token ||=
|
||||||
|
begin
|
||||||
|
_headers = request.headers
|
||||||
|
_token ||= _headers['X-Gitlab-Token'].presence
|
||||||
|
_token ||= token_from_signature(_headers['X-Gitea-Signature'].presence)
|
||||||
|
_token ||= token_from_signature(_headers['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
|
|
@ -4,8 +4,7 @@ module Api
|
||||||
module V1
|
module V1
|
||||||
# Recibe webhooks y lanza un PullJob
|
# Recibe webhooks y lanza un PullJob
|
||||||
class WebhooksController < BaseController
|
class WebhooksController < BaseController
|
||||||
# responde con forbidden si falla la validación del token
|
include WebhookConcern
|
||||||
rescue_from ActiveRecord::RecordNotFound, with: :platforms_answer
|
|
||||||
|
|
||||||
# Trae los cambios a partir de un post de Webhooks:
|
# Trae los cambios a partir de un post de Webhooks:
|
||||||
# (Gitlab, Github, Gitea, etc)
|
# (Gitlab, Github, Gitea, etc)
|
||||||
|
@ -19,59 +18,6 @@ module Api
|
||||||
GitPullJob.perform_later(site, usuarie, message)
|
GitPullJob.perform_later(site, usuarie, message)
|
||||||
head :ok
|
head :ok
|
||||||
end
|
end
|
||||||
|
|
||||||
private
|
|
||||||
|
|
||||||
# encuentra el sitio a partir de la url
|
|
||||||
def site
|
|
||||||
@site ||= Site.find_by_name!(params[:site_id])
|
|
||||||
end
|
|
||||||
|
|
||||||
# valida el token que envía la plataforma del webhook
|
|
||||||
#
|
|
||||||
# @return [String]
|
|
||||||
def token
|
|
||||||
@token ||=
|
|
||||||
begin
|
|
||||||
# Gitlab
|
|
||||||
if request.headers['X-Gitlab-Token'].present?
|
|
||||||
request.headers['X-Gitlab-Token']
|
|
||||||
# Github
|
|
||||||
elsif request.headers['X-Hub-Signature-256'].present?
|
|
||||||
token_from_signature(request.headers['X-Hub-Signature-256'], 'sha256=')
|
|
||||||
# Gitea
|
|
||||||
elsif request.headers['X-Gitea-Signature'].present?
|
|
||||||
token_from_signature(request.headers['X-Gitea-Signature'])
|
|
||||||
else
|
|
||||||
raise ActiveRecord::RecordNotFound, 'proveedor no soportado'
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
# valida token a partir de firma de webhook
|
|
||||||
#
|
|
||||||
# @return [String, Boolean]
|
|
||||||
def token_from_signature(signature, prepend = '')
|
|
||||||
payload = request.body.read
|
|
||||||
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.tap do |t|
|
|
||||||
raise ActiveRecord::RecordNotFound, 'token no encontrado' if t.nil?
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
# encuentra le usuarie
|
|
||||||
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
|
||||||
|
|
|
@ -18,7 +18,9 @@ Rails.application.routes.draw do
|
||||||
get :'contact/cookie', to: 'invitades#contact_cookie'
|
get :'contact/cookie', to: 'invitades#contact_cookie'
|
||||||
post :'contact/:form', to: 'contact#receive', as: :contact
|
post :'contact/:form', to: 'contact#receive', as: :contact
|
||||||
|
|
||||||
post :'webhooks/pull', to: 'webhooks#pull'
|
namespace :webhooks do
|
||||||
|
post :pull, to: 'webhooks#pull'
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
Loading…
Reference in a new issue