From e63051cdef2552f9ba55f5adf1aeb4e095d08491 Mon Sep 17 00:00:00 2001 From: Rachael Sewell Date: Thu, 15 Nov 2018 12:44:47 -0600 Subject: [PATCH 01/19] Update to the latest template app --- .env-example | 3 ++ .gitignore | 3 ++ advanced_server.rb | 3 +- server.rb | 71 ++++++++++++++++++---------------------------- 4 files changed, 35 insertions(+), 45 deletions(-) create mode 100644 .env-example create mode 100644 .gitignore diff --git a/.env-example b/.env-example new file mode 100644 index 0000000..fbf6aeb --- /dev/null +++ b/.env-example @@ -0,0 +1,3 @@ +GITHUB_PRIVATE_KEY= +GITHUB_APP_IDENTIFIER= +GITHUB_WEBHOOK_SECRET= diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..7545483 --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +node_modules +package-lock.json +.env diff --git a/advanced_server.rb b/advanced_server.rb index d617d5a..4d4597a 100644 --- a/advanced_server.rb +++ b/advanced_server.rb @@ -73,8 +73,7 @@ class GHAapp < Sinatra::Application end end - 'ok' # we have to return _something_ ;) - + 'ok' # You have to return _something_. ;) end diff --git a/server.rb b/server.rb index 9fd6b7b..9f129ab 100644 --- a/server.rb +++ b/server.rb @@ -1,26 +1,28 @@ require 'sinatra' require 'octokit' +require 'dotenv/load' # Manages environment variables +require 'git' require 'json' -require 'openssl' # Used to verify the webhook signature -require 'jwt' # Used to authenticate a GitHub App -require 'time' # Used to get ISO 8601 representation of a Time object -require 'logger' +require 'openssl' # Verifies the webhook signature +require 'jwt' # Authenticates a GitHub App +require 'time' # Gets ISO 8601 representation of a Time object +require 'logger' # Logs debug statements set :port, 3000 +set :bind, '0.0.0.0' # This is template code to create a GitHub App server. # You can read more about GitHub Apps here: # https://developer.github.com/apps/ # # On its own, this app does absolutely nothing, except that it can be installed. -# It's up to you to add fun functionality! +# It's up to you to add functionality! # You can check out one example in advanced_server.rb. # # This code is a Sinatra app, for two reasons: # 1. Because the app will require a landing page for installation. # 2. To easily handle webhook events. # -# # Of course, not all apps need to receive and process events! # Feel free to rip out the event handling code if you don't need it. # @@ -29,16 +31,7 @@ class GHAapp < Sinatra::Application - # !!! DO NOT EVER USE HARD-CODED VALUES IN A REAL APP !!! - # Instead, set and read app tokens or other secrets in your code - # in a runtime source, like an environment variable like below - - # Expects that the private key has been set as an environment variable in - # PEM format using the following command to replace newlines with the - # literal `\n`: - # export GITHUB_PRIVATE_KEY=`awk '{printf "%s\\n", $0}' private-key.pem` - # - # Converts the newlines + # Expects that the private key in PEM format. Converts the newlines PRIVATE_KEY = OpenSSL::PKey::RSA.new(ENV['GITHUB_PRIVATE_KEY'].gsub('\n', "\n")) # Your registered app must have a secret set. The secret is used to verify @@ -59,26 +52,25 @@ class GHAapp < Sinatra::Application get_payload_request(request) verify_webhook_signature authenticate_app - # Authenticate each installation of the app in order to run API operations + # Authenticate the app installation in order to run API operations authenticate_installation(@payload) end post '/event_handler' do - # # # # # # # # # # # # # # # # # # # - # ADD YOUR CODE HERE # - # # # # # # # # # # # # # # # # # # # + # # # # # # # # # # # # + # ADD YOUR CODE HERE # + # # # # # # # # # # # # - 'ok' # We've got to return _something_. ;) end helpers do - # # # # # # # # # # # # # # # # # # # - # ADD YOUR HELPERS METHODS HERE # - # # # # # # # # # # # # # # # # # # # + # # # # # # # # # # # # # # # # # + # ADD YOUR HELPER METHODS HERE # + # # # # # # # # # # # # # # # # # # Saves the raw payload and converts the payload to JSON format def get_payload_request(request) @@ -95,7 +87,7 @@ def get_payload_request(request) end # Instantiate an Octokit client authenticated as a GitHub App. - # GitHub App authentication equires that we construct a + # GitHub App authentication requires that you construct a # JWT (https://jwt.io/introduction/) signed with the app's private key, # so GitHub can be sure that it came from the app an not altererd by # a malicious third party. @@ -111,15 +103,15 @@ def authenticate_app iss: APP_IDENTIFIER } - # Cryptographically sign the JWT + # Cryptographically sign the JWT. jwt = JWT.encode(payload, PRIVATE_KEY, 'RS256') # Create the Octokit client, using the JWT as the auth token. @app_client ||= Octokit::Client.new(bearer_token: jwt) end - # Instantiate an Octokit client authenticated as an installation of a - # GitHub App to run API operations. + # Instantiate an Octokit client, authenticated as an installation of a + # GitHub App, to run API operations. def authenticate_installation(payload) installation_id = payload['installation']['id'] installation_token = @app_client.create_app_installation_access_token(installation_id)[:token] @@ -129,14 +121,14 @@ def authenticate_installation(payload) # Check X-Hub-Signature to confirm that this webhook was generated by # GitHub, and not a malicious third party. # - # GitHub will the WEBHOOK_SECRET, registered - # to the GitHub App, to create a hash signature sent in each webhook payload - # in the `X-HUB-Signature` header. This code computes the expected hash - # signature and compares it to the signature sent in the `X-HUB-Signature` - # header. If they don't match, this request is an attack, and we should - # reject it. GitHub uses the HMAC hexdigest to compute the signature. The - # `X-HUB-Signature` looks something like this: "sha1=123456" - # See https://developer.github.com/webhooks/securing/ for details + # GitHub uses the WEBHOOK_SECRET, registered to the GitHub App, to + # create the hash signature sent in the `X-HUB-Signature` header of each + # webhook. This code computes the expected hash signature and compares it to + # the signature sent in the `X-HUB-Signature` header. If they don't match, + # this request is an attack, and you should reject it. GitHub uses the HMAC + # hexdigest to compute the signature. The `X-HUB-Signature` looks something + # like this: "sha1=123456". + # See https://developer.github.com/webhooks/securing/ for details. def verify_webhook_signature their_signature_header = request.env['HTTP_X_HUB_SIGNATURE'] || 'sha1=' method, their_digest = their_signature_header.split('=') @@ -150,12 +142,5 @@ def verify_webhook_signature end end - - - # Finally some logic to let us run this server directly from the commandline, or with Rack - # Don't worry too much about this code ;) But, for the curious: - # $0 is the executed file - # __FILE__ is the current file - # If they are the same—that is, we are running this file directly, call the Sinatra run method run! if __FILE__ == $0 end From c6cdf6c84b10f75e2073e1e779bf62011c069715 Mon Sep 17 00:00:00 2001 From: Rachael Sewell Date: Thu, 15 Nov 2018 12:49:02 -0600 Subject: [PATCH 02/19] Align with template code --- server.rb | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/server.rb b/server.rb index 9f129ab..712c1f5 100644 --- a/server.rb +++ b/server.rb @@ -1,7 +1,6 @@ require 'sinatra' require 'octokit' require 'dotenv/load' # Manages environment variables -require 'git' require 'json' require 'openssl' # Verifies the webhook signature require 'jwt' # Authenticates a GitHub App @@ -63,6 +62,7 @@ class GHAapp < Sinatra::Application # ADD YOUR CODE HERE # # # # # # # # # # # # # + 200 # success status end @@ -142,5 +142,11 @@ def verify_webhook_signature end end + + # Finally some logic to let us run this server directly from the commandline, or with Rack + # Don't worry too much about this code. But, for the curious: + # $0 is the executed file + # __FILE__ is the current file + # If they are the same—that is, we are running this file directly, call the Sinatra run method run! if __FILE__ == $0 end From 20716ee653f671ebcea1659d252b6c84fdc437f7 Mon Sep 17 00:00:00 2001 From: Rachael Sewell Date: Thu, 15 Nov 2018 12:50:29 -0600 Subject: [PATCH 03/19] normalize file names --- server.rb | 73 ++++++++++++++---------- advanced_server.rb => template_server.rb | 73 ++++++++++-------------- 2 files changed, 73 insertions(+), 73 deletions(-) rename advanced_server.rb => template_server.rb (66%) diff --git a/server.rb b/server.rb index 712c1f5..4d4597a 100644 --- a/server.rb +++ b/server.rb @@ -1,27 +1,26 @@ require 'sinatra' require 'octokit' -require 'dotenv/load' # Manages environment variables require 'json' -require 'openssl' # Verifies the webhook signature -require 'jwt' # Authenticates a GitHub App -require 'time' # Gets ISO 8601 representation of a Time object -require 'logger' # Logs debug statements +require 'openssl' # Used to verify the webhook signature +require 'jwt' # Used to authenticate a GitHub App +require 'time' # Used to get ISO 8601 representation of a Time object +require 'logger' set :port, 3000 -set :bind, '0.0.0.0' # This is template code to create a GitHub App server. # You can read more about GitHub Apps here: # https://developer.github.com/apps/ # # On its own, this app does absolutely nothing, except that it can be installed. -# It's up to you to add functionality! +# It's up to you to add fun functionality! # You can check out one example in advanced_server.rb. # # This code is a Sinatra app, for two reasons: # 1. Because the app will require a landing page for installation. # 2. To easily handle webhook events. # +# # Of course, not all apps need to receive and process events! # Feel free to rip out the event handling code if you don't need it. # @@ -30,7 +29,16 @@ class GHAapp < Sinatra::Application - # Expects that the private key in PEM format. Converts the newlines + # !!! DO NOT EVER USE HARD-CODED VALUES IN A REAL APP !!! + # Instead, set and read app tokens or other secrets in your code + # in a runtime source, like an environment variable like below + + # Expects that the private key has been set as an environment variable in + # PEM format using the following command to replace newlines with the + # literal `\n`: + # export GITHUB_PRIVATE_KEY=`awk '{printf "%s\\n", $0}' private-key.pem` + # + # Converts the newlines PRIVATE_KEY = OpenSSL::PKey::RSA.new(ENV['GITHUB_PRIVATE_KEY'].gsub('\n', "\n")) # Your registered app must have a secret set. The secret is used to verify @@ -51,26 +59,32 @@ class GHAapp < Sinatra::Application get_payload_request(request) verify_webhook_signature authenticate_app - # Authenticate the app installation in order to run API operations + # Authenticate each installation of the app in order to run API operations authenticate_installation(@payload) end post '/event_handler' do - # # # # # # # # # # # # - # ADD YOUR CODE HERE # - # # # # # # # # # # # # + case request.env['HTTP_X_GITHUB_EVENT'] + when 'issues' + if @payload['action'] === 'opened' + handle_issue_opened_event(@payload) + end + end - 200 # success status + 'ok' # You have to return _something_. ;) end helpers do - # # # # # # # # # # # # # # # # # - # ADD YOUR HELPER METHODS HERE # - # # # # # # # # # # # # # # # # # + # When an issue is opened, add a label + def handle_issue_opened_event(payload) + repo = payload['repository']['full_name'] + issue_number = payload['issue']['number'] + @installation_client.add_labels_to_an_issue(repo, issue_number, ['needs-response']) + end # Saves the raw payload and converts the payload to JSON format def get_payload_request(request) @@ -87,7 +101,7 @@ def get_payload_request(request) end # Instantiate an Octokit client authenticated as a GitHub App. - # GitHub App authentication requires that you construct a + # GitHub App authentication equires that we construct a # JWT (https://jwt.io/introduction/) signed with the app's private key, # so GitHub can be sure that it came from the app an not altererd by # a malicious third party. @@ -103,15 +117,15 @@ def authenticate_app iss: APP_IDENTIFIER } - # Cryptographically sign the JWT. + # Cryptographically sign the JWT jwt = JWT.encode(payload, PRIVATE_KEY, 'RS256') # Create the Octokit client, using the JWT as the auth token. @app_client ||= Octokit::Client.new(bearer_token: jwt) end - # Instantiate an Octokit client, authenticated as an installation of a - # GitHub App, to run API operations. + # Instantiate an Octokit client authenticated as an installation of a + # GitHub App to run API operations. def authenticate_installation(payload) installation_id = payload['installation']['id'] installation_token = @app_client.create_app_installation_access_token(installation_id)[:token] @@ -121,14 +135,14 @@ def authenticate_installation(payload) # Check X-Hub-Signature to confirm that this webhook was generated by # GitHub, and not a malicious third party. # - # GitHub uses the WEBHOOK_SECRET, registered to the GitHub App, to - # create the hash signature sent in the `X-HUB-Signature` header of each - # webhook. This code computes the expected hash signature and compares it to - # the signature sent in the `X-HUB-Signature` header. If they don't match, - # this request is an attack, and you should reject it. GitHub uses the HMAC - # hexdigest to compute the signature. The `X-HUB-Signature` looks something - # like this: "sha1=123456". - # See https://developer.github.com/webhooks/securing/ for details. + # GitHub will the WEBHOOK_SECRET, registered + # to the GitHub App, to create a hash signature sent in each webhook payload + # in the `X-HUB-Signature` header. This code computes the expected hash + # signature and compares it to the signature sent in the `X-HUB-Signature` + # header. If they don't match, this request is an attack, and we should + # reject it. GitHub uses the HMAC hexdigest to compute the signature. The + # `X-HUB-Signature` looks something like this: "sha1=123456" + # See https://developer.github.com/webhooks/securing/ for details def verify_webhook_signature their_signature_header = request.env['HTTP_X_HUB_SIGNATURE'] || 'sha1=' method, their_digest = their_signature_header.split('=') @@ -143,8 +157,9 @@ def verify_webhook_signature end + # Finally some logic to let us run this server directly from the commandline, or with Rack - # Don't worry too much about this code. But, for the curious: + # Don't worry too much about this code ;) But, for the curious: # $0 is the executed file # __FILE__ is the current file # If they are the same—that is, we are running this file directly, call the Sinatra run method diff --git a/advanced_server.rb b/template_server.rb similarity index 66% rename from advanced_server.rb rename to template_server.rb index 4d4597a..712c1f5 100644 --- a/advanced_server.rb +++ b/template_server.rb @@ -1,26 +1,27 @@ require 'sinatra' require 'octokit' +require 'dotenv/load' # Manages environment variables require 'json' -require 'openssl' # Used to verify the webhook signature -require 'jwt' # Used to authenticate a GitHub App -require 'time' # Used to get ISO 8601 representation of a Time object -require 'logger' +require 'openssl' # Verifies the webhook signature +require 'jwt' # Authenticates a GitHub App +require 'time' # Gets ISO 8601 representation of a Time object +require 'logger' # Logs debug statements set :port, 3000 +set :bind, '0.0.0.0' # This is template code to create a GitHub App server. # You can read more about GitHub Apps here: # https://developer.github.com/apps/ # # On its own, this app does absolutely nothing, except that it can be installed. -# It's up to you to add fun functionality! +# It's up to you to add functionality! # You can check out one example in advanced_server.rb. # # This code is a Sinatra app, for two reasons: # 1. Because the app will require a landing page for installation. # 2. To easily handle webhook events. # -# # Of course, not all apps need to receive and process events! # Feel free to rip out the event handling code if you don't need it. # @@ -29,16 +30,7 @@ class GHAapp < Sinatra::Application - # !!! DO NOT EVER USE HARD-CODED VALUES IN A REAL APP !!! - # Instead, set and read app tokens or other secrets in your code - # in a runtime source, like an environment variable like below - - # Expects that the private key has been set as an environment variable in - # PEM format using the following command to replace newlines with the - # literal `\n`: - # export GITHUB_PRIVATE_KEY=`awk '{printf "%s\\n", $0}' private-key.pem` - # - # Converts the newlines + # Expects that the private key in PEM format. Converts the newlines PRIVATE_KEY = OpenSSL::PKey::RSA.new(ENV['GITHUB_PRIVATE_KEY'].gsub('\n', "\n")) # Your registered app must have a secret set. The secret is used to verify @@ -59,32 +51,26 @@ class GHAapp < Sinatra::Application get_payload_request(request) verify_webhook_signature authenticate_app - # Authenticate each installation of the app in order to run API operations + # Authenticate the app installation in order to run API operations authenticate_installation(@payload) end post '/event_handler' do - case request.env['HTTP_X_GITHUB_EVENT'] - when 'issues' - if @payload['action'] === 'opened' - handle_issue_opened_event(@payload) - end - end + # # # # # # # # # # # # + # ADD YOUR CODE HERE # + # # # # # # # # # # # # - 'ok' # You have to return _something_. ;) + 200 # success status end helpers do - # When an issue is opened, add a label - def handle_issue_opened_event(payload) - repo = payload['repository']['full_name'] - issue_number = payload['issue']['number'] - @installation_client.add_labels_to_an_issue(repo, issue_number, ['needs-response']) - end + # # # # # # # # # # # # # # # # # + # ADD YOUR HELPER METHODS HERE # + # # # # # # # # # # # # # # # # # # Saves the raw payload and converts the payload to JSON format def get_payload_request(request) @@ -101,7 +87,7 @@ def get_payload_request(request) end # Instantiate an Octokit client authenticated as a GitHub App. - # GitHub App authentication equires that we construct a + # GitHub App authentication requires that you construct a # JWT (https://jwt.io/introduction/) signed with the app's private key, # so GitHub can be sure that it came from the app an not altererd by # a malicious third party. @@ -117,15 +103,15 @@ def authenticate_app iss: APP_IDENTIFIER } - # Cryptographically sign the JWT + # Cryptographically sign the JWT. jwt = JWT.encode(payload, PRIVATE_KEY, 'RS256') # Create the Octokit client, using the JWT as the auth token. @app_client ||= Octokit::Client.new(bearer_token: jwt) end - # Instantiate an Octokit client authenticated as an installation of a - # GitHub App to run API operations. + # Instantiate an Octokit client, authenticated as an installation of a + # GitHub App, to run API operations. def authenticate_installation(payload) installation_id = payload['installation']['id'] installation_token = @app_client.create_app_installation_access_token(installation_id)[:token] @@ -135,14 +121,14 @@ def authenticate_installation(payload) # Check X-Hub-Signature to confirm that this webhook was generated by # GitHub, and not a malicious third party. # - # GitHub will the WEBHOOK_SECRET, registered - # to the GitHub App, to create a hash signature sent in each webhook payload - # in the `X-HUB-Signature` header. This code computes the expected hash - # signature and compares it to the signature sent in the `X-HUB-Signature` - # header. If they don't match, this request is an attack, and we should - # reject it. GitHub uses the HMAC hexdigest to compute the signature. The - # `X-HUB-Signature` looks something like this: "sha1=123456" - # See https://developer.github.com/webhooks/securing/ for details + # GitHub uses the WEBHOOK_SECRET, registered to the GitHub App, to + # create the hash signature sent in the `X-HUB-Signature` header of each + # webhook. This code computes the expected hash signature and compares it to + # the signature sent in the `X-HUB-Signature` header. If they don't match, + # this request is an attack, and you should reject it. GitHub uses the HMAC + # hexdigest to compute the signature. The `X-HUB-Signature` looks something + # like this: "sha1=123456". + # See https://developer.github.com/webhooks/securing/ for details. def verify_webhook_signature their_signature_header = request.env['HTTP_X_HUB_SIGNATURE'] || 'sha1=' method, their_digest = their_signature_header.split('=') @@ -157,9 +143,8 @@ def verify_webhook_signature end - # Finally some logic to let us run this server directly from the commandline, or with Rack - # Don't worry too much about this code ;) But, for the curious: + # Don't worry too much about this code. But, for the curious: # $0 is the executed file # __FILE__ is the current file # If they are the same—that is, we are running this file directly, call the Sinatra run method From 177a288244d41d8a68afa31f77a91519aec2c93a Mon Sep 17 00:00:00 2001 From: Rachael Sewell Date: Thu, 15 Nov 2018 13:14:05 -0600 Subject: [PATCH 04/19] Remove package-lock.json from gitignore --- .gitignore | 1 - server.rb | 55 +++++++++++++++++++++++------------------------------- 2 files changed, 23 insertions(+), 33 deletions(-) diff --git a/.gitignore b/.gitignore index 7545483..37d7e73 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,2 @@ node_modules -package-lock.json .env diff --git a/server.rb b/server.rb index 4d4597a..0890dc6 100644 --- a/server.rb +++ b/server.rb @@ -1,26 +1,27 @@ require 'sinatra' require 'octokit' +require 'dotenv/load' # Manages environment variables require 'json' -require 'openssl' # Used to verify the webhook signature -require 'jwt' # Used to authenticate a GitHub App -require 'time' # Used to get ISO 8601 representation of a Time object -require 'logger' +require 'openssl' # Verifies the webhook signature +require 'jwt' # Authenticates a GitHub App +require 'time' # Gets ISO 8601 representation of a Time object +require 'logger' # Logs debug statements set :port, 3000 +set :bind, '0.0.0.0' # This is template code to create a GitHub App server. # You can read more about GitHub Apps here: # https://developer.github.com/apps/ # # On its own, this app does absolutely nothing, except that it can be installed. -# It's up to you to add fun functionality! +# It's up to you to add functionality! # You can check out one example in advanced_server.rb. # # This code is a Sinatra app, for two reasons: # 1. Because the app will require a landing page for installation. # 2. To easily handle webhook events. # -# # Of course, not all apps need to receive and process events! # Feel free to rip out the event handling code if you don't need it. # @@ -29,16 +30,7 @@ class GHAapp < Sinatra::Application - # !!! DO NOT EVER USE HARD-CODED VALUES IN A REAL APP !!! - # Instead, set and read app tokens or other secrets in your code - # in a runtime source, like an environment variable like below - - # Expects that the private key has been set as an environment variable in - # PEM format using the following command to replace newlines with the - # literal `\n`: - # export GITHUB_PRIVATE_KEY=`awk '{printf "%s\\n", $0}' private-key.pem` - # - # Converts the newlines + # Expects that the private key in PEM format. Converts the newlines PRIVATE_KEY = OpenSSL::PKey::RSA.new(ENV['GITHUB_PRIVATE_KEY'].gsub('\n', "\n")) # Your registered app must have a secret set. The secret is used to verify @@ -59,7 +51,7 @@ class GHAapp < Sinatra::Application get_payload_request(request) verify_webhook_signature authenticate_app - # Authenticate each installation of the app in order to run API operations + # Authenticate the app installation in order to run API operations authenticate_installation(@payload) end @@ -73,7 +65,7 @@ class GHAapp < Sinatra::Application end end - 'ok' # You have to return _something_. ;) + 200 # success status end @@ -101,7 +93,7 @@ def get_payload_request(request) end # Instantiate an Octokit client authenticated as a GitHub App. - # GitHub App authentication equires that we construct a + # GitHub App authentication requires that you construct a # JWT (https://jwt.io/introduction/) signed with the app's private key, # so GitHub can be sure that it came from the app an not altererd by # a malicious third party. @@ -117,15 +109,15 @@ def authenticate_app iss: APP_IDENTIFIER } - # Cryptographically sign the JWT + # Cryptographically sign the JWT. jwt = JWT.encode(payload, PRIVATE_KEY, 'RS256') # Create the Octokit client, using the JWT as the auth token. @app_client ||= Octokit::Client.new(bearer_token: jwt) end - # Instantiate an Octokit client authenticated as an installation of a - # GitHub App to run API operations. + # Instantiate an Octokit client, authenticated as an installation of a + # GitHub App, to run API operations. def authenticate_installation(payload) installation_id = payload['installation']['id'] installation_token = @app_client.create_app_installation_access_token(installation_id)[:token] @@ -135,14 +127,14 @@ def authenticate_installation(payload) # Check X-Hub-Signature to confirm that this webhook was generated by # GitHub, and not a malicious third party. # - # GitHub will the WEBHOOK_SECRET, registered - # to the GitHub App, to create a hash signature sent in each webhook payload - # in the `X-HUB-Signature` header. This code computes the expected hash - # signature and compares it to the signature sent in the `X-HUB-Signature` - # header. If they don't match, this request is an attack, and we should - # reject it. GitHub uses the HMAC hexdigest to compute the signature. The - # `X-HUB-Signature` looks something like this: "sha1=123456" - # See https://developer.github.com/webhooks/securing/ for details + # GitHub uses the WEBHOOK_SECRET, registered to the GitHub App, to + # create the hash signature sent in the `X-HUB-Signature` header of each + # webhook. This code computes the expected hash signature and compares it to + # the signature sent in the `X-HUB-Signature` header. If they don't match, + # this request is an attack, and you should reject it. GitHub uses the HMAC + # hexdigest to compute the signature. The `X-HUB-Signature` looks something + # like this: "sha1=123456". + # See https://developer.github.com/webhooks/securing/ for details. def verify_webhook_signature their_signature_header = request.env['HTTP_X_HUB_SIGNATURE'] || 'sha1=' method, their_digest = their_signature_header.split('=') @@ -157,9 +149,8 @@ def verify_webhook_signature end - # Finally some logic to let us run this server directly from the commandline, or with Rack - # Don't worry too much about this code ;) But, for the curious: + # Don't worry too much about this code. But, for the curious: # $0 is the executed file # __FILE__ is the current file # If they are the same—that is, we are running this file directly, call the Sinatra run method From c7ed6ea89607fbb46959801787aaa48a51d46b06 Mon Sep 17 00:00:00 2001 From: Rachael Sewell Date: Tue, 20 Nov 2018 12:30:11 -0600 Subject: [PATCH 05/19] Require dotenv --- Gemfile | 1 + Gemfile.lock | 20 +++++++++++--------- 2 files changed, 12 insertions(+), 9 deletions(-) diff --git a/Gemfile b/Gemfile index 0799a52..6b23a59 100644 --- a/Gemfile +++ b/Gemfile @@ -3,3 +3,4 @@ source 'http://rubygems.org' gem 'sinatra', '~> 2.0' gem 'jwt', '~> 2.1' gem 'octokit', '~> 4.0' +gem 'dotenv' diff --git a/Gemfile.lock b/Gemfile.lock index 5cbe9b9..6c57b34 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -3,24 +3,25 @@ GEM specs: addressable (2.5.2) public_suffix (>= 2.0.2, < 4.0) - faraday (0.15.2) + dotenv (2.5.0) + faraday (0.15.3) multipart-post (>= 1.2, < 3) jwt (2.1.0) multipart-post (2.0.0) - mustermann (1.0.2) - octokit (4.9.0) + mustermann (1.0.3) + octokit (4.13.0) sawyer (~> 0.8.0, >= 0.5.3) - public_suffix (3.0.2) - rack (2.0.5) - rack-protection (2.0.3) + public_suffix (3.0.3) + rack (2.0.6) + rack-protection (2.0.4) rack sawyer (0.8.1) addressable (>= 2.3.5, < 2.6) faraday (~> 0.8, < 1.0) - sinatra (2.0.3) + sinatra (2.0.4) mustermann (~> 1.0) rack (~> 2.0) - rack-protection (= 2.0.3) + rack-protection (= 2.0.4) tilt (~> 2.0) tilt (2.0.8) @@ -28,9 +29,10 @@ PLATFORMS ruby DEPENDENCIES + dotenv jwt (~> 2.1) octokit (~> 4.0) sinatra (~> 2.0) BUNDLED WITH - 1.14.6 + 1.17.1 From e642c60d6c942a717f9e8879b7dcf65792cc372d Mon Sep 17 00:00:00 2001 From: Rachael Sewell Date: Tue, 20 Nov 2018 15:50:48 -0600 Subject: [PATCH 06/19] Add globals --- server.rb | 6 +++--- template_server.rb | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/server.rb b/server.rb index 0890dc6..2fcb069 100644 --- a/server.rb +++ b/server.rb @@ -119,9 +119,9 @@ def authenticate_app # Instantiate an Octokit client, authenticated as an installation of a # GitHub App, to run API operations. def authenticate_installation(payload) - installation_id = payload['installation']['id'] - installation_token = @app_client.create_app_installation_access_token(installation_id)[:token] - @installation_client = Octokit::Client.new(bearer_token: installation_token) + @installation_id = payload['installation']['id'] + @installation_token = @app_client.create_app_installation_access_token(@installation_id)[:token] + @installation_client = Octokit::Client.new(bearer_token: @installation_token) end # Check X-Hub-Signature to confirm that this webhook was generated by diff --git a/template_server.rb b/template_server.rb index 712c1f5..5972df0 100644 --- a/template_server.rb +++ b/template_server.rb @@ -113,9 +113,9 @@ def authenticate_app # Instantiate an Octokit client, authenticated as an installation of a # GitHub App, to run API operations. def authenticate_installation(payload) - installation_id = payload['installation']['id'] - installation_token = @app_client.create_app_installation_access_token(installation_id)[:token] - @installation_client = Octokit::Client.new(bearer_token: installation_token) + @installation_id = payload['installation']['id'] + @installation_token = @app_client.create_app_installation_access_token(@installation_id)[:token] + @installation_client = Octokit::Client.new(bearer_token: @installation_token) end # Check X-Hub-Signature to confirm that this webhook was generated by From dc51a68d21d06011b504cfd49541f29fdb0558f2 Mon Sep 17 00:00:00 2001 From: Rachael Sewell Date: Tue, 27 Nov 2018 16:53:15 -0600 Subject: [PATCH 07/19] Use same base code as template-github-app --- server.rb | 34 +++++++++------------------------- template_server.rb | 9 +++++---- 2 files changed, 14 insertions(+), 29 deletions(-) diff --git a/server.rb b/server.rb index 2fcb069..7733687 100644 --- a/server.rb +++ b/server.rb @@ -10,30 +10,13 @@ set :port, 3000 set :bind, '0.0.0.0' - -# This is template code to create a GitHub App server. -# You can read more about GitHub Apps here: # https://developer.github.com/apps/ -# -# On its own, this app does absolutely nothing, except that it can be installed. -# It's up to you to add functionality! -# You can check out one example in advanced_server.rb. -# -# This code is a Sinatra app, for two reasons: -# 1. Because the app will require a landing page for installation. -# 2. To easily handle webhook events. -# -# Of course, not all apps need to receive and process events! -# Feel free to rip out the event handling code if you don't need it. -# -# Have fun! -# - class GHAapp < Sinatra::Application - # Expects that the private key in PEM format. Converts the newlines + # Converts the newlines. Expects that the private key has been set as an + # environment variable in PEM format. PRIVATE_KEY = OpenSSL::PKey::RSA.new(ENV['GITHUB_PRIVATE_KEY'].gsub('\n', "\n")) - # Your registered app must have a secret set. The secret is used to verify + # Your registered app must set have a secret set. The secret is used to verify # that webhooks are sent by GitHub. WEBHOOK_SECRET = ENV['GITHUB_WEBHOOK_SECRET'] @@ -46,10 +29,10 @@ class GHAapp < Sinatra::Application end - # Before each request to the `/event_handler` route + # Executed before each request to the `/event_handler` route before '/event_handler' do get_payload_request(request) - verify_webhook_signature + verify_webhook_signature! authenticate_app # Authenticate the app installation in order to run API operations authenticate_installation(@payload) @@ -149,10 +132,11 @@ def verify_webhook_signature end - # Finally some logic to let us run this server directly from the commandline, or with Rack - # Don't worry too much about this code. But, for the curious: + # Finally some logic to let us run this server directly from the command line, + # or with Rack. Don't worry too much about this code. But, for the curious: # $0 is the executed file # __FILE__ is the current file - # If they are the same—that is, we are running this file directly, call the Sinatra run method + # If they are the same—that is, we are running this file directly, call the + # Sinatra run method run! if __FILE__ == $0 end diff --git a/template_server.rb b/template_server.rb index 5972df0..deb8e20 100644 --- a/template_server.rb +++ b/template_server.rb @@ -49,7 +49,7 @@ class GHAapp < Sinatra::Application # Before each request to the `/event_handler` route before '/event_handler' do get_payload_request(request) - verify_webhook_signature + verify_webhook_signature! authenticate_app # Authenticate the app installation in order to run API operations authenticate_installation(@payload) @@ -143,10 +143,11 @@ def verify_webhook_signature end - # Finally some logic to let us run this server directly from the commandline, or with Rack - # Don't worry too much about this code. But, for the curious: + # Finally some logic to let us run this server directly from the command line, + # or with Rack. Don't worry too much about this code. But, for the curious: # $0 is the executed file # __FILE__ is the current file - # If they are the same—that is, we are running this file directly, call the Sinatra run method + # If they are the same—that is, we are running this file directly, call the + # Sinatra run method run! if __FILE__ == $0 end From ef1fe1678c8b423ddc24940e6f83c840ee428381 Mon Sep 17 00:00:00 2001 From: Rachael Sewell Date: Tue, 27 Nov 2018 17:02:39 -0600 Subject: [PATCH 08/19] Remove exclamation from method signature --- server.rb | 4 ++-- template_server.rb | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/server.rb b/server.rb index 7733687..27b976a 100644 --- a/server.rb +++ b/server.rb @@ -16,7 +16,7 @@ class GHAapp < Sinatra::Application # environment variable in PEM format. PRIVATE_KEY = OpenSSL::PKey::RSA.new(ENV['GITHUB_PRIVATE_KEY'].gsub('\n', "\n")) - # Your registered app must set have a secret set. The secret is used to verify + # Your registered app must have a secret set. The secret is used to verify # that webhooks are sent by GitHub. WEBHOOK_SECRET = ENV['GITHUB_WEBHOOK_SECRET'] @@ -32,7 +32,7 @@ class GHAapp < Sinatra::Application # Executed before each request to the `/event_handler` route before '/event_handler' do get_payload_request(request) - verify_webhook_signature! + verify_webhook_signature authenticate_app # Authenticate the app installation in order to run API operations authenticate_installation(@payload) diff --git a/template_server.rb b/template_server.rb index deb8e20..518be21 100644 --- a/template_server.rb +++ b/template_server.rb @@ -49,7 +49,7 @@ class GHAapp < Sinatra::Application # Before each request to the `/event_handler` route before '/event_handler' do get_payload_request(request) - verify_webhook_signature! + verify_webhook_signature authenticate_app # Authenticate the app installation in order to run API operations authenticate_installation(@payload) From 4c1ed484708ae521fded9910f5072f0bd0e8880e Mon Sep 17 00:00:00 2001 From: Rachael Sewell Date: Tue, 27 Nov 2018 20:35:15 -0600 Subject: [PATCH 09/19] Add quotes --- .env-example | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.env-example b/.env-example index fbf6aeb..0ea477b 100644 --- a/.env-example +++ b/.env-example @@ -1,3 +1,3 @@ -GITHUB_PRIVATE_KEY= +GITHUB_PRIVATE_KEY="" GITHUB_APP_IDENTIFIER= GITHUB_WEBHOOK_SECRET= From dec7f119aa65d752c9e49e3952da8f14349e5fd0 Mon Sep 17 00:00:00 2001 From: Rachael Sewell Date: Wed, 28 Nov 2018 17:47:19 -0600 Subject: [PATCH 10/19] Update with new Quickstart information --- README.md | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 2a8f4f9..ddc9341 100644 --- a/README.md +++ b/README.md @@ -1,13 +1,21 @@ -This is the sample project built by following the "[Building Your First GitHub App](https://developer.github.com/apps/building-your-first-github-app)" Quickstart guide on developer.github.com. +This is an example GitHub App that adds a label to all new issues opened in a repository. You can follow the "[Building your first GitHub App](https://developer.github.com/apps/quickstart-guide/building-your-first-github-app)" Quickstart guide on developer.github.com to learn how to build the app code in `server.rb`. -It consists of two different servers: `server.rb` (boilerplate) and `advanced_server.rb` (completed project). +This project listens for webhook events and uses the Octokit.rb library to make REST API calls. This example project consists of two different servers: +* `template_server.rb` (GitHub App template code) +* `server.rb` (completed project) -## Install and run +To learn how to set up a template GitHub App, follow the "[Configuring a GitHub App](https://developer.github.com/apps/quickstart-guide/configuring-ast-github-app)" Quickstart guide on developer.github.com. + +## Install To run the code, make sure you have [Bundler](http://gembundler.com/) installed; then enter `bundle install` on the command line. -* For the boilerplate project, enter `ruby server.rb` on the command line. +## Set environment variables + +1. Create a copy of the `.env-example` file called `.env`. +2. Add your GitHub App's private key, app ID, and webhook secret to the `.env` file. -* For the completed project, enter `ruby advanced_server.rb` on the command line. +## Run the server -Both commands will run the server at `localhost:3000`. +1. Run `ruby template_server.rb` or `ruby server.rb` on the command line. +1. View the default Sinatra app at `localhost:3000`. From bd735229933e87182d366cfdfe419251fbec273d Mon Sep 17 00:00:00 2001 From: Rachael Sewell Date: Mon, 10 Dec 2018 10:37:12 -0600 Subject: [PATCH 11/19] Correct spelling --- template_server.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/template_server.rb b/template_server.rb index 518be21..5a945d0 100644 --- a/template_server.rb +++ b/template_server.rb @@ -137,7 +137,7 @@ def verify_webhook_signature # The X-GITHUB-EVENT header provides the name of the event. # The action value indicates the which action triggered the event. - logger.debug "---- recevied event #{request.env['HTTP_X_GITHUB_EVENT']}" + logger.debug "---- received event #{request.env['HTTP_X_GITHUB_EVENT']}" logger.debug "---- action #{@payload['action']}" unless @payload['action'].nil? end From 4ac138c318d014c7cfc661d1d506e772cb509699 Mon Sep 17 00:00:00 2001 From: Rachael Sewell Date: Mon, 10 Dec 2018 10:37:32 -0600 Subject: [PATCH 12/19] Correct spelling --- server.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server.rb b/server.rb index 27b976a..f75b66d 100644 --- a/server.rb +++ b/server.rb @@ -126,7 +126,7 @@ def verify_webhook_signature # The X-GITHUB-EVENT header provides the name of the event. # The action value indicates the which action triggered the event. - logger.debug "---- recevied event #{request.env['HTTP_X_GITHUB_EVENT']}" + logger.debug "---- received event #{request.env['HTTP_X_GITHUB_EVENT']}" logger.debug "---- action #{@payload['action']}" unless @payload['action'].nil? end From b076931c65778817685eb9e200721451e3937803 Mon Sep 17 00:00:00 2001 From: Rachael Sewell Date: Mon, 17 Dec 2018 15:18:02 -0600 Subject: [PATCH 13/19] Update to latest guide name --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index ddc9341..7da0ac7 100644 --- a/README.md +++ b/README.md @@ -1,10 +1,10 @@ -This is an example GitHub App that adds a label to all new issues opened in a repository. You can follow the "[Building your first GitHub App](https://developer.github.com/apps/quickstart-guide/building-your-first-github-app)" Quickstart guide on developer.github.com to learn how to build the app code in `server.rb`. +This is an example GitHub App that adds a label to all new issues opened in a repository. You can follow the "[Using the GitHub API in your app](https://developer.github.com/apps/quickstart-guide/using-the-github-api-in-your-app)" quickstart guide on developer.github.com to learn how to build the app code in `server.rb`. This project listens for webhook events and uses the Octokit.rb library to make REST API calls. This example project consists of two different servers: * `template_server.rb` (GitHub App template code) * `server.rb` (completed project) -To learn how to set up a template GitHub App, follow the "[Configuring a GitHub App](https://developer.github.com/apps/quickstart-guide/configuring-ast-github-app)" Quickstart guide on developer.github.com. +To learn how to set up a template GitHub App, follow the "[Setting up your development environment](https://developer.github.com/apps/quickstart-guide/setting-up-your-development-environment)" quickstart guide on developer.github.com. ## Install From 7cad7d91ba1b1f8658b56911d449c195c4c4f440 Mon Sep 17 00:00:00 2001 From: Rachael Sewell Date: Mon, 17 Dec 2018 15:34:27 -0600 Subject: [PATCH 14/19] Update README.md --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 7da0ac7..81f494b 100644 --- a/README.md +++ b/README.md @@ -1,10 +1,10 @@ -This is an example GitHub App that adds a label to all new issues opened in a repository. You can follow the "[Using the GitHub API in your app](https://developer.github.com/apps/quickstart-guide/using-the-github-api-in-your-app)" quickstart guide on developer.github.com to learn how to build the app code in `server.rb`. +This is an example GitHub App that adds a label to all new issues opened in a repository. You can follow the "[Using the GitHub API in your app](https://developer.github.com/apps/quickstart-guides/using-the-github-api-in-your-app/)" quickstart guide on developer.github.com to learn how to build the app code in `server.rb`. This project listens for webhook events and uses the Octokit.rb library to make REST API calls. This example project consists of two different servers: * `template_server.rb` (GitHub App template code) * `server.rb` (completed project) -To learn how to set up a template GitHub App, follow the "[Setting up your development environment](https://developer.github.com/apps/quickstart-guide/setting-up-your-development-environment)" quickstart guide on developer.github.com. +To learn how to set up a template GitHub App, follow the "[Setting up your development environment](https://developer.github.com/apps/quickstart-guides/setting-up-your-development-environment/)" quickstart guide on developer.github.com. ## Install From 870e1990bb896fc8a8fbf530cea64913657c0549 Mon Sep 17 00:00:00 2001 From: Nicholas Bishop Date: Sun, 14 Jul 2019 15:26:42 -0400 Subject: [PATCH 15/19] Fix typos --- server.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server.rb b/server.rb index f75b66d..8a40db4 100644 --- a/server.rb +++ b/server.rb @@ -78,7 +78,7 @@ def get_payload_request(request) # Instantiate an Octokit client authenticated as a GitHub App. # GitHub App authentication requires that you construct a # JWT (https://jwt.io/introduction/) signed with the app's private key, - # so GitHub can be sure that it came from the app an not altererd by + # so GitHub can be sure that it came from the app and was not altered by # a malicious third party. def authenticate_app payload = { From 9417f957cb3976cbdf4df32c389b125c239abc97 Mon Sep 17 00:00:00 2001 From: David Porcel Date: Mon, 12 Aug 2019 11:02:38 +0200 Subject: [PATCH 16/19] Fix typos --- template_server.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/template_server.rb b/template_server.rb index 5a945d0..f913aa1 100644 --- a/template_server.rb +++ b/template_server.rb @@ -89,7 +89,7 @@ def get_payload_request(request) # Instantiate an Octokit client authenticated as a GitHub App. # GitHub App authentication requires that you construct a # JWT (https://jwt.io/introduction/) signed with the app's private key, - # so GitHub can be sure that it came from the app an not altererd by + # so GitHub can be sure that it came from the app and wasn't alterered by # a malicious third party. def authenticate_app payload = { From fbcd89666d0356d11d9eb7b607e1d0170fecad44 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 19 Dec 2019 08:25:23 +0000 Subject: [PATCH 17/19] Bump rack from 2.0.6 to 2.0.8 Bumps [rack](https://github.com/rack/rack) from 2.0.6 to 2.0.8. - [Release notes](https://github.com/rack/rack/releases) - [Changelog](https://github.com/rack/rack/blob/master/CHANGELOG.md) - [Commits](https://github.com/rack/rack/compare/2.0.6...2.0.8) Signed-off-by: dependabot[bot] --- Gemfile.lock | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Gemfile.lock b/Gemfile.lock index 6c57b34..95b9036 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -12,7 +12,7 @@ GEM octokit (4.13.0) sawyer (~> 0.8.0, >= 0.5.3) public_suffix (3.0.3) - rack (2.0.6) + rack (2.0.8) rack-protection (2.0.4) rack sawyer (0.8.1) From dbead8f7944228729dab7f4a83434d57c238a9a1 Mon Sep 17 00:00:00 2001 From: Francis <15894826+francisfuzz@users.noreply.github.com> Date: Fri, 12 Jun 2020 17:21:17 -0700 Subject: [PATCH 18/19] docs: update link to Bundler --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 81f494b..ec206ba 100644 --- a/README.md +++ b/README.md @@ -8,7 +8,7 @@ To learn how to set up a template GitHub App, follow the "[Setting up your devel ## Install -To run the code, make sure you have [Bundler](http://gembundler.com/) installed; then enter `bundle install` on the command line. +To run the code, make sure you have [Bundler](https://bundler.io/) installed; then enter `bundle install` on the command line. ## Set environment variables From c6150dbc0951e71ba556e09dd026bd59f1ef3025 Mon Sep 17 00:00:00 2001 From: Sarah Edwards Date: Wed, 7 Jun 2023 15:15:14 -0700 Subject: [PATCH 19/19] Prepare repo for archive --- README.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index ec206ba..6905dce 100644 --- a/README.md +++ b/README.md @@ -1,10 +1,12 @@ -This is an example GitHub App that adds a label to all new issues opened in a repository. You can follow the "[Using the GitHub API in your app](https://developer.github.com/apps/quickstart-guides/using-the-github-api-in-your-app/)" quickstart guide on developer.github.com to learn how to build the app code in `server.rb`. +⚠️ Note: This repository is not maintained. For more recent guides about how to build GitHub Apps, see "[About writing code for a GitHub App](https://docs.github.com/en/apps/creating-github-apps/writing-code-for-a-github-app/about-writing-code-for-a-github-app)." + +This is an example GitHub App that adds a label to all new issues opened in a repository. You can follow the archived "[Using the GitHub API in your app](https://web.archive.org/web/20230604175646/https://docs.github.com/en/apps/creating-github-apps/writing-code-for-a-github-app/using-the-github-api-in-your-app)" guide to learn how to build the app code in `server.rb`. This project listens for webhook events and uses the Octokit.rb library to make REST API calls. This example project consists of two different servers: * `template_server.rb` (GitHub App template code) * `server.rb` (completed project) -To learn how to set up a template GitHub App, follow the "[Setting up your development environment](https://developer.github.com/apps/quickstart-guides/setting-up-your-development-environment/)" quickstart guide on developer.github.com. +To learn how to set up a template GitHub App, follow the archived "[Setting up your development environment](https://web.archive.org/web/20230604175646/https://docs.github.com/en/apps/creating-github-apps/writing-code-for-a-github-app/setting-up-your-development-environment-to-create-a-github-app)" guide. ## Install