11require 'sinatra'
22require 'octokit'
3+ require 'dotenv/load' # Manages environment variables
34require 'json'
4- require 'openssl' # Used to verify the webhook signature
5- require 'jwt' # Used to authenticate a GitHub App
6- require 'time' # Used to get ISO 8601 representation of a Time object
7- require 'logger'
5+ require 'openssl' # Verifies the webhook signature
6+ require 'jwt' # Authenticates a GitHub App
7+ require 'time' # Gets ISO 8601 representation of a Time object
8+ require 'logger' # Logs debug statements
89
910set :port , 3000
11+ set :bind , '0.0.0.0'
1012
1113
1214# This is template code to create a GitHub App server.
1315# You can read more about GitHub Apps here: # https://developer.github.com/apps/
1416#
1517# On its own, this app does absolutely nothing, except that it can be installed.
16- # It's up to you to add fun functionality!
18+ # It's up to you to add functionality!
1719# You can check out one example in advanced_server.rb.
1820#
1921# This code is a Sinatra app, for two reasons:
2022# 1. Because the app will require a landing page for installation.
2123# 2. To easily handle webhook events.
2224#
23- #
2425# Of course, not all apps need to receive and process events!
2526# Feel free to rip out the event handling code if you don't need it.
2627#
2930
3031class GHAapp < Sinatra ::Application
3132
32- # !!! DO NOT EVER USE HARD-CODED VALUES IN A REAL APP !!!
33- # Instead, set and read app tokens or other secrets in your code
34- # in a runtime source, like an environment variable like below
35-
36- # Expects that the private key has been set as an environment variable in
37- # PEM format using the following command to replace newlines with the
38- # literal `\n`:
39- # export GITHUB_PRIVATE_KEY=`awk '{printf "%s\\n", $0}' private-key.pem`
40- #
41- # Converts the newlines
33+ # Expects that the private key in PEM format. Converts the newlines
4234 PRIVATE_KEY = OpenSSL ::PKey ::RSA . new ( ENV [ 'GITHUB_PRIVATE_KEY' ] . gsub ( '\n' , "\n " ) )
4335
4436 # Your registered app must have a secret set. The secret is used to verify
@@ -59,7 +51,7 @@ class GHAapp < Sinatra::Application
5951 get_payload_request ( request )
6052 verify_webhook_signature
6153 authenticate_app
62- # Authenticate each installation of the app in order to run API operations
54+ # Authenticate the app installation in order to run API operations
6355 authenticate_installation ( @payload )
6456 end
6557
@@ -73,7 +65,7 @@ class GHAapp < Sinatra::Application
7365 end
7466 end
7567
76- 'ok' # You have to return _something_. ;)
68+ 200 # success status
7769 end
7870
7971
@@ -101,7 +93,7 @@ def get_payload_request(request)
10193 end
10294
10395 # Instantiate an Octokit client authenticated as a GitHub App.
104- # GitHub App authentication equires that we construct a
96+ # GitHub App authentication requires that you construct a
10597 # JWT (https://jwt.io/introduction/) signed with the app's private key,
10698 # so GitHub can be sure that it came from the app an not altererd by
10799 # a malicious third party.
@@ -117,15 +109,15 @@ def authenticate_app
117109 iss : APP_IDENTIFIER
118110 }
119111
120- # Cryptographically sign the JWT
112+ # Cryptographically sign the JWT.
121113 jwt = JWT . encode ( payload , PRIVATE_KEY , 'RS256' )
122114
123115 # Create the Octokit client, using the JWT as the auth token.
124116 @app_client ||= Octokit ::Client . new ( bearer_token : jwt )
125117 end
126118
127- # Instantiate an Octokit client authenticated as an installation of a
128- # GitHub App to run API operations.
119+ # Instantiate an Octokit client, authenticated as an installation of a
120+ # GitHub App, to run API operations.
129121 def authenticate_installation ( payload )
130122 installation_id = payload [ 'installation' ] [ 'id' ]
131123 installation_token = @app_client . create_app_installation_access_token ( installation_id ) [ :token ]
@@ -135,14 +127,14 @@ def authenticate_installation(payload)
135127 # Check X-Hub-Signature to confirm that this webhook was generated by
136128 # GitHub, and not a malicious third party.
137129 #
138- # GitHub will the WEBHOOK_SECRET, registered
139- # to the GitHub App, to create a hash signature sent in each webhook payload
140- # in the `X-HUB-Signature` header . This code computes the expected hash
141- # signature and compares it to the signature sent in the `X-HUB-Signature`
142- # header. If they don't match, this request is an attack, and we should
143- # reject it. GitHub uses the HMAC hexdigest to compute the signature. The
144- # `X-HUB-Signature` looks something like this: "sha1=123456"
145- # See https://developer.github.com/webhooks/securing/ for details
130+ # GitHub uses the WEBHOOK_SECRET, registered to the GitHub App, to
131+ # create the hash signature sent in the `X-HUB-Signature` header of each
132+ # webhook . This code computes the expected hash signature and compares it to
133+ # the signature sent in the `X-HUB-Signature` header. If they don't match,
134+ # this request is an attack, and you should reject it. GitHub uses the HMAC
135+ # hexdigest to compute the signature. The `X-HUB-Signature` looks something
136+ # like this: "sha1=123456".
137+ # See https://developer.github.com/webhooks/securing/ for details.
146138 def verify_webhook_signature
147139 their_signature_header = request . env [ 'HTTP_X_HUB_SIGNATURE' ] || 'sha1='
148140 method , their_digest = their_signature_header . split ( '=' )
@@ -157,9 +149,8 @@ def verify_webhook_signature
157149
158150 end
159151
160-
161152 # Finally some logic to let us run this server directly from the commandline, or with Rack
162- # Don't worry too much about this code ;) But, for the curious:
153+ # Don't worry too much about this code. But, for the curious:
163154 # $0 is the executed file
164155 # __FILE__ is the current file
165156 # If they are the same—that is, we are running this file directly, call the Sinatra run method
0 commit comments