duodealer_app 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (212) hide show
  1. checksums.yaml +7 -0
  2. data/.!66854!duodealer_app.gemspec +0 -0
  3. data/.babelrc +5 -0
  4. data/.gitignore +16 -0
  5. data/.nvmrc +1 -0
  6. data/.rubocop.yml +263 -0
  7. data/.ruby-version +1 -0
  8. data/.travis.yml +27 -0
  9. data/Gemfile +8 -0
  10. data/LICENSE +19 -0
  11. data/README.md +553 -0
  12. data/Rakefile +6 -0
  13. data/app/assets/images/storage_access.svg +2 -0
  14. data/app/assets/javascripts/duodealer_app/enable_cookies.js +3 -0
  15. data/app/assets/javascripts/duodealer_app/itp_helper.js +40 -0
  16. data/app/assets/javascripts/duodealer_app/partition_cookies.js +8 -0
  17. data/app/assets/javascripts/duodealer_app/redirect.js +33 -0
  18. data/app/assets/javascripts/duodealer_app/request_storage_access.js +3 -0
  19. data/app/assets/javascripts/duodealer_app/storage_access.js +153 -0
  20. data/app/assets/javascripts/duodealer_app/storage_access_redirect.js +17 -0
  21. data/app/assets/javascripts/duodealer_app/top_level.js +2 -0
  22. data/app/assets/javascripts/duodealer_app/top_level_interaction.js +11 -0
  23. data/app/controllers/concerns/duodealer_app/authenticated.rb +15 -0
  24. data/app/controllers/concerns/duodealer_app/authenticated.rb-e +15 -0
  25. data/app/controllers/duodealer_app/authenticated_controller.rb +9 -0
  26. data/app/controllers/duodealer_app/authenticated_controller.rb-e +9 -0
  27. data/app/controllers/duodealer_app/callback_controller.rb +104 -0
  28. data/app/controllers/duodealer_app/callback_controller.rb-e +104 -0
  29. data/app/controllers/duodealer_app/extension_verification_controller.rb +19 -0
  30. data/app/controllers/duodealer_app/extension_verification_controller.rb-e +19 -0
  31. data/app/controllers/duodealer_app/sessions_controller.rb +159 -0
  32. data/app/controllers/duodealer_app/sessions_controller.rb-e +159 -0
  33. data/app/controllers/duodealer_app/webhooks_controller.rb +37 -0
  34. data/app/controllers/duodealer_app/webhooks_controller.rb-e +37 -0
  35. data/app/views/duodealer_app/partials/_button_styles.html.erb +104 -0
  36. data/app/views/duodealer_app/partials/_button_styles.html.erb-e +104 -0
  37. data/app/views/duodealer_app/partials/_card_styles.html.erb +33 -0
  38. data/app/views/duodealer_app/partials/_card_styles.html.erb-e +33 -0
  39. data/app/views/duodealer_app/partials/_empty_state_styles.html.erb +129 -0
  40. data/app/views/duodealer_app/partials/_empty_state_styles.html.erb-e +129 -0
  41. data/app/views/duodealer_app/partials/_layout_styles.html.erb +167 -0
  42. data/app/views/duodealer_app/partials/_layout_styles.html.erb-e +167 -0
  43. data/app/views/duodealer_app/partials/_typography_styles.html.erb +35 -0
  44. data/app/views/duodealer_app/partials/_typography_styles.html.erb-e +35 -0
  45. data/app/views/duodealer_app/sessions/enable_cookies.html.erb +75 -0
  46. data/app/views/duodealer_app/sessions/enable_cookies.html.erb-e +75 -0
  47. data/app/views/duodealer_app/sessions/new.html.erb +123 -0
  48. data/app/views/duodealer_app/sessions/new.html.erb-e +123 -0
  49. data/app/views/duodealer_app/sessions/request_storage_access.html.erb +68 -0
  50. data/app/views/duodealer_app/sessions/request_storage_access.html.erb-e +68 -0
  51. data/app/views/duodealer_app/sessions/top_level_interaction.html.erb +64 -0
  52. data/app/views/duodealer_app/sessions/top_level_interaction.html.erb-e +64 -0
  53. data/app/views/duodealer_app/shared/redirect.html.erb +23 -0
  54. data/app/views/duodealer_app/shared/redirect.html.erb-e +23 -0
  55. data/config/locales/cs.yml +23 -0
  56. data/config/locales/da.yml +20 -0
  57. data/config/locales/de.yml +22 -0
  58. data/config/locales/en.yml +15 -0
  59. data/config/locales/es.yml +22 -0
  60. data/config/locales/fi.yml +20 -0
  61. data/config/locales/fr.yml +23 -0
  62. data/config/locales/hi.yml +23 -0
  63. data/config/locales/it.yml +21 -0
  64. data/config/locales/ja.yml +17 -0
  65. data/config/locales/ko.yml +19 -0
  66. data/config/locales/ms.yml +22 -0
  67. data/config/locales/nb.yml +21 -0
  68. data/config/locales/nl.yml +21 -0
  69. data/config/locales/pl.yml +21 -0
  70. data/config/locales/pt-BR.yml +21 -0
  71. data/config/locales/pt-PT.yml +22 -0
  72. data/config/locales/sv.yml +21 -0
  73. data/config/locales/th.yml +20 -0
  74. data/config/locales/tr.yml +22 -0
  75. data/config/locales/zh-CN.yml +16 -0
  76. data/config/locales/zh-TW.yml +16 -0
  77. data/config/routes.rb +22 -0
  78. data/docs/.!20385!test-your-app.png +0 -0
  79. data/docs/.!20388!install-on-dev-shop.png +0 -0
  80. data/docs/.!62511!test-your-app.png +0 -0
  81. data/docs/.!62512!install-on-dev-shop.png +0 -0
  82. data/docs/.!62763!test-your-app.png +0 -0
  83. data/docs/.!62765!install-on-dev-shop.png +0 -0
  84. data/docs/.!63018!test-your-app.png +0 -0
  85. data/docs/.!63020!install-on-dev-shop.png +0 -0
  86. data/docs/.!63289!test-your-app.png +0 -0
  87. data/docs/.!63291!install-on-dev-shop.png +0 -0
  88. data/docs/.!63562!test-your-app.png +0 -0
  89. data/docs/.!63564!install-on-dev-shop.png +0 -0
  90. data/docs/.!63872!test-your-app.png +0 -0
  91. data/docs/.!63874!install-on-dev-shop.png +0 -0
  92. data/docs/.!64151!test-your-app.png +0 -0
  93. data/docs/.!64153!install-on-dev-shop.png +0 -0
  94. data/docs/.!64428!test-your-app.png +0 -0
  95. data/docs/.!64431!install-on-dev-shop.png +0 -0
  96. data/docs/.!64737!test-your-app.png +0 -0
  97. data/docs/.!64740!install-on-dev-shop.png +0 -0
  98. data/docs/.!65025!test-your-app.png +0 -0
  99. data/docs/.!65028!install-on-dev-shop.png +0 -0
  100. data/docs/.!65324!test-your-app.png +0 -0
  101. data/docs/.!65327!install-on-dev-shop.png +0 -0
  102. data/docs/.!65626!test-your-app.png +0 -0
  103. data/docs/.!65629!install-on-dev-shop.png +0 -0
  104. data/docs/.!65942!test-your-app.png +0 -0
  105. data/docs/.!65945!install-on-dev-shop.png +0 -0
  106. data/docs/.!66760!test-your-app.png +0 -0
  107. data/docs/.!66763!install-on-dev-shop.png +0 -0
  108. data/docs/.!67028!test-your-app.png +0 -0
  109. data/docs/.!67031!install-on-dev-shop.png +0 -0
  110. data/docs/.!67657!test-your-app.png +0 -0
  111. data/docs/.!67660!install-on-dev-shop.png +0 -0
  112. data/docs/.!68031!test-your-app.png +0 -0
  113. data/docs/.!68034!install-on-dev-shop.png +0 -0
  114. data/docs/.!68363!test-your-app.png +0 -0
  115. data/docs/.!68366!install-on-dev-shop.png +0 -0
  116. data/docs/Quickstart.md +103 -0
  117. data/docs/Releasing.md +17 -0
  118. data/docs/Troubleshooting.md +16 -0
  119. data/docs/install-on-dev-shop.png +0 -0
  120. data/docs/test-your-app.png +0 -0
  121. data/duodealer_app.gemspec +34 -0
  122. data/images/.!20334!app-proxy-screenshot.png +0 -0
  123. data/images/.!62504!app-proxy-screenshot.png +0 -0
  124. data/images/.!62754!app-proxy-screenshot.png +0 -0
  125. data/images/.!63008!app-proxy-screenshot.png +0 -0
  126. data/images/.!63277!app-proxy-screenshot.png +0 -0
  127. data/images/.!63548!app-proxy-screenshot.png +0 -0
  128. data/images/.!63855!app-proxy-screenshot.png +0 -0
  129. data/images/.!64132!app-proxy-screenshot.png +0 -0
  130. data/images/.!64407!app-proxy-screenshot.png +0 -0
  131. data/images/.!64714!app-proxy-screenshot.png +0 -0
  132. data/images/.!65000!app-proxy-screenshot.png +0 -0
  133. data/images/.!65296!app-proxy-screenshot.png +0 -0
  134. data/images/.!65594!app-proxy-screenshot.png +0 -0
  135. data/images/.!65908!app-proxy-screenshot.png +0 -0
  136. data/images/.!66724!app-proxy-screenshot.png +0 -0
  137. data/images/.!66989!app-proxy-screenshot.png +0 -0
  138. data/images/.!67614!app-proxy-screenshot.png +0 -0
  139. data/images/.!67986!app-proxy-screenshot.png +0 -0
  140. data/images/.!68314!app-proxy-screenshot.png +0 -0
  141. data/images/app-proxy-screenshot.png +0 -0
  142. data/karma.conf.js +44 -0
  143. data/lib/duodealer_app.rb +54 -0
  144. data/lib/duodealer_app/configuration.rb +85 -0
  145. data/lib/duodealer_app/controller_concerns/app_proxy_verification.rb +39 -0
  146. data/lib/duodealer_app/controller_concerns/embedded_app.rb +20 -0
  147. data/lib/duodealer_app/controller_concerns/itp.rb +44 -0
  148. data/lib/duodealer_app/controller_concerns/localization.rb +23 -0
  149. data/lib/duodealer_app/controller_concerns/login_protection.rb +180 -0
  150. data/lib/duodealer_app/controller_concerns/webhook_verification.rb +39 -0
  151. data/lib/duodealer_app/engine.rb +22 -0
  152. data/lib/duodealer_app/jobs/scripttags_manager_job.rb +17 -0
  153. data/lib/duodealer_app/jobs/webhooks_manager_job.rb +17 -0
  154. data/lib/duodealer_app/managers/scripttags_manager.rb +78 -0
  155. data/lib/duodealer_app/managers/webhooks_manager.rb +62 -0
  156. data/lib/duodealer_app/middleware/same_site_cookie_middleware.rb +69 -0
  157. data/lib/duodealer_app/session/in_memory_session_store.rb +29 -0
  158. data/lib/duodealer_app/session/session_repository.rb +33 -0
  159. data/lib/duodealer_app/session/session_storage.rb +31 -0
  160. data/lib/duodealer_app/session/storage_strategies/shop_storage_strategy.rb +25 -0
  161. data/lib/duodealer_app/session/storage_strategies/user_storage_strategy.rb +26 -0
  162. data/lib/duodealer_app/utils.rb +24 -0
  163. data/lib/duodealer_app/version.rb +5 -0
  164. data/lib/generators/duodealer_app/add_after_authenticate_job/add_after_authenticate_job_generator.rb +46 -0
  165. data/lib/generators/duodealer_app/add_after_authenticate_job/templates/after_authenticate_job.rb +10 -0
  166. data/lib/generators/duodealer_app/add_marketing_activity_extension/add_marketing_activity_extension_generator.rb +40 -0
  167. data/lib/generators/duodealer_app/add_marketing_activity_extension/templates/marketing_activities_controller.rb +62 -0
  168. data/lib/generators/duodealer_app/add_webhook/add_webhook_generator.rb +69 -0
  169. data/lib/generators/duodealer_app/add_webhook/templates/webhook_job.rb +8 -0
  170. data/lib/generators/duodealer_app/app_proxy_controller/app_proxy_controller_generator.rb +27 -0
  171. data/lib/generators/duodealer_app/app_proxy_controller/templates/app_proxy_controller.rb +9 -0
  172. data/lib/generators/duodealer_app/app_proxy_controller/templates/app_proxy_route.rb +10 -0
  173. data/lib/generators/duodealer_app/app_proxy_controller/templates/index.html.erb +19 -0
  174. data/lib/generators/duodealer_app/authenticated_controller/authenticated_controller_generator.rb +15 -0
  175. data/lib/generators/duodealer_app/authenticated_controller/templates/authenticated_controller.rb +5 -0
  176. data/lib/generators/duodealer_app/controllers/controllers_generator.rb +30 -0
  177. data/lib/generators/duodealer_app/duodealer_app_generator.rb +19 -0
  178. data/lib/generators/duodealer_app/home_controller/home_controller_generator.rb +27 -0
  179. data/lib/generators/duodealer_app/home_controller/templates/home_controller.rb +8 -0
  180. data/lib/generators/duodealer_app/home_controller/templates/index.html.erb +21 -0
  181. data/lib/generators/duodealer_app/install/install_generator.rb +83 -0
  182. data/lib/generators/duodealer_app/install/templates/_flash_messages.html.erb +3 -0
  183. data/lib/generators/duodealer_app/install/templates/duodealer_app.js +15 -0
  184. data/lib/generators/duodealer_app/install/templates/duodealer_app.rb +15 -0
  185. data/lib/generators/duodealer_app/install/templates/duodealer_app_index.js +2 -0
  186. data/lib/generators/duodealer_app/install/templates/duodealer_provider.rb +20 -0
  187. data/lib/generators/duodealer_app/install/templates/embedded_app.html.erb +41 -0
  188. data/lib/generators/duodealer_app/install/templates/flash_messages.js +26 -0
  189. data/lib/generators/duodealer_app/install/templates/omniauth.rb +2 -0
  190. data/lib/generators/duodealer_app/install/templates/session_store.rb +4 -0
  191. data/lib/generators/duodealer_app/install/templates/user_agent.rb +5 -0
  192. data/lib/generators/duodealer_app/rotate_duodealer_token_job/rotate_duodealer_token_job_generator.rb +16 -0
  193. data/lib/generators/duodealer_app/rotate_duodealer_token_job/templates/rotate_duodealer_token.rake +17 -0
  194. data/lib/generators/duodealer_app/rotate_duodealer_token_job/templates/rotate_duodealer_token_job.rb +42 -0
  195. data/lib/generators/duodealer_app/routes/routes_generator.rb +32 -0
  196. data/lib/generators/duodealer_app/routes/templates/routes.rb +11 -0
  197. data/lib/generators/duodealer_app/shop_model/shop_model_generator.rb +39 -0
  198. data/lib/generators/duodealer_app/shop_model/templates/db/migrate/create_shops.erb +15 -0
  199. data/lib/generators/duodealer_app/shop_model/templates/shop.rb +7 -0
  200. data/lib/generators/duodealer_app/shop_model/templates/shops.yml +3 -0
  201. data/lib/generators/duodealer_app/user_model/templates/db/migrate/create_users.erb +16 -0
  202. data/lib/generators/duodealer_app/user_model/templates/user.rb +7 -0
  203. data/lib/generators/duodealer_app/user_model/templates/users.yml +4 -0
  204. data/lib/generators/duodealer_app/user_model/user_model_generator.rb +39 -0
  205. data/lib/generators/duodealer_app/views/views_generator.rb +30 -0
  206. data/package-lock.json +7224 -0
  207. data/package.json +28 -0
  208. data/shipit.rubygems.yml +4 -0
  209. data/translation.yml +7 -0
  210. data/webpack.config.js +24 -0
  211. data/yarn.lock +5263 -0
  212. metadata +447 -0
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 867012539e0d946ff8737b9f5a10995a2e40762ba4245c00fb4cbdfba998d3af
4
+ data.tar.gz: 976c1f4cc69c53a17fc6241594fd9a3405369dfca8dc2e01efd21906a2400c48
5
+ SHA512:
6
+ metadata.gz: 7012a1cd22626b677d50ed634e41084c55f7f170f1cdd3781f77b169c8c9434ae8ce04f8efc9e559adeb51175e2391dc0578d867d87f3678b389ebbf36a2286d
7
+ data.tar.gz: 73874f4a88d4a4b744b7b95f43681f5c0083465cb7cb4e6c6f40f9c8f7195b96e79928552c2e4ddb240a62a6985e8cb0cff7e539fa273e01fbb07f46b60d9f67
File without changes
data/.babelrc ADDED
@@ -0,0 +1,5 @@
1
+ {
2
+ "babel": {
3
+ "presets": ["duodealer/web"]
4
+ }
5
+ }
data/.gitignore ADDED
@@ -0,0 +1,16 @@
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/*
14
+ /node_modules/
15
+ .byebug_history
16
+
data/.nvmrc ADDED
@@ -0,0 +1 @@
1
+ 8.10.0
data/.rubocop.yml ADDED
@@ -0,0 +1,263 @@
1
+ inherit_gem:
2
+ rubocop-rails_config:
3
+ - config/rails.yml
4
+ require:
5
+ - rubocop-rails
6
+ - rubocop-performance
7
+
8
+ AllCops:
9
+ TargetRubyVersion: 2.6
10
+ # RuboCop has a bunch of cops enabled by default. This setting tells RuboCop
11
+ # to ignore them, so only the ones explicitly set in this file are enabled.
12
+ DisabledByDefault: true
13
+ Exclude:
14
+ - '**/templates/**/*'
15
+ - '**/node_modules/**/*'
16
+
17
+ Performance:
18
+ Exclude:
19
+ - '**/test/**/*'
20
+
21
+ Rails:
22
+ Enabled: true
23
+
24
+ # Prefer assert_not over assert !
25
+ Rails/AssertNot:
26
+ Include:
27
+ - '**/test/**/*'
28
+
29
+ # Prefer assert_not_x over refute_x
30
+ Rails/RefuteMethods:
31
+ Include:
32
+ - '**/test/**/*'
33
+
34
+ Rails/UnknownEnv:
35
+ Environments:
36
+ - production
37
+ - development
38
+ - test
39
+ - staging
40
+ - integration
41
+
42
+ # Prefer &&/|| over and/or.
43
+ Style/AndOr:
44
+ Enabled: true
45
+
46
+ # Align `when` with `case`.
47
+ Layout/CaseIndentation:
48
+ Enabled: true
49
+
50
+ # Align comments with method definitions.
51
+ Layout/CommentIndentation:
52
+ Enabled: true
53
+
54
+ Layout/ElseAlignment:
55
+ Enabled: true
56
+
57
+ # Align `end` with the matching keyword or starting expression except for
58
+ # assignments, where it should be aligned with the LHS.
59
+ Layout/EndAlignment:
60
+ Enabled: true
61
+ EnforcedStyleAlignWith: variable
62
+ AutoCorrect: true
63
+
64
+ Layout/EmptyLineAfterMagicComment:
65
+ Enabled: true
66
+
67
+ Layout/EmptyLinesAroundBlockBody:
68
+ Enabled: true
69
+ Exclude:
70
+ - "db/schema.rb"
71
+
72
+ # In a regular class definition, no empty lines around the body.
73
+ Layout/EmptyLinesAroundClassBody:
74
+ Enabled: true
75
+
76
+ # In a regular method definition, no empty lines around the body.
77
+ Layout/EmptyLinesAroundMethodBody:
78
+ Enabled: true
79
+
80
+ # In a regular module definition, no empty lines around the body.
81
+ Layout/EmptyLinesAroundModuleBody:
82
+ Enabled: true
83
+
84
+ Layout/FirstArgumentIndentation:
85
+ Enabled: true
86
+
87
+ # Use Ruby >= 1.9 syntax for hashes. Prefer { a: :b } over { :a => :b }.
88
+ Style/HashSyntax:
89
+ Enabled: true
90
+
91
+ # Method definitions after `private` or `protected` isolated calls need one
92
+ # extra level of indentation.
93
+ Layout/IndentationConsistency:
94
+ Enabled: true
95
+ EnforcedStyle: indented_internal_methods
96
+
97
+ # Two spaces, no tabs (for indentation).
98
+ Layout/IndentationWidth:
99
+ Enabled: true
100
+
101
+ Layout/LeadingCommentSpace:
102
+ Enabled: true
103
+
104
+ Layout/SpaceAfterColon:
105
+ Enabled: true
106
+
107
+ Layout/SpaceAfterComma:
108
+ Enabled: true
109
+
110
+ Layout/SpaceAfterSemicolon:
111
+ Enabled: true
112
+
113
+ Layout/SpaceAroundEqualsInParameterDefault:
114
+ Enabled: true
115
+
116
+ Layout/SpaceAroundKeyword:
117
+ Enabled: true
118
+
119
+ Layout/SpaceAroundOperators:
120
+ Enabled: true
121
+
122
+ Layout/SpaceBeforeComma:
123
+ Enabled: true
124
+
125
+ Layout/SpaceBeforeComment:
126
+ Enabled: true
127
+
128
+ Layout/SpaceBeforeFirstArg:
129
+ Enabled: true
130
+
131
+ Style/DefWithParentheses:
132
+ Enabled: true
133
+
134
+ # Defining a method with parameters needs parentheses.
135
+ Style/MethodDefParentheses:
136
+ Enabled: true
137
+
138
+ Style/RedundantFreeze:
139
+ Enabled: true
140
+
141
+ # Use `foo {}` not `foo{}`.
142
+ Layout/SpaceBeforeBlockBraces:
143
+ Enabled: true
144
+
145
+ # Use `foo { bar }` not `foo {bar}`.
146
+ Layout/SpaceInsideBlockBraces:
147
+ Enabled: true
148
+ EnforcedStyleForEmptyBraces: space
149
+
150
+ # Use `{ a: 1 }` not `{a:1}`.
151
+ Layout/SpaceInsideHashLiteralBraces:
152
+ Enabled: true
153
+
154
+ Layout/SpaceInsideParens:
155
+ Enabled: true
156
+
157
+ # Check quotes usage according to lint rule below.
158
+ Style/StringLiterals:
159
+ Enabled: true
160
+ EnforcedStyle: double_quotes
161
+
162
+ # Detect hard tabs, no hard tabs.
163
+ Layout/Tab:
164
+ Enabled: true
165
+
166
+ # Empty lines should not have any spaces.
167
+ Layout/TrailingEmptyLines:
168
+ Enabled: true
169
+
170
+ # No trailing whitespace.
171
+ Layout/TrailingWhitespace:
172
+ Enabled: true
173
+
174
+ # Use quotes for string literals when they are enough.
175
+ Style/RedundantPercentQ:
176
+ Enabled: true
177
+
178
+ Lint/AmbiguousOperator:
179
+ Enabled: true
180
+
181
+ Lint/AmbiguousRegexpLiteral:
182
+ Enabled: true
183
+
184
+ Lint/ErbNewArguments:
185
+ Enabled: true
186
+
187
+ # Use my_method(my_arg) not my_method( my_arg ) or my_method my_arg.
188
+ Lint/RequireParentheses:
189
+ Enabled: true
190
+
191
+ Lint/ShadowingOuterLocalVariable:
192
+ Enabled: true
193
+
194
+ Lint/RedundantStringCoercion:
195
+ Enabled: true
196
+
197
+ Lint/UriEscapeUnescape:
198
+ Enabled: true
199
+
200
+ Lint/UselessAssignment:
201
+ Enabled: true
202
+
203
+ Lint/DeprecatedClassMethods:
204
+ Enabled: true
205
+
206
+ Style/ParenthesesAroundCondition:
207
+ Enabled: true
208
+
209
+ Style/RedundantBegin:
210
+ Enabled: true
211
+
212
+ Style/RedundantReturn:
213
+ Enabled: true
214
+ AllowMultipleReturnValues: true
215
+
216
+ Style/Semicolon:
217
+ Enabled: true
218
+ AllowAsExpressionSeparator: true
219
+
220
+ # Prefer Foo.method over Foo::method
221
+ Style/ColonMethodCall:
222
+ Enabled: true
223
+
224
+ Style/TrivialAccessors:
225
+ Enabled: true
226
+
227
+ Performance/FlatMap:
228
+ Enabled: true
229
+
230
+ Performance/RedundantMerge:
231
+ Enabled: true
232
+
233
+ Performance/StartWith:
234
+ Enabled: true
235
+
236
+ Performance/EndWith:
237
+ Enabled: true
238
+
239
+ Performance/RegexpMatch:
240
+ Enabled: true
241
+
242
+ Performance/ReverseEach:
243
+ Enabled: true
244
+
245
+ Performance/UnfreezeString:
246
+ Enabled: true
247
+
248
+ # Frozen String Literal
249
+ Style/FrozenStringLiteralComment:
250
+ Enabled: true
251
+ Exclude:
252
+ - 'config.ru'
253
+ - 'Dangerfile'
254
+ - 'Gemfile'
255
+ - 'Rakefile'
256
+ - 'app/views/**/*'
257
+ - 'config/**/*'
258
+ - 'danger/**/*'
259
+ - 'db/schema.rb'
260
+ - 'lib/tasks/**/*'
261
+ - 'qa/**/*'
262
+ - 'rubocop/**/*'
263
+ - 'scripts/**/*'
data/.ruby-version ADDED
@@ -0,0 +1 @@
1
+ 2.6.4
data/.travis.yml ADDED
@@ -0,0 +1,27 @@
1
+ sudo: required
2
+ dist: trusty
3
+ addons:
4
+ chrome: stable
5
+ before_script:
6
+ - "sudo chown root /opt/google/chrome/chrome-sandbox"
7
+ - "sudo chmod 4755 /opt/google/chrome/chrome-sandbox"
8
+ language: ruby
9
+ cache:
10
+ bundler: true
11
+ directories:
12
+ - node_modules
13
+ yarn: true
14
+
15
+ rvm:
16
+ - 2.4.3
17
+ - 2.5.0
18
+ - 2.6.2
19
+
20
+ install:
21
+ - bundle install
22
+ - nvm install node
23
+ - yarn
24
+
25
+ script:
26
+ - yarn test
27
+ - bundle exec rake test
data/Gemfile ADDED
@@ -0,0 +1,8 @@
1
+ source "https://rubygems.org"
2
+
3
+ # Specify your gem's dependencies in duodealer_app.gemspec
4
+ gemspec
5
+
6
+ gem "rails-controller-testing", group: :test
7
+ gem "rubocop", "~> 0.80.0", require: false
8
+ gem "rubocop-rails_config", "~> 0.10.0"
data/LICENSE ADDED
@@ -0,0 +1,19 @@
1
+ Copyright (c) 2020 Duo Dealer
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining a copy
4
+ of this software and associated documentation files (the "Software"), to deal
5
+ in the Software without restriction, including without limitation the rights
6
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7
+ copies of the Software, and to permit persons to whom the Software is
8
+ furnished to do so, subject to the following conditions:
9
+
10
+ The above copyright notice and this permission notice shall be included in
11
+ all copies or substantial portions of the Software.
12
+
13
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19
+ THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,553 @@
1
+ Duo Dealer App
2
+ ===========
3
+ [![Version][gem]][gem_url] [![Build Status](https://travis-ci.org/Duo Dealer/duodealer_app.png)](https://travis-ci.org/Duo Dealer/duodealer_app)
4
+
5
+ [gem]: https://img.shields.io/gem/v/duodealer_app.svg
6
+ [gem_url]: https://rubygems.org/gems/duodealer_app
7
+
8
+
9
+ Duo Dealer Application Rails engine and generator
10
+
11
+ #### 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.
12
+
13
+ Table of Contents
14
+ -----------------
15
+ - [Introduction](#introduction)
16
+ - [Become a Duo Dealer App Developer](#become-a-duodealer-app-developer)
17
+ - [Installation](#installation)
18
+ - [Generators](#generators)
19
+ - [Mounting the Engine](#mounting-the-engine)
20
+ - [Authentication](#authentication)
21
+ - [WebhooksManager](#webhooksmanager)
22
+ - [ScripttagsManager](#scripttagsmanager)
23
+ - [RotateDuo DealerTokenJob](#rotateduodealertokenjob)
24
+ - [App Tunneling](#app-tunneling)
25
+ - [AppProxyVerification](#appproxyverification)
26
+ - [Troubleshooting](#troubleshooting)
27
+ - [Testing an embedded app outside the Duo Dealer admin](#testing-an-embedded-app-outside-the-duodealer-admin)
28
+ - [Questions or problems?](#questions-or-problems-)
29
+ - [Rails 6 Compatibility](#rails-6-compatibility)
30
+ - [Upgrading from 8.6 to 9.0.0](#upgrading-from-86-to-900)
31
+
32
+ Introduction
33
+ -----------
34
+ Get started with the [Duo Dealer Admin API](https://help.duodealer.com/en/api/getting-started) faster; This gem includes a Rails Engine and generators for writing Rails applications using the Duo Dealer API. The Engine provides a SessionsController and all the required code for authenticating with a shop via Oauth (other authentication methods are not supported).
35
+
36
+ *Note: It's recommended to use this on a new Rails project, so that the generator won't overwrite/delete your files.*
37
+
38
+ Learn how to create and deploy a new Duo Dealer App to Heroku with our [quickstart guide](https://github.com/Duo Dealer/duodealer_app/blob/master/docs/Quickstart.md), or dive in in less than 5 minutes with this quickstart video:
39
+
40
+ [https://www.youtube.com/watch?v=yGxeoAHlQOg](https://www.youtube.com/watch?v=yGxeoAHlQOg)
41
+
42
+ Become a Duo Dealer App Developer
43
+ --------------------------------
44
+ To become a Duo Dealer App Developer you'll need a [Duo Dealer Partner account.](http://duodealer.com/partners) If you don't have a Duo Dealer Partner account, head to http://duodealer.com/partners to create one before you start.
45
+
46
+ Once you have a Partner account, [create a new application in the Partner Dashboard](https://help.duodealer.com/en/api/tools/partner-dashboard/your-apps) to get an API key and other API credentials.
47
+
48
+ To create an application for development set your new app's `App URL` to the URL provided by [your tunnel](#app-tunneling), ensuring that you use `https://`. If you are not planning to embed your app inside the Duo Dealer admin or receive webhooks, set your redirect URL to `http://localhost:3000/` and the `Whitelisted redirection URL(s)` to contain `<App URL>/auth/duodealer/callback`.
49
+
50
+ Installation
51
+ ------------
52
+ To get started add `duodealer_app` to your Gemfile and run `bundle install`:
53
+
54
+ ``` sh
55
+ # Create a new rails app
56
+ $ rails new my_duodealer_app
57
+ $ cd my_duodealer_app
58
+
59
+ # Add the gem duodealer_app to your Gemfile
60
+ $ echo "gem 'duodealer_app'" >> Gemfile
61
+ $ bundle install
62
+ ```
63
+
64
+ Now we are ready to run any of the [generators](#generators) included with `duodealer_app`. The following section explains the generators and what you can do with them.
65
+
66
+
67
+ #### Rails Compatibility
68
+
69
+ The lastest version of duodealer_app is compatible with Rails `>= 5`. Use version `<= v7.2.8` if you need to work with Rails 4.
70
+
71
+
72
+ Generators
73
+ ----------
74
+
75
+ ### Default Generator
76
+
77
+ The default generator will run the `install`, `shop`, and `home_controller` generators. This is the recommended way to start a new app from scratch:
78
+
79
+ ```sh
80
+ $ rails generate duodealer_app
81
+ ```
82
+
83
+ After running the generator, you will need to run `rails db:migrate` to add new tables to your database. You can start your app with `bundle exec rails server` and install your app by visiting `http://localhost` in your web browser.
84
+
85
+ ### API Keys
86
+
87
+ The default and install generators have been updated to source Duo Dealer API key and secret from an Environment (`.env`) variables file, which you will need to create with the following format:
88
+
89
+ ```
90
+ DUODEALER_API_KEY=your api key
91
+ DUODEALER_API_SECRET=your api secret
92
+ ```
93
+
94
+ These values can be found on the "App Setup" page in the [Duo Dealer Partners Dashboard][dashboard]. If you are checking your code into a code repository, ensure your `.gitignore` prevents your `.env` file from being checked into any publicly accessible code.
95
+
96
+ ### Install Generator
97
+
98
+ ```sh
99
+ $ rails generate duodealer_app:install
100
+
101
+ # or optionally with arguments:
102
+
103
+ $ rails generate duodealer_app:install
104
+ ```
105
+
106
+ Other options include:
107
+ * `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"`)
108
+ * `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
109
+ (e.g. `--scope read_products, write_orders, write_products` or `--scope "read_products, write_orders, write_products"`)
110
+ For more information, refer the [docs](http://docs.duodealer.com/api/tutorials/oauth).
111
+ * `embedded` - the default is to generate an [embedded app](http://docs.duodealer.com/embedded-app-sdk), if you want a legacy non-embedded app then set this to false, `--embedded false`
112
+
113
+ You can update any of these settings later on easily, the arguments are simply for convenience.
114
+
115
+ The generator adds DuodealerApp and the required initializers to the host Rails application.
116
+
117
+ After running the `install` generator, you can start your app with `bundle exec rails server` and install your app by visiting localhost.
118
+
119
+
120
+ ### Home Controller Generator
121
+
122
+ ```sh
123
+ $ rails generate duodealer_app:home_controller
124
+ ```
125
+
126
+ This generator creates an example home controller and view which fetches and displays products using the Duo Dealer API
127
+
128
+
129
+ ### App Proxy Controller Generator
130
+
131
+ ```sh
132
+ $ rails generate duodealer_app:app_proxy_controller
133
+ ```
134
+
135
+ 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
136
+
137
+ ### Marketing Extension Generator
138
+
139
+ ```sh
140
+ $ rails generate duodealer_app:add_marketing_activity_extension
141
+ ```
142
+
143
+ This will create a controller with the endpoints required to build a [marketing activities extension](https://help.duodealer.com/en/api/embedded-apps/app-extensions/duodealer-admin/marketing-activities). The extension will be generated with a base url at `/marketing_activities`, which should also be configured in partners.
144
+
145
+ ### Controllers, Routes and Views
146
+
147
+ 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 duodealer_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.
148
+
149
+ Mounting the Engine
150
+ -------------------
151
+
152
+ Mounting the Engine will provide the basic routes to authenticating a shop with your application. By default it will provide:
153
+
154
+ | Verb | Route | Action |
155
+ |--------|-------------------------------|------------------------------|
156
+ |GET |'/login' |Login |
157
+ |POST |'/login' |Login |
158
+ |GET |'/auth/duodealer/callback' |Authenticate Callback |
159
+ |GET |'/logout' |Logout |
160
+ |POST |'/webhooks/:type' |Webhook Callback |
161
+
162
+ ### Nested Routes
163
+
164
+ The engine may also be mounted at a nested route, for example:
165
+
166
+ ```ruby
167
+ mount DuodealerApp::Engine, at: '/nested'
168
+ ```
169
+
170
+ This will create the Duo Dealer engine routes under the specified subpath. You'll also need to make some updates to your `duodealer_app.rb` and `omniauth.rb` initializers. First update the duodealer_app initializer to include a custom `root_url` e.g.:
171
+
172
+ ```ruby
173
+ DuodealerApp.configure do |config|
174
+ config.root_url = '/nested'
175
+ end
176
+ ```
177
+
178
+ then update the omniauth initializer to include a custom `callback_path` e.g.:
179
+
180
+ ```ruby
181
+ provider :duodealer,
182
+ DuodealerApp.configuration.api_key,
183
+ DuodealerApp.configuration.secret,
184
+ scope: DuodealerApp.configuration.scope,
185
+ callback_path: '/nested/auth/duodealer/callback'
186
+ ```
187
+
188
+ You may also need to change your `config/routes.rb` to render a view for `/nested`, since this is what will be rendered in the Duo Dealer Admin of any shops that have installed your app. The engine itself doesn't have a view for this, so you'll need something like this:
189
+
190
+ ```ruby
191
+ # config/routes.rb
192
+ Rails.application.routes.draw do
193
+ root :to => 'something_else#index'
194
+ get "/nested", to: "home#index"
195
+ mount DuodealerApp::Engine, at: '/nested'
196
+ end
197
+ ```
198
+
199
+ Finally, note that if you do this, to add your app to a store, you must navigate to `/nested` in order to render the `Enter your shop domain to log in or install this app.` UI.
200
+
201
+ ### Custom login URL
202
+
203
+ While you can customize the login view by creating a `/app/views/duodealer_app/sessions/new.html.erb` file, you may also want to customize the URL entirely. You can modify your `duodealer_app.rb` initializer to provide a custom `login_url` e.g.:
204
+
205
+ ```ruby
206
+ DuodealerApp.configure do |config|
207
+ config.login_url = 'https://my.domain.com/nested/login'
208
+ end
209
+ ```
210
+
211
+ Authentication
212
+ --------------
213
+
214
+ ### DuodealerApp::SessionRepository
215
+
216
+ `DuodealerApp::SessionRepository` allows you as a developer to define how your sessions are stored and retrieved for shops. The `SessionRepository` is configured in the `config/initializers/duodealer_app.rb` file and can be set to any object that implements `self.store(auth_session, *args)` which stores the session and returns a unique identifier and `self.retrieve(id)` which returns a `DuodealerAPI::Session` for the passed id. These methods are already implemented as part of the `DuodealerApp::SessionStorage` concern, but can be overridden for custom implementation.
217
+
218
+ 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. For multi-server environments, implement one of the following token-storage strategies.
219
+
220
+ #### Shop-based token storage
221
+ Storing tokens on the store model means that any user login associated to the store will have equal access levels to whatever the original user granted the app.
222
+ ```sh
223
+ $ rails generate duodealer_app:shop_model
224
+ ```
225
+ This will generate a shop model which will be the storage for the tokens necessary for authentication.
226
+
227
+ #### User-based token storage
228
+ A more granular control over level of access per user on an app might be necessary, to which the shop-based token strategy is not sufficient. Duo Dealer supports a user-based token storage strategy where a unique token to each user can be managed.
229
+ ```sh
230
+ $ rails generate duodealer_app:user_model
231
+ ```
232
+ This will generate a user model which will be the storage for the tokens necessary for authentication.
233
+
234
+ The current Duo Dealer user will be stored in the rails session at `session[:duodealer_user]`
235
+
236
+ In this mode, The `self.store(auth_session, *args)` will be invoked with a Duo Dealer User object hash, which is then used to store the token as part of a user record, rather than a store record.
237
+
238
+ This will change the type of token that Duo Dealer returns and it will only be valid for a short time. Read more about `Online access` [here](https://help.duodealer.com/api/getting-started/authentication/oauth). Note that this means you won't be able to use this token to respond to Webhooks.
239
+
240
+ #### Migrating from shop-based to user-based token strategy
241
+ After running the generator, ensure that configuration settings are successfully changed:
242
+
243
+ ```ruby
244
+ # In the `omniauth.rb` initializer:
245
+ provider :duodealer,
246
+ DuodealerApp.configuration.api_key,
247
+ DuodealerApp.configuration.secret,
248
+ scope: DuodealerApp.configuration.scope,
249
+ per_user_permissions: true
250
+
251
+ # In the `duodealer_app.rb` initializer:
252
+ config.session_repository = 'User'
253
+ config.per_user_tokens = true
254
+ ```
255
+
256
+ ### Authenticated
257
+
258
+ The engine provides a `DuodealerApp::Authenticated` concern which should be included in any controller that is intended to be behind Duo Dealer OAuth. It adds `before_action`s to ensure that the user is authenticated and will redirect to the Duo Dealer login page if not. It is best practice to include this concern in a base controller inheriting from your `ApplicationController`, from which all controllers that require Duo Dealer authentication inherit.
259
+
260
+ For backwards compatibility, the engine still provides a controller called `DuodealerApp::AuthenticatedController` which includes the `DuodealerApp::Authenticated` concern. Note that it inherits directly from `ActionController::Base`, so you will not be able to share functionality between it and your application's `ApplicationController`.
261
+
262
+ ### AfterAuthenticate Job
263
+
264
+ If your app needs to perform specific actions after the user is authenticated successfully (i.e. every time a new session is created), DuodealerApp can queue or run a job of your choosing (note that we already provide support for automatically creating Webhooks and Scripttags). To configure the after authenticate job update your initializer as follows:
265
+
266
+ ```ruby
267
+ DuodealerApp.configure do |config|
268
+ config.after_authenticate_job = { job: "Duo Dealer::AfterAuthenticateJob" }
269
+ end
270
+ ```
271
+
272
+ The job can be configured as either a class or a class name string.
273
+
274
+ If you need the job to run synchronously add the `inline` flag:
275
+
276
+ ```ruby
277
+ DuodealerApp.configure do |config|
278
+ config.after_authenticate_job = { job: Duo Dealer::AfterAuthenticateJob, inline: true }
279
+ end
280
+ ```
281
+
282
+ We've also provided a generator which creates a skeleton job and updates the initializer for you:
283
+
284
+ ```
285
+ bin/rails g duodealer_app:add_after_authenticate_job
286
+ ```
287
+
288
+ If you want to perform that action only once, e.g. send a welcome email to the user when they install the app, you should make sure that this action is idempotent, meaning that it won't have an impact if run multiple times.
289
+
290
+ API Versioning
291
+ --------------
292
+
293
+ Duo Dealer's API is versioned, and you can [read about that process in the Duo Dealer Developers documentation page](https://duodealer.dev/concepts/about-apis/versioning).
294
+
295
+ Since duodealer_app gem version 1.11.0, the included duodealer_api gem has also been updated to allow you to easily set and switch what version of the Duo Dealer API you want your app or service to use, as well as surface warnings to Rails apps about [deprecated endpoints, GraphQL fields and more](https://duodealer.dev/concepts/about-apis/versioning#deprecation-practices).
296
+
297
+ See the [duodealer_api gem README](https://github.com/Duo Dealer/duodealer_api/) for more details.
298
+
299
+ WebhooksManager
300
+ ---------------
301
+
302
+ DuodealerApp can manage your app's webhooks for you if you set which webhooks you require in the initializer:
303
+
304
+ ```ruby
305
+ DuodealerApp.configure do |config|
306
+ config.webhooks = [
307
+ {topic: 'carts/update', address: 'https://example-app.com/webhooks/carts_update'}
308
+ ]
309
+ end
310
+ ```
311
+
312
+ When the oauth callback is completed successfully DuodealerApp 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.
313
+
314
+ DuodealerApp also provides a WebhooksController that receives webhooks and queues a job based on the received topic. 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).
315
+
316
+ If you would like to namespace your jobs you may set `webhook_jobs_namespace` in the config. For example if your app handles webhooks from other ecommerce applications as well, and you want Duo Dealer cart update webhooks to be processed by a job living in `jobs/duodealer/webhooks/carts_update_job.rb` rather than `jobs/carts_update_job.rb`):
317
+
318
+ ```ruby
319
+ DuodealerApp.configure do |config|
320
+ config.webhook_jobs_namespace = 'duodealer/webhooks'
321
+ end
322
+ ```
323
+
324
+ If you are only interested in particular fields, you can optionally filter the data sent by Duo Dealer by specifying the `fields` parameter in `config/webhooks`. Note that you will still receive a webhook request from Duo Dealer every time the resource is updated, but only the specified fields will be sent.
325
+
326
+ ```ruby
327
+ DuodealerApp.configure do |config|
328
+ config.webhooks = [
329
+ {topic: 'products/update', address: 'https://example-app.com/webhooks/products_update', fields: ['title', 'vendor']}
330
+ ]
331
+ end
332
+ ```
333
+
334
+ If you'd rather implement your own controller then you'll want to use the WebhookVerification module to verify your webhooks, example:
335
+
336
+ ```ruby
337
+ class CustomWebhooksController < ApplicationController
338
+ include DuodealerApp::WebhookVerification
339
+
340
+ def carts_update
341
+ params.permit!
342
+ SomeJob.perform_later(shop_domain: shop_domain, webhook: webhook_params.to_h)
343
+ head :no_content
344
+ end
345
+
346
+ private
347
+
348
+ def webhook_params
349
+ params.except(:controller, :action, :type)
350
+ end
351
+ end
352
+ ```
353
+
354
+ The module skips the `verify_authenticity_token` before_action and adds an action to verify that the webhook came from Duo Dealer. You can now add a post route to your application pointing to the controller and action to accept the webhook data from Duo Dealer.
355
+
356
+ 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.
357
+
358
+ DuodealerApp 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.
359
+
360
+ ```
361
+ rails g duodealer_app:add_webhook -t carts/update -a https://example.com/webhooks/carts_update
362
+ ```
363
+
364
+ where `-t` is the topic and `-a` is the address the webhook should be sent to.
365
+
366
+ ScripttagsManager
367
+ -----------------
368
+
369
+ As with webhooks, DuodealerApp can manage your app's scripttags for you by setting which scripttags you require in the initializer:
370
+
371
+ ```ruby
372
+ DuodealerApp.configure do |config|
373
+ config.scripttags = [
374
+ {event:'onload', src: 'https://my-duodealerapp.herokuapp.com/fancy.js'},
375
+ {event:'onload', src: ->(domain) { dynamic_tag_url(domain) } }
376
+ ]
377
+ end
378
+ ```
379
+
380
+ You also need to have write_script_tags permission in the config scope in order to add script tags automatically:
381
+
382
+ ```ruby
383
+ config.scope = '... , write_script_tags'
384
+ ```
385
+
386
+ Scripttags are created in the same way as the Webhooks, with a background job which will create the required scripttags.
387
+
388
+ 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.
389
+
390
+ RotateDuo DealerTokenJob
391
+ ---------------------
392
+
393
+ If your Duo Dealer secret key is leaked, you can use the RotateDuo DealerTokenJob to perform [API Credential Rotation](https://help.duodealer.com/en/api/getting-started/authentication/oauth/api-credential-rotation).
394
+
395
+ Before running the job, you'll need to generate a new secret key from your Duo Dealer Partner dashboard, and update the `/config/initializers/duodealer_app.rb` to hold your new and old secret keys:
396
+
397
+ ```ruby
398
+ config.secret = Rails.application.secrets.duodealer_secret
399
+ config.old_secret = Rails.application.secrets.old_duodealer_secret
400
+ ```
401
+
402
+ We've provided a generator which creates the job and an example rake task:
403
+
404
+ ```sh
405
+ bin/rails g duodealer_app:rotate_duodealer_token_job
406
+ ```
407
+
408
+ The generated rake task will be found at `lib/tasks/duodealer/rotate_duodealer_token.rake` and is provided strictly for example purposes. It might not work with your application out of the box without some configuration.
409
+
410
+ ⚠️ Note: if you are updating `duodealer_app` from a version prior to 8.4.2 (and do not wish to run the default/install generator again), you will need to add [the following line](https://github.com/Duo Dealer/duodealer_app/blob/4f7e6cca2a472d8f7af44b938bd0fcafe4d8e88a/lib/generators/duodealer_app/install/templates/duodealer_provider.rb#L18) to `config/intializers/omniauth.rb`:
411
+
412
+ ```ruby
413
+ strategy.options[:old_client_secret] = DuodealerApp.configuration.old_secret
414
+ ```
415
+
416
+ App Tunneling
417
+ -------------
418
+
419
+ Your local app needs to be accessible from the public Internet in order to install it on a Duo Dealer store, to use the [App Proxy Controller](#app-proxy-controller-generator) or receive Webhooks.
420
+
421
+ Use a tunneling service like [ngrok](https://ngrok.com/), [Forward](https://forwardhq.com/), [Beeceptor](https://beeceptor.com/), [Mockbin](http://mockbin.org/), or [Hookbin](https://hookbin.com/) to make your development environment accessible to the internet.
422
+
423
+ For example with [ngrok](https://ngrok.com/), run this command to set up a tunnel proxy to Rails' default port:
424
+
425
+ ```sh
426
+ ngrok http 3000
427
+ ```
428
+
429
+ AppProxyVerification
430
+ --------------------
431
+
432
+ The engine provides a mixin for verifying incoming HTTP requests sent via an App Proxy. Any controller that `include`s `DuodealerApp::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.
433
+
434
+ ### Recommended Usage
435
+
436
+ The App Proxy Controller Generator automatically adds the mixin to the generated app_proxy_controller.rb
437
+ Additional controllers for resources within the App_Proxy namespace, will need to include the mixin like so:
438
+
439
+ ```ruby
440
+ # app/controllers/app_proxy/reviews_controller.rb
441
+ class ReviewsController < ApplicationController
442
+ include DuodealerApp::AppProxyVerification
443
+ # ...
444
+ end
445
+ ```
446
+
447
+ Create your app proxy url in the [Duo Dealer Partners' Dashboard][dashboard], making sure to point it to `https://your_app_website.com/app_proxy`.
448
+ ![Creating an App Proxy](/images/app-proxy-screenshot.png)
449
+
450
+ App Bridge
451
+ ---
452
+
453
+ A basic example of using [App Bridge][app-bridge] is included in the install generator. An app instance is automatically initialized in [duodealer_app.js](https://github.com/Duo Dealer/duodealer_app/blob/master/lib/generators/duodealer_app/install/templates/duodealer_app.js) and [flash_messages.js](https://github.com/Duo Dealer/duodealer_app/blob/master/lib/generators/duodealer_app/install/templates/flash_messages.js) converts Rails [flash messages](https://api.rubyonrails.org/classes/ActionDispatch/Flash.html) to App Bridge Toast actions automatically. By default, this library is included via [unpkg in the embedded_app layout](https://github.com/Duo Dealer/duodealer_app/blob/master/lib/generators/duodealer_app/install/templates/embedded_app.html.erb#L27). For more advanced uses it is recommended to [install App Bridge via npm or yarn](https://help.duodealer.com/en/api/embedded-apps/app-bridge/getting-started#set-up-duodealer-app-bridge-in-your-app).
454
+
455
+ Troubleshooting
456
+ ---------------
457
+
458
+ see [TROUBLESHOOTING.md](https://github.com/Duo Dealer/duodealer_app/blob/master/docs/Troubleshooting.md)
459
+
460
+ Testing an embedded app outside the Duo Dealer admin
461
+ -------------------------------------------------
462
+
463
+ By default, loading your embedded app will redirect to the Duo Dealer admin, with the app view loaded in an `iframe`. If you need to load your app outside of the Duo Dealer admin (e.g., for performance testing), you can change `forceRedirect: true` to `false` in `DuodealerApp.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:
464
+
465
+ ```javascript
466
+ forceRedirect: <%= Rails.env.development? || Rails.env.test? ? 'false' : 'true' %>
467
+ ```
468
+
469
+ Questions or problems?
470
+ ----------------------
471
+
472
+ - [Ask questions!](https://ecommerce.duodealer.com/c/duodealer-apis-and-technology)
473
+ - [Read the docs!](https://help.duodealer.com/api/guides)
474
+
475
+ Upgrading to 11.7.0
476
+ ---------------------------
477
+
478
+ ### Session storage method signature breaking change
479
+ If you override `def self.store(auth_session)` method in your session storage model (e.g. Shop), the method signature has changed to `def self.store(auth_session, *args)` in order to support user-based token storage. Please update your method signature to include the second argument.
480
+
481
+ Rails 6 Compatibility
482
+ ---------------------
483
+
484
+ ### Disable Webpacker
485
+ If you are using sprockets in rails 6 or want to generate a duodealer_app without webpacker run the install task by running
486
+
487
+ ```
488
+ DUODEALER_APP_DISABLE_WEBPACKER=1 rails generate duodealer_app
489
+ ```
490
+
491
+ and then in your DuodealerApp configuration block, add
492
+
493
+ ```
494
+ DuodealerApp.configure do |config|
495
+ config.disable_webpacker = true
496
+ end
497
+ ```
498
+
499
+ Upgrading from 8.6 to 9.0.0
500
+ ---------------------------
501
+
502
+ ### Configuration change
503
+
504
+ Add an api version configuration in `config/initializers/duodealer_app.rb`
505
+ Set this to the version you want to run against by default. See [Duo Dealer API docs](https://help.duodealer.com/en/api/versioning) for versions available.
506
+ ```ruby
507
+ config.api_version = '2019-04'
508
+ ```
509
+
510
+ ### Session storage change
511
+
512
+ You will need to add an `api_version` method to you session storage object. The default implementation for this is.
513
+ ```ruby
514
+ def api_version
515
+ DuodealerApp.configuration.api_version
516
+ end
517
+ ```
518
+
519
+ ### Generated file change
520
+
521
+ `embedded_app.html.erb` the usage of `shop_session.url` needs to be changed to `shop_session.domain`
522
+ ```erb
523
+ <script type="text/javascript">
524
+ DuodealerApp.init({
525
+ apiKey: "<%= DuodealerApp.configuration.api_key %>",
526
+
527
+ shopOrigin: "<%= "https://#{ @shop_session.url }" if @shop_session %>",
528
+
529
+ debug: false,
530
+ forceRedirect: true
531
+ });
532
+ </script>
533
+ ```
534
+ is changed to
535
+ ```erb
536
+ <script type="text/javascript">
537
+ DuodealerApp.init({
538
+ apiKey: "<%= DuodealerApp.configuration.api_key %>",
539
+
540
+ shopOrigin: "<%= "https://#{ @shop_session.domain }" if @shop_session %>",
541
+
542
+ debug: false,
543
+ forceRedirect: true
544
+ });
545
+ </script>
546
+ ```
547
+
548
+ ### DuodealerAPI changes
549
+
550
+ You will need to also follow the DuodealerAPI [upgrade guide](https://github.com/Duo Dealer/duodealer_api/blob/master/README.md#-breaking-change-notice-for-version-700-) to ensure your app is ready to work with api versioning.
551
+
552
+ [dashboard]:https://partners.duodealer.com
553
+ [app-bridge]:https://help.duodealer.com/en/api/embedded-apps/app-bridge