qbo_api 1.8.2 → 1.8.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/Gemfile +0 -1
- data/README.md +46 -15
- data/bin/console +1 -0
- data/example/base.rb +54 -0
- data/example/oauth.rb +62 -0
- data/example/oauth2.rb +69 -0
- data/example/views/index.erb +0 -1
- data/lib/qbo_api/version.rb +1 -1
- data/qbo_api.gemspec +0 -5
- metadata +5 -73
- data/example/app.rb +0 -118
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 1a14e9e5e66c903adfe8068876926ab4a7cb1a6a
|
4
|
+
data.tar.gz: 81dea94865459c92b103ae0b6804b85f2287e23c
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 5c7a3e681f058684ccec7da9db94da92ce20f010f6762b91eb7e87cf10b83a320897a8fcd84f882d841544ec17b08ab3e90711c3674ef0662669861e3108ed58
|
7
|
+
data.tar.gz: 5ffdd016f2ef8f8d83b9b700d76a835cdb86fd39a85621976fc0fef99a69c9dff30b5c4b0a40bbf2624a5fd163bfe71753aebc2058ca03f55a6f76b90e8615f2
|
data/Gemfile
CHANGED
data/README.md
CHANGED
@@ -353,16 +353,22 @@ See [docs](https://developer.intuit.com/docs/0100_quickbooks_online/0100_essenti
|
|
353
353
|
- If needed create an account at [https://developer.intuit.com](https://developer.intuit.com)
|
354
354
|
- Click `Get started coding`
|
355
355
|
- Create an app with both the `Accounting` & `Payments` selected.
|
356
|
-
- Go to the `Development` tab
|
357
|
-
|
358
|
-
|
359
|
-
|
360
|
-
-
|
356
|
+
- Go to the [`Development` tab](https://developer.intuit.com/v2/ui#/app/dashboard)
|
357
|
+
and copy the 'Client ID' and the 'Client 'Secret' to your .env
|
358
|
+
as QBO_API_CLIENT_ID and QBO_API_CLIENT_SECRET respectively
|
359
|
+
- Add a Redirect URI: `http://localhost:9393/oauth2-redirect` (or whatever PORT= is in your .env)
|
360
|
+
- Create a new Company ([from the manage sandboxes page](https://developer.intuit.com/v2/ui#/sandbox))
|
361
|
+
Don't use it for anything else besides testing this app.
|
362
|
+
-. Copy the 'Company ID' to your .env as QBO_API_COMPANY_ID
|
363
|
+
- Start up the example OAuth2 app
|
364
|
+
- `ruby example/oauth2.rb`
|
365
|
+
- Go to `http://localhost:9393/oauth2`
|
361
366
|
- Use the `Connect to QuickBooks` button to connect to your QuickBooks sandbox, which you receive when signing up at [https://developer.intuit.com](https://developer.intuit.com).
|
362
|
-
- After successfully connecting to your sandbox
|
367
|
+
- After successfully connecting to your sandbox go to :
|
363
368
|
- `http://localhost:9393/oauth2/customer/5`
|
364
369
|
- You should see "Dukes Basketball Camp" displayed
|
365
|
-
- Checkout [`example/
|
370
|
+
- Checkout [`example/oauth2.rb`](https://github.com/minimul/qbo_api/blob/master/example/oauth2.rb)
|
371
|
+
to see what is going on under the hood.
|
366
372
|
|
367
373
|
## OAuth1: Spin up an example
|
368
374
|
### OLD LEGACY - SEE OAUTH2 EXAMPLE ABOVE
|
@@ -374,20 +380,47 @@ See [docs](https://developer.intuit.com/docs/0100_quickbooks_online/0100_essenti
|
|
374
380
|
- If needed create an account at [https://developer.intuit.com](https://developer.intuit.com)
|
375
381
|
- Click `Get started coding`
|
376
382
|
- Create an app with both the `Accounting` & `Payments` selected.
|
377
|
-
- Go to the `Development` tab and copy and paste the consumer key and secret into the `.env` file
|
378
|
-
|
383
|
+
- Go to the `Development` tab and copy and paste the consumer key and secret into the `.env` file
|
384
|
+
as QBO_API_CONSUMER_KEY and QBO_API_CONSUMER_SECRET respectively.
|
379
385
|
- Start up the example app
|
380
|
-
- `ruby example/
|
381
|
-
-
|
386
|
+
- `ruby example/oauth.rb`
|
387
|
+
- Go to `http://localhost:9393`
|
382
388
|
- Use the `Connect to QuickBooks` button to connect to your QuickBooks sandbox, which you receive when signing up at [https://developer.intuit.com](https://developer.intuit.com).
|
383
389
|
- After successfully connecting to your sandbox run:
|
384
390
|
- `http://localhost:9393/customer/5`
|
385
391
|
- You should see "Dukes Basketball Camp" displayed
|
386
|
-
- Checkout [`example/
|
392
|
+
- Checkout [`example/oauth.rb`](https://github.com/minimul/qbo_api/blob/master/example/oauth.rb)
|
393
|
+
to see what is going on under the hood.
|
387
394
|
|
388
395
|
## Webhooks
|
389
396
|
- <a href="http://minimul.com/getting-started-with-quickbooks-online-webhooks.html" target="_blank">Check out this tutorial and screencast on handling a webhook request</a>. Also checkout [`example/app.rb`](https://github.com/minimul/qbo_api/blob/master/example/app.rb) for the request handling code.
|
390
397
|
|
398
|
+
See https://www.twilio.com/blog/2015/09/6-awesome-reasons-to-use-ngrok-when-testing-webhooks.html
|
399
|
+
for how to install ngrok and what it is.
|
400
|
+
|
401
|
+
- With either the oauth1 or oauth2 examples running, run:
|
402
|
+
`ngrok http 9393 -subdomain=somereasonablyuniquenamehere`
|
403
|
+
|
404
|
+
- Go to the [`Development` tab](https://developer.intuit.com/v2/ui#/app/dashboard)
|
405
|
+
- Add a webhook, Select all triggers and enter the https url from the ngrok output
|
406
|
+
`https://somereasonablyuniquenamehere/webhooks`
|
407
|
+
|
408
|
+
- After saving the webhook, click 'show token'.
|
409
|
+
Add the token to your .env as QBO_API_VERIFIER_TOKEN
|
410
|
+
|
411
|
+
- In another tab, create a customer via the (OAuth2) API:
|
412
|
+
`bundle exec ruby -rqbo_api -rdotenv -e 'Dotenv.load; p QboApi.new(access_token: ENV.fetch("QBO_API_OAUTH2_ACCESS_TOKEN"), realm_id: ENV.fetch("QBO_API_COMPANY_ID")).create(:customer, payload: { DisplayName: "TestCustomer" })'`
|
413
|
+
(You'll also need to have added the QBO_API_COMPANY_ID and QBO_API_OAUTH2_ACCESS_TOKEN to your .env)
|
414
|
+
|
415
|
+
There could be a delay of up to a minute before the webhook fires.
|
416
|
+
|
417
|
+
It'll appear in your logs like:
|
418
|
+
```
|
419
|
+
{"eventNotifications"=>[{"realmId"=>"XXXX", "dataChangeEvent"=>{"entities"=>[{"name"=>"Customer", "id"=>"62", "operation"=>"Create", "lastUpdated"=>"2018-04-08T04:14:39.000Z"}]}}]}
|
420
|
+
Verified: true
|
421
|
+
"POST /webhooks HTTP/1.1" 200 - 0.0013
|
422
|
+
```
|
423
|
+
|
391
424
|
## Contributing
|
392
425
|
|
393
426
|
Bug reports and pull requests are welcome on GitHub at https://github.com/minimul/qbo_api.
|
@@ -408,9 +441,7 @@ Bug reports and pull requests are welcome on GitHub at https://github.com/minimu
|
|
408
441
|
#### Protip: Once your .env file is completely filled out you can use the console to play around in your sandbox
|
409
442
|
```
|
410
443
|
bin/console test
|
411
|
-
>>
|
412
|
-
>> q = QboApi.new(oauth2_creds.to_h) # FOR OAuth2
|
413
|
-
>> q.get :customer, 1
|
444
|
+
>> @qbo_api.get :customer, 1
|
414
445
|
```
|
415
446
|
|
416
447
|
## License
|
data/bin/console
CHANGED
@@ -6,6 +6,7 @@ require "qbo_api"
|
|
6
6
|
if ARGV[0] == "test"
|
7
7
|
require_relative '../spec/support/credentials'
|
8
8
|
ARGV[0] = nil # needed to avoid irb error
|
9
|
+
instance_variable_set(:@qbo_api, QboApi.new(creds.to_h))
|
9
10
|
end
|
10
11
|
|
11
12
|
# You can add fixtures and/or initialization code here to make experimenting
|
data/example/base.rb
ADDED
@@ -0,0 +1,54 @@
|
|
1
|
+
BASE_GEMS = proc do
|
2
|
+
gem 'qbo_api', path: '.'
|
3
|
+
# This app
|
4
|
+
gem 'sinatra'
|
5
|
+
gem 'sinatra-contrib'
|
6
|
+
|
7
|
+
# Creds from ../.env
|
8
|
+
gem 'dotenv'
|
9
|
+
end
|
10
|
+
|
11
|
+
BASE_SETUP = proc do
|
12
|
+
# Webhook support
|
13
|
+
require 'json'
|
14
|
+
require 'openssl'
|
15
|
+
require 'base64'
|
16
|
+
|
17
|
+
Dotenv.load "#{__dir__}/../.env"
|
18
|
+
end
|
19
|
+
|
20
|
+
BASE_APP_CONFIG = proc do
|
21
|
+
PORT = ENV.fetch("PORT", 9393)
|
22
|
+
# WebHook verifier token
|
23
|
+
VERIFIER_TOKEN = ENV['QBO_API_VERIFIER_TOKEN']
|
24
|
+
|
25
|
+
configure do
|
26
|
+
$VERBOSE = nil # silence redefined constant warning
|
27
|
+
register Sinatra::Reloader
|
28
|
+
end
|
29
|
+
|
30
|
+
set :sessions, :true
|
31
|
+
set :port, PORT
|
32
|
+
|
33
|
+
before do
|
34
|
+
# Rewrite trailing slashes
|
35
|
+
next unless request.path_info =~ %r{/(.+)/$}
|
36
|
+
redirect(Regexp.last_match[1], 301)
|
37
|
+
end
|
38
|
+
|
39
|
+
post '/webhooks' do
|
40
|
+
request.body.rewind
|
41
|
+
data = request.body.read
|
42
|
+
puts JSON.parse data
|
43
|
+
verified = verify_webhook(data, env['HTTP_INTUIT_SIGNATURE'])
|
44
|
+
puts "Verified: #{verified}"
|
45
|
+
end
|
46
|
+
|
47
|
+
helpers do
|
48
|
+
def verify_webhook(data, hmac_header)
|
49
|
+
digest = OpenSSL::Digest.new('sha256')
|
50
|
+
calculated_hmac = Base64.encode64(OpenSSL::HMAC.digest(digest, VERIFIER_TOKEN, data)).strip
|
51
|
+
calculated_hmac == hmac_header
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
data/example/oauth.rb
ADDED
@@ -0,0 +1,62 @@
|
|
1
|
+
require 'bundler/inline'
|
2
|
+
|
3
|
+
require File.expand_path(File.join('..', 'base'), __FILE__)
|
4
|
+
|
5
|
+
install_gems = true
|
6
|
+
gemfile(install_gems) do
|
7
|
+
source 'https://rubygems.org'
|
8
|
+
|
9
|
+
instance_eval(&BASE_GEMS)
|
10
|
+
|
11
|
+
gem 'omniauth'
|
12
|
+
gem 'omniauth-quickbooks'
|
13
|
+
end
|
14
|
+
|
15
|
+
instance_eval(&BASE_SETUP)
|
16
|
+
|
17
|
+
class OAuthApp < Sinatra::Base
|
18
|
+
instance_eval(&BASE_APP_CONFIG)
|
19
|
+
|
20
|
+
CONSUMER_KEY = ENV['QBO_API_CONSUMER_KEY']
|
21
|
+
CONSUMER_SECRET = ENV['QBO_API_CONSUMER_SECRET']
|
22
|
+
|
23
|
+
use Rack::Session::Cookie, secret: '34233adasf/qewrq453agqr9(lasfa)'
|
24
|
+
use OmniAuth::Builder do
|
25
|
+
provider :quickbooks, CONSUMER_KEY, CONSUMER_SECRET
|
26
|
+
end
|
27
|
+
|
28
|
+
get '/' do
|
29
|
+
@app_center = QboApi::APP_CENTER_BASE
|
30
|
+
@auth_data = oauth_data
|
31
|
+
@port = PORT
|
32
|
+
erb :index
|
33
|
+
end
|
34
|
+
|
35
|
+
get '/customer/:id' do
|
36
|
+
if session[:token]
|
37
|
+
api = QboApi.new(oauth_data)
|
38
|
+
@resp = api.get :customer, params[:id]
|
39
|
+
end
|
40
|
+
erb :customer
|
41
|
+
end
|
42
|
+
|
43
|
+
get '/auth/quickbooks/callback' do
|
44
|
+
auth = env["omniauth.auth"][:credentials]
|
45
|
+
session[:token] = auth[:token]
|
46
|
+
session[:secret] = auth[:secret]
|
47
|
+
session[:realm_id] = params['realmId']
|
48
|
+
'<!DOCTYPE html><html lang="en"><head></head><body><script>window.opener.location.reload(); window.close();</script></body></html>'
|
49
|
+
end
|
50
|
+
|
51
|
+
def oauth_data
|
52
|
+
{
|
53
|
+
consumer_key: CONSUMER_KEY,
|
54
|
+
consumer_secret: CONSUMER_SECRET,
|
55
|
+
token: session[:token],
|
56
|
+
token_secret: session[:secret],
|
57
|
+
realm_id: session[:realm_id]
|
58
|
+
}
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
OAuthApp.run!
|
data/example/oauth2.rb
ADDED
@@ -0,0 +1,69 @@
|
|
1
|
+
require 'bundler/inline'
|
2
|
+
|
3
|
+
require File.expand_path(File.join('..', 'base'), __FILE__)
|
4
|
+
|
5
|
+
install_gems = true
|
6
|
+
gemfile(install_gems) do
|
7
|
+
source 'https://rubygems.org'
|
8
|
+
|
9
|
+
instance_eval(&BASE_GEMS)
|
10
|
+
|
11
|
+
gem 'rack-oauth2'
|
12
|
+
end
|
13
|
+
|
14
|
+
instance_eval(&BASE_SETUP)
|
15
|
+
|
16
|
+
class OAuth2App < Sinatra::Base
|
17
|
+
instance_eval(&BASE_APP_CONFIG)
|
18
|
+
|
19
|
+
CLIENT_ID = ENV['QBO_API_CLIENT_ID']
|
20
|
+
CLIENT_SECRET = ENV['QBO_API_CLIENT_SECRET']
|
21
|
+
|
22
|
+
helpers do
|
23
|
+
def oauth2_client
|
24
|
+
client = Rack::OAuth2::Client.new(
|
25
|
+
identifier: CLIENT_ID,
|
26
|
+
secret: CLIENT_SECRET,
|
27
|
+
redirect_uri: "http://localhost:#{PORT}/oauth2-redirect",
|
28
|
+
authorization_endpoint: "https://appcenter.intuit.com/connect/oauth2",
|
29
|
+
token_endpoint: "https://oauth.platform.intuit.com/oauth2/v1/tokens/bearer"
|
30
|
+
)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
get '/oauth2' do
|
35
|
+
session[:state] = SecureRandom.uuid
|
36
|
+
@client = oauth2_client
|
37
|
+
erb :oauth2
|
38
|
+
end
|
39
|
+
|
40
|
+
get '/oauth2-redirect' do
|
41
|
+
state = params[:state]
|
42
|
+
error = params[:error]
|
43
|
+
code = params[:code]
|
44
|
+
if state == session[:state]
|
45
|
+
client = oauth2_client
|
46
|
+
client.authorization_code = code
|
47
|
+
if resp = client.access_token!
|
48
|
+
session[:refresh_token] = resp.refresh_token
|
49
|
+
session[:access_token] = resp.access_token
|
50
|
+
session[:realm_id] = params[:realmId]
|
51
|
+
erb :oauth2_redirect
|
52
|
+
else
|
53
|
+
"Something went wrong. Try the process again"
|
54
|
+
end
|
55
|
+
else
|
56
|
+
"Error: #{error}"
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
get '/oauth2/customer/:id' do
|
61
|
+
if access_token = session[:access_token]
|
62
|
+
api = QboApi.new(access_token: access_token, realm_id: session[:realm_id])
|
63
|
+
@resp = api.get :customer, params[:id]
|
64
|
+
end
|
65
|
+
erb :customer
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
OAuth2App.run!
|
data/example/views/index.erb
CHANGED
data/lib/qbo_api/version.rb
CHANGED
data/qbo_api.gemspec
CHANGED
@@ -22,12 +22,7 @@ Gem::Specification.new do |spec|
|
|
22
22
|
spec.add_development_dependency "rake", "~> 10.0"
|
23
23
|
spec.add_development_dependency "rspec"
|
24
24
|
spec.add_development_dependency 'webmock'
|
25
|
-
spec.add_development_dependency 'sinatra'
|
26
|
-
spec.add_development_dependency 'rack-oauth2'
|
27
25
|
spec.add_development_dependency 'simple_oauth'
|
28
|
-
spec.add_development_dependency 'omniauth'
|
29
|
-
spec.add_development_dependency 'omniauth-quickbooks'
|
30
|
-
spec.add_development_dependency 'shotgun'
|
31
26
|
spec.add_development_dependency 'dotenv'
|
32
27
|
spec.add_development_dependency 'vcr'
|
33
28
|
spec.add_development_dependency 'awesome_print'
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: qbo_api
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.8.
|
4
|
+
version: 1.8.3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Christian Pelczarski
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2018-04-
|
11
|
+
date: 2018-04-12 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -66,34 +66,6 @@ dependencies:
|
|
66
66
|
- - ">="
|
67
67
|
- !ruby/object:Gem::Version
|
68
68
|
version: '0'
|
69
|
-
- !ruby/object:Gem::Dependency
|
70
|
-
name: sinatra
|
71
|
-
requirement: !ruby/object:Gem::Requirement
|
72
|
-
requirements:
|
73
|
-
- - ">="
|
74
|
-
- !ruby/object:Gem::Version
|
75
|
-
version: '0'
|
76
|
-
type: :development
|
77
|
-
prerelease: false
|
78
|
-
version_requirements: !ruby/object:Gem::Requirement
|
79
|
-
requirements:
|
80
|
-
- - ">="
|
81
|
-
- !ruby/object:Gem::Version
|
82
|
-
version: '0'
|
83
|
-
- !ruby/object:Gem::Dependency
|
84
|
-
name: rack-oauth2
|
85
|
-
requirement: !ruby/object:Gem::Requirement
|
86
|
-
requirements:
|
87
|
-
- - ">="
|
88
|
-
- !ruby/object:Gem::Version
|
89
|
-
version: '0'
|
90
|
-
type: :development
|
91
|
-
prerelease: false
|
92
|
-
version_requirements: !ruby/object:Gem::Requirement
|
93
|
-
requirements:
|
94
|
-
- - ">="
|
95
|
-
- !ruby/object:Gem::Version
|
96
|
-
version: '0'
|
97
69
|
- !ruby/object:Gem::Dependency
|
98
70
|
name: simple_oauth
|
99
71
|
requirement: !ruby/object:Gem::Requirement
|
@@ -108,48 +80,6 @@ dependencies:
|
|
108
80
|
- - ">="
|
109
81
|
- !ruby/object:Gem::Version
|
110
82
|
version: '0'
|
111
|
-
- !ruby/object:Gem::Dependency
|
112
|
-
name: omniauth
|
113
|
-
requirement: !ruby/object:Gem::Requirement
|
114
|
-
requirements:
|
115
|
-
- - ">="
|
116
|
-
- !ruby/object:Gem::Version
|
117
|
-
version: '0'
|
118
|
-
type: :development
|
119
|
-
prerelease: false
|
120
|
-
version_requirements: !ruby/object:Gem::Requirement
|
121
|
-
requirements:
|
122
|
-
- - ">="
|
123
|
-
- !ruby/object:Gem::Version
|
124
|
-
version: '0'
|
125
|
-
- !ruby/object:Gem::Dependency
|
126
|
-
name: omniauth-quickbooks
|
127
|
-
requirement: !ruby/object:Gem::Requirement
|
128
|
-
requirements:
|
129
|
-
- - ">="
|
130
|
-
- !ruby/object:Gem::Version
|
131
|
-
version: '0'
|
132
|
-
type: :development
|
133
|
-
prerelease: false
|
134
|
-
version_requirements: !ruby/object:Gem::Requirement
|
135
|
-
requirements:
|
136
|
-
- - ">="
|
137
|
-
- !ruby/object:Gem::Version
|
138
|
-
version: '0'
|
139
|
-
- !ruby/object:Gem::Dependency
|
140
|
-
name: shotgun
|
141
|
-
requirement: !ruby/object:Gem::Requirement
|
142
|
-
requirements:
|
143
|
-
- - ">="
|
144
|
-
- !ruby/object:Gem::Version
|
145
|
-
version: '0'
|
146
|
-
type: :development
|
147
|
-
prerelease: false
|
148
|
-
version_requirements: !ruby/object:Gem::Requirement
|
149
|
-
requirements:
|
150
|
-
- - ">="
|
151
|
-
- !ruby/object:Gem::Version
|
152
|
-
version: '0'
|
153
83
|
- !ruby/object:Gem::Dependency
|
154
84
|
name: dotenv
|
155
85
|
requirement: !ruby/object:Gem::Requirement
|
@@ -266,7 +196,9 @@ files:
|
|
266
196
|
- Rakefile
|
267
197
|
- bin/console
|
268
198
|
- bin/setup
|
269
|
-
- example/
|
199
|
+
- example/base.rb
|
200
|
+
- example/oauth.rb
|
201
|
+
- example/oauth2.rb
|
270
202
|
- example/views/customer.erb
|
271
203
|
- example/views/index.erb
|
272
204
|
- example/views/oauth2.erb
|
data/example/app.rb
DELETED
@@ -1,118 +0,0 @@
|
|
1
|
-
require "bundler/setup"
|
2
|
-
require 'sinatra'
|
3
|
-
require 'json'
|
4
|
-
require 'openssl'
|
5
|
-
require 'base64'
|
6
|
-
require 'omniauth'
|
7
|
-
require 'omniauth-quickbooks'
|
8
|
-
require 'dotenv'
|
9
|
-
require 'rack/oauth2'
|
10
|
-
require 'qbo_api'
|
11
|
-
|
12
|
-
Dotenv.load "#{__dir__}/../.env"
|
13
|
-
|
14
|
-
PORT = ENV.fetch("PORT", 9393)
|
15
|
-
CONSUMER_KEY = ENV['QBO_API_CONSUMER_KEY']
|
16
|
-
CONSUMER_SECRET = ENV['QBO_API_CONSUMER_SECRET']
|
17
|
-
CLIENT_ID = ENV['QBO_API_CLIENT_ID']
|
18
|
-
CLIENT_SECRET = ENV['QBO_API_CLIENT_SECRET']
|
19
|
-
VERIFIER_TOKEN = ENV['QBO_API_VERIFIER_TOKEN']
|
20
|
-
|
21
|
-
set :port, PORT
|
22
|
-
use Rack::Session::Cookie, secret: '34233adasf/qewrq453agqr9(lasfa)'
|
23
|
-
use OmniAuth::Builder do
|
24
|
-
provider :quickbooks, CONSUMER_KEY, CONSUMER_SECRET
|
25
|
-
end
|
26
|
-
|
27
|
-
helpers do
|
28
|
-
def verify_webhook(data, hmac_header)
|
29
|
-
digest = OpenSSL::Digest.new('sha256')
|
30
|
-
calculated_hmac = Base64.encode64(OpenSSL::HMAC.digest(digest, VERIFIER_TOKEN, data)).strip
|
31
|
-
calculated_hmac == hmac_header
|
32
|
-
end
|
33
|
-
|
34
|
-
def oauth2_client
|
35
|
-
client = Rack::OAuth2::Client.new(
|
36
|
-
identifier: CLIENT_ID,
|
37
|
-
secret: CLIENT_SECRET,
|
38
|
-
redirect_uri: "http://localhost:#{PORT}/oauth2-redirect",
|
39
|
-
authorization_endpoint: "https://appcenter.intuit.com/connect/oauth2",
|
40
|
-
token_endpoint: "https://oauth.platform.intuit.com/oauth2/v1/tokens/bearer"
|
41
|
-
)
|
42
|
-
end
|
43
|
-
end
|
44
|
-
|
45
|
-
get '/' do
|
46
|
-
@app_center = QboApi::APP_CENTER_BASE
|
47
|
-
@auth_data = oauth_data
|
48
|
-
@port = PORT
|
49
|
-
erb :index
|
50
|
-
end
|
51
|
-
|
52
|
-
get '/oauth2' do
|
53
|
-
session[:state] = SecureRandom.uuid
|
54
|
-
@client = oauth2_client
|
55
|
-
erb :oauth2
|
56
|
-
end
|
57
|
-
|
58
|
-
get '/oauth2-redirect' do
|
59
|
-
state = params[:state]
|
60
|
-
error = params[:error]
|
61
|
-
code = params[:code]
|
62
|
-
if state == session[:state]
|
63
|
-
client = oauth2_client
|
64
|
-
client.authorization_code = code
|
65
|
-
if resp = client.access_token!
|
66
|
-
session[:refresh_token] = resp.refresh_token
|
67
|
-
session[:access_token] = resp.access_token
|
68
|
-
session[:realm_id] = params[:realmId]
|
69
|
-
erb :oauth2_redirect
|
70
|
-
else
|
71
|
-
"Something went wrong. Try the process again"
|
72
|
-
end
|
73
|
-
else
|
74
|
-
"Error: #{error}"
|
75
|
-
end
|
76
|
-
end
|
77
|
-
|
78
|
-
get '/oauth2/customer/:id' do
|
79
|
-
if access_token = session[:access_token]
|
80
|
-
api = QboApi.new(access_token: access_token, realm_id: session[:realm_id])
|
81
|
-
@resp = api.get :customer, params[:id]
|
82
|
-
end
|
83
|
-
erb :customer
|
84
|
-
end
|
85
|
-
|
86
|
-
get '/customer/:id' do
|
87
|
-
if session[:token]
|
88
|
-
api = QboApi.new(oauth_data)
|
89
|
-
@resp = api.get :customer, params[:id]
|
90
|
-
end
|
91
|
-
erb :customer
|
92
|
-
end
|
93
|
-
|
94
|
-
post '/webhooks' do
|
95
|
-
request.body.rewind
|
96
|
-
data = request.body.read
|
97
|
-
puts JSON.parse data
|
98
|
-
verified = verify_webhook(data, env['HTTP_INTUIT_SIGNATURE'])
|
99
|
-
puts "Verified: #{verified}"
|
100
|
-
end
|
101
|
-
|
102
|
-
def oauth_data
|
103
|
-
{
|
104
|
-
consumer_key: CONSUMER_KEY,
|
105
|
-
consumer_secret: CONSUMER_SECRET,
|
106
|
-
token: session[:token],
|
107
|
-
token_secret: session[:secret],
|
108
|
-
realm_id: session[:realm_id]
|
109
|
-
}
|
110
|
-
end
|
111
|
-
|
112
|
-
get '/auth/quickbooks/callback' do
|
113
|
-
auth = env["omniauth.auth"][:credentials]
|
114
|
-
session[:token] = auth[:token]
|
115
|
-
session[:secret] = auth[:secret]
|
116
|
-
session[:realm_id] = params['realmId']
|
117
|
-
'<!DOCTYPE html><html lang="en"><head></head><body><script>window.opener.location.reload(); window.close();</script></body></html>'
|
118
|
-
end
|