lib/site_hook/webhook.rb in site_hook-0.8.0 vs lib/site_hook/webhook.rb in site_hook-0.8.1

- old
+ new

@@ -4,42 +4,34 @@ # -> Author: Ken Spencer <me@iotaspencer.me> # -> Last Modified: 1/10/2018 21:35:44 # -> Copyright (c) 2018 Ken Spencer # -> License: MIT ########## - +require 'site_hook/persist' +require 'site_hook/const' require 'sinatra' module SiteHook class Webhook < Sinatra::Base - HOOKLOG = SiteHook::HookLogger::HookLog.new(SiteHook::Logs.log_levels['hook']).log - BUILDLOG = SiteHook::HookLogger::BuildLog.new(SiteHook::Logs.log_levels['build']).log - APPLOG = SiteHook::HookLogger::AppLog.new(SiteHook::Logs.log_levels['app']).log - JPHRC = YAML.load_file(Pathname(Dir.home).join('.jph', 'config')) - def self.set_bind(host, port, config) - self.set port: port - self.set bind: host - if config == '_config.yml' - SiteHook.set_options(:BUILD_CONFIG, '_config.yml') - else - SiteHook.set_options(:BUILD_CONFIG, config) - end - end set server: %w[thin] set quiet: true set raise_errors: true set views: Pathname(SiteHook::Paths.lib_dir).join('site_hook', 'views') - set :public_folder, Pathname(SiteHook::Paths.lib_dir).join('site_hook', 'static') - use SassHandler + set :public_folder, Pathname(SiteHook::Paths.lib_dir).join('site_hook', 'assets') use CoffeeHandler + def self.set_options(host, port) + self.set bind: host.to_s + self.set port: port.to_i + end -# + # # @param [String] body JSON String of body # @param [String] sig Signature or token from git service # @param [String] secret User-defined verification token # @param [Boolean] plaintext Whether the verification is plaintext + # @param [String] service service name def self.verified?(body, sig, secret, plaintext:, service:) if plaintext sig == secret else case service @@ -51,61 +43,64 @@ when 'github' if sig == OpenSSL::HMAC.hexdigest(OpenSSL::Digest::SHA1.new, secret, body) APPLOG.debug "Secret verified: #{sig} === #{OpenSSL::HMAC.hexdigest(OpenSSL::Digest::SHA1.new, secret, body)}" true end + else + # This shouldn't happen end end end + CONTENT_TYPE = 'Content-Type' get '/' do - halt 403, { 'Content-Type' => 'text/html' }, '<h1>See <a href="/webhooks/">here</a> for the active webhooks</h1>' + halt 403, {CONTENT_TYPE => 'text/html'}, '<h1>See <a href="/webhooks/">here</a> for the active webhooks</h1>' end + APPLICATION_JSON = 'application/json' get '/webhooks.json', provides: :json do - content_type 'application/json' + content_type APPLICATION_JSON public_projects = JPHRC['projects'].select do |_project, hsh| - (hsh.fetch('private', nil) == false) || hsh.fetch('private', nil).nil? + !hsh.fetch('private') end - result = {} + result = {} public_projects.each do |project, hsh| result[project] = {} hsh.delete('hookpass') result[project].merge!(hsh) end - headers 'Content-Type' => 'application/json', 'Accept' => 'application/json' + headers CONTENT_TYPE => APPLICATION_JSON, 'Accept' => APPLICATION_JSON json result, layout: false end get '/webhooks/?' do - haml :webhooks, locals: { 'projects' => JPHRC['projects'] } + haml :webhooks, locals: {'projects' => JPHRC['projects']} end get '/webhook/*' do if params[:splat] pass else - halt 405, { 'Content-Type' => 'application/json' }, { message: 'GET not allowed' }.to_json + halt 405, {CONTENT_TYPE => APPLICATION_JSON}, {message: 'GET not allowed'}.to_json end end post '/webhook/:hook_name/?' do service = nil request.body.rewind req_body = request.body.read - js = RecursiveOpenStruct.new(JSON.parse(req_body)) + js = RecursiveOpenStruct.new(JSON.parse(req_body)) projects = JPHRC['projects'] - begin - project = projects.fetch(params[:hook_name]) - rescue KeyError => e - halt 404, { 'Content-Type' => 'application/json' }, { message: 'no such project', status: 1 }.to_json + project = projects.fetch(params[:hook_name], nil) + if project.nil? + halt 404, {CONTENT_TYPE => APPLICATION_JSON}, {message: 'no such project', status: 1}.to_json end plaintext = false signature = nil - event = nil - gogs = request.env.fetch('HTTP_X_GOGS_EVENT', nil) + event = nil + gogs = request.env.fetch('HTTP_X_GOGS_EVENT', nil) unless gogs.nil? event = 'push' if gogs == 'push' end github = request.env.fetch('HTTP_X_GITHUB_EVENT', nil) unless github.nil? @@ -114,31 +109,29 @@ gitlab = request.env.fetch('HTTP_X_GITLAB_EVENT', nil) unless gitlab.nil? event = 'push' if gitlab == 'push' end - events = { 'github' => github, 'gitlab' => gitlab, 'gogs' => gogs } + events = {'github' => github, 'gitlab' => gitlab, 'gogs' => gogs} if events['github'] && events['gogs'] events['github'] = nil end events_m_e = events.values.one? case events_m_e when true - event = 'push' + event = 'push' service = events.select { |_key, value| value }.keys.first when false - halt 400, { 'Content-Type': 'application/json' }, { message: 'events are mutually exclusive', status: 'failure' }.to_json + halt 400, {CONTENT_TYPE: APPLICATION_JSON}, {message: 'events are mutually exclusive', status: 'failure'}.to_json else halt 400, - { 'Content-Type': 'application/json' }, + {CONTENT_TYPE: APPLICATION_JSON}, 'status': 'failure', 'message': 'something weird happened' end - if event != 'push' - if event.nil? - halt 400, { 'Content-Type': 'application/json' }, { message: 'no event header' }.to_json - end + if event != 'push' && event.nil? + halt 400, {CONTENT_TYPE: APPLICATION_JSON}, {message: 'no event header'}.to_json end case service when 'gitlab' signature = request.env.fetch('HTTP_X_GITLAB_TOKEN', '') plaintext = true @@ -147,36 +140,38 @@ plaintext = false when 'gogs' signature = request.env.fetch('HTTP_X_GOGS_SIGNATURE', '') plaintext = false + else + # This shouldn't happen end if Webhook.verified?(req_body.to_s, signature, project['hookpass'], plaintext: plaintext, service: service) BUILDLOG.info 'Building...' begin - jekyllbuild = SiteHook::Senders::Jekyll.build(project['src'], project['dst'], BUILDLOG, options: {config: SiteHook::BUILD_CONFIG}) - jekyll_status = jekyllbuild + jekyll_status = SiteHook::Senders::Jekyll.build(project['src'], project['dst'], BUILDLOG, options: {config: project['config']}) case jekyll_status when 0 status 200 - headers 'Content-Type' => 'application/json' - body { { 'status': 'success' }.to_json } + headers CONTENT_TYPE => APPLICATION_JSON + body { {'status': 'success'}.to_json } when -1, -2, -3 - halt 400, { 'Content-Type' => 'application/json' }, { 'status': 'exception', error: jekyll_status.fetch(:message).to_s } - + halt 400, {CONTENT_TYPE => APPLICATION_JSON}, {'status': 'exception', error: jekyll_status.fetch(:message).to_s} + else + # This shouldn't happen end rescue => e - halt 500, { 'Content-Type' => 'application/json' }, { 'status': 'exception', error: e.to_s} + halt 500, {CONTENT_TYPE => APPLICATION_JSON}, {'status': 'exception', error: e.to_s} end else - halt 403, { 'Content-Type' => 'application/json' }, { message: 'incorrect secret', 'status': 'failure' }.to_json + halt 403, {CONTENT_TYPE => APPLICATION_JSON}, {message: 'incorrect secret', 'status': 'failure'}.to_json end end post '/webhook/?' do - halt 403, { 'Content-Type' => 'application/json' }, { message: 'pick a hook', error: 'root webhook hit', 'status': 'failure' }.to_json + halt 403, {CONTENT_TYPE => APPLICATION_JSON}, {message: 'pick a hook', error: 'root webhook hit', 'status': 'failure'}.to_json end end end