mirror of
https://0xacab.org/sutty/sutty
synced 2024-11-15 18:41:42 +00:00
Merge branch 'issue-13903' into 'rails'
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
Webhooks Controller | Webhooks Closes #13903 and #14089 See merge request sutty/sutty!198
This commit is contained in:
commit
22b9bc5efd
9 changed files with 126 additions and 3 deletions
77
app/controllers/api/v1/webhooks_controller.rb
Normal file
77
app/controllers/api/v1/webhooks_controller.rb
Normal file
|
@ -0,0 +1,77 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
module Api
|
||||||
|
module V1
|
||||||
|
# Recibe webhooks y lanza un PullJob
|
||||||
|
class WebhooksController < BaseController
|
||||||
|
# responde con forbidden si falla la validación del token
|
||||||
|
rescue_from ActiveRecord::RecordNotFound, with: :platforms_answer
|
||||||
|
|
||||||
|
# Trae los cambios a partir de un post de Webhooks:
|
||||||
|
# (Gitlab, Github, Gitea, etc)
|
||||||
|
#
|
||||||
|
# @return [nil]
|
||||||
|
def pull
|
||||||
|
message = I18n.with_locale(site.default_locale) do
|
||||||
|
I18n.t('webhooks.pull.message')
|
||||||
|
end
|
||||||
|
|
||||||
|
GitPullJob.perform_later(site, usuarie, message)
|
||||||
|
head :ok
|
||||||
|
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
|
13
app/jobs/git_pull_job.rb
Normal file
13
app/jobs/git_pull_job.rb
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
# Permite traer los cambios desde webhooks
|
||||||
|
|
||||||
|
class GitPullJob < ApplicationJob
|
||||||
|
# @param :site [Site]
|
||||||
|
# @param :usuarie [Usuarie]
|
||||||
|
# @param :message [String]
|
||||||
|
# @return [nil]
|
||||||
|
def perform(site, usuarie, message)
|
||||||
|
site.repository.merge(usuarie, message) if site.repository.fetch&.positive?
|
||||||
|
end
|
||||||
|
end
|
|
@ -14,6 +14,8 @@ class Rol < ApplicationRecord
|
||||||
|
|
||||||
validates_inclusion_of :rol, in: ROLES
|
validates_inclusion_of :rol, in: ROLES
|
||||||
|
|
||||||
|
before_save :add_token_if_missing!
|
||||||
|
|
||||||
def invitade?
|
def invitade?
|
||||||
rol == INVITADE
|
rol == INVITADE
|
||||||
end
|
end
|
||||||
|
@ -25,4 +27,11 @@ class Rol < ApplicationRecord
|
||||||
def self.role?(rol)
|
def self.role?(rol)
|
||||||
ROLES.include? rol
|
ROLES.include? rol
|
||||||
end
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
# Asegurarse que tenga un token
|
||||||
|
def add_token_if_missing!
|
||||||
|
self.token ||= SecureRandom.hex(64)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -54,7 +54,7 @@ class Site
|
||||||
# Incorpora los cambios en el repositorio actual
|
# Incorpora los cambios en el repositorio actual
|
||||||
#
|
#
|
||||||
# @return [Rugged::Commit]
|
# @return [Rugged::Commit]
|
||||||
def merge(usuarie)
|
def merge(usuarie, message = I18n.t('sites.fetch.merge.message'))
|
||||||
merge = rugged.merge_commits(head_commit, remote_head_commit)
|
merge = rugged.merge_commits(head_commit, remote_head_commit)
|
||||||
|
|
||||||
# No hacemos nada si hay conflictos, pero notificarnos
|
# No hacemos nada si hay conflictos, pero notificarnos
|
||||||
|
@ -69,12 +69,16 @@ class Site
|
||||||
.create(rugged, update_ref: 'HEAD',
|
.create(rugged, update_ref: 'HEAD',
|
||||||
parents: [head_commit, remote_head_commit],
|
parents: [head_commit, remote_head_commit],
|
||||||
tree: merge.write_tree(rugged),
|
tree: merge.write_tree(rugged),
|
||||||
message: I18n.t('sites.fetch.merge.message'),
|
message: message,
|
||||||
author: author(usuarie), committer: committer)
|
author: author(usuarie), committer: committer)
|
||||||
|
|
||||||
# Forzamos el checkout para mover el HEAD al último commit y
|
# Forzamos el checkout para mover el HEAD al último commit y
|
||||||
# escribir los cambios
|
# escribir los cambios
|
||||||
rugged.checkout 'HEAD', strategy: :force
|
rugged.checkout 'HEAD', strategy: :force
|
||||||
|
|
||||||
|
git_sh("git", "lfs", "fetch", "origin", default_branch)
|
||||||
|
# reemplaza los pointers por los archivos correspondientes
|
||||||
|
git_sh("git", "lfs", "checkout")
|
||||||
commit
|
commit
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -142,7 +142,7 @@ Rails.application.configure do
|
||||||
}
|
}
|
||||||
config.action_mailer.default_options = { from: ENV.fetch('DEFAULT_FROM', "noreply@sutty.nl") }
|
config.action_mailer.default_options = { from: ENV.fetch('DEFAULT_FROM', "noreply@sutty.nl") }
|
||||||
|
|
||||||
config.middleware.use ExceptionNotification::Rack, gitlab: {}, ignore_exceptions: (['DeployJob::DeployAlreadyRunningException'] + ExceptionNotifier.ignored_exceptions)
|
config.middleware.use ExceptionNotification::Rack, gitlab: {}, ignore_exceptions: ['DeployJob::DeployAlreadyRunningException']
|
||||||
|
|
||||||
Rails.application.routes.default_url_options[:host] = "panel.#{ENV.fetch('SUTTY', 'sutty.nl')}"
|
Rails.application.routes.default_url_options[:host] = "panel.#{ENV.fetch('SUTTY', 'sutty.nl')}"
|
||||||
Rails.application.routes.default_url_options[:protocol] = 'https'
|
Rails.application.routes.default_url_options[:protocol] = 'https'
|
||||||
|
|
|
@ -485,6 +485,9 @@ en:
|
||||||
success: 'Site upgrade has been completed. Your next build will run this upgrade :)'
|
success: 'Site upgrade has been completed. Your next build will run this upgrade :)'
|
||||||
error: "There was an error when trying to upgrade your site. This could be due to conflicts that couldn't be solved automatically. A report of the issue has already been sent to our admins. Sorry for the inconvenience! :("
|
error: "There was an error when trying to upgrade your site. This could be due to conflicts that couldn't be solved automatically. A report of the issue has already been sent to our admins. Sorry for the inconvenience! :("
|
||||||
message: 'Skeleton upgrade'
|
message: 'Skeleton upgrade'
|
||||||
|
webhooks:
|
||||||
|
pull:
|
||||||
|
message: 'Webhooks pull'
|
||||||
footer:
|
footer:
|
||||||
powered_by: 'is developed by'
|
powered_by: 'is developed by'
|
||||||
i18n:
|
i18n:
|
||||||
|
|
|
@ -493,6 +493,9 @@ es:
|
||||||
success: 'Ya se incorporaron los cambios en el sitio, se aplicarán en la próxima compilación que hagas :)'
|
success: 'Ya se incorporaron los cambios en el sitio, se aplicarán en la próxima compilación que hagas :)'
|
||||||
error: 'Hubo un error al incorporar los cambios en el sitio. Esto puede deberse a conflictos entre cambios que no se pueden resolver automáticamente. Hemos enviado un reporte del problema a les administradores de Sutty para que estén al tanto de la situación. ¡Lo sentimos! :('
|
error: 'Hubo un error al incorporar los cambios en el sitio. Esto puede deberse a conflictos entre cambios que no se pueden resolver automáticamente. Hemos enviado un reporte del problema a les administradores de Sutty para que estén al tanto de la situación. ¡Lo sentimos! :('
|
||||||
message: 'Actualización del esqueleto'
|
message: 'Actualización del esqueleto'
|
||||||
|
webhooks:
|
||||||
|
pull:
|
||||||
|
message: 'Traer los cambios a partir de un evento remoto'
|
||||||
footer:
|
footer:
|
||||||
powered_by: 'es desarrollada por'
|
powered_by: 'es desarrollada por'
|
||||||
i18n:
|
i18n:
|
||||||
|
|
|
@ -17,6 +17,8 @@ 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'
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
12
db/migrate/20230731195050_add_token_to_roles.rb
Normal file
12
db/migrate/20230731195050_add_token_to_roles.rb
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
class AddTokenToRoles < ActiveRecord::Migration[6.1]
|
||||||
|
def up
|
||||||
|
add_column :roles, :token, :string
|
||||||
|
Rol.find_each do |m|
|
||||||
|
m.update_column( :token, SecureRandom.hex(64) )
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def down
|
||||||
|
remove_column :roles, :token
|
||||||
|
end
|
||||||
|
end
|
Loading…
Reference in a new issue