spiffy_stores_app 8.2.6

Sign up to get free protection for your applications and to get access to all the features.
Files changed (68) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +13 -0
  3. data/.rubocop.yml +7 -0
  4. data/.travis.yml +9 -0
  5. data/CHANGELOG.md +3 -0
  6. data/Gemfile +6 -0
  7. data/README.md +346 -0
  8. data/Rakefile +6 -0
  9. data/app/assets/javascripts/spiffy_stores_app/redirect.js +19 -0
  10. data/app/controllers/spiffy_stores_app/authenticated_controller.rb +11 -0
  11. data/app/controllers/spiffy_stores_app/sessions_controller.rb +113 -0
  12. data/app/controllers/spiffy_stores_app/webhooks_controller.rb +36 -0
  13. data/app/views/spiffy_stores_app/sessions/new.html.erb +123 -0
  14. data/app/views/spiffy_stores_app/shared/redirect.html.erb +22 -0
  15. data/config/locales/de.yml +3 -0
  16. data/config/locales/en.yml +4 -0
  17. data/config/locales/es.yml +3 -0
  18. data/config/locales/fr.yml +4 -0
  19. data/config/locales/ja.yml +3 -0
  20. data/config/routes.rb +12 -0
  21. data/docs/Quickstart.md +76 -0
  22. data/images/app-proxy-screenshot.png +0 -0
  23. data/lib/generators/spiffy_stores_app/add_after_authenticate_job/add_after_authenticate_job_generator.rb +43 -0
  24. data/lib/generators/spiffy_stores_app/add_after_authenticate_job/templates/after_authenticate_job.rb +10 -0
  25. data/lib/generators/spiffy_stores_app/add_webhook/add_webhook_generator.rb +68 -0
  26. data/lib/generators/spiffy_stores_app/add_webhook/templates/webhook_job.rb +8 -0
  27. data/lib/generators/spiffy_stores_app/app_proxy_controller/app_proxy_controller_generator.rb +25 -0
  28. data/lib/generators/spiffy_stores_app/app_proxy_controller/templates/app_proxy_controller.rb +8 -0
  29. data/lib/generators/spiffy_stores_app/app_proxy_controller/templates/app_proxy_route.rb +10 -0
  30. data/lib/generators/spiffy_stores_app/app_proxy_controller/templates/index.html.erb +19 -0
  31. data/lib/generators/spiffy_stores_app/controllers/controllers_generator.rb +29 -0
  32. data/lib/generators/spiffy_stores_app/home_controller/home_controller_generator.rb +31 -0
  33. data/lib/generators/spiffy_stores_app/home_controller/templates/home_controller.rb +6 -0
  34. data/lib/generators/spiffy_stores_app/home_controller/templates/index.html.erb +21 -0
  35. data/lib/generators/spiffy_stores_app/home_controller/templates/spiffy_stores_app_ready_script.html.erb +7 -0
  36. data/lib/generators/spiffy_stores_app/install/install_generator.rb +58 -0
  37. data/lib/generators/spiffy_stores_app/install/templates/_flash_messages.html.erb +19 -0
  38. data/lib/generators/spiffy_stores_app/install/templates/embedded_app.html.erb +40 -0
  39. data/lib/generators/spiffy_stores_app/install/templates/omniauth.rb +2 -0
  40. data/lib/generators/spiffy_stores_app/install/templates/spiffy_provider.rb +11 -0
  41. data/lib/generators/spiffy_stores_app/install/templates/spiffy_stores_app.rb +9 -0
  42. data/lib/generators/spiffy_stores_app/routes/routes_generator.rb +31 -0
  43. data/lib/generators/spiffy_stores_app/routes/templates/routes.rb +11 -0
  44. data/lib/generators/spiffy_stores_app/shop_model/shop_model_generator.rb +38 -0
  45. data/lib/generators/spiffy_stores_app/shop_model/templates/db/migrate/create_shops.erb +15 -0
  46. data/lib/generators/spiffy_stores_app/shop_model/templates/shop.rb +3 -0
  47. data/lib/generators/spiffy_stores_app/shop_model/templates/shops.yml +3 -0
  48. data/lib/generators/spiffy_stores_app/spiffy_stores_app_generator.rb +16 -0
  49. data/lib/generators/spiffy_stores_app/views/views_generator.rb +29 -0
  50. data/lib/spiffy_stores_app.rb +34 -0
  51. data/lib/spiffy_stores_app/configuration.rb +72 -0
  52. data/lib/spiffy_stores_app/controller_concerns/app_proxy_verification.rb +38 -0
  53. data/lib/spiffy_stores_app/controller_concerns/embedded_app.rb +19 -0
  54. data/lib/spiffy_stores_app/controller_concerns/localization.rb +22 -0
  55. data/lib/spiffy_stores_app/controller_concerns/login_protection.rb +103 -0
  56. data/lib/spiffy_stores_app/controller_concerns/webhook_verification.rb +34 -0
  57. data/lib/spiffy_stores_app/engine.rb +10 -0
  58. data/lib/spiffy_stores_app/jobs/scripttags_manager_job.rb +15 -0
  59. data/lib/spiffy_stores_app/jobs/webhooks_manager_job.rb +15 -0
  60. data/lib/spiffy_stores_app/managers/scripttags_manager.rb +77 -0
  61. data/lib/spiffy_stores_app/managers/webhooks_manager.rb +61 -0
  62. data/lib/spiffy_stores_app/session/in_memory_session_store.rb +27 -0
  63. data/lib/spiffy_stores_app/session/session_repository.rb +34 -0
  64. data/lib/spiffy_stores_app/session/session_storage.rb +32 -0
  65. data/lib/spiffy_stores_app/utils.rb +16 -0
  66. data/lib/spiffy_stores_app/version.rb +3 -0
  67. data/spiffy_stores_app.gemspec +26 -0
  68. metadata +220 -0
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: a78e64b5b0748a7da935db707643314cc0f24b6ba0a0094fdfc3ce10190664a7
4
+ data.tar.gz: 7e0acce6ae15900333c1e7674adbb13712cada445649c93077a7d60f51d70dea
5
+ SHA512:
6
+ metadata.gz: e52e85775523f58aeb3bda9186f858d889de0be007e9e68ff9b1d273952e04c86058f440a45b6d7ab27853f1db6a4abfa9e4a45198a8d9ff2f9d323db22906db
7
+ data.tar.gz: f276ac6f2d6843e4b9bc3cca44d4051f9e1bf0a907e3d0bc82bd78d62d7bede1962d774798aff027ba877ada7c9475b538fa130163e5716177577a65f9dd110c
@@ -0,0 +1,13 @@
1
+ *.gem
2
+ .bundle
3
+ Gemfile.lock
4
+ pkg/*
5
+ .DS_Store
6
+ .yardoc
7
+ doc/
8
+ *.log
9
+ *.sqlite3
10
+ test/tmp/*
11
+ .idea
12
+ # ignore sprockets cache
13
+ /test/dummy/tmp/*
@@ -0,0 +1,7 @@
1
+ LineLength:
2
+ Exclude:
3
+ - test/**/*
4
+
5
+ Metrics/ClassLength:
6
+ Exclude:
7
+ - test/**/*
@@ -0,0 +1,9 @@
1
+ language: ruby
2
+ before_install: gem update --system
3
+ cache: bundler
4
+ sudo: false
5
+
6
+ rvm:
7
+ - 2.3.6
8
+ - 2.4.3
9
+ - 2.5.0
@@ -0,0 +1,3 @@
1
+ 8.2.6
2
+ ----
3
+ * Initial Release
data/Gemfile ADDED
@@ -0,0 +1,6 @@
1
+ source "https://rubygems.org"
2
+
3
+ # Specify your gem's dependencies in spiffy_stores_app.gemspec
4
+ gemspec
5
+
6
+ gem 'rails-controller-testing', group: :test
@@ -0,0 +1,346 @@
1
+ SpiffyStores App
2
+ ================
3
+ [![Build Status](https://travis-ci.com/SpiffyStores/spiffy_stores_app.svg?branch=master)](https://travis-ci.com/SpiffyStores/spiffy_stores_app)
4
+
5
+ Spiffy Stores Application Rails engine and generator
6
+
7
+ #### NOTE : Versions 8.0.0 through 8.2.3 contained a CSRF vulnerability that was addressed in version 8.2.4. Please update to version 8.2.4 if you're using an old version.
8
+
9
+ Table of Contents
10
+ -----------------
11
+ * [**Description**](#description)
12
+ * [**Quickstart**](#quickstart)
13
+ * [**Installation**](#installation)
14
+ * [Rails Compatibility](#rails-compatibility)
15
+ * [**Generators**](#generators)
16
+ * [Default Generator](#default-generator)
17
+ * [Install Generator](#install-generator)
18
+ * [Shop Model Generator](#shop-model-generator)
19
+ * [Home Controller Generator](#home-controller-generator)
20
+ * [App Proxy Controller Generator](#app-proxy-controller-generator)
21
+ * [Controllers, Routes and Views](#controllers-routes-and-views)
22
+ * [**Mounting the Engine**](#mounting-the-engine)
23
+ * [**Managing Api Keys**](#managing-api-keys)
24
+ * [**WebhooksManager**](#webhooksmanager)
25
+ * [**ScripttagsManager**](#scripttagsmanager)
26
+ * [**AfterAuthenticate Job**](#afterauthenticate-job)
27
+ * [**SpiffyStoresApp::SessionRepository**](#spiffystoresappsessionrepository)
28
+ * [**AuthenticatedController**](#authenticatedcontroller)
29
+ * [**AppProxyVerification**](#appproxyverification)
30
+ * [Recommended Usage](#recommended-usage)
31
+ * [**Troubleshooting**](#troubleshooting)
32
+ * [Generator spiffy_stores_app:install hangs](#generator-spiffy_stores_appinstall-hangs)
33
+ * [**Testing an embedded app outside the Spiffy Stores admin**](#testing-an-embedded-app-outside-the-spiffy-stores-admin)
34
+ * [**App Tunneling**](#app-tunneling)
35
+ * [**Questions or problems?**](#questions-or-problems)
36
+
37
+
38
+ Description
39
+ -----------
40
+ This gem includes a Rails Engine and generators for writing Rails applications using the Spiffy Stores API. The Engine provides a SessionsController and all the required code for authenticating with a shop via Oauth (other authentication methods are not supported).
41
+
42
+ The [example](https://github.com/SpiffyStores/spiffy_stores_app/tree/master/example) directory contains an app that was generated with this gem. It also contains sample code demonstrating the usage of the embedded app sdk.
43
+
44
+ *Note: It's recommended to use this on a new Rails project, so that the generator won't overwrite/delete some of your files.*
45
+
46
+ Installation
47
+ ------------
48
+ To get started add spiffy_stores_app to your Gemfile and bundle install
49
+
50
+ ``` sh
51
+ # Create a new rails app
52
+ $ rails new my_spiffy_stores_app
53
+ $ cd my_spiffy_stores_app
54
+
55
+ # Add the gem spiffy_stores_app to your Gemfile
56
+ $ echo "gem 'spiffy_stores_app'" >> Gemfile
57
+ $ bundle install
58
+ ```
59
+
60
+ Now we are ready to run any of the spiffy_stores_app generators. The following section explains the generators and what they can do.
61
+
62
+
63
+ #### Rails Compatibility
64
+
65
+ The lastest version of spiffy_stores_app is compatible with Rails `>= 5`. Use version `<= v7.2.8` if you need to work with Rails 4.
66
+
67
+
68
+ Generators
69
+ ----------
70
+
71
+ ### Default Generator
72
+
73
+ The default generator will run the `install`, `shop`, and `home_controller` generators. This is the recommended way to start your app.
74
+
75
+ ```sh
76
+ $ rails generate spiffy_stores_app --api_key <your_api_key> --secret <your_app_secret>
77
+ ```
78
+
79
+
80
+ ### Install Generator
81
+
82
+ ```sh
83
+ $ rails generate spiffy_stores_app:install
84
+
85
+ # or optionally with arguments:
86
+
87
+ $ rails generate spiffy_stores_app:install --api_key <your_api_key> --secret <your_app_secret>
88
+ ```
89
+
90
+ Other options include:
91
+ * `application_name` - the name of your app, it can be supplied with or without double-quotes if a whitespace is present. (e.g. `--application_name Example App` or `--application_name "Example App"`)
92
+ * `scope` - the Oauth access scope required for your app, eg **read_products, write_orders**. *Multiple options* need to be delimited by a comma-space, and can be supplied with or without double-quotes
93
+ (e.g. `--scope read_products, write_orders, write_products` or `--scope "read_products, write_orders, write_products"`)
94
+ * `embedded` - the default is to generate an embedded app, if you want a legacy non-embedded app then set this to false, `--embedded false`
95
+
96
+ You can update any of these settings later on easily, the arguments are simply for convenience.
97
+
98
+ The generator adds SpiffyStoresApp and the required initializers to the host Rails application.
99
+
100
+ After running the `install` generator, you can start your app with `bundle exec rails server` and install your app by visiting localhost.
101
+
102
+
103
+ ### Shop Model Generator
104
+
105
+ ```sh
106
+ $ rails generate spiffy_stores_app:shop_model
107
+ ```
108
+
109
+ The `install` generator doesn't create any database tables or models for you. If you are starting a new app its quite likely that you will want a shops table and model to store the tokens when your app is installed (most of our internally developed apps do!). This generator creates a shop model and a migration. This model includes the `SpiffyStoresApp::SessionStorage` concern which adds two methods to make it compatible as a `SessionRepository`. After running this generator you'll notice the `session_repository` in your `config/initializers/spiffy_stores_app.rb` will be set to the `Shop` model. This means that internally SpiffyStoresApp will try and load tokens from this model.
110
+
111
+ *Note that you will need to run rake db:migrate after this generator*
112
+
113
+
114
+ ### Home Controller Generator
115
+
116
+ ```sh
117
+ $ rails generate spiffy_stores_app:home_controller
118
+ ```
119
+
120
+ This generator creates an example home controller and view which fetches and displays products using the SpiffyStoresAPI
121
+
122
+
123
+ ### App Proxy Controller Generator
124
+
125
+ ```sh
126
+ $ rails generate spiffy_stores_app:app_proxy_controller
127
+ ```
128
+
129
+ This optional generator, not included with the default generator, creates the app proxy controller to handle proxy requests to the app from your shop storefront, modifies 'config/routes.rb' with a namespace route, and an example view which displays current shop information using the LiquidAPI
130
+
131
+
132
+ ### Controllers, Routes and Views
133
+
134
+ The last group of generators are for your convenience if you want to start overriding code included as part of the Rails engine. For example by default the engine provides a simple SessionController, if you run the `rails generate spiffy_stores_app:controllers` generator then this code gets copied out into your app so you can start adding to it. Routes and views follow the exact same pattern.
135
+
136
+ Mounting the Engine
137
+ -------------------
138
+
139
+ Mounting the Engine will provide the basic routes to authenticating a shop with your custom application. It will provide:
140
+
141
+ | Verb | Route | Action |
142
+ |--------|-------------------------------|------------------------------|
143
+ |GET |'/login' |Login |
144
+ |POST |'/login' |Login |
145
+ |GET |'/auth/spiffy/callback' |Authenticate Callback |
146
+ |GET |'/logout' |Logout |
147
+ |POST |'/webhooks/:type' |Webhook Callback |
148
+
149
+
150
+ The default routes of the Spiffy Stores rails engine, which is mounted to the root, can be altered to mount on a different route. The `config/routes.rb` can be modified to put these under a nested route (say `/app-name`) as:
151
+
152
+ ```ruby
153
+ mount SpiffyStoresApp::Engine, at: '/app-name'
154
+ ```
155
+
156
+ This will create the Spiffy Stores engine routes under the specified Subdirectory, as a result it will redirect new consumers to `/app-name/login` and following a similar format for the other engine routes.
157
+
158
+ To use named routes with the engine so that it can route between the application and the engine's routes it should be prefixed with `main_app` or `spiffy_stores_app`.
159
+
160
+ ```ruby
161
+ main_app.login_path # For a named login route on the rails app.
162
+
163
+ spiffy_stores_app.login_path # For the spiffy stores app store login route.
164
+ ```
165
+
166
+ Managing Api Keys
167
+ -----------------
168
+
169
+ The `install` generator places your Api credentials directly into the spiffy_stores_app initializer which is convenient and fine for development but once your app goes into production **your api credentials should not be in source control**. When we develop apps we keep our keys in environment variables so a production spiffy_stores_app initializer would look like this:
170
+
171
+ ```ruby
172
+ SpiffyStoresApp.configure do |config|
173
+ config.application_name = 'Your app name' # Optional
174
+ config.api_key = ENV['SPIFFY_STORES_CLIENT_API_KEY']
175
+ config.secret = ENV['SPIFFY_STORES_CLIENT_API_SECRET']
176
+ config.scope = 'read_customers, read_orders, write_products'
177
+ config.embedded_app = true
178
+ end
179
+ ```
180
+
181
+
182
+ WebhooksManager
183
+ ---------------
184
+
185
+ SpiffyStoresApp can manage your app's webhooks for you by setting which webhooks you require in the initializer:
186
+
187
+ ```ruby
188
+ SpiffyStoresApp.configure do |config|
189
+ config.webhooks = [
190
+ {topic: 'carts/update', address: 'https://example-app.com/webhooks/carts_update'}
191
+ ]
192
+ end
193
+ ```
194
+
195
+ When the oauth callback is completed successfully SpiffyStoresApp will queue a background job which will ensure all the specified webhooks exist for that shop. Because this runs on every oauth callback it means your app will always have the webhooks it needs even if the user uninstalls and re-installs the app.
196
+
197
+ SpiffyStoresApp also provides a WebhooksController that receives webhooks and queues a job based on the webhook url. For example if you register the webhook from above then all you need to do is create a job called `CartsUpdateJob`. The job will be queued with 2 params `shop_domain` and `webhook` which is the webhook body.
198
+
199
+ If you'd rather implement your own controller then you'll want to use the WebhookVerfication module to verify your webhooks:
200
+
201
+ ```ruby
202
+ class CustomWebhooksController < ApplicationController
203
+ include SpiffyStoresApp::WebhookVerification
204
+
205
+ def carts_update
206
+ SomeJob.perform_later(spiffy_stores_domain: shop_domain, webhook: params)
207
+ head :ok
208
+ end
209
+ end
210
+ ```
211
+
212
+ The module skips the `verify_authenticity_token` before_action and adds an action to verify that the webhook came from Spiffy Stores.
213
+
214
+ The WebhooksManager uses ActiveJob, if ActiveJob is not configured then by default Rails will run the jobs inline. However it is highly recommended to configure a proper background processing queue like sidekiq or resque in production.
215
+
216
+ SpiffyStoresApp can create webhooks for you using the `add_webhook` generator. This will add the new webhook to your config and create the required job class for you.
217
+
218
+ ```
219
+ rails g spiffy_stores_app:add_webhook -t carts/update -a https://example.com/webhooks/carts_update
220
+ ```
221
+
222
+ where `-t` is the topic and `-a` is the address the webhook should be sent to.
223
+
224
+ ScripttagsManager
225
+ -----------------
226
+
227
+ As with webhooks, SpiffyStoresApp can manage your app's scripttags for you by setting which scripttags you require in the initializer:
228
+
229
+ ```ruby
230
+ SpiffyStoresApp.configure do |config|
231
+ config.scripttags = [
232
+ {event:'onload', src: 'https://my-spiffy-stores-app.herokuapp.com/fancy.js'}
233
+ {event:'onload', src: ->(domain) { dynamic_tag_url(domain) } }
234
+ ]
235
+ end
236
+ ```
237
+
238
+ Scripttags are created in the same way as the Webhooks, with a background job which will create the required scripttags.
239
+
240
+ If `src` responds to `call` its return value will be used as the scripttag's source. It will be called on scripttag creation and deletion.
241
+
242
+ SpiffyStoresApp::SessionRepository
243
+ -----------------------------
244
+
245
+ `SpiffyStoresApp::SessionRepository` allows you as a developer to define how your sessions are retrieved and stored for a shop. The `SessionRepository` is configured using the `config/initializers/spiffy_stores_session_repository.rb` file and can be set to any object that implements `self.store(spiffy_stores_session)` which stores the session and returns a unique identifier and `self.retrieve(id)` which returns a `SpiffyStoresAPI::Session` for the passed id. See either the `InMemorySessionStore` or the `SessionStorage` module for examples.
246
+
247
+ If you only run the install generator then by default you will have an in memory store but it **won't work** on multi-server environments including Heroku. If you ran all the generators including the shop_model generator then the Shop model itself will be the `SessionRepository`. If you look at the implementation of the generated shop model you'll see that this gem provides an activerecord mixin for the `SessionRepository`. You can use this mixin on any model that responds to `spiffy_stores_domain` and `spiffy_stores_token`.
248
+
249
+ AuthenticatedController
250
+ -----------------------
251
+
252
+ The engine includes a controller called `SpiffyStoresApp::AuthenticatedController` which inherits from `ApplicationController`. It adds some before_filters which ensure the user is authenticated and will redirect to the login page if not. It is best practice to have all controllers that belong to the Spiffy Stores part of your app inherit from this controller. The HomeController that is generated already inherits from AuthenticatedController.
253
+
254
+ AppProxyVerification
255
+ --------------------
256
+
257
+ The engine provides a mixin for verifying incoming HTTP requests sent via an App Proxy. Any controller that `include`s `SpiffyStoresApp::AppProxyVerification` will verify that each request has a valid `signature` query parameter that is calculated using the other query parameters and the app's shared secret.
258
+
259
+ ### Recommended Usage
260
+
261
+ 1. Use the `namespace` method to create app proxy routes
262
+ ```ruby
263
+ # config/routes.rb
264
+ namespace :app_proxy do
265
+ # simple routes without a specified controller will go to AppProxyController
266
+ # GET '/app_proxy/basic' will be routed to AppProxyController#basic
267
+ get :basic
268
+
269
+ # this will route GET /app_proxy to AppProxyController#main
270
+ root action: :main
271
+
272
+ # more complex routes will go to controllers in the AppProxy namespace
273
+ resources :reviews
274
+ # GET /app_proxy/reviews will now be routed to
275
+ # AppProxy::ReviewsController#index, for example
276
+ end
277
+ ```
278
+
279
+ 2. `include` the mixin in your app proxy controllers
280
+ ```ruby
281
+ # app/controllers/app_proxy_controller.rb
282
+ class AppProxyController < ApplicationController
283
+ include SpiffyStoresApp::AppProxyVerification
284
+
285
+ def basic
286
+ render text: 'Signature verification passed!'
287
+ end
288
+ end
289
+
290
+ # app/controllers/app_proxy/reviews_controller.rb
291
+ class ReviewsController < ApplicationController
292
+ include SpiffyStoresApp::AppProxyVerification
293
+ # ...
294
+ end
295
+ ```
296
+ 3. Contact us for further information on this feature.
297
+
298
+ Troubleshooting
299
+ ---------------
300
+
301
+ ### Generator spiffy_stores_app:install hangs
302
+
303
+ Rails uses spring by default to speed up development. To run the generator, spring has to be stopped:
304
+
305
+ ```sh
306
+ $ bundle exec spring stop
307
+ ```
308
+
309
+ Run spiffy_stores_app generator again.
310
+
311
+ Testing an embedded app outside the Spiffy Stores admin
312
+ -------------------------------------------------------
313
+
314
+ By default, loading your embedded app will redirect to the Spiffy Stores admin, with the app view loaded in an `iframe`. If you need to load your app outside of the Spiffy Stores admin (e.g., for performance testing), you can change `forceRedirect: false` to `true` in `SpiffyApp.init` block in the `embedded_app` view. To keep the redirect on in production but off in your `development` and `test` environments, you can use:
315
+
316
+ ```javascript
317
+ forceRedirect: <%= Rails.env.development? || Rails.env.test? ? 'false' : 'true' %>
318
+ ```
319
+
320
+ Questions or problems?
321
+ ----------------------
322
+
323
+ https://www.spiffystores.com.au/kb/An_Introduction_to_the_Spiffy_Stores_API <= Read the docs!
324
+
325
+ License
326
+ -------
327
+
328
+ Copyright (c) 2018 Spiffy Stores
329
+
330
+ Permission is hereby granted, free of charge, to any person obtaining a copy
331
+ of this software and associated documentation files (the "Software"), to deal
332
+ in the Software without restriction, including without limitation the rights
333
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
334
+ copies of the Software, and to permit persons to whom the Software is
335
+ furnished to do so, subject to the following conditions:
336
+
337
+ The above copyright notice and this permission notice shall be included in
338
+ all copies or substantial portions of the Software.
339
+
340
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
341
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
342
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
343
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
344
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
345
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
346
+ THE SOFTWARE.
@@ -0,0 +1,6 @@
1
+ require 'bundler/gem_tasks'
2
+ require 'rake/testtask'
3
+
4
+ require File.expand_path('../test/dummy/config/application', __FILE__)
5
+
6
+ Rails.application.load_tasks
@@ -0,0 +1,19 @@
1
+ document.addEventListener("DOMContentLoaded", function() {
2
+ var redirectTargetElement = document.getElementById("redirection-target");
3
+ var targetInfo = JSON.parse(redirectTargetElement.dataset.target)
4
+
5
+ if (window.top == window.self) {
6
+ // If the current window is the 'parent', change the URL by setting location.href
7
+ window.top.location.href = targetInfo.url;
8
+ } else {
9
+ // If the current window is the 'child', change the parent's URL with postMessage
10
+ normalizedLink = document.createElement('a');
11
+ normalizedLink.href = targetInfo.url;
12
+
13
+ data = JSON.stringify({
14
+ message: 'SpiffyStores.API.remoteRedirect',
15
+ data: { location: normalizedLink.href }
16
+ });
17
+ window.parent.postMessage(data, targetInfo.myspiffyUrl);
18
+ }
19
+ });
@@ -0,0 +1,11 @@
1
+ module SpiffyStoresApp
2
+ class AuthenticatedController < ActionController::Base
3
+ include SpiffyStoresApp::Localization
4
+ include SpiffyStoresApp::LoginProtection
5
+ include SpiffyStoresApp::EmbeddedApp
6
+
7
+ protect_from_forgery with: :exception
8
+ before_action :login_again_if_different_shop
9
+ around_action :spiffy_stores_session
10
+ end
11
+ end
@@ -0,0 +1,113 @@
1
+ module SpiffyStoresApp
2
+ class SessionsController < ActionController::Base
3
+ include SpiffyStoresApp::LoginProtection
4
+ layout false, only: :new
5
+ after_action only: [:new, :create] do |controller|
6
+ controller.response.headers.except!('X-Frame-Options')
7
+ end
8
+
9
+ def new
10
+ authenticate if sanitized_shop_name.present?
11
+ end
12
+
13
+ def create
14
+ authenticate
15
+ end
16
+
17
+ def callback
18
+ if auth_hash
19
+ login_shop
20
+ install_webhooks
21
+ install_scripttags
22
+ perform_after_authenticate_job
23
+
24
+ redirect_to return_address
25
+ else
26
+ flash[:error] = I18n.t('could_not_log_in')
27
+ redirect_to login_url
28
+ end
29
+ end
30
+
31
+ def destroy
32
+ reset_session
33
+ flash[:notice] = I18n.t('.logged_out')
34
+ redirect_to login_url
35
+ end
36
+
37
+ private
38
+
39
+ def authenticate
40
+ if sanitized_shop_name.present?
41
+ session['spiffy.omniauth_params'] = { store: sanitized_shop_name }
42
+ fullpage_redirect_to "#{main_app.root_path}auth/spiffy"
43
+ else
44
+ flash[:error] = I18n.t('invalid_shop_url')
45
+ redirect_to return_address
46
+ end
47
+ end
48
+
49
+ def login_shop
50
+ sess = SpiffyStoresAPI::Session.new(shop_name, token)
51
+
52
+ request.session_options[:renew] = true
53
+ session.delete(:_csrf_token)
54
+
55
+ session[:spiffy_stores] = SpiffyStoresApp::SessionRepository.store(sess)
56
+ session[:spiffy_stores_domain] = shop_name
57
+ session[:spiffy_stores_user] = associated_user if associated_user.present?
58
+ end
59
+
60
+ def auth_hash
61
+ request.env['omniauth.auth']
62
+ end
63
+
64
+ def shop_name
65
+ auth_hash.uid
66
+ end
67
+
68
+ def associated_user
69
+ return unless auth_hash['extra'].present?
70
+ auth_hash['extra']['associated_user']
71
+ end
72
+
73
+ def token
74
+ auth_hash['credentials']['token']
75
+ end
76
+
77
+ def install_webhooks
78
+ return unless SpiffyStoresApp.configuration.has_webhooks?
79
+
80
+ WebhooksManager.queue(
81
+ shop_name,
82
+ token,
83
+ SpiffyStoresApp.configuration.webhooks
84
+ )
85
+ end
86
+
87
+ def install_scripttags
88
+ return unless SpiffyStoresApp.configuration.has_scripttags?
89
+
90
+ ScripttagsManager.queue(
91
+ shop_name,
92
+ token,
93
+ SpiffyStoresApp.configuration.scripttags
94
+ )
95
+ end
96
+
97
+ def perform_after_authenticate_job
98
+ config = SpiffyStoresApp.configuration.after_authenticate_job
99
+
100
+ return unless config && config[:job].present?
101
+
102
+ if config[:inline] == true
103
+ config[:job].perform_now(shop_domain: session[:spiffy_stores_domain])
104
+ else
105
+ config[:job].perform_later(shop_domain: session[:spiffy_stores_domain])
106
+ end
107
+ end
108
+
109
+ def return_address
110
+ session.delete(:return_to) || SpiffyStoresApp::configuration.root_url
111
+ end
112
+ end
113
+ end