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