Skip to content

Instantly share code, notes, and snippets.

@thinca
Created May 7, 2023 10:27
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save thinca/ce4db5e7c7f7e5e1a18ad9f6e20740d0 to your computer and use it in GitHub Desktop.
Save thinca/ce4db5e7c7f7e5e1a18ad9f6e20740d0 to your computer and use it in GitHub Desktop.
GitHub から Webhooks を受け取り、MODal をデプロイする雑サーバ

使い方

  • compose.yml と同じディレクトリに置く
  • compose.yml のあるディレクトリで git clone https://github.com/thinca/MODal modal をして modal ディレクトリにリポジトリがあるようにしておく
  • GitHub Webhooks で設定した token を SECRET_TOKEN に設定する
  • sbt~/.local/bin/sbt にある前提になっている
  • LISTEN ポートは 20001 (適当)
  • その他、X-Forwarded-For ヘッダを表示するようにしていたり payload をデバッグ目的で全ダンプしていたりと全体的に雑
require 'webrick'
require 'openssl'
require 'json'
SECRET_TOKEN = 'XXX'
def secure_compare(a, b)
return false unless a.bytesize == b.bytesize
OpenSSL.fixed_length_secure_compare(a, b)
end
def verify_signature(payload_body, signature)
return false unless signature
calced_signature = "sha256=#{OpenSSL::HMAC.hexdigest(OpenSSL::Digest.new('sha256'), SECRET_TOKEN, payload_body)}"
secure_compare(calced_signature, signature).tap do |b|
puts "signature doesn't match: #{calced_signature} <=> #{signature}" unless b
end
end
def deploy(payload)
unless payload[:ref] == 'refs/heads/main'
puts "Does not a target ref. ignored: #{payload[:ref]}"
return
end
spawn('bash', '-c', <<-SHELL, chdir: __dir__)
set -eu
cd modal
git pull
rm -fr target/scala-*
git rev-parse --short @ > src/main/resources/commit_hash
~/.local/bin/sbt package
cp target/scala-*/modal_*.jar ../data/plugins
cd ..
docker compose exec minecraft rcon-cli plugman reload MODal
SHELL
end
srv = WEBrick::HTTPServer.new({
:BindAddress => '127.0.0.1',
:Port => 20001,
})
srv.mount_proc('/') { |req, res|
puts "X-Forwarded-For: #{req['X-Forwarded-For']}"
if req.request_method != 'POST'
res.status = 405
elsif !verify_signature(req.body, req['x-hub-signature-256'])
res.status = 403
else
payload = JSON.parse(req.body, symbolize_names: true)
pp payload
deploy(payload)
res.status = 200
end
res.content_type = 'text/plain'
res.body = res.reason_phrase
}
Signal.trap(:INT){ srv.shutdown }
srv.start
source 'https://rubygems.org'
gem 'webrick'
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment